mirror of
https://github.com/liquidraver/ZephCore.git
synced 2026-09-02 06:33:42 +00:00
sx1276: fix loramac-node direction fast-path, resetAGC, add BW 62.5kHz
Three correctness fixes for the SX127x radio adapter on top of Rastislav's initial sx1276 + patch commits: 1. _loramac_node flag (LoRaRadioBase + SX127xRadio): Guard the direction-only fast path in configureTx()/configureRx() so loramac-node always calls both Radio.SetTxConfig() and Radio.SetRxConfig(). Skipping either leaves TxTimeout=0 in the library, causing an immediate TX timeout callback, which prevents the _tx_signal from ever being raised and blocks the TX wait thread for TX_TIMEOUT_MS (5 s) — a 5-second RX blackout per transmission. This was the root cause of "boots but no RX". 2. SX127xRadio::resetAGC() override: The base-class resetAGC() calls startReceive() after hwResetAGC(). During async RX the loramac-node modem mutex is STATE_BUSY, so lora_recv_async() returns -EBUSY, which sets _in_recv_mode = 0 and corrupts the receive state machine. Override skips the call entirely — the loramac-node driver self-manages AGC. 3. BW 62.5 kHz support in loramac-node/sx1276.c + patch: Rastislav's 0004-lora-sx127x-62k5-bandwidth.patch adds BW_62_KHZ support to sx12xx_common.c (Zephyr side) but not to the loramac- node library itself. Without this fix bandwidth index 3 hits the "while(1)" fatal guard in SX1276SetRxConfig/SX1276SetTxConfig. This commit patches sx1276.c directly and adds patches/modules/loramac-node/0001-sx1276-bw62k5.patch so the fix survives west update. CMakeLists.txt is extended to apply module patches via the existing zephcore_apply_patches() mechanism.
This commit is contained in:
@@ -121,6 +121,16 @@ if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/patches/zephyr)
|
||||
)
|
||||
endif()
|
||||
|
||||
# Apply patches to loramac-node module
|
||||
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/patches/modules/loramac-node)
|
||||
message(STATUS "Applying ZephCore patches to loramac-node...")
|
||||
zephcore_apply_patches(
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/patches/modules/loramac-node"
|
||||
"${MODULES_DIR}/lib/loramac-node"
|
||||
"loramac-node"
|
||||
)
|
||||
endif()
|
||||
|
||||
# Copy new files into Zephyr tree
|
||||
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/patches/zephyr-new)
|
||||
file(GLOB_RECURSE ZEPHCORE_NEW_FILES
|
||||
|
||||
@@ -29,6 +29,7 @@ LoRaRadioBase::LoRaRadioBase(const struct device *lora_dev, MainBoard &board,
|
||||
_rx_duty_cycle_enabled(IS_ENABLED(CONFIG_ZEPHCORE_LORA_RX_DUTY_CYCLE)),
|
||||
_rx_boost_enabled(true),
|
||||
_tx_power_reduction_db(0),
|
||||
_loramac_node(false),
|
||||
_config_cached(false),
|
||||
_rx_cb(nullptr), _rx_cb_user_data(nullptr),
|
||||
_tx_done_cb(nullptr), _tx_done_cb_user_data(nullptr),
|
||||
@@ -272,8 +273,12 @@ void LoRaRadioBase::configureRx()
|
||||
* RX config (RadioSetRxConfig) from a previous cycle — Radio.Rx(0)
|
||||
* in hwStartReceive() will use those register values directly.
|
||||
* This avoids the modem_acquire → modem_release → Radio.Sleep()
|
||||
* round-trip that wastes ~5 ms on every TX→RX transition. */
|
||||
if (_config_cached && onlyDirectionDiffers(cfg, _last_cfg)) {
|
||||
* round-trip that wastes ~5 ms on every TX→RX transition.
|
||||
*
|
||||
* Not used for loramac-node: Radio.SetTxConfig() and Radio.SetRxConfig()
|
||||
* configure completely disjoint internal state (including TxTimeout).
|
||||
* Skipping either on a direction change leaves that state uninitialized. */
|
||||
if (!_loramac_node && _config_cached && onlyDirectionDiffers(cfg, _last_cfg)) {
|
||||
LOG_DBG("configureRx: direction-only change, skip hwConfigure");
|
||||
_last_cfg = cfg;
|
||||
return;
|
||||
@@ -300,8 +305,9 @@ void LoRaRadioBase::configureTx()
|
||||
|
||||
/* Fast path: direction-only change (RX→TX). The driver already
|
||||
* has a valid TX config (RadioSetTxConfig with TxTimeout=4000)
|
||||
* from a previous cycle — Radio.Send() will use those values. */
|
||||
if (_config_cached && onlyDirectionDiffers(cfg, _last_cfg)) {
|
||||
* from a previous cycle — Radio.Send() will use those values.
|
||||
* Not used for loramac-node (see configureRx comment above). */
|
||||
if (!_loramac_node && _config_cached && onlyDirectionDiffers(cfg, _last_cfg)) {
|
||||
LOG_DBG("configureTx: direction-only change, skip hwConfigure");
|
||||
_last_cfg = cfg;
|
||||
return;
|
||||
|
||||
@@ -90,6 +90,13 @@ protected:
|
||||
/** GPIO-only BUSY check (no SPI). Default false for chips without duty-cycle sleep. */
|
||||
virtual bool hwIsChipBusy() { return false; }
|
||||
|
||||
/* Set to true by subclasses using the loramac-node driver backend.
|
||||
* Disables the direction-only fast path in configureTx()/configureRx():
|
||||
* loramac-node calls Radio.SetTxConfig() and Radio.SetRxConfig() which
|
||||
* configure completely disjoint internal state — skipping either leaves
|
||||
* TxTimeout/RxConfig uninitialized in the loramac-node library. */
|
||||
bool _loramac_node;
|
||||
|
||||
/* ── Shared helpers available to subclasses ────────────────── */
|
||||
|
||||
void buildModemConfig(struct lora_modem_config &cfg, bool tx);
|
||||
|
||||
@@ -32,6 +32,10 @@ SX127xRadio::SX127xRadio(const struct device *lora_dev, MainBoard &board,
|
||||
{
|
||||
/* SX127x has no RX boost feature — start with boost disabled */
|
||||
_rx_boost_enabled = false;
|
||||
/* loramac-node requires full lora_config() on every TX/RX direction
|
||||
* change — Radio.SetTxConfig() and Radio.SetRxConfig() configure
|
||||
* completely disjoint internal state in the loramac-node library. */
|
||||
_loramac_node = true;
|
||||
}
|
||||
|
||||
void SX127xRadio::begin()
|
||||
@@ -91,8 +95,18 @@ void SX127xRadio::hwResetAGC()
|
||||
{
|
||||
/* The loramac-node SX127x driver manages AGC recalibration internally
|
||||
* (RadioSetRxConfig re-programs all gain registers on every RX config
|
||||
* call). No explicit AGC reset is needed or possible via the
|
||||
* standard API. The base class will restart RX after this call. */
|
||||
* call). No explicit AGC reset is needed or possible via the standard
|
||||
* API. */
|
||||
}
|
||||
|
||||
void SX127xRadio::resetAGC()
|
||||
{
|
||||
/* hwResetAGC() is a no-op, so skip the base-class resetAGC() entirely.
|
||||
* The base class calls startReceive() after hwResetAGC(), but the
|
||||
* loramac-node modem mutex (STATE_BUSY during async RX) causes
|
||||
* lora_recv_async() to return -EBUSY, setting _in_recv_mode = 0 and
|
||||
* corrupting the state machine. The loramac-node driver self-manages
|
||||
* AGC, so nothing needs to happen here. */
|
||||
}
|
||||
|
||||
} /* namespace mesh */
|
||||
|
||||
@@ -43,6 +43,12 @@ protected:
|
||||
/* SX127x loramac-node driver manages AGC automatically. No-op. */
|
||||
void hwResetAGC() override;
|
||||
|
||||
/* Override public resetAGC(): hwResetAGC() is a no-op, and the
|
||||
* loramac-node modem mutex makes the base-class startReceive() call
|
||||
* fail with -EBUSY (modem STATE_BUSY during async RX), which would
|
||||
* set _in_recv_mode = 0 and corrupt the state machine. */
|
||||
void resetAGC() override;
|
||||
|
||||
/* SX127x has no BUSY pin. Default (false) from base is correct. */
|
||||
/* bool hwIsChipBusy() — inherited, returns false */
|
||||
};
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
diff --git a/src/radio/sx1276/sx1276.c b/src/radio/sx1276/sx1276.c
|
||||
index 7dd9b122..3ea5320d 100644
|
||||
--- a/src/radio/sx1276/sx1276.c
|
||||
+++ b/src/radio/sx1276/sx1276.c
|
||||
@@ -523,12 +523,14 @@ void SX1276SetRxConfig( RadioModems_t modem, uint32_t bandwidth,
|
||||
break;
|
||||
case MODEM_LORA:
|
||||
{
|
||||
- if( bandwidth > 2 )
|
||||
+ if( bandwidth > 3 )
|
||||
{
|
||||
- // Fatal error: When using LoRa modem only bandwidths 125, 250 and 500 kHz are supported
|
||||
+ // Fatal error: When using LoRa modem only bandwidths 62.5, 125, 250 and 500 kHz are supported
|
||||
while( 1 );
|
||||
}
|
||||
- bandwidth += 7;
|
||||
+ // Map loramac-node index to SX1276 BW register value:
|
||||
+ // 0=125kHz->7, 1=250kHz->8, 2=500kHz->9, 3=62.5kHz->6
|
||||
+ bandwidth = ( bandwidth == 3 ) ? 6 : ( bandwidth + 7 );
|
||||
SX1276.Settings.LoRa.Bandwidth = bandwidth;
|
||||
SX1276.Settings.LoRa.Datarate = datarate;
|
||||
SX1276.Settings.LoRa.Coderate = coderate;
|
||||
@@ -550,7 +552,9 @@ void SX1276SetRxConfig( RadioModems_t modem, uint32_t bandwidth,
|
||||
datarate = 6;
|
||||
}
|
||||
|
||||
- if( ( ( bandwidth == 7 ) && ( ( datarate == 11 ) || ( datarate == 12 ) ) ) ||
|
||||
+ // BW 62.5kHz (reg 6): LDRO required for SF10/11/12 (symbol time >16ms)
|
||||
+ if( ( ( bandwidth == 6 ) && ( ( datarate == 10 ) || ( datarate == 11 ) || ( datarate == 12 ) ) ) ||
|
||||
+ ( ( bandwidth == 7 ) && ( ( datarate == 11 ) || ( datarate == 12 ) ) ) ||
|
||||
( ( bandwidth == 8 ) && ( datarate == 12 ) ) )
|
||||
{
|
||||
SX1276.Settings.LoRa.LowDatarateOptimize = 0x01;
|
||||
@@ -687,12 +691,14 @@ void SX1276SetTxConfig( RadioModems_t modem, int8_t power, uint32_t fdev,
|
||||
case MODEM_LORA:
|
||||
{
|
||||
SX1276.Settings.LoRa.Power = power;
|
||||
- if( bandwidth > 2 )
|
||||
+ if( bandwidth > 3 )
|
||||
{
|
||||
- // Fatal error: When using LoRa modem only bandwidths 125, 250 and 500 kHz are supported
|
||||
+ // Fatal error: When using LoRa modem only bandwidths 62.5, 125, 250 and 500 kHz are supported
|
||||
while( 1 );
|
||||
}
|
||||
- bandwidth += 7;
|
||||
+ // Map loramac-node index to SX1276 BW register value:
|
||||
+ // 0=125kHz->7, 1=250kHz->8, 2=500kHz->9, 3=62.5kHz->6
|
||||
+ bandwidth = ( bandwidth == 3 ) ? 6 : ( bandwidth + 7 );
|
||||
SX1276.Settings.LoRa.Bandwidth = bandwidth;
|
||||
SX1276.Settings.LoRa.Datarate = datarate;
|
||||
SX1276.Settings.LoRa.Coderate = coderate;
|
||||
@@ -712,7 +718,9 @@ void SX1276SetTxConfig( RadioModems_t modem, int8_t power, uint32_t fdev,
|
||||
{
|
||||
datarate = 6;
|
||||
}
|
||||
- if( ( ( bandwidth == 7 ) && ( ( datarate == 11 ) || ( datarate == 12 ) ) ) ||
|
||||
+ // BW 62.5kHz (reg 6): LDRO required for SF10/11/12 (symbol time >16ms)
|
||||
+ if( ( ( bandwidth == 6 ) && ( ( datarate == 10 ) || ( datarate == 11 ) || ( datarate == 12 ) ) ) ||
|
||||
+ ( ( bandwidth == 7 ) && ( ( datarate == 11 ) || ( datarate == 12 ) ) ) ||
|
||||
( ( bandwidth == 8 ) && ( datarate == 12 ) ) )
|
||||
{
|
||||
SX1276.Settings.LoRa.LowDatarateOptimize = 0x01;
|
||||
@@ -1437,6 +1445,9 @@ static uint32_t SX1276GetLoRaBandwidthInHz( uint32_t bw )
|
||||
case 2: // 500 kHz
|
||||
bandwidthInHz = 500000UL;
|
||||
break;
|
||||
+ case 3: // 62.5 kHz
|
||||
+ bandwidthInHz = 62500UL;
|
||||
+ break;
|
||||
}
|
||||
|
||||
return bandwidthInHz;
|
||||
@@ -1475,8 +1486,11 @@ static uint32_t SX1276GetLoRaTimeOnAirNumerator( uint32_t bandwidth,
|
||||
}
|
||||
}
|
||||
|
||||
+ // index 0=125kHz: LDRO for SF11/12; index 1=250kHz: LDRO for SF12
|
||||
+ // index 3=62.5kHz: LDRO for SF10/11/12 (symbol time >16ms)
|
||||
if( ( ( bandwidth == 0 ) && ( ( datarate == 11 ) || ( datarate == 12 ) ) ) ||
|
||||
- ( ( bandwidth == 1 ) && ( datarate == 12 ) ) )
|
||||
+ ( ( bandwidth == 1 ) && ( datarate == 12 ) ) ||
|
||||
+ ( ( bandwidth == 3 ) && ( ( datarate == 10 ) || ( datarate == 11 ) || ( datarate == 12 ) ) ) )
|
||||
{
|
||||
lowDatareOptimize = true;
|
||||
}
|
||||
Reference in New Issue
Block a user