From 92d09c84ef6329031baef20d65a577ed75fb3cd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaros=C5=82aw=20Doma=C5=84ski?= Date: Wed, 8 Jul 2026 23:49:35 +0200 Subject: [PATCH] Fixed RX power saving RSSI sampling during listen windows --- src/helpers/radiolib/CustomLR1110.h | 13 ++++++++----- src/helpers/radiolib/CustomLR1110Wrapper.h | 3 +++ src/helpers/radiolib/CustomSX1262.h | 13 ++++++++----- src/helpers/radiolib/CustomSX1262Wrapper.h | 5 ++++- src/helpers/radiolib/RadioLibWrappers.cpp | 19 +++++++++---------- src/helpers/radiolib/RadioLibWrappers.h | 3 +++ 6 files changed, 35 insertions(+), 21 deletions(-) diff --git a/src/helpers/radiolib/CustomLR1110.h b/src/helpers/radiolib/CustomLR1110.h index 95e51ba4..e4f9d06f 100644 --- a/src/helpers/radiolib/CustomLR1110.h +++ b/src/helpers/radiolib/CustomLR1110.h @@ -65,12 +65,15 @@ class CustomLR1110 : public LR1110 { bool getRxBoostedGainMode() const { return _rx_boosted; } - bool isReceiving() { - // BUSY high means the chip is asleep (RX duty-cycle sleep window) or mid - // command, so it cannot be mid-receive - and the SPI read below would - // stall until the chip's next listen window. + // BUSY high means the chip is asleep (RX duty-cycle sleep window) or mid + // command; any SPI access would stall until the chip's next listen window. + bool isChipBusy() { uint32_t busy = this->mod->getGpio(); - if (busy != RADIOLIB_NC && this->mod->hal->digitalRead(busy)) return false; + return busy != RADIOLIB_NC && this->mod->hal->digitalRead(busy); + } + + bool isReceiving() { + if (isChipBusy()) return false; // asleep, cannot be mid-receive uint16_t irq = getIrqStatus(); bool detected = ((irq & RADIOLIB_LR11X0_IRQ_SYNC_WORD_HEADER_VALID) || (irq & RADIOLIB_LR11X0_IRQ_PREAMBLE_DETECTED)); diff --git a/src/helpers/radiolib/CustomLR1110Wrapper.h b/src/helpers/radiolib/CustomLR1110Wrapper.h index f5e7dbff..56aec8be 100644 --- a/src/helpers/radiolib/CustomLR1110Wrapper.h +++ b/src/helpers/radiolib/CustomLR1110Wrapper.h @@ -20,6 +20,9 @@ public: bool isReceivingPacket() override { return ((CustomLR1110 *)_radio)->isReceiving(); } + bool isChipBusy() override { + return ((CustomLR1110 *)_radio)->isChipBusy(); + } float getCurrentRSSI() override { float rssi = -110; ((CustomLR1110 *)_radio)->getRssiInst(&rssi); diff --git a/src/helpers/radiolib/CustomSX1262.h b/src/helpers/radiolib/CustomSX1262.h index 87b6b548..f24604e8 100644 --- a/src/helpers/radiolib/CustomSX1262.h +++ b/src/helpers/radiolib/CustomSX1262.h @@ -86,12 +86,15 @@ class CustomSX1262 : public SX1262 { return true; // success } - bool isReceiving() { - // BUSY high means the chip is asleep (RX duty-cycle sleep window) or mid - // command, so it cannot be mid-receive - and the SPI read below would - // stall until the chip's next listen window. + // BUSY high means the chip is asleep (RX duty-cycle sleep window) or mid + // command; any SPI access would stall until the chip's next listen window. + bool isChipBusy() { uint32_t busy = this->mod->getGpio(); - if (busy != RADIOLIB_NC && this->mod->hal->digitalRead(busy)) return false; + return busy != RADIOLIB_NC && this->mod->hal->digitalRead(busy); + } + + bool isReceiving() { + if (isChipBusy()) return false; // asleep, cannot be mid-receive uint16_t irq = getIrqFlags(); bool detected = (irq & SX126X_IRQ_HEADER_VALID) || (irq & SX126X_IRQ_PREAMBLE_DETECTED); diff --git a/src/helpers/radiolib/CustomSX1262Wrapper.h b/src/helpers/radiolib/CustomSX1262Wrapper.h index 6e880c0e..585ba4a9 100644 --- a/src/helpers/radiolib/CustomSX1262Wrapper.h +++ b/src/helpers/radiolib/CustomSX1262Wrapper.h @@ -20,9 +20,12 @@ public: updatePreamble(sf); } - bool isReceivingPacket() override { + bool isReceivingPacket() override { return ((CustomSX1262 *)_radio)->isReceiving(); } + bool isChipBusy() override { + return ((CustomSX1262 *)_radio)->isChipBusy(); + } float getCurrentRSSI() override { return ((CustomSX1262 *)_radio)->getRSSI(false); } diff --git a/src/helpers/radiolib/RadioLibWrappers.cpp b/src/helpers/radiolib/RadioLibWrappers.cpp index 66001102..f93bf350 100644 --- a/src/helpers/radiolib/RadioLibWrappers.cpp +++ b/src/helpers/radiolib/RadioLibWrappers.cpp @@ -85,12 +85,11 @@ void RadioLibWrapper::resetAGC() { } void RadioLibWrapper::loop() { - // In RX duty-cycle (powersaving) mode the radio auto-sleeps between listen - // windows, so getCurrentRSSI() would read a sleeping frontend and corrupt the - // noise floor. Skip adaptive sampling; note this also degrades interference - // detection (isChannelActive) while powersaving is enabled. - if (!_rx_ps_enabled && state == STATE_RX && _num_floor_samples < NUM_NOISE_FLOOR_SAMPLES) { - if (!isReceivingPacket()) { + if (state == STATE_RX && _num_floor_samples < NUM_NOISE_FLOOR_SAMPLES) { + // In RX duty-cycle (powersaving) mode only sample while the chip is in a + // listen window: during the sleep window the frontend is off, so the RSSI + // is meaningless and the SPI read would stall until the next window. + if (!(_rx_ps_armed && isChipBusy()) && !isReceivingPacket()) { int rssi = getCurrentRSSI(); if (rssi < _noise_floor + SAMPLING_THRESHOLD) { // only consider samples below current floor + sampling THRESHOLD _num_floor_samples++; @@ -231,10 +230,10 @@ int16_t RadioLibWrapper::performChannelScan() { bool RadioLibWrapper::isChannelActive() { // int.thresh: RSSI-based interference detection (relative to noise floor). - // Skipped in RX duty-cycle mode: the frontend sleeps part of the time, so an - // instantaneous RSSI is meaningless and the SPI read would block until the - // chip's next listen window. - if (!_rx_ps_enabled && _threshold != 0 && getCurrentRSSI() > _noise_floor + _threshold) return true; + // In RX duty-cycle mode only checked while the chip is in a listen window + // (during the sleep window the frontend is off and the read would stall). + if (_threshold != 0 && !(_rx_ps_armed && isChipBusy()) + && getCurrentRSSI() > _noise_floor + _threshold) return true; // cad: hardware channel activity detection if (_cad_enabled) { diff --git a/src/helpers/radiolib/RadioLibWrappers.h b/src/helpers/radiolib/RadioLibWrappers.h index 12f3e4e4..a4236982 100644 --- a/src/helpers/radiolib/RadioLibWrappers.h +++ b/src/helpers/radiolib/RadioLibWrappers.h @@ -30,6 +30,9 @@ protected: virtual int startReceiveMode(); virtual void stopReceiveDutyCycle(); virtual bool isPacketReady(); + // true while the chip cannot service SPI (RX duty-cycle sleep window, or + // briefly while processing a command); radios expose this via the BUSY pin + virtual bool isChipBusy() { return false; } float packetScoreInt(float snr, int sf, int packet_len); virtual bool isReceivingPacket() =0; virtual void doResetAGC();