@@ -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 );
0 commit comments