Skip to content

Commit 2d11d9f

Browse files
committed
Add exponential backoff for channel busy detection
Replace fixed random(8000-22000ms) backoff with exponential backoff: - 1st busy: 3-6s - 2nd busy: 6-12s - 3rd+ busy: 12-20s (capped) - Reset counter on channel free Results (48-byte simultaneous DM, JP SF12/BW125/CR4-5): - 3/3 success, delivered within 0:23-0:45 - Previous fixed backoff: 1:03-3:55
1 parent c5bacd7 commit 2d11d9f

2 files changed

Lines changed: 20 additions & 14 deletions

File tree

src/helpers/radiolib/RadioLibWrappers.cpp

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ void RadioLibWrapper::begin() {
3434

3535
_noise_floor = 0;
3636
_threshold = 0;
37+
_busy_count = 0; // initialize exponential backoff counter
3738

3839
// start average out some samples
3940
_num_floor_samples = 0;
@@ -183,39 +184,43 @@ bool RadioLibWrapper::isChannelActive() {
183184
if (_threshold == 0) return false; // interference check is disabled
184185

185186
#ifdef JP_STRICT
186-
// ARIB STD-T108 compliant LBT: continuous RSSI sensing for >= 5ms
187-
// Energy-based sensing required; LoRa CAD alone is not sufficient
187+
// 5ms continuous RSSI sensing
188188
uint32_t sense_start = millis();
189-
uint32_t sense_duration_ms = 5;
190-
while (millis() - sense_start < sense_duration_ms) {
189+
while (millis() - sense_start < 5) {
191190
if (getCurrentRSSI() > -80.0f) {
192-
// Channel busy detected during 5ms sensing window
193-
uint32_t backoff_until = millis() + random(8000, 22000);
191+
// RSSI busy: backoff and return without CAD
192+
_busy_count++;
193+
uint32_t base_ms = 3000;
194+
uint32_t max_backoff = min(base_ms * (1u << _busy_count), (uint32_t)20000);
195+
uint32_t backoff_until = millis() + random(max_backoff / 2, max_backoff);
194196
while (millis() < backoff_until) {
195-
vTaskDelay(1); // yield CPU to FreeRTOS tasks including BLE
197+
vTaskDelay(1);
196198
}
197199
return true;
198200
}
199-
vTaskDelay(1); // yield CPU between RSSI samples
201+
vTaskDelay(1);
200202
}
201203
#endif
202204

205+
// CAD
203206
int16_t result = performChannelScan();
204-
// scanChannel() triggers DIO interrupt (CAD done) which sets STATE_INT_READY
205-
// via setFlag() ISR. Clear it before restarting RX so recvRaw() doesn't
206-
// try to read a non-existent packet and count a spurious recv error.
207207
state = STATE_IDLE;
208208
startRecv();
209209

210210
if (result != RADIOLIB_CHANNEL_FREE) {
211-
// Random backoff to desynchronize retries between competing nodes
212-
uint32_t backoff_until = millis() + random(8000, 22000);
211+
// CAD busy: backoff
212+
_busy_count++;
213+
uint32_t base_ms = 3000;
214+
uint32_t max_backoff = min(base_ms * (1u << _busy_count), (uint32_t)20000);
215+
uint32_t backoff_until = millis() + random(max_backoff / 2, max_backoff);
213216
while (millis() < backoff_until) {
214-
vTaskDelay(1); // yield CPU to FreeRTOS tasks including BLE
217+
vTaskDelay(1);
215218
}
216219
return true;
217220
}
218221

222+
_busy_count = 0;
223+
219224
// Small jitter even when channel is free to prevent simultaneous TX
220225
// from two nodes that both detect a free channel at the same time
221226
uint32_t jitter_until = millis() + random(0, 500);

src/helpers/radiolib/RadioLibWrappers.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ class RadioLibWrapper : public mesh::Radio {
99
mesh::MainBoard* _board;
1010
uint32_t n_recv, n_sent, n_recv_errors, _tx_start_ms;
1111
int16_t _noise_floor, _threshold;
12+
uint8_t _busy_count; // consecutive busy detections for exponential backoff
1213
uint16_t _num_floor_samples;
1314
int32_t _floor_sample_sum;
1415

0 commit comments

Comments
 (0)