Files
ZephCore/zephcore/adapters/radio/SX126xRadio.cpp
T
liquidraver a3244e2dc2 Three driver fixes for RX duty cycle, all applied to the existing patch
stolen from Zephyr main:

  1. Issue StopTimerOnPreamble=1 before SetRxDutyCycle so the chip's
     timer is not reset on every preamble detect (per §13.1 of the
     datasheet). Without this, duty cycle effectively never sleeps in
     noisy RF and current draw spikes.
  2. On IRQ_RX_TX_TIMEOUT during duty-cycle RX, re-arm via
     sx126x_restart_rx() instead of falling through to set_sleep().
     The old path silently killed duty cycle after the first preamble
     false-positive.
  3. On recv_duty_cycle(NULL) cancel, wake the radio before issuing
     SetStandby — BUSY stays asserted during the sleep phase and the
     standby command was being dropped.

Also adds a dc_timeout_restarts atomic counter incremented on the Fix 2
path, exposed end-to-end: sx126x_ext.h accessors → LoRaRadioBase vtable
→ SX126xRadio override → CommonCLICallbacks → RepeaterMesh. Query via
`get dc.restarts` on the repeater CLI; cleared by `clear stats`. High
values indicate a noisy environment or a too-loose preamble threshold.

(+increase ESP BT stack because future zephyr pin advance will trip that mine)
2026-04-20 13:36:45 +02:00

99 lines
2.4 KiB
C++

/*
* SPDX-License-Identifier: Apache-2.0
* SX126x hardware hooks for LoRaRadioBase — native Zephyr driver.
*/
#include "SX126xRadio.h"
#include <zephyr/kernel.h>
/* Native SX126x driver extension API */
extern "C" {
#include "sx126x_ext.h"
}
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(sx126x_radio, CONFIG_ZEPHCORE_LORA_LOG_LEVEL);
namespace mesh {
K_THREAD_STACK_DEFINE(sx126x_tx_wait_stack, TX_WAIT_THREAD_STACK_SIZE);
SX126xRadio::SX126xRadio(const struct device *lora_dev, MainBoard &board,
NodePrefs *prefs)
: LoRaRadioBase(lora_dev, board, prefs)
{
}
void SX126xRadio::begin()
{
startTxThread(sx126x_tx_wait_stack,
K_THREAD_STACK_SIZEOF(sx126x_tx_wait_stack));
LoRaRadioBase::begin();
#if IS_ENABLED(CONFIG_ZEPHCORE_SX126X_HELTEC_REG_PATCH)
/* Apply undocumented register 0x8B5 RX improvement (MeshCore PR#1398).
* Must run after lora_config() has been called (via startReceive above). */
sx126x_apply_heltec_reg_patch(_dev);
LOG_INF("Applied Heltec reg 0x8B5 RX patch");
#endif
}
/* ── Hardware primitives ──────────────────────────────────────────────── */
void SX126xRadio::hwConfigure(const struct lora_modem_config &cfg)
{
int ret = lora_config(_dev, const_cast<struct lora_modem_config *>(&cfg));
if (ret < 0) {
LOG_ERR("lora_config failed: %d", ret);
}
}
void SX126xRadio::hwCancelReceive()
{
lora_recv_async(_dev, NULL, NULL);
}
int SX126xRadio::hwSendAsync(uint8_t *buf, uint32_t len,
struct k_poll_signal *sig)
{
return lora_send_async(_dev, buf, len, sig);
}
int16_t SX126xRadio::hwGetCurrentRSSI()
{
return sx126x_get_rssi_inst(_dev);
}
bool SX126xRadio::hwIsPreambleDetected()
{
return sx126x_is_receiving(_dev);
}
void SX126xRadio::hwSetRxBoost(bool enable)
{
sx126x_set_rx_boost(_dev, enable);
}
void SX126xRadio::hwResetAGC()
{
/* Warm sleep → Calibrate(ALL) → re-calibrate image → re-apply RX settings */
sx126x_reset_agc(_dev);
}
bool SX126xRadio::hwIsChipBusy()
{
return sx126x_is_chip_busy(_dev);
}
uint32_t SX126xRadio::getDutyCycleTimeoutRestarts() const
{
return sx126x_get_dc_timeout_restarts(_dev);
}
void SX126xRadio::resetDutyCycleTimeoutRestarts()
{
sx126x_reset_dc_timeout_restarts(_dev);
}
} /* namespace mesh */