mirror of
https://github.com/liquidraver/ZephCore.git
synced 2026-09-02 00:38:50 +00:00
implement "isradioready" for early returns in rx duty cycling
This commit is contained in:
@@ -504,6 +504,11 @@ bool LoRaRadioBase::startSendRaw(const uint8_t *bytes, int len)
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Defensive gate: callers should defer TX while radio is BUSY. */
|
||||
if (!isRadioReady()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Last-moment hardware check before killing active RX.
|
||||
* Closes the race between the Dispatcher's isReceiving() guard
|
||||
* and hwCancelReceive() — if a preamble arrived in that gap,
|
||||
@@ -561,6 +566,13 @@ float LoRaRadioBase::getLastSNR() const
|
||||
return _last_snr;
|
||||
}
|
||||
|
||||
bool LoRaRadioBase::isRadioReady()
|
||||
{
|
||||
/* BUSY high means the radio cannot accept SPI commands now
|
||||
* (e.g. duty-cycle sleep phase on SX126x/LR11xx). */
|
||||
return !hwIsChipBusy();
|
||||
}
|
||||
|
||||
/* ── Airtime + scoring ────────────────────────────────────────────────── */
|
||||
|
||||
uint32_t LoRaRadioBase::getEstAirtimeFor(int len_bytes)
|
||||
@@ -617,12 +629,9 @@ void LoRaRadioBase::triggerNoiseFloorCalibrate(int threshold)
|
||||
return;
|
||||
}
|
||||
|
||||
/* When duty cycle is active the chip alternates between short RX
|
||||
* windows and sleep. GetRssiInst during the sleep phase hangs the
|
||||
* SPI bus (BUSY stuck high for the full 3 s timeout). Check the
|
||||
* BUSY pin directly (GPIO read, no SPI) — if the chip is sleeping,
|
||||
* skip this cycle and try again next housekeeping tick. */
|
||||
if (_rx_duty_cycle_enabled && hwIsChipBusy()) {
|
||||
/* Skip when the radio cannot accept commands right now
|
||||
* (e.g. duty-cycle sleep BUSY window). */
|
||||
if (!isRadioReady()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -53,6 +53,7 @@ public:
|
||||
bool isInRecvMode() const override;
|
||||
float getLastRSSI() const override;
|
||||
float getLastSNR() const override;
|
||||
bool isRadioReady() override;
|
||||
|
||||
/* Packet statistics */
|
||||
uint32_t getPacketsRecv() const override { return (uint32_t)atomic_get(&_packets_recv); }
|
||||
|
||||
@@ -1,42 +1,43 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* ZephCore Radio interface - matches Dispatcher.h
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace mesh {
|
||||
|
||||
class Radio {
|
||||
public:
|
||||
virtual void begin() {}
|
||||
|
||||
virtual int recvRaw(uint8_t *bytes, int sz) = 0;
|
||||
virtual uint32_t getEstAirtimeFor(int len_bytes) = 0;
|
||||
virtual float packetScore(float snr, int packet_len) = 0;
|
||||
virtual bool startSendRaw(const uint8_t *bytes, int len) = 0;
|
||||
virtual bool isSendComplete() = 0;
|
||||
virtual void onSendFinished() = 0;
|
||||
|
||||
virtual int getNoiseFloor() const { return 0; }
|
||||
virtual void triggerNoiseFloorCalibrate(int threshold) { (void)threshold; }
|
||||
virtual void resetAGC() {}
|
||||
|
||||
virtual bool isInRecvMode() const = 0;
|
||||
virtual bool isReceiving() { return false; }
|
||||
virtual float getLastRSSI() const { return 0; }
|
||||
virtual float getLastSNR() const { return 0; }
|
||||
|
||||
/* Adaptive Power Control */
|
||||
virtual void setTxPowerReduction(int8_t reduction_db) { (void)reduction_db; }
|
||||
virtual int8_t getTxPowerReduction() const { return 0; }
|
||||
|
||||
/* Packet statistics */
|
||||
virtual uint32_t getPacketsRecv() const { return 0; }
|
||||
virtual uint32_t getPacketsSent() const { return 0; }
|
||||
virtual uint32_t getPacketsRecvErrors() const { return 0; }
|
||||
};
|
||||
|
||||
} /* namespace mesh */
|
||||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* ZephCore Radio interface - matches Dispatcher.h
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace mesh {
|
||||
|
||||
class Radio {
|
||||
public:
|
||||
virtual void begin() {}
|
||||
|
||||
virtual int recvRaw(uint8_t *bytes, int sz) = 0;
|
||||
virtual uint32_t getEstAirtimeFor(int len_bytes) = 0;
|
||||
virtual float packetScore(float snr, int packet_len) = 0;
|
||||
virtual bool startSendRaw(const uint8_t *bytes, int len) = 0;
|
||||
virtual bool isSendComplete() = 0;
|
||||
virtual void onSendFinished() = 0;
|
||||
|
||||
virtual int getNoiseFloor() const { return 0; }
|
||||
virtual void triggerNoiseFloorCalibrate(int threshold) { (void)threshold; }
|
||||
virtual void resetAGC() {}
|
||||
|
||||
virtual bool isInRecvMode() const = 0;
|
||||
virtual bool isReceiving() { return false; }
|
||||
virtual bool isRadioReady() { return true; }
|
||||
virtual float getLastRSSI() const { return 0; }
|
||||
virtual float getLastSNR() const { return 0; }
|
||||
|
||||
/* Adaptive Power Control */
|
||||
virtual void setTxPowerReduction(int8_t reduction_db) { (void)reduction_db; }
|
||||
virtual int8_t getTxPowerReduction() const { return 0; }
|
||||
|
||||
/* Packet statistics */
|
||||
virtual uint32_t getPacketsRecv() const { return 0; }
|
||||
virtual uint32_t getPacketsSent() const { return 0; }
|
||||
virtual uint32_t getPacketsRecvErrors() const { return 0; }
|
||||
};
|
||||
|
||||
} /* namespace mesh */
|
||||
|
||||
@@ -376,8 +376,9 @@ void Dispatcher::checkSend()
|
||||
}
|
||||
}
|
||||
|
||||
if (_radio->isReceiving()) {
|
||||
/* Channel busy — enforce retry timer so we don't hammer the check */
|
||||
if (_radio->isReceiving() || !_radio->isRadioReady()) {
|
||||
/* Channel busy or radio not command-ready — enforce retry timer
|
||||
* so we don't hammer checks during RX activity or BUSY windows. */
|
||||
if (!millisHasNowPassed(next_tx_time)) {
|
||||
if (_tx_queued_cb) {
|
||||
uint32_t remaining = next_tx_time - now;
|
||||
@@ -443,10 +444,9 @@ void Dispatcher::checkSend()
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Final LBT check — close the gap between initial
|
||||
* isReceiving() and actual TX start (serialisation +
|
||||
* logging can take 1-5 ms). */
|
||||
if (_radio->isReceiving()) {
|
||||
/* Final gate — close the gap between initial checks and
|
||||
* actual TX start (serialisation + logging can take 1-5 ms). */
|
||||
if (_radio->isReceiving() || !_radio->isRadioReady()) {
|
||||
uint32_t retry = getCADFailRetryDelay();
|
||||
_mgr->queueOutbound(outbound, 0, futureMillis((int)retry));
|
||||
outbound = nullptr;
|
||||
|
||||
Reference in New Issue
Block a user