Skip to content

Commit 8f4c45b

Browse files
authored
Reset noise floor on frequency changes (#10752)
1 parent 2a855af commit 8f4c45b

4 files changed

Lines changed: 120 additions & 4 deletions

File tree

src/mesh/RadioInterface.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -240,8 +240,8 @@ class RadioInterface
240240
protected:
241241
int8_t power = 17; // Set by applyModemConfig()
242242

243-
float savedFreq;
244-
uint32_t savedChannelNum;
243+
float savedFreq = 0.0f;
244+
uint32_t savedChannelNum = 0;
245245

246246
/***
247247
* given a packet set sendingPacket and decode the protobufs into radiobuf. Returns # of bytes to send (including the

src/mesh/RadioLibInterface.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,12 @@ RadioLibInterface::RadioLibInterface(LockingArduinoHal *hal, RADIOLIB_PIN_TYPE c
5454
#endif
5555
}
5656

57+
static bool radioFrequencyChanged(float previousFreq, float currentFreq)
58+
{
59+
const float delta = currentFreq - previousFreq;
60+
return delta > 0.000001f || delta < -0.000001f;
61+
}
62+
5763
#ifdef ARCH_ESP32
5864
// ESP32 doesn't use that flag
5965
#define YIELD_FROM_ISR(x) portYIELD_FROM_ISR()
@@ -228,6 +234,16 @@ bool RadioLibInterface::canSleep()
228234
return res;
229235
}
230236

237+
bool RadioLibInterface::reconfigure()
238+
{
239+
const float previousFreq = getFreq();
240+
bool result = RadioInterface::reconfigure();
241+
if (result && radioFrequencyChanged(previousFreq, getFreq())) {
242+
resetNoiseFloor();
243+
}
244+
return result;
245+
}
246+
231247
/** Allow other firmware components to ask whether we are currently sending a packet
232248
Initially implemented to protect T-Echo's capacitive touch button from spurious presses during tx
233249
*/
@@ -331,6 +347,7 @@ void RadioLibInterface::resetNoiseFloor()
331347
{
332348
currentSampleIndex = 0;
333349
isNoiseFloorBufferFull = false;
350+
lastNoiseFloorUpdate = 0;
334351
currentNoiseFloor = NOISE_FLOOR_DEFAULT;
335352
LOG_INFO("Noise floor reset - rolling window collection will restart");
336353
}

src/mesh/RadioLibInterface.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,8 @@ class RadioLibInterface : public RadioInterface, protected concurrency::Notified
167167
RadioLibInterface(LockingArduinoHal *hal, RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst,
168168
RADIOLIB_PIN_TYPE busy, PhysicalLayer *iface = NULL);
169169

170+
virtual bool reconfigure() override;
171+
170172
virtual ErrorCode send(meshtastic_MeshPacket *p) override;
171173

172174
/**

test/test_radio/test_main.cpp

Lines changed: 99 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,54 @@
11
#include "MeshRadio.h"
2+
#include "MeshService.h"
3+
#include "NodeDB.h"
24
#include "RadioInterface.h"
5+
#include "RadioLibInterface.h"
36
#include "TestUtil.h"
7+
#include <SPI.h>
48
#include <unity.h>
59

610
#include "meshtastic/config.pb.h"
711

12+
class MockMeshService : public MeshService
13+
{
14+
public:
15+
void sendClientNotification(meshtastic_ClientNotification *n) override { releaseClientNotificationToPool(n); }
16+
};
17+
18+
static MockMeshService *mockMeshService;
19+
20+
static LockingArduinoHal *getTestHal()
21+
{
22+
static LockingArduinoHal hal(SPI, SPISettings(1000000, MSBFIRST, SPI_MODE0));
23+
return &hal;
24+
}
25+
26+
class TestableRadioLibInterface : public RadioLibInterface
27+
{
28+
public:
29+
TestableRadioLibInterface() : RadioLibInterface(getTestHal(), RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC, nullptr) {}
30+
31+
void seedNoiseFloorForTest()
32+
{
33+
noiseFloorSamples[0] = -110;
34+
currentSampleIndex = 1;
35+
isNoiseFloorBufferFull = false;
36+
lastNoiseFloorUpdate = 1234;
37+
currentNoiseFloor = -110;
38+
}
39+
40+
uint32_t getLastNoiseFloorUpdateForTest() const { return lastNoiseFloorUpdate; }
41+
42+
protected:
43+
void disableInterrupt() override {}
44+
void enableInterrupt(void (*)()) override {}
45+
bool isChannelActive() override { return false; }
46+
bool isActivelyReceiving() override { return false; }
47+
void addReceiveMetadata(meshtastic_MeshPacket *) override {}
48+
uint32_t getPacketTime(uint32_t, bool) override { return 0; }
49+
int16_t getCurrentRSSI() override { return NOISE_FLOOR_DEFAULT; }
50+
};
51+
852
static void test_bwCodeToKHz_specialMappings()
953
{
1054
TEST_ASSERT_FLOAT_WITHIN(0.0001f, 31.25f, bwCodeToKHz(31));
@@ -77,8 +121,59 @@ static void test_bootstrapLoRaConfigFromPreset_fallsBackIfBandwidthExceedsRegion
77121
TEST_ASSERT_EQUAL_UINT32(11, cfg.spread_factor);
78122
}
79123

80-
void setUp(void) {}
81-
void tearDown(void) {}
124+
static void configureLongFastUs(float frequencyOffset = 0.0f)
125+
{
126+
config.lora = meshtastic_Config_LoRaConfig_init_zero;
127+
config.lora.region = meshtastic_Config_LoRaConfig_RegionCode_US;
128+
config.lora.use_preset = true;
129+
config.lora.modem_preset = meshtastic_Config_LoRaConfig_ModemPreset_LONG_FAST;
130+
config.lora.frequency_offset = frequencyOffset;
131+
}
132+
133+
static void test_radioLibReconfigureResetsNoiseFloorWhenFrequencyChanges()
134+
{
135+
TestableRadioLibInterface testRadioLib;
136+
configureLongFastUs();
137+
testRadioLib.reconfigure();
138+
testRadioLib.seedNoiseFloorForTest();
139+
140+
config.lora.frequency_offset = 0.125f;
141+
testRadioLib.reconfigure();
142+
143+
TEST_ASSERT_FALSE(testRadioLib.hasNoiseFloorSamples());
144+
TEST_ASSERT_EQUAL_INT32(-120, testRadioLib.getNoiseFloor());
145+
TEST_ASSERT_EQUAL_UINT32(0, testRadioLib.getLastNoiseFloorUpdateForTest());
146+
}
147+
148+
static void test_radioLibReconfigureKeepsNoiseFloorWhenFrequencyUnchanged()
149+
{
150+
TestableRadioLibInterface testRadioLib;
151+
configureLongFastUs();
152+
testRadioLib.reconfigure();
153+
testRadioLib.seedNoiseFloorForTest();
154+
155+
testRadioLib.reconfigure();
156+
157+
TEST_ASSERT_TRUE(testRadioLib.hasNoiseFloorSamples());
158+
TEST_ASSERT_EQUAL_INT32(-110, testRadioLib.getNoiseFloor());
159+
TEST_ASSERT_EQUAL_UINT32(1234, testRadioLib.getLastNoiseFloorUpdateForTest());
160+
}
161+
162+
void setUp(void)
163+
{
164+
mockMeshService = new MockMeshService();
165+
service = mockMeshService;
166+
167+
config.lora.region = meshtastic_Config_LoRaConfig_RegionCode_US;
168+
initRegion();
169+
}
170+
171+
void tearDown(void)
172+
{
173+
service = nullptr;
174+
delete mockMeshService;
175+
mockMeshService = nullptr;
176+
}
82177

83178
void setup()
84179
{
@@ -94,6 +189,8 @@ void setup()
94189
RUN_TEST(test_bootstrapLoRaConfigFromPreset_setsDerivedFields_nonWideRegion);
95190
RUN_TEST(test_bootstrapLoRaConfigFromPreset_setsDerivedFields_wideRegion);
96191
RUN_TEST(test_bootstrapLoRaConfigFromPreset_fallsBackIfBandwidthExceedsRegionSpan);
192+
RUN_TEST(test_radioLibReconfigureResetsNoiseFloorWhenFrequencyChanges);
193+
RUN_TEST(test_radioLibReconfigureKeepsNoiseFloorWhenFrequencyUnchanged);
97194
exit(UNITY_END());
98195
}
99196

0 commit comments

Comments
 (0)