From a1d20a97ef746049543b6756f2af11b64e3fcc52 Mon Sep 17 00:00:00 2001 From: Robert Ekl Date: Mon, 23 Mar 2026 09:59:24 -0500 Subject: [PATCH] Add error-aware SX126x receive hook --- src/helpers/radiolib/CustomLLCC68.h | 7 ++- src/helpers/radiolib/CustomLLCC68Wrapper.h | 10 ++++ src/helpers/radiolib/CustomSTM32WLx.h | 11 +++- src/helpers/radiolib/CustomSTM32WLxWrapper.h | 10 ++++ src/helpers/radiolib/CustomSX1262.h | 7 ++- src/helpers/radiolib/CustomSX1262Wrapper.h | 10 ++++ src/helpers/radiolib/CustomSX1268.h | 7 ++- src/helpers/radiolib/CustomSX1268Wrapper.h | 10 ++++ src/helpers/radiolib/RadioLibWrappers.cpp | 41 +++++++++---- src/helpers/radiolib/RadioLibWrappers.h | 4 +- src/helpers/radiolib/SX126xReadHelper.h | 62 ++++++++++++++++++++ 11 files changed, 162 insertions(+), 17 deletions(-) create mode 100644 src/helpers/radiolib/SX126xReadHelper.h diff --git a/src/helpers/radiolib/CustomLLCC68.h b/src/helpers/radiolib/CustomLLCC68.h index c239cc412a..398c02c243 100644 --- a/src/helpers/radiolib/CustomLLCC68.h +++ b/src/helpers/radiolib/CustomLLCC68.h @@ -1,6 +1,7 @@ #pragma once #include +#include "SX126xReadHelper.h" #define SX126X_IRQ_HEADER_VALID 0b0000010000 // 4 4 valid LoRa header received #define SX126X_IRQ_PREAMBLE_DETECTED 0x04 @@ -9,6 +10,10 @@ class CustomLLCC68 : public LLCC68 { public: CustomLLCC68(Module *mod) : LLCC68(mod) { } + int tryReadData(uint8_t* data, size_t max_len, size_t* out_len = nullptr) { + return sx126xTryReadData(*this, data, max_len, out_len); + } + #ifdef RP2040_PLATFORM bool std_init(SPIClassRP2040* spi = NULL) #else @@ -84,4 +89,4 @@ class CustomLLCC68 : public LLCC68 { bool detected = (irq & SX126X_IRQ_HEADER_VALID) || (irq & SX126X_IRQ_PREAMBLE_DETECTED); return detected; } -}; \ No newline at end of file +}; diff --git a/src/helpers/radiolib/CustomLLCC68Wrapper.h b/src/helpers/radiolib/CustomLLCC68Wrapper.h index f7dd7a9f16..9bafb45513 100644 --- a/src/helpers/radiolib/CustomLLCC68Wrapper.h +++ b/src/helpers/radiolib/CustomLLCC68Wrapper.h @@ -6,6 +6,16 @@ class CustomLLCC68Wrapper : public RadioLibWrapper { public: CustomLLCC68Wrapper(CustomLLCC68& radio, mesh::MainBoard& board) : RadioLibWrapper(radio, board) { } +protected: + int tryReadRawWithMeta(uint8_t* bytes, int sz, int* out_len) override { + size_t len = 0; + int err = ((CustomLLCC68*)_radio)->tryReadData(bytes, (size_t)sz, &len); + if (out_len) { + *out_len = (err == RADIOLIB_ERR_NONE) ? (int)len : 0; + } + return err; + } +public: bool isReceivingPacket() override { return ((CustomLLCC68 *)_radio)->isReceiving(); } diff --git a/src/helpers/radiolib/CustomSTM32WLx.h b/src/helpers/radiolib/CustomSTM32WLx.h index cbdd5c8c4e..b1ea4042fa 100644 --- a/src/helpers/radiolib/CustomSTM32WLx.h +++ b/src/helpers/radiolib/CustomSTM32WLx.h @@ -1,6 +1,7 @@ #pragma once #include +#include "SX126xReadHelper.h" #define SX126X_IRQ_HEADER_VALID 0b0000010000 // 4 4 valid LoRa header received #define SX126X_IRQ_PREAMBLE_DETECTED 0x04 @@ -9,9 +10,17 @@ class CustomSTM32WLx : public STM32WLx { public: CustomSTM32WLx(STM32WLx_Module *mod) : STM32WLx(mod) { } + int tryReadData(uint8_t* data, size_t max_len, size_t* out_len = nullptr) { + return sx126xTryReadData(*this, data, max_len, out_len); + } + bool isReceiving() { uint16_t irq = getIrqFlags(); bool detected = (irq & SX126X_IRQ_HEADER_VALID) || (irq & SX126X_IRQ_PREAMBLE_DETECTED); return detected; } -}; \ No newline at end of file +}; + +inline int sx126xClearAllIrqs(CustomSTM32WLx& radio) { + return radio.clearIrqStatus(RADIOLIB_SX126X_IRQ_ALL); +} diff --git a/src/helpers/radiolib/CustomSTM32WLxWrapper.h b/src/helpers/radiolib/CustomSTM32WLxWrapper.h index 9e2d0441d9..784e7eb6c7 100644 --- a/src/helpers/radiolib/CustomSTM32WLxWrapper.h +++ b/src/helpers/radiolib/CustomSTM32WLxWrapper.h @@ -7,6 +7,16 @@ class CustomSTM32WLxWrapper : public RadioLibWrapper { public: CustomSTM32WLxWrapper(CustomSTM32WLx& radio, mesh::MainBoard& board) : RadioLibWrapper(radio, board) { } +protected: + int tryReadRawWithMeta(uint8_t* bytes, int sz, int* out_len) override { + size_t len = 0; + int err = ((CustomSTM32WLx*)_radio)->tryReadData(bytes, (size_t)sz, &len); + if (out_len) { + *out_len = (err == RADIOLIB_ERR_NONE) ? (int)len : 0; + } + return err; + } +public: bool isReceivingPacket() override { return ((CustomSTM32WLx *)_radio)->isReceiving(); } diff --git a/src/helpers/radiolib/CustomSX1262.h b/src/helpers/radiolib/CustomSX1262.h index be6812c6f3..8bef57d660 100644 --- a/src/helpers/radiolib/CustomSX1262.h +++ b/src/helpers/radiolib/CustomSX1262.h @@ -1,6 +1,7 @@ #pragma once #include +#include "SX126xReadHelper.h" #define SX126X_IRQ_HEADER_VALID 0b0000010000 // 4 4 valid LoRa header received #define SX126X_IRQ_PREAMBLE_DETECTED 0x04 @@ -9,6 +10,10 @@ class CustomSX1262 : public SX1262 { public: CustomSX1262(Module *mod) : SX1262(mod) { } + int tryReadData(uint8_t* data, size_t max_len, size_t* out_len = nullptr) { + return sx126xTryReadData(*this, data, max_len, out_len); + } + #ifdef RP2040_PLATFORM bool std_init(SPIClassRP2040* spi = NULL) #else @@ -92,4 +97,4 @@ class CustomSX1262 : public SX1262 { bool detected = (irq & SX126X_IRQ_HEADER_VALID) || (irq & SX126X_IRQ_PREAMBLE_DETECTED); return detected; } -}; \ No newline at end of file +}; diff --git a/src/helpers/radiolib/CustomSX1262Wrapper.h b/src/helpers/radiolib/CustomSX1262Wrapper.h index 1afee5e8bd..5067f2933e 100644 --- a/src/helpers/radiolib/CustomSX1262Wrapper.h +++ b/src/helpers/radiolib/CustomSX1262Wrapper.h @@ -6,6 +6,16 @@ class CustomSX1262Wrapper : public RadioLibWrapper { public: CustomSX1262Wrapper(CustomSX1262& radio, mesh::MainBoard& board) : RadioLibWrapper(radio, board) { } +protected: + int tryReadRawWithMeta(uint8_t* bytes, int sz, int* out_len) override { + size_t len = 0; + int err = ((CustomSX1262*)_radio)->tryReadData(bytes, (size_t)sz, &len); + if (out_len) { + *out_len = (err == RADIOLIB_ERR_NONE) ? (int)len : 0; + } + return err; + } +public: bool isReceivingPacket() override { return ((CustomSX1262 *)_radio)->isReceiving(); } diff --git a/src/helpers/radiolib/CustomSX1268.h b/src/helpers/radiolib/CustomSX1268.h index 1e2e262049..0f9f5dd33b 100644 --- a/src/helpers/radiolib/CustomSX1268.h +++ b/src/helpers/radiolib/CustomSX1268.h @@ -1,6 +1,7 @@ #pragma once #include +#include "SX126xReadHelper.h" #define SX126X_IRQ_HEADER_VALID 0b0000010000 // 4 4 valid LoRa header received #define SX126X_IRQ_PREAMBLE_DETECTED 0x04 @@ -9,6 +10,10 @@ class CustomSX1268 : public SX1268 { public: CustomSX1268(Module *mod) : SX1268(mod) { } + int tryReadData(uint8_t* data, size_t max_len, size_t* out_len = nullptr) { + return sx126xTryReadData(*this, data, max_len, out_len); + } + #ifdef RP2040_PLATFORM bool std_init(SPIClassRP2040* spi = NULL) #else @@ -84,4 +89,4 @@ class CustomSX1268 : public SX1268 { bool detected = (irq & SX126X_IRQ_HEADER_VALID) || (irq & SX126X_IRQ_PREAMBLE_DETECTED); return detected; } -}; \ No newline at end of file +}; diff --git a/src/helpers/radiolib/CustomSX1268Wrapper.h b/src/helpers/radiolib/CustomSX1268Wrapper.h index 5d7106b405..d243869c5a 100644 --- a/src/helpers/radiolib/CustomSX1268Wrapper.h +++ b/src/helpers/radiolib/CustomSX1268Wrapper.h @@ -6,6 +6,16 @@ class CustomSX1268Wrapper : public RadioLibWrapper { public: CustomSX1268Wrapper(CustomSX1268& radio, mesh::MainBoard& board) : RadioLibWrapper(radio, board) { } +protected: + int tryReadRawWithMeta(uint8_t* bytes, int sz, int* out_len) override { + size_t len = 0; + int err = ((CustomSX1268*)_radio)->tryReadData(bytes, (size_t)sz, &len); + if (out_len) { + *out_len = (err == RADIOLIB_ERR_NONE) ? (int)len : 0; + } + return err; + } +public: bool isReceivingPacket() override { return ((CustomSX1268 *)_radio)->isReceiving(); } diff --git a/src/helpers/radiolib/RadioLibWrappers.cpp b/src/helpers/radiolib/RadioLibWrappers.cpp index cf3e1266b9..fb51be467f 100644 --- a/src/helpers/radiolib/RadioLibWrappers.cpp +++ b/src/helpers/radiolib/RadioLibWrappers.cpp @@ -95,21 +95,38 @@ bool RadioLibWrapper::isInRecvMode() const { return (state & ~STATE_INT_READY) == STATE_RX; } +int RadioLibWrapper::tryReadRawWithMeta(uint8_t* bytes, int sz, int* out_len) { + int len = _radio->getPacketLength(); + if (len <= 0) { + if (out_len) { *out_len = 0; } + return RADIOLIB_ERR_NONE; + } + + if (len > sz) { + len = sz; + } + + int err = _radio->readData(bytes, len); + if (err != RADIOLIB_ERR_NONE) { + if (out_len) { *out_len = 0; } + return err; + } + + if (out_len) { *out_len = len; } + return RADIOLIB_ERR_NONE; +} + int RadioLibWrapper::recvRaw(uint8_t* bytes, int sz) { int len = 0; if (state & STATE_INT_READY) { - len = _radio->getPacketLength(); - if (len > 0) { - if (len > sz) { len = sz; } - int err = _radio->readData(bytes, len); - if (err != RADIOLIB_ERR_NONE) { - MESH_DEBUG_PRINTLN("RadioLibWrapper: error: readData(%d)", err); - len = 0; - n_recv_errors++; - } else { - // Serial.print(" readData() -> "); Serial.println(len); - n_recv++; - } + int err = tryReadRawWithMeta(bytes, sz, &len); + if (err != RADIOLIB_ERR_NONE) { + MESH_DEBUG_PRINTLN("RadioLibWrapper: error: readData(%d)", err); + len = 0; + n_recv_errors++; + } else if (len > 0) { + // Serial.print(" readData() -> "); Serial.println(len); + n_recv++; } state = STATE_IDLE; // need another startReceive() } diff --git a/src/helpers/radiolib/RadioLibWrappers.h b/src/helpers/radiolib/RadioLibWrappers.h index 9ac1bbaeb3..40e66d1dd8 100644 --- a/src/helpers/radiolib/RadioLibWrappers.h +++ b/src/helpers/radiolib/RadioLibWrappers.h @@ -15,10 +15,12 @@ class RadioLibWrapper : public mesh::Radio { void idle(); void startRecv(); float packetScoreInt(float snr, int sf, int packet_len); + virtual int tryReadRawWithMeta(uint8_t* bytes, int sz, int* out_len); virtual bool isReceivingPacket() =0; public: - RadioLibWrapper(PhysicalLayer& radio, mesh::MainBoard& board) : _radio(&radio), _board(&board) { n_recv = n_sent = 0; } + RadioLibWrapper(PhysicalLayer& radio, mesh::MainBoard& board) + : _radio(&radio), _board(&board), n_recv(0), n_sent(0), n_recv_errors(0) {} void begin() override; virtual void powerOff() { _radio->sleep(); } diff --git a/src/helpers/radiolib/SX126xReadHelper.h b/src/helpers/radiolib/SX126xReadHelper.h new file mode 100644 index 0000000000..7d3a733f99 --- /dev/null +++ b/src/helpers/radiolib/SX126xReadHelper.h @@ -0,0 +1,62 @@ +#pragma once + +#include + +#define SX126X_HELPER_IRQ_HEADER_VALID 0b0000010000 + +template +inline int sx126xClearAllIrqs(RadioT& radio) { + return radio.clearIrqStatus(); +} + +template +inline int sx126xTryReadData(RadioT& radio, uint8_t* data, size_t max_len, size_t* out_len = nullptr) { + int16_t state = radio.mod->SPIcheckStream(); + uint16_t irq = radio.getIrqFlags(); + if ((state == RADIOLIB_ERR_SPI_CMD_TIMEOUT) && (irq & RADIOLIB_SX126X_IRQ_TIMEOUT)) { + return RADIOLIB_ERR_RX_TIMEOUT; + } + if (state != RADIOLIB_ERR_NONE) { + return state; + } + + int16_t crcState = RADIOLIB_ERR_NONE; + if ((irq & RADIOLIB_SX126X_IRQ_CRC_ERR) || ((irq & RADIOLIB_SX126X_IRQ_HEADER_ERR) && !(irq & SX126X_HELPER_IRQ_HEADER_VALID))) { + crcState = RADIOLIB_ERR_CRC_MISMATCH; + } + + uint8_t offset = 0; + size_t length = radio.implicitLen; + if (radio.headerType != RADIOLIB_SX126X_LORA_HEADER_IMPLICIT) { + uint8_t rxBufStatus[2] = {0, 0}; + state = radio.mod->SPIreadStream(RADIOLIB_SX126X_CMD_GET_RX_BUFFER_STATUS, rxBufStatus, 2); + if (state != RADIOLIB_ERR_NONE) { + return state; + } + + offset = rxBufStatus[1]; + length = (size_t)rxBufStatus[0]; + } + + if ((max_len != 0) && (max_len < length)) { + length = max_len; + } + + state = radio.readBuffer(data, length, offset); + if (state != RADIOLIB_ERR_NONE) { + return state; + } + + state = sx126xClearAllIrqs(radio); + if (crcState != RADIOLIB_ERR_NONE) { + return crcState; + } + if (state != RADIOLIB_ERR_NONE) { + return state; + } + + if (out_len) { + *out_len = length; + } + return RADIOLIB_ERR_NONE; +}