mirror of
https://github.com/mikecarper/MeshCore.git
synced 2026-09-09 16:55:35 +00:00
Fixed LR1110 RX duty-cycle setup and calibration. Noise floor calibration is now performed right after radio module start.
This commit is contained in:
@@ -27,13 +27,26 @@ class CustomLR1110 : public LR1110 {
|
||||
int16_t startReceiveDutyCycle(uint32_t rxPeriod, uint32_t sleepPeriod,
|
||||
RadioLibIrqFlags_t irqFlags = RADIOLIB_IRQ_RX_DEFAULT_FLAGS,
|
||||
RadioLibIrqFlags_t irqMask = RADIOLIB_IRQ_RX_DEFAULT_MASK) {
|
||||
// RadioLib's LR11x0 duty-cycle path stages RX but does not call
|
||||
// launchMode(), where the software RF switch is normally set to RX.
|
||||
uint32_t symbolPeriod = (uint32_t)(((1000.0f * (float)(1UL << this->spreadingFactor)) /
|
||||
this->bandwidthKhz) + 0.999f);
|
||||
uint32_t transitionTime = this->tcxoDelay + 1000;
|
||||
sleepPeriod -= transitionTime;
|
||||
if (sleepPeriod <= transitionTime) {
|
||||
return RADIOLIB_ERR_INVALID_SLEEP_PERIOD;
|
||||
}
|
||||
uint32_t programmedSleepPeriod = sleepPeriod - transitionTime;
|
||||
|
||||
uint32_t rxPeriodRaw = (rxPeriod * 32768UL) / 1000000UL;
|
||||
uint32_t sleepPeriodRaw = (sleepPeriod * 32768UL) / 1000000UL;
|
||||
// PreambleDetected restarts the timeout at 2*rx + sleep. LR1110 testing
|
||||
// established 78 ms RX / 26.851 ms sleep as the production minimum at
|
||||
// SF8, BW 62.5 kHz. Preamble + 11 symbols plus 1 ms preserves that margin.
|
||||
uint64_t requiredExtendedPeriod =
|
||||
((uint64_t)this->preambleLengthLoRa + 11ULL) * symbolPeriod + 1000ULL;
|
||||
uint64_t extendedPeriod = 2ULL * rxPeriod + programmedSleepPeriod;
|
||||
if (extendedPeriod < requiredExtendedPeriod) {
|
||||
rxPeriod = (uint32_t)((requiredExtendedPeriod - programmedSleepPeriod + 1ULL) / 2ULL);
|
||||
}
|
||||
|
||||
uint32_t rxPeriodRaw = (uint32_t)(((uint64_t)rxPeriod * 32768UL) / 1000000UL);
|
||||
uint32_t sleepPeriodRaw = (uint32_t)(((uint64_t)programmedSleepPeriod * 32768UL) / 1000000UL);
|
||||
|
||||
if ((rxPeriodRaw & 0xFF000000) || (rxPeriodRaw == 0)) {
|
||||
return RADIOLIB_ERR_INVALID_RX_PERIOD;
|
||||
@@ -43,6 +56,13 @@ class CustomLR1110 : public LR1110 {
|
||||
return RADIOLIB_ERR_INVALID_SLEEP_PERIOD;
|
||||
}
|
||||
|
||||
// Semtech requires Standby RC and an explicitly configured RTC source
|
||||
// before SetRxDutyCycle. RadioLib does neither in its LoRa RXPS path.
|
||||
int16_t state = standby(RADIOLIB_LR11X0_STANDBY_RC);
|
||||
RADIOLIB_ASSERT(state);
|
||||
state = configLfClock(RADIOLIB_LR11X0_LF_CLK_RC | RADIOLIB_LR11X0_LF_BUSY_RELEASE_ENABLED);
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
RadioModeConfig_t cfg = {
|
||||
.receive = {
|
||||
.timeout = RADIOLIB_LR11X0_RX_TIMEOUT_INF,
|
||||
@@ -51,10 +71,11 @@ class CustomLR1110 : public LR1110 {
|
||||
.len = 0,
|
||||
}
|
||||
};
|
||||
int16_t state = this->stageMode(RADIOLIB_RADIO_MODE_RX, &cfg);
|
||||
state = this->stageMode(RADIOLIB_RADIO_MODE_RX, &cfg);
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
this->mod->setRfSwitchState(Module::MODE_RX);
|
||||
// Send the already converted values. RadioLib 7.7.1 converts them again
|
||||
// with 32-bit arithmetic, which overflows for periods above about 131 ms.
|
||||
return this->setRxDutyCycle(rxPeriodRaw, sleepPeriodRaw, RADIOLIB_LR11X0_RX_DUTY_CYCLE_MODE_RX);
|
||||
}
|
||||
|
||||
|
||||
@@ -163,7 +163,7 @@ void RadioLibWrapper::rxPsWatchdogCheck() {
|
||||
}
|
||||
}
|
||||
|
||||
// Periodic noise-floor calibration, active only with RX duty-cycle powersaving:
|
||||
// Initial and periodic noise-floor calibration, active only with RX duty-cycle powersaving:
|
||||
// a duty-cycled receiver can't be sampled reliably (the frontend is off in the
|
||||
// sleep windows and settling right after each wake), so at least once a minute
|
||||
// the receive mode is dropped to plain continuous RX, a fresh sample batch is
|
||||
@@ -178,7 +178,7 @@ void RadioLibWrapper::noiseFloorCalibCheck() {
|
||||
endNoiseFloorCalib(now);
|
||||
}
|
||||
} else if (_rx_ps_enabled && _rx_ps_armed && state == STATE_RX
|
||||
&& now - _nf_last_calib >= NF_CALIB_INTERVAL_MS
|
||||
&& (_nf_last_calib == 0 || now - _nf_last_calib >= NF_CALIB_INTERVAL_MS)
|
||||
&& !isReceivingPacket()) {
|
||||
// never interrupt an ongoing reception to calibrate (a TX in flight is
|
||||
// already excluded by state == STATE_RX); retries next loop iteration
|
||||
|
||||
@@ -48,11 +48,10 @@ protected:
|
||||
int8_t _cur_dbm;
|
||||
bool _params_valid, _dbm_valid;
|
||||
|
||||
// Periodic noise-floor calibration (only while RX duty-cycle powersaving is
|
||||
// armed): a duty-cycled receiver can't be sampled reliably, so at least once
|
||||
// a minute the wrapper drops to plain continuous RX, collects a fresh sample
|
||||
// batch exactly like the non-powersaving path does, publishes the average
|
||||
// into _noise_floor and re-arms the duty cycle.
|
||||
// Initial and periodic noise-floor calibration (only while RX duty-cycle
|
||||
// powersaving is armed): a duty-cycled receiver can't be sampled reliably,
|
||||
// so at least once a minute the wrapper drops to plain continuous RX,
|
||||
// collects a fresh sample batch, publishes it and re-arms the duty cycle.
|
||||
bool _nf_calib_active;
|
||||
unsigned long _nf_last_calib; // millis of last completed/attempted window
|
||||
unsigned long _nf_calib_deadline; // abort window if the batch can't complete
|
||||
|
||||
Reference in New Issue
Block a user