From 3cec3ac2a41b4133a5be3e37b3bcb7d6886c17d6 Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Wed, 30 Jun 2021 13:40:17 +1000 Subject: [PATCH] lora: detect failed transmissions Detect failed transmissions using `lora_send` by only waiting for some multiple of the actual on-air time before giving up. We use this instead of the inbuilt TxTimeout functionality because the value of this timeout is set by `lora_configure`, and therefore doesn't change with different packet lengths. This is a limitation of the underlying `RadioSend` function, not the Zephyr driver. Signed-off-by: Jordan Yates --- drivers/lora/sx12xx_common.c | 43 ++++++++++++++++++++++++++++++------ 1 file changed, 36 insertions(+), 7 deletions(-) diff --git a/drivers/lora/sx12xx_common.c b/drivers/lora/sx12xx_common.c index 28debdbd1f9..c0da1584b5f 100644 --- a/drivers/lora/sx12xx_common.c +++ b/drivers/lora/sx12xx_common.c @@ -32,6 +32,7 @@ struct sx12xx_rx_params { static struct sx12xx_data { struct k_poll_signal *operation_done; RadioEvents_t events; + struct lora_modem_config tx_cfg; atomic_t modem_usage; struct sx12xx_rx_params rx_params; } dev_data; @@ -144,11 +145,11 @@ static void sx12xx_ev_tx_done(void) { struct k_poll_signal *sig = dev_data.operation_done; - modem_release(&dev_data); - - /* Raise signal if provided */ - if (sig) { - k_poll_signal_raise(sig, 0); + if (modem_release(&dev_data)) { + /* Raise signal if provided */ + if (sig) { + k_poll_signal_raise(sig, 0); + } } } @@ -160,16 +161,41 @@ int sx12xx_lora_send(const struct device *dev, uint8_t *data, K_POLL_TYPE_SIGNAL, K_POLL_MODE_NOTIFY_ONLY, &done); + uint32_t air_time; int ret; + /* Validate that we have a TX configuration */ + if (!dev_data.tx_cfg.frequency) { + return -EINVAL; + } + ret = sx12xx_lora_send_async(dev, data, data_len, &done); if (ret < 0) { return ret; } - /* Wait for transmission to complete */ - k_poll(&evt, 1, K_FOREVER); + /* Calculate expected airtime of the packet */ + air_time = Radio.TimeOnAir(MODEM_LORA, + dev_data.tx_cfg.bandwidth, + dev_data.tx_cfg.datarate, + dev_data.tx_cfg.coding_rate, + dev_data.tx_cfg.preamble_len, + 0, data_len, true); + LOG_DBG("Expected air time of %d bytes = %dms", data_len, air_time); + /* Wait for the packet to finish transmitting. + * Use twice the tx duration to ensure that we are actually detecting + * a failed transmission, and not some minor timing variation between + * modem and driver. + */ + ret = k_poll(&evt, 1, K_MSEC(2 * air_time)); + if (ret < 0) { + LOG_ERR("Packet transmission failed!"); + if (!modem_release(&dev_data)) { + /* TX done interrupt is currently running */ + k_poll(&evt, 1, K_FOREVER); + } + } return 0; } @@ -247,6 +273,9 @@ int sx12xx_lora_config(const struct device *dev, Radio.SetChannel(config->frequency); if (config->tx) { + /* Store TX config locally for airtime calculations */ + memcpy(&dev_data.tx_cfg, config, sizeof(dev_data.tx_cfg)); + /* Configure radio driver */ Radio.SetTxConfig(MODEM_LORA, config->tx_power, 0, config->bandwidth, config->datarate, config->coding_rate, config->preamble_len,