diff --git a/src/energenie/build b/src/energenie/build index a476cf0..d8405e8 100755 --- a/src/energenie/build +++ b/src/energenie/build @@ -7,15 +7,35 @@ chmod u+x gpio_test -# build spi_test -gcc spi_test.c spi.c gpio.c -mv a.out spi_test -chmod u+x spi_test +# build spis_test (soft SPI tester) +gcc spi_test.c spis.c gpio.c +mv a.out spis_test +chmod u+x spis_test + +# build spih_test (hard SPI tester) +gcc spi_test.c spih.c gpio.c +mv a.out spih_test +chmod u+x spish_test + + +# build hrf69_test +## gcc hrf69_test.c hrf69.c spis.c gpio.c +## mv a.out hrf69_test +## chmod u+x hrf69_test + + +# build radio_test +## gcc radio_test.c radio.c hrf69.c spis.c gpio.c +## mv a.out radio_test +## chmod u+x radio_test # build spi .so library on Raspberry Pi -gcc -Wall -shared -o spi_rpi.so -fPIC spi.c gpio.c -#nm -D spi.so +gcc -Wall -shared -o spi_rpi.so -fPIC spis.c gpio.c +# nm -D spi_rpi.so +# radio spi .so library on Raspberry Pi +## gcc -Wall -shared -o radio_rpi.so -fPIC radio.c hrf69.c spis.c gpio.c +## nm -D spi_rpi.so - +# END diff --git a/src/energenie/hrf69.c b/src/energenie/hrf69.c new file mode 100644 index 0000000..652ff47 --- /dev/null +++ b/src/energenie/hrf69.c @@ -0,0 +1,51 @@ +/* hrf69.c 03/04/2016 D.J.Whale + * + * Hope RF RFM69 radio controller code. + */ + +//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 + + +//def HRF_writereg(addr, data): + +//def HRF_readreg(addr): + +//def HRF_writefifo_burst(buf): + +//def HRF_readfifo_burst(): + +//def HRF_checkreg(addr, mask, value): + +//def HRF_pollreg(addr, mask, value): + +//def HRF_wait_ready(): + +//def HRF_wait_txready(): + +//def HRF_change_mode(mode): + +//def HRF_clear_fifo(): + +//def HRF_check_payload(): + +//def HRF_receive_payload(): + +//def HRF_send_payload(payload): + +//def HRF_config(config): + + +//# END diff --git a/src/energenie/hrf69.h b/src/energenie/hrf69.h new file mode 100644 index 0000000..6fa06c5 --- /dev/null +++ b/src/energenie/hrf69.h @@ -0,0 +1,121 @@ +/* hrf69.h 03/04/2016 D.J.Whale + * + * Interface for HopeRF RFM69 radio + */ + +//# 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 + + +//def HRF_writereg(addr, data): + +//def HRF_readreg(addr): + +//def HRF_writefifo_burst(buf): + +//def HRF_readfifo_burst(): + +//def HRF_checkreg(addr, mask, value): + +//def HRF_pollreg(addr, mask, value): + +//def HRF_wait_ready(): + +//def HRF_wait_txready(): + +//def HRF_change_mode(mode): + +//def HRF_clear_fifo(): + +//def HRF_check_payload(): + +//def HRF_receive_payload(): + +//def HRF_send_payload(payload): + +//def HRF_config(config): + +//# END diff --git a/src/energenie/hrf69_test.c b/src/energenie/hrf69_test.c new file mode 100644 index 0000000..2e62d03 --- /dev/null +++ b/src/energenie/hrf69_test.c @@ -0,0 +1,24 @@ +/* hrf69_test.c D.J.Whale 03/04/2016 + * + * A simple exerciser for the HopeRF RFM69 radio + */ + + +/***** INCLUDES *****/ + +//#include +//#include +//#include "gpio.h" +//#include "spi.h" + + +/***** CONSTANTS *****/ + +int main(int argc, char **argv) +{ + //TODO + return 0; +} + + +/***** END OF FILE *****/ diff --git a/src/energenie/radio.c b/src/energenie/radio.c new file mode 100644 index 0000000..93310fe --- /dev/null +++ b/src/energenie/radio.c @@ -0,0 +1,451 @@ +//TODO + +# 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 diff --git a/src/energenie/radio.h b/src/energenie/radio.h new file mode 100644 index 0000000..3cb897c --- /dev/null +++ b/src/energenie/radio.h @@ -0,0 +1,25 @@ +/* radio.h 03/04/2016 D.J.Whale + * + * Energenie radio interface + */ + + +//def HRF_send_OOK_payload(payload): + +//def init(): + +//def modulation(fsk=None, ook=None): + +//def transmitter(fsk=None, ook=None): + +//def transmit(payload): + +//def receiver(fsk=None, ook=None): + +//def isReceiveWaiting(): + +//def receive(): + +//def finished(): + +//# END diff --git a/src/energenie/radio_test.c b/src/energenie/radio_test.c new file mode 100644 index 0000000..b4232fe --- /dev/null +++ b/src/energenie/radio_test.c @@ -0,0 +1,25 @@ +/* radio_test.c D.J.Whale 03/04/2016 + * + * A simple Energenie radio exerciser + */ + + +/***** INCLUDES *****/ + +//#include +//#include +//#include "gpio.h" +//#include "spi.h" + + +/***** CONSTANTS *****/ + + +int main(int argc, char **argv) +{ + //TODO + return 0; +} + + +/***** END OF FILE *****/ diff --git a/src/energenie/spi.c b/src/energenie/spi.c deleted file mode 100644 index 0f60a10..0000000 --- a/src/energenie/spi.c +++ /dev/null @@ -1,172 +0,0 @@ -/* spi.c D.J.Whale 19/07/2014 - */ - - -/***** INCLUDES *****/ - -#include -#include -//#include -#include -#include - -#include "spi.h" -#include "gpio.h" - - -/***** MACROS *****/ - -#define CLOCK_ACTIVE() gpio_write(config.sclk, config.cpol?0:1) -#define CLOCK_IDLE() gpio_write(config.sclk, config.cpol?1:0) - -#define SELECTED() gpio_write(config.cs, config.spol?1:0) -#define NOT_SELECTED() gpio_write(config.cs, config.spol?0:1) - - -/***** VARIABLES *****/ - -static SPI_CONFIG config; - - -/* Based on code suggested by Gordon Henderson: - * https://github.com/WiringPi/WiringPi/blob/master/wiringPi/wiringPi.c - * - * Note that his trick of using the hardware timer just didn't work, - * and this is the best of a bad bunch. nanosleep() delays at least - * 100uS in some cases. - */ - -static void delayus(unsigned int us) -{ - struct timeval tNow, tLong, tEnd; - - gettimeofday(&tNow, NULL); - tLong.tv_sec = us / 1000000; - tLong.tv_usec = us % 1000000; - timeradd(&tNow, &tLong, &tEnd); - - while (timercmp(&tNow, &tEnd, <)) - { - gettimeofday(&tNow, NULL); - } -} - - -void spi_init_defaults(void) -{ -#define CS 7 //CE1 -#define SCLK 11 -#define MOSI 10 -#define MISO 9 - -/* ms */ -#define TSETTLE (1) /* us settle */ -#define THOLD (1) /* us hold */ -#define TFREQ (1) /* us half clock */ - - SPI_CONFIG defaultConfig = {CS, SCLK, MOSI, MISO, SPI_SPOL0, SPI_CPOL0, SPI_CPHA0, - TSETTLE, THOLD, TFREQ}; - - spi_init(&defaultConfig); -} - - -void spi_init(SPI_CONFIG* pConfig) -{ - /* It's a standalone library, so init GPIO also */ - gpio_init(); - memcpy(&config, pConfig, sizeof(SPI_CONFIG)); - - //TODO: Implement CPHA1 - if (config.cpha != 0) - { - fprintf(stderr, "error: CPHA 1 not yet supported"); - exit(-1); - } - - gpio_setout(config.sclk); - CLOCK_IDLE(); - - gpio_setout(config.mosi); - gpio_low(config.mosi); - gpio_setin(config.miso); - - gpio_setout(config.cs); - NOT_SELECTED(); -} - - -void spi_finished(void) -{ - gpio_setin(config.mosi); - gpio_setin(config.sclk); - gpio_setin(config.cs); -} - - -void spi_select(void) -{ - SELECTED(); - delayus(config.tSettle); -} - - -void spi_deselect(void) -{ - NOT_SELECTED(); - delayus(config.tSettle); -} - - -int spi_byte(int txbyte) -{ - int rxbyte = 0; - int bitno; - int bit ; - - //TODO: Implement CPHA1 - - for (bitno=0; bitno<8; bitno++) - { - /* Transmit MSB first */ - bit = ((txbyte & 0x80) != 0x00); - txbyte <<= 1; - gpio_write(config.mosi, bit); - delayus(config.tSettle); - CLOCK_ACTIVE(); - delayus(config.tHold); - delayus(config.tFreq); - - /* Read MSB first */ - bit = gpio_read(config.miso); - rxbyte = (rxbyte<<1) | bit; - - CLOCK_IDLE(); - delayus(config.tFreq); - } - return rxbyte; -} - - -void spi_frame(unsigned char* pTx, unsigned char* pRx, unsigned char count) -{ - unsigned char tx = 0; - unsigned char rx; - - while (count > 0) - { - if (pTx != NULL) - { - tx = *(pTx++); - } - rx = spi_byte(tx); - if (pRx != NULL) - { - *(pRx++) = rx; - } - count--; - } -} - - -/***** END OF FILE *****/ diff --git a/src/energenie/spi_test.c b/src/energenie/spi_test.c index a7ca0f7..4fe2332 100644 --- a/src/energenie/spi_test.c +++ b/src/energenie/spi_test.c @@ -1,10 +1,14 @@ /* spi_test.c D.J.Whale 18/07/2014 * * A simple SPI port exerciser. + * currently only uses the soft SPI (spis) + * TODO: Later will also support hard SPI (spih) + * but will have to sort out the pin configuration structure first for that to work. */ /***** INCLUDES *****/ + #include #include #include "gpio.h" diff --git a/src/energenie/spih.c b/src/energenie/spih.c new file mode 100644 index 0000000..622afd5 --- /dev/null +++ b/src/energenie/spih.c @@ -0,0 +1,65 @@ +/* spih.c (Hard SPI) D.J.Whale 19/07/2014 + */ + + +/***** INCLUDES *****/ + +//#include +//#include +//#include +//#include +//#include + +//#include "spi.h" +//#include "gpio.h" + + + +/***** VARIABLES *****/ + +static SPI_CONFIG config; + + +void spi_init_defaults(void) +{ + //TODO +} + + +void spi_init(SPI_CONFIG* pConfig) +{ + //TODO +} + + +void spi_finished(void) +{ + //TODO +} + + +void spi_select(void) +{ + //TODO +} + + +void spi_deselect(void) +{ + //TODO +} + + +int spi_byte(int txbyte) +{ + //TODO +} + + +void spi_frame(unsigned char* pTx, unsigned char* pRx, unsigned char count) +{ + //TODO +} + + +/***** END OF FILE *****/ diff --git a/src/energenie/spis.c b/src/energenie/spis.c new file mode 100644 index 0000000..f77b606 --- /dev/null +++ b/src/energenie/spis.c @@ -0,0 +1,172 @@ +/* spis.c (soft SPI) D.J.Whale 19/07/2014 + */ + + +/***** INCLUDES *****/ + +#include +#include +//#include +#include +#include + +#include "spi.h" +#include "gpio.h" + + +/***** MACROS *****/ + +#define CLOCK_ACTIVE() gpio_write(config.sclk, config.cpol?0:1) +#define CLOCK_IDLE() gpio_write(config.sclk, config.cpol?1:0) + +#define SELECTED() gpio_write(config.cs, config.spol?1:0) +#define NOT_SELECTED() gpio_write(config.cs, config.spol?0:1) + + +/***** VARIABLES *****/ + +static SPI_CONFIG config; + + +/* Based on code suggested by Gordon Henderson: + * https://github.com/WiringPi/WiringPi/blob/master/wiringPi/wiringPi.c + * + * Note that his trick of using the hardware timer just didn't work, + * and this is the best of a bad bunch. nanosleep() delays at least + * 100uS in some cases. + */ + +static void delayus(unsigned int us) +{ + struct timeval tNow, tLong, tEnd; + + gettimeofday(&tNow, NULL); + tLong.tv_sec = us / 1000000; + tLong.tv_usec = us % 1000000; + timeradd(&tNow, &tLong, &tEnd); + + while (timercmp(&tNow, &tEnd, <)) + { + gettimeofday(&tNow, NULL); + } +} + + +void spi_init_defaults(void) +{ +#define CS 7 //CE1 +#define SCLK 11 +#define MOSI 10 +#define MISO 9 + +/* ms */ +#define TSETTLE (1) /* us settle */ +#define THOLD (1) /* us hold */ +#define TFREQ (1) /* us half clock */ + + SPI_CONFIG defaultConfig = {CS, SCLK, MOSI, MISO, SPI_SPOL0, SPI_CPOL0, SPI_CPHA0, + TSETTLE, THOLD, TFREQ}; + + spi_init(&defaultConfig); +} + + +void spi_init(SPI_CONFIG* pConfig) +{ + /* It's a standalone library, so init GPIO also */ + gpio_init(); + memcpy(&config, pConfig, sizeof(SPI_CONFIG)); + + //TODO: Implement CPHA1 + if (config.cpha != 0) + { + fprintf(stderr, "error: CPHA 1 not yet supported"); + exit(-1); + } + + gpio_setout(config.sclk); + CLOCK_IDLE(); + + gpio_setout(config.mosi); + gpio_low(config.mosi); + gpio_setin(config.miso); + + gpio_setout(config.cs); + NOT_SELECTED(); +} + + +void spi_finished(void) +{ + gpio_setin(config.mosi); + gpio_setin(config.sclk); + gpio_setin(config.cs); +} + + +void spi_select(void) +{ + SELECTED(); + delayus(config.tSettle); +} + + +void spi_deselect(void) +{ + NOT_SELECTED(); + delayus(config.tSettle); +} + + +int spi_byte(int txbyte) +{ + int rxbyte = 0; + int bitno; + int bit ; + + //TODO: Implement CPHA1 + + for (bitno=0; bitno<8; bitno++) + { + /* Transmit MSB first */ + bit = ((txbyte & 0x80) != 0x00); + txbyte <<= 1; + gpio_write(config.mosi, bit); + delayus(config.tSettle); + CLOCK_ACTIVE(); + delayus(config.tHold); + delayus(config.tFreq); + + /* Read MSB first */ + bit = gpio_read(config.miso); + rxbyte = (rxbyte<<1) | bit; + + CLOCK_IDLE(); + delayus(config.tFreq); + } + return rxbyte; +} + + +void spi_frame(unsigned char* pTx, unsigned char* pRx, unsigned char count) +{ + unsigned char tx = 0; + unsigned char rx; + + while (count > 0) + { + if (pTx != NULL) + { + tx = *(pTx++); + } + rx = spi_byte(tx); + if (pRx != NULL) + { + *(pRx++) = rx; + } + count--; + } +} + + +/***** END OF FILE *****/