diff --git a/keywords.txt b/keywords.txt index 31d82ea1..7a47ab48 100644 --- a/keywords.txt +++ b/keywords.txt @@ -162,7 +162,7 @@ ERR_NONE LITERAL1 ERR_UNKNOWN LITERAL1 ERR_CHIP_NOT_FOUND LITERAL1 -ERR_EEPROM_NOT_INITIALIZED LITERAL1 +ERR_MEMORY_ALLOCATION_FAILED LITERAL1 ERR_PACKET_TOO_LONG LITERAL1 ERR_TX_TIMEOUT LITERAL1 ERR_RX_TIMEOUT LITERAL1 diff --git a/src/TypeDef.h b/src/TypeDef.h index b007f408..73c81802 100644 --- a/src/TypeDef.h +++ b/src/TypeDef.h @@ -150,9 +150,9 @@ #define ERR_CHIP_NOT_FOUND -2 /*! - \brief Deprecated. + \brief Failed to allocate memory for temporary buffer. This can be cause by not enough RAM or by passing invalid pointer. */ -#define ERR_EEPROM_NOT_INITIALIZED -3 +#define ERR_MEMORY_ALLOCATION_FAILED -3 /*! \brief Packet supplied to transmission method was longer than limit. diff --git a/src/modules/SX1272.cpp b/src/modules/SX1272.cpp index b6cbcddc..f592cff9 100644 --- a/src/modules/SX1272.cpp +++ b/src/modules/SX1272.cpp @@ -58,9 +58,9 @@ int16_t SX1272::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync return(state); } -int16_t SX1272::beginFSK(float freq, float br, float rxBw, float freqDev, int8_t power, uint8_t currentLimit, bool enableOOK) { +int16_t SX1272::beginFSK(float freq, float br, float rxBw, float freqDev, int8_t power, uint8_t currentLimit, uint16_t preambleLength, bool enableOOK) { // execute common part - int16_t state = SX127x::beginFSK(SX1272_CHIP_VERSION, br, rxBw, freqDev, currentLimit, enableOOK); + int16_t state = SX127x::beginFSK(SX1272_CHIP_VERSION, br, rxBw, freqDev, currentLimit, preambleLength, enableOOK); if(state != ERR_NONE) { return(state); } @@ -294,13 +294,14 @@ int16_t SX1272::setDataShaping(float sh) { int16_t state = SX127x::standby(); // set data shaping + sh *= 10.0; if(abs(sh - 0.0) <= 0.001) { state |= _mod->SPIsetRegValue(SX127X_REG_OP_MODE, SX1272_NO_SHAPING, 4, 3); - } else if(abs(sh - 0.3) <= 0.001) { + } else if(abs(sh - 3.0) <= 0.001) { state |= _mod->SPIsetRegValue(SX127X_REG_OP_MODE, SX1272_FSK_GAUSSIAN_0_3, 4, 3); - } else if(abs(sh - 0.5) <= 0.001) { + } else if(abs(sh - 5.0) <= 0.001) { state |= _mod->SPIsetRegValue(SX127X_REG_OP_MODE, SX1272_FSK_GAUSSIAN_0_5, 4, 3); - } else if(abs(sh - 1.0) <= 0.001) { + } else if(abs(sh - 10.0) <= 0.001) { state |= _mod->SPIsetRegValue(SX127X_REG_OP_MODE, SX1272_FSK_GAUSSIAN_1_0, 4, 3); } else { return(ERR_INVALID_DATA_SHAPING); diff --git a/src/modules/SX1272.h b/src/modules/SX1272.h index aec213c8..95f4068f 100644 --- a/src/modules/SX1272.h +++ b/src/modules/SX1272.h @@ -148,11 +148,13 @@ class SX1272: public SX127x { \param currentLimit Trim value for OCP (over current protection) in mA. Can be set to multiplies of 5 in range 45 to 120 mA and to multiples of 10 in range 120 to 240 mA. Set to 0 to disable OCP (not recommended). + \param preambleLength Length of FSK preamble in bits. + \param enableOOK Use OOK modulation instead of FSK. \returns \ref status_codes */ - int16_t beginFSK(float freq = 915.0, float br = 48.0, float rxBw = 125.0, float freqDev = 50.0, int8_t power = 13, uint8_t currentLimit = 100, bool enableOOK = false); + int16_t beginFSK(float freq = 915.0, float br = 48.0, float rxBw = 125.0, float freqDev = 50.0, int8_t power = 13, uint8_t currentLimit = 100, uint16_t preambleLength = 16, bool enableOOK = false); // configuration methods @@ -252,7 +254,7 @@ class SX1272: public SX127x { int16_t setBandwidthRaw(uint8_t newBandwidth); int16_t setSpreadingFactorRaw(uint8_t newSpreadingFactor); int16_t setCodingRateRaw(uint8_t newCodingRate); - + int16_t configFSK(); private: diff --git a/src/modules/SX1278.cpp b/src/modules/SX1278.cpp index 36ccef39..7f6ad28a 100644 --- a/src/modules/SX1278.cpp +++ b/src/modules/SX1278.cpp @@ -51,9 +51,9 @@ int16_t SX1278::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync return(state); } -int16_t SX1278::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t power, uint8_t currentLimit, bool enableOOK) { +int16_t SX1278::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t power, uint8_t currentLimit, uint16_t preambleLength, bool enableOOK) { // execute common part - int16_t state = SX127x::beginFSK(SX1278_CHIP_VERSION, br, freqDev, rxBw, currentLimit, enableOOK); + int16_t state = SX127x::beginFSK(SX1278_CHIP_VERSION, br, freqDev, rxBw, currentLimit, preambleLength, enableOOK); if(state != ERR_NONE) { return(state); } @@ -364,13 +364,14 @@ int16_t SX1278::setDataShaping(float sh) { int16_t state = SX127x::standby(); // set data shaping + sh *= 10.0; if(abs(sh - 0.0) <= 0.001) { state |= _mod->SPIsetRegValue(SX127X_REG_PA_RAMP, SX1278_NO_SHAPING, 6, 5); - } else if(abs(sh - 0.3) <= 0.001) { + } else if(abs(sh - 3.0) <= 0.001) { state |= _mod->SPIsetRegValue(SX127X_REG_PA_RAMP, SX1278_FSK_GAUSSIAN_0_3, 6, 5); - } else if(abs(sh - 0.5) <= 0.001) { + } else if(abs(sh - 5.0) <= 0.001) { state |= _mod->SPIsetRegValue(SX127X_REG_PA_RAMP, SX1278_FSK_GAUSSIAN_0_5, 6, 5); - } else if(abs(sh - 1.0) <= 0.001) { + } else if(abs(sh - 10.0) <= 0.001) { state |= _mod->SPIsetRegValue(SX127X_REG_PA_RAMP, SX1278_FSK_GAUSSIAN_1_0, 6, 5); } else { return(ERR_INVALID_DATA_SHAPING); diff --git a/src/modules/SX1278.h b/src/modules/SX1278.h index 0786b45f..937b0c58 100644 --- a/src/modules/SX1278.h +++ b/src/modules/SX1278.h @@ -157,11 +157,13 @@ class SX1278: public SX127x { \param currentLimit Trim value for OCP (over current protection) in mA. Can be set to multiplies of 5 in range 45 to 120 mA and to multiples of 10 in range 120 to 240 mA. Set to 0 to disable OCP (not recommended). + \param preambleLength Length of FSK preamble in bits. + \param enableOOK Use OOK modulation instead of FSK. \returns \ref status_codes */ - int16_t beginFSK(float freq = 434.0, float br = 48.0, float freqDev = 50.0, float rxBw = 125.0, int8_t power = 13, uint8_t currentLimit = 100, bool enableOOK = false); + int16_t beginFSK(float freq = 434.0, float br = 48.0, float freqDev = 50.0, float rxBw = 125.0, int8_t power = 13, uint8_t currentLimit = 100, uint16_t preambleLength = 16, bool enableOOK = false); // configuration methods @@ -261,7 +263,7 @@ class SX1278: public SX127x { int16_t setBandwidthRaw(uint8_t newBandwidth); int16_t setSpreadingFactorRaw(uint8_t newSpreadingFactor); int16_t setCodingRateRaw(uint8_t newCodingRate); - + int16_t configFSK(); private: diff --git a/src/modules/SX127x.cpp b/src/modules/SX127x.cpp index ce5a84dc..e9af0db6 100644 --- a/src/modules/SX127x.cpp +++ b/src/modules/SX127x.cpp @@ -1,7 +1,8 @@ #include "SX127x.h" -SX127x::SX127x(Module* mod) : PhysicalLayer(SX127X_CRYSTAL_FREQ, SX127X_DIV_EXPONENT) { +SX127x::SX127x(Module* mod) : PhysicalLayer(SX127X_CRYSTAL_FREQ, SX127X_DIV_EXPONENT, SX127X_MAX_PACKET_LENGTH) { _mod = mod; + _packetLengthQueried = false; } int16_t SX127x::begin(uint8_t chipVersion, uint8_t syncWord, uint8_t currentLimit, uint16_t preambleLength) { @@ -48,7 +49,7 @@ int16_t SX127x::begin(uint8_t chipVersion, uint8_t syncWord, uint8_t currentLimi return(state); } -int16_t SX127x::beginFSK(uint8_t chipVersion, float br, float freqDev, float rxBw, uint8_t currentLimit, bool enableOOK) { +int16_t SX127x::beginFSK(uint8_t chipVersion, float br, float freqDev, float rxBw, uint8_t currentLimit, uint16_t preambleLength, bool enableOOK) { // set module properties _mod->init(USE_SPI, INT_BOTH); @@ -95,6 +96,12 @@ int16_t SX127x::beginFSK(uint8_t chipVersion, float br, float freqDev, float rxB return(state); } + // set preamble length + state = SX127x::setPreambleLength(preambleLength); + if(state != ERR_NONE) { + return(state); + } + // default sync word value 0x2D01 is the same as the default in LowPowerLab RFM69 library uint8_t syncWord[] = {0x2D, 0x01}; state = setSyncWord(syncWord, 2); @@ -130,7 +137,7 @@ int16_t SX127x::transmit(uint8_t* data, size_t len, uint8_t addr) { float crc = (float)(_mod->SPIgetRegValue(SX127X_REG_MODEM_CONFIG_2, 2, 2) >> 2); float n_pre = (float)((_mod->SPIgetRegValue(SX127X_REG_PREAMBLE_MSB) << 8) | _mod->SPIgetRegValue(SX127X_REG_PREAMBLE_LSB)); float n_pay = 8.0 + max(ceil((8.0 * (float)len - 4.0 * (float)_sf + 28.0 + 16.0 * crc - 20.0 * ih)/(4.0 * (float)_sf - 8.0 * de)) * (float)_cr, 0.0); - uint32_t timeout = ceil(symbolLength * (n_pre + n_pay + 4.25) * 1.5); + uint32_t timeout = ceil(symbolLength * (n_pre + n_pay + 4.25) * 1500.0); // start transmission state = startTransmit(data, len, addr); @@ -139,17 +146,17 @@ int16_t SX127x::transmit(uint8_t* data, size_t len, uint8_t addr) { } // wait for packet transmission or timeout - uint32_t start = millis(); + uint32_t start = micros(); while(!digitalRead(_mod->getInt0())) { - if(millis() - start > timeout) { + if(micros() - start > timeout) { clearIRQFlags(); return(ERR_TX_TIMEOUT); } } - uint32_t elapsed = millis() - start; + uint32_t elapsed = micros() - start; // update data rate - _dataRate = (len*8.0)/((float)elapsed/1000.0); + _dataRate = (len*8.0)/((float)elapsed/1000000.0); // clear interrupt flags clearIRQFlags(); @@ -157,8 +164,8 @@ int16_t SX127x::transmit(uint8_t* data, size_t len, uint8_t addr) { return(ERR_NONE); } else if(modem == SX127X_FSK_OOK) { - // calculate timeout (150 % of expected time-on-air) - uint32_t timeout = (uint32_t)((((float)(len * 8)) / (_br * 1000.0)) * 1500.0); + // calculate timeout (5ms + 150 % of expected time-on-air) + uint32_t timeout = 5000 + (uint32_t)((((float)(len * 8)) / (_br * 1000.0)) * 1500000.0); // start transmission state = startTransmit(data, len, addr); @@ -167,9 +174,9 @@ int16_t SX127x::transmit(uint8_t* data, size_t len, uint8_t addr) { } // wait for transmission end or timeout - uint32_t start = millis(); + uint32_t start = micros(); while(!digitalRead(_mod->getInt0())) { - if(millis() - start > timeout) { + if(micros() - start > timeout) { clearIRQFlags(); standby(); return(ERR_TX_TIMEOUT); @@ -195,7 +202,7 @@ int16_t SX127x::receive(uint8_t* data, size_t len) { int16_t modem = getActiveModem(); if(modem == SX127X_LORA) { // set mode to receive - state = startReceive(SX127X_RXSINGLE); + state = startReceive(len, SX127X_RXSINGLE); if(state != ERR_NONE) { return(state); } @@ -208,19 +215,12 @@ int16_t SX127x::receive(uint8_t* data, size_t len) { } } - // read the received data - return(readData(data, len)); - } else if(modem == SX127X_FSK_OOK) { // calculate timeout (500 % of expected time-one-air) - size_t maxLen = len; - if(len == 0) { - maxLen = 0xFF; - } - uint32_t timeout = (uint32_t)((((float)(maxLen * 8)) / (_br * 1000.0)) * 5000.0); + uint32_t timeout = (uint32_t)((((float)(len * 8)) / (_br * 1000.0)) * 5000.0); // set mode to receive - state = startReceive(SX127X_RX); + state = startReceive(len, SX127X_RX); if(state != ERR_NONE) { return(state); } @@ -233,12 +233,12 @@ int16_t SX127x::receive(uint8_t* data, size_t len) { return(ERR_RX_TIMEOUT); } } - - // read the received data - return(readData(data, len)); } - return(ERR_UNKNOWN); + // read the received data + state = readData(data, len); + + return(state); } int16_t SX127x::scanChannel() { @@ -351,7 +351,7 @@ int16_t SX127x::packetMode() { return(_mod->SPIsetRegValue(SX127X_REG_PACKET_CONFIG_2, SX127X_DATA_MODE_PACKET, 6, 6)); } -int16_t SX127x::startReceive(uint8_t mode) { +int16_t SX127x::startReceive(uint8_t len, uint8_t mode) { // set mode to standby int16_t state = setMode(SX127X_STANDBY); @@ -360,6 +360,11 @@ int16_t SX127x::startReceive(uint8_t mode) { // set DIO pin mapping state |= _mod->SPIsetRegValue(SX127X_REG_DIO_MAPPING_1, SX127X_DIO0_RX_DONE | SX127X_DIO1_RX_TIMEOUT, 7, 4); + // set expected packet length for SF6 + if(_sf == 6) { + state |= _mod->SPIsetRegValue(SX127X_REG_PAYLOAD_LENGTH, len); + } + // clear interrupt flags clearIRQFlags(); @@ -469,7 +474,13 @@ int16_t SX127x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { int16_t SX127x::readData(uint8_t* data, size_t len) { int16_t modem = getActiveModem(); size_t length = len; + if(modem == SX127X_LORA) { + // len set to maximum indicates unknown packet length, read the number of actually received bytes + if(len == SX127X_MAX_PACKET_LENGTH) { + length = getPacketLength(); + } + // check integrity CRC if(_mod->SPIgetRegValue(SX127X_REG_IRQ_FLAGS, 5, 5) == SX127X_CLEAR_IRQ_FLAG_PAYLOAD_CRC_ERROR) { // clear interrupt flags @@ -478,14 +489,9 @@ int16_t SX127x::readData(uint8_t* data, size_t len) { return(ERR_CRC_MISMATCH); } - // get packet length - if(_sf != 6) { - length = _mod->SPIgetRegValue(SX127X_REG_RX_NB_BYTES); - } - } else if(modem == SX127X_FSK_OOK) { - // get packet length - length = _mod->SPIreadRegister(SX127X_REG_FIFO); + // read packet length (always required in FSK) + length = getPacketLength(); // check address filtering uint8_t filter = _mod->SPIgetRegValue(SX127X_REG_PACKET_CONFIG_1, 2, 1); @@ -495,16 +501,16 @@ int16_t SX127x::readData(uint8_t* data, size_t len) { } // read packet data - if(len == 0) { - // argument len equal to zero indicates String call, which means dynamically allocated data array - // dispose of the original and create a new one - delete[] data; - data = new uint8_t[length + 1]; - } _mod->SPIreadRegisterBurst(SX127X_REG_FIFO, length, data); - // add terminating null - data[length] = 0; + // dump bytes that weren't requested + size_t packetLength = getPacketLength(); + if(packetLength > length) { + clearFIFO(packetLength - length); + } + + // clear internal flag so getPacketLength can return the new packet length + _packetLengthQueried = false; // clear interrupt flags clearIRQFlags(); @@ -550,23 +556,33 @@ int16_t SX127x::setCurrentLimit(uint8_t currentLimit) { } int16_t SX127x::setPreambleLength(uint16_t preambleLength) { - // check active modem - if(getActiveModem() != SX127X_LORA) { - return(ERR_WRONG_MODEM); - } - - // check allowed range - if(preambleLength < 6) { - return(ERR_INVALID_PREAMBLE_LENGTH); - } - // set mode to standby int16_t state = setMode(SX127X_STANDBY); + if(state != ERR_NONE) { + return(state); + } - // set preamble length - state |= _mod->SPIsetRegValue(SX127X_REG_PREAMBLE_MSB, (preambleLength & 0xFF00) >> 8); - state |= _mod->SPIsetRegValue(SX127X_REG_PREAMBLE_LSB, preambleLength & 0x00FF); - return(state); + // check active modem + uint8_t modem = getActiveModem(); + if(modem == SX127X_LORA) { + // check allowed range + if(preambleLength < 6) { + return(ERR_INVALID_PREAMBLE_LENGTH); + } + + // set preamble length + state = _mod->SPIsetRegValue(SX127X_REG_PREAMBLE_MSB, (preambleLength & 0xFF00) >> 8); + state |= _mod->SPIsetRegValue(SX127X_REG_PREAMBLE_LSB, preambleLength & 0x00FF); + return(state); + + } else if(modem == SX127X_FSK_OOK) { + // set preamble length + state = _mod->SPIsetRegValue(SX127X_REG_PREAMBLE_MSB_FSK, (preambleLength & 0xFF00) >> 8); + state |= _mod->SPIsetRegValue(SX127X_REG_PREAMBLE_LSB_FSK, preambleLength & 0x00FF); + return(state); + } + + return(ERR_UNKNOWN); } float SX127x::getFrequencyError(bool autoCorrect) { @@ -740,7 +756,6 @@ int16_t SX127x::setRxBandwidth(float rxBw) { } } } - return(ERR_UNKNOWN); } @@ -862,6 +877,30 @@ int16_t SX127x::setFrequencyRaw(float newFreq) { return(state); } +size_t SX127x::getPacketLength(bool update) { + int16_t modem = getActiveModem(); + + if(modem == SX127X_LORA) { + if(_sf != 6) { + // get packet length for SF7 - SF12 + return(_mod->SPIreadRegister(SX127X_REG_RX_NB_BYTES)); + + } else { + // return the maximum value for SF6 + return(SX127X_MAX_PACKET_LENGTH); + } + + } else if(modem == SX127X_FSK_OOK) { + // get packet length + if(!_packetLengthQueried && update) { + _packetLength = _mod->SPIreadRegister(SX127X_REG_FIFO); + _packetLengthQueried = true; + } + } + + return(_packetLength); +} + int16_t SX127x::config() { // turn off frequency hopping int16_t state = _mod->SPIsetRegValue(SX127X_REG_HOP_PERIOD, SX127X_HOP_PERIOD_OFF); @@ -879,12 +918,18 @@ int16_t SX127x::configFSK() { _mod->SPIwriteRegister(SX127X_REG_IRQ_FLAGS_2, SX127X_FLAG_FIFO_OVERRUN); // set packet configuration - state = _mod->SPIsetRegValue(SX127X_REG_PACKET_CONFIG_1, SX127X_PACKET_VARIABLE | SX127X_DC_FREE_NONE | SX127X_CRC_ON | SX127X_CRC_AUTOCLEAR_ON, 7, 3); + state = _mod->SPIsetRegValue(SX127X_REG_PACKET_CONFIG_1, SX127X_PACKET_VARIABLE | SX127X_DC_FREE_WHITENING | SX127X_CRC_ON | SX127X_CRC_AUTOCLEAR_ON | SX127X_ADDRESS_FILTERING_OFF | SX127X_CRC_WHITENING_TYPE_CCITT, 7, 0); state |= _mod->SPIsetRegValue(SX127X_REG_PACKET_CONFIG_2, SX127X_DATA_MODE_PACKET | SX127X_IO_HOME_OFF, 6, 5); if(state != ERR_NONE) { return(state); } + // set preamble polarity + state =_mod->SPIsetRegValue(SX127X_REG_SYNC_CONFIG, SX127X_PREAMBLE_POLARITY_55, 5, 5); + if(state != ERR_NONE) { + return(state); + } + // set FIFO threshold state = _mod->SPIsetRegValue(SX127X_REG_FIFO_THRESH, SX127X_TX_START_FIFO_NOT_EMPTY, 7, 7); state |= _mod->SPIsetRegValue(SX127X_REG_FIFO_THRESH, SX127X_FIFO_THRESH, 5, 0); @@ -901,7 +946,7 @@ int16_t SX127x::configFSK() { } // enable preamble detector and set preamble length - state = _mod->SPIsetRegValue(SX127X_REG_PREAMBLE_DETECT, SX127X_PREAMBLE_DETECTOR_ON | SX127X_PREAMBLE_DETECTOR_1_BYTE | SX127X_PREAMBLE_DETECTOR_TOL); + state = _mod->SPIsetRegValue(SX127X_REG_PREAMBLE_DETECT, SX127X_PREAMBLE_DETECTOR_ON | SX127X_PREAMBLE_DETECTOR_2_BYTE | SX127X_PREAMBLE_DETECTOR_TOL); state |= _mod->SPIsetRegValue(SX127X_REG_PREAMBLE_MSB_FSK, SX127X_PREAMBLE_SIZE_MSB); state |= _mod->SPIsetRegValue(SX127X_REG_PREAMBLE_LSB_FSK, SX127X_PREAMBLE_SIZE_LSB); if(state != ERR_NONE) { @@ -969,6 +1014,13 @@ void SX127x::clearIRQFlags() { } } +void SX127x::clearFIFO(size_t count) { + while(count) { + _mod->SPIreadRegister(SX127X_REG_FIFO); + count--; + } +} + #ifdef RADIOLIB_DEBUG void SX127x::regDump() { Serial.println(); diff --git a/src/modules/SX127x.h b/src/modules/SX127x.h index 063d5b0f..5236e595 100644 --- a/src/modules/SX127x.h +++ b/src/modules/SX127x.h @@ -9,6 +9,7 @@ // SX127x physical layer properties #define SX127X_CRYSTAL_FREQ 32.0 #define SX127X_DIV_EXPONENT 19 +#define SX127X_MAX_PACKET_LENGTH 256 // SX127x series common LoRa registers #define SX127X_REG_FIFO 0x00 @@ -574,11 +575,13 @@ class SX127x: public PhysicalLayer { \param currentLimit Trim value for OCP (over current protection) in mA. + \param preambleLength Length of FSK preamble in bits. + \param enableOOK Flag to specify OOK mode. This modulation is similar to FSK. \returns \ref status_codes */ - int16_t beginFSK(uint8_t chipVersion, float br, float freqDev, float rxBw, uint8_t currentLimit, bool enableOOK); + int16_t beginFSK(uint8_t chipVersion, float br, float freqDev, float rxBw, uint8_t currentLimit, uint16_t preambleLength, bool enableOOK); /*! \brief Binary transmit method. Will transmit arbitrary binary data up to 255 bytes long using %LoRa or up to 63 bytes using FSK modem. @@ -686,14 +689,16 @@ class SX127x: public PhysicalLayer { /*! \brief Interrupt-driven receive method. DIO0 will be activated when full valid packet is received. + \param len Expected length of packet to be received. Required for LoRa spreading factor 6. + \param mode Receive mode to be used. Defaults to RxContinuous. \returns \ref status_codes */ - int16_t startReceive(uint8_t mode = SX127X_RXCONTINUOUS); + int16_t startReceive(uint8_t len = 0, uint8_t mode = SX127X_RXCONTINUOUS); /*! - \brief Reads data that was received after calling startReceive method. + \brief Reads data that was received after calling startReceive method. This method reads len characters. \param data Pointer to array to save the received binary data. @@ -828,6 +833,15 @@ class SX127x: public PhysicalLayer { */ int16_t setOOK(bool enableOOK); + /*! + \brief Query modem for the packet length of received payload. + + \param update Update received packet length. Will return cached value when set to false. + + \returns Length of last received packet in bytes. + */ + size_t getPacketLength(bool update = true); + #ifdef RADIOLIB_DEBUG void regDump(); #endif @@ -849,13 +863,17 @@ class SX127x: public PhysicalLayer { int16_t getActiveModem(); int16_t directMode(); + private: float _dataRate; + size_t _packetLength; + bool _packetLengthQueried; // FSK packet length is the first byte in FIFO, length can only be queried once bool findChip(uint8_t ver); int16_t setMode(uint8_t mode); int16_t setActiveModem(uint8_t modem); void clearIRQFlags(); + void clearFIFO(size_t count); // used mostly to clear remaining bytes in FIFO after a packet read }; #endif diff --git a/src/protocols/PhysicalLayer.cpp b/src/protocols/PhysicalLayer.cpp index 0fe2f268..23fb798c 100644 --- a/src/protocols/PhysicalLayer.cpp +++ b/src/protocols/PhysicalLayer.cpp @@ -1,8 +1,9 @@ #include "PhysicalLayer.h" -PhysicalLayer::PhysicalLayer(float crysFreq, uint8_t divExp) { +PhysicalLayer::PhysicalLayer(float crysFreq, uint8_t divExp, size_t maxPacketLength) { _crystalFreq = crysFreq; _divExponent = divExp; + _maxPacketLength = maxPacketLength; } int16_t PhysicalLayer::transmit(__FlashStringHelper* fstr, uint8_t addr) { @@ -49,30 +50,76 @@ int16_t PhysicalLayer::startTransmit(const char* str, uint8_t addr) { } int16_t PhysicalLayer::readData(String& str, size_t len) { - // create temporary array to store received data - char* data = new char[len + 1]; - int16_t state = readData((uint8_t*)data, len); + int16_t state = ERR_NONE; - // if packet was received successfully, copy data into String - if(state == ERR_NONE) { - str = String(data); + // read the number of actually received bytes + size_t length = getPacketLength(); + + if((len < length) && (len != 0)) { + // user requested less bytes than were received, this is allowed (but frowned upon) + // requests for more data than were received will only return the number of actually received bytes (unlike PhysicalLayer::receive()) + length = len; } + // build a temporary buffer + uint8_t* data = new uint8_t[length + 1]; + if(!data) { + return(ERR_MEMORY_ALLOCATION_FAILED); + } + + // read the received data + state = readData(data, length); + + if(state == ERR_NONE) { + // add null terminator + data[length] = 0; + + // initialize Arduino String class + str = String((char*)data); + } + + // deallocate temporary buffer delete[] data; + return(state); } int16_t PhysicalLayer::receive(String& str, size_t len) { - // create temporary array to store received data - char* data = new char[len + 1]; - int16_t state = receive((uint8_t*)data, len); + int16_t state = ERR_NONE; - // if packet was received successfully, copy data into String - if(state == ERR_NONE) { - str = String(data); + // user can override the length of data to read + size_t length = len; + + if(len == 0) { + // unknown packet length, set to maximum + length = _maxPacketLength; } + // build a temporary buffer + uint8_t* data = new uint8_t[length + 1]; + if(!data) { + return(ERR_MEMORY_ALLOCATION_FAILED); + } + + // attempt packet reception + state = receive(data, length); + + if(state == ERR_NONE) { + // read the number of actually received bytes (for unknown packets) + if(len == 0) { + length = getPacketLength(false); + } + + // add null terminator + data[length] = 0; + + // initialize Arduino String class + str = String((char*)data); + } + + // deallocate temporary buffer delete[] data; + return(state); } diff --git a/src/protocols/PhysicalLayer.h b/src/protocols/PhysicalLayer.h index 6aa8a0fa..51c01b98 100644 --- a/src/protocols/PhysicalLayer.h +++ b/src/protocols/PhysicalLayer.h @@ -21,8 +21,10 @@ class PhysicalLayer { \param crysFreq Frequency of crystal oscillator inside the module in MHz. \param divExp Exponent of module frequency divider. + + \param maxPacketLength Maximum length of packet that can be received by the module- */ - PhysicalLayer(float crysFreq, uint8_t divExp); + PhysicalLayer(float crysFreq, uint8_t divExp, size_t maxPacketLength); // basic methods @@ -77,12 +79,19 @@ class PhysicalLayer { \param str Address of Arduino String to save the received data. - \param len Expected number of characters in the message. + \param len Expected number of characters in the message. Leave as 0 if expecting a unknown size packet \returns \ref status_codes */ int16_t receive(String& str, size_t len = 0); + /*! + \brief Sets module to standby. + + \returns \ref status_codes + */ + virtual int16_t standby() = 0; + /*! \brief Binary receive method. Must be implemented in module class. @@ -94,13 +103,6 @@ class PhysicalLayer { */ virtual int16_t receive(uint8_t* data, size_t len) = 0; - /*! - \brief Sets module to standby. - - \returns \ref status_codes - */ - virtual int16_t standby() = 0; - /*! \brief Interrupt-driven Arduino String transmit method. Unlike the standard transmit method, this one is non-blocking. Interrupt pin will be activated when transmission finishes. @@ -168,7 +170,7 @@ class PhysicalLayer { \returns \ref status_codes */ - virtual int16_t transmitDirect(uint32_t frf = 0) = 0; + virtual int16_t transmitDirect(uint32_t FRF = 0) = 0; /*! \brief Enables direct reception mode on pins DIO1 (clock) and DIO2 (data). Must be implemented in module class. @@ -204,9 +206,19 @@ class PhysicalLayer { */ uint8_t getDivExponent(); + /*! + \brief Query modem for the packet length of received payload. + + \param update Update received packet length. Will return cached value when set to false. + + \returns Length of last received packet in bytes. + */ + virtual size_t getPacketLength(bool update = true) = 0; + private: float _crystalFreq; uint8_t _divExponent; + size_t _maxPacketLength; }; #endif