diff --git a/src/energenie/drv/build_mac b/src/energenie/drv/build_mac index 3949287..e96ac74 100755 --- a/src/energenie/drv/build_mac +++ b/src/energenie/drv/build_mac @@ -29,9 +29,9 @@ # build hrf69_test -## gcc hrf69_test.c hrf69.c spis_rpi.c gpio_rpi.c -## mv a.out hrf69_test -## chmod u+x hrf69_test +##gcc hrf69_test.c hrf69.c spis_rpi.c gpio_rpi.c +##mv a.out hrf69_test +##chmod u+x hrf69_test # build radio_test @@ -42,13 +42,13 @@ # build spi .so library on Raspberry Pi ##gcc -Wall -shared -o spi_rpi.so -fPIC spis_rpi.c gpio_rpi.c -## nm -D spi_rpi.so +##nm -D spi_rpi.so ##cp spi_rpi.so .. # radio spi .so library on Mac gcc -Wall -shared -o radio_mac.so -fPIC radio.c hrfm69.c spis.c gpio_sim.c delay_posix.c -nm -g radio_mac.so -## cp radio_mac.so .. +##nm -g radio_mac.so +##cp radio_mac.so .. # END diff --git a/src/energenie/drv/gpio.h b/src/energenie/drv/gpio.h index 2b261fe..cfe319b 100644 --- a/src/energenie/drv/gpio.h +++ b/src/energenie/drv/gpio.h @@ -8,6 +8,8 @@ #include "system.h" +extern const uint8_t gpio_sim; /* 0=> not simulated */ + /***** FUNCTION PROTOTYPES *****/ void gpio_init(void); diff --git a/src/energenie/drv/gpio_rpi.c b/src/energenie/drv/gpio_rpi.c index 8896682..f57a9a5 100644 --- a/src/energenie/drv/gpio_rpi.c +++ b/src/energenie/drv/gpio_rpi.c @@ -33,6 +33,8 @@ static volatile unsigned *gpio; +const uint8_t gpio_sim=0; /* 0=> not simulated */ + /****** MACROS *****/ diff --git a/src/energenie/drv/gpio_sim.c b/src/energenie/drv/gpio_sim.c index f7a2871..741d2cc 100644 --- a/src/energenie/drv/gpio_sim.c +++ b/src/energenie/drv/gpio_sim.c @@ -13,7 +13,7 @@ /***** CONFIGURATION *****/ #define GPIO_MAX 20 -#define GPIO_DEBUG +//#define GPIO_DEBUG //#define GPIO_LOOPBACK @@ -24,6 +24,7 @@ static uint8_t gpio_out[GPIO_MAX] = {0}; static uint8_t gpio_in[GPIO_MAX] = {0}; +const uint8_t gpio_sim=1; /* 1=> is simulated */ void gpio_init() { diff --git a/src/energenie/drv/hrfm69.c b/src/energenie/drv/hrfm69.c index 27f1757..c7d59d5 100644 --- a/src/energenie/drv/hrfm69.c +++ b/src/energenie/drv/hrfm69.c @@ -7,6 +7,7 @@ #include "hrfm69.h" #include "spi.h" #include "trace.h" +#include "gpio.h" /*---------------------------------------------------------------------------*/ @@ -93,9 +94,15 @@ void HRF_pollreg(uint8_t addr, uint8_t mask, uint8_t value) { + if (gpio_sim) + { + TRACE_OUTS("gpio simulated, bailing early to prevent lockup\n"); + return; + } + while (! HRF_checkreg(addr, mask, value)) { - // busy wait + // busy wait (TODO:with no timeout & error recovery?) } } @@ -105,6 +112,7 @@ void HRF_clear_fifo(void) { + //TODO: max fifolen is 66, should bail after that to prevent lockup while ((HRF_readreg(HRF_ADDR_IRQFLAGS2) & HRF_MASK_FIFONOTEMPTY) == HRF_MASK_FIFONOTEMPTY) { HRF_readreg(HRF_ADDR_FIFO); diff --git a/src/energenie/drv/radio.c b/src/energenie/drv/radio.c index ba891ca..eed2e91 100644 --- a/src/energenie/drv/radio.c +++ b/src/energenie/drv/radio.c @@ -17,6 +17,9 @@ /***** CONFIGURATION *****/ +#define EXPECTED_RADIOVER 36 + + // Energenie specific radio config values //#define RADIO_VAL_SYNCVALUE1FSK 0x2D // 1st byte of Sync word //#define RADIO_VAL_SYNCVALUE2FSK 0xD4 // 2nd byte of Sync word @@ -118,6 +121,7 @@ static void _wait_ready(void) { + TRACE_OUTS("_wait_ready\n"); HRF_pollreg(HRF_ADDR_IRQFLAGS1, HRF_MASK_MODEREADY, HRF_MASK_MODEREADY); } @@ -140,6 +144,7 @@ static void _wait_txready(void) { + TRACE_OUTS("_wait_txready\n"); HRF_pollreg(HRF_ADDR_IRQFLAGS1, HRF_MASK_MODEREADY|HRF_MASK_TXREADY, HRF_MASK_MODEREADY|HRF_MASK_TXREADY); } @@ -203,14 +208,19 @@ uint8_t rv = radio_get_ver(); TRACE_OUTN(rv); TRACE_NL(); - if (rv != 36) + if (rv < EXPECTED_RADIOVER) { - TRACE_FAIL("unexpected radio ver, not 36(dec)\n"); + TRACE_OUTS("warning:unexpected radio ver EXPECTED_RADIOVER) + { + TRACE_OUTS("warning:unexpected radio ver>exp\n"); } TRACE_OUTS("standby mode\n"); _change_mode(HRF_MODE_STANDBY); - HRF_pollreg(HRF_ADDR_IRQFLAGS1, HRF_MASK_MODEREADY, HRF_MASK_MODEREADY); + _wait_ready(); } /*---------------------------------------------------------------------------*/ @@ -274,26 +284,64 @@ /*---------------------------------------------------------------------------*/ // Send a payload of data -//TODO: Rewrite this to use FIFOLEV and FIFOEMPTY with payloadlen=0 -//rather than PACKETSENT, as it will allow any number of repeats. -/* NEW DESIGN +/* DESIGN FOR DUTY CYCLE PROTECTION REQUIREMENT (write this later) + * + * At OOK 4800bps, 1 bit is 20uS, 1 byte is 1.6ms, 16 bytes is 26.6ms + * 15 repeats (old design limit) is 400ms + * 255 repeats (new design limit) is 6.8s + + * See page 3 of this app note: http://www.ti.com/lit/an/swra090/swra090.pdf + * + * Transmitter duty cycle + * The transmitter duty cycle is defined as the ratio of the maximum ”on” time, relative to a onehour period. + * If message acknowledgement is required, the additional ”on” time shall be included. Advisory limits are: + * + * Duty cycle Maximum “on” time [sec] Minimum “off” time [sec] + * 0.1 % 0.72 0.72 + * 1 % 3.6 1.8 + * 10 % 36 3.6 + */ + +/* DESIGN FOR >255 payload len (write this later) + + will need to set fifolevel as a proportion of payload len + and load that proportion. + i.e. inside the payload repeat loop + load the fifo up in non integral payload portions + also, txstart condition would need to start before whole payload loaded in FIFO + that is probably ok, but fifolev is more to do with fill rate and transmit rate, + and less to do with the actual payload length. + Note that FIFO empties at a rate proportional to the bitrate, + and also adding on manchester coding will slow the emptying rate. + */ + +/* DESIGN FOR NEW TRANSMITTER (write this first) + payloadlen of 256 would mean loading 255 into fifolev register + if fifolev is filled based on packetlen (as it is at moment) + FIFO is only 66 bytes in size, so would be better to set it max midway (33) + and therefore limit the payload size to say 32 bytes. + + VALIDATE + if payloadlen>32, reject (too long for this design) + i.e. fifolen is 66 CONFIGURE set packetlen=0 (arbitrary length) set fifolevel=payloadlen-1 - set txcondition=fifolevel - TRANSMIT PAYLOAD - fifo burst a single payload into fifo - WAIT NEXT - wait for fifolev interrupt flag to be set + set txstartcondition=fifolevel + BURST + TRANSMIT PAYLOAD + fifo burst a single payload into fifo + WAIT NEXT + wait for fifolev interrupt flag to be set (not greater than fifolev) WAIT FINISHED wait for fifoempty interrupt flag to be set - (wait 1 byte * bps to ensure last byte transmitted) + ??check data sheet: (wait 1 byte * bps to ensure last byte transmitted) */ -void radio_send_payload(uint8_t* payload, uint8_t len, uint8_t repeats) +void radio_send_payload(uint8_t* payload, uint8_t len, uint8_t times) { - TRACE_OUTS("send_payload\n"); + TRACE_OUTS("radio_send_payload\n"); // Note, when PA starts up, radio inserts a 01 at start before any user data // we might need to pad away from this by sending a sync of many zero bits @@ -307,28 +355,33 @@ uint8_t irqflags1; uint8_t irqflags2; - /* CONFIGURE: Setup the radio for transmit of the correct payload length */ - TRACE_OUTS("config\n"); - if ((unsigned int)repeats * (unsigned int)len > 255) + /* VALIDATE: Check input parameters are in range */ + if (times == 0 || len == 0) + { + TRACE_FAIL("zero times or payloadlen\n"); + } + if ((unsigned int)times * (unsigned int)len > 255) { // This is a temporary situation until the new 'indefinite transmit' // scheme is implemented using fifolevel only, and ignoring packetsent. - TRACE_FAIL("repeats*payloadlen > 255, can't configure\n"); + TRACE_FAIL("times*payloadlen > 255, can't configure\n"); } + /* CONFIGURE: Setup the radio for transmit of the correct payload length */ + TRACE_OUTS("config\n"); // the full packet/burst consists of repeated payloads // packetsent will trigger when this number of bytes have been transmitted - HRF_writereg(HRF_ADDR_PAYLOADLEN, len * repeats); + HRF_writereg(HRF_ADDR_PAYLOADLEN, len * times); // but the FIFO is filled in 1 message (4+10+2=16 byte) sections // level triggers when it 'strictly exceeds' level (i.e. 16 bytes starts tx, // and <=15 bytes triggers fifolevel irqflag to be cleared) HRF_writereg(HRF_ADDR_FIFOTHRESH, len-1); - /* Bring into transmitter mode and ramp up the PA */ + //TODO don't need this if already in transmitter mode, + //this should be in transmit(), as send_payload is the raw sender TRACE_OUTS("transmitter mode\n"); _change_mode(HRF_MODE_TRANSMITTER); - TRACE_OUTS("wait for modeready,txready in irqflags1\n"); HRF_pollreg(HRF_ADDR_IRQFLAGS1, HRF_MASK_MODEREADY|HRF_MASK_TXREADY, HRF_MASK_MODEREADY|HRF_MASK_TXREADY); @@ -345,7 +398,7 @@ TRACE_OUTS("tx repeats in a single burst\n"); // send a number of payload repeats for the whole packet burst - for (i=0; i #include -#define TRACE_OUTS(s) printf("%s", s) -#define TRACE_OUTN(n) printf("%d", (unsigned int)n) -#define TRACE_OUTC(c) putc(c, stdout) -#define TRACE_NL() TRACE_OUTC('\n') - -#define TRACE_FAIL(msg) do { \ - fprintf(stderr, "%s", msg); \ - exit(-1); \ -} while (0) +#define TRACE_OUTS(S) do{printf("%s", S);fflush(stdout);} while (0) +#define TRACE_OUTN(N) do{printf("%d", (unsigned int)N);fflush(stdout);} while (0) +#define TRACE_OUTC(C) putc(C, stdout) +#define TRACE_NL() do{TRACE_OUTC('\n');fflush(stdout);} while (0) +#define TRACE_FAIL(msg) do{fprintf(stderr, "%s", msg);exit(-1);} while (0) #endif diff --git a/src/energenie/radio2.py b/src/energenie/radio2.py index 8d3d0b0..84fc0f0 100644 --- a/src/energenie/radio2.py +++ b/src/energenie/radio2.py @@ -2,23 +2,22 @@ # # New version of the radio driver, with most of the fast stuff pushed into C. # -# This is a temporary test only, eventually when OOK and FSK are reimplemented -# and re-tested, this module will replace the radio.py/spi.py and spi_rpi.so files. +# NOTE 1: This is partially tested, and only used for OOK transmit at the moment. +# FSK transmit and receive is inside radio.py, as the underlying radio.c code +# does not yet support FSK mode. -#NOTE 1: THIS IS A WORK IN PROGRESS - DO NOT USE -#It has the same interface as radio.py (intentionally) -#so that when it is finished, we can just exchange it and all should work -#as before, but faster and more reliably. +# NOTE 2: Also there is an idea to do a python wrapper, build the C code +# for an Arduino and wrap it with a simple serial message handler. +# This would then make it possible to use the Energenie Radio on a Mac/PC/Linux +# machine but by still using the same higher level Python code. +# All you would need is a different radio.py that marshalled data to and from +# the Arduino via pyserial. -#NOTE 2: Also there is an idea to do a python wrapper, build the C code -#for an Arduino and wrap it with a simple serial message handler. -#This would then make it possible to use the Energenie Radio on a Mac/PC/Linux -#machine but by still using the same higher level Python code. -#All you would need is a different radio.py that marshalled data to and from -#the Arduino via pyserial. +#TODO: Should really add parameter validation here, so that C code doesn't have to. +#although it will be faster in C (C could be made optional, like an assert?) -LIBNAME = "radio_rpi.so" -#LIBNAME = "radio_mac.so" # testing +#LIBNAME = "radio_rpi.so" +LIBNAME = "drv/radio_mac.so" # testing import ctypes from os import path @@ -80,28 +79,31 @@ radio_transmitter_fn(m) -def transmit(payload, times=1): - """Transmit a single payload using the present modulation scheme""" - #Note, this does a mode change before and after - #extern void radio_transmit(uint8_t* payload, uint8_t len, uint8_t repeats); - framelen = len(payload) - Frame = ctypes.c_ubyte * framelen - txframe = Frame(*payload) - repeats = ctypes.c_ubyte(times) - radio_transmit_fn(txframe, framelen, repeats) +#TODO: Underlying C code is buggy at moment, so disabled temporarily. +#def transmit(payload, times=1): +# """Transmit a single payload using the present modulation scheme""" +# #Note, this does a mode change before and after +# #extern void radio_transmit(uint8_t* payload, uint8_t len, uint8_t repeats); +# framelen = len(payload) +# Frame = ctypes.c_ubyte * framelen +# txframe = Frame(*payload) +# repeats = ctypes.c_ubyte(times) +# radio_transmit_fn(txframe, framelen, repeats) def send_payload(payload, times=1): """Transmit a payload in present modulation scheme, repeated""" #Note, this does not do a mode change before or after, #and assumes the mode is already transmit - #extern void radio_send_payload(uint8_t* payload, uint8_t len, uint8_t repeats); + #extern void radio_send_payload(uint8_t* payload, uint8_t len, uint8_t times); + #TODO: Should really validate parameters here, so that C code doesn't have to. + #see note at top of this file. framelen = len(payload) Frame = ctypes.c_ubyte * framelen txframe = Frame(*payload) - repeats = ctypes.c_ubyte(times) - radio_send_payload_fn(txframe, framelen, repeats) + times = ctypes.c_ubyte(times) + radio_send_payload_fn(txframe, framelen, times) #def receiver(fsk=None, ook=None):