mirror of https://github.com/arendst/Tasmota.git
Add SX127x lora support
This commit is contained in:
parent
b218f6bff1
commit
c9c1eee302
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Reference in New Issue