Fixed RX power saving RSSI sampling during listen windows

This commit is contained in:
Jarosław Domański
2026-07-08 23:49:35 +02:00
parent 38034d2ee2
commit 92d09c84ef
6 changed files with 35 additions and 21 deletions
+8 -5
View File
@@ -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));
@@ -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);
+8 -5
View File
@@ -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);
+4 -1
View File
@@ -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);
}
+9 -10
View File
@@ -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) {
+3
View File
@@ -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();