From 5bab97d16bbc803de1d05b1876c393fcc32af779 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Grome=C5=A1?= Date: Sat, 18 Aug 2018 16:17:10 +0200 Subject: [PATCH] [SX127x] Sync with LoRaLib v5.1.1 --- keywords.txt | 1 + src/TypeDef.h | 1 + src/modules/SX1272.cpp | 63 +++ src/modules/SX1272.h | 51 +- src/modules/SX1278.cpp | 63 +++ src/modules/SX1278.h | 52 +- src/modules/SX127x.cpp | 1078 +++++++++++++++++++++++++++++++--------- src/modules/SX127x.h | 388 ++++++++++++++- 8 files changed, 1442 insertions(+), 255 deletions(-) diff --git a/keywords.txt b/keywords.txt index 5d766dce..314e7d6e 100644 --- a/keywords.txt +++ b/keywords.txt @@ -122,6 +122,7 @@ ERR_SPI_WRITE_FAILED LITERAL1 ERR_INVALID_CURRENT_LIMIT LITERAL1 ERR_INVALID_PREAMBLE_LENGTH LITERAL1 ERR_INVALID_GAIN LITERAL1 +ERR_WRONG_MODEM LITERAL1 ERR_INVALID_BIT_RATE LITERAL1 ERR_INVALID_FREQUENCY_DEVIATION LITERAL1 diff --git a/src/TypeDef.h b/src/TypeDef.h index 91cd2cf5..88e41be6 100644 --- a/src/TypeDef.h +++ b/src/TypeDef.h @@ -79,6 +79,7 @@ #define ERR_INVALID_CURRENT_LIMIT -17 #define ERR_INVALID_PREAMBLE_LENGTH -18 #define ERR_INVALID_GAIN -19 +#define ERR_WRONG_MODEM -20 // RF69-specific status codes #define ERR_INVALID_BIT_RATE -101 diff --git a/src/modules/SX1272.cpp b/src/modules/SX1272.cpp index 82040d72..0d601d24 100644 --- a/src/modules/SX1272.cpp +++ b/src/modules/SX1272.cpp @@ -58,6 +58,33 @@ 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) { + // execute common part + int16_t state = SX127x::beginFSK(SX1272_CHIP_VERSION, br, rxBw, freqDev, currentLimit); + if(state != ERR_NONE) { + return(state); + } + + // configure settings not accessible by API + state = configFSK(); + if(state != ERR_NONE) { + return(state); + } + + // configure publicly accessible settings + state = setFrequency(freq); + if(state != ERR_NONE) { + return(state); + } + + state = setOutputPower(power); + if(state != ERR_NONE) { + return(state); + } + + return(state); +} + int16_t SX1272::setFrequency(float freq) { // check frequency range if((freq < 860.0) || (freq > 1020.0)) { @@ -69,6 +96,11 @@ int16_t SX1272::setFrequency(float freq) { } int16_t SX1272::setBandwidth(float bw) { + // check active modem + if(getActiveModem() != SX127X_LORA) { + return(ERR_WRONG_MODEM); + } + uint8_t newBandwidth; // check alowed bandwidth values @@ -91,6 +123,11 @@ int16_t SX1272::setBandwidth(float bw) { } int16_t SX1272::setSpreadingFactor(uint8_t sf) { + // check active modem + if(getActiveModem() != SX127X_LORA) { + return(ERR_WRONG_MODEM); + } + uint8_t newSpreadingFactor; // check allowed spreading factor values @@ -129,6 +166,11 @@ int16_t SX1272::setSpreadingFactor(uint8_t sf) { } int16_t SX1272::setCodingRate(uint8_t cr) { + // check active modem + if(getActiveModem() != SX127X_LORA) { + return(ERR_WRONG_MODEM); + } + uint8_t newCodingRate; // check allowed coding rate values @@ -187,6 +229,11 @@ int16_t SX1272::setOutputPower(int8_t power) { } int16_t SX1272::setGain(uint8_t gain) { + // check active modem + if(getActiveModem() != SX127X_LORA) { + return(ERR_WRONG_MODEM); + } + // check allowed range if(gain > 6) { return(ERR_INVALID_GAIN); @@ -260,3 +307,19 @@ int16_t SX1272::config() { } return(state); } + +int16_t SX1272::configFSK() { + // configure common registers + int16_t state = SX127x::configFSK(); + if(state != ERR_NONE) { + return(state); + } + + // set data shaping + state = _mod->SPIsetRegValue(SX127X_REG_PA_RAMP, SX1272_FSK_GAUSSIAN_0_3, 6, 5); + if(state != ERR_NONE) { + return(state); + } + + return(state); +} diff --git a/src/modules/SX1272.h b/src/modules/SX1272.h index ffcd1074..011ee851 100644 --- a/src/modules/SX1272.h +++ b/src/modules/SX1272.h @@ -5,7 +5,7 @@ #include "Module.h" #include "SX127x.h" -//SX1272 specific register map +// SX1272 specific register map #define SX1272_REG_AGC_REF 0x43 #define SX1272_REG_AGC_THRESH_1 0x44 #define SX1272_REG_AGC_THRESH_2 0x45 @@ -18,13 +18,13 @@ #define SX1272_REG_FORMER_TEMP 0x6C #define SX1272_REG_BIT_RATE_FRAC 0x70 -//SX1272 LoRa modem settings -//SX1272_REG_FRF_MSB + REG_FRF_MID + REG_FRF_LSB +// SX1272 LoRa modem settings +// SX1272_REG_FRF_MSB + REG_FRF_MID + REG_FRF_LSB #define SX1272_FRF_MSB 0xE4 // 7 0 carrier frequency setting: f_RF = (F(XOSC) * FRF)/2^19 #define SX1272_FRF_MID 0xC0 // 7 0 where F(XOSC) = 32 MHz #define SX1272_FRF_LSB 0x00 // 7 0 FRF = 3 byte value of FRF registers -//SX1272_REG_MODEM_CONFIG_1 +// SX1272_REG_MODEM_CONFIG_1 #define SX1272_BW_125_00_KHZ 0b00000000 // 7 6 bandwidth: 125 kHz #define SX1272_BW_250_00_KHZ 0b01000000 // 7 6 250 kHz #define SX1272_BW_500_00_KHZ 0b10000000 // 7 6 500 kHz @@ -39,13 +39,50 @@ #define SX1272_LOW_DATA_RATE_OPT_OFF 0b00000000 // 0 0 low data rate optimization disabled #define SX1272_LOW_DATA_RATE_OPT_ON 0b00000001 // 0 0 low data rate optimization enabled, mandatory for SF 11 and 12 with BW 125 kHz -//SX1272_REG_MODEM_CONFIG_2 +// SX1272_REG_MODEM_CONFIG_2 #define SX1272_AGC_AUTO_OFF 0b00000000 // 2 2 LNA gain set by REG_LNA #define SX1272_AGC_AUTO_ON 0b00000100 // 2 2 LNA gain set by internal AGC loop -//SX127X_REG_VERSION +// SX127X_REG_VERSION #define SX1272_CHIP_VERSION 0x22 +// SX1272 FSK modem settings +// SX127X_REG_OP_MODE +#define SX1272_NO_SHAPING 0b00000000 // 4 3 data shaping: no shaping (default) +#define SX1272_FSK_GAUSSIAN_1_0 0b00001000 // 4 3 FSK modulation Gaussian filter, BT = 1.0 +#define SX1272_FSK_GAUSSIAN_0_5 0b00010000 // 4 3 FSK modulation Gaussian filter, BT = 0.5 +#define SX1272_FSK_GAUSSIAN_0_3 0b00011000 // 4 3 FSK modulation Gaussian filter, BT = 0.3 +#define SX1272_OOK_FILTER_BR 0b00001000 // 4 3 OOK modulation filter, f_cutoff = BR +#define SX1272_OOK_FILTER_2BR 0b00010000 // 4 3 OOK modulation filter, f_cutoff = 2*BR + +// SX127X_REG_PA_RAMP +#define SX1272_LOW_PN_TX_PLL_OFF 0b00010000 // 4 4 use standard PLL in transmit mode (default) +#define SX1272_LOW_PN_TX_PLL_ON 0b00000000 // 4 4 use lower phase noise PLL in transmit mode + +// SX127X_REG_SYNC_CONFIG +#define SX1272_FIFO_FILL_CONDITION_SYNC_ADDRESS 0b00000000 // 3 3 FIFO will be filled when sync address interrupt occurs (default) +#define SX1272_FIFO_FILL_CONDITION_ALWAYS 0b00001000 // 3 3 FIFO will be filled as long as this bit is set + +// SX1272_REG_AGC_REF +#define SX1272_AGC_REFERENCE_LEVEL 0x13 // 5 0 floor reference for AGC thresholds: AgcRef = -174 + 10*log(2*RxBw) + 8 + AGC_REFERENCE_LEVEL [dBm] + +// SX1272_REG_AGC_THRESH_1 +#define SX1272_AGC_STEP_1 0x0E // 4 0 1st AGC threshold + +// SX1272_REG_AGC_THRESH_2 +#define SX1272_AGC_STEP_2 0x50 // 7 4 2nd AGC threshold +#define SX1272_AGC_STEP_3 0x0B // 4 0 3rd AGC threshold + +// SX1272_REG_AGC_THRESH_3 +#define SX1272_AGC_STEP_4 0xD0 // 7 4 4th AGC threshold +#define SX1272_AGC_STEP_5 0x0B // 4 0 5th AGC threshold + +// SX1272_REG_PLL_LOW_PN +#define SX1272_PLL_LOW_PN_BANDWIDTH_75_KHZ 0b00000000 // 7 6 low phase noise PLL bandwidth: 75 kHz +#define SX1272_PLL_LOW_PN_BANDWIDTH_150_KHZ 0b01000000 // 7 6 150 kHz +#define SX1272_PLL_LOW_PN_BANDWIDTH_225_KHZ 0b10000000 // 7 6 225 kHz +#define SX1272_PLL_LOW_PN_BANDWIDTH_300_KHZ 0b11000000 // 7 6 300 kHz (default) + class SX1272: public SX127x { public: // constructor @@ -53,6 +90,7 @@ class SX1272: public SX127x { // basic methods int16_t begin(float freq = 915.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = SX127X_SYNC_WORD, int8_t power = 17, uint8_t currentLimit = 100, uint16_t preambleLength = 8, uint8_t gain = 0); + int16_t beginFSK(float freq = 434.0, float br = 48.0, float rxBw = 125.0, float freqDev = 50.0, int8_t power = 13, uint8_t currentLimit = 100); // configuration methods int16_t setFrequency(float freq); @@ -68,6 +106,7 @@ class SX1272: public SX127x { int16_t setCodingRateRaw(uint8_t newCodingRate); int16_t config(); + int16_t configFSK(); private: diff --git a/src/modules/SX1278.cpp b/src/modules/SX1278.cpp index a171ff6a..4b895959 100644 --- a/src/modules/SX1278.cpp +++ b/src/modules/SX1278.cpp @@ -51,6 +51,33 @@ 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) { + // execute common part + int16_t state = SX127x::beginFSK(SX1278_CHIP_VERSION, br, freqDev, rxBw, currentLimit); + if(state != ERR_NONE) { + return(state); + } + + // configure settings not accessible by API + state = configFSK(); + if(state != ERR_NONE) { + return(state); + } + + // configure publicly accessible settings + state = setFrequency(freq); + if(state != ERR_NONE) { + return(state); + } + + state = setOutputPower(power); + if(state != ERR_NONE) { + return(state); + } + + return(state); +} + int16_t SX1278::setFrequency(float freq) { // check frequency range if((freq < 137.0) || (freq > 525.0)) { @@ -122,6 +149,11 @@ int16_t SX1278::setFrequency(float freq) { } int16_t SX1278::setBandwidth(float bw) { + // check active modem + if(getActiveModem() != SX127X_LORA) { + return(ERR_WRONG_MODEM); + } + uint8_t newBandwidth; // check alowed bandwidth values @@ -158,6 +190,11 @@ int16_t SX1278::setBandwidth(float bw) { } int16_t SX1278::setSpreadingFactor(uint8_t sf) { + // check active modem + if(getActiveModem() != SX127X_LORA) { + return(ERR_WRONG_MODEM); + } + uint8_t newSpreadingFactor; // check allowed spreading factor values @@ -196,6 +233,11 @@ int16_t SX1278::setSpreadingFactor(uint8_t sf) { } int16_t SX1278::setCodingRate(uint8_t cr) { + // check active modem + if(getActiveModem() != SX127X_LORA) { + return(ERR_WRONG_MODEM); + } + uint8_t newCodingRate; // check allowed coding rate values @@ -254,6 +296,11 @@ int16_t SX1278::setOutputPower(int8_t power) { } int16_t SX1278::setGain(uint8_t gain) { + // check active modem + if(getActiveModem() != SX127X_LORA) { + return(ERR_WRONG_MODEM); + } + // check allowed range if(gain > 6) { return(ERR_INVALID_GAIN); @@ -327,3 +374,19 @@ int16_t SX1278::config() { } return(state); } + +int16_t SX1278::configFSK() { + // configure common registers + int16_t state = SX127x::configFSK(); + if(state != ERR_NONE) { + return(state); + } + + // set data shaping + state = _mod->SPIsetRegValue(SX127X_REG_PA_RAMP, SX1278_FSK_GAUSSIAN_0_3, 6, 5); + if(state != ERR_NONE) { + return(state); + } + + return(state); +} diff --git a/src/modules/SX1278.h b/src/modules/SX1278.h index a2513a2b..184c981d 100644 --- a/src/modules/SX1278.h +++ b/src/modules/SX1278.h @@ -5,35 +5,37 @@ #include "Module.h" #include "SX127x.h" -//SX1278 specific register map +// SX1278 specific register map #define SX1278_REG_MODEM_CONFIG_3 0x26 +#define SX1278_REG_PLL_HOP 0x44 #define SX1278_REG_TCXO 0x4B #define SX1278_REG_PA_DAC 0x4D -#define SX1278_REG_FORMER_TEMP 0x5D +#define SX1278_REG_FORMER_TEMP 0x5B +#define SX1278_REG_REG_BIT_RATE_FRAC 0x5D #define SX1278_REG_AGC_REF 0x61 #define SX1278_REG_AGC_THRESH_1 0x62 #define SX1278_REG_AGC_THRESH_2 0x63 #define SX1278_REG_AGC_THRESH_3 0x64 #define SX1278_REG_PLL 0x70 -//SX1278 LoRa modem settings -//SX1278_REG_OP_MODE MSB LSB DESCRIPTION +// SX1278 LoRa modem settings +// SX1278_REG_OP_MODE MSB LSB DESCRIPTION #define SX1278_HIGH_FREQ 0b00000000 // 3 3 access HF test registers #define SX1278_LOW_FREQ 0b00001000 // 3 3 access LF test registers -//SX1278_REG_FRF_MSB + REG_FRF_MID + REG_FRF_LSB +// SX1278_REG_FRF_MSB + REG_FRF_MID + REG_FRF_LSB #define SX1278_FRF_MSB 0x6C // 7 0 carrier frequency setting: f_RF = (F(XOSC) * FRF)/2^19 #define SX1278_FRF_MID 0x80 // 7 0 where F(XOSC) = 32 MHz #define SX1278_FRF_LSB 0x00 // 7 0 FRF = 3 byte value of FRF registers -//SX1278_REG_PA_CONFIG +// SX1278_REG_PA_CONFIG #define SX1278_MAX_POWER 0b01110000 // 6 4 max power: P_max = 10.8 + 0.6*MAX_POWER [dBm]; P_max(MAX_POWER = 0b111) = 15 dBm #define SX1278_LOW_POWER 0b00100000 // 6 4 -//SX1278_REG_LNA +// SX1278_REG_LNA #define SX1278_LNA_BOOST_LF_OFF 0b00000000 // 4 3 default LNA current -//SX1278_REG_MODEM_CONFIG_1 +// SX1278_REG_MODEM_CONFIG_1 #define SX1278_BW_7_80_KHZ 0b00000000 // 7 4 bandwidth: 7.80 kHz #define SX1278_BW_10_40_KHZ 0b00010000 // 7 4 10.40 kHz #define SX1278_BW_15_60_KHZ 0b00100000 // 7 4 15.60 kHz @@ -51,19 +53,45 @@ #define SX1278_HEADER_EXPL_MODE 0b00000000 // 0 0 explicit header mode #define SX1278_HEADER_IMPL_MODE 0b00000001 // 0 0 implicit header mode -//SX1278_REG_MODEM_CONFIG_2 +// SX1278_REG_MODEM_CONFIG_2 #define SX1278_RX_CRC_MODE_OFF 0b00000000 // 2 2 CRC disabled #define SX1278_RX_CRC_MODE_ON 0b00000100 // 2 2 CRC enabled -//SX1278_REG_MODEM_CONFIG_3 +// SX1278_REG_MODEM_CONFIG_3 #define SX1278_LOW_DATA_RATE_OPT_OFF 0b00000000 // 3 3 low data rate optimization disabled #define SX1278_LOW_DATA_RATE_OPT_ON 0b00001000 // 3 3 low data rate optimization enabled #define SX1278_AGC_AUTO_OFF 0b00000000 // 2 2 LNA gain set by REG_LNA #define SX1278_AGC_AUTO_ON 0b00000100 // 2 2 LNA gain set by internal AGC loop -//SX127X_REG_VERSION +// SX127X_REG_VERSION #define SX1278_CHIP_VERSION 0x12 +// SX1278 FSK modem settings +// SX127X_REG_PA_RAMP +#define SX1278_NO_SHAPING 0b00000000 // 6 5 data shaping: no shaping (default) +#define SX1278_FSK_GAUSSIAN_1_0 0b00100000 // 6 5 FSK modulation Gaussian filter, BT = 1.0 +#define SX1278_FSK_GAUSSIAN_0_5 0b01000000 // 6 5 FSK modulation Gaussian filter, BT = 0.5 +#define SX1278_FSK_GAUSSIAN_0_3 0b01100000 // 6 5 FSK modulation Gaussian filter, BT = 0.3 +#define SX1278_OOK_FILTER_BR 0b00100000 // 6 5 OOK modulation filter, f_cutoff = BR +#define SX1278_OOK_FILTER_2BR 0b01000000 // 6 5 OOK modulation filter, f_cutoff = 2*BR + +// SX1278_REG_AGC_REF +#define SX1278_AGC_REFERENCE_LEVEL_LF 0x19 // 5 0 floor reference for AGC thresholds: AgcRef = -174 + 10*log(2*RxBw) + 8 + AGC_REFERENCE_LEVEL [dBm]: below 525 MHz +#define SX1278_AGC_REFERENCE_LEVEL_HF 0x1C // 5 0 above 779 MHz + +// SX1278_REG_AGC_THRESH_1 +#define SX1278_AGC_STEP_1_LF 0x0C // 4 0 1st AGC threshold: below 525 MHz +#define SX1278_AGC_STEP_1_HF 0x0E // 4 0 above 779 MHz + +// SX1278_REG_AGC_THRESH_2 +#define SX1278_AGC_STEP_2_LF 0x40 // 7 4 2nd AGC threshold: below 525 MHz +#define SX1278_AGC_STEP_2_HF 0x50 // 7 4 above 779 MHz +#define SX1278_AGC_STEP_3 0x0B // 3 0 3rd AGC threshold + +// SX1278_REG_AGC_THRESH_3 +#define SX1278_AGC_STEP_4 0xC0 // 7 4 4th AGC threshold +#define SX1278_AGC_STEP_5 0x0C // 4 0 5th AGC threshold + class SX1278: public SX127x { public: // constructor @@ -71,6 +99,7 @@ class SX1278: public SX127x { // basic methods int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint8_t syncWord = SX127X_SYNC_WORD, int8_t power = 17, uint8_t currentLimit = 100, uint16_t preambleLength = 8, uint8_t gain = 0); + 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); // configuration methods int16_t setFrequency(float freq); @@ -86,6 +115,7 @@ class SX1278: public SX127x { int16_t setCodingRateRaw(uint8_t newCodingRate); int16_t config(); + int16_t configFSK(); private: diff --git a/src/modules/SX127x.cpp b/src/modules/SX127x.cpp index 6aa2f735..f39c200d 100644 --- a/src/modules/SX127x.cpp +++ b/src/modules/SX127x.cpp @@ -9,30 +9,7 @@ int16_t SX127x::begin(uint8_t chipVersion, uint8_t syncWord, uint8_t currentLimi _mod->init(USE_SPI, INT_BOTH); // try to find the SX127x chip - uint8_t i = 0; - bool flagFound = false; - while((i < 10) && !flagFound) { - uint8_t version = _mod->SPIreadRegister(SX127X_REG_VERSION); - if(version == chipVersion) { - flagFound = true; - } else { - #ifdef KITELIB_DEBUG - Serial.print(F("SX127x not found! (")); - Serial.print(i + 1); - Serial.print(F(" of 10 tries) SX127X_REG_VERSION == ")); - - char buffHex[5]; - sprintf(buffHex, "0x%02X", version); - Serial.print(buffHex); - Serial.print(F(", expected 0x00")); - Serial.print(chipVersion, HEX); - Serial.println(); - #endif - delay(1000); - i++; - } - } - if(!flagFound) { + if(!SX127x::findChip(chipVersion)) { DEBUG_PRINTLN_STR("No SX127x found!"); SPI.end(); return(ERR_CHIP_NOT_FOUND); @@ -40,8 +17,18 @@ int16_t SX127x::begin(uint8_t chipVersion, uint8_t syncWord, uint8_t currentLimi DEBUG_PRINTLN_STR("Found SX127x!"); } + // check active modem + int16_t state; + if(getActiveModem() != SX127X_LORA) { + // set LoRa mode + state = setActiveModem(SX127X_LORA); + if(state != ERR_NONE) { + return(state); + } + } + // set LoRa sync word - int16_t state = SX127x::setSyncWord(syncWord); + state = SX127x::setSyncWord(syncWord); if(state != ERR_NONE) { return(state); } @@ -54,82 +41,189 @@ int16_t SX127x::begin(uint8_t chipVersion, uint8_t syncWord, uint8_t currentLimi // set preamble length state = SX127x::setPreambleLength(preambleLength); - if(state != ERR_NONE) { - return(state); - } return(state); } -int16_t SX127x::transmit(String& str) { - return(SX127x::transmit(str.c_str())); -} - -int16_t SX127x::transmit(const char* str) { - return(SX127x::transmit((uint8_t*)str, strlen(str))); -} - -int16_t SX127x::transmit(uint8_t* data, size_t len) { - // check packet length - if(len >= 256) { - return(ERR_PACKET_TOO_LONG); +int16_t SX127x::beginFSK(uint8_t chipVersion, float br, float freqDev, float rxBw, uint8_t currentLimit) { + // set module properties + _mod->init(USE_SPI, INT_BOTH); + + // try to find the SX127x chip + if(!SX127x::findChip(chipVersion)) { + DEBUG_PRINTLN_STR("No SX127x found!"); + SPI.end(); + return(ERR_CHIP_NOT_FOUND); + } else { + DEBUG_PRINTLN_STR("Found SX127x!"); } - - // calculate timeout - uint16_t base = 1; - float symbolLength = (float)(base << _sf) / (float)_bw; - float de = 0; - if(symbolLength >= 0.016) { - de = 1; + + // check currently active modem + int16_t state; + if(getActiveModem() != SX127X_FSK_OOK) { + // set FSK mode + state = setActiveModem(SX127X_FSK_OOK); + if(state != ERR_NONE) { + return(state); + } } - float ih = (float)_mod->SPIgetRegValue(SX127X_REG_MODEM_CONFIG_1, 0, 0); - float crc = (float)(_mod->SPIgetRegValue(SX127X_REG_MODEM_CONFIG_2, 2, 2) >> 2); - float n_pre = (float)_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) * 1000.0); - // set mode to standby - int16_t state = setMode(SX127X_STANDBY); - - // set DIO mapping - _mod->SPIsetRegValue(SX127X_REG_DIO_MAPPING_1, SX127X_DIO0_TX_DONE, 7, 6); - - // clear interrupt flags - clearIRQFlags(); - - // set packet length - state |= _mod->SPIsetRegValue(SX127X_REG_PAYLOAD_LENGTH, len); - - // set FIFO pointers - 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); - - // write packet to FIFO - _mod->SPIwriteRegisterBurst(SX127X_REG_FIFO, data, len); - - // start transmission - state |= setMode(SX127X_TX); + // set bit rate + state = SX127x::setBitRate(br); if(state != ERR_NONE) { return(state); } - // wait for packet transmission or timeout - uint32_t start = millis(); - while(!digitalRead(_mod->int0())) { - if(millis() - start > timeout) { - clearIRQFlags(); - return(ERR_TX_TIMEOUT); - } + // set frequency deviation + state = SX127x::setFrequencyDeviation(freqDev); + if(state != ERR_NONE) { + return(state); } - uint32_t elapsed = millis() - start; - // update data rate - dataRate = (len*8.0)/((float)elapsed/1000.0); + // set receiver bandwidth + state = SX127x::setRxBandwidth(rxBw); + if(state != ERR_NONE) { + return(state); + } - // clear interrupt flags - clearIRQFlags(); + // set over current protection + state = SX127x::setCurrentLimit(currentLimit); + if(state != ERR_NONE) { + return(state); + } - return(ERR_NONE); + // default sync word value 0x2D01 is the same as the default in LowPowerLab RFM69 library + uint8_t syncWord[] = {0x2D, 0x01}; + state = setSyncWord(syncWord, 2); + if(state != ERR_NONE) { + return(state); + } + + // disable address filtering + state = disableAddressFiltering(); + + return(state); +} + +int16_t SX127x::transmit(String& str, uint8_t addr) { + return(SX127x::transmit(str.c_str()), addr); +} + +int16_t SX127x::transmit(const char* str, uint8_t addr) { + return(SX127x::transmit((uint8_t*)str, strlen(str)), addr); +} + +int16_t SX127x::transmit(uint8_t* data, size_t len, uint8_t addr) { + // set mode to standby + int16_t state = setMode(SX127X_STANDBY); + + int16_t modem = getActiveModem(); + if(modem == SX127X_LORA) { + // check packet length + if(len >= 256) { + return(ERR_PACKET_TOO_LONG); + } + + // calculate timeout + uint16_t base = 1; + float symbolLength = (float)(base << _sf) / (float)_bw; + float de = 0; + if(symbolLength >= 0.016) { + de = 1; + } + float ih = (float)_mod->SPIgetRegValue(SX127X_REG_MODEM_CONFIG_1, 0, 0); + float crc = (float)(_mod->SPIgetRegValue(SX127X_REG_MODEM_CONFIG_2, 2, 2) >> 2); + float n_pre = (float)_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) * 1000.0); + + // set DIO mapping + _mod->SPIsetRegValue(SX127X_REG_DIO_MAPPING_1, SX127X_DIO0_TX_DONE, 7, 6); + + // clear interrupt flags + clearIRQFlags(); + + // set packet length + state |= _mod->SPIsetRegValue(SX127X_REG_PAYLOAD_LENGTH, len); + + // set FIFO pointers + 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); + + // write packet to FIFO + _mod->SPIwriteRegisterBurst(SX127X_REG_FIFO, data, len); + + // start transmission + state |= setMode(SX127X_TX); + if(state != ERR_NONE) { + return(state); + } + + // wait for packet transmission or timeout + uint32_t start = millis(); + while(!digitalRead(_mod->int0())) { + if(millis() - start > timeout) { + clearIRQFlags(); + return(ERR_TX_TIMEOUT); + } + } + uint32_t elapsed = millis() - start; + + // update data rate + dataRate = (len*8.0)/((float)elapsed/1000.0); + + // clear interrupt flags + clearIRQFlags(); + + return(ERR_NONE); + + } else if(modem == SX127X_FSK_OOK) { + // check packet length + if(len >= 64) { + return(ERR_PACKET_TOO_LONG); + } + + // set DIO mapping + _mod->SPIsetRegValue(SX127X_REG_DIO_MAPPING_1, SX127X_DIO0_PACK_PACKET_SENT, 7, 6); + + // clear interrupt flags + clearIRQFlags(); + + // set packet length + _mod->SPIwriteRegister(SX127X_REG_FIFO, len); + + // check address filtering + uint8_t filter = _mod->SPIgetRegValue(SX127X_REG_PACKET_CONFIG_1, 2, 1); + 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); + + // start transmission + state |= setMode(SX127X_TX); + if(state != ERR_NONE) { + return(state); + } + + // wait for transmission end or timeout (150 % of expected time-one-air) + uint32_t timeout = (uint32_t)((((float)(len * 8)) / (_br * 1000.0)) * 1500.0); + uint32_t start = millis(); + while(!digitalRead(_mod->int0())) { + if(millis() - start > timeout) { + clearIRQFlags(); + return(ERR_TX_TIMEOUT); + } + } + + // clear interrupt flags + clearIRQFlags(); + + return(ERR_NONE); + } + + return(ERR_UNKNOWN); } int16_t SX127x::receive(String& str, size_t len) { @@ -147,71 +241,139 @@ int16_t SX127x::receive(String& str, size_t len) { } int16_t SX127x::receive(uint8_t* data, size_t len) { - // set mode to standby - int16_t state = setMode(SX127X_STANDBY); - - // set DIO pin mapping - state |= _mod->SPIsetRegValue(SX127X_REG_DIO_MAPPING_1, SX127X_DIO0_RX_DONE | SX127X_DIO1_RX_TIMEOUT, 7, 4); - - // clear interrupt flags - clearIRQFlags(); - - // set FIFO pointers - state |= _mod->SPIsetRegValue(SX127X_REG_FIFO_RX_BASE_ADDR, SX127X_FIFO_RX_BASE_ADDR_MAX); - state |= _mod->SPIsetRegValue(SX127X_REG_FIFO_ADDR_PTR, SX127X_FIFO_RX_BASE_ADDR_MAX); - - // set mode to receive - state |= setMode(SX127X_RXSINGLE); - if(state != ERR_NONE) { - return(state); - } - - // wait for packet reception or timeout - uint32_t start = millis(); - while(!digitalRead(_mod->int0())) { - if(digitalRead(_mod->int1())) { - clearIRQFlags(); - return(ERR_RX_TIMEOUT); + int16_t modem = getActiveModem(); + if(modem == SX127X_LORA) { + // set mode to standby + int16_t state = setMode(SX127X_STANDBY); + + // set DIO pin mapping + state |= _mod->SPIsetRegValue(SX127X_REG_DIO_MAPPING_1, SX127X_DIO0_RX_DONE | SX127X_DIO1_RX_TIMEOUT, 7, 4); + + // clear interrupt flags + clearIRQFlags(); + + // set FIFO pointers + state |= _mod->SPIsetRegValue(SX127X_REG_FIFO_RX_BASE_ADDR, SX127X_FIFO_RX_BASE_ADDR_MAX); + state |= _mod->SPIsetRegValue(SX127X_REG_FIFO_ADDR_PTR, SX127X_FIFO_RX_BASE_ADDR_MAX); + + // set mode to receive + state |= setMode(SX127X_RXSINGLE); + if(state != ERR_NONE) { + return(state); } + + // wait for packet reception or timeout + uint32_t start = millis(); + while(!digitalRead(_mod->int0())) { + if(digitalRead(_mod->int1())) { + clearIRQFlags(); + return(ERR_RX_TIMEOUT); + } + } + + // check integrity CRC + if(_mod->SPIgetRegValue(SX127X_REG_IRQ_FLAGS, 5, 5) == SX127X_CLEAR_IRQ_FLAG_PAYLOAD_CRC_ERROR) { + return(ERR_CRC_MISMATCH); + } + + // get packet length + size_t length = len; + if(_sf != 6) { + length = _mod->SPIgetRegValue(SX127X_REG_RX_NB_BYTES); + } + + // 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 + if(len == 0) { + data[length] = 0; + } + + // update RSSI and SNR + lastPacketRSSI = -157 + _mod->SPIgetRegValue(SX127X_REG_PKT_RSSI_VALUE); + int8_t rawSNR = (int8_t)_mod->SPIgetRegValue(SX127X_REG_PKT_SNR_VALUE); + lastPacketSNR = rawSNR / 4.0; + + // clear interrupt flags + clearIRQFlags(); + + return(ERR_NONE); + + } else if(modem == SX127X_FSK_OOK) { + // set mode to standby + int16_t state = setMode(SX127X_STANDBY); + + // set DIO pin mapping + state |= _mod->SPIsetRegValue(SX127X_REG_DIO_MAPPING_1, SX127X_DIO0_PACK_PACKET_SENT, 7, 6); + + // clear interrupt flags + clearIRQFlags(); + + // set mode to receive + state |= setMode(SX127X_RX); + if(state != ERR_NONE) { + return(state); + } + + // wait for packet reception or timeout (150 % 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)) * 1500.0); + uint32_t start = millis(); + while(!digitalRead(_mod->int0())) { + if(millis() - start > timeout) { + clearIRQFlags(); + return(ERR_RX_TIMEOUT); + } + } + + // get packet length + size_t length = _mod->SPIreadRegister(SX127X_REG_FIFO); + + // check address filtering + uint8_t filter = _mod->SPIgetRegValue(SX127X_REG_PACKET_CONFIG_1, 2, 1); + if((filter == SX127X_ADDRESS_FILTERING_NODE) || (filter == SX127X_ADDRESS_FILTERING_NODE_BROADCAST)) { + _mod->SPIreadRegister(SX127X_REG_FIFO); + } + + // 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 + if(len == 0) { + data[length] = 0; + } + + // clear interrupt flags + clearIRQFlags(); + + return(ERR_NONE); } - // check integrity CRC - if(_mod->SPIgetRegValue(SX127X_REG_IRQ_FLAGS, 5, 5) == SX127X_CLEAR_IRQ_FLAG_PAYLOAD_CRC_ERROR) { - return(ERR_CRC_MISMATCH); - } - - // get packet length - size_t length = len; - if(_sf != 6) { - length = _mod->SPIgetRegValue(SX127X_REG_RX_NB_BYTES); - } - - // 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 - if(len == 0) { - data[length] = 0; - } - - // update RSSI and SNR - lastPacketRSSI = -157 + _mod->SPIgetRegValue(SX127X_REG_PKT_RSSI_VALUE); - int8_t rawSNR = (int8_t)_mod->SPIgetRegValue(SX127X_REG_PKT_SNR_VALUE); - lastPacketSNR = rawSNR / 4.0; - - // clear interrupt flags - clearIRQFlags(); - - return(ERR_NONE); + return(ERR_UNKNOWN); } int16_t SX127x::scanChannel() { + // check active modem + if(getActiveModem() != SX127X_LORA) { + return(ERR_WRONG_MODEM); + } + // set mode to standby int16_t state = setMode(SX127X_STANDBY); @@ -280,15 +442,15 @@ void SX127x::setDio1Action(void (*func)(void)) { attachInterrupt(digitalPinToInterrupt(_mod->int1()), func, RISING); } -int16_t SX127x::startTransmit(String& str) { - return(SX127x::startTransmit(str.c_str())); +int16_t SX127x::startTransmit(String& str, uint8_t addr) { + return(SX127x::startTransmit(str.c_str()), addr); } -int16_t SX127x::startTransmit(const char* str) { - return(SX127x::startTransmit((uint8_t*)str, strlen(str))); +int16_t SX127x::startTransmit(const char* str, uint8_t addr) { + return(SX127x::startTransmit((uint8_t*)str, strlen(str)), addr); } -int16_t SX127x::startTransmit(uint8_t* data, size_t len) { +int16_t SX127x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { // check packet length if(len >= 256) { return(ERR_PACKET_TOO_LONG); @@ -297,27 +459,61 @@ int16_t SX127x::startTransmit(uint8_t* data, size_t len) { // set mode to standby int16_t state = setMode(SX127X_STANDBY); - // set DIO mapping - _mod->SPIsetRegValue(SX127X_REG_DIO_MAPPING_1, SX127X_DIO0_TX_DONE, 7, 6); - - // clear interrupt flags - clearIRQFlags(); - - // set packet length - state |= _mod->SPIsetRegValue(SX127X_REG_PAYLOAD_LENGTH, len); - - // set FIFO pointers - 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); - - // write packet to FIFO - _mod->SPIwriteRegisterBurst(SX127X_REG_FIFO, data, len); - - // start transmission - state |= setMode(SX127X_TX); - if(state != ERR_NONE) { - return(state); + int16_t modem = getActiveModem(); + if(modem == SX127X_LORA) { + // set DIO mapping + _mod->SPIsetRegValue(SX127X_REG_DIO_MAPPING_1, SX127X_DIO0_TX_DONE, 7, 6); + + // clear interrupt flags + clearIRQFlags(); + + // set packet length + state |= _mod->SPIsetRegValue(SX127X_REG_PAYLOAD_LENGTH, len); + + // set FIFO pointers + 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); + + // write packet to FIFO + _mod->SPIwriteRegisterBurst(SX127X_REG_FIFO, data, len); + + // start transmission + state |= setMode(SX127X_TX); + if(state != ERR_NONE) { + return(state); + } + + return(ERR_NONE); + + } else if(modem == SX127X_FSK_OOK) { + // set DIO mapping + _mod->SPIsetRegValue(SX127X_REG_DIO_MAPPING_1, SX127X_DIO0_PACK_PACKET_SENT, 7, 6); + + // clear interrupt flags + clearIRQFlags(); + + // set packet length + _mod->SPIwriteRegister(SX127X_REG_FIFO, len); + + // check address filtering + uint8_t filter = _mod->SPIgetRegValue(SX127X_REG_PACKET_CONFIG_1, 2, 1); + 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); + + // start transmission + state |= setMode(SX127X_TX); + if(state != ERR_NONE) { + return(state); + } + + return(ERR_NONE); } + + return(ERR_UNKNOWN); } int16_t SX127x::readData(String& str, size_t len) { @@ -335,43 +531,82 @@ int16_t SX127x::readData(String& str, size_t len) { } int16_t SX127x::readData(uint8_t* data, size_t len) { - // check integrity CRC - if(_mod->SPIgetRegValue(SX127X_REG_IRQ_FLAGS, 5, 5) == SX127X_CLEAR_IRQ_FLAG_PAYLOAD_CRC_ERROR) { - return(ERR_CRC_MISMATCH); + int16_t modem = getActiveModem(); + if(modem == SX127X_LORA) { + // check integrity CRC + if(_mod->SPIgetRegValue(SX127X_REG_IRQ_FLAGS, 5, 5) == SX127X_CLEAR_IRQ_FLAG_PAYLOAD_CRC_ERROR) { + return(ERR_CRC_MISMATCH); + } + + // get packet length + size_t length = len; + if(_sf != 6) { + length = _mod->SPIgetRegValue(SX127X_REG_RX_NB_BYTES); + } + + // 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 + if(len == 0) { + data[length] = 0; + } + + // update RSSI and SNR + lastPacketRSSI = -157 + _mod->SPIgetRegValue(SX127X_REG_PKT_RSSI_VALUE); + int8_t rawSNR = (int8_t)_mod->SPIgetRegValue(SX127X_REG_PKT_SNR_VALUE); + lastPacketSNR = rawSNR / 4.0; + + // clear interrupt flags + clearIRQFlags(); + + return(ERR_NONE); + + } else if(modem == SX127X_FSK_OOK) { + // get packet length + size_t length = _mod->SPIreadRegister(SX127X_REG_FIFO); + + // check address filtering + uint8_t filter = _mod->SPIgetRegValue(SX127X_REG_PACKET_CONFIG_1, 2, 1); + if((filter == SX127X_ADDRESS_FILTERING_NODE) || (filter == SX127X_ADDRESS_FILTERING_NODE_BROADCAST)) { + _mod->SPIreadRegister(SX127X_REG_FIFO); + } + + // 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 + if(len == 0) { + data[length] = 0; + } + + // clear interrupt flags + clearIRQFlags(); + + return(ERR_NONE); } - // get packet length - size_t length = len; - if(_sf != 6) { - length = _mod->SPIgetRegValue(SX127X_REG_RX_NB_BYTES); - } - - // 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 - if(len == 0) { - data[length] = 0; - } - - // update RSSI and SNR - lastPacketRSSI = -157 + _mod->SPIgetRegValue(SX127X_REG_PKT_RSSI_VALUE); - int8_t rawSNR = (int8_t)_mod->SPIgetRegValue(SX127X_REG_PKT_SNR_VALUE); - lastPacketSNR = rawSNR / 4.0; - - // clear interrupt flags - clearIRQFlags(); - - return(ERR_NONE); + return(ERR_UNKNOWN); } int16_t SX127x::setSyncWord(uint8_t syncWord) { + // check active modem + if(getActiveModem() != SX127X_LORA) { + return(ERR_WRONG_MODEM); + } + // set mode to standby setMode(SX127X_STANDBY); @@ -404,6 +639,11 @@ 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); @@ -419,24 +659,281 @@ int16_t SX127x::setPreambleLength(uint16_t preambleLength) { } float SX127x::getFrequencyError() { - // get raw frequency error - uint32_t raw = _mod->SPIgetRegValue(SX127X_REG_FEI_MSB, 3, 0) << 16; - raw |= _mod->SPIgetRegValue(SX127X_REG_FEI_MID) << 8; - raw |= _mod->SPIgetRegValue(SX127X_REG_FEI_LSB); - - uint32_t base = (uint32_t)2 << 23; - float error; - - // check the first bit - if(raw & 0x80000) { - // frequency error is negative - raw = ~raw + 1; - error = (((float)raw * (float)base)/32000000.0) * (_bw/500.0) * -1.0; - } else { - error = (((float)raw * (float)base)/32000000.0) * (_bw/500.0); + int16_t modem = getActiveModem(); + if(modem == SX127X_LORA) { + // get raw frequency error + uint32_t raw = _mod->SPIgetRegValue(SX127X_REG_FEI_MSB, 3, 0) << 16; + raw |= _mod->SPIgetRegValue(SX127X_REG_FEI_MID) << 8; + raw |= _mod->SPIgetRegValue(SX127X_REG_FEI_LSB); + + uint32_t base = (uint32_t)2 << 23; + float error; + + // check the first bit + if(raw & 0x80000) { + // frequency error is negative + raw = ~raw + 1; + error = (((float)raw * (float)base)/32000000.0) * (_bw/500.0) * -1.0; + } else { + error = (((float)raw * (float)base)/32000000.0) * (_bw/500.0); + } + + return(error); + + } else if(modem == SX127X_FSK_OOK) { + // get raw frequency error + uint16_t raw = _mod->SPIgetRegValue(SX127X_REG_FEI_MSB_FSK) << 8; + raw |= _mod->SPIgetRegValue(SX127X_REG_FEI_LSB_FSK); + + uint32_t base = 1; + float error; + + // check the first bit + if(raw & 0x8000) { + // frequency error is negative + raw = ~raw + 1; + error = (float)raw * (32000000.0 / (float)(base << 19)) * -1.0; + } else { + error = (float)raw * (32000000.0 / (float)(base << 19)); + } + + return(error); } - return(error); + return(ERR_UNKNOWN); +} + +int16_t SX127x::setBitRate(float br) { + // check active modem + if(getActiveModem() != SX127X_FSK_OOK) { + return(ERR_WRONG_MODEM); + } + + // check allowed bitrate + if((br < 1.2) || (br > 300.0)) { + return(ERR_INVALID_BIT_RATE); + } + + // set mode to STANDBY + int16_t state = setMode(SX127X_STANDBY); + if(state != ERR_NONE) { + return(state); + } + + // set bit rate + uint16_t bitRate = 32000 / br; + state = _mod->SPIsetRegValue(SX127X_REG_BITRATE_MSB, (bitRate & 0xFF00) >> 8, 7, 0); + state |= _mod->SPIsetRegValue(SX127X_REG_BITRATE_MSB, bitRate & 0x00FF, 7, 0); + // TODO: fractional part of bit rate setting + if(state == ERR_NONE) { + SX127x::_br = br; + } + return(state); +} + +int16_t SX127x::setFrequencyDeviation(float freqDev) { + // check active modem + if(getActiveModem() != SX127X_FSK_OOK) { + return(ERR_WRONG_MODEM); + } + + // check frequency deviation range + if(!((freqDev + _br/2.0 <= 250.0) && (freqDev >= 0.6) && (freqDev <= 200.0))) { + return(ERR_INVALID_FREQUENCY_DEVIATION); + } + + // set mode to STANDBY + int16_t state = setMode(SX127X_STANDBY); + if(state != ERR_NONE) { + return(state); + } + + // set allowed frequency deviation + uint32_t base = 1; + uint32_t FDEV = (freqDev * (base << 19)) / 32000; + state = _mod->SPIsetRegValue(SX127X_REG_FDEV_MSB, (FDEV & 0xFF00) >> 8, 5, 0); + state |= _mod->SPIsetRegValue(SX127X_REG_FDEV_LSB, FDEV & 0x00FF, 7, 0); + return(state); +} + +int16_t SX127x::setRxBandwidth(float rxBw) { + // check active modem + if(getActiveModem() != SX127X_FSK_OOK) { + return(ERR_WRONG_MODEM); + } + + // check allowed bandwidth values + uint8_t bwMant, bwExp; + if(abs(rxBw - 2.6) <= 0.001) { + bwMant = SX127X_RX_BW_MANT_24; + bwExp = 7; + } else if(abs(rxBw - 3.1) <= 0.001) { + bwMant = SX127X_RX_BW_MANT_20; + bwExp = 7; + } else if(abs(rxBw - 3.9) <= 0.001) { + bwMant = SX127X_RX_BW_MANT_16; + bwExp = 7; + } else if(abs(rxBw - 5.2) <= 0.001) { + bwMant = SX127X_RX_BW_MANT_24; + bwExp = 6; + } else if(abs(rxBw - 6.3) <= 0.001) { + bwMant = SX127X_RX_BW_MANT_20; + bwExp = 6; + } else if(abs(rxBw - 7.8) <= 0.001) { + bwMant = SX127X_RX_BW_MANT_16; + bwExp = 6; + } else if(abs(rxBw - 10.4) <= 0.001) { + bwMant = SX127X_RX_BW_MANT_24; + bwExp = 5; + } else if(abs(rxBw - 12.5) <= 0.001) { + bwMant = SX127X_RX_BW_MANT_20; + bwExp = 5; + } else if(abs(rxBw - 15.6) <= 0.001) { + bwMant = SX127X_RX_BW_MANT_16; + bwExp = 5; + } else if(abs(rxBw - 20.8) <= 0.001) { + bwMant = SX127X_RX_BW_MANT_24; + bwExp = 4; + } else if(abs(rxBw - 25.0) <= 0.001) { + bwMant = SX127X_RX_BW_MANT_20; + bwExp = 4; + } else if(abs(rxBw - 31.3) <= 0.001) { + bwMant = SX127X_RX_BW_MANT_16; + bwExp = 4; + } else if(abs(rxBw - 41.7) <= 0.001) { + bwMant = SX127X_RX_BW_MANT_24; + bwExp = 3; + } else if(abs(rxBw - 50.0) <= 0.001) { + bwMant = SX127X_RX_BW_MANT_20; + bwExp = 3; + } else if(abs(rxBw - 62.5) <= 0.001) { + bwMant = SX127X_RX_BW_MANT_16; + bwExp = 3; + } else if(abs(rxBw - 83.3) <= 0.001) { + bwMant = SX127X_RX_BW_MANT_24; + bwExp = 2; + } else if(abs(rxBw - 100.0) <= 0.001) { + bwMant = SX127X_RX_BW_MANT_20; + bwExp = 2; + } else if(abs(rxBw - 125.0) <= 0.001) { + bwMant = SX127X_RX_BW_MANT_16; + bwExp = 2; + } else if(abs(rxBw - 166.7) <= 0.001) { + bwMant = SX127X_RX_BW_MANT_24; + bwExp = 1; + } else if(abs(rxBw - 200.0) <= 0.001) { + bwMant = SX127X_RX_BW_MANT_20; + bwExp = 1; + } else if(abs(rxBw - 250.0) <= 0.001) { + bwMant = SX127X_RX_BW_MANT_16; + bwExp = 1; + } else { + return(ERR_INVALID_RX_BANDWIDTH); + } + + // set mode to STANDBY + int16_t state = setMode(SX127X_STANDBY); + if(state != ERR_NONE) { + return(state); + } + + // set Rx bandwidth during AFC + state = _mod->SPIsetRegValue(SX127X_REG_AFC_BW, bwMant | bwExp, 4, 0); + if(state != ERR_NONE) { + return(state); + } + + // set Rx bandwidth + state = _mod->SPIsetRegValue(SX127X_REG_RX_BW, bwMant | bwExp, 4, 0); + if(state == ERR_NONE) { + SX127x::_rxBw = rxBw; + } + + return(state); +} + +int16_t SX127x::setSyncWord(uint8_t* syncWord, size_t len) { + // check active modem + if(getActiveModem() != SX127X_FSK_OOK) { + return(ERR_WRONG_MODEM); + } + + // check constraints + if(len > 7) { + return(ERR_INVALID_SYNC_WORD); + } + + // sync word must not contain value 0x00 + for(uint8_t i = 0; i < len; i++) { + if(syncWord[i] == 0x00) { + return(ERR_INVALID_SYNC_WORD); + } + } + + // enable sync word recognition + int16_t state = _mod->SPIsetRegValue(SX127X_REG_SYNC_CONFIG, SX127X_SYNC_ON, 4, 4); + state |= _mod->SPIsetRegValue(SX127X_REG_SYNC_CONFIG, len, 2, 0); + if(state != ERR_NONE) { + return(state); + } + + // set sync word + _mod->SPIwriteRegisterBurst(SX127X_SYNC_VALUE_1, syncWord, len); + return(ERR_NONE); +} + +int16_t SX127x::setNodeAddress(uint8_t nodeAddr) { + // check active modem + if(getActiveModem() != SX127X_FSK_OOK) { + return(ERR_WRONG_MODEM); + } + + // enable address filtering (node only) + int16_t state = _mod->SPIsetRegValue(SX127X_REG_PACKET_CONFIG_1, SX127X_ADDRESS_FILTERING_NODE, 2, 1); + if(state != ERR_NONE) { + return(state); + } + + // set node address + return(_mod->SPIsetRegValue(SX127X_REG_NODE_ADRS, nodeAddr)); +} + +int16_t SX127x::setBroadcastAddress(uint8_t broadAddr) { + // check active modem + if(getActiveModem() != SX127X_FSK_OOK) { + return(ERR_WRONG_MODEM); + } + + // enable address filtering (node + broadcast) + int16_t state = _mod->SPIsetRegValue(SX127X_REG_PACKET_CONFIG_1, SX127X_ADDRESS_FILTERING_NODE_BROADCAST, 2, 1); + if(state != ERR_NONE) { + return(state); + } + + // set broadcast address + return(_mod->SPIsetRegValue(SX127X_REG_BROADCAST_ADRS, broadAddr)); +} + +int16_t SX127x::disableAddressFiltering() { + // check active modem + if(getActiveModem() != SX127X_FSK_OOK) { + return(ERR_WRONG_MODEM); + } + + // disable address filtering + int16_t state = _mod->SPIsetRegValue(SX127X_REG_PACKET_CONFIG_1, SX127X_ADDRESS_FILTERING_OFF, 2, 1); + if(state != ERR_NONE) { + return(state); + } + + // set node address to default (0x00) + state = _mod->SPIsetRegValue(SX127X_REG_NODE_ADRS, 0x00); + if(state != ERR_NONE) { + return(state); + } + + // set broadcast address to default (0x00) + return(_mod->SPIsetRegValue(SX127X_REG_BROADCAST_ADRS, 0x00)); } int16_t SX127x::setFrequencyRaw(float newFreq) { @@ -455,24 +952,145 @@ int16_t SX127x::setFrequencyRaw(float newFreq) { } int16_t SX127x::config() { - // set mode to SLEEP - int16_t state = setMode(SX127X_SLEEP); - - // set LoRa mode - state |= _mod->SPIsetRegValue(SX127X_REG_OP_MODE, SX127X_LORA, 7, 7); - - // set mode to STANDBY - state |= setMode(SX127X_STANDBY); - // turn off frequency hopping - state |= _mod->SPIsetRegValue(SX127X_REG_HOP_PERIOD, SX127X_HOP_PERIOD_OFF); + int16_t state = _mod->SPIsetRegValue(SX127X_REG_HOP_PERIOD, SX127X_HOP_PERIOD_OFF); return(state); } +int16_t SX127x::configFSK() { + // set FSK modulation + int16_t state = _mod->SPIsetRegValue(SX127X_REG_OP_MODE, SX127X_MODULATION_FSK, 6, 5); + if(state != ERR_NONE) { + return(state); + } + + // set RSSI threshold + state = _mod->SPIsetRegValue(SX127X_REG_RSSI_THRESH, SX127X_RSSI_THRESHOLD); + if(state != ERR_NONE) { + return(state); + } + + // reset FIFO flag + _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_2, SX127X_DATA_MODE_PACKET | SX127X_IO_HOME_OFF, 6, 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); + if(state != ERR_NONE) { + return(state); + } + + // disable Rx timeouts + state = _mod->SPIsetRegValue(SX127X_REG_RX_TIMEOUT_1, SX127X_TIMEOUT_RX_RSSI_OFF); + state |= _mod->SPIsetRegValue(SX127X_REG_RX_TIMEOUT_2, SX127X_TIMEOUT_RX_PREAMBLE_OFF); + state |= _mod->SPIsetRegValue(SX127X_REG_RX_TIMEOUT_3, SX127X_TIMEOUT_SIGNAL_SYNC_OFF); + if(state != ERR_NONE) { + return(state); + } + + // enable preamble detector and set preamble length + state = _mod->SPIsetRegValue(SX127X_REG_PREAMBLE_DETECT, SX127X_REG_PREAMBLE_DETECT | SX127X_PREAMBLE_DETECTOR_1_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) { + return(state); + } + + // set frequency error to zero + // for some reason unbeknownst to man, this write always fails, yet without it, switching modems doesn't work + // literally spent 8 hours debugging this ... well played Semtech, well played + _mod->SPIsetRegValue(SX127X_REG_FEI_MSB_FSK, 0x00); + _mod->SPIsetRegValue(SX127X_REG_FEI_LSB_FSK, 0x00); + + return(state); +} + +bool SX127x::findChip(uint8_t ver) { + uint8_t i = 0; + bool flagFound = false; + while((i < 10) && !flagFound) { + uint8_t version = _mod->SPIreadRegister(SX127X_REG_VERSION); + if(version == ver) { + flagFound = true; + } else { + #ifdef KITELIB_DEBUG + Serial.print(F("SX127x not found! (")); + Serial.print(i + 1); + Serial.print(F(" of 10 tries) SX127X_REG_VERSION == ")); + + char buffHex[5]; + sprintf(buffHex, "0x%02X", version); + Serial.print(buffHex); + Serial.print(F(", expected 0x00")); + Serial.print(ver, HEX); + Serial.println(); + #endif + delay(1000); + i++; + } + } + + return(flagFound); +} + int16_t SX127x::setMode(uint8_t mode) { return(_mod->SPIsetRegValue(SX127X_REG_OP_MODE, mode, 2, 0)); } -void SX127x::clearIRQFlags() { - _mod->SPIwriteRegister(SX127X_REG_IRQ_FLAGS, 0b11111111); +int16_t SX127x::getActiveModem() { + return(_mod->SPIgetRegValue(SX127X_REG_OP_MODE, 7, 7)); } + +int16_t SX127x::setActiveModem(uint8_t modem) { + // set mode to SLEEP + int16_t state = setMode(SX127X_SLEEP); + + // set LoRa mode + state |= _mod->SPIsetRegValue(SX127X_REG_OP_MODE, modem, 7, 7); + + // set mode to STANDBY + state |= setMode(SX127X_STANDBY); + return(state); +} + +void SX127x::clearIRQFlags() { + int16_t modem = getActiveModem(); + if(modem == SX127X_LORA) { + _mod->SPIwriteRegister(SX127X_REG_IRQ_FLAGS, 0b11111111); + } else if(modem == SX127X_FSK_OOK) { + _mod->SPIwriteRegister(SX127X_REG_IRQ_FLAGS_1, 0b11111111); + _mod->SPIwriteRegister(SX127X_REG_IRQ_FLAGS_2, 0b11111111); + } +} + +#ifdef KITELIB_DEBUG +void SX127x::regDump() { + Serial.println(); + Serial.println(F("ADDR\tVALUE")); + for(uint16_t addr = 0x01; addr <= 0x70; addr++) { + if(addr <= 0x0F) { + Serial.print(F("0x0")); + } else { + Serial.print(F("0x")); + } + Serial.print(addr, HEX); + Serial.print('\t'); + uint8_t val = _mod->SPIreadRegister(addr); + if(val <= 0x0F) { + Serial.print(F("0x0")); + } else { + Serial.print(F("0x")); + } + Serial.println(val, HEX); + + delay(50); + } +} +#endif diff --git a/src/modules/SX127x.h b/src/modules/SX127x.h index f3427bc4..c879fc41 100644 --- a/src/modules/SX127x.h +++ b/src/modules/SX127x.h @@ -4,7 +4,7 @@ #include "TypeDef.h" #include "Module.h" -// SX127x series common registers +// SX127x series common LoRa registers #define SX127X_REG_FIFO 0x00 #define SX127X_REG_OP_MODE 0x01 #define SX127X_REG_FRF_MSB 0x06 @@ -51,7 +51,7 @@ #define SX127X_REG_DIO_MAPPING_2 0x41 #define SX127X_REG_VERSION 0x42 -// SX127x common modem settings +// SX127x common LoRa modem settings // SX127X_REG_OP_MODE MSB LSB DESCRIPTION #define SX127X_FSK_OOK 0b00000000 // 7 7 FSK/OOK mode #define SX127X_LORA 0b10000000 // 7 7 LoRa mode @@ -160,6 +160,360 @@ #define SX127X_SYNC_WORD 0x12 // 7 0 default LoRa sync word #define SX127X_SYNC_WORD_LORAWAN 0x34 // 7 0 sync word reserved for LoRaWAN networks +// SX127x series common FSK registers +// NOTE: FSK register names that are conflicting with LoRa registers are marked with "_FSK" suffix +#define SX127X_REG_BITRATE_MSB 0x02 +#define SX127X_REG_BITRATE_LSB 0x03 +#define SX127X_REG_FDEV_MSB 0x04 +#define SX127X_REG_FDEV_LSB 0x05 +#define SX127X_REG_RX_CONFIG 0x0D +#define SX127X_REG_RSSI_CONFIG 0x0E +#define SX127X_REG_RSSI_COLLISION 0x0F +#define SX127X_REG_RSSI_THRESH 0x10 +#define SX127X_REG_RSSI_VALUE_FSK 0x11 +#define SX127X_REG_RX_BW 0x12 +#define SX127X_REG_AFC_BW 0x13 +#define SX127X_REG_OOK_PEAK 0x14 +#define SX127X_REG_OOK_FIX 0x15 +#define SX127X_REG_OOK_AVG 0x16 +#define SX127X_REG_AFC_FEI 0x1A +#define SX127X_REG_AFC_MSB 0x1B +#define SX127X_REG_AFC_LSB 0x1C +#define SX127X_REG_FEI_MSB_FSK 0x1D +#define SX127X_REG_FEI_LSB_FSK 0x1E +#define SX127X_REG_PREAMBLE_DETECT 0x1F +#define SX127X_REG_RX_TIMEOUT_1 0x20 +#define SX127X_REG_RX_TIMEOUT_2 0x21 +#define SX127X_REG_RX_TIMEOUT_3 0x22 +#define SX127X_REG_RX_DELAY 0x23 +#define SX127X_REG_OSC 0x24 +#define SX127X_REG_PREAMBLE_MSB_FSK 0x25 +#define SX127X_REG_PREAMBLE_LSB_FSK 0x26 +#define SX127X_REG_SYNC_CONFIG 0x27 +#define SX127X_REG_SYNC_VALUE_1 0x28 +#define SX127X_REG_SYNC_VALUE_2 0x29 +#define SX127X_REG_SYNC_VALUE_3 0x2A +#define SX127X_REG_SYNC_VALUE_4 0x2B +#define SX127X_REG_SYNC_VALUE_5 0x2C +#define SX127X_REG_SYNC_VALUE_6 0x2D +#define SX127X_REG_SYNC_VALUE_7 0x2E +#define SX127X_REG_SYNC_VALUE_8 0x2F +#define SX127X_REG_PACKET_CONFIG_1 0x30 +#define SX127X_REG_PACKET_CONFIG_2 0x31 +#define SX127X_REG_PAYLOAD_LENGTH_FSK 0x32 +#define SX127X_REG_NODE_ADRS 0x33 +#define SX127X_REG_BROADCAST_ADRS 0x34 +#define SX127X_REG_FIFO_THRESH 0x35 +#define SX127X_REG_SEQ_CONFIG_1 0x36 +#define SX127X_REG_SEQ_CONFIG_2 0x37 +#define SX127X_REG_TIMER_RESOL 0x38 +#define SX127X_REG_TIMER1_COEF 0x39 +#define SX127X_REG_TIMER2_COEF 0x3A +#define SX127X_REG_IMAGE_CAL 0x3B +#define SX127X_REG_TEMP 0x3C +#define SX127X_REG_LOW_BAT 0x3D +#define SX127X_REG_IRQ_FLAGS_1 0x3E +#define SX127X_REG_IRQ_FLAGS_2 0x3F + +// SX127x common FSK modem settings +// SX127X_REG_OP_MODE +#define SX127X_MODULATION_FSK 0b00000000 // 6 5 FSK modulation scheme +#define SX127X_MODULATION_OOK 0b00100000 // 6 5 OOK modulation scheme +#define SX127X_RX 0b00000101 // 2 0 receiver mode + +// SX127X_REG_BITRATE_MSB + SX127X_REG_BITRATE_LSB +#define SX127X_BITRATE_MSB 0x1A // 7 0 bit rate setting: BitRate = F(XOSC)/(BITRATE + BITRATE_FRAC/16) +#define SX127X_BITRATE_LSB 0x0B // 7 0 default value: 4.8 kbps + +// SX127X_REG_FDEV_MSB + SX127X_REG_FDEV_LSB +#define SX127X_FDEV_MSB 0x00 // 5 0 frequency deviation: Fdev = Fstep * FDEV +#define SX127X_FDEV_LSB 0x52 // 7 0 default value: 5 kHz + +// SX127X_REG_RX_CONFIG +#define SX127X_RESTART_RX_ON_COLLISION_OFF 0b00000000 // 7 7 automatic receiver restart disabled (default) +#define SX127X_RESTART_RX_ON_COLLISION_ON 0b10000000 // 7 7 automatically restart receiver if it gets saturated or on packet collision +#define SX127X_RESTART_RX_WITHOUT_PLL_LOCK 0b01000000 // 6 6 manually restart receiver without frequency change +#define SX127X_RESTART_RX_WITH_PLL_LOCK 0b00100000 // 5 5 manually restart receiver with frequency change +#define SX127X_AFC_AUTO_OFF 0b00000000 // 4 4 no AFC performed (default) +#define SX127X_AFC_AUTO_ON 0b00010000 // 4 4 AFC performed at each receiver startup +#define SX127X_AGC_AUTO_OFF 0b00000000 // 3 3 LNA gain set manually by register +#define SX127X_AGC_AUTO_ON 0b00001000 // 3 3 LNA gain controlled by AGC +#define SX127X_RX_TRIGGER_NONE 0b00000000 // 2 0 receiver startup at: none +#define SX127X_RX_TRIGGER_RSSI_INTERRUPT 0b00000001 // 2 0 RSSI interrupt +#define SX127X_RX_TRIGGER_PREAMBLE_DETECT 0b00000110 // 2 0 preamble detected +#define SX127X_RX_TRIGGER_BOTH 0b00000111 // 2 0 RSSI interrupt and preamble detected + +// SX127X_REG_RSSI_CONFIG +#define SX127X_RSSI_SMOOTHING_SAMPLES_2 0b00000000 // 2 0 number of samples for RSSI average: 2 +#define SX127X_RSSI_SMOOTHING_SAMPLES_4 0b00000001 // 2 0 4 +#define SX127X_RSSI_SMOOTHING_SAMPLES_8 0b00000010 // 2 0 8 (default) +#define SX127X_RSSI_SMOOTHING_SAMPLES_16 0b00000011 // 2 0 16 +#define SX127X_RSSI_SMOOTHING_SAMPLES_32 0b00000100 // 2 0 32 +#define SX127X_RSSI_SMOOTHING_SAMPLES_64 0b00000101 // 2 0 64 +#define SX127X_RSSI_SMOOTHING_SAMPLES_128 0b00000110 // 2 0 128 +#define SX127X_RSSI_SMOOTHING_SAMPLES_256 0b00000111 // 2 0 256 + +// SX127X_REG_RSSI_COLLISION +#define SX127X_RSSI_COLLISION_THRESHOLD 0x0A // 7 0 RSSI threshold in dB that will be considered a collision, default value: 10 dB + +// SX127X_REG_RSSI_THRESH +#define SX127X_RSSI_THRESHOLD 0xFF // 7 0 RSSI threshold that will trigger RSSI interrupt, RssiThreshold = RSSI_THRESHOLD / 2 [dBm] + +// SX127X_REG_RX_BW +#define SX127X_RX_BW_MANT_16 0b00000000 // 4 3 channel filter bandwidth: RxBw = F(XOSC) / (RxBwMant * 2^(RxBwExp + 2)) [kHz] +#define SX127X_RX_BW_MANT_20 0b00001000 // 4 3 +#define SX127X_RX_BW_MANT_24 0b00010000 // 4 3 default RxBwMant parameter +#define SX127X_RX_BW_EXP 0b00000101 // 2 0 default RxBwExp parameter + +// SX127X_REG_AFC_BW +#define SX127X_RX_BW_MANT_AFC 0b00001000 // 4 3 default RxBwMant parameter used during AFC +#define SX127X_RX_BW_EXP_AFC 0b00000011 // 2 0 default RxBwExp parameter used during AFC + +// SX127X_REG_OOK_PEAK +#define SX127X_BIT_SYNC_OFF 0b00000000 // 5 5 bit synchronizer disabled (not allowed in packet mode) +#define SX127X_BIT_SYNC_ON 0b00100000 // 5 5 bit synchronizer enabled (default) +#define SX127X_OOK_THRESH_FIXED 0b00000000 // 4 3 OOK threshold type: fixed value +#define SX127X_OOK_THRESH_PEAK 0b00001000 // 4 3 peak mode (default) +#define SX127X_OOK_THRESH_AVERAGE 0b00010000 // 4 3 average mode +#define SX127X_OOK_PEAK_THRESH_STEP_0_5_DB 0b00000000 // 2 0 OOK demodulator step size: 0.5 dB (default) +#define SX127X_OOK_PEAK_THRESH_STEP_1_0_DB 0b00000001 // 2 0 1.0 dB +#define SX127X_OOK_PEAK_THRESH_STEP_1_5_DB 0b00000010 // 2 0 1.5 dB +#define SX127X_OOK_PEAK_THRESH_STEP_2_0_DB 0b00000011 // 2 0 2.0 dB +#define SX127X_OOK_PEAK_THRESH_STEP_3_0_DB 0b00000100 // 2 0 3.0 dB +#define SX127X_OOK_PEAK_THRESH_STEP_4_0_DB 0b00000101 // 2 0 4.0 dB +#define SX127X_OOK_PEAK_THRESH_STEP_5_0_DB 0b00000110 // 2 0 5.0 dB +#define SX127X_OOK_PEAK_THRESH_STEP_6_0_DB 0b00000111 // 2 0 6.0 dB + +// SX127X_REG_OOK_FIX +#define SX127X_OOK_FIXED_THRESHOLD 0x0C // 7 0 default fixed threshold for OOK data slicer + +// SX127X_REG_OOK_AVG +#define SX127X_OOK_PEAK_THRESH_DEC_1_1_CHIP 0b00000000 // 7 5 OOK demodulator step period: once per chip (default) +#define SX127X_OOK_PEAK_THRESH_DEC_1_2_CHIP 0b00100000 // 7 5 once every 2 chips +#define SX127X_OOK_PEAK_THRESH_DEC_1_4_CHIP 0b01000000 // 7 5 once every 4 chips +#define SX127X_OOK_PEAK_THRESH_DEC_1_8_CHIP 0b01100000 // 7 5 once every 8 chips +#define SX127X_OOK_PEAK_THRESH_DEC_2_1_CHIP 0b10000000 // 7 5 2 times per chip +#define SX127X_OOK_PEAK_THRESH_DEC_4_1_CHIP 0b10100000 // 7 5 4 times per chip +#define SX127X_OOK_PEAK_THRESH_DEC_8_1_CHIP 0b11000000 // 7 5 8 times per chip +#define SX127X_OOK_PEAK_THRESH_DEC_16_1_CHIP 0b11100000 // 7 5 16 times per chip +#define SX127X_OOK_AVERAGE_OFFSET_0_DB 0b00000000 // 3 2 OOK average threshold offset: 0.0 dB (default) +#define SX127X_OOK_AVERAGE_OFFSET_2_DB 0b00000100 // 3 2 2.0 dB +#define SX127X_OOK_AVERAGE_OFFSET_4_DB 0b00001000 // 3 2 4.0 dB +#define SX127X_OOK_AVERAGE_OFFSET_6_DB 0b00001100 // 3 2 6.0 dB +#define SX127X_OOK_AVG_THRESH_FILT_32_PI 0b00000000 // 1 0 OOK average filter coefficient: chip rate / 32*pi +#define SX127X_OOK_AVG_THRESH_FILT_8_PI 0b00000001 // 1 0 chip rate / 8*pi +#define SX127X_OOK_AVG_THRESH_FILT_4_PI 0b00000010 // 1 0 chip rate / 4*pi (default) +#define SX127X_OOK_AVG_THRESH_FILT_2_PI 0b00000011 // 1 0 chip rate / 2*pi + +// SX127X_REG_AFC_FEI +#define SX127X_AGC_START 0b00010000 // 4 4 manually start AGC sequence +#define SX127X_AFC_CLEAR 0b00000010 // 1 1 manually clear AFC register +#define SX127X_AFC_AUTO_CLEAR_OFF 0b00000000 // 0 0 AFC register will not be cleared at the start of AFC (default) +#define SX127X_AFC_AUTO_CLEAR_ON 0b00000001 // 0 0 AFC register will be cleared at the start of AFC + +// SX127X_REG_PREAMBLE_DETECT +#define SX127X_PREAMBLE_DETECTOR_OFF 0b00000000 // 7 7 preamble detection disabled +#define SX127X_PREAMBLE_DETECTOR_ON 0b10000000 // 7 7 preamble detection enabled (default) +#define SX127X_PREAMBLE_DETECTOR_1_BYTE 0b00000000 // 6 5 preamble detection size: 1 byte (default) +#define SX127X_PREAMBLE_DETECTOR_2_BYTE 0b00100000 // 6 5 2 bytes +#define SX127X_PREAMBLE_DETECTOR_2_BYTE 0b01000000 // 6 5 3 bytes +#define SX127X_PREAMBLE_DETECTOR_TOL 0x0A // 4 0 default number of tolerated errors per chip (4 chips per bit) + +// SX127X_REG_RX_TIMEOUT_1 +#define SX127X_TIMEOUT_RX_RSSI_OFF 0x00 // 7 0 disable receiver timeout when RSSI interrupt doesn't occur (default) + +// SX127X_REG_RX_TIMEOUT_2 +#define SX127X_TIMEOUT_RX_PREAMBLE_OFF 0x00 // 7 0 disable receiver timeout when preamble interrupt doesn't occur (default) + +// SX127X_REG_RX_TIMEOUT_3 +#define SX127X_TIMEOUT_SIGNAL_SYNC_OFF 0x00 // 7 0 disable receiver timeout when sync address interrupt doesn't occur (default) + +// SX127X_REG_OSC +#define SX127X_RC_CAL_START 0b00000000 // 3 3 manually start RC oscillator calibration +#define SX127X_CLK_OUT_FXOSC 0b00000000 // 2 0 ClkOut frequency: F(XOSC) +#define SX127X_CLK_OUT_FXOSC_2 0b00000001 // 2 0 F(XOSC) / 2 +#define SX127X_CLK_OUT_FXOSC_4 0b00000010 // 2 0 F(XOSC) / 4 +#define SX127X_CLK_OUT_FXOSC_8 0b00000011 // 2 0 F(XOSC) / 8 +#define SX127X_CLK_OUT_FXOSC_16 0b00000100 // 2 0 F(XOSC) / 16 +#define SX127X_CLK_OUT_FXOSC_32 0b00000101 // 2 0 F(XOSC) / 32 +#define SX127X_CLK_OUT_RC 0b00000110 // 2 0 RC +#define SX127X_CLK_OUT_OFF 0b00000111 // 2 0 disabled (default) + +// SX127X_REG_PREAMBLE_MSB_FSK + SX127X_REG_PREAMBLE_LSB_FSK +#define SX127X_PREAMBLE_SIZE_MSB 0x00 // 7 0 preamble size in bytes +#define SX127X_PREAMBLE_SIZE_LSB 0x03 // 7 0 default value: 3 bytes + +// SX127X_REG_SYNC_CONFIG +#define SX127X_AUTO_RESTART_RX_MODE_OFF 0b00000000 // 7 6 Rx mode restart after packet reception: disabled +#define SX127X_AUTO_RESTART_RX_MODE_NO_PLL 0b01000000 // 7 6 enabled, don't wait for PLL lock +#define SX127X_AUTO_RESTART_RX_MODE_PLL 0b10000000 // 7 6 enabled, wait for PLL lock (default) +#define SX127X_PREAMBLE_POLARITY_AA 0b00000000 // 5 5 preamble polarity: 0xAA = 0b10101010 (default) +#define SX127X_PREAMBLE_POLARITY_55 0b00100000 // 5 5 0x55 = 0b01010101 +#define SX127X_SYNC_OFF 0b00000000 // 4 4 sync word disabled +#define SX127X_SYNC_ON 0b00010000 // 4 4 sync word enabled (default) +#define SX127X_SYNC_SIZE 0x03 // 2 0 sync word size in bytes, SyncSize = SYNC_SIZE + 1 bytes + +// SX127X_REG_SYNC_VALUE_1 - SX127X_REG_SYNC_VALUE_8 +#define SX127X_SYNC_VALUE_1 0x01 // 7 0 sync word: 1st byte (MSB) +#define SX127X_SYNC_VALUE_2 0x01 // 7 0 2nd byte +#define SX127X_SYNC_VALUE_3 0x01 // 7 0 3rd byte +#define SX127X_SYNC_VALUE_4 0x01 // 7 0 4th byte +#define SX127X_SYNC_VALUE_5 0x01 // 7 0 5th byte +#define SX127X_SYNC_VALUE_6 0x01 // 7 0 6th byte +#define SX127X_SYNC_VALUE_7 0x01 // 7 0 7th byte +#define SX127X_SYNC_VALUE_8 0x01 // 7 0 8th byte (LSB) + +// SX127X_REG_PACKET_CONFIG_1 +#define SX127X_PACKET_FIXED 0b00000000 // 7 7 packet format: fixed length +#define SX127X_PACKET_VARIABLE 0b10000000 // 7 7 variable length (default) +#define SX127X_DC_FREE_NONE 0b00000000 // 6 5 DC-free encoding: disabled (default) +#define SX127X_DC_FREE_MANCHESTER 0b00100000 // 6 5 Manchester +#define SX127X_DC_FREE_WHITENING 0b01000000 // 6 5 Whitening +#define SX127X_CRC_OFF 0b00000000 // 4 4 CRC disabled +#define SX127X_CRC_ON 0b00010000 // 4 4 CRC enabled (default) +#define SX127X_CRC_AUTOCLEAR_OFF 0b00001000 // 3 3 keep FIFO on CRC mismatch, issue payload ready interrupt +#define SX127X_CRC_AUTOCLEAR_ON 0b00000000 // 3 3 clear FIFO on CRC mismatch, do not issue payload ready interrupt +#define SX127X_ADDRESS_FILTERING_OFF 0b00000000 // 2 1 address filtering: none (default) +#define SX127X_ADDRESS_FILTERING_NODE 0b00000010 // 2 1 node +#define SX127X_ADDRESS_FILTERING_NODE_BROADCAST 0b00000100 // 2 1 node or broadcast +#define SX127X_CRC_WHITENING_TYPE_CCITT 0b00000000 // 0 0 CRC and whitening algorithms: CCITT CRC with standard whitening (default) +#define SX127X_CRC_WHITENING_TYPE_IBM 0b00000001 // 0 0 IBM CRC with alternate whitening + +// SX127X_REG_PACKET_CONFIG_2 +#define SX127X_DATA_MODE_PACKET 0b01000000 // 6 6 data mode: packet (default) +#define SX127X_DATA_MODE_CONTINUOUS 0b00000000 // 6 6 continuous +#define SX127X_IO_HOME_OFF 0b00000000 // 5 5 io-homecontrol compatibility disabled (default) +#define SX127X_IO_HOME_ON 0b00100000 // 5 5 io-homecontrol compatibility enabled + +// SX127X_REG_FIFO_THRESH +#define SX127X_TX_START_FIFO_LEVEL 0b00000000 // 7 7 start packet transmission when: number of bytes in FIFO exceeds FIFO_THRESHOLD +#define SX127X_TX_START_FIFO_NOT_EMPTY 0b10000000 // 7 7 at least one byte in FIFO (default) +#define SX127X_FIFO_THRESH 0x0F // 5 0 FIFO level threshold + +// SX127X_REG_SEQ_CONFIG_1 +#define SX127X_SEQUENCER_START 0b10000000 // 7 7 manually start sequencer +#define SX127X_SEQUENCER_STOP 0b01000000 // 6 6 manually stop sequencer +#define SX127X_IDLE_MODE_STANDBY 0b00000000 // 5 5 chip mode during sequencer idle mode: standby (default) +#define SX127X_IDLE_MODE_SLEEP 0b00100000 // 5 5 sleep +#define SX127X_FROM_START_LP_SELECTION 0b00000000 // 4 3 mode that will be set after starting sequencer: low power selection (default) +#define SX127X_FROM_START_RECEIVE 0b00001000 // 4 3 receive +#define SX127X_FROM_START_TRANSMIT 0b00010000 // 4 3 transmit +#define SX127X_FROM_START_TRANSMIT_FIFO_LEVEL 0b00011000 // 4 3 transmit on a FIFO level interrupt +#define SX127X_LP_SELECTION_SEQ_OFF 0b00000000 // 2 2 mode that will be set after exiting low power selection: sequencer off (default) +#define SX127X_LP_SELECTION_IDLE 0b00000100 // 2 2 idle state +#define SX127X_FROM_IDLE_TRANSMIT 0b00000000 // 1 1 mode that will be set after exiting idle mode: transmit (default) +#define SX127X_FROM_IDLE_RECEIVE 0b00000010 // 1 1 receive +#define SX127X_FROM_TRANSMIT_LP_SELECTION 0b00000000 // 0 0 mode that will be set after exiting transmit mode: low power selection (default) +#define SX127X_FROM_TRANSMIT_RECEIVE 0b00000001 // 0 0 receive + +// SX127X_REG_SEQ_CONFIG_2 +#define SX127X_FROM_RECEIVE_PACKET_RECEIVED_PAYLOAD 0b00100000 // 7 5 mode that will be set after exiting receive mode: packet received on payload ready interrupt (default) +#define SX127X_FROM_RECEIVE_LP_SELECTION 0b01000000 // 7 5 low power selection +#define SX127X_FROM_RECEIVE_PACKET_RECEIVED_CRC_OK 0b01100000 // 7 5 packet received on CRC OK interrupt +#define SX127X_FROM_RECEIVE_SEQ_OFF_RSSI 0b10000000 // 7 5 sequencer off on RSSI interrupt +#define SX127X_FROM_RECEIVE_SEQ_OFF_SYNC_ADDR 0b10100000 // 7 5 sequencer off on sync address interrupt +#define SX127X_FROM_RECEIVE_SEQ_OFF_PREAMBLE_DETECT 0b11000000 // 7 5 sequencer off on preamble detect interrupt +#define SX127X_FROM_RX_TIMEOUT_RECEIVE 0b00000000 // 4 3 mode that will be set after Rx timeout: receive (default) +#define SX127X_FROM_RX_TIMEOUT_TRANSMIT 0b00001000 // 4 3 transmit +#define SX127X_FROM_RX_TIMEOUT_LP_SELECTION 0b00010000 // 4 3 low power selection +#define SX127X_FROM_RX_TIMEOUT_SEQ_OFF 0b00011000 // 4 3 sequencer off +#define SX127X_FROM_PACKET_RECEIVED_SEQ_OFF 0b00000000 // 2 0 mode that will be set after packet received: sequencer off (default) +#define SX127X_FROM_PACKET_RECEIVED_TRANSMIT 0b00000001 // 2 0 transmit +#define SX127X_FROM_PACKET_RECEIVED_LP_SELECTION 0b00000010 // 2 0 low power selection +#define SX127X_FROM_PACKET_RECEIVED_RECEIVE_FS 0b00000011 // 2 0 receive via FS +#define SX127X_FROM_PACKET_RECEIVED_RECEIVE 0b00000100 // 2 0 receive + +// SX127X_REG_TIMER_RESOL +#define SX127X_TIMER1_OFF 0b00000000 // 3 2 timer 1 resolution: disabled (default) +#define SX127X_TIMER1_RESOLUTION_64_US 0b00000100 // 3 2 64 us +#define SX127X_TIMER1_RESOLUTION_4_1_MS 0b00001000 // 3 2 4.1 ms +#define SX127X_TIMER1_RESOLUTION_262_MS 0b00001100 // 3 2 262 ms +#define SX127X_TIMER2_OFF 0b00000000 // 3 2 timer 2 resolution: disabled (default) +#define SX127X_TIMER2_RESOLUTION_64_US 0b00000001 // 3 2 64 us +#define SX127X_TIMER2_RESOLUTION_4_1_MS 0b00000010 // 3 2 4.1 ms +#define SX127X_TIMER2_RESOLUTION_262_MS 0b00000011 // 3 2 262 ms + +// SX127X_REG_TIMER1_COEF +#define SX127X_TIMER1_COEFFICIENT 0xF5 // 7 0 multiplication coefficient for timer 1 + +// SX127X_REG_TIMER2_COEF +#define SX127X_TIMER2_COEFFICIENT 0x20 // 7 0 multiplication coefficient for timer 2 + +// SX127X_REG_IMAGE_CAL +#define SX127X_AUTO_IMAGE_CAL_OFF 0b00000000 // 7 7 temperature calibration disabled (default) +#define SX127X_AUTO_IMAGE_CAL_ON 0b10000000 // 7 7 temperature calibration enabled +#define SX127X_IMAGE_CAL_START 0b01000000 // 6 6 start temperature calibration +#define SX127X_IMAGE_CAL_RUNNING 0b00100000 // 5 5 temperature calibration is on-going +#define SX127X_IMAGE_CAL_COMPLETE 0b00000000 // 5 5 temperature calibration finished +#define SX127X_TEMP_CHANGED 0b00001000 // 3 3 temperature changed more than TEMP_THRESHOLD since last calibration +#define SX127X_TEMP_THRESHOLD_5_DEG_C 0b00000000 // 2 1 temperature change threshold: 5 deg. C +#define SX127X_TEMP_THRESHOLD_10_DEG_C 0b00000010 // 2 1 10 deg. C (default) +#define SX127X_TEMP_THRESHOLD_15_DEG_C 0b00000100 // 2 1 15 deg. C +#define SX127X_TEMP_THRESHOLD_20_DEG_C 0b00000110 // 2 1 20 deg. C +#define SX127X_TEMP_MONITOR_OFF 0b00000000 // 0 0 temperature monitoring disabled (default) +#define SX127X_TEMP_MONITOR_ON 0b00000001 // 0 0 temperature monitoring enabled + +// SX127X_REG_LOW_BAT +#define SX127X_LOW_BAT_OFF 0b00000000 // 3 3 low battery detector disabled +#define SX127X_LOW_BAT_ON 0b00001000 // 3 3 low battery detector enabled +#define SX127X_LOW_BAT_TRIM_1_695_V 0b00000000 // 2 0 battery voltage threshold: 1.695 V +#define SX127X_LOW_BAT_TRIM_1_764_V 0b00000001 // 2 0 1.764 V +#define SX127X_LOW_BAT_TRIM_1_835_V 0b00000010 // 2 0 1.835 V (default) +#define SX127X_LOW_BAT_TRIM_1_905_V 0b00000011 // 2 0 1.905 V +#define SX127X_LOW_BAT_TRIM_1_976_V 0b00000100 // 2 0 1.976 V +#define SX127X_LOW_BAT_TRIM_2_045_V 0b00000101 // 2 0 2.045 V +#define SX127X_LOW_BAT_TRIM_2_116_V 0b00000110 // 2 0 2.116 V +#define SX127X_LOW_BAT_TRIM_2_185_V 0b00000111 // 2 0 2.185 V + +// SX127X_REG_IRQ_FLAGS_1 +#define SX127X_FLAG_MODE_READY 0b10000000 // 7 7 requested mode is ready +#define SX127X_FLAG_RX_READY 0b01000000 // 6 6 reception ready (after RSSI, AGC, AFC) +#define SX127X_FLAG_TX_READY 0b00100000 // 5 5 transmission ready (after PA ramp-up) +#define SX127X_FLAG_PLL_LOCK 0b00010000 // 4 4 PLL locked +#define SX127X_FLAG_RSSI 0b00001000 // 3 3 RSSI value exceeds RSSI threshold +#define SX127X_FLAG_TIMEOUT 0b00000100 // 2 2 timeout occured +#define SX127X_FLAG_PREAMBLE_DETECT 0b00000010 // 1 1 valid preamble was detected +#define SX127X_FLAG_SYNC_ADDRESS_MATCH 0b00000001 // 0 0 sync address matched + +// SX127X_REG_IRQ_FLAGS_2 +#define SX127X_FLAG_FIFO_FULL 0b10000000 // 7 7 FIFO is full +#define SX127X_FLAG_FIFO_EMPTY 0b01000000 // 6 6 FIFO is empty +#define SX127X_FLAG_FIFO_LEVEL 0b00100000 // 5 5 number of bytes in FIFO exceeds FIFO_THRESHOLD +#define SX127X_FLAG_FIFO_OVERRUN 0b00010000 // 4 4 FIFO overrun occured +#define SX127X_FLAG_PACKET_SENT 0b00001000 // 3 3 packet was successfully sent +#define SX127X_FLAG_PAYLOAD_READY 0b00000100 // 2 2 packet was successfully received +#define SX127X_FLAG_CRC_OK 0b00000010 // 1 1 CRC check passed +#define SX127X_FLAG_LOW_BAT 0b00000001 // 0 0 battery voltage dropped below threshold + +// SX127X_REG_DIO_MAPPING_1 +#define SX127X_DIO0_CONT_SYNC_ADDRESS 0b00000000 // 7 6 +#define SX127X_DIO0_CONT_TX_READY 0b00000000 // 7 6 +#define SX127X_DIO0_CONT_RSSI_PREAMBLE_DETECTED 0b01000000 // 7 6 +#define SX127X_DIO0_CONT_RX_READY 0b10000000 // 7 6 +#define SX127X_DIO0_PACK_PAYLOAD_READY 0b00000000 // 7 6 +#define SX127X_DIO0_PACK_PACKET_SENT 0b00000000 // 7 6 +#define SX127X_DIO0_PACK_CRC_OK 0b01000000 // 7 6 +#define SX127X_DIO0_PACK_TEMP_CHANGE_LOW_BAT 0b11000000 // 7 6 +#define SX127X_DIO1_CONT_DCLK 0b00000000 // 5 4 +#define SX127X_DIO1_CONT_RSSI_PREAMBLE_DETECTED 0b00010000 // 5 4 +#define SX127X_DIO1_PACK_FIFO_LEVEL 0b00000000 // 5 4 +#define SX127X_DIO1_PACK_FIFO_EMPTY 0b00010000 // 5 4 +#define SX127X_DIO1_PACK_FIFO_FULL 0b00100000 // 5 4 + +// SX1272_REG_PLL_HOP + SX1278_REG_PLL_HOP +#define SX127X_FAST_HOP_OFF 0b10000000 // 7 7 carrier frequency validated when FRF registers are written +#define SX127X_FAST_HOP_ON 0b00000000 // 7 7 carrier frequency validated when FS modes are requested + +// SX1272_REG_TCXO + SX1278_REG_TCXO +#define SX127X_TCXO_INPUT_EXTERNAL 0b00000000 // 4 4 use external crystal oscillator +#define SX127X_TCXO_INPUT_EXTERNAL_CLIPPED 0b00010000 // 4 4 use external crystal oscillator clipped sine connected to XTA pin + +// SX1272_REG_PLL + SX1278_REG_PLL +#define SX127X_PLL_BANDWIDTH_75_KHZ 0b00000000 // 7 6 PLL bandwidth: 75 kHz +#define SX127X_PLL_BANDWIDTH_150_KHZ 0b01000000 // 7 6 150 kHz +#define SX127X_PLL_BANDWIDTH_225_KHZ 0b10000000 // 7 6 225 kHz +#define SX127X_PLL_BANDWIDTH_300_KHZ 0b11000000 // 7 6 300 kHz (default) + class SX127x { public: // constructor @@ -172,9 +526,10 @@ class SX127x { // basic methods int16_t begin(uint8_t chipVersion, uint8_t syncWord, uint8_t currentLimit, uint16_t preambleLength); - int16_t transmit(String& str); - int16_t transmit(const char* str); - int16_t transmit(uint8_t* data, size_t len); + int16_t beginFSK(uint8_t chipVersion, float br, float freqDev, float rxBw, uint8_t currentLimit); + int16_t transmit(String& str, uint8_t addr = 0); + int16_t transmit(const char* str, uint8_t addr = 0); + int16_t transmit(uint8_t* data, size_t len, uint8_t addr = 0); int16_t receive(String& str, size_t len = 0); int16_t receive(uint8_t* data, size_t len); int16_t scanChannel(); @@ -184,9 +539,9 @@ class SX127x { // interrupt methods void setDio0Action(void (*func)(void)); void setDio1Action(void (*func)(void)); - int16_t startTransmit(String& str); - int16_t startTransmit(const char* str); - int16_t startTransmit(uint8_t* data, size_t len); + int16_t startTransmit(String& str, uint8_t addr = 0); + int16_t startTransmit(const char* str, uint8_t addr = 0); + int16_t startTransmit(uint8_t* data, size_t len, uint8_t addr = 0); int16_t startReceive(); int16_t readData(String& str, size_t len = 0); int16_t readData(uint8_t* data, size_t len); @@ -196,6 +551,17 @@ class SX127x { int16_t setCurrentLimit(uint8_t currentLimit); int16_t setPreambleLength(uint16_t preambleLength); float getFrequencyError(); + int16_t setBitRate(float br); + int16_t setFrequencyDeviation(float freqDev); + int16_t setRxBandwidth(float rxBw); + int16_t setSyncWord(uint8_t* syncWord, size_t len); + int16_t setNodeAddress(uint8_t nodeAddr); + int16_t setBroadcastAddress(uint8_t broadAddr); + int16_t disableAddressFiltering(); + + #ifdef KITELIB_DEBUG + void regDump(); + #endif protected: Module* _mod; @@ -203,14 +569,20 @@ class SX127x { float _bw; uint8_t _sf; uint8_t _cr; + float _br; + float _rxBw; int16_t tx(char* data, uint8_t length); int16_t rxSingle(char* data, uint8_t* length); int16_t setFrequencyRaw(float newFreq); int16_t config(); + int16_t configFSK(); + int16_t getActiveModem(); private: + bool findChip(uint8_t ver); int16_t setMode(uint8_t mode); + int16_t setActiveModem(uint8_t modem); void clearIRQFlags(); };