Skip to content
20 changes: 6 additions & 14 deletions examples/simple_repeater/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,7 @@ void halt() {
static char command[160];

// For power saving
unsigned long lastActive = 0; // mark last active time
unsigned long nextSleepinSecs = 120; // next sleep in seconds. The first sleep (if enabled) is after 2 minutes from boot
unsigned long POWERSAVING_FIRSTSLEEP_SECS = 120; // The first sleep (if enabled) from boot

void setup() {
Serial.begin(115200);
Expand All @@ -35,9 +34,6 @@ void setup() {
delay(5000);
#endif

// For power saving
lastActive = millis(); // mark last active time since boot

#ifdef DISPLAY_CLASS
if (display.begin()) {
display.startFrame();
Expand Down Expand Up @@ -135,16 +131,12 @@ void loop() {
rtc_clock.tick();

if (the_mesh.getNodePrefs()->powersaving_enabled && !the_mesh.hasPendingWork()) {
#if defined(NRF52_PLATFORM)
#if defined(NRF52_PLATFORM)
board.sleep(1800); // nrf ignores seconds param, sleeps whenever possible
#else
if (the_mesh.millisHasNowPassed(lastActive + nextSleepinSecs * 1000)) { // To check if it is time to sleep
board.sleep(1800); // To sleep. Wake up after 30 minutes or when receiving a LoRa packet
lastActive = millis();
nextSleepinSecs = 5; // Default: To work for 5s and sleep again
} else {
nextSleepinSecs += 5; // When there is pending work, to work another 5s
#else
if (the_mesh.millisHasNowPassed(POWERSAVING_FIRSTSLEEP_SECS * 1000)) { // To check if it is time to sleep
board.sleep(1800); // Sleep. Wake up after 30 minutes or when receiving a LoRa packet
}
#endif
#endif
}
}
1 change: 1 addition & 0 deletions src/MeshCore.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ class MainBoard {
virtual void onAfterTransmit() { }
virtual void reboot() = 0;
virtual void powerOff() { /* no op */ }
virtual uint32_t getIRQGpio() { return -1; } // not supported. Returns DIO1 (SX1262) and DIO0 (SX127x)
virtual void sleep(uint32_t secs) { /* no op */ }
virtual uint32_t getGpio() { return 0; }
virtual void setGpio(uint32_t values) {}
Expand Down
18 changes: 14 additions & 4 deletions src/helpers/CommonCLI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -747,18 +747,28 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch
}
#endif
} else if (memcmp(command, "powersaving on", 14) == 0) {
#if defined(NRF52_PLATFORM)
_prefs->powersaving_enabled = 1;
savePrefs();
strcpy(reply, "ok"); // TODO: to return Not supported if required
strcpy(reply, "On - Immediate effect");
#elif defined(ESP32) && !defined(WITH_BRIDGE)
_prefs->powersaving_enabled = 1;
savePrefs();
strcpy(reply, "On - After 2 minutes");
#elif defined(WITH_BRIDGE)
strcpy(reply, "Bridge not supported");
#else
strcpy(reply, "Board not supported");
#endif
} else if (memcmp(command, "powersaving off", 15) == 0) {
_prefs->powersaving_enabled = 0;
savePrefs();
strcpy(reply, "ok");
strcpy(reply, "Off");
} else if (memcmp(command, "powersaving", 11) == 0) {
if (_prefs->powersaving_enabled) {
strcpy(reply, "on");
strcpy(reply, "On");
} else {
strcpy(reply, "off");
strcpy(reply, "Off");
}
} else if (memcmp(command, "log start", 9) == 0) {
_callbacks->setLoggingOn(true);
Expand Down
61 changes: 47 additions & 14 deletions src/helpers/ESP32Board.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
#include <rom/rtc.h>
#include <sys/time.h>
#include <Wire.h>
#include "driver/rtc_io.h"
#include "soc/rtc.h"
#include "esp_system.h"

class ESP32Board : public mesh::MainBoard {
protected:
Expand Down Expand Up @@ -56,25 +57,57 @@ class ESP32Board : public mesh::MainBoard {
return raw / 4;
}

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
uint32_t getIRQGpio() {
return P_LORA_DIO_1; // default for SX1262
}

void sleep(uint32_t secs) override {
// Skip if not allow to sleep
if (inhibit_sleep) {
delay(1); // Give MCU to OTA to run
return;
}

if (secs > 0) {
esp_sleep_enable_timer_wakeup(secs * 1000000); // To wake up every hour to do periodically jobs
}
// Use more accurate clock in sleep
#if SOC_RTC_SLOW_CLK_SUPPORT_RC_FAST_D256
if (rtc_clk_slow_src_get() != SOC_RTC_SLOW_CLK_SRC_RC_FAST) {

esp_light_sleep_start(); // CPU enters light sleep
// Switch slow clock source to RC_FAST / 256 (~31.25 kHz)
rtc_clk_slow_src_set(SOC_RTC_SLOW_CLK_SRC_RC_FAST);

// Calibrate slow clock
esp_clk_slow_boot_cal(1024);
}
#endif
}

void sleep(uint32_t secs) override {
if (!inhibit_sleep) {
enterLightSleep(secs); // To wake up after "secs" seconds or when receiving a LoRa packet
// Configure GPIO wakeup
gpio_num_t wakeupPin = (gpio_num_t)getIRQGpio();
esp_sleep_enable_gpio_wakeup();
gpio_wakeup_enable((gpio_num_t)wakeupPin, GPIO_INTR_HIGH_LEVEL); // Wake up when receiving a LoRa packet

// Configure timer wakeup
if (secs > 0) {
esp_sleep_enable_timer_wakeup(secs * 1000000ULL); // Wake up periodically to do scheduled jobs
}

// Disable CPU interrupt servicing
noInterrupts();

// Skip sleep if there is a LoRa packet
if (digitalRead(wakeupPin) == HIGH) {
interrupts();
return;
}

// MCU enters light sleep
esp_light_sleep_start();

// Avoid ISR flood during wakeup due to HIGH LEVEL interrupt
gpio_wakeup_disable(wakeupPin);
gpio_set_intr_type(wakeupPin, GPIO_INTR_POSEDGE);

// Enable CPU interrupt servicing
interrupts();
}

uint8_t getStartupReason() const override { return startup_reason; }
Expand Down
14 changes: 7 additions & 7 deletions src/helpers/esp32/TBeamBoard.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,13 +59,13 @@
// 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 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
Expand Down
16 changes: 10 additions & 6 deletions variants/heltec_v2/HeltecV2Board.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,28 +17,28 @@ class HeltecV2Board : public ESP32Board {
esp_reset_reason_t reason = esp_reset_reason();
if (reason == ESP_RST_DEEPSLEEP) {
long wakeup_source = esp_sleep_get_ext1_wakeup_status();
if (wakeup_source & (1 << P_LORA_DIO_1)) { // received a LoRa packet (while in deep sleep)
if (wakeup_source & (1 << P_LORA_DIO_0)) { // received a LoRa packet (while in deep sleep)
startup_reason = BD_STARTUP_RX_PACKET;
}

rtc_gpio_hold_dis((gpio_num_t)P_LORA_NSS);
rtc_gpio_deinit((gpio_num_t)P_LORA_DIO_1);
rtc_gpio_deinit((gpio_num_t)P_LORA_DIO_0);
}
}

void enterDeepSleep(uint32_t secs, int pin_wake_btn = -1) {
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);

// Make sure the DIO1 and NSS GPIOs are hold on required levels during deep sleep
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_set_direction((gpio_num_t)P_LORA_DIO_0, RTC_GPIO_MODE_INPUT_ONLY);
rtc_gpio_pulldown_en((gpio_num_t)P_LORA_DIO_0);

rtc_gpio_hold_en((gpio_num_t)P_LORA_NSS);

if (pin_wake_btn < 0) {
esp_sleep_enable_ext1_wakeup( (1L << P_LORA_DIO_1), ESP_EXT1_WAKEUP_ANY_HIGH); // wake up on: recv LoRa packet
esp_sleep_enable_ext1_wakeup( (1L << P_LORA_DIO_0), ESP_EXT1_WAKEUP_ANY_HIGH); // wake up on: recv LoRa packet
} else {
esp_sleep_enable_ext1_wakeup( (1L << P_LORA_DIO_1) | (1L << pin_wake_btn), ESP_EXT1_WAKEUP_ANY_HIGH); // wake up on: recv LoRa packet OR wake btn
esp_sleep_enable_ext1_wakeup( (1L << P_LORA_DIO_0) | (1L << pin_wake_btn), ESP_EXT1_WAKEUP_ANY_HIGH); // wake up on: recv LoRa packet OR wake btn
}

if (secs > 0) {
Expand All @@ -64,4 +64,8 @@ class HeltecV2Board : public ESP32Board {
const char* getManufacturerName() const override {
return "Heltec V2";
}

uint32_t getIRQGpio() override {
return P_LORA_DIO_0; // default for SX1276
}
};
6 changes: 3 additions & 3 deletions variants/heltec_v2/platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ build_flags =
-D HELTEC_LORA_V2
-D RADIO_CLASS=CustomSX1276
-D WRAPPER_CLASS=CustomSX1276Wrapper
-D P_LORA_DIO_1=26
-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
Expand Down
4 changes: 2 additions & 2 deletions variants/heltec_v2/target.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
10 changes: 10 additions & 0 deletions variants/lilygo_t3s3_sx1276/LilygoT3S3SX1276Board.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#pragma once

#include <helpers/ESP32Board.h>

class LilygoT3S3SX1276Board : public ESP32Board {
public:
uint32_t getIRQGpio() override {
return P_LORA_DIO_0; // default for SX1276
}
};
2 changes: 1 addition & 1 deletion variants/lilygo_t3s3_sx1276/target.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#include <Arduino.h>
#include "target.h"

ESP32Board board;
LilygoT3S3SX1276Board board;

#if defined(P_LORA_SCLK)
static SPIClass spi;
Expand Down
4 changes: 2 additions & 2 deletions variants/lilygo_t3s3_sx1276/target.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
#define RADIOLIB_STATIC_ONLY 1
#include <RadioLib.h>
#include <helpers/radiolib/RadioLibWrappers.h>
#include <helpers/ESP32Board.h>
#include <LilygoT3S3SX1276Board.h>
#include <helpers/radiolib/CustomSX1276Wrapper.h>
#include <helpers/AutoDiscoverRTCClock.h>
#include <helpers/SensorManager.h>
Expand All @@ -12,7 +12,7 @@
#include <helpers/ui/MomentaryButton.h>
#endif

extern ESP32Board board;
extern LilygoT3S3SX1276Board board;
extern WRAPPER_CLASS radio_driver;
extern AutoDiscoverRTCClock rtc_clock;
extern SensorManager sensors;
Expand Down
7 changes: 7 additions & 0 deletions variants/lilygo_tbeam_SX1262/platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
10 changes: 10 additions & 0 deletions variants/lilygo_tbeam_SX1276/LilygoTBeamSX1276Board.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#pragma once

#include <helpers/esp32/TBeamBoard.h>

class LilygoTBeamSX1276Board : public TBeamBoard {
public:
uint32_t getIRQGpio() override {
return P_LORA_DIO_0; // default for SX1276
}
};
7 changes: 7 additions & 0 deletions variants/lilygo_tbeam_SX1276/platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@ 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
Expand Down
2 changes: 1 addition & 1 deletion variants/lilygo_tbeam_SX1276/target.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#include <Arduino.h>
#include "target.h"

TBeamBoard board;
LilygoTBeamSX1276Board board;

#if defined(P_LORA_SCLK)
static SPIClass spi;
Expand Down
4 changes: 2 additions & 2 deletions variants/lilygo_tbeam_SX1276/target.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
#define RADIOLIB_STATIC_ONLY 1
//#include <RadioLib.h>
#include <helpers/radiolib/RadioLibWrappers.h>
#include <helpers/esp32/TBeamBoard.h>
#include <LilygoTBeamSX1276Board.h>
#include <helpers/radiolib/CustomSX1276Wrapper.h>
#include <helpers/AutoDiscoverRTCClock.h>
#include <helpers/sensors/EnvironmentSensorManager.h>
Expand All @@ -12,7 +12,7 @@
#include <helpers/ui/MomentaryButton.h>
#endif

extern TBeamBoard board;
extern LilygoTBeamSX1276Board board;
extern WRAPPER_CLASS radio_driver;
extern AutoDiscoverRTCClock rtc_clock;
extern EnvironmentSensorManager sensors;
Expand Down
7 changes: 7 additions & 0 deletions variants/lilygo_tbeam_supreme_SX1262/platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 4 additions & 0 deletions variants/lilygo_tlora_v2_1/LilyGoTLoraBoard.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,8 @@ class LilyGoTLoraBoard : public ESP32Board {

return (2 * raw);
}

uint32_t getIRQGpio() override {
return P_LORA_DIO_0; // default for SX1276
}
};