Merge IoTThinks PowerSaving-v17

Port current-compatible power-saving updates while retaining newer local implementations.
This commit is contained in:
mikecarper committed 2026-08-17 23:45:06 -07:00
commit 32a681a59b
10 files changed
+115 -31

No files matched your search

@@ -86,6 +86,11 @@ protected:
}
int startReceiveMode() override {
// Do not abort a frame that started while a calibration transition was
// being scheduled. recvRaw() will move it to continuous RX afterward.
if (_nf_calib_active && _rx_ps_armed && isPacketPendingOrReceiving()) {
return RADIOLIB_ERR_NONE;
}
if (_rx_ps_armed) {
// stop the previous duty-cycle sequence with an explicit standby before
// reconfiguring the radio
@@ -99,6 +99,11 @@ public:
protected:
int startReceiveMode() override {
// Do not abort a frame that started while a calibration transition was
// being scheduled. recvRaw() will move it to continuous RX afterward.
if (_nf_calib_active && _rx_ps_armed && isPacketPendingOrReceiving()) {
return RADIOLIB_ERR_NONE;
}
if (_rx_ps_armed) {
// leaving duty-cycle mode (after RxDone or a reconfig): stop the
// sequencer and the still-running RTC, or its pending event can
+30 -19
View File
@@ -235,25 +235,16 @@ void RadioLibWrapper::doResetAGC() {
void RadioLibWrapper::resetAGC() {
// make sure we're not mid-receiving and mid-sending of packet!
if ((state & STATE_INT_READY) != 0 || isReceivingPacket() || (state == STATE_TX_WAIT)) return;
if (isPacketPendingOrReceiving() || (state == STATE_TX_WAIT)) return;
doResetAGC();
state = STATE_IDLE; // trigger a startReceive()
if (_rx_boosted_gain_valid) applyRxBoostedGainMode(_cur_rx_boosted_gain);
// Reset noise floor sampling so it reconverges from scratch.
// Without this, a stuck _noise_floor of -120 makes the sampling threshold
// too low (-106) to accept normal samples (~-105), self-reinforcing the
// stuck value even after the receiver has recovered.
_noise_floor = 0;
_noise_floor_valid = false;
_nf_calib_active = false;
_nf_refresh_requested = true;
_nf_last_calib = 0;
_nf_sample_from = 0;
_num_floor_samples = 0;
_floor_sample_sum = 0;
_nf_calib_deadline = 0; // starts after reset recovery reaches RX
// Preserve the last published value while a fresh post-reset batch is
// collected. Invalidating the sample gate lets the new floor converge even
// when the old value was stuck at its lower clamp.
recalibrateNoiseFloor();
}
bool RadioLibWrapper::recoverRadio(bool hard) {
@@ -371,6 +362,20 @@ void RadioLibWrapper::rxPsWatchdogCheck() {
// sleep windows and settling right after each wake), so a requested refresh
// drops receive mode to plain continuous RX, collects a fresh sample batch,
// and re-arms the duty cycle. Requests are rate-limited and coalesced.
void RadioLibWrapper::requestRestartRecv() {
// An RX interrupt can arrive between the caller's idle check and this state
// transition. Preserve that flag so the completed packet is still consumed.
noInterrupts();
if ((state & ~STATE_INT_READY) != STATE_TX_WAIT) {
state &= STATE_INT_READY;
}
interrupts();
}
bool RadioLibWrapper::isPacketPendingOrReceiving() {
return (state & STATE_INT_READY) != 0 || isReceivingPacket();
}
void RadioLibWrapper::noiseFloorCalibCheck(unsigned long now) {
if (_nf_calib_active) {
if (!_rx_ps_enabled
@@ -379,11 +384,15 @@ void RadioLibWrapper::noiseFloorCalibCheck(unsigned long now) {
// powersaving turned off mid-window, or the batch couldn't complete
// (busy channel / stuck filter) - keep the previous floor
endNoiseFloorCalib(now);
} else if (_rx_ps_armed && !isPacketPendingOrReceiving()) {
// A packet can delay the transition from RXPS to continuous RX. Retry
// once the radio is idle without discarding a pending interrupt.
requestRestartRecv();
}
} else if (_nf_refresh_requested && _rx_ps_enabled && _rx_ps_armed && state == STATE_RX
&& ((!_noise_floor_valid && _nf_last_calib == 0)
|| now - _nf_last_calib >= NF_CALIB_INTERVAL_MS)
&& !isReceivingPacket()) {
&& !isPacketPendingOrReceiving()) {
// never interrupt an ongoing reception to calibrate (a TX in flight is
// already excluded by state == STATE_RX); retries next loop iteration
_nf_calib_active = true;
@@ -391,8 +400,9 @@ void RadioLibWrapper::noiseFloorCalibCheck(unsigned long now) {
_nf_sample_from = now + NF_CALIB_SETTLE_MS;
_num_floor_samples = 0; // start a fresh batch for this window
_floor_sample_sum = 0;
state = STATE_IDLE; // recvRaw() re-arms; startReceiveMode() sees the
// active flag and starts continuous RX, not duty-cycle
if (!isPacketPendingOrReceiving()) {
requestRestartRecv(); // startReceiveMode() selects continuous RX
}
}
}
@@ -404,8 +414,9 @@ void RadioLibWrapper::endNoiseFloorCalib(unsigned long now) {
// force a receive re-arm back into duty-cycle mode, but don't clobber a
// completed-but-unread packet or an in-flight TX (recvRaw()/onSendFinished()
// will re-arm right after those anyway; same guard style as setRxPowerSaving)
if ((state & STATE_INT_READY) == 0 && (state & ~STATE_INT_READY) != STATE_TX_WAIT) {
state = STATE_IDLE;
if ((state & ~STATE_INT_READY) != STATE_TX_WAIT
&& !isPacketPendingOrReceiving()) {
requestRestartRecv();
}
}
+2
View File
@@ -81,6 +81,8 @@ protected:
void startRecv() override;
void rxPsWatchdogCheck();
void requestNoiseFloorRefresh();
void requestRestartRecv();
bool isPacketPendingOrReceiving();
void noiseFloorCalibCheck(unsigned long now);
void endNoiseFloorCalib(unsigned long now);
void finishReceiveProcessing();
+10 -10
View File
@@ -426,16 +426,16 @@ bool ST7735Display::i2c_probe(TwoWire& wire, uint8_t addr) {
#define PIN_TFT_LEDA_CTL_ACTIVE HIGH
#endif
// Color scheme
ColorVal UIColor::window_bkg = ST77XX_WHITE;
ColorVal UIColor::title_bkg = ST77XX_BLUE;
ColorVal UIColor::title_txt = ST77XX_WHITE;
ColorVal UIColor::primary_txt = ST77XX_BLACK;
ColorVal UIColor::secondary_txt = (18 << 11) | (36 << 5) | 18; // mid-gray
ColorVal UIColor::warning_txt = ST77XX_ORANGE;
ColorVal UIColor::popup_bkg = ST77XX_CYAN;
ColorVal UIColor::popup_txt = ST77XX_BLACK;
ColorVal UIColor::corp_blue = 0x001A;
// Dark colors reduce panel current on the PowerSaving builds.
ColorVal UIColor::window_bkg = ST77XX_BLACK;
ColorVal UIColor::title_bkg = ST77XX_BLACK;
ColorVal UIColor::title_txt = ST77XX_GREEN;
ColorVal UIColor::primary_txt = ST77XX_GREEN;
ColorVal UIColor::secondary_txt = ST77XX_YELLOW;
ColorVal UIColor::warning_txt = ST77XX_RED;
ColorVal UIColor::popup_bkg = ST77XX_BLACK;
ColorVal UIColor::popup_txt = ST77XX_WHITE;
ColorVal UIColor::corp_blue = ST77XX_BLUE;
bool ST7735Display::begin() {
if (!sprite) {