-- Title: SPI_RF12B  ( spi_RF12B.jal )
-- Author H.v.Broekhuyzen (henk@henkzelf.nl)
-- Compiler: 2.4m
--
-- This file is a part of jallib (http:jallib.googlecode.com)
-- Released under the ZLIB licence:
--                       (http://www.opensource.org/licenses/zlib-license.html)
--
-- Description: This module is a driver for a tranceiver module RFM70 by HOPERF.
--
-- Before this module is included, module spi_sw_master.jal must be included.
-- Beside this, the calling program must define the IO variable: SPI_RF12B_CS_n
-- as define it as output.  Like:
--            var bit SPI_RF12B_CS_n is pin_a0  pin_a0_direction = output ;
-- This output has to be initialised to 1 ( SPI_RF12B_CS_n = 1 ) as soon as
--  possible after PowerUp/Reset because the RF12B's chip-select is active low,
--  as it is after the PIC is reset.
--
--  procedure SPI_RF12B_Init() has to be called at least 100 ms after Power_Up
--  because the RF12B neads this time.
--
---------- This module supplies the following procedures
-- procedure SPI_RF12B_writeCommand(word in com)  (mostly for local use)
-- procedure SPI_RF12B_Init()
-- procedure SPI_RF12B_set_Frequency()
-- procedure SPI_RF12B_set_Bandwidth()
-- procedure SPI_RF12B_set_Datarate
-- procedure SPI_RF12B_toReceive()
-- procedure SPI_RF12B_toTransmit()
-- procedure SPI_RF12B_toOff()
-- procedure SPI_RF12B_ResetFifo()
-- function  SPI_RF12B_readStatus()
-- function  SPI_RF12B_TX_not_empty()
-- function  SPI_RF12B_FIFO_empty()
-- function  SPI_RF12B_byteFromFiFo()
-- procedure SPI_RF12B_transmit(byte in toSend)
-- procedure SPI_RF12B_transmit_preamble()
-- procedure SPI_RF12B_transmit_packet(sbyte in nrOfBytes)
-- function  SPI_RF12B_receive_packet(word in maxLoops)
--
---------- For the last 2 procedures, the calling software has to define
-- two byte arrays for the payload data of a 'packet'. To save RAMspace
-- the same array can be used.
-- Example:
--        const byte MaxPayloadSize = 32
--        var byte RF12BpacketToTransmit[MaxPayloadSize]
--        var byte RF12BpacketReceived[MaxPayloadSize] at RF12BpacketToTransmit
--
-- Two constants in the calling software may modify how this file is compiled:
-- if const bit spi_rf12b_debug is defined and = true then
--   a status history (log) of 10 long is maintained. See SPI_RF12B_readStatus()
-- else: the log length == 1.
-- if const bit spi_rf12b_use_CRC is defined and = true then
--    procedure SPI_RF12B_transmit_packet() will calculate a 1 byte CRC from
--      the data and send this after the payload-data.
--    function  SPI_RF12B_receive_packet() will calculate the CRC from the
--      received data, and returns an errorcode if it is not equal to the
--      received CRC. (so the received data is unreliable)
--
--
-- SPI_RF12B_Init() has to be called after the SPIbus is initialised
--         (spi_init() see spi_sw_master.jal or (if used)  spi_hw_master.jal).
-- SPI_RF12B_Init() has to be called at least 100 ms after Power_Up because the
--         RF12B neads this time to start-up.
-- SPI_RF12B_Init() configures the RF12B. Most af the many parameters that can
--         be set do not depend on wheter the module is used to Tansmit or to
--         Receive. SPI_RF12B_Init switches circuits to Transmit OFF and for
--         Receiving OFF. Because the receiving circuit is switched off, the
--         FIFO for reeived bits / bytes stays empty what whould not be sure
--         when initialised in receive mode.
--         The Frequency in the band, Bandwidth and Datarate are set to the same
--         values as in the supplier's demo-program (might not be optimal).
--         They can be changed with next 3 procedures.
-- procedure SPI_RF12B_set_Frequency(word in f_spec) submits the RF12B's
--         Frequency setting command. For the meaning of f_spec see the suppiers
--         documentation. Init value == 1600 decimal
-- procedure SPI_RF12B_set_Bandwidth(word in band_width_code) submits the
--         RF12B's Receiver Control Command to change the Receiver baseband
--         band with setting. For the meaning of band_with_code see the suppiers
--         documentation. Init value == 200 kHz (code = 4)
-- procedure SPI_RF12B_set_Datarate(word in data_rate_code) submits the RF12B's
--         Dara Rate Command to change the Data_rate setting (bit/sec over the
--         air). For the meaning of data_rate_code see the suppiers
--         documentation. Init value == 71 (~~ 4800 bits/sec)
-- SPI_RF12B_toReceive() changes the setting of the RF12B to Receive.
-- SPI_RF12B_toTransmit() changes the setting to the Tranmit mode.
-- SPI_RF12B_toOff() changes the setting of the RF12B Off mode.
-- SPI_RF12B_ResetFifo() is to be used when receiving. SPI_RF12B_Init() controls
--         the RF12B so that NO bits are stored in the teceiver FIFO until
--         a pattern (0x2DD4) is received. So the transmitter
--         has to send uninterupted: 2 - 3 times 0xAA for clock-syncronisation
--         the Syncronisation pattern, and than the data to transport.
--         When the data is transported and the tranmitter stops sending bytes
--         (transmitbuffer underflow) the receivers FIFO is filled with 0x00 or
--         when the tranmitter is switched off, with random bytes.
--         So when a complete message is received, SPI_RF12B_ResetFifo() is
--         called to prevent bits to store in the FIFO until a new
--         Syncronisation pattern is received.
-- function SPI_RF12B_readStatus() returns the status word read from the RF12B.
--         For the meaning of these 16 bits see the spec of the IC.
--            Note: For debugging purposes: this function maintains a log of
--                  statusses read. A status is only inserted in the log when it
--                  differs from the one before.
--                  If the calling software has defined a constant:
--                     const bit spi_rf12b_debug   = true
--                  then: the last 10 different statusses are stored.
--                  else: only the last different status is remembered.
--    procedure SPI_RF12B_print_status_history() can be used to print
--                  the status log via the hardware RS232 interface.
--         The bit labeled RGIT of the status is the most significant  bit
--         in the returned value.
--         The most frequent use of reading the status is to check whether the
--         TX buffer can accept a next byte to send, and to check if a byte is
--         available in the receiver-FIFO.
--         That is why the following 2 functions are made available.
-- function SPI_RF12B_TX_not_empty() returns TRUE when the called has to wait
--         before the next byte to send can be presented.
--         Simple example: while SPI_RF12B_TX_not_empty() loop end loop
-- function SPI_RF12B_FIFO_empty() returns TRUE when the is no byte in the
--         receiver-FIFO. If not, it can be read using the following function:
-- function SPI_RF12B_ByteFromFiFo() returns a byte from the receiver FIFO
-- function SPI_RF12B_transmit(byte in toSend) can be used to store <toSend> in
--         the TX-buffer. Use SPI_RF12B_TX_not_empty() to wait until it is free.
-- procedure SPI_RF12B_transmit_preamble() is to be used at the beginning of
--         a 'packet'. When a RF12B is witched to receive, its HF circuits
--         will detect garbage bits until the detection circuit is locked on
--         the tranmitters bit rate. The RF12B will not present data to the
--         FIFO until the detection circuit is locked and two special code bytes
--         are received. Thats why the transmitter has to send preamble bytes
--         before the data to be stored in the FIFO.
--         NOTE: The meaningfull data has to be send without pauses otherwise
--               zero bits may be inserted. Also: The receiver has to know when
--               all meaningfull bytes are received. This can be archieved in
--               3 way's: 1) Each message has a fixed length known by tansmitter
--               and receiver. 2) The last byte is a special one (like a zero).
--               This methode is limited, because no 0 byte may be in the
--               playload data. 3) The number of playload bytes is sent in an
--               extra byte before the payload data. This last method is
--               implemented by SPI_RF12B_transmit_packet(byte in nrOfBytes)
--               and function  SPI_RF12B_receive_packet()
-- procedure SPI_RF12B_transmit_packet(sbyte in nrOfBytes) executes the
--               sequence:
--             - If <nrOfBytes> > 0 and spi_rf12b_use_CRC is defined and = true
--                   it calculates a 1-byte CRC from <nrOfBytes> and the
--                   payload-data.
--             - Then it switches to transmit mode, sends the preamble,
--             - Then: a byte: <nrOfBytes>. If the parameter <nrOfBytes> =< 0,
--               only this parameter is sent. We call these shortest messages:
--               "Signals". For more abaut signals, read below under
--               function  SPI_RF12B_receive_packet(maxLoops).
--             - Then an it sends <nrOfBytes> of array: RF12BpacketToTransmit
--             - Than, but only when <nrOfBytes> > 0 and spi_rf12b_use_CRC
--                        is defined and = true, it sends a CRC byte that
--               is calculated from <nrOfBytes> and the sent bytes from
--               RF12BpacketToTransmit. Function  SPI_RF12B_receive_packet()
--               will use this value to validate what is received.
--             - Then, to be shure that all above is transmitted, it presends a
--               dummy zero the one of the two transmisbuffers and waits until
--               at least one of these buffers is free again.
--             - Then it switches the RF12B to the off mode.
-- function  SPI_RF12B_receive_packet(maxLoops) executes normally the following
--               sequence:
--             - It switches to receive mode, and waits until the
--               'nrOfBytes' byte (or signal) arrives in the FIFO and stores
--               this locally,
--             - Then, is reads the payload bytes and stores these in the array
--               RF12BpacketReceived (counting until 'nrOfBytes' are received).
--             - Then it reads the CRC-byte sent by SPI_RF12B_transmit_packet()
--               compares this with the CRC value it calculates over received
--               bytes and if wrong: returns an error code (see below).
--             - Then it switches the RF12B to the OFF mode, and returns
--               'nrOfBytes' to the caller.
--      However:
--             - When the receiver is out of reach of the transmitter,
--               or the link is lost:the receiver-software whould become
--               'hanging' preventing corrective actions.
--               That is why the number of times the status of the RF12B is
--               polled for the arrival of the bytes, and when this reaches
--               <maxLoops> while waiting for the first byte, this function
--               switches the RF12B to mode OFF and
--           returns -1.
--               The time used for the loop reading the statusses depends
--               on the used speed of the SPI bus. When using SPI_sw_master.jal
--               is about 1 sec / 10000 loops.
--             - When the status indicates unreliable reception of data,
--               this function
--           returns -2.
--             - When the byte received as first (='nrOfBytes'> > 0, and so
--               also a CRC byte is received, a CRC check is performed. If
--               there is a mismatch, this function
--           returns -3 instead of 'nrOfBytes
--
--           NOTE: Mark that 'nrOfBytes' '(the value returned) has the
--               range of -128 ... +127.
--               If the received 'nrOfBytes' < 1 no payload data and CRC is
--               expected and this 'nrOfBytes' is returned. We call these
--               short messages SIGNALs
--               This enables the calling software to use zero negative values
--               as signals like ACK and NACK to acknowlege (or not) correct
--               arrival of the package.
--               Mark that signals -1, -2, and -3 are beter not tansmitted,
--               because they can not be distinguised from error-indications
--               as discribed above.
--               Signal -4 is reserved for: Calling software. It can
--               recall in a loop SPI_RF12B_receive_packet() when it returns -1
--               and define in this way its owen time-out conditions. In case
--               of this time-out it beter calls also procedure
--               SPI_RF12B_toOff()
--

--*****************************************************************************
-- Constants and variables for Debugging
--*****************************************************************************
-- When debuging is enabled a log of last 10 DIFFERENT statusses is maintained.
-- Else the log has a length of only 1 to save var space and CPU time
if defined(spi_rf12b_debug) == true then
  if spi_rf12b_debug == true then
    const byte HistSize = 10
  else
    const byte HistSize = 1
  end if
else
  const byte HistSize = 1
end if

--******************************************* Data
var word SPI_RF12B_status_log[HistSize]
--************************************************************************
--                   Procedures and functions                            *
--************************************************************************
procedure SPI_RF12B_print_status_history() is
  var byte i = 0
  var word s
  var word mask

  while i < HistSize loop
    mask = 0x8000
    s = SPI_RF12B_status_log[i]
    print_crlf(Serial_HW_data)
    format_word_hex(Serial_HW_data,s)
    serial_hw_write(" ")
    serial_hw_write("=")
    for 4 loop
      serial_hw_write(" ")
      for 4 loop
        if (s & mask) !=0 then
          serial_hw_write("1")
        else
          serial_hw_write("0")
        end if
        mask = mask >> 1
      end loop
    end loop
    i = i + 1
  end loop
  print_crlf(Serial_HW_data)
end procedure
--*****************************************************************************
procedure SPI_RF12B_writeCommand(word in com) is
  var byte comBytes[2] at com
  SPI_RF12B_CS_n = 0 ; selected
  spi_master_put_byte(comBytes[1])
  spi_master_put_byte(comBytes[0])
  SPI_RF12B_CS_n = 1 ; unselected
end procedure
--*****************************************************************************
function  SPI_RF12B_readStatus() return word is
  var word status
  var byte statusbytes[2] at status
  SPI_RF12B_CS_n = 0 ; selected
  statusBytes[1] = spi_master_get_byte()
  statusBytes[0] = spi_master_get_byte()
  SPI_RF12B_CS_n = 1 ; unselected
  ---------------------------------------------- for debugging
  if defined(spi_rf12b_debug) == true then
    if spi_rf12b_debug == true then
      if(status & 0xFF00)!= (SPI_RF12B_status_log[HistSize - 1] & 0xFF00) then
        ; Shift history log (oldest out)
        var byte i = 1
        while i < HistSize loop
          SPI_RF12B_status_log[i-1] = SPI_RF12B_status_log[i]
          i = i + 1
        end loop
      end if
    end if
  end if
  ----------------------------------------------- end for debugging
  SPI_RF12B_status_log[HistSize - 1] = status
  return status
end function
--*****************************************************************************
procedure SPI_RF12B_Init() is ; INITIALISES all and ready to SEND.
  pragma inline
   ; ----------------- 1 Configuration Setting Command ----------(spec page 13)
   SPI_RF12B_writeCommand(0x80D8)
           ; enable data registers, enable FIFO,
           ; freq band = 433 MHz, X-tal Load 12,5 pf
   ; ----------------- 2 Power Management Command ---------------(spec page 14)
   SPI_RF12B_writeCommand(0x8208)
           ; receiver chain = OFF, receiver baasband circuit = OFF,
           ; PLL + powerampl = OFF
           ; synthesizer = OFF, X-tal osc on,  low bat det=off, WakeUp timer=off,
           ; Clock output pin = not disabled
   ; ----------------- 3 Freq.Setting Command -------------------(spec page 15)
   SPI_RF12B_writeCommand(0xA640)
           ; Synthesizer band center = 434 Mhz
   ; ----------------- 4 Data-Rate Command ----------------------(spec page 15)
   SPI_RF12B_writeCommand(0xC647)
           ; 4,8567 kbps ~~ 4800 baut
   ; ----------------- 12 PLL Setting Command -------------------(spec page 20)
   SPI_RF12B_writeCommand(0xCC17)
           ; uC Clcck freq rise and fall time for 10 Mhz
           ; delay in phase detector = off
           ; dithering in PLL loop = disabled
           ; bandwidth for max 256 kbps
   ; ----------------- 5 Receiver Control Command ---------------(spec page 15)
   SPI_RF12B_writeCommand(0x94A0)
           ; P16 = VDI output (Valid Data Output), VDI response = fast
           ; Receiver basebandwidth = 134kHz,
           ; Low Noise Ampl = Max *0dBm,
           ; RSSI detector treshold = -103dBm
   ; ----------------- 6 Data Filter Command --------------------(spec page 16)
   SPI_RF12B_writeCommand(0xC2AC)
           ; Auto lockcontrol (clock recouvery) = on. and on slow mode.
           ; Filtertype= digital, DQD treshold=4 for 7 (medium)
   ; ----------------- 7 FIFO and Reset Mode Command ------------(spec page 17)
   SPI_RF12B_writeCommand(0xCA80)
           ; FIFO generates interupt when 8 bits are received,
           ; Syncrone pattern = 0x2DD4
           ; FIFO fill startcondition = Synchrone pattern
           ; FIFO fill stops (this bit is cleared)
           ; High sensitivity reset mode is on (500 mV glitch may couse reset)
   ; ----------------- 7 FIFO and Reset Mode command ----------- (spec page 17)
   SPI_RF12B_writeCommand(0xCA83)
           ; as last BUT
           ; FIFO fill will be enabled after synchron pattern reception
           ; High sensitivity reset mode = off (glitch does not couse reset)
           ; SO: the FIFO is reset and only filled after the Syncronisation
           ; Pattern. See also procedure SPI_RF12B_ResetFifo() below.
   ; ***************** 8 Synchron pattern Command --(CExx)-------(spec page 18)
           ; Left default 0xCED4 but not used (see command 7)
   ; ***************** 9 Receive FIFO Read Command --------------(spec pace 18)
           ; No input to do during init.
   ; ----------------- 10 AFC parameters ------------------------(spec page 18)
   SPI_RF12B_writeCommand(0xC49B)
           ; Automatic mode = keep the foffset only during receiving (VDI=high)
           ; Range limit (for freq offset) = +15 fres to -16 fres
           ; strobe edge : store last calculated freq error.
           ; Fine ome = off
           ; Frequency offset register = enabled
           ; Calculation of the offset frequency = enabled
   ; ---------------- 11 TX Configuration Control Command -------(spec page 20)
   SPI_RF12B_writeCommand(0x9850)
           ; !mp, 9810=30kHz, MAX OUT
           ; ********* 13 TX register write command -------------(spec page 21)
           ; no output to do during init.
   ; ----------------- 14 Wake-up timer Command -----------------(spec page 21)
   SPI_RF12B_writeCommand(0xE000)
           ; Note: Waikup Timer not in use. See: Power Management Command
   ; ----------------- 15 Low Duty Cycle command ----------------(spec page 21)
   SPI_RF12B_writeCommand(0xC800)
           ; not Enabled
   ; ----------------- 16 Low Bat.Detector and uC Clock setting -(spec page 22)
   SPI_RF12B_writeCommand(0xC080)
           ;  2,2V  1,0 MHz,
   ; ***************** 17 Status read command -------------------(spec page 22)
           ; Not an init command
end procedure
--*****************************************************************************
procedure SPI_RF12B_set_Frequency(word in f_spec) is
   SPI_RF12B_writeCommand(0xA000 | (f_spec & 0x0FFF) )
end procedure
--*****************************************************************************
procedure SPI_RF12B_set_Bandwidth(word in band_width_code) is
                          ; 1= 400, 2=340, 3=270,4=200, 5=134, 6=67 kHz
   if band_width_code < 1 then
     band_width_code = 1
   elsif band_width_code > 6  then
     band_width_code = 6
   end if
   band_width_code = band_width_code << 5
   SPI_RF12B_writeCommand(0x9410 | band_width_code)
end procedure
--*****************************************************************************
procedure SPI_RF12B_set_Datarate(word in data_rate_code) is
   SPI_RF12B_writeCommand(0xC600 | (data_rate_code & 0x00FF) )
end procedure
--*****************************************************************************
function SPI_RF12B_TX_not_empty() return bit is
  var word statusRF12B
    statusRF12B = SPI_RF12B_readStatus()
  if (statusRF12B & 0x8000) == 0 then
    return true
  else
    return false
  end if
end function
--*****************************************************************************
function SPI_RF12B_TX_Underrun() return bit is
  var word statusRF12B
    statusRF12B = SPI_RF12B_readStatus()
  if (statusRF12B & 0x2000) == 0 then
    return true
  else
    return false
  end if
end function
--*****************************************************************************
function SPI_RF12B_FIFO_empty() return bit is
  var word statusRF12B
    statusRF12B = SPI_RF12B_readStatus()
  if (statusRF12B & 0x0100) == 0 then
    return true
  else
    return false
  end if
end function
--*****************************************************************************
procedure SPI_RF12B_toReceive() is ; toReceive mode after toTransmit or init
  pragma inline
   ; ----------------- 2 Power Management Command ---------------(spec page 14)
           ; receiver chain = ON, receiver baseband circuit = ON,
           ; PLL + powerampl = OFF if TX enabled,
           ; synthesizer = on, X-tal osc on,  low bat det=off, WakeUp timer=off,
           ; Clock output pin = not disabled
   SPI_RF12B_writeCommand(0x82D8)
       ;   SPI_RF12B_writeCommand(0x8288) ; Also used for ceceive. What's OK ??
end procedure
--*****************************************************************************
procedure SPI_RF12B_toTransmit() is ; toTransmit mode after toReceive
  pragma inline
   ; ----------------- 2 Power Management Command ---------------(spec page 14)
           ; receiver chain = OFF, receiver baasband circuit = OFF,
           ; PLL + powerampl = ON if TX enabled,
           ; synthesizer = on, X-tal osc on,  low bat det=off, WakeUp timer=off,
           ; Clock output pin = not disabled
   SPI_RF12B_writeCommand(0x8238)
end procedure
--*****************************************************************************
procedure SPI_RF12B_toOff() is ; toOff mode (minimal Power consumption)
  pragma inline
   SPI_RF12B_writeCommand(0x8018) ; Config setting default
   SPI_RF12B_writeCommand(0x80D8) ; SPI_RF12B_writeCommand(0x80D8)
   ; ----------------- 2 Power Management Command ---------------(spec page 14)
           ; receiver chain = OFF, receiver baseband circuit = OFF,
           ; PLL + powerampl = OFF
           ; synthesizer = OFF, X-tal osc on,  low bat det=off, WakeUp timer=off,
           ; Clock output pin = not disabled

   SPI_RF12B_writeCommand(0x8208)
   SPI_RF12B_readStatus()
   SPI_RF12B_readStatus() ; clear remainig status bits
end procedure
--*****************************************************************************
function SPI_RF12B_ByteFromFiFo() return byte is
  var byte fromRF12B
  SPI_RF12B_CS_n = 0 ; selected
  spi_master_put_byte(0xB0)
  fromRF12B = spi_master_get_byte()
  SPI_RF12B_CS_n = 1 ; unselected
  return fromRF12B
end function
--*****************************************************************************
procedure SPI_RF12B_ResetFifo() is
   ; ----------------- 7 FIFO and Reset Mode command ----------- (spec page 17)
   SPI_RF12B_writeCommand(0xCA81)
   ; ----------------- 7 FIFO and Reset Mode command ----------- (spec page 17)
   SPI_RF12B_writeCommand(0xCA83)
           ; SO: the FIFO is reset and only filled after the Syncronisation
           ; Pattern. See also procedure SPI_RF12B_Init()
end procedure
--*****************************************************************************
procedure SPI_RF12B_transmit(byte in toSend) is
  while SPI_RF12B_TX_not_empty() loop  end loop ; wait
  SPI_RF12B_CS_n = 0 ; selected
  spi_master_put_byte(0xB8)
  spi_master_put_byte(toSend)
  SPI_RF12B_CS_n = 1 ; unselected
end procedure
--*****************************************************************************
procedure SPI_RF12B_transmit_preamble() is  ; called in
  SPI_RF12B_readStatus()
  SPI_RF12B_transmit(0xAA)
  SPI_RF12B_transmit(0xAA)
 ; SPI_RF12B_transmit(0xAA)
  SPI_RF12B_transmit(0x2D)
  SPI_RF12B_transmit(0xD4)
end procedure
--*****************************************************************************
procedure SPI_RF12B_transmit_packet(sbyte in nrOfBytes) is
   var sbyte index = 0
   var byte CRC = nrOfBytes
   var byte highbit


   if defined(spi_rf12b_use_CRC) == true then
     if spi_rf12b_use_CRC == true then
       ---- calc CRC == rotate CRC 1 Left and exlusive-or with new
       while index < nrOfBytes  loop
         highbit = CRC & 0x80
         CRC = CRC << 1
         if  highbit != 0 then
           CRC = CRC | 0x01
         else
           CRC = CRC & 0xFE
         end if
         CRC = CRC ^ RF12BpacketToTransmit[index]
         index = index + 1
       end loop
     end if
   end if
   -- transmit preamble and nrOfBytes or the signal
   SPI_RF12B_toTransmit()
   SPI_RF12B_transmit_preamble()
   SPI_RF12B_transmit(nrOfBytes)
   -- transmit payload if there is.
   index = 0
   while index < nrOfBytes  loop
     SPI_RF12B_transmit(RF12BpacketToTransmit[index])
     index = index + 1
   end loop
   if defined(spi_rf12b_use_CRC) == true then
     if spi_rf12b_use_CRC == true then
       -- transmit CRC
       if nrOfBytes > 0 then
         SPI_RF12B_transmit(CRC)
       end if
     end if
   end if
   -- sent some zero's to RF12B to enshure that last byte is sent before toOff()
   SPI_RF12B_transmit(0)
   SPI_RF12B_transmit(0)
   while SPI_RF12B_TX_not_empty() loop
   end loop
   SPI_RF12B_toOff()
end procedure
--*****************************************************************************
function SPI_RF12B_receive_packet(word in maxLoops) return sbyte is

  var word statCount = maxLoops
  var word statusRF12B  = 0
  var sbyte index = 0
  var sbyte nrReqBytes = 0
  var sbyte nrCRCbytes = 0
  var byte CRC
  var byte highbit
  var byte RecByte

  if defined(spi_rf12b_use_CRC) == true then
    if spi_rf12b_use_CRC == true then
      nrCRCbytes = 1
    end if
  end if
  SPI_RF12B_toReceive()
  -- Now wait for first byte == nr of bytes payload---------------------
  while ((statusRF12B & 0x8080) != 0x8080) & (statCount > 0) loop
                  ;wait FIFO filled (FFIT(not RGIT) and DQD) but not forever
        statCount = statCount - 1
        statusRF12B = SPI_RF12B_readStatus()
  end loop
  if statCount == 0 then
    ; not SPI_RF12B_toOff() ; calling software may retry for a while
    return -1               ;************************** ERROR RETURN (timeout)
  else
    nrReqBytes = SPI_RF12B_ByteFromFiFo()
  end if
  if  nrReqBytes <= 0 then
    SPI_RF12B_toOff()
    return  nrReqBytes     ;******* EXEPTIONAL RETURN length might be a signal
  end if
  if  nrReqBytes > MaxPayloadSize then
     nrReqBytes  = MaxPayloadSize ; prevent buffer overflow
  end if
  -- So from now we know that there is payload (no signal was sent)
  -- Now read payload (AND CRC if used)
  statCount = 0x7FFF  ; good enough when using SPI_sw_master.jal
  index = 0
  while (index < (nrReqBytes + nrCRCbytes)) & (statCount > 0) loop
     statusRF12B = SPI_RF12B_readStatus()
     while ((statusRF12B & 0x8000) == 0) & (statCount > 0) loop
        statCount = statCount - 1
        statusRF12B = SPI_RF12B_readStatus()
     end loop  ; wait for byte in FIFO or timeout
     if  (statCount == 0) then
       SPI_RF12B_toOff()
       return -2            ;************************** ERROR RETURN
     end if
     if ((statusRF12B & 0x0080) == 0) then
                                 ; if DQD bit not set or timeout during payload
       SPI_RF12B_toOff()
       return -2            ;************************** ERROR RETURN
     end if
     RecByte = SPI_RF12B_ByteFromFiFo()
     if (index < nrReqBytes) then ;all exept CRC
        RF12BpacketReceived[index] = RecByte
     end if
     index = index + 1
  end loop
  -- The received CRC is not stored in  RF12BpacketReceived but is in RecByte
  SPI_RF12B_toOff()

  if defined(spi_rf12b_use_CRC) == true then
    if spi_rf12b_use_CRC == true then
      -- Now: calculate CRC == rotate CRC 1 Left and exlusive-or with new
      -- now calculate CRC
      CRC = nrReqBytes
      index = 0
      while (index < nrReqBytes) & (index < MaxPayloadSize) loop
         highbit = CRC & 0x80
         CRC = CRC << 1
         if highbit != 0 then
            CRC = CRC | 0x01
         else
           CRC = CRC & 0xFE
         end if
         CRC = CRC ^ RF12BpacketReceived[index]
         index = index + 1
      end loop
      if CRC != RecByte then
        nrReqBytes = -3 ; ******************************* signal CRC ERROR
      end if
    end if
  end if
  return nrReqBytes
end function
--*****************************************************************************

