From aa1593340e6c33fc05f8a891eb7acfafda839f51 Mon Sep 17 00:00:00 2001 From: Kevin Le Date: Sat, 19 Sep 2026 08:00:55 +0700 Subject: [PATCH 1/4] Added RXPSv2 for sensor firmware --- examples/simple_sensor/SensorMesh.cpp | 31 ++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/examples/simple_sensor/SensorMesh.cpp b/examples/simple_sensor/SensorMesh.cpp index 7bd89ab2..a01d8276 100644 --- a/examples/simple_sensor/SensorMesh.cpp +++ b/examples/simple_sensor/SensorMesh.cpp @@ -1,4 +1,28 @@ #include "SensorMesh.h" +#include "helpers/radiolib/RXPowerSaving.h" + +static RxPowerSavingControl* getRxPowerSavingControl() { +#ifdef WRAPPER_CLASS + return &radio_driver; +#else + return nullptr; +#endif +} + +static void applyRxPowerSavingConfig(NodePrefs& prefs, uint8_t sf, float bw) { + RxPowerSavingControl* control = getRxPowerSavingControl(); + normalizeRxPowerSavingConfig(&prefs.rxps, sf, bw, rxPowerSavingCaptureCost(control), + rxPowerSavingTransition(control)); + bool ok = control != nullptr + ? control->setRxPowerSaving( + prefs.rxps.enabled != 0, prefs.rxps.rx_us, prefs.rxps.sleep_us) + : prefs.rxps.enabled == 0; + MESH_DEBUG_PRINTLN("RX Power Saving: desired=%s, rx=%lu, sleep=%lu, %s", + prefs.rxps.enabled ? "on" : "off", + (unsigned long)prefs.rxps.rx_us, + (unsigned long)prefs.rxps.sleep_us, + ok ? "accepted" : "unsupported"); +} /* ------------------------------ Config -------------------------------- */ @@ -709,7 +733,7 @@ void SensorMesh::onAckRecv(mesh::Packet* packet, uint32_t ack_crc) { SensorMesh::SensorMesh(mesh::MainBoard& board, mesh::Radio& radio, mesh::MillisecondClock& ms, mesh::RNG& rng, mesh::RTCClock& rtc, mesh::MeshTables& tables) : mesh::Mesh(radio, ms, rng, rtc, *new StaticPoolPacketManager(32), tables), region_map(key_store), - _cli(board, rtc, sensors, region_map, acl, &_prefs, this), + _cli(board, rtc, sensors, region_map, acl, &_prefs, this, getRxPowerSavingControl()), telemetry(MAX_PACKET_PAYLOAD - 4) { next_local_advert = next_flood_advert = 0; @@ -782,6 +806,7 @@ void SensorMesh::begin(FILESYSTEM* fs) { radio_driver.setTxPower(_prefs.tx_power_dbm); board.setLoRaFemLnaEnabled(_prefs.radio_fem_rxgain); board.setLoRaFemPaGainEnabled(_prefs.radio_fem_txgain); + applyRxPowerSavingConfig(_prefs, _prefs.sf, _prefs.bw); updateAdvertTimer(); updateFloodAdvertTimer(); @@ -925,12 +950,14 @@ void SensorMesh::loop() { if (set_radio_at && millisHasNowPassed(set_radio_at)) { // apply pending (temporary) radio params set_radio_at = 0; // clear timer radio_driver.setParams(pending_freq, pending_bw, pending_sf, pending_cr); + applyRxPowerSavingConfig(_prefs, pending_sf, pending_bw); MESH_DEBUG_PRINTLN("Temp radio params"); } if (revert_radio_at && millisHasNowPassed(revert_radio_at)) { // revert radio params to orig revert_radio_at = 0; // clear timer radio_driver.setParams(_prefs.freq, _prefs.bw, _prefs.sf, _prefs.cr); + applyRxPowerSavingConfig(_prefs, _prefs.sf, _prefs.bw); MESH_DEBUG_PRINTLN("Radio params restored"); } @@ -991,5 +1018,7 @@ void SensorMesh::loop() { // To check if there is pending work bool SensorMesh::hasPendingWork() const { + const RxPowerSavingControl* control = getRxPowerSavingControl(); + if (control != nullptr && control->isRxPowerSavingCalibrationActive()) return true; return _mgr->getOutboundTotal() > 0; } \ No newline at end of file From 26538e8a35ddb50fd523403574e33b51e617d61d Mon Sep 17 00:00:00 2001 From: Kevin Le Date: Sat, 19 Sep 2026 11:03:20 +0700 Subject: [PATCH 2/4] Do not turn on LED before powering off --- examples/simple_repeater/UITask.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/examples/simple_repeater/UITask.cpp b/examples/simple_repeater/UITask.cpp index 89c833fa..32db6751 100644 --- a/examples/simple_repeater/UITask.cpp +++ b/examples/simple_repeater/UITask.cpp @@ -151,9 +151,6 @@ void UITask::loop() { } if (_powering_off_at > 0) { // power off timer armed -#ifdef LED_PIN - digitalWrite(LED_PIN, LED_STATE_ON); // switch on the led until poweroff -#endif if (millis() > _powering_off_at) { _board->powerOff(); // should not return } From 166fd6a941213d0026c64228aa7a7b20ff6785c7 Mon Sep 17 00:00:00 2001 From: Kevin Le Date: Sat, 19 Sep 2026 11:38:37 +0700 Subject: [PATCH 3/4] Off LED before powering off for repeaters --- examples/simple_repeater/UITask.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/examples/simple_repeater/UITask.cpp b/examples/simple_repeater/UITask.cpp index 32db6751..f79330c8 100644 --- a/examples/simple_repeater/UITask.cpp +++ b/examples/simple_repeater/UITask.cpp @@ -151,6 +151,11 @@ void UITask::loop() { } if (_powering_off_at > 0) { // power off timer armed +#if defined(LED_PIN) && defined(LED_STATE_ON) + digitalWrite(LED_PIN, LED_STATE_ON); // switch on the led until poweroff + delay(1000); + digitalWrite(LED_PIN, !LED_STATE_ON); // off LED +#endif if (millis() > _powering_off_at) { _board->powerOff(); // should not return } From d9c42964eb80f570a267ff92250aaddf6b3e49ae Mon Sep 17 00:00:00 2001 From: Kevin Le Date: Sat, 19 Sep 2026 18:37:03 +0700 Subject: [PATCH 4/4] Added enterDeepSleep() for NRF52 and shutdownPeripherals() for ESP32 --- src/MeshCore.h | 1 + src/helpers/ESP32Board.cpp | 14 ++++++---- src/helpers/ESP32Board.h | 3 ++- src/helpers/NRF52Board.cpp | 23 ++++++++++++++++ src/helpers/NRF52Board.h | 1 + .../GAT56230SMeshKitBoard.h | 6 ++--- .../gat562_mesh_evb_pro/GAT562EVBProBoard.h | 6 ++--- .../GAT562MeshTrackerProBoard.h | 6 ++--- .../GAT56MeshWatch13Board.h | 6 ++--- variants/heltec_rc32/HeltecRC32Board.cpp | 4 --- variants/heltec_rc32/HeltecRC32Board.h | 1 - variants/heltec_t096/T096Board.cpp | 5 ++-- variants/heltec_t096/T096Board.h | 2 +- variants/heltec_t1/T1Board.cpp | 5 ++-- variants/heltec_t1/T1Board.h | 2 +- variants/heltec_t114/T114Board.h | 6 ++--- .../heltec_tower_v2/HeltecTowerV2Board.cpp | 7 ++--- variants/heltec_tower_v2/HeltecTowerV2Board.h | 2 +- .../HeltecTrackerV2Board.cpp | 6 ++--- .../heltec_tracker_v2/HeltecTrackerV2Board.h | 2 +- variants/heltec_v4/HeltecV4Board.cpp | 6 ++--- variants/heltec_v4/HeltecV4Board.h | 2 +- variants/heltec_v4_r8/HeltecV4R8Board.cpp | 26 +++---------------- variants/heltec_v4_r8/HeltecV4R8Board.h | 3 +-- variants/lilygo_tbeam_1w/TBeam1WBoard.cpp | 6 ++--- variants/lilygo_tbeam_1w/TBeam1WBoard.h | 2 +- variants/meshtiny/MeshtinyBoard.h | 6 ++--- variants/meshtracker_x1/MeshTrackerX1Board.h | 6 ++--- .../MinewsemiME25LS01Board.h | 5 ++-- variants/muziworks_r1_neo/R1NeoBoard.h | 2 ++ variants/nano_g2_ultra/nano-g2.h | 6 ++--- variants/rak_wismesh_tag/RAKWismeshTagBoard.h | 6 ++--- variants/sensecap_solar/SenseCapSolarBoard.h | 8 +++++- variants/station_g3_esp32/StationG3Board.cpp | 6 ++--- variants/station_g3_esp32/StationG3Board.h | 2 +- variants/t1000-e/T1000eBoard.h | 6 ++--- variants/thinknode_m1/ThinkNodeM1Board.h | 6 ++--- variants/thinknode_m3/ThinkNodeM3Board.h | 7 +++-- variants/thinknode_m6/ThinkNodeM6Board.h | 6 ++--- variants/wio-tracker-l1/WioTrackerL1Board.h | 4 --- variants/xiao_nrf52/XiaoNrf52Board.h | 6 ++--- 41 files changed, 120 insertions(+), 115 deletions(-) diff --git a/src/MeshCore.h b/src/MeshCore.h index 12f591e2..dbfc2bd5 100644 --- a/src/MeshCore.h +++ b/src/MeshCore.h @@ -62,6 +62,7 @@ public: virtual void onAfterTransmit() { } virtual void reboot() = 0; virtual void powerOff() { /* no op */ } + virtual void enterDeepSleep(uint32_t secs) { /* no op */ } // Called by example setup() functions to signal that boot is complete. // Boards may override to stop a boot-indicator LED sequence or similar. // Default no-op: boards that don't care need not implement anything. diff --git a/src/helpers/ESP32Board.cpp b/src/helpers/ESP32Board.cpp index a55abb26..57bff06e 100644 --- a/src/helpers/ESP32Board.cpp +++ b/src/helpers/ESP32Board.cpp @@ -45,11 +45,7 @@ bool ESP32Board::startOTAUpdate(const char* id, char reply[]) { } #endif -void ESP32Board::powerOff() { - enterDeepSleep(0); // Do not wakeup -} - -void ESP32Board::enterDeepSleep(uint32_t secs) { +void ESP32Board::shutdownPeripherals() { // Power off the display if any #ifdef DISPLAY_CLASS display.turnOff(); @@ -74,6 +70,14 @@ void ESP32Board::enterDeepSleep(uint32_t secs) { // Flush serial buffers Serial.flush(); delay(100); +} + +void ESP32Board::powerOff() { + enterDeepSleep(0); // Do not wakeup +} + +void ESP32Board::enterDeepSleep(uint32_t secs) { + shutdownPeripherals(); // Clear stale wakeup sources to avoid ghost wakeup // This is required when Power Management and automatic lightsleep are enabled diff --git a/src/helpers/ESP32Board.h b/src/helpers/ESP32Board.h index 2e22a47d..d8389e77 100644 --- a/src/helpers/ESP32Board.h +++ b/src/helpers/ESP32Board.h @@ -64,8 +64,9 @@ public: return raw / 4; } + virtual void shutdownPeripherals(); virtual void powerOff() override; - void enterDeepSleep(uint32_t secs); + virtual void enterDeepSleep(uint32_t secs) override; uint32_t getIRQGpio() override { return P_LORA_DIO_1; // default for SX1262 diff --git a/src/helpers/NRF52Board.cpp b/src/helpers/NRF52Board.cpp index eb88c897..6453645f 100644 --- a/src/helpers/NRF52Board.cpp +++ b/src/helpers/NRF52Board.cpp @@ -383,6 +383,29 @@ void NRF52Board::powerOff() { } } +void NRF52Board::enterDeepSleep(uint32_t secs) { + if (secs == 0) { + powerOff(); // Not wake up + } else { + shutdownPeripherals(); + +// Clear FPU interrupt flags to avoid insomnia +// see errata 87 for details +// https://docs.nordicsemi.com/bundle/errata_nRF52840_Rev3/page/ERR/nRF52840/Rev3/latest/anomaly_840_87.html +#if (__FPU_USED == 1) + __set_FPSCR(__get_FPSCR() & ~(0x0000009F)); + (void)__get_FPSCR(); + NVIC_ClearPendingIRQ(FPU_IRQn); +#endif + + // Attemp to sleep + vTaskDelay(pdMS_TO_TICKS(secs * 1000)); + + // Reboot for a fresh recovery + reboot(); + } +} + bool NRF52Board::getBootloaderVersion(char* out, size_t max_len) { static const char BOOTLOADER_MARKER[] = "UF2 Bootloader "; const uint8_t* flash = (const uint8_t*)0x000FB000; // earliest known info.txt location is 0xFB90B, latest is 0xFCC4B diff --git a/src/helpers/NRF52Board.h b/src/helpers/NRF52Board.h index dba15f97..02848c32 100644 --- a/src/helpers/NRF52Board.h +++ b/src/helpers/NRF52Board.h @@ -52,6 +52,7 @@ public: virtual void reboot() override { NVIC_SystemReset(); } virtual void shutdownPeripherals(); virtual void powerOff() override; + virtual void enterDeepSleep(uint32_t secs) override; virtual bool getBootloaderVersion(char* version, size_t max_len) override; virtual bool startOTAUpdate(const char *id, char reply[]) override; virtual void sleep(uint32_t secs) override; diff --git a/variants/gat562_30s_mesh_kit/GAT56230SMeshKitBoard.h b/variants/gat562_30s_mesh_kit/GAT56230SMeshKitBoard.h index 0b0f701c..82034c7e 100644 --- a/variants/gat562_30s_mesh_kit/GAT56230SMeshKitBoard.h +++ b/variants/gat562_30s_mesh_kit/GAT56230SMeshKitBoard.h @@ -43,11 +43,11 @@ public: } #endif - void powerOff() override { + void shutdownPeripherals() override { + NRF52Board::shutdownPeripherals(); + uint32_t button_pin = PIN_BUTTON1; nrf_gpio_cfg_input(button_pin, NRF_GPIO_PIN_PULLUP); nrf_gpio_cfg_sense_set(button_pin, NRF_GPIO_PIN_SENSE_LOW); - NRF52Board::powerOff(); } - }; diff --git a/variants/gat562_mesh_evb_pro/GAT562EVBProBoard.h b/variants/gat562_mesh_evb_pro/GAT562EVBProBoard.h index 66c77099..a3d738ca 100644 --- a/variants/gat562_mesh_evb_pro/GAT562EVBProBoard.h +++ b/variants/gat562_mesh_evb_pro/GAT562EVBProBoard.h @@ -43,11 +43,11 @@ public: } #endif - void powerOff() override { + void shutdownPeripherals() override { + NRF52Board::shutdownPeripherals(); + uint32_t button_pin = PIN_BUTTON1; nrf_gpio_cfg_input(button_pin, NRF_GPIO_PIN_PULLUP); nrf_gpio_cfg_sense_set(button_pin, NRF_GPIO_PIN_SENSE_LOW); - NRF52Board::powerOff(); } - }; diff --git a/variants/gat562_mesh_tracker_pro/GAT562MeshTrackerProBoard.h b/variants/gat562_mesh_tracker_pro/GAT562MeshTrackerProBoard.h index 39b55911..f179cdc7 100644 --- a/variants/gat562_mesh_tracker_pro/GAT562MeshTrackerProBoard.h +++ b/variants/gat562_mesh_tracker_pro/GAT562MeshTrackerProBoard.h @@ -43,11 +43,11 @@ public: } #endif - void powerOff() override { + void shutdownPeripherals() override { + NRF52Board::shutdownPeripherals(); + uint32_t button_pin = PIN_BUTTON1; nrf_gpio_cfg_input(button_pin, NRF_GPIO_PIN_PULLUP); nrf_gpio_cfg_sense_set(button_pin, NRF_GPIO_PIN_SENSE_LOW); - NRF52Board::powerOff(); } - }; diff --git a/variants/gat562_mesh_watch13/GAT56MeshWatch13Board.h b/variants/gat562_mesh_watch13/GAT56MeshWatch13Board.h index 805ca67f..d8fcb2bb 100644 --- a/variants/gat562_mesh_watch13/GAT56MeshWatch13Board.h +++ b/variants/gat562_mesh_watch13/GAT56MeshWatch13Board.h @@ -34,11 +34,11 @@ public: } - void powerOff() override { + void shutdownPeripherals() override { + NRF52Board::shutdownPeripherals(); + uint32_t button_pin = PIN_BUTTON1; nrf_gpio_cfg_input(button_pin, NRF_GPIO_PIN_PULLUP); nrf_gpio_cfg_sense_set(button_pin, NRF_GPIO_PIN_SENSE_LOW); - NRF52Board::powerOff(); } - }; diff --git a/variants/heltec_rc32/HeltecRC32Board.cpp b/variants/heltec_rc32/HeltecRC32Board.cpp index 59920d23..1ead34bf 100644 --- a/variants/heltec_rc32/HeltecRC32Board.cpp +++ b/variants/heltec_rc32/HeltecRC32Board.cpp @@ -31,10 +31,6 @@ void HeltecRC32Board::begin() { } } -void HeltecRC32Board::powerOff() { - enterDeepSleep(0); -} - void HeltecRC32Board::onBeforeTransmit() { digitalWrite(P_LORA_TX_LED, HIGH); } diff --git a/variants/heltec_rc32/HeltecRC32Board.h b/variants/heltec_rc32/HeltecRC32Board.h index 5b2093c8..e53111e7 100644 --- a/variants/heltec_rc32/HeltecRC32Board.h +++ b/variants/heltec_rc32/HeltecRC32Board.h @@ -21,7 +21,6 @@ public: void begin(); void onBeforeTransmit() override; void onAfterTransmit() override; - void powerOff() override; uint16_t getBattMilliVolts() override; bool setAdcMultiplier(float multiplier) override; float getAdcMultiplier() const override { return adc_mult; } diff --git a/variants/heltec_t096/T096Board.cpp b/variants/heltec_t096/T096Board.cpp index af048e38..f7805e49 100644 --- a/variants/heltec_t096/T096Board.cpp +++ b/variants/heltec_t096/T096Board.cpp @@ -111,10 +111,11 @@ void T096Board::variant_shutdown() { nrf_gpio_cfg_default(PIN_GPS_TX); } -void T096Board::powerOff() { +void T096Board::shutdownPeripherals() { + NRF52Board::shutdownPeripherals(); + loRaFEMControl.setSleepModeEnable(); nrf_gpio_cfg_default(PIN_GPS_EN); // 363uA down to 39uA - NRF52Board::powerOff(); } const char* T096Board::getManufacturerName() const { diff --git a/variants/heltec_t096/T096Board.h b/variants/heltec_t096/T096Board.h index 15c7e68b..7911f194 100644 --- a/variants/heltec_t096/T096Board.h +++ b/variants/heltec_t096/T096Board.h @@ -24,7 +24,7 @@ public: void onAfterTransmit(void) override; uint16_t getBattMilliVolts() override; const char* getManufacturerName() const override ; - void powerOff() override; + void shutdownPeripherals() override; bool setLoRaFemLnaEnabled(bool enable) override; bool canControlLoRaFemLna() const override; bool isLoRaFemLnaEnabled() const override; diff --git a/variants/heltec_t1/T1Board.cpp b/variants/heltec_t1/T1Board.cpp index 1ef5b766..a54b8eae 100644 --- a/variants/heltec_t1/T1Board.cpp +++ b/variants/heltec_t1/T1Board.cpp @@ -97,9 +97,10 @@ void T1Board::variant_shutdown() { digitalWrite(PIN_BAT_CTL, !ADC_CTRL_ENABLED); } -void T1Board::powerOff() { +void T1Board::shutdownPeripherals() { + NRF52Board::shutdownPeripherals(); + variant_shutdown(); - NRF52Board::powerOff(); } const char* T1Board::getManufacturerName() const { diff --git a/variants/heltec_t1/T1Board.h b/variants/heltec_t1/T1Board.h index 9b46fd11..3e9afd1b 100644 --- a/variants/heltec_t1/T1Board.h +++ b/variants/heltec_t1/T1Board.h @@ -22,5 +22,5 @@ public: void onAfterTransmit() override; uint16_t getBattMilliVolts() override; const char* getManufacturerName() const override; - void powerOff() override; + void shutdownPeripherals() override; }; diff --git a/variants/heltec_t114/T114Board.h b/variants/heltec_t114/T114Board.h index bd76d3de..6d7664cb 100644 --- a/variants/heltec_t114/T114Board.h +++ b/variants/heltec_t114/T114Board.h @@ -46,11 +46,11 @@ public: return "Heltec T114"; } - void powerOff() override { + void shutdownPeripherals() override { + NRF52Board::shutdownPeripherals(); + #ifdef LED_PIN digitalWrite(LED_PIN, HIGH); #endif - - NRF52Board::powerOff(); } }; diff --git a/variants/heltec_tower_v2/HeltecTowerV2Board.cpp b/variants/heltec_tower_v2/HeltecTowerV2Board.cpp index 04213bda..a02f8e9c 100644 --- a/variants/heltec_tower_v2/HeltecTowerV2Board.cpp +++ b/variants/heltec_tower_v2/HeltecTowerV2Board.cpp @@ -88,7 +88,9 @@ const char* HeltecTowerV2Board::getManufacturerName() const { return "Heltec Tower V2"; } -void HeltecTowerV2Board::powerOff() { +void HeltecTowerV2Board::shutdownPeripherals() { + NRF52Board::shutdownPeripherals(); + pinMode(PIN_GPS_EN, OUTPUT); digitalWrite(PIN_GPS_EN, !PIN_GPS_EN_ACTIVE); pinMode(PIN_GPS_STANDBY, OUTPUT); @@ -99,5 +101,4 @@ void HeltecTowerV2Board::powerOff() { pinMode(PIN_BAT_CTL, OUTPUT); digitalWrite(PIN_BAT_CTL, LOW); variant_shutdown(); - sd_power_system_off(); -} +} \ No newline at end of file diff --git a/variants/heltec_tower_v2/HeltecTowerV2Board.h b/variants/heltec_tower_v2/HeltecTowerV2Board.h index 6912acde..b5e7f127 100644 --- a/variants/heltec_tower_v2/HeltecTowerV2Board.h +++ b/variants/heltec_tower_v2/HeltecTowerV2Board.h @@ -20,5 +20,5 @@ public: void onAfterTransmit() override; uint16_t getBattMilliVolts() override; const char* getManufacturerName() const override; - void powerOff() override; + void shutdownPeripherals() override; }; diff --git a/variants/heltec_tracker_v2/HeltecTrackerV2Board.cpp b/variants/heltec_tracker_v2/HeltecTrackerV2Board.cpp index bb3993b4..ba343ac6 100644 --- a/variants/heltec_tracker_v2/HeltecTrackerV2Board.cpp +++ b/variants/heltec_tracker_v2/HeltecTrackerV2Board.cpp @@ -35,12 +35,12 @@ void HeltecTrackerV2Board::begin() { loRaFEMControl.setRxModeEnable(); } - void HeltecTrackerV2Board::powerOff() { + void HeltecTrackerV2Board::shutdownPeripherals() { + ESP32Board::shutdownPeripherals(); + // Turn off PA digitalWrite(P_LORA_PA_POWER, LOW); rtc_gpio_hold_en((gpio_num_t)P_LORA_PA_POWER); - - ESP32Board::powerOff(); } uint16_t HeltecTrackerV2Board::getBattMilliVolts() { diff --git a/variants/heltec_tracker_v2/HeltecTrackerV2Board.h b/variants/heltec_tracker_v2/HeltecTrackerV2Board.h index 2bd6a025..cc5b173b 100644 --- a/variants/heltec_tracker_v2/HeltecTrackerV2Board.h +++ b/variants/heltec_tracker_v2/HeltecTrackerV2Board.h @@ -16,7 +16,7 @@ public: void begin(); void onBeforeTransmit(void) override; void onAfterTransmit(void) override; - void powerOff() override; + void shutdownPeripherals() override; uint16_t getBattMilliVolts() override; const char* getManufacturerName() const override ; bool setLoRaFemLnaEnabled(bool enable) override; diff --git a/variants/heltec_v4/HeltecV4Board.cpp b/variants/heltec_v4/HeltecV4Board.cpp index ba3a7f1c..7ee317b3 100644 --- a/variants/heltec_v4/HeltecV4Board.cpp +++ b/variants/heltec_v4/HeltecV4Board.cpp @@ -32,12 +32,12 @@ void HeltecV4Board::begin() { loRaFEMControl.setRxModeEnable(); } - void HeltecV4Board::powerOff() { + void HeltecV4Board::shutdownPeripherals() { + ESP32Board::shutdownPeripherals(); + // Turn off PA digitalWrite(P_LORA_PA_POWER, LOW); rtc_gpio_hold_en((gpio_num_t)P_LORA_PA_POWER); - - ESP32Board::powerOff(); } uint16_t HeltecV4Board::getBattMilliVolts() { diff --git a/variants/heltec_v4/HeltecV4Board.h b/variants/heltec_v4/HeltecV4Board.h index 55166bb3..5905a8dc 100644 --- a/variants/heltec_v4/HeltecV4Board.h +++ b/variants/heltec_v4/HeltecV4Board.h @@ -22,7 +22,7 @@ public: void begin(); void onBeforeTransmit(void) override; void onAfterTransmit(void) override; - void powerOff() override; + void shutdownPeripherals() override; bool setLoRaFemLnaEnabled(bool enable) override; bool canControlLoRaFemLna() const override; bool isLoRaFemLnaEnabled() const override; diff --git a/variants/heltec_v4_r8/HeltecV4R8Board.cpp b/variants/heltec_v4_r8/HeltecV4R8Board.cpp index 1fb123b2..b1db7d78 100644 --- a/variants/heltec_v4_r8/HeltecV4R8Board.cpp +++ b/variants/heltec_v4_r8/HeltecV4R8Board.cpp @@ -39,30 +39,10 @@ void HeltecV4R8Board::onAfterTransmit(void) { loRaFEMControl.setRxModeEnable(); } -void HeltecV4R8Board::enterDeepSleep(uint32_t secs, int pin_wake_btn) { - esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON); - - rtc_gpio_set_direction((gpio_num_t)P_LORA_DIO_1, RTC_GPIO_MODE_INPUT_ONLY); - rtc_gpio_pulldown_en((gpio_num_t)P_LORA_DIO_1); - - rtc_gpio_hold_en((gpio_num_t)P_LORA_NSS); +void HeltecV4R8Board::shutdownPeripherals() { + ESP32Board::shutdownPeripherals(); + loRaFEMControl.setRxModeEnableWhenMCUSleep(); - - if (pin_wake_btn < 0) { - esp_sleep_enable_ext1_wakeup((1L << P_LORA_DIO_1), ESP_EXT1_WAKEUP_ANY_HIGH); - } else { - esp_sleep_enable_ext1_wakeup((1L << P_LORA_DIO_1) | (1L << pin_wake_btn), ESP_EXT1_WAKEUP_ANY_HIGH); - } - - if (secs > 0) { - esp_sleep_enable_timer_wakeup(secs * 1000000); - } - - esp_deep_sleep_start(); -} - -void HeltecV4R8Board::powerOff() { - enterDeepSleep(0); } uint16_t HeltecV4R8Board::getBattMilliVolts() { diff --git a/variants/heltec_v4_r8/HeltecV4R8Board.h b/variants/heltec_v4_r8/HeltecV4R8Board.h index 20811abb..232390fc 100644 --- a/variants/heltec_v4_r8/HeltecV4R8Board.h +++ b/variants/heltec_v4_r8/HeltecV4R8Board.h @@ -23,8 +23,7 @@ public: void begin(); void onBeforeTransmit(void) override; void onAfterTransmit(void) override; - void enterDeepSleep(uint32_t secs, int pin_wake_btn = -1); - void powerOff() override; + void shutdownPeripherals() override; uint16_t getBattMilliVolts() override; bool setAdcMultiplier(float multiplier) override { if (multiplier == 0.0f) { diff --git a/variants/lilygo_tbeam_1w/TBeam1WBoard.cpp b/variants/lilygo_tbeam_1w/TBeam1WBoard.cpp index 1719d733..e9a9a323 100644 --- a/variants/lilygo_tbeam_1w/TBeam1WBoard.cpp +++ b/variants/lilygo_tbeam_1w/TBeam1WBoard.cpp @@ -47,7 +47,9 @@ const char* TBeam1WBoard::getManufacturerName() const { return "LilyGo T-Beam 1W"; } -void TBeam1WBoard::powerOff() { +void TBeam1WBoard::shutdownPeripherals() { + ESP32Board::shutdownPeripherals(); + // Turn off radio LNA (CTRL pin must be LOW when not receiving) digitalWrite(SX126X_RXEN, LOW); @@ -58,8 +60,6 @@ void TBeam1WBoard::powerOff() { // Turn off LED and fan digitalWrite(LED_PIN, LOW); digitalWrite(FAN_CTRL_PIN, LOW); - - ESP32Board::powerOff(); } void TBeam1WBoard::setFanEnabled(bool enabled) { diff --git a/variants/lilygo_tbeam_1w/TBeam1WBoard.h b/variants/lilygo_tbeam_1w/TBeam1WBoard.h index d999dfd4..009b65de 100644 --- a/variants/lilygo_tbeam_1w/TBeam1WBoard.h +++ b/variants/lilygo_tbeam_1w/TBeam1WBoard.h @@ -37,7 +37,7 @@ public: void onAfterTransmit() override; uint16_t getBattMilliVolts() override; const char* getManufacturerName() const override; - void powerOff() override; + void shutdownPeripherals() override; // Fan control methods void setFanEnabled(bool enabled); diff --git a/variants/meshtiny/MeshtinyBoard.h b/variants/meshtiny/MeshtinyBoard.h index 67a521fe..ba42d673 100644 --- a/variants/meshtiny/MeshtinyBoard.h +++ b/variants/meshtiny/MeshtinyBoard.h @@ -34,7 +34,8 @@ public: void reboot() override { NVIC_SystemReset(); } - void powerOff() override { + void shutdownPeripherals() override { + NRF52Board::shutdownPeripherals(); #ifdef PIN_USER_BTN while (digitalRead(PIN_USER_BTN) == LOW) { @@ -59,8 +60,5 @@ public: #ifdef PIN_USER_BTN nrf_gpio_cfg_sense_input(g_ADigitalPinMap[PIN_USER_BTN], NRF_GPIO_PIN_PULLUP, NRF_GPIO_PIN_SENSE_LOW); #endif - - NRF52Board::powerOff(); } - }; diff --git a/variants/meshtracker_x1/MeshTrackerX1Board.h b/variants/meshtracker_x1/MeshTrackerX1Board.h index 51f022e0..e153dd7f 100644 --- a/variants/meshtracker_x1/MeshTrackerX1Board.h +++ b/variants/meshtracker_x1/MeshTrackerX1Board.h @@ -46,7 +46,9 @@ public: return 0; } - void powerOff() override { + void shutdownPeripherals() override { + NRF52Board::shutdownPeripherals(); + #ifdef HAS_GPS digitalWrite(GPS_VRTC_EN, LOW); digitalWrite(GPS_RESET, LOW); @@ -81,7 +83,5 @@ public: #ifdef BUTTON_PIN nrf_gpio_cfg_sense_input(BUTTON_PIN, NRF_GPIO_PIN_PULLDOWN, NRF_GPIO_PIN_SENSE_HIGH); #endif - - sd_power_system_off(); } }; diff --git a/variants/minewsemi_me25ls01/MinewsemiME25LS01Board.h b/variants/minewsemi_me25ls01/MinewsemiME25LS01Board.h index 450a3d13..e4bbc7d0 100644 --- a/variants/minewsemi_me25ls01/MinewsemiME25LS01Board.h +++ b/variants/minewsemi_me25ls01/MinewsemiME25LS01Board.h @@ -45,7 +45,9 @@ public: return "Minewsemi"; } - void powerOff() override { + void shutdownPeripherals() override { + NRF52Board::shutdownPeripherals(); + #ifdef HAS_GPS digitalWrite(GPS_VRTC_EN, LOW); digitalWrite(GPS_RESET, LOW); @@ -65,7 +67,6 @@ public: #ifdef BUTTON_PIN nrf_gpio_cfg_sense_input(digitalPinToInterrupt(BUTTON_PIN), NRF_GPIO_PIN_PULLUP, NRF_GPIO_PIN_SENSE_LOW); #endif - NRF52Board::powerOff(); } #if defined(P_LORA_TX_LED) diff --git a/variants/muziworks_r1_neo/R1NeoBoard.h b/variants/muziworks_r1_neo/R1NeoBoard.h index c56f1f5c..47b70571 100644 --- a/variants/muziworks_r1_neo/R1NeoBoard.h +++ b/variants/muziworks_r1_neo/R1NeoBoard.h @@ -20,6 +20,8 @@ public: #ifdef NRF52_POWER_MANAGEMENT void powerOff() override { + shutdownPeripherals(); + initiateShutdown(SHUTDOWN_REASON_USER); } #endif diff --git a/variants/nano_g2_ultra/nano-g2.h b/variants/nano_g2_ultra/nano-g2.h index bf9543b0..8e5875c4 100644 --- a/variants/nano_g2_ultra/nano-g2.h +++ b/variants/nano_g2_ultra/nano-g2.h @@ -43,7 +43,9 @@ public: const char *getManufacturerName() const override { return "Nano G2 Ultra"; } - void powerOff() override { + void shutdownPeripherals() override { + NRF52Board::shutdownPeripherals(); + // put GPS chip to sleep digitalWrite(PIN_GPS_STANDBY, LOW); // TODO: unset buzzer to prevent notification circuit activating on hibernate @@ -51,7 +53,5 @@ public: nrf_gpio_cfg_sense_input(digitalPinToInterrupt(PIN_USER_BTN), NRF_GPIO_PIN_NOPULL, NRF_GPIO_PIN_SENSE_LOW); - - NRF52Board::powerOff(); } }; diff --git a/variants/rak_wismesh_tag/RAKWismeshTagBoard.h b/variants/rak_wismesh_tag/RAKWismeshTagBoard.h index daa90d74..9368d17e 100644 --- a/variants/rak_wismesh_tag/RAKWismeshTagBoard.h +++ b/variants/rak_wismesh_tag/RAKWismeshTagBoard.h @@ -40,7 +40,9 @@ public: return "RAK WisMesh Tag"; } - void powerOff() override { + void shutdownPeripherals() override { + NRF52Board::shutdownPeripherals(); + #ifdef BUZZER_EN digitalWrite(BUZZER_EN, LOW); #endif @@ -68,7 +70,5 @@ public: // configure button press to wake up when in powered off state nrf_gpio_cfg_sense_input(digitalPinToInterrupt(BUTTON_PIN), NRF_GPIO_PIN_PULLUP, NRF_GPIO_PIN_SENSE_LOW); #endif - - NRF52Board::powerOff(); } }; diff --git a/variants/sensecap_solar/SenseCapSolarBoard.h b/variants/sensecap_solar/SenseCapSolarBoard.h index 5a8861c2..ad0b62ab 100644 --- a/variants/sensecap_solar/SenseCapSolarBoard.h +++ b/variants/sensecap_solar/SenseCapSolarBoard.h @@ -37,7 +37,9 @@ public: return "Seeed SenseCap Solar"; } - void powerOff() override { + void shutdownPeripherals() override { + NRF52Board::shutdownPeripherals(); + digitalWrite(LED_WHITE, LOW); digitalWrite(LED_BLUE, LOW); @@ -50,6 +52,10 @@ public: // Keep pull-up enabled in system-off so the wake line doesn't float low. nrf_gpio_cfg_sense_input(digitalPinToInterrupt(g_ADigitalPinMap[PIN_BUTTON1]), NRF_GPIO_PIN_PULLUP, NRF_GPIO_PIN_SENSE_LOW); #endif + } + + void powerOff() override { + shutdownPeripherals(); #ifdef NRF52_POWER_MANAGEMENT initiateShutdown(SHUTDOWN_REASON_USER); diff --git a/variants/station_g3_esp32/StationG3Board.cpp b/variants/station_g3_esp32/StationG3Board.cpp index dd863aca..cafd4cd2 100644 --- a/variants/station_g3_esp32/StationG3Board.cpp +++ b/variants/station_g3_esp32/StationG3Board.cpp @@ -1,6 +1,8 @@ #include "StationG3Board.h" -void StationG3Board::powerOff() { +void StationG3Board::shutdownPeripherals() { + ESP32Board::shutdownPeripherals(); + loRaFEMControl.setSleepModeEnable(); #ifdef P_PA1_EN rtc_gpio_hold_en((gpio_num_t)P_PA1_EN); @@ -9,8 +11,6 @@ void StationG3Board::powerOff() { #ifdef P_PRIMARY_LNA_EN rtc_gpio_hold_en((gpio_num_t)P_PRIMARY_LNA_EN); #endif - - ESP32Board::powerOff(); } bool StationG3Board::setLoRaFemLnaEnabled(bool enable) { diff --git a/variants/station_g3_esp32/StationG3Board.h b/variants/station_g3_esp32/StationG3Board.h index 52628eb6..d1c4dec3 100644 --- a/variants/station_g3_esp32/StationG3Board.h +++ b/variants/station_g3_esp32/StationG3Board.h @@ -50,7 +50,7 @@ public: bool canControlLoRaFemPaGain() const override; bool isLoRaFemPaGainEnabled() const override; - void powerOff() override; + void shutdownPeripherals() override; uint16_t getBattMilliVolts() override { return 0; diff --git a/variants/t1000-e/T1000eBoard.h b/variants/t1000-e/T1000eBoard.h index 1111d3c4..84021fac 100644 --- a/variants/t1000-e/T1000eBoard.h +++ b/variants/t1000-e/T1000eBoard.h @@ -49,7 +49,9 @@ public: return 0; } - void powerOff() override { + void shutdownPeripherals() override { + NRF52Board::shutdownPeripherals(); + #ifdef HAS_GPS digitalWrite(GPS_VRTC_EN, LOW); digitalWrite(GPS_RESET, LOW); @@ -87,7 +89,5 @@ public: #ifdef BUTTON_PIN nrf_gpio_cfg_sense_input(BUTTON_PIN, NRF_GPIO_PIN_NOPULL, NRF_GPIO_PIN_SENSE_HIGH); #endif - - NRF52Board::powerOff(); } }; diff --git a/variants/thinknode_m1/ThinkNodeM1Board.h b/variants/thinknode_m1/ThinkNodeM1Board.h index 94224d9c..e5af3690 100644 --- a/variants/thinknode_m1/ThinkNodeM1Board.h +++ b/variants/thinknode_m1/ThinkNodeM1Board.h @@ -32,14 +32,12 @@ public: return "Elecrow ThinkNode-M1"; } - void powerOff() override { + void shutdownPeripherals() override { + NRF52Board::shutdownPeripherals(); // turn off all leds, sd_power_system_off will not do this for us #ifdef P_LORA_TX_LED digitalWrite(P_LORA_TX_LED, LOW); #endif - - // power off board - NRF52Board::powerOff(); } }; diff --git a/variants/thinknode_m3/ThinkNodeM3Board.h b/variants/thinknode_m3/ThinkNodeM3Board.h index 9e8f4989..496ee2e0 100644 --- a/variants/thinknode_m3/ThinkNodeM3Board.h +++ b/variants/thinknode_m3/ThinkNodeM3Board.h @@ -42,13 +42,12 @@ public: return 0; } - void powerOff() override { + void shutdownPeripherals() override { + NRF52Board::shutdownPeripherals(); + // turn off all leds, sd_power_system_off will not do this for us digitalWrite(PIN_LED_BLUE, !LED_STATE_ON); digitalWrite(PIN_LED_GREEN, !LED_STATE_ON); digitalWrite(PIN_LED_RED, !LED_STATE_ON); - - // power off board - NRF52Board::powerOff(); } }; diff --git a/variants/thinknode_m6/ThinkNodeM6Board.h b/variants/thinknode_m6/ThinkNodeM6Board.h index 78815e2c..25f6255c 100644 --- a/variants/thinknode_m6/ThinkNodeM6Board.h +++ b/variants/thinknode_m6/ThinkNodeM6Board.h @@ -36,14 +36,12 @@ public: return "Elecrow ThinkNode M6"; } - void powerOff() override { + void shutdownPeripherals() override { + NRF52Board::shutdownPeripherals(); // turn off all leds, sd_power_system_off will not do this for us #ifdef P_LORA_TX_LED digitalWrite(P_LORA_TX_LED, LOW); #endif - - // power off board - NRF52Board::powerOff(); } }; diff --git a/variants/wio-tracker-l1/WioTrackerL1Board.h b/variants/wio-tracker-l1/WioTrackerL1Board.h index e376e066..1b1f8040 100644 --- a/variants/wio-tracker-l1/WioTrackerL1Board.h +++ b/variants/wio-tracker-l1/WioTrackerL1Board.h @@ -33,8 +33,4 @@ public: const char* getManufacturerName() const override { return "Seeed Wio Tracker L1"; } - - void powerOff() override { - NRF52Board::powerOff(); - } }; diff --git a/variants/xiao_nrf52/XiaoNrf52Board.h b/variants/xiao_nrf52/XiaoNrf52Board.h index e71e7f65..94c478e2 100644 --- a/variants/xiao_nrf52/XiaoNrf52Board.h +++ b/variants/xiao_nrf52/XiaoNrf52Board.h @@ -35,7 +35,9 @@ public: return "Seeed Xiao-nrf52"; } - void powerOff() override { + void shutdownPeripherals() override { + NRF52Board::shutdownPeripherals(); + // set led on and wait for button release before poweroff digitalWrite(PIN_LED, LOW); #ifdef PIN_USER_BTN @@ -49,8 +51,6 @@ public: // configure button press to wake up when in powered off state nrf_gpio_cfg_sense_input(digitalPinToInterrupt(g_ADigitalPinMap[PIN_USER_BTN]), NRF_GPIO_PIN_PULLUP, NRF_GPIO_PIN_SENSE_LOW); #endif - - NRF52Board::powerOff(); } };