From e30b611bf6d3f211be817f20548c125820676282 Mon Sep 17 00:00:00 2001 From: Kevin Le Date: Fri, 9 Jan 2026 17:38:21 +0700 Subject: [PATCH 1/5] To support PowerSaving for all ESP32-based repeaters and NRF52-based repeaters. --- src/helpers/ESP32Board.h | 24 ++++++++------ src/helpers/NRF52Board.cpp | 38 ++++++++++++++++++++++- src/helpers/NRF52Board.h | 2 ++ src/helpers/radiolib/RadioLibWrappers.cpp | 13 +++++++- 4 files changed, 66 insertions(+), 11 deletions(-) diff --git a/src/helpers/ESP32Board.h b/src/helpers/ESP32Board.h index 01b4c980c..21d2d45a5 100644 --- a/src/helpers/ESP32Board.h +++ b/src/helpers/ESP32Board.h @@ -57,18 +57,24 @@ class ESP32Board : public mesh::MainBoard { } void enterLightSleep(uint32_t secs) { -#if defined(CONFIG_IDF_TARGET_ESP32S3) && defined(P_LORA_DIO_1) // Supported ESP32 variants - if (rtc_gpio_is_valid_gpio((gpio_num_t)P_LORA_DIO_1)) { // Only enter sleep mode if P_LORA_DIO_1 is RTC pin - esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON); - esp_sleep_enable_ext1_wakeup((1L << P_LORA_DIO_1), ESP_EXT1_WAKEUP_ANY_HIGH); // To wake up when receiving a LoRa packet +#if defined(RADIO_SX1276) && defined(P_LORA_DIO_0) // SX1276 + gpio_num_t wakeupPin = (gpio_num_t) P_LORA_DIO_0; +#elif defined(P_LORA_DIO_1) // SX1262 + gpio_num_t wakeupPin = (gpio_num_t) P_LORA_DIO_1; +#else + return; // Not supported +#endif - if (secs > 0) { - esp_sleep_enable_timer_wakeup(secs * 1000000); // To wake up every hour to do periodically jobs - } + gpio_intr_disable((gpio_num_t) wakeupPin); // To disable ISR for LoRa + esp_sleep_enable_gpio_wakeup(); + gpio_wakeup_enable((gpio_num_t) wakeupPin, GPIO_INTR_HIGH_LEVEL); // To wake up when receiving a LoRa packet - esp_light_sleep_start(); // CPU enters light sleep + if (secs > 0) { + esp_sleep_enable_timer_wakeup(secs * 1000000); // To wake up periodically to do scheduled jobs } -#endif + + esp_light_sleep_start(); // CPU enters light sleep + gpio_intr_enable((gpio_num_t) wakeupPin); // Wakeup. Let ISR to handle LoRa packet as normal } void sleep(uint32_t secs) override { diff --git a/src/helpers/NRF52Board.cpp b/src/helpers/NRF52Board.cpp index c0d58314e..25a6bec3c 100644 --- a/src/helpers/NRF52Board.cpp +++ b/src/helpers/NRF52Board.cpp @@ -1,8 +1,11 @@ #if defined(NRF52_PLATFORM) #include "NRF52Board.h" - +#include "nrf_sdm.h" #include +// For PowerSaving +static SoftwareTimer wakeupTimer; + static BLEDfu bledfu; static void connect_callback(uint16_t conn_handle) { @@ -101,4 +104,37 @@ bool NRF52BoardOTA::startOTAUpdate(const char *id, char reply[]) { return true; } + +static void wakeUpCallback(TimerHandle_t xTimer) { + // To wake up based on timer + resumeLoop(); + wakeupTimer.stop(); +} + +void NRF52Board::enterLightSleep(uint32_t secs) { +#if defined(P_LORA_DIO_1) + // To prevent to enter suspendLoop when the loop has not processed the pending RX + if(digitalRead(P_LORA_DIO_1) == HIGH) { + return; + } + + // To wake up periodically to do scheduled jobs + wakeupTimer.stop(); + wakeupTimer.begin(secs * 1000, wakeUpCallback, nullptr, false); + wakeupTimer.start(); + + // To pause MCU to sleep + suspendLoop(); +#endif +} + +void NRF52Board::sleep(uint32_t secs) { + // To check if the BLE is powered and looking for/connected to a phone + uint8_t sd_enabled; + sd_softdevice_is_enabled(&sd_enabled); // To set sd_enabled to 1 if the BLE stack is active. + + if (!sd_enabled) { // BLE is off ~ No active OTA, safe to go to sleep + enterLightSleep(secs); // To wake up after "secs" seconds or when receiving a LoRa packet + } +} #endif diff --git a/src/helpers/NRF52Board.h b/src/helpers/NRF52Board.h index 0d6c0a431..a5306d8c2 100644 --- a/src/helpers/NRF52Board.h +++ b/src/helpers/NRF52Board.h @@ -14,6 +14,8 @@ class NRF52Board : public mesh::MainBoard { virtual uint8_t getStartupReason() const override { return startup_reason; } virtual float getMCUTemperature() override; virtual void reboot() override { NVIC_SystemReset(); } + virtual void enterLightSleep(uint32_t secs); + virtual void sleep(uint32_t secs) override; }; /* diff --git a/src/helpers/radiolib/RadioLibWrappers.cpp b/src/helpers/radiolib/RadioLibWrappers.cpp index e34078211..9043f8902 100644 --- a/src/helpers/radiolib/RadioLibWrappers.cpp +++ b/src/helpers/radiolib/RadioLibWrappers.cpp @@ -22,6 +22,18 @@ static void setFlag(void) { // we sent a packet, set the flag state |= STATE_INT_READY; + + // To avoid ISR flood during wakeup due to HIGH LEVEL interrupt +#if defined(ESP32) && defined(RADIO_SX1276) && defined(P_LORA_DIO_0) // SX1276 + gpio_set_intr_type((gpio_num_t)P_LORA_DIO_0, GPIO_INTR_POSEDGE); +#elif defined(ESP32) && defined(P_LORA_DIO_1) // SX1262 + gpio_set_intr_type((gpio_num_t)P_LORA_DIO_1, GPIO_INTR_POSEDGE); +#endif + +// To wakeup when there is a LoRa message +#if defined(NRF52_PLATFORM) + resumeLoop(); +#endif } void RadioLibWrapper::begin() { @@ -137,7 +149,6 @@ bool RadioLibWrapper::startSendRaw(const uint8_t* bytes, int len) { } MESH_DEBUG_PRINTLN("RadioLibWrapper: error: startTransmit(%d)", err); idle(); // trigger another startRecv() - _board->onAfterTransmit(); return false; } From ea42140b316af0a8f8c303ec8c23f8f5bcb62262 Mon Sep 17 00:00:00 2001 From: Kevin Le Date: Fri, 9 Jan 2026 17:42:19 +0700 Subject: [PATCH 2/5] To add flag RADIO_SX1276 to support PowerSaving for SX1276. SX1276 uses DIO0 to wakeup MCU instead of DIO1 --- variants/heltec_v2/platformio.ini | 8 ++++---- variants/heltec_v2/target.cpp | 4 ++-- variants/lilygo_t3s3_sx1276/platformio.ini | 1 + variants/lilygo_tbeam_SX1276/platformio.ini | 8 ++++++++ variants/lilygo_tlora_v2_1/platformio.ini | 2 +- 5 files changed, 16 insertions(+), 7 deletions(-) diff --git a/variants/heltec_v2/platformio.ini b/variants/heltec_v2/platformio.ini index f8cc93608..baf0a1b0e 100644 --- a/variants/heltec_v2/platformio.ini +++ b/variants/heltec_v2/platformio.ini @@ -7,10 +7,11 @@ build_flags = -D HELTEC_LORA_V2 -D RADIO_CLASS=CustomSX1276 -D WRAPPER_CLASS=CustomSX1276Wrapper - -D P_LORA_DIO_1=26 + -D RADIO_SX1276 + -D P_LORA_DIO_0=26 + -D P_LORA_DIO_1=35 -D P_LORA_NSS=18 - -D P_LORA_RESET=RADIOLIB_NC - -D P_LORA_BUSY=RADIOLIB_NC + -D P_LORA_RESET=14 -D P_LORA_SCLK=5 -D P_LORA_MISO=19 -D P_LORA_MOSI=27 @@ -183,7 +184,6 @@ build_flags = -D WIFI_DEBUG_LOGGING=1 -D WIFI_SSID='"myssid"' -D WIFI_PWD='"mypwd"' - -D OFFLINE_QUEUE_SIZE=256 ; -D MESH_PACKET_LOGGING=1 ; -D MESH_DEBUG=1 build_src_filter = ${Heltec_lora32_v2.build_src_filter} diff --git a/variants/heltec_v2/target.cpp b/variants/heltec_v2/target.cpp index df71d3f4b..bf9fb440a 100644 --- a/variants/heltec_v2/target.cpp +++ b/variants/heltec_v2/target.cpp @@ -5,9 +5,9 @@ HeltecV2Board board; #if defined(P_LORA_SCLK) static SPIClass spi; - RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, spi); + RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_0, P_LORA_RESET, P_LORA_DIO_1, spi); #else - RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY); + RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_0, P_LORA_RESET, P_LORA_DIO_1); #endif WRAPPER_CLASS radio_driver(radio, board); diff --git a/variants/lilygo_t3s3_sx1276/platformio.ini b/variants/lilygo_t3s3_sx1276/platformio.ini index f544be113..4c8d9f123 100644 --- a/variants/lilygo_t3s3_sx1276/platformio.ini +++ b/variants/lilygo_t3s3_sx1276/platformio.ini @@ -20,6 +20,7 @@ build_flags = -D PIN_OLED_RESET=21 -D RADIO_CLASS=CustomSX1276 -D WRAPPER_CLASS=CustomSX1276Wrapper + -D RADIO_SX1276 -D SX127X_CURRENT_LIMIT=120 -D SX176X_RXEN=21 -D SX176X_TXEN=10 diff --git a/variants/lilygo_tbeam_SX1276/platformio.ini b/variants/lilygo_tbeam_SX1276/platformio.ini index 3562c40e9..7c4c3dd63 100644 --- a/variants/lilygo_tbeam_SX1276/platformio.ini +++ b/variants/lilygo_tbeam_SX1276/platformio.ini @@ -5,9 +5,17 @@ build_flags = ${esp32_base.build_flags} -I variants/lilygo_tbeam_SX1276 -D TBEAM_SX1276 + -D P_LORA_DIO_0=26 + -D P_LORA_DIO_1=33 + -D P_LORA_NSS=18 + -D P_LORA_RESET=23 + -D P_LORA_SCLK=5 + -D P_LORA_MISO=19 + -D P_LORA_MOSI=27 -D SX127X_CURRENT_LIMIT=120 -D RADIO_CLASS=CustomSX1276 -D WRAPPER_CLASS=CustomSX1276Wrapper + -D RADIO_SX1276 -D DISPLAY_CLASS=SSD1306Display -D LORA_TX_POWER=20 -D P_LORA_TX_LED=4 diff --git a/variants/lilygo_tlora_v2_1/platformio.ini b/variants/lilygo_tlora_v2_1/platformio.ini index f27f57fd9..c0b419eb6 100644 --- a/variants/lilygo_tlora_v2_1/platformio.ini +++ b/variants/lilygo_tlora_v2_1/platformio.ini @@ -27,6 +27,7 @@ build_flags = -D DISPLAY_CLASS=SSD1306Display -D RADIO_CLASS=CustomSX1276 -D WRAPPER_CLASS=CustomSX1276Wrapper + -D RADIO_SX1276 -D SX127X_CURRENT_LIMIT=120 -D LORA_TX_POWER=20 build_src_filter = ${esp32_base.build_src_filter} @@ -136,7 +137,6 @@ build_flags = -D WIFI_SSID='"ssid"' -D WIFI_PWD='"password"' -D WIFI_DEBUG_LOGGING=1 - -D OFFLINE_QUEUE_SIZE=256 build_src_filter = ${LilyGo_TLora_V2_1_1_6.build_src_filter} + + From 07b0c728a8cfff0b34bed7936fc39407c3b58618 Mon Sep 17 00:00:00 2001 From: Kevin Le Date: Fri, 9 Jan 2026 17:45:20 +0700 Subject: [PATCH 3/5] To expose LoRa pins at platformio.ini instead of header files --- src/helpers/esp32/TBeamBoard.h | 8 -------- variants/heltec_mesh_solar/MeshSolarBoard.h | 12 ------------ variants/heltec_mesh_solar/platformio.ini | 9 +++++++++ variants/lilygo_tbeam_SX1262/platformio.ini | 7 +++++++ variants/lilygo_tbeam_supreme_SX1262/platformio.ini | 7 +++++++ variants/promicro/PromicroBoard.h | 13 ------------- variants/promicro/platformio.ini | 12 ++++++++++++ variants/rak4631/RAK4631Board.h | 10 ---------- variants/rak4631/platformio.ini | 8 ++++++++ 9 files changed, 43 insertions(+), 43 deletions(-) diff --git a/src/helpers/esp32/TBeamBoard.h b/src/helpers/esp32/TBeamBoard.h index 4ff955510..5fee40fc2 100644 --- a/src/helpers/esp32/TBeamBoard.h +++ b/src/helpers/esp32/TBeamBoard.h @@ -59,14 +59,6 @@ // uint32_t P_LORA_BUSY = 0; //shared, so define at run // uint32_t P_LORA_DIO_2 = 0; //SX1276 only, so define at run - #define P_LORA_DIO_0 26 - #define P_LORA_DIO_1 33 - #define P_LORA_NSS 18 - #define P_LORA_RESET 23 - #define P_LORA_SCLK 5 - #define P_LORA_MISO 19 - #define P_LORA_MOSI 27 - // #define PIN_GPS_RX 34 // #define PIN_GPS_TX 12 diff --git a/variants/heltec_mesh_solar/MeshSolarBoard.h b/variants/heltec_mesh_solar/MeshSolarBoard.h index 69437c877..4208aed5f 100644 --- a/variants/heltec_mesh_solar/MeshSolarBoard.h +++ b/variants/heltec_mesh_solar/MeshSolarBoard.h @@ -8,18 +8,6 @@ #include "meshSolarApp.h" #endif -// LoRa radio module pins for Heltec T114 -#define P_LORA_DIO_1 20 -#define P_LORA_NSS 24 -#define P_LORA_RESET 25 -#define P_LORA_BUSY 17 -#define P_LORA_SCLK 19 -#define P_LORA_MISO 23 -#define P_LORA_MOSI 22 - -#define SX126X_DIO2_AS_RF_SWITCH true -#define SX126X_DIO3_TCXO_VOLTAGE 1.8 - class MeshSolarBoard : public NRF52BoardOTA { public: MeshSolarBoard() : NRF52BoardOTA("MESH_SOLAR_OTA") {} diff --git a/variants/heltec_mesh_solar/platformio.ini b/variants/heltec_mesh_solar/platformio.ini index 7bfbac85a..c5c889a48 100644 --- a/variants/heltec_mesh_solar/platformio.ini +++ b/variants/heltec_mesh_solar/platformio.ini @@ -9,6 +9,15 @@ build_flags = ${nrf52_base.build_flags} -I lib/nrf52/s140_nrf52_6.1.1_API/include/nrf52 -I variants/heltec_mesh_solar -D HELTEC_MESH_SOLAR + -D P_LORA_DIO_1=20 + -D P_LORA_NSS=24 + -D P_LORA_RESET=25 + -D P_LORA_BUSY=17 + -D P_LORA_SCLK=19 + -D P_LORA_MISO=23 + -D P_LORA_MOSI=22 + -D SX126X_DIO2_AS_RF_SWITCH=true + -D SX126X_DIO3_TCXO_VOLTAGE=1.8 -D RADIO_CLASS=CustomSX1262 -D WRAPPER_CLASS=CustomSX1262Wrapper -D LORA_TX_POWER=22 diff --git a/variants/lilygo_tbeam_SX1262/platformio.ini b/variants/lilygo_tbeam_SX1262/platformio.ini index 9fb4805fc..67e46a8ba 100644 --- a/variants/lilygo_tbeam_SX1262/platformio.ini +++ b/variants/lilygo_tbeam_SX1262/platformio.ini @@ -5,6 +5,13 @@ build_flags = ${esp32_base.build_flags} -I variants/lilygo_tbeam_SX1262 -D TBEAM_SX1262 + -D P_LORA_DIO_0=26 + -D P_LORA_DIO_1=33 + -D P_LORA_NSS=18 + -D P_LORA_RESET=23 + -D P_LORA_SCLK=5 + -D P_LORA_MISO=19 + -D P_LORA_MOSI=27 -D SX126X_DIO2_AS_RF_SWITCH=true -D SX126X_DIO3_TCXO_VOLTAGE=1.8 -D SX126X_CURRENT_LIMIT=140 diff --git a/variants/lilygo_tbeam_supreme_SX1262/platformio.ini b/variants/lilygo_tbeam_supreme_SX1262/platformio.ini index 2d2a095aa..ef0e8a394 100644 --- a/variants/lilygo_tbeam_supreme_SX1262/platformio.ini +++ b/variants/lilygo_tbeam_supreme_SX1262/platformio.ini @@ -5,6 +5,13 @@ build_flags = ${esp32_base.build_flags} -I variants/lilygo_tbeam_supreme_SX1262 -D TBEAM_SUPREME_SX1262 + -D P_LORA_DIO_0=26 + -D P_LORA_DIO_1=33 + -D P_LORA_NSS=18 + -D P_LORA_RESET=23 + -D P_LORA_SCLK=5 + -D P_LORA_MISO=19 + -D P_LORA_MOSI=27 -D SX126X_CURRENT_LIMIT=140 -D SX126X_RX_BOOSTED_GAIN=1 -D RADIO_CLASS=CustomSX1262 diff --git a/variants/promicro/PromicroBoard.h b/variants/promicro/PromicroBoard.h index c23ed1c99..198e7d66e 100644 --- a/variants/promicro/PromicroBoard.h +++ b/variants/promicro/PromicroBoard.h @@ -4,19 +4,6 @@ #include #include -#define P_LORA_NSS 13 //P1.13 45 -#define P_LORA_DIO_1 11 //P0.10 10 -#define P_LORA_RESET 10 //P0.09 9 -#define P_LORA_BUSY 16 //P0.29 29 -#define P_LORA_MISO 15 //P0.02 2 -#define P_LORA_SCLK 12 //P1.11 43 -#define P_LORA_MOSI 14 //P1.15 47 -#define SX126X_POWER_EN 21 //P0.13 13 -#define SX126X_RXEN 2 //P0.17 -#define SX126X_TXEN RADIOLIB_NC -#define SX126X_DIO2_AS_RF_SWITCH true -#define SX126X_DIO3_TCXO_VOLTAGE (1.8f) - #define PIN_VBAT_READ 17 #define ADC_MULTIPLIER (1.815f) // dependent on voltage divider resistors. TODO: more accurate battery tracking diff --git a/variants/promicro/platformio.ini b/variants/promicro/platformio.ini index 15bb5ce67..5626f09ea 100644 --- a/variants/promicro/platformio.ini +++ b/variants/promicro/platformio.ini @@ -4,6 +4,18 @@ board = promicro_nrf52840 build_flags = ${nrf52_base.build_flags} -I variants/promicro -D PROMICRO + -D P_LORA_NSS=13 + -D P_LORA_DIO_1=11 + -D P_LORA_RESET=10 + -D P_LORA_BUSY=16 + -D P_LORA_MISO=15 + -D P_LORA_SCLK=12 + -D P_LORA_MOSI=14 + -D SX126X_POWER_EN=21 + -D SX126X_RXEN=2 + -D SX126X_TXEN=RADIOLIB_NC + -D SX126X_DIO2_AS_RF_SWITCH=true + -D SX126X_DIO3_TCXO_VOLTAGE=1.8f -D RADIO_CLASS=CustomSX1262 -D WRAPPER_CLASS=CustomSX1262Wrapper -D LORA_TX_POWER=22 diff --git a/variants/rak4631/RAK4631Board.h b/variants/rak4631/RAK4631Board.h index a181256b0..c0f39afe6 100644 --- a/variants/rak4631/RAK4631Board.h +++ b/variants/rak4631/RAK4631Board.h @@ -4,16 +4,6 @@ #include #include -// LoRa radio module pins for RAK4631 -#define P_LORA_DIO_1 47 -#define P_LORA_NSS 42 -#define P_LORA_RESET RADIOLIB_NC // 38 -#define P_LORA_BUSY 46 -#define P_LORA_SCLK 43 -#define P_LORA_MISO 45 -#define P_LORA_MOSI 44 -#define SX126X_POWER_EN 37 - //#define PIN_GPS_SDA 13 //GPS SDA pin (output option) //#define PIN_GPS_SCL 14 //GPS SCL pin (output option) //#define PIN_GPS_TX 16 //GPS TX pin diff --git a/variants/rak4631/platformio.ini b/variants/rak4631/platformio.ini index 7293b4d49..c54163c32 100644 --- a/variants/rak4631/platformio.ini +++ b/variants/rak4631/platformio.ini @@ -7,6 +7,14 @@ build_flags = ${nrf52_base.build_flags} -I variants/rak4631 -D RAK_4631 -D RAK_BOARD + -D P_LORA_DIO_1=47 + -D P_LORA_NSS=42 + -D P_LORA_RESET=38 + -D P_LORA_BUSY=46 + -D P_LORA_SCLK=43 + -D P_LORA_MISO=45 + -D P_LORA_MOSI=44 + -D SX126X_POWER_EN=37 -D PIN_BOARD_SCL=14 -D PIN_BOARD_SDA=13 -D PIN_GPS_TX=PIN_SERIAL1_RX From 67a4398aa7639f89d93a767fe2e93ed3971742ab Mon Sep 17 00:00:00 2001 From: Kevin Le Date: Tue, 13 Jan 2026 22:04:18 +0700 Subject: [PATCH 4/5] To implement power saving for NRF52 using System-Idle On --- src/helpers/NRF52Board.cpp | 29 +++++++---------------- src/helpers/radiolib/RadioLibWrappers.cpp | 5 ---- 2 files changed, 9 insertions(+), 25 deletions(-) diff --git a/src/helpers/NRF52Board.cpp b/src/helpers/NRF52Board.cpp index 25a6bec3c..a321969d4 100644 --- a/src/helpers/NRF52Board.cpp +++ b/src/helpers/NRF52Board.cpp @@ -3,9 +3,6 @@ #include "nrf_sdm.h" #include -// For PowerSaving -static SoftwareTimer wakeupTimer; - static BLEDfu bledfu; static void connect_callback(uint16_t conn_handle) { @@ -105,26 +102,18 @@ bool NRF52BoardOTA::startOTAUpdate(const char *id, char reply[]) { return true; } -static void wakeUpCallback(TimerHandle_t xTimer) { - // To wake up based on timer - resumeLoop(); - wakeupTimer.stop(); -} - void NRF52Board::enterLightSleep(uint32_t secs) { #if defined(P_LORA_DIO_1) - // To prevent to enter suspendLoop when the loop has not processed the pending RX - if(digitalRead(P_LORA_DIO_1) == HIGH) { - return; + // To mark the start of the sleep + uint32_t startTime = millis(); + + // To wake up when a LoRa packet comes or sleep timeout. Safe to 49-day overflow + while (digitalRead(P_LORA_DIO_1) == LOW && (millis() - startTime < secs*1000)) { + // To enter System-on idle + __SEV(); // To clear any stale event flag + __WFE(); // To consume that event + __WFE(); // To actually puts CPU to sleep } - - // To wake up periodically to do scheduled jobs - wakeupTimer.stop(); - wakeupTimer.begin(secs * 1000, wakeUpCallback, nullptr, false); - wakeupTimer.start(); - - // To pause MCU to sleep - suspendLoop(); #endif } diff --git a/src/helpers/radiolib/RadioLibWrappers.cpp b/src/helpers/radiolib/RadioLibWrappers.cpp index 9043f8902..a59642c8f 100644 --- a/src/helpers/radiolib/RadioLibWrappers.cpp +++ b/src/helpers/radiolib/RadioLibWrappers.cpp @@ -29,11 +29,6 @@ void setFlag(void) { #elif defined(ESP32) && defined(P_LORA_DIO_1) // SX1262 gpio_set_intr_type((gpio_num_t)P_LORA_DIO_1, GPIO_INTR_POSEDGE); #endif - -// To wakeup when there is a LoRa message -#if defined(NRF52_PLATFORM) - resumeLoop(); -#endif } void RadioLibWrapper::begin() { From f988eb33538575263adff570c5dc0adf3af95171 Mon Sep 17 00:00:00 2001 From: Kevin Le Date: Wed, 14 Jan 2026 14:22:02 +0700 Subject: [PATCH 5/5] To implement light sleep for ESP32 without changing setFlag To put back missing code board->onAfterTransmit(); --- src/helpers/ESP32Board.h | 23 +++++++++++++++++++---- src/helpers/radiolib/RadioLibWrappers.cpp | 8 +------- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/src/helpers/ESP32Board.h b/src/helpers/ESP32Board.h index 21d2d45a5..32501b9b0 100644 --- a/src/helpers/ESP32Board.h +++ b/src/helpers/ESP32Board.h @@ -65,16 +65,31 @@ class ESP32Board : public mesh::MainBoard { return; // Not supported #endif - gpio_intr_disable((gpio_num_t) wakeupPin); // To disable ISR for LoRa + // To configure GPIO wakeup esp_sleep_enable_gpio_wakeup(); gpio_wakeup_enable((gpio_num_t) wakeupPin, GPIO_INTR_HIGH_LEVEL); // To wake up when receiving a LoRa packet + // To configure timer wakeup if (secs > 0) { - esp_sleep_enable_timer_wakeup(secs * 1000000); // To wake up periodically to do scheduled jobs + esp_sleep_enable_timer_wakeup(secs * 1000000ULL); // To wake up periodically to do scheduled jobs } - esp_light_sleep_start(); // CPU enters light sleep - gpio_intr_enable((gpio_num_t) wakeupPin); // Wakeup. Let ISR to handle LoRa packet as normal + // To disable CPU interrupt servicing + noInterrupts(); + + // MCU to enter light sleep + esp_light_sleep_start(); + Serial.println(esp_sleep_get_wakeup_cause()); + + // To avoid ISR flood during wakeup due to HIGH LEVEL interrupt +#if defined(ESP32) && defined(RADIO_SX1276) && defined(P_LORA_DIO_0) // SX1276 + gpio_set_intr_type((gpio_num_t)P_LORA_DIO_0, GPIO_INTR_POSEDGE); +#elif defined(ESP32) && defined(P_LORA_DIO_1) // SX1262 + gpio_set_intr_type((gpio_num_t)P_LORA_DIO_1, GPIO_INTR_POSEDGE); +#endif + + // To disable CPU interrupt servicing + interrupts(); } void sleep(uint32_t secs) override { diff --git a/src/helpers/radiolib/RadioLibWrappers.cpp b/src/helpers/radiolib/RadioLibWrappers.cpp index a59642c8f..e34078211 100644 --- a/src/helpers/radiolib/RadioLibWrappers.cpp +++ b/src/helpers/radiolib/RadioLibWrappers.cpp @@ -22,13 +22,6 @@ static void setFlag(void) { // we sent a packet, set the flag state |= STATE_INT_READY; - - // To avoid ISR flood during wakeup due to HIGH LEVEL interrupt -#if defined(ESP32) && defined(RADIO_SX1276) && defined(P_LORA_DIO_0) // SX1276 - gpio_set_intr_type((gpio_num_t)P_LORA_DIO_0, GPIO_INTR_POSEDGE); -#elif defined(ESP32) && defined(P_LORA_DIO_1) // SX1262 - gpio_set_intr_type((gpio_num_t)P_LORA_DIO_1, GPIO_INTR_POSEDGE); -#endif } void RadioLibWrapper::begin() { @@ -144,6 +137,7 @@ bool RadioLibWrapper::startSendRaw(const uint8_t* bytes, int len) { } MESH_DEBUG_PRINTLN("RadioLibWrapper: error: startTransmit(%d)", err); idle(); // trigger another startRecv() + _board->onAfterTransmit(); return false; }