Add SX127x lora support

This commit is contained in:
Theo Arends 2024-02-25 17:03:46 +01:00
parent b218f6bff1
commit c9c1eee302
5 changed files with 208 additions and 122 deletions

View File

@ -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

View File

@ -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 <RadioLib.h>
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

View File

@ -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 <RadioLib.h>
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

View File

@ -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 <LoRa.h>
/*********************************************************************************************/
// 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

View File

@ -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