From 7dedc57b4cb0f11a8a66f6364d5ae0a9af47714f Mon Sep 17 00:00:00 2001 From: Justin Stephens Date: Wed, 8 Dec 2021 11:02:33 -0500 Subject: [PATCH] Initial work on full-length FSK messages based on ISR callbacks. Untested, but it does compile. --- .../SX127x_FSK_FIFO_Refill.ino | 83 ++++++++++++++++++ src/modules/SX127x/SX127x.cpp | 85 ++++++++++++++++++- src/modules/SX127x/SX127x.h | 23 ++++- src/protocols/PhysicalLayer/PhysicalLayer.h | 37 ++++++++ 4 files changed, 224 insertions(+), 4 deletions(-) create mode 100644 examples/SX127x/SX127x_FSK_FIFO_Refill/SX127x_FSK_FIFO_Refill.ino diff --git a/examples/SX127x/SX127x_FSK_FIFO_Refill/SX127x_FSK_FIFO_Refill.ino b/examples/SX127x/SX127x_FSK_FIFO_Refill/SX127x_FSK_FIFO_Refill.ino new file mode 100644 index 00000000..d99f971e --- /dev/null +++ b/examples/SX127x/SX127x_FSK_FIFO_Refill/SX127x_FSK_FIFO_Refill.ino @@ -0,0 +1,83 @@ +/* + RadioLib SX127x FSK FIFO on-the-fly Refilling Example + + This example shows how to use refill the FIFO buffer in SX127x chips, to allow for transmitting + FSK/OOK packets longer than 256 bytes. + + For default module settings, see the wiki page + https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx127xrfm9x---fsk-modem + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1276 has the following connections: +// NSS pin: 8 +// DIO0 pin: 51 +// RESET pin: 22 +// DIO1 pin: 52 +SX1276 radio = new Module(8, 51, 22, 52); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1278 fsk = RadioShield.ModuleA; + +uint8_t syncWord[] = { 0x91, 0xD3, 0x91, 0xD3 }; + +char* msg = "This is just some message that extends well beyond the 64 bytes limit of the FIFO"; +size_t msg_length; +size_t msg_counter; + +// this interrupt is called whenever the FIFO buffer falls below a certain threshold +void fifoRefill() { + msg_counter += radio.fifoAppend( + (uint8_t*)msg + msg_counter, // start of message, offset by # of bytes already sent + msg_length - msg_counter // # of bytes left to send + ); +} + +void setup() { + Serial.begin(9600); + + // RF switch for my board + pinMode(47, OUTPUT); + + // initialize SX1278 FSK modem with default settings + Serial.print(F("[SX1276] Initializing ... ")); + int state = radio.beginFSK(); + if (state == ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // Set config options + radio.setDataShaping(RADIOLIB_SHAPING_NONE); + radio.setSyncWord(syncWord, sizeof(syncWord)); + radio.setEncoding(RADIOLIB_ENCODING_WHITENING); + radio.setCRC(true); + + // Set up FIFO operations + radio.setFifoThreshold(16); + radio.setFifoThresholdAction(fifoRefill); +} + +void loop() { + + radio.variablePacketLengthMode(); + + // set RF switch to TX mode + digitalWrite(47, LOW); + + // start transmission of message + msg_length = strlen(msg); + radio.startTransmit((uint8_t*)msg, msg_length, msg_counter); + while (msg_counter != msg_length); + + Serial.println("[SX1276] Done transmitting"); +} diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index b0f1f8ab..fc9d5d23 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -446,6 +446,19 @@ void SX127x::clearDio1Action() { } int16_t SX127x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { + + // if in FSK/OOK mode and trying to send a packet larger than can fit in the + // FIFO, error out. For packets larger than FIFO, the startTransmit overload + // with a counter outparam must be used. + if (getActiveModem() == SX127X_FSK_OOK && len >= SX127X_FIFO_CAPACITY) { + return ERR_PACKET_TOO_LONG; + } + + // call the "full" startTransmit overload + return startTransmit(data, len, 0, addr); +} + +int16_t SX127x::startTransmit(uint8_t* data, size_t len, size_t&& counter, uint8_t addr) { // set mode to standby int16_t state = setMode(SX127X_STANDBY); @@ -472,12 +485,28 @@ int16_t SX127x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { state |= _mod->SPIsetRegValue(SX127X_REG_FIFO_TX_BASE_ADDR, SX127X_FIFO_TX_BASE_ADDR_MAX); state |= _mod->SPIsetRegValue(SX127X_REG_FIFO_ADDR_PTR, SX127X_FIFO_TX_BASE_ADDR_MAX); + // set the counter to the length written to FIFO + counter = len; + + // write packet to FIFO + _mod->SPIwriteRegisterBurst(SX127X_REG_FIFO, data, len); + } else if(modem == SX127X_FSK_OOK) { // check packet length if(len >= SX127X_MAX_PACKET_LENGTH_FSK) { return(ERR_PACKET_TOO_LONG); } + // if packet is too large to fit in the FIFO at once, attach the fifo-refill ISR to DIO1. If no + // ISR has been defined by the user, error out. + else if (len >= SX127X_FIFO_CAPACITY) { + if (_fifoThresholdISR == NULL) { + return ERR_PACKET_TOO_LONG; + } else { + Module::attachInterrupt(RADIOLIB_DIGITAL_PIN_TO_INTERRUPT(_mod->getGpio()), _fifoThresholdISR, RISING); + } + } + // set DIO mapping _mod->SPIsetRegValue(SX127X_REG_DIO_MAPPING_1, SX127X_DIO0_PACK_PACKET_SENT, 7, 6); @@ -494,10 +523,13 @@ int16_t SX127x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { if((filter == SX127X_ADDRESS_FILTERING_NODE) || (filter == SX127X_ADDRESS_FILTERING_NODE_BROADCAST)) { _mod->SPIwriteRegister(SX127X_REG_FIFO, addr); } - } - // write packet to FIFO - _mod->SPIwriteRegisterBurst(SX127X_REG_FIFO, data, len); + // set the byte counter to the length to be written to FIFO + counter = min(len, SX127X_FIFO_CAPACITY - 1); + + // write packet to FIFO + _mod->SPIwriteRegisterBurst(SX127X_REG_FIFO, data, counter); + } // set RF switch (if present) _mod->setRfSwitchState(LOW, HIGH); @@ -509,6 +541,41 @@ int16_t SX127x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { return(ERR_NONE); } +void SX127x::setFifoThresholdAction(void (*func)(void)) { + _fifoThresholdISR = func; +} + +int SX127x::fifoAppend(uint8_t* buff, size_t remaining) { + // check modem + if (getActiveModem() != SX127X_FSK_OOK) { + return ERR_WRONG_MODEM; + } + + // figure out how much to write + uint8_t fifoThresh = _mod->SPIreadRegister(SX127X_FIFO_THRESH) & 0x3F; + uint8_t toWrite = min(remaining, SX127X_FIFO_CAPACITY - fifoThresh); + + // write to the register + _mod->SPIwriteRegisterBurst(SX127X_REG_FIFO, buff, toWrite); + return toWrite; +} + +int SX127x::fifoGet(uint8_t* buff, size_t available) { + // check modem + if (getActiveModem() != SX127X_FSK_OOK) { + return ERR_WRONG_MODEM; + } + + // figure out how many bytes to read in + uint8_t fifoThresh = _mod->SPIreadRegister(SX127X_FIFO_THRESH) & 0x3F; + uint8_t toRead = min(available, fifoThresh); + + // write to the register + _mod->SPIreadRegisterBurst(SX127X_REG_FIFO, toRead, buff); + return toRead; + +} + int16_t SX127x::readData(uint8_t* data, size_t len) { int16_t modem = getActiveModem(); size_t length = len; @@ -1003,6 +1070,18 @@ int16_t SX127x::variablePacketLengthMode(uint8_t maxLen) { return(SX127x::setPacketMode(SX127X_PACKET_VARIABLE, maxLen)); } +int16_t SX127x::setFifoThreshold(uint8_t cap) { + // check active modem + if (getActiveModem() != SX127X_FSK_OOK) { + return ERR_WRONG_MODEM; + } else if (cap > 63) { + return ERR_PACKET_TOO_LONG; + } + + // write the 6 LSbits to the register + return _mod->SPIsetRegValue(SX127X_REG_FIFO_THRESH, cap & 0x3F); +} + int16_t SX127x::setRSSIConfig(uint8_t smoothingSamples, int8_t offset) { // check active modem if(getActiveModem() != SX127X_FSK_OOK) { diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index dc33ec08..19a4279b 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -12,7 +12,8 @@ // SX127x physical layer properties #define SX127X_FREQUENCY_STEP_SIZE 61.03515625 #define SX127X_MAX_PACKET_LENGTH 255 -#define SX127X_MAX_PACKET_LENGTH_FSK 64 +#define SX127X_MAX_PACKET_LENGTH_FSK 255 +#define SX127X_FIFO_CAPACITY 64 #define SX127X_CRYSTAL_FREQ 32.0 #define SX127X_DIV_EXPONENT 19 @@ -712,6 +713,16 @@ class SX127x: public PhysicalLayer { */ int16_t startTransmit(uint8_t* data, size_t len, uint8_t addr = 0) override; + /*! + \brief Interrupt-driven binary transmit method. Will start transmitting arbitrary binary data up to 255 bytes long using %LoRa or up to 255 bytes using FSK modem. + \param data Binary data that will be transmitted. + \param len Length of binary data to transmit (in bytes). + \param[out] counter Reference to a variable to track the number of sent bytes in + \param addr Node address to transmit the packet to. Only used in FSK mode. + \returns \ref status_codes + */ + int16_t startTransmit(uint8_t* data, size_t len, size_t&& counter, uint8_t addr = 0) override; + /*! \brief Interrupt-driven receive method. DIO0 will be activated when full valid packet is received. @@ -947,6 +958,15 @@ class SX127x: public PhysicalLayer { */ int16_t variablePacketLengthMode(uint8_t maxLen = SX127X_MAX_PACKET_LENGTH_FSK); + /*! + \brief Set the level at which the FIFO Threshold interrupt triggers + \param cap A capacity 0-63 for the FIFO buffer. + */ + int16_t setFifoThreshold(uint8_t cap = 16); + void setFifoThresholdAction(void (*func)(void)) override; + int fifoAppend(uint8_t* buff, size_t remaining) override; + int fifoGet(uint8_t* buff, size_t remaining) override; + /*! \brief Sets RSSI measurement configuration in FSK mode. @@ -1071,6 +1091,7 @@ class SX127x: public PhysicalLayer { float _dataRate = 0; bool _packetLengthQueried = false; // FSK packet length is the first byte in FIFO, length can only be queried once uint8_t _packetLengthConfig = SX127X_PACKET_VARIABLE; + void (*_fifoThresholdISR)(void) = NULL; bool findChip(uint8_t ver); int16_t setMode(uint8_t mode); diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.h b/src/protocols/PhysicalLayer/PhysicalLayer.h index 8b91d530..f1f22e47 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.h +++ b/src/protocols/PhysicalLayer/PhysicalLayer.h @@ -139,6 +139,43 @@ class PhysicalLayer { */ virtual int16_t startTransmit(uint8_t* data, size_t len, uint8_t addr = 0) = 0; + /*! + \brief Interrupt-driven binary transmit method. + \param data Binary data that will be transmitted. + \param len Length of binary data to transmit (in bytes). + \param[out] counter Reference to a variable to track the number of bytes sent in. + \param addr Node address to transmit the packet to. Only used in FSK mode. + */ + virtual int16_t startTransmit(uint8_t* data, size_t len, size_t&& counter, uint8_t add = 0) = 0; + + /*! + \brief Set the ISR routine to execute when the FIFO falls below the threshold. + + This interrupt will only be called when transmitting a message larger than the FIFO capacity. + + \param func Pointer to an Interrupt Service Routine. `NULL` will clear action. + */ + virtual void setFifoThresholdAction(void (*func)(void)) = 0; + + /*! + \brief Append more data into the FIFO Buffer + + This is used for stream-based transmissions. + + \param buff A pointer to the start of the data to append + \param remaining A pointer to a counter variable + \return Number of bytes consumed from `buff`, or error code. + */ + virtual int16_t fifoAppend(uint8_t* buff, size_t remaining) = 0; + + /*! + \brief Read data from the FIFO buffer. + \param buff the buffer to read data into + \param available the maximum number of bytes available in `buff` + \return Number of bytes read in from FIFO, or error code. + */ + virtual int16_t fifoGet(uint8_t* buff, size_t available) = 0; + /*! \brief Reads data that was received after calling startReceive method.