Newer
Older
pyenergenie / src / energenie / drv / radio.c
/* radio.c    D.J.Whale */

// # test1.py  26/09/2015  D.J.Whale
// #
// # Simple low level test of the HopeRF interface
// # Uses direct SPI commands to exercise the interface.
// #
// # Receives and dumps payload buffers.
// #
// # Eventually a lot of this will be pushed into a separate module,
// # and then pushed back into C once it is proved working.
// // 
// 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