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 543304a3b..eba2460f9 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_73_0_lora_struct.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_73_0_lora_struct.ino @@ -8,8 +8,44 @@ #ifdef USE_SPI #ifdef USE_SPI_LORA +/*********************************************************************************************\ + * LoRa defines and global struct +\*********************************************************************************************/ -#define LORA_MAX_PACKET_LENGTH 252 // Max packet length allowed (defined by RadioLib driver) +//#define USE_LORA_DEBUG + +#define LORA_MAX_PACKET_LENGTH 252 // Max packet length allowed (keeping room for control bytes) + +#ifndef TAS_LORA_FREQUENCY +#define TAS_LORA_FREQUENCY 868.0 // Allowed values range from 150.0 to 960.0 MHz +#endif +#ifndef TAS_LORA_BANDWIDTH +#define TAS_LORA_BANDWIDTH 125.0 // Allowed values are 7.8, 10.4, 15.6, 20.8, 31.25, 41.7, 62.5, 125.0, 250.0 and 500.0 kHz +#endif +#ifndef TAS_LORA_SPREADING_FACTOR +#define TAS_LORA_SPREADING_FACTOR 9 // Allowed values range from 5 to 12 +#endif +#ifndef TAS_LORA_CODING_RATE +#define TAS_LORA_CODING_RATE 7 // Allowed values range from 5 to 8 +#endif +#ifndef TAS_LORA_SYNC_WORD +#define TAS_LORA_SYNC_WORD 0x12 // Allowed values range from 1 to 255 +#endif +#ifndef TAS_LORA_OUTPUT_POWER +#define TAS_LORA_OUTPUT_POWER 10 // Allowed values range from 1 to 20 +#endif +#ifndef TAS_LORA_PREAMBLE_LENGTH +#define TAS_LORA_PREAMBLE_LENGTH 8 // Allowed values range from 1 to 65535 +#endif +#ifndef TAS_LORA_CURRENT_LIMIT +#define TAS_LORA_CURRENT_LIMIT 60.0 // Overcurrent Protection - OCP in mA +#endif +#ifndef TAS_LORA_HEADER +#define TAS_LORA_HEADER 0 // Explicit (0) or Implicit (1 to 4) Header +#endif +#ifndef TAS_LORA_CRC_BYTES +#define TAS_LORA_CRC_BYTES 2 // No (0) or Number (1 to 4) of CRC bytes +#endif struct { bool (* Config)(void); @@ -18,18 +54,17 @@ struct { bool (* Send)(char*, uint32_t); float rssi; float snr; - int packet_size; float frequency; // 868.0 MHz float bandwidth; // 125.0 kHz - int spreading_factor; // 9 - int coding_rate; // 7 - int sync_word; // 0x12 - int output_power; // 10 dBm - long preamble_length; // 8 symbols float current_limit; // 60.0 mA (Overcurrent Protection (OCP)) - int implicit_header; // 0 - bool crc_bytes; // 2 bytes - uint8_t gain; + uint16_t preamble_length; // 8 symbols + uint8_t sync_word; // 0x12 + uint8_t spreading_factor; // 9 + uint8_t coding_rate; // 7 + uint8_t output_power; // 10 dBm + uint8_t implicit_header; // 0 + uint8_t crc_bytes; // 2 bytes + uint8_t packet_size; // Max is 255 (LORA_MAX_PACKET_LENGTH) volatile bool receivedFlag; // flag to indicate that a packet was received volatile bool enableInterrupt; // disable interrupt when it's not needed bool sendFlag; diff --git a/tasmota/tasmota_xdrv_driver/xdrv_73_3_lora_sx126x.ino b/tasmota/tasmota_xdrv_driver/xdrv_73_3_lora_sx126x.ino index 223586eb3..63332619f 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_73_3_lora_sx126x.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_73_3_lora_sx126x.ino @@ -22,8 +22,8 @@ * - SPI_MOSI * - LoRa_CS * - LoRa_Rst - * - Lora_Busy (Tasmota currently does not support user config of GPIO34 on ESP32S3 - * - Lora_DI1 (Tasmota currently does not support user config of GPIO33 on ESP32S3 + * - Lora_Busy + * - Lora_DI1 \*********************************************************************************************/ #include @@ -46,10 +46,10 @@ int LoraReceiveSx126x(char* data) { 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++; } + packet_size = LoRaRadio.getPacketLength(); +#ifdef USE_LORA_DEBUG + AddLog(LOG_LEVEL_DEBUG, PSTR("LOR: Packet %d, Rcvd %32_H"), packet_size, data); +#endif } } else if (RADIOLIB_ERR_CRC_MISMATCH == state) { @@ -72,36 +72,45 @@ int LoraReceiveSx126x(char* data) { bool LoraSendSx126x(char* data, uint32_t len) { Lora.sendFlag = true; -// int state = LoRaRadio.startTransmit(data, len); -// return (RADIOLIB_ERR_NONE == state); +#ifdef USE_LORA_DEBUG + AddLog(LOG_LEVEL_DEBUG, PSTR("LOR: Len %d, Send %*_H"), len, len + 2, data); +#endif +/* + int state = LoRaRadio.startTransmit(data, len); + return (RADIOLIB_ERR_NONE == state); +*/ // https://learn.circuit.rocks/battery-powered-lora-sensor-node uint32_t retry_CAD = 0; uint32_t retry_send = 0; bool send_success = false; while (!send_success) { -// time_t lora_time = millis(); +#ifdef USE_LORA_DEBUG + time_t lora_time = millis(); +#endif // Check 200ms for an opportunity to send while (LoRaRadio.scanChannel() != RADIOLIB_CHANNEL_FREE) { retry_CAD++; if (retry_CAD == 20) { // LoRa channel is busy too long, give up - -// AddLog(LOG_LEVEL_DEBUG, PSTR("LOR: Channel is too busy, give up")); - +#ifdef USE_LORA_DEBUG + AddLog(LOG_LEVEL_DEBUG, PSTR("LOR: Channel is too busy, give up")); +#endif retry_send++; break; } } - -// AddLog(LOG_LEVEL_DEBUG, PSTR("LOR: CAD finished after %ldms tried %d times"), (millis() - loraTime), retryCAD); - +#ifdef USE_LORA_DEBUG + AddLog(LOG_LEVEL_DEBUG, PSTR("LOR: CAD finished after %ldms tried %d times"), (millis() - lora_time), retry_CAD); +#endif if (retry_CAD < 20) { // Channel is free, start sending -// lora_time = millis(); +#ifdef USE_LORA_DEBUG + lora_time = millis(); +#endif int status = LoRaRadio.transmit(data, len); - -// AddLog(LOG_LEVEL_DEBUG, PSTR("LOR: Transmit finished after %ldms with status %d"), (millis() - loraTime), status); - +#ifdef USE_LORA_DEBUG + AddLog(LOG_LEVEL_DEBUG, PSTR("LOR: Transmit finished after %ldms with status %d"), (millis() - lora_time), status); +#endif if (status == RADIOLIB_ERR_NONE) { send_success = true; } @@ -110,9 +119,9 @@ bool LoraSendSx126x(char* data, uint32_t len) { } } if (retry_send == 3) { - -// AddLog(LOG_LEVEL_DEBUG, PSTR("LOR: Failed 3 times to send data, giving up")); - +#ifdef USE_LORA_DEBUG + AddLog(LOG_LEVEL_DEBUG, PSTR("LOR: Failed 3 times to send data, giving up")); +#endif send_success = true; } } @@ -120,15 +129,15 @@ bool LoraSendSx126x(char* data, uint32_t len) { } bool LoraConfigSx126x(void) { - LoRaRadio.setFrequency(Lora.frequency); - LoRaRadio.setBandwidth(Lora.bandwidth); - LoRaRadio.setSpreadingFactor(Lora.spreading_factor); LoRaRadio.setCodingRate(Lora.coding_rate); LoRaRadio.setSyncWord(Lora.sync_word); - LoRaRadio.setOutputPower(Lora.output_power); LoRaRadio.setPreambleLength(Lora.preamble_length); LoRaRadio.setCurrentLimit(Lora.current_limit); LoRaRadio.setCRC(Lora.crc_bytes); + LoRaRadio.setSpreadingFactor(Lora.spreading_factor); + LoRaRadio.setBandwidth(Lora.bandwidth); + LoRaRadio.setFrequency(Lora.frequency); + LoRaRadio.setOutputPower(Lora.output_power); if (Lora.implicit_header) { LoRaRadio.implicitHeader(Lora.implicit_header); } else { @@ -138,11 +147,7 @@ bool LoraConfigSx126x(void) { } bool LoraInitSx126x(void) { - int lora_di1 = Pin(GPIO_LORA_DI1); - if (lora_di1 == -1) { lora_di1 = 33; } // Workaround support user config of GPIO33 on ESP32S3 for LilyGo T3S3 - int lora_busy = Pin(GPIO_LORA_BUSY); - if (lora_busy == -1) { lora_busy = 34; } // Workaround support user config of GPIO34 on ESP32S3 for LilyGo T3S3 - LoRaRadio = new Module(Pin(GPIO_LORA_CS), lora_di1, Pin(GPIO_LORA_RST), lora_busy); + LoRaRadio = new Module(Pin(GPIO_LORA_CS), Pin(GPIO_LORA_DI1), Pin(GPIO_LORA_RST), Pin(GPIO_LORA_BUSY)); if (RADIOLIB_ERR_NONE == LoRaRadio.begin(Lora.frequency)) { LoraConfigSx126x(); LoRaRadio.setDio1Action(LoraOnReceiveSx126x); diff --git a/tasmota/tasmota_xdrv_driver/xdrv_73_3_lora_sx127x.ino b/tasmota/tasmota_xdrv_driver/xdrv_73_3_lora_sx127x.ino index e7f8c1c60..ba1147b79 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_73_3_lora_sx127x.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_73_3_lora_sx127x.ino @@ -31,9 +31,9 @@ void LoraOnCadDoneSx127x(boolean signalDetected) { if (signalDetected) { // detect preamble - +#ifdef USE_LORA_DEBUG AddLog(LOG_LEVEL_DEBUG, PSTR("LOR: Signal detected")); - +#endif LoRa.receive(); // put the radio into continuous receive mode } else { LoRa.channelActivityDetection(); // try next activity dectection diff --git a/tasmota/tasmota_xdrv_driver/xdrv_73_9_lora.ino b/tasmota/tasmota_xdrv_driver/xdrv_73_9_lora.ino index 8b45dbbee..64d73bb79 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_73_9_lora.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_73_9_lora.ino @@ -49,6 +49,19 @@ void LoraInput(void) { MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, PSTR("LoRaReceived")); } +void LoraDefaults(void) { + Lora.frequency = TAS_LORA_FREQUENCY; + Lora.bandwidth = TAS_LORA_BANDWIDTH; + Lora.spreading_factor = TAS_LORA_SPREADING_FACTOR; + Lora.coding_rate = TAS_LORA_CODING_RATE; + Lora.sync_word = TAS_LORA_SYNC_WORD; + Lora.output_power = TAS_LORA_OUTPUT_POWER; + Lora.preamble_length = TAS_LORA_PREAMBLE_LENGTH; + Lora.current_limit = TAS_LORA_CURRENT_LIMIT; + Lora.implicit_header = TAS_LORA_HEADER; + Lora.crc_bytes = TAS_LORA_CRC_BYTES; +} + void LoraInit(void) { if ((SPI_MOSI_MISO == TasmotaGlobal.spi_enabled) && (PinUsed(GPIO_LORA_CS)) && (PinUsed(GPIO_LORA_RST))) { @@ -59,18 +72,8 @@ void LoraInit(void) { SPI.begin(Pin(GPIO_SPI_CLK), Pin(GPIO_SPI_MISO), Pin(GPIO_SPI_MOSI), -1); #endif // ESP32 - Lora.frequency = 868.0; // MHz - Lora.bandwidth = 125.0; // kHz - Lora.spreading_factor = 9; - Lora.coding_rate = 7; - Lora.sync_word = 0x12; - Lora.output_power = 10; // dBm - Lora.preamble_length = 8; // symbols - Lora.current_limit = 60.0; // mA (Overcurrent Protection (OCP)) - Lora.implicit_header = 0; // explicit - Lora.crc_bytes = 2; // bytes - Lora.enableInterrupt = true; + LoraDefaults(); char hardware[20]; if (false) { @@ -89,14 +92,16 @@ void LoraInit(void) { } #endif // USE_LORA_SX127X #ifdef USE_LORA_SX126X - else if (LoraInitSx126x()) { + else if (PinUsed(GPIO_LORA_DI1) && PinUsed(GPIO_LORA_BUSY)) { // SX1262, LilyGoT3S3 - Lora.Config = &LoraConfigSx126x; - Lora.Available = &LoraAvailableSx126x; - Lora.Receive = &LoraReceiveSx126x; - Lora.Send = &LoraSendSx126x; - strcpy_P(hardware, PSTR("SX126x")); - Lora.present = true; + if (LoraInitSx126x()) { + Lora.Config = &LoraConfigSx126x; + Lora.Available = &LoraAvailableSx126x; + Lora.Receive = &LoraReceiveSx126x; + Lora.Send = &LoraSendSx126x; + strcpy_P(hardware, PSTR("SX126x")); + Lora.present = true; + } } #endif // USE_LORA_SX126X else { @@ -121,18 +126,23 @@ void (* const LoraCommand[])(void) PROGMEM = { void CmndLoraSend(void) { // LoRaSend "Hello Tiger" - Send "Hello Tiger\n" + // LoRaSend - Set to text decoding // LoRaSend1 "Hello Tiger" - Send "Hello Tiger\n" // LoRaSend2 "Hello Tiger" - Send "Hello Tiger" // LoRaSend3 "Hello Tiger" - Send "Hello Tiger\f" - // LoRaSend4 = LoraSend2 + // LoRaSend4 - Set to binary decoding + // LoRaSend4 "Hello Tiger" - Send "Hello Tiger" and set to binary decoding // LoRaSend5 "AA004566" - Send "AA004566" as hex values // LoRaSend6 "72,101,108,108" - Send decimals as hex values // if (XdrvMailbox.index > 9) { XdrvMailbox.index -= 10; } // Allows leading spaces (not supported - See support_command/CommandHandler) if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= 6)) { Lora.raw = (XdrvMailbox.index > 3); // Global flag set even without data if (XdrvMailbox.data_len > 0) { - char data[LORA_MAX_PACKET_LENGTH]; + char data[LORA_MAX_PACKET_LENGTH] = { 0 }; uint32_t len = (XdrvMailbox.data_len < LORA_MAX_PACKET_LENGTH -1) ? XdrvMailbox.data_len : LORA_MAX_PACKET_LENGTH -2; +#ifdef USE_LORA_DEBUG + AddLog(LOG_LEVEL_DEBUG, PSTR("DBG: Len %d, Send %*_H"), len, len + 2, XdrvMailbox.data); +#endif if (1 == XdrvMailbox.index) { // "Hello Tiger\n" memcpy(data, XdrvMailbox.data, len); data[len++] = '\n'; @@ -183,23 +193,29 @@ void CmndLoraSend(void) { void CmndLoraConfig(void) { // LoRaConfig - Show all parameters + // LoRaConfig 1 - Set default parameters // LoRaConfig {"Frequency":868.0,"Bandwidth":125.0} - Enter float parameters // LoRaConfig {"SyncWord":18} - Enter decimal parameter (=0x12) if (XdrvMailbox.data_len > 0) { - JsonParser parser(XdrvMailbox.data); - JsonParserObject root = parser.getRootObject(); - if (root) { - Lora.frequency = root.getFloat(PSTR(D_JSON_FREQUENCY), Lora.frequency); - Lora.bandwidth = root.getFloat(PSTR(D_JSON_BANDWIDTH), Lora.bandwidth); - Lora.spreading_factor = root.getUInt(PSTR(D_JSON_SPREADING_FACTOR), Lora.spreading_factor); - Lora.coding_rate = root.getUInt(PSTR(D_JSON_CODINGRATE4), Lora.coding_rate); - Lora.sync_word = root.getUInt(PSTR(D_JSON_SYNCWORD), Lora.sync_word); - Lora.output_power = root.getUInt(PSTR(D_JSON_OUTPUT_POWER), Lora.output_power); - Lora.preamble_length = root.getUInt(PSTR(D_JSON_PREAMBLE_LENGTH), Lora.preamble_length); - Lora.current_limit = root.getFloat(PSTR(D_JSON_CURRENT_LIMIT), Lora.current_limit); - Lora.implicit_header = root.getUInt(PSTR(D_JSON_IMPLICIT_HEADER), Lora.implicit_header); - Lora.crc_bytes = root.getUInt(PSTR(D_JSON_CRC_BYTES), Lora.crc_bytes); + if (XdrvMailbox.payload == 1) { + LoraDefaults(); Lora.Config(); + } else { + JsonParser parser(XdrvMailbox.data); + JsonParserObject root = parser.getRootObject(); + if (root) { + Lora.frequency = root.getFloat(PSTR(D_JSON_FREQUENCY), Lora.frequency); + Lora.bandwidth = root.getFloat(PSTR(D_JSON_BANDWIDTH), Lora.bandwidth); + Lora.spreading_factor = root.getUInt(PSTR(D_JSON_SPREADING_FACTOR), Lora.spreading_factor); + Lora.coding_rate = root.getUInt(PSTR(D_JSON_CODINGRATE4), Lora.coding_rate); + Lora.sync_word = root.getUInt(PSTR(D_JSON_SYNCWORD), Lora.sync_word); + Lora.output_power = root.getUInt(PSTR(D_JSON_OUTPUT_POWER), Lora.output_power); + Lora.preamble_length = root.getUInt(PSTR(D_JSON_PREAMBLE_LENGTH), Lora.preamble_length); + Lora.current_limit = root.getFloat(PSTR(D_JSON_CURRENT_LIMIT), Lora.current_limit); + Lora.implicit_header = root.getUInt(PSTR(D_JSON_IMPLICIT_HEADER), Lora.implicit_header); + Lora.crc_bytes = root.getUInt(PSTR(D_JSON_CRC_BYTES), Lora.crc_bytes); + Lora.Config(); + } } } ResponseCmnd(); // {"LoRaConfig":