diff --git a/tasmota/tasmota_xdrv_driver/xdrv_73_0_lora_struct.ino b/tasmota/tasmota_xdrv_driver/xdrv_73_0_lora_struct.ino index f3922180d..f69675b74 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_73_0_lora_struct.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_73_0_lora_struct.ino @@ -9,7 +9,21 @@ #ifdef USE_SPI #ifdef USE_SPI_LORA -#define LORA_MAX_PACKET_LENGTH 252 // Max packet length allowed (defined by RadioLib driver) +#define LORA_MAX_PACKET_LENGTH 252 // Max packet length allowed (defined by RadioLib driver) + +struct { + bool (* Available)(void); + int (* Receive)(char*); + bool (* Send)(char*, uint32_t); + float rssi; + float snr; + int packet_size; + volatile bool receivedFlag; // flag to indicate that a packet was received + volatile bool enableInterrupt; // disable interrupt when it's not needed + bool sendFlag; + bool raw; + bool present; +} Lora; #endif // USE_SPI_LORA #endif // USE_SPI diff --git a/tasmota/tasmota_xdrv_driver/xdrv_73_3_lora_sx1262.ino b/tasmota/tasmota_xdrv_driver/xdrv_73_3_lora_sx1262.ino deleted file mode 100644 index 4642f9ebc..000000000 --- a/tasmota/tasmota_xdrv_driver/xdrv_73_3_lora_sx1262.ino +++ /dev/null @@ -1,106 +0,0 @@ -/* - xdrv_73_3_lora_sx1262.ino - LoRa support for Tasmota - - SPDX-FileCopyrightText: 2024 Theo Arends - - SPDX-License-Identifier: GPL-3.0-only -*/ - -#ifdef USE_SPI -#ifdef USE_SPI_LORA -#ifdef USE_LORA_SX1262 -/*********************************************************************************************\ - * Demo of LoRa using LilyGo T3S3 using SX1262 on 868MHz - * - * Tasmota currently does not support user config of GPIO33 and GPIO34 on ESP32S3 -\*********************************************************************************************/ - -#include -SX1262 LoRa = nullptr; - -struct { - // flag to indicate that a packet was received - volatile bool receivedFlag; - // disable interrupt when it's not needed - volatile bool enableInterrupt; - - bool sendFlag; -} Sx1262; - -/*********************************************************************************************/ - -// 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 LoraSetFlagSx1262(void) { - // check if the interrupt is enabled - if (!Sx1262.enableInterrupt) { return; } - // we got a packet, set the flag - Sx1262.receivedFlag = true; -} - -bool LoraAvailableSx1262(void) { - // check if the flag is set - return (Sx1262.receivedFlag); -} - -int LoraInputSx1262(char* data) { - int packet_size = 0; - - // disable the interrupt service routine while processing the data - Sx1262.enableInterrupt = false; - - // reset flag - Sx1262.receivedFlag = false; - -// String str; -// int state = LoRa.readData(str); - int state = LoRa.readData((uint8_t*)data, LORA_MAX_PACKET_LENGTH -1); - if (state == RADIOLIB_ERR_NONE) { - if (!Sx1262.sendFlag) { - // Find end of raw data being non-zero (No way to know raw data length) - packet_size = LORA_MAX_PACKET_LENGTH; - while (packet_size-- && (0 == data[packet_size])); - if (0 != data[packet_size]) { packet_size++; } - } - } - else if (state == RADIOLIB_ERR_CRC_MISMATCH) { - // packet was received, but is malformed - AddLog(LOG_LEVEL_DEBUG, PSTR("LOR: CRC error")); - } - else { - // some other error occurred - AddLog(LOG_LEVEL_DEBUG, PSTR("LOR: Receive error %d"), state); - } - - // put module back to listen mode - LoRa.startReceive(); - - Sx1262.sendFlag = false; - // we're ready to receive more packets, enable interrupt service routine - Sx1262.enableInterrupt = true; - - return packet_size; -} - -bool LoraInitSx1262(void) { -// LoRa = new Module(Pin(GPIO_LORA_CS), Pin(GPIO_LORA_DI1), Pin(GPIO_LORA_RST), Pin(GPIO_LORA_BUSY)); - LoRa = new Module(Pin(GPIO_LORA_CS), 33, Pin(GPIO_LORA_RST), 34); - if (RADIOLIB_ERR_NONE == LoRa.begin(868.0)) { - Sx1262.enableInterrupt = true; - LoRa.setDio1Action(LoraSetFlagSx1262); - if (RADIOLIB_ERR_NONE == LoRa.startReceive()) { - return true; - } - } - return false; -} - -void LoraSendSx1262(char* data, uint32_t len) { - Sx1262.sendFlag = true; - LoRa.startTransmit(data, len); -} - -#endif // USE_LORA_SX1262 -#endif // USE_SPI_LORA -#endif // USE_SPI - diff --git a/tasmota/tasmota_xdrv_driver/xdrv_73_3_lora_sx126x.ino b/tasmota/tasmota_xdrv_driver/xdrv_73_3_lora_sx126x.ino new file mode 100644 index 000000000..47824d25c --- /dev/null +++ b/tasmota/tasmota_xdrv_driver/xdrv_73_3_lora_sx126x.ino @@ -0,0 +1,84 @@ +/* + xdrv_73_3_lora_sx126x.ino - LoRa support for Tasmota + + SPDX-FileCopyrightText: 2024 Theo Arends + + SPDX-License-Identifier: GPL-3.0-only +*/ + +#ifdef USE_SPI +#ifdef USE_SPI_LORA +#ifdef USE_LORA_SX126X +/*********************************************************************************************\ + * SX126x like LilyGo T3S3 (868MHz) + * + * Tasmota currently does not support user config of GPIO33 and GPIO34 on ESP32S3 +\*********************************************************************************************/ + +#include +SX1262 LoRaRadio = nullptr; + +/*********************************************************************************************/ + +void LoraOnReceiveSx126x(void) { + if (!Lora.enableInterrupt) { return; } // check if the interrupt is enabled + Lora.receivedFlag = true; // we got a packet, set the flag +} + +bool LoraAvailableSx126x(void) { + return (Lora.receivedFlag); // check if the flag is set +} + +int LoraReceiveSx126x(char* data) { + Lora.enableInterrupt = false; // disable the interrupt service routine while processing the data + Lora.receivedFlag = false; // reset flag + + int packet_size = 0; + int state = LoRaRadio.readData((uint8_t*)data, LORA_MAX_PACKET_LENGTH -1); + if (RADIOLIB_ERR_NONE == state) { + if (!Lora.sendFlag) { + // Find end of raw data being non-zero (No way to know raw data length) + packet_size = LORA_MAX_PACKET_LENGTH; + while (packet_size-- && (0 == data[packet_size])); + if (0 != data[packet_size]) { packet_size++; } + } + } + else if (RADIOLIB_ERR_CRC_MISMATCH == state) { + // packet was received, but is malformed + AddLog(LOG_LEVEL_DEBUG, PSTR("LOR: CRC error")); + } + else { + // some other error occurred + AddLog(LOG_LEVEL_DEBUG, PSTR("LOR: Receive error %d"), state); + } + + LoRaRadio.startReceive(); // put module back to listen mode + Lora.sendFlag = false; + Lora.enableInterrupt = true; // we're ready to receive more packets, enable interrupt service routine + + Lora.rssi = LoRaRadio.getRSSI(); + Lora.snr = LoRaRadio.getSNR(); + return packet_size; +} + +bool LoraSendSx126x(char* data, uint32_t len) { + Lora.sendFlag = true; + int state = LoRaRadio.startTransmit(data, len); + return (RADIOLIB_ERR_NONE == state); +} + +bool LoraInitSx126x(void) { +// LoRa = new Module(Pin(GPIO_LORA_CS), Pin(GPIO_LORA_DI1), Pin(GPIO_LORA_RST), Pin(GPIO_LORA_BUSY)); + LoRaRadio = new Module(Pin(GPIO_LORA_CS), 33, Pin(GPIO_LORA_RST), 34); + if (RADIOLIB_ERR_NONE == LoRaRadio.begin(868.0)) { + LoRaRadio.setDio1Action(LoraOnReceiveSx126x); + if (RADIOLIB_ERR_NONE == LoRaRadio.startReceive()) { + return true; + } + } + return false; +} + +#endif // USE_LORA_SX126X +#endif // USE_SPI_LORA +#endif // USE_SPI diff --git a/tasmota/tasmota_xdrv_driver/xdrv_73_3_lora_sx127x.ino b/tasmota/tasmota_xdrv_driver/xdrv_73_3_lora_sx127x.ino new file mode 100644 index 000000000..c441b0859 --- /dev/null +++ b/tasmota/tasmota_xdrv_driver/xdrv_73_3_lora_sx127x.ino @@ -0,0 +1,74 @@ +/* + xdrv_73_3_lora_sx127x.ino - LoRa support for Tasmota + + SPDX-FileCopyrightText: 2024 Theo Arends + + SPDX-License-Identifier: GPL-3.0-only +*/ + +#ifdef USE_SPI +#ifdef USE_SPI_LORA +#ifdef USE_LORA_SX127X +/*********************************************************************************************\ + * SX127x and RFM95W +\*********************************************************************************************/ + +#include + +/*********************************************************************************************/ + +// this function is called when a complete packet is received by the module +void LoraOnReceiveSx127x(int packet_size) { + if (0 == packet_size) { return; } // if there's no packet, return + if (!Lora.enableInterrupt) { return; } // check if the interrupt is enabled + Lora.packet_size = packet_size; // we got a packet, set the flag +} + +bool LoraAvailableSx127x(void) { + return (Lora.packet_size > 0); // check if the flag is set +} + +int LoraReceiveSx127x(char* data) { + Lora.enableInterrupt = false; // disable the interrupt service routine while processing the data + + int packet_size = 0; + while (LoRa.available()) { // read packet up to LORA_MAX_PACKET_LENGTH + char sdata = LoRa.read(); + if (packet_size < LORA_MAX_PACKET_LENGTH -1) { + data[packet_size++] = sdata; + } + } + packet_size = (Lora.sendFlag) ? 0 : +1; + + Lora.sendFlag = false; + Lora.packet_size = 0; // reset flag + Lora.enableInterrupt = true; // we're ready to receive more packets, enable interrupt service routine + + Lora.rssi = LoRa.packetRssi(); + Lora.snr = LoRa.packetSnr(); + return packet_size; +} + +bool LoraSendSx127x(char* data, uint32_t len) { + Lora.sendFlag = true; + LoRa.beginPacket(); // start packet + LoRa.write((uint8_t*)data, len); // send message + LoRa.endPacket(); // finish packet and send it + LoRa.receive(); // go back into receive mode + return true; +} + +bool LoraInitSx127x(void) { + LoRa.setPins(Pin(GPIO_LORA_CS), Pin(GPIO_LORA_RST), Pin(GPIO_LORA_DI0)); + if (LoRa.begin(868E6)) { +// LoRa.setSyncWord(0x12); + LoRa.onReceive(LoraOnReceiveSx127x); + LoRa.receive(); + return true; + } + return false; +} + +#endif // USE_LORA_SX127X +#endif // USE_SPI_LORA +#endif // USE_SPI diff --git a/tasmota/tasmota_xdrv_driver/xdrv_73_9_lora.ino b/tasmota/tasmota_xdrv_driver/xdrv_73_9_lora.ino index 7d02540d4..6c1ea814c 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_73_9_lora.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_73_9_lora.ino @@ -14,18 +14,13 @@ #define XDRV_73 73 -struct { - bool raw; - bool present; -} Lora; - /*********************************************************************************************/ void LoraInput(void) { - if (!LoraAvailableSx1262()) { return; } + if (!Lora.Available()) { return; } char data[LORA_MAX_PACKET_LENGTH] = { 0 }; - int packet_size = LoraInputSx1262(data); + int packet_size = Lora.Receive(data); if (!packet_size) { return; } bool raw = Lora.raw; @@ -49,10 +44,7 @@ void LoraInput(void) { } ResponseAppend_P(PSTR("\"")); } -// float rssi = LoRa.getRSSI(); -// float snr = LoRa.getSNR(); -// ResponseAppend_P(PSTR(",\"RSSI\":%1_f,\"SNR\":%1_f}"), &rssi, &snr); - ResponseJsonEnd(); + ResponseAppend_P(PSTR(",\"RSSI\":%1_f,\"SNR\":%1_f}"), &Lora.rssi, &Lora.snr); MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, PSTR("LoRaReceived")); } @@ -66,10 +58,39 @@ void LoraInit(void) { #ifdef ESP32 SPI.begin(Pin(GPIO_SPI_CLK), Pin(GPIO_SPI_MISO), Pin(GPIO_SPI_MOSI), -1); #endif // ESP32 - if (LoraInitSx1262()) { - AddLog(LOG_LEVEL_DEBUG, PSTR("LOR: Initialized")); + + char hardware[20]; + if (false) { + } +#ifdef USE_LORA_SX127X + else if (PinUsed(GPIO_LORA_DI0)) { + // SX1276, RFM95W + if (LoraInitSx127x()) { + Lora.Available = &LoraAvailableSx127x; + Lora.Receive = &LoraReceiveSx127x; + Lora.Send = &LoraSendSx127x; + strcpy_P(hardware, PSTR("SX127x")); + Lora.present = true; + } + } +#endif // USE_LORA_SX127X +#ifdef USE_LORA_SX126X + else if (LoraInitSx126x()) { + // SX1262, LilyGoT3S3 + Lora.Available = &LoraAvailableSx126x; + Lora.Receive = &LoraReceiveSx126x; + Lora.Send = &LoraSendSx126x; + strcpy_P(hardware, PSTR("SX126x")); Lora.present = true; } +#endif // USE_LORA_SX126X + else { + strcpy_P(hardware, PSTR("Not")); + } + if (Lora.present) { + Lora.enableInterrupt = true; + } + AddLog(LOG_LEVEL_DEBUG, PSTR("LOR: %s initialized"), hardware); } } @@ -140,7 +161,7 @@ void CmndLoraSend(void) { len = 0; } if (len) { - LoraSendSx1262(data, len); + Lora.Send(data, len); } ResponseCmndDone(); } @@ -176,4 +197,3 @@ bool Xdrv73(uint32_t function) { #endif // USE_SPI_LORA #endif // USE_SPI -