mirror of
https://github.com/MarekZegare4/MeshCore-Solo.git
synced 2026-08-03 10:46:12 +00:00
feat(power): CAD-windowed receive (battery saver) — phase 1
Add an optional low-power RX mode: instead of listening continuously, the radio periodically runs a Channel Activity Detection scan and sits in standby between scans; on detected activity it drops into a full receive to catch the packet. Cuts average RX current several-fold (the dominant draw on this node). - RadioLibWrapper: CAD state machine (scan → sleep window → rx) driven from loop(), which runs before recvRaw each cycle. `state` stays STATE_RX through all phases so the dispatcher's not-in-RX watchdog never trips. Re-arm routes through armRecv() in both startRecv() and recvRaw(); toggling on/off switches mode safely at the next idle. Falls back to continuous RX if CAD is unsupported. setPowerSaving()/getPowerSaving() control it. - Software CSMA is already disabled on this firmware (interference threshold 0), so duty-cycling doesn't affect listen-before-talk; airtime budget still gates TX, and isReceivingPacket() still defers TX while a packet is mid-air. - Companion: new rx_powersave pref (schema 0xC0DE0008), Settings › Radio › "Pwr save" toggle, applied at boot (MyMesh) and on change (UITask). CAD window = 45 ms (< the 16-symbol preamble at SF8/BW62.5) and CAD params use RadioLib defaults — both will want on-hardware tuning + a before/after current measurement to confirm reception is intact. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -54,6 +54,7 @@ class SettingsScreen : public UIScreen {
|
||||
// Radio section
|
||||
SECTION_RADIO,
|
||||
TX_POWER,
|
||||
POWER_SAVE,
|
||||
// System section
|
||||
SECTION_SYSTEM,
|
||||
TIMEZONE,
|
||||
@@ -479,6 +480,10 @@ class SettingsScreen : public UIScreen {
|
||||
snprintf(buf, sizeof(buf),"%ddBm", p ? p->tx_power_dbm : 0);
|
||||
display.setCursor(display.valCol(), y);
|
||||
display.print(buf);
|
||||
} else if (item == POWER_SAVE) {
|
||||
display.print("Pwr save");
|
||||
display.setCursor(display.valCol(), y);
|
||||
display.print((p && p->rx_powersave) ? "ON" : "OFF");
|
||||
#if AUTO_OFF_MILLIS > 0
|
||||
} else if (item == AUTO_OFF) {
|
||||
display.print("AutoOff");
|
||||
@@ -736,6 +741,12 @@ public:
|
||||
if (right && p->tx_power_dbm < 22) { p->tx_power_dbm++; _task->applyTxPower(); _dirty = true; return true; }
|
||||
if (left && p->tx_power_dbm > 2) { p->tx_power_dbm--; _task->applyTxPower(); _dirty = true; return true; }
|
||||
}
|
||||
if (_selected == POWER_SAVE && p && (left || right || enter)) {
|
||||
p->rx_powersave ^= 1;
|
||||
_task->applyPowerSave();
|
||||
_dirty = true;
|
||||
return true;
|
||||
}
|
||||
#if AUTO_OFF_MILLIS > 0
|
||||
if (_selected == AUTO_OFF && p) {
|
||||
int idx = autoOffIndex();
|
||||
|
||||
@@ -2066,6 +2066,11 @@ void UITask::applyTxPower() {
|
||||
radio_driver.setTxPower(_node_prefs->tx_power_dbm);
|
||||
}
|
||||
|
||||
void UITask::applyPowerSave() {
|
||||
if (_node_prefs == NULL) return;
|
||||
radio_driver.setPowerSaving(_node_prefs->rx_powersave);
|
||||
}
|
||||
|
||||
void UITask::applyBrightness() {
|
||||
if (_display != NULL && _node_prefs != NULL) {
|
||||
_display->setBrightness(_node_prefs->display_brightness);
|
||||
|
||||
@@ -249,6 +249,7 @@ public:
|
||||
void setBuzzerVolumeLevel(uint8_t level);
|
||||
uint8_t getBuzzerVolume() const { return _node_prefs ? _node_prefs->buzzer_volume : 4; }
|
||||
void applyTxPower();
|
||||
void applyPowerSave(); // CAD-windowed RX on/off from prefs
|
||||
void applyFont();
|
||||
void applyRotation();
|
||||
void applyFullRefreshInterval();
|
||||
|
||||
Reference in New Issue
Block a user