/* radio.c 12/04/2016 D.J.Whale
*
* An interface to the Energenie radio.
*/
/***** CONFIGURATION TABLES *****/
// //
// import spi
// //
// def warning(msg):
// print("warning:" + str(msg))
// //
// def trace(msg):
// print(str(msg))
// //
//
// def ashex(p):
// line = ""
// for b in p:
// line += str(hex(b)) + " "
// return line
// //
//
// #----- HOPERF REGISTER INTERFACE ----------------------------------------------
// # Precise register descriptions can be found in:
// # www.hoperf.com/upload/rf/RFM69W-V1.3.pdf
// # on page 63 - 74
// //
// ADDR_FIFO = 0x00
// ADDR_OPMODE = 0x01
// ADDR_REGDATAMODUL = 0x02
// ADDR_BITRATEMSB = 0x03
// ADDR_BITRATELSB = 0x04
// ADDR_FDEVMSB = 0x05
// ADDR_FDEVLSB = 0x06
// ADDR_FRMSB = 0x07
// ADDR_FRMID = 0x08
// ADDR_FRLSB = 0x09
// ADDR_AFCCTRL = 0x0B
// ADDR_LNA = 0x18
// ADDR_RXBW = 0x19
// ADDR_AFCFEI = 0x1E
// ADDR_IRQFLAGS1 = 0x27
// ADDR_IRQFLAGS2 = 0x28
// ADDR_RSSITHRESH = 0x29
// ADDR_PREAMBLELSB = 0x2D
// ADDR_SYNCCONFIG = 0x2E
// ADDR_SYNCVALUE1 = 0x2F
// ADDR_SYNCVALUE2 = 0x30
// ADDR_SYNCVALUE3 = 0x31
// ADDR_SYNCVALUE4 = 0x32
// ADDR_PACKETCONFIG1 = 0x37
// ADDR_PAYLOADLEN = 0x38
// ADDR_NODEADDRESS = 0x39
// ADDR_FIFOTHRESH = 0x3C
// //
// # HopeRF masks to set and clear bits
// MASK_REGDATAMODUL_OOK = 0x08
// MASK_REGDATAMODUL_FSK = 0x00
// MASK_WRITE_DATA = 0x80
// MASK_MODEREADY = 0x80
// MASK_FIFONOTEMPTY = 0x40
// MASK_FIFOLEVEL = 0x20
// MASK_FIFOOVERRUN = 0x10
// MASK_PACKETSENT = 0x08
// MASK_TXREADY = 0x20
// MASK_PACKETMODE = 0x60
// MASK_MODULATION = 0x18
// MASK_PAYLOADRDY = 0x04
// //
// MODE_STANDBY = 0x04 # Standby
// MODE_TRANSMITER = 0x0C # Transmiter
// MODE_RECEIVER = 0x10 # Receiver
// VAL_REGDATAMODUL_FSK = 0x00 # Modulation scheme FSK
// VAL_REGDATAMODUL_OOK = 0x08 # Modulation scheme OOK
// VAL_FDEVMSB30 = 0x01 # frequency deviation 5kHz 0x0052 -> 30kHz 0x01EC
// VAL_FDEVLSB30 = 0xEC # frequency deviation 5kHz 0x0052 -> 30kHz 0x01EC
// VAL_FRMSB434 = 0x6C # carrier freq -> 434.3MHz 0x6C9333
// VAL_FRMID434 = 0x93 # carrier freq -> 434.3MHz 0x6C9333
// VAL_FRLSB434 = 0x33 # carrier freq -> 434.3MHz 0x6C9333
// VAL_FRMSB433 = 0x6C # carrier freq -> 433.92MHz 0x6C7AE1
// VAL_FRMID433 = 0x7A # carrier freq -> 433.92MHz 0x6C7AE1
// VAL_FRLSB433 = 0xE1 # carrier freq -> 433.92MHz 0x6C7AE1
// VAL_AFCCTRLS = 0x00 # standard AFC routine
// VAL_AFCCTRLI = 0x20 # improved AFC routine
// VAL_LNA50 = 0x08 # LNA input impedance 50 ohms
// VAL_LNA50G = 0x0E # LNA input impedance 50 ohms, LNA gain -> 48db
// VAL_LNA200 = 0x88 # LNA input impedance 200 ohms
// VAL_RXBW60 = 0x43 # channel filter bandwidth 10kHz -> 60kHz page:26
// VAL_RXBW120 = 0x41 # channel filter bandwidth 120kHz
// VAL_AFCFEIRX = 0x04 # AFC is performed each time RX mode is entered
// VAL_RSSITHRESH220 = 0xDC # RSSI threshold 0xE4 -> 0xDC (220)
// VAL_PREAMBLELSB3 = 0x03 # preamble size LSB 3
// VAL_PREAMBLELSB5 = 0x05 # preamble size LSB 5
// VAL_SYNCCONFIG2 = 0x88 # Size of the Synch word = 2 (SyncSize + 1)
// VAL_SYNCCONFIG4 = 0x98 # Size of the Synch word = 4 (SyncSize + 1)
// VAL_SYNCVALUE1FSK = 0x2D # 1st byte of Sync word
// VAL_SYNCVALUE2FSK = 0xD4 # 2nd byte of Sync word
// VAL_SYNCVALUE1OOK = 0x80 # 1nd byte of Sync word
// VAL_PACKETCONFIG1FSK = 0xA2 # Variable length, Manchester coding, Addr must match NodeAddress
// VAL_PACKETCONFIG1FSKNO = 0xA0 # Variable length, Manchester coding
// VAL_PACKETCONFIG1OOK = 0 # Fixed length, no Manchester coding
// VAL_PAYLOADLEN255 = 0xFF # max Length in RX, not used in Tx
// VAL_PAYLOADLEN66 = 66 # max Length in RX, not used in Tx
// VAL_PAYLOADLEN_OOK = (13 + 8 * 17) # Payload Length
// VAL_NODEADDRESS01 = 0x01 # Node address used in address filtering
// VAL_NODEADDRESS04 = 0x04 # Node address used in address filtering
// VAL_FIFOTHRESH1 = 0x81 # Condition to start packet transmission: at least one byte in FIFO
// VAL_FIFOTHRESH30 = 0x1E # Condition to start packet transmission: wait for 30 bytes in FIFO
// //
//
// #----- HOPERF RADIO INTERFACE -------------------------------------------------
// //
// def HRF_writereg(addr, data):
// """Write an 8 bit value to a register"""
// buf = [addr | MASK_WRITE_DATA, data]
// spi.select()
// spi.frame(buf)
// spi.deselect()
// //
//
// def HRF_readreg(addr):
// """Read an 8 bit value from a register"""
// buf = [addr, 0x00]
// spi.select()
// res = spi.frame(buf)
// spi.deselect()
// #print(hex(res[1]))
// return res[1] # all registers are 8 bit
// //
//
// def HRF_writefifo_burst(buf):
// """Write all bytes in buf to the payload FIFO, in a single burst"""
// # Don't modify buf, in case caller reuses it
// txbuf = [ADDR_FIFO | MASK_WRITE_DATA]
// for b in buf:
// txbuf.append(b)
// #print("write FIFO %s" % ashex(txbuf))
// //
// spi.select()
// spi.frame(txbuf)
// spi.deselect()
// //
//
// def HRF_readfifo_burst():
// """Read bytes from the payload FIFO using burst read"""
// #first byte read is the length in remaining bytes
// buf = []
// spi.select()
// spi.frame([ADDR_FIFO])
// count = 1 # read at least the length byte
// while count > 0:
// rx = spi.frame([ADDR_FIFO])
// data = rx[0]
// if len(buf) == 0:
// count = data
// else:
// count -= 1
// buf.append(data)
// spi.deselect()
// trace("readfifo:" + str(ashex(buf)))
// return buf
// //
//
// def HRF_checkreg(addr, mask, value):
// """Check to see if a register matches a specific value or not"""
// regval = HRF_readreg(addr)
// #print("addr %d mask %d wanted %d actual %d" % (addr,mask,value,regval))
// return (regval & mask) == value
// //
//
// def HRF_pollreg(addr, mask, value):
// """Poll a register until it meet some criteria"""
// while not HRF_checkreg(addr, mask, value):
// pass
// //
//
// def HRF_wait_ready():
// """Wait for HRF to be ready after last command"""
// HRF_pollreg(ADDR_IRQFLAGS1, MASK_MODEREADY, MASK_MODEREADY)
// //
//
// def HRF_wait_txready():
// """Wait for HRF to be ready and ready for tx, after last command"""
// trace("waiting for transmit ready...")
// HRF_pollreg(ADDR_IRQFLAGS1, MASK_MODEREADY|MASK_TXREADY, MASK_MODEREADY|MASK_TXREADY)
// trace("transmit ready")
// //
//
// def HRF_change_mode(mode):
// HRF_writereg(ADDR_OPMODE, mode)
// //
//
// def HRF_clear_fifo():
// """Clear any data in the HRF payload FIFO by reading until empty"""
// while (HRF_readreg(ADDR_IRQFLAGS2) & MASK_FIFONOTEMPTY) == MASK_FIFONOTEMPTY:
// HRF_readreg(ADDR_FIFO)
// //
//
// def HRF_check_payload():
// """Check if there is a payload in the FIFO waiting to be processed"""
// irqflags1 = HRF_readreg(ADDR_IRQFLAGS1)
// irqflags2 = HRF_readreg(ADDR_IRQFLAGS2)
// #trace("irq1 %s irq2 %s" % (hex(irqflags1), hex(irqflags2)))
// //
// return (irqflags2 & MASK_PAYLOADRDY) == MASK_PAYLOADRDY
// //
//
// def HRF_receive_payload():
// """Receive the whole payload"""
// return HRF_readfifo_burst()
// //
//
// def HRF_send_payload(payload):
// trace("send_payload")
// #trace("payload:%s" % ashex(payload))
// HRF_writefifo_burst(payload)
// trace(" waiting for sent...")
// HRF_pollreg(ADDR_IRQFLAGS2, MASK_PACKETSENT, MASK_PACKETSENT)
// trace(" sent")
// reg = HRF_readreg(ADDR_IRQFLAGS2)
// trace(" irqflags2=%s" % hex(reg))
// if ((reg & MASK_FIFONOTEMPTY) != 0) or ((reg & MASK_FIFOOVERRUN) != 0):
// warning("Failed to send payload to HRF")
// //
//
//
// #----- ENERGENIE SPECIFIC CONFIGURATIONS --------------------------------------
// //
// config_FSK = [
// [ADDR_REGDATAMODUL, VAL_REGDATAMODUL_FSK], # modulation scheme FSK
// [ADDR_FDEVMSB, VAL_FDEVMSB30], # frequency deviation 5kHz 0x0052 -> 30kHz 0x01EC
// [ADDR_FDEVLSB, VAL_FDEVLSB30], # frequency deviation 5kHz 0x0052 -> 30kHz 0x01EC
// [ADDR_FRMSB, VAL_FRMSB434], # carrier freq -> 434.3MHz 0x6C9333
// [ADDR_FRMID, VAL_FRMID434], # carrier freq -> 434.3MHz 0x6C9333
// [ADDR_FRLSB, VAL_FRLSB434], # carrier freq -> 434.3MHz 0x6C9333
// [ADDR_AFCCTRL, VAL_AFCCTRLS], # standard AFC routine
// [ADDR_LNA, VAL_LNA50], # 200ohms, gain by AGC loop -> 50ohms
// [ADDR_RXBW, VAL_RXBW60], # channel filter bandwidth 10kHz -> 60kHz page:26
// [ADDR_BITRATEMSB, 0x1A], # 4800b/s
// [ADDR_BITRATELSB, 0x0B], # 4800b/s
// #[ADDR_AFCFEI, VAL_AFCFEIRX], # AFC is performed each time rx mode is entered
// #[ADDR_RSSITHRESH, VAL_RSSITHRESH220], # RSSI threshold 0xE4 -> 0xDC (220)
// #[ADDR_PREAMBLELSB, VAL_PREAMBLELSB5], # preamble size LSB set to 5
// [ADDR_SYNCCONFIG, VAL_SYNCCONFIG2], # Size of the Synch word = 2 (SyncSize + 1)
// [ADDR_SYNCVALUE1, VAL_SYNCVALUE1FSK], # 1st byte of Sync word
// [ADDR_SYNCVALUE2, VAL_SYNCVALUE2FSK], # 2nd byte of Sync word
// #[ADDR_PACKETCONFIG1, VAL_PACKETCONFIG1FSK], # Variable length, Manchester coding, Addr must match NodeAddress
// [ADDR_PACKETCONFIG1, VAL_PACKETCONFIG1FSKNO], # Variable length, Manchester coding
// [ADDR_PAYLOADLEN, VAL_PAYLOADLEN66], # max Length in RX, not used in Tx
// #[ADDR_NODEADDRESS, VAL_NODEADDRESS01], # Node address used in address filtering
// [ADDR_NODEADDRESS, 0x06], # Node address used in address filtering
// [ADDR_FIFOTHRESH, VAL_FIFOTHRESH1], # Condition to start packet transmission: at least one byte in FIFO
// [ADDR_OPMODE, MODE_RECEIVER] # Operating mode to Receiver
// ]
// //
// config_OOK = [
// [ADDR_REGDATAMODUL, VAL_REGDATAMODUL_OOK], # modulation scheme OOK
// [ADDR_FDEVMSB, 0], # frequency deviation -> 0kHz
// [ADDR_FDEVLSB, 0], # frequency deviation -> 0kHz
// [ADDR_FRMSB, VAL_FRMSB433], # carrier freq -> 433.92MHz 0x6C7AE1
// [ADDR_FRMID, VAL_FRMID433], # carrier freq -> 433.92MHz 0x6C7AE1
// [ADDR_FRLSB, VAL_FRLSB433], # carrier freq -> 433.92MHz 0x6C7AE1
// [ADDR_RXBW, VAL_RXBW120], # channel filter bandwidth 120kHz
// [ADDR_BITRATEMSB, 0x40], # 1938b/s
// [ADDR_BITRATELSB, 0x80], # 1938b/s
// [ADDR_PREAMBLELSB, 0], # preamble size LSB 3
// [ADDR_SYNCCONFIG, VAL_SYNCCONFIG4], # Size of the Sync word = 4 (SyncSize + 1)
// [ADDR_SYNCVALUE1, VAL_SYNCVALUE1OOK], # sync value 1
// [ADDR_SYNCVALUE2, 0], # sync value 2
// [ADDR_SYNCVALUE3, 0], # sync value 3
// [ADDR_SYNCVALUE4, 0], # sync value 4
// [ADDR_PACKETCONFIG1, VAL_PACKETCONFIG1OOK], # Fixed length, no Manchester coding, OOK
// [ADDR_PAYLOADLEN, VAL_PAYLOADLEN_OOK], # Payload Length
// [ADDR_FIFOTHRESH, VAL_FIFOTHRESH30], # Condition to start packet transmission: wait for 30 bytes in FIFO
// ]
// //
//
// def HRF_config(config):
// """Load a table of configuration values into HRF registers"""
// for cmd in config:
// HRF_writereg(cmd[0], cmd[1])
// HRF_wait_ready()
// //
//
// #ORIGINAL C CODE
// #void HRF_send_OOK_msg(uint8_t relayState)
// #{
// # uint8_t buf[17];
// # uint8_t i;
// #
// # HRF_config_OOK();
// #
// # buf[1] = 0x80; // Preambule 32b enclosed in sync words
// # buf[2] = 0x00;
// # buf[3] = 0x00;
// # buf[4] = 0x00;
// #
// # for (i = 5; i <= 14; ++i){
// # buf[i] = 8 + (i&1) * 6 + 128 + (i&2) * 48; // address 20b * 4 = 10 Bytes
// # }
// #
// # if (relayState == 1)
// # {
// # printf("relay ON\n\n");
// # buf[15] = 0xEE; // D0-high, D1-h // S1 on
// # buf[16] = 0xEE; // D2-h, D3-h
// # }
// # else
// # {
// # printf("relay OFF\n\n");
// # buf[15] = 0xEE; // D0-high, D1-h // S1 off
// # buf[16] = 0xE8; // D2-h, D3-l
// # }
// #
// # HRF_wait_for (ADDR_IRQFLAGS1, MASK_MODEREADY | MASK_TXREADY, true); // wait for ModeReady + TX ready
// # HRF_reg_Wn(buf + 4, 0, 12); // don't include sync word (4 bytes) into data buffer
// #
// # for (i = 0; i < 8; ++i) // Send the same message few more times
// # {
// # HRF_wait_for(ADDR_IRQFLAGS2, MASK_FIFOLEVEL, false);
// # HRF_reg_Wn(buf, 0, 16); // with sync word
// # }
// #
// # HRF_wait_for (ADDR_IRQFLAGS2, MASK_PACKETSENT, true); // wait for Packet sent
// # HRF_assert_reg_val(ADDR_IRQFLAGS2, MASK_FIFONOTEMPTY | MASK_FIFOOVERRUN, false, "are all bytes sent?");
// # HRF_config_FSK();
// # HRF_wait_for (ADDR_IRQFLAGS1, MASK_MODEREADY, true); // wait for ModeReady
// #}
// //
//
// def HRF_send_OOK_payload(payload):
// """Send a payload multiple times"""
// //
// p1 = [0x00] + payload
// # This sync pattern does not match C code, but it works.
// # The sync pattern from the C code does not work here
// # Note that buf[0] in the C is undefined due to being uninitialised
// #pn = [0x00,0x80,0x00,0x00,0x00] # from the C
// # Currently there is no explanation for this.
// pn = [0x80,0x80,0x80,0x80,0x80] + payload
// //
// HRF_pollreg(ADDR_IRQFLAGS1, MASK_MODEREADY|MASK_TXREADY, MASK_MODEREADY|MASK_TXREADY)
// HRF_writefifo_burst(p1)
//
// for i in range(8):
// HRF_pollreg(ADDR_IRQFLAGS2, MASK_FIFOLEVEL, 0)
// HRF_writefifo_burst(pn)
// //
// HRF_pollreg(ADDR_IRQFLAGS2, MASK_PACKETSENT, MASK_PACKETSENT) # wait for Packet sent
// //
// reg = HRF_readreg(ADDR_IRQFLAGS2)
// #trace(" irqflags2=%s" % hex(reg))
// if (reg & (MASK_FIFONOTEMPTY) != 0) or ((reg & MASK_FIFOOVERRUN) != 0):
// warning("Failed to send repeated payload to HRF")
// //
//
//
// #----- RADIO API --------------------------------------------------------------
// //
// mode = None
// modulation_fsk = None
// //
// def init():
// """Initialise the module ready for use"""
// spi.init_defaults()
// trace("RESET")
// //
// # Note that if another program left GPIO pins in a different state
// # and did a dirty exit, the reset fails to work and the clear fifo hangs.
// # Might have to make the spi.init() set everything to inputs first,
// # then set to outputs, to make sure that the
// # GPIO registers are in a deterministic start state.
// spi.reset() # send a hardware reset to ensure radio in clean state
// //
// HRF_clear_fifo()
// //
//
// def modulation(fsk=None, ook=None):
// """Switch modulation, if needed"""
// global modulation_fsk
// //
// # Handle sensible module defaults for earlier versions of user code
// if fsk == None and ook == None:
// # Force FSK mode
// fsk = True
// //
// if fsk != None and fsk:
// if modulation_fsk == None or modulation_fsk == False:
// trace("switch to FSK")
// HRF_config(config_FSK)
// modulation_fsk = True
// //
// elif ook != None and ook:
// if modulation_fsk == None or modulation_fsk == True:
// trace("switch to OOK")
// HRF_config(config_OOK)
// modulation_fsk = False
// //
//
// def transmitter(fsk=None, ook=None):
// """Change into transmitter mode"""
// global mode
// //
// trace("transmitter mode")
// modulation(fsk, ook)
// HRF_change_mode(MODE_TRANSMITER)
// mode = "TRANSMITTER"
// HRF_wait_txready()
// //
//
// def transmit(payload):
// """Transmit a single payload using the present modulation scheme"""
// if not modulation_fsk:
// HRF_send_OOK_payload(payload)
// else:
// HRF_send_payload(payload)
// //
//
// def receiver(fsk=None, ook=None):
// """Change into receiver mode"""
// global mode
// //
// trace("receiver mode")
// modulation(fsk, ook)
// HRF_change_mode(MODE_RECEIVER)
// HRF_wait_ready()
// mode = "RECEIVER"
// //
//
// def isReceiveWaiting():
// """Check to see if a payload is waiting in the receive buffer"""
// return HRF_check_payload()
// //
//
// def receive():
// """Receive a single payload from the buffer using the present modulation scheme"""
// return HRF_receive_payload()
// //
//
// def finished():
// """Close the library down cleanly when finished"""
// spi.finished()
// //
//
// # END