From 6c9948634317b2da511c5d627f89bb9008e100af Mon Sep 17 00:00:00 2001 From: Callan Bryant Date: Mon, 16 Mar 2020 12:12:06 +0000 Subject: [PATCH 01/57] Swap delayMicroseconds() to delay where appropriate See https://github.com/jgromes/RadioLib/issues/126 for context. --- src/modules/RF69/RF69.cpp | 2 +- src/modules/SX126x/SX126x.cpp | 4 ++-- src/modules/SX127x/SX1272.cpp | 2 +- src/modules/SX127x/SX1278.cpp | 2 +- src/modules/XBee/XBee.cpp | 4 ++-- src/modules/nRF24/nRF24.cpp | 4 ++-- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/modules/RF69/RF69.cpp b/src/modules/RF69/RF69.cpp index b652a5fd..052bbd2c 100644 --- a/src/modules/RF69/RF69.cpp +++ b/src/modules/RF69/RF69.cpp @@ -101,7 +101,7 @@ int16_t RF69::begin(float freq, float br, float freqDev, float rxBw, int8_t powe void RF69::reset() { Module::pinMode(_mod->getRst(), OUTPUT); Module::digitalWrite(_mod->getRst(), HIGH); - delayMicroseconds(100); + delay(1); Module::digitalWrite(_mod->getRst(), LOW); delay(10); } diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 6b9aa0e4..6b72f690 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -153,7 +153,7 @@ int16_t SX126x::reset(bool verify) { // run the reset sequence Module::pinMode(_mod->getRst(), OUTPUT); Module::digitalWrite(_mod->getRst(), LOW); - delayMicroseconds(150); + delay(1); Module::digitalWrite(_mod->getRst(), HIGH); // return immediately when verification is disabled @@ -364,7 +364,7 @@ int16_t SX126x::sleep(bool retainConfig) { int16_t state = SPIwriteCommand(SX126X_CMD_SET_SLEEP, &sleepMode, 1, false); // wait for SX126x to safely enter sleep mode - delayMicroseconds(500); + delay(1); return(state); } diff --git a/src/modules/SX127x/SX1272.cpp b/src/modules/SX127x/SX1272.cpp index 1251d90a..06646d1f 100644 --- a/src/modules/SX127x/SX1272.cpp +++ b/src/modules/SX127x/SX1272.cpp @@ -60,7 +60,7 @@ int16_t SX1272::beginFSK(float freq, float br, float rxBw, float freqDev, int8_t void SX1272::reset() { Module::pinMode(_mod->getRst(), OUTPUT); Module::digitalWrite(_mod->getRst(), HIGH); - delayMicroseconds(100); + delay(1); Module::digitalWrite(_mod->getRst(), LOW); delay(5); } diff --git a/src/modules/SX127x/SX1278.cpp b/src/modules/SX127x/SX1278.cpp index 24ea9e64..5989aa13 100644 --- a/src/modules/SX127x/SX1278.cpp +++ b/src/modules/SX127x/SX1278.cpp @@ -55,7 +55,7 @@ int16_t SX1278::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t void SX1278::reset() { Module::pinMode(_mod->getRst(), OUTPUT); Module::digitalWrite(_mod->getRst(), LOW); - delayMicroseconds(100); + delay(1); Module::digitalWrite(_mod->getRst(), HIGH); delay(5); } diff --git a/src/modules/XBee/XBee.cpp b/src/modules/XBee/XBee.cpp index 1e5d7a15..cefc7dff 100644 --- a/src/modules/XBee/XBee.cpp +++ b/src/modules/XBee/XBee.cpp @@ -54,7 +54,7 @@ int16_t XBee::begin(long speed) { void XBee::reset() { pinMode(_mod->getRst(), OUTPUT); digitalWrite(_mod->getRst(), LOW); - delayMicroseconds(200); + delay(1); digitalWrite(_mod->getRst(), HIGH); } @@ -218,7 +218,7 @@ int16_t XBeeSerial::begin(long speed) { void XBeeSerial::reset() { pinMode(_mod->getRst(), OUTPUT); digitalWrite(_mod->getRst(), LOW); - delayMicroseconds(200); + delay(1); digitalWrite(_mod->getRst(), HIGH); pinMode(_mod->getRst(), INPUT); } diff --git a/src/modules/nRF24/nRF24.cpp b/src/modules/nRF24/nRF24.cpp index 732fc20b..7316f2f0 100644 --- a/src/modules/nRF24/nRF24.cpp +++ b/src/modules/nRF24/nRF24.cpp @@ -172,7 +172,7 @@ int16_t nRF24::startTransmit(uint8_t* data, size_t len, uint8_t addr) { // CE high to start transmitting digitalWrite(_mod->getRst(), HIGH); - delayMicroseconds(10); + delay(1); digitalWrite(_mod->getRst(), LOW); return(state); @@ -199,7 +199,7 @@ int16_t nRF24::startReceive() { digitalWrite(_mod->getRst(), HIGH); // wait to enter Rx state - delayMicroseconds(130); + delay(1); return(state); } From 3bb81988dde001c35d862c41715dfa315c69dfdb Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 22 Mar 2020 08:10:23 +0100 Subject: [PATCH 02/57] [AX25] Fixed typos --- examples/AX25/AX25_Transmit/AX25_Transmit.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/AX25/AX25_Transmit/AX25_Transmit.ino b/examples/AX25/AX25_Transmit/AX25_Transmit.ino index fa97067d..ac0eb1d2 100644 --- a/examples/AX25/AX25_Transmit/AX25_Transmit.ino +++ b/examples/AX25/AX25_Transmit/AX25_Transmit.ino @@ -68,7 +68,7 @@ void setup() { } void loop() { - // send AX.25 unnumbered infomration frame + // send AX.25 unnumbered information frame Serial.print(F("[AX.25] Sending UI frame ... ")); // destination station callsign: "NJ7P" // destination station SSID: 0 From 28c12f45769f85c5f658cc56f1b20e5f85806819 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 22 Mar 2020 08:10:49 +0100 Subject: [PATCH 03/57] [CC1101] Fixed typos --- .../CC1101_Transmit_Address.ino | 4 ++-- .../CC1101_Transmit_Interrupt.ino | 4 ++-- src/modules/CC1101/CC1101.cpp | 16 ++++++++-------- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/examples/CC1101/CC1101_Transmit_Address/CC1101_Transmit_Address.ino b/examples/CC1101/CC1101_Transmit_Address/CC1101_Transmit_Address.ino index 7e130920..94905bad 100644 --- a/examples/CC1101/CC1101_Transmit_Address/CC1101_Transmit_Address.ino +++ b/examples/CC1101/CC1101_Transmit_Address/CC1101_Transmit_Address.ino @@ -91,11 +91,11 @@ void loop() { if (state == ERR_NONE) { // the packet was successfully transmitted - Serial.println(F(" success!")); + Serial.println(F("success!")); } else if (state == ERR_PACKET_TOO_LONG) { // the supplied packet was longer than 255 bytes - Serial.println(F(" too long!")); + Serial.println(F("too long!")); } else { // some other error occurred diff --git a/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino b/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino index dde5d54d..a89cf0ca 100644 --- a/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino +++ b/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino @@ -123,8 +123,8 @@ void loop() { // you can also transmit byte array up to 256 bytes long /* - byte byteArr[] = {0x01, 0x23, 0x45, 0x56, - 0x78, 0xAB, 0xCD, 0xEF}; + byte byteArr[] = {0x01, 0x23, 0x45, 0x67, + 0x89, 0xAB, 0xCD, 0xEF}; int state = cc.startTransmit(byteArr, 8); */ diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index a207bafb..f8e2aa1e 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -76,7 +76,7 @@ int16_t CC1101::begin(float freq, float br, float freqDev, float rxBw, int8_t po state = variablePacketLengthMode(); RADIOLIB_ASSERT(state); - // configure default preamble lenght + // configure default preamble length state = setPreambleLength(preambleLength); RADIOLIB_ASSERT(state); @@ -330,7 +330,7 @@ int16_t CC1101::setBitRate(float br) { // set mode to standby SPIsendCommand(CC1101_CMD_IDLE); - // calculate exponent and mantisa values + // calculate exponent and mantissa values uint8_t e = 0; uint8_t m = 0; getExpMant(br * 1000.0, 256, 28, 14, e, m); @@ -350,7 +350,7 @@ int16_t CC1101::setRxBandwidth(float rxBw) { // set mode to standby SPIsendCommand(CC1101_CMD_IDLE); - // calculate exponent and mantisa values + // calculate exponent and mantissa values for(int8_t e = 3; e >= 0; e--) { for(int8_t m = 3; m >= 0; m --) { float point = (CC1101_CRYSTAL_FREQ * 1000000.0)/(8 * (m + 4) * ((uint32_t)1 << e)); @@ -380,7 +380,7 @@ int16_t CC1101::setFrequencyDeviation(float freqDev) { // set mode to standby SPIsendCommand(CC1101_CMD_IDLE); - // calculate exponent and mantisa values + // calculate exponent and mantissa values uint8_t e = 0; uint8_t m = 0; getExpMant(freqDev * 1000.0, 8, 17, 7, e, m); @@ -563,8 +563,8 @@ int16_t CC1101::setOOK(bool enableOOK) { int16_t state = SPIsetRegValue(CC1101_REG_MDMCFG2, CC1101_MOD_FORMAT_ASK_OOK, 6, 4); RADIOLIB_ASSERT(state); - // PA_TABLE[0] is (by default) the power value used when transmitting a "0L". - // Set PA_TABLE[1] to be used when transmitting a "1L". + // PA_TABLE[0] is (by default) the power value used when transmitting a "0". + // Set PA_TABLE[1] to be used when transmitting a "1". state = SPIsetRegValue(CC1101_REG_FREND0, 1, 2, 0); RADIOLIB_ASSERT(state); @@ -627,11 +627,11 @@ int16_t CC1101::variablePacketLengthMode(uint8_t maxLen) { int16_t CC1101::enableSyncWordFiltering(uint8_t maxErrBits, bool requireCarrierSense) { switch (maxErrBits){ case 0: - // in 16 bit sync word, expect all 16 bits. + // in 16 bit sync word, expect all 16 bits return (SPIsetRegValue(CC1101_REG_MDMCFG2, requireCarrierSense ? CC1101_SYNC_MODE_16_16_THR : CC1101_SYNC_MODE_16_16, 2, 0)); case 1: - // in 16 bit sync word, expect at least 15 bits. + // in 16 bit sync word, expect at least 15 bits return (SPIsetRegValue(CC1101_REG_MDMCFG2, requireCarrierSense ? CC1101_SYNC_MODE_15_16_THR : CC1101_SYNC_MODE_15_16, 2, 0)); default: From 089d925f82a63c8c31c69ae45a912fbd3645c475 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 22 Mar 2020 08:11:32 +0100 Subject: [PATCH 04/57] [RF69] Fixed typos --- .../RF69/RF69_Receive_Address/RF69_Receive_Address.ino | 4 ++-- .../RF69_Receive_Interrupt/RF69_Receive_Interrupt.ino | 2 +- examples/RF69/RF69_Transmit_AES/RF69_Transmit_AES.ino | 4 ++-- .../RF69/RF69_Transmit_Address/RF69_Transmit_Address.ino | 8 ++++---- .../RF69_Transmit_Interrupt/RF69_Transmit_Interrupt.ino | 8 ++++---- src/modules/RF69/RF69.cpp | 2 +- src/modules/RF69/RF69.h | 6 +++--- 7 files changed, 17 insertions(+), 17 deletions(-) diff --git a/examples/RF69/RF69_Receive_Address/RF69_Receive_Address.ino b/examples/RF69/RF69_Receive_Address/RF69_Receive_Address.ino index 86e1ebbc..08242ec3 100644 --- a/examples/RF69/RF69_Receive_Address/RF69_Receive_Address.ino +++ b/examples/RF69/RF69_Receive_Address/RF69_Receive_Address.ino @@ -58,8 +58,8 @@ void setup() { } // set broadcast address - // NOTE: calling this method will autmatically enable - // address filtering (node or broadcast address) + // NOTE: calling this method will automatically enable + // address filtering (node or broadcast address) Serial.print(F("[RF69] Setting broadcast address ... ")); state = rf.setBroadcastAddress(0xFF); if (state == ERR_NONE) { diff --git a/examples/RF69/RF69_Receive_Interrupt/RF69_Receive_Interrupt.ino b/examples/RF69/RF69_Receive_Interrupt/RF69_Receive_Interrupt.ino index 2e8929ac..32aef55f 100644 --- a/examples/RF69/RF69_Receive_Interrupt/RF69_Receive_Interrupt.ino +++ b/examples/RF69/RF69_Receive_Interrupt/RF69_Receive_Interrupt.ino @@ -104,7 +104,7 @@ void loop() { // you can also read received data as byte array /* byte byteArr[8]; - int state = lora.readData(byteArr, 8); + int state = rf.readData(byteArr, 8); */ if (state == ERR_NONE) { diff --git a/examples/RF69/RF69_Transmit_AES/RF69_Transmit_AES.ino b/examples/RF69/RF69_Transmit_AES/RF69_Transmit_AES.ino index a9ec4ff5..5df09c65 100644 --- a/examples/RF69/RF69_Transmit_AES/RF69_Transmit_AES.ino +++ b/examples/RF69/RF69_Transmit_AES/RF69_Transmit_AES.ino @@ -71,11 +71,11 @@ void loop() { if (state == ERR_NONE) { // the packet was successfully transmitted - Serial.println(F(" success!")); + Serial.println(F("success!")); } else if (state == ERR_PACKET_TOO_LONG) { // the supplied packet was longer than 64 bytes - Serial.println(F(" too long!")); + Serial.println(F("too long!")); } else { // some other error occurred diff --git a/examples/RF69/RF69_Transmit_Address/RF69_Transmit_Address.ino b/examples/RF69/RF69_Transmit_Address/RF69_Transmit_Address.ino index b9b36870..7413822e 100644 --- a/examples/RF69/RF69_Transmit_Address/RF69_Transmit_Address.ino +++ b/examples/RF69/RF69_Transmit_Address/RF69_Transmit_Address.ino @@ -72,7 +72,7 @@ void setup() { // address filtering can also be disabled // NOTE: calling this method will also erase previously set - // node and broadcast address + // node and broadcast address /* Serial.print(F("[RF69] Disabling address filtering ... ")); state = rf.disableAddressFiltering(); @@ -105,17 +105,17 @@ void loop() { // transmit byte array in broadcast mode /* - byte byteArr[] = {0x01, 0x23, 0x45, 0x56, 0x78, 0xAB, 0xCD, 0xEF}; + byte byteArr[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}; int state = rf.transmit(byteArr, 8, 0xFF); */ if (state == ERR_NONE) { // the packet was successfully transmitted - Serial.println(F(" success!")); + Serial.println(F("success!")); } else if (state == ERR_PACKET_TOO_LONG) { // the supplied packet was longer than 64 bytes - Serial.println(F(" too long!")); + Serial.println(F("too long!")); } else { // some other error occurred diff --git a/examples/RF69/RF69_Transmit_Interrupt/RF69_Transmit_Interrupt.ino b/examples/RF69/RF69_Transmit_Interrupt/RF69_Transmit_Interrupt.ino index 0387849a..3e83042a 100644 --- a/examples/RF69/RF69_Transmit_Interrupt/RF69_Transmit_Interrupt.ino +++ b/examples/RF69/RF69_Transmit_Interrupt/RF69_Transmit_Interrupt.ino @@ -61,8 +61,8 @@ void setup() { // you can also transmit byte array up to 64 bytes long /* - byte byteArr[] = {0x01, 0x23, 0x45, 0x56, - 0x78, 0xAB, 0xCD, 0xEF}; + byte byteArr[] = {0x01, 0x23, 0x45, 0x67, + 0x89, 0xAB, 0xCD, 0xEF}; state = rf.startTransmit(byteArr, 8); */ } @@ -123,8 +123,8 @@ void loop() { // you can also transmit byte array up to 64 bytes long /* - byte byteArr[] = {0x01, 0x23, 0x45, 0x56, - 0x78, 0xAB, 0xCD, 0xEF}; + byte byteArr[] = {0x01, 0x23, 0x45, 0x67, + 0x89, 0xAB, 0xCD, 0xEF}; int state = rf.startTransmit(byteArr, 8); */ diff --git a/src/modules/RF69/RF69.cpp b/src/modules/RF69/RF69.cpp index 052bbd2c..69dc4351 100644 --- a/src/modules/RF69/RF69.cpp +++ b/src/modules/RF69/RF69.cpp @@ -308,7 +308,7 @@ int16_t RF69::startTransmit(uint8_t* data, size_t len, uint8_t addr) { } int16_t RF69::readData(uint8_t* data, size_t len) { - // set mdoe to standby + // set mode to standby int16_t state = standby(); RADIOLIB_ASSERT(state); // get packet length diff --git a/src/modules/RF69/RF69.h b/src/modules/RF69/RF69.h index 6c5333fe..1a40e5dc 100644 --- a/src/modules/RF69/RF69.h +++ b/src/modules/RF69/RF69.h @@ -144,7 +144,7 @@ #define RF69_LISTEN_RES_IDLE_64_US 0b01000000 // 7 6 resolution of Listen mode idle time: 64 us #define RF69_LISTEN_RES_IDLE_4_1_MS 0b10000000 // 7 6 4.1 ms (default) #define RF69_LISTEN_RES_IDLE_262_MS 0b11000000 // 7 6 262 ms -#define RF69_LISTEN_RES_RX_64_US 0b00010000 // 5 4 resolution of Listen mode ry time: 64 us (default) +#define RF69_LISTEN_RES_RX_64_US 0b00010000 // 5 4 resolution of Listen mode rx time: 64 us (default) #define RF69_LISTEN_RES_RX_4_1_MS 0b00100000 // 5 4 4.1 ms #define RF69_LISTEN_RES_RX_262_MS 0b00110000 // 5 4 262 ms #define RF69_LISTEN_ACCEPT_ABOVE_RSSI_THRESH 0b00000000 // 3 3 packet acceptance criteria: RSSI above threshold @@ -305,7 +305,7 @@ #define RF69_IRQ_TX_READY 0b00100000 // 5 5 Tx mode ready #define RF69_IRQ_PLL_LOCK 0b00010000 // 4 4 PLL is locked #define RF69_IRQ_RSSI 0b00001000 // 3 3 RSSI value exceeded RssiThreshold -#define RF69_IRQ_TIMEOUT 0b00000100 // 2 2 timeout occured +#define RF69_IRQ_TIMEOUT 0b00000100 // 2 2 timeout occurred #define RF69_IRQ_AUTO_MODE 0b00000010 // 1 1 entered intermediate mode #define RF69_SYNC_ADDRESS_MATCH 0b00000001 // 0 0 sync address detected @@ -313,7 +313,7 @@ #define RF69_IRQ_FIFO_FULL 0b10000000 // 7 7 FIFO is full #define RF69_IRQ_FIFO_NOT_EMPTY 0b01000000 // 6 6 FIFO contains at least 1 byte #define RF69_IRQ_FIFO_LEVEL 0b00100000 // 5 5 FIFO contains more than FifoThreshold bytes -#define RF69_IRQ_FIFO_OVERRUN 0b00010000 // 4 4 FIFO overrun occured +#define RF69_IRQ_FIFO_OVERRUN 0b00010000 // 4 4 FIFO overrun occurred #define RF69_IRQ_PACKET_SENT 0b00001000 // 3 3 packet was sent #define RF69_IRQ_PAYLOAD_READY 0b00000100 // 2 2 last payload byte received and CRC check passed #define RF69_IRQ_CRC_OK 0b00000010 // 1 1 CRC check passed From 2f4a5c660c1f6bf74ae457ea7c0e800574dbb309 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 22 Mar 2020 08:11:55 +0100 Subject: [PATCH 05/57] [SX1231] Fixed typos --- examples/SX1231/SX1231_Transmit/SX1231_Transmit.ino | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/SX1231/SX1231_Transmit/SX1231_Transmit.ino b/examples/SX1231/SX1231_Transmit/SX1231_Transmit.ino index c781b02a..e651202a 100644 --- a/examples/SX1231/SX1231_Transmit/SX1231_Transmit.ino +++ b/examples/SX1231/SX1231_Transmit/SX1231_Transmit.ino @@ -53,17 +53,17 @@ void loop() { // you can also transmit byte array up to 256 bytes long /* - byte byteArr[] = {0x01, 0x23, 0x45, 0x56, 0x78, 0xAB, 0xCD, 0xEF}; + byte byteArr[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}; int state = rf.transmit(byteArr, 8); */ if (state == ERR_NONE) { // the packet was successfully transmitted - Serial.println(F(" success!")); + Serial.println(F("success!")); } else if (state == ERR_PACKET_TOO_LONG) { // the supplied packet was longer than 256 bytes - Serial.println(F(" too long!")); + Serial.println(F("too long!")); } From f1f995e9d81364a53538422833cc8d3c50888b00 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 22 Mar 2020 08:12:38 +0100 Subject: [PATCH 06/57] [SX126x] Fixed typos --- .../SX126x_FSK_Modem/SX126x_FSK_Modem.ino | 4 ++-- .../SX126x/SX126x_Settings/SX126x_Settings.ino | 8 ++++---- .../SX126x_Transmit_Interrupt.ino | 12 ++++++------ src/modules/SX126x/SX126x.cpp | 18 +++++++++--------- 4 files changed, 21 insertions(+), 21 deletions(-) diff --git a/examples/SX126x/SX126x_FSK_Modem/SX126x_FSK_Modem.ino b/examples/SX126x/SX126x_FSK_Modem/SX126x_FSK_Modem.ino index e3e04627..90730ed0 100644 --- a/examples/SX126x/SX126x_FSK_Modem/SX126x_FSK_Modem.ino +++ b/examples/SX126x/SX126x_FSK_Modem/SX126x_FSK_Modem.ino @@ -99,8 +99,8 @@ void loop() { // transmit FSK packet int state = fsk.transmit("Hello World!"); /* - byte byteArr[] = {0x01, 0x23, 0x45, 0x56, - 0x78, 0xAB, 0xCD, 0xEF}; + byte byteArr[] = {0x01, 0x23, 0x45, 0x67, + 0x89, 0xAB, 0xCD, 0xEF}; int state = lora.transmit(byteArr, 8); */ if (state == ERR_NONE) { diff --git a/examples/SX126x/SX126x_Settings/SX126x_Settings.ino b/examples/SX126x/SX126x_Settings/SX126x_Settings.ino index 3c8a3e5e..3da7d650 100644 --- a/examples/SX126x/SX126x_Settings/SX126x_Settings.ino +++ b/examples/SX126x/SX126x_Settings/SX126x_Settings.ino @@ -76,12 +76,12 @@ void setup() { // bandwidth: 500.0 kHz // spreading factor: 6 // coding rate: 5 - // sync word: 0x34 (public network) + // sync word: 0x34 (public network/LoRaWAN) // output power: 2 dBm // current limit: 50 mA // preamble length: 20 symbols // CRC: enabled - state = loraSX1268.begin(915.0, 500.0, 6, 5, 0x3444, 50, 20); + state = loraSX1268.begin(915.0, 500.0, 6, 5, 0x34, 50, 20); if (state == ERR_NONE) { Serial.println(F("success!")); } else { @@ -117,8 +117,8 @@ void setup() { while (true); } - // set LoRa sync word to 0x1234 - if (loraSX1262.setSyncWord(0x1234) != ERR_NONE) { + // set LoRa sync word to 0xAB + if (loraSX1262.setSyncWord(0xAB) != ERR_NONE) { Serial.println(F("Unable to set sync word!")); while (true); } diff --git a/examples/SX126x/SX126x_Transmit_Interrupt/SX126x_Transmit_Interrupt.ino b/examples/SX126x/SX126x_Transmit_Interrupt/SX126x_Transmit_Interrupt.ino index 157f00a1..724e05dc 100644 --- a/examples/SX126x/SX126x_Transmit_Interrupt/SX126x_Transmit_Interrupt.ino +++ b/examples/SX126x/SX126x_Transmit_Interrupt/SX126x_Transmit_Interrupt.ino @@ -65,9 +65,9 @@ void setup() { // you can also transmit byte array up to 256 bytes long /* - byte byteArr[] = {0x01, 0x23, 0x45, 0x56, - 0x78, 0xAB, 0xCD, 0xEF}; - state = lora.transmit(byteArr, 8); + byte byteArr[] = {0x01, 0x23, 0x45, 0x67, + 0x89, 0xAB, 0xCD, 0xEF}; + state = lora.startTransmit(byteArr, 8); */ } @@ -127,9 +127,9 @@ void loop() { // you can also transmit byte array up to 256 bytes long /* - byte byteArr[] = {0x01, 0x23, 0x45, 0x56, - 0x78, 0xAB, 0xCD, 0xEF}; - int state = lora.transmit(byteArr, 8); + byte byteArr[] = {0x01, 0x23, 0x45, 0x67, + 0x89, 0xAB, 0xCD, 0xEF}; + int state = lora.startTransmit(byteArr, 8); */ // we're ready to send more packets, diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 6b72f690..5754893f 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -310,7 +310,7 @@ int16_t SX126x::transmitDirect(uint32_t frf) { } int16_t SX126x::receiveDirect() { - // SX126x is unable to ouput received data directly + // SX126x is unable to output received data directly return(ERR_UNKNOWN); } @@ -486,7 +486,7 @@ int16_t SX126x::startReceiveDutyCycleAuto(uint16_t senderPreambleLength, uint16_ senderPreambleLength = _preambleLength; } - // worst case is that the sender starts transmiting when we're just less than minSymbols from going back to sleep. + // worst case is that the sender starts transmitting when we're just less than minSymbols from going back to sleep. // in this case, we don't catch minSymbols before going to sleep, // so we must be awake for at least that long before the sender stops transmitting. uint16_t sleepSymbols = senderPreambleLength - 2 * minSymbols; @@ -504,7 +504,7 @@ int16_t SX126x::startReceiveDutyCycleAuto(uint16_t senderPreambleLength, uint16_ // when the unit detects a preamble, it starts a timer that will timeout if it doesn't receive a header in time. // the duration is sleepPeriod + 2 * wakePeriod. // The sleepPeriod doesn't take into account shutdown and startup time for the unit (~1ms) - // We need to ensure that the timout is longer than senderPreambleLength. + // We need to ensure that the timeout is longer than senderPreambleLength. // So we must satisfy: wakePeriod > (preamblePeriod - (sleepPeriod - 1000)) / 2. (A) // we also need to ensure the unit is awake to see at least minSymbols. (B) uint32_t wakePeriod = max( @@ -513,7 +513,7 @@ int16_t SX126x::startReceiveDutyCycleAuto(uint16_t senderPreambleLength, uint16_ RADIOLIB_DEBUG_PRINT(F("Auto wake period: ")); RADIOLIB_DEBUG_PRINTLN(wakePeriod); - //If our sleep period is shorter than our transition time, just use the standard startReceive + // If our sleep period is shorter than our transition time, just use the standard startReceive if(sleepPeriod < _tcxoDelay + 1016) { return(startReceive()); } @@ -711,7 +711,7 @@ int16_t SX126x::setFrequencyDeviation(float freqDev) { return(ERR_WRONG_MODEM); } - // check alowed frequency deviation values + // check allowed frequency deviation values if(!(freqDev <= 200.0)) { return(ERR_INVALID_FREQUENCY_DEVIATION); } @@ -735,7 +735,7 @@ int16_t SX126x::setBitRate(float br) { return(ERR_WRONG_MODEM); } - // check alowed bit rate values + // check allowed bit rate values if(!((br >= 0.6) && (br <= 300.0))) { return(ERR_INVALID_BIT_RATE); } @@ -765,7 +765,7 @@ int16_t SX126x::setRxBandwidth(float rxBw) { }*/ _rxBwKhz = rxBw; - // check alowed receiver bandwidth values + // check allowed receiver bandwidth values if(abs(rxBw - 4.8) <= 0.001) { _rxBw = SX126X_GFSK_RX_BW_4_8; } else if(abs(rxBw - 5.8) <= 0.001) { @@ -980,7 +980,7 @@ int16_t SX126x::setCRC(uint8_t len, uint16_t initial, uint16_t polynomial, bool return(state); } else if(modem == SX126X_PACKET_TYPE_LORA) { - // LoRa CRC doesn't allow to set CRC polynomial, inital value, or inversion + // LoRa CRC doesn't allow to set CRC polynomial, initial value, or inversion // update packet parameters if(len) { @@ -1526,7 +1526,7 @@ int16_t SX126x::SPItransfer(uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* d // pull NSS low digitalWrite(_mod->getCs(), LOW); - // ensure BUSY is low (state meachine ready) + // ensure BUSY is low (state machine ready) uint32_t start = millis(); while(digitalRead(_mod->getGpio())) { if(millis() - start >= timeout) { From caa05f8ad8aa8f0d7e629228732dc3f3514a62b6 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 22 Mar 2020 08:13:27 +0100 Subject: [PATCH 07/57] [SX127x] Fixed typos --- .../SX127x_Channel_Activity_Detection.ino | 4 ++-- .../SX127x/SX127x_FSK_Modem/SX127x_FSK_Modem.ino | 6 +++--- .../SX127x_Receive_Interrupt.ino | 2 +- examples/SX127x/SX127x_Settings/SX127x_Settings.ino | 7 ++----- examples/SX127x/SX127x_Transmit/SX127x_Transmit.ino | 8 ++++---- .../SX127x_Transmit_Interrupt.ino | 12 ++++++------ src/modules/SX127x/SX127x.cpp | 2 +- src/modules/SX127x/SX127x.h | 9 ++++----- 8 files changed, 23 insertions(+), 27 deletions(-) diff --git a/examples/SX127x/SX127x_Channel_Activity_Detection/SX127x_Channel_Activity_Detection.ino b/examples/SX127x/SX127x_Channel_Activity_Detection/SX127x_Channel_Activity_Detection.ino index 163f8273..4d946254 100644 --- a/examples/SX127x/SX127x_Channel_Activity_Detection/SX127x_Channel_Activity_Detection.ino +++ b/examples/SX127x/SX127x_Channel_Activity_Detection/SX127x_Channel_Activity_Detection.ino @@ -59,11 +59,11 @@ void loop() { if (state == PREAMBLE_DETECTED) { // LoRa preamble was detected - Serial.println(F(" detected preamble!")); + Serial.println(F("detected preamble!")); } else if (state == CHANNEL_FREE) { // no preamble was detected, channel is free - Serial.println(F(" channel is free!")); + Serial.println(F("channel is free!")); } diff --git a/examples/SX127x/SX127x_FSK_Modem/SX127x_FSK_Modem.ino b/examples/SX127x/SX127x_FSK_Modem/SX127x_FSK_Modem.ino index f9e2821d..7727bcfe 100644 --- a/examples/SX127x/SX127x_FSK_Modem/SX127x_FSK_Modem.ino +++ b/examples/SX127x/SX127x_FSK_Modem/SX127x_FSK_Modem.ino @@ -97,8 +97,8 @@ void loop() { // transmit FSK packet int state = fsk.transmit("Hello World!"); /* - byte byteArr[] = {0x01, 0x23, 0x45, 0x56, - 0x78, 0xAB, 0xCD, 0xEF}; + byte byteArr[] = {0x01, 0x23, 0x45, 0x67, + 0x89, 0xAB, 0xCD, 0xEF}; int state = lora.transmit(byteArr, 8); */ if (state == ERR_NONE) { @@ -151,7 +151,7 @@ void loop() { // address filtering can also be disabled // NOTE: calling this method will also erase previously set - // node and broadcast address + // node and broadcast address /* state = fsk.disableAddressFiltering(); if (state != ERR_NONE) { diff --git a/examples/SX127x/SX127x_Receive_Interrupt/SX127x_Receive_Interrupt.ino b/examples/SX127x/SX127x_Receive_Interrupt/SX127x_Receive_Interrupt.ino index fbc20651..7f192757 100644 --- a/examples/SX127x/SX127x_Receive_Interrupt/SX127x_Receive_Interrupt.ino +++ b/examples/SX127x/SX127x_Receive_Interrupt/SX127x_Receive_Interrupt.ino @@ -118,7 +118,7 @@ void loop() { // you can also read received data as byte array /* byte byteArr[8]; - int state = lora.receive(byteArr, 8); + int state = lora.readData(byteArr, 8); */ if (state == ERR_NONE) { diff --git a/examples/SX127x/SX127x_Settings/SX127x_Settings.ino b/examples/SX127x/SX127x_Settings/SX127x_Settings.ino index 681c76d2..76b26b10 100644 --- a/examples/SX127x/SX127x_Settings/SX127x_Settings.ino +++ b/examples/SX127x/SX127x_Settings/SX127x_Settings.ino @@ -91,9 +91,6 @@ void setup() { // you can also change the settings at runtime // and check if the configuration was changed successfully - // different modules accept different parameters - // see https://github.com/jgromes/LoRaLib/wiki/Supported-LoRa-modules - // set carrier frequency to 433.5 MHz if (loraSX1278.setFrequency(433.5) == ERR_INVALID_FREQUENCY) { Serial.println(F("Selected frequency is invalid for this module!")); @@ -147,14 +144,14 @@ void setup() { } // set amplifier gain to 1 (accepted range is 1 - 6, where 1 is maximum gain) - // NOTE: set value to 0 to enable autmatic gain control + // NOTE: set value to 0 to enable automatic gain control // leave at 0 unless you know what you're doing if (loraSX1278.setGain(1) == ERR_INVALID_GAIN) { Serial.println(F("Selected gain is invalid for this module!")); while (true); } - Serial.println(F("All settings succesfully changed!")); + Serial.println(F("All settings successfully changed!")); } void loop() { diff --git a/examples/SX127x/SX127x_Transmit/SX127x_Transmit.ino b/examples/SX127x/SX127x_Transmit/SX127x_Transmit.ino index d14e76f7..cd5ad220 100644 --- a/examples/SX127x/SX127x_Transmit/SX127x_Transmit.ino +++ b/examples/SX127x/SX127x_Transmit/SX127x_Transmit.ino @@ -63,7 +63,7 @@ void loop() { // you can also transmit byte array up to 256 bytes long /* - byte byteArr[] = {0x01, 0x23, 0x45, 0x56, 0x78, 0xAB, 0xCD, 0xEF}; + byte byteArr[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}; int state = lora.transmit(byteArr, 8); */ @@ -78,11 +78,11 @@ void loop() { } else if (state == ERR_PACKET_TOO_LONG) { // the supplied packet was longer than 256 bytes - Serial.println(F(" too long!")); + Serial.println(F("too long!")); } else if (state == ERR_TX_TIMEOUT) { - // timeout occured while transmitting packet - Serial.println(F(" timeout!")); + // timeout occurred while transmitting packet + Serial.println(F("timeout!")); } else { // some other error occurred diff --git a/examples/SX127x/SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino b/examples/SX127x/SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino index 8368a7d4..0290e54b 100644 --- a/examples/SX127x/SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino +++ b/examples/SX127x/SX127x_Transmit_Interrupt/SX127x_Transmit_Interrupt.ino @@ -67,9 +67,9 @@ void setup() { // you can also transmit byte array up to 256 bytes long /* - byte byteArr[] = {0x01, 0x23, 0x45, 0x56, - 0x78, 0xAB, 0xCD, 0xEF}; - state = lora.transmit(byteArr, 8); + byte byteArr[] = {0x01, 0x23, 0x45, 0x67, + 0x89, 0xAB, 0xCD, 0xEF}; + state = lora.startTransmit(byteArr, 8); */ } @@ -129,9 +129,9 @@ void loop() { // you can also transmit byte array up to 256 bytes long /* - byte byteArr[] = {0x01, 0x23, 0x45, 0x56, - 0x78, 0xAB, 0xCD, 0xEF}; - int state = lora.transmit(byteArr, 8); + byte byteArr[] = {0x01, 0x23, 0x45, 0x67, + 0x89, 0xAB, 0xCD, 0xEF}; + int state = lora.startTransmit(byteArr, 8); */ // we're ready to send more packets, diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 1ba7b49e..b8b01dbc 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -43,7 +43,7 @@ int16_t SX127x::begin(uint8_t chipVersion, uint8_t syncWord, uint8_t currentLimi state = SX127x::setPreambleLength(preambleLength); RADIOLIB_ASSERT(state); - // initalize internal variables + // initialize internal variables _dataRate = 0.0; return(state); diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index aa6bb03b..1edf5917 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -480,7 +480,7 @@ #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_TIMEOUT 0b00000100 // 2 2 timeout occurred #define SX127X_FLAG_PREAMBLE_DETECT 0b00000010 // 1 1 valid preamble was detected #define SX127X_FLAG_SYNC_ADDRESS_MATCH 0b00000001 // 0 0 sync address matched @@ -488,7 +488,7 @@ #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_FIFO_OVERRUN 0b00010000 // 4 4 FIFO overrun occurred #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 @@ -565,7 +565,7 @@ class SX127x: public PhysicalLayer { int16_t begin(uint8_t chipVersion, uint8_t syncWord, uint8_t currentLimit, uint16_t preambleLength); /*! - \brief Reset method. Will reset the chip to the default state using RST pin. Declared pure virtual since SX1272 and SX1278 implmentations differ. + \brief Reset method. Will reset the chip to the default state using RST pin. Declared pure virtual since SX1272 and SX1278 implementations differ. */ virtual void reset() = 0; @@ -663,7 +663,6 @@ class SX127x: public PhysicalLayer { */ int16_t packetMode(); - // interrupt methods /*! @@ -880,7 +879,7 @@ class SX127x: public PhysicalLayer { /*! \brief Sets RSSI measurement configuration in FSK mode. - \param smoothingSamples Number of samples taken to avergae the RSSI result. + \param smoothingSamples Number of samples taken to average the RSSI result. numSamples = 2 ^ (1 + smoothingSamples), allowed values are in range 0 (2 samples) - 7 (256 samples) \param offset Signed RSSI offset that will be automatically compensated. 1 dB per LSB, defaults to 0, allowed values are in range -16 dB to +15 dB. From d3cec5d3b43d6ad4d85977f3e59307b838935ddd Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 22 Mar 2020 08:14:03 +0100 Subject: [PATCH 08/57] [Module] Removed String class from AT commands --- src/Module.cpp | 11 ++++++----- src/Module.h | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/Module.cpp b/src/Module.cpp index 7a714d85..06213b55 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -137,19 +137,20 @@ bool Module::ATsendData(uint8_t* data, uint32_t len) { } bool Module::ATgetResponse() { - String data = ""; + char data[128]; + char* dataPtr = data; uint32_t start = millis(); - while (millis() - start < _ATtimeout) { + while(millis() - start < _ATtimeout) { while(ModuleSerial->available() > 0) { char c = ModuleSerial->read(); RADIOLIB_VERBOSE_PRINT(c); - data += c; + *dataPtr++ = c; } - if(data.indexOf("OK") != -1) { + if(strstr(data, "OK") == 0) { RADIOLIB_VERBOSE_PRINTLN(); return(true); - } else if (data.indexOf("ERROR") != -1) { + } else if(strstr(data, "ERROR") == 0) { RADIOLIB_VERBOSE_PRINTLN(); return(false); } diff --git a/src/Module.h b/src/Module.h index ddc43c51..fd0b4e25 100644 --- a/src/Module.h +++ b/src/Module.h @@ -172,7 +172,7 @@ class Module { /*! \brief Get response after sending AT command. - \returns True if AT response contains the string "OK", false otehrwise. + \returns True if AT response contains the string "OK", false otherwise. */ bool ATgetResponse(); From 61bb57b9be0c5617e62186e5fe8ca06ed8c930fc Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 22 Mar 2020 08:14:23 +0100 Subject: [PATCH 09/57] [ESP8266] Fixed typos --- src/modules/ESP8266/ESP8266.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/ESP8266/ESP8266.h b/src/modules/ESP8266/ESP8266.h index aa4e145c..0469cd01 100644 --- a/src/modules/ESP8266/ESP8266.h +++ b/src/modules/ESP8266/ESP8266.h @@ -46,7 +46,7 @@ class ESP8266: public TransportLayer { */ int16_t join(const char* ssid, const char* password); - // transport layer methods (implementations of purely virtual methods in TransportMethod class) + // transport layer methods (implementations of purely virtual methods in TransportLayer class) int16_t openTransportConnection(const char* host, const char* protocol, uint16_t port, uint16_t tcpKeepAlive = 0); int16_t closeTransportConnection(); int16_t send(const char* data); From 73d5a482d16ab4e77431cb29e93ab7d157dac154 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 22 Mar 2020 08:14:32 +0100 Subject: [PATCH 10/57] [nRF24] Fixed typos --- src/modules/nRF24/nRF24.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/nRF24/nRF24.h b/src/modules/nRF24/nRF24.h index 70362dfe..a3205f78 100644 --- a/src/modules/nRF24/nRF24.h +++ b/src/modules/nRF24/nRF24.h @@ -428,7 +428,7 @@ class nRF24: public PhysicalLayer { int16_t setCrcFiltering(bool crcOn = true); /*! - \brief Enable or disable auto-acknowlede packets on all pipes + \brief Enable or disable auto-acknowledge packets on all pipes \param autoAckOn Enable (true) or disable (false) auto-acks. @@ -437,7 +437,7 @@ class nRF24: public PhysicalLayer { int16_t setAutoAck(bool autoAckOn = true); /*! - \brief Enable or disable auto-acknowlede packets on given pipe. + \brief Enable or disable auto-acknowledge packets on given pipe. \param pipeNum Number of pipe to which enable / disable auto-acks. From b05c264363cf43edcbf303a5639527ce3cc2255b Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 23 Mar 2020 20:23:37 +0100 Subject: [PATCH 11/57] Fixed typo in version macro --- src/TypeDef.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/TypeDef.h b/src/TypeDef.h index d149ca1b..adc3b1eb 100644 --- a/src/TypeDef.h +++ b/src/TypeDef.h @@ -13,7 +13,7 @@ #define RADIOLIB_VERSION_PATCH (0x00) #define RADIOLIB_VERSION_EXTRA (0x00) -#define RADIOLIB_VERSION ((RADIOLIB_VERSION_MAJOR << 24) | (RADIOLIB_VERSION_MAJOR << 16) | (RADIOLIB_VERSION_MAJOR << 8) | (RADIOLIB_VERSION_EXTRA)) +#define RADIOLIB_VERSION ((RADIOLIB_VERSION_MAJOR << 24) | (RADIOLIB_VERSION_MINOR << 16) | (RADIOLIB_VERSION_PATCH << 8) | (RADIOLIB_VERSION_EXTRA)) /* * Uncomment to enable static-only memory management: no dynamic allocation will be performed. From 8a496efd4186e3156544ebc81529a5220050d89b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Grome=C5=A1?= Date: Thu, 26 Mar 2020 21:41:52 +0100 Subject: [PATCH 12/57] Update CONTRIBUTING.md --- CONTRIBUTING.md | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 12fa8518..563d444f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -67,3 +67,44 @@ If you're adding a new method, make sure to add appropriate Doxygen comments, so 6. **Keywords** This is an Arduino library, so it needs to comply with the Arduino library specification. To add a new keyword to the Arduino IDE syntax highlighting, add it to the keywords.txt file. **Use true tabs in keywords.txt! No spaces there!** + +7. **Dynamic memory** +Sometimes, RadioLib might be used in critical applications where dynamic memory allocation using `new` or `malloc` might cause issues. For such cases, RadioLib provides the option to compile using only static arrays. This means that every dynamically allocated array must have a sufficiently large static counterpart. Naturally, all dynamically allocated memory must be properly de-allocated using `delete` or `free`. + +```c++ +// build a temporary buffer +#ifdef RADIOLIB_STATIC_ONLY + uint8_t data[RADIOLIB_STATIC_ARRAY_SIZE + 1]; +#else + uint8_t* data = new uint8_t[length + 1]; + if(!data) { + return(ERR_MEMORY_ALLOCATION_FAILED); + } +#endif + +// read the received data +readData(data, length); + +// deallocate temporary buffer +#ifndef RADIOLIB_STATIC_ONLY + delete[] data; +#endif +``` + +8. **God Mode** +During development, it can be useful to have access to the low level drivers, such as the SPI commands. These are incredibly powerful, since they will basically let user do anything he wants with the module, outside of the normal level of sanity checks. As such, they are normally protected using C++ access modifiers `private` or `protected`. God mode disables this protection, and so any newly implemented `class` must contain the appropriate macro check: + +```c++ +class Module { + void publicMethod(); + +#ifndef RADIOLIB_GODMODE + private: +#endif + + void privateMethod(); +}; +``` + +9. **No Arduino Strings** +Arduino `String` class should never be used internally in the library. The only allowed occurence of Arduino `String` is in public API methods, and only at the top-most layer. From fd6ef55a068d2209a5b301375a2e96facb7b737e Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 27 Mar 2020 14:09:46 +0100 Subject: [PATCH 13/57] Simplified ESP8266 detection macro --- src/RadioLib.h | 9 +++++---- src/modules/ESP8266/ESP8266.cpp | 2 +- src/modules/ESP8266/ESP8266.h | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/RadioLib.h b/src/RadioLib.h index 1775fa0e..78b0f8ae 100644 --- a/src/RadioLib.h +++ b/src/RadioLib.h @@ -44,9 +44,9 @@ #endif #include "modules/CC1101/CC1101.h" -#ifndef ESP8266 +//#if !defined(ESP8266) && !defined(ARDUINO_ARDUINO_NANO33BLE) #include "modules/ESP8266/ESP8266.h" -#endif +//#endif #include "modules/HC05/HC05.h" #include "modules/JDY08/JDY08.h" #include "modules/nRF24/nRF24.h" @@ -54,6 +54,7 @@ #include "modules/RFM9x/RFM95.h" #include "modules/RFM9x/RFM96.h" #include "modules/RFM9x/RFM97.h" +//#include "modules/Si443x/Si4432.h" #include "modules/SX1231/SX1231.h" #include "modules/SX126x/SX1261.h" #include "modules/SX126x/SX1262.h" @@ -73,11 +74,11 @@ #include "protocols/RTTY/RTTY.h" // transport layer protocols -#ifndef ESP8266 +//#if !defined(ESP8266) && !defined(ARDUINO_ARDUINO_NANO33BLE) #include "protocols/TransportLayer/TransportLayer.h" #include "protocols/HTTP/HTTP.h" #include "protocols/MQTT/MQTT.h" -#endif +//#endif // only create Radio class when using RadioShield #ifdef RADIOLIB_RADIOSHIELD diff --git a/src/modules/ESP8266/ESP8266.cpp b/src/modules/ESP8266/ESP8266.cpp index ab50f640..b221d0ff 100644 --- a/src/modules/ESP8266/ESP8266.cpp +++ b/src/modules/ESP8266/ESP8266.cpp @@ -1,4 +1,4 @@ -#ifndef ESP8266 +#if !defined(ESP8266) && !defined(ARDUINO_ARDUINO_NANO33BLE) #include "ESP8266.h" ESP8266::ESP8266(Module* module) { diff --git a/src/modules/ESP8266/ESP8266.h b/src/modules/ESP8266/ESP8266.h index 0469cd01..e817038e 100644 --- a/src/modules/ESP8266/ESP8266.h +++ b/src/modules/ESP8266/ESP8266.h @@ -1,4 +1,4 @@ -#if !defined(_RADIOLIB_ESP8266_H) && !defined(ESP8266) +#if !defined(_RADIOLIB_ESP8266_H) #define _RADIOLIB_ESP8266_H #include "../../Module.h" From 39c259848c8cf30b282b741b2dcc107a3a292178 Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 27 Mar 2020 14:10:45 +0100 Subject: [PATCH 14/57] Added support for Nano 33 BLE --- src/Module.cpp | 43 ++++++----- src/Module.h | 55 ++++++++------ src/TypeDef.h | 131 ++++++++++++++++++++++++++++++---- src/modules/CC1101/CC1101.cpp | 8 +-- src/modules/CC1101/CC1101.h | 4 +- src/modules/RF69/RF69.cpp | 4 +- src/modules/SX127x/SX127x.cpp | 4 +- 7 files changed, 184 insertions(+), 65 deletions(-) diff --git a/src/Module.cpp b/src/Module.cpp index 06213b55..8482e32c 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -1,9 +1,9 @@ #include "Module.h" -Module::Module(int16_t cs, int16_t irq, int16_t rst) { +Module::Module(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst) { _cs = cs; - _rx = NC; - _tx = NC; + _rx = RADIOLIB_NC; + _tx = RADIOLIB_NC; _irq = irq; _rst = rst; _spi = &SPI; @@ -11,10 +11,10 @@ Module::Module(int16_t cs, int16_t irq, int16_t rst) { _initInterface = true; } -Module::Module(int16_t cs, int16_t irq, int16_t rst, int16_t gpio) { +Module::Module(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE gpio) { _cs = cs; _rx = gpio; - _tx = NC; + _tx = RADIOLIB_NC; _irq = irq; _rst = rst; _spi = &SPI; @@ -22,11 +22,11 @@ Module::Module(int16_t cs, int16_t irq, int16_t rst, int16_t gpio) { _initInterface = true; } -Module::Module(int16_t rx, int16_t tx, HardwareSerial* useSer, int16_t rst) { - _cs = NC; +Module::Module(RADIOLIB_PIN_TYPE rx, RADIOLIB_PIN_TYPE tx, HardwareSerial* useSer, RADIOLIB_PIN_TYPE rst) { + _cs = RADIOLIB_NC; _rx = rx; _tx = tx; - _irq = NC; + _irq = RADIOLIB_NC; _rst = rst; _initInterface = true; @@ -38,10 +38,10 @@ Module::Module(int16_t rx, int16_t tx, HardwareSerial* useSer, int16_t rst) { #endif } -Module::Module(int16_t cs, int16_t irq, int16_t rst, SPIClass& spi, SPISettings spiSettings) { +Module::Module(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, SPIClass& spi, SPISettings spiSettings) { _cs = cs; - _rx = NC; - _tx = NC; + _rx = RADIOLIB_NC; + _tx = RADIOLIB_NC; _irq = irq; _rst = rst; _spi = &spi; @@ -49,10 +49,10 @@ Module::Module(int16_t cs, int16_t irq, int16_t rst, SPIClass& spi, SPISettings _initInterface = false; } -Module::Module(int16_t cs, int16_t irq, int16_t rst, int16_t gpio, SPIClass& spi, SPISettings spiSettings) { +Module::Module(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE gpio, SPIClass& spi, SPISettings spiSettings) { _cs = cs; _rx = gpio; - _tx = NC; + _tx = RADIOLIB_NC; _irq = irq; _rst = rst; _spi = &spi; @@ -60,7 +60,7 @@ Module::Module(int16_t cs, int16_t irq, int16_t rst, int16_t gpio, SPIClass& spi _initInterface = false; } -Module::Module(int16_t cs, int16_t irq, int16_t rst, int16_t rx, int16_t tx, SPIClass& spi, SPISettings spiSettings, HardwareSerial* useSer) { +Module::Module(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE rx, RADIOLIB_PIN_TYPE tx, SPIClass& spi, SPISettings spiSettings, HardwareSerial* useSer) { _cs = cs; _rx = rx; _tx = tx; @@ -276,14 +276,21 @@ void Module::SPItransfer(uint8_t cmd, uint8_t reg, uint8_t* dataOut, uint8_t* da _spi->endTransaction(); } -void Module::pinMode(int16_t pin, uint8_t mode) { - if(pin != NC) { +void Module::pinMode(RADIOLIB_PIN_TYPE pin, RADIOLIB_PIN_MODE mode) { + if(pin != RADIOLIB_NC) { ::pinMode(pin, mode); } } -void Module::digitalWrite(int16_t pin, uint8_t value) { - if(pin != NC) { +void Module::digitalWrite(RADIOLIB_PIN_TYPE pin, RADIOLIB_PIN_STATUS value) { + if(pin != RADIOLIB_NC) { ::digitalWrite(pin, value); } } + +RADIOLIB_PIN_STATUS Module::digitalRead(RADIOLIB_PIN_TYPE pin) { + if(pin != RADIOLIB_NC) { + return(::digitalRead(pin)); + } + return(LOW); +} diff --git a/src/Module.h b/src/Module.h index fd0b4e25..ebc81986 100644 --- a/src/Module.h +++ b/src/Module.h @@ -30,9 +30,9 @@ class Module { \param rst Arduino pin to be used as hardware reset for the module. Defaults to NC (unused). */ #ifdef RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED - Module(int16_t tx, int16_t rx, HardwareSerial* serial = &Serial1, int16_t rst = NC); + Module(RADIOLIB_PIN_TYPE tx, RADIOLIB_PIN_TYPE rx, HardwareSerial* serial = &RADIOLIB_HARDWARE_SERIAL_PORT, RADIOLIB_PIN_TYPE rst = RADIOLIB_NC); #else - Module(int16_t tx, int16_t rx, HardwareSerial* serial = nullptr, int16_t rst = NC); + Module(RADIOLIB_PIN_TYPE tx, RADIOLIB_PIN_TYPE rx, HardwareSerial* serial = nullptr, RADIOLIB_PIN_TYPE rst = RADIOLIB_NC); #endif /*! @@ -44,7 +44,7 @@ class Module { \param rst Arduino pin to be used as hardware reset for the module. */ - Module(int16_t cs, int16_t irq, int16_t rst); + Module(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst); /*! \brief Extended SPI-based module constructor. Will use the default SPI interface automatically initialize it. @@ -57,7 +57,7 @@ class Module { \param gpio Arduino pin to be used as additional interrupt/GPIO. */ - Module(int16_t cs, int16_t irq, int16_t rst, int16_t gpio); + Module(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE gpio); /*! \brief SPI-based module constructor. @@ -72,7 +72,7 @@ class Module { \param spiSettings SPI interface settings. */ - Module(int16_t cs, int16_t irq, int16_t rst, SPIClass& spi, SPISettings spiSettings); + Module(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, SPIClass& spi, SPISettings spiSettings); /*! \brief Extended SPI-based module constructor. @@ -89,7 +89,7 @@ class Module { \param spiSettings SPI interface settings. */ - Module(int16_t cs, int16_t irq, int16_t rst, int16_t gpio, SPIClass& spi, SPISettings spiSettings); + Module(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE gpio, SPIClass& spi, SPISettings spiSettings); /*! \brief Generic module constructor. @@ -111,9 +111,9 @@ class Module { \param serial HardwareSerial to be used on ESP32 and SAMD. Defaults to 1 */ #ifdef RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED - Module(int16_t cs, int16_t irq, int16_t rst, int16_t rx, int16_t tx, SPIClass& spi = SPI, SPISettings spiSettings = SPISettings(2000000, MSBFIRST, SPI_MODE0), HardwareSerial* serial = &Serial1); + Module(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE rx, RADIOLIB_PIN_TYPE tx, SPIClass& spi = SPI, SPISettings spiSettings = SPISettings(2000000, MSBFIRST, SPI_MODE0), HardwareSerial* serial = &RADIOLIB_HARDWARE_SERIAL_PORT); #else - Module(int16_t cs, int16_t irq, int16_t rst, int16_t rx, int16_t tx, SPIClass& spi = SPI, SPISettings spiSettings = SPISettings(2000000, MSBFIRST, SPI_MODE0), HardwareSerial* serial = nullptr); + Module(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE rx, RADIOLIB_PIN_TYPE tx, SPIClass& spi = SPI, SPISettings spiSettings = SPISettings(2000000, MSBFIRST, SPI_MODE0), HardwareSerial* serial = nullptr); #endif @@ -290,42 +290,42 @@ class Module { \returns Pin number of SPI chip select configured in the constructor. */ - int16_t getCs() const { return(_cs); } + RADIOLIB_PIN_TYPE getCs() const { return(_cs); } /*! \brief Access method to get the pin number of interrupt/GPIO. \returns Pin number of interrupt/GPIO configured in the constructor. */ - int16_t getIrq() const { return(_irq); } + RADIOLIB_PIN_TYPE getIrq() const { return(_irq); } /*! \brief Access method to get the pin number of hardware reset pin. \returns Pin number of hardware reset pin configured in the constructor. */ - int16_t getRst() const { return(_rst); } + RADIOLIB_PIN_TYPE getRst() const { return(_rst); } /*! \brief Access method to get the pin number of second interrupt/GPIO. \returns Pin number of second interrupt/GPIO configured in the constructor. */ - int16_t getGpio() const { return(_rx); } + RADIOLIB_PIN_TYPE getGpio() const { return(_rx); } /*! \brief Access method to get the pin number of UART Rx. \returns Pin number of UART Rx configured in the constructor. */ - int16_t getRx() const { return(_rx); } + RADIOLIB_PIN_TYPE getRx() const { return(_rx); } /*! \brief Access method to get the pin number of UART Rx. \returns Pin number of UART Rx configured in the constructor. */ - int16_t getTx() const { return(_tx); } + RADIOLIB_PIN_TYPE getTx() const { return(_tx); } /*! \brief Access method to get the SPI interface. @@ -342,31 +342,40 @@ class Module { SPISettings getSpiSettings() const { return(_spiSettings); } /*! - \brief Arduino core pinMode override that checks -1 as alias for unused pin. + \brief Arduino core pinMode override that checks RADIOLIB_NC as alias for unused pin. \param pin Pin to change the mode of. \param mode Which mode to set. */ - static void pinMode(int16_t pin, uint8_t mode); + static void pinMode(RADIOLIB_PIN_TYPE pin, RADIOLIB_PIN_MODE mode); /*! - \brief Arduino core digitalWrite override that checks -1 as alias for unused pin. + \brief Arduino core digitalWrite override that checks RADIOLIB_NC as alias for unused pin. \param pin Pin to write to. \param value Whether to set the pin high or low. */ - static void digitalWrite(int16_t pin, uint8_t value); + static void digitalWrite(RADIOLIB_PIN_TYPE pin, RADIOLIB_PIN_STATUS value); + + /*! + \brief Arduino core digitalWrite override that checks RADIOLIB_NC as alias for unused pin. + + \param pin Pin to read from. + + \returns Pin value. + */ + static RADIOLIB_PIN_STATUS digitalRead(RADIOLIB_PIN_TYPE pin); #ifndef RADIOLIB_GODMODE private: #endif - int16_t _cs; - int16_t _tx; - int16_t _rx; - int16_t _irq; - int16_t _rst; + RADIOLIB_PIN_TYPE _cs; + RADIOLIB_PIN_TYPE _tx; + RADIOLIB_PIN_TYPE _rx; + RADIOLIB_PIN_TYPE _irq; + RADIOLIB_PIN_TYPE _rst; bool _initInterface; SPIClass* _spi; diff --git a/src/TypeDef.h b/src/TypeDef.h index adc3b1eb..08c58f6e 100644 --- a/src/TypeDef.h +++ b/src/TypeDef.h @@ -7,6 +7,123 @@ #error "Unsupported Arduino version (< 1.0.0)" #endif +/* + * Platform-specific configuration. + * + * RADIOLIB_PIN_TYPE - which type should be used for pin numbers in functions like digitalRead(). + * RADIOLIB_PIN_MODE - which type should be used for pin modes in functions like pinMode(). + * RADIOLIB_PIN_STATUS - which type should be used for pin values in functions like digitalWrite(). + * RADIOLIB_NC - alias for unused pin, usually the largest possible value of RADIOLIB_PIN_TYPE. + * RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED - defined if the specific platfrom does not support SoftwareSerial. + * RADIOLIB_HARDWARE_SERIAL_PORT - which hardware serial port should be used on platfroms taht do not have SoftwareSerial support. + * + * In addition, some platforms amy require RadioLib to disable spceific drivers (such as ESP8266). + */ +#if defined(__AVR__) && !(defined(ARDUINO_AVR_UNO_WIFI_REV2) || defined(ARDUINO_AVR_NANO_EVERY)) + // Arduino AVR boards (except for megaAVR) - Uno, Mega etc. + #define RADIOLIB_PIN_TYPE uint8_t + #define RADIOLIB_PIN_MODE uint8_t + #define RADIOLIB_PIN_STATUS uint8_t + #define RADIOLIB_NC (0xFF) + +#elif defined(ESP8266) + // ESP8266 boards + #define RADIOLIB_PIN_TYPE uint8_t + #define RADIOLIB_PIN_MODE uint8_t + #define RADIOLIB_PIN_STATUS uint8_t + #define RADIOLIB_NC (0xFF) + + // RadioLib has ESPS8266 driver, this must be disabled to use ESP8266 as platform + #define _RADIOLIB_ESP8266_H + +#elif defined(ESP32) + // ESP32 boards + #define RADIOLIB_PIN_TYPE uint8_t + #define RADIOLIB_PIN_MODE uint8_t + #define RADIOLIB_PIN_STATUS uint8_t + #define RADIOLIB_NC (0xFF) + #define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED + #define RADIOLIB_HARDWARE_SERIAL_PORT Serial1 + +#elif defined(ARDUINO_ARCH_STM32) + // STM32duino boards + #define RADIOLIB_PIN_TYPE uint32_t + #define RADIOLIB_PIN_MODE uint32_t + #define RADIOLIB_PIN_STATUS uint32_t + #define RADIOLIB_NC (0xFFFFFFFF) + #define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED + #define RADIOLIB_HARDWARE_SERIAL_PORT Serial1 + +#elif defined(SAMD_SERIES) + // Arduino SAMD boards - Zero, MKR, etc. + #define RADIOLIB_PIN_TYPE uint32_t + #define RADIOLIB_PIN_MODE uint32_t + #define RADIOLIB_PIN_STATUS uint32_t + #define RADIOLIB_NC (0xFFFFFFFF) + #define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED + #define RADIOLIB_HARDWARE_SERIAL_PORT Serial1 + +#elif defined(__SAM3X8E__) + // Arduino Due + #define RADIOLIB_PIN_TYPE uint32_t + #define RADIOLIB_PIN_MODE uint32_t + #define RADIOLIB_PIN_STATUS uint32_t + #define RADIOLIB_NC (0xFFFFFFFF) + #define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED + #define RADIOLIB_HARDWARE_SERIAL_PORT Serial1 + +#elif (defined(NRF52832_XXAA) || defined(NRF52840_XXAA)) && !defined(ARDUINO_ARDUINO_NANO33BLE) + // Adafruit nRF52 boards + #define RADIOLIB_PIN_TYPE uint32_t + #define RADIOLIB_PIN_MODE uint32_t + #define RADIOLIB_PIN_STATUS uint32_t + #define RADIOLIB_NC (0xFFFFFFFF) + +#elif defined(ARDUINO_ARC32_TOOLS) + // Intel Curie + #define RADIOLIB_PIN_TYPE uint8_t + #define RADIOLIB_PIN_MODE uint8_t + #define RADIOLIB_PIN_STATUS uint8_t + #define RADIOLIB_NC (0xFF) + +#elif defined(ARDUINO_AVR_UNO_WIFI_REV2) || defined(ARDUINO_AVR_NANO_EVERY) + // Arduino megaAVR boards - Uno Wifi Rev.2, Nano Every + #define RADIOLIB_PIN_TYPE uint8_t + #define RADIOLIB_PIN_MODE PinMode + #define RADIOLIB_PIN_STATUS PinStatus + #define RADIOLIB_NC (0xFF) + +#elif defined(AM_PART_APOLLO3) + // Sparkfun Artemis boards + #define RADIOLIB_PIN_TYPE uint8_t + #define RADIOLIB_PIN_MODE uint8_t + #define RADIOLIB_PIN_STATUS uint8_t + #define RADIOLIB_NC (0xFF) + #define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED + #define RADIOLIB_HARDWARE_SERIAL_PORT Serial1 + +#elif defined(ARDUINO_ARDUINO_NANO33BLE) + // Arduino Nano 33 BLE + #define RADIOLIB_PIN_TYPE pin_size_t + #define RADIOLIB_PIN_MODE PinMode + #define RADIOLIB_PIN_STATUS PinStatus + #define RADIOLIB_NC (0xFF) + #define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED + #define RADIOLIB_HARDWARE_SERIAL_PORT Serial1 + + // Nano 33 BLE uses mbed libraries, which already contain ESP8266 driver + #define _RADIOLIB_ESP8266_H + +#else + // other platforms not covered by the above list - this may or may not work + #warning "RadioLib might not be compatible with this Arduino board - check supported platforms at https://github.com/jgromes/RadioLib!" + #define RADIOLIB_PIN_TYPE uint8_t + #define RADIOLIB_PIN_MODE uint8_t + #define RADIOLIB_PIN_STATUS uint8_t + #define RADIOLIB_NC (0xFF) + +#endif + // version definitions #define RADIOLIB_VERSION_MAJOR (0x03) #define RADIOLIB_VERSION_MINOR (0x04) @@ -67,20 +184,6 @@ */ //#define RADIOLIB_RADIOSHIELD -/* - * The following platforms do not support SoftwareSerial library. - */ -#if defined(ESP32) || defined(SAMD_SERIES) || defined(ARDUINO_ARCH_STM32) || defined(__SAM3X8E__) || defined(AM_PART_APOLLO3) - #define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED -#endif - -/*! - \brief Alias for unused pin, if not supplied by the Arduino core. -*/ -#if !(defined(NC) || defined(ARDUINO_ARCH_STM32)) -#define NC (-1) -#endif - /*! \brief A simple assert macro, will return on error. */ diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index f8e2aa1e..823b6b27 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -179,7 +179,7 @@ int16_t CC1101::packetMode() { return(state); } -void CC1101::setGdo0Action(void (*func)(void), uint8_t dir) { +void CC1101::setGdo0Action(void (*func)(void), RADIOLIB_PIN_STATUS dir) { attachInterrupt(digitalPinToInterrupt(_mod->getIrq()), func, dir); } @@ -187,8 +187,8 @@ void CC1101::clearGdo0Action() { detachInterrupt(digitalPinToInterrupt(_mod->getIrq())); } -void CC1101::setGdo2Action(void (*func)(void), uint8_t dir) { - if(_mod->getGpio() != NC) { +void CC1101::setGdo2Action(void (*func)(void), RADIOLIB_PIN_STATUS dir) { + if(_mod->getGpio() != RADIOLIB_NC) { return; } Module::pinMode(_mod->getGpio(), INPUT); @@ -196,7 +196,7 @@ void CC1101::setGdo2Action(void (*func)(void), uint8_t dir) { } void CC1101::clearGdo2Action() { - if(_mod->getGpio() != NC) { + if(_mod->getGpio() != RADIOLIB_NC) { return; } detachInterrupt(digitalPinToInterrupt(_mod->getGpio())); diff --git a/src/modules/CC1101/CC1101.h b/src/modules/CC1101/CC1101.h index 2486647f..c1969d27 100644 --- a/src/modules/CC1101/CC1101.h +++ b/src/modules/CC1101/CC1101.h @@ -600,7 +600,7 @@ class CC1101: public PhysicalLayer { \param dir Signal change direction. Defaults to FALLING. */ - void setGdo0Action(void (*func)(void), uint8_t dir = FALLING); + void setGdo0Action(void (*func)(void), RADIOLIB_PIN_STATUS dir = FALLING); /*! \brief Clears interrupt service routine to call when GDO0 activates. @@ -614,7 +614,7 @@ class CC1101: public PhysicalLayer { \param dir Signal change direction. Defaults to FALLING. */ - void setGdo2Action(void (*func)(void), uint8_t dir = FALLING); + void setGdo2Action(void (*func)(void), RADIOLIB_PIN_STATUS dir = FALLING); /*! \brief Clears interrupt service routine to call when GDO0 activates. diff --git a/src/modules/RF69/RF69.cpp b/src/modules/RF69/RF69.cpp index 69dc4351..2ef86d4e 100644 --- a/src/modules/RF69/RF69.cpp +++ b/src/modules/RF69/RF69.cpp @@ -251,7 +251,7 @@ void RF69::clearDio0Action() { } void RF69::setDio1Action(void (*func)(void)) { - if(_mod->getGpio() != NC) { + if(_mod->getGpio() != RADIOLIB_NC) { return; } Module::pinMode(_mod->getGpio(), INPUT); @@ -259,7 +259,7 @@ void RF69::setDio1Action(void (*func)(void)) { } void RF69::clearDio1Action() { - if(_mod->getGpio() != NC) { + if(_mod->getGpio() != RADIOLIB_NC) { return; } detachInterrupt(digitalPinToInterrupt(_mod->getGpio())); diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index b8b01dbc..5eab0195 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -376,14 +376,14 @@ void SX127x::clearDio0Action() { } void SX127x::setDio1Action(void (*func)(void)) { - if(_mod->getGpio() != NC) { + if(_mod->getGpio() != RADIOLIB_NC) { return; } attachInterrupt(digitalPinToInterrupt(_mod->getGpio()), func, RISING); } void SX127x::clearDio1Action() { - if(_mod->getGpio() != NC) { + if(_mod->getGpio() != RADIOLIB_NC) { return; } detachInterrupt(digitalPinToInterrupt(_mod->getGpio())); From c9785f30b2b3d421b795dbbe82ca24b7fffe43ae Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 27 Mar 2020 14:11:13 +0100 Subject: [PATCH 15/57] Renamed NC macro --- .../CC1101/CC1101_Receive/CC1101_Receive.ino | 2 +- .../CC1101_Receive_Address.ino | 2 +- .../CC1101_Receive_Interrupt.ino | 17 ++++++++++------- .../CC1101/CC1101_Settings/CC1101_Settings.ino | 4 ++-- .../CC1101/CC1101_Transmit/CC1101_Transmit.ino | 2 +- .../CC1101_Transmit_Address.ino | 2 +- .../CC1101_Transmit_Interrupt.ino | 2 +- keywords.txt | 2 +- 8 files changed, 18 insertions(+), 15 deletions(-) diff --git a/examples/CC1101/CC1101_Receive/CC1101_Receive.ino b/examples/CC1101/CC1101_Receive/CC1101_Receive.ino index e36c1d9a..fa8f3aa8 100644 --- a/examples/CC1101/CC1101_Receive/CC1101_Receive.ino +++ b/examples/CC1101/CC1101_Receive/CC1101_Receive.ino @@ -21,7 +21,7 @@ // GDO0 pin: 2 // RST pin: unused // GDO2 pin: 3 (optional) -CC1101 cc = new Module(10, 2, NC, 3); +CC1101 cc = new Module(10, 2, RADIOLIB_NC, 3); // or using RadioShield // https://github.com/jgromes/RadioShield diff --git a/examples/CC1101/CC1101_Receive_Address/CC1101_Receive_Address.ino b/examples/CC1101/CC1101_Receive_Address/CC1101_Receive_Address.ino index 4cbd10f2..3e12b6d5 100644 --- a/examples/CC1101/CC1101_Receive_Address/CC1101_Receive_Address.ino +++ b/examples/CC1101/CC1101_Receive_Address/CC1101_Receive_Address.ino @@ -19,7 +19,7 @@ // GDO0 pin: 2 // RST pin: unused // GDO2 pin: 3 (optional) -CC1101 cc = new Module(10, 2, NC, 3); +CC1101 cc = new Module(10, 2, RADIOLIB_NC, 3); // or using RadioShield // https://github.com/jgromes/RadioShield diff --git a/examples/CC1101/CC1101_Receive_Interrupt/CC1101_Receive_Interrupt.ino b/examples/CC1101/CC1101_Receive_Interrupt/CC1101_Receive_Interrupt.ino index 46f3279d..b57c4102 100644 --- a/examples/CC1101/CC1101_Receive_Interrupt/CC1101_Receive_Interrupt.ino +++ b/examples/CC1101/CC1101_Receive_Interrupt/CC1101_Receive_Interrupt.ino @@ -24,7 +24,7 @@ // GDO0 pin: 2 // RST pin: unused // GDO2 pin: 3 (optional) -CC1101 cc = new Module(10, 2, NC, 3); +CC1101 cc = new Module(5, 2, RADIOLIB_NC, 3); // or using RadioShield // https://github.com/jgromes/RadioShield @@ -105,22 +105,25 @@ void loop() { receivedFlag = false; // you can read received data as an Arduino String - String str; - int state = cc.readData(str); + //String str; + //int state = cc.readData(str); // you can also read received data as byte array - /* + byte byteArr[8]; int state = cc.readData(byteArr, 8); - */ + if (state == ERR_NONE) { // packet was successfully received Serial.println(F("[CC1101] Received packet!")); // print data of the packet - Serial.print(F("[CC1101] Data:\t\t")); - Serial.println(str); + Serial.println(F("[CC1101] Data:\t\t")); + //Serial.println(str); + for(uint8_t i = 0; i < 8; i++) { + Serial.println(byteArr[i], HEX); + } // print RSSI (Received Signal Strength Indicator) // of the last received packet diff --git a/examples/CC1101/CC1101_Settings/CC1101_Settings.ino b/examples/CC1101/CC1101_Settings/CC1101_Settings.ino index 74b2b3b1..02394da1 100644 --- a/examples/CC1101/CC1101_Settings/CC1101_Settings.ino +++ b/examples/CC1101/CC1101_Settings/CC1101_Settings.ino @@ -23,14 +23,14 @@ // GDO0 pin: 2 // RST pin: unused // GDO2 pin: 3 (optional) -CC1101 cc1 = new Module(10, 2, NC, 3); +CC1101 cc1 = new Module(10, 2, RADIOLIB_NC, 3); // second CC1101 has different connections: // CS pin: 9 // GDO0 pin: 4 // RST pin: unused // GDO2 pin: 5 (optional) -CC1101 cc2 = new Module(9, 4, NC, 53); +CC1101 cc2 = new Module(9, 4, RADIOLIB_NC, 53); // or using RadioShield // https://github.com/jgromes/RadioShield diff --git a/examples/CC1101/CC1101_Transmit/CC1101_Transmit.ino b/examples/CC1101/CC1101_Transmit/CC1101_Transmit.ino index 104fe2bb..be530890 100644 --- a/examples/CC1101/CC1101_Transmit/CC1101_Transmit.ino +++ b/examples/CC1101/CC1101_Transmit/CC1101_Transmit.ino @@ -19,7 +19,7 @@ // GDO0 pin: 2 // RST pin: unused // GDO2 pin: 3 (optional) -CC1101 cc = new Module(10, 2, NC, 3); +CC1101 cc = new Module(10, 2, RADIOLIB_NC, 3); // or using RadioShield // https://github.com/jgromes/RadioShield diff --git a/examples/CC1101/CC1101_Transmit_Address/CC1101_Transmit_Address.ino b/examples/CC1101/CC1101_Transmit_Address/CC1101_Transmit_Address.ino index 94905bad..e584eb7c 100644 --- a/examples/CC1101/CC1101_Transmit_Address/CC1101_Transmit_Address.ino +++ b/examples/CC1101/CC1101_Transmit_Address/CC1101_Transmit_Address.ino @@ -19,7 +19,7 @@ // GDO0 pin: 2 // RST pin: unused // GDO2 pin: 3 (optional) -CC1101 cc = new Module(10, 2, NC, 3); +CC1101 cc = new Module(10, 2, RADIOLIB_NC, 3); // or using RadioShield // https://github.com/jgromes/RadioShield diff --git a/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino b/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino index a89cf0ca..47991677 100644 --- a/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino +++ b/examples/CC1101/CC1101_Transmit_Interrupt/CC1101_Transmit_Interrupt.ino @@ -20,7 +20,7 @@ // GDO0 pin: 2 // RST pin: unused // GDO2 pin: 3 (optional) -CC1101 cc = new Module(10, 2, NC, 3); +CC1101 cc = new Module(10, 2, RADIOLIB_NC, 3); // or using RadioShield // https://github.com/jgromes/RadioShield diff --git a/keywords.txt b/keywords.txt index 10f66074..a5ba3b5a 100644 --- a/keywords.txt +++ b/keywords.txt @@ -188,7 +188,7 @@ sendFrame KEYWORD2 # Constants (LITERAL1) ####################################### -NC LITERAL1 +RADIOLIB_NC LITERAL1 RADIOLIB_VERSION LITERAL1 ERR_NONE LITERAL1 From d8816f7bad90102511df6b7bb5d81dedbcf355a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Grome=C5=A1?= Date: Fri, 27 Mar 2020 14:39:45 +0100 Subject: [PATCH 16/57] Update README.md --- README.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index b3980dee..dce4e29a 100644 --- a/README.md +++ b/README.md @@ -32,16 +32,17 @@ RadioLib was originally created as a driver for [__RadioShield__](https://github * __AX.25__ for modules: SX127x, RFM9x, SX126x, RF69, SX1231 and CC1101 ### Supported platforms: -* __AVR__ - tested with hardware on Uno, Mega and Leonardo +* __Arduino AVR__ - tested with hardware on Uno, Mega and Leonardo * __ESP8266__ - tested with hardware on NodeMCU and Wemos D1 * __ESP32__ - tested with hardware on ESP-WROOM-32 * __STM32__ - tested with hardware on Nucleo L452RE-P -* __SAMD__ - Arduino Zero, Arduino MKR boards, M0 Pro etc. -* __SAM__ - Arduino Due -* __nRF52__ - Adafruit Bluefruit Feather etc. +* __Arduino SAMD__ - Arduino Zero, Arduino MKR boards, M0 Pro etc. +* __Arduino SAM__ - Arduino Due +* __Adafruit nRF52__ - Adafruit Bluefruit Feather etc. * _Intel Curie_ - Arduino 101 -* _megaAVR_ - Arduino Uno WiFi Rev.2 etc. +* _Arduino megaAVR_ - Arduino Uno WiFi Rev.2 etc. * _Apollo3_ - SparkFun Artemis Redboard etc. +* _Arduino nRF52__ - Arduino Nano 33 BLE The list above is by no means exhaustive. Most of RadioLib code is independent of the used platform, so as long as your board is running some Arduino-compatible core, RadioLib should work. Compilation of all examples is tested for all platoforms in __bold__ on each git push. Platforms in _italic_ are not tested on each push, but do compile and should be working. From 035693fc11b613458735826c583b485f7d1e8579 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Grome=C5=A1?= Date: Fri, 27 Mar 2020 14:40:20 +0100 Subject: [PATCH 17/57] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index dce4e29a..61bf5c97 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ RadioLib was originally created as a driver for [__RadioShield__](https://github * _Intel Curie_ - Arduino 101 * _Arduino megaAVR_ - Arduino Uno WiFi Rev.2 etc. * _Apollo3_ - SparkFun Artemis Redboard etc. -* _Arduino nRF52__ - Arduino Nano 33 BLE +* _Arduino nRF52_ - Arduino Nano 33 BLE The list above is by no means exhaustive. Most of RadioLib code is independent of the used platform, so as long as your board is running some Arduino-compatible core, RadioLib should work. Compilation of all examples is tested for all platoforms in __bold__ on each git push. Platforms in _italic_ are not tested on each push, but do compile and should be working. From 512567b9f31de764266679464b827646bf81da72 Mon Sep 17 00:00:00 2001 From: jgromes Date: Fri, 27 Mar 2020 21:03:23 +0100 Subject: [PATCH 18/57] Fixed typos --- src/RadioLib.h | 5 ----- src/TypeDef.h | 6 +++--- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/src/RadioLib.h b/src/RadioLib.h index 78b0f8ae..d434a8d5 100644 --- a/src/RadioLib.h +++ b/src/RadioLib.h @@ -44,9 +44,7 @@ #endif #include "modules/CC1101/CC1101.h" -//#if !defined(ESP8266) && !defined(ARDUINO_ARDUINO_NANO33BLE) #include "modules/ESP8266/ESP8266.h" -//#endif #include "modules/HC05/HC05.h" #include "modules/JDY08/JDY08.h" #include "modules/nRF24/nRF24.h" @@ -54,7 +52,6 @@ #include "modules/RFM9x/RFM95.h" #include "modules/RFM9x/RFM96.h" #include "modules/RFM9x/RFM97.h" -//#include "modules/Si443x/Si4432.h" #include "modules/SX1231/SX1231.h" #include "modules/SX126x/SX1261.h" #include "modules/SX126x/SX1262.h" @@ -74,11 +71,9 @@ #include "protocols/RTTY/RTTY.h" // transport layer protocols -//#if !defined(ESP8266) && !defined(ARDUINO_ARDUINO_NANO33BLE) #include "protocols/TransportLayer/TransportLayer.h" #include "protocols/HTTP/HTTP.h" #include "protocols/MQTT/MQTT.h" -//#endif // only create Radio class when using RadioShield #ifdef RADIOLIB_RADIOSHIELD diff --git a/src/TypeDef.h b/src/TypeDef.h index 08c58f6e..4f4c2171 100644 --- a/src/TypeDef.h +++ b/src/TypeDef.h @@ -14,10 +14,10 @@ * RADIOLIB_PIN_MODE - which type should be used for pin modes in functions like pinMode(). * RADIOLIB_PIN_STATUS - which type should be used for pin values in functions like digitalWrite(). * RADIOLIB_NC - alias for unused pin, usually the largest possible value of RADIOLIB_PIN_TYPE. - * RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED - defined if the specific platfrom does not support SoftwareSerial. - * RADIOLIB_HARDWARE_SERIAL_PORT - which hardware serial port should be used on platfroms taht do not have SoftwareSerial support. + * RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED - defined if the specific platform does not support SoftwareSerial. + * RADIOLIB_HARDWARE_SERIAL_PORT - which hardware serial port should be used on platform that do not have SoftwareSerial support. * - * In addition, some platforms amy require RadioLib to disable spceific drivers (such as ESP8266). + * In addition, some platforms may require RadioLib to disable specific drivers (such as ESP8266). */ #if defined(__AVR__) && !(defined(ARDUINO_AVR_UNO_WIFI_REV2) || defined(ARDUINO_AVR_NANO_EVERY)) // Arduino AVR boards (except for megaAVR) - Uno, Mega etc. From 7007cd873adea87329625b09cdd3cea1390dba11 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 29 Mar 2020 10:02:23 +0200 Subject: [PATCH 19/57] Extracted build options into a new file --- src/BuildOpt.h | 198 +++++++++++++++++++++++++++++++++++++++++++++++++ src/TypeDef.h | 188 +--------------------------------------------- 2 files changed, 199 insertions(+), 187 deletions(-) create mode 100644 src/BuildOpt.h diff --git a/src/BuildOpt.h b/src/BuildOpt.h new file mode 100644 index 00000000..6e1a8690 --- /dev/null +++ b/src/BuildOpt.h @@ -0,0 +1,198 @@ +#ifndef _RADIOLIB_BUILD_OPTIONS_H +#define _RADIOLIB_BUILD_OPTIONS_H + +#if ARDUINO >= 100 + #include "Arduino.h" +#else + #error "Unsupported Arduino version (< 1.0.0)" +#endif + +/* + * Platform-specific configuration. + * + * RADIOLIB_PIN_TYPE - which type should be used for pin numbers in functions like digitalRead(). + * RADIOLIB_PIN_MODE - which type should be used for pin modes in functions like pinMode(). + * RADIOLIB_PIN_STATUS - which type should be used for pin values in functions like digitalWrite(). + * RADIOLIB_NC - alias for unused pin, usually the largest possible value of RADIOLIB_PIN_TYPE. + * RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED - defined if the specific platform does not support SoftwareSerial. + * RADIOLIB_HARDWARE_SERIAL_PORT - which hardware serial port should be used on platform that do not have SoftwareSerial support. + * + * In addition, some platforms may require RadioLib to disable specific drivers (such as ESP8266). + */ +#if defined(__AVR__) && !(defined(ARDUINO_AVR_UNO_WIFI_REV2) || defined(ARDUINO_AVR_NANO_EVERY)) + // Arduino AVR boards (except for megaAVR) - Uno, Mega etc. + #define RADIOLIB_PIN_TYPE uint8_t + #define RADIOLIB_PIN_MODE uint8_t + #define RADIOLIB_PIN_STATUS uint8_t + #define RADIOLIB_NC (0xFF) + +#elif defined(ESP8266) + // ESP8266 boards + #define RADIOLIB_PIN_TYPE uint8_t + #define RADIOLIB_PIN_MODE uint8_t + #define RADIOLIB_PIN_STATUS uint8_t + #define RADIOLIB_NC (0xFF) + + // RadioLib has ESPS8266 driver, this must be disabled to use ESP8266 as platform + #define _RADIOLIB_ESP8266_H + +#elif defined(ESP32) + // ESP32 boards + #define RADIOLIB_PIN_TYPE uint8_t + #define RADIOLIB_PIN_MODE uint8_t + #define RADIOLIB_PIN_STATUS uint8_t + #define RADIOLIB_NC (0xFF) + #define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED + #define RADIOLIB_HARDWARE_SERIAL_PORT Serial1 + +#elif defined(ARDUINO_ARCH_STM32) + // STM32duino boards + #define RADIOLIB_PIN_TYPE uint32_t + #define RADIOLIB_PIN_MODE uint32_t + #define RADIOLIB_PIN_STATUS uint32_t + #define RADIOLIB_NC (0xFFFFFFFF) + #define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED + #define RADIOLIB_HARDWARE_SERIAL_PORT Serial1 + +#elif defined(SAMD_SERIES) + // Arduino SAMD boards - Zero, MKR, etc. + #define RADIOLIB_PIN_TYPE uint32_t + #define RADIOLIB_PIN_MODE uint32_t + #define RADIOLIB_PIN_STATUS uint32_t + #define RADIOLIB_NC (0xFFFFFFFF) + #define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED + #define RADIOLIB_HARDWARE_SERIAL_PORT Serial1 + +#elif defined(__SAM3X8E__) + // Arduino Due + #define RADIOLIB_PIN_TYPE uint32_t + #define RADIOLIB_PIN_MODE uint32_t + #define RADIOLIB_PIN_STATUS uint32_t + #define RADIOLIB_NC (0xFFFFFFFF) + #define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED + #define RADIOLIB_HARDWARE_SERIAL_PORT Serial1 + +#elif (defined(NRF52832_XXAA) || defined(NRF52840_XXAA)) && !defined(ARDUINO_ARDUINO_NANO33BLE) + // Adafruit nRF52 boards + #define RADIOLIB_PIN_TYPE uint32_t + #define RADIOLIB_PIN_MODE uint32_t + #define RADIOLIB_PIN_STATUS uint32_t + #define RADIOLIB_NC (0xFFFFFFFF) + +#elif defined(ARDUINO_ARC32_TOOLS) + // Intel Curie + #define RADIOLIB_PIN_TYPE uint8_t + #define RADIOLIB_PIN_MODE uint8_t + #define RADIOLIB_PIN_STATUS uint8_t + #define RADIOLIB_NC (0xFF) + +#elif defined(ARDUINO_AVR_UNO_WIFI_REV2) || defined(ARDUINO_AVR_NANO_EVERY) + // Arduino megaAVR boards - Uno Wifi Rev.2, Nano Every + #define RADIOLIB_PIN_TYPE uint8_t + #define RADIOLIB_PIN_MODE PinMode + #define RADIOLIB_PIN_STATUS PinStatus + #define RADIOLIB_NC (0xFF) + +#elif defined(AM_PART_APOLLO3) + // Sparkfun Artemis boards + #define RADIOLIB_PIN_TYPE uint8_t + #define RADIOLIB_PIN_MODE uint8_t + #define RADIOLIB_PIN_STATUS uint8_t + #define RADIOLIB_NC (0xFF) + #define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED + #define RADIOLIB_HARDWARE_SERIAL_PORT Serial1 + +#elif defined(ARDUINO_ARDUINO_NANO33BLE) + // Arduino Nano 33 BLE + #define RADIOLIB_PIN_TYPE pin_size_t + #define RADIOLIB_PIN_MODE PinMode + #define RADIOLIB_PIN_STATUS PinStatus + #define RADIOLIB_NC (0xFF) + #define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED + #define RADIOLIB_HARDWARE_SERIAL_PORT Serial1 + + // Nano 33 BLE uses mbed libraries, which already contain ESP8266 driver + #define _RADIOLIB_ESP8266_H + +#else + // other platforms not covered by the above list - this may or may not work + #warning "RadioLib might not be compatible with this Arduino board - check supported platforms at https://github.com/jgromes/RadioLib!" + #define RADIOLIB_PIN_TYPE uint8_t + #define RADIOLIB_PIN_MODE uint8_t + #define RADIOLIB_PIN_STATUS uint8_t + #define RADIOLIB_NC (0xFF) + +#endif + +/* + * Uncomment to enable debug output. + * Warning: Debug output will slow down the whole system significantly. + * Also, it will result in larger compiled binary. + * Levels: debug - only main info + * verbose - full transcript of all SPI/UART communication + */ + +//#define RADIOLIB_DEBUG +//#define RADIOLIB_VERBOSE + +// set which Serial port should be used for debug output +#define RADIOLIB_DEBUG_PORT Serial + +#ifdef RADIOLIB_DEBUG + #define RADIOLIB_DEBUG_PRINT(...) { RADIOLIB_DEBUG_PORT.print(__VA_ARGS__); } + #define RADIOLIB_DEBUG_PRINTLN(...) { RADIOLIB_DEBUG_PORT.println(__VA_ARGS__); } +#else + #define RADIOLIB_DEBUG_PRINT(...) {} + #define RADIOLIB_DEBUG_PRINTLN(...) {} +#endif + +#ifdef RADIOLIB_VERBOSE + #define RADIOLIB_VERBOSE_PRINT(...) { RADIOLIB_DEBUG_PORT.print(__VA_ARGS__); } + #define RADIOLIB_VERBOSE_PRINTLN(...) { RADIOLIB_DEBUG_PORT.println(__VA_ARGS__); } +#else + #define RADIOLIB_VERBOSE_PRINT(...) {} + #define RADIOLIB_VERBOSE_PRINTLN(...) {} +#endif + +/* + * Uncomment to enable god mode - all methods and member variables in all classes will be made public, thus making them accessible from Arduino code. + * Warning: Come on, it's called GOD mode - obviously only use this if you know what you're doing. + * Failure to heed the above warning may result in bricked module. + */ +//#define RADIOLIB_GODMODE + +/* + * Uncomment to enable pre-defined modules when using RadioShield. + */ +//#define RADIOLIB_RADIOSHIELD + +/* + * Uncomment to enable static-only memory management: no dynamic allocation will be performed. + * Warning: Large static arrays will be created in some methods. It is not advised to send large packets in this mode. + */ + +//#define RADIOLIB_STATIC_ONLY + +// set the size of static arrays to use +#define RADIOLIB_STATIC_ARRAY_SIZE 256 + +/*! + \brief A simple assert macro, will return on error. +*/ +#define RADIOLIB_ASSERT(STATEVAR) { if((STATEVAR) != ERR_NONE) { return(STATEVAR); } } + +/*! + \brief Macro to check variable is within constraints - this is commonly used to check parameter ranges. +*/ +#define RADIOLIB_CHECK_CONSTRAINTS(VAR, MIN, MAX, ERR) { if(!(((VAR) >= (MIN)) && ((VAR) <= (MAX)))) { return(ERR); } } + + +// version definitions +#define RADIOLIB_VERSION_MAJOR (0x03) +#define RADIOLIB_VERSION_MINOR (0x04) +#define RADIOLIB_VERSION_PATCH (0x00) +#define RADIOLIB_VERSION_EXTRA (0x00) + +#define RADIOLIB_VERSION ((RADIOLIB_VERSION_MAJOR << 24) | (RADIOLIB_VERSION_MINOR << 16) | (RADIOLIB_VERSION_PATCH << 8) | (RADIOLIB_VERSION_EXTRA)) + +#endif diff --git a/src/TypeDef.h b/src/TypeDef.h index 4f4c2171..00ef2096 100644 --- a/src/TypeDef.h +++ b/src/TypeDef.h @@ -1,193 +1,7 @@ #ifndef _RADIOLIB_TYPES_H #define _RADIOLIB_TYPES_H -#if ARDUINO >= 100 - #include "Arduino.h" -#else - #error "Unsupported Arduino version (< 1.0.0)" -#endif - -/* - * Platform-specific configuration. - * - * RADIOLIB_PIN_TYPE - which type should be used for pin numbers in functions like digitalRead(). - * RADIOLIB_PIN_MODE - which type should be used for pin modes in functions like pinMode(). - * RADIOLIB_PIN_STATUS - which type should be used for pin values in functions like digitalWrite(). - * RADIOLIB_NC - alias for unused pin, usually the largest possible value of RADIOLIB_PIN_TYPE. - * RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED - defined if the specific platform does not support SoftwareSerial. - * RADIOLIB_HARDWARE_SERIAL_PORT - which hardware serial port should be used on platform that do not have SoftwareSerial support. - * - * In addition, some platforms may require RadioLib to disable specific drivers (such as ESP8266). - */ -#if defined(__AVR__) && !(defined(ARDUINO_AVR_UNO_WIFI_REV2) || defined(ARDUINO_AVR_NANO_EVERY)) - // Arduino AVR boards (except for megaAVR) - Uno, Mega etc. - #define RADIOLIB_PIN_TYPE uint8_t - #define RADIOLIB_PIN_MODE uint8_t - #define RADIOLIB_PIN_STATUS uint8_t - #define RADIOLIB_NC (0xFF) - -#elif defined(ESP8266) - // ESP8266 boards - #define RADIOLIB_PIN_TYPE uint8_t - #define RADIOLIB_PIN_MODE uint8_t - #define RADIOLIB_PIN_STATUS uint8_t - #define RADIOLIB_NC (0xFF) - - // RadioLib has ESPS8266 driver, this must be disabled to use ESP8266 as platform - #define _RADIOLIB_ESP8266_H - -#elif defined(ESP32) - // ESP32 boards - #define RADIOLIB_PIN_TYPE uint8_t - #define RADIOLIB_PIN_MODE uint8_t - #define RADIOLIB_PIN_STATUS uint8_t - #define RADIOLIB_NC (0xFF) - #define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED - #define RADIOLIB_HARDWARE_SERIAL_PORT Serial1 - -#elif defined(ARDUINO_ARCH_STM32) - // STM32duino boards - #define RADIOLIB_PIN_TYPE uint32_t - #define RADIOLIB_PIN_MODE uint32_t - #define RADIOLIB_PIN_STATUS uint32_t - #define RADIOLIB_NC (0xFFFFFFFF) - #define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED - #define RADIOLIB_HARDWARE_SERIAL_PORT Serial1 - -#elif defined(SAMD_SERIES) - // Arduino SAMD boards - Zero, MKR, etc. - #define RADIOLIB_PIN_TYPE uint32_t - #define RADIOLIB_PIN_MODE uint32_t - #define RADIOLIB_PIN_STATUS uint32_t - #define RADIOLIB_NC (0xFFFFFFFF) - #define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED - #define RADIOLIB_HARDWARE_SERIAL_PORT Serial1 - -#elif defined(__SAM3X8E__) - // Arduino Due - #define RADIOLIB_PIN_TYPE uint32_t - #define RADIOLIB_PIN_MODE uint32_t - #define RADIOLIB_PIN_STATUS uint32_t - #define RADIOLIB_NC (0xFFFFFFFF) - #define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED - #define RADIOLIB_HARDWARE_SERIAL_PORT Serial1 - -#elif (defined(NRF52832_XXAA) || defined(NRF52840_XXAA)) && !defined(ARDUINO_ARDUINO_NANO33BLE) - // Adafruit nRF52 boards - #define RADIOLIB_PIN_TYPE uint32_t - #define RADIOLIB_PIN_MODE uint32_t - #define RADIOLIB_PIN_STATUS uint32_t - #define RADIOLIB_NC (0xFFFFFFFF) - -#elif defined(ARDUINO_ARC32_TOOLS) - // Intel Curie - #define RADIOLIB_PIN_TYPE uint8_t - #define RADIOLIB_PIN_MODE uint8_t - #define RADIOLIB_PIN_STATUS uint8_t - #define RADIOLIB_NC (0xFF) - -#elif defined(ARDUINO_AVR_UNO_WIFI_REV2) || defined(ARDUINO_AVR_NANO_EVERY) - // Arduino megaAVR boards - Uno Wifi Rev.2, Nano Every - #define RADIOLIB_PIN_TYPE uint8_t - #define RADIOLIB_PIN_MODE PinMode - #define RADIOLIB_PIN_STATUS PinStatus - #define RADIOLIB_NC (0xFF) - -#elif defined(AM_PART_APOLLO3) - // Sparkfun Artemis boards - #define RADIOLIB_PIN_TYPE uint8_t - #define RADIOLIB_PIN_MODE uint8_t - #define RADIOLIB_PIN_STATUS uint8_t - #define RADIOLIB_NC (0xFF) - #define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED - #define RADIOLIB_HARDWARE_SERIAL_PORT Serial1 - -#elif defined(ARDUINO_ARDUINO_NANO33BLE) - // Arduino Nano 33 BLE - #define RADIOLIB_PIN_TYPE pin_size_t - #define RADIOLIB_PIN_MODE PinMode - #define RADIOLIB_PIN_STATUS PinStatus - #define RADIOLIB_NC (0xFF) - #define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED - #define RADIOLIB_HARDWARE_SERIAL_PORT Serial1 - - // Nano 33 BLE uses mbed libraries, which already contain ESP8266 driver - #define _RADIOLIB_ESP8266_H - -#else - // other platforms not covered by the above list - this may or may not work - #warning "RadioLib might not be compatible with this Arduino board - check supported platforms at https://github.com/jgromes/RadioLib!" - #define RADIOLIB_PIN_TYPE uint8_t - #define RADIOLIB_PIN_MODE uint8_t - #define RADIOLIB_PIN_STATUS uint8_t - #define RADIOLIB_NC (0xFF) - -#endif - -// version definitions -#define RADIOLIB_VERSION_MAJOR (0x03) -#define RADIOLIB_VERSION_MINOR (0x04) -#define RADIOLIB_VERSION_PATCH (0x00) -#define RADIOLIB_VERSION_EXTRA (0x00) - -#define RADIOLIB_VERSION ((RADIOLIB_VERSION_MAJOR << 24) | (RADIOLIB_VERSION_MINOR << 16) | (RADIOLIB_VERSION_PATCH << 8) | (RADIOLIB_VERSION_EXTRA)) - -/* - * Uncomment to enable static-only memory management: no dynamic allocation will be performed. - * Warning: Large static arrays will be created in some methods. It is not advised to send large packets in this mode. - */ - -//#define RADIOLIB_STATIC_ONLY - -// set the size of static arrays to use -#define RADIOLIB_STATIC_ARRAY_SIZE 256 - -/* - * Uncomment to enable debug output. - * Warning: Debug output will slow down the whole system significantly. - * Also, it will result in larger compiled binary. - * Levels: debug - only main info - * verbose - full transcript of all SPI/UART communication - */ - -//#define RADIOLIB_DEBUG -//#define RADIOLIB_VERBOSE - -// set which Serial port should be used for debug output -#define RADIOLIB_DEBUG_PORT Serial - -#ifdef RADIOLIB_DEBUG - #define RADIOLIB_DEBUG_PRINT(...) { RADIOLIB_DEBUG_PORT.print(__VA_ARGS__); } - #define RADIOLIB_DEBUG_PRINTLN(...) { RADIOLIB_DEBUG_PORT.println(__VA_ARGS__); } -#else - #define RADIOLIB_DEBUG_PRINT(...) {} - #define RADIOLIB_DEBUG_PRINTLN(...) {} -#endif - -#ifdef RADIOLIB_VERBOSE - #define RADIOLIB_VERBOSE_PRINT(...) { RADIOLIB_DEBUG_PORT.print(__VA_ARGS__); } - #define RADIOLIB_VERBOSE_PRINTLN(...) { RADIOLIB_DEBUG_PORT.println(__VA_ARGS__); } -#else - #define RADIOLIB_VERBOSE_PRINT(...) {} - #define RADIOLIB_VERBOSE_PRINTLN(...) {} -#endif - -/* - * Uncomment to enable god mode - all methods and member variables in all classes will be made public, thus making them accessible from Arduino code. - * Warning: Come on, it's called GOD mode - obviously only use this if you know what you're doing. - * Failure to heed the above warning may result in bricked module. - */ -//#define RADIOLIB_GODMODE - -/* - * Uncomment to enable pre-defined modules when using RadioShield. - */ -//#define RADIOLIB_RADIOSHIELD - -/*! - \brief A simple assert macro, will return on error. -*/ -#define RADIOLIB_ASSERT(STATEVAR) { if(STATEVAR != ERR_NONE) { return(STATEVAR); } } +#include "BuildOpt.h" /*! \defgroup shield_config Shield Configuration From 29103517408e73c71d297bf0b429f21214af36a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Grome=C5=A1?= Date: Sun, 29 Mar 2020 10:05:03 +0200 Subject: [PATCH 20/57] Update issue templates --- .github/ISSUE_TEMPLATE/bug_report.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 779c3533..49d358d7 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -11,7 +11,7 @@ assignees: '' Before submitting new issue, please check the [Wiki](https://github.com/jgromes/RadioLib/wiki) and the [API documentation](https://jgromes.github.io/RadioLib/). You might find a solution to your issue there. **Describe the bug** -A clear and concise description of what the bug is. When applicable, please include debug mode output: uncomment [debug macro definitions in TypeDef.h](https://github.com/jgromes/RadioLib/blob/master/src/TypeDef.h#L36) and post the output. +A clear and concise description of what the bug is. When applicable, please include debug mode output: uncomment [debug macro definitions in BuildOpt.h](https://github.com/jgromes/RadioLib/blob/master/src/BuildOpt.h#L135) and post the output. **To Reproduce** Minimal Arduino sketch to reproduce the behavior. Please user Markdown to style the code to make it readable (see [Markdown Cheatsheet](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet#code)). @@ -24,6 +24,6 @@ If applicable, add screenshots to help explain your problem. **Additional info (please complete):** - MCU: [e.g. Arduino Uno, ESP8266 etc.] - - Wireless module type [e.g. SX1276, ESP8266, etc.] + - Wireless module type [e.g. CC1101, SX1268, etc.] - Arduino IDE version [e.g. 1.8.5] - - Library version [e.g. 1.0.1] + - Library version [e.g. 3.0.0] From 83b713b7769d179fe8ef29787a1f1cd8469e7d23 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 30 Mar 2020 17:38:04 +0200 Subject: [PATCH 21/57] [Si443x] Added support for Si443x/RFM2x --- README.md | 10 +- .../Si443x/Si443x_Receive/Si443x_Receive.ino | 87 ++ .../Si443x_Receive_Interrupt.ino | 139 ++++ .../Si443x_Settings/Si443x_Settings.ino | 126 +++ .../Si443x_Transmit/Si443x_Transmit.ino | 87 ++ .../Si443x_Transmit_Interrupt.ino | 133 +++ keywords.txt | 6 + src/RadioLib.h | 6 + src/modules/RFM2x/RFM22.h | 16 + src/modules/RFM2x/RFM23.h | 16 + src/modules/Si443x/Si4430.cpp | 34 + src/modules/Si443x/Si4430.h | 74 ++ src/modules/Si443x/Si4431.cpp | 27 + src/modules/Si443x/Si4431.h | 65 ++ src/modules/Si443x/Si4432.cpp | 34 + src/modules/Si443x/Si4432.h | 74 ++ src/modules/Si443x/Si443x.cpp | 668 +++++++++++++++ src/modules/Si443x/Si443x.h | 786 ++++++++++++++++++ 18 files changed, 2384 insertions(+), 4 deletions(-) create mode 100644 examples/Si443x/Si443x_Receive/Si443x_Receive.ino create mode 100644 examples/Si443x/Si443x_Receive_Interrupt/Si443x_Receive_Interrupt.ino create mode 100644 examples/Si443x/Si443x_Settings/Si443x_Settings.ino create mode 100644 examples/Si443x/Si443x_Transmit/Si443x_Transmit.ino create mode 100644 examples/Si443x/Si443x_Transmit_Interrupt/Si443x_Transmit_Interrupt.ino create mode 100644 src/modules/RFM2x/RFM22.h create mode 100644 src/modules/RFM2x/RFM23.h create mode 100644 src/modules/Si443x/Si4430.cpp create mode 100644 src/modules/Si443x/Si4430.h create mode 100644 src/modules/Si443x/Si4431.cpp create mode 100644 src/modules/Si443x/Si4431.h create mode 100644 src/modules/Si443x/Si4432.cpp create mode 100644 src/modules/Si443x/Si4432.h create mode 100644 src/modules/Si443x/Si443x.cpp create mode 100644 src/modules/Si443x/Si443x.h diff --git a/README.md b/README.md index 61bf5c97..0a789d21 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,9 @@ RadioLib was originally created as a driver for [__RadioShield__](https://github * __JDY08__ BLE module * __nRF24L01__ 2.4 GHz module * __RF69__ FSK/OOK radio module +* __RFM2x__ series FSK modules (RFM22, RM23) * __RFM9x__ series LoRa modules (RFM95, RM96, RFM97, RFM98) +* __Si443x__ series FSK modules (Si4430, Si4431, Si4432) * __SX127x__ series LoRa modules (SX1272, SX1273, SX1276, SX1277, SX1278, SX1279) * __SX126x__ series LoRa modules (SX1261, SX1262, SX1268) * __SX1231__ FSK/OOK radio module @@ -27,9 +29,9 @@ RadioLib was originally created as a driver for [__RadioShield__](https://github ### Supported protocols: * __MQTT__ for modules: ESP8266 * __HTTP__ for modules: ESP8266 -* __RTTY__ for modules: SX127x, RFM9x, SX126x, RF69, SX1231, CC1101 and nRF24L01 -* __Morse Code__ for modules: SX127x, RFM9x, SX126x, RF69, SX1231, CC1101 and nRF24L01 -* __AX.25__ for modules: SX127x, RFM9x, SX126x, RF69, SX1231 and CC1101 +* __RTTY__ for modules: SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, nRF24L01, RFM2x and Si443x +* __Morse Code__ for modules: SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, nRF24L01, RFM2x and Si443x +* __AX.25__ for modules: SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, RFM2x and Si443x ### Supported platforms: * __Arduino AVR__ - tested with hardware on Uno, Mega and Leonardo @@ -44,7 +46,7 @@ RadioLib was originally created as a driver for [__RadioShield__](https://github * _Apollo3_ - SparkFun Artemis Redboard etc. * _Arduino nRF52_ - Arduino Nano 33 BLE -The list above is by no means exhaustive. Most of RadioLib code is independent of the used platform, so as long as your board is running some Arduino-compatible core, RadioLib should work. Compilation of all examples is tested for all platoforms in __bold__ on each git push. Platforms in _italic_ are not tested on each push, but do compile and should be working. +The list above is by no means exhaustive. Most of RadioLib code is independent of the used platform, so as long as your board is running some Arduino-compatible core, RadioLib should work. Compilation of all examples is tested for all platforms in __bold__ on each git push. Platforms in _italic_ are not tested on each push, but do compile and should be working. ### In development: * __SIM800C__ GSM module diff --git a/examples/Si443x/Si443x_Receive/Si443x_Receive.ino b/examples/Si443x/Si443x_Receive/Si443x_Receive.ino new file mode 100644 index 00000000..345fb8a6 --- /dev/null +++ b/examples/Si443x/Si443x_Receive/Si443x_Receive.ino @@ -0,0 +1,87 @@ +/* + RadioLib Si443x Receive Example + + This example receives packets using Si443x FSK radio module. + To successfully receive data, the following settings have to be the same + on both transmitter and receiver: + - carrier frequency + - bit rate + - frequency deviation + - sync word + + Other modules from Si443x/RFM2x family can also be used. + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// Si4432 has the following connections: +// nSEL pin: 10 +// nIRQ pin: 2 +// SDN pin: 9 +Si4432 fsk = new Module(10, 2, 9); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//Si4432 fsk = RadioShield.ModuleA; + +void setup() { + Serial.begin(9600); + + // initialize Si4432 with default settings + Serial.print(F("[Si4432] Initializing ... ")); + // carrier frequency: 434.0 MHz + // bit rate: 48.0 kbps + // frequency deviation: 50.0 kHz + // Rx bandwidth: 225.1 kHz + // output power: 11 dBm + // sync word: 0x2D 0x01 + int state = fsk.begin(); + if (state == ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } +} + +void loop() { + Serial.print(F("[Si4432] Waiting for incoming transmission ... ")); + + // you can receive data as an Arduino String + String str; + int state = fsk.receive(str); + + // you can also receive data as byte array + /* + byte byteArr[8]; + int state = rf.receive(byteArr, 8); + */ + + if (state == ERR_NONE) { + // packet was successfully received + Serial.println(F("success!")); + + // print the data of the packet + Serial.print(F("[Si4432] Data:\t\t")); + Serial.println(str); + + } else if (state == ERR_RX_TIMEOUT) { + // timeout occurred while waiting for a packet + Serial.println(F("timeout!")); + + } else if (state == ERR_CRC_MISMATCH) { + // packet was received, but is malformed + Serial.println(F("CRC error!")); + + } else { + // some other error occurred + Serial.print(F("failed, code ")); + Serial.println(state); + + } +} diff --git a/examples/Si443x/Si443x_Receive_Interrupt/Si443x_Receive_Interrupt.ino b/examples/Si443x/Si443x_Receive_Interrupt/Si443x_Receive_Interrupt.ino new file mode 100644 index 00000000..a514980e --- /dev/null +++ b/examples/Si443x/Si443x_Receive_Interrupt/Si443x_Receive_Interrupt.ino @@ -0,0 +1,139 @@ +/* + RadioLib Si443x Receive with Interrupts Example + + This example listens for FSK transmissions and tries to + receive them. Once a packet is received, an interrupt is + triggered. + + Other modules from Si443x/RFM2x family can also be used. + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// Si4432 has the following connections: +// nSEL pin: 10 +// nIRQ pin: 2 +// SDN pin: 9 +Si4432 fsk = new Module(10, 2, 9); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//Si4432 fsk = RadioShield.ModuleA; + +void setup() { + Serial.begin(9600); + + // initialize Si4432 with default settings + Serial.print(F("[Si4432] Initializing ... ")); + // carrier frequency: 434.0 MHz + // bit rate: 48.0 kbps + // frequency deviation: 50.0 kHz + // Rx bandwidth: 225.1 kHz + // output power: 11 dBm + // sync word: 0x2D 0x01 + int state = fsk.begin(); + if (state == ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // set the function that will be called + // when new packet is received + fsk.setIrqAction(setFlag); + + // start listening for packets + Serial.print(F("[Si4432] Starting to listen ... ")); + state = fsk.startReceive(); + if (state == ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // if needed, 'listen' mode can be disabled by calling + // any of the following methods: + // + // fsk.standby() + // fsk.sleep() + // fsk.transmit(); + // fsk.receive(); + // fsk.readData(); +} + +// flag to indicate that a packet was received +volatile bool receivedFlag = false; + +// disable interrupt when it's not needed +volatile bool enableInterrupt = true; + +// this function is called when a complete packet +// is received by the module +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +void setFlag(void) { + // check if the interrupt is enabled + if(!enableInterrupt) { + return; + } + + // we got a packet, set the flag + receivedFlag = true; +} + +void loop() { + // check if the flag is set + if(receivedFlag) { + // disable the interrupt service routine while + // processing the data + enableInterrupt = false; + + // reset flag + receivedFlag = false; + + // you can read received data as an Arduino String + String str; + int state = fsk.readData(str); + + // you can also read received data as byte array + /* + byte byteArr[8]; + int state = fsk.readData(byteArr, 8); + */ + + if (state == ERR_NONE) { + // packet was successfully received + Serial.println(F("[Si4432] Received packet!")); + + // print data of the packet + Serial.print(F("[Si4432] Data:\t\t\t")); + Serial.println(str); + + } else if (state == ERR_CRC_MISMATCH) { + // packet was received, but is malformed + Serial.println(F("CRC error!")); + + } else { + // some other error occurred + Serial.print(F("failed, code ")); + Serial.println(state); + + } + + // put module back to listen mode + fsk.startReceive(); + + // we're ready to receive more packets, + // enable interrupt service routine + enableInterrupt = true; + } + +} diff --git a/examples/Si443x/Si443x_Settings/Si443x_Settings.ino b/examples/Si443x/Si443x_Settings/Si443x_Settings.ino new file mode 100644 index 00000000..b3d1ab82 --- /dev/null +++ b/examples/Si443x/Si443x_Settings/Si443x_Settings.ino @@ -0,0 +1,126 @@ +/* + RadioLib Si443x Settings Example + + This example shows how to change all the properties of RF69 radio. + RadioLib currently supports the following settings: + - pins (SPI slave select, nIRQ, shutdown) + - carrier frequency + - bit rate + - receiver bandwidth + - frequency deviation + - output power during transmission + - sync word + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// Si4432 has the following connections: +// nSEL pin: 10 +// nIRQ pin: 2 +// SDN pin: 9 +Si4432 fsk1 = new Module(10, 2, 9); + +// Si4432 has the following connections: +// nSEL pin: 8 +// nIRQ pin: 3 +// SDN pin: 7 +Si4432 fsk2 = new Module(8, 3, 7); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//Si4432 fsk3 = RadioShield.ModuleB; + +void setup() { + Serial.begin(9600); + + // initialize Si4432 with default settings + Serial.print(F("[Si4432] Initializing ... ")); + // carrier frequency: 434.0 MHz + // bit rate: 48.0 kbps + // frequency deviation: 50.0 kHz + // Rx bandwidth: 225.1 kHz + // output power: 11 dBm + // sync word: 0x2D 0x01 + int state = fsk1.begin(); + if (state == ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // initialize Si4432 with non-default settings + Serial.print(F("[Si4432] Initializing ... ")); + // carrier frequency: 868.0 MHz + // bit rate: 200.0 kbps + // frequency deviation: 60.0 kHz + // Rx bandwidth: 335.5 kHz + // output power: 17 dBm + // sync word: 0x2D 0x01 + state = fsk2.begin(868.0, 200.0, 60.0, 335.5, 17); + if (state == ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // you can also change the settings at runtime + // and check if the configuration was changed successfully + + // set carrier frequency to 433.5 MHz + if (fsk1.setFrequency(433.5) == ERR_INVALID_FREQUENCY) { + Serial.println(F("[Si4432] Selected frequency is invalid for this module!")); + while (true); + } + + // set bit rate to 100.0 kbps + state = fsk1.setBitRate(100.0); + if (state == ERR_INVALID_BIT_RATE) { + Serial.println(F("[Si4432] Selected bit rate is invalid for this module!")); + while (true); + } else if (state == ERR_INVALID_BIT_RATE_BW_RATIO) { + Serial.println(F("[Si4432] Selected bit rate to bandwidth ratio is invalid!")); + Serial.println(F("[Si4432] Increase receiver bandwidth to set this bit rate.")); + while (true); + } + + // set receiver bandwidth to 284.8 kHz + state = fsk1.setRxBandwidth(284.8); + if (state == ERR_INVALID_RX_BANDWIDTH) { + Serial.println(F("[Si4432] Selected receiver bandwidth is invalid for this module!")); + while (true); + } + + // set frequency deviation to 10.0 kHz + if (fsk1.setFrequencyDeviation(10.0) == ERR_INVALID_FREQUENCY_DEVIATION) { + Serial.println(F("[Si4432] Selected frequency deviation is invalid for this module!")); + while (true); + } + + // set output power to 2 dBm + if (fsk1.setOutputPower(2) == ERR_INVALID_OUTPUT_POWER) { + Serial.println(F("[Si4432] Selected output power is invalid for this module!")); + while (true); + } + + // up to 4 bytes can be set as sync word + // set sync word to 0x01234567 + uint8_t syncWord[] = {0x01, 0x23, 0x45, 0x67}; + if (fsk1.setSyncWord(syncWord, 4) == ERR_INVALID_SYNC_WORD) { + Serial.println(F("[Si4432] Selected sync word is invalid for this module!")); + while (true); + } + + Serial.println(F("[Si4432] All settings changed successfully!")); +} + +void loop() { + // nothing here +} diff --git a/examples/Si443x/Si443x_Transmit/Si443x_Transmit.ino b/examples/Si443x/Si443x_Transmit/Si443x_Transmit.ino new file mode 100644 index 00000000..34a278da --- /dev/null +++ b/examples/Si443x/Si443x_Transmit/Si443x_Transmit.ino @@ -0,0 +1,87 @@ +/* + RadioLib Si443x Transmit Example + + This example transmits packets using Si4432 FSK radio module. + Each packet contains up to 64 bytes of data, in the form of: + - Arduino String + - null-terminated char array (C-string) + - arbitrary binary data (byte array) + + Other modules from Si443x/RFM2x family can also be used. + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// Si4432 has the following connections: +// nSEL pin: 10 +// nIRQ pin: 2 +// SDN pin: 9 +Si4432 fsk = new Module(10, 2, 9); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//Si4432 fsk = RadioShield.ModuleA; + +void setup() { + Serial.begin(9600); + + // initialize Si4432 with default settings + Serial.print(F("[Si4432] Initializing ... ")); + // carrier frequency: 434.0 MHz + // bit rate: 48.0 kbps + // frequency deviation: 50.0 kHz + // Rx bandwidth: 225.1 kHz + // output power: 11 dBm + // sync word: 0x2D 0x01 + int state = fsk.begin(); + if (state == ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } +} + +void loop() { + Serial.print(F("[Si4432] Transmitting packet ... ")); + + // you can transmit C-string or Arduino string up to + // 64 characters long + // NOTE: transmit() is a blocking method! + // See example Si443x_Transmit_Interrupt for details + // on non-blocking transmission method. + int state = fsk.transmit("Hello World!"); + + // you can also transmit byte array up to 64 bytes long + /* + byte byteArr[] = {0x01, 0x23, 0x45, 0x56, 0x78, 0xAB, 0xCD, 0xEF}; + int state = fsk.transmit(byteArr, 8); + */ + + if (state == ERR_NONE) { + // the packet was successfully transmitted + Serial.println(F(" success!")); + + } else if (state == ERR_PACKET_TOO_LONG) { + // the supplied packet was longer than 256 bytes + Serial.println(F(" too long!")); + + } else if (state == ERR_TX_TIMEOUT) { + // timeout occured while transmitting packet + Serial.println(F(" timeout!")); + + } else { + // some other error occurred + Serial.print(F("failed, code ")); + Serial.println(state); + + } + + // wait for a second before transmitting again + delay(1000); +} diff --git a/examples/Si443x/Si443x_Transmit_Interrupt/Si443x_Transmit_Interrupt.ino b/examples/Si443x/Si443x_Transmit_Interrupt/Si443x_Transmit_Interrupt.ino new file mode 100644 index 00000000..e4c56c18 --- /dev/null +++ b/examples/Si443x/Si443x_Transmit_Interrupt/Si443x_Transmit_Interrupt.ino @@ -0,0 +1,133 @@ +/* + RadioLib Si443x Transmit with Interrupts Example + + This example transmits packets using Si4432 FSK radio module. + Each packet contains up to 64 bytes of data, in the form of: + - Arduino String + - null-terminated char array (C-string) + - arbitrary binary data (byte array) + + Other modules from Si443x/RFM2x family can also be used. + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// Si4432 has the following connections: +// nSEL pin: 10 +// nIRQ pin: 2 +// SDN pin: 9 +Si4432 fsk = new Module(10, 2, 9); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//Si4432 fsk = RadioShield.ModuleA; + +// save transmission state between loops +int transmissionState = ERR_NONE; + +void setup() { + Serial.begin(9600); + + // initialize Si4432 with default settings + Serial.print(F("[Si4432] Initializing ... ")); + // carrier frequency: 434.0 MHz + // bit rate: 48.0 kbps + // frequency deviation: 50.0 kHz + // Rx bandwidth: 225.1 kHz + // output power: 11 dBm + // sync word: 0x2D 0x01 + int state = fsk.begin(); + fsk.setOutputPower(13); + if (state == ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // set the function that will be called + // when packet transmission is finished + fsk.setIrqAction(setFlag); + + // start transmitting the first packet + Serial.print(F("[Si4432] Sending first packet ... ")); + + // you can transmit C-string or Arduino string up to + // 64 characters long + transmissionState = fsk.startTransmit("Hello World!"); + + // you can also transmit byte array up to 64 bytes long + /* + byte byteArr[] = {0x01, 0x23, 0x45, 0x67, + 0x89, 0xAB, 0xCD, 0xEF}; + state = fsk.startTransmit(byteArr, 8); + */ +} + +// flag to indicate that a packet was sent +volatile bool transmittedFlag = false; + +// disable interrupt when it's not needed +volatile bool enableInterrupt = true; + +// this function is called when a complete packet +// is transmitted by the module +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +void setFlag(void) { + // check if the interrupt is enabled + if(!enableInterrupt) { + return; + } + + // we sent a packet, set the flag + transmittedFlag = true; +} + +void loop() { + // check if the previous transmission finished + if(transmittedFlag) { + // disable the interrupt service routine while + // processing the data + enableInterrupt = false; + + // reset flag + transmittedFlag = false; + + if (transmissionState == ERR_NONE) { + // packet was successfully sent + Serial.println(F("transmission finished!")); + + } else { + Serial.print(F("failed, code ")); + Serial.println(transmissionState); + + } + + // wait a second before transmitting again + delay(1000); + + // send another one + Serial.print(F("[Si4432] Sending another packet ... ")); + + // you can transmit C-string or Arduino string up to + // 256 characters long + transmissionState = fsk.startTransmit("Hello World!"); + + // you can also transmit byte array up to 64 bytes long + /* + byte byteArr[] = {0x01, 0x23, 0x45, 0x67, + 0x89, 0xAB, 0xCD, 0xEF}; + int state = fsk.startTransmit(byteArr, 8); + */ + + // we're ready to send more packets, + // enable interrupt service routine + enableInterrupt = true; + } +} diff --git a/keywords.txt b/keywords.txt index a5ba3b5a..bcf0f9fd 100644 --- a/keywords.txt +++ b/keywords.txt @@ -16,10 +16,15 @@ HC05 KEYWORD1 JDY08 KEYWORD1 nRF24 KEYWORD1 RF69 KEYWORD1 +RFM22 KEYWORD1 +RFM23 KEYWORD1 RFM95 KEYWORD1 RFM96 KEYWORD1 RFM97 KEYWORD1 RFM98 KEYWORD1 +Si4430 KEYWORD1 +Si4431 KEYWORD1 +Si4432 KEYWORD1 SIM800 KEYWORD1 SX1231 KEYWORD1 SX1261 KEYWORD1 @@ -140,6 +145,7 @@ getPacketSource KEYWORD2 getPacketData KEYWORD2 # nRF24 +setIrqAction KEYWORD2 setAddressWidth KEYWORD2 setTransmitPipe KEYWORD2 setReceivePipe KEYWORD2 diff --git a/src/RadioLib.h b/src/RadioLib.h index d434a8d5..16947fbd 100644 --- a/src/RadioLib.h +++ b/src/RadioLib.h @@ -11,6 +11,7 @@ - HC05 Bluetooth module - JDY08 BLE module - RF69 FSK module + - Si443x FSK module - SX126x LoRa/FSK module - SX127x LoRa/FSK module - SX1231 FSK module @@ -49,9 +50,14 @@ #include "modules/JDY08/JDY08.h" #include "modules/nRF24/nRF24.h" #include "modules/RF69/RF69.h" +#include "modules/RFM2x/RFM22.h" +#include "modules/RFM2x/RFM23.h" #include "modules/RFM9x/RFM95.h" #include "modules/RFM9x/RFM96.h" #include "modules/RFM9x/RFM97.h" +#include "modules/Si443x/Si4430.h" +#include "modules/Si443x/Si4431.h" +#include "modules/Si443x/Si4432.h" #include "modules/SX1231/SX1231.h" #include "modules/SX126x/SX1261.h" #include "modules/SX126x/SX1262.h" diff --git a/src/modules/RFM2x/RFM22.h b/src/modules/RFM2x/RFM22.h new file mode 100644 index 00000000..e3cd4a4d --- /dev/null +++ b/src/modules/RFM2x/RFM22.h @@ -0,0 +1,16 @@ +#ifndef _RADIOLIB_RFM22_H +#define _RADIOLIB_RFM22_H + +#include "../../TypeDef.h" +#include "../../Module.h" +#include "../Si443x/Si443x.h" +#include "../Si443x/Si4432.h" + +/*! + \class RFM22 + + \brief Only exists as alias for Si4432, since there seems to be no difference between %RFM22 and %Si4432 modules. +*/ +using RFM22 = Si4432; + +#endif diff --git a/src/modules/RFM2x/RFM23.h b/src/modules/RFM2x/RFM23.h new file mode 100644 index 00000000..4f72557d --- /dev/null +++ b/src/modules/RFM2x/RFM23.h @@ -0,0 +1,16 @@ +#ifndef _RADIOLIB_RFM23_H +#define _RADIOLIB_RFM23_H + +#include "../../TypeDef.h" +#include "../../Module.h" +#include "../Si443x/Si443x.h" +#include "../Si443x/Si4431.h" + +/*! + \class RFM23 + + \brief Only exists as alias for Si4431, since there seems to be no difference between %RFM23 and %Si4431 modules. +*/ +using RFM23 = Si4431; + +#endif diff --git a/src/modules/Si443x/Si4430.cpp b/src/modules/Si443x/Si4430.cpp new file mode 100644 index 00000000..c59f1ea7 --- /dev/null +++ b/src/modules/Si443x/Si4430.cpp @@ -0,0 +1,34 @@ +#include "Si4430.h" + +Si4430::Si4430(Module* mod) : Si4432(mod) { + +} + +int16_t Si4430::begin(float freq, float br, float freqDev, float rxBw, int8_t power) { + // execute common part + int16_t state = Si443x::begin(br, freqDev, rxBw); + RADIOLIB_ASSERT(state); + + // configure publicly accessible settings + state = setFrequency(freq); + RADIOLIB_ASSERT(state); + + state = setOutputPower(power); + RADIOLIB_ASSERT(state); + + return(state); +} + +int16_t Si4430::setFrequency(float freq) { + RADIOLIB_CHECK_RANGE(freq, 900.0, 960.0, ERR_INVALID_FREQUENCY); + + // set frequency + return(Si443x::setFrequencyRaw(freq)); +} + +int16_t Si4430::setOutputPower(int8_t power) { + RADIOLIB_CHECK_RANGE(power, -8, 13, ERR_INVALID_OUTPUT_POWER); + + // set output power + return(_mod->SPIsetRegValue(SI443X_REG_TX_POWER, (uint8_t)((power + 8) / 3), 2, 0)); +} diff --git a/src/modules/Si443x/Si4430.h b/src/modules/Si443x/Si4430.h new file mode 100644 index 00000000..7e7f8b36 --- /dev/null +++ b/src/modules/Si443x/Si4430.h @@ -0,0 +1,74 @@ +#ifndef _RADIOLIB_SI4430_H +#define _RADIOLIB_SI4430_H + +#include "../../TypeDef.h" +#include "../../Module.h" +#include "Si4432.h" + +/*! + \class Si4430 + + \brief Derived class for %Si4430 modules. +*/ +class Si4430: public Si4432 { + public: + + // constructor + + /*! + \brief Default constructor. + + \param mod Instance of Module that will be used to communicate with the radio chip. + */ + Si4430(Module* mod); + + // basic methods + + /*! + \brief Initialization method. Must be called at least once from Arduino sketch to initialize the module. + + \param freq Carrier frequency in MHz. Allowed values range from 900.0 MHz to 960.0 MHz. + + \param br Bit rate of the FSK transmission in kbps (kilobits per second). Allowed values range from 0.123 to 256.0 kbps. + + \param freqDev Frequency deviation of the FSK transmission in kHz. Allowed values range from 0.625 to 320.0 kbps. + + \param rxBw Receiver bandwidth in kHz. Allowed values range from 2.6 to 620.7 kHz. + + \param power Transmission output power in dBm. Allowed values range from -8 to 13 dBm in 3 dBm steps. + + \returns \ref status_codes + */ + int16_t begin(float freq = 434.0, float br = 48.0, float freqDev = 50.0, float rxBw = 181.1, int8_t power = 10); + + // configuration methods + + /*! + \brief Sets carrier frequency. Allowed values range from 900.0 MHz to 960.0 MHz. + + \param freq Carrier frequency to be set in MHz. + + \returns \ref status_codes + */ + int16_t setFrequency(float freq); + + /*! + \brief Sets output power. Allowed values range from -8 to 13 dBm in 3 dBm steps. + + \param power Output power to be set in dBm. + + \returns \ref status_codes + */ + int16_t setOutputPower(int8_t power); + + +#ifndef RADIOLIB_GODMODE + protected: +#endif + +#ifndef RADIOLIB_GODMODE + private: +#endif +}; + +#endif diff --git a/src/modules/Si443x/Si4431.cpp b/src/modules/Si443x/Si4431.cpp new file mode 100644 index 00000000..25c7baf9 --- /dev/null +++ b/src/modules/Si443x/Si4431.cpp @@ -0,0 +1,27 @@ +#include "Si4431.h" + +Si4431::Si4431(Module* mod) : Si4432(mod) { + +} + +int16_t Si4431::begin(float freq, float br, float freqDev, float rxBw, int8_t power) { + // execute common part + int16_t state = Si443x::begin(br, freqDev, rxBw); + RADIOLIB_ASSERT(state); + + // configure publicly accessible settings + state = setFrequency(freq); + RADIOLIB_ASSERT(state); + + state = setOutputPower(power); + RADIOLIB_ASSERT(state); + + return(state); +} + +int16_t Si4431::setOutputPower(int8_t power) { + RADIOLIB_CHECK_RANGE(power, -8, 13, ERR_INVALID_OUTPUT_POWER); + + // set output power + return(_mod->SPIsetRegValue(SI443X_REG_TX_POWER, (uint8_t)((power + 8) / 3), 2, 0)); +} diff --git a/src/modules/Si443x/Si4431.h b/src/modules/Si443x/Si4431.h new file mode 100644 index 00000000..c033bcbd --- /dev/null +++ b/src/modules/Si443x/Si4431.h @@ -0,0 +1,65 @@ +#ifndef _RADIOLIB_SI4431_H +#define _RADIOLIB_SI4431_H + +#include "../../TypeDef.h" +#include "../../Module.h" +#include "Si4432.h" + +/*! + \class Si4431 + + \brief Derived class for %Si4431 modules. +*/ +class Si4431: public Si4432 { + public: + + // constructor + + /*! + \brief Default constructor. + + \param mod Instance of Module that will be used to communicate with the radio chip. + */ + Si4431(Module* mod); + + // basic methods + + /*! + \brief Initialization method. Must be called at least once from Arduino sketch to initialize the module. + + \param freq Carrier frequency in MHz. Allowed values range from 240.0 MHz to 930.0 MHz. + + \param br Bit rate of the FSK transmission in kbps (kilobits per second). Allowed values range from 0.123 to 256.0 kbps. + + \param freqDev Frequency deviation of the FSK transmission in kHz. Allowed values range from 0.625 to 320.0 kbps. + + \param rxBw Receiver bandwidth in kHz. Allowed values range from 2.6 to 620.7 kHz. + + \param power Transmission output power in dBm. Allowed values range from -8 to 13 dBm in 3 dBm steps. + + \returns \ref status_codes + */ + int16_t begin(float freq = 434.0, float br = 48.0, float freqDev = 50.0, float rxBw = 181.1, int8_t power = 10); + + // configuration methods + + /*! + \brief Sets output power. Allowed values range from -8 to 13 dBm in 3 dBm steps. + + \param power Output power to be set in dBm. + + \returns \ref status_codes + */ + int16_t setOutputPower(int8_t power); + + +#ifndef RADIOLIB_GODMODE + protected: +#endif + +#ifndef RADIOLIB_GODMODE + private: +#endif +}; + +#endif diff --git a/src/modules/Si443x/Si4432.cpp b/src/modules/Si443x/Si4432.cpp new file mode 100644 index 00000000..38d42863 --- /dev/null +++ b/src/modules/Si443x/Si4432.cpp @@ -0,0 +1,34 @@ +#include "Si4432.h" + +Si4432::Si4432(Module* mod) : Si443x(mod) { + +} + +int16_t Si4432::begin(float freq, float br, float freqDev, float rxBw, int8_t power) { + // execute common part + int16_t state = Si443x::begin(br, freqDev, rxBw); + RADIOLIB_ASSERT(state); + + // configure publicly accessible settings + state = setFrequency(freq); + RADIOLIB_ASSERT(state); + + state = setOutputPower(power); + RADIOLIB_ASSERT(state); + + return(state); +} + +int16_t Si4432::setFrequency(float freq) { + RADIOLIB_CHECK_RANGE(freq, 240.0, 930.0, ERR_INVALID_FREQUENCY); + + // set frequency + return(Si443x::setFrequencyRaw(freq)); +} + +int16_t Si4432::setOutputPower(int8_t power) { + RADIOLIB_CHECK_RANGE(power, -1, 20, ERR_INVALID_OUTPUT_POWER); + + // set output power + return(_mod->SPIsetRegValue(SI443X_REG_TX_POWER, (uint8_t)((power + 1) / 3), 2, 0)); +} diff --git a/src/modules/Si443x/Si4432.h b/src/modules/Si443x/Si4432.h new file mode 100644 index 00000000..01dd92c5 --- /dev/null +++ b/src/modules/Si443x/Si4432.h @@ -0,0 +1,74 @@ +#ifndef _RADIOLIB_SI4432_H +#define _RADIOLIB_SI4432_H + +#include "../../TypeDef.h" +#include "../../Module.h" +#include "Si443x.h" + +/*! + \class Si4432 + + \brief Derived class for %Si4432 modules. +*/ +class Si4432: public Si443x { + public: + + // constructor + + /*! + \brief Default constructor. + + \param mod Instance of Module that will be used to communicate with the radio chip. + */ + Si4432(Module* mod); + + // basic methods + + /*! + \brief Initialization method. Must be called at least once from Arduino sketch to initialize the module. + + \param freq Carrier frequency in MHz. Allowed values range from 240.0 MHz to 930.0 MHz. + + \param br Bit rate of the FSK transmission in kbps (kilobits per second). Allowed values range from 0.123 to 256.0 kbps. + + \param freqDev Frequency deviation of the FSK transmission in kHz. Allowed values range from 0.625 to 320.0 kbps. + + \param rxBw Receiver bandwidth in kHz. Allowed values range from 2.6 to 620.7 kHz. + + \param power Transmission output power in dBm. Allowed values range from -1 to 20 dBm in 3 dBm steps. + + \returns \ref status_codes + */ + int16_t begin(float freq = 434.0, float br = 48.0, float freqDev = 50.0, float rxBw = 181.1, int8_t power = 11); + + // configuration methods + + /*! + \brief Sets carrier frequency. Allowed values range from 240.0 MHz to 930.0 MHz. + + \param freq Carrier frequency to be set in MHz. + + \returns \ref status_codes + */ + int16_t setFrequency(float freq); + + /*! + \brief Sets output power. Allowed values range from -1 to 20 dBm in 3 dBm steps. + + \param power Output power to be set in dBm. + + \returns \ref status_codes + */ + int16_t setOutputPower(int8_t power); + + +#ifndef RADIOLIB_GODMODE + protected: +#endif + +#ifndef RADIOLIB_GODMODE + private: +#endif +}; + +#endif diff --git a/src/modules/Si443x/Si443x.cpp b/src/modules/Si443x/Si443x.cpp new file mode 100644 index 00000000..6cfc6ffd --- /dev/null +++ b/src/modules/Si443x/Si443x.cpp @@ -0,0 +1,668 @@ +#include "Si443x.h" + +Si443x::Si443x(Module* mod) : PhysicalLayer(SI443X_FREQUENCY_STEP_SIZE, SI443X_MAX_PACKET_LENGTH) { + _mod = mod; + + _packetLengthQueried = false; +} + +int16_t Si443x::begin(float br, float freqDev, float rxBw) { + // set module properties + _mod->init(RADIOLIB_USE_SPI); + Module::pinMode(_mod->getIrq(), INPUT); + Module::pinMode(_mod->getRst(), OUTPUT); + Module::digitalWrite(_mod->getRst(), LOW); + + // try to find the Si443x chip + if(!Si443x::findChip()) { + RADIOLIB_DEBUG_PRINTLN(F("No Si443x found!")); + _mod->term(); + return(ERR_CHIP_NOT_FOUND); + } else { + RADIOLIB_DEBUG_PRINTLN(F("Found Si443x!")); + } + + // clear POR interrupt + clearIRQFlags(); + + // configure settings not accessible by API + int16_t state = config(); + RADIOLIB_ASSERT(state); + + // configure publicly accessible settings + state = setBitRate(br); + RADIOLIB_ASSERT(state); + + state = setFrequencyDeviation(freqDev); + RADIOLIB_ASSERT(state); + + state = setRxBandwidth(rxBw); + RADIOLIB_ASSERT(state); + + uint8_t syncWord[] = {0x2D, 0x01}; + state = setSyncWord(syncWord, sizeof(syncWord)); + RADIOLIB_ASSERT(state); + + state = packetMode(); + RADIOLIB_ASSERT(state); + + state = setDataShaping(0); + RADIOLIB_ASSERT(state); + + state = setEncoding(0); + RADIOLIB_ASSERT(state); + + return(state); +} + +void Si443x::reset() { + Module::pinMode(_mod->getRst(), OUTPUT); + Module::digitalWrite(_mod->getRst(), HIGH); + delay(1); + Module::digitalWrite(_mod->getRst(), LOW); + delay(100); +} + +int16_t Si443x::transmit(uint8_t* data, size_t len, uint8_t addr) { + // calculate timeout (5ms + 500 % of expected time-on-air) + uint32_t timeout = 5000000 + (uint32_t)((((float)(len * 8)) / (_br * 1000.0)) * 5000000.0); + + // start transmission + int16_t state = startTransmit(data, len, addr); + RADIOLIB_ASSERT(state); + + // wait for transmission end or timeout + uint32_t start = micros(); + while(digitalRead(_mod->getIrq())) { + if(micros() - start > timeout) { + standby(); + clearIRQFlags(); + return(ERR_TX_TIMEOUT); + } + } + + // set mode to standby + state = standby(); + + // clear interrupt flags + clearIRQFlags(); + + return(state); +} + +int16_t Si443x::receive(uint8_t* data, size_t len) { + // calculate timeout (500 ms + 400 full 64-byte packets at current bit rate) + uint32_t timeout = 500000 + (1.0/(_br*1000.0))*(SI443X_MAX_PACKET_LENGTH*400.0); + + // start reception + int16_t state = startReceive(); + RADIOLIB_ASSERT(state); + + // wait for packet reception or timeout + uint32_t start = micros(); + while(digitalRead(_mod->getIrq())) { + if(micros() - start > timeout) { + standby(); + clearIRQFlags(); + return(ERR_RX_TIMEOUT); + } + } + + // read packet data + return(readData(data, len)); +} + +int16_t Si443x::sleep() { + // disable wakeup timer interrupt + int16_t state = _mod->SPIsetRegValue(SI443X_REG_INTERRUPT_ENABLE_1, 0x00); + RADIOLIB_ASSERT(state); + state = _mod->SPIsetRegValue(SI443X_REG_INTERRUPT_ENABLE_2, 0x00); + RADIOLIB_ASSERT(state); + + // enable wakeup timer to set mode to sleep + _mod->SPIwriteRegister(SI443X_REG_OP_FUNC_CONTROL_1, SI443X_ENABLE_WAKEUP_TIMER); + + return(state); +} + +int16_t Si443x::standby() { + return(_mod->SPIsetRegValue(SI443X_REG_OP_FUNC_CONTROL_1, SI443X_XTAL_ON, 7, 0, 10)); +} + +int16_t Si443x::transmitDirect(uint32_t frf) { + // user requested to start transmitting immediately (required for RTTY) + if(frf != 0) { + // convert the 24-bit frequency to the format accepted by the module + // TODO integers only + float newFreq = frf / 6400.0; + + // check high/low band + uint8_t bandSelect = SI443X_BAND_SELECT_LOW; + uint8_t freqBand = (newFreq / 10) - 24; + if(newFreq >= 480.0) { + bandSelect = SI443X_BAND_SELECT_HIGH; + freqBand = (newFreq / 20) - 24; + } + + // calculate register values + uint16_t freqCarrier = ((newFreq / (10 * ((bandSelect >> 5) + 1))) - freqBand - 24) * (uint32_t)64000; + + // update registers + _mod->SPIwriteRegister(SI443X_REG_FREQUENCY_BAND_SELECT, SI443X_SIDE_BAND_SELECT_LOW | bandSelect | freqBand); + _mod->SPIwriteRegister(SI443X_REG_NOM_CARRIER_FREQUENCY_1, (uint8_t)((freqCarrier & 0xFF00) >> 8)); + _mod->SPIwriteRegister(SI443X_REG_NOM_CARRIER_FREQUENCY_0, (uint8_t)(freqCarrier & 0xFF)); + + // start direct transmission + directMode(); + _mod->SPIwriteRegister(SI443X_REG_OP_FUNC_CONTROL_1, SI443X_TX_ON); + + return(ERR_NONE); + } + + // activate direct mode + int16_t state = directMode(); + RADIOLIB_ASSERT(state); + + // start transmitting + _mod->SPIwriteRegister(SI443X_REG_OP_FUNC_CONTROL_1, SI443X_TX_ON); + return(state); +} + +int16_t Si443x::receiveDirect() { + // activate direct mode + int16_t state = directMode(); + RADIOLIB_ASSERT(state); + + // start receiving + _mod->SPIwriteRegister(SI443X_REG_OP_FUNC_CONTROL_1, SI443X_RX_ON); + return(state); +} + +int16_t Si443x::packetMode() { + return(_mod->SPIsetRegValue(SI443X_REG_MODULATION_MODE_CONTROL_2, SI443X_TX_DATA_SOURCE_FIFO, 5, 4)); +} + +void Si443x::setIrqAction(void (*func)(void)) { + attachInterrupt(digitalPinToInterrupt(_mod->getIrq()), func, FALLING); +} + +void Si443x::clearIrqAction() { + detachInterrupt(digitalPinToInterrupt(_mod->getIrq())); +} + +int16_t Si443x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { + // check packet length + if(len > SI443X_MAX_PACKET_LENGTH) { + return(ERR_PACKET_TOO_LONG); + } + + // set mode to standby + int16_t state = standby(); + RADIOLIB_ASSERT(state); + + // clear Tx FIFO + _mod->SPIsetRegValue(SI443X_REG_OP_FUNC_CONTROL_2, SI443X_TX_FIFO_RESET, 0, 0); + _mod->SPIsetRegValue(SI443X_REG_OP_FUNC_CONTROL_2, SI443X_TX_FIFO_CLEAR, 0, 0); + + // set interrupt mapping + state = _mod->SPIsetRegValue(SI443X_REG_INTERRUPT_ENABLE_1, SI443X_PACKET_SENT_ENABLED); + RADIOLIB_ASSERT(state); + + // clear interrupt flags + clearIRQFlags(); + + // set packet length + // TODO variable packet length + _mod->SPIwriteRegister(SI443X_REG_TRANSMIT_PACKET_LENGTH, len); + + // TODO use header as address field? + (void)addr; + + // write packet to FIFO + _mod->SPIwriteRegisterBurst(SI443X_REG_FIFO_ACCESS, data, len); + + // set mode to transmit + _mod->SPIwriteRegister(SI443X_REG_OP_FUNC_CONTROL_1, SI443X_TX_ON); + + return(state); +} + +int16_t Si443x::startReceive() { + // set mode to standby + int16_t state = standby(); + RADIOLIB_ASSERT(state); + + // clear Rx FIFO + _mod->SPIsetRegValue(SI443X_REG_OP_FUNC_CONTROL_2, SI443X_RX_FIFO_RESET, 1, 1); + _mod->SPIsetRegValue(SI443X_REG_OP_FUNC_CONTROL_2, SI443X_RX_FIFO_CLEAR, 1, 1); + + // set interrupt mapping + state = _mod->SPIsetRegValue(SI443X_REG_INTERRUPT_ENABLE_1, SI443X_VALID_PACKET_RECEIVED_ENABLED, SI443X_CRC_ERROR_ENABLED); + RADIOLIB_ASSERT(state); + state = _mod->SPIsetRegValue(SI443X_REG_INTERRUPT_ENABLE_2, 0x00); + RADIOLIB_ASSERT(state); + + // clear interrupt flags + clearIRQFlags(); + + // set mode to receive + _mod->SPIwriteRegister(SI443X_REG_OP_FUNC_CONTROL_1, SI443X_RX_ON); + + return(state); +} + +int16_t Si443x::readData(uint8_t* data, size_t len) { + // clear interrupt flags + clearIRQFlags(); + + // get packet length + size_t length = len; + if(len == SI443X_MAX_PACKET_LENGTH) { + length = getPacketLength(); + } + + // read packet data + _mod->SPIreadRegisterBurst(SI443X_REG_FIFO_ACCESS, length, data); + + // clear internal flag so getPacketLength can return the new packet length + _packetLengthQueried = false; + + // set mode to standby + int16_t state = standby(); + RADIOLIB_ASSERT(state); + + // clear interrupt flags + clearIRQFlags(); + + return(ERR_NONE); +} + +int16_t Si443x::setBitRate(float br) { + RADIOLIB_CHECK_RANGE(br, 0.123, 256.0, ERR_INVALID_BIT_RATE); + + // check high data rate + uint8_t dataRateMode = SI443X_LOW_DATA_RATE_MODE; + uint8_t exp = 21; + if(br >= 30.0) { + // bit rate above 30 kbps + dataRateMode = SI443X_HIGH_DATA_RATE_MODE; + exp = 16; + } + + // calculate raw data rate value + uint16_t txDr = (br * ((uint32_t)1 << exp)) / 1000.0; + + // update registers + int16_t state = _mod->SPIsetRegValue(SI443X_REG_MODULATION_MODE_CONTROL_1, dataRateMode, 5, 5); + _mod->SPIwriteRegister(SI443X_REG_TX_DATA_RATE_1, (uint8_t)((txDr & 0xFF00) >> 8)); + _mod->SPIwriteRegister(SI443X_REG_TX_DATA_RATE_0, (uint8_t)(txDr & 0xFF)); + + if(state == ERR_NONE) { + _br = br; + } + RADIOLIB_ASSERT(state); + + // update clock recovery + state = updateClockRecovery(); + + return(state); +} + +int16_t Si443x::setFrequencyDeviation(float freqDev) { + // set frequency deviation to lowest available setting (required for RTTY) + if(freqDev == 0.0) { + int16_t state = _mod->SPIsetRegValue(SI443X_REG_MODULATION_MODE_CONTROL_2, 0x00, 2, 2); + _mod->SPIwriteRegister(SI443X_REG_FREQUENCY_DEVIATION, 0x00); + + if(state == ERR_NONE) { + _freqDev = freqDev; + } + + } + + RADIOLIB_CHECK_RANGE(freqDev, 0.625, 320.0, ERR_INVALID_FREQUENCY_DEVIATION); + + // calculate raw frequency deviation value + uint16_t fdev = (uint16_t)(freqDev / 0.625); + + // update registers + int16_t state = _mod->SPIsetRegValue(SI443X_REG_MODULATION_MODE_CONTROL_2, (uint8_t)((fdev & 0x0100) >> 6), 2, 2); + _mod->SPIwriteRegister(SI443X_REG_FREQUENCY_DEVIATION, (uint8_t)(fdev & 0xFF)); + + if(state == ERR_NONE) { + _freqDev = freqDev; + } + + return(state); +} + +int16_t Si443x::setRxBandwidth(float rxBw) { + RADIOLIB_CHECK_RANGE(rxBw, 2.6, 620.7, ERR_INVALID_RX_BANDWIDTH); + + // decide which approximation to use for decimation rate and filter tap calculation + uint8_t bypass = SI443X_BYPASS_DEC_BY_3_OFF; + uint8_t decRate = SI443X_IF_FILTER_DEC_RATE; + uint8_t filterSet = SI443X_IF_FILTER_COEFF_SET; + + // this is the "well-behaved" section - can be linearly approximated + if((rxBw >= 2.6) && (rxBw <= 4.5)) { + decRate = 5; + filterSet = ((rxBw - 2.1429)/0.3250 + 0.5); + } else if((rxBw > 4.5) && (rxBw <= 8.8)) { + decRate = 4; + filterSet = ((rxBw - 3.9857)/0.6643 + 0.5); + } else if((rxBw > 8.8) && (rxBw <= 17.5)) { + decRate = 3; + filterSet = ((rxBw - 7.6714)/1.3536 + 0.5); + } else if((rxBw > 17.5) && (rxBw <= 34.7)) { + decRate = 2; + filterSet = ((rxBw - 15.2000)/2.6893 + 0.5); + } else if((rxBw > 34.7) && (rxBw <= 69.2)) { + decRate = 1; + filterSet = ((rxBw - 30.2430)/5.3679 + 0.5); + } else if((rxBw > 69.2) && (rxBw <= 137.9)) { + decRate = 0; + filterSet = ((rxBw - 60.286)/10.7000 + 0.5); + + // this is the "Lord help thee who tread 'ere" section - no way to approximate this mess + } else if(rxBw == 142.8) { + bypass = SI443X_BYPASS_DEC_BY_3_ON; + decRate = 1; + filterSet = 4; + } else if(rxBw == 167.8) { + bypass = SI443X_BYPASS_DEC_BY_3_ON; + decRate = 1; + filterSet = 5; + } else if(rxBw == 181.1) { + bypass = SI443X_BYPASS_DEC_BY_3_ON; + decRate = 1; + filterSet = 6; + } else if(rxBw == 191.5) { + bypass = SI443X_BYPASS_DEC_BY_3_ON; + decRate = 0; + filterSet = 15; + } else if(rxBw == 225.1) { + bypass = SI443X_BYPASS_DEC_BY_3_ON; + decRate = 0; + filterSet = 1; + } else if(rxBw == 248.8) { + bypass = SI443X_BYPASS_DEC_BY_3_ON; + decRate = 0; + filterSet = 2; + } else if(rxBw == 269.3) { + bypass = SI443X_BYPASS_DEC_BY_3_ON; + decRate = 0; + filterSet = 3; + } else if(rxBw == 284.8) { + bypass = SI443X_BYPASS_DEC_BY_3_ON; + decRate = 0; + filterSet = 4; + } else if(rxBw == 335.5) { + bypass = SI443X_BYPASS_DEC_BY_3_ON; + decRate = 0; + filterSet = 8; + } else if(rxBw == 391.8) { + bypass = SI443X_BYPASS_DEC_BY_3_ON; + decRate = 0; + filterSet = 9; + } else if(rxBw == 420.2) { + bypass = SI443X_BYPASS_DEC_BY_3_ON; + decRate = 0; + filterSet = 10; + } else if(rxBw == 468.4) { + bypass = SI443X_BYPASS_DEC_BY_3_ON; + decRate = 0; + filterSet = 11; + } else if(rxBw == 518.8) { + bypass = SI443X_BYPASS_DEC_BY_3_ON; + decRate = 0; + filterSet = 12; + } else if(rxBw == 577.0) { + bypass = SI443X_BYPASS_DEC_BY_3_ON; + decRate = 0; + filterSet = 13; + } else if(rxBw == 620.7) { + bypass = SI443X_BYPASS_DEC_BY_3_ON; + decRate = 0; + filterSet = 14; + } else { + return(ERR_INVALID_RX_BANDWIDTH); + } + + // shift decimation rate bits + decRate <<= 4; + + // update register + int16_t state = _mod->SPIsetRegValue(SI443X_REG_IF_FILTER_BANDWIDTH, bypass | decRate | filterSet); + RADIOLIB_ASSERT(state); + + // update clock recovery + state = updateClockRecovery(); + + return(state); +} + +int16_t Si443x::setSyncWord(uint8_t* syncWord, size_t len) { + RADIOLIB_CHECK_RANGE(len, 1, 4, ERR_INVALID_SYNC_WORD); + + // set mode to standby + int16_t state = standby(); + RADIOLIB_ASSERT(state); + + // set sync word length + state = _mod->SPIsetRegValue(SI443X_REG_HEADER_CONTROL_2, (uint8_t)(len - 1) << 1, 2, 1); + RADIOLIB_ASSERT(state); + + // set sync word bytes + _mod->SPIwriteRegisterBurst(SI443X_REG_SYNC_WORD_3, syncWord, len); + + return(state); +} + +size_t Si443x::getPacketLength(bool update) { + // TODO variable length mode + if(!_packetLengthQueried && update) { + _packetLength = _mod->SPIreadRegister(SI443X_REG_RECEIVED_PACKET_LENGTH); + _packetLengthQueried = true; + } + + return(_packetLength); +} + +int16_t Si443x::setEncoding(uint8_t encoding) { + // set mode to standby + int16_t state = standby(); + RADIOLIB_ASSERT(state); + + // set encoding + // TODO - add inverted Manchester? + switch(encoding) { + case 0: + return(_mod->SPIsetRegValue(SI443X_REG_MODULATION_MODE_CONTROL_1, SI443X_MANCHESTER_INVERTED_OFF | SI443X_MANCHESTER_OFF | SI443X_WHITENING_OFF, 2, 0)); + case 1: + return(_mod->SPIsetRegValue(SI443X_REG_MODULATION_MODE_CONTROL_1, SI443X_MANCHESTER_INVERTED_OFF | SI443X_MANCHESTER_ON | SI443X_WHITENING_OFF, 2, 0)); + case 2: + return(_mod->SPIsetRegValue(SI443X_REG_MODULATION_MODE_CONTROL_1, SI443X_MANCHESTER_INVERTED_OFF | SI443X_MANCHESTER_OFF | SI443X_WHITENING_ON, 2, 0)); + default: + return(ERR_INVALID_ENCODING); + } +} + +int16_t Si443x::setDataShaping(float sh) { + // set mode to standby + int16_t state = standby(); + RADIOLIB_ASSERT(state); + + if(sh == 0.0) { + // set modulation to FSK + return(_mod->SPIsetRegValue(SI443X_REG_MODULATION_MODE_CONTROL_2, SI443X_MODULATION_FSK, 1, 0)); + } else { + // set modulation to GFSK + // TODO implement fiter configuration - docs claim this should be possible, but seems undocumented + return(_mod->SPIsetRegValue(SI443X_REG_MODULATION_MODE_CONTROL_2, SI443X_MODULATION_GFSK, 1, 0)); + } +} + +int16_t Si443x::setFrequencyRaw(float newFreq) { + // set mode to standby + int16_t state = standby(); + RADIOLIB_ASSERT(state); + + // check high/low band + uint8_t bandSelect = SI443X_BAND_SELECT_LOW; + uint8_t freqBand = (newFreq / 10) - 24; + if(newFreq >= 480.0) { + bandSelect = SI443X_BAND_SELECT_HIGH; + freqBand = (newFreq / 20) - 24; + } + + // calculate register values + uint16_t freqCarrier = ((newFreq / (10 * ((bandSelect >> 5) + 1))) - freqBand - 24) * (uint32_t)64000; + + // update registers + state = _mod->SPIsetRegValue(SI443X_REG_FREQUENCY_BAND_SELECT, bandSelect | freqBand, 5, 0); + state |= _mod->SPIsetRegValue(SI443X_REG_NOM_CARRIER_FREQUENCY_1, (uint8_t)((freqCarrier & 0xFF00) >> 8)); + state |= _mod->SPIsetRegValue(SI443X_REG_NOM_CARRIER_FREQUENCY_0, (uint8_t)(freqCarrier & 0xFF)); + + return(state); +} + +bool Si443x::findChip() { + uint8_t i = 0; + bool flagFound = false; + while((i < 10) && !flagFound) { + // reset the module + reset(); + + // check version register + uint8_t version = _mod->SPIreadRegister(SI443X_REG_DEVICE_VERSION); + if(version == SI443X_DEVICE_VERSION) { + flagFound = true; + } else { + #ifdef RADIOLIB_DEBUG + RADIOLIB_DEBUG_PRINT(F("Si443x not found! (")); + RADIOLIB_DEBUG_PRINT(i + 1); + RADIOLIB_DEBUG_PRINT(F(" of 10 tries) SI443X_REG_DEVICE_VERSION == ")); + + char buffHex[5]; + sprintf(buffHex, "0x%02X", version); + RADIOLIB_DEBUG_PRINT(buffHex); + RADIOLIB_DEBUG_PRINT(F(", expected 0x00")); + RADIOLIB_DEBUG_PRINTLN(SI443X_DEVICE_VERSION, HEX); + #endif + delay(1000); + i++; + } + } + + return(flagFound); +} + +void Si443x::clearIRQFlags() { + _mod->SPIreadRegister(SI443X_REG_INTERRUPT_STATUS_1); + _mod->SPIreadRegister(SI443X_REG_INTERRUPT_STATUS_2); +} + +int16_t Si443x::config() { + // set mode to standby + int16_t state = standby(); + RADIOLIB_ASSERT(state); + + // disable POR and chip ready interrupts + state = _mod->SPIsetRegValue(SI443X_REG_INTERRUPT_ENABLE_2, 0x00); + RADIOLIB_ASSERT(state); + + // disable packet header + state = _mod->SPIsetRegValue(SI443X_REG_HEADER_CONTROL_2, SI443X_SYNC_WORD_TIMEOUT_ON | SI443X_HEADER_LENGTH_HEADER_NONE, 7, 4); + RADIOLIB_ASSERT(state); + + // disable packet header checking + state = _mod->SPIsetRegValue(SI443X_REG_HEADER_CONTROL_1, SI443X_BROADCAST_ADDR_CHECK_NONE | SI443X_RECEIVED_HEADER_CHECK_NONE); + RADIOLIB_ASSERT(state); + + return(state); +} + +int16_t Si443x::updateClockRecovery() { + // get the parameters + uint8_t bypass = _mod->SPIgetRegValue(SI443X_REG_IF_FILTER_BANDWIDTH, 7, 7) >> 7; + uint8_t decRate = _mod->SPIgetRegValue(SI443X_REG_IF_FILTER_BANDWIDTH, 6, 4) >> 4; + uint8_t manch = _mod->SPIgetRegValue(SI443X_REG_MODULATION_MODE_CONTROL_1, 1, 1) >> 1; + + // calculate oversampling ratio, NCO offset and clock recovery gain + float rxOsr = ((float)(500 * (1 + 2*bypass))) / (((float)((uint16_t)(1) << decRate)) * _br * ((float)(1 + manch))); + uint32_t ncoOff = (_br * (1 + manch) * ((uint32_t)(1) << (20 + decRate))) / (500 * (1 + 2*bypass)); + uint16_t crGain = 2 + (((float)(65536.0 * (1 + manch)) * _br) / (rxOsr * (_freqDev / 0.625))); + + // convert oversampling ratio from float to fixed point + uint8_t rxOsr_int = (uint8_t)rxOsr; + uint8_t rxOsr_dec = 0; + float rxOsr_temp = rxOsr; + if(rxOsr_temp - rxOsr_int >= 0.5) { + rxOsr_dec |= 0x04; + rxOsr_temp -= 0.5; + } + if(rxOsr_temp - rxOsr_int >= 0.25) { + rxOsr_dec |= 0x02; + rxOsr_temp -= 0.25; + } + if(rxOsr_temp - rxOsr_int >= 0.125) { + rxOsr_dec |= 0x01; + rxOsr_temp -= 0.125; + } + uint16_t rxOsr_fixed = ((uint16_t)rxOsr_int << 3) | ((uint16_t)rxOsr_dec); + + // print that whole mess + RADIOLIB_DEBUG_PRINTLN(bypass, HEX); + RADIOLIB_DEBUG_PRINTLN(decRate, HEX); + RADIOLIB_DEBUG_PRINTLN(manch, HEX); + RADIOLIB_DEBUG_PRINT(rxOsr, 3); + RADIOLIB_DEBUG_PRINT('\t'); + RADIOLIB_DEBUG_PRINT(rxOsr_int); + RADIOLIB_DEBUG_PRINT('\t'); + RADIOLIB_DEBUG_PRINT(rxOsr_int, HEX); + RADIOLIB_DEBUG_PRINT('\t'); + RADIOLIB_DEBUG_PRINT(rxOsr_dec); + RADIOLIB_DEBUG_PRINT('\t'); + RADIOLIB_DEBUG_PRINT(rxOsr_dec, HEX); + RADIOLIB_DEBUG_PRINT('\t'); + RADIOLIB_DEBUG_PRINT(rxOsr_fixed); + RADIOLIB_DEBUG_PRINT('\t'); + RADIOLIB_DEBUG_PRINTLN(rxOsr_fixed, HEX); + RADIOLIB_DEBUG_PRINT(ncoOff); + RADIOLIB_DEBUG_PRINT('\t'); + RADIOLIB_DEBUG_PRINTLN(ncoOff, HEX); + RADIOLIB_DEBUG_PRINT(crGain); + RADIOLIB_DEBUG_PRINT('\t'); + RADIOLIB_DEBUG_PRINTLN(crGain, HEX); + + // update oversampling ratio + int16_t state = _mod->SPIsetRegValue(SI443X_REG_CLOCK_REC_OFFSET_2, (uint8_t)((rxOsr_fixed & 0x0700) >> 3), 7, 5); + RADIOLIB_ASSERT(state); + state = _mod->SPIsetRegValue(SI443X_REG_CLOCK_REC_OVERSAMP_RATIO, (uint8_t)(rxOsr_fixed & 0x00FF)); + RADIOLIB_ASSERT(state); + + // update NCO offset + state = _mod->SPIsetRegValue(SI443X_REG_CLOCK_REC_OFFSET_2, (uint8_t)((ncoOff & 0x0F0000) >> 16), 3, 0); + RADIOLIB_ASSERT(state); + state = _mod->SPIsetRegValue(SI443X_REG_CLOCK_REC_OFFSET_1, (uint8_t)((ncoOff & 0x00FF00) >> 8)); + RADIOLIB_ASSERT(state); + state = _mod->SPIsetRegValue(SI443X_REG_CLOCK_REC_OFFSET_0, (uint8_t)(ncoOff & 0x0000FF)); + RADIOLIB_ASSERT(state); + + // update clock recovery loop gain + state = _mod->SPIsetRegValue(SI443X_REG_CLOCK_REC_TIMING_LOOP_GAIN_1, (uint8_t)((crGain & 0x0700) >> 8), 2, 0); + RADIOLIB_ASSERT(state); + state = _mod->SPIsetRegValue(SI443X_REG_CLOCK_REC_TIMING_LOOP_GAIN_0, (uint8_t)(crGain & 0x00FF)); + RADIOLIB_ASSERT(state); + + return(state); +} + +int16_t Si443x::directMode() { + int16_t state = _mod->SPIsetRegValue(SI443X_REG_MODULATION_MODE_CONTROL_2, SI443X_TX_DATA_SOURCE_GPIO, 5, 4); + RADIOLIB_ASSERT(state); + + state = _mod->SPIsetRegValue(SI443X_REG_MODULATION_MODE_CONTROL_2, SI443X_MODULATION_NONE, 1, 0); + return(state); +} diff --git a/src/modules/Si443x/Si443x.h b/src/modules/Si443x/Si443x.h new file mode 100644 index 00000000..df5ae4d0 --- /dev/null +++ b/src/modules/Si443x/Si443x.h @@ -0,0 +1,786 @@ +#ifndef _RADIOLIB_SI443X_H +#define _RADIOLIB_SI443X_H + +#include "../../TypeDef.h" +#include "../../Module.h" + +#include "../../protocols/PhysicalLayer/PhysicalLayer.h" + +// Si443x physical layer properties +#define SI443X_FREQUENCY_STEP_SIZE 156.25 +#define SI443X_MAX_PACKET_LENGTH 64 + +// Si443x series common registers +#define SI443X_REG_DEVICE_TYPE 0x00 +#define SI443X_REG_DEVICE_VERSION 0x01 +#define SI443X_REG_DEVICE_STATUS 0x02 +#define SI443X_REG_INTERRUPT_STATUS_1 0x03 +#define SI443X_REG_INTERRUPT_STATUS_2 0x04 +#define SI443X_REG_INTERRUPT_ENABLE_1 0x05 +#define SI443X_REG_INTERRUPT_ENABLE_2 0x06 +#define SI443X_REG_OP_FUNC_CONTROL_1 0x07 +#define SI443X_REG_OP_FUNC_CONTROL_2 0x08 +#define SI443X_REG_XOSC_LOAD_CAPACITANCE 0x09 +#define SI443X_REG_MCU_OUTPUT_CLOCK 0x0A +#define SI443X_REG_GPIO0_CONFIG 0x0B +#define SI443X_REG_GPIO1_CONFIG 0x0C +#define SI443X_REG_GPIO2_CONFIG 0x0D +#define SI443X_REG_IO_PORT_CONFIG 0x0E +#define SI443X_REG_ADC_CONFIG 0x0F +#define SI443X_REG_ADC_SENSOR_AMP_OFFSET 0x10 +#define SI443X_REG_ADC_VALUE 0x11 +#define SI443X_REG_TEMP_SENSOR_CONTROL 0x12 +#define SI443X_REG_TEMP_VALUE_OFFSET 0x13 +#define SI443X_REG_WAKEUP_TIMER_PERIOD_1 0x14 +#define SI443X_REG_WAKEUP_TIMER_PERIOD_2 0x15 +#define SI443X_REG_WAKEUP_TIMER_PERIOD_3 0x16 +#define SI443X_REG_WAKEUP_TIMER_VALUE_1 0x17 +#define SI443X_REG_WAKEUP_TIMER_VALUE_2 0x18 +#define SI443X_REG_LOW_DC_MODE_DURATION 0x19 +#define SI443X_REG_LOW_BATT_DET_THRESHOLD 0x1A +#define SI443X_REG_BATT_VOLTAGE_LEVEL 0x1B +#define SI443X_REG_IF_FILTER_BANDWIDTH 0x1C +#define SI443X_REG_AFC_LOOP_GEARSHIFT_OVERRIDE 0x1D +#define SI443X_REG_AFC_TIMING_CONTROL 0x1E +#define SI443X_REG_CLOCK_REC_GEARSHIFT_OVERRIDE 0x1F +#define SI443X_REG_CLOCK_REC_OVERSAMP_RATIO 0x20 +#define SI443X_REG_CLOCK_REC_OFFSET_2 0x21 +#define SI443X_REG_CLOCK_REC_OFFSET_1 0x22 +#define SI443X_REG_CLOCK_REC_OFFSET_0 0x23 +#define SI443X_REG_CLOCK_REC_TIMING_LOOP_GAIN_1 0x24 +#define SI443X_REG_CLOCK_REC_TIMING_LOOP_GAIN_0 0x25 +#define SI443X_REG_RSSI 0x26 +#define SI443X_REG_RSSI_CLEAR_CHANNEL_THRESHOLD 0x27 +#define SI443X_REG_ANTENNA_DIVERSITY_1 0x28 +#define SI443X_REG_ANTENNA_DIVERSITY_2 0x29 +#define SI443X_REG_AFC_LIMITER 0x2A +#define SI443X_REG_AFC_CORRECTION 0x2B +#define SI443X_REG_OOK_COUNTER_1 0x2C +#define SI443X_REG_OOK_COUNTER_2 0x2D +#define SI443X_REG_SLICER_PEAK_HOLD 0x2E +#define SI443X_REG_DATA_ACCESS_CONTROL 0x30 +#define SI443X_REG_EZMAC_STATUS 0x31 +#define SI443X_REG_HEADER_CONTROL_1 0x32 +#define SI443X_REG_HEADER_CONTROL_2 0x33 +#define SI443X_REG_PREAMBLE_LENGTH 0x34 +#define SI443X_REG_PREAMBLE_DET_CONTROL 0x35 +#define SI443X_REG_SYNC_WORD_3 0x36 +#define SI443X_REG_SYNC_WORD_2 0x37 +#define SI443X_REG_SYNC_WORD_1 0x38 +#define SI443X_REG_SYNC_WORD_0 0x39 +#define SI443X_REG_TRANSMIT_HEADER_3 0x3A +#define SI443X_REG_TRANSMIT_HEADER_2 0x3B +#define SI443X_REG_TRANSMIT_HEADER_1 0x3C +#define SI443X_REG_TRANSMIT_HEADER_0 0x3D +#define SI443X_REG_TRANSMIT_PACKET_LENGTH 0x3E +#define SI443X_REG_CHECK_HEADER_3 0x3F +#define SI443X_REG_CHECK_HEADER_2 0x40 +#define SI443X_REG_CHECK_HEADER_1 0x41 +#define SI443X_REG_CHECK_HEADER_0 0x42 +#define SI443X_REG_HEADER_ENABLE_3 0x43 +#define SI443X_REG_HEADER_ENABLE_2 0x44 +#define SI443X_REG_HEADER_ENABLE_1 0x45 +#define SI443X_REG_HEADER_ENABLE_0 0x46 +#define SI443X_REG_RECEIVED_HEADER_3 0x47 +#define SI443X_REG_RECEIVED_HEADER_2 0x48 +#define SI443X_REG_RECEIVED_HEADER_1 0x49 +#define SI443X_REG_RECEIVED_HEADER_0 0x4A +#define SI443X_REG_RECEIVED_PACKET_LENGTH 0x4B +#define SI443X_REG_ADC8_CONTROL 0x4F +#define SI443X_REG_CHANNEL_FILTER_COEFF 0x60 +#define SI443X_REG_XOSC_CONTROL_TEST 0x62 +#define SI443X_REG_AGC_OVERRIDE_1 0x69 +#define SI443X_REG_TX_POWER 0x6D +#define SI443X_REG_TX_DATA_RATE_1 0x6E +#define SI443X_REG_TX_DATA_RATE_0 0x6F +#define SI443X_REG_MODULATION_MODE_CONTROL_1 0x70 +#define SI443X_REG_MODULATION_MODE_CONTROL_2 0x71 +#define SI443X_REG_FREQUENCY_DEVIATION 0x72 +#define SI443X_REG_FREQUENCY_OFFSET_1 0x73 +#define SI443X_REG_FREQUENCY_OFFSET_2 0x74 +#define SI443X_REG_FREQUENCY_BAND_SELECT 0x75 +#define SI443X_REG_NOM_CARRIER_FREQUENCY_1 0x76 +#define SI443X_REG_NOM_CARRIER_FREQUENCY_0 0x77 +#define SI443X_REG_FREQUENCY_HOPPING_CHANNEL_SEL 0x79 +#define SI443X_REG_FREQUENCY_HOPPING_STEP_SIZE 0x7A +#define SI443X_REG_TX_FIFO_CONTROL_1 0x7C +#define SI443X_REG_TX_FIFO_CONTROL_2 0x7D +#define SI443X_REG_RX_FIFO_CONTROL 0x7E +#define SI443X_REG_FIFO_ACCESS 0x7F + +// SI443X_REG_DEVICE_TYPE MSB LSB DESCRIPTION +#define SI443X_DEVICE_TYPE 0x08 // 4 0 device identification register + +// SI443X_REG_DEVICE_VERSION +#define SI443X_DEVICE_VERSION 0x06 // 4 0 chip version register + +// SI443X_REG_DEVICE_STATUS +#define SI443X_RX_TX_FIFO_OVERFLOW 0b10000000 // 7 7 Rx/Tx FIFO overflow flag +#define SI443X_RX_TX_FIFO_UNDERFLOW 0b01000000 // 6 6 Rx/Tx FIFO underflow flag +#define SI443X_RX_FIFO_EMPTY 0b00100000 // 5 5 Rx FIFO empty flag +#define SI443X_HEADER_ERROR 0b00010000 // 4 4 header error flag +#define SI443X_FREQUENCY_ERROR 0b00001000 // 3 3 frequency error flag (frequency outside allowed range) +#define SI443X_TX 0b00000010 // 1 0 power state: Tx +#define SI443X_RX 0b00000001 // 1 0 Rx +#define SI443X_IDLE 0b00000000 // 1 0 idle + +// SI443X_REG_INTERRUPT_STATUS_1 +#define SI443X_FIFO_LEVEL_ERROR_INTERRUPT 0b10000000 // 7 7 Tx/Rx FIFO overflow or underflow +#define SI443X_TX_FIFO_ALMOST_FULL_INTERRUPT 0b01000000 // 6 6 Tx FIFO almost full +#define SI443X_TX_FIFO_ALMOST_EMPTY_INTERRUPT 0b00100000 // 5 5 Tx FIFO almost empty +#define SI443X_RX_FIFO_ALMOST_FULL_INTERRUPT 0b00010000 // 4 4 Rx FIFO almost full +#define SI443X_EXTERNAL_INTERRUPT 0b00001000 // 3 3 external interrupt occurred on GPIOx +#define SI443X_PACKET_SENT_INTERRUPT 0b00000100 // 2 2 packet transmission done +#define SI443X_VALID_PACKET_RECEIVED_INTERRUPT 0b00000010 // 1 1 valid packet has been received +#define SI443X_CRC_ERROR_INTERRUPT 0b00000001 // 0 0 CRC failed + +// SI443X_REG_INTERRUPT_STATUS_2 +#define SI443X_SYNC_WORD_DETECTED_INTERRUPT 0b10000000 // 7 7 sync word has been detected +#define SI443X_VALID_PREAMBLE_DETECTED_INTERRUPT 0b01000000 // 6 6 valid preamble has been detected +#define SI443X_INVALID_PREAMBLE_DETECTED_INTERRUPT 0b00100000 // 5 5 invalid preamble has been detected +#define SI443X_RSSI_INTERRUPT 0b00010000 // 4 4 RSSI exceeded programmed threshold +#define SI443X_WAKEUP_TIMER_INTERRUPT 0b00001000 // 3 3 wake-up timer expired +#define SI443X_LOW_BATTERY_INTERRUPT 0b00000100 // 2 2 low battery detected +#define SI443X_CHIP_READY_INTERRUPT 0b00000010 // 1 1 chip ready event detected +#define SI443X_POWER_ON_RESET_INTERRUPT 0b00000001 // 0 0 power-on-reset detected + +// SI443X_REG_INTERRUPT_ENABLE_1 +#define SI443X_FIFO_LEVEL_ERROR_ENABLED 0b10000000 // 7 7 Tx/Rx FIFO overflow or underflow interrupt enabled +#define SI443X_TX_FIFO_ALMOST_FULL_ENABLED 0b01000000 // 6 6 Tx FIFO almost full interrupt enabled +#define SI443X_TX_FIFO_ALMOST_EMPTY_ENABLED 0b00100000 // 5 5 Tx FIFO almost empty interrupt enabled +#define SI443X_RX_FIFO_ALMOST_FULL_ENABLED 0b00010000 // 4 4 Rx FIFO almost full interrupt enabled +#define SI443X_EXTERNAL_ENABLED 0b00001000 // 3 3 external interrupt interrupt enabled +#define SI443X_PACKET_SENT_ENABLED 0b00000100 // 2 2 packet transmission done interrupt enabled +#define SI443X_VALID_PACKET_RECEIVED_ENABLED 0b00000010 // 1 1 valid packet received interrupt enabled +#define SI443X_CRC_ERROR_ENABLED 0b00000001 // 0 0 CRC failed interrupt enabled + +// SI443X_REG_INTERRUPT_ENABLE_2 +#define SI443X_SYNC_WORD_DETECTED_ENABLED 0b10000000 // 7 7 sync word interrupt enabled +#define SI443X_VALID_PREAMBLE_DETECTED_ENABLED 0b01000000 // 6 6 valid preamble interrupt enabled +#define SI443X_INVALID_PREAMBLE_DETECTED_ENABLED 0b00100000 // 5 5 invalid preamble interrupt enabled +#define SI443X_RSSI_ENABLED 0b00010000 // 4 4 RSSI exceeded programmed threshold interrupt enabled +#define SI443X_WAKEUP_TIMER_ENABLED 0b00001000 // 3 3 wake-up timer interrupt enabled +#define SI443X_LOW_BATTERY_ENABLED 0b00000100 // 2 2 low battery interrupt enabled +#define SI443X_CHIP_READY_ENABLED 0b00000010 // 1 1 chip ready event interrupt enabled +#define SI443X_POWER_ON_RESET_ENABLED 0b00000001 // 0 0 power-on-reset interrupt enabled + +// SI443X_REG_OP_FUNC_CONTROL_1 +#define SI443X_SOFTWARE_RESET 0b10000000 // 7 7 reset all registers to default values +#define SI443X_ENABLE_LOW_BATTERY_DETECT 0b01000000 // 6 6 enable low battery detection +#define SI443X_ENABLE_WAKEUP_TIMER 0b00100000 // 5 5 enable wakeup timer +#define SI443X_32_KHZ_RC 0b00000000 // 4 4 32.768 kHz source: RC oscillator (default) +#define SI443X_32_KHZ_XOSC 0b00010000 // 4 4 crystal oscillator +#define SI443X_TX_ON 0b00001000 // 3 3 Tx on in manual transmit mode +#define SI443X_RX_ON 0b00000100 // 2 2 Rx on in manual receive mode +#define SI443X_PLL_ON 0b00000010 // 1 1 PLL on (tune mode) +#define SI443X_XTAL_OFF 0b00000000 // 0 0 crystal oscillator: off (standby mode) +#define SI443X_XTAL_ON 0b00000001 // 0 0 on (ready mode) + +// SI443X_REG_OP_FUNC_CONTROL_2 +#define SI443X_ANT_DIV_TR_HL_IDLE_L 0b00000000 // 7 5 GPIO1/2 states: Tx/Rx GPIO1 H, GPIO2 L; idle low (default) +#define SI443X_ANT_DIV_TR_LH_IDLE_L 0b00100000 // 7 5 Tx/Rx GPIO1 L, GPIO2 H; idle low +#define SI443X_ANT_DIV_TR_HL_IDLE_H 0b01000000 // 7 5 Tx/Rx GPIO1 H, GPIO2 L; idle high +#define SI443X_ANT_DIV_TR_LH_IDLE_H 0b01100000 // 7 5 Tx/Rx GPIO1 L, GPIO2 H; idle high +#define SI443X_ANT_DIV_TR_ALG_IDLE_L 0b10000000 // 7 5 Tx/Rx diversity algorithm; idle low +#define SI443X_ANT_DIV_TR_ALG_IDLE_H 0b10100000 // 7 5 Tx/Rx diversity algorithm; idle high +#define SI443X_ANT_DIV_TR_ALG_BEACON_IDLE_L 0b11000000 // 7 5 Tx/Rx diversity algorithm (beacon); idle low +#define SI443X_ANT_DIV_TR_ALG_BEACON_IDLE_H 0b11100000 // 7 5 Tx/Rx diversity algorithm (beacon); idle high +#define SI443X_RX_MULTIPACKET_OFF 0b00000000 // 4 4 Rx multipacket: disabled (default) +#define SI443X_RX_MULTIPACKET_ON 0b00010000 // 4 4 enabled +#define SI443X_AUTO_TX_OFF 0b00000000 // 3 3 Tx autotransmit on FIFO almost full: disabled (default) +#define SI443X_AUTO_TX_ON 0b00001000 // 3 3 enabled +#define SI443X_LOW_DUTY_CYCLE_OFF 0b00000000 // 2 2 low duty cycle mode: disabled (default) +#define SI443X_LOW_DUTY_CYCLE_ON 0b00000100 // 2 2 enabled +#define SI443X_RX_FIFO_RESET 0b00000010 // 1 1 Rx FIFO reset/clear: reset (call first) +#define SI443X_RX_FIFO_CLEAR 0b00000000 // 1 1 clear (call second) +#define SI443X_TX_FIFO_RESET 0b00000001 // 0 0 Tx FIFO reset/clear: reset (call first) +#define SI443X_TX_FIFO_CLEAR 0b00000000 // 0 0 clear (call second) + +// SI443X_REG_XOSC_LOAD_CAPACITANCE +#define SI443X_XTAL_SHIFT 0b00000000 // 7 7 crystal capacitance configuration: +#define SI443X_XTAL_LOAD_CAPACITANCE 0b01111111 // 6 0 C_int = 1.8 pF + 0.085 pF * SI443X_XTAL_LOAD_CAPACITANCE + 3.7 pF * SI443X_XTAL_SHIFT + +// SI443X_REG_MCU_OUTPUT_CLOCK +#define SI443X_CLOCK_TAIL_CYCLES_OFF 0b00000000 // 5 4 additional clock cycles: none (default) +#define SI443X_CLOCK_TAIL_CYCLES_128 0b00010000 // 5 4 128 +#define SI443X_CLOCK_TAIL_CYCLES_256 0b00100000 // 5 4 256 +#define SI443X_CLOCK_TAIL_CYCLES_512 0b00110000 // 5 4 512 +#define SI443X_LOW_FREQ_CLOCK_OFF 0b00000000 // 3 3 32.768 kHz clock output: disabled (default) +#define SI443X_LOW_FREQ_CLOCK_ON 0b00001000 // 3 3 enabled +#define SI443X_MCU_CLOCK_30_MHZ 0b00000000 // 2 0 GPIO clock output: 30 MHz +#define SI443X_MCU_CLOCK_15_MHZ 0b00000001 // 2 0 15 MHz +#define SI443X_MCU_CLOCK_10_MHZ 0b00000010 // 2 0 10 MHz +#define SI443X_MCU_CLOCK_4_MHZ 0b00000011 // 2 0 4 MHz +#define SI443X_MCU_CLOCK_3_MHZ 0b00000100 // 2 0 3 MHz +#define SI443X_MCU_CLOCK_2_MHZ 0b00000101 // 2 0 2 MHz +#define SI443X_MCU_CLOCK_1_MHZ 0b00000110 // 2 0 1 MHz (default) +#define SI443X_MCU_CLOCK_32_KHZ 0b00000111 // 2 0 32.768 kHz + +// SI443X_REG_GPIO0_CONFIG + SI443X_REG_GPIO1_CONFIG + SI443X_REG_GPIO2_CONFIG +#define SI443X_GPIOX_DRIVE_STRENGTH 0b00000000 // 7 6 GPIOx drive strength (higher number = stronger drive) +#define SI443X_GPIOX_PULLUP_OFF 0b00000000 // 5 5 GPIOx internal 200k pullup: disabled (default) +#define SI443X_GPIOX_PULLUP_ON 0b00100000 // 5 5 enabled +#define SI443X_GPIO0_POWER_ON_RESET_OUT 0b00000000 // 4 0 GPIOx function: power-on-reset output (GPIO0 only, default) +#define SI443X_GPIO1_POWER_ON_RESET_INV_OUT 0b00000000 // 4 0 inverted power-on-reset output (GPIO1 only, default) +#define SI443X_GPIO2_MCU_CLOCK_OUT 0b00000000 // 4 0 MCU clock output (GPIO2 only, default) +#define SI443X_GPIOX_WAKEUP_OUT 0b00000001 // 4 0 wakeup timer expired output +#define SI443X_GPIOX_LOW_BATTERY_OUT 0b00000010 // 4 0 low battery detect output +#define SI443X_GPIOX_DIGITAL_OUT 0b00000011 // 4 0 direct digital output +#define SI443X_GPIOX_EXT_INT_FALLING_IN 0b00000100 // 4 0 external interrupt, falling edge +#define SI443X_GPIOX_EXT_INT_RISING_IN 0b00000101 // 4 0 external interrupt, rising edge +#define SI443X_GPIOX_EXT_INT_CHANGE_IN 0b00000110 // 4 0 external interrupt, state change +#define SI443X_GPIOX_ADC_IN 0b00000111 // 4 0 ADC analog input +#define SI443X_GPIOX_ANALOG_TEST_N_IN 0b00001000 // 4 0 analog test N input +#define SI443X_GPIOX_ANALOG_TEST_P_IN 0b00001001 // 4 0 analog test P input +#define SI443X_GPIOX_DIGITAL_IN 0b00001010 // 4 0 direct digital input +#define SI443X_GPIOX_DIGITAL_TEST_OUT 0b00001011 // 4 0 digital test output +#define SI443X_GPIOX_ANALOG_TEST_N_OUT 0b00001100 // 4 0 analog test N output +#define SI443X_GPIOX_ANALOG_TEST_P_OUT 0b00001101 // 4 0 analog test P output +#define SI443X_GPIOX_REFERENCE_VOLTAGE_OUT 0b00001110 // 4 0 reference voltage output +#define SI443X_GPIOX_TX_RX_DATA_CLK_OUT 0b00001111 // 4 0 Tx/Rx clock output in direct mode +#define SI443X_GPIOX_TX_DATA_IN 0b00010000 // 4 0 Tx data input direct mode +#define SI443X_GPIOX_EXT_RETRANSMIT_REQUEST_IN 0b00010001 // 4 0 external retransmission request input +#define SI443X_GPIOX_TX_STATE_OUT 0b00010010 // 4 0 Tx state output +#define SI443X_GPIOX_TX_FIFO_ALMOST_FULL_OUT 0b00010011 // 4 0 Tx FIFO almost full output +#define SI443X_GPIOX_RX_DATA_OUT 0b00010100 // 4 0 Rx data output +#define SI443X_GPIOX_RX_STATE_OUT 0b00010101 // 4 0 Rx state output +#define SI443X_GPIOX_RX_FIFO_ALMOST_FULL_OUT 0b00010110 // 4 0 Rx FIFO almost full output +#define SI443X_GPIOX_ANT_DIV_1_OUT 0b00010111 // 4 0 antenna diversity output 1 +#define SI443X_GPIOX_ANT_DIV_2_OUT 0b00011000 // 4 0 antenna diversity output 2 +#define SI443X_GPIOX_VALID_PREAMBLE_OUT 0b00011001 // 4 0 valid preamble detected output +#define SI443X_GPIOX_INVALID_PREAMBLE_OUT 0b00011010 // 4 0 invalid preamble detected output +#define SI443X_GPIOX_SYNC_WORD_DETECTED_OUT 0b00011011 // 4 0 sync word detected output +#define SI443X_GPIOX_CLEAR_CHANNEL_OUT 0b00011100 // 4 0 clear channel assessment output +#define SI443X_GPIOX_VDD 0b00011101 // 4 0 VDD +#define SI443X_GPIOX_GND 0b00011110 // 4 0 GND + +// SI443X_REG_IO_PORT_CONFIG +#define SI443X_GPIO2_EXT_INT_STATE_MASK 0b01000000 // 6 6 external interrupt state mask for: GPIO2 +#define SI443X_GPIO1_EXT_INT_STATE_MASK 0b00100000 // 5 5 GPIO1 +#define SI443X_GPIO0_EXT_INT_STATE_MASK 0b00010000 // 4 4 GPIO0 +#define SI443X_IRQ_BY_SDO_OFF 0b00000000 // 3 3 output IRQ state on SDO pin: disabled (default) +#define SI443X_IRQ_BY_SDO_ON 0b00001000 // 3 3 enabled +#define SI443X_GPIO2_DIGITAL_STATE_MASK 0b00000100 // 2 2 digital state mask for: GPIO2 +#define SI443X_GPIO1_DIGITAL_STATE_MASK 0b00000010 // 1 1 GPIO1 +#define SI443X_GPIO0_DIGITAL_STATE_MASK 0b00000001 // 0 0 GPIO0 + +// SI443X_REG_ADC_CONFIG +#define SI443X_ADC_START 0b10000000 // 7 7 ADC control: start measurement +#define SI443X_ADC_RUNNING 0b00000000 // 7 7 measurement in progress +#define SI443X_ADC_DONE 0b10000000 // 7 7 done +#define SI443X_ADC_SOURCE_TEMPERATURE 0b00000000 // 6 4 ADC source: internal temperature sensor (default) +#define SI443X_ADC_SOURCE_GPIO0_SINGLE 0b00010000 // 6 4 single-ended on GPIO0 +#define SI443X_ADC_SOURCE_GPIO1_SINGLE 0b00100000 // 6 4 single-ended on GPIO1 +#define SI443X_ADC_SOURCE_GPIO2_SINGLE 0b00110000 // 6 4 single-ended on GPIO2 +#define SI443X_ADC_SOURCE_GPIO01_DIFF 0b01000000 // 6 4 differential on GPIO0 (+) and GPIO1 (-) +#define SI443X_ADC_SOURCE_GPIO12_DIFF 0b01010000 // 6 4 differential on GPIO1 (+) and GPIO2 (-) +#define SI443X_ADC_SOURCE_GPIO02_DIFF 0b01100000 // 6 4 differential on GPIO0 (+) and GPIO2 (-) +#define SI443X_ADC_SOURCE_GND 0b01110000 // 6 4 GND +#define SI443X_ADC_REFERNCE_BAND_GAP 0b00000000 // 3 2 ADC reference: internal bandgap 1.2 V (default) +#define SI443X_ADC_REFERNCE_VDD_3 0b00001000 // 3 2 VDD/3 +#define SI443X_ADC_REFERNCE_VDD_2 0b00001100 // 3 2 VDD/2 +#define SI443X_ADC_GAIN 0b00000000 // 1 0 ADC amplifier gain + +// SI443X_REG_ADC_SENSOR_AMP_OFFSET +#define SI443X_ADC_OFFSET 0b00000000 // 3 0 ADC offset + +// SI443X_REG_TEMP_SENSOR_CONTROL +#define SI443X_TEMP_SENSOR_RANGE_64_TO_64_C 0b00000000 // 7 6 temperature sensor range: -64 to 64 deg. C, 0.5 deg. C resolution (default) +#define SI443X_TEMP_SENSOR_RANGE_64_TO_192_C 0b01000000 // 7 6 -64 to 192 deg. C, 1.0 deg. C resolution +#define SI443X_TEMP_SENSOR_RANGE_0_TO_128_C 0b11000000 // 7 6 0 to 128 deg. C, 0.5 deg. C resolution +#define SI443X_TEMP_SENSOR_RANGE_40_TO_216_F 0b10000000 // 7 6 -40 to 216 deg. F, 1.0 deg. F resolution +#define SI443X_TEMP_SENSOR_KELVIN_TO_CELSIUS_OFF 0b00000000 // 5 5 Kelvin to Celsius offset: disabled +#define SI443X_TEMP_SENSOR_KELVIN_TO_CELSIUS_ON 0b00100000 // 5 5 enabled (default) +#define SI443X_TEMP_SENSOR_TRIM_OFF 0b00000000 // 4 4 temperature sensor trim: disabled (default) +#define SI443X_TEMP_SENSOR_TRIM_ON 0b00010000 // 4 4 enabled +#define SI443X_TEMP_SENSOR_TRIM_VALUE 0b00000000 // 3 0 temperature sensor trim value + +// SI443X_REG_WAKEUP_TIMER_PERIOD_1 +#define SI443X_WAKEUP_TIMER_EXPONENT 0b00000011 // 4 0 wakeup timer value exponent + +// SI443X_REG_WAKEUP_TIMER_PERIOD_2 + SI443X_REG_WAKEUP_TIMER_PERIOD_3 +#define SI443X_WAKEUP_TIMER_MANTISSA_MSB 0x00 // 7 0 wakeup timer value: +#define SI443X_WAKEUP_TIMER_MANTISSA_LSB 0x01 // 7 0 T = (4 * SI443X_WAKEUP_TIMER_MANTISSA * 2 ^ SI443X_WAKEUP_TIMER_EXPONENT) / 32.768 ms + +// SI443X_REG_LOW_DC_MODE_DURATION +#define SI443X_LOW_DC_MODE_DURATION_MANTISSA 0x01 // 7 0 low duty cycle mode duration: T = (4 * SI443X_LOW_DC_MODE_DURATION_MANTISSA * 2 ^ SI443X_WAKEUP_TIMER_EXPONENT) / 32.768 ms + +// SI443X_REG_LOW_BATT_DET_THRESHOLD +#define SI443X_LOW_BATT_DET_THRESHOLD 0b00010100 // 4 0 low battery detection threshold: Vth = 1.7 + SI443X_LOW_BATT_DET_THRESHOLD * 0.05 V (defaults to 2.7 V) + +// SI443X_REG_IF_FILTER_BANDWIDTH +#define SI443X_BYPASS_DEC_BY_3_OFF 0b00000000 // 7 7 bypass decimate-by-3 stage: disabled (default) +#define SI443X_BYPASS_DEC_BY_3_ON 0b10000000 // 7 7 enabled +#define SI443X_IF_FILTER_DEC_RATE 0b00000000 // 6 4 IF filter decimation rate +#define SI443X_IF_FILTER_COEFF_SET 0b00000001 // 3 0 IF filter coefficient set selection + +// SI443X_REG_AFC_LOOP_GEARSHIFT_OVERRIDE +#define SI443X_AFC_WIDEBAND_OFF 0b00000000 // 7 7 AFC wideband: disabled (default) +#define SI443X_AFC_WIDEBAND_ON 0b10000000 // 7 7 enabled +#define SI443X_AFC_OFF 0b00000000 // 6 6 AFC: disabled +#define SI443X_AFC_ON 0b01000000 // 6 6 enabled (default) +#define SI443X_AFC_HIGH_GEAR_SETTING 0b00000000 // 5 3 AFC high gear setting +#define SI443X_SECOND_PHASE_BIAS_0_DB 0b00000100 // 2 2 second phase antenna selection bias: 0 dB (default) +#define SI443X_SECOND_PHASE_BIAS_1_5_DB 0b00000000 // 2 2 1.5 dB +#define SI443X_MOVING_AVERAGE_TAP_8 0b00000010 // 1 1 moving average filter tap length: 8*Tb +#define SI443X_MOVING_AVERAGE_TAP_4 0b00000000 // 1 1 4*Tb after first preamble (default) +#define SI443X_ZERO_PHASE_RESET_5 0b00000000 // 0 0 reset preamble detector after: 5 zero phases (default) +#define SI443X_ZERO_PHASE_RESET_2 0b00000001 // 0 0 3 zero phases + +// SI443X_REG_AFC_TIMING_CONTROL +#define SI443X_SW_ANT_TIMER 0b00000000 // 7 6 number of periods to wait for RSSI to stabilize during antenna switching +#define SI443X_SHORT_WAIT 0b00001000 // 5 3 period to wait after AFC correction +#define SI443X_ANTENNA_SWITCH_WAIT 0b00000010 // 2 0 antenna switching wait time + +// SI443X_REG_CLOCK_REC_GEARSHIFT_OVERRIDE +#define SI443X_CLOCK_RECOVER_FAST_GEARSHIFT 0b00000000 // 5 3 clock recovery fast gearshift value +#define SI443X_CLOCK_RECOVER_SLOW_GEARSHIFT 0b00000011 // 2 0 clock recovery slow gearshift value + +// SI443X_REG_CLOCK_REC_OVERSAMP_RATIO +#define SI443X_CLOCK_REC_OVERSAMP_RATIO_LSB 0b01100100 // 7 0 oversampling rate LSB, defaults to 12.5 clock cycles per bit + +// SI443X_REG_CLOCK_REC_OFFSET_2 +#define SI443X_CLOCK_REC_OVERSAMP_RATIO_MSB 0b00000000 // 7 5 oversampling rate MSB, defaults to 12.5 clock cycles per bit +#define SI443X_SECOND_PHASE_SKIP_THRESHOLD 0b00000000 // 4 4 skip seconds phase antenna diversity threshold +#define SI443X_NCO_OFFSET_MSB 0b00000001 // 3 0 NCO offset MSB + +// SI443X_REG_CLOCK_REC_OFFSET_1 +#define SI443X_NCO_OFFSET_MID 0b01000111 // 7 0 NCO offset MID + +// SI443X_REG_CLOCK_REC_OFFSET_0 +#define SI443X_NCO_OFFSET_LSB 0b10101110 // 7 0 NCO offset LSB + +// SI443X_REG_CLOCK_REC_TIMING_LOOP_GAIN_1 +#define SI443X_RX_COMPENSATION_OFF 0b00000000 // 4 4 Rx compensation for high data rate: disabled (default) +#define SI443X_RX_COMPENSATION_ON 0b00010000 // 4 4 enabled +#define SI443X_CLOCK_REC_GAIN_DOUBLE_OFF 0b00000000 // 3 3 clock recovery gain doubling: disabled (default) +#define SI443X_CLOCK_REC_GAIN_DOUBLE_ON 0b00001000 // 3 3 enabled +#define SI443X_CLOCK_REC_LOOP_GAIN_MSB 0b00000010 // 2 0 clock recovery timing loop gain MSB + +// SI443X_REG_CLOCK_REC_TIMING_LOOP_GAIN_0 +#define SI443X_CLOCK_REC_LOOP_GAIN_LSB 0b10001111 // 7 0 clock recovery timing loop gain LSB + +// SI443X_REG_RSSI_CLEAR_CHANNEL_THRESHOLD +#define SI443X_RSSI_CLEAR_CHANNEL_THRESHOLD 0b00011110 // 7 0 RSSI clear channel interrupt threshold + +// SI443X_REG_AFC_LIMITER +#define SI443X_AFC_LIMITER 0x00 // 7 0 AFC limiter value + +// SI443X_REG_OOK_COUNTER_1 +#define SI443X_OOK_FREEZE_OFF 0b00000000 // 5 5 OOK moving average detector freeze: disabled (default) +#define SI443X_OOK_FREEZE_ON 0b00100000 // 5 5 enabled +#define SI443X_PEAK_DETECTOR_OFF 0b00000000 // 4 4 peak detector: disabled +#define SI443X_PEAK_DETECTOR_ON 0b00010000 // 4 4 enabled (default) +#define SI443X_OOK_MOVING_AVERAGE_OFF 0b00000000 // 3 3 OOK moving average: disabled +#define SI443X_OOK_MOVING_AVERAGE_ON 0b00001000 // 3 3 enabled (default) +#define SI443X_OOK_COUNTER_MSB 0b00000000 // 2 0 OOK counter MSB + +// SI443X_REG_OOK_COUNTER_2 +#define SI443X_OOK_COUNTER_LSB 0b10111100 // 7 0 OOK counter LSB + +// SI443X_REG_SLICER_PEAK_HOLD +#define SI443X_PEAK_DETECTOR_ATTACK 0b00010000 // 6 4 OOK peak detector attach time +#define SI443X_PEAK_DETECTOR_DECAY 0b00001100 // 3 0 OOK peak detector decay time + +// SI443X_REG_DATA_ACCESS_CONTROL +#define SI443X_PACKET_RX_HANDLING_OFF 0b00000000 // 7 7 packet Rx handling: disabled +#define SI443X_PACKET_RX_HANDLING_ON 0b10000000 // 7 7 enabled (default) +#define SI443X_LSB_FIRST_OFF 0b00000000 // 6 6 LSB first transmission: disabled (default) +#define SI443X_LSB_FIRST_ON 0b01000000 // 6 6 enabled +#define SI443X_CRC_DATA_ONLY_OFF 0b00000000 // 5 5 CRC calculated only from data fields: disabled (default) +#define SI443X_CRC_DATA_ONLY_ON 0b00100000 // 5 5 enabled +#define SI443X_SKIP_SECOND_PHASE_PREAMBLE_DET_OFF 0b00000000 // 4 4 skip second phase of preamble detection: disabled (default) +#define SI443X_SKIP_SECOND_PHASE_PREAMBLE_DET_ON 0b00010000 // 4 4 enabled +#define SI443X_PACKET_TX_HANDLING_OFF 0b00000000 // 3 3 packet Tx handling: disabled +#define SI443X_PACKET_TX_HANDLING_ON 0b00001000 // 3 3 enabled (default) +#define SI443X_CRC_OFF 0b00000000 // 2 2 CRC: disabled +#define SI443X_CRC_ON 0b00000100 // 2 2 enabled (default) +#define SI443X_CRC_CCITT 0b00000000 // 1 0 CRC type: CCITT +#define SI443X_CRC_IBM_CRC16 0b00000001 // 1 0 IBM CRC-16 (default) +#define SI443X_CRC_IEC16 0b00000010 // 1 0 IEC-16 +#define SI443X_CRC_BIACHEVA 0b00000011 // 1 0 Biacheva + +// SI443X_REG_EZMAC_STATUS +#define SI443X_CRC_ALL_ONE 0b01000000 // 6 6 last received CRC was all ones +#define SI443X_PACKET_SEARCHING 0b00100000 // 5 5 radio is searching for a valid packet +#define SI443X_PACKET_RECEIVING 0b00010000 // 4 4 radio is currently receiving packet +#define SI443X_VALID_PACKET_RECEIVED 0b00001000 // 3 3 valid packet was received +#define SI443X_CRC_ERROR 0b00000100 // 2 2 CRC check failed +#define SI443X_PACKET_TRANSMITTING 0b00000010 // 1 1 radio is currently transmitting packet +#define SI443X_PACKET_SENT 0b00000001 // 0 0 packet sent + +// SI443X_REG_HEADER_CONTROL_1 +#define SI443X_BROADCAST_ADDR_CHECK_NONE 0b00000000 // 7 4 broadcast address check: none (default) +#define SI443X_BROADCAST_ADDR_CHECK_BYTE0 0b00010000 // 7 4 on byte 0 +#define SI443X_BROADCAST_ADDR_CHECK_BYTE1 0b00100000 // 7 4 on byte 1 +#define SI443X_BROADCAST_ADDR_CHECK_BYTE2 0b01000000 // 7 4 on byte 2 +#define SI443X_BROADCAST_ADDR_CHECK_BYTE3 0b10000000 // 7 4 on byte 3 +#define SI443X_RECEIVED_HEADER_CHECK_NONE 0b00000000 // 3 0 received header check: none +#define SI443X_RECEIVED_HEADER_CHECK_BYTE0 0b00000001 // 3 0 on byte 0 +#define SI443X_RECEIVED_HEADER_CHECK_BYTE1 0b00000010 // 3 0 on byte 1 +#define SI443X_RECEIVED_HEADER_CHECK_BYTE2 0b00000100 // 3 0 on byte 2 (default) +#define SI443X_RECEIVED_HEADER_CHECK_BYTE3 0b00001000 // 3 0 on byte 3 (default) + +// SI443X_REG_HEADER_CONTROL_2 +#define SI443X_SYNC_WORD_TIMEOUT_OFF 0b00000000 // 7 7 ignore timeout period when searching for sync word: disabled (default) +#define SI443X_SYNC_WORD_TIMEOUT_ON 0b10000000 // 7 7 enabled +#define SI443X_HEADER_LENGTH_HEADER_NONE 0b00000000 // 6 4 header length: none +#define SI443X_HEADER_LENGTH_HEADER_3 0b00010000 // 6 4 header 3 +#define SI443X_HEADER_LENGTH_HEADER_32 0b00100000 // 6 4 header 3 and 2 +#define SI443X_HEADER_LENGTH_HEADER_321 0b00110000 // 6 4 header 3, 2 and 1 (default) +#define SI443X_HEADER_LENGTH_HEADER_3210 0b01000000 // 6 4 header 3, 2, 1, and 0 +#define SI443X_FIXED_PACKET_LENGTH_OFF 0b00000000 // 3 3 fixed packet length mode: disabled (default) +#define SI443X_FIXED_PACKET_LENGTH_ON 0b00001000 // 3 3 enabled +#define SI443X_SYNC_LENGTH_SYNC_3 0b00000000 // 2 1 sync word length: sync 3 +#define SI443X_SYNC_LENGTH_SYNC_32 0b00000010 // 2 1 sync 3 and 2 (default) +#define SI443X_SYNC_LENGTH_SYNC_321 0b00000100 // 2 1 sync 3, 2 and 1 +#define SI443X_SYNC_LENGTH_SYNC_3210 0b00000110 // 2 1 sync 3, 2, 1 and 0 +#define SI443X_PREAMBLE_LENGTH_MSB 0b00000000 // 0 0 preamble length MSB + +// SI443X_REG_PREAMBLE_LENGTH +#define SI443X_PREAMBLE_LENGTH_LSB 0b00001000 // 0 0 preamble length LSB, defaults to 32 bits + +// SI443X_REG_PREAMBLE_DET_CONTROL +#define SI443X_PREAMBLE_DET_THRESHOLD 0b00101000 // 7 3 number of 4-bit nibbles in valid preamble, defaults to 20 bits +#define SI443X_RSSI_OFFSET 0b00000010 // 2 0 RSSI calculation offset, defaults to +8 dB + +// SI443X_REG_SYNC_WORD_3 - SI443X_REG_SYNC_WORD_0 +#define SI443X_SYNC_WORD_3 0x2D // 7 0 sync word: 4th byte (MSB) +#define SI443X_SYNC_WORD_2 0xD4 // 7 0 3rd byte +#define SI443X_SYNC_WORD_1 0x00 // 7 0 2nd byte +#define SI443X_SYNC_WORD_0 0x00 // 7 0 1st byte (LSB) + +// SI443X_REG_CHANNEL_FILTER_COEFF +#define SI443X_INVALID_PREAMBLE_THRESHOLD 0b00000000 // 7 4 invalid preamble threshold in nibbles + +// SI443X_REG_XOSC_CONTROL_TEST +#define SI443X_STATE_LOW_POWER 0b00000000 // 7 5 chip power state: low power +#define SI443X_STATE_READY 0b00100000 // 7 5 ready +#define SI443X_STATE_TUNE 0b01100000 // 7 5 tune +#define SI443X_STATE_TX 0b01000000 // 7 5 Tx +#define SI443X_STATE_RX 0b11100000 // 7 5 Rx + +// SI443X_REG_AGC_OVERRIDE_1 +#define SI443X_AGC_GAIN_INCREASE_OFF 0b00000000 // 6 6 AGC gain increase override: disabled (default) +#define SI443X_AGC_GAIN_INCREASE_ON 0b01000000 // 6 6 enabled +#define SI443X_AGC_OFF 0b00000000 // 5 5 AGC loop: disabled +#define SI443X_AGC_ON 0b00100000 // 5 5 enabled (default) +#define SI443X_LNA_GAIN_MIN 0b00000000 // 4 4 LNA gain select: 5 dB (default) +#define SI443X_LNA_GAIN_MAX 0b00010000 // 4 4 25 dB +#define SI443X_PGA_GAIN_OVERRIDE 0b00000000 // 3 0 PGA gain override, gain = SI443X_PGA_GAIN_OVERRIDE * 3 dB + +// SI443X_REG_TX_POWER +#define SI443X_LNA_SWITCH_OFF 0b00000000 // 3 3 LNA switch control: disabled +#define SI443X_LNA_SWITCH_ON 0b00001000 // 3 3 enabled (default) +#define SI443X_OUTPUT_POWER 0b00000000 // 2 0 output power in 3 dB steps, 0 is chip min, 7 is chip max + +// SI443X_REG_TX_DATA_RATE_1 + SI443X_REG_TX_DATA_RATE_0 +#define SI443X_DATA_RATE_MSB 0x0A // 7 0 data rate: DR = 10^6 * (SI443X_DATA_RATE / 2^16) in high data rate mode or +#define SI443X_DATA_RATE_LSB 0x3D // 7 0 DR = 10^6 * (SI443X_DATA_RATE / 2^21) in low data rate mode (defaults to 40 kbps) + +// SI443X_REG_MODULATION_MODE_CONTROL_1 +#define SI443X_HIGH_DATA_RATE_MODE 0b00000000 // 5 5 data rate: above 30 kbps (default) +#define SI443X_LOW_DATA_RATE_MODE 0b00100000 // 5 5 below 30 kbps +#define SI443X_PACKET_HANDLER_POWER_DOWN_OFF 0b00000000 // 4 4 power off packet handler in low power mode: disabled (default) +#define SI443X_PACKET_HANDLER_POWER_DOWN_ON 0b00010000 // 4 4 enabled +#define SI443X_MANCHESTER_PREAMBLE_POL_LOW 0b00000000 // 3 3 preamble polarity in Manchester mode: low +#define SI443X_MANCHESTER_PREAMBLE_POL_HIGH 0b00001000 // 3 3 high (default) +#define SI443X_MANCHESTER_INVERTED_OFF 0b00000000 // 2 2 inverted Manchester encoding: disabled +#define SI443X_MANCHESTER_INVERTED_ON 0b00000100 // 2 2 enabled (default) +#define SI443X_MANCHESTER_OFF 0b00000000 // 1 1 Manchester encoding: disabled (default) +#define SI443X_MANCHESTER_ON 0b00000010 // 1 1 enabled +#define SI443X_WHITENING_OFF 0b00000000 // 0 0 data whitening: disabled (default) +#define SI443X_WHITENING_ON 0b00000001 // 0 0 enabled + +// SI443X_REG_MODULATION_MODE_CONTROL_2 +#define SI443X_TX_DATA_CLOCK_NONE 0b00000000 // 7 6 Tx data clock: disabled (default) +#define SI443X_TX_DATA_CLOCK_GPIO 0b01000000 // 7 6 GPIO pin +#define SI443X_TX_DATA_CLOCK_SDI 0b10000000 // 7 6 SDI pin +#define SI443X_TX_DATA_CLOCK_NIRQ 0b11000000 // 7 6 nIRQ pin +#define SI443X_TX_DATA_SOURCE_GPIO 0b00000000 // 5 4 Tx data source in direct mode: GPIO pin (default) +#define SI443X_TX_DATA_SOURCE_SDI 0b00010000 // 5 4 SDI pin +#define SI443X_TX_DATA_SOURCE_FIFO 0b00100000 // 5 4 FIFO +#define SI443X_TX_DATA_SOURCE_PN9 0b00110000 // 5 4 PN9 internal +#define SI443X_TX_RX_INVERTED_OFF 0b00000000 // 3 3 Tx/Rx data inverted: disabled (default) +#define SI443X_TX_RX_INVERTED_ON 0b00001000 // 3 3 enabled +#define SI443X_FREQUENCY_DEVIATION_MSB 0b00000000 // 2 2 frequency deviation MSB +#define SI443X_MODULATION_NONE 0b00000000 // 1 0 modulation type: unmodulated carrier (default) +#define SI443X_MODULATION_OOK 0b00000001 // 1 0 OOK +#define SI443X_MODULATION_FSK 0b00000010 // 1 0 FSK +#define SI443X_MODULATION_GFSK 0b00000011 // 1 0 GFSK + +// SI443X_REG_FREQUENCY_DEVIATION +#define SI443X_FREQUENCY_DEVIATION_LSB 0b00100000 // 7 0 frequency deviation LSB, Fd = 625 Hz * SI443X_FREQUENCY_DEVIATION, defaults to 20 kHz + +// SI443X_REG_FREQUENCY_OFFSET_1 + SI443X_REG_FREQUENCY_OFFSET_2 +#define SI443X_FREQUENCY_OFFSET_MSB 0x00 // 7 0 frequency offset: +#define SI443X_FREQUENCY_OFFSET_LSB 0x00 // 1 0 Foff = 156.25 Hz * (SI443X_BAND_SELECT + 1) * SI443X_FREQUENCY_OFFSET, defaults to 156.25 Hz + +// SI443X_REG_FREQUENCY_BAND_SELECT +#define SI443X_SIDE_BAND_SELECT_LOW 0b00000000 // 6 6 Rx LO tuning: below channel frequency (default) +#define SI443X_SIDE_BAND_SELECT_HIGH 0b01000000 // 6 6 above channel frequency +#define SI443X_BAND_SELECT_LOW 0b00000000 // 5 5 band select: low, 240 - 479.9 MHz +#define SI443X_BAND_SELECT_HIGH 0b00100000 // 5 5 high, 480 - 960 MHz (default) +#define SI443X_FREQUENCY_BAND_SELECT 0b00010101 // 4 0 frequency band select + +// SI443X_REG_NOM_CARRIER_FREQUENCY_1 + SI443X_REG_NOM_CARRIER_FREQUENCY_0 +#define SI443X_NOM_CARRIER_FREQUENCY_MSB 0b10111011 // 7 0 nominal carrier frequency: +#define SI443X_NOM_CARRIER_FREQUENCY_LSB 0b10000000 // 7 0 Fc = (SI443X_BAND_SELECT + 1)*10*(SI443X_FREQUENCY_BAND_SELECT + 24) + (SI443X_NOM_CARRIER_FREQUENCY - SI443X_FREQUENCY_OFFSET)/6400 [MHz] + +// SI443X_REG_FREQUENCY_HOPPING_CHANNEL_SEL +#define SI443X_FREQUENCY_HOPPING_CHANNEL 0x00 // 7 0 frequency hopping channel number + +// SI443X_REG_FREQUENCY_HOPPING_STEP_SIZE +#define SI443X_FREQUENCY_HOPPING_STEP_SIZE 0x00 // 7 0 frequency hopping step size + +// SI443X_REG_TX_FIFO_CONTROL_1 +#define SI443X_TX_FIFO_ALMOST_FULL_THRESHOLD 0x37 // 5 0 Tx FIFO almost full threshold + +// SI443X_REG_TX_FIFO_CONTROL_2 +#define SI443X_TX_FIFO_ALMOST_EMPTY_THRESHOLD 0x04 // 5 0 Tx FIFO almost full threshold + +// SI443X_REG_RX_FIFO_CONTROL +#define SI443X_RX_FIFO_ALMOST_FULL_THRESHOLD 0x37 // 5 0 Rx FIFO almost full threshold + +/*! + \class Si443x + + \brief Base class for Si443x series. All derived classes for Si443x (e.g. Si4431 or Si4432) inherit from this base class. + This class should not be instantiated directly from Arduino sketch, only from its derived classes. +*/ +class Si443x: public PhysicalLayer { + public: + // introduce PhysicalLayer overloads + using PhysicalLayer::transmit; + using PhysicalLayer::receive; + using PhysicalLayer::startTransmit; + using PhysicalLayer::readData; + + // constructor + + /*! + \brief Default constructor. + + \param mod Instance of Module that will be used to communicate with the radio. + */ + Si443x(Module* mod); + + // basic methods + + /*! + \brief Initialization method. + + \param br Bit rate of the FSK transmission in kbps (kilobits per second). + + \param freqDev Frequency deviation of the FSK transmission in kHz. + + \param rxBw Receiver bandwidth in kHz. + + \returns \ref status_codes + */ + int16_t begin(float br, float freqDev, float rxBw); + + /*! + \brief Reset method. Will reset the chip to the default state using SDN pin. + */ + void reset(); + + /*! + \brief Binary transmit method. Will transmit arbitrary binary data up to 64 bytes long. + For overloads to transmit Arduino String or C-string, see PhysicalLayer::transmit. + + \param data Binary data that will be transmitted. + + \param len Length of binary data to transmit (in bytes). + + \param addr Node address to transmit the packet to. + + \returns \ref status_codes + */ + int16_t transmit(uint8_t* data, size_t len, uint8_t addr = 0); + + /*! + \brief Binary receive method. Will attempt to receive arbitrary binary data up to 64 bytes long. + For overloads to receive Arduino String, see PhysicalLayer::receive. + + \param data Pointer to array to save the received binary data. + + \param len Number of bytes that will be received. Must be known in advance for binary transmissions. + + \returns \ref status_codes + */ + int16_t receive(uint8_t* data, size_t len); + + /*! + \brief Sets the module to sleep to save power. %Module will not be able to transmit or receive any data while in sleep mode. + %Module will wake up automatically when methods like transmit or receive are called. + + \returns \ref status_codes + */ + int16_t sleep(); + + /*! + \brief Sets the module to standby. + + \returns \ref status_codes + */ + int16_t standby(); + + /*! + \brief Enables direct transmission mode. While in direct mode, the module will not be able to transmit or receive packets. + + \param FRF 24-bit raw frequency value to start transmitting at. Required for quick frequency shifts in RTTY. + + \returns \ref status_codes + */ + int16_t transmitDirect(uint32_t frf = 0); + + /*! + \brief Enables direct reception mode. While in direct mode, the module will not be able to transmit or receive packets. + + \returns \ref status_codes + */ + int16_t receiveDirect(); + + /*! + \brief Disables direct mode and enables packet mode, allowing the module to receive packets. + + \returns \ref status_codes + */ + int16_t packetMode(); + + // interrupt methods + + /*! + \brief Sets interrupt service routine to call when IRQ activates. + + \param func ISR to call. + */ + void setIrqAction(void (*func)(void)); + + /*! + \brief Clears interrupt service routine to call when IRQ activates. + */ + void clearIrqAction(); + + /*! + \brief Interrupt-driven binary transmit method. Will start transmitting arbitrary binary data up to 64 bytes long. + + \param data Binary data that will be transmitted. + + \param len Length of binary data to transmit (in bytes). + + \param addr Node address to transmit the packet to. + + \returns \ref status_codes + */ + int16_t startTransmit(uint8_t* data, size_t len, uint8_t addr = 0); + + /*! + \brief Interrupt-driven receive method. IRQ will be activated when full valid packet is received. + + \returns \ref status_codes + */ + int16_t startReceive(); + + /*! + \brief Reads data that was received after calling startReceive method. This method reads len characters. + + \param data Pointer to array to save the received binary data. + + \param len Number of bytes that will be received. Must be known in advance for binary transmissions. + + \returns \ref status_codes + */ + int16_t readData(uint8_t* data, size_t len); + + // configuration methods + + /*! + \brief Sets FSK bit rate. Allowed values range from 0.123 to 256.0 kbps. + + \param br Bit rate to be set (in kbps). + + \returns \ref status_codes + */ + int16_t setBitRate(float br); + + /*! + \brief Sets FSK frequency deviation from carrier frequency. Allowed values range from 0.625 to 320.0 kHz. + + \param freqDev Frequency deviation to be set (in kHz). + + \returns \ref status_codes + */ + int16_t setFrequencyDeviation(float freqDev); + + /*! + \brief Sets receiver bandwidth. Allowed values range from 2.6 to 620.7 kHz. + + \param rxBw Receiver bandwidth to be set in kHz. + + \returns \ref status_codes + */ + int16_t setRxBandwidth(float rxBw); + + /*! + \brief Sets sync word. Up to 4 bytes can be set as sync word. + + \param syncWord Pointer to the array of sync word bytes. + + \param len Sync word length in bytes. + */ + int16_t setSyncWord(uint8_t* syncWord, size_t len); + + /*! + \brief Query modem for the packet length of received payload. + + \param update Update received packet length. Will return cached value when set to false. + + \returns Length of last received packet in bytes. + */ + size_t getPacketLength(bool update = true); + + /*! + \brief Sets transmission encoding. Only available in FSK mode. + + \param encoding Encoding to be used. Set to 0 for NRZ, 1 for Manchester and 2 for whitening. + + \returns \ref status_codes + */ + int16_t setEncoding(uint8_t encoding); + + /*! + \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 + + \returns \ref status_codes + */ + int16_t setDataShaping(float sh); + +#ifndef RADIOLIB_GODMODE + protected: +#endif + Module* _mod; + + float _br; + float _freqDev; + + size_t _packetLength; + bool _packetLengthQueried; + + int16_t setFrequencyRaw(float newFreq); + +#ifndef RADIOLIB_GODMODE + private: +#endif + bool findChip(); + void clearIRQFlags(); + int16_t config(); + int16_t updateClockRecovery(); + int16_t directMode(); +}; + +#endif From 43295e6827855f007e0d9fc566465dc6e20c8b17 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 30 Mar 2020 17:38:21 +0200 Subject: [PATCH 22/57] Renamed range check macro --- src/BuildOpt.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/BuildOpt.h b/src/BuildOpt.h index 6e1a8690..2112e21a 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -184,7 +184,7 @@ /*! \brief Macro to check variable is within constraints - this is commonly used to check parameter ranges. */ -#define RADIOLIB_CHECK_CONSTRAINTS(VAR, MIN, MAX, ERR) { if(!(((VAR) >= (MIN)) && ((VAR) <= (MAX)))) { return(ERR); } } +#define RADIOLIB_CHECK_RANGE(VAR, MIN, MAX, ERR) { if(!(((VAR) >= (MIN)) && ((VAR) <= (MAX)))) { return(ERR); } } // version definitions From d795787c6ccd09cc9c6f8c88a69de79232f04833 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 30 Mar 2020 17:39:03 +0200 Subject: [PATCH 23/57] [AX25] Added note about Si443x support --- examples/AX25/AX25_Frames/AX25_Frames.ino | 15 ++++++++------- examples/AX25/AX25_Transmit/AX25_Transmit.ino | 3 ++- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/examples/AX25/AX25_Frames/AX25_Frames.ino b/examples/AX25/AX25_Frames/AX25_Frames.ino index 0d5ae5b6..c6af0ad8 100644 --- a/examples/AX25/AX25_Frames/AX25_Frames.ino +++ b/examples/AX25/AX25_Frames/AX25_Frames.ino @@ -11,6 +11,7 @@ - CC1101 - SX126x - nRF24 + - Si443x/RFM2x Using raw AX.25 frames requires some knowledge of the protocol, refer to @@ -48,7 +49,7 @@ void setup() { int state = fsk.beginFSK(434.0, 1.2, 0.5); // when using one of the non-LoRa modules for AX.25 - // (RF69, CC1101, etc.), use the basic begin() method + // (RF69, CC1101, Si4432 etc.), use the basic begin() method // int state = fsk.begin(); if(state == ERR_NONE) { @@ -83,10 +84,10 @@ void loop() { // control field: UI, P/F not used, unnumbered frame // protocol identifier: no layer 3 protocol implemented // information field: "Hello World!" - AX25Frame frameUI("NJ7P", 0, "N7LEM", 0, AX25_CONTROL_U_UNNUMBERED_INFORMATION | + AX25Frame frameUI("NJ7P", 0, "N7LEM", 0, AX25_CONTROL_U_UNNUMBERED_INFORMATION | AX25_CONTROL_POLL_FINAL_DISABLED | AX25_CONTROL_UNNUMBERED_FRAME, AX25_PID_NO_LAYER_3, "Hello World (unnumbered)!"); - + // send the frame Serial.print(F("[AX.25] Sending UI frame ... ")); int state = ax25.sendFrame(&frameUI); @@ -109,12 +110,12 @@ void loop() { // source station callsign: "N7LEM" // source station SSID: 0 // control field: RR, P/F not used, supervisory frame - AX25Frame frameRR("NJ7P", 0, "N7LEM", 0, AX25_CONTROL_S_RECEIVE_READY | + AX25Frame frameRR("NJ7P", 0, "N7LEM", 0, AX25_CONTROL_S_RECEIVE_READY | AX25_CONTROL_POLL_FINAL_DISABLED | AX25_CONTROL_SUPERVISORY_FRAME); // set receive sequence number (0 - 7) frameRR.setRecvSequence(0); - + // send the frame Serial.print(F("[AX.25] Sending RR frame ... ")); state = ax25.sendFrame(&frameRR); @@ -139,7 +140,7 @@ void loop() { // control field: P/F not used, information frame // protocol identifier: no layer 3 protocol implemented // information field: "Hello World (numbered)!" - AX25Frame frameI("NJ7P", 0, "N7LEM", 0, AX25_CONTROL_POLL_FINAL_DISABLED | + AX25Frame frameI("NJ7P", 0, "N7LEM", 0, AX25_CONTROL_POLL_FINAL_DISABLED | AX25_CONTROL_INFORMATION_FRAME, AX25_PID_NO_LAYER_3, "Hello World (numbered)!"); @@ -148,7 +149,7 @@ void loop() { // set send sequence number (0 - 7) frameI.setSendSequence(0); - + // send the frame Serial.print(F("[AX.25] Sending I frame ... ")); state = ax25.sendFrame(&frameI); diff --git a/examples/AX25/AX25_Transmit/AX25_Transmit.ino b/examples/AX25/AX25_Transmit/AX25_Transmit.ino index ac0eb1d2..0a462eff 100644 --- a/examples/AX25/AX25_Transmit/AX25_Transmit.ino +++ b/examples/AX25/AX25_Transmit/AX25_Transmit.ino @@ -11,6 +11,7 @@ - CC1101 - SX126x - nRF24 + - Si443x/RFM2x */ // include the library @@ -41,7 +42,7 @@ void setup() { int state = fsk.beginFSK(434.0, 1.2, 0.5); // when using one of the non-LoRa modules for AX.25 - // (RF69, CC1101, etc.), use the basic begin() method + // (RF69, CC1101,, Si4432 etc.), use the basic begin() method // int state = fsk.begin(); if(state == ERR_NONE) { From 0cdee788dd067e829ae9b6a6ff1fd26bcbaf589e Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 30 Mar 2020 17:39:13 +0200 Subject: [PATCH 24/57] [Morse] Added note about Si443x support --- examples/Morse/Morse_Transmit/Morse_Transmit.ino | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/Morse/Morse_Transmit/Morse_Transmit.ino b/examples/Morse/Morse_Transmit/Morse_Transmit.ino index 6d71d1a4..0cf02e6e 100644 --- a/examples/Morse/Morse_Transmit/Morse_Transmit.ino +++ b/examples/Morse/Morse_Transmit/Morse_Transmit.ino @@ -11,6 +11,7 @@ - CC1101 - SX126x - nRF24 + - Si443x/RFM2x */ // include the library @@ -45,7 +46,7 @@ void setup() { int state = fsk.beginFSK(); // when using one of the non-LoRa modules for Morse code - // (RF69, CC1101, etc.), use the basic begin() method + // (RF69, CC1101, Si4432 etc.), use the basic begin() method // int state = fsk.begin(); if(state == ERR_NONE) { From 46e5f88bf106308a250b335696a8579152b8607c Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 30 Mar 2020 17:39:47 +0200 Subject: [PATCH 25/57] [RTTY] Added note about Si443x support --- examples/RTTY/RTTY_Transmit/RTTY_Transmit.ino | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/examples/RTTY/RTTY_Transmit/RTTY_Transmit.ino b/examples/RTTY/RTTY_Transmit/RTTY_Transmit.ino index da77ea5b..d456b041 100644 --- a/examples/RTTY/RTTY_Transmit/RTTY_Transmit.ino +++ b/examples/RTTY/RTTY_Transmit/RTTY_Transmit.ino @@ -11,6 +11,7 @@ - CC1101 - SX126x - nRF24 + - Si443x/RFM2x For full API reference, see the GitHub Pages https://jgromes.github.io/RadioLib/ @@ -48,7 +49,7 @@ void setup() { int state = fsk.beginFSK(); // when using one of the non-LoRa modules for RTTY - // (RF69, CC1101, etc.), use the basic begin() method + // (RF69, CC1101, Si4432 etc.), use the basic begin() method // int state = fsk.begin(); if(state == ERR_NONE) { @@ -63,11 +64,12 @@ void setup() { // NOTE: RTTY frequency shift will be rounded // to the nearest multiple of frequency step size. // The exact value depends on the module: - // SX127x - 61 Hz + // SX127x/RFM9x - 61 Hz // RF69 - 61 Hz // CC1101 - 397 Hz // SX126x - 1 Hz // nRF24 - 1000000 Hz + // Si443x/RFM2x - 156 Hz Serial.print(F("[RTTY] Initializing ... ")); // low ("space") frequency: 434.0 MHz // frequency shift: 183 Hz From d58a4c008e6fcabcb6a26b2e927210dd4b302113 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 30 Mar 2020 19:27:17 +0200 Subject: [PATCH 26/57] [nRF24] Using range check macro --- src/modules/nRF24/nRF24.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/modules/nRF24/nRF24.cpp b/src/modules/nRF24/nRF24.cpp index 7316f2f0..a05d52e3 100644 --- a/src/modules/nRF24/nRF24.cpp +++ b/src/modules/nRF24/nRF24.cpp @@ -225,14 +225,11 @@ int16_t nRF24::readData(uint8_t* data, size_t len) { } int16_t nRF24::setFrequency(int16_t freq) { - // check allowed range - if(!((freq >= 2400) && (freq <= 2525))) { - return(ERR_INVALID_FREQUENCY); - } + RADIOLIB_CHECK_RANGE(freq, 2400, 2525, ERR_INVALID_FREQUENCY); // set frequency uint8_t freqRaw = freq - 2400; - return _mod->SPIsetRegValue(NRF24_REG_RF_CH, freqRaw, 6, 0); + return(_mod->SPIsetRegValue(NRF24_REG_RF_CH, freqRaw, 6, 0)); } int16_t nRF24::setDataRate(int16_t dataRate) { @@ -420,7 +417,7 @@ int16_t nRF24::getStatus(uint8_t mask) { } bool nRF24::isCarrierDetected() { - return(_mod->SPIgetRegValue(NRF24_REG_RPD, 0,0)) == 1; + return(_mod->SPIgetRegValue(NRF24_REG_RPD, 0, 0) == 1); } int16_t nRF24::setFrequencyDeviation(float freqDev) { From 274b38d55618007c0848106e16b54f47c6bda679 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 30 Mar 2020 19:29:29 +0200 Subject: [PATCH 27/57] [SX127x] Using range check macro --- src/modules/SX127x/SX1272.cpp | 5 +---- src/modules/SX127x/SX1276.cpp | 5 +---- src/modules/SX127x/SX1277.cpp | 5 +---- src/modules/SX127x/SX1278.cpp | 5 +---- src/modules/SX127x/SX1279.cpp | 5 +---- src/modules/SX127x/SX127x.cpp | 22 +++++----------------- 6 files changed, 10 insertions(+), 37 deletions(-) diff --git a/src/modules/SX127x/SX1272.cpp b/src/modules/SX127x/SX1272.cpp index 06646d1f..28fedba3 100644 --- a/src/modules/SX127x/SX1272.cpp +++ b/src/modules/SX127x/SX1272.cpp @@ -66,10 +66,7 @@ void SX1272::reset() { } int16_t SX1272::setFrequency(float freq) { - // check frequency range - if((freq < 860.0) || (freq > 1020.0)) { - return(ERR_INVALID_FREQUENCY); - } + RADIOLIB_CHECK_RANGE(freq, 860.0, 1020.0, ERR_INVALID_FREQUENCY); // set frequency and if successful, save the new setting int16_t state = SX127x::setFrequencyRaw(freq); diff --git a/src/modules/SX127x/SX1276.cpp b/src/modules/SX127x/SX1276.cpp index 40a141a4..2fecd63a 100644 --- a/src/modules/SX127x/SX1276.cpp +++ b/src/modules/SX127x/SX1276.cpp @@ -35,10 +35,7 @@ int16_t SX1276::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync } int16_t SX1276::setFrequency(float freq) { - // check frequency range - if((freq < 137.0) || (freq > 1020.0)) { - return(ERR_INVALID_FREQUENCY); - } + RADIOLIB_CHECK_RANGE(freq, 137.0, 1020.0, ERR_INVALID_FREQUENCY); // SX1276/77/78 Errata fixes if(getActiveModem() == SX127X_LORA) { diff --git a/src/modules/SX127x/SX1277.cpp b/src/modules/SX127x/SX1277.cpp index bed5a84e..715d8853 100644 --- a/src/modules/SX127x/SX1277.cpp +++ b/src/modules/SX127x/SX1277.cpp @@ -35,10 +35,7 @@ int16_t SX1277::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync } int16_t SX1277::setFrequency(float freq) { - // check frequency range - if((freq < 137.0) || (freq > 1020.0)) { - return(ERR_INVALID_FREQUENCY); - } + RADIOLIB_CHECK_RANGE(freq, 137.0, 1020.0, ERR_INVALID_FREQUENCY); // SX1276/77/78 Errata fixes if(getActiveModem() == SX127X_LORA) { diff --git a/src/modules/SX127x/SX1278.cpp b/src/modules/SX127x/SX1278.cpp index 5989aa13..af3fc0b3 100644 --- a/src/modules/SX127x/SX1278.cpp +++ b/src/modules/SX127x/SX1278.cpp @@ -61,10 +61,7 @@ void SX1278::reset() { } int16_t SX1278::setFrequency(float freq) { - // check frequency range - if((freq < 137.0) || (freq > 525.0)) { - return(ERR_INVALID_FREQUENCY); - } + RADIOLIB_CHECK_RANGE(freq, 137.0, 525.0, ERR_INVALID_FREQUENCY); // SX1276/77/78 Errata fixes if(getActiveModem() == SX127X_LORA) { diff --git a/src/modules/SX127x/SX1279.cpp b/src/modules/SX127x/SX1279.cpp index 3468b0b1..1b45c9b7 100644 --- a/src/modules/SX127x/SX1279.cpp +++ b/src/modules/SX127x/SX1279.cpp @@ -35,10 +35,7 @@ int16_t SX1279::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t sync } int16_t SX1279::setFrequency(float freq) { - // check frequency range - if((freq < 137.0) || (freq > 960.0)) { - return(ERR_INVALID_FREQUENCY); - } + RADIOLIB_CHECK_RANGE(freq, 137.0, 960.0, ERR_INVALID_FREQUENCY); // set frequency return(SX127x::setFrequencyRaw(freq)); diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 5eab0195..15053fd9 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -647,13 +647,9 @@ int16_t SX127x::setBitRate(float br) { // check allowed bit rate if(_ook) { - if((br < 1.2) || (br > 32.768)) { - return(ERR_INVALID_BIT_RATE); - } + RADIOLIB_CHECK_RANGE(br, 1.2, 32.768, ERR_INVALID_BIT_RATE); } else { - if((br < 1.2) || (br > 300.0)) { - return(ERR_INVALID_BIT_RATE); - } + RADIOLIB_CHECK_RANGE(br, 1.2, 300.0, ERR_INVALID_BIT_RATE); } // set mode to STANDBY @@ -701,10 +697,7 @@ int16_t SX127x::setRxBandwidth(float rxBw) { return(ERR_WRONG_MODEM); } - // check allowed bandwidth values - if(!((rxBw >= 2.6) && (rxBw <= 250.0))) { - return(ERR_INVALID_RX_BANDWIDTH); - } + RADIOLIB_CHECK_RANGE(rxBw, 2.6, 250.0, ERR_INVALID_RX_BANDWIDTH); // set mode to STANDBY int16_t state = setMode(SX127X_STANDBY); @@ -738,10 +731,7 @@ int16_t SX127x::setSyncWord(uint8_t* syncWord, size_t len) { return(ERR_WRONG_MODEM); } - // check constraints - if((len > 8) || (len < 1)) { - return(ERR_INVALID_SYNC_WORD); - } + RADIOLIB_CHECK_RANGE(len, 1, 8, ERR_INVALID_SYNC_WORD); // sync word must not contain value 0x00 for(uint8_t i = 0; i < len; i++) { @@ -887,9 +877,7 @@ int16_t SX127x::setRSSIConfig(uint8_t smoothingSamples, int8_t offset) { return(ERR_INVALID_NUM_SAMPLES); } - if(!((offset >= -16) && (offset <= 15))) { - return(ERR_INVALID_RSSI_OFFSET); - } + RADIOLIB_CHECK_RANGE(offset, -16, 15, ERR_INVALID_RSSI_OFFSET); // set new register values state = _mod->SPIsetRegValue(SX127X_REG_RSSI_CONFIG, offset, 7, 3); From 08e4c3b13be181e8ca82a254e51775d04660925e Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 30 Mar 2020 19:29:55 +0200 Subject: [PATCH 28/57] [RFM9x] Using range check macro --- src/modules/RFM9x/RFM95.cpp | 5 +---- src/modules/RFM9x/RFM96.cpp | 5 +---- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/src/modules/RFM9x/RFM95.cpp b/src/modules/RFM9x/RFM95.cpp index 72df63c4..49557190 100644 --- a/src/modules/RFM9x/RFM95.cpp +++ b/src/modules/RFM9x/RFM95.cpp @@ -35,10 +35,7 @@ int16_t RFM95::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncW } int16_t RFM95::setFrequency(float freq) { - // check frequency range - if((freq < 868.0) || (freq > 915.0)) { - return(ERR_INVALID_FREQUENCY); - } + RADIOLIB_CHECK_RANGE(freq, 868.0, 915.0, ERR_INVALID_FREQUENCY); // set frequency return(SX127x::setFrequencyRaw(freq)); diff --git a/src/modules/RFM9x/RFM96.cpp b/src/modules/RFM9x/RFM96.cpp index 1e045536..cf81ca40 100644 --- a/src/modules/RFM9x/RFM96.cpp +++ b/src/modules/RFM9x/RFM96.cpp @@ -35,10 +35,7 @@ int16_t RFM96::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint8_t syncW } int16_t RFM96::setFrequency(float freq) { - // check frequency range - if((freq < 433.0) || (freq > 470.0)) { - return(ERR_INVALID_FREQUENCY); - } + RADIOLIB_CHECK_RANGE(freq, 433.0, 470.0, ERR_INVALID_FREQUENCY); // set frequency return(SX127x::setFrequencyRaw(freq)); From 7f083bb0837a8efa1836d5fef0858a835c32bd10 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 30 Mar 2020 19:31:02 +0200 Subject: [PATCH 29/57] [SX126x] Using range check macro --- src/modules/SX126x/SX1261.cpp | 5 +---- src/modules/SX126x/SX1262.cpp | 10 ++-------- src/modules/SX126x/SX1268.cpp | 10 ++-------- src/modules/SX126x/SX126x.cpp | 37 ++++++++++++----------------------- 4 files changed, 17 insertions(+), 45 deletions(-) diff --git a/src/modules/SX126x/SX1261.cpp b/src/modules/SX126x/SX1261.cpp index dcf34fac..a78d2578 100644 --- a/src/modules/SX126x/SX1261.cpp +++ b/src/modules/SX126x/SX1261.cpp @@ -5,10 +5,7 @@ SX1261::SX1261(Module* mod): SX1262(mod) { } int16_t SX1261::setOutputPower(int8_t power) { - // check allowed power range - if (!((power >= -17) && (power <= 14))) { - return(ERR_INVALID_OUTPUT_POWER); - } + RADIOLIB_CHECK_RANGE(power, -17, 14, ERR_INVALID_OUTPUT_POWER); // get current OCP configuration uint8_t ocp = 0; diff --git a/src/modules/SX126x/SX1262.cpp b/src/modules/SX126x/SX1262.cpp index 3a9d211a..7d1f6efe 100644 --- a/src/modules/SX126x/SX1262.cpp +++ b/src/modules/SX126x/SX1262.cpp @@ -39,10 +39,7 @@ int16_t SX1262::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t } int16_t SX1262::setFrequency(float freq, bool calibrate) { - // check frequency range - if((freq < 150.0) || (freq > 960.0)) { - return(ERR_INVALID_FREQUENCY); - } + RADIOLIB_CHECK_RANGE(freq, 150.0, 960.0, ERR_INVALID_FREQUENCY); int16_t state = ERR_NONE; @@ -74,10 +71,7 @@ int16_t SX1262::setFrequency(float freq, bool calibrate) { } int16_t SX1262::setOutputPower(int8_t power) { - // check allowed power range - if (!((power >= -17) && (power <= 22))) { - return(ERR_INVALID_OUTPUT_POWER); - } + RADIOLIB_CHECK_RANGE(power, -17, 22, ERR_INVALID_OUTPUT_POWER); // get current OCP configuration uint8_t ocp = 0; diff --git a/src/modules/SX126x/SX1268.cpp b/src/modules/SX126x/SX1268.cpp index b6daa489..6b7f3ad2 100644 --- a/src/modules/SX126x/SX1268.cpp +++ b/src/modules/SX126x/SX1268.cpp @@ -38,10 +38,7 @@ int16_t SX1268::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t } int16_t SX1268::setFrequency(float freq, bool calibrate) { - // check frequency range - if((freq < 410.0) || (freq > 810.0)) { - return(ERR_INVALID_FREQUENCY); - } + RADIOLIB_CHECK_RANGE(freq, 410.0, 810.0, ERR_INVALID_FREQUENCY); int16_t state = ERR_NONE; @@ -67,10 +64,7 @@ int16_t SX1268::setFrequency(float freq, bool calibrate) { } int16_t SX1268::setOutputPower(int8_t power) { - // check allowed power range - if(!((power >= -9) && (power <= 22))) { - return(ERR_INVALID_OUTPUT_POWER); - } + RADIOLIB_CHECK_RANGE(power, -9, 22, ERR_INVALID_OUTPUT_POWER); // get current OCP configuration uint8_t ocp = 0; diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 5754893f..93b98dc7 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -140,10 +140,10 @@ int16_t SX126x::beginFSK(float br, float freqDev, float rxBw, float currentLimit state = setDio2AsRfSwitch(false); RADIOLIB_ASSERT(state); - if (useRegulatorLDO) { - state = setRegulatorLDO(); + if(useRegulatorLDO) { + state = setRegulatorLDO(); } else { - state = setRegulatorDCDC(); + state = setRegulatorDCDC(); } return(state); @@ -580,12 +580,10 @@ int16_t SX126x::setBandwidth(float bw) { return(ERR_WRONG_MODEM); } - // ensure byte conversion doesn't overflow: - if(!((bw > 0) && (bw < 510))) { - return(ERR_INVALID_BANDWIDTH); - } + // ensure byte conversion doesn't overflow + RADIOLIB_CHECK_RANGE(bw, 0.0, 510.0, ERR_INVALID_BANDWIDTH); - // check alowed bandwidth values + // check allowed bandwidth values uint8_t bw_div2 = bw / 2 + 0.01; switch (bw_div2) { case 3: // 7.8: @@ -633,10 +631,7 @@ int16_t SX126x::setSpreadingFactor(uint8_t sf) { return(ERR_WRONG_MODEM); } - // check allowed spreading factor values - if(!((sf >= 5) && (sf <= 12))) { - return(ERR_INVALID_SPREADING_FACTOR); - } + RADIOLIB_CHECK_RANGE(sf, 5, 12, ERR_INVALID_SPREADING_FACTOR); // update modulation parameters _sf = sf; @@ -649,10 +644,7 @@ int16_t SX126x::setCodingRate(uint8_t cr) { return(ERR_WRONG_MODEM); } - // check allowed spreading factor values - if(!((cr >= 5) && (cr <= 8))) { - return(ERR_INVALID_CODING_RATE); - } + RADIOLIB_CHECK_RANGE(cr, 5, 8, ERR_INVALID_CODING_RATE); // update modulation parameters _cr = cr - 4; @@ -711,10 +703,7 @@ int16_t SX126x::setFrequencyDeviation(float freqDev) { return(ERR_WRONG_MODEM); } - // check allowed frequency deviation values - if(!(freqDev <= 200.0)) { - return(ERR_INVALID_FREQUENCY_DEVIATION); - } + RADIOLIB_CHECK_RANGE(freqDev, 0.0, 200.0, ERR_INVALID_FREQUENCY_DEVIATION); // calculate raw frequency deviation value uint32_t freqDevRaw = (uint32_t)(((freqDev * 1000.0) * (float)((uint32_t)(1) << 25)) / (SX126X_CRYSTAL_FREQ * 1000000.0)); @@ -735,10 +724,7 @@ int16_t SX126x::setBitRate(float br) { return(ERR_WRONG_MODEM); } - // check allowed bit rate values - if(!((br >= 0.6) && (br <= 300.0))) { - return(ERR_INVALID_BIT_RATE); - } + RADIOLIB_CHECK_RANGE(br, 0.6, 300.0, ERR_INVALID_BIT_RATE); // calculate raw bit rate value uint32_t brRaw = (uint32_t)((SX126X_CRYSTAL_FREQ * 1000000.0 * 32.0) / (br * 1000.0)); @@ -1002,12 +988,13 @@ int16_t SX126x::setWhitening(bool enabled, uint16_t initial) { } int16_t state = ERR_NONE; - if(enabled != true) { + if(!enabled) { // disable whitening _whitening = SX126X_GFSK_WHITENING_OFF; state = setPacketParamsFSK(_preambleLengthFSK, _crcTypeFSK, _syncWordLength, _addrComp, _whitening, _packetType); RADIOLIB_ASSERT(state); + } else { // enable whitening _whitening = SX126X_GFSK_WHITENING_ON; From 532c1e6fe94eecbb7644de14db0b7ff9e16e73be Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 30 Mar 2020 19:31:20 +0200 Subject: [PATCH 30/57] [RF69] Using range check macro --- src/modules/RF69/RF69.cpp | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/modules/RF69/RF69.cpp b/src/modules/RF69/RF69.cpp index 2ef86d4e..2e2eab0e 100644 --- a/src/modules/RF69/RF69.cpp +++ b/src/modules/RF69/RF69.cpp @@ -359,10 +359,7 @@ int16_t RF69::setFrequency(float freq) { } int16_t RF69::setBitRate(float br) { - // check allowed bitrate - if((br < 1.2) || (br > 300.0)) { - return(ERR_INVALID_BIT_RATE); - } + RADIOLIB_CHECK_RANGE(br, 1.2, 300.0, ERR_INVALID_BIT_RATE); // check bitrate-bandwidth ratio if(!(br < 2000 * _rxBw)) { @@ -496,10 +493,7 @@ int16_t RF69::setFrequencyDeviation(float freqDev) { } int16_t RF69::setOutputPower(int8_t power) { - // check output power range - if((power < -18) || (power > 17)) { - return(ERR_INVALID_OUTPUT_POWER); - } + RADIOLIB_CHECK_RANGE(power, -18, 17, ERR_INVALID_OUTPUT_POWER); // set mode to standby setMode(RF69_STANDBY); From 75b9395349ad53bd78901d64a115f3a64f5af968 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 30 Mar 2020 19:31:52 +0200 Subject: [PATCH 31/57] [CC1101] Using range check macro --- src/modules/CC1101/CC1101.cpp | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index 823b6b27..f05fa32e 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -322,10 +322,7 @@ int16_t CC1101::setFrequency(float freq) { } int16_t CC1101::setBitRate(float br) { - // check allowed bit rate range - if(!((br >= 0.025) && (br <= 600.0))) { - return(ERR_INVALID_BIT_RATE); - } + RADIOLIB_CHECK_RANGE(br, 0.025, 600.0, ERR_INVALID_BIT_RATE); // set mode to standby SPIsendCommand(CC1101_CMD_IDLE); @@ -342,10 +339,7 @@ int16_t CC1101::setBitRate(float br) { } int16_t CC1101::setRxBandwidth(float rxBw) { - // check allowed bandwidth range - if(!((rxBw >= 58.0) && (rxBw <= 812.0))) { - return(ERR_INVALID_RX_BANDWIDTH); - } + RADIOLIB_CHECK_RANGE(rxBw, 58.0, 812.0, ERR_INVALID_RX_BANDWIDTH); // set mode to standby SPIsendCommand(CC1101_CMD_IDLE); @@ -372,10 +366,7 @@ int16_t CC1101::setFrequencyDeviation(float freqDev) { return(state); } - // check allowed frequency deviation range - if(!((freqDev >= 1.587) && (freqDev <= 380.8))) { - return(ERR_INVALID_FREQUENCY_DEVIATION); - } + RADIOLIB_CHECK_RANGE(freqDev, 1.587, 380.8, ERR_INVALID_FREQUENCY_DEVIATION); // set mode to standby SPIsendCommand(CC1101_CMD_IDLE); @@ -535,9 +526,7 @@ int16_t CC1101::setPreambleLength(uint8_t preambleLength) { int16_t CC1101::setNodeAddress(uint8_t nodeAddr, uint8_t numBroadcastAddrs) { - if(!(numBroadcastAddrs > 0) && (numBroadcastAddrs <= 2)) { - return(ERR_INVALID_NUM_BROAD_ADDRS); - } + RADIOLIB_CHECK_RANGE(numBroadcastAddrs, 1, 2, ERR_INVALID_NUM_BROAD_ADDRS); // enable address filtering int16_t state = SPIsetRegValue(CC1101_REG_PKTCTRL1, numBroadcastAddrs + 0x01, 1, 0); From c39c4f6b0d8ecfda140dd413cc656ee29f54ff9c Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 31 Mar 2020 17:31:10 +0200 Subject: [PATCH 32/57] [SSTV] Added SSTV support --- README.md | 1 + examples/SSTV/SSTV_Transmit/SSTV_Transmit.ino | 160 +++++++++++ keywords.txt | 19 ++ src/RadioLib.h | 1 + src/protocols/SSTV/SSTV.cpp | 266 ++++++++++++++++++ src/protocols/SSTV/SSTV.h | 123 ++++++++ 6 files changed, 570 insertions(+) create mode 100644 examples/SSTV/SSTV_Transmit/SSTV_Transmit.ino create mode 100644 src/protocols/SSTV/SSTV.cpp create mode 100644 src/protocols/SSTV/SSTV.h diff --git a/README.md b/README.md index 0a789d21..9f5e2dc0 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,7 @@ RadioLib was originally created as a driver for [__RadioShield__](https://github * __RTTY__ for modules: SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, nRF24L01, RFM2x and Si443x * __Morse Code__ for modules: SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, nRF24L01, RFM2x and Si443x * __AX.25__ for modules: SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, RFM2x and Si443x +* __SSTV__ for modules: SX127x, RFM9x, SX126x, RF69 and SX1231 ### Supported platforms: * __Arduino AVR__ - tested with hardware on Uno, Mega and Leonardo diff --git a/examples/SSTV/SSTV_Transmit/SSTV_Transmit.ino b/examples/SSTV/SSTV_Transmit/SSTV_Transmit.ino new file mode 100644 index 00000000..92bdde6f --- /dev/null +++ b/examples/SSTV/SSTV_Transmit/SSTV_Transmit.ino @@ -0,0 +1,160 @@ +/* + RadioLib SSTV Transmit Example + + The following example sends SSTV picture using + SX1278's FSK modem. + + Other modules that can be used for SSTV: + - SX127x/RFM9x + - RF69 + - SX1231 + - SX126x + + NOTE: SSTV is an analog modulation, and + requires precise frequency control. + Some of the above modules can only + set their frequency in rough steps, + so the result can be distorted. + Using high-precision radio with TCXO + (like SX126x) is recommended. + + NOTE: Some platforms (such as Arduino Uno) + might not be fast enough to correctly + send pictures via high-speed modes + like Scottie2 or Martin2. For those, + lower speed modes such as Wrasse, + Scottie1 or Martin1 are recommended. + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1278 has the following connections: +// NSS pin: 10 +// DIO0 pin: 2 +// RESET pin: 9 +// DIO1 pin: 3 +SX1278 fsk = new Module(10, 2, 9, 3); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1278 fsk = RadioShield.ModuleA; + +// create SSTV client instance using the FSK module +SSTVClient sstv(&fsk); + +// test "image" - actually just a single 320px line +// will be sent over and over again, to create vertical color stripes at the receiver +uint32_t line[320] = { + // black + 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, + 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, + + // blue + 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, + 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, 0x0000FF, + + // green + 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, + 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, 0x00FF00, + + // cyan + 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, + 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF, + + // red + 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, + 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, + + // magenta + 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, + 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, + + // yellow + 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, + 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, 0xFFFF00, + + // white + 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, + 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF, 0xFFFFFF +}; + +void setup() { + Serial.begin(9600); + + // initialize SX1278 + Serial.print(F("[SX1278] Initializing ... ")); + // carrier frequency: 434.0 MHz + // bit rate: 48.0 kbps + // frequency deviation: 50.0 kHz + // Rx bandwidth: 125.0 kHz + // output power: 13 dBm + // current limit: 100 mA + // sync word: 0x2D 0x01 + int state = fsk.beginFSK(); + if (state == ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // when using one of the non-LoRa modules for SSTV + // (RF69, SX1231 etc.), use the basic begin() method + // int state = fsk.begin(); + + // initialize SSTV client + Serial.print(F("[SSTV] Initializing ... ")); + // 0 Hz tone frequency: 434.0 MHz + // SSTV mode: Wrasse (SC2-180) + // correction factor: 0.95 + // NOTE: Due to different speeds of various platforms + // supported by RadioLib (Arduino Uno, ESP32 etc), + // and because SSTV is analog protocol, incorrect + // timing of pulses can lead to distortions. + // To compensate, correction factor can be used + // to adjust the length of timing pulses + // (lower number = shorter pulses). + // The value is usually around 0.95 (95%). + state = sstv.begin(434.0, Wrasse, 0.95); + if(state == ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // to help tune the receiver, SSTVClient can send + // continuous beep at the frequency corresponding to + // 1900 Hz in upper sideband (aka USB) modulation + // (SSTV header "leader tone") + /* + sstv.idle(); + while(true); + */ +} + +void loop() { + // send picture with 8 color stripes + Serial.print(F("[SSTV] Sending test picture ... ")); + + // send synchronization header first + sstv.sendHeader(); + + // send all picture lines + for(uint16_t i = 0; i < sstv.getPictureHeight(); i++) { + sstv.sendLine(line); + } + + // turn off transmitter + fsk.standby(); + + Serial.println(F("done!")); + + delay(30000); +} diff --git a/keywords.txt b/keywords.txt index bcf0f9fd..57b8b822 100644 --- a/keywords.txt +++ b/keywords.txt @@ -10,6 +10,7 @@ RadioLib KEYWORD1 RadioShield KEYWORD1 Module KEYWORD1 +# modules CC1101 KEYWORD1 ESP8266 KEYWORD1 HC05 KEYWORD1 @@ -39,6 +40,7 @@ SX1279 KEYWORD1 XBee KEYWORD1 XBeeSerial KEYWORD1 +# protocols MQTTClient KEYWORD1 HTTPClient KEYWORD1 RTTYClient KEYWORD1 @@ -46,6 +48,18 @@ MorseClient KEYWORD1 PagerClient KEYWORD1 AX25Client KEYWORD1 AX25Frame KEYWORD1 +SSTVClient KEYWORD1 + +# SSTV modes +Scottie1 KEYWORD1 +Scottie2 KEYWORD1 +ScottieDX KEYWORD1 +Martin1 KEYWORD1 +Martin2 KEYWORD1 +Wrasse KEYWORD1 +PasokonP3 KEYWORD1 +PasokonP5 KEYWORD1 +PasokonP7 KEYWORD1 ####################################### # Methods and Functions (KEYWORD2) @@ -190,6 +204,11 @@ setRecvSequence KEYWORD2 setSendSequence KEYWORD2 sendFrame KEYWORD2 +# SSTV +sendHeader KEYWORD2 +sendLine KEYWORD2 +getPictureHeight KEYWORD2 + ####################################### # Constants (LITERAL1) ####################################### diff --git a/src/RadioLib.h b/src/RadioLib.h index 16947fbd..bb5e085e 100644 --- a/src/RadioLib.h +++ b/src/RadioLib.h @@ -75,6 +75,7 @@ #include "protocols/AX25/AX25.h" #include "protocols/Morse/Morse.h" #include "protocols/RTTY/RTTY.h" +#include "protocols/SSTV/SSTV.h" // transport layer protocols #include "protocols/TransportLayer/TransportLayer.h" diff --git a/src/protocols/SSTV/SSTV.cpp b/src/protocols/SSTV/SSTV.cpp new file mode 100644 index 00000000..dfbeea30 --- /dev/null +++ b/src/protocols/SSTV/SSTV.cpp @@ -0,0 +1,266 @@ +#include "SSTV.h" + +const SSTVMode_t Scottie1 { + .visCode = SSTV_SCOTTIE_1, + .width = 320, + .height = 256, + .scanPixelLen = 432, + .numTones = 7, + .tones = { + { .type = tone_t::GENERIC, .len = 1500, .freq = 1500 }, + { .type = tone_t::SCAN_GREEN, .len = 0, .freq = 0 }, + { .type = tone_t::GENERIC, .len = 1500, .freq = 1500 }, + { .type = tone_t::SCAN_BLUE, .len = 0, .freq = 0 }, + { .type = tone_t::GENERIC, .len = 9000, .freq = 1200 }, + { .type = tone_t::GENERIC, .len = 1500, .freq = 1500 }, + { .type = tone_t::SCAN_RED, .len = 0, .freq = 0 } + } +}; + +const SSTVMode_t Scottie2 { + .visCode = SSTV_SCOTTIE_2, + .width = 320, + .height = 256, + .scanPixelLen = 275, + .numTones = 7, + .tones = { + { .type = tone_t::GENERIC, .len = 1500, .freq = 1500 }, + { .type = tone_t::SCAN_GREEN, .len = 0, .freq = 0 }, + { .type = tone_t::GENERIC, .len = 1500, .freq = 1500 }, + { .type = tone_t::SCAN_BLUE, .len = 0, .freq = 0 }, + { .type = tone_t::GENERIC, .len = 9000, .freq = 1200 }, + { .type = tone_t::GENERIC, .len = 1500, .freq = 1500 }, + { .type = tone_t::SCAN_RED, .len = 0, .freq = 0 } + } +}; + +const SSTVMode_t ScottieDX { + .visCode = SSTV_SCOTTIE_DX, + .width = 320, + .height = 256, + .scanPixelLen = 1080, + .numTones = 7, + .tones = { + { .type = tone_t::GENERIC, .len = 1500, .freq = 1500 }, + { .type = tone_t::SCAN_GREEN, .len = 0, .freq = 0 }, + { .type = tone_t::GENERIC, .len = 1500, .freq = 1500 }, + { .type = tone_t::SCAN_BLUE, .len = 0, .freq = 0 }, + { .type = tone_t::GENERIC, .len = 9000, .freq = 1200 }, + { .type = tone_t::GENERIC, .len = 1500, .freq = 1500 }, + { .type = tone_t::SCAN_RED, .len = 0, .freq = 0 } + } +}; + +const SSTVMode_t Martin1 { + .visCode = SSTV_MARTIN_1, + .width = 320, + .height = 256, + .scanPixelLen = 458, + .numTones = 8, + .tones = { + { .type = tone_t::GENERIC, .len = 4862, .freq = 1200 }, + { .type = tone_t::GENERIC, .len = 572, .freq = 1500 }, + { .type = tone_t::SCAN_GREEN, .len = 0, .freq = 0 }, + { .type = tone_t::GENERIC, .len = 572, .freq = 1500 }, + { .type = tone_t::SCAN_BLUE, .len = 0, .freq = 0 }, + { .type = tone_t::GENERIC, .len = 572, .freq = 1500 }, + { .type = tone_t::SCAN_RED, .len = 0, .freq = 0 }, + { .type = tone_t::GENERIC, .len = 572, .freq = 1500 } + } +}; + +const SSTVMode_t Martin2 { + .visCode = SSTV_MARTIN_2, + .width = 320, + .height = 256, + .scanPixelLen = 229, + .numTones = 8, + .tones = { + { .type = tone_t::GENERIC, .len = 4862, .freq = 1200 }, + { .type = tone_t::GENERIC, .len = 572, .freq = 1500 }, + { .type = tone_t::SCAN_GREEN, .len = 0, .freq = 0 }, + { .type = tone_t::GENERIC, .len = 572, .freq = 1500 }, + { .type = tone_t::SCAN_BLUE, .len = 0, .freq = 0 }, + { .type = tone_t::GENERIC, .len = 572, .freq = 1500 }, + { .type = tone_t::SCAN_RED, .len = 0, .freq = 0 }, + { .type = tone_t::GENERIC, .len = 572, .freq = 1500 } + } +}; + +const SSTVMode_t Wrasse { + .visCode = SSTV_WRASSE_SC2_180, + .width = 320, + .height = 256, + .scanPixelLen = 734, + .numTones = 5, + .tones = { + { .type = tone_t::GENERIC, .len = 5523, .freq = 1200 }, + { .type = tone_t::GENERIC, .len = 500, .freq = 1500 }, + { .type = tone_t::SCAN_RED, .len = 0, .freq = 0 }, + { .type = tone_t::SCAN_GREEN, .len = 0, .freq = 0 }, + { .type = tone_t::SCAN_BLUE, .len = 0, .freq = 0 } + } +}; + +const SSTVMode_t PasokonP3 { + .visCode = SSTV_PASOKON_P3, + .width = 640, + .height = 496, + .scanPixelLen = 208, + .numTones = 7, + .tones = { + { .type = tone_t::GENERIC, .len = 5208, .freq = 1200 }, + { .type = tone_t::GENERIC, .len = 1042, .freq = 1500 }, + { .type = tone_t::SCAN_RED, .len = 0, .freq = 0 }, + { .type = tone_t::GENERIC, .len = 1042, .freq = 1500 }, + { .type = tone_t::SCAN_GREEN, .len = 0, .freq = 0 }, + { .type = tone_t::GENERIC, .len = 1042, .freq = 1500 }, + { .type = tone_t::SCAN_BLUE, .len = 0, .freq = 0 } + } +}; + +const SSTVMode_t PasokonP5 { + .visCode = SSTV_PASOKON_P5, + .width = 640, + .height = 496, + .scanPixelLen = 312, + .numTones = 7, + .tones = { + { .type = tone_t::GENERIC, .len = 7813, .freq = 1200 }, + { .type = tone_t::GENERIC, .len = 1563, .freq = 1500 }, + { .type = tone_t::SCAN_RED, .len = 0, .freq = 0 }, + { .type = tone_t::GENERIC, .len = 1563, .freq = 1500 }, + { .type = tone_t::SCAN_GREEN, .len = 0, .freq = 0 }, + { .type = tone_t::GENERIC, .len = 1563, .freq = 1500 }, + { .type = tone_t::SCAN_BLUE, .len = 0, .freq = 0 } + } +}; + +const SSTVMode_t PasokonP7 { + .visCode = SSTV_PASOKON_P7, + .width = 640, + .height = 496, + .scanPixelLen = 417, + .numTones = 7, + .tones = { + { .type = tone_t::GENERIC, .len = 10417, .freq = 1200 }, + { .type = tone_t::GENERIC, .len = 2083, .freq = 1500 }, + { .type = tone_t::SCAN_RED, .len = 0, .freq = 0 }, + { .type = tone_t::GENERIC, .len = 2083, .freq = 1500 }, + { .type = tone_t::SCAN_GREEN, .len = 0, .freq = 0 }, + { .type = tone_t::GENERIC, .len = 2083, .freq = 1500 }, + { .type = tone_t::SCAN_BLUE, .len = 0, .freq = 0 } + } +}; + +SSTVClient::SSTVClient(PhysicalLayer* phy) { + _phy = phy; +} + +int16_t SSTVClient::begin(float base, SSTVMode_t mode, float correction) { + // save mode + _mode = mode; + + // apply correction factor to all timings + _mode.scanPixelLen *= correction; + for(uint8_t i = 0; i < _mode.numTones; i++) { + _mode.tones[i].len *= correction; + } + + // calculate 24-bit frequency + _base = (base * 1000000.0) / _phy->getFreqStep(); + + // set module frequency deviation to 0 + int16_t state = _phy->setFrequencyDeviation(0); + + return(state); +} + +void SSTVClient::idle() { + tone(SSTV_TONE_LEADER); +} + +void SSTVClient::sendHeader() { + // save first header flag for Scottie modes + _firstLine = true; + + // send the first part of header (leader-break-leader) + tone(SSTV_TONE_LEADER, SSTV_HEADER_LEADER_LENGTH); + tone(SSTV_TONE_BREAK, SSTV_HEADER_BREAK_LENGTH); + tone(SSTV_TONE_LEADER, SSTV_HEADER_LEADER_LENGTH); + + // VIS start bit + tone(SSTV_TONE_BREAK, SSTV_HEADER_BIT_LENGTH); + + // VIS code + uint8_t parityCount = 0; + for(uint8_t mask = 0x01; mask < 0x80; mask <<= 1) { + if(_mode.visCode & mask) { + tone(SSTV_TONE_VIS_1, SSTV_HEADER_BIT_LENGTH); + parityCount++; + } else { + tone(SSTV_TONE_VIS_0, SSTV_HEADER_BIT_LENGTH); + } + } + + // VIS parity + if(parityCount % 2 == 0) { + // even parity + tone(SSTV_TONE_VIS_0, SSTV_HEADER_BIT_LENGTH); + } else { + // odd parity + tone(SSTV_TONE_VIS_1, SSTV_HEADER_BIT_LENGTH); + } + + // VIS stop bit + tone(SSTV_TONE_BREAK, SSTV_HEADER_BIT_LENGTH); +} + +void SSTVClient::sendLine(uint32_t* imgLine) { + // check first line flag in Scottie modes + if(_firstLine && ((_mode.visCode == SSTV_SCOTTIE_1) || (_mode.visCode == SSTV_SCOTTIE_2) || (_mode.visCode == SSTV_SCOTTIE_DX))) { + _firstLine = false; + + // send start sync tone + tone(SSTV_TONE_BREAK, 9000); + } + + // send all tones in sequence + for(uint8_t i = 0; i < _mode.numTones; i++) { + if((_mode.tones[i].type == tone_t::GENERIC) && (_mode.tones[i].len > 0)) { + // sync/porch tones + tone(_mode.tones[i].freq, _mode.tones[i].len); + } else { + // scan lines + for(uint16_t j = 0; j < _mode.width; j++) { + uint32_t color = imgLine[j]; + switch(_mode.tones[i].type) { + case(tone_t::SCAN_RED): + color &= 0x00FF0000; + color >>= 16; + break; + case(tone_t::SCAN_GREEN): + color &= 0x0000FF00; + color >>= 8; + break; + case(tone_t::SCAN_BLUE): + color &= 0x000000FF; + break; + case(tone_t::GENERIC): + break; + } + tone(SSTV_TONE_BRIGHTNESS_MIN + ((float)color * 3.1372549), _mode.scanPixelLen); + } + } + } +} + +uint16_t SSTVClient::getPictureHeight() { + return(_mode.height); +} + +void SSTVClient::tone(float freq, uint32_t len) { + uint32_t start = micros(); + _phy->transmitDirect(_base + (freq / _phy->getFreqStep())); + while(micros() - start < len); +} diff --git a/src/protocols/SSTV/SSTV.h b/src/protocols/SSTV/SSTV.h new file mode 100644 index 00000000..8242d674 --- /dev/null +++ b/src/protocols/SSTV/SSTV.h @@ -0,0 +1,123 @@ +#ifndef _RADIOLIB_SSTV_H +#define _RADIOLIB_SSTV_H + +#include "../../TypeDef.h" +#include "../PhysicalLayer/PhysicalLayer.h" + +// the following implementation is based on information from +// http://www.barberdsp.com/downloads/Dayton%20Paper.pdf + +// VIS codes +#define SSTV_SCOTTIE_1 60 +#define SSTV_SCOTTIE_2 56 +#define SSTV_SCOTTIE_DX 76 +#define SSTV_MARTIN_1 44 +#define SSTV_MARTIN_2 40 +#define SSTV_WRASSE_SC2_180 55 +#define SSTV_PASOKON_P3 113 +#define SSTV_PASOKON_P5 114 +#define SSTV_PASOKON_P7 115 + +// SSTV tones in Hz +#define SSTV_TONE_LEADER 1900 +#define SSTV_TONE_BREAK 1200 +#define SSTV_TONE_VIS_1 1100 +#define SSTV_TONE_VIS_0 1300 +#define SSTV_TONE_BRIGHTNESS_MIN 1500 +#define SSTV_TONE_BRIGHTNESS_MAX 2300 + +// calibration header timing in us +#define SSTV_HEADER_LEADER_LENGTH 300000 +#define SSTV_HEADER_BREAK_LENGTH 10000 +#define SSTV_HEADER_BIT_LENGTH 30000 + +// structure to save data about tone +struct tone_t { + enum { + GENERIC = 0, + SCAN_GREEN, + SCAN_BLUE, + SCAN_RED + } type; + uint32_t len; + uint16_t freq; +}; + +// structure to save data about SSTV mode +struct SSTVMode_t { + uint8_t visCode; + uint16_t width; + uint16_t height; + uint16_t scanPixelLen; + uint8_t numTones; + tone_t tones[8]; +}; + +// all currently supported SSTV modes +extern const SSTVMode_t Scottie1; +extern const SSTVMode_t Scottie2; +extern const SSTVMode_t ScottieDX; +extern const SSTVMode_t Martin1; +extern const SSTVMode_t Martin2; +extern const SSTVMode_t Wrasse; +extern const SSTVMode_t PasokonP3; +extern const SSTVMode_t PasokonP5; +extern const SSTVMode_t PasokonP7; + +class SSTVClient { + public: + /*! + \brief Default constructor. + + \param phy Pointer to the wireless module providing PhysicalLayer communication. + */ + SSTVClient(PhysicalLayer* phy); + + // basic methods + + /*! + \brief Initialization method. + + \param base Base RF frequency to be used in MHz. In USB modulation, this corresponds to "0 Hz tone". + + \param mode SSTV mode to be used. Currently supported modes are Scottie1, Scottie2, ScottieDX, Martin1, Martin2, Wrasse, PasokonP3, PasokonP5 and PasokonP7. + */ + int16_t begin(float base, SSTVMode_t mode, float correction = 1.0); + + /*! + \brief Sends out tone at 1900 Hz. + */ + void idle(); + + /*! + \brief Sends synchronization header for the SSTV mode set in begin method. + */ + void sendHeader(); + + /*! + \brief Sends single picture line in the currently configured SSTV mode. + + \param imgLine Image line to send, in 24-bit RGB. It is up to the user to ensure that imgLine has enough pixels to send it in the current SSTV mode. + */ + void sendLine(uint32_t* imgLine); + + /*! + \brief Get picture height of the currently configured SSTV mode. + + \returns Picture height of the currently configured SSTV mode in pixels. + */ + uint16_t getPictureHeight(); + +#ifndef RADIOLIB_GODMODE + private: +#endif + PhysicalLayer* _phy; + + uint32_t _base; + SSTVMode_t _mode; + bool _firstLine; + + void tone(float freq, uint32_t len = 0); +}; + +#endif From b731b60852bc2157292d10e1d1581ebc2904afa0 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 31 Mar 2020 18:02:51 +0200 Subject: [PATCH 33/57] [SSTV] Added missing Doxygen comments --- src/RadioLib.h | 1 + src/protocols/SSTV/SSTV.h | 53 +++++++++++++++++++++++++++++++++++++-- 2 files changed, 52 insertions(+), 2 deletions(-) diff --git a/src/RadioLib.h b/src/RadioLib.h index bb5e085e..eea7044d 100644 --- a/src/RadioLib.h +++ b/src/RadioLib.h @@ -20,6 +20,7 @@ - RTTY (RTTYClient) - Morse Code (MorseClient) - AX.25 (AX25Client) + - SSTV (SSTVClient) - TransportLayer protocols - HTTP (HTTPClient) - MQTT (MQTTClient) diff --git a/src/protocols/SSTV/SSTV.h b/src/protocols/SSTV/SSTV.h index 8242d674..d8dc0c8b 100644 --- a/src/protocols/SSTV/SSTV.h +++ b/src/protocols/SSTV/SSTV.h @@ -31,25 +31,69 @@ #define SSTV_HEADER_BREAK_LENGTH 10000 #define SSTV_HEADER_BIT_LENGTH 30000 -// structure to save data about tone +/*! + \struct tone_t + + \brief Structure to save data about tone. +*/ struct tone_t { + + /*! + \brief Tone type: GENERIC for sync and porch tones, SCAN_GREEN, SCAN_BLUE and SCAN_RED for scan lines. + */ enum { GENERIC = 0, SCAN_GREEN, SCAN_BLUE, SCAN_RED } type; + + /*! + \brief Length of tone in us, set to 0 for picture scan tones. + */ uint32_t len; + + /*! + \brief Frequency of tone in Hz, set to 0 for picture scan tones. + */ uint16_t freq; }; -// structure to save data about SSTV mode +/*! + \struct SSTVMode_t + + \brief Structure to save data about supported SSTV modes. +*/ struct SSTVMode_t { + + /*! + \brief Unique VIS code of the SSTV mode. + */ uint8_t visCode; + + /*! + \brief Picture width in pixels. + */ uint16_t width; + + /*! + \brief Picture height in pixels. + */ uint16_t height; + + /*! + \brief Pixel scan length in us. + */ uint16_t scanPixelLen; + + /*! + \brief Number of tones in each transmission line. Picture scan data is considered single tone. + */ uint8_t numTones; + + /*! + \brief Sequence of tones in each transmission line. This is used to create the correct encoding sequence. + */ tone_t tones[8]; }; @@ -64,6 +108,11 @@ extern const SSTVMode_t PasokonP3; extern const SSTVMode_t PasokonP5; extern const SSTVMode_t PasokonP7; +/*! + \class SSTVClient + + \brief Client for SSTV transmissions. +*/ class SSTVClient { public: /*! From 9c0cd464d1dcd20148a5054decc64c6cf4253789 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 1 Apr 2020 10:49:45 +0200 Subject: [PATCH 34/57] Moved unsupported platform warning to RadioLib.h to only show it once --- src/BuildOpt.h | 2 +- src/RadioLib.h | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/BuildOpt.h b/src/BuildOpt.h index 2112e21a..063a8e05 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -116,7 +116,7 @@ #else // other platforms not covered by the above list - this may or may not work - #warning "RadioLib might not be compatible with this Arduino board - check supported platforms at https://github.com/jgromes/RadioLib!" + #define RADIOLIB_UNKNOWN_PLATFORM #define RADIOLIB_PIN_TYPE uint8_t #define RADIOLIB_PIN_MODE uint8_t #define RADIOLIB_PIN_STATUS uint8_t diff --git a/src/RadioLib.h b/src/RadioLib.h index eea7044d..ae4a6909 100644 --- a/src/RadioLib.h +++ b/src/RadioLib.h @@ -41,10 +41,18 @@ #include "TypeDef.h" #include "Module.h" +// warnings are printed in this file since BuildOpt.h is compiled in multiple places + +// check God mode #ifdef RADIOLIB_GODMODE #warning "God mode active, I hope it was intentional. Buckle up, lads." #endif +// check unknown/unsupported platform +#ifdef RADIOLIB_UNKNOWN_PLATFORM + #warning "RadioLib might not be compatible with this Arduino board - check supported platforms at https://github.com/jgromes/RadioLib!" +#endif + #include "modules/CC1101/CC1101.h" #include "modules/ESP8266/ESP8266.h" #include "modules/HC05/HC05.h" From 7fec5e629b50fbc54d170b258e9a6a5aadd1b9ed Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 1 Apr 2020 14:01:02 +0200 Subject: [PATCH 35/57] [ESP8266] Added missing calls to yield --- src/modules/ESP8266/ESP8266.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/modules/ESP8266/ESP8266.cpp b/src/modules/ESP8266/ESP8266.cpp index b221d0ff..1aa959a9 100644 --- a/src/modules/ESP8266/ESP8266.cpp +++ b/src/modules/ESP8266/ESP8266.cpp @@ -195,6 +195,7 @@ size_t ESP8266::receive(uint8_t* data, size_t len, uint32_t timeout) { // wait until the required number of bytes is received or until timeout while((millis() - start < timeout) && (i < len)) { + yield(); while(_mod->ModuleSerial->available() > 0) { uint8_t b = _mod->ModuleSerial->read(); RADIOLIB_DEBUG_PRINT(b); @@ -209,6 +210,7 @@ size_t ESP8266::getNumBytes(uint32_t timeout, size_t minBytes) { // wait for available data uint32_t start = millis(); while(_mod->ModuleSerial->available() < (int16_t)minBytes) { + yield(); if(millis() - start >= timeout) { return(0); } @@ -219,6 +221,7 @@ size_t ESP8266::getNumBytes(uint32_t timeout, size_t minBytes) { uint8_t i = 0; start = millis(); while(_mod->ModuleSerial->available() > 0) { + yield(); char c = _mod->ModuleSerial->read(); rawStr[i++] = c; if(c == ':') { From 901783cf3948917f964d9800147053ae88cf8380 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 1 Apr 2020 14:01:18 +0200 Subject: [PATCH 36/57] [RF69] Added missing calls to yield --- src/modules/RF69/RF69.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/modules/RF69/RF69.cpp b/src/modules/RF69/RF69.cpp index 2e2eab0e..c9e9fa90 100644 --- a/src/modules/RF69/RF69.cpp +++ b/src/modules/RF69/RF69.cpp @@ -117,6 +117,8 @@ int16_t RF69::transmit(uint8_t* data, size_t len, uint8_t addr) { // wait for transmission end or timeout uint32_t start = micros(); while(!digitalRead(_mod->getIrq())) { + yield(); + if(micros() - start > timeout) { standby(); clearIRQFlags(); @@ -144,6 +146,8 @@ int16_t RF69::receive(uint8_t* data, size_t len) { // wait for packet reception or timeout uint32_t start = micros(); while(!digitalRead(_mod->getIrq())) { + yield(); + if(micros() - start > timeout) { standby(); clearIRQFlags(); From a46a1f5f1c10303620fa028db88e87421c6c19f1 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 1 Apr 2020 14:01:27 +0200 Subject: [PATCH 37/57] [SX126x] Added missing calls to yield --- src/modules/SX126x/SX126x.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 93b98dc7..1fdf6cc7 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -219,6 +219,7 @@ int16_t SX126x::transmit(uint8_t* data, size_t len, uint8_t addr) { // wait for packet transmission or timeout uint32_t start = micros(); while(!digitalRead(_mod->getIrq())) { + yield(); if(micros() - start > timeout) { clearIrqStatus(); standby(); @@ -278,6 +279,7 @@ int16_t SX126x::receive(uint8_t* data, size_t len) { // wait for packet reception or timeout uint32_t start = micros(); while(!digitalRead(_mod->getIrq())) { + yield(); if(micros() - start > timeout) { fixImplicitTimeout(); clearIrqStatus(); @@ -1516,6 +1518,7 @@ int16_t SX126x::SPItransfer(uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* d // ensure BUSY is low (state machine ready) uint32_t start = millis(); while(digitalRead(_mod->getGpio())) { + yield(); if(millis() - start >= timeout) { return(ERR_SPI_CMD_TIMEOUT); } @@ -1583,6 +1586,7 @@ int16_t SX126x::SPItransfer(uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* d delayMicroseconds(1); start = millis(); while(digitalRead(_mod->getGpio())) { + yield(); if(millis() - start >= timeout) { status = SX126X_STATUS_CMD_TIMEOUT; break; From 218587b887f34c8aa6d91b761c970e4b64e82ab9 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 1 Apr 2020 14:01:41 +0200 Subject: [PATCH 38/57] [SX127x] Added missing calls to yield --- src/modules/SX127x/SX127x.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 15053fd9..727cf2b1 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -144,6 +144,7 @@ int16_t SX127x::transmit(uint8_t* data, size_t len, uint8_t addr) { // wait for packet transmission or timeout start = micros(); while(!digitalRead(_mod->getIrq())) { + yield(); if(micros() - start > timeout) { clearIRQFlags(); return(ERR_TX_TIMEOUT); @@ -161,6 +162,7 @@ int16_t SX127x::transmit(uint8_t* data, size_t len, uint8_t addr) { // wait for transmission end or timeout start = micros(); while(!digitalRead(_mod->getIrq())) { + yield(); if(micros() - start > timeout) { clearIRQFlags(); standby(); @@ -194,6 +196,7 @@ int16_t SX127x::receive(uint8_t* data, size_t len) { // wait for packet reception or timeout (100 LoRa symbols) while(!digitalRead(_mod->getIrq())) { + yield(); if(digitalRead(_mod->getGpio())) { clearIRQFlags(); return(ERR_RX_TIMEOUT); @@ -211,6 +214,7 @@ int16_t SX127x::receive(uint8_t* data, size_t len) { // wait for packet reception or timeout uint32_t start = micros(); while(!digitalRead(_mod->getIrq())) { + yield(); if(micros() - start > timeout) { clearIRQFlags(); return(ERR_RX_TIMEOUT); @@ -247,6 +251,7 @@ int16_t SX127x::scanChannel() { // wait for channel activity detected or timeout while(!digitalRead(_mod->getIrq())) { + yield(); if(digitalRead(_mod->getGpio())) { clearIRQFlags(); return(PREAMBLE_DETECTED); From a7c4dd44ce14930c1f90ce2e24fd491c81481aa1 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 1 Apr 2020 14:01:49 +0200 Subject: [PATCH 39/57] [Si443x] Added missing calls to yield --- src/modules/Si443x/Si443x.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/modules/Si443x/Si443x.cpp b/src/modules/Si443x/Si443x.cpp index 6cfc6ffd..13af7747 100644 --- a/src/modules/Si443x/Si443x.cpp +++ b/src/modules/Si443x/Si443x.cpp @@ -74,6 +74,7 @@ int16_t Si443x::transmit(uint8_t* data, size_t len, uint8_t addr) { // wait for transmission end or timeout uint32_t start = micros(); while(digitalRead(_mod->getIrq())) { + yield(); if(micros() - start > timeout) { standby(); clearIRQFlags(); From eb71582a96ee4bd5abb99914bf762358e2658579 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 1 Apr 2020 14:01:57 +0200 Subject: [PATCH 40/57] [XBee] Added missing calls to yield --- src/modules/XBee/XBee.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/modules/XBee/XBee.cpp b/src/modules/XBee/XBee.cpp index cefc7dff..aa365ea3 100644 --- a/src/modules/XBee/XBee.cpp +++ b/src/modules/XBee/XBee.cpp @@ -405,6 +405,7 @@ int16_t XBee::readApiFrame(uint8_t frameID, uint8_t codePos, uint16_t timeout) { // wait until all response bytes are available (5s timeout) uint32_t start = millis(); while(_mod->ModuleSerial->available() < (int16_t)numBytes) { + yield(); if(millis() - start >= timeout/2) { return(ERR_FRAME_MALFORMED); } @@ -456,6 +457,7 @@ uint16_t XBee::getNumBytes(uint32_t timeout, size_t minBytes) { // wait for available data uint32_t start = millis(); while((size_t)_mod->ModuleSerial->available() < minBytes) { + yield(); if(millis() - start >= timeout) { return(0); } @@ -466,6 +468,7 @@ uint16_t XBee::getNumBytes(uint32_t timeout, size_t minBytes) { uint8_t i = 0; RADIOLIB_DEBUG_PRINT(F("reading frame length: ")); while(_mod->ModuleSerial->available() > 0) { + yield(); uint8_t b = _mod->ModuleSerial->read(); RADIOLIB_DEBUG_PRINT(b, HEX); RADIOLIB_DEBUG_PRINT('\t'); From 6a4fdd9a9207f5c630d932c86e603acd2f002637 Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 1 Apr 2020 14:02:06 +0200 Subject: [PATCH 41/57] [nRF24] Added missing calls to yield --- src/modules/nRF24/nRF24.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/modules/nRF24/nRF24.cpp b/src/modules/nRF24/nRF24.cpp index a05d52e3..ab6cc6b6 100644 --- a/src/modules/nRF24/nRF24.cpp +++ b/src/modules/nRF24/nRF24.cpp @@ -72,6 +72,8 @@ int16_t nRF24::transmit(uint8_t* data, size_t len, uint8_t addr) { // wait until transmission is finished uint32_t start = micros(); while(digitalRead(_mod->getIrq())) { + yield(); + // check maximum number of retransmits if(getStatus(NRF24_MAX_RT)) { standby(); @@ -101,6 +103,8 @@ int16_t nRF24::receive(uint8_t* data, size_t len) { // wait for Rx_DataReady or timeout uint32_t start = micros(); while(digitalRead(_mod->getIrq())) { + yield(); + // check timeout: 15 retries * 4ms (max Tx time as per datasheet) if(micros() - start >= 60000) { standby(); From 87014929596b5600ba417ae03efbdefb5084493a Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 1 Apr 2020 14:02:16 +0200 Subject: [PATCH 42/57] [RTTY] Added missing calls to yield --- src/protocols/RTTY/RTTY.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/protocols/RTTY/RTTY.cpp b/src/protocols/RTTY/RTTY.cpp index c5eebe6c..085d3794 100644 --- a/src/protocols/RTTY/RTTY.cpp +++ b/src/protocols/RTTY/RTTY.cpp @@ -392,13 +392,17 @@ size_t RTTYClient::println(double d, int digits) { void RTTYClient::mark() { uint32_t start = micros(); _phy->transmitDirect(_base + _shift); - while(micros() - start < _bitDuration); + while(micros() - start < _bitDuration) { + yield(); + } } void RTTYClient::space() { uint32_t start = micros(); _phy->transmitDirect(_base); - while(micros() - start < _bitDuration); + while(micros() - start < _bitDuration) { + yield(); + } } size_t RTTYClient::printNumber(unsigned long n, uint8_t base) { From 34559fdee3a174a6a4c2c1469efe9802cf6e803c Mon Sep 17 00:00:00 2001 From: jgromes Date: Wed, 1 Apr 2020 14:02:25 +0200 Subject: [PATCH 43/57] [SSTV] Added missing calls to yield --- src/protocols/SSTV/SSTV.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/protocols/SSTV/SSTV.cpp b/src/protocols/SSTV/SSTV.cpp index dfbeea30..c3843ad8 100644 --- a/src/protocols/SSTV/SSTV.cpp +++ b/src/protocols/SSTV/SSTV.cpp @@ -262,5 +262,7 @@ uint16_t SSTVClient::getPictureHeight() { void SSTVClient::tone(float freq, uint32_t len) { uint32_t start = micros(); _phy->transmitDirect(_base + (freq / _phy->getFreqStep())); - while(micros() - start < len); + while(micros() - start < len) { + yield(); + } } From cc903453423468b842f3027599d37bab7064fe87 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 7 Apr 2020 13:27:55 +0200 Subject: [PATCH 44/57] [SX126x] Minor formatting fixes --- src/modules/SX126x/SX126x.cpp | 29 +++++++++++++---------------- src/modules/SX126x/SX126x.h | 26 +++++++++++++------------- 2 files changed, 26 insertions(+), 29 deletions(-) diff --git a/src/modules/SX126x/SX126x.cpp b/src/modules/SX126x/SX126x.cpp index 1fdf6cc7..685163cf 100644 --- a/src/modules/SX126x/SX126x.cpp +++ b/src/modules/SX126x/SX126x.cpp @@ -78,6 +78,7 @@ int16_t SX126x::beginFSK(float br, float freqDev, float rxBw, float currentLimit // set module properties _mod->init(RADIOLIB_USE_SPI); Module::pinMode(_mod->getIrq(), INPUT); + Module::pinMode(_mod->getGpio(), INPUT); // initialize configuration variables (will be overwritten during public settings configuration) _br = 21333; // 48.0 kbps @@ -553,7 +554,6 @@ int16_t SX126x::readData(uint8_t* data, size_t len) { uint16_t irq = getIrqStatus(); int16_t crcState = ERR_NONE; if((irq & SX126X_IRQ_CRC_ERR) || (irq & SX126X_IRQ_HEADER_ERR)) { - clearIrqStatus(); crcState = ERR_CRC_MISMATCH; } @@ -1171,12 +1171,12 @@ int16_t SX126x::setDio2AsRfSwitch(bool enable) { } int16_t SX126x::setTx(uint32_t timeout) { - uint8_t data[3] = {(uint8_t)((timeout >> 16) & 0xFF), (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF)}; + uint8_t data[] = { (uint8_t)((timeout >> 16) & 0xFF), (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF)} ; return(SPIwriteCommand(SX126X_CMD_SET_TX, data, 3)); } int16_t SX126x::setRx(uint32_t timeout) { - uint8_t data[3] = {(uint8_t)((timeout >> 16) & 0xFF), (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF)}; + uint8_t data[] = { (uint8_t)((timeout >> 16) & 0xFF), (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF) }; return(SPIwriteCommand(SX126X_CMD_SET_RX, data, 3)); } @@ -1185,32 +1185,28 @@ int16_t SX126x::setCad() { } int16_t SX126x::setPaConfig(uint8_t paDutyCycle, uint8_t deviceSel, uint8_t hpMax, uint8_t paLut) { - uint8_t data[4] = {paDutyCycle, hpMax, deviceSel, paLut}; + uint8_t data[] = { paDutyCycle, hpMax, deviceSel, paLut }; return(SPIwriteCommand(SX126X_CMD_SET_PA_CONFIG, data, 4)); } int16_t SX126x::writeRegister(uint16_t addr, uint8_t* data, uint8_t numBytes) { uint8_t cmd[] = { SX126X_CMD_WRITE_REGISTER, (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF) }; - int16_t state = SPIwriteCommand(cmd, 3, data, numBytes); - return(state); + return(SPIwriteCommand(cmd, 3, data, numBytes)); } int16_t SX126x::readRegister(uint16_t addr, uint8_t* data, uint8_t numBytes) { - uint8_t cmd[] = {SX126X_CMD_READ_REGISTER, (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF)}; + uint8_t cmd[] = { SX126X_CMD_READ_REGISTER, (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF) }; return(SX126x::SPItransfer(cmd, 3, false, NULL, data, numBytes, true)); } int16_t SX126x::writeBuffer(uint8_t* data, uint8_t numBytes, uint8_t offset) { uint8_t cmd[] = { SX126X_CMD_WRITE_BUFFER, offset }; - int16_t state = SPIwriteCommand(cmd, 2, data, numBytes); - - return(state); + return(SPIwriteCommand(cmd, 2, data, numBytes)); } int16_t SX126x::readBuffer(uint8_t* data, uint8_t numBytes) { uint8_t cmd[] = { SX126X_CMD_READ_BUFFER, SX126X_CMD_NOP }; - int16_t state = SPIreadCommand(cmd, 2, data, numBytes); - return(state); + return(SPIreadCommand(cmd, 2, data, numBytes)); } int16_t SX126x::setDioIrqParams(uint16_t irqMask, uint16_t dio1Mask, uint16_t dio2Mask, uint16_t dio3Mask) { @@ -1222,18 +1218,18 @@ int16_t SX126x::setDioIrqParams(uint16_t irqMask, uint16_t dio1Mask, uint16_t di } uint16_t SX126x::getIrqStatus() { - uint8_t data[2] = {0, 0};; + uint8_t data[] = { 0x00, 0x00 }; SPIreadCommand(SX126X_CMD_GET_IRQ_STATUS, data, 2); return(((uint16_t)(data[0]) << 8) | data[1]); } int16_t SX126x::clearIrqStatus(uint16_t clearIrqParams) { - uint8_t data[2] = {(uint8_t)((clearIrqParams >> 8) & 0xFF), (uint8_t)(clearIrqParams & 0xFF)}; + uint8_t data[] = { (uint8_t)((clearIrqParams >> 8) & 0xFF), (uint8_t)(clearIrqParams & 0xFF) }; return(SPIwriteCommand(SX126X_CMD_CLEAR_IRQ_STATUS, data, 2)); } int16_t SX126x::setRfFrequency(uint32_t frf) { - uint8_t data[4] = {(uint8_t)((frf >> 24) & 0xFF), (uint8_t)((frf >> 16) & 0xFF), (uint8_t)((frf >> 8) & 0xFF), (uint8_t)(frf & 0xFF)}; + uint8_t data[] = { (uint8_t)((frf >> 24) & 0xFF), (uint8_t)((frf >> 16) & 0xFF), (uint8_t)((frf >> 8) & 0xFF), (uint8_t)(frf & 0xFF) }; return(SPIwriteCommand(SX126X_CMD_SET_RF_FREQUENCY, data, 4)); } @@ -1248,7 +1244,7 @@ uint8_t SX126x::getPacketType() { } int16_t SX126x::setTxParams(uint8_t power, uint8_t rampTime) { - uint8_t data[2] = {power, rampTime}; + uint8_t data[] = { power, rampTime }; return(SPIwriteCommand(SX126X_CMD_SET_TX_PARAMS, data, 2)); } @@ -1520,6 +1516,7 @@ int16_t SX126x::SPItransfer(uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* d while(digitalRead(_mod->getGpio())) { yield(); if(millis() - start >= timeout) { + digitalWrite(_mod->getCs(), HIGH); return(ERR_SPI_CMD_TIMEOUT); } } diff --git a/src/modules/SX126x/SX126x.h b/src/modules/SX126x/SX126x.h index 1b9ce54f..e6a7f078 100644 --- a/src/modules/SX126x/SX126x.h +++ b/src/modules/SX126x/SX126x.h @@ -106,7 +106,7 @@ // SX126X SPI command variables -//SX126X_CMD_SET_SLEEP +//SX126X_CMD_SET_SLEEP MSB LSB DESCRIPTION #define SX126X_SLEEP_START_COLD 0b00000000 // 2 2 sleep mode: cold start, configuration is lost (default) #define SX126X_SLEEP_START_WARM 0b00000100 // 2 2 warm start, configuration is retained #define SX126X_SLEEP_RTC_OFF 0b00000000 // 0 0 wake on RTC timeout: disabled @@ -768,7 +768,7 @@ class SX126x: public PhysicalLayer { */ float getSNR(); - /*! + /*! \brief Query modem for the packet length of received payload. \param update Update received packet length. Will return cached value when set to false. @@ -786,7 +786,7 @@ class SX126x: public PhysicalLayer { */ int16_t fixedPacketLengthMode(uint8_t len = SX126X_MAX_PACKET_LENGTH); - /*! + /*! \brief Set modem in variable packet length mode. Available in FSK mode only. \param len Maximum packet length. @@ -795,7 +795,7 @@ class SX126x: public PhysicalLayer { */ int16_t variablePacketLengthMode(uint8_t maxLen = SX126X_MAX_PACKET_LENGTH); - /*! + /*! \brief Get expected time-on-air for a given size of payload \param len Payload length in bytes. @@ -804,14 +804,14 @@ class SX126x: public PhysicalLayer { */ uint32_t getTimeOnAir(size_t len); - /*! + /*! \brief Set implicit header mode for future reception/transmission. \returns \ref status_codes */ int16_t implicitHeader(size_t len); - /*! + /*! \brief Set explicit header mode for future reception/transmission. \param len Payload length in bytes. @@ -821,17 +821,17 @@ class SX126x: public PhysicalLayer { int16_t explicitHeader(); /*! - \brief Set regulator mode to LDO. + \brief Set regulator mode to LDO. - \returns \ref status_codes - */ + \returns \ref status_codes + */ int16_t setRegulatorLDO(); /*! - \brief Set regulator mode to DC-DC. + \brief Set regulator mode to DC-DC. - \returns \ref status_codes - */ + \returns \ref status_codes + */ int16_t setRegulatorDCDC(); /*! @@ -846,7 +846,7 @@ class SX126x: public PhysicalLayer { #ifndef RADIOLIB_GODMODE protected: #endif - // SX1276x SPI command implementations + // SX126x SPI command implementations int16_t setTx(uint32_t timeout = 0); int16_t setRx(uint32_t timeout); int16_t setCad(); From 55ad72e0e0f9e92440899a70f4fd3fb7b0b95cb0 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 7 Apr 2020 13:30:05 +0200 Subject: [PATCH 45/57] [SX128x] Added support for SX128x --- .../SX128x_Channel_Activity_Detection.ino | 72 + .../SX128x_GFSK_Modem/SX128x_GFSK_Modem.ino | 116 ++ .../SX128x/SX128x_Receive/SX128x_Receive.ino | 106 ++ .../SX128x_Receive_Interrupt.ino | 159 +++ .../SX128x_Settings/SX128x_Settings.ino | 134 ++ .../SX128x_Transmit/SX128x_Transmit.ino | 85 ++ .../SX128x_Transmit_Interrupt.ino | 135 ++ keywords.txt | 6 + src/RadioLib.h | 5 +- src/modules/SX128x/SX1280.cpp | 5 + src/modules/SX128x/SX1280.h | 31 + src/modules/SX128x/SX1281.cpp | 5 + src/modules/SX128x/SX1281.h | 28 + src/modules/SX128x/SX1282.cpp | 5 + src/modules/SX128x/SX1282.h | 31 + src/modules/SX128x/SX128x.cpp | 1208 +++++++++++++++++ src/modules/SX128x/SX128x.h | 748 ++++++++++ 17 files changed, 2878 insertions(+), 1 deletion(-) create mode 100644 examples/SX128x/SX128x_Channel_Activity_Detection/SX128x_Channel_Activity_Detection.ino create mode 100644 examples/SX128x/SX128x_GFSK_Modem/SX128x_GFSK_Modem.ino create mode 100644 examples/SX128x/SX128x_Receive/SX128x_Receive.ino create mode 100644 examples/SX128x/SX128x_Receive_Interrupt/SX128x_Receive_Interrupt.ino create mode 100644 examples/SX128x/SX128x_Settings/SX128x_Settings.ino create mode 100644 examples/SX128x/SX128x_Transmit/SX128x_Transmit.ino create mode 100644 examples/SX128x/SX128x_Transmit_Interrupt/SX128x_Transmit_Interrupt.ino create mode 100644 src/modules/SX128x/SX1280.cpp create mode 100644 src/modules/SX128x/SX1280.h create mode 100644 src/modules/SX128x/SX1281.cpp create mode 100644 src/modules/SX128x/SX1281.h create mode 100644 src/modules/SX128x/SX1282.cpp create mode 100644 src/modules/SX128x/SX1282.h create mode 100644 src/modules/SX128x/SX128x.cpp create mode 100644 src/modules/SX128x/SX128x.h diff --git a/examples/SX128x/SX128x_Channel_Activity_Detection/SX128x_Channel_Activity_Detection.ino b/examples/SX128x/SX128x_Channel_Activity_Detection/SX128x_Channel_Activity_Detection.ino new file mode 100644 index 00000000..6ec30377 --- /dev/null +++ b/examples/SX128x/SX128x_Channel_Activity_Detection/SX128x_Channel_Activity_Detection.ino @@ -0,0 +1,72 @@ +/* + RadioLib SX128x Channel Activity Detection Example + + This example uses SX1280 to scan the current LoRa + channel and detect ongoing LoRa transmissions. + + Other modules from SX128x family can also be used. + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1280 has the following connections: +// NSS pin: 10 +// DIO1 pin: 2 +// NRST pin: 3 +// BUSY pin: 9 +SX1280 lora = new Module(10, 2, 3, 9); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1280 lora = RadioShield.ModuleA; + +void setup() { + Serial.begin(9600); + + // initialize SX1280 with default settings + Serial.print(F("[SX1280] Initializing ... ")); + // carrier frequency: 2400.0 MHz + // bandwidth: 812.5 kHz + // spreading factor: 9 + // coding rate: 7 + // output power: 10 dBm + // preamble length: 12 symbols + // CRC: enabled + int state = lora.begin(); + if (state == ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } +} + +void loop() { + Serial.print(F("[SX1280] Scanning channel for LoRa transmission ... ")); + + // start scanning current channel + int state = lora.scanChannel(); + + if (state == LORA_DETECTED) { + // LoRa preamble was detected + Serial.println(F("detected!")); + + } else if (state == CHANNEL_FREE) { + // no preamble was detected, channel is free + Serial.println(F("channel is free!")); + + } else { + // some other error occurred + Serial.print(F("failed, code ")); + Serial.println(state); + + } + + // wait 100 ms before new scan + delay(100); +} diff --git a/examples/SX128x/SX128x_GFSK_Modem/SX128x_GFSK_Modem.ino b/examples/SX128x/SX128x_GFSK_Modem/SX128x_GFSK_Modem.ino new file mode 100644 index 00000000..9b93c481 --- /dev/null +++ b/examples/SX128x/SX128x_GFSK_Modem/SX128x_GFSK_Modem.ino @@ -0,0 +1,116 @@ +/* + RadioLib SX128x GFSK Modem Example + + This example shows how to use GFSK modem in SX128x chips. + + NOTE: The sketch below is just a guide on how to use + GFSK modem, so this code should not be run directly! + Instead, modify the other examples to use GFSK + modem and use the appropriate configuration + methods. + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1280 has the following connections: +// NSS pin: 10 +// DIO1 pin: 2 +// NRST pin: 3 +// BUSY pin: 9 +SX1280 gfsk = new Module(10, 2, 3, 9); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1280 lora = RadioShield.ModuleA; + +void setup() { + Serial.begin(9600); + + // initialize SX1280 with default settings + Serial.print(F("[SX1280] Initializing ... ")); + // carrier frequency: 2400.0 MHz + // bit rate: 800 kbps + // frequency deviation: 400.0 kHz + // output power: 10 dBm + // preamble length: 16 bits + // coding rate: 7 + // data shaping: Gaussian, BT = 0.5 + // sync word: 0x2D 0x01 + // CRC: enabled, CRC16 (CCIT) + int state = gfsk.beginGFSK(); + if (state == ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // if needed, you can switch between LoRa and FSK modes + // + // gfsk.begin() start LoRa mode (and disable GFSK) + // lora.beginGFSK() start GFSK mode (and disable LoRa) + + // the following settings can also + // be modified at run-time + state = gfsk.setFrequency(2410.5); + state = gfsk.setBitRate(200); + state = gfsk.setFrequencyDeviation(100.0); + state = gfsk.setRxBandwidth(250.0); + state = gfsk.setOutputPower(5); + state = gfsk.setDataShaping(1.0); + uint8_t syncWord[] = {0x01, 0x23, 0x45, 0x67, 0x89}; + state = gfsk.setSyncWord(syncWord, 5); + if (state != ERR_NONE) { + Serial.print(F("Unable to set configuration, code ")); + Serial.println(state); + while (true); + } + + #warning "This sketch is just an API guide! Read the note at line 6." +} + +void loop() { + // GFSK modem can use the same transmit/receive methods + // as the LoRa modem, even their interrupt-driven versions + + // transmit GFSK packet + int state = gfsk.transmit("Hello World!"); + /* + byte byteArr[] = {0x01, 0x23, 0x45, 0x67, + 0x89, 0xAB, 0xCD, 0xEF}; + int state = gfsk.transmit(byteArr, 8); + */ + if (state == ERR_NONE) { + Serial.println(F("[SX1280] Packet transmitted successfully!")); + } else if (state == ERR_PACKET_TOO_LONG) { + Serial.println(F("[SX1280] Packet too long!")); + } else if (state == ERR_TX_TIMEOUT) { + Serial.println(F("[SX1280] Timed out while transmitting!")); + } else { + Serial.println(F("[SX1280] Failed to transmit packet, code ")); + Serial.println(state); + } + + // receive GFSK packet + String str; + state = gfsk.receive(str); + /* + byte byteArr[8]; + int state = gfsk.receive(byteArr, 8); + */ + if (state == ERR_NONE) { + Serial.println(F("[SX1280] Received packet!")); + Serial.print(F("[SX1280] Data:\t")); + Serial.println(str); + } else if (state == ERR_RX_TIMEOUT) { + Serial.println(F("[SX1280] Timed out while waiting for packet!")); + } else { + Serial.print(F("[SX1280] Failed to receive packet, code ")); + Serial.println(state); + } +} diff --git a/examples/SX128x/SX128x_Receive/SX128x_Receive.ino b/examples/SX128x/SX128x_Receive/SX128x_Receive.ino new file mode 100644 index 00000000..0427cf41 --- /dev/null +++ b/examples/SX128x/SX128x_Receive/SX128x_Receive.ino @@ -0,0 +1,106 @@ +/* + RadioLib SX128x Receive Example + + This example listens for LoRa transmissions using SX126x Lora modules. + To successfully receive data, the following settings have to be the same + on both transmitter and receiver: + - carrier frequency + - bandwidth + - spreading factor + - coding rate + - sync word + - preamble length + + Other modules from SX128x family can also be used. + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1280 has the following connections: +// NSS pin: 10 +// DIO1 pin: 2 +// NRST pin: 3 +// BUSY pin: 9 +SX1280 lora = new Module(10, 2, 3, 9); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1280 lora = RadioShield.ModuleA; + +void setup() { + Serial.begin(9600); + + // initialize SX1280 with default settings + Serial.print(F("[SX1280] Initializing ... ")); + // carrier frequency: 2400.0 MHz + // bandwidth: 812.5 kHz + // spreading factor: 9 + // coding rate: 7 + // output power: 10 dBm + // preamble length: 12 symbols + // CRC: enabled + int state = lora.begin(); + if (state == ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } +} + +void loop() { + Serial.print(F("[SX1280] 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); + + // you can also receive data as byte array + /* + byte byteArr[8]; + int state = lora.receive(byteArr, 8); + */ + + if (state == ERR_NONE) { + // packet was successfully received + Serial.println(F("success!")); + + // print the data of the packet + Serial.print(F("[SX1280] Data:\t\t")); + Serial.println(str); + + // print the RSSI (Received Signal Strength Indicator) + // of the last received packet + Serial.print(F("[SX1280] RSSI:\t\t")); + Serial.print(lora.getRSSI()); + Serial.println(F(" dBm")); + + // print the SNR (Signal-to-Noise Ratio) + // of the last received packet + Serial.print(F("[SX1280] SNR:\t\t")); + Serial.print(lora.getSNR()); + Serial.println(F(" dB")); + + } else if (state == ERR_RX_TIMEOUT) { + // timeout occurred while waiting for a packet + Serial.println(F("timeout!")); + + } else if (state == ERR_CRC_MISMATCH) { + // packet was received, but is malformed + Serial.println(F("CRC error!")); + + } else { + // some other error occurred + Serial.print(F("failed, code ")); + Serial.println(state); + + } +} diff --git a/examples/SX128x/SX128x_Receive_Interrupt/SX128x_Receive_Interrupt.ino b/examples/SX128x/SX128x_Receive_Interrupt/SX128x_Receive_Interrupt.ino new file mode 100644 index 00000000..2d6f1664 --- /dev/null +++ b/examples/SX128x/SX128x_Receive_Interrupt/SX128x_Receive_Interrupt.ino @@ -0,0 +1,159 @@ +/* + RadioLib SX128x Receive with Interrupts Example + + This example listens for LoRa transmissions and tries to + receive them. Once a packet is received, an interrupt is + triggered. To successfully receive data, the following + settings have to be the same on both transmitter + and receiver: + - carrier frequency + - bandwidth + - spreading factor + - coding rate + - sync word + + Other modules from SX128x family can also be used. + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1280 has the following connections: +// NSS pin: 10 +// DIO1 pin: 2 +// NRST pin: 3 +// BUSY pin: 9 +SX1280 lora = new Module(10, 2, 3, 9); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1280 lora = RadioShield.ModuleA; + +void setup() { + Serial.begin(9600); + + // initialize SX1280 with default settings + Serial.print(F("[SX1280] Initializing ... ")); + // carrier frequency: 2400.0 MHz + // bandwidth: 812.5 kHz + // spreading factor: 9 + // coding rate: 7 + // output power: 10 dBm + // preamble length: 12 symbols + // CRC: enabled + int state = lora.begin(); + if (state == ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // set the function that will be called + // when new packet is received + lora.setDio1Action(setFlag); + + // start listening for LoRa packets + Serial.print(F("[SX1280] Starting to listen ... ")); + state = lora.startReceive(); + if (state == ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // if needed, 'listen' mode can be disabled by calling + // any of the following methods: + // + // lora.standby() + // lora.sleep() + // lora.transmit(); + // lora.receive(); + // lora.readData(); + // lora.scanChannel(); +} + +// flag to indicate that a packet was received +volatile bool receivedFlag = false; + +// disable interrupt when it's not needed +volatile bool enableInterrupt = true; + +// this function is called when a complete packet +// is received by the module +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +void setFlag(void) { + // check if the interrupt is enabled + if(!enableInterrupt) { + return; + } + + // we got a packet, set the flag + receivedFlag = true; +} + +void loop() { + // check if the flag is set + if(receivedFlag) { + // disable the interrupt service routine while + // processing the data + enableInterrupt = false; + + // reset flag + receivedFlag = false; + + // you can read received data as an Arduino String + String str; + int state = lora.readData(str); + + // you can also read received data as byte array + /* + byte byteArr[8]; + int state = lora.readData(byteArr, 8); + */ + + if (state == ERR_NONE) { + // packet was successfully received + Serial.println(F("[SX1280] Received packet!")); + + // print data of the packet + Serial.print(F("[SX1280] Data:\t\t")); + Serial.println(str); + + // print RSSI (Received Signal Strength Indicator) + Serial.print(F("[SX1280] RSSI:\t\t")); + Serial.print(lora.getRSSI()); + Serial.println(F(" dBm")); + + // print SNR (Signal-to-Noise Ratio) + Serial.print(F("[SX1280] SNR:\t\t")); + Serial.print(lora.getSNR()); + Serial.println(F(" dB")); + + } else if (state == ERR_CRC_MISMATCH) { + // packet was received, but is malformed + Serial.println(F("CRC error!")); + + } else { + // some other error occurred + Serial.print(F("failed, code ")); + Serial.println(state); + + } + + // put module back to listen mode + lora.startReceive(); + + // we're ready to receive more packets, + // enable interrupt service routine + enableInterrupt = true; + } + +} diff --git a/examples/SX128x/SX128x_Settings/SX128x_Settings.ino b/examples/SX128x/SX128x_Settings/SX128x_Settings.ino new file mode 100644 index 00000000..49d218d6 --- /dev/null +++ b/examples/SX128x/SX128x_Settings/SX128x_Settings.ino @@ -0,0 +1,134 @@ +/* + RadioLib SX128x Settings Example + + This example shows how to change all the properties of LoRa transmission. + RadioLib currently supports the following settings: + - pins (SPI slave select, DIO1, DIO2, BUSY pin) + - carrier frequency + - bandwidth + - spreading factor + - coding rate + - output power during transmission + - CRC + - preamble length + + Other modules from SX128x family can also be used. + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1280 has the following connections: +// NSS pin: 10 +// DIO1 pin: 2 +// NRST pin: 3 +// BUSY pin: 9 +SX1280 loraSX1280 = new Module(10, 2, 3, 9); + +// SX1280 has the following connections: +// NSS pin: 8 +// DIO1 pin: 4 +// NRST pin: 5 +// BUSY pin: 6 +SX1281 loraSX1281 = new Module(8, 4, 5, 6); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1282 loraSX1282 = RadioShield.ModuleB; + +void setup() { + Serial.begin(9600); + + // initialize SX1280 with default settings + Serial.print(F("[SX1280] Initializing ... ")); + // carrier frequency: 2400.0 MHz + // bandwidth: 812.5 kHz + // spreading factor: 9 + // coding rate: 7 + // output power: 10 dBm + // preamble length: 12 symbols + // CRC: enabled + int state = loraSX1280.begin(); + if (state == ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // initialize the second LoRa instance with + // non-default settings + // this LoRa link will have high data rate, + // but lower range + Serial.print(F("[SX1281] Initializing ... ")); + // carrier frequency: 2450.0 MHz + // bandwidth: 1625.0 kHz + // spreading factor: 7 + // coding rate: 5 + // output power: 2 dBm + // preamble length: 20 symbols + // CRC: enabled + state = loraSX1281.begin(2450.0, 1625.0, 7, 5, 2, 20); + if (state == ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // you can also change the settings at runtime + // and check if the configuration was changed successfully + + // set carrier frequency to 2410.5 MHz + if (loraSX1280.setFrequency(2410.5) == ERR_INVALID_FREQUENCY) { + Serial.println(F("Selected frequency is invalid for this module!")); + while (true); + } + + // set bandwidth to 203.125 kHz + if (loraSX1280.setBandwidth(203.125) == ERR_INVALID_BANDWIDTH) { + Serial.println(F("Selected bandwidth is invalid for this module!")); + while (true); + } + + // set spreading factor to 10 + if (loraSX1280.setSpreadingFactor(10) == ERR_INVALID_SPREADING_FACTOR) { + Serial.println(F("Selected spreading factor is invalid for this module!")); + while (true); + } + + // set coding rate to 6 + if (loraSX1280.setCodingRate(6) == ERR_INVALID_CODING_RATE) { + Serial.println(F("Selected coding rate is invalid for this module!")); + while (true); + } + + // set output power to -2 dBm + if (loraSX1280.setOutputPower(-2) == ERR_INVALID_OUTPUT_POWER) { + Serial.println(F("Selected output power is invalid for this module!")); + while (true); + } + + // set LoRa preamble length to 16 symbols (accepted range is 2 - 65535) + if (loraSX1280.setPreambleLength(16) == ERR_INVALID_PREAMBLE_LENGTH) { + Serial.println(F("Selected preamble length is invalid for this module!")); + while (true); + } + + // disable CRC + if (loraSX1280.setCRC(false) == ERR_INVALID_CRC_CONFIGURATION) { + Serial.println(F("Selected CRC is invalid for this module!")); + while (true); + } + + Serial.println(F("All settings succesfully changed!")); +} + +void loop() { + // nothing here +} diff --git a/examples/SX128x/SX128x_Transmit/SX128x_Transmit.ino b/examples/SX128x/SX128x_Transmit/SX128x_Transmit.ino new file mode 100644 index 00000000..e8e777dc --- /dev/null +++ b/examples/SX128x/SX128x_Transmit/SX128x_Transmit.ino @@ -0,0 +1,85 @@ +/* + RadioLib SX128x Transmit Example + + This example transmits packets using SX1280 LoRa radio module. + Each packet contains up to 256 bytes of data, in the form of: + - Arduino String + - null-terminated char array (C-string) + - arbitrary binary data (byte array) + + Other modules from SX128x family can also be used. + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1280 has the following connections: +// NSS pin: 10 +// DIO1 pin: 2 +// NRST pin: 3 +// BUSY pin: 9 +SX1280 lora = new Module(10, 2, 3, 9); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1280 lora = RadioShield.ModuleA; + +void setup() { + Serial.begin(9600); + + // initialize SX1280 with default settings + Serial.print(F("[SX1280] Initializing ... ")); + // carrier frequency: 2400.0 MHz + // bandwidth: 812.5 kHz + // spreading factor: 9 + // coding rate: 7 + // output power: 10 dBm + // preamble length: 12 symbols + // CRC: enabled + int state = lora.begin(); + if (state == ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } +} + +void loop() { + Serial.print(F("[SX1280] Transmitting packet ... ")); + + // you can transmit C-string or Arduino string up to + // 256 characters long + // NOTE: transmit() is a blocking method! + // See example SX128x_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 + /* + byte byteArr[] = {0x01, 0x23, 0x45, 0x56, 0x78, 0xAB, 0xCD, 0xEF}; + int state = lora.transmit(byteArr, 8); + */ + + if (state == ERR_NONE) { + // the packet was successfully transmitted + Serial.println(F("success!")); + + } else if (state == ERR_PACKET_TOO_LONG) { + // the supplied packet was longer than 256 bytes + Serial.println(F("too long!")); + + } else { + // some other error occurred + Serial.print(F("failed, code ")); + Serial.println(state); + + } + + // wait for a second before transmitting again + delay(1000); +} diff --git a/examples/SX128x/SX128x_Transmit_Interrupt/SX128x_Transmit_Interrupt.ino b/examples/SX128x/SX128x_Transmit_Interrupt/SX128x_Transmit_Interrupt.ino new file mode 100644 index 00000000..284244e8 --- /dev/null +++ b/examples/SX128x/SX128x_Transmit_Interrupt/SX128x_Transmit_Interrupt.ino @@ -0,0 +1,135 @@ +/* + RadioLib SX128x Transmit with Interrupts Example + + This example transmits LoRa packets with one second delays + between them. Each packet contains up to 256 bytes + of data, in the form of: + - Arduino String + - null-terminated char array (C-string) + - arbitrary binary data (byte array) + + Other modules from SX128x family can also be used. + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1280 has the following connections: +// NSS pin: 10 +// DIO1 pin: 2 +// NRST pin: 3 +// BUSY pin: 9 +SX1280 lora = new Module(10, 2, 3, 9); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1280 lora = RadioShield.ModuleA; + +// save transmission state between loops +int transmissionState = ERR_NONE; + +void setup() { + Serial.begin(9600); + + // initialize SX1280 with default settings + Serial.print(F("[SX1280] Initializing ... ")); + // carrier frequency: 2400.0 MHz + // bandwidth: 812.5 kHz + // spreading factor: 9 + // coding rate: 7 + // output power: 10 dBm + // preamble length: 12 symbols + // CRC: enabled + int state = lora.begin(); + if (state == ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // set the function that will be called + // when packet transmission is finished + lora.setDio1Action(setFlag); + + // start transmitting the first packet + Serial.print(F("[SX1280] Sending first packet ... ")); + + // you can transmit C-string or Arduino string up to + // 256 characters long + transmissionState = lora.startTransmit("Hello World!"); + + // you can also transmit byte array up to 256 bytes long + /* + byte byteArr[] = {0x01, 0x23, 0x45, 0x67, + 0x89, 0xAB, 0xCD, 0xEF}; + state = lora.startTransmit(byteArr, 8); + */ +} + +// flag to indicate that a packet was sent +volatile bool transmittedFlag = false; + +// disable interrupt when it's not needed +volatile bool enableInterrupt = true; + +// this function is called when a complete packet +// is transmitted by the module +// IMPORTANT: this function MUST be 'void' type +// and MUST NOT have any arguments! +void setFlag(void) { + // check if the interrupt is enabled + if(!enableInterrupt) { + return; + } + + // we sent a packet, set the flag + transmittedFlag = true; +} + +void loop() { + // check if the previous transmission finished + if(transmittedFlag) { + // disable the interrupt service routine while + // processing the data + enableInterrupt = false; + + // reset flag + transmittedFlag = false; + + if (transmissionState == ERR_NONE) { + // packet was successfully sent + Serial.println(F("transmission finished!")); + + } else { + Serial.print(F("failed, code ")); + Serial.println(transmissionState); + + } + + // wait a second before transmitting again + delay(1000); + + // send another one + Serial.print(F("[SX1280] Sending another packet ... ")); + + // you can transmit C-string or Arduino string up to + // 256 characters long + transmissionState = lora.startTransmit("Hello World!"); + + // you can also transmit byte array up to 256 bytes long + /* + byte byteArr[] = {0x01, 0x23, 0x45, 0x67, + 0x89, 0xAB, 0xCD, 0xEF}; + int state = lora.startTransmit(byteArr, 8); + */ + + // we're ready to send more packets, + // enable interrupt service routine + enableInterrupt = true; + } +} diff --git a/keywords.txt b/keywords.txt index 57b8b822..d42b2c73 100644 --- a/keywords.txt +++ b/keywords.txt @@ -37,6 +37,9 @@ SX1276 KEYWORD1 SX1277 KEYWORD1 SX1278 KEYWORD1 SX1279 KEYWORD1 +SX1280 KEYWORD1 +SX1281 KEYWORD1 +SX1282 KEYWORD1 XBee KEYWORD1 XBeeSerial KEYWORD1 @@ -209,6 +212,9 @@ sendHeader KEYWORD2 sendLine KEYWORD2 getPictureHeight KEYWORD2 +# SX128x +beginGFSK KEYWORD2 + ####################################### # Constants (LITERAL1) ####################################### diff --git a/src/RadioLib.h b/src/RadioLib.h index ae4a6909..d4911d51 100644 --- a/src/RadioLib.h +++ b/src/RadioLib.h @@ -14,6 +14,7 @@ - Si443x FSK module - SX126x LoRa/FSK module - SX127x LoRa/FSK module + - SX128x LoRa/GFSK/BLE/FLRC module - SX1231 FSK module - XBee module (S2B) - PhysicalLayer protocols @@ -77,6 +78,9 @@ #include "modules/SX127x/SX1277.h" #include "modules/SX127x/SX1278.h" #include "modules/SX127x/SX1279.h" +#include "modules/SX128x/SX1280.h" +#include "modules/SX128x/SX1281.h" +#include "modules/SX128x/SX1282.h" #include "modules/XBee/XBee.h" // physical layer protocols @@ -110,7 +114,6 @@ \brief Library control object when using RadioShield. Contains two pre-configured "modules", which correspond to the slots on shield. */ - class Radio { public: diff --git a/src/modules/SX128x/SX1280.cpp b/src/modules/SX128x/SX1280.cpp new file mode 100644 index 00000000..afbc96df --- /dev/null +++ b/src/modules/SX128x/SX1280.cpp @@ -0,0 +1,5 @@ +#include "SX1280.h" + +SX1280::SX1280(Module* mod) : SX1281(mod) { + +} diff --git a/src/modules/SX128x/SX1280.h b/src/modules/SX128x/SX1280.h new file mode 100644 index 00000000..08aa1ec1 --- /dev/null +++ b/src/modules/SX128x/SX1280.h @@ -0,0 +1,31 @@ +#ifndef _RADIOLIB_SX1280_H +#define _RADIOLIB_SX1280_H + +#include "../../TypeDef.h" +#include "../../Module.h" +#include "SX128x.h" +#include "SX1281.h" + +// TODO implement ranging + +/*! + \class SX1280 + + \brief Derived class for %SX1280 modules. +*/ +class SX1280: public SX1281 { + public: + /*! + \brief Default constructor. + + \param mod Instance of Module that will be used to communicate with the radio. + */ + SX1280(Module* mod); + +#ifndef RADIOLIB_GODMODE + private: +#endif + +}; + +#endif diff --git a/src/modules/SX128x/SX1281.cpp b/src/modules/SX128x/SX1281.cpp new file mode 100644 index 00000000..4aa09b0d --- /dev/null +++ b/src/modules/SX128x/SX1281.cpp @@ -0,0 +1,5 @@ +#include "SX1281.h" + +SX1281::SX1281(Module* mod) : SX128x(mod) { + +} diff --git a/src/modules/SX128x/SX1281.h b/src/modules/SX128x/SX1281.h new file mode 100644 index 00000000..88037a09 --- /dev/null +++ b/src/modules/SX128x/SX1281.h @@ -0,0 +1,28 @@ +#ifndef _RADIOLIB_SX1281_H +#define _RADIOLIB_SX1281_H + +#include "../../TypeDef.h" +#include "../../Module.h" +#include "SX128x.h" + +/*! + \class SX1281 + + \brief Derived class for %SX1281 modules. +*/ +class SX1281: public SX128x { + public: + /*! + \brief Default constructor. + + \param mod Instance of Module that will be used to communicate with the radio. + */ + SX1281(Module* mod); + +#ifndef RADIOLIB_GODMODE + private: +#endif + +}; + +#endif diff --git a/src/modules/SX128x/SX1282.cpp b/src/modules/SX128x/SX1282.cpp new file mode 100644 index 00000000..847a36d1 --- /dev/null +++ b/src/modules/SX128x/SX1282.cpp @@ -0,0 +1,5 @@ +#include "SX1282.h" + +SX1282::SX1282(Module* mod) : SX1280(mod) { + +} diff --git a/src/modules/SX128x/SX1282.h b/src/modules/SX128x/SX1282.h new file mode 100644 index 00000000..09f92075 --- /dev/null +++ b/src/modules/SX128x/SX1282.h @@ -0,0 +1,31 @@ +#ifndef _RADIOLIB_SX1282_H +#define _RADIOLIB_SX1282_H + +#include "../../TypeDef.h" +#include "../../Module.h" +#include "SX128x.h" +#include "SX1280.h" + +// TODO implement advanced ranging + +/*! + \class SX1282 + + \brief Derived class for %SX1282 modules. +*/ +class SX1282: public SX1280 { + public: + /*! + \brief Default constructor. + + \param mod Instance of Module that will be used to communicate with the radio. + */ + SX1282(Module* mod); + +#ifndef RADIOLIB_GODMODE + private: +#endif + +}; + +#endif diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp new file mode 100644 index 00000000..a11b1788 --- /dev/null +++ b/src/modules/SX128x/SX128x.cpp @@ -0,0 +1,1208 @@ +#include "SX128x.h" + +SX128x::SX128x(Module* mod) : PhysicalLayer(SX128X_FREQUENCY_STEP_SIZE, SX128X_MAX_PACKET_LENGTH) { + _mod = mod; +} + +int16_t SX128x::begin(float freq, float bw, uint8_t sf, uint8_t cr, int8_t power, uint16_t preambleLength) { + // set module properties + _mod->init(RADIOLIB_USE_SPI); + Module::pinMode(_mod->getIrq(), INPUT); + Module::pinMode(_mod->getGpio(), INPUT); + + // initialize LoRa modulation variables + _bwKhz = bw; + _sf = SX128X_LORA_SF_9; + _cr = SX128X_LORA_CR_4_7; + + // initialize LoRa packet variables + _preambleLengthLoRa = preambleLength; + _headerType = SX128X_LORA_HEADER_EXPLICIT; + _payloadLen = 0xFF; + _crcLoRa = SX128X_LORA_CRC_ON; + + // reset the module and verify startup + int16_t state = reset(); + RADIOLIB_ASSERT(state); + + // set mode to standby + state = standby(); + RADIOLIB_ASSERT(state); + + // configure settings not accessible by API + state = config(SX128X_PACKET_TYPE_LORA); + RADIOLIB_ASSERT(state); + + // configure publicly accessible settings + state = setFrequency(freq); + RADIOLIB_ASSERT(state); + + state = setBandwidth(bw); + RADIOLIB_ASSERT(state); + + state = setSpreadingFactor(sf); + RADIOLIB_ASSERT(state); + + state = setCodingRate(cr); + RADIOLIB_ASSERT(state); + + state = setPreambleLength(preambleLength); + RADIOLIB_ASSERT(state); + + state = setOutputPower(power); + RADIOLIB_ASSERT(state); + + return(state); +} + +int16_t SX128x::beginGFSK(float freq, uint16_t br, float freqDev, int8_t power, uint16_t preambleLength, float dataShaping) { + // set module properties + _mod->init(RADIOLIB_USE_SPI); + Module::pinMode(_mod->getIrq(), INPUT); + Module::pinMode(_mod->getGpio(), INPUT); + + // initialize GFSK modulation variables + _brKbps = br; + _br = SX128X_BLE_GFSK_BR_0_800_BW_2_4; + _modIndexReal = 1.0; + _modIndex = SX128X_BLE_GFSK_MOD_IND_1_00; + _shaping = SX128X_BLE_GFSK_BT_0_5; + + // initialize GFSK packet variables + _preambleLengthGFSK = preambleLength; + _syncWordLen = 2; + _syncWordMatch = SX128X_GFSK_FLRC_SYNC_WORD_1; + _crcGFSK = SX128X_GFSK_FLRC_CRC_2_BYTE; + _whitening = SX128X_GFSK_BLE_WHITENING_ON; + + // reset the module and verify startup + int16_t state = reset(); + RADIOLIB_ASSERT(state); + + // set mode to standby + state = standby(); + RADIOLIB_ASSERT(state); + + // configure settings not accessible by API + state = config(SX128X_PACKET_TYPE_GFSK); + RADIOLIB_ASSERT(state); + + // configure publicly accessible settings + state = setFrequency(freq); + RADIOLIB_ASSERT(state); + + state = setBitRate(br); + RADIOLIB_ASSERT(state); + + state = setFrequencyDeviation(freqDev); + RADIOLIB_ASSERT(state); + + state = setOutputPower(power); + RADIOLIB_ASSERT(state); + + state = setPreambleLength(preambleLength); + RADIOLIB_ASSERT(state); + + state = setDataShaping(dataShaping); + RADIOLIB_ASSERT(state); + + // set publicly accessible settings that are not a part of begin method + uint8_t sync[] = { 0x2D, 0x01 }; + state = setSyncWord(sync, 2); + RADIOLIB_ASSERT(state); + + return(state); +} + +int16_t SX128x::reset(bool verify) { + // run the reset sequence - same as SX126x, as SX128x docs don't seem to mention this + Module::pinMode(_mod->getRst(), OUTPUT); + Module::digitalWrite(_mod->getRst(), LOW); + delay(1); + Module::digitalWrite(_mod->getRst(), HIGH); + + // return immediately when verification is disabled + if(!verify) { + return(ERR_NONE); + } + + // set mode to standby + uint32_t start = millis(); + while(true) { + // try to set mode to standby + int16_t state = standby(); + if(state == ERR_NONE) { + // standby command successful + return(ERR_NONE); + } + + // standby command failed, check timeout and try again + if(millis() - start >= 3000) { + // timed out, possibly incorrect wiring + return(state); + } + + // wait a bit to not spam the module + delay(10); + } +} + +int16_t SX128x::transmit(uint8_t* data, size_t len, uint8_t addr) { + // check packet length + if(len > SX128X_MAX_PACKET_LENGTH) { + return(ERR_PACKET_TOO_LONG); + } + + // check active modem + uint8_t modem = getPacketType(); + if(modem == SX128X_PACKET_TYPE_RANGING) { + return(ERR_WRONG_MODEM); + } + + // set mode to standby + int16_t state = standby(); + RADIOLIB_ASSERT(state); + + // calculate timeout (500% of expected time-on-air) + uint32_t timeout = getTimeOnAir(len) * 5; + + RADIOLIB_DEBUG_PRINT(F("Timeout in ")); + RADIOLIB_DEBUG_PRINT(timeout); + RADIOLIB_DEBUG_PRINTLN(F(" us")); + + // start transmission + state = startTransmit(data, len, addr); + RADIOLIB_ASSERT(state); + + // wait for packet transmission or timeout + uint32_t start = micros(); + while(!digitalRead(_mod->getIrq())) { + yield(); + if(micros() - start > timeout) { + clearIrqStatus(); + standby(); + return(ERR_TX_TIMEOUT); + } + } + + // clear interrupt flags + state = clearIrqStatus(); + RADIOLIB_ASSERT(state); + + // set mode to standby to disable transmitter + state = standby(); + + return(state); +} + +int16_t SX128x::receive(uint8_t* data, size_t len) { + // check active modem + uint8_t modem = getPacketType(); + if(modem == SX128X_PACKET_TYPE_RANGING) { + return(ERR_WRONG_MODEM); + } + + // set mode to standby + int16_t state = standby(); + RADIOLIB_ASSERT(state); + + // calculate timeout (1000% of expected time-on-air) + uint32_t timeout = getTimeOnAir(len) * 10; + + RADIOLIB_DEBUG_PRINT(F("Timeout in ")); + RADIOLIB_DEBUG_PRINT(timeout); + RADIOLIB_DEBUG_PRINTLN(F(" us")); + + // start reception + uint32_t timeoutValue = (uint32_t)((float)timeout / 15.625); + state = startReceive(timeoutValue); + RADIOLIB_ASSERT(state); + + // wait for packet reception or timeout + uint32_t start = micros(); + while(!digitalRead(_mod->getIrq())) { + yield(); + if(micros() - start > timeout) { + clearIrqStatus(); + standby(); + return(ERR_RX_TIMEOUT); + } + } + + // read the received data + return(readData(data, len)); +} + +int16_t SX128x::transmitDirect(uint32_t frf) { + // user requested to start transmitting immediately (required for RTTY) + int16_t state = ERR_NONE; + if(frf != 0) { + state = setRfFrequency(frf); + } + RADIOLIB_ASSERT(state); + + // start transmitting + return(SPIwriteCommand(SX128X_CMD_SET_TX_CONTINUOUS_WAVE, NULL, 0)); +} + +int16_t SX128x::receiveDirect() { + // SX128x is unable to output received data directly + return(ERR_UNKNOWN); +} + +int16_t SX128x::scanChannel() { + // check active modem + if(getPacketType() != SX128X_PACKET_TYPE_LORA) { + return(ERR_WRONG_MODEM); + } + + // set mode to standby + int16_t state = standby(); + RADIOLIB_ASSERT(state); + + // set DIO pin mapping + state = setDioIrqParams(SX128X_IRQ_CAD_DETECTED | SX128X_IRQ_CAD_DONE, SX128X_IRQ_CAD_DETECTED | SX128X_IRQ_CAD_DONE); + RADIOLIB_ASSERT(state); + + // clear interrupt flags + state = clearIrqStatus(); + RADIOLIB_ASSERT(state); + + // set mode to CAD + state = setCad(); + RADIOLIB_ASSERT(state); + + // wait for channel activity detected or timeout + while(!digitalRead(_mod->getIrq())) { + yield(); + } + + // check CAD result + uint16_t cadResult = getIrqStatus(); + if(cadResult & SX128X_IRQ_CAD_DETECTED) { + // detected some LoRa activity + clearIrqStatus(); + return(LORA_DETECTED); + } else if(cadResult & SX128X_IRQ_CAD_DONE) { + // channel is free + clearIrqStatus(); + return(CHANNEL_FREE); + } + + return(ERR_UNKNOWN); +} + +int16_t SX128x::sleep(bool retainConfig) { + uint8_t sleepConfig = SX128X_SLEEP_DATA_BUFFER_RETAIN | SX128X_SLEEP_DATA_RAM_RETAIN; + if(!retainConfig) { + sleepConfig = SX128X_SLEEP_DATA_BUFFER_FLUSH | SX128X_SLEEP_DATA_RAM_FLUSH; + } + int16_t state = SPIwriteCommand(SX128X_CMD_SET_SLEEP, &sleepConfig, 1, false); + + // wait for SX128x to safely enter sleep mode + delay(1); + + return(state); +} + +int16_t SX128x::standby() { + return(SX128x::standby(SX128X_STANDBY_RC)); +} + +int16_t SX128x::standby(uint8_t mode) { + uint8_t data[] = { mode }; + return(SPIwriteCommand(SX128X_CMD_SET_STANDBY, data, 1)); +} + +void SX128x::setDio1Action(void (*func)(void)) { + attachInterrupt(digitalPinToInterrupt(_mod->getIrq()), func, RISING); +} + +void SX128x::clearDio1Action() { + detachInterrupt(digitalPinToInterrupt(_mod->getIrq())); +} + +int16_t SX128x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { + // suppress unused variable warning + (void)addr; + + // check packet length + if(len > SX128X_MAX_PACKET_LENGTH) { + return(ERR_PACKET_TOO_LONG); + } + + // set packet Length + int16_t state = ERR_NONE; + uint8_t modem = getPacketType(); + if(modem == SX128X_PACKET_TYPE_LORA) { + state = setPacketParamsLoRa(_preambleLengthLoRa, _headerType, len, _crcLoRa); + } else if(modem == SX128X_PACKET_TYPE_GFSK) { + state = setPacketParamsGFSK(_preambleLengthGFSK, _syncWordLen, _syncWordMatch, _crcGFSK, _whitening, len); + } else { + return(ERR_WRONG_MODEM); + } + RADIOLIB_ASSERT(state); + + // update output power + state = setTxParams(_pwr); + RADIOLIB_ASSERT(state); + + // set buffer pointers + state = setBufferBaseAddress(); + RADIOLIB_ASSERT(state); + + // write packet to buffer + state = writeBuffer(data, len); + RADIOLIB_ASSERT(state); + + // set DIO mapping + state = setDioIrqParams(SX128X_IRQ_TX_DONE | SX128X_IRQ_RX_TX_TIMEOUT, SX128X_IRQ_TX_DONE); + RADIOLIB_ASSERT(state); + + // clear interrupt flags + state = clearIrqStatus(); + RADIOLIB_ASSERT(state); + + // start transmission + state = setTx(SX128X_TX_TIMEOUT_NONE); + RADIOLIB_ASSERT(state); + + // wait for BUSY to go low (= PA ramp up done) + while(digitalRead(_mod->getGpio())) { + yield(); + } + + return(state); +} + +int16_t SX128x::startReceive(uint16_t timeout) { + // check active modem + if(getPacketType() == SX128X_PACKET_TYPE_RANGING) { + return(ERR_WRONG_MODEM); + } + + // set DIO mapping + int16_t state = setDioIrqParams(SX128X_IRQ_RX_DONE | SX128X_IRQ_RX_TX_TIMEOUT | SX128X_IRQ_CRC_ERROR | SX128X_IRQ_HEADER_ERROR, SX128X_IRQ_RX_DONE); + RADIOLIB_ASSERT(state); + + // set buffer pointers + state = setBufferBaseAddress(); + RADIOLIB_ASSERT(state); + + // clear interrupt flags + state = clearIrqStatus(); + RADIOLIB_ASSERT(state); + + // set implicit mode and expected len if applicable + if((_headerType == SX128X_LORA_HEADER_IMPLICIT) && (getPacketType() == SX128X_PACKET_TYPE_LORA)) { + state = setPacketParamsLoRa(_preambleLengthLoRa, _headerType, _payloadLen, _crcLoRa); + RADIOLIB_ASSERT(state); + } + + // set mode to receive + state = setRx(timeout); + + return(state); +} + +int16_t SX128x::readData(uint8_t* data, size_t len) { + // set mode to standby + int16_t state = standby(); + RADIOLIB_ASSERT(state); + + // check integrity CRC + uint16_t irq = getIrqStatus(); + int16_t crcState = ERR_NONE; + if((irq & SX128X_IRQ_CRC_ERROR) || (irq & SX128X_IRQ_HEADER_ERROR)) { + crcState = ERR_CRC_MISMATCH; + } + + // get packet length + size_t length = len; + if(len == SX128X_MAX_PACKET_LENGTH) { + length = getPacketLength(); + } + + // read packet data + state = readBuffer(data, length); + RADIOLIB_ASSERT(state); + + // clear interrupt flags + state = clearIrqStatus(); + + // check if CRC failed - this is done after reading data to give user the option to keep them + RADIOLIB_ASSERT(crcState); + + return(state); +} + +int16_t SX128x::setFrequency(float freq) { + RADIOLIB_CHECK_RANGE(freq, 2400.0, 2500.0, ERR_INVALID_FREQUENCY); + + // calculate raw value + uint32_t frf = (freq * (uint32_t(1) << SX128X_DIV_EXPONENT)) / SX128X_CRYSTAL_FREQ; + return(setRfFrequency(frf)); +} + +int16_t SX128x::setBandwidth(float bw) { + // check active modem + uint8_t modem = getPacketType(); + if(modem == SX128X_PACKET_TYPE_LORA) { + // check range for LoRa + RADIOLIB_CHECK_RANGE(bw, 203.125, 1625.0, ERR_INVALID_BANDWIDTH); + } else if(modem == SX128X_PACKET_TYPE_RANGING) { + // check range for ranging + RADIOLIB_CHECK_RANGE(bw, 406.25, 1625.0, ERR_INVALID_BANDWIDTH); + } else { + return(ERR_WRONG_MODEM); + } + + if(abs(bw - 203.125) <= 0.001) { + _bw = SX128X_LORA_BW_203_125; + } else if(abs(bw - 406.25) <= 0.001) { + _bw = SX128X_LORA_BW_406_25; + } else if(abs(bw - 812.5) <= 0.001) { + _bw = SX128X_LORA_BW_812_50; + } else if(abs(bw - 1625.0) <= 0.001) { + _bw = SX128X_LORA_BW_1625_00; + } else { + return(ERR_INVALID_BANDWIDTH); + } + + // update modulation parameters + _bwKhz = bw; + return(setModulationParams(_sf, _bw, _cr)); +} + +int16_t SX128x::setSpreadingFactor(uint8_t sf) { + // check active modem + uint8_t modem = getPacketType(); + if(modem == SX128X_PACKET_TYPE_LORA) { + // check range for LoRa + RADIOLIB_CHECK_RANGE(sf, 5, 12, ERR_INVALID_SPREADING_FACTOR); + } else if(modem == SX128X_PACKET_TYPE_RANGING) { + // check range for ranging + RADIOLIB_CHECK_RANGE(sf, 5, 10, ERR_INVALID_SPREADING_FACTOR); + } else { + return(ERR_WRONG_MODEM); + } + + // update modulation parameters + _sf = sf << 4; + int16_t state = setModulationParams(_sf, _bw, _cr); + RADIOLIB_ASSERT(state); + + // update mystery register in LoRa mode - SX1280 datasheet v3.0 section 13.4.1 + if(modem == SX128X_PACKET_TYPE_LORA) { + uint8_t data = 0; + if((_sf == SX128X_LORA_SF_5) || (_sf == SX128X_LORA_SF_6)) { + data = 0x1E; + } else if((_sf == SX128X_LORA_SF_7) || (_sf == SX128X_LORA_SF_8)) { + data = 0x37; + } else { + data = 0x32; + } + state = SX128x::writeRegister(SX128X_REG_LORA_SF_CONFIG, &data, 1); + } + + return(state); +} + +int16_t SX128x::setCodingRate(uint8_t cr, bool longInterleaving) { + // check active modem + uint8_t modem = getPacketType(); + if(!((modem == SX128X_PACKET_TYPE_LORA) || (modem == SX128X_PACKET_TYPE_RANGING))) { + return(ERR_WRONG_MODEM); + } + + RADIOLIB_CHECK_RANGE(cr, 5, 8, ERR_INVALID_CODING_RATE); + + // update modulation parameters + if(longInterleaving && (modem == SX128X_PACKET_TYPE_LORA)) { + _cr = cr; + } else { + _cr = cr - 4; + } + return(setModulationParams(_sf, _bw, _cr)); +} + +int16_t SX128x::setOutputPower(int8_t power) { + RADIOLIB_CHECK_RANGE(power, -18, 13, ERR_INVALID_OUTPUT_POWER); + _pwr = power + 18; + return(setTxParams(_pwr)); +} + +int16_t SX128x::setPreambleLength(uint32_t preambleLength) { + uint8_t modem = getPacketType(); + if((modem == SX128X_PACKET_TYPE_LORA) || (modem == SX128X_PACKET_TYPE_RANGING)) { + // LoRa or ranging + RADIOLIB_CHECK_RANGE(preambleLength, 2, 491520, ERR_INVALID_PREAMBLE_LENGTH); + + // check preamble length is even - no point even trying odd numbers + if(preambleLength % 2 != 0) { + return(ERR_INVALID_PREAMBLE_LENGTH); + } + + // calculate exponent and mantissa values (use the next longer preamble if there's no exact match) + uint8_t e = 1; + uint8_t m = 1; + uint32_t len = 0; + for(; e <= 15; e++) { + for(; m <= 15; m++) { + len = m * (uint32_t(1) << e); + if(len >= preambleLength) { + break; + } + } + if(len >= preambleLength) { + break; + } + } + + // update packet parameters + _preambleLengthLoRa = (e << 4) | m; + return(setPacketParamsLoRa(_preambleLengthLoRa, _headerType, _payloadLen, _crcLoRa)); + + } else if((modem == SX128X_PACKET_TYPE_GFSK) || (modem == SX128X_PACKET_TYPE_FLRC)) { + // GFSK or FLRC + RADIOLIB_CHECK_RANGE(preambleLength, 4, 32, ERR_INVALID_PREAMBLE_LENGTH); + + // check preamble length is multiple of 4 + if(preambleLength % 4 != 0) { + return(ERR_INVALID_PREAMBLE_LENGTH); + } + + // update packet parameters + _preambleLengthGFSK = ((preambleLength / 4) - 1) << 4; + return(setPacketParamsGFSK(_preambleLengthGFSK, _syncWordLen, _syncWordMatch, _crcGFSK, _whitening)); + } + + return(ERR_WRONG_MODEM); +} + +int16_t SX128x::setBitRate(uint16_t br) { + // check active modem + uint8_t modem = getPacketType(); + if(!((modem == SX128X_PACKET_TYPE_GFSK) || (modem == SX128X_PACKET_TYPE_BLE))) { + return(ERR_WRONG_MODEM); + } + + if(br == 125) { + _br = SX128X_BLE_GFSK_BR_0_125_BW_0_3; + } else if(br == 250) { + _br = SX128X_BLE_GFSK_BR_0_250_BW_0_6; + } else if(br == 400) { + _br = SX128X_BLE_GFSK_BR_0_400_BW_1_2; + } else if(br == 500) { + _br = SX128X_BLE_GFSK_BR_0_500_BW_1_2; + } else if(br == 800) { + _br = SX128X_BLE_GFSK_BR_0_800_BW_2_4; + } else if(br == 1000) { + _br = SX128X_BLE_GFSK_BR_1_000_BW_2_4; + } else if(br == 1600) { + _br = SX128X_BLE_GFSK_BR_1_600_BW_2_4; + } else if(br == 2000) { + _br = SX128X_BLE_GFSK_BR_2_000_BW_2_4; + } else { + return(ERR_INVALID_BIT_RANGE); + } + + // update modulation parameters + _brKbps = br; + return(setModulationParams(_br, _modIndex, _shaping)); +} + +int16_t SX128x::setFrequencyDeviation(float freqDev) { + // check active modem + uint8_t modem = getPacketType(); + if(!((modem == SX128X_PACKET_TYPE_GFSK) || (modem == SX128X_PACKET_TYPE_BLE))) { + return(ERR_WRONG_MODEM); + } + + RADIOLIB_CHECK_RANGE(freqDev, 0.0, 3200.0, ERR_INVALID_FREQUENCY_DEVIATION); + + // override for the lowest possible frequency deviation - required for some PhysicalLayer protocols + if(freqDev == 0.0) { + _modIndex = SX128X_BLE_GFSK_MOD_IND_0_35; + _br = SX128X_BLE_GFSK_BR_0_125_BW_0_3; + return(setModulationParams(_br, _modIndex, _shaping)); + } + + // update modulation parameters + uint8_t modIndex = (uint8_t)((8.0 * (freqDev / (float)_brKbps)) - 1.0); + if(modIndex > SX128X_BLE_GFSK_MOD_IND_4_00) { + return(ERR_INVALID_MODULATION_PARAMETERS); + } + + // update modulation parameters + _modIndex = modIndex; + return(setModulationParams(_br, _modIndex, _shaping)); +} + +int16_t SX128x::setDataShaping(float dataShaping) { + // check active modem + uint8_t modem = getPacketType(); + if(!((modem == SX128X_PACKET_TYPE_GFSK) || (modem == SX128X_PACKET_TYPE_BLE))) { + return(ERR_WRONG_MODEM); + } + + // check allowed values + dataShaping *= 10.0; + if(abs(dataShaping - 0.0) <= 0.001) { + _shaping = SX128X_BLE_GFSK_BT_OFF; + } else if(abs(dataShaping - 5.0) <= 0.001) { + _shaping = SX128X_BLE_GFSK_BT_0_5; + } else if(abs(dataShaping - 10.0) <= 0.001) { + _shaping = SX128X_BLE_GFSK_BT_1_0; + } else { + return(ERR_INVALID_DATA_SHAPING); + } + + // update modulation parameters + return(setModulationParams(_br, _modIndex, _shaping)); +} + +int16_t SX128x::setSyncWord(uint8_t* syncWord, uint8_t len) { + // check active modem + uint8_t modem = getPacketType(); + if(!((modem == SX128X_PACKET_TYPE_GFSK) || (modem == SX128X_PACKET_TYPE_FLRC))) { + return(ERR_WRONG_MODEM); + } + + if(len > 5) { + return(ERR_INVALID_SYNC_WORD); + } + + // reverse sync word byte order + uint8_t syncWordBuff[] = { 0x00, 0x00, 0x00, 0x00, 0x00 }; + for(uint8_t i = 0; i < len; i++) { + syncWordBuff[4 - i] = syncWord[i]; + } + + // update sync word + int16_t state = SX128x::writeRegister(SX128X_REG_SYNC_WORD_1_BYTE_4, syncWordBuff, 5); + RADIOLIB_ASSERT(state); + + // update packet parameters + _syncWordLen = len; + if(_syncWordLen == 0) { + _syncWordMatch = SX128X_GFSK_FLRC_SYNC_WORD_OFF; + } else { + // TODO add support for multiple sync words + _syncWordMatch = SX128X_GFSK_FLRC_SYNC_WORD_1; + } + return(setPacketParamsGFSK(_preambleLengthGFSK, _syncWordLen, _syncWordMatch, _crcGFSK, _whitening)); +} + +int16_t SX128x::setCRC(uint8_t len, uint32_t initial, uint16_t polynomial) { + // check active modem + uint8_t modem = getPacketType(); + + int16_t state = ERR_NONE; + if((modem == SX128X_PACKET_TYPE_GFSK) || (modem == SX128X_PACKET_TYPE_FLRC)) { + // update packet parameters + if(modem == SX128X_PACKET_TYPE_GFSK) { + if(len > 2) { + return(ERR_INVALID_CRC_CONFIGURATION); + } + } else { + if(len > 3) { + return(ERR_INVALID_CRC_CONFIGURATION); + } + } + _crcGFSK = len << 4; + state = setPacketParamsGFSK(_preambleLengthGFSK, _syncWordLen, _syncWordMatch, _crcGFSK, _whitening); + RADIOLIB_ASSERT(state); + + // set initial CRC value + uint8_t data[] = { (uint8_t)((initial >> 8) & 0xFF), (uint8_t)(initial & 0xFF) }; + state = writeRegister(SX128X_REG_CRC_INITIAL_MSB, data, 2); + RADIOLIB_ASSERT(state); + + // set CRC polynomial + data[0] = (uint8_t)((polynomial >> 8) & 0xFF); + data[1] = (uint8_t)(polynomial & 0xFF); + state = writeRegister(SX128X_REG_CRC_POLYNOMIAL_MSB, data, 2); + return(state); + + } else if(modem == SX128X_PACKET_TYPE_BLE) { + // update packet parameters + if(len == 0) { + _crcBLE = SX128X_BLE_CRC_OFF; + } else if(len == 3) { + _crcBLE = SX128X_BLE_CRC_3_BYTE; + } else { + return(ERR_INVALID_CRC_CONFIGURATION); + } + state = setPacketParamsBLE(_connectionState, _crcBLE, _bleTestPayload, _whitening); + RADIOLIB_ASSERT(state); + + // set initial CRC value + uint8_t data[] = { (uint8_t)((initial >> 16) & 0xFF), (uint8_t)((initial >> 8) & 0xFF), (uint8_t)(initial & 0xFF) }; + state = writeRegister(SX128X_REG_BLE_CRC_INITIAL_MSB, data, 3); + return(state); + + } else if((modem == SX128X_PACKET_TYPE_LORA) || (modem == SX128X_PACKET_TYPE_RANGING)) { + // update packet parameters + if(len == 0) { + _crcLoRa = SX128X_LORA_CRC_OFF; + } else if(len == 2) { + _crcLoRa = SX128X_LORA_CRC_ON; + } else { + return(ERR_INVALID_CRC_CONFIGURATION); + } + state = setPacketParamsLoRa(_preambleLengthLoRa, _headerType, _payloadLen, _crcLoRa); + return(state); + } + + return(ERR_UNKNOWN); +} + +int16_t SX128x::setWhitening(bool enabled) { + // check active modem + uint8_t modem = getPacketType(); + if(!((modem == SX128X_PACKET_TYPE_GFSK) || (modem == SX128X_PACKET_TYPE_BLE))) { + return(ERR_WRONG_MODEM); + } + + // update packet parameters + if(enabled) { + _whitening = SX128X_GFSK_BLE_WHITENING_ON; + } else { + _whitening = SX128X_GFSK_BLE_WHITENING_OFF; + } + + if(modem == SX128X_PACKET_TYPE_GFSK) { + return(setPacketParamsGFSK(_preambleLengthGFSK, _syncWordLen, _syncWordMatch, _crcGFSK, _whitening)); + } + return(setPacketParamsBLE(_connectionState, _crcBLE, _bleTestPayload, _whitening)); +} + +float SX128x::getRSSI() { + // get packet status + uint8_t packetStatus[5]; + SPIreadCommand(SX128X_CMD_GET_PACKET_STATUS, packetStatus, 5); + + // check active modem + uint8_t modem = getPacketType(); + if((modem == SX128X_PACKET_TYPE_LORA) || (modem == SX128X_PACKET_TYPE_RANGING)) { + // LoRa or ranging + uint8_t rssiSync = packetStatus[0]; + float rssiMeasured = -1.0 * rssiSync/2.0; + float snr = getSNR(); + if(snr <= 0.0) { + return(rssiMeasured - snr); + } else { + return(rssiMeasured); + } + } else { + // GFSK, BLE or FLRC + uint8_t rssiSync = packetStatus[1]; + return(-1.0 * rssiSync/2.0); + } +} + +float SX128x::getSNR() { + // check active modem + uint8_t modem = getPacketType(); + if(!((modem == SX128X_PACKET_TYPE_LORA) || (modem == SX128X_PACKET_TYPE_RANGING))) { + return(0.0); + } + + // get packet status + uint8_t packetStatus[5]; + SPIreadCommand(SX128X_CMD_GET_PACKET_STATUS, packetStatus, 5); + + // calculate real SNR + uint8_t snr = packetStatus[1]; + if(snr < 128) { + return(snr/4.0); + } else { + return((snr - 256)/4.0); + } +} + +size_t SX128x::getPacketLength(bool update) { + (void)update; + uint8_t rxBufStatus[2]; + SPIreadCommand(SX128X_CMD_GET_RX_BUFFER_STATUS, rxBufStatus, 2); + return((size_t)rxBufStatus[0]); +} + +uint32_t SX128x::getTimeOnAir(size_t len) { + // check active modem + uint8_t modem = getPacketType(); + if(modem == SX128X_PACKET_TYPE_LORA) { + // calculate number of symbols + float N_symbol = 0; + uint8_t sf = _sf >> 4; + if(_cr <= SX128X_LORA_CR_4_8) { + // legacy coding rate - nice and simple + + // get SF coefficients + float coeff1 = 0; + uint8_t coeff2 = 0; + uint8_t coeff3 = 0; + if(sf < 7) { + // SF5, SF6 + coeff1 = 6.25; + coeff2 = 4*sf; + coeff3 = 4*sf; + } else if(sf < 11) { + // SF7. SF8, SF9, SF10 + coeff1 = 4.25; + coeff2 = 4*sf + 8; + coeff3 = 4*sf; + } else { + // SF11, SF12 + coeff1 = 4.25; + coeff2 = 4*sf + 8; + coeff3 = 4*(sf - 2); + } + + // get CRC length + uint8_t N_bitCRC = 16; + if(_crcLoRa == SX128X_LORA_CRC_OFF) { + N_bitCRC = 0; + } + + // get header length + uint8_t N_symbolHeader = 20; + if(_headerType == SX128X_LORA_HEADER_IMPLICIT) { + N_symbolHeader = 0; + } + + // calculate number of LoRa preamble symbols + uint32_t N_symbolPreamble = (_preambleLengthLoRa & 0x0F) * (uint32_t(1) << ((_preambleLengthLoRa & 0xF0) >> 4)); + + // calculate the number of symbols + N_symbol = (float)N_symbolPreamble + coeff1 + 8.0 + ceil(max(8 * len + N_bitCRC - coeff2 + N_symbolHeader, 0) / (float)coeff3) * (float)(_cr + 4); + + } else { + // long interleaving - abandon hope all ye who enter here + // TODO implement this mess - SX1280 datasheet v3.0 section 7.4.4.2 + + } + + // get time-on-air in us + return(((uint32_t(1) << sf) / _bwKhz) * N_symbol * 1000.0); + + } else { + return((len * 8) / _brKbps); + } + +} + +int16_t SX128x::implicitHeader(size_t len) { + return(setHeaderType(SX128X_LORA_HEADER_IMPLICIT, len)); +} + +int16_t SX128x::explicitHeader() { + return(setHeaderType(SX128X_LORA_HEADER_EXPLICIT)); +} + +int16_t SX128x::setEncoding(uint8_t encoding) { + return(setWhitening(encoding)); +} + +uint8_t SX128x::getStatus() { + uint8_t data = 0; + SPIreadCommand(SX128X_CMD_GET_STATUS, &data, 1); + return(data); +} + +int16_t SX128x::writeRegister(uint16_t addr, uint8_t* data, uint8_t numBytes) { + uint8_t cmd[] = { SX128X_CMD_WRITE_REGISTER, (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF) }; + return(SPIwriteCommand(cmd, 3, data, numBytes)); +} + +int16_t SX128x::readRegister(uint16_t addr, uint8_t* data, uint8_t numBytes) { + uint8_t cmd[] = { SX128X_CMD_READ_REGISTER, (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF) }; + return(SX128x::SPItransfer(cmd, 3, false, NULL, data, numBytes, true)); +} + +int16_t SX128x::writeBuffer(uint8_t* data, uint8_t numBytes, uint8_t offset) { + uint8_t cmd[] = { SX128X_CMD_WRITE_BUFFER, offset }; + return(SPIwriteCommand(cmd, 2, data, numBytes)); +} + +int16_t SX128x::readBuffer(uint8_t* data, uint8_t numBytes) { + uint8_t cmd[] = { SX128X_CMD_READ_BUFFER, SX128X_CMD_NOP }; + return(SPIreadCommand(cmd, 2, data, numBytes)); +} + +int16_t SX128x::setTx(uint16_t periodBaseCount, uint8_t periodBase) { + uint8_t data[] = { periodBase, (uint8_t)((periodBaseCount >> 8) & 0xFF), (uint8_t)(periodBaseCount & 0xFF) }; + return(SPIwriteCommand(SX128X_CMD_SET_TX, data, 3)); +} + +int16_t SX128x::setRx(uint16_t periodBaseCount, uint8_t periodBase) { + uint8_t data[] = { periodBase, (uint8_t)((periodBaseCount >> 8) & 0xFF), (uint8_t)(periodBaseCount & 0xFF) }; + return(SPIwriteCommand(SX128X_CMD_SET_RX, data, 3)); +} + +int16_t SX128x::setCad() { + return(SPIwriteCommand(SX128X_CMD_SET_CAD, NULL, 0)); +} + +uint8_t SX128x::getPacketType() { + uint8_t data = 0xFF; + SPIreadCommand(SX128X_CMD_GET_PACKET_TYPE, &data, 1); + return(data); +} + +int16_t SX128x::setRfFrequency(uint32_t frf) { + uint8_t data[] = { (uint8_t)((frf >> 16) & 0xFF), (uint8_t)((frf >> 8) & 0xFF), (uint8_t)(frf & 0xFF) }; + return(SPIwriteCommand(SX128X_CMD_SET_RF_FREQUENCY, data, 3)); +} + +int16_t SX128x::setTxParams(uint8_t power, uint8_t rampTime) { + uint8_t data[] = { power, rampTime }; + return(SPIwriteCommand(SX128X_CMD_SET_TX_PARAMS, data, 2)); +} + +int16_t SX128x::setBufferBaseAddress(uint8_t txBaseAddress, uint8_t rxBaseAddress) { + uint8_t data[] = { txBaseAddress, rxBaseAddress }; + return(SPIwriteCommand(SX128X_CMD_SET_BUFFER_BASE_ADDRESS, data, 2)); +} + +int16_t SX128x::setModulationParams(uint8_t modParam1, uint8_t modParam2, uint8_t modParam3) { + uint8_t data[] = { modParam1, modParam2, modParam3 }; + return(SPIwriteCommand(SX128X_CMD_SET_MODULATION_PARAMS, data, 3)); +} + +int16_t SX128x::setPacketParamsGFSK(uint8_t preambleLen, uint8_t syncWordLen, uint8_t syncWordMatch, uint8_t crcLen, uint8_t whitening, uint8_t payloadLen, uint8_t headerType) { + uint8_t data[] = { preambleLen, syncWordLen, syncWordMatch, headerType, payloadLen, crcLen, whitening }; + return(SPIwriteCommand(SX128X_CMD_SET_PACKET_PARAMS, data, 7)); +} + +int16_t SX128x::setPacketParamsBLE(uint8_t connState, uint8_t crcLen, uint8_t bleTestPayload, uint8_t whitening) { + uint8_t data[] = { connState, crcLen, bleTestPayload, whitening, 0x00, 0x00, 0x00 }; + return(SPIwriteCommand(SX128X_CMD_SET_PACKET_PARAMS, data, 7)); +} + +int16_t SX128x::setPacketParamsLoRa(uint8_t preambleLen, uint8_t headerType, uint8_t payloadLen, uint8_t crc, uint8_t invertIQ) { + uint8_t data[] = { preambleLen, headerType, payloadLen, crc, invertIQ, 0x00, 0x00 }; + return(SPIwriteCommand(SX128X_CMD_SET_PACKET_PARAMS, data, 7)); +} + +int16_t SX128x::setDioIrqParams(uint16_t irqMask, uint16_t dio1Mask, uint16_t dio2Mask, uint16_t dio3Mask) { + uint8_t data[] = { (uint8_t)((irqMask >> 8) & 0xFF), (uint8_t)(irqMask & 0xFF), + (uint8_t)((dio1Mask >> 8) & 0xFF), (uint8_t)(dio1Mask & 0xFF), + (uint8_t)((dio2Mask >> 8) & 0xFF), (uint8_t)(dio2Mask & 0xFF), + (uint8_t)((dio3Mask >> 8) & 0xFF), (uint8_t)(dio3Mask & 0xFF) }; + return(SPIwriteCommand(SX128X_CMD_SET_DIO_IRQ_PARAMS, data, 8)); +} + +uint16_t SX128x::getIrqStatus() { + uint8_t data[] = { 0x00, 0x00 }; + SPIreadCommand(SX128X_CMD_GET_IRQ_STATUS, data, 2); + return(((uint16_t)(data[0]) << 8) | data[1]); +} + +int16_t SX128x::clearIrqStatus(uint16_t clearIrqParams) { + uint8_t data[] = { (uint8_t)((clearIrqParams >> 8) & 0xFF), (uint8_t)(clearIrqParams & 0xFF) }; + return(SPIwriteCommand(SX128X_CMD_CLEAR_IRQ_STATUS, data, 2)); +} + +int16_t SX128x::setHeaderType(uint8_t headerType, size_t len) { + // check active modem + uint8_t modem = getPacketType(); + if(!((modem == SX128X_PACKET_TYPE_LORA) || (modem == SX128X_PACKET_TYPE_RANGING))) { + return(ERR_WRONG_MODEM); + } + + // update packet parameters + _headerType = headerType; + _payloadLen = len; + return(setPacketParamsLoRa(_preambleLengthLoRa, _headerType, _payloadLen, _crcLoRa)); +} + +int16_t SX128x::config(uint8_t modem) { + // reset buffer base address + int16_t state = setBufferBaseAddress(); + RADIOLIB_ASSERT(state); + + // set modem + uint8_t data[1]; + data[0] = modem; + state = SPIwriteCommand(SX128X_CMD_SET_PACKET_TYPE, data, 1); + RADIOLIB_ASSERT(state); + + // set CAD parameters + data[0] = SX128X_CAD_ON_8_SYMB; + state = SPIwriteCommand(SX128X_CMD_SET_CAD_PARAMS, data, 1); + RADIOLIB_ASSERT(state); + + return(ERR_NONE); +} + +int16_t SX128x::SPIwriteCommand(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, uint8_t numBytes, bool waitForBusy) { + return(SX128x::SPItransfer(cmd, cmdLen, true, data, NULL, numBytes, waitForBusy)); +} + +int16_t SX128x::SPIwriteCommand(uint8_t cmd, uint8_t* data, uint8_t numBytes, bool waitForBusy) { + return(SX128x::SPItransfer(&cmd, 1, true, data, NULL, numBytes, waitForBusy)); +} + +int16_t SX128x::SPIreadCommand(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, uint8_t numBytes, bool waitForBusy) { + return(SX128x::SPItransfer(cmd, cmdLen, false, NULL, data, numBytes, waitForBusy)); +} + +int16_t SX128x::SPIreadCommand(uint8_t cmd, uint8_t* data, uint8_t numBytes, bool waitForBusy) { + return(SX128x::SPItransfer(&cmd, 1, false, NULL, data, numBytes, waitForBusy)); +} + +int16_t SX128x::SPItransfer(uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* dataOut, uint8_t* dataIn, uint8_t numBytes, bool waitForBusy, uint32_t timeout) { + // get pointer to used SPI interface and the settings + SPIClass* spi = _mod->getSpi(); + SPISettings spiSettings = _mod->getSpiSettings(); + + #ifdef RADIOLIB_VERBOSE + uint8_t debugBuff[256]; + #endif + + // ensure BUSY is low (state machine ready) + uint32_t start = millis(); + while(digitalRead(_mod->getGpio())) { + yield(); + if(millis() - start >= timeout) { + digitalWrite(_mod->getCs(), HIGH); + return(ERR_SPI_CMD_TIMEOUT); + } + } + + // pull NSS low + digitalWrite(_mod->getCs(), LOW); + + // start transfer + spi->beginTransaction(spiSettings); + + // send command byte(s) + for(uint8_t n = 0; n < cmdLen; n++) { + spi->transfer(cmd[n]); + } + + // variable to save error during SPI transfer + uint8_t status = 0; + + // send/receive all bytes + if(write) { + for(uint8_t n = 0; n < numBytes; n++) { + // send byte + uint8_t in = spi->transfer(dataOut[n]); + #ifdef RADIOLIB_VERBOSE + debugBuff[n] = in; + #endif + + // check status + if(((in & 0b00011100) == SX128X_STATUS_CMD_TIMEOUT) || + ((in & 0b00011100) == SX128X_STATUS_CMD_ERROR) || + ((in & 0b00011100) == SX128X_STATUS_CMD_FAILED)) { + status = in & 0b00011100; + break; + } else if(in == 0x00 || in == 0xFF) { + status = SX128X_STATUS_SPI_FAILED; + break; + } + } + + } else { + // skip the first byte for read-type commands (status-only) + uint8_t in = spi->transfer(SX128X_CMD_NOP); + #ifdef RADIOLIB_VERBOSE + debugBuff[0] = in; + #endif + + // check status + if(((in & 0b00011100) == SX128X_STATUS_CMD_TIMEOUT) || + ((in & 0b00011100) == SX128X_STATUS_CMD_ERROR) || + ((in & 0b00011100) == SX128X_STATUS_CMD_FAILED)) { + status = in & 0b00011100; + } else if(in == 0x00 || in == 0xFF) { + status = SX128X_STATUS_SPI_FAILED; + } else { + for(uint8_t n = 0; n < numBytes; n++) { + dataIn[n] = spi->transfer(SX128X_CMD_NOP); + } + } + } + + // stop transfer + spi->endTransaction(); + digitalWrite(_mod->getCs(), HIGH); + + // wait for BUSY to go high and then low + if(waitForBusy) { + delayMicroseconds(1); + start = millis(); + while(digitalRead(_mod->getGpio())) { + yield(); + if(millis() - start >= timeout) { + status = SX128X_STATUS_CMD_TIMEOUT; + break; + } + } + } + + // print debug output + #ifdef RADIOLIB_VERBOSE + // print command byte(s) + RADIOLIB_VERBOSE_PRINT("CMD\t"); + for(uint8_t n = 0; n < cmdLen; n++) { + RADIOLIB_VERBOSE_PRINT(cmd[n], HEX); + RADIOLIB_VERBOSE_PRINT('\t'); + } + RADIOLIB_VERBOSE_PRINTLN(); + + // print data bytes + RADIOLIB_VERBOSE_PRINT("DAT"); + if(write) { + RADIOLIB_VERBOSE_PRINT("W\t"); + for(uint8_t n = 0; n < numBytes; n++) { + RADIOLIB_VERBOSE_PRINT(dataOut[n], HEX); + RADIOLIB_VERBOSE_PRINT('\t'); + RADIOLIB_VERBOSE_PRINT(debugBuff[n], HEX); + RADIOLIB_VERBOSE_PRINT('\t'); + } + RADIOLIB_VERBOSE_PRINTLN(); + } else { + RADIOLIB_VERBOSE_PRINT("R\t"); + // skip the first byte for read-type commands (status-only) + RADIOLIB_VERBOSE_PRINT(SX128X_CMD_NOP, HEX); + RADIOLIB_VERBOSE_PRINT('\t'); + RADIOLIB_VERBOSE_PRINT(debugBuff[0], HEX); + RADIOLIB_VERBOSE_PRINT('\t') + + for(uint8_t n = 0; n < numBytes; n++) { + RADIOLIB_VERBOSE_PRINT(SX128X_CMD_NOP, HEX); + RADIOLIB_VERBOSE_PRINT('\t'); + RADIOLIB_VERBOSE_PRINT(dataIn[n], HEX); + RADIOLIB_VERBOSE_PRINT('\t'); + } + RADIOLIB_VERBOSE_PRINTLN(); + } + RADIOLIB_VERBOSE_PRINTLN(); + #else + // some faster platforms require a short delay here + // not sure why, but it seems that long enough SPI transaction + // (e.g. setPacketParams for GFSK) will fail without it + #if defined(ARDUINO_ARCH_STM32) + delay(1); + #endif + #endif + + // parse status + switch(status) { + case SX128X_STATUS_CMD_TIMEOUT: + return(ERR_SPI_CMD_TIMEOUT); + case SX128X_STATUS_CMD_ERROR: + return(ERR_SPI_CMD_INVALID); + case SX128X_STATUS_CMD_FAILED: + return(ERR_SPI_CMD_FAILED); + case SX128X_STATUS_SPI_FAILED: + return(ERR_CHIP_NOT_FOUND); + default: + return(ERR_NONE); + } +} diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h new file mode 100644 index 00000000..2e74f7e0 --- /dev/null +++ b/src/modules/SX128x/SX128x.h @@ -0,0 +1,748 @@ +#ifndef _RADIOLIB_SX128X_H +#define _RADIOLIB_SX128X_H + +#include "../../TypeDef.h" +#include "../../Module.h" + +#include "../../protocols/PhysicalLayer/PhysicalLayer.h" + +// SX128X physical layer properties +#define SX128X_FREQUENCY_STEP_SIZE 198.3642578 +#define SX128X_MAX_PACKET_LENGTH 255 +#define SX128X_CRYSTAL_FREQ 52.0 +#define SX128X_DIV_EXPONENT 18 + +// SX128X SPI commands +#define SX128X_CMD_NOP 0x00 +#define SX128X_CMD_GET_STATUS 0xC0 +#define SX128X_CMD_WRITE_REGISTER 0x18 +#define SX128X_CMD_READ_REGISTER 0x19 +#define SX128X_CMD_WRITE_BUFFER 0x1A +#define SX128X_CMD_READ_BUFFER 0x1B +#define SX128X_CMD_SET_SLEEP 0x84 +#define SX128X_CMD_SET_STANDBY 0x80 +#define SX128X_CMD_SET_FS 0xC1 +#define SX128X_CMD_SET_TX 0x83 +#define SX128X_CMD_SET_RX 0x82 +#define SX128X_CMD_SET_RX_DUTY_CYCLE 0x94 +#define SX128X_CMD_SET_CAD 0xC5 +#define SX128X_CMD_SET_TX_CONTINUOUS_WAVE 0xD1 +#define SX128X_CMD_SET_TX_CONTINUOUS_PREAMBLE 0xD2 +#define SX128X_CMD_SET_PACKET_TYPE 0x8A +#define SX128X_CMD_GET_PACKET_TYPE 0x03 +#define SX128X_CMD_SET_RF_FREQUENCY 0x86 +#define SX128X_CMD_SET_TX_PARAMS 0x8E +#define SX128X_CMD_SET_CAD_PARAMS 0x88 +#define SX128X_CMD_SET_BUFFER_BASE_ADDRESS 0x8F +#define SX128X_CMD_SET_MODULATION_PARAMS 0x8B +#define SX128X_CMD_SET_PACKET_PARAMS 0x8C +#define SX128X_CMD_GET_RX_BUFFER_STATUS 0x17 +#define SX128X_CMD_GET_PACKET_STATUS 0x1D +#define SX128X_CMD_GET_RSSI_INST 0x1F +#define SX128X_CMD_SET_DIO_IRQ_PARAMS 0x8D +#define SX128X_CMD_GET_IRQ_STATUS 0x15 +#define SX128X_CMD_CLEAR_IRQ_STATUS 0x97 +#define SX128X_CMD_SET_REGULATOR_MODE 0x96 +#define SX128X_CMD_SET_SAVE_CONTEXT 0xD5 +#define SX128X_CMD_SET_AUTO_TX 0x98 +#define SX128X_CMD_SET_AUTO_FS 0x9E +#define SX128X_CMD_SET_PERF_COUNTER_MODE 0x9C +#define SX128X_CMD_SET_LONG_PREAMBLE 0x9B +#define SX128X_CMD_SET_UART_SPEED 0x9D +#define SX128X_CMD_SET_RANGING_ROLE 0xA3 +#define SX128X_CMD_SET_ADVANCED_RANGING 0x9A + +// SX128X register map +#define SX128X_REG_SYNC_WORD_1_BYTE_4 0x09CE +#define SX128X_REG_SYNC_WORD_1_BYTE_3 0x09CF +#define SX128X_REG_SYNC_WORD_1_BYTE_2 0x09D0 +#define SX128X_REG_SYNC_WORD_1_BYTE_1 0x09D1 +#define SX128X_REG_SYNC_WORD_1_BYTE_0 0x09D2 +#define SX128X_REG_SYNC_WORD_2_BYTE_4 0x09D3 +#define SX128X_REG_SYNC_WORD_2_BYTE_3 0x09D4 +#define SX128X_REG_SYNC_WORD_2_BYTE_2 0x09D5 +#define SX128X_REG_SYNC_WORD_2_BYTE_1 0x09D6 +#define SX128X_REG_SYNC_WORD_2_BYTE_0 0x09D7 +#define SX128X_REG_SYNC_WORD_3_BYTE_4 0x09D8 +#define SX128X_REG_SYNC_WORD_3_BYTE_3 0x09D9 +#define SX128X_REG_SYNC_WORD_3_BYTE_2 0x09DA +#define SX128X_REG_SYNC_WORD_3_BYTE_1 0x09DB +#define SX128X_REG_SYNC_WORD_3_BYTE_0 0x09DC +#define SX128X_REG_CRC_INITIAL_MSB 0x09C8 +#define SX128X_REG_CRC_INITIAL_LSB 0x09C9 +#define SX128X_REG_CRC_POLYNOMIAL_MSB 0x09C6 +#define SX128X_REG_CRC_POLYNOMIAL_LSB 0x09C7 +#define SX128X_REG_ACCESS_ADDRESS_BYTE_3 (SX128X_REG_SYNC_WORD_1_BYTE_3) +#define SX128X_REG_ACCESS_ADDRESS_BYTE_2 (SX128X_REG_SYNC_WORD_1_BYTE_2) +#define SX128X_REG_ACCESS_ADDRESS_BYTE_1 (SX128X_REG_SYNC_WORD_1_BYTE_1) +#define SX128X_REG_ACCESS_ADDRESS_BYTE_0 (SX128X_REG_SYNC_WORD_1_BYTE_0) +#define SX128X_REG_BLE_CRC_INITIAL_MSB 0x09C7 +#define SX128X_REG_BLE_CRC_INITIAL_MID (SX128X_REG_CRC_INITIAL_MSB) +#define SX128X_REG_BLE_CRC_INITIAL_LSB (SX128X_REG_CRC_INITIAL_LSB) +#define SX128X_REG_SLAVE_RANGING_ADDRESS_BYTE_3 0x0916 +#define SX128X_REG_SLAVE_RANGING_ADDRESS_BYTE_2 0x0917 +#define SX128X_REG_SLAVE_RANGING_ADDRESS_BYTE_1 0x0918 +#define SX128X_REG_SLAVE_RANGING_ADDRESS_BYTE_0 0x0919 +#define SX128X_REG_SLAVE_RANGING_ADDRESS_WIDTH 0x0931 +#define SX128X_REG_MASTER_RANGING_ADDRESS_BYTE_3 0x0912 +#define SX128X_REG_MASTER_RANGING_ADDRESS_BYTE_2 0x0913 +#define SX128X_REG_MASTER_RANGING_ADDRESS_BYTE_1 0x0914 +#define SX128X_REG_MASTER_RANGING_ADDRESS_BYTE_0 0x0915 +#define SX128X_REG_RANGING_CALIBRATION_MSB 0x092C +#define SX128X_REG_RANGING_CALIBRATION_LSB 0x092D +#define SX128X_REG_RANGING_RESULT_MSB 0x0961 +#define SX128X_REG_RANGING_RESULT_MID 0x0962 +#define SX128X_REG_RANGING_RESULT_LSB 0x0963 +#define SX128X_REG_MANUAL_GAIN_CONTROL_ENABLE_1 0x089F +#define SX128X_REG_MANUAL_GAIN_CONTROL_ENABLE_2 0x0895 +#define SX128X_REG_MANUAL_GAIN_SETTING 0x089E +#define SX128X_REG_GAIN_MODE 0x0891 +#define SX128X_REG_LORA_FIXED_PAYLOAD_LENGTH 0x0901 +#define SX128X_REG_LORA_SF_CONFIG 0x0925 +#define SX128X_REG_FEI_MSB 0x0954 +#define SX128X_REG_FEI_MID 0x0955 +#define SX128X_REG_FEI_LSB 0x0956 +#define SX128X_REG_RANGING_FILTER_WINDOW_SIZE 0x091E +#define SX128X_REG_RANGING_FILTER_RSSI_OFFSET 0x0953 +#define SX128X_REG_RANGING_FILTER_RESET 0x0923 +#define SX128X_REG_RANGING_LORA_CLOCK_ENABLE 0x097F +#define SX128X_REG_RANGING_TYPE 0x0924 +#define SX128X_REG_RANGING_ADDRESS_SWITCH 0x0927 +#define SX128X_REG_RANGING_ADDRESS_MSB 0x095F +#define SX128X_REG_RANGING_ADDRESS_LSB 0x0960 + + +// SX128X SPI command variables +//SX128X_CMD_GET_STATUS MSB LSB DESCRIPTION +#define SX128X_STATUS_MODE_STDBY_RC 0b01000000 // 7 5 current chip mode: STDBY_RC +#define SX128X_STATUS_MODE_STDBY_XOSC 0b01100000 // 7 5 STDBY_XOSC +#define SX128X_STATUS_MODE_FS 0b10000000 // 7 5 FS +#define SX128X_STATUS_MODE_RX 0b10100000 // 7 5 Rx +#define SX128X_STATUS_MODE_TX 0b11000000 // 7 5 Tx +#define SX128X_STATUS_CMD_PROCESSED 0b00000100 // 4 2 command status: processing OK +#define SX128X_STATUS_DATA_AVAILABLE 0b00001000 // 4 2 data available +#define SX128X_STATUS_CMD_TIMEOUT 0b00001100 // 4 2 timeout +#define SX128X_STATUS_CMD_ERROR 0b00010000 // 4 2 processing error +#define SX128X_STATUS_CMD_FAILED 0b00010100 // 4 2 failed to execute +#define SX128X_STATUS_TX_DONE 0b00011000 // 4 2 transmission finished +#define SX128X_STATUS_BUSY 0b00000001 // 0 0 chip busy +#define SX128X_STATUS_SPI_FAILED 0b11111111 // 7 0 SPI transaction failed + +//SX128X_CMD_SET_SLEEP +#define SX128X_SLEEP_DATA_BUFFER_FLUSH 0b00000000 // 1 1 data buffer behavior in sleep mode: flush +#define SX128X_SLEEP_DATA_BUFFER_RETAIN 0b00000010 // 1 1 retain +#define SX128X_SLEEP_DATA_RAM_FLUSH 0b00000000 // 0 0 data RAM (configuration) behavior in sleep mode: flush +#define SX128X_SLEEP_DATA_RAM_RETAIN 0b00000001 // 0 0 retain + +//SX128X_CMD_SET_STANDBY +#define SX128X_STANDBY_RC 0x00 // 7 0 standby mode: 13 MHz RC oscillator +#define SX128X_STANDBY_XOSC 0x01 // 7 0 52 MHz crystal oscillator + +//SX128X_CMD_SET_TX + SX128X_CMD_SET_RX + SX128X_CMD_SET_RX_DUTY_CYCLE +#define SX128X_PERIOD_BASE_15_625_US 0x00 // 7 0 time period step: 15.625 us +#define SX128X_PERIOD_BASE_62_5_US 0x01 // 7 0 62.5 us +#define SX128X_PERIOD_BASE_1_MS 0x02 // 7 0 1 ms +#define SX128X_PERIOD_BASE_4_MS 0x03 // 7 0 4 ms + +//SX128X_CMD_SET_TX +#define SX128X_TX_TIMEOUT_NONE 0x0000 // 15 0 Tx timeout duration: no timeout (Tx single mode) + +//SX128X_CMD_SET_RX +#define SX128X_RX_TIMEOUT_NONE 0x0000 // 15 0 Rx timeout duration: no timeout (Rx single mode) +#define SX128X_RX_TIMEOUT_INF 0xFFFF // 15 0 infinite (Rx continuous mode) + +//SX128X_CMD_SET_PACKET_TYPE +#define SX128X_PACKET_TYPE_GFSK 0x00 // 7 0 packet type: (G)FSK +#define SX128X_PACKET_TYPE_LORA 0x01 // 7 0 LoRa +#define SX128X_PACKET_TYPE_RANGING 0x02 // 7 0 ranging engine +#define SX128X_PACKET_TYPE_FLRC 0x03 // 7 0 FLRC +#define SX128X_PACKET_TYPE_BLE 0x04 // 7 0 BLE + +//SX128X_CMD_SET_TX_PARAMS +#define SX128X_PA_RAMP_02_US 0x00 // 7 0 PA ramp time: 2 us +#define SX128X_PA_RAMP_04_US 0x20 // 7 0 4 us +#define SX128X_PA_RAMP_06_US 0x40 // 7 0 6 us +#define SX128X_PA_RAMP_08_US 0x60 // 7 0 8 us +#define SX128X_PA_RAMP_10_US 0x80 // 7 0 10 us +#define SX128X_PA_RAMP_12_US 0xA0 // 7 0 12 us +#define SX128X_PA_RAMP_16_US 0xC0 // 7 0 16 us +#define SX128X_PA_RAMP_20_US 0xE0 // 7 0 20 us + +//SX128X_CMD_SET_CAD_PARAMS +#define SX128X_CAD_ON_1_SYMB 0x00 // 7 0 number of symbols used for CAD: 1 +#define SX128X_CAD_ON_2_SYMB 0x20 // 7 0 2 +#define SX128X_CAD_ON_4_SYMB 0x40 // 7 0 4 +#define SX128X_CAD_ON_8_SYMB 0x60 // 7 0 8 +#define SX128X_CAD_ON_16_SYMB 0x80 // 7 0 16 + +//SX128X_CMD_SET_MODULATION_PARAMS +#define SX128X_BLE_GFSK_BR_2_000_BW_2_4 0x04 // 7 0 GFSK/BLE bit rate and bandwidth setting: 2.0 Mbps 2.4 MHz +#define SX128X_BLE_GFSK_BR_1_600_BW_2_4 0x28 // 7 0 1.6 Mbps 2.4 MHz +#define SX128X_BLE_GFSK_BR_1_000_BW_2_4 0x4C // 7 0 1.0 Mbps 2.4 MHz +#define SX128X_BLE_GFSK_BR_1_000_BW_1_2 0x45 // 7 0 1.0 Mbps 1.2 MHz +#define SX128X_BLE_GFSK_BR_0_800_BW_2_4 0x70 // 7 0 0.8 Mbps 2.4 MHz +#define SX128X_BLE_GFSK_BR_0_800_BW_1_2 0x69 // 7 0 0.8 Mbps 1.2 MHz +#define SX128X_BLE_GFSK_BR_0_500_BW_1_2 0x8D // 7 0 0.5 Mbps 1.2 MHz +#define SX128X_BLE_GFSK_BR_0_500_BW_0_6 0x86 // 7 0 0.5 Mbps 0.6 MHz +#define SX128X_BLE_GFSK_BR_0_400_BW_1_2 0xB1 // 7 0 0.4 Mbps 1.2 MHz +#define SX128X_BLE_GFSK_BR_0_400_BW_0_6 0xAA // 7 0 0.4 Mbps 0.6 MHz +#define SX128X_BLE_GFSK_BR_0_250_BW_0_6 0xCE // 7 0 0.25 Mbps 0.6 MHz +#define SX128X_BLE_GFSK_BR_0_250_BW_0_3 0xC7 // 7 0 0.25 Mbps 0.3 MHz +#define SX128X_BLE_GFSK_BR_0_125_BW_0_3 0xEF // 7 0 0.125 Mbps 0.3 MHz +#define SX128X_BLE_GFSK_MOD_IND_0_35 0x00 // 7 0 GFSK/BLE modulation index: 0.35 +#define SX128X_BLE_GFSK_MOD_IND_0_50 0x01 // 7 0 0.50 +#define SX128X_BLE_GFSK_MOD_IND_0_75 0x02 // 7 0 0.75 +#define SX128X_BLE_GFSK_MOD_IND_1_00 0x03 // 7 0 1.00 +#define SX128X_BLE_GFSK_MOD_IND_1_25 0x04 // 7 0 1.25 +#define SX128X_BLE_GFSK_MOD_IND_1_50 0x05 // 7 0 1.50 +#define SX128X_BLE_GFSK_MOD_IND_1_75 0x06 // 7 0 1.75 +#define SX128X_BLE_GFSK_MOD_IND_2_00 0x07 // 7 0 2.00 +#define SX128X_BLE_GFSK_MOD_IND_2_25 0x08 // 7 0 2.25 +#define SX128X_BLE_GFSK_MOD_IND_2_50 0x09 // 7 0 2.50 +#define SX128X_BLE_GFSK_MOD_IND_2_75 0x0A // 7 0 2.75 +#define SX128X_BLE_GFSK_MOD_IND_3_00 0x0B // 7 0 3.00 +#define SX128X_BLE_GFSK_MOD_IND_3_25 0x0C // 7 0 3.25 +#define SX128X_BLE_GFSK_MOD_IND_3_50 0x0D // 7 0 3.50 +#define SX128X_BLE_GFSK_MOD_IND_3_75 0x0E // 7 0 3.75 +#define SX128X_BLE_GFSK_MOD_IND_4_00 0x0F // 7 0 4.00 +#define SX128X_BLE_GFSK_BT_OFF 0x00 // 7 0 GFSK Gaussian filter BT product: filter disabled +#define SX128X_BLE_GFSK_BT_1_0 0x10 // 7 0 1.0 +#define SX128X_BLE_GFSK_BT_0_5 0x20 // 7 0 0.5 +#define SX128X_FLRC_BR_1_300_BW_1_2 0x45 // 7 0 FLRC bit rate and bandwidth setting: 1.3 Mbps 1.2 MHz +#define SX128X_FLRC_BR_1_000_BW_1_2 0x69 // 7 0 1.04 Mbps 1.2 MHz +#define SX128X_FLRC_BR_0_650_BW_0_6 0x86 // 7 0 0.65 Mbps 0.6 MHz +#define SX128X_FLRC_BR_0_520_BW_0_6 0xAA // 7 0 0.52 Mbps 0.6 MHz +#define SX128X_FLRC_BR_0_325_BW_0_3 0xC7 // 7 0 0.325 Mbps 0.3 MHz +#define SX128X_FLRC_BR_0_260_BW_0_3 0xEB // 7 0 0.260 Mbps 0.3 MHz +#define SX128X_FLRC_CR_1_2 0x00 // 7 0 FLRC coding rate: 1/2 +#define SX128X_FLRC_CR_3_4 0x02 // 7 0 3/4 +#define SX128X_FLRC_CR_1_0 0x04 // 7 0 1/1 +#define SX128X_FLRC_BT_OFF 0x00 // 7 0 FLRC Gaussian filter BT product: filter disabled +#define SX128X_FLRC_BT_1_0 0x10 // 7 0 1.0 +#define SX128X_FLRC_BT_0_5 0x20 // 7 0 0.5 +#define SX128X_LORA_SF_5 0x50 // 7 0 LoRa spreading factor: 5 +#define SX128X_LORA_SF_6 0x60 // 7 0 6 +#define SX128X_LORA_SF_7 0x70 // 7 0 7 +#define SX128X_LORA_SF_8 0x80 // 7 0 8 +#define SX128X_LORA_SF_9 0x90 // 7 0 9 +#define SX128X_LORA_SF_10 0xA0 // 7 0 10 +#define SX128X_LORA_SF_11 0xB0 // 7 0 11 +#define SX128X_LORA_SF_12 0xC0 // 7 0 12 +#define SX128X_LORA_BW_1625_00 0x0A // 7 0 LoRa bandwidth: 1625.0 kHz +#define SX128X_LORA_BW_812_50 0x18 // 7 0 812.5 kHz +#define SX128X_LORA_BW_406_25 0x26 // 7 0 406.25 kHz +#define SX128X_LORA_BW_203_125 0x34 // 7 0 203.125 kHz +#define SX128X_LORA_CR_4_5 0x01 // 7 0 LoRa coding rate: 4/5 +#define SX128X_LORA_CR_4_6 0x02 // 7 0 4/6 +#define SX128X_LORA_CR_4_7 0x03 // 7 0 4/7 +#define SX128X_LORA_CR_4_8 0x04 // 7 0 4/8 +#define SX128X_LORA_CR_4_5_LI 0x05 // 7 0 4/5, long interleaving +#define SX128X_LORA_CR_4_6_LI 0x06 // 7 0 4/6, long interleaving +#define SX128X_LORA_CR_4_7_LI 0x07 // 7 0 4/7, long interleaving + +//SX128X_CMD_SET_PACKET_PARAMS +#define SX128X_GFSK_FLRC_SYNC_WORD_OFF 0x00 // 7 0 GFSK/FLRC sync word used: none +#define SX128X_GFSK_FLRC_SYNC_WORD_1 0x10 // 7 0 sync word 1 +#define SX128X_GFSK_FLRC_SYNC_WORD_2 0x20 // 7 0 sync word 2 +#define SX128X_GFSK_FLRC_SYNC_WORD_1_2 0x30 // 7 0 sync words 1 and 2 +#define SX128X_GFSK_FLRC_SYNC_WORD_3 0x40 // 7 0 sync word 3 +#define SX128X_GFSK_FLRC_SYNC_WORD_1_3 0x50 // 7 0 sync words 1 and 3 +#define SX128X_GFSK_FLRC_SYNC_WORD_2_3 0x60 // 7 0 sync words 2 and 3 +#define SX128X_GFSK_FLRC_SYNC_WORD_1_2_3 0x70 // 7 0 sync words 1, 2 and 3 +#define SX128X_GFSK_FLRC_PACKET_FIXED 0x00 // 7 0 GFSK/FLRC packet length mode: fixed +#define SX128X_GFSK_FLRC_PACKET_VARIABLE 0x20 // 7 0 variable +#define SX128X_GFSK_FLRC_CRC_OFF 0x00 // 7 0 GFSK/FLRC packet CRC: none +#define SX128X_GFSK_FLRC_CRC_1_BYTE 0x10 // 7 0 1 byte +#define SX128X_GFSK_FLRC_CRC_2_BYTE 0x20 // 7 0 2 bytes +#define SX128X_GFSK_FLRC_CRC_3_BYTE 0x30 // 7 0 3 bytes (FLRC only) +#define SX128X_GFSK_BLE_WHITENING_ON 0x00 // 7 0 GFSK/BLE whitening: enabled +#define SX128X_GFSK_BLE_WHITENING_OFF 0x08 // 7 0 disabled +#define SX128X_BLE_PAYLOAD_LENGTH_MAX_31 0x00 // 7 0 BLE maximum payload length: 31 bytes +#define SX128X_BLE_PAYLOAD_LENGTH_MAX_37 0x20 // 7 0 37 bytes +#define SX128X_BLE_PAYLOAD_LENGTH_TEST 0x40 // 7 0 63 bytes (test mode) +#define SX128X_BLE_PAYLOAD_LENGTH_MAX_255 0x80 // 7 0 255 bytes (Bluetooth 4.2 and above) +#define SX128X_BLE_CRC_OFF 0x00 // 7 0 BLE packet CRC: none +#define SX128X_BLE_CRC_3_BYTE 0x10 // 7 0 3 byte +#define SX128X_BLE_PRBS_9 0x00 // 7 0 BLE test payload contents: PRNG sequence using x^9 + x^5 + x +#define SX128X_BLE_EYELONG 0x04 // 7 0 repeated 0xF0 +#define SX128X_BLE_EYESHORT 0x08 // 7 0 repeated 0xAA +#define SX128X_BLE_PRBS_15 0x0C // 7 0 PRNG sequence using x^15 + x^14 + x^13 + x^12 + x^2 + x + 1 +#define SX128X_BLE_ALL_1 0x10 // 7 0 repeated 0xFF +#define SX128X_BLE_ALL_0 0x14 // 7 0 repeated 0x00 +#define SX128X_BLE_EYELONG_INV 0x18 // 7 0 repeated 0x0F +#define SX128X_BLE_EYESHORT_INV 0x1C // 7 0 repeated 0x55 +#define SX128X_FLRC_SYNC_WORD_OFF 0x00 // 7 0 FLRC sync word: disabled +#define SX128X_FLRC_SYNC_WORD_ON 0x04 // 7 0 enabled +#define SX128X_LORA_HEADER_EXPLICIT 0x00 // 7 0 LoRa header mode: explicit +#define SX128X_LORA_HEADER_IMPLICIT 0x80 // 7 0 implicit +#define SX128X_LORA_CRC_OFF 0x00 // 7 0 LoRa packet CRC: disabled +#define SX128X_LORA_CRC_ON 0x20 // 7 0 enabled +#define SX128X_LORA_IQ_STANDARD 0x40 // 7 0 LoRa IQ: standard +#define SX128X_LORA_IQ_INVERTED 0x00 // 7 0 inverted + +//SX128X_CMD_GET_PACKET_STATUS +#define SX128X_PACKET_STATUS_SYNC_ERROR 0b01000000 // 6 6 packet status errors byte: sync word error +#define SX128X_PACKET_STATUS_LENGTH_ERROR 0b00100000 // 5 5 packet length error +#define SX128X_PACKET_STATUS_CRC_ERROR 0b00010000 // 4 4 CRC error +#define SX128X_PACKET_STATUS_ABORT_ERROR 0b00001000 // 3 3 packet reception aborted +#define SX128X_PACKET_STATUS_HEADER_RECEIVED 0b00000100 // 2 2 header received +#define SX128X_PACKET_STATUS_PACKET_RECEIVED 0b00000010 // 1 1 packet received +#define SX128X_PACKET_STATUS_PACKET_CTRL_BUSY 0b00000001 // 0 0 packet controller is busy +#define SX128X_PACKET_STATUS_RX_PID 0b11000000 // 7 6 packet status status byte: PID field of the received packet +#define SX128X_PACKET_STATUS_NO_ACK 0b00100000 // 5 5 NO_ACK field of the received packet +#define SX128X_PACKET_STATUS_RX_PID_ERROR 0b00010000 // 4 4 PID field error +#define SX128X_PACKET_STATUS_PACKET_SENT 0b00000001 // 0 0 packet sent +#define SX128X_PACKET_STATUS_SYNC_DET_ERROR 0b00000000 // 2 0 packet status sync byte: sync word detection error +#define SX128X_PACKET_STATUS_SYNC_DET_1 0b00000001 // 2 0 detected sync word 1 +#define SX128X_PACKET_STATUS_SYNC_DET_2 0b00000010 // 2 0 detected sync word 2 +#define SX128X_PACKET_STATUS_SYNC_DET_3 0b00000100 // 2 0 detected sync word 3 + +//SX128X_CMD_SET_DIO_IRQ_PARAMS +#define SX128X_IRQ_PREAMBLE_DETECTED 0x8000 // 15 15 interrupt source: preamble detected +#define SX128X_IRQ_ADVANCED_RANGING_DONE 0x8000 // 15 15 advanced ranging done +#define SX128X_IRQ_RX_TX_TIMEOUT 0x4000 // 14 14 Rx or Tx timeout +#define SX128X_IRQ_CAD_DETECTED 0x2000 // 13 13 channel activity detected +#define SX128X_IRQ_CAD_DONE 0x1000 // 12 12 CAD finished +#define SX128X_IRQ_RANGING_SLAVE_REQ_VALID 0x0800 // 11 11 ranging request valid (slave) +#define SX128X_IRQ_RANGING_MASTER_TIMEOUT 0x0400 // 10 10 ranging timeout (master) +#define SX128X_IRQ_RANGING_MASTER_RES_VALID 0x0200 // 9 9 ranging result valid (master) +#define SX128X_IRQ_RANGING_SLAVE_REQ_DISCARD 0x0100 // 8 8 ranging result valid (master) +#define SX128X_IRQ_RANGING_SLAVE_RESP_DONE 0x0080 // 7 7 ranging response complete (slave) +#define SX128X_IRQ_CRC_ERROR 0x0040 // 6 6 CRC error +#define SX128X_IRQ_HEADER_ERROR 0x0020 // 5 5 header error +#define SX128X_IRQ_HEADER_VALID 0x0010 // 4 4 header valid +#define SX128X_IRQ_SYNC_WORD_ERROR 0x0008 // 3 3 sync word error +#define SX128X_IRQ_SYNC_WORD_VALID 0x0004 // 2 2 sync word valid +#define SX128X_IRQ_RX_DONE 0x0002 // 1 1 Rx done +#define SX128X_IRQ_TX_DONE 0x0001 // 0 0 Tx done +#define SX128X_IRQ_NONE 0x0000 // 15 0 none +#define SX128X_IRQ_ALL 0xFFFF // 15 0 all + +/*! + \class SX128x + + \brief Base class for %SX128x series. All derived classes for %SX128x (e.g. SX1280 or SX1281) inherit from this base class. + This class should not be instantiated directly from Arduino sketch, only from its derived classes. +*/ +class SX128x: public PhysicalLayer { + public: + // introduce PhysicalLayer overloads + using PhysicalLayer::transmit; + using PhysicalLayer::receive; + using PhysicalLayer::startTransmit; + using PhysicalLayer::readData; + + /*! + \brief Default constructor. + + \param mod Instance of Module that will be used to communicate with the radio. + */ + SX128x(Module* mod); + + // basic methods + + /*! + \brief Initialization method for LoRa modem. + + \param freq Carrier frequency in MHz. Defaults to 2400.0 MHz. + + \param bw LoRa bandwidth in kHz. Defaults to 812.5 kHz. + + \param sf LoRa spreading factor. Defaults to 9. + + \param cr LoRa coding rate denominator. Defaults to 7 (coding rate 4/7). + + \param power Output power in dBm. Defaults to 10 dBm. + + \param preambleLength LoRa preamble length in symbols. Defaults to 12 symbols. + + \returns \ref status_codes + */ + int16_t begin(float freq = 2400.0, float bw = 812.5, uint8_t sf = 9, uint8_t cr = 7, int8_t power = 10, uint16_t preambleLength = 12); + + /*! + \brief Initialization method for GFSK modem. + + \param freq Carrier frequency in MHz. Defaults to 2400.0 MHz. + + \param br FSK bit rate in kbps. Defaults to 800 kbps. + + \param freqDev Frequency deviation from carrier frequency in kHz. Defaults to 400.0 kHz. + + \param power Output power in dBm. Defaults to 10 dBm. + + \parma preambleLength FSK preamble length in bits. Defaults to 16 bits. + + \param dataShaping Time-bandwidth product of the Gaussian filter to be used for shaping. Defaults to 0.5. + + \returns \ref status_codes + */ + int16_t beginGFSK(float freq = 2400.0, uint16_t br = 800, float freqDev = 400.0, int8_t power = 10, uint16_t preambleLength = 16, float dataShaping = 0.5); + + /*! + \brief Reset method. Will reset the chip to the default state using RST pin. + + \param verify Whether correct module startup should be verified. When set to true, RadioLib will attempt to verify the module has started correctly + by repeatedly issuing setStandby command. Enabled by default. + + \returns \ref status_codes + */ + int16_t reset(bool verify = true); + + /*! + \brief Blocking binary transmit method. + Overloads for string-based transmissions are implemented in PhysicalLayer. + + \param data Binary data to be sent. + + \param len Number of bytes to send. + + \param addr Address to send the data to. Will only be added if address filtering was enabled. + + \returns \ref status_codes + */ + int16_t transmit(uint8_t* data, size_t len, uint8_t addr = 0); + + /*! + \brief Blocking binary receive method. + Overloads for string-based transmissions are implemented in PhysicalLayer. + + \param data Binary data to be sent. + + \param len Number of bytes to send. + + \returns \ref status_codes + */ + int16_t receive(uint8_t* data, size_t len); + + /*! + \brief Starts direct mode transmission. + + \param frf Raw RF frequency value. Defaults to 0, required for quick frequency shifts in RTTY. + + \returns \ref status_codes + */ + int16_t transmitDirect(uint32_t frf = 0); + + /*! + \brief Starts direct mode reception. Only implemented for PhysicalLayer compatibility, as %SX128x series does not support direct mode reception. + Will always return ERR_UNKNOWN. + + \returns \ref status_codes + */ + int16_t receiveDirect(); + + /*! + \brief Performs scan for LoRa transmission in the current channel. Detects both preamble and payload. + + \returns \ref status_codes + */ + int16_t scanChannel(); + + /*! + \brief Sets the module to sleep mode. + + \param retainConfig Set to true to retain configuration and data buffer or to false to discard current configuration and data buffer. Defaults to true. + + \returns \ref status_codes + */ + int16_t sleep(bool retainConfig = true); + + /*! + \brief Sets the module to standby mode (overload for PhysicalLayer compatibility, uses 13 MHz RC oscillator). + + \returns \ref status_codes + */ + int16_t standby(); + + /*! + \brief Sets the module to standby mode. + + \param mode Oscillator to be used in standby mode. Can be set to SX128X_STANDBY_RC (13 MHz RC oscillator) or SX128X_STANDBY_XOSC (52 MHz external crystal oscillator). + + \returns \ref status_codes + */ + int16_t standby(uint8_t mode); + + // interrupt methods + + /*! + \brief Sets interrupt service routine to call when DIO1 activates. + + \param func ISR to call. + */ + void setDio1Action(void (*func)(void)); + + /*! + \brief Clears interrupt service routine to call when DIO1 activates. + */ + void clearDio1Action(); + + /*! + \brief Interrupt-driven binary transmit method. + Overloads for string-based transmissions are implemented in PhysicalLayer. + + \param data Binary data to be sent. + + \param len Number of bytes to send. + + \param addr Address to send the data to. Will only be added if address filtering was enabled. + + \returns \ref status_codes + */ + int16_t startTransmit(uint8_t* data, size_t len, uint8_t addr = 0); + + /*! + \brief Interrupt-driven receive method. DIO1 will be activated when full packet is received. + + \param timeout Raw timeout value, expressed as multiples of 15.625 us. Defaults to SX128X_RX_TIMEOUT_INF for infinite timeout (Rx continuous mode), set to SX128X_RX_TIMEOUT_NONE for no timeout (Rx single mode). + + \returns \ref status_codes + */ + int16_t startReceive(uint16_t timeout = SX128X_RX_TIMEOUT_INF); + + /*! + \brief Reads data received after calling startReceive method. + + \param data Pointer to array to save the received binary data. + + \param len Number of bytes that will be received. Must be known in advance for binary transmissions. + + \returns \ref status_codes + */ + int16_t readData(uint8_t* data, size_t len); + + // configuration methods + + /*! + \brief Sets carrier frequency. Allowed values are in range from 2400.0 to 2500.0 MHz. + + \param freq Carrier frequency to be set in MHz. + + \returns \ref status_codes + */ + int16_t setFrequency(float freq); + + /*! + \brief Sets LoRa bandwidth. Allowed values are 203.125, 406.25, 812.5 and 1625.0 kHz. + + \param bw LoRa bandwidth to be set in kHz. + + \returns \ref status_codes + */ + int16_t setBandwidth(float bw); + + /*! + \brief Sets LoRa spreading factor. Allowed values range from 5 to 12. + + \param sf LoRa spreading factor to be set. + + \returns \ref status_codes + */ + int16_t setSpreadingFactor(uint8_t sf); + + /*! + \brief Sets LoRa coding rate denominator. Allowed values range from 5 to 8. + + \param cr LoRa coding rate denominator to be set. + + \param longInterleaving Whether to enable long interleaving mode. Not available for coding rate 4/7, defaults to false. + + \returns \ref status_codes + */ + int16_t setCodingRate(uint8_t cr, bool longInterleaving = false); + + /*! + \brief Sets output power. Allowed values are in range from -18 to 13 dBm. + + \param power Output power to be set in dBm. + + \returns \ref status_codes + */ + int16_t setOutputPower(int8_t power); + + /*! + \brief Sets preamble length for currently active modem. Allowed values range from 1 to 65535. + + \param preambleLength Preamble length to be set in symbols (LoRa) or bits (FSK/BLE/FLRC). + + \returns \ref status_codes + */ + int16_t setPreambleLength(uint32_t preambleLength); + + /*! + \brief Sets FSK bit rate. Allowed values are 125, 250, 400, 500, 800, 1000, 1600 and 2000 kbps. + + \param br FSK bit rate to be set in kbps. + + \returns \ref status_codes + */ + int16_t setBitRate(uint16_t br); + + /*! + \brief Sets FSK frequency deviation. Allowed values range from 0.0 to 3200.0 kHz. + + \param freqDev FSK frequency deviation to be set in kHz. + + \returns \ref status_codes + */ + int16_t setFrequencyDeviation(float freqDev); + + /*! + \brief Sets time-bandwidth product of Gaussian filter applied for shaping. Allowed values are 0.5 and 1.0. Set to 0 to disable shaping. + + \param sh Time-bandwidth product of Gaussian filter to be set. + + \returns \ref status_codes + */ + int16_t setDataShaping(float dataShaping); + + /*! + \brief Sets sync word in the form of array of up to 8 bytes. + + \param syncWord Sync word to be set. + + \param len Sync word length in bytes. + + \returns \ref status_codes + */ + int16_t setSyncWord(uint8_t* syncWord, uint8_t len); + + /*! + \brief Sets CRC configuration. + + \param len CRC length in bytes, Allowed values are 1, 2 or 3, set to 0 to disable CRC. + + \param initial Initial CRC value. Defaults to 0x1D0F (CCIT CRC), not available for LoRa modem. + + \param polynomial Polynomial for CRC calculation. Defaults to 0x1021 (CCIT CRC), not available for LoRa or BLE modem. + + \returns \ref status_codes + */ + int16_t setCRC(uint8_t len, uint32_t initial = 0x1D0F, uint16_t polynomial = 0x1021); + + /*! + \brief Sets whitening parameters, not available for LoRa or FLRC modem. + + \param enabled Set to true to enable whitening. + + \returns \ref status_codes + */ + int16_t setWhitening(bool enabled); + + /*! + \brief Gets RSSI (Recorded Signal Strength Indicator) of the last received packet. + + \returns RSSI of the last received packet in dBm. + */ + float getRSSI(); + + /*! + \brief Gets SNR (Signal to Noise Ratio) of the last received packet. Only available for LoRa or ranging modem. + + \returns SNR of the last received packet in dB. + */ + float getSNR(); + + /*! + \brief Query modem for the packet length of received payload. + + \param update Update received packet length. Will return cached value when set to false. + + \returns Length of last received packet in bytes. + */ + size_t getPacketLength(bool update = true); + + /*! + \brief Get expected time-on-air for a given size of payload. + + \param len Payload length in bytes. + + \returns Expected time-on-air in microseconds. + */ + uint32_t getTimeOnAir(size_t len); + + /*! + \brief Set implicit header mode for future reception/transmission. + + \returns \ref status_codes + */ + int16_t implicitHeader(size_t len); + + /*! + \brief Set explicit header mode for future reception/transmission. + + \param len Payload length in bytes. + + \returns \ref status_codes + */ + int16_t explicitHeader(); + + /*! + \brief Sets transmission encoding. Serves only as alias for PhysicalLayer compatibility. + + \param encoding Encoding to be used. Set to 0 for NRZ, and 2 for whitening. + + \returns \ref status_codes + */ + int16_t setEncoding(uint8_t encoding); + +#ifndef RADIOLIB_GODMODE + protected: +#endif + // SX128x SPI command implementations + uint8_t getStatus(); + int16_t writeRegister(uint16_t addr, uint8_t* data, uint8_t numBytes); + int16_t readRegister(uint16_t addr, uint8_t* data, uint8_t numBytes); + int16_t writeBuffer(uint8_t* data, uint8_t numBytes, uint8_t offset = 0x00); + int16_t readBuffer(uint8_t* data, uint8_t numBytes); + int16_t setTx(uint16_t periodBaseCount = SX128X_TX_TIMEOUT_NONE, uint8_t periodBase = SX128X_PERIOD_BASE_15_625_US); + int16_t setRx(uint16_t periodBaseCount, uint8_t periodBase = SX128X_PERIOD_BASE_15_625_US); + int16_t setCad(); + uint8_t getPacketType(); + int16_t setRfFrequency(uint32_t frf); + int16_t setTxParams(uint8_t power, uint8_t rampTime = SX128X_PA_RAMP_10_US); + int16_t setBufferBaseAddress(uint8_t txBaseAddress = 0x00, uint8_t rxBaseAddress = 0x00); + int16_t setModulationParams(uint8_t modParam1, uint8_t modParam2, uint8_t modParam3); + int16_t setPacketParamsGFSK(uint8_t preambleLen, uint8_t syncWordLen, uint8_t syncWordMatch, uint8_t crcLen, uint8_t whitening, uint8_t payloadLen = 0xFF, uint8_t headerType = SX128X_GFSK_FLRC_PACKET_VARIABLE); + int16_t setPacketParamsBLE(uint8_t connState, uint8_t crcLen, uint8_t bleTestPayload, uint8_t whitening); + int16_t setPacketParamsLoRa(uint8_t preambleLen, uint8_t headerType, uint8_t payloadLen, uint8_t crc, uint8_t invertIQ = SX128X_LORA_IQ_STANDARD); + int16_t setDioIrqParams(uint16_t irqMask, uint16_t dio1Mask, uint16_t dio2Mask = SX128X_IRQ_NONE, uint16_t dio3Mask = SX128X_IRQ_NONE); + uint16_t getIrqStatus(); + int16_t clearIrqStatus(uint16_t clearIrqParams = SX128X_IRQ_ALL); + + int16_t setHeaderType(uint8_t headerType, size_t len = 0xFF); + +#ifndef RADIOLIB_GODMODE + private: +#endif + Module* _mod; + + // common parameters + uint8_t _pwr; + + // cached LoRa parameters + float _bwKhz; + uint8_t _bw, _sf, _cr; + uint8_t _preambleLengthLoRa, _headerType, _payloadLen, _crcLoRa; + + // cached GFSK parameters + float _modIndexReal; + uint16_t _brKbps; + uint8_t _br, _modIndex, _shaping; + uint8_t _preambleLengthGFSK, _syncWordLen, _syncWordMatch, _crcGFSK, _whitening; + + // cached BLE parameters + uint8_t _connectionState, _crcBLE, _bleTestPayload; + + int16_t config(uint8_t modem); + + // common low-level SPI interface + int16_t SPIwriteCommand(uint8_t cmd, uint8_t* data, uint8_t numBytes, bool waitForBusy = true); + int16_t SPIwriteCommand(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, uint8_t numBytes, bool waitForBusy = true); + int16_t SPIreadCommand(uint8_t cmd, uint8_t* data, uint8_t numBytes, bool waitForBusy = true); + int16_t SPIreadCommand(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, uint8_t numBytes, bool waitForBusy = true); + int16_t SPItransfer(uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* dataOut, uint8_t* dataIn, uint8_t numBytes, bool waitForBusy, uint32_t timeout = 5000); +}; + +#endif From acc2fd36f69607eb9895f2f17de7b1981217d0f2 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 7 Apr 2020 13:30:20 +0200 Subject: [PATCH 46/57] [Morse] Added note about SX128x usage --- examples/Morse/Morse_Transmit/Morse_Transmit.ino | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/Morse/Morse_Transmit/Morse_Transmit.ino b/examples/Morse/Morse_Transmit/Morse_Transmit.ino index 0cf02e6e..e0d6d1fe 100644 --- a/examples/Morse/Morse_Transmit/Morse_Transmit.ino +++ b/examples/Morse/Morse_Transmit/Morse_Transmit.ino @@ -12,6 +12,7 @@ - SX126x - nRF24 - Si443x/RFM2x + - SX128x */ // include the library @@ -44,7 +45,7 @@ void setup() { // current limit: 100 mA // sync word: 0x2D 0x01 int state = fsk.beginFSK(); - + // when using one of the non-LoRa modules for Morse code // (RF69, CC1101, Si4432 etc.), use the basic begin() method // int state = fsk.begin(); From 4b0c68e2973e1a20677491cffadf3c7fbc1f7f36 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 7 Apr 2020 13:30:27 +0200 Subject: [PATCH 47/57] [RTTY] Added note about SX128x usage --- examples/RTTY/RTTY_Transmit/RTTY_Transmit.ino | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/RTTY/RTTY_Transmit/RTTY_Transmit.ino b/examples/RTTY/RTTY_Transmit/RTTY_Transmit.ino index d456b041..f565c6f0 100644 --- a/examples/RTTY/RTTY_Transmit/RTTY_Transmit.ino +++ b/examples/RTTY/RTTY_Transmit/RTTY_Transmit.ino @@ -12,6 +12,7 @@ - SX126x - nRF24 - Si443x/RFM2x + - SX128x For full API reference, see the GitHub Pages https://jgromes.github.io/RadioLib/ @@ -70,6 +71,7 @@ void setup() { // SX126x - 1 Hz // nRF24 - 1000000 Hz // Si443x/RFM2x - 156 Hz + // SX128x - 198 Hz Serial.print(F("[RTTY] Initializing ... ")); // low ("space") frequency: 434.0 MHz // frequency shift: 183 Hz From 5eb92ef4dcfcdaddc94141cd455563686c35019d Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 7 Apr 2020 13:41:44 +0200 Subject: [PATCH 48/57] Updated readme --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 9f5e2dc0..1884cd88 100644 --- a/README.md +++ b/README.md @@ -21,16 +21,17 @@ RadioLib was originally created as a driver for [__RadioShield__](https://github * __RFM2x__ series FSK modules (RFM22, RM23) * __RFM9x__ series LoRa modules (RFM95, RM96, RFM97, RFM98) * __Si443x__ series FSK modules (Si4430, Si4431, Si4432) -* __SX127x__ series LoRa modules (SX1272, SX1273, SX1276, SX1277, SX1278, SX1279) * __SX126x__ series LoRa modules (SX1261, SX1262, SX1268) +* __SX127x__ series LoRa modules (SX1272, SX1273, SX1276, SX1277, SX1278, SX1279) +* __SX128x__ series LoRa/GFSK/BLE/FLRC modules (SX1280, SX1281, SX1282) * __SX1231__ FSK/OOK radio module * __XBee__ modules (S2B) ### Supported protocols: * __MQTT__ for modules: ESP8266 * __HTTP__ for modules: ESP8266 -* __RTTY__ for modules: SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, nRF24L01, RFM2x and Si443x -* __Morse Code__ for modules: SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, nRF24L01, RFM2x and Si443x +* __RTTY__ for modules: SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, nRF24L01, RFM2x, Si443x and SX128x +* __Morse Code__ for modules: SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, nRF24L01, RFM2x, Si443x and SX128x * __AX.25__ for modules: SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, RFM2x and Si443x * __SSTV__ for modules: SX127x, RFM9x, SX126x, RF69 and SX1231 From 46be8529154a34c32dd3574c416dd6d3f39c393a Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 7 Apr 2020 13:42:09 +0200 Subject: [PATCH 49/57] [SX128x] Removed reference to unsupported method --- examples/SX128x/SX128x_GFSK_Modem/SX128x_GFSK_Modem.ino | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/SX128x/SX128x_GFSK_Modem/SX128x_GFSK_Modem.ino b/examples/SX128x/SX128x_GFSK_Modem/SX128x_GFSK_Modem.ino index 9b93c481..1ee3a7a4 100644 --- a/examples/SX128x/SX128x_GFSK_Modem/SX128x_GFSK_Modem.ino +++ b/examples/SX128x/SX128x_GFSK_Modem/SX128x_GFSK_Modem.ino @@ -60,7 +60,6 @@ void setup() { state = gfsk.setFrequency(2410.5); state = gfsk.setBitRate(200); state = gfsk.setFrequencyDeviation(100.0); - state = gfsk.setRxBandwidth(250.0); state = gfsk.setOutputPower(5); state = gfsk.setDataShaping(1.0); uint8_t syncWord[] = {0x01, 0x23, 0x45, 0x67, 0x89}; From 7c9f422e0c9820c4af2d96b889eda5089353b743 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 7 Apr 2020 13:42:30 +0200 Subject: [PATCH 50/57] [SX128x] Fixed type conflict in max() --- src/modules/SX128x/SX128x.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index a11b1788..186e7d86 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -841,8 +841,8 @@ uint32_t SX128x::getTimeOnAir(size_t len) { // get SF coefficients float coeff1 = 0; - uint8_t coeff2 = 0; - uint8_t coeff3 = 0; + int16_t coeff2 = 0; + int16_t coeff3 = 0; if(sf < 7) { // SF5, SF6 coeff1 = 6.25; @@ -861,13 +861,13 @@ uint32_t SX128x::getTimeOnAir(size_t len) { } // get CRC length - uint8_t N_bitCRC = 16; + int16_t N_bitCRC = 16; if(_crcLoRa == SX128X_LORA_CRC_OFF) { N_bitCRC = 0; } // get header length - uint8_t N_symbolHeader = 20; + int16_t N_symbolHeader = 20; if(_headerType == SX128X_LORA_HEADER_IMPLICIT) { N_symbolHeader = 0; } @@ -876,7 +876,7 @@ uint32_t SX128x::getTimeOnAir(size_t len) { uint32_t N_symbolPreamble = (_preambleLengthLoRa & 0x0F) * (uint32_t(1) << ((_preambleLengthLoRa & 0xF0) >> 4)); // calculate the number of symbols - N_symbol = (float)N_symbolPreamble + coeff1 + 8.0 + ceil(max(8 * len + N_bitCRC - coeff2 + N_symbolHeader, 0) / (float)coeff3) * (float)(_cr + 4); + N_symbol = (float)N_symbolPreamble + coeff1 + 8.0 + ceil(max((int16_t)(8 * len + N_bitCRC - coeff2 + N_symbolHeader), (int16_t)0) / (float)coeff3) * (float)(_cr + 4); } else { // long interleaving - abandon hope all ye who enter here From f8c9b5d03a01c74fc4649047f47be3f6d85cbf20 Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 9 Apr 2020 09:58:35 +0200 Subject: [PATCH 51/57] [SX128x] Fixed incorrect status code --- src/modules/SX128x/SX128x.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index 186e7d86..c61900a5 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -604,7 +604,7 @@ int16_t SX128x::setBitRate(uint16_t br) { } else if(br == 2000) { _br = SX128X_BLE_GFSK_BR_2_000_BW_2_4; } else { - return(ERR_INVALID_BIT_RANGE); + return(ERR_INVALID_BIT_RATE); } // update modulation parameters From 635c008e26ca718b0121604ae33acd6c3e3e1024 Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 9 Apr 2020 09:59:31 +0200 Subject: [PATCH 52/57] [SX128x] Fixed bug in ToA calculation for non-LoRa modems (#132) --- src/modules/SX128x/SX128x.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index c61900a5..369d7b67 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -888,7 +888,7 @@ uint32_t SX128x::getTimeOnAir(size_t len) { return(((uint32_t(1) << sf) / _bwKhz) * N_symbol * 1000.0); } else { - return((len * 8) / _brKbps); + return(((uint32_t)len * 8 * 1000) / _brKbps); } } From 5c0c7f32c301855c699d481403c3161e3ed556d5 Mon Sep 17 00:00:00 2001 From: jgromes Date: Thu, 9 Apr 2020 12:10:38 +0200 Subject: [PATCH 53/57] [SX128x] Set default regulator mode to DC-DC --- src/modules/SX128x/SX128x.cpp | 5 +++++ src/modules/SX128x/SX128x.h | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index 369d7b67..4b765b6d 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -1034,6 +1034,11 @@ int16_t SX128x::config(uint8_t modem) { state = SPIwriteCommand(SX128X_CMD_SET_CAD_PARAMS, data, 1); RADIOLIB_ASSERT(state); + // set regulator mode to DC-DC + data[0] = SX128X_REGULATOR_DC_DC; + state = SPIwriteCommand(SX128X_CMD_SET_REGULATOR_MODE, data, 1); + RADIOLIB_ASSERT(state); + return(ERR_NONE); } diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h index 2e74f7e0..a06a4cca 100644 --- a/src/modules/SX128x/SX128x.h +++ b/src/modules/SX128x/SX128x.h @@ -318,6 +318,11 @@ #define SX128X_IRQ_NONE 0x0000 // 15 0 none #define SX128X_IRQ_ALL 0xFFFF // 15 0 all +//SX128X_CMD_SET_REGULATOR_MODE +#define SX128X_REGULATOR_LDO 0x00 // 7 0 set regulator mode: LDO (default) +#define SX128X_REGULATOR_DC_DC 0x01 // 7 0 DC-DC + + /*! \class SX128x From ff3225cd199c95da7e0bc6acc81ba5ce0f439cef Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 12 Apr 2020 11:05:16 +0200 Subject: [PATCH 54/57] [SX128x] Added FLRC modem support --- .../SX128x_FLRC_Modem/SX128x_FLRC_Modem.ino | 114 ++++++++++ .../SX128x_GFSK_Modem/SX128x_GFSK_Modem.ino | 1 - keywords.txt | 5 + src/modules/SX128x/SX128x.cpp | 202 ++++++++++++++---- src/modules/SX128x/SX128x.h | 28 ++- 5 files changed, 304 insertions(+), 46 deletions(-) create mode 100644 examples/SX128x/SX128x_FLRC_Modem/SX128x_FLRC_Modem.ino diff --git a/examples/SX128x/SX128x_FLRC_Modem/SX128x_FLRC_Modem.ino b/examples/SX128x/SX128x_FLRC_Modem/SX128x_FLRC_Modem.ino new file mode 100644 index 00000000..1f28b834 --- /dev/null +++ b/examples/SX128x/SX128x_FLRC_Modem/SX128x_FLRC_Modem.ino @@ -0,0 +1,114 @@ +/* + RadioLib SX128x FLRC Modem Example + + This example shows how to use FLRC modem in SX128x chips. + + NOTE: The sketch below is just a guide on how to use + FLRC modem, so this code should not be run directly! + Instead, modify the other examples to use FLRC + modem and use the appropriate configuration + methods. + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1280 has the following connections: +// NSS pin: 10 +// DIO1 pin: 2 +// NRST pin: 3 +// BUSY pin: 9 +SX1280 flrc = new Module(10, 2, 3, 9); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1280 flrc = RadioShield.ModuleA; + +void setup() { + Serial.begin(9600); + + // initialize SX1280 with default settings + Serial.print(F("[SX1280] Initializing ... ")); + // carrier frequency: 2400.0 MHz + // bit rate: 650 kbps + // coding rate: 3 + // output power: 10 dBm + // preamble length: 16 bits + // data shaping: Gaussian, BT = 0.5 + // sync word: 0x2D 0x01 0x4B 0x1D + // CRC: enabled + int state = flrc.beginFLRC(); + if (state == ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // if needed, you can switch between LoRa and FLRC modes + // + // flrc.begin() start LoRa mode (and disable FLRC) + // lora.beginFLRC() start FLRC mode (and disable LoRa) + + // the following settings can also + // be modified at run-time + state = flrc.setFrequency(2410.5); + state = flrc.setBitRate(200); + state = flrc.setCodingRate(2); + state = flrc.setOutputPower(5); + state = flrc.setDataShaping(1.0); + uint8_t syncWord[] = {0x01, 0x23, 0x45, 0x67}; + state = flrc.setSyncWord(syncWord, 4); + if (state != ERR_NONE) { + Serial.print(F("Unable to set configuration, code ")); + Serial.println(state); + while (true); + } + + #warning "This sketch is just an API guide! Read the note at line 6." +} + +void loop() { + // FLRC modem can use the same transmit/receive methods + // as the LoRa modem, even their interrupt-driven versions + + // transmit FLRC packet + int state = flrc.transmit("Hello World!"); + /* + byte byteArr[] = {0x01, 0x23, 0x45, 0x67, + 0x89, 0xAB, 0xCD, 0xEF}; + int state = flrc.transmit(byteArr, 8); + */ + if (state == ERR_NONE) { + Serial.println(F("[SX1280] Packet transmitted successfully!")); + } else if (state == ERR_PACKET_TOO_LONG) { + Serial.println(F("[SX1280] Packet too long!")); + } else if (state == ERR_TX_TIMEOUT) { + Serial.println(F("[SX1280] Timed out while transmitting!")); + } else { + Serial.println(F("[SX1280] Failed to transmit packet, code ")); + Serial.println(state); + } + + // receive GFSK packet + String str; + state = flrc.receive(str); + /* + byte byteArr[8]; + int state = flrc.receive(byteArr, 8); + */ + if (state == ERR_NONE) { + Serial.println(F("[SX1280] Received packet!")); + Serial.print(F("[SX1280] Data:\t")); + Serial.println(str); + } else if (state == ERR_RX_TIMEOUT) { + Serial.println(F("[SX1280] Timed out while waiting for packet!")); + } else { + Serial.print(F("[SX1280] Failed to receive packet, code ")); + Serial.println(state); + } +} diff --git a/examples/SX128x/SX128x_GFSK_Modem/SX128x_GFSK_Modem.ino b/examples/SX128x/SX128x_GFSK_Modem/SX128x_GFSK_Modem.ino index 1ee3a7a4..adfc5320 100644 --- a/examples/SX128x/SX128x_GFSK_Modem/SX128x_GFSK_Modem.ino +++ b/examples/SX128x/SX128x_GFSK_Modem/SX128x_GFSK_Modem.ino @@ -37,7 +37,6 @@ void setup() { // frequency deviation: 400.0 kHz // output power: 10 dBm // preamble length: 16 bits - // coding rate: 7 // data shaping: Gaussian, BT = 0.5 // sync word: 0x2D 0x01 // CRC: enabled, CRC16 (CCIT) diff --git a/keywords.txt b/keywords.txt index d42b2c73..af21ca40 100644 --- a/keywords.txt +++ b/keywords.txt @@ -214,6 +214,11 @@ getPictureHeight KEYWORD2 # SX128x beginGFSK KEYWORD2 +beginFLRC KEYWORD2 +beginBLE KEYWORD2 +range KEYWORD2 +startRanging KEYWORD2 +getRangingResult KEYWORD2 ####################################### # Constants (LITERAL1) diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index 4b765b6d..73a25fe5 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -114,6 +114,64 @@ int16_t SX128x::beginGFSK(float freq, uint16_t br, float freqDev, int8_t power, return(state); } +int16_t SX128x::beginFLRC(float freq, uint16_t br, uint8_t cr, int8_t power, uint16_t preambleLength, float dataShaping) { + // set module properties + _mod->init(RADIOLIB_USE_SPI); + Module::pinMode(_mod->getIrq(), INPUT); + Module::pinMode(_mod->getGpio(), INPUT); + + // initialize FLRC modulation variables + _brKbps = br; + _br = SX128X_FLRC_BR_0_650_BW_0_6; + _crFLRC = SX128X_FLRC_CR_3_4; + _shaping = SX128X_FLRC_BT_0_5; + + // initialize FLRC packet variables + _preambleLengthGFSK = preambleLength; + _syncWordLen = 2; + _syncWordMatch = SX128X_GFSK_FLRC_SYNC_WORD_1; + _crcGFSK = SX128X_GFSK_FLRC_CRC_2_BYTE; + _whitening = SX128X_GFSK_BLE_WHITENING_OFF; + + // reset the module and verify startup + int16_t state = reset(); + RADIOLIB_ASSERT(state); + + // set mode to standby + state = standby(); + RADIOLIB_ASSERT(state); + + // configure settings not accessible by API + state = config(SX128X_PACKET_TYPE_FLRC); + RADIOLIB_ASSERT(state); + + // configure publicly accessible settings + state = setFrequency(freq); + RADIOLIB_ASSERT(state); + + state = setBitRate(br); + RADIOLIB_ASSERT(state); + + state = setCodingRate(cr); + RADIOLIB_ASSERT(state); + + state = setOutputPower(power); + RADIOLIB_ASSERT(state); + + state = setPreambleLength(preambleLength); + RADIOLIB_ASSERT(state); + + state = setDataShaping(dataShaping); + RADIOLIB_ASSERT(state); + + // set publicly accessible settings that are not a part of begin method + uint8_t sync[] = { 0x2D, 0x01, 0x4B, 0x1D}; + state = setSyncWord(sync, 4); + RADIOLIB_ASSERT(state); + + return(state); +} + int16_t SX128x::reset(bool verify) { // run the reset sequence - same as SX126x, as SX128x docs don't seem to mention this Module::pinMode(_mod->getRst(), OUTPUT); @@ -336,7 +394,7 @@ int16_t SX128x::startTransmit(uint8_t* data, size_t len, uint8_t addr) { uint8_t modem = getPacketType(); if(modem == SX128X_PACKET_TYPE_LORA) { state = setPacketParamsLoRa(_preambleLengthLoRa, _headerType, len, _crcLoRa); - } else if(modem == SX128X_PACKET_TYPE_GFSK) { + } else if((modem == SX128X_PACKET_TYPE_GFSK) || (modem == SX128X_PACKET_TYPE_FLRC)) { state = setPacketParamsGFSK(_preambleLengthGFSK, _syncWordLen, _syncWordMatch, _crcGFSK, _whitening, len); } else { return(ERR_WRONG_MODEM); @@ -406,6 +464,11 @@ int16_t SX128x::startReceive(uint16_t timeout) { } int16_t SX128x::readData(uint8_t* data, size_t len) { + // check active modem + if(getPacketType() == SX128X_PACKET_TYPE_RANGING) { + return(ERR_WRONG_MODEM); + } + // set mode to standby int16_t state = standby(); RADIOLIB_ASSERT(state); @@ -511,19 +574,29 @@ int16_t SX128x::setSpreadingFactor(uint8_t sf) { int16_t SX128x::setCodingRate(uint8_t cr, bool longInterleaving) { // check active modem uint8_t modem = getPacketType(); - if(!((modem == SX128X_PACKET_TYPE_LORA) || (modem == SX128X_PACKET_TYPE_RANGING))) { - return(ERR_WRONG_MODEM); + + // LoRa/ranging + if((modem == SX128X_PACKET_TYPE_LORA) || (modem == SX128X_PACKET_TYPE_RANGING)) { + RADIOLIB_CHECK_RANGE(cr, 5, 8, ERR_INVALID_CODING_RATE); + + // update modulation parameters + if(longInterleaving && (modem == SX128X_PACKET_TYPE_LORA)) { + _cr = cr; + } else { + _cr = cr - 4; + } + return(setModulationParams(_sf, _bw, _cr)); + + // FLRC + } else if(modem == SX128X_PACKET_TYPE_FLRC) { + RADIOLIB_CHECK_RANGE(cr, 2, 4, ERR_INVALID_CODING_RATE); + + // update modulation parameters + _crFLRC = (cr - 2) * 2; + return(setModulationParams(_br, _crFLRC, _shaping)); } - RADIOLIB_CHECK_RANGE(cr, 5, 8, ERR_INVALID_CODING_RATE); - - // update modulation parameters - if(longInterleaving && (modem == SX128X_PACKET_TYPE_LORA)) { - _cr = cr; - } else { - _cr = cr - 4; - } - return(setModulationParams(_sf, _bw, _cr)); + return(ERR_WRONG_MODEM); } int16_t SX128x::setOutputPower(int8_t power) { @@ -583,33 +656,58 @@ int16_t SX128x::setPreambleLength(uint32_t preambleLength) { int16_t SX128x::setBitRate(uint16_t br) { // check active modem uint8_t modem = getPacketType(); - if(!((modem == SX128X_PACKET_TYPE_GFSK) || (modem == SX128X_PACKET_TYPE_BLE))) { - return(ERR_WRONG_MODEM); + + // GFSK/BLE + if((modem == SX128X_PACKET_TYPE_GFSK) || (modem == SX128X_PACKET_TYPE_BLE)) { + if(br == 125) { + _br = SX128X_BLE_GFSK_BR_0_125_BW_0_3; + } else if(br == 250) { + _br = SX128X_BLE_GFSK_BR_0_250_BW_0_6; + } else if(br == 400) { + _br = SX128X_BLE_GFSK_BR_0_400_BW_1_2; + } else if(br == 500) { + _br = SX128X_BLE_GFSK_BR_0_500_BW_1_2; + } else if(br == 800) { + _br = SX128X_BLE_GFSK_BR_0_800_BW_2_4; + } else if(br == 1000) { + _br = SX128X_BLE_GFSK_BR_1_000_BW_2_4; + } else if(br == 1600) { + _br = SX128X_BLE_GFSK_BR_1_600_BW_2_4; + } else if(br == 2000) { + _br = SX128X_BLE_GFSK_BR_2_000_BW_2_4; + } else { + return(ERR_INVALID_BIT_RATE); + } + + // update modulation parameters + _brKbps = br; + return(setModulationParams(_br, _modIndex, _shaping)); + + // FLRC + } else if(modem == SX128X_PACKET_TYPE_FLRC) { + if(br == 260) { + _br = SX128X_FLRC_BR_0_260_BW_0_3; + } else if(br == 325) { + _br = SX128X_FLRC_BR_0_325_BW_0_3; + } else if(br == 520) { + _br = SX128X_FLRC_BR_0_520_BW_0_6; + } else if(br == 650) { + _br = SX128X_FLRC_BR_0_650_BW_0_6; + } else if(br == 1000) { + _br = SX128X_FLRC_BR_1_000_BW_1_2; + } else if(br == 1300) { + _br = SX128X_FLRC_BR_1_300_BW_1_2; + } else { + return(ERR_INVALID_BIT_RATE); + } + + // update modulation parameters + _brKbps = br; + return(setModulationParams(_br, _crFLRC, _shaping)); + } - if(br == 125) { - _br = SX128X_BLE_GFSK_BR_0_125_BW_0_3; - } else if(br == 250) { - _br = SX128X_BLE_GFSK_BR_0_250_BW_0_6; - } else if(br == 400) { - _br = SX128X_BLE_GFSK_BR_0_400_BW_1_2; - } else if(br == 500) { - _br = SX128X_BLE_GFSK_BR_0_500_BW_1_2; - } else if(br == 800) { - _br = SX128X_BLE_GFSK_BR_0_800_BW_2_4; - } else if(br == 1000) { - _br = SX128X_BLE_GFSK_BR_1_000_BW_2_4; - } else if(br == 1600) { - _br = SX128X_BLE_GFSK_BR_1_600_BW_2_4; - } else if(br == 2000) { - _br = SX128X_BLE_GFSK_BR_2_000_BW_2_4; - } else { - return(ERR_INVALID_BIT_RATE); - } - - // update modulation parameters - _brKbps = br; - return(setModulationParams(_br, _modIndex, _shaping)); + return(ERR_WRONG_MODEM); } int16_t SX128x::setFrequencyDeviation(float freqDev) { @@ -642,7 +740,7 @@ int16_t SX128x::setFrequencyDeviation(float freqDev) { int16_t SX128x::setDataShaping(float dataShaping) { // check active modem uint8_t modem = getPacketType(); - if(!((modem == SX128X_PACKET_TYPE_GFSK) || (modem == SX128X_PACKET_TYPE_BLE))) { + if(!((modem == SX128X_PACKET_TYPE_GFSK) || (modem == SX128X_PACKET_TYPE_BLE) || (modem == SX128X_PACKET_TYPE_FLRC))) { return(ERR_WRONG_MODEM); } @@ -659,7 +757,11 @@ int16_t SX128x::setDataShaping(float dataShaping) { } // update modulation parameters - return(setModulationParams(_br, _modIndex, _shaping)); + if((modem == SX128X_PACKET_TYPE_GFSK) || (modem == SX128X_PACKET_TYPE_BLE)) { + return(setModulationParams(_br, _modIndex, _shaping)); + } else { + return(setModulationParams(_br, _crFLRC, _shaping)); + } } int16_t SX128x::setSyncWord(uint8_t* syncWord, uint8_t len) { @@ -669,8 +771,25 @@ int16_t SX128x::setSyncWord(uint8_t* syncWord, uint8_t len) { return(ERR_WRONG_MODEM); } - if(len > 5) { - return(ERR_INVALID_SYNC_WORD); + if(modem == SX128X_PACKET_TYPE_GFSK) { + // GFSK can use up to 5 bytes as sync word + if(len > 5) { + return(ERR_INVALID_SYNC_WORD); + } + + // calculate sync word length parameter value + if(len > 0) { + _syncWordLen = (len - 1)*2; + } + + } else { + // FLRC requires 32-bit sync word + if(!((len == 0) || (len == 4))) { + return(ERR_INVALID_SYNC_WORD); + } + + // save sync word length parameter value + _syncWordLen = len; } // reverse sync word byte order @@ -684,7 +803,6 @@ int16_t SX128x::setSyncWord(uint8_t* syncWord, uint8_t len) { RADIOLIB_ASSERT(state); // update packet parameters - _syncWordLen = len; if(_syncWordLen == 0) { _syncWordMatch = SX128X_GFSK_FLRC_SYNC_WORD_OFF; } else { diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h index a06a4cca..6548f511 100644 --- a/src/modules/SX128x/SX128x.h +++ b/src/modules/SX128x/SX128x.h @@ -384,6 +384,25 @@ class SX128x: public PhysicalLayer { */ int16_t beginGFSK(float freq = 2400.0, uint16_t br = 800, float freqDev = 400.0, int8_t power = 10, uint16_t preambleLength = 16, float dataShaping = 0.5); + /*! + \brief Initialization method for FLRC modem. + + \param freq Carrier frequency in MHz. Defaults to 2400.0 MHz. + + \param br FLRC bit rate in kbps. Defaults to 650 kbps. + + \param cr FLRC coding rate. Defaults to 3 (coding rate 3/4). + + \param power Output power in dBm. Defaults to 10 dBm. + + \parma preambleLength FLRC preamble length in bits. Defaults to 16 bits. + + \param dataShaping Time-bandwidth product of the Gaussian filter to be used for shaping. Defaults to 0.5. + + \returns \ref status_codes + */ + int16_t beginFLRC(float freq = 2400.0, uint16_t br = 650, uint8_t cr = 3, int8_t power = 10, uint16_t preambleLength = 16, float dataShaping = 0.5); + /*! \brief Reset method. Will reset the chip to the default state using RST pin. @@ -576,9 +595,9 @@ class SX128x: public PhysicalLayer { int16_t setPreambleLength(uint32_t preambleLength); /*! - \brief Sets FSK bit rate. Allowed values are 125, 250, 400, 500, 800, 1000, 1600 and 2000 kbps. + \brief Sets FSK or FLRC bit rate. Allowed values are 125, 250, 400, 500, 800, 1000, 1600 and 2000 kbps (for FSK modem) or 260, 325, 520, 650, 1000 and 1300 (for FLRC modem). - \param br FSK bit rate to be set in kbps. + \param br FSK/FLRC bit rate to be set in kbps. \returns \ref status_codes */ @@ -603,7 +622,7 @@ class SX128x: public PhysicalLayer { int16_t setDataShaping(float dataShaping); /*! - \brief Sets sync word in the form of array of up to 8 bytes. + \brief Sets FSK/FLRC sync word in the form of array of up to 5 bytes (FSK). For FLRC modem, the sync word must be exactly 4 bytes long \param syncWord Sync word to be set. @@ -737,6 +756,9 @@ class SX128x: public PhysicalLayer { uint8_t _br, _modIndex, _shaping; uint8_t _preambleLengthGFSK, _syncWordLen, _syncWordMatch, _crcGFSK, _whitening; + // cached FLRC parameters + uint8_t _crFLRC; + // cached BLE parameters uint8_t _connectionState, _crcBLE, _bleTestPayload; From a355a098e6543cb2101f10b5a2d517e7c6301a65 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 12 Apr 2020 11:32:07 +0200 Subject: [PATCH 55/57] [SX128x] Added BLE modem support --- .../SX128x_BLE_Modem/SX128x_BLE_Modem.ino | 114 ++++++++++++++++++ keywords.txt | 1 + src/modules/SX128x/SX128x.cpp | 61 +++++++++- src/modules/SX128x/SX128x.h | 26 ++++ 4 files changed, 201 insertions(+), 1 deletion(-) create mode 100644 examples/SX128x/SX128x_BLE_Modem/SX128x_BLE_Modem.ino diff --git a/examples/SX128x/SX128x_BLE_Modem/SX128x_BLE_Modem.ino b/examples/SX128x/SX128x_BLE_Modem/SX128x_BLE_Modem.ino new file mode 100644 index 00000000..166215b7 --- /dev/null +++ b/examples/SX128x/SX128x_BLE_Modem/SX128x_BLE_Modem.ino @@ -0,0 +1,114 @@ +/* + RadioLib SX128x BLE Modem Example + + This example shows how to use BLE modem in SX128x chips. + RadioLib does not provide BLE protocol support (yet), + only compatibility with the physical layer. + + NOTE: The sketch below is just a guide on how to use + BLE modem, so this code should not be run directly! + Instead, modify the other examples to use BLE + modem and use the appropriate configuration + methods. + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1280 has the following connections: +// NSS pin: 10 +// DIO1 pin: 2 +// NRST pin: 3 +// BUSY pin: 9 +SX1280 ble = new Module(10, 2, 3, 9); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1280 ble = RadioShield.ModuleA; + +void setup() { + Serial.begin(9600); + + // initialize SX1280 with default settings + Serial.print(F("[SX1280] Initializing ... ")); + // carrier frequency: 2400.0 MHz + // bit rate: 800 kbps + // frequency deviation: 400.0 kHz + // output power: 10 dBm + // preamble length: 16 bits + // data shaping: Gaussian, BT = 0.5 + // CRC: enabled, CRC16 (CCIT) + int state = ble.beginBLE(); + if (state == ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // if needed, you can switch between LoRa and FSK modes + // + // ble.begin() start LoRa mode (and disable BLE) + // lora.beginBLE() start BLE mode (and disable LoRa) + + // the following settings can also + // be modified at run-time + state = ble.setFrequency(2410.5); + state = ble.setBitRate(200); + state = ble.setFrequencyDeviation(100.0); + state = ble.setOutputPower(5); + state = ble.setDataShaping(1.0); + state = ble.setAccessAddress(0x12345678); + if (state != ERR_NONE) { + Serial.print(F("Unable to set configuration, code ")); + Serial.println(state); + while (true); + } + + #warning "This sketch is just an API guide! Read the note at line 6." +} + +void loop() { + // BLE modem can use the same transmit/receive methods + // as the LoRa modem, even their interrupt-driven versions + + // transmit BLE packet + int state = ble.transmit("Hello World!"); + /* + byte byteArr[] = {0x01, 0x23, 0x45, 0x67, + 0x89, 0xAB, 0xCD, 0xEF}; + int state = ble.transmit(byteArr, 8); + */ + if (state == ERR_NONE) { + Serial.println(F("[SX1280] Packet transmitted successfully!")); + } else if (state == ERR_PACKET_TOO_LONG) { + Serial.println(F("[SX1280] Packet too long!")); + } else if (state == ERR_TX_TIMEOUT) { + Serial.println(F("[SX1280] Timed out while transmitting!")); + } else { + Serial.println(F("[SX1280] Failed to transmit packet, code ")); + Serial.println(state); + } + + // receive BLE packet + String str; + state = ble.receive(str); + /* + byte byteArr[8]; + int state = ble.receive(byteArr, 8); + */ + if (state == ERR_NONE) { + Serial.println(F("[SX1280] Received packet!")); + Serial.print(F("[SX1280] Data:\t")); + Serial.println(str); + } else if (state == ERR_RX_TIMEOUT) { + Serial.println(F("[SX1280] Timed out while waiting for packet!")); + } else { + Serial.print(F("[SX1280] Failed to receive packet, code ")); + Serial.println(state); + } +} diff --git a/keywords.txt b/keywords.txt index af21ca40..6afdf6ba 100644 --- a/keywords.txt +++ b/keywords.txt @@ -216,6 +216,7 @@ getPictureHeight KEYWORD2 beginGFSK KEYWORD2 beginFLRC KEYWORD2 beginBLE KEYWORD2 +setAccessAddress KEYWORD2 range KEYWORD2 startRanging KEYWORD2 getRangingResult KEYWORD2 diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index 73a25fe5..2404e420 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -114,6 +114,54 @@ int16_t SX128x::beginGFSK(float freq, uint16_t br, float freqDev, int8_t power, return(state); } +int16_t SX128x::beginBLE(float freq, uint16_t br, float freqDev, int8_t power, float dataShaping) { + // set module properties + _mod->init(RADIOLIB_USE_SPI); + Module::pinMode(_mod->getIrq(), INPUT); + Module::pinMode(_mod->getGpio(), INPUT); + + // initialize BLE modulation variables + _brKbps = br; + _br = SX128X_BLE_GFSK_BR_0_800_BW_2_4; + _modIndexReal = 1.0; + _modIndex = SX128X_BLE_GFSK_MOD_IND_1_00; + _shaping = SX128X_BLE_GFSK_BT_0_5; + + // initialize BLE packet variables + _crcGFSK = SX128X_BLE_CRC_3_BYTE; + _whitening = SX128X_GFSK_BLE_WHITENING_ON; + + // reset the module and verify startup + int16_t state = reset(); + RADIOLIB_ASSERT(state); + + // set mode to standby + state = standby(); + RADIOLIB_ASSERT(state); + + // configure settings not accessible by API + state = config(SX128X_PACKET_TYPE_BLE); + RADIOLIB_ASSERT(state); + + // configure publicly accessible settings + state = setFrequency(freq); + RADIOLIB_ASSERT(state); + + state = setBitRate(br); + RADIOLIB_ASSERT(state); + + state = setFrequencyDeviation(freqDev); + RADIOLIB_ASSERT(state); + + state = setOutputPower(power); + RADIOLIB_ASSERT(state); + + state = setDataShaping(dataShaping); + RADIOLIB_ASSERT(state); + + return(state); +} + int16_t SX128x::beginFLRC(float freq, uint16_t br, uint8_t cr, int8_t power, uint16_t preambleLength, float dataShaping) { // set module properties _mod->init(RADIOLIB_USE_SPI); @@ -468,7 +516,7 @@ int16_t SX128x::readData(uint8_t* data, size_t len) { if(getPacketType() == SX128X_PACKET_TYPE_RANGING) { return(ERR_WRONG_MODEM); } - + // set mode to standby int16_t state = standby(); RADIOLIB_ASSERT(state); @@ -896,6 +944,17 @@ int16_t SX128x::setWhitening(bool enabled) { return(setPacketParamsBLE(_connectionState, _crcBLE, _bleTestPayload, _whitening)); } +int16_t SX128x::setAccessAddress(uint32_t addr) { + // check active modem + if(getPacketType() != SX128X_PACKET_TYPE_BLE) { + return(ERR_WRONG_MODEM); + } + + // use setSyncWord to set the address + uint8_t syncWord[] = { (uint8_t)((addr >> 24) & 0xFF), (uint8_t)((addr >> 16) & 0xFF), (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF) }; + return(setSyncWord(syncWord, 4)); +} + float SX128x::getRSSI() { // get packet status uint8_t packetStatus[5]; diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h index 6548f511..82e19884 100644 --- a/src/modules/SX128x/SX128x.h +++ b/src/modules/SX128x/SX128x.h @@ -384,6 +384,23 @@ class SX128x: public PhysicalLayer { */ int16_t beginGFSK(float freq = 2400.0, uint16_t br = 800, float freqDev = 400.0, int8_t power = 10, uint16_t preambleLength = 16, float dataShaping = 0.5); + /*! + \brief Initialization method for BLE modem. + + \param freq Carrier frequency in MHz. Defaults to 2400.0 MHz. + + \param br BLE bit rate in kbps. Defaults to 800 kbps. + + \param freqDev Frequency deviation from carrier frequency in kHz. Defaults to 400.0 kHz. + + \param power Output power in dBm. Defaults to 10 dBm. + + \param dataShaping Time-bandwidth product of the Gaussian filter to be used for shaping. Defaults to 0.5. + + \returns \ref status_codes + */ + int16_t beginBLE(float freq = 2400.0, uint16_t br = 800, float freqDev = 400.0, int8_t power = 10, float dataShaping = 0.5); + /*! \brief Initialization method for FLRC modem. @@ -654,6 +671,15 @@ class SX128x: public PhysicalLayer { */ int16_t setWhitening(bool enabled); + /*! + \brief Sets BLE access address. + + \param addr BLE access address. + + \returns \ref status_codes + */ + int16_t setAccessAddress(uint32_t addr); + /*! \brief Gets RSSI (Recorded Signal Strength Indicator) of the last received packet. From 1592831e0c99913e6cea2a3a619961c69fe99c3f Mon Sep 17 00:00:00 2001 From: jgromes Date: Sun, 12 Apr 2020 13:47:56 +0200 Subject: [PATCH 56/57] [SX128x] Implemented ranging --- .../SX128x/SX128x_Ranging/SX128x_Ranging.ino | 84 ++++++++++++++ keywords.txt | 2 + src/TypeDef.h | 7 ++ src/modules/SX128x/SX1280.cpp | 108 ++++++++++++++++++ src/modules/SX128x/SX1280.h | 31 ++++- src/modules/SX128x/SX128x.cpp | 10 ++ src/modules/SX128x/SX128x.h | 20 ++-- 7 files changed, 253 insertions(+), 9 deletions(-) create mode 100644 examples/SX128x/SX128x_Ranging/SX128x_Ranging.ino diff --git a/examples/SX128x/SX128x_Ranging/SX128x_Ranging.ino b/examples/SX128x/SX128x_Ranging/SX128x_Ranging.ino new file mode 100644 index 00000000..585f948b --- /dev/null +++ b/examples/SX128x/SX128x_Ranging/SX128x_Ranging.ino @@ -0,0 +1,84 @@ +/* + RadioLib SX128x Ranging Example + + This example performs ranging exchange between two + SX1280 LoRa radio modules. Ranging allows to measure + distance between the modules using time-of-flight + measurement. + + Only SX1280 and SX1282 support ranging! + + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ +*/ + +// include the library +#include + +// SX1280 has the following connections: +// NSS pin: 10 +// DIO1 pin: 2 +// NRST pin: 3 +// BUSY pin: 9 +SX1280 lora = new Module(10, 2, 3, 9); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1280 lora = RadioShield.ModuleA; + +void setup() { + Serial.begin(9600); + + // initialize SX1280 with default settings + Serial.print(F("[SX1280] Initializing ... ")); + // carrier frequency: 2400.0 MHz + // bandwidth: 812.5 kHz + // spreading factor: 9 + // coding rate: 7 + // output power: 10 dBm + // preamble length: 12 symbols + // CRC: enabled + int state = lora.begin(); + if (state == ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } +} + +void loop() { + Serial.print(F("[SX1280] Ranging ... ")); + + // start ranging exchange + // range as master: true + // slave address: 0x12345678 + int state = lora.range(true, 0x12345678); + + // the other module must be configured as slave with the same address + /* + int state = lora.range(false, 0x12345678); + */ + + if (state == ERR_NONE) { + // ranging finished successfully + Serial.println(F("success!")); + Serial.print(F("[SX1280] Distance:\t\t\t")); + Serial.print(lora.getRangingResult()); + Serial.println(F(" meters")); + + } else if (state == ERR_RANGING_TIMEOUT) { + // timed out waiting for ranging packet + Serial.println(F("timed out!")); + + } else { + // some other error occurred + Serial.print(F("failed, code ")); + Serial.println(state); + + } + + // wait for a second before ranging again + delay(1000); +} diff --git a/keywords.txt b/keywords.txt index 6afdf6ba..bcc233c4 100644 --- a/keywords.txt +++ b/keywords.txt @@ -311,3 +311,5 @@ ERR_INVALID_RX_PERIOD LITERAL1 ERR_INVALID_CALLSIGN LITERAL1 ERR_INVALID_NUM_REPEATERS LITERAL1 ERR_INVALID_REPEATER_CALLSIGN LITERAL1 + +ERR_RANGING_TIMEOUT LITERAL1 diff --git a/src/TypeDef.h b/src/TypeDef.h index 00ef2096..f8254d3d 100644 --- a/src/TypeDef.h +++ b/src/TypeDef.h @@ -480,6 +480,13 @@ */ #define ERR_INVALID_REPEATER_CALLSIGN -803 +// SX128x-specific status codes + +/*! + \brief Timed out waiting for ranging exchange finish. +*/ +#define ERR_RANGING_TIMEOUT -901 + /*! \} */ diff --git a/src/modules/SX128x/SX1280.cpp b/src/modules/SX128x/SX1280.cpp index afbc96df..2c4d09ee 100644 --- a/src/modules/SX128x/SX1280.cpp +++ b/src/modules/SX128x/SX1280.cpp @@ -3,3 +3,111 @@ SX1280::SX1280(Module* mod) : SX1281(mod) { } + +int16_t SX1280::range(bool master, uint32_t addr) { + // start ranging + int16_t state = startRanging(master, addr); + RADIOLIB_ASSERT(state); + + // wait until ranging is finished + uint32_t start = millis(); + while(!digitalRead(_mod->getIrq())) { + yield(); + if(millis() - start > 10000) { + clearIrqStatus(); + standby(); + return(ERR_RANGING_TIMEOUT); + } + } + + // clear interrupt flags + state = clearIrqStatus(); + RADIOLIB_ASSERT(state); + + // set mode to standby + state = standby(); + + return(state); +} + +int16_t SX1280::startRanging(bool master, uint32_t addr) { + // check active modem + uint8_t modem = getPacketType(); + if(!((modem == SX128X_PACKET_TYPE_LORA) || (modem == SX128X_PACKET_TYPE_RANGING))) { + return(ERR_WRONG_MODEM); + } + + // ensure modem is set to ranging + int16_t state = ERR_NONE; + if(modem == SX128X_PACKET_TYPE_LORA) { + state = setPacketType(SX128X_PACKET_TYPE_RANGING); + RADIOLIB_ASSERT(state); + } + + // set modulation parameters + state = setModulationParams(_sf, _bw, _cr); + RADIOLIB_ASSERT(state); + + // set packet parameters + state = setPacketParamsLoRa(_preambleLengthLoRa, _headerType, _payloadLen, _crcLoRa); + RADIOLIB_ASSERT(state); + + // check all address bits + uint8_t regValue; + state = readRegister(SX128X_REG_SLAVE_RANGING_ADDRESS_WIDTH, ®Value, 1); + RADIOLIB_ASSERT(state); + regValue &= 0b00111111; + regValue |= 0b11000000; + state = writeRegister(SX128X_REG_SLAVE_RANGING_ADDRESS_WIDTH, ®Value, 1); + RADIOLIB_ASSERT(state); + + // set remaining parameter values + uint32_t addrReg = SX128X_REG_SLAVE_RANGING_ADDRESS_BYTE_3; + uint32_t irqMask = SX128X_IRQ_RANGING_SLAVE_RESP_DONE | SX128X_IRQ_RANGING_SLAVE_REQ_DISCARD; + uint32_t irqDio1 = SX128X_IRQ_RANGING_SLAVE_RESP_DONE; + if(master) { + addrReg = SX128X_REG_MASTER_RANGING_ADDRESS_BYTE_3; + irqMask = SX128X_IRQ_RANGING_MASTER_RES_VALID | SX128X_IRQ_RANGING_MASTER_TIMEOUT; + irqDio1 = SX128X_IRQ_RANGING_MASTER_RES_VALID; + } + + // set ranging address + uint8_t addrBuff[] = { (uint8_t)((addr >> 24) & 0xFF), (uint8_t)((addr >> 16) & 0xFF), (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF) }; + state = writeRegister(addrReg, addrBuff, 4); + RADIOLIB_ASSERT(state); + + // set DIO mapping + state = setDioIrqParams(irqMask, irqDio1); + RADIOLIB_ASSERT(state); + + // set role and start ranging + if(master) { + state = setRangingRole(SX128X_RANGING_ROLE_MASTER); + RADIOLIB_ASSERT(state); + + state = setTx(SX128X_TX_TIMEOUT_NONE); + RADIOLIB_ASSERT(state); + + } else { + state = setRangingRole(SX128X_RANGING_ROLE_SLAVE); + RADIOLIB_ASSERT(state); + + state = setRx(SX128X_RX_TIMEOUT_INF); + RADIOLIB_ASSERT(state); + + } + + return(state); +} + +float SX1280::getRangingResult() { + // read the register values + uint8_t data[4]; + int16_t state = readRegister(SX128X_REG_RANGING_RESULT_MSB, data + 1, 3); + RADIOLIB_ASSERT(state); + + // calculate the real result + uint32_t raw = 0; + memcpy(&raw, data, sizeof(uint32_t)); + return((float)raw * (150.0/(4.096 * _bwKhz))); +} diff --git a/src/modules/SX128x/SX1280.h b/src/modules/SX128x/SX1280.h index 08aa1ec1..ea8c5a18 100644 --- a/src/modules/SX128x/SX1280.h +++ b/src/modules/SX128x/SX1280.h @@ -6,8 +6,6 @@ #include "SX128x.h" #include "SX1281.h" -// TODO implement ranging - /*! \class SX1280 @@ -22,6 +20,35 @@ class SX1280: public SX1281 { */ SX1280(Module* mod); + /*! + \brief Blocking ranging method. + + \param master Whether to execute ranging in master mode (true) or slave mode (false). + + \param addr Ranging address to be used. + + \returns \ref status_codes + */ + int16_t range(bool master, uint32_t addr); + + /*! + \brief Interrupt-driven ranging method. + + \param master Whether to execute ranging in master mode (true) or slave mode (false). + + \param addr Ranging address to be used. + + \returns \ref status_codes + */ + int16_t startRanging(bool master, uint32_t addr); + + /*! + \brief Gets ranging result of the last ranging exchange. + + \returns Ranging result in meters. + */ + float getRangingResult(); + #ifndef RADIOLIB_GODMODE private: #endif diff --git a/src/modules/SX128x/SX128x.cpp b/src/modules/SX128x/SX128x.cpp index 2404e420..e4dae862 100644 --- a/src/modules/SX128x/SX128x.cpp +++ b/src/modules/SX128x/SX128x.cpp @@ -1182,6 +1182,16 @@ int16_t SX128x::clearIrqStatus(uint16_t clearIrqParams) { return(SPIwriteCommand(SX128X_CMD_CLEAR_IRQ_STATUS, data, 2)); } +int16_t SX128x::setRangingRole(uint8_t role) { + uint8_t data[] = { role }; + return(SPIwriteCommand(SX128X_CMD_SET_RANGING_ROLE, data, 1)); +} + +int16_t SX128x::setPacketType(uint8_t type) { + uint8_t data[] = { type }; + return(SPIwriteCommand(SX128X_CMD_SET_PACKET_TYPE, data, 1)); +} + int16_t SX128x::setHeaderType(uint8_t headerType, size_t len) { // check active modem uint8_t modem = getPacketType(); diff --git a/src/modules/SX128x/SX128x.h b/src/modules/SX128x/SX128x.h index 82e19884..f093a3c9 100644 --- a/src/modules/SX128x/SX128x.h +++ b/src/modules/SX128x/SX128x.h @@ -322,6 +322,10 @@ #define SX128X_REGULATOR_LDO 0x00 // 7 0 set regulator mode: LDO (default) #define SX128X_REGULATOR_DC_DC 0x01 // 7 0 DC-DC +//SX128X_CMD_SET_RANGING_ROLE +#define SX128X_RANGING_ROLE_MASTER 0x01 // 7 0 ranging role: master +#define SX128X_RANGING_ROLE_SLAVE 0x00 // 7 0 slave + /*! \class SX128x @@ -740,6 +744,13 @@ class SX128x: public PhysicalLayer { #ifndef RADIOLIB_GODMODE protected: #endif + Module* _mod; + + // cached LoRa parameters + float _bwKhz; + uint8_t _bw, _sf, _cr; + uint8_t _preambleLengthLoRa, _headerType, _payloadLen, _crcLoRa; + // SX128x SPI command implementations uint8_t getStatus(); int16_t writeRegister(uint16_t addr, uint8_t* data, uint8_t numBytes); @@ -760,22 +771,17 @@ class SX128x: public PhysicalLayer { int16_t setDioIrqParams(uint16_t irqMask, uint16_t dio1Mask, uint16_t dio2Mask = SX128X_IRQ_NONE, uint16_t dio3Mask = SX128X_IRQ_NONE); uint16_t getIrqStatus(); int16_t clearIrqStatus(uint16_t clearIrqParams = SX128X_IRQ_ALL); + int16_t setRangingRole(uint8_t role); + int16_t setPacketType(uint8_t type); int16_t setHeaderType(uint8_t headerType, size_t len = 0xFF); #ifndef RADIOLIB_GODMODE private: #endif - Module* _mod; - // common parameters uint8_t _pwr; - // cached LoRa parameters - float _bwKhz; - uint8_t _bw, _sf, _cr; - uint8_t _preambleLengthLoRa, _headerType, _payloadLen, _crcLoRa; - // cached GFSK parameters float _modIndexReal; uint16_t _brKbps; From abad47bdaea864d50cb92a8ac44c7065c677f900 Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 14 Apr 2020 09:33:39 +0200 Subject: [PATCH 57/57] [Hell] Added Hellschreiber support --- README.md | 13 +- .../Hellschreiber_Transmit.ino | 117 ++++++++ keywords.txt | 4 + src/RadioLib.h | 1 + src/protocols/Hellschreiber/Hellschreiber.cpp | 271 ++++++++++++++++++ src/protocols/Hellschreiber/Hellschreiber.h | 151 ++++++++++ 6 files changed, 551 insertions(+), 6 deletions(-) create mode 100644 examples/Hellschreiber/Hellschreiber_Transmit/Hellschreiber_Transmit.ino create mode 100644 src/protocols/Hellschreiber/Hellschreiber.cpp create mode 100644 src/protocols/Hellschreiber/Hellschreiber.h diff --git a/README.md b/README.md index 1884cd88..c62b393a 100644 --- a/README.md +++ b/README.md @@ -6,8 +6,8 @@ ## See the [Wiki](https://github.com/jgromes/RadioLib/wiki) for further information. See the [GitHub Pages](https://jgromes.github.io/RadioLib) for detailed and up-to-date API reference. -RadioLib allows its users to integrate all sorts of different wireless communication modules into a single consistent system. -Want to add a Bluetooth interface to your ZigBee network? Sure thing! Need to connect LoRa network to the Internet with a GSM module? RadioLib has got your back! +RadioLib allows its users to integrate all sorts of different wireless communication modules, protocols and even digital modes into a single consistent system. +Want to add a Bluetooth interface to your LoRa network? Sure thing! Do you just want to go really old-school and play around with radio teletype, slow-scan TV, or even Hellschreiber using nothing but a cheap radio module? Why not! RadioLib was originally created as a driver for [__RadioShield__](https://github.com/jgromes/RadioShield), but it can be used to control as many different wireless modules as you like - or at least as many as your Arduino can handle! @@ -27,13 +27,14 @@ RadioLib was originally created as a driver for [__RadioShield__](https://github * __SX1231__ FSK/OOK radio module * __XBee__ modules (S2B) -### Supported protocols: +### Supported protocols and digital modes: * __MQTT__ for modules: ESP8266 * __HTTP__ for modules: ESP8266 -* __RTTY__ for modules: SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, nRF24L01, RFM2x, Si443x and SX128x -* __Morse Code__ for modules: SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, nRF24L01, RFM2x, Si443x and SX128x * __AX.25__ for modules: SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, RFM2x and Si443x -* __SSTV__ for modules: SX127x, RFM9x, SX126x, RF69 and SX1231 +* [__RTTY__](https://www.sigidwiki.com/wiki/RTTY) for modules: SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, nRF24L01, RFM2x, Si443x and SX128x +* [__Morse Code__](https://www.sigidwiki.com/wiki/Morse_Code_(CW)) for modules: SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, nRF24L01, RFM2x, Si443x and SX128x +* [__SSTV__](https://www.sigidwiki.com/wiki/SSTV) for modules: SX127x, RFM9x, SX126x, RF69 and SX1231 +* [__Hellschreiber__](https://www.sigidwiki.com/wiki/Hellschreiber) for modules: SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, nRF24L01, RFM2x, Si443x and SX128x ### Supported platforms: * __Arduino AVR__ - tested with hardware on Uno, Mega and Leonardo diff --git a/examples/Hellschreiber/Hellschreiber_Transmit/Hellschreiber_Transmit.ino b/examples/Hellschreiber/Hellschreiber_Transmit/Hellschreiber_Transmit.ino new file mode 100644 index 00000000..c1d74d31 --- /dev/null +++ b/examples/Hellschreiber/Hellschreiber_Transmit/Hellschreiber_Transmit.ino @@ -0,0 +1,117 @@ +/* + RadioLib Hellschreiber Transmit Example + + This example sends Hellschreiber message using + SX1278's FSK modem. + + Other modules that can be used for Hellschreiber: + - SX127x/RFM9x + - RF69 + - SX1231 + - CC1101 + - SX126x + - nRF24 + - Si443x/RFM2x + - SX128x +*/ + +// include the library +#include + +// SX1278 has the following connections: +// NSS pin: 10 +// DIO0 pin: 2 +// RESET pin: 9 +// DIO1 pin: 3 +SX1278 fsk = new Module(10, 2, 9, 3); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1278 fsk = RadioShield.ModuleA; + +// create Hellschreiber client instance using the FSK module +HellClient hell(&fsk); + +void setup() { + Serial.begin(9600); + + // initialize SX1278 + Serial.print(F("[SX1278] Initializing ... ")); + // carrier frequency: 434.0 MHz + // bit rate: 48.0 kbps + // frequency deviation: 50.0 kHz + // Rx bandwidth: 125.0 kHz + // output power: 13 dBm + // current limit: 100 mA + // sync word: 0x2D 0x01 + int state = fsk.beginFSK(); + + // when using one of the non-LoRa modules for Morse code + // (RF69, CC1101, Si4432 etc.), use the basic begin() method + // int state = fsk.begin(); + + if(state == ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // initialize Hellschreiber client + Serial.print(F("[Hell] Initializing ... ")); + // base frequency: 434.0 MHz + // speed: 122.5 Baud ("Feld Hell") + state = hell.begin(434.0); + if(state == ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } +} + +void loop() { + Serial.print(F("[Hell] Sending Hellschreiber data ... ")); + + // HellClient supports all methods of the Serial class + // NOTE: Lower case letter will be capitalized. + + // Arduino String class + String aStr = "Arduino String"; + hell.print(aStr); + + // character array (C-String) + hell.print("C-String"); + + // string saved in flash + hell.print(F("Flash String")); + + // character + hell.print('c'); + + // byte + // formatting DEC/HEX/OCT/BIN is supported for + // any integer type (byte/int/long) + hell.print(255, HEX); + + // integer number + int i = 1000; + hell.print(i); + + // floating point number + // NOTE: println() has no effect on the transmission, + // and is only kept for compatibility reasons. + float f = -3.1415; + hell.println(f, 3); + + // custom glyph - must be a 7 byte array of rows 7 pixels long + uint8_t customGlyph[] = { 0b0000000, 0b0010100, 0b0010100, 0b0000000, 0b0100010, 0b0011100, 0b0000000 }; + hell.printGlyph(customGlyph); + + Serial.println(F("done!")); + + // wait for a second before transmitting again + delay(1000); +} diff --git a/keywords.txt b/keywords.txt index bcc233c4..21e58818 100644 --- a/keywords.txt +++ b/keywords.txt @@ -52,6 +52,7 @@ PagerClient KEYWORD1 AX25Client KEYWORD1 AX25Frame KEYWORD1 SSTVClient KEYWORD1 +HellClient KEYWORD1 # SSTV modes Scottie1 KEYWORD1 @@ -221,6 +222,9 @@ range KEYWORD2 startRanging KEYWORD2 getRangingResult KEYWORD2 +# Hellschreiber +printGlyph KEYWORD2 + ####################################### # Constants (LITERAL1) ####################################### diff --git a/src/RadioLib.h b/src/RadioLib.h index d4911d51..04ea18e7 100644 --- a/src/RadioLib.h +++ b/src/RadioLib.h @@ -86,6 +86,7 @@ // physical layer protocols #include "protocols/PhysicalLayer/PhysicalLayer.h" #include "protocols/AX25/AX25.h" +#include "protocols/Hellschreiber/Hellschreiber.h" #include "protocols/Morse/Morse.h" #include "protocols/RTTY/RTTY.h" #include "protocols/SSTV/SSTV.h" diff --git a/src/protocols/Hellschreiber/Hellschreiber.cpp b/src/protocols/Hellschreiber/Hellschreiber.cpp new file mode 100644 index 00000000..ffc30ee3 --- /dev/null +++ b/src/protocols/Hellschreiber/Hellschreiber.cpp @@ -0,0 +1,271 @@ +#include "Hellschreiber.h" + +HellClient::HellClient(PhysicalLayer* phy) { + _phy = phy; +} + +int16_t HellClient::begin(float base, float rate) { + // calculate 24-bit frequency + _base = (base * 1000000.0) / _phy->getFreqStep(); + + // calculate "pixel" duration + _pixelDuration = 1000000.0/rate; + + // set module frequency deviation to 0 + int16_t state = _phy->setFrequencyDeviation(0); + + return(state); +} + +size_t HellClient::printGlyph(uint8_t* buff) { + // print the character + for(uint8_t mask = 0x40; mask >= 0x01; mask >>= 1) { + for(int8_t i = HELL_FONT_HEIGHT - 1; i >= 0; i--) { + uint32_t start = micros(); + if(buff[i] & mask) { + _phy->transmitDirect(_base); + } else { + _phy->standby(); + } + while(micros() - start < _pixelDuration); + } + } + + // make sure transmitter is off + _phy->standby(); + + return(1); +} + +size_t HellClient::write(const char* str) { + if(str == NULL) { + return(0); + } + return(HellClient::write((uint8_t *)str, strlen(str))); +} + +size_t HellClient::write(uint8_t* buff, size_t len) { + size_t n = 0; + for(size_t i = 0; i < len; i++) { + n += HellClient::write(buff[i]); + } + return(n); +} + +size_t HellClient::write(uint8_t b) { + // convert to position in font buffer + uint8_t pos = b; + if((pos >= ' ') && (pos <= '_')) { + pos -= ' '; + } else if((pos >= 'a') && (pos <= 'z')) { + pos -= (2*' '); + } else { + return(0); + } + + // fetch character from flash + uint8_t buff[HELL_FONT_WIDTH]; + buff[0] = 0x00; + for(uint8_t i = 0; i < HELL_FONT_WIDTH - 2; i++) { + buff[i + 1] = pgm_read_byte(&HellFont[pos][i]); + } + buff[HELL_FONT_WIDTH - 1] = 0x00; + + // print the character + return(printGlyph(buff)); +} + +size_t HellClient::print(__FlashStringHelper* fstr) { + PGM_P p = reinterpret_cast(fstr); + size_t n = 0; + while(true) { + char c = pgm_read_byte(p++); + if(c == '\0') { + break; + } + n += HellClient::write(c); + } + return n; +} + +size_t HellClient::print(const String& str) { + return(HellClient::write((uint8_t*)str.c_str(), str.length())); +} + +size_t HellClient::print(const char* str) { + return(HellClient::write((uint8_t*)str, strlen(str))); +} + +size_t HellClient::print(char c) { + return(HellClient::write(c)); +} + +size_t HellClient::print(unsigned char b, int base) { + return(HellClient::print((unsigned long)b, base)); +} + +size_t HellClient::print(int n, int base) { + return(HellClient::print((long)n, base)); +} + +size_t HellClient::print(unsigned int n, int base) { + return(HellClient::print((unsigned long)n, base)); +} + +size_t HellClient::print(long n, int base) { + if(base == 0) { + return(HellClient::write(n)); + } else if(base == DEC) { + if (n < 0) { + int t = HellClient::print('-'); + n = -n; + return(HellClient::printNumber(n, DEC) + t); + } + return(HellClient::printNumber(n, DEC)); + } else { + return(HellClient::printNumber(n, base)); + } +} + +size_t HellClient::print(unsigned long n, int base) { + if(base == 0) { + return(HellClient::write(n)); + } else { + return(HellClient::printNumber(n, base)); + } +} + +size_t HellClient::print(double n, int digits) { + return(HellClient::printFloat(n, digits)); +} + +size_t HellClient::println(void) { + return(0); +} + +size_t HellClient::println(__FlashStringHelper* fstr) { + size_t n = HellClient::print(fstr); + n += HellClient::println(); + return(n); +} + +size_t HellClient::println(const String& str) { + size_t n = HellClient::print(str); + n += HellClient::println(); + return(n); +} + +size_t HellClient::println(const char* str) { + size_t n = HellClient::print(str); + n += HellClient::println(); + return(n); +} + +size_t HellClient::println(char c) { + size_t n = HellClient::print(c); + n += HellClient::println(); + return(n); +} + +size_t HellClient::println(unsigned char b, int base) { + size_t n = HellClient::print(b, base); + n += HellClient::println(); + return(n); +} + +size_t HellClient::println(int num, int base) { + size_t n = HellClient::print(num, base); + n += HellClient::println(); + return(n); +} + +size_t HellClient::println(unsigned int num, int base) { + size_t n = HellClient::print(num, base); + n += HellClient::println(); + return(n); +} + +size_t HellClient::println(long num, int base) { + size_t n = HellClient::print(num, base); + n += HellClient::println(); + return(n); +} + +size_t HellClient::println(unsigned long num, int base) { + size_t n = HellClient::print(num, base); + n += HellClient::println(); + return(n); +} + +size_t HellClient::println(double d, int digits) { + size_t n = HellClient::print(d, digits); + n += HellClient::println(); + return(n); +} + +size_t HellClient::printNumber(unsigned long n, uint8_t base) { + char buf[8 * sizeof(long) + 1]; + char *str = &buf[sizeof(buf) - 1]; + + *str = '\0'; + + if(base < 2) { + base = 10; + } + + do { + char c = n % base; + n /= base; + + *--str = c < 10 ? c + '0' : c + 'A' - 10; + } while(n); + + return(HellClient::write(str)); +} + +size_t HellClient::printFloat(double number, uint8_t digits) { + size_t n = 0; + + char code[] = {0x00, 0x00, 0x00, 0x00}; + if (isnan(number)) strcpy(code, "nan"); + if (isinf(number)) strcpy(code, "inf"); + if (number > 4294967040.0) strcpy(code, "ovf"); // constant determined empirically + if (number <-4294967040.0) strcpy(code, "ovf"); // constant determined empirically + + if(code[0] != 0x00) { + return(HellClient::write(code)); + } + + // Handle negative numbers + if (number < 0.0) { + n += HellClient::print('-'); + number = -number; + } + + // Round correctly so that print(1.999, 2) prints as "2.00" + double rounding = 0.5; + for(uint8_t i = 0; i < digits; ++i) { + rounding /= 10.0; + } + number += rounding; + + // Extract the integer part of the number and print it + unsigned long int_part = (unsigned long)number; + double remainder = number - (double)int_part; + n += HellClient::print(int_part); + + // Print the decimal point, but only if there are digits beyond + if(digits > 0) { + n += HellClient::print('.'); + } + + // Extract digits from the remainder one at a time + while(digits-- > 0) { + remainder *= 10.0; + unsigned int toPrint = (unsigned int)(remainder); + n += HellClient::print(toPrint); + remainder -= toPrint; + } + + return n; +} diff --git a/src/protocols/Hellschreiber/Hellschreiber.h b/src/protocols/Hellschreiber/Hellschreiber.h new file mode 100644 index 00000000..9b14c27e --- /dev/null +++ b/src/protocols/Hellschreiber/Hellschreiber.h @@ -0,0 +1,151 @@ +#ifndef _RADIOLIB_HELLSCHREIBER_H +#define _RADIOLIB_HELLSCHREIBER_H + +#include "../../TypeDef.h" +#include "../PhysicalLayer/PhysicalLayer.h" + +#define HELL_FONT_WIDTH 7 +#define HELL_FONT_HEIGHT 7 + +// font definition: characters are stored in rows, +// least significant byte of each character is the first row +// Hellschreiber use 7x7 characters, but this simplified font uses only 5x5 - the extra bytes aren't stored +static const uint8_t HellFont[64][HELL_FONT_WIDTH - 2] PROGMEM = { + { 0b0000000, 0b0000000, 0b0000000, 0b0000000, 0b0000000 }, // space + { 0b0001000, 0b0001000, 0b0001000, 0b0000000, 0b0001000 }, // ! + { 0b0010100, 0b0010100, 0b0000000, 0b0000000, 0b0000000 }, // " + { 0b0010100, 0b0111110, 0b0010100, 0b0111110, 0b0010100 }, // # + { 0b0111110, 0b0101000, 0b0111110, 0b0001010, 0b0111110 }, // $ + { 0b0110010, 0b0110100, 0b0001000, 0b0010110, 0b0100110 }, // % + { 0b0010000, 0b0101000, 0b0010000, 0b0101000, 0b0110100 }, // & + { 0b0001000, 0b0001000, 0b0000000, 0b0000000, 0b0000000 }, // ' + { 0b0000100, 0b0001000, 0b0001000, 0b0001000, 0b0000100 }, // ( + { 0b0010000, 0b0001000, 0b0001000, 0b0001000, 0b0010000 }, // ) + { 0b0010100, 0b0001000, 0b0010100, 0b0000000, 0b0000000 }, // * + { 0b0001000, 0b0001000, 0b0111110, 0b0001000, 0b0001000 }, // + + { 0b0001000, 0b0010000, 0b0000000, 0b0000000, 0b0000000 }, // ยด + { 0b0000000, 0b0000000, 0b0111110, 0b0000000, 0b0000000 }, // - + { 0b0000000, 0b0000000, 0b0000000, 0b0000000, 0b0001000 }, // . + { 0b0000010, 0b0000100, 0b0001000, 0b0010000, 0b0100000 }, // / + { 0b0011100, 0b0100110, 0b0101010, 0b0110010, 0b0011100 }, // 0 + { 0b0011000, 0b0001000, 0b0001000, 0b0001000, 0b0001000 }, // 1 + { 0b0011000, 0b0100100, 0b0001000, 0b0010000, 0b0111100 }, // 2 + { 0b0111100, 0b0000100, 0b0011100, 0b0000100, 0b0111100 }, // 3 + { 0b0100100, 0b0100100, 0b0111100, 0b0000100, 0b0000100 }, // 4 + { 0b0011100, 0b0100000, 0b0111100, 0b0000100, 0b0111100 }, // 5 + { 0b0111100, 0b0100000, 0b0111100, 0b0100100, 0b0111100 }, // 6 + { 0b0111100, 0b0000100, 0b0001000, 0b0010000, 0b0100000 }, // 7 + { 0b0111100, 0b0100100, 0b0011000, 0b0100100, 0b0111100 }, // 8 + { 0b0111100, 0b0100100, 0b0111100, 0b0000100, 0b0111100 }, // 9 + { 0b0000000, 0b0001000, 0b0000000, 0b0000000, 0b0001000 }, // : + { 0b0000000, 0b0001000, 0b0000000, 0b0001000, 0b0001000 }, // ; + { 0b0000100, 0b0001000, 0b0010000, 0b0001000, 0b0000100 }, // < + { 0b0000000, 0b0111110, 0b0000000, 0b0111110, 0b0000000 }, // = + { 0b0010000, 0b0001000, 0b0000100, 0b0001000, 0b0010000 }, // > + { 0b0011100, 0b0000100, 0b0001000, 0b0000000, 0b0001000 }, // ? + { 0b0011100, 0b0100010, 0b0101110, 0b0101010, 0b0001100 }, // @ + { 0b0111110, 0b0100010, 0b0111110, 0b0100010, 0b0100010 }, // A + { 0b0111100, 0b0010010, 0b0011110, 0b0010010, 0b0111100 }, // B + { 0b0011110, 0b0110000, 0b0100000, 0b0110000, 0b0011110 }, // C + { 0b0111100, 0b0100010, 0b0100010, 0b0100010, 0b0111100 }, // D + { 0b0111110, 0b0100000, 0b0111100, 0b0100000, 0b0111110 }, // E + { 0b0111110, 0b0100000, 0b0111100, 0b0100000, 0b0100000 }, // F + { 0b0111110, 0b0100000, 0b0101110, 0b0100010, 0b0111110 }, // G + { 0b0100010, 0b0100010, 0b0111110, 0b0100010, 0b0100010 }, // H + { 0b0011100, 0b0001000, 0b0001000, 0b0001000, 0b0011100 }, // I + { 0b0111100, 0b0001000, 0b0001000, 0b0101000, 0b0111000 }, // J + { 0b0100100, 0b0101000, 0b0110000, 0b0101000, 0b0100100 }, // K + { 0b0100000, 0b0100000, 0b0100000, 0b0100000, 0b0111100 }, // L + { 0b0100010, 0b0110110, 0b0101010, 0b0100010, 0b0100010 }, // M + { 0b0100010, 0b0110010, 0b0101010, 0b0100110, 0b0100010 }, // N + { 0b0011100, 0b0100010, 0b0100010, 0b0100010, 0b0011100 }, // O + { 0b0111110, 0b0100010, 0b0111110, 0b0100000, 0b0100000 }, // P + { 0b0111110, 0b0100010, 0b0100010, 0b0100110, 0b0111110 }, // Q + { 0b0111110, 0b0100010, 0b0111110, 0b0100100, 0b0100010 }, // R + { 0b0111110, 0b0100000, 0b0111110, 0b0000010, 0b0111110 }, // S + { 0b0111110, 0b0001000, 0b0001000, 0b0001000, 0b0001000 }, // T + { 0b0100010, 0b0100010, 0b0100010, 0b0100010, 0b0111110 }, // U + { 0b0100010, 0b0100010, 0b0010100, 0b0010100, 0b0001000 }, // V + { 0b0100010, 0b0100010, 0b0101010, 0b0110110, 0b0100010 }, // W + { 0b0100010, 0b0010100, 0b0001000, 0b0010100, 0b0100010 }, // X + { 0b0100010, 0b0010100, 0b0001000, 0b0001000, 0b0001000 }, // Y + { 0b0111110, 0b0000100, 0b0001000, 0b0010000, 0b0111110 }, // Z + { 0b0001100, 0b0001000, 0b0001000, 0b0001000, 0b0001100 }, // [ + { 0b0100000, 0b0010000, 0b0001000, 0b0000100, 0b0000010 }, // backslash + { 0b0011000, 0b0001000, 0b0001000, 0b0001000, 0b0011000 }, // ] + { 0b0001000, 0b0010100, 0b0000000, 0b0000000, 0b0000000 }, // ^ + { 0b0000000, 0b0000000, 0b0000000, 0b0000000, 0b0111110 } // _ +}; + +/*! + \class HellClient + + \brief Client for Hellschreiber transmissions. +*/ +class HellClient { + public: + /*! + \brief Default constructor. + + \param phy Pointer to the wireless module providing PhysicalLayer communication. + */ + HellClient(PhysicalLayer* phy); + + // basic methods + + /*! + \brief Initialization method. + + \param base Base RF frequency to be used in MHz. + + \param rate Baud rate to be used during transmission. Defaults to 122.5 ("Feld Hell") + */ + int16_t begin(float base, float rate = 122.5); + + /*! + \brief Method to "print" a buffer of pixels, this is exposed to allow users to send custom characters. + + \param buff Buffer of pixels to send, in a 7x7 pixel array. + */ + size_t printGlyph(uint8_t* buff); + + size_t write(const char* str); + size_t write(uint8_t* buff, size_t len); + size_t write(uint8_t b); + + size_t print(__FlashStringHelper*); + size_t print(const String &); + size_t print(const char[]); + size_t print(char); + size_t print(unsigned char, int = DEC); + size_t print(int, int = DEC); + size_t print(unsigned int, int = DEC); + size_t print(long, int = DEC); + size_t print(unsigned long, int = DEC); + size_t print(double, int = 2); + + size_t println(void); + size_t println(__FlashStringHelper*); + size_t println(const String &s); + size_t println(const char[]); + size_t println(char); + size_t println(unsigned char, int = DEC); + size_t println(int, int = DEC); + size_t println(unsigned int, int = DEC); + size_t println(long, int = DEC); + size_t println(unsigned long, int = DEC); + size_t println(double, int = 2); + +#ifndef RADIOLIB_GODMODE + private: +#endif + PhysicalLayer* _phy; + + uint32_t _base; + uint32_t _pixelDuration; + + size_t printNumber(unsigned long, uint8_t); + size_t printFloat(double, uint8_t); +}; + +#endif