Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 7 additions & 15 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

#if defined(PIN_USER_BTN) && defined(_SEEED_SENSECAP_SOLAR_H_)
static unsigned long userBtnDownAt = 0;
Expand All @@ -40,9 +39,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 @@ -155,16 +151,12 @@ void loop() {
rtc_clock.tick();

if (the_mesh.getNodePrefs()->powersaving_enabled && !the_mesh.hasPendingWork()) {
#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
#if defined(NRF52_PLATFORM)
board.sleep(0); // nrf ignores seconds param, sleeps whenever possible
#else
if (the_mesh.millisHasNowPassed(POWERSAVING_FIRSTSLEEP_SECS * 1000)) { // To check if it is time to sleep
board.sleep(30); // Sleep. Wake up after a while 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 @@ -52,6 +52,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 @@ -851,18 +851,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
69 changes: 47 additions & 22 deletions src/helpers/ESP32Board.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,19 @@
#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:
uint8_t startup_reason;
bool inhibit_sleep = false;
static inline portMUX_TYPE sleepMux = portMUX_INITIALIZER_UNLOCKED;

public:
void begin() {
// for future use, sub-classes SHOULD call this from their begin()
startup_reason = BD_STARTUP_NORMAL;
startup_reason = BD_STARTUP_NORMAL;

#ifdef ESP32_CPU_FREQ
setCpuFrequencyMhz(ESP32_CPU_FREQ);
Expand All @@ -41,7 +43,7 @@ class ESP32Board : public mesh::MainBoard {
#endif
#else
Wire.begin();
#endif
#endif
}

// Temperature from ESP32 MCU
Expand All @@ -56,25 +58,48 @@ 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
}
// Set GPIO wakeup
gpio_num_t wakeupPin = (gpio_num_t)getIRQGpio();

esp_light_sleep_start(); // CPU enters light sleep
// Configure timer wakeup
if (secs > 0) {
esp_sleep_enable_timer_wakeup(secs * 1000000ULL); // Wake up periodically to do scheduled jobs
}
#endif
}

void sleep(uint32_t secs) override {
if (!inhibit_sleep) {
enterLightSleep(secs); // To wake up after "secs" seconds or when receiving a LoRa packet
// Disable CPU interrupt servicing
portENTER_CRITICAL(&sleepMux);

// Skip sleep if there is a LoRa packet
if (gpio_get_level(wakeupPin) == HIGH) {
portEXIT_CRITICAL(&sleepMux);
delay(1);
return;
}

// Configure GPIO wakeup
esp_sleep_enable_gpio_wakeup();
gpio_wakeup_enable((gpio_num_t)wakeupPin, GPIO_INTR_HIGH_LEVEL); // Wake up when receiving a LoRa packet

// 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
portEXIT_CRITICAL(&sleepMux);
}

uint8_t getStartupReason() const override { return startup_reason; }
Expand All @@ -98,7 +123,7 @@ class ESP32Board : public mesh::MainBoard {
#endif

uint16_t getBattMilliVolts() override {
#ifdef PIN_VBAT_READ
#ifdef PIN_VBAT_READ
analogReadResolution(12);

uint32_t raw = 0;
Expand Down Expand Up @@ -137,16 +162,16 @@ class ESP32RTCClock : public mesh::RTCClock {
// start with some date/time in the recent past
struct timeval tv;
tv.tv_sec = 1715770351; // 15 May 2024, 8:50pm
tv.tv_usec = 0;
settimeofday(&tv, NULL);
}
tv.tv_usec = 0;
settimeofday(&tv, NULL);
}
}
uint32_t getCurrentTime() override {
time_t _now;
time(&_now);
return _now;
}
void setCurrentTime(uint32_t time) override {
void setCurrentTime(uint32_t time) override {
struct timeval tv;
tv.tv_sec = time;
tv.tv_usec = 0;
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
Loading