fix sx1262 cad timeout issue

This commit is contained in:
liquidraver
2026-09-02 15:37:07 +02:00
parent dc143b7bea
commit 4b497d66a4
@@ -577,7 +577,7 @@ Regenerate with:
appended to this preamble.
diff --git a/drivers/lora/native/sx126x/sx126x.c b/drivers/lora/native/sx126x/sx126x.c
index 30243ba5dc7..a2c57493caf 100644
index 30243ba5dc7..d512fb59afc 100644
--- a/drivers/lora/native/sx126x/sx126x.c
+++ b/drivers/lora/native/sx126x/sx126x.c
@@ -6,72 +6,236 @@
@@ -1787,7 +1787,7 @@ index 30243ba5dc7..a2c57493caf 100644
sx126x_set_sleep(dev);
if (data->tx_async_signal != NULL) {
@@ -630,13 +1548,80 @@ static void sx126x_irq_work_handler(struct k_work *work)
@@ -630,13 +1548,97 @@ static void sx126x_irq_work_handler(struct k_work *work)
}
if (irq_status & SX126X_IRQ_RX_DONE) {
@@ -1817,7 +1817,24 @@ index 30243ba5dc7..a2c57493caf 100644
+ * negative CAD_RX exits to STDBY_RC exactly like CAD_ONLY, so
+ * there is nothing to track. */
+ if (data->cad_exit_rx && detected) {
+ /* CAD_ONLY has left the chip in STDBY_RC (DS 13.1.8), so
+ * arm the follow-on Rx ourselves with an explicit
+ * SetRx(timeout). That re-invokes and re-programs the RTC,
+ * which is exactly what cadTimeout fails to do after
+ * SetRxDutyCycle -- so the terminal IRQ (RX_DONE, CRC_ERR or
+ * RX_TX_TIMEOUT) is genuinely guaranteed here, duty cycle or
+ * not. Bound is max-length-packet airtime +25% +100 ms, the
+ * same figure cadTimeout used, so a real packet still
+ * completes inside it. Cost is the ~1 ms of SPI between
+ * CAD_DONE and Rx, well inside the (P-8)-symbol preamble
+ * budget the probe already spends. */
+ uint8_t rxbuf[3];
+ uint32_t tmo = SX126X_MS_TO_TIMEOUT(
+ sx126x_max_payload_ms(data));
+
+ sys_put_be24(tmo & 0xFFFFFFU, rxbuf);
+ atomic_set(&data->cad_rx_state, SX126X_CAD_RX_ARMED);
+ sx126x_hal_write_cmd(dev, SX126X_CMD_SET_RX, rxbuf, 3);
+ }
+
+ if (data->cad_cb) {
@@ -1868,7 +1885,7 @@ index 30243ba5dc7..a2c57493caf 100644
/* Re-enable the DIO1 interrupt for the next event (unless sleeping) */
if (atomic_get(&data->state) != SX126X_REST_STATE) {
sx126x_hal_dio1_irq_enable(dev);
@@ -648,6 +1633,7 @@ static int sx126x_lora_config(const struct device *dev,
@@ -648,6 +1650,7 @@ static int sx126x_lora_config(const struct device *dev,
{
struct sx126x_data *data = dev->data;
const struct sx126x_hal_config *hal_config = dev->config;
@@ -1876,11 +1893,14 @@ index 30243ba5dc7..a2c57493caf 100644
bool ldro;
int ret;
@@ -679,25 +1665,45 @@ static int sx126x_lora_config(const struct device *dev,
@@ -679,25 +1682,45 @@ static int sx126x_lora_config(const struct device *dev,
goto out;
}
- /* Configure PA and TX power based on chip variant and frequency */
- ret = sx126x_hal_configure_tx_params(dev, config->tx_power,
- config->frequency,
- SX126X_RAMP_200_US);
+ /* Install the band's RSSI/AGC calibration (DS Sec 6.1.6) before the
+ * RX gain write below, which consumes the AgcSensiAdjust this caches.
+ * Re-run on every config so a runtime frequency change switches bands
@@ -1891,9 +1911,8 @@ index 30243ba5dc7..a2c57493caf 100644
+ }
+
+ /* Configure PA and TX power based on chip variant and frequency */
ret = sx126x_hal_configure_tx_params(dev, config->tx_power,
config->frequency,
- SX126X_RAMP_200_US);
+ ret = sx126x_hal_configure_tx_params(dev, config->tx_power,
+ config->frequency,
+ SX126X_TX_RAMP_TIME);
if (ret < 0) {
goto out;
@@ -1925,7 +1944,7 @@ index 30243ba5dc7..a2c57493caf 100644
/* Set sync word */
ret = sx126x_set_sync_word(dev, config->public_network);
if (ret < 0) {
@@ -721,6 +1727,10 @@ out:
@@ -721,6 +1744,10 @@ out:
return ret;
}
@@ -1936,7 +1955,7 @@ index 30243ba5dc7..a2c57493caf 100644
static int sx126x_lora_send_async(const struct device *dev,
uint8_t *data_buf, uint32_t data_len,
struct k_poll_signal *async)
@@ -738,11 +1748,27 @@ static int sx126x_lora_send_async(const struct device *dev,
@@ -738,11 +1765,27 @@ static int sx126x_lora_send_async(const struct device *dev,
return -EINVAL;
}
@@ -1966,7 +1985,7 @@ index 30243ba5dc7..a2c57493caf 100644
k_mutex_lock(&data->lock, K_FOREVER);
ret = sx126x_ensure_ready(dev);
@@ -752,6 +1778,59 @@ static int sx126x_lora_send_async(const struct device *dev,
@@ -752,6 +1795,59 @@ static int sx126x_lora_send_async(const struct device *dev,
return ret;
}
@@ -2026,7 +2045,7 @@ index 30243ba5dc7..a2c57493caf 100644
data->tx_async_signal = async;
k_msgq_purge(&data->tx_msgq);
@@ -777,8 +1856,99 @@ static int sx126x_lora_send_async(const struct device *dev,
@@ -777,8 +1873,99 @@ static int sx126x_lora_send_async(const struct device *dev,
/* Enable antenna and set TX path */
sx126x_set_rf_path(dev, true, true);
@@ -2128,7 +2147,7 @@ index 30243ba5dc7..a2c57493caf 100644
if (ret < 0) {
goto out_error;
}
@@ -847,6 +2017,8 @@ static int sx126x_lora_recv(const struct device *dev, uint8_t *data_buf,
@@ -847,6 +2034,8 @@ static int sx126x_lora_recv(const struct device *dev, uint8_t *data_buf,
}
data->rx_cb = NULL;
@@ -2137,7 +2156,7 @@ index 30243ba5dc7..a2c57493caf 100644
k_msgq_purge(&data->rx_msgq);
/* Set packet parameters for variable length reception */
@@ -918,6 +2090,8 @@ static int sx126x_lora_recv_async(const struct device *dev,
@@ -918,6 +2107,8 @@ static int sx126x_lora_recv_async(const struct device *dev,
/* Stop async reception */
data->rx_cb = NULL;
data->rx_cb_user_data = NULL;
@@ -2146,7 +2165,7 @@ index 30243ba5dc7..a2c57493caf 100644
if (atomic_cas(&data->state, SX126X_STATE_RX, SX126X_STATE_IDLE)) {
sx126x_set_standby(dev, SX126X_STANDBY_RC);
sx126x_set_sleep(dev);
@@ -932,6 +2106,19 @@ static int sx126x_lora_recv_async(const struct device *dev,
@@ -932,6 +2123,19 @@ static int sx126x_lora_recv_async(const struct device *dev,
return -EINVAL;
}
@@ -2166,7 +2185,7 @@ index 30243ba5dc7..a2c57493caf 100644
if (!atomic_cas(&data->state, SX126X_REST_STATE, SX126X_STATE_RX)) {
LOG_ERR("Busy");
k_mutex_unlock(&data->lock);
@@ -945,8 +2132,18 @@ static int sx126x_lora_recv_async(const struct device *dev,
@@ -945,8 +2149,18 @@ static int sx126x_lora_recv_async(const struct device *dev,
return ret;
}
@@ -2185,7 +2204,7 @@ index 30243ba5dc7..a2c57493caf 100644
/* Set packet parameters */
ret = sx126x_set_packet_params(dev,
@@ -959,6 +2156,7 @@ static int sx126x_lora_recv_async(const struct device *dev,
@@ -959,6 +2173,7 @@ static int sx126x_lora_recv_async(const struct device *dev,
SX126X_LORA_IQ_INVERTED : SX126X_LORA_IQ_STANDARD);
if (ret < 0) {
data->rx_cb = NULL;
@@ -2193,7 +2212,7 @@ index 30243ba5dc7..a2c57493caf 100644
sx126x_set_sleep(dev);
k_mutex_unlock(&data->lock);
return ret;
@@ -971,11 +2169,21 @@ static int sx126x_lora_recv_async(const struct device *dev,
@@ -971,11 +2186,21 @@ static int sx126x_lora_recv_async(const struct device *dev,
ret = sx126x_set_rx(dev, 0);
if (ret < 0) {
data->rx_cb = NULL;
@@ -2215,7 +2234,7 @@ index 30243ba5dc7..a2c57493caf 100644
k_mutex_unlock(&data->lock);
return 0;
}
@@ -993,7 +2201,9 @@ static uint32_t sx126x_lora_airtime(const struct device *dev, uint32_t data_len)
@@ -993,7 +2218,9 @@ static uint32_t sx126x_lora_airtime(const struct device *dev, uint32_t data_len)
}
/* Calculate symbol time in microseconds */
@@ -2226,7 +2245,7 @@ index 30243ba5dc7..a2c57493caf 100644
sf = data->config.datarate;
/* Symbol time = 2^SF / BW (seconds) */
@@ -1051,7 +2261,7 @@ static int sx126x_lora_test_cw(const struct device *dev, uint32_t frequency,
@@ -1051,7 +2278,7 @@ static int sx126x_lora_test_cw(const struct device *dev, uint32_t frequency,
/* Set PA config and TX power */
ret = sx126x_hal_configure_tx_params(dev, tx_power, frequency,
@@ -2235,7 +2254,7 @@ index 30243ba5dc7..a2c57493caf 100644
if (ret < 0) {
sx126x_set_sleep(dev);
k_mutex_unlock(&data->lock);
@@ -1083,14 +2293,1067 @@ static int sx126x_lora_test_cw(const struct device *dev, uint32_t frequency,
@@ -1083,14 +2310,1076 @@ static int sx126x_lora_test_cw(const struct device *dev, uint32_t frequency,
return 0;
}
@@ -2837,13 +2856,22 @@ index 30243ba5dc7..a2c57493caf 100644
+ * It is a chip-side deadline that always raises RX_TX_TIMEOUT, which is
+ * what lets the outcome be *observed* rather than polled for. */
+ uint8_t buf[7];
+ uint32_t cad_timeout = data->cad_exit_rx
+ ? SX126X_MS_TO_TIMEOUT(sx126x_max_payload_ms(data)) : 0U;
+ /* Always CAD_ONLY on the wire. cadTimeout is NOT honoured once
+ * SetRxDutyCycle has run -- the DS command table says that command
+ * "stores values of RTC setup for listen mode", and errata 15.3 notes a
+ * stale RTC misbehaves in "any subsequent mode where the RTC isn't
+ * re-invoked, and therefore reset and re-programmed". A CAD_RX exit
+ * does not re-program it, so on a duty-cycled node the chip entered Rx
+ * unbounded and no terminal IRQ ever arrived (measured: GetStatus 0x52
+ * = RX, IRQ register 0x0000, long past even a 500 ms cadTimeout).
+ * The probe therefore arms its Rx explicitly after CAD_DONE instead --
+ * see the cad_exit_rx branch in the DIO1 work handler. */
+ uint32_t cad_timeout = 0U;
+
+ buf[0] = symb_nb;
+ buf[1] = detect_peak;
+ buf[2] = mc->cad.detection_minimum ? mc->cad.detection_minimum : 10;
+ buf[3] = data->cad_exit_rx ? 0x01 : 0x00; /* CAD_RX : CAD_ONLY */
+ buf[3] = 0x00; /* CAD_ONLY -- see the cad_timeout note above */
+ sys_put_be24(cad_timeout & 0xFFFFFFU, &buf[4]);
+
+ ret = sx126x_hal_write_cmd(dev, SX126X_CMD_SET_CAD_PARAMS, buf, 7);
@@ -3310,7 +3338,7 @@ index 30243ba5dc7..a2c57493caf 100644
};
#ifdef CONFIG_PM_DEVICE
@@ -1112,6 +3375,7 @@ static int sx126x_pm_action(const struct device *dev,
@@ -1112,6 +3401,7 @@ static int sx126x_pm_action(const struct device *dev,
static int sx126x_init(const struct device *dev)
{
struct sx126x_data *data = dev->data;
@@ -3318,7 +3346,7 @@ index 30243ba5dc7..a2c57493caf 100644
int ret;
/* Initialize data structures */
@@ -1121,9 +3385,33 @@ static int sx126x_init(const struct device *dev)
@@ -1121,9 +3411,33 @@ static int sx126x_init(const struct device *dev)
k_msgq_init(&data->rx_msgq, (char *)&data->rx_result,
sizeof(struct sx126x_rx_result), 1);
k_work_init(&data->irq_work, sx126x_irq_work_handler);
@@ -3352,7 +3380,7 @@ index 30243ba5dc7..a2c57493caf 100644
/* Initialize HAL */
ret = sx126x_hal_init(dev);
@@ -1185,6 +3473,8 @@ static int sx126x_init(const struct device *dev)
@@ -1185,6 +3499,8 @@ static int sx126x_init(const struct device *dev)
{0}), \
.rx_enable = GPIO_DT_SPEC_INST_GET_OR(inst, rx_enable_gpios, \
{0}), \
@@ -3361,7 +3389,7 @@ index 30243ba5dc7..a2c57493caf 100644
.dio2_tx_enable = DT_INST_PROP(inst, dio2_tx_enable), \
.dio3_tcxo_enable = DT_INST_NODE_HAS_PROP(inst, dio3_tcxo_voltage), \
.dio3_tcxo_voltage = DT_INST_PROP_OR(inst, dio3_tcxo_voltage, 0), \
@@ -1239,6 +3529,8 @@ DT_INST_FOREACH_STATUS_OKAY_VARGS(SX126X_INIT, true)
@@ -1239,6 +3555,8 @@ DT_INST_FOREACH_STATUS_OKAY_VARGS(SX126X_INIT, true)
{0}), \
.rx_enable = GPIO_DT_SPEC_INST_GET_OR(inst, rx_enable_gpios, \
{0}), \