forked from ExpressLRS/ExpressLRS
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add Listen Before Talk for 2.4GHz band - EU compliance (ExpressLRS#1243)
* sx1280Driver: Add getRssiInst function * Clear Channel Assessment aka Listen Before Talk, first working prototype. 500hz, hardcoded rxtimeout and threshold * Repurposed downlink link quality for LBT success ratio * Add dynamic GetRssiInst() valid delay depending on Lora SF mode Add dynamic listen before talk rssi dBm threshold depending in tx power * use currPower instead of max dynamic power for LBT threshold * fix currPower() for rssi threshold * Listen Before Talk Got rid of while loop waiting for rx valid by enabling rx for LBT early in TX interrupt Changed LBT RSSI thresholds to not adjusted for receiver bandwidth. This interpretation of the thresholds assumes RSSI dBm values from sx1280 already are correct for the configure receiver bandwidth configuration. * removed unused valid rssi delay * restart RX to clear potential packets received during listen before talk from rx buffer * restore downlink LQ to normal operation, keep LQ calc for LBT for future use * work in progress, LBT on rx side * document polling loop on getRssiInst, restore downlink LQ to indicate downlink LQ, not LBT success rate * add -DRegulatory_Domain_EU_CE_LBT_2400 define for enabling LBT * add adjustment offset #define for rssi reading * Exclude LBT code from radio_900 builds * move LBT clear channel assessment closer to where TX happens to simplify rx_main * add us wait delay for valid RSSI reading instead of just waiting for rssi to be above -127db, fixes issue with too low rssi for rx target, where rssi is read very soon after lbt rx enable * attempt at more clever way to select LBT mode if minpower is higher than non-LBT 10mW limit * Single EU_CE regulatory option Add preprocessor switch between LBT or non-LBT operation based on configured maxPower * remove debug #warning for LBT_ACTIVE * remove LBT regulatory define from user_defines * use delayMicroseconds instead of while-loop in LBT waiting for readability * Auto switch LBT based on power config (#1) * auto switch LBT based on config * changes after review Co-authored-by: Anders G <andlier@users.noreply.github.com> * add safe runtime disabling of LBT, since LBT routines fiddles with interrupt enable flags * make LBTEnable if else formatting more concise * Move LBTEnable flag and if-else logic into LBT.cpp, keeps tx/rx_main less cluttered * fixes after rebasing on master * Using flag to skip ISR instead of disabling interrupts while doing LBT * simplified LBT, attempts to be compatible with rx-auto-off timeout * add lbtstarted flag to allow calling beginCCA twice without restarting RX and timer * attempt at fixing listen before talk for 1:2 rate telemetry * Remove unused GetMode function in sx1280 driver and rename LBT flag variable for delayed call of TXdoneCallback. * Improvements after review LBT.h/cpp: remove uneccessary volatiles, add static to LBT internal variables. Remove LBTChannelBusy variable, use LQCALC currentIsSet for LBT success instead. Wrap LBT.h/cpp in #if defined REG_DOMAIN * POWERMGNT.h/cpp: Inline currPower * LBT: simplify calculation of remaining validRssiDelay wait time * Repurpose downlink LQ for LBT success ratio when EU reg domain defined * simplified LBTEnable functionality, does not need to be synchronized disabling Co-authored-by: Alexander van Saase <avsaase@gmail.com> Co-authored-by: Paul Kendall <pkendall64@gmail.com>
- Loading branch information
1 parent
0dbba4e
commit d543a81
Showing
10 changed files
with
222 additions
and
15 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
#if defined(Regulatory_Domain_EU_CE_2400) | ||
#include "common.h" | ||
#include "logging.h" | ||
#include "LBT.h" | ||
|
||
extern SX1280Driver Radio; | ||
|
||
LQCALC<100> LBTSuccessCalc; | ||
static uint32_t rxStartTime; | ||
|
||
#if !defined(LBT_RSSI_THRESHOLD_OFFSET_DB) | ||
#define LBT_RSSI_THRESHOLD_OFFSET_DB 0 | ||
#endif | ||
|
||
bool LBTEnabled = false; | ||
static bool LBTStarted = false; | ||
|
||
uint32_t ICACHE_RAM_ATTR SpreadingFactorToRSSIvalidDelayUs(SX1280_RadioLoRaSpreadingFactors_t SF) | ||
{ | ||
// The necessary wait time from RX start to valid instant RSSI reading | ||
// changes with the spreading factor setting. | ||
// The worst case necessary wait time is TX->RX switch time + Lora symbol time | ||
// This assumes the radio switches from either TX, RX or FS (Freq Synth mode) | ||
// TX to RX switch time is 60us for sx1280 | ||
// Lora symbol time for the relevant spreading factors is: | ||
// SF5: 39.4us | ||
// SF6: 78.8us | ||
// SF7: 157.6us | ||
// SF9: 630.5us | ||
// However, by measuring when the RSSI reading is stable and valid, it was found that | ||
// actual necessary wait times are: | ||
// SF5 ~100us (60us + SF5 symbol time) | ||
// SF6 ~141us (60us + SF6 symbol time) | ||
// SF7 ~218us (60us + SF7 symbol time) | ||
// SF9 ~218us (Odd one out, measured to same as SF7 wait time) | ||
|
||
switch(SF) | ||
{ | ||
case SX1280_LORA_SF5: return 100; | ||
case SX1280_LORA_SF6: return 141; | ||
case SX1280_LORA_SF7: return 218; | ||
case SX1280_LORA_SF9: return 218; | ||
default: return 218; // Values above 100mW are not relevant, default to 100mW threshold | ||
} | ||
} | ||
|
||
int8_t ICACHE_RAM_ATTR PowerEnumToLBTLimit(PowerLevels_e txPower) | ||
{ | ||
// Calculated from EN 300 328, adjusted for 800kHz BW for sx1280 | ||
// TL = -70 dBm/MHz + 10*log10(0.8MHz) + 10 × log10 (100 mW / Pout) (Pout in mW e.i.r.p.) | ||
// This threshold should be offset with a #define config for each HW that corrects for antenna gain, | ||
// different RF frontends. | ||
// TODO: Maybe individual adjustment offset for differences in | ||
// rssi reading between bandwidth setting is also necessary when other BW than 0.8MHz are used. | ||
|
||
switch(txPower) | ||
{ | ||
case PWR_10mW: return -61 + LBT_RSSI_THRESHOLD_OFFSET_DB; | ||
case PWR_25mW: return -65 + LBT_RSSI_THRESHOLD_OFFSET_DB; | ||
case PWR_50mW: return -68 + LBT_RSSI_THRESHOLD_OFFSET_DB; | ||
case PWR_100mW: return -71 + LBT_RSSI_THRESHOLD_OFFSET_DB; | ||
// Values above 100mW are not relevant, default to 100mW threshold | ||
default: return -71 + LBT_RSSI_THRESHOLD_OFFSET_DB; | ||
} | ||
} | ||
|
||
void ICACHE_RAM_ATTR BeginClearChannelAssessment(void) | ||
{ | ||
if (!LBTEnabled) | ||
{ | ||
return; | ||
} | ||
|
||
if(!LBTStarted) | ||
{ | ||
Radio.RXnb(); | ||
rxStartTime = micros(); | ||
LBTStarted = true; | ||
} | ||
} | ||
|
||
bool ICACHE_RAM_ATTR ChannelIsClear(void) | ||
{ | ||
LBTSuccessCalc.inc(); // Increment count for every channel check | ||
if (!LBTEnabled) | ||
{ | ||
LBTSuccessCalc.add(); | ||
return true; | ||
} | ||
|
||
LBTStarted = false; | ||
|
||
// Read rssi after waiting the minimum RSSI valid delay. | ||
// If this function is called long enough after RX enable, | ||
// this will always be ok on first try as is the case for TX. | ||
|
||
// TODO: Better way than busypolling this for RX? | ||
// this loop should only run for RX, where listen before talk RX is started right after FHSS hop | ||
// so there is no dead-time to run RX before telemetry TX is supposed to happen. | ||
// if flipping the logic, so telemetry TX happens right before FHSS hop, then TX-side ends up with polling here instead? | ||
// Maybe it could be skipped if there was only TX of telemetry happening when FHSShop does not happen. | ||
// Then RX for LBT could stay enabled from last received packet, and RSSI would be valid instantly. | ||
// But for now, FHSShops and telemetry rates does not divide evenly, so telemetry will some times happen | ||
// right after FHSS and we need wait here. | ||
|
||
uint32_t validRSSIdelayUs = SpreadingFactorToRSSIvalidDelayUs((SX1280_RadioLoRaSpreadingFactors_t)ExpressLRS_currAirRate_Modparams->sf); | ||
uint32_t elapsed = micros() - rxStartTime; | ||
if(elapsed < validRSSIdelayUs) | ||
{ | ||
delayMicroseconds(validRSSIdelayUs - elapsed); | ||
} | ||
|
||
int8_t rssiInst = Radio.GetRssiInst(); | ||
Radio.SetTxIdleMode(); | ||
bool channelClear = rssiInst < PowerEnumToLBTLimit((PowerLevels_e)POWERMGNT::currPower()); | ||
|
||
// Useful to debug if and how long the rssi wait is, and rssi threshold level | ||
// DBGLN("wait: %d, rssi: %d", delayRemaining, rssiInst); | ||
|
||
if(channelClear) | ||
{ | ||
LBTSuccessCalc.add(); // Add success only when actually preparing for TX | ||
} | ||
|
||
return channelClear; | ||
} | ||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
#if defined(Regulatory_Domain_EU_CE_2400) | ||
#pragma once | ||
|
||
#include "POWERMGNT.h" | ||
#include "LQCALC.h" | ||
#include "SX1280Driver.h" | ||
|
||
extern LQCALC<100> LBTSuccessCalc; | ||
extern bool LBTEnabled; | ||
|
||
uint32_t SpreadingFactorToRSSIvalidDelayUs(SX1280_RadioLoRaSpreadingFactors_t SF); | ||
int8_t ICACHE_RAM_ATTR PowerEnumToLBTLimit(PowerLevels_e txPower); | ||
void ICACHE_RAM_ATTR BeginClearChannelAssessment(void); | ||
bool ICACHE_RAM_ATTR ChannelIsClear(void); | ||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters