diff --git a/examples/SX127x/SX127x_FSK_Modem/SX127x_FSK_Modem.ino b/examples/SX127x/SX127x_FSK_Modem/SX127x_FSK_Modem.ino index d5e23bf7..c129c6e1 100644 --- a/examples/SX127x/SX127x_FSK_Modem/SX127x_FSK_Modem.ino +++ b/examples/SX127x/SX127x_FSK_Modem/SX127x_FSK_Modem.ino @@ -29,6 +29,7 @@ void setup() { // current limit: 100 mA // data shaping: Gaussian, BT = 0.3 // sync word: 0x2D 0x01 + // OOK modulation: false int state = fsk.beginFSK(); if (state == ERR_NONE) { Serial.println(F("success!")); @@ -61,6 +62,19 @@ void setup() { while (true); } + // FSK modulation can be changed to OOK + // NOTE: When using OOK, the maximum bit rate is only 32.768 kbps! + // Also, data shaping changes from Gaussian filter to + // simple filter with cutoff frequency. Make sure to call + // setDataShapingOOK() to set the correct shaping! + state = fsk.setOOK(true); + state = fsk.setDataShapingOOK(1); + if (state != ERR_NONE) { + Serial.print(F("Unable to change modulation, code ")); + Serial.println(state); + while (true); + } + #warning "This sketch is just an API guide! Read the note at line 6." } diff --git a/examples/SX127x/SX127x_Receive/SX127x_Receive.ino b/examples/SX127x/SX127x_Receive/SX127x_Receive.ino index d70d1caa..b1f44767 100644 --- a/examples/SX127x/SX127x_Receive/SX127x_Receive.ino +++ b/examples/SX127x/SX127x_Receive/SX127x_Receive.ino @@ -48,6 +48,9 @@ void loop() { Serial.print(F("[SX1278] Waiting for incoming transmission ... ")); // you can receive data as an Arduino String + // NOTE: receive() is a blocking method! + // See example ReceiveInterrupt for details + // on non-blocking reception method. String str; int state = lora.receive(str); diff --git a/examples/SX127x/SX127x_Transmit/SX127x_Transmit.ino b/examples/SX127x/SX127x_Transmit/SX127x_Transmit.ino index 008e9156..9ac2a098 100644 --- a/examples/SX127x/SX127x_Transmit/SX127x_Transmit.ino +++ b/examples/SX127x/SX127x_Transmit/SX127x_Transmit.ino @@ -45,6 +45,9 @@ void loop() { // you can transmit C-string or Arduino string up to // 256 characters long + // NOTE: transmit() is a blocking method! + // See example SX127x_Transmit_Interrupt for details + // on non-blocking transmission method. int state = lora.transmit("Hello World!"); // you can also transmit byte array up to 256 bytes long diff --git a/keywords.txt b/keywords.txt index fd020ec1..93d4afbc 100644 --- a/keywords.txt +++ b/keywords.txt @@ -79,6 +79,9 @@ setNodeAddress KEYWORD2 setBroadcastAddress KEYWORD2 disableAddressFiltering KEYWORD2 setDataShaping KEYWORD2 +setOOK KEYWORD2 +setDataShapingOOK KEYWORD2 +setCRC KEYWORD2 # RF69-specific setAESKey KEYWORD2 @@ -162,6 +165,7 @@ ERR_INVALID_BIT_RATE_BW_RATIO LITERAL1 ERR_INVALID_RX_BANDWIDTH LITERAL1 ERR_INVALID_SYNC_WORD LITERAL1 ERR_INVALID_DATA_SHAPING LITERAL1 +ERR_INVALID_MODULATION LITERAL1 ERR_AT_FAILED LITERAL1 ERR_URL_MALFORMED LITERAL1 diff --git a/src/Module.cpp b/src/Module.cpp index 59f9a8c9..95653fca 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -10,20 +10,22 @@ Module::Module(int rx, int tx) { ModuleSerial = new SoftwareSerial(_rx, _tx); } -Module::Module(int cs, int int0, int int1) { +Module::Module(int cs, int int0, int int1, SPIClass& spi) { _cs = cs; _rx = -1; _tx = -1; _int0 = int0; _int1 = int1; + _spi = &spi; } -Module::Module(int cs, int rx, int tx, int int0, int int1) { +Module::Module(int cs, int rx, int tx, int int0, int int1, SPIClass& spi) { _cs = cs; _rx = rx; _tx = tx; _int0 = int0; _int1 = int1; + _spi = &spi; ModuleSerial = new SoftwareSerial(_rx, _tx); } @@ -33,7 +35,7 @@ void Module::init(uint8_t interface, uint8_t gpio) { case USE_SPI: pinMode(_cs, OUTPUT); digitalWrite(_cs, HIGH); - SPI.begin(); + _spi->begin(); break; case USE_UART: ModuleSerial->begin(baudrate); @@ -58,6 +60,11 @@ void Module::init(uint8_t interface, uint8_t gpio) { } } +void Module::term() { + // stop SPI + _spi->end(); +} + void Module::ATemptyBuffer() { while(ModuleSerial->available() > 0) { ModuleSerial->read(); @@ -160,39 +167,47 @@ int16_t Module::SPIsetRegValue(uint8_t reg, uint8_t value, uint8_t msb, uint8_t } void Module::SPIreadRegisterBurst(uint8_t reg, uint8_t numBytes, uint8_t* inBytes) { - digitalWrite(_cs, LOW); - SPI.transfer(reg | SPIreadCommand); - for(uint8_t i = 0; i < numBytes; i++) { - inBytes[i] = SPI.transfer(reg); - } - digitalWrite(_cs, HIGH); + SPItransfer(SPIreadCommand, reg, NULL, inBytes, numBytes); } uint8_t Module::SPIreadRegister(uint8_t reg) { - uint8_t inByte; - digitalWrite(_cs, LOW); - SPI.beginTransaction(SPISettings(2000000, MSBFIRST, SPI_MODE0)); - SPI.transfer(reg | SPIreadCommand); - SPI.endTransaction(); - inByte = SPI.transfer(0x00); - digitalWrite(_cs, HIGH); - return(inByte); + uint8_t resp; + SPItransfer(SPIreadCommand, reg, NULL, &resp, 1); + return(resp); } void Module::SPIwriteRegisterBurst(uint8_t reg, uint8_t* data, uint8_t numBytes) { - digitalWrite(_cs, LOW); - SPI.transfer(reg | SPIwriteCommand); - for(uint8_t i = 0; i < numBytes; i++) { - SPI.transfer(data[i]); - } - digitalWrite(_cs, HIGH); + SPItransfer(SPIwriteCommand, reg, data, NULL, numBytes); } void Module::SPIwriteRegister(uint8_t reg, uint8_t data) { - digitalWrite(_cs, LOW); - SPI.beginTransaction(SPISettings(2000000, MSBFIRST, SPI_MODE0)); - SPI.transfer(reg | SPIwriteCommand); - SPI.transfer(data); - SPI.endTransaction(); - digitalWrite(_cs, HIGH); + SPItransfer(SPIwriteCommand, reg, &data, NULL, 1); +} + +void Module::SPItransfer(uint8_t cmd, uint8_t reg, uint8_t* dataOut, uint8_t* dataIn, uint8_t numBytes) { + // start SPI transaction + _spi->beginTransaction(SPISettings(2000000, MSBFIRST, SPI_MODE0)); + + // pull CS low + digitalWrite(_cs, LOW); + + // send SPI register address with access command + _spi->transfer(reg | cmd); + + // send data or get response + if(cmd == SPIwriteCommand) { + for(size_t n = 0; n < numBytes; n++) { + _spi->transfer(dataOut[n]); + } + } else if (cmd == SPIreadCommand) { + for(size_t n = 0; n < numBytes; n++) { + dataIn[n] = _spi->transfer(0x00); + } + } + + // release CS + digitalWrite(_cs, HIGH); + + // end SPI transaction + _spi->endTransaction(); } diff --git a/src/Module.h b/src/Module.h index aae40eac..7ee55b0c 100644 --- a/src/Module.h +++ b/src/Module.h @@ -10,8 +10,8 @@ class Module { public: Module(int tx, int rx); - Module(int cs, int int0, int int1); - Module(int cs, int rx, int tx, int int0, int int1); + Module(int cs, int int0, int int1, SPIClass& spi = SPI); + Module(int cs, int rx, int tx, int int0, int int1, SPIClass& spi = SPI); SoftwareSerial* ModuleSerial; @@ -22,6 +22,7 @@ class Module { uint8_t SPIwriteCommand = 0b10000000; void init(uint8_t interface, uint8_t gpio); + void term(); void ATemptyBuffer(); bool ATgetResponse(); @@ -37,6 +38,8 @@ class Module { void SPIwriteRegisterBurst(uint8_t reg, uint8_t* data, uint8_t numBytes); void SPIwriteRegister(uint8_t reg, uint8_t data); + void SPItransfer(uint8_t cmd, uint8_t reg, uint8_t* dataOut, uint8_t* dataIn, uint8_t numBytes); + int getCs() const { return(_cs); } int getInt0() const { return(_int0); } int getInt1() const { return(_int1); } @@ -48,6 +51,8 @@ class Module { int _int0; int _int1; + SPIClass* _spi; + uint32_t _ATtimeout = 15000; }; diff --git a/src/TypeDef.h b/src/TypeDef.h index 01ae29d9..30a077c1 100644 --- a/src/TypeDef.h +++ b/src/TypeDef.h @@ -70,6 +70,7 @@ #define ERR_INVALID_RX_BANDWIDTH -104 #define ERR_INVALID_SYNC_WORD -105 #define ERR_INVALID_DATA_SHAPING -106 +#define ERR_INVALID_MODULATION -107 // ESP8266 status codes #define ERR_AT_FAILED -201 diff --git a/src/modules/SX1272.cpp b/src/modules/SX1272.cpp index 04288d08..57cc72f9 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, float sh) { +int16_t SX1272::beginFSK(float freq, float br, float rxBw, float freqDev, int8_t power, uint8_t currentLimit, bool enableOOK) { // execute common part - int16_t state = SX127x::beginFSK(SX1272_CHIP_VERSION, br, rxBw, freqDev, currentLimit); + int16_t state = SX127x::beginFSK(SX1272_CHIP_VERSION, br, rxBw, freqDev, currentLimit, enableOOK); if(state != ERR_NONE) { return(state); } @@ -82,11 +82,6 @@ int16_t SX1272::beginFSK(float freq, float br, float rxBw, float freqDev, int8_t return(state); } - state = setDataShaping(sh); - if(state != ERR_NONE) { - return(state); - } - return(state); } @@ -268,6 +263,11 @@ int16_t SX1272::setDataShaping(float sh) { return(ERR_WRONG_MODEM); } + // check modulation + if(!SX127x::_ook) { + return(ERR_INVALID_MODULATION); + } + // set mode to standby int16_t state = SX127x::standby(); @@ -286,6 +286,39 @@ int16_t SX1272::setDataShaping(float sh) { return(state); } +int16_t SX1272::setDataShapingOOK(uint8_t sh) { + // check active modem + if(getActiveModem() != SX127X_FSK_OOK) { + return(ERR_WRONG_MODEM); + } + + // check modulation + if(!SX127x::_ook) { + return(ERR_INVALID_MODULATION); + } + + // set mode to standby + int16_t state = SX127x::standby(); + + // set data shaping + switch(sh) { + case 0: + state |= _mod->SPIsetRegValue(SX127X_REG_PA_RAMP, SX1272_NO_SHAPING, 4, 3); + break; + case 1: + state |= _mod->SPIsetRegValue(SX127X_REG_PA_RAMP, SX1272_OOK_FILTER_BR, 4, 3); + break; + case 2: + state |= _mod->SPIsetRegValue(SX127X_REG_PA_RAMP, SX1272_OOK_FILTER_2BR, 4, 3); + break; + default: + state = ERR_INVALID_DATA_SHAPING; + break; + } + + return(state); +} + int8_t SX1272::getRSSI() { // check active modem if(getActiveModem() != SX127X_LORA) { @@ -304,6 +337,24 @@ int8_t SX1272::getRSSI() { return(lastPacketRSSI); } +int16_t SX1272::setCRC(bool enableCRC) { + if(getActiveModem() == SX127X_LORA) { + // set LoRa CRC + if(enableCRC) { + return(_mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_2, SX1272_RX_CRC_MODE_ON, 2, 2)); + } else { + return(_mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_2, SX1272_RX_CRC_MODE_OFF, 2, 2)); + } + } else { + // set FSK CRC + if(enableCRC) { + return(_mod->SPIsetRegValue(SX127X_REG_PACKET_CONFIG_1, SX127X_CRC_ON, 4, 4)); + } else { + return(_mod->SPIsetRegValue(SX127X_REG_PACKET_CONFIG_1, SX127X_CRC_OFF, 4, 4)); + } + } +} + int16_t SX1272::setBandwidthRaw(uint8_t newBandwidth) { // set mode to standby int16_t state = SX127x::standby(); @@ -319,7 +370,7 @@ int16_t SX1272::setSpreadingFactorRaw(uint8_t newSpreadingFactor) { // write registers if(newSpreadingFactor == SX127X_SF_6) { - state |= _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_1, SX1272_HEADER_IMPL_MODE | SX1272_RX_CRC_MODE_OFF, 2, 1); + state |= _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_1, SX1272_HEADER_IMPL_MODE | SX1272_RX_CRC_MODE_ON, 2, 1); state |= _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_2, SX127X_SF_6 | SX127X_TX_MODE_SINGLE, 7, 3); state |= _mod->SPIsetRegValue(SX127X_REG_DETECT_OPTIMIZE, SX127X_DETECT_OPTIMIZE_SF_6, 2, 0); state |= _mod->SPIsetRegValue(SX127X_REG_DETECTION_THRESHOLD, SX127X_DETECTION_THRESHOLD_SF_6); diff --git a/src/modules/SX1272.h b/src/modules/SX1272.h index c2a8707e..38a39432 100644 --- a/src/modules/SX1272.h +++ b/src/modules/SX1272.h @@ -148,11 +148,11 @@ 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 sh Gaussian shaping bandwidth-time product that will be used for data shaping. Allowed values are 0.3, 0.5 or 1.0. Set to 0 to disable data shaping. + \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, float sh = 0.3); + 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); // configuration methods @@ -212,8 +212,8 @@ class SX1272: public SX127x { int16_t setGain(uint8_t gain); /*! - \brief Sets gaussian shaping bandwidth-time product that will be used for data shaping. - Allowed values are 0.3, 0.5 or 1.0. Set to 0 to disable data shaping. Only available in FSK mode. + \brief Sets Gaussian filter bandwidth-time product that will be used for data shaping. + Allowed values are 0.3, 0.5 or 1.0. Set to 0 to disable data shaping. Only available in FSK mode with FSK modulation. \param sh Gaussian shaping bandwidth-time product that will be used for data shaping @@ -221,12 +221,32 @@ class SX1272: public SX127x { */ int16_t setDataShaping(float sh); + /*! + \brief Sets filter cutoff frequency that will be used for data shaping. + Allowed values are 1 for frequency equal to bit rate and 2 for frequency equal to 2x bit rate. Set to 0 to disable data shaping. + Only available in FSK mode with OOK modulation. + + \param sh Cutoff frequency that will be used for data shaping + + \returns \ref status_codes + */ + int16_t setDataShapingOOK(uint8_t sh); + /*! \brief Gets recorded signal strength indicator of the latest received packet. \returns Last packet recorded signal strength indicator (RSSI). */ int8_t getRSSI(); + + /*! + \brief Enables/disables CRC check of received packets. + + \param enableCRC Enable (true) or disable (false) CRC. + + \returns \ref status_codes + */ + int16_t setCRC(bool enableCRC); protected: int16_t setBandwidthRaw(uint8_t newBandwidth); diff --git a/src/modules/SX1278.cpp b/src/modules/SX1278.cpp index 91d9ef7a..effb54fc 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, float sh) { +int16_t SX1278::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t power, uint8_t currentLimit, bool enableOOK) { // execute common part - int16_t state = SX127x::beginFSK(SX1278_CHIP_VERSION, br, freqDev, rxBw, currentLimit); + int16_t state = SX127x::beginFSK(SX1278_CHIP_VERSION, br, freqDev, rxBw, currentLimit, enableOOK); if(state != ERR_NONE) { return(state); } @@ -75,11 +75,6 @@ int16_t SX1278::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t return(state); } - state = setDataShaping(sh); - if(state != ERR_NONE) { - return(state); - } - return(state); } @@ -338,6 +333,11 @@ int16_t SX1278::setDataShaping(float sh) { return(ERR_WRONG_MODEM); } + // check modulation + if(SX127x::_ook) { + return(ERR_INVALID_MODULATION); + } + // set mode to standby int16_t state = SX127x::standby(); @@ -356,6 +356,38 @@ int16_t SX1278::setDataShaping(float sh) { return(state); } +int16_t SX1278::setDataShapingOOK(uint8_t sh) { + // check active modem + if(getActiveModem() != SX127X_FSK_OOK) { + return(ERR_WRONG_MODEM); + } + + // check modulation + if(!SX127x::_ook) { + return(ERR_INVALID_MODULATION); + } + + // set mode to standby + int16_t state = SX127x::standby(); + + // set data shaping + switch(sh) { + case 0: + state |= _mod->SPIsetRegValue(SX127X_REG_PA_RAMP, SX1278_NO_SHAPING, 6, 5); + break; + case 1: + state |= _mod->SPIsetRegValue(SX127X_REG_PA_RAMP, SX1278_OOK_FILTER_BR, 6, 5); + break; + case 2: + state |= _mod->SPIsetRegValue(SX127X_REG_PA_RAMP, SX1278_OOK_FILTER_2BR, 6, 5); + break; + default: + return(ERR_INVALID_DATA_SHAPING); + } + + return(state); +} + int8_t SX1278::getRSSI() { // check active modem if(getActiveModem() != SX127X_LORA) { @@ -381,6 +413,24 @@ int8_t SX1278::getRSSI() { return(lastPacketRSSI); } +int16_t SX1278::setCRC(bool enableCRC) { + if(getActiveModem() == SX127X_LORA) { + // set LoRa CRC + if(enableCRC) { + return(_mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_2, SX1278_RX_CRC_MODE_ON, 2, 2)); + } else { + return(_mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_2, SX1278_RX_CRC_MODE_OFF, 2, 2)); + } + } else { + // set FSK CRC + if(enableCRC) { + return(_mod->SPIsetRegValue(SX127X_REG_PACKET_CONFIG_1, SX127X_CRC_ON, 4, 4)); + } else { + return(_mod->SPIsetRegValue(SX127X_REG_PACKET_CONFIG_1, SX127X_CRC_OFF, 4, 4)); + } + } +} + int16_t SX1278::setBandwidthRaw(uint8_t newBandwidth) { // set mode to standby int16_t state = SX127x::standby(); @@ -397,12 +447,12 @@ int16_t SX1278::setSpreadingFactorRaw(uint8_t newSpreadingFactor) { // write registers if(newSpreadingFactor == SX127X_SF_6) { state |= _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_1, SX1278_HEADER_IMPL_MODE, 0, 0); - state |= _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_2, SX127X_SF_6 | SX127X_TX_MODE_SINGLE | SX1278_RX_CRC_MODE_OFF, 7, 2); + state |= _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_2, SX127X_SF_6 | SX127X_TX_MODE_SINGLE | SX1278_RX_CRC_MODE_ON, 7, 2); state |= _mod->SPIsetRegValue(SX127X_REG_DETECT_OPTIMIZE, SX127X_DETECT_OPTIMIZE_SF_6, 2, 0); state |= _mod->SPIsetRegValue(SX127X_REG_DETECTION_THRESHOLD, SX127X_DETECTION_THRESHOLD_SF_6); } else { state |= _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_1, SX1278_HEADER_EXPL_MODE, 0, 0); - state |= _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_2, newSpreadingFactor | SX127X_TX_MODE_SINGLE | SX1278_RX_CRC_MODE_OFF, 7, 2); + state |= _mod->SPIsetRegValue(SX127X_REG_MODEM_CONFIG_2, newSpreadingFactor | SX127X_TX_MODE_SINGLE | SX1278_RX_CRC_MODE_ON, 7, 2); state |= _mod->SPIsetRegValue(SX127X_REG_DETECT_OPTIMIZE, SX127X_DETECT_OPTIMIZE_SF_7_12, 2, 0); state |= _mod->SPIsetRegValue(SX127X_REG_DETECTION_THRESHOLD, SX127X_DETECTION_THRESHOLD_SF_7_12); } diff --git a/src/modules/SX1278.h b/src/modules/SX1278.h index 6349989b..5273175b 100644 --- a/src/modules/SX1278.h +++ b/src/modules/SX1278.h @@ -157,11 +157,11 @@ 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 sh Gaussian shaping bandwidth-time product that will be used for data shaping. Allowed values are 0.3, 0.5 or 1.0. Set to 0 to disable data shaping. + \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, float sh = 0.3); + 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); // configuration methods @@ -221,8 +221,8 @@ class SX1278: public SX127x { int16_t setGain(uint8_t gain); /*! - \brief Sets gaussian shaping bandwidth-time product that will be used for data shaping. - Allowed values are 0.3, 0.5 or 1.0. Set to 0 to disable data shaping. Only available in FSK mode. + \brief Sets Gaussian filter bandwidth-time product that will be used for data shaping. + Allowed values are 0.3, 0.5 or 1.0. Set to 0 to disable data shaping. Only available in FSK mode with FSK modulation. \param sh Gaussian shaping bandwidth-time product that will be used for data shaping @@ -230,12 +230,32 @@ class SX1278: public SX127x { */ int16_t setDataShaping(float sh); + /*! + \brief Sets filter cutoff frequency that will be used for data shaping. + Allowed values are 1 for frequency equal to bit rate and 2 for frequency equal to 2x bit rate. Set to 0 to disable data shaping. + Only available in FSK mode with OOK modulation. + + \param sh Cutoff frequency that will be used for data shaping + + \returns \ref status_codes + */ + int16_t setDataShapingOOK(uint8_t sh); + /*! \brief Gets recorded signal strength indicator of the latest received packet. \returns Last packet recorded signal strength indicator (RSSI). */ int8_t getRSSI(); + + /*! + \brief Enables/disables CRC check of received packets. + + \param enableCRC Enable (true) or disable (false) CRC. + + \returns \ref status_codes + */ + int16_t setCRC(bool enableCRC); protected: int16_t setBandwidthRaw(uint8_t newBandwidth); diff --git a/src/modules/SX127x.cpp b/src/modules/SX127x.cpp index 5b3d9745..a00d23a9 100644 --- a/src/modules/SX127x.cpp +++ b/src/modules/SX127x.cpp @@ -10,11 +10,11 @@ int16_t SX127x::begin(uint8_t chipVersion, uint8_t syncWord, uint8_t currentLimi // try to find the SX127x chip if(!SX127x::findChip(chipVersion)) { - DEBUG_PRINTLN(F("No SX127x found!")); - SPI.end(); + DEBUG_PRINTLN("No SX127x found!"); + _mod->term(); return(ERR_CHIP_NOT_FOUND); } else { - DEBUG_PRINTLN(F("Found SX127x!")); + DEBUG_PRINTLN("Found SX127x!"); } // check active modem @@ -48,17 +48,17 @@ 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) { +int16_t SX127x::beginFSK(uint8_t chipVersion, float br, float freqDev, float rxBw, uint8_t currentLimit, bool enableOOK) { // set module properties _mod->init(USE_SPI, INT_BOTH); // try to find the SX127x chip if(!SX127x::findChip(chipVersion)) { - DEBUG_PRINTLN(F("No SX127x found!")); - SPI.end(); + DEBUG_PRINTLN("No SX127x found!"); + _mod->term(); return(ERR_CHIP_NOT_FOUND); } else { - DEBUG_PRINTLN(F("Found SX127x!")); + DEBUG_PRINTLN("Found SX127x!"); } // check currently active modem @@ -104,6 +104,12 @@ int16_t SX127x::beginFSK(uint8_t chipVersion, float br, float freqDev, float rxB // disable address filtering state = disableAddressFiltering(); + if(state != ERR_NONE) { + return(state); + } + + // enable/disable OOK + state = setOOK(enableOOK); return(state); } @@ -208,6 +214,7 @@ int16_t SX127x::transmit(uint8_t* data, size_t len, uint8_t addr) { while(!digitalRead(_mod->getInt0())) { if(millis() - start > timeout) { clearIRQFlags(); + standby(); return(ERR_TX_TIMEOUT); } } @@ -215,7 +222,10 @@ int16_t SX127x::transmit(uint8_t* data, size_t len, uint8_t addr) { // clear interrupt flags clearIRQFlags(); - return(ERR_NONE); + // set mode to standby to disable transmitter + state |= standby(); + + return(state); } return(ERR_UNKNOWN); @@ -785,8 +795,14 @@ int16_t SX127x::setBitRate(float br) { } // check allowed bitrate - if((br < 1.2) || (br > 300.0)) { - return(ERR_INVALID_BIT_RATE); + if(_ook) { + if((br < 1.2) || (br > 32.768)) { + return(ERR_INVALID_BIT_RATE); + } + } else { + if((br < 1.2) || (br > 300.0)) { + return(ERR_INVALID_BIT_RATE); + } } // set mode to STANDBY @@ -794,12 +810,13 @@ int16_t SX127x::setBitRate(float br) { if(state != ERR_NONE) { return(state); } - + // set bit rate - uint16_t bitRate = 32000 / br; + uint16_t bitRate = (SX127X_CRYSTAL_FREQ * 1000.0) / br; state = _mod->SPIsetRegValue(SX127X_REG_BITRATE_MSB, (bitRate & 0xFF00) >> 8, 7, 0); state |= _mod->SPIsetRegValue(SX127X_REG_BITRATE_LSB, bitRate & 0x00FF, 7, 0); - // TODO: fractional part of bit rate setting + + // TODO: fractional part of bit rate setting (not in OOK) if(state == ERR_NONE) { SX127x::_br = br; } @@ -899,7 +916,7 @@ int16_t SX127x::setSyncWord(uint8_t* syncWord, size_t len) { } // set sync word - _mod->SPIwriteRegisterBurst(SX127X_SYNC_VALUE_1, syncWord, len); + _mod->SPIwriteRegisterBurst(SX127X_REG_SYNC_VALUE_1, syncWord, len); return(ERR_NONE); } @@ -957,6 +974,26 @@ int16_t SX127x::disableAddressFiltering() { return(_mod->SPIsetRegValue(SX127X_REG_BROADCAST_ADRS, 0x00)); } +int16_t SX127x::setOOK(bool enableOOK) { + // check active modem + if(getActiveModem() != SX127X_FSK_OOK) { + return(ERR_WRONG_MODEM); + } + + // set OOK and if successful, save the new setting + int16_t state = ERR_NONE; + if(enableOOK) { + state = _mod->SPIsetRegValue(SX127X_REG_OP_MODE, SX127X_MODULATION_OOK, 6, 5, 5); + } else { + state = _mod->SPIsetRegValue(SX127X_REG_OP_MODE, SX127X_MODULATION_FSK, 6, 5, 5); + } + if(state == ERR_NONE) { + _ook = enableOOK; + } + + return(state); +} + int16_t SX127x::setFrequencyRaw(float newFreq) { // set mode to standby int16_t state = setMode(SX127X_STANDBY); @@ -978,14 +1015,8 @@ int16_t SX127x::config() { } int16_t SX127x::configFSK() { - // set FSK modulation - int16_t state = _mod->SPIsetRegValue(SX127X_REG_OP_MODE, SX127X_MODULATION_FSK, 6, 5, 5); - if(state != ERR_NONE) { - return(state); - } - // set RSSI threshold - state = _mod->SPIsetRegValue(SX127X_REG_RSSI_THRESH, SX127X_RSSI_THRESHOLD); + int16_t state = _mod->SPIsetRegValue(SX127X_REG_RSSI_THRESH, SX127X_RSSI_THRESHOLD); if(state != ERR_NONE) { return(state); } diff --git a/src/modules/SX127x.h b/src/modules/SX127x.h index 6d9a9e10..70ba2085 100644 --- a/src/modules/SX127x.h +++ b/src/modules/SX127x.h @@ -572,9 +572,11 @@ class SX127x: public PhysicalLayer { \param currentLimit Trim value for OCP (over current protection) in mA. + \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); + int16_t beginFSK(uint8_t chipVersion, float br, float freqDev, float rxBw, uint8_t currentLimit, 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. @@ -848,6 +850,15 @@ class SX127x: public PhysicalLayer { */ int16_t disableAddressFiltering(); + /*! + \brief Enables/disables OOK modulation instead of FSK. + + \param enableOOK Enable (true) or disable (false) OOK. + + \returns \ref status_codes + */ + int16_t setOOK(bool enableOOK); + #ifdef RADIOLIB_DEBUG void regDump(); #endif @@ -861,6 +872,7 @@ class SX127x: public PhysicalLayer { uint8_t _cr; float _br; float _rxBw; + bool _ook; int16_t tx(char* data, uint8_t length); int16_t rxSingle(char* data, uint8_t* length);