Repository navigation
Conversation
gpsResetPin defaulted to 0, which is a real GPIO on nRF52 (P0.00, the 32 kHz LFXO crystal). -1 makes pinMode/digitalWrite no-ops until a GPS enable pin is actually found.
getSettingByKey("gps") returns NULL on sensor managers without a gps
setting, and strcmp(NULL, "1") crashed.
From PowerSaving-v17 e3d7feb.
PIN_VBAT_READ=1 (D0) as in the PowerSaving-v17 build. From PowerSaving-v17 43882d8.
The Bluefruit library blinks LED_BLUE while advertising. DISABLE_BLE_LED keeps it off; the upstream LED init (HIGH = off) stays, so the active-LOW pin is never left floating. From PowerSaving-v17 e7bd0a8 (same goal, different mechanism).
…E builds From PowerSaving-v17 8002d1e.
From PowerSaving-v17 22fdd86.
Repeater and room server builds point ENV_PIN_SDA/SCL at the Wire1 bus. From PowerSaving-v17 ba1a2ff.
ARDUINO_USB_MODE in heltec_v4.json has no effect, so the flag is set in build_flags. The KISS modem env still unsets it. From PowerSaving-v17 1a7f70e.
USE_CC310_HW_CRYPTO (upstream PR meshcore-dev#2824) stays off until its benefit is proven: no measurable current difference on RAK4631 with PowerSaving, and the per-call nRFCrypto begin()/end() was questioned in review. Re-enable by uncommenting the flag. From PowerSaving-v17 d302651.
Two more lines on the radio page of the repeater display: battery voltage and whether powersaving is on. From PowerSaving-v17 4cb67d9.
A 64-bit Uptime counter is ticked from UITask::loop(), so it keeps counting while the screen is off and across the 32-bit millis() wrap. The page dots are left-aligned and their step shrinks only when they would run into the uptime (9 pages on a 128 px display). From PowerSaving-v17 54f292f, 167a32f and 4eae86f.
Black background with green/yellow text, as before v1.17. On the T096 the light theme costs about 3.5 mA more with the backlight on. From PowerSaving-v17 e1758d2.
With the display supply cut, CS/DC/SDA/SCL/RST/LEDA held as outputs back-power the panel (about 2.8 mA on the T096). turnOff() now releases the SPI bus and switches the pins to inputs; turnOn() restores CS/DC/RST/LEDA and starts the SPI bus again before re-init. SCK/MOSI must not be restored with pinMode(): on ESP32 it routes the pin back to plain GPIO, detaching it from the SPI peripheral, and on nRF52 it drops the SCK input buffer that SPIM needs. The panel then gets no init commands and wakes with the backlight on and a blank screen. From PowerSaving-v17 6e4e6f1.
begin() claims the peripheral power only when the display was off and releases it again if no panel answers, so claims and releases stay balanced. turnOn() re-runs begin() only when the supply was switched off. Without switched power the panel kept its state, and a full begin() would pulse PIN_OLED_RESET, which defaults to 21 = SX126X_POWER_EN (FEM enable) on RAK3401 and cut the FEM for ~10 ms on every display wake. Host tests in test_ssd1306 use display mocks; run them with "pio test -e native_ssd1306".
- get sensor: the I2C pins in use for environment sensors (Wire1 or Wire) and the GPS serial pins, with whether GPS is configured. - get powerlog: last reset reason and, where power management is initialised, the shutdown reason and boot voltage. From PowerSaving-v17 4cb67d9.
During light sleep PIN_USER_BTN is also a GPIO wake source. When the button is still pressed after wake-up, sleep is held off for 30 s so the button and display can be used; the hold-off uses a uint32_t millis() difference and survives the wrap. The TLoRa V2.1 repeater has no usable user button (GPIO0 wake kept it from booting), so it sets PIN_USER_BTN=-1 after the base flags, where the last -D wins. From PowerSaving-v17 da1cc88 and 374aba4.
Generic_ESPNOW_* envs did not build: ESP32Board used P_LORA_DIO_1 and P_LORA_NSS unconditionally. Without them getIRQGpio() falls back to "none", sleep() stays awake (there is no LoRa wake source and Wi-Fi must keep receiving) and the NSS hold in shutdownPeripherals() is skipped. ESPNOWRadio::setRxBoostedGainMode() now returns a value.
Repeater, room server and sensor start with powersaving_enabled = 1. A saved setting still wins. From PowerSaving-v17 9414de8.
A companion must not go idle while received frames wait to be processed. BaseSerialInterface defaults to false, so Wi-Fi, RP2040 BLE, Ethernet and Arduino serial need no change. ESP32 and nRF52 BLE report their receive queues, and MultiSerialInterface aggregates the enabled interfaces. From PowerSaving-v17 594d770.
With rxdelay, received packets are queued for later processing. The repeater's hasPendingWork() only looked at the outbound queue, so the MCU could sleep past their scheduled time. PacketManager now reports the inbound queue length (StaticPoolPacketManager: rx_queue) and the repeater counts it as pending work.
Repeater, room server, sensor, companion BLE/USB/Wi-Fi, ESP-NOW bridge and terminal chat envs; BOOT works as the user button. No RS232 bridge env: in the v17 wiring GPIO5 is both the SX1262 reset and the bridge RX. PinChecks.h rejects any build where the bridge RX or TX pin equals P_LORA_RESET. From PowerSaving-v17 f024668, a4fb9d2, 9639763, 3d830a9 and fc182b7.
From the remote admin console a client can read or set the path the repeater uses for replies to it: flood, direct, clear (automatic learning) or an explicit list of 1-, 2- or 3-byte hop hashes. Hop lists are parsed with full hex validation. A forced flood is stored in the ACL and survives reboot, login and learned PATH messages. Direct and hop lists are replaced by the next flood login or PATH, as before. The ACL is saved about 5 s later. From PowerSaving-v17 0024226 and 4cb67d9.
nRF52840 + SX1262 with TCA9535 expander, ADS1115, NV3031B LCD with GT911 touch, GNSS and audio. Repeater, room server and companion BLE/USB envs. getTouch() delegates to the variant's readTouch(), which checks for an actual touch before reading coordinates. From PowerSaving-v17 6c7b751 (upstream PR meshcore-dev#3381).
Replace the git commit pin with the 7.8.1 release. CustomLR2021 now updates its cached boosted-gain state only when setRxBoostedGainMode() succeeds, so getRxBoostedGainMode() reads back the level the radio accepted. From PowerSaving-v17 c0c0354.
VolatileRTCClock stores the current time and a magic number in an 8-byte NOLOAD .persistent section and restores it after a reset. A bad magic or a time before 2026-03-01 falls back to that date. prev_millis is uint32_t so the millis() wrap does not jump the clock. The v6, v7 and extrafs linker scripts gain the .persistent section, and ten nRF52 board bases select the repo's script explicitly so the section is present on every build. Retention covers software resets only, not power loss. From PowerSaving-v17 2384af1 and 772dc84.
MainBoard gains shutdownPeripherals() and enterDeepSleep(secs). Board hooks that used to override powerOff() now override shutdownPeripherals(), so a timed sleep turns off the same GPS, display, LEDs, FEM/PA and rails as a full power off. - ESP32: enterDeepSleep() runs shutdownPeripherals() and arms the timer wake-up. - nRF52: SYSTEMOFF has no timer wake, so a timed sleep keeps the RTOS running in one-second steps, advances the retained clock, then reboots. - Heltec V4 R8: its own deep-sleep path left the RX path on; it now uses the shared one, which turns off the radio and FEM. - Wio Tracker L1 1W: the PA is now also turned off on timed sleep. From PowerSaving-v17 d9c4296.
RX power saving (RXPS) keeps the radio asleep between short RX windows
that are still long enough to catch a preamble.
- Levels 1-10 with preamble 16 or 32 symbols. Levels 9
("overdrive") and 10 ("riskyWorkingMax") run outside the datasheet
timing rule.
- Presets: on/conservative = 3, balanced = 6, max = 8.
- Manual rx/sleep periods of 1000-30000000 us.
- The calculator models the chip's preamble capture cost and rejects
invalid SF/BW, NaN/Inf and overflowing periods.
- A profile that does not fit the active modulation falls back to
continuous RX, flags a timing error and keeps the saved intent, so
stale periods are never armed.
- RXPowerSavingCLI parses 'set radio.rxps ...' and formats
'get radio.rxps'. The 'catch' margin is shown only when the
windows are valid and no error is pending.
Pure logic with host tests in test_rx_power_saving; radios and roles
use it in the following commits.
From PowerSaving-v17 285cf10 and 6bbd34a.
RadioLibWrapper gains the RXPS state machine. When enabled, RX is started through the driver's armDutyCycle() instead of continuous startReceive(). Requested and effective periods are kept apart. TX, CAD, idle, power off and any radio reconfiguration (via prepareForRadioConfig()) stop the duty cycle first; recvRaw() reads a packet only once RX_DONE is set. A failed arm stops the hardware duty cycle and falls back to continuous RX, recording the error. CustomSX1262 implements the duty cycle: - TCXO start-up delay of 1600 us, as in v17; - BUSY is checked so the sleeping radio is not hit by SPI; - RXEN returns to RX; - the duty cycle is stopped through standby. LR2021 keeps its idle() before setOutputPower() in setTxPower(), which the PA/TxParams standby-only commands need (upstream 114093e). Host tests in test/host (CMake, needs a RadioLib source tree): wrapper_lifecycle covers TX, CAD, arm failure and on/off, and wrapper_lifecycle_lr2021 covers the LR2021 set-tx path. From PowerSaving-v17 285cf10.
RadioLibWrapper counts CAD scans that detect LoRa activity (not free channel results or scan errors) and resets the count with the other packet stats. 'get cad' prints "on/off; channel busy: N". ESP-NOW has no CAD and reports 0. In v17 the counter was declared but never incremented.
- Calibration: the periodic noise-floor/AGC calibration runs in continuous RX, then the duty cycle is re-armed. A frame that starts during calibration is not aborted, and RSSI/SNR of the last packet are cached so they can be read while the radio sleeps. - Mode changes: a change of RX mode waits for a frame in flight or a TX to finish. RX restart requests keep an interrupt that the ISR raises meanwhile. - Retries: after three failed arm attempts the radio stays in continuous RX until the RXPS setting changes, instead of paying for a failing SPI round-trip on every RX restart. - Errors: continuous RX is started through a virtual startContinuousReceive(), whose result is reported as the RXPS 'err' status (RXPS off, during calibration, after the retry limit and as the arm-failure fallback). From PowerSaving-v17 0965a6a and be4b276.
CustomLR1110 arms the duty cycle with its own period conversion. The stock RadioLib 7.8.1 path multiplies the period by 32768 in 32 bits and overflows above ~131 ms. Arming switches the LF clock to RC with BUSY release. Stopping the duty cycle restores the XOSC LF clock with BUSY release off. Every continuous RX first enters standby and restores the clock, so a failed restore cannot leave continuous RX on the RC clock. driver_spi in test/host checks the SPI commands that the SX1262 and LR1110 drivers send for a range of periods, including the 6553-tick LR1110 command for 200 ms. It also checks injected command errors, the stop paths, and that every calculator profile yields valid periods above the radio's transition time. From PowerSaving-v17 307bc93.
Both NodePrefs types (repeater/room/sensor and companion) store the RXPS config under the v17 JSON keys: rxps_en, rxps_rx_us, rxps_sleep_us, rxps_level and rxps_preamble. Fresh installs start with Balanced (level 6, preamble 16); a saved setting, including off, wins. CommonRadioPrefs handles 'get radio.rxps' and 'set radio.rxps' for every role and applies the config to the RadioLib wrapper. Temporary radio parameters do not overwrite the stored automatic periods. 'set radio' re-checks the RXPS timing for the new SF/BW. If the profile no longer fits, the node drops to continuous RX with err=-10001 while the saved choice is kept. config_lifecycle in test/host (GoogleTest) loads and saves the real NodePrefs of both types through the shared CLI. From PowerSaving-v17 aa15933 and b1119e3.
Repeater, room server, sensor and companion apply the stored RXPS config after setParams() at boot, after temporary radio params and their revert, and after the companion's CMD_SET_RADIO_PARAMS. The repeater and companion do not count as idle while transmitting or while the noise-floor calibration holds the radio in continuous RX. From PowerSaving-v17 aa15933, 78e134b and fd14208.
…r all roles Fresh installs of every role start with the external LoRa FEM receive LNA off, which saves power; a saved setting wins. A build can default it on with -D RADIO_FEM_RXGAIN=1, replacing the separate _femon/_femoff images of v17. 'get/set radio.fem.rxgain' is handled once in CommonRadioPrefs: - it accepts only on or off; - it answers "Error: unsupported" on boards without a controllable LNA; - it marks the prefs dirty so the value is saved even when it lives in the dynamic store. config_lifecycle covers the defaults, persistence across save/load and unsupported boards. From PowerSaving-v17 9414de8, 0e47bdf, fde20d3, bbcec95 and d6a75ff.
Same package as PowerSaving-v17 (esp32-2.0.17.zip). It enables the power management and tickless-idle configuration that automatic light sleep needs; the stock 2.0.17 core has it disabled. esp32c6_base now extends arduino_base, so C6 boards stay on the pioarduino 3.x framework (without power management). From PowerSaving-v17 c0af1b5 and cb7c4b0.
The companion stores the flag as power.pwr_sav_en, the same key as CommonCLI. It is on for fresh installs; a saved value wins. The 'powersaving', 'powersaving on' and 'powersaving off' commands read and save it. On its own the flag does nothing yet; the ESP32 light sleep that uses it follows. From PowerSaving-v17 594d770 and 9414de8.
esp_pm scales the CPU between 80 and 40 MHz. When powersaving is on, it also enables automatic light sleep, and the BLE controller sleeps between connection events. The idle loop yields to the idle task only when no work is pending and no interface has a frame queued (isReadBusy/isWriteBusy). Changing the flag from the CLI reconfigures power management without a reboot. Light sleep stays off, keeping frequency scaling only, where a wake-up source would be missed: - USB CDC; - hardware UART (SERIAL_RX); - Ethernet (INT pin); - ESP-NOW (the Wi-Fi receiver is the mesh radio); - a configured Wi-Fi network. POWERSAVING_DEBUG_PRINT/LN log these decisions when built with -D POWERSAVING_DEBUG=1. From PowerSaving-v17 594d770, d42f424, a3b9ad9, 9c728e6, 4027acc and 1e888cb.
With powersaving on, the room server sleeps when it has no pending work. - Pending work: an outbound or delayed inbound packet, a TX, the noise-floor calibration, a CLI command or serial input. - Sleep length: the time to the next deadline (adverts, temporary radio params and their revert, contact save, push to logged-in clients), at most IDLE_SLEEP_MAX_MILLIS = 30 s, the repeater's and v17's limit. A LoRa packet or the user button wakes it earlier. Shared helpers: - IdleSleepBudget computes the sleep length; tested in test_idle_sleep. - sleepRoleIfIdle() (RoleSleep.h) keeps the node awake during OTA, with Ethernet, with active USB CDC, with GPS on, for the first 120 s after boot, and while a frame is being received. It observes the wrapper without starting CAD, so duty-cycled RX is not disturbed. - MainBoard gains sleepMillis(); ESP32Board implements it as a light sleep with a microsecond timer. From PowerSaving-v17 be6f359 and 61048f5.
With powersaving on, the sensor sleeps like the room server, through sleepRoleIfIdle(). The sleep is shortened to the next sensor read and to the send deadline of every queued alert. It does not sleep when a read is already due. Delayed inbound packets, TX and the noise-floor calibration count as pending work. From PowerSaving-v17 e125d37 and 1ce07cd.
|
I am doing my merge and will reference to this PR for comparision too. |
On Heltec Tracker V2 and Wireless Tracker the screen and the LoRa radio share one SPI bus. Turning the screen off also stopped that bus, so the radio hung on its next access and the whole device froze (USB, screen and button) until reset. Turning the screen off now releases only the screen's own lines and keeps the bus running for the radio.
1e74c8b to
7985978
Compare
| void setRepeatEn(bool en) { repeat.disable_fwd = en ? 0 : 1; } | ||
|
|
||
| CommonRadioPrefs* getRadioPrefs() { return &radio; } | ||
| const CommonRadioPrefs* getRadioPrefs() const { return &radio; } |
There was a problem hiding this comment.
So we have two methods?
CommonRadioPrefs* getRadioPrefs() { return &radio; }
const CommonRadioPrefs* getRadioPrefs() const { return &radio;
There was a problem hiding this comment.
This is not a duplicate, this is normal C++ construct. Removing the const version would still work, but will need more changes in main meshcore.
It is here because it is needed by _prefs.getRadioPrefs()->isRxPowerSavingCalibrationActive(), inside only const version is used so only const accessor can be used here. The non-const stays for paths that change radio settings - like applyRxPowerSaving() or handleCommand(). Same pair exists in CommonCLI.h for the other roles.
| #if defined(NRF52_PLATFORM) | ||
| board.sleep(0); // nrf ignores seconds param, sleeps whenever possible | ||
| #elif defined(ESP32_PLATFORM) | ||
| if (the_mesh.getNodePrefs()->powersaving_enabled && |
There was a problem hiding this comment.
We have to test this.
Last time I use the same code, it is much slower for BLE companions as it may need to check all the interfaces.
There was a problem hiding this comment.
ok, this may be true, we need to test it as You said 👍
| } | ||
|
|
||
| #if defined(ESP32_PLATFORM) | ||
| static uint8_t applied_powersaving = the_mesh.getNodePrefs()->powersaving_enabled; |
There was a problem hiding this comment.
Should this setting is already applied in CLI "powersaving on" of the Companion CLI?
It should be same to repeater CLI.
There was a problem hiding this comment.
Repeater sleeps a bit differently, it uses board.sleep(), but companion uses light_sleep and it is checked in main.cpp. This is companion specific, and the flag needs to be checked in case a user changes the powersaving flag on/off. applyCompanionPowerSaving is in main.cpp, and it depends on wifi/usb/uart state. Polling the setting here picks up the change without a reboot.
|
|
||
| public: | ||
| NodePrefs() : ConfigSerializer(), bridge(this), gps(this), radio(this), power(this), repeat(this), room(this), custom(&radio) { | ||
| rxps.enabled = 1; // fresh installs: Balanced L6/p16; loaded fields override this |
There was a problem hiding this comment.
This is a note to myself.
I set this rxps.enabled = 0;
The defaults are in NodePres.h or MyMesh.h.
|
I have merged all your RXPS code and most of your changes. Some of the features are good. |
I have updated the PowerSaving to work on main firmware v1.18.0
What is NOT included:
What 1.18 already had:
Done differently because it wasn't straightforward:
Different fixes that I was waiting to do a PR for PS17:
All different functions are done it different commits, so it is easy to track what was changed what for.