From b218f6bff1a57f55deb5ed343b2c12f869315573 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sun, 25 Feb 2024 14:29:56 +0100 Subject: [PATCH] Allow lora on ESP8266 --- .../xdrv_73_0_lora_struct.ino | 15 ++ .../xdrv_73_3_lora_sx1262.ino | 106 +++++++++++++ ...v_80_esp32_lora.ino => xdrv_73_9_lora.ino} | 146 +++++------------- 3 files changed, 163 insertions(+), 104 deletions(-) create mode 100644 tasmota/tasmota_xdrv_driver/xdrv_73_0_lora_struct.ino create mode 100644 tasmota/tasmota_xdrv_driver/xdrv_73_3_lora_sx1262.ino rename tasmota/tasmota_xdrv_driver/{xdrv_80_esp32_lora.ino => xdrv_73_9_lora.ino} (53%) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_73_0_lora_struct.ino b/tasmota/tasmota_xdrv_driver/xdrv_73_0_lora_struct.ino new file mode 100644 index 000000000..f3922180d --- /dev/null +++ b/tasmota/tasmota_xdrv_driver/xdrv_73_0_lora_struct.ino @@ -0,0 +1,15 @@ +/* + xdrv_73_0_lora_struct.ino - LoRa support for Tasmota + + SPDX-FileCopyrightText: 2024 Theo Arends + + SPDX-License-Identifier: GPL-3.0-only +*/ + +#ifdef USE_SPI +#ifdef USE_SPI_LORA + +#define LORA_MAX_PACKET_LENGTH 252 // Max packet length allowed (defined by RadioLib driver) + +#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 new file mode 100644 index 000000000..4642f9ebc --- /dev/null +++ b/tasmota/tasmota_xdrv_driver/xdrv_73_3_lora_sx1262.ino @@ -0,0 +1,106 @@ +/* + 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_80_esp32_lora.ino b/tasmota/tasmota_xdrv_driver/xdrv_73_9_lora.ino similarity index 53% rename from tasmota/tasmota_xdrv_driver/xdrv_80_esp32_lora.ino rename to tasmota/tasmota_xdrv_driver/xdrv_73_9_lora.ino index 2bf3a2541..7d02540d4 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_80_esp32_lora.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_73_9_lora.ino @@ -1,133 +1,74 @@ /* - xdrv_80_esp32_lora.ino - LoRa support for Tasmota + xdrv_73_9_lora.ino - LoRa support for Tasmota SPDX-FileCopyrightText: 2024 Theo Arends SPDX-License-Identifier: GPL-3.0-only */ -#ifdef ESP32 #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 + * LoRa \*********************************************************************************************/ -#define XDRV_80 80 - -#define LORA_MAX_PACKET_LENGTH 252 // Max packet length allowed (defined by RadioLib driver) - -#include -SX1262 LoRa = nullptr; +#define XDRV_73 73 struct { - // flag to indicate that a packet was received - volatile bool receivedFlag; - // disable interrupt when it's not needed - volatile bool enableInterrupt; - - bool sendFlag; bool raw; bool present; } Lora; /*********************************************************************************************/ -// 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 LoraSetFlag(void) { - // check if the interrupt is enabled - if (!Lora.enableInterrupt) { return; } - // we got a packet, set the flag - Lora.receivedFlag = true; -} - -/*********************************************************************************************/ - void LoraInput(void) { - // check if the flag is set - if (!Lora.receivedFlag) { return; } + if (!LoraAvailableSx1262()) { return; } - // disable the interrupt service routine while processing the data - Lora.enableInterrupt = false; - - // reset flag - Lora.receivedFlag = false; - -// String str; -// int state = LoRa.readData(str); char data[LORA_MAX_PACKET_LENGTH] = { 0 }; - int state = LoRa.readData((uint8_t*)data, LORA_MAX_PACKET_LENGTH -1); - if (state == RADIOLIB_ERR_NONE) { - if (!Lora.sendFlag) { - // Find end of raw data being non-zero (No way to know raw data length) - uint32_t len = LORA_MAX_PACKET_LENGTH; - while (len-- && (0 == data[len])); - if (len) { - len++; - bool raw = Lora.raw; - // Set raw mode if zeroes within data - for (uint32_t i = 0; i < len; i++) { - if (0 == data[i]) { - raw = true; - break; - } - } - bool assume_json = (!raw && (data[0] == '{')); - Response_P(PSTR("{\"LoRaReceived\":")); - if (assume_json) { - ResponseAppend_P(data); - } else { - ResponseAppend_P(PSTR("\"")); - if (raw) { - ResponseAppend_P(PSTR("%*_H"), len, data); - } else { - ResponseAppend_P(EscapeJSONString(data).c_str()); - } - ResponseAppend_P(PSTR("\"")); - } - float rssi = LoRa.getRSSI(); - float snr = LoRa.getSNR(); - ResponseAppend_P(PSTR(",\"RSSI\":%1_f,\"SNR\":%1_f}"), &rssi, &snr); - MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, PSTR("LoRaReceived")); - } + int packet_size = LoraInputSx1262(data); + if (!packet_size) { return; } + + bool raw = Lora.raw; + // Set raw mode if zeroes within data + for (uint32_t i = 0; i < packet_size; i++) { + if (0 == data[i]) { + raw = true; + break; } } - 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); + bool assume_json = (!raw && (data[0] == '{')); + Response_P(PSTR("{\"LoRaReceived\":")); + if (assume_json) { + ResponseAppend_P(data); + } else { + ResponseAppend_P(PSTR("\"")); + if (raw) { + ResponseAppend_P(PSTR("%*_H"), packet_size, data); + } else { + ResponseAppend_P(EscapeJSONString(data).c_str()); + } + ResponseAppend_P(PSTR("\"")); } +// float rssi = LoRa.getRSSI(); +// float snr = LoRa.getSNR(); +// ResponseAppend_P(PSTR(",\"RSSI\":%1_f,\"SNR\":%1_f}"), &rssi, &snr); + ResponseJsonEnd(); - // put module back to listen mode - LoRa.startReceive(); - - Lora.sendFlag = false; - // we're ready to receive more packets, - // enable interrupt service routine - Lora.enableInterrupt = true; + MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, PSTR("LoRaReceived")); } void LoraInit(void) { if ((SPI_MOSI_MISO == TasmotaGlobal.spi_enabled) && (PinUsed(GPIO_LORA_CS)) && (PinUsed(GPIO_LORA_RST))) { +#ifdef ESP8266 + SPI.begin(); +#endif // ESP8266 +#ifdef ESP32 SPI.begin(Pin(GPIO_SPI_CLK), Pin(GPIO_SPI_MISO), Pin(GPIO_SPI_MOSI), -1); - -// 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)) { - Lora.enableInterrupt = true; - LoRa.setDio1Action(LoraSetFlag); - if (RADIOLIB_ERR_NONE == LoRa.startReceive()) { - AddLog(LOG_LEVEL_DEBUG, PSTR("LOR: Initialized")); - Lora.present = true; - } +#endif // ESP32 + if (LoraInitSx1262()) { + AddLog(LOG_LEVEL_DEBUG, PSTR("LOR: Initialized")); + Lora.present = true; } } } @@ -156,11 +97,11 @@ void CmndLoraSend(void) { if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= 6)) { Lora.raw = (XdrvMailbox.index > 3); // Global flag set even without data if (XdrvMailbox.data_len > 0) { - uint8_t data[LORA_MAX_PACKET_LENGTH]; + char data[LORA_MAX_PACKET_LENGTH]; uint32_t len = (XdrvMailbox.data_len < LORA_MAX_PACKET_LENGTH -1) ? XdrvMailbox.data_len : LORA_MAX_PACKET_LENGTH -2; if (1 == XdrvMailbox.index) { // "Hello Tiger\n" memcpy(data, XdrvMailbox.data, len); - data[len++] = (uint8_t)'\n'; + data[len++] = '\n'; } else if ((2 == XdrvMailbox.index) || (4 == XdrvMailbox.index)) { // "Hello Tiger" or "A0" memcpy(data, XdrvMailbox.data, len); @@ -199,8 +140,7 @@ void CmndLoraSend(void) { len = 0; } if (len) { - Lora.sendFlag = true; - LoRa.startTransmit(data, len); + LoraSendSx1262(data, len); } ResponseCmndDone(); } @@ -211,7 +151,7 @@ void CmndLoraSend(void) { * Interface \*********************************************************************************************/ -bool Xdrv80(uint32_t function) { +bool Xdrv73(uint32_t function) { bool result = false; if (FUNC_INIT == function) { @@ -234,8 +174,6 @@ bool Xdrv80(uint32_t function) { return result; } -#endif // USE_LORA_SX1262 #endif // USE_SPI_LORA #endif // USE_SPI -#endif // ESP32