From 2f8d9cf96ab06bc24c258d9f77b48465a5ca2613 Mon Sep 17 00:00:00 2001 From: Scott Powell Date: Sat, 24 May 2025 20:42:00 +1000 Subject: [PATCH 1/5] * refactor of RadioLibWrapper::isReceiving() --- src/helpers/CustomLLCC68Wrapper.h | 14 ++------------ src/helpers/CustomLR1110Wrapper.h | 14 ++------------ src/helpers/CustomSTM32WLxWrapper.h | 14 ++------------ src/helpers/CustomSX1262Wrapper.h | 15 ++------------- src/helpers/CustomSX1268Wrapper.h | 14 ++------------ src/helpers/CustomSX1276Wrapper.h | 14 ++------------ src/helpers/RadioLibWrappers.cpp | 12 ++++++++++++ src/helpers/RadioLibWrappers.h | 8 ++++++++ 8 files changed, 32 insertions(+), 73 deletions(-) diff --git a/src/helpers/CustomLLCC68Wrapper.h b/src/helpers/CustomLLCC68Wrapper.h index c7d95c41..d547880f 100644 --- a/src/helpers/CustomLLCC68Wrapper.h +++ b/src/helpers/CustomLLCC68Wrapper.h @@ -6,18 +6,8 @@ class CustomLLCC68Wrapper : public RadioLibWrapper { public: CustomLLCC68Wrapper(CustomLLCC68& radio, mesh::MainBoard& board) : RadioLibWrapper(radio, board) { } - bool isReceiving() override { - if (((CustomLLCC68 *)_radio)->isReceiving()) return true; - - idle(); // put sx126x into standby - // do some basic CAD (blocks for ~12780 micros (on SF 10)!) - bool activity = (((CustomLLCC68 *)_radio)->scanChannel() == RADIOLIB_LORA_DETECTED); - if (activity) { - startRecv(); - } else { - idle(); - } - return activity; + bool isReceivingPacket() override { + return ((CustomLLCC68 *)_radio)->isReceiving(); } float getLastRSSI() const override { return ((CustomLLCC68 *)_radio)->getRSSI(); } float getLastSNR() const override { return ((CustomLLCC68 *)_radio)->getSNR(); } diff --git a/src/helpers/CustomLR1110Wrapper.h b/src/helpers/CustomLR1110Wrapper.h index 3a96d3c2..c02052a1 100644 --- a/src/helpers/CustomLR1110Wrapper.h +++ b/src/helpers/CustomLR1110Wrapper.h @@ -6,18 +6,8 @@ class CustomLR1110Wrapper : public RadioLibWrapper { public: CustomLR1110Wrapper(CustomLR1110& radio, mesh::MainBoard& board) : RadioLibWrapper(radio, board) { } - bool isReceiving() override { - if (((CustomLR1110 *)_radio)->isReceiving()) return true; - - idle(); // put sx126x into standby - // do some basic CAD (blocks for ~12780 micros (on SF 10)!) - bool activity = (((CustomLR1110 *)_radio)->scanChannel() == RADIOLIB_LORA_DETECTED); - if (activity) { - startRecv(); - } else { - idle(); - } - return activity; + bool isReceivingPacket() override { + return ((CustomLR1110 *)_radio)->isReceiving(); } void onSendFinished() override { diff --git a/src/helpers/CustomSTM32WLxWrapper.h b/src/helpers/CustomSTM32WLxWrapper.h index 84f78376..491d648e 100644 --- a/src/helpers/CustomSTM32WLxWrapper.h +++ b/src/helpers/CustomSTM32WLxWrapper.h @@ -7,18 +7,8 @@ class CustomSTM32WLxWrapper : public RadioLibWrapper { public: CustomSTM32WLxWrapper(CustomSTM32WLx& radio, mesh::MainBoard& board) : RadioLibWrapper(radio, board) { } - bool isReceiving() override { - if (((CustomSTM32WLx *)_radio)->isReceiving()) return true; - - idle(); // put sx126x into standby - // do some basic CAD (blocks for ~12780 micros (on SF 10)!) - bool activity = (((CustomSTM32WLx *)_radio)->scanChannel() == RADIOLIB_LORA_DETECTED); - if (activity) { - startRecv(); - } else { - idle(); - } - return activity; + bool isReceivingPacket() override { + return ((CustomSTM32WLx *)_radio)->isReceiving(); } float getLastRSSI() const override { return ((CustomSTM32WLx *)_radio)->getRSSI(); } float getLastSNR() const override { return ((CustomSTM32WLx *)_radio)->getSNR(); } diff --git a/src/helpers/CustomSX1262Wrapper.h b/src/helpers/CustomSX1262Wrapper.h index ea2da5fe..3aee2966 100644 --- a/src/helpers/CustomSX1262Wrapper.h +++ b/src/helpers/CustomSX1262Wrapper.h @@ -2,23 +2,12 @@ #include "CustomSX1262.h" #include "RadioLibWrappers.h" -#include class CustomSX1262Wrapper : public RadioLibWrapper { public: CustomSX1262Wrapper(CustomSX1262& radio, mesh::MainBoard& board) : RadioLibWrapper(radio, board) { } - bool isReceiving() override { - if (((CustomSX1262 *)_radio)->isReceiving()) return true; - - idle(); // put sx126x into standby - // do some basic CAD (blocks for ~12780 micros (on SF 10)!) - bool activity = (((CustomSX1262 *)_radio)->scanChannel() == RADIOLIB_LORA_DETECTED); - if (activity) { - startRecv(); - } else { - idle(); - } - return activity; + bool isReceivingPacket() override { + return ((CustomSX1262 *)_radio)->isReceiving(); } float getLastRSSI() const override { return ((CustomSX1262 *)_radio)->getRSSI(); } float getLastSNR() const override { return ((CustomSX1262 *)_radio)->getSNR(); } diff --git a/src/helpers/CustomSX1268Wrapper.h b/src/helpers/CustomSX1268Wrapper.h index f9eee447..5ee8e6a2 100644 --- a/src/helpers/CustomSX1268Wrapper.h +++ b/src/helpers/CustomSX1268Wrapper.h @@ -6,18 +6,8 @@ class CustomSX1268Wrapper : public RadioLibWrapper { public: CustomSX1268Wrapper(CustomSX1268& radio, mesh::MainBoard& board) : RadioLibWrapper(radio, board) { } - bool isReceiving() override { - if (((CustomSX1268 *)_radio)->isReceiving()) return true; - - idle(); // put sx126x into standby - // do some basic CAD (blocks for ~12780 micros (on SF 10)!) - bool activity = (((CustomSX1268 *)_radio)->scanChannel() == RADIOLIB_LORA_DETECTED); - if (activity) { - startRecv(); - } else { - idle(); - } - return activity; + bool isReceivingPacket() override { + return ((CustomSX1268 *)_radio)->isReceiving(); } float getLastRSSI() const override { return ((CustomSX1268 *)_radio)->getRSSI(); } float getLastSNR() const override { return ((CustomSX1268 *)_radio)->getSNR(); } diff --git a/src/helpers/CustomSX1276Wrapper.h b/src/helpers/CustomSX1276Wrapper.h index f9900705..26e925a9 100644 --- a/src/helpers/CustomSX1276Wrapper.h +++ b/src/helpers/CustomSX1276Wrapper.h @@ -6,18 +6,8 @@ class CustomSX1276Wrapper : public RadioLibWrapper { public: CustomSX1276Wrapper(CustomSX1276& radio, mesh::MainBoard& board) : RadioLibWrapper(radio, board) { } - bool isReceiving() override { - if (((CustomSX1276 *)_radio)->isReceiving()) return true; - - idle(); // put into standby - // do some basic CAD (blocks for ~12780 micros (on SF 10)!) - bool activity = (((CustomSX1276 *)_radio)->tryScanChannel() == RADIOLIB_PREAMBLE_DETECTED); - if (activity) { - startRecv(); - } else { - idle(); - } - return activity; + bool isReceivingPacket() override { + return ((CustomSX1276 *)_radio)->isReceiving(); } float getLastRSSI() const override { return ((CustomSX1276 *)_radio)->getRSSI(); } float getLastSNR() const override { return ((CustomSX1276 *)_radio)->getSNR(); } diff --git a/src/helpers/RadioLibWrappers.cpp b/src/helpers/RadioLibWrappers.cpp index 39fb340e..358c5f42 100644 --- a/src/helpers/RadioLibWrappers.cpp +++ b/src/helpers/RadioLibWrappers.cpp @@ -108,6 +108,18 @@ void RadioLibWrapper::onSendFinished() { state = STATE_IDLE; } +bool RadioLibWrapper::isChannelActive() { + idle(); // put sx126x into standby + // do some basic CAD (blocks for ~12780 micros (on SF 10)!) + bool activity = _radio->scanChannel() == RADIOLIB_LORA_DETECTED; + if (activity) { + startRecv(); + } else { + idle(); + } + return activity; +} + float RadioLibWrapper::getLastRSSI() const { return _radio->getRSSI(); } diff --git a/src/helpers/RadioLibWrappers.h b/src/helpers/RadioLibWrappers.h index bdbadb19..3e8b9fea 100644 --- a/src/helpers/RadioLibWrappers.h +++ b/src/helpers/RadioLibWrappers.h @@ -12,6 +12,7 @@ protected: void idle(); void startRecv(); float packetScoreInt(float snr, int sf, int packet_len); + virtual bool isReceivingPacket() =0; public: RadioLibWrapper(PhysicalLayer& radio, mesh::MainBoard& board) : _radio(&radio), _board(&board) { n_recv = n_sent = 0; } @@ -23,6 +24,13 @@ public: bool isSendComplete() override; void onSendFinished() override; bool isInRecvMode() const override; + bool isChannelActive(); + + bool isReceiving() override { + if (isReceivingPacket()) return true; + + return isChannelActive(); + } uint32_t getPacketsRecv() const { return n_recv; } uint32_t getPacketsSent() const { return n_sent; } From f2243b78ae8467e271491cbd9109592afa759714 Mon Sep 17 00:00:00 2001 From: Scott Powell Date: Sat, 24 May 2025 21:24:44 +1000 Subject: [PATCH 2/5] * added Radio::loop() virtual function * RadioLibWrapper: new isChannelActive() based on current RSSI being above noise_floor + THRESHOLD --- src/Dispatcher.cpp | 2 ++ src/Dispatcher.h | 5 ++++ src/helpers/CustomLLCC68Wrapper.h | 3 +++ src/helpers/CustomLR1110Wrapper.h | 5 ++++ src/helpers/CustomSTM32WLxWrapper.h | 3 +++ src/helpers/CustomSX1262Wrapper.h | 3 +++ src/helpers/CustomSX1268Wrapper.h | 3 +++ src/helpers/CustomSX1276Wrapper.h | 3 +++ src/helpers/RadioLibWrappers.cpp | 36 +++++++++++++++++++++-------- src/helpers/RadioLibWrappers.h | 6 +++++ 10 files changed, 60 insertions(+), 9 deletions(-) diff --git a/src/Dispatcher.cpp b/src/Dispatcher.cpp index 3d5b04fc..6412b6a9 100644 --- a/src/Dispatcher.cpp +++ b/src/Dispatcher.cpp @@ -36,6 +36,8 @@ uint32_t Dispatcher::getCADFailMaxDuration() const { } void Dispatcher::loop() { + _radio->loop(); + // check for radio 'stuck' in mode other than Rx bool is_recv = _radio->isInRecvMode(); if (is_recv != prev_isrecv_mode) { diff --git a/src/Dispatcher.h b/src/Dispatcher.h index d03c9f73..7a48067d 100644 --- a/src/Dispatcher.h +++ b/src/Dispatcher.h @@ -56,6 +56,11 @@ public: */ virtual void onSendFinished() = 0; + /** + * \brief do any processing needed on each loop cycle + */ + virtual void loop() { } + virtual bool isInRecvMode() const = 0; /** diff --git a/src/helpers/CustomLLCC68Wrapper.h b/src/helpers/CustomLLCC68Wrapper.h index d547880f..f7dd7a9f 100644 --- a/src/helpers/CustomLLCC68Wrapper.h +++ b/src/helpers/CustomLLCC68Wrapper.h @@ -9,6 +9,9 @@ public: bool isReceivingPacket() override { return ((CustomLLCC68 *)_radio)->isReceiving(); } + float getCurrentRSSI() override { + return ((CustomLLCC68 *)_radio)->getRSSI(false); + } float getLastRSSI() const override { return ((CustomLLCC68 *)_radio)->getRSSI(); } float getLastSNR() const override { return ((CustomLLCC68 *)_radio)->getSNR(); } diff --git a/src/helpers/CustomLR1110Wrapper.h b/src/helpers/CustomLR1110Wrapper.h index c02052a1..7e2ffa2d 100644 --- a/src/helpers/CustomLR1110Wrapper.h +++ b/src/helpers/CustomLR1110Wrapper.h @@ -9,6 +9,11 @@ public: bool isReceivingPacket() override { return ((CustomLR1110 *)_radio)->isReceiving(); } + float getCurrentRSSI() override { + float rssi = -110; + ((CustomLR1110 *)_radio)->getRssiInst(&rssi); + return rssi; + } void onSendFinished() override { RadioLibWrapper::onSendFinished(); diff --git a/src/helpers/CustomSTM32WLxWrapper.h b/src/helpers/CustomSTM32WLxWrapper.h index 491d648e..9e2d0441 100644 --- a/src/helpers/CustomSTM32WLxWrapper.h +++ b/src/helpers/CustomSTM32WLxWrapper.h @@ -10,6 +10,9 @@ public: bool isReceivingPacket() override { return ((CustomSTM32WLx *)_radio)->isReceiving(); } + float getCurrentRSSI() override { + return ((CustomSTM32WLx *)_radio)->getRSSI(false); + } float getLastRSSI() const override { return ((CustomSTM32WLx *)_radio)->getRSSI(); } float getLastSNR() const override { return ((CustomSTM32WLx *)_radio)->getSNR(); } diff --git a/src/helpers/CustomSX1262Wrapper.h b/src/helpers/CustomSX1262Wrapper.h index 3aee2966..119f6dce 100644 --- a/src/helpers/CustomSX1262Wrapper.h +++ b/src/helpers/CustomSX1262Wrapper.h @@ -9,6 +9,9 @@ public: bool isReceivingPacket() override { return ((CustomSX1262 *)_radio)->isReceiving(); } + float getCurrentRSSI() override { + return ((CustomSX1262 *)_radio)->getRSSI(false); + } float getLastRSSI() const override { return ((CustomSX1262 *)_radio)->getRSSI(); } float getLastSNR() const override { return ((CustomSX1262 *)_radio)->getSNR(); } diff --git a/src/helpers/CustomSX1268Wrapper.h b/src/helpers/CustomSX1268Wrapper.h index 5ee8e6a2..5d7106b4 100644 --- a/src/helpers/CustomSX1268Wrapper.h +++ b/src/helpers/CustomSX1268Wrapper.h @@ -9,6 +9,9 @@ public: bool isReceivingPacket() override { return ((CustomSX1268 *)_radio)->isReceiving(); } + float getCurrentRSSI() override { + return ((CustomSX1268 *)_radio)->getRSSI(false); + } float getLastRSSI() const override { return ((CustomSX1268 *)_radio)->getRSSI(); } float getLastSNR() const override { return ((CustomSX1268 *)_radio)->getSNR(); } diff --git a/src/helpers/CustomSX1276Wrapper.h b/src/helpers/CustomSX1276Wrapper.h index 26e925a9..28257990 100644 --- a/src/helpers/CustomSX1276Wrapper.h +++ b/src/helpers/CustomSX1276Wrapper.h @@ -9,6 +9,9 @@ public: bool isReceivingPacket() override { return ((CustomSX1276 *)_radio)->isReceiving(); } + float getCurrentRSSI() override { + return ((CustomSX1276 *)_radio)->getRSSI(false); + } float getLastRSSI() const override { return ((CustomSX1276 *)_radio)->getRSSI(); } float getLastSNR() const override { return ((CustomSX1276 *)_radio)->getSNR(); } diff --git a/src/helpers/RadioLibWrappers.cpp b/src/helpers/RadioLibWrappers.cpp index 358c5f42..d52d81ff 100644 --- a/src/helpers/RadioLibWrappers.cpp +++ b/src/helpers/RadioLibWrappers.cpp @@ -8,6 +8,12 @@ #define STATE_TX_DONE 4 #define STATE_INT_READY 16 +#ifndef INTERFERENCE_THRESHOLD_DB + #define INTERFERENCE_THRESHOLD_DB 14 +#endif + +#define NUM_NOISE_FLOOR_SAMPLES 64 + static volatile uint8_t state = STATE_IDLE; // this function is called when a complete packet @@ -28,6 +34,12 @@ void RadioLibWrapper::begin() { if (_board->getStartupReason() == BD_STARTUP_RX_PACKET) { // received a LoRa packet (while in deep sleep) setFlag(); // LoRa packet is already received } + + _noise_floor = -140; + + // start average out some samples + _num_floor_samples = 0; + _floor_sample_sum = 0; } void RadioLibWrapper::idle() { @@ -35,6 +47,20 @@ void RadioLibWrapper::idle() { state = STATE_IDLE; // need another startReceive() } +void RadioLibWrapper::loop() { + if (state == STATE_RX && _num_floor_samples < NUM_NOISE_FLOOR_SAMPLES) { + if (!isReceivingPacket()) { + _num_floor_samples++; + _floor_sample_sum += getCurrentRSSI(); + } + } else if (_floor_sample_sum != 0) { + _noise_floor = _floor_sample_sum / NUM_NOISE_FLOOR_SAMPLES; + _floor_sample_sum = 0; + + MESH_DEBUG_PRINTLN("RadioLibWrapper: noise_floor = %d", (int)_noise_floor); + } +} + void RadioLibWrapper::startRecv() { int err = _radio->startReceive(); if (err == RADIOLIB_ERR_NONE) { @@ -109,15 +135,7 @@ void RadioLibWrapper::onSendFinished() { } bool RadioLibWrapper::isChannelActive() { - idle(); // put sx126x into standby - // do some basic CAD (blocks for ~12780 micros (on SF 10)!) - bool activity = _radio->scanChannel() == RADIOLIB_LORA_DETECTED; - if (activity) { - startRecv(); - } else { - idle(); - } - return activity; + return getCurrentRSSI() > _noise_floor + INTERFERENCE_THRESHOLD_DB; } float RadioLibWrapper::getLastRSSI() const { diff --git a/src/helpers/RadioLibWrappers.h b/src/helpers/RadioLibWrappers.h index 3e8b9fea..211e0187 100644 --- a/src/helpers/RadioLibWrappers.h +++ b/src/helpers/RadioLibWrappers.h @@ -8,11 +8,15 @@ protected: PhysicalLayer* _radio; mesh::MainBoard* _board; uint32_t n_recv, n_sent; + int16_t _noise_floor; + uint16_t _num_floor_samples; + int32_t _floor_sample_sum; void idle(); void startRecv(); float packetScoreInt(float snr, int sf, int packet_len); virtual bool isReceivingPacket() =0; + virtual float getCurrentRSSI() =0; public: RadioLibWrapper(PhysicalLayer& radio, mesh::MainBoard& board) : _radio(&radio), _board(&board) { n_recv = n_sent = 0; } @@ -32,6 +36,8 @@ public: return isChannelActive(); } + void loop() override; + uint32_t getPacketsRecv() const { return n_recv; } uint32_t getPacketsSent() const { return n_sent; } void resetStats() { n_recv = n_sent = 0; } From 0e35ae5ec63e6b16d633712df86d2b6821223758 Mon Sep 17 00:00:00 2001 From: Scott Powell Date: Sun, 25 May 2025 21:44:15 +1000 Subject: [PATCH 3/5] * dynamic noise floor sampling --- src/Dispatcher.cpp | 8 ++++++++ src/Dispatcher.h | 6 ++++++ src/helpers/RadioLibWrappers.cpp | 18 ++++++++++++++---- src/helpers/RadioLibWrappers.h | 6 +++++- 4 files changed, 33 insertions(+), 5 deletions(-) diff --git a/src/Dispatcher.cpp b/src/Dispatcher.cpp index 6412b6a9..06c5e035 100644 --- a/src/Dispatcher.cpp +++ b/src/Dispatcher.cpp @@ -10,6 +10,10 @@ namespace mesh { #define MAX_RX_DELAY_MILLIS 32000 // 32 seconds +#ifndef NOISE_FLOOR_CALIB_INTERVAL + #define NOISE_FLOOR_CALIB_INTERVAL 2000 // 2 seconds +#endif + void Dispatcher::begin() { n_sent_flood = n_sent_direct = 0; n_recv_flood = n_recv_direct = 0; @@ -36,6 +40,10 @@ uint32_t Dispatcher::getCADFailMaxDuration() const { } void Dispatcher::loop() { + if (millisHasNowPassed(next_floor_calib_time)) { + _radio->triggerNoiseFloorCalibrate(); + next_floor_calib_time = futureMillis(NOISE_FLOOR_CALIB_INTERVAL); + } _radio->loop(); // check for radio 'stuck' in mode other than Rx diff --git a/src/Dispatcher.h b/src/Dispatcher.h index 7a48067d..37f327e3 100644 --- a/src/Dispatcher.h +++ b/src/Dispatcher.h @@ -61,6 +61,10 @@ public: */ virtual void loop() { } + virtual int getNoiseFloor() const { return 0; } + + virtual void triggerNoiseFloorCalibrate() { } + virtual bool isInRecvMode() const = 0; /** @@ -112,6 +116,7 @@ class Dispatcher { unsigned long next_tx_time; unsigned long cad_busy_start; unsigned long radio_nonrx_start; + unsigned long next_floor_calib_time; bool prev_isrecv_mode; uint32_t n_sent_flood, n_sent_direct; uint32_t n_recv_flood, n_recv_direct; @@ -129,6 +134,7 @@ protected: { outbound = NULL; total_air_time = 0; next_tx_time = 0; cad_busy_start = 0; + next_floor_calib_time = 0; _err_flags = 0; radio_nonrx_start = 0; prev_isrecv_mode = true; diff --git a/src/helpers/RadioLibWrappers.cpp b/src/helpers/RadioLibWrappers.cpp index d52d81ff..d7b93a2f 100644 --- a/src/helpers/RadioLibWrappers.cpp +++ b/src/helpers/RadioLibWrappers.cpp @@ -35,7 +35,7 @@ void RadioLibWrapper::begin() { setFlag(); // LoRa packet is already received } - _noise_floor = -140; + _noise_floor = 0; // start average out some samples _num_floor_samples = 0; @@ -47,13 +47,23 @@ void RadioLibWrapper::idle() { state = STATE_IDLE; // need another startReceive() } +void RadioLibWrapper::triggerNoiseFloorCalibrate() { + if (_num_floor_samples >= NUM_NOISE_FLOOR_SAMPLES) { // ignore trigger if currently sampling + _num_floor_samples = 0; + _floor_sample_sum = 0; + } +} + void RadioLibWrapper::loop() { if (state == STATE_RX && _num_floor_samples < NUM_NOISE_FLOOR_SAMPLES) { if (!isReceivingPacket()) { - _num_floor_samples++; - _floor_sample_sum += getCurrentRSSI(); + int rssi = getCurrentRSSI(); + if (rssi < _noise_floor + INTERFERENCE_THRESHOLD_DB) { // only consider samples below current floor+THRESHOLD + _num_floor_samples++; + _floor_sample_sum += rssi; + } } - } else if (_floor_sample_sum != 0) { + } else if (_num_floor_samples >= NUM_NOISE_FLOOR_SAMPLES && _floor_sample_sum != 0) { _noise_floor = _floor_sample_sum / NUM_NOISE_FLOOR_SAMPLES; _floor_sample_sum = 0; diff --git a/src/helpers/RadioLibWrappers.h b/src/helpers/RadioLibWrappers.h index 211e0187..9ac7e72c 100644 --- a/src/helpers/RadioLibWrappers.h +++ b/src/helpers/RadioLibWrappers.h @@ -16,7 +16,6 @@ protected: void startRecv(); float packetScoreInt(float snr, int sf, int packet_len); virtual bool isReceivingPacket() =0; - virtual float getCurrentRSSI() =0; public: RadioLibWrapper(PhysicalLayer& radio, mesh::MainBoard& board) : _radio(&radio), _board(&board) { n_recv = n_sent = 0; } @@ -36,6 +35,11 @@ public: return isChannelActive(); } + virtual float getCurrentRSSI() =0; + + int getNoiseFloor() const override { return _noise_floor; } + void triggerNoiseFloorCalibrate() override; + void loop() override; uint32_t getPacketsRecv() const { return n_recv; } From b3d78ac8a798279e45338c2d2b49cf09bb454474 Mon Sep 17 00:00:00 2001 From: Scott Powell Date: Mon, 26 May 2025 17:18:49 +1000 Subject: [PATCH 4/5] * interference threshold now stored in prefs, CLI: set/get "int.thresh" --- examples/simple_repeater/main.cpp | 4 ++++ examples/simple_room_server/main.cpp | 4 ++++ src/Dispatcher.cpp | 2 +- src/Dispatcher.h | 3 ++- src/helpers/CommonCLI.cpp | 8 ++++++++ src/helpers/CommonCLI.h | 1 + src/helpers/RadioLibWrappers.cpp | 16 ++++++++-------- src/helpers/RadioLibWrappers.h | 4 ++-- 8 files changed, 30 insertions(+), 12 deletions(-) diff --git a/examples/simple_repeater/main.cpp b/examples/simple_repeater/main.cpp index 12c843b7..06edec13 100644 --- a/examples/simple_repeater/main.cpp +++ b/examples/simple_repeater/main.cpp @@ -327,6 +327,9 @@ protected: uint32_t t = (_radio->getEstAirtimeFor(packet->path_len + packet->payload_len + 2) * _prefs.direct_tx_delay_factor); return getRNG()->nextInt(0, 6)*t; } + int getInterferenceThreshold() const override { + return _prefs.interference_threshold; + } void onAnonDataRecv(mesh::Packet* packet, uint8_t type, const mesh::Identity& sender, uint8_t* data, size_t len) override { if (type == PAYLOAD_TYPE_ANON_REQ) { // received an initial request by a possible admin client (unknown at this stage) @@ -565,6 +568,7 @@ public: _prefs.advert_interval = 1; // default to 2 minutes for NEW installs _prefs.flood_advert_interval = 3; // 3 hours _prefs.flood_max = 64; + _prefs.interference_threshold = 14; // DB } CommonCLI* getCLI() { return &_cli; } diff --git a/examples/simple_room_server/main.cpp b/examples/simple_room_server/main.cpp index dad7ce78..d46270ac 100644 --- a/examples/simple_room_server/main.cpp +++ b/examples/simple_room_server/main.cpp @@ -406,6 +406,9 @@ protected: uint32_t t = (_radio->getEstAirtimeFor(packet->path_len + packet->payload_len + 2) * _prefs.direct_tx_delay_factor); return getRNG()->nextInt(0, 6)*t; } + int getInterferenceThreshold() const override { + return _prefs.interference_threshold; + } bool allowPacketForward(const mesh::Packet* packet) override { if (_prefs.disable_fwd) return false; @@ -711,6 +714,7 @@ public: _prefs.advert_interval = 1; // default to 2 minutes for NEW installs _prefs.flood_advert_interval = 3; // 3 hours _prefs.flood_max = 64; + _prefs.interference_threshold = 14; // DB #ifdef ROOM_PASSWORD StrHelper::strncpy(_prefs.guest_password, ROOM_PASSWORD, sizeof(_prefs.guest_password)); #endif diff --git a/src/Dispatcher.cpp b/src/Dispatcher.cpp index 06c5e035..7ac5cbe3 100644 --- a/src/Dispatcher.cpp +++ b/src/Dispatcher.cpp @@ -41,7 +41,7 @@ uint32_t Dispatcher::getCADFailMaxDuration() const { void Dispatcher::loop() { if (millisHasNowPassed(next_floor_calib_time)) { - _radio->triggerNoiseFloorCalibrate(); + _radio->triggerNoiseFloorCalibrate(getInterferenceThreshold()); next_floor_calib_time = futureMillis(NOISE_FLOOR_CALIB_INTERVAL); } _radio->loop(); diff --git a/src/Dispatcher.h b/src/Dispatcher.h index 37f327e3..bce13b6b 100644 --- a/src/Dispatcher.h +++ b/src/Dispatcher.h @@ -63,7 +63,7 @@ public: virtual int getNoiseFloor() const { return 0; } - virtual void triggerNoiseFloorCalibrate() { } + virtual void triggerNoiseFloorCalibrate(int threshold) { } virtual bool isInRecvMode() const = 0; @@ -153,6 +153,7 @@ protected: virtual int calcRxDelay(float score, uint32_t air_time) const; virtual uint32_t getCADFailRetryDelay() const; virtual uint32_t getCADFailMaxDuration() const; + virtual int getInterferenceThreshold() const { return 0; } // disabled by default public: void begin(); diff --git a/src/helpers/CommonCLI.cpp b/src/helpers/CommonCLI.cpp index 8b8296f5..baad8f40 100644 --- a/src/helpers/CommonCLI.cpp +++ b/src/helpers/CommonCLI.cpp @@ -56,6 +56,7 @@ void CommonCLI::loadPrefsInt(FILESYSTEM* fs, const char* filename) { file.read(pad, 4); // 120 file.read((uint8_t *) &_prefs->flood_max, sizeof(_prefs->flood_max)); // 124 file.read((uint8_t *) &_prefs->flood_advert_interval, sizeof(_prefs->flood_advert_interval)); // 125 + file.read((uint8_t *) &_prefs->interference_threshold, sizeof(_prefs->interference_threshold)); // 126 // sanitise bad pref values _prefs->rx_delay_base = constrain(_prefs->rx_delay_base, 0, 20.0f); @@ -109,6 +110,7 @@ void CommonCLI::savePrefs(FILESYSTEM* fs) { file.write(pad, 4); // 120 file.write((uint8_t *) &_prefs->flood_max, sizeof(_prefs->flood_max)); // 124 file.write((uint8_t *) &_prefs->flood_advert_interval, sizeof(_prefs->flood_advert_interval)); // 125 + file.write((uint8_t *) &_prefs->interference_threshold, sizeof(_prefs->interference_threshold)); // 126 file.close(); } @@ -176,6 +178,8 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch const char* config = &command[4]; if (memcmp(config, "af", 2) == 0) { sprintf(reply, "> %s", StrHelper::ftoa(_prefs->airtime_factor)); + } else if (memcmp(config, "int.thresh", 10) == 0) { + sprintf(reply, "> %d", (uint32_t) _prefs->interference_threshold); } else if (memcmp(config, "allow.read.only", 15) == 0) { sprintf(reply, "> %s", _prefs->allow_read_only ? "on" : "off"); } else if (memcmp(config, "flood.advert.interval", 21) == 0) { @@ -223,6 +227,10 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch _prefs->airtime_factor = atof(&config[3]); savePrefs(); strcpy(reply, "OK"); + } else if (memcmp(config, "int.thresh ", 11) == 0) { + _prefs->interference_threshold = atoi(&config[11]); + savePrefs(); + strcpy(reply, "OK"); } else if (memcmp(config, "allow.read.only ", 16) == 0) { _prefs->allow_read_only = memcmp(&config[16], "on", 2) == 0; savePrefs(); diff --git a/src/helpers/CommonCLI.h b/src/helpers/CommonCLI.h index 0e88c266..37402c09 100644 --- a/src/helpers/CommonCLI.h +++ b/src/helpers/CommonCLI.h @@ -24,6 +24,7 @@ struct NodePrefs { // persisted to file uint8_t reserved2; float bw; uint8_t flood_max; + uint8_t interference_threshold; }; class CommonCLICallbacks { diff --git a/src/helpers/RadioLibWrappers.cpp b/src/helpers/RadioLibWrappers.cpp index d7b93a2f..d37bc498 100644 --- a/src/helpers/RadioLibWrappers.cpp +++ b/src/helpers/RadioLibWrappers.cpp @@ -8,10 +8,6 @@ #define STATE_TX_DONE 4 #define STATE_INT_READY 16 -#ifndef INTERFERENCE_THRESHOLD_DB - #define INTERFERENCE_THRESHOLD_DB 14 -#endif - #define NUM_NOISE_FLOOR_SAMPLES 64 static volatile uint8_t state = STATE_IDLE; @@ -36,6 +32,7 @@ void RadioLibWrapper::begin() { } _noise_floor = 0; + _threshold = 0; // start average out some samples _num_floor_samples = 0; @@ -47,8 +44,9 @@ void RadioLibWrapper::idle() { state = STATE_IDLE; // need another startReceive() } -void RadioLibWrapper::triggerNoiseFloorCalibrate() { - if (_num_floor_samples >= NUM_NOISE_FLOOR_SAMPLES) { // ignore trigger if currently sampling +void RadioLibWrapper::triggerNoiseFloorCalibrate(int threshold) { + _threshold = threshold; + if (threshold > 0 && _num_floor_samples >= NUM_NOISE_FLOOR_SAMPLES) { // ignore trigger if currently sampling _num_floor_samples = 0; _floor_sample_sum = 0; } @@ -58,7 +56,7 @@ void RadioLibWrapper::loop() { if (state == STATE_RX && _num_floor_samples < NUM_NOISE_FLOOR_SAMPLES) { if (!isReceivingPacket()) { int rssi = getCurrentRSSI(); - if (rssi < _noise_floor + INTERFERENCE_THRESHOLD_DB) { // only consider samples below current floor+THRESHOLD + if (rssi < _noise_floor + _threshold) { // only consider samples below current floor+THRESHOLD _num_floor_samples++; _floor_sample_sum += rssi; } @@ -145,7 +143,9 @@ void RadioLibWrapper::onSendFinished() { } bool RadioLibWrapper::isChannelActive() { - return getCurrentRSSI() > _noise_floor + INTERFERENCE_THRESHOLD_DB; + return _threshold == 0 + ? false // interference check is disabled + : getCurrentRSSI() > _noise_floor + _threshold; } float RadioLibWrapper::getLastRSSI() const { diff --git a/src/helpers/RadioLibWrappers.h b/src/helpers/RadioLibWrappers.h index 9ac7e72c..bb308071 100644 --- a/src/helpers/RadioLibWrappers.h +++ b/src/helpers/RadioLibWrappers.h @@ -8,7 +8,7 @@ protected: PhysicalLayer* _radio; mesh::MainBoard* _board; uint32_t n_recv, n_sent; - int16_t _noise_floor; + int16_t _noise_floor, _threshold; uint16_t _num_floor_samples; int32_t _floor_sample_sum; @@ -38,7 +38,7 @@ public: virtual float getCurrentRSSI() =0; int getNoiseFloor() const override { return _noise_floor; } - void triggerNoiseFloorCalibrate() override; + void triggerNoiseFloorCalibrate(int threshold) override; void loop() override; From a86364e6d8390e0378b4252eaaa0cfa62ba3e99b Mon Sep 17 00:00:00 2001 From: Scott Powell Date: Tue, 27 May 2025 00:28:23 +1000 Subject: [PATCH 5/5] * stats: curr_free_queue_len now repurposed to noise_floor --- examples/simple_repeater/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/simple_repeater/main.cpp b/examples/simple_repeater/main.cpp index 06edec13..5db62ff1 100644 --- a/examples/simple_repeater/main.cpp +++ b/examples/simple_repeater/main.cpp @@ -79,7 +79,7 @@ struct RepeaterStats { uint16_t batt_milli_volts; uint16_t curr_tx_queue_len; - uint16_t curr_free_queue_len; + int16_t noise_floor; int16_t last_rssi; uint32_t n_packets_recv; uint32_t n_packets_sent; @@ -183,7 +183,7 @@ class MyMesh : public mesh::Mesh, public CommonCLICallbacks { RepeaterStats stats; stats.batt_milli_volts = board.getBattMilliVolts(); stats.curr_tx_queue_len = _mgr->getOutboundCount(0xFFFFFFFF); - stats.curr_free_queue_len = _mgr->getFreeCount(); + stats.noise_floor = (int16_t)_radio->getNoiseFloor(); stats.last_rssi = (int16_t) radio_driver.getLastRSSI(); stats.n_packets_recv = radio_driver.getPacketsRecv(); stats.n_packets_sent = radio_driver.getPacketsSent();