mirror of
https://github.com/liquidraver/ZephCore.git
synced 2026-09-01 21:08:19 +00:00
rx duty cycle rework
This commit is contained in:
@@ -143,10 +143,6 @@ void LoRaRadioBase::rxCallbackStatic(const struct device *dev, uint8_t *data,
|
||||
self->_packets_recv_errors++;
|
||||
LOG_DBG("RX error (CRC/header), total errors: %u",
|
||||
self->_packets_recv_errors);
|
||||
/* Driver restarted with Radio.Rx(0) — restore duty cycle */
|
||||
if (self->_rx_duty_cycle_enabled) {
|
||||
self->hwSetRxDutyCycle(true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -159,11 +155,6 @@ void LoRaRadioBase::rxCallbackStatic(const struct device *dev, uint8_t *data,
|
||||
if (next_head == self->_rx_tail) {
|
||||
LOG_WRN("RX ring full, dropping new packet");
|
||||
self->_packets_recv_errors++;
|
||||
/* Still restore duty cycle and notify — main loop should
|
||||
* drain faster next time. */
|
||||
if (self->_rx_duty_cycle_enabled) {
|
||||
self->hwSetRxDutyCycle(true);
|
||||
}
|
||||
if (self->_rx_cb) {
|
||||
self->_rx_cb(self->_rx_cb_user_data);
|
||||
}
|
||||
@@ -182,11 +173,6 @@ void LoRaRadioBase::rxCallbackStatic(const struct device *dev, uint8_t *data,
|
||||
self->_last_snr = (float)snr;
|
||||
self->_packets_recv++;
|
||||
|
||||
/* Driver restarted with Radio.Rx(0) — restore duty cycle */
|
||||
if (self->_rx_duty_cycle_enabled) {
|
||||
self->hwSetRxDutyCycle(true);
|
||||
}
|
||||
|
||||
if (self->_rx_cb) {
|
||||
self->_rx_cb(self->_rx_cb_user_data);
|
||||
}
|
||||
|
||||
@@ -259,35 +259,16 @@ static void lr11xx_apply_modem_config(struct lr11xx_data *data,
|
||||
0);
|
||||
}
|
||||
|
||||
/* ── CAD det_peak lookup (from Semtech ral_lr11xx reference) ─────────── */
|
||||
/* ── RX duty cycle (RadioLib algorithm, same as SX126x) ─────────────── */
|
||||
|
||||
static uint8_t lr11xx_cad_det_peak(uint8_t sf, enum lora_signal_bandwidth bw)
|
||||
{
|
||||
static const uint8_t peak_bw500[] = {
|
||||
/* SF5 SF6 SF7 SF8 SF9 SF10 SF11 SF12 */
|
||||
65, 70, 77, 85, 78, 80, 79, 82
|
||||
};
|
||||
static const uint8_t peak_bw250[] = {
|
||||
60, 61, 64, 72, 63, 71, 73, 75
|
||||
};
|
||||
static const uint8_t peak_bw125[] = {
|
||||
56, 52, 52, 58, 58, 62, 66, 68
|
||||
};
|
||||
/* Same algorithm as SX126x SetRxDutyCycle — standard RX during the wake
|
||||
* window, full demodulation capability. Preamble detected → hardware
|
||||
* extends timeout to receive the complete packet. No activity → back
|
||||
* to sleep. Identical detection reliability to the SX126x driver. */
|
||||
|
||||
if (sf < 5 || sf > 12) return 0x32;
|
||||
uint8_t idx = sf - 5;
|
||||
|
||||
if (bw >= BW_500_KHZ) return peak_bw500[idx];
|
||||
if (bw >= BW_250_KHZ) return peak_bw250[idx];
|
||||
return peak_bw125[idx];
|
||||
}
|
||||
|
||||
/* ── RX duty cycle (hardware CAD mode) ──────────────────────────────── */
|
||||
|
||||
/* LR1110 native CAD duty cycle: on each wake the chip runs a fast CAD
|
||||
* (~2 symbols) instead of full RX. Preamble detected → auto-RX with
|
||||
* extended timeout. No activity → straight back to sleep. The entire
|
||||
* loop runs in HW with zero IRQ overhead per cycle. */
|
||||
#define LR11XX_DC_MIN_SYMBOLS_SF7_PLUS 8
|
||||
#define LR11XX_DC_MIN_SYMBOLS_SF6_LESS 12
|
||||
#define LR11XX_DC_TCXO_DELAY_US 1000
|
||||
|
||||
static void lr11xx_apply_rx_duty_cycle(struct lr11xx_data *data)
|
||||
{
|
||||
@@ -298,55 +279,50 @@ static void lr11xx_apply_rx_duty_cycle(struct lr11xx_data *data)
|
||||
float bw_khz = bw_enum_to_khz(mc->bandwidth);
|
||||
uint16_t preamble_len = mc->preamble_len;
|
||||
|
||||
/* Margin must cover:
|
||||
* 2 sym CAD scan duration (cad_symb_nb = 2 symbols)
|
||||
* 4 sym demodulator preamble acquisition (~4.25 sym minimum)
|
||||
* 4 sym RTC jitter + TCXO startup + state transitions
|
||||
* ─────
|
||||
* 10 sym total — matches the SX126x driver margin and ensures
|
||||
* ≥6 symbols of preamble remain after worst-case wake.
|
||||
*
|
||||
* The original margin of 4 left only ~2 usable symbols — any TCXO
|
||||
* startup or timer jitter caused missed packets. */
|
||||
uint32_t symbol_us = (uint32_t)((float)(1 << sf) * 1000.0f / bw_khz);
|
||||
int16_t margin = 10;
|
||||
int16_t sleep_symbols = (int16_t)preamble_len - margin;
|
||||
uint16_t min_symbols = (sf >= 7) ? LR11XX_DC_MIN_SYMBOLS_SF7_PLUS
|
||||
: LR11XX_DC_MIN_SYMBOLS_SF6_LESS;
|
||||
|
||||
if (sleep_symbols < 2) {
|
||||
LOG_WRN("Preamble too short for CAD duty cycle (%d sym), "
|
||||
"continuous RX", preamble_len);
|
||||
int16_t sleep_symbols = (int16_t)preamble_len - (int16_t)min_symbols;
|
||||
if (sleep_symbols <= 0) {
|
||||
LOG_WRN("Preamble too short for duty cycle (need >%d, have %d)",
|
||||
min_symbols, preamble_len);
|
||||
data->rx_duty_cycle_enabled = false;
|
||||
lr11xx_radio_set_rx(ctx, 0xFFFFFF);
|
||||
return;
|
||||
}
|
||||
|
||||
/* CAD params: 2 symbols, Semtech det_peak table, auto-RX on detect */
|
||||
uint8_t det_peak = lr11xx_cad_det_peak(sf, mc->bandwidth);
|
||||
lr11xx_radio_cad_params_t cad = {
|
||||
.cad_symb_nb = 1, /* enum: 1 = 2 symbols */
|
||||
.cad_detect_peak = det_peak,
|
||||
.cad_detect_min = 10,
|
||||
.cad_exit_mode = LR11XX_RADIO_CAD_EXIT_MODE_RX,
|
||||
.cad_timeout = 0,
|
||||
};
|
||||
lr11xx_radio_set_cad_params(ctx, &cad);
|
||||
uint32_t symbol_us = (uint32_t)((float)(1 << sf) * 1000.0f / bw_khz);
|
||||
|
||||
uint32_t sleep_us = (uint16_t)sleep_symbols * symbol_us;
|
||||
/* Shave 2 symbols off sleep for timing margin */
|
||||
int16_t sleep_symbols_safe = sleep_symbols - 2;
|
||||
if (sleep_symbols_safe < 1) {
|
||||
sleep_symbols_safe = 1;
|
||||
}
|
||||
uint32_t sleep_period_us = (uint16_t)sleep_symbols_safe * symbol_us;
|
||||
|
||||
/* RX period: on CAD detect, chip enters RX for (2*rx + sleep).
|
||||
* Must cover remaining preamble + sync word + header. */
|
||||
uint32_t rx_us = (preamble_len + 1) * symbol_us;
|
||||
uint32_t preamble_total_us = (preamble_len + 1) * symbol_us;
|
||||
int32_t wake_calc1 = ((int32_t)preamble_total_us -
|
||||
((int32_t)sleep_period_us - LR11XX_DC_TCXO_DELAY_US)) / 2;
|
||||
uint32_t wake_calc2 = (min_symbols + 1) * symbol_us;
|
||||
|
||||
uint32_t rx_ms = (rx_us + 500) / 1000;
|
||||
uint32_t sleep_ms = (sleep_us + 500) / 1000;
|
||||
if (rx_ms < 1) rx_ms = 1;
|
||||
if (sleep_ms < 1) sleep_ms = 1;
|
||||
uint32_t wake_period_us = (wake_calc1 > 0 && (uint32_t)wake_calc1 > wake_calc2)
|
||||
? (uint32_t)wake_calc1 : wake_calc2;
|
||||
|
||||
/* LR1110 API takes milliseconds (converted to RTC steps internally) */
|
||||
uint32_t rx_ms = (wake_period_us + 500) / 1000;
|
||||
uint32_t sleep_ms = (sleep_period_us + 500) / 1000;
|
||||
if (rx_ms < 1) {
|
||||
rx_ms = 1;
|
||||
}
|
||||
if (sleep_ms < 1) {
|
||||
sleep_ms = 1;
|
||||
}
|
||||
|
||||
lr11xx_radio_set_rx_duty_cycle(ctx, rx_ms, sleep_ms,
|
||||
LR11XX_RADIO_RX_DUTY_CYCLE_MODE_CAD);
|
||||
LR11XX_RADIO_RX_DUTY_CYCLE_MODE_RX);
|
||||
|
||||
LOG_INF("RX CAD duty cycle: rx=%ums sleep=%ums peak=%u (SF%d BW%.0f)",
|
||||
rx_ms, sleep_ms, det_peak, sf, (double)bw_khz);
|
||||
LOG_INF("RX duty cycle: rx=%ums sleep=%ums (SF%d BW%.0f)",
|
||||
rx_ms, sleep_ms, sf, (double)bw_khz);
|
||||
}
|
||||
|
||||
/* ── Start RX (internal) ────────────────────────────────────────────── */
|
||||
|
||||
@@ -634,11 +634,9 @@ int main(void)
|
||||
}
|
||||
}
|
||||
|
||||
/* Apply RX boost from prefs. Duty cycle is disabled — CAD-based
|
||||
* duty cycling misses weak packets that continuous RX would catch.
|
||||
* Arduino reference uses continuous RX for all boards. */
|
||||
/* Apply RX boost and duty cycle from prefs */
|
||||
lora_radio.setRxBoost(companion_mesh.prefs.rx_boost != 0);
|
||||
lora_radio.enableRxDutyCycle(false);
|
||||
lora_radio.enableRxDutyCycle(companion_mesh.prefs.rx_duty_cycle != 0);
|
||||
|
||||
/* Initialize mesh event object */
|
||||
k_event_init(&mesh_events);
|
||||
|
||||
@@ -474,11 +474,9 @@ int main(void)
|
||||
}
|
||||
}
|
||||
|
||||
/* Apply RX boost from prefs. Duty cycle is disabled — CAD-based
|
||||
* duty cycling misses weak packets that continuous RX would catch.
|
||||
* Arduino reference uses continuous RX for all boards. */
|
||||
/* Apply RX boost and duty cycle from prefs */
|
||||
lora_radio.setRxBoost(prefs->rx_boost != 0);
|
||||
lora_radio.enableRxDutyCycle(false);
|
||||
lora_radio.enableRxDutyCycle(prefs->rx_duty_cycle != 0);
|
||||
|
||||
/* Feed initial UI state from loaded prefs */
|
||||
ui_set_node_name(prefs->node_name);
|
||||
|
||||
Reference in New Issue
Block a user