disable default duty cycling + SX driver fixes

This commit is contained in:
liquidraver committed 2026-05-05 21:56:00 +02:00
1 parent 5e7adfb130
commit 6bc3ba7405
5 files changed
+57 -35

No files matched your search

+5 -4
View File
@@ -393,17 +393,18 @@ menu "LoRa Power Saving"
config ZEPHCORE_LORA_RX_DUTY_CYCLE
bool "Enable LoRa RX duty cycle power saving"
default y if (ZEPHCORE_ROLE_COMPANION || ZEPHCORE_ROLE_REPEATER) && !ZEPHCORE_RADIO_LR1110 && !ZEPHCORE_RADIO_LR2021 && !ZEPHCORE_RADIO_SX127X
default n
help
Enable RX duty cycling for power saving on battery-powered devices.
Uses RadioLib's algorithm to calculate optimal timing based on SF/BW.
Auto-enabled for companion and repeater devices with SX1262/LLCC68
radios. Duty cycle mode also resets AGC state after every received
Disabled by default for all roles. Enable manually if you want
power savings and have verified acceptable packet loss/latency for
your environment and radio.
Duty cycle mode also resets AGC state after every received
packet via Calibrate(ALL), preventing the "near-far" gain-lock
problem where a strong signal desensitises the receiver.
Disabled for LR1110 (cannot lock on mid-preamble, causes packet
Still disabled for LR1110 (cannot lock on mid-preamble, causes packet
loss) and LR2021 (untested — enable manually after verifying no
packet loss). Can be toggled at runtime via CLI.
+7 -6
View File
@@ -137,9 +137,6 @@ bool RepeaterDataStore::loadPrefs(NodePrefs& prefs) {
prefs.flood_advert_interval = 25;
prefs.loop_detect = LOOP_DETECT_MINIMAL;
prefs.path_hash_mode = 1;
#if IS_ENABLED(CONFIG_ZEPHCORE_LORA_RX_DUTY_CYCLE)
prefs.rx_duty_cycle = 1;
#endif
/* Persist defaults so flash always has a prefs file from boot 1.
* Lets later code (e.g. tempradio revert) trust that flash is
* authoritative without a "first run" special case. */
@@ -237,12 +234,16 @@ bool RepeaterDataStore::loadPrefs(NodePrefs& prefs) {
prefs.rx_boost = 1;
prefs.path_hash_mode = 1;
prefs.loop_detect = LOOP_DETECT_MINIMAL;
#if IS_ENABLED(CONFIG_ZEPHCORE_LORA_RX_DUTY_CYCLE)
prefs.rx_duty_cycle = 1;
#endif
savePrefs(prefs);
LOG_INF("loadPrefs: upgraded prefs format (%d -> 294 bytes)", (int)entry.size);
}
/* One-time migration: disable RX duty cycle if it was previously enabled. */
if (prefs.rx_duty_cycle != 0) {
prefs.rx_duty_cycle = 0;
savePrefs(prefs);
LOG_INF("loadPrefs: migrated rx_duty_cycle to disabled");
}
return true;
}
+2 -2
View File
@@ -195,8 +195,8 @@ CONFIG_POWEROFF=y
# ========== LoRa Power Saving ==========
# RX duty cycle defaults are in Kconfig:
# ON for companion + SX1262/LLCC68 (safe, saves 60-70% RX current)
# OFF for repeaters (latency > battery) and LR1110 (mid-preamble bug)
# OFF for all roles by default
# LR1110 remains explicitly unsupported (mid-preamble lock bug)
# Override at runtime via CLI "set rxduty on/off".
# ========== ZephCore Log Levels ==========
@@ -68,7 +68,7 @@ index 17689720dd2..09982dc2e70 100644
return -EINVAL;
}
diff --git a/drivers/lora/native/sx126x/sx126x.c b/drivers/lora/native/sx126x/sx126x.c
index 30243ba5dc7..8611d76a782 100644
index 30243ba5dc7..befb84797eb 100644
--- a/drivers/lora/native/sx126x/sx126x.c
+++ b/drivers/lora/native/sx126x/sx126x.c
@@ -10,10 +10,16 @@
@@ -201,7 +201,27 @@ index 30243ba5dc7..8611d76a782 100644
/* Set packet type to LoRa */
ret = sx126x_set_packet_type(dev, SX126X_PACKET_TYPE_LORA);
if (ret < 0) {
@@ -398,7 +439,7 @@ static void sx126x_dio1_callback(const struct device *dev)
@@ -374,10 +415,16 @@ static int sx126x_chip_init(const struct device *dev)
LOG_ERR("Set packet type failed: %d", ret);
return ret;
}
- /* Configure IRQs on DIO1: TX done, RX done, timeout */
+ /* Global mask includes preamble/header so the status register bits are
+ * set (enabling sx126x_is_receiving() polling); DIO1 excludes them to
+ * avoid spurious work-queue wakeups on every detected preamble. */
uint16_t irq_mask = SX126X_IRQ_TX_DONE | SX126X_IRQ_RX_DONE |
- SX126X_IRQ_RX_TX_TIMEOUT | SX126X_IRQ_CRC_ERR;
- ret = sx126x_set_dio_irq_params(dev, irq_mask, irq_mask, 0, 0);
+ SX126X_IRQ_RX_TX_TIMEOUT | SX126X_IRQ_CRC_ERR |
+ SX126X_IRQ_CAD_DONE | SX126X_IRQ_CAD_ACTIVITY_DETECTED |
+ SX126X_IRQ_PREAMBLE_DETECTED | SX126X_IRQ_HEADER_VALID;
+ uint16_t dio1_mask = irq_mask &
+ ~(SX126X_IRQ_PREAMBLE_DETECTED | SX126X_IRQ_HEADER_VALID);
+ ret = sx126x_set_dio_irq_params(dev, irq_mask, dio1_mask, 0, 0);
if (ret < 0) {
LOG_ERR("Set IRQ params failed: %d", ret);
@@ -398,7 +445,7 @@ static void sx126x_dio1_callback(const struct device *dev)
{
struct sx126x_data *data = dev->data;
@@ -210,7 +230,7 @@ index 30243ba5dc7..8611d76a782 100644
}
static void sx126x_set_rf_path(const struct device *dev, bool enable, bool tx)
@@ -406,7 +447,20 @@ static void sx126x_set_rf_path(const struct device *dev, bool enable, bool tx)
@@ -406,7 +453,20 @@ static void sx126x_set_rf_path(const struct device *dev, bool enable, bool tx)
const struct sx126x_hal_config *config = dev->config;
sx126x_hal_set_antenna_enable(dev, enable);
@@ -232,7 +252,7 @@ index 30243ba5dc7..8611d76a782 100644
sx126x_hal_set_rf_switch(dev, enable, tx);
}
}
@@ -455,6 +509,80 @@ static int sx126x_reconnect_rf_gpios(const struct device *dev)
@@ -455,6 +515,80 @@ static int sx126x_reconnect_rf_gpios(const struct device *dev)
}
#endif /* CONFIG_PM_DEVICE */
@@ -313,7 +333,7 @@ index 30243ba5dc7..8611d76a782 100644
static int sx126x_set_sleep(const struct device *dev)
{
struct sx126x_data *data = dev->data;
@@ -533,6 +661,9 @@ static void sx126x_handle_irq_rx_done(const struct device *dev, uint16_t irq_sta
@@ -533,6 +667,9 @@ static void sx126x_handle_irq_rx_done(const struct device *dev, uint16_t irq_sta
struct sx126x_data *data = dev->data;
struct sx126x_rx_result result = { 0 };
uint8_t payload_len = 0, offset = 0;
@@ -323,7 +343,7 @@ index 30243ba5dc7..8611d76a782 100644
int ret;
/* Get received packet info */
@@ -564,20 +695,34 @@ static void sx126x_handle_irq_rx_done(const struct device *dev, uint16_t irq_sta
@@ -564,20 +701,34 @@ static void sx126x_handle_irq_rx_done(const struct device *dev, uint16_t irq_sta
}
}
@@ -370,7 +390,7 @@ index 30243ba5dc7..8611d76a782 100644
}
} else {
/* Sync mode */
@@ -589,8 +734,46 @@ static void sx126x_handle_irq_rx_done(const struct device *dev, uint16_t irq_sta
@@ -589,8 +740,46 @@ static void sx126x_handle_irq_rx_done(const struct device *dev, uint16_t irq_sta
static void sx126x_handle_irq_timeout(const struct device *dev)
{
struct sx126x_data *data = dev->data;
@@ -417,7 +437,7 @@ index 30243ba5dc7..8611d76a782 100644
sx126x_set_sleep(dev);
if (data->tx_async_signal != NULL) {
@@ -637,6 +820,25 @@ static void sx126x_irq_work_handler(struct k_work *work)
@@ -637,6 +826,25 @@ static void sx126x_irq_work_handler(struct k_work *work)
sx126x_handle_irq_timeout(dev);
}
@@ -443,7 +463,7 @@ index 30243ba5dc7..8611d76a782 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);
@@ -682,7 +884,7 @@ static int sx126x_lora_config(const struct device *dev,
@@ -682,7 +890,7 @@ static int sx126x_lora_config(const struct device *dev,
/* Configure PA and TX power based on chip variant and frequency */
ret = sx126x_hal_configure_tx_params(dev, config->tx_power,
config->frequency,
@@ -452,7 +472,7 @@ index 30243ba5dc7..8611d76a782 100644
if (ret < 0) {
goto out;
}
@@ -698,6 +900,29 @@ static int sx126x_lora_config(const struct device *dev,
@@ -698,6 +906,29 @@ static int sx126x_lora_config(const struct device *dev,
goto out;
}
@@ -482,7 +502,7 @@ index 30243ba5dc7..8611d76a782 100644
/* Set sync word */
ret = sx126x_set_sync_word(dev, config->public_network);
if (ret < 0) {
@@ -721,6 +946,8 @@ out:
@@ -721,6 +952,8 @@ out:
return ret;
}
@@ -491,7 +511,7 @@ index 30243ba5dc7..8611d76a782 100644
static int sx126x_lora_send_async(const struct device *dev,
uint8_t *data_buf, uint32_t data_len,
struct k_poll_signal *async)
@@ -752,6 +979,65 @@ static int sx126x_lora_send_async(const struct device *dev,
@@ -752,6 +985,65 @@ static int sx126x_lora_send_async(const struct device *dev,
return ret;
}
@@ -557,7 +577,7 @@ index 30243ba5dc7..8611d76a782 100644
data->tx_async_signal = async;
k_msgq_purge(&data->tx_msgq);
@@ -777,6 +1063,29 @@ static int sx126x_lora_send_async(const struct device *dev,
@@ -777,6 +1069,29 @@ static int sx126x_lora_send_async(const struct device *dev,
/* Enable antenna and set TX path */
sx126x_set_rf_path(dev, true, true);
@@ -587,7 +607,7 @@ index 30243ba5dc7..8611d76a782 100644
/* Start transmission with 10 second timeout */
ret = sx126x_set_tx(dev, 10000);
if (ret < 0) {
@@ -847,6 +1156,8 @@ static int sx126x_lora_recv(const struct device *dev, uint8_t *data_buf,
@@ -847,6 +1162,8 @@ static int sx126x_lora_recv(const struct device *dev, uint8_t *data_buf,
}
data->rx_cb = NULL;
@@ -596,7 +616,7 @@ index 30243ba5dc7..8611d76a782 100644
k_msgq_purge(&data->rx_msgq);
/* Set packet parameters for variable length reception */
@@ -918,6 +1229,7 @@ static int sx126x_lora_recv_async(const struct device *dev,
@@ -918,6 +1235,7 @@ static int sx126x_lora_recv_async(const struct device *dev,
/* Stop async reception */
data->rx_cb = NULL;
data->rx_cb_user_data = NULL;
@@ -604,7 +624,7 @@ index 30243ba5dc7..8611d76a782 100644
if (atomic_cas(&data->state, SX126X_STATE_RX, SX126X_STATE_IDLE)) {
sx126x_set_standby(dev, SX126X_STANDBY_RC);
sx126x_set_sleep(dev);
@@ -947,6 +1259,8 @@ static int sx126x_lora_recv_async(const struct device *dev,
@@ -947,6 +1265,8 @@ static int sx126x_lora_recv_async(const struct device *dev,
data->rx_cb = cb;
data->rx_cb_user_data = user_data;
@@ -613,7 +633,7 @@ index 30243ba5dc7..8611d76a782 100644
/* Set packet parameters */
ret = sx126x_set_packet_params(dev,
@@ -959,6 +1273,7 @@ static int sx126x_lora_recv_async(const struct device *dev,
@@ -959,6 +1279,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;
@@ -621,7 +641,7 @@ index 30243ba5dc7..8611d76a782 100644
sx126x_set_sleep(dev);
k_mutex_unlock(&data->lock);
return ret;
@@ -971,11 +1286,21 @@ static int sx126x_lora_recv_async(const struct device *dev,
@@ -971,11 +1292,21 @@ static int sx126x_lora_recv_async(const struct device *dev,
ret = sx126x_set_rx(dev, 0);
if (ret < 0) {
data->rx_cb = NULL;
@@ -643,7 +663,7 @@ index 30243ba5dc7..8611d76a782 100644
k_mutex_unlock(&data->lock);
return 0;
}
@@ -1051,7 +1376,7 @@ static int sx126x_lora_test_cw(const struct device *dev, uint32_t frequency,
@@ -1051,7 +1382,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,
@@ -652,7 +672,7 @@ index 30243ba5dc7..8611d76a782 100644
if (ret < 0) {
sx126x_set_sleep(dev);
k_mutex_unlock(&data->lock);
@@ -1083,14 +1408,500 @@ static int sx126x_lora_test_cw(const struct device *dev, uint32_t frequency,
@@ -1083,14 +1414,500 @@ static int sx126x_lora_test_cw(const struct device *dev, uint32_t frequency,
return 0;
}
@@ -1160,7 +1180,7 @@ index 30243ba5dc7..8611d76a782 100644
};
#ifdef CONFIG_PM_DEVICE
@@ -1112,6 +1923,7 @@ static int sx126x_pm_action(const struct device *dev,
@@ -1112,6 +1929,7 @@ static int sx126x_pm_action(const struct device *dev,
static int sx126x_init(const struct device *dev)
{
struct sx126x_data *data = dev->data;
@@ -1168,7 +1188,7 @@ index 30243ba5dc7..8611d76a782 100644
int ret;
/* Initialize data structures */
@@ -1121,9 +1933,25 @@ static int sx126x_init(const struct device *dev)
@@ -1121,9 +1939,25 @@ 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);
+1 -1
View File
@@ -534,7 +534,7 @@ int main(void)
companion_mesh.prefs.tx_power_dbm = 22;
companion_mesh.prefs.rx_delay_base = 0.0f; /* Disabled for companion */
companion_mesh.prefs.airtime_factor = 9.0f; /* Arduino formula: 100/(af+1) → 10% (EU 868 default) */
companion_mesh.prefs.rx_duty_cycle = 1; /* Companions: duty cycle ON by default (power save) */
companion_mesh.prefs.rx_duty_cycle = 0; /* Default OFF: continuous RX */
companion_mesh.prefs.rx_boost = 1; /* Default: boosted RX (+3dB sensitivity, +2mA) */
companion_mesh.prefs.apc_enabled = 0; /* Default: APC off */
companion_mesh.prefs.apc_margin = 20; /* Companions: more conservative margin (mobile) */