Remove PowerSaving changes from Halo retry branch

This commit is contained in:
mikecarper
2026-06-15 16:02:22 -07:00
parent 17dc51dbce
commit 2acd61ec84
33 changed files with 93 additions and 536 deletions
-32
View File
@@ -1,32 +0,0 @@
name: 'Run Stale Bot'
on:
schedule:
- cron: '30 1 * * *' # daily at 1:30am
workflow_dispatch: {}
permissions:
actions: write
issues: write
pull-requests: write
jobs:
close-issues:
# only run on main repo, not forks
if: github.repository == 'meshcore-dev/MeshCore'
runs-on: ubuntu-latest
steps:
- name: Close Stale Issues
uses: actions/stale@v10
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
# auto close issues
days-before-issue-stale: 60
days-before-issue-close: 7
exempt-issue-labels: "keep-open"
stale-issue-label: "stale"
stale-issue-message: "This issue is stale because it has been open for 60 days with no activity. Remove the stale label or add a comment if this issue is still relevant, otherwise this issue will automatically close in 7 days."
close-issue-message: "This issue was closed because it has been inactive for 7 days since being marked as stale."
# don't auto close prs
days-before-pr-stale: -1
days-before-pr-close: -1
-57
View File
@@ -1,57 +0,0 @@
# Security Policy
## Supported Versions
Security fixes are applied to the latest release only. We do not backport
fixes to older versions.
| Version | Supported |
|---------|-----------|
| 1.15+ | ✅ |
| <1.15 | ❌ |
## Reporting a Vulnerability
**Please do not report security vulnerabilities through public GitHub issues.**
Use GitHub's private vulnerability reporting instead:
1. Go to the **Security** tab of this repository
2. Click **Report a vulnerability**
3. Fill in the details and submit
### What to include
A useful report tells us:
- Which component or file is affected
- What an attacker can do (impact) and under what conditions
- A minimal reproduction case or proof-of-concept if you have one
- Whether you believe it is remotely exploitable
You do not need a working exploit to report. An incomplete report is better
than no report.
## What to expect
This is a volunteer-maintained open-source project. We will do our best to
respond in a reasonable timeframe, but cannot commit to specific deadlines.
We ask that you give us a fair opportunity to investigate and address the
issue before any public disclosure. If you have not heard back after
**90 days**, feel free to follow up or proceed with disclosure at your
discretion.
## Scope
In scope:
- Remote code execution, memory corruption, or denial-of-service via crafted
radio packets
- Authentication or encryption bypasses
- Vulnerabilities in the packet routing or path handling logic
Out of scope:
- Physical access attacks (e.g., JTAG, UART extraction of keys)
- Regulatory compliance (duty cycle, frequency restrictions)
- Jamming or other physical-layer radio interference
- Issues in third-party libraries (RadioLib, Crypto, etc.) — report those
upstream
- "Best practice" suggestions without a demonstrated attack path
-135
View File
@@ -1,135 +0,0 @@
# sh ./build-repeaters-iotthinks.sh
export FIRMWARE_VERSION="PowerSaving16"
############# Repeaters #############
# Commonly-used boards
## ESP32 - 17 boards
sh build.sh build-firmware \
Heltec_v3_repeater \
Heltec_WSL3_repeater \
heltec_v4_repeater \
Station_G2_repeater \
T_Beam_S3_Supreme_SX1262_repeater \
Tbeam_SX1262_repeater \
LilyGo_T3S3_sx1262_repeater \
Xiao_S3_WIO_repeater \
Xiao_C3_repeater \
Xiao_C6_repeater_ \
Heltec_E290_repeater \
Heltec_Wireless_Tracker_repeater \
LilyGo_TBeam_1W_repeater \
Xiao_S3_repeater \
heltec_tracker_v2_repeater \
Heltec_Wireless_Paper_repeater \
Heltec_ct62_repeater
## NRF52 - 17 boards
sh build.sh build-firmware \
RAK_4631_repeater \
Heltec_t114_repeater \
Xiao_nrf52_repeater \
Heltec_mesh_solar_repeater \
ProMicro_repeater \
SenseCap_Solar_repeater \
t1000e_repeater \
LilyGo_T-Echo_repeater \
WioTrackerL1_repeater \
RAK_3401_repeater \
RAK_WisMesh_Tag_repeater \
GAT562_30S_Mesh_Kit_repeater \
GAT562_Mesh_Tracker_Pro_repeater \
ikoka_nano_nrf_22dbm_repeater \
ikoka_nano_nrf_30dbm_repeater \
ikoka_nano_nrf_33dbm_repeater \
ThinkNode_M1_repeater \
Heltec_t096_repeater
## ESP32, SX1276 - 3 boards
sh build.sh build-firmware \
Heltec_v2_repeater \
LilyGo_TLora_V2_1_1_6_repeater \
Tbeam_SX1276_repeater
############# Room Server #############
# ESP32 - 7 boards
sh build.sh build-firmware \
Heltec_v3_room_server \
heltec_v4_room_server \
LilyGo_TBeam_1W_room_server \
Heltec_WSL3_room_server \
Xiao_S3_room_server \
heltec_tracker_v2_room_server \
Heltec_Wireless_Paper_room_server
# NRF52 - 6 boards
sh build.sh build-firmware \
RAK_4631_room_server \
Heltec_t114_room_server \
Xiao_nrf52_room_server \
t1000e_room_server \
WioTrackerL1_room_server \
RAK_3401_room_server \
Heltec_t096_room_server
############# Companions BLE #############
# NRF52 - 12 boards
sh build.sh build-firmware \
RAK_4631_companion_radio_ble \
Heltec_t114_companion_radio_ble \
Xiao_nrf52_companion_radio_ble \
t1000e_companion_radio_ble \
LilyGo_T-Echo_companion_radio_ble \
WioTrackerL1_companion_radio_ble \
RAK_3401_companion_radio_ble \
RAK_WisMesh_Tag_companion_radio_ble \
SenseCap_Solar_companion_radio_ble \
ThinkNode_M1_companion_radio_ble \
Heltec_t096_companion_radio_ble \
Heltec_t096_companion_radio_ble_femoff
############# Companions BLE PS #############
# ESP32 - 18 boards
sh build.sh build-firmware \
Heltec_v3_companion_radio_ble_ps \
heltec_v4_companion_radio_ble_ps \
heltec_v4_3_companion_radio_ble_ps_femoff \
Xiao_C3_companion_radio_ble_ps \
Xiao_S3_companion_radio_ble_ps \
Xiao_S3_WIO_companion_radio_ble_ps \
Heltec_v2_companion_radio_ble_ps \
LilyGo_TBeam_1W_companion_radio_ble_ps \
Heltec_WSL3_companion_radio_ble_ps \
Heltec_Wireless_Tracker_companion_radio_ble_ps \
heltec_tracker_v2_companion_radio_ble_ps \
Heltec_Wireless_Paper_companion_radio_ble_ps \
LilyGo_TLora_V2_1_1_6_companion_radio_ble_ps \
Heltec_ct62_companion_radio_ble_ps \
T_Beam_S3_Supreme_SX1262_companion_radio_ble_ps \
Tbeam_SX1262_companion_radio_ble_ps \
heltec_v4_expansionkit_tft_companion_radio_ble_ps \
LilyGo_T3S3_sx1262_companion_radio_ble_ps
# Not working
Tbeam_SX1276_companion_radio_ble_ps \
############# Companions USB #############
sh build.sh build-firmware \
Heltec_t096_companion_radio_usb
############# Sample builds #############
# 14 boards
sh build.sh build-firmware \
Heltec_v3_repeater \
heltec_v4_repeater \
Xiao_C3_repeater \
Xiao_C6_repeater_ \
RAK_4631_repeater \
Heltec_t096_repeater \
Heltec_v3_companion_radio_ble_ps \
heltec_v4_companion_radio_ble_ps \
heltec_v4_3_companion_radio_ble_ps_femoff \
Xiao_C3_companion_radio_ble_ps \
Xiao_C6_companion_radio_ble_ \
RAK_4631_companion_radio_ble \
Heltec_t096_companion_radio_ble \
Heltec_t096_companion_radio_ble_femoff
-2
View File
@@ -233,7 +233,6 @@ void DataStore::loadPrefsInt(const char *filename, NodePrefs& _prefs, double& no
file.read((uint8_t *)&_prefs.rx_boosted_gain, sizeof(_prefs.rx_boosted_gain)); // 89
file.read((uint8_t *)_prefs.default_scope_name, sizeof(_prefs.default_scope_name)); // 90
file.read((uint8_t *)_prefs.default_scope_key, sizeof(_prefs.default_scope_key)); // 121
file.read((uint8_t *)&_prefs.radio_fem_rxgain, sizeof(_prefs.radio_fem_rxgain)); // 122
file.close();
}
@@ -274,7 +273,6 @@ void DataStore::savePrefs(const NodePrefs& _prefs, double node_lat, double node_
file.write((uint8_t *)&_prefs.rx_boosted_gain, sizeof(_prefs.rx_boosted_gain)); // 89
file.write((uint8_t *)_prefs.default_scope_name, sizeof(_prefs.default_scope_name)); // 90
file.write((uint8_t *)_prefs.default_scope_key, sizeof(_prefs.default_scope_key)); // 121
file.write((uint8_t *)&_prefs.radio_fem_rxgain, sizeof(_prefs.radio_fem_rxgain)); // 122
file.close();
}
-29
View File
@@ -62,8 +62,6 @@
#define CMD_SET_DEFAULT_FLOOD_SCOPE 63
#define CMD_GET_DEFAULT_FLOOD_SCOPE 64
#define CMD_SEND_RAW_PACKET 65
#define CMD_GET_RADIO_FEM_RXGAIN 66
#define CMD_SET_RADIO_FEM_RXGAIN 67
// Stats sub-types for CMD_GET_STATS
#define STATS_TYPE_CORE 0
@@ -891,7 +889,6 @@ MyMesh::MyMesh(mesh::Radio &radio, mesh::RNG &rng, mesh::RTCClock &rtc, SimpleMe
_prefs.rx_boosted_gain = 1; // enabled by default
#endif
#endif
_prefs.radio_fem_rxgain = 1;
}
void MyMesh::begin(bool has_display) {
@@ -941,7 +938,6 @@ void MyMesh::begin(bool has_display) {
_prefs.tx_power_dbm = constrain(_prefs.tx_power_dbm, -9, MAX_LORA_TX_POWER);
_prefs.gps_enabled = constrain(_prefs.gps_enabled, 0, 1); // Ensure boolean 0 or 1
_prefs.gps_interval = constrain(_prefs.gps_interval, 0, 86400); // Max 24 hours
_prefs.radio_fem_rxgain = constrain(_prefs.radio_fem_rxgain, 0, 1);
#ifdef BLE_PIN_CODE // 123456 by default
if (_prefs.ble_pin == 0) {
@@ -971,7 +967,6 @@ void MyMesh::begin(bool has_display) {
radio_driver.setParams(_prefs.freq, _prefs.bw, _prefs.sf, _prefs.cr);
radio_driver.setTxPower(_prefs.tx_power_dbm);
radio_driver.setRxBoostedGainMode(_prefs.rx_boosted_gain);
board.setLoRaFemLnaEnabled(_prefs.radio_fem_rxgain);
MESH_DEBUG_PRINTLN("RX Boosted Gain Mode: %s",
radio_driver.getRxBoostedGainMode() ? "Enabled" : "Disabled");
}
@@ -1830,30 +1825,6 @@ void MyMesh::handleCmdFrame(size_t len) {
} else {
writeErrFrame(ERR_CODE_ILLEGAL_ARG);
}
} else if (cmd_frame[0] == CMD_GET_RADIO_FEM_RXGAIN) {
if (!board.canControlLoRaFemLna()) {
writeErrFrame(ERR_CODE_UNSUPPORTED_CMD);
} else {
out_frame[0] = RESP_CODE_OK;
uint8_t value = board.isLoRaFemLnaEnabled() ? 1 : 0;
memcpy(&out_frame[1], &value, 1);
_serial->writeFrame(out_frame, 2);
}
} else if (cmd_frame[0] == CMD_SET_RADIO_FEM_RXGAIN && len >= 2) {
uint8_t value = cmd_frame[1];
if (!board.canControlLoRaFemLna()) {
writeErrFrame(ERR_CODE_UNSUPPORTED_CMD);
} else if (value <= 1) {
_prefs.radio_fem_rxgain = value;
if (board.setLoRaFemLnaEnabled(value != 0)) {
savePrefs();
writeOKFrame();
} else {
writeErrFrame(ERR_CODE_UNSUPPORTED_CMD);
}
} else {
writeErrFrame(ERR_CODE_ILLEGAL_ARG);
}
} else if (cmd_frame[0] == CMD_GET_ADVERT_PATH && len >= PUB_KEY_SIZE+2) {
// FUTURE use: uint8_t reserved = cmd_frame[1];
uint8_t *pub_key = &cmd_frame[2];
+1 -1
View File
@@ -166,7 +166,7 @@ protected:
public:
void savePrefs() { _store->savePrefs(_prefs, sensors.node_lat, sensors.node_lon); }
#if ENV_INCLUDE_GPS == 1
void applyGpsPrefs() {
sensors.setSettingValue("gps", _prefs.gps_enabled ? "1" : "0");
+1 -2
View File
@@ -29,10 +29,9 @@ struct NodePrefs { // persisted to file
uint32_t gps_interval; // GPS read interval in seconds
uint8_t autoadd_config; // bitmask for auto-add contacts config
uint8_t rx_boosted_gain; // SX126x RX boosted gain mode (0=power saving, 1=boosted)
uint8_t radio_fem_rxgain; // LoRa FEM RX gain setting
uint8_t client_repeat;
uint8_t path_hash_mode; // which path mode to use when sending
uint8_t autoadd_max_hops; // 0 = no limit, 1 = direct (0 hops), N = up to N-1 hops (max 64)
char default_scope_name[31];
uint8_t default_scope_key[16];
};
};
-40
View File
@@ -2,11 +2,6 @@
#include <Mesh.h>
#include "MyMesh.h"
#ifdef ESP32_PLATFORM
#include "esp_pm.h"
#include "esp_bt.h"
#endif
// Believe it or not, this std C function is busted on some platforms!
static uint32_t _atoi(const char* sp) {
uint32_t n = 0;
@@ -245,37 +240,6 @@ void setup() {
#endif
board.onBootComplete();
#ifdef ESP32_PLATFORM
#if !CONFIG_IDF_TARGET_ESP32C6
// Enable BLE sleep
esp_err_t errBLESleep = esp_bt_sleep_enable();
if (errBLESleep == ESP_OK) {
Serial.println("Bluetooth sleep enabled successfully");
} else {
Serial.printf("Bluetooth sleep enable failed: %s\n", esp_err_to_name(errBLESleep));
}
#endif
#if CONFIG_IDF_TARGET_ESP32C3
esp_pm_config_esp32c3_t pm_config;
#elif CONFIG_IDF_TARGET_ESP32S3
esp_pm_config_esp32s3_t pm_config;
#elif CONFIG_IDF_TARGET_ESP32
esp_pm_config_esp32_t pm_config;
#elif CONFIG_IDF_TARGET_ESP32C6
esp_pm_config_t pm_config;
#endif
// Configure Power Management
pm_config = { .max_freq_mhz = 80, .min_freq_mhz = 40, .light_sleep_enable = true };
esp_err_t errPM = esp_pm_configure(&pm_config);
if (errPM == ESP_OK) {
Serial.println("Power Management configured successfully");
} else {
Serial.printf("Power Management failed to configure: %d\r\n", errPM);
}
#endif
}
void loop() {
@@ -289,10 +253,6 @@ void loop() {
if (!the_mesh.hasPendingWork()) {
#if defined(NRF52_PLATFORM)
board.sleep(0); // nrf ignores seconds param, sleeps whenever possible
#elif defined(ESP32_PLATFORM)
if (!serial_interface.isReadBusy() && !serial_interface.isWriteBusy()) { // BLE is not busy
vTaskDelay(pdMS_TO_TICKS(10)); // attempt to sleep
}
#endif
}
-8
View File
@@ -1031,11 +1031,3 @@ void MyMesh::loop() {
uptime_millis += now - last_millis;
last_millis = now;
}
// To check if there is pending work
bool MyMesh::hasPendingWork() const {
#if defined(WITH_BRIDGE)
if (bridge.isRunning()) return true; // bridge needs WiFi radio, can't sleep
#endif
return _mgr->getOutboundTotal() > 0;
}
-3
View File
@@ -225,7 +225,4 @@ public:
void clearStats() override;
void handleCommand(uint32_t sender_timestamp, char* command, char* reply);
void loop();
// To check if there is pending work
bool hasPendingWork() const;
};
-13
View File
@@ -18,9 +18,6 @@ void halt() {
static char command[MAX_POST_TEXT_LEN+1];
// For power saving
unsigned long POWERSAVING_FIRSTSLEEP_SECS = 120; // The first sleep (if enabled) from boot
void setup() {
Serial.begin(115200);
delay(1000);
@@ -118,14 +115,4 @@ void loop() {
ui_task.loop();
#endif
rtc_clock.tick();
if (the_mesh.getNodePrefs()->powersaving_enabled && !the_mesh.hasPendingWork()) {
#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
}
}
+4
View File
@@ -53,6 +53,10 @@ public:
virtual void onAfterTransmit() { }
virtual void reboot() = 0;
virtual void powerOff() { /* 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.
virtual void onBootComplete() { /* 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; }
-6
View File
@@ -1,6 +0,0 @@
#include <stdint.h>
extern "C" {
__attribute__((section(".persistent_magic"))) uint32_t persistent_magic;
__attribute__((section(".persistent_data"))) uint32_t persistent_time;
}
+2 -40
View File
@@ -3,57 +3,19 @@
#include <Mesh.h>
#include <Arduino.h>
#ifdef NRF52_PLATFORM
#define CLOCK_MAGIC_NUM 0xAA55CC33
#define RTC_TIME_MIN 1772323200 // 1 Mar 2026
extern uint32_t persistent_magic;
extern uint32_t persistent_time;
#endif
class VolatileRTCClock : public mesh::RTCClock {
uint32_t base_time;
uint64_t accumulator;
unsigned long prev_millis;
public:
VolatileRTCClock() {
#ifdef NRF52_PLATFORM
if (persistent_magic == CLOCK_MAGIC_NUM && persistent_time >= RTC_TIME_MIN) {
base_time = persistent_time;
} else {
base_time = RTC_TIME_MIN;
}
#else
base_time = 1715770351;
#endif
accumulator = 0;
prev_millis = millis();
}
VolatileRTCClock() { base_time = 1715770351; accumulator = 0; prev_millis = millis(); } // 15 May 2024, 8:50pm
uint32_t getCurrentTime() override { return base_time + accumulator/1000; }
void setCurrentTime(uint32_t time) override {
base_time = time;
accumulator = 0;
prev_millis = millis();
#ifdef NRF52_PLATFORM
persistent_magic = CLOCK_MAGIC_NUM;
persistent_time = time;
#endif
}
void setCurrentTime(uint32_t time) override { base_time = time; accumulator = 0; prev_millis = millis(); }
void tick() override {
unsigned long now = millis();
accumulator += (now - prev_millis);
prev_millis = now;
#ifdef NRF52_PLATFORM
persistent_magic = CLOCK_MAGIC_NUM;
persistent_time = getCurrentTime();
#endif
}
};
-4
View File
@@ -17,10 +17,6 @@ bool ArduinoSerialInterface::isConnected() const {
return true; // no way of knowing, so assume yes
}
bool ArduinoSerialInterface::isReadBusy() const {
return false;
}
bool ArduinoSerialInterface::isWriteBusy() const {
return false;
}
+1 -2
View File
@@ -28,8 +28,7 @@ public:
bool isConnected() const override;
bool isReadBusy() const override;
bool isWriteBusy() const override;
size_t writeFrame(const uint8_t src[], size_t len) override;
size_t checkRecvFrame(uint8_t dest[]) override;
};
};
+6 -4
View File
@@ -38,6 +38,8 @@ public:
#define MAX_CONTACTS 32
#endif
#define MAX_ANON_CONTACTS 8
#ifndef MAX_CONNECTIONS
#define MAX_CONNECTIONS 16
#endif
@@ -59,9 +61,9 @@ class BaseChatMesh : public mesh::Mesh {
friend class ContactsIterator;
ContactInfo contacts[MAX_CONTACTS];
ContactInfo contacts[MAX_CONTACTS+MAX_ANON_CONTACTS];
int num_contacts;
int sort_array[MAX_CONTACTS];
int sort_array[MAX_CONTACTS+MAX_ANON_CONTACTS];
int matching_peer_indexes[MAX_SEARCH_RESULTS];
unsigned long txt_send_timeout;
#ifdef MAX_GROUP_CHANNELS
@@ -73,7 +75,7 @@ class BaseChatMesh : public mesh::Mesh {
ConnectionInfo connections[MAX_CONNECTIONS];
mesh::Packet* composeMsgPacket(const ContactInfo& recipient, uint32_t timestamp, uint8_t attempt, const char *text, uint32_t& expected_ack);
void sendAckTo(const ContactInfo& dest, uint32_t ack_hash);
void sendAckTo(const ContactInfo& dest, const uint8_t* ack_hash, uint8_t ack_len=4);
protected:
BaseChatMesh(mesh::Radio& radio, mesh::MillisecondClock& ms, mesh::RNG& rng, mesh::RTCClock& rtc, mesh::PacketManager& mgr, mesh::MeshTables& tables)
@@ -97,7 +99,7 @@ protected:
num_contacts = MAX_ANON_CONTACTS; // seed the first contacts for anon requests
}
void populateContactFromAdvert(ContactInfo& ci, const mesh::Identity& id, const AdvertDataParser& parser, uint32_t timestamp);
ContactInfo* allocateContactSlot(); // helper to find slot for new contact
ContactInfo* allocateContactSlot(bool transient_only=false); // helper to find slot for new contact
// 'UI' concepts, for sub-classes to implement
virtual bool isAutoAddEnabled() const { return true; }
-1
View File
@@ -15,7 +15,6 @@ public:
virtual bool isConnected() const = 0;
virtual bool isReadBusy() const = 0;
virtual bool isWriteBusy() const = 0;
virtual size_t writeFrame(const uint8_t src[], size_t len) = 0;
virtual size_t checkRecvFrame(uint8_t dest[]) = 0;
+8 -98
View File
@@ -14,7 +14,6 @@
#include <Wire.h>
#include "soc/rtc.h"
#include "esp_system.h"
#include <driver/rtc_io.h>
class ESP32Board : public mesh::MainBoard {
protected:
@@ -25,7 +24,7 @@ protected:
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);
@@ -48,7 +47,7 @@ public:
#endif
#else
Wire.begin();
#endif
#endif
}
// Temperature from ESP32 MCU
@@ -63,31 +62,6 @@ public:
return raw / 4;
}
void powerOff() override {
enterDeepSleep(0); // Do not wakeup
}
void enterDeepSleep(uint32_t secs) {
// Clear stale wakeup sources to avoid ghost wakeup
// This is required when Power Management and automatic lightsleep are enabled
esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_ALL);
if (secs > 0) {
esp_sleep_enable_timer_wakeup(secs * 1000000ULL);
}
// Keep LoRa inactive during deepsleep
digitalWrite(P_LORA_NSS, HIGH);
#if CONFIG_IDF_TARGET_ESP32C3
gpio_hold_en((gpio_num_t)P_LORA_NSS);
#else
rtc_gpio_hold_en((gpio_num_t)P_LORA_NSS);
#endif
// Finally set ESP32 into deepsleep
esp_deep_sleep_start(); // CPU halts here and never returns!
}
uint32_t getIRQGpio() override {
return P_LORA_DIO_1; // default for SX1262
}
@@ -99,15 +73,8 @@ public:
return;
}
#if defined(ARDUINO_USB_CDC_ON_BOOT) && ARDUINO_USB_CDC_ON_BOOT
if (Serial) {
delay(1);
return;
}
#endif
// Set GPIO wakeup
gpio_num_t wakeupPin = (gpio_num_t)getIRQGpio();
gpio_num_t wakeupPin = (gpio_num_t)getIRQGpio();
// Configure timer wakeup
if (secs > 0) {
@@ -188,68 +155,21 @@ public:
void setInhibitSleep(bool inhibit) {
inhibit_sleep = inhibit;
}
uint32_t getResetReason() const override {
return esp_reset_reason();
}
// https://docs.espressif.com/projects/esp-idf/en/v4.4.7/esp32/api-reference/system/system.html
const char *getResetReasonString(uint32_t reason) {
switch (reason) {
case ESP_RST_UNKNOWN:
return "Unknown or first boot";
case ESP_RST_POWERON:
return "Power-on reset";
case ESP_RST_EXT:
return "External reset";
case ESP_RST_SW:
return "Software reset";
case ESP_RST_PANIC:
return "Panic / exception reset";
case ESP_RST_INT_WDT:
return "Interrupt watchdog reset";
case ESP_RST_TASK_WDT:
return "Task watchdog reset";
case ESP_RST_WDT:
return "Other watchdog reset";
case ESP_RST_DEEPSLEEP:
return "Wake from deep sleep";
case ESP_RST_BROWNOUT:
return "Brownout (low voltage)";
case ESP_RST_SDIO:
return "SDIO reset";
default:
static char buf[40];
snprintf(buf, sizeof(buf), "Unknown reset reason (%d)", reason);
return buf;
}
}
};
static RTC_NOINIT_ATTR uint32_t _rtc_backup_time;
static RTC_NOINIT_ATTR uint32_t _rtc_backup_magic;
#define RTC_BACKUP_MAGIC 0xAA55CC33
#define RTC_TIME_MIN 1772323200 // 1 Mar 2026
class ESP32RTCClock : public mesh::RTCClock {
public:
ESP32RTCClock() { }
void begin() {
esp_reset_reason_t reason = esp_reset_reason();
if (reason == ESP_RST_DEEPSLEEP) {
return; // ESP-IDF preserves system time across deep sleep
}
// All other resets (power-on, crash, WDT, brownout) lose system time.
// Restore from RTC backup if valid, otherwise use hardcoded seed.
struct timeval tv;
if (_rtc_backup_magic == RTC_BACKUP_MAGIC && _rtc_backup_time > RTC_TIME_MIN) {
tv.tv_sec = _rtc_backup_time;
} else {
tv.tv_sec = 1772323200; // 1 Mar 2026
}
if (reason == ESP_RST_POWERON) {
// 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);
}
}
uint32_t getCurrentTime() override {
time_t _now;
time(&_now);
@@ -260,16 +180,6 @@ public:
tv.tv_sec = time;
tv.tv_usec = 0;
settimeofday(&tv, NULL);
_rtc_backup_time = time;
_rtc_backup_magic = RTC_BACKUP_MAGIC;
}
void tick() override {
time_t now;
time(&now);
if (now > RTC_TIME_MIN && (uint32_t)now != _rtc_backup_time) {
_rtc_backup_time = (uint32_t)now;
_rtc_backup_magic = RTC_BACKUP_MAGIC;
}
}
};
+30
View File
@@ -15,6 +15,8 @@
#include "ESP32Board.h"
#include <driver/rtc_io.h>
class MeshadventurerBoard : public ESP32Board {
public:
@@ -33,6 +35,34 @@ public:
}
}
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 held 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_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
} 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
}
if (secs > 0) {
esp_sleep_enable_timer_wakeup(secs * 1000000);
}
// Finally set ESP32 into sleep
esp_deep_sleep_start(); // CPU halts here and never returns!
}
void powerOff() override {
// TODO: re-enable this when there is a definite wake-up source pin:
// enterDeepSleep(0);
}
uint16_t getBattMilliVolts() override {
analogReadResolution(12);
+14 -14
View File
@@ -66,20 +66,6 @@ void NRF52Board::initPowerMgr() {
}
}
bool NRF52Board::isExternalPowered() {
// Check if SoftDevice is enabled before using its API
uint8_t sd_enabled = 0;
sd_softdevice_is_enabled(&sd_enabled);
if (sd_enabled) {
uint32_t usb_status;
sd_power_usbregstatus_get(&usb_status);
return (usb_status & POWER_USBREGSTATUS_VBUSDETECT_Msk) != 0;
} else {
return (NRF_POWER->USBREGSTATUS & POWER_USBREGSTATUS_VBUSDETECT_Msk) != 0;
}
}
const char* NRF52Board::getResetReasonString(uint32_t reason) {
if (reason & POWER_RESETREAS_RESETPIN_Msk) return "Reset Pin";
if (reason & POWER_RESETREAS_DOG_Msk) return "Watchdog";
@@ -251,6 +237,20 @@ void NRF52BoardDCDC::begin() {
}
}
bool NRF52Board::isExternalPowered() {
// Check if SoftDevice is enabled before using its API
uint8_t sd_enabled = 0;
sd_softdevice_is_enabled(&sd_enabled);
if (sd_enabled) {
uint32_t usb_status;
sd_power_usbregstatus_get(&usb_status);
return (usb_status & POWER_USBREGSTATUS_VBUSDETECT_Msk) != 0;
} else {
return (NRF_POWER->USBREGSTATUS & POWER_USBREGSTATUS_VBUSDETECT_Msk) != 0;
}
}
void NRF52Board::sleep(uint32_t secs) {
// 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
+2 -2
View File
@@ -53,9 +53,9 @@ public:
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;
bool isExternalPowered() override;
#ifdef NRF52_POWER_MANAGEMENT
bool isExternalPowered() override;
uint16_t getBootVoltage() override { return boot_voltage_mv; }
virtual uint32_t getResetReason() const override { return reset_reason; }
uint8_t getShutdownReason() const override { return shutdown_reason; }
@@ -67,7 +67,7 @@ public:
/*
* The NRF52 has an internal DC/DC regulator that allows increased efficiency
* compared to the LDO regulator. For being able to use it, the module/board
* needs to have the required inductors and and capacitors populated. If the
* needs to have the required inductors and capacitors populated. If the
* hardware requirements are met, this subclass can be used to enable the DC/DC
* regulator.
*/
-2
View File
@@ -2,7 +2,6 @@
#include <CayenneLPP.h>
#include "sensors/LocationProvider.h"
#include <Wire.h>
#define TELEM_PERM_BASE 0x01 // 'base' permission includes battery
#define TELEM_PERM_LOCATION 0x02
@@ -16,7 +15,6 @@ public:
double node_altitude; // altitude in meters
SensorManager() { node_lat = 0; node_lon = 0; node_altitude = 0; }
virtual bool i2c_probe(TwoWire& wire, uint8_t addr) { return false; }
virtual bool begin() { return false; }
virtual bool querySensors(uint8_t requester_permissions, CayenneLPP& telemetry) { return false; }
virtual void loop() { }
-4
View File
@@ -182,10 +182,6 @@ size_t SerialBLEInterface::writeFrame(const uint8_t src[], size_t len) {
#define BLE_WRITE_MIN_INTERVAL 60
bool SerialBLEInterface::isReadBusy() const {
return (recv_queue_len > 0);
}
bool SerialBLEInterface::isWriteBusy() const {
return millis() < _last_write + BLE_WRITE_MIN_INTERVAL; // still too soon to start another write?
}
-1
View File
@@ -76,7 +76,6 @@ public:
bool isConnected() const override;
bool isReadBusy() const override;
bool isWriteBusy() const override;
size_t writeFrame(const uint8_t src[], size_t len) override;
size_t checkRecvFrame(uint8_t dest[]) override;
@@ -39,10 +39,6 @@ size_t SerialWifiInterface::writeFrame(const uint8_t src[], size_t len) {
return 0;
}
bool SerialWifiInterface::isReadBusy() const {
return false;
}
bool SerialWifiInterface::isWriteBusy() const {
return false;
}
-1
View File
@@ -52,7 +52,6 @@ public:
bool isEnabled() const override { return _isEnabled; }
bool isConnected() const override;
bool isReadBusy() const override;
bool isWriteBusy() const override;
size_t writeFrame(const uint8_t src[], size_t len) override;
+24
View File
@@ -86,6 +86,7 @@
#include <Arduino.h>
#include "XPowersLib.h"
#include "helpers/ESP32Board.h"
#include <driver/rtc_io.h>
class TBeamBoard : public ESP32Board {
XPowersLibInterface *PMU = NULL;
@@ -130,6 +131,29 @@ public:
}
#endif
void enterDeepSleep(uint32_t secs, int pin_wake_btn) {
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_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
} 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
}
if (secs > 0) {
esp_sleep_enable_timer_wakeup(secs * 1000000);
}
// Finally set ESP32 into sleep
esp_deep_sleep_start(); // CPU halts here and never returns!
}
uint16_t getBattMilliVolts(){
return PMU->getBattVoltage();
}
-4
View File
@@ -401,10 +401,6 @@ bool SerialBLEInterface::isConnected() const {
return _isDeviceConnected && Bluefruit.connected() > 0;
}
bool SerialBLEInterface::isReadBusy() const {
return (recv_queue_len > 0);
}
bool SerialBLEInterface::isWriteBusy() const {
return send_queue_len >= (FRAME_QUEUE_SIZE * 2 / 3);
}
-1
View File
@@ -66,7 +66,6 @@ public:
void disable() override;
bool isEnabled() const override { return _isEnabled; }
bool isConnected() const override;
bool isReadBusy() const override;
bool isWriteBusy() const override;
size_t writeFrame(const uint8_t src[], size_t len) override;
size_t checkRecvFrame(uint8_t dest[]) override;
@@ -15,7 +15,6 @@
#if ENV_INCLUDE_BME680_BSEC
#ifndef TELEM_BME680_ADDRESS
#define TELEM_BME680_ADDRESS 0x76
#define TELEM_BME680_ADDRESS_2 0x77
#endif
#define TELEM_BME680_SEALEVELPRESSURE_HPA (1013.25)
#include <bsec.h>
@@ -41,7 +40,6 @@ static uint32_t bsec_last_save_ms = 0;
#ifdef ENV_INCLUDE_BME680
#ifndef TELEM_BME680_ADDRESS
#define TELEM_BME680_ADDRESS 0x76
#define TELEM_BME680_ADDRESS_2 0x77
#endif
#define TELEM_BME680_SEALEVELPRESSURE_HPA (1013.25)
#include <Adafruit_BME680.h>
@@ -65,7 +63,6 @@ static Adafruit_AHTX0 AHTX0;
#if ENV_INCLUDE_BME280
#ifndef TELEM_BME280_ADDRESS
#define TELEM_BME280_ADDRESS 0x76 // BME280 environmental sensor I2C address
#define TELEM_BME280_ADDRESS_2 0x77
#endif
#define TELEM_BME280_SEALEVELPRESSURE_HPA (1013.25) // Atmospheric pressure at sea level
#include <Adafruit_BME280.h>
@@ -75,7 +72,6 @@ static Adafruit_BME280 BME280;
#if ENV_INCLUDE_BMP280
#ifndef TELEM_BMP280_ADDRESS
#define TELEM_BMP280_ADDRESS 0x76 // BMP280 environmental sensor I2C address
#define TELEM_BMP280_ADDRESS_2 0x77
#endif
#define TELEM_BMP280_SEALEVELPRESSURE_HPA (1013.25) // Atmospheric pressure at sea level
#include <Adafruit_BMP280.h>
@@ -561,27 +557,15 @@ static const SensorDef SENSOR_TABLE[] = {
#endif
#ifdef ENV_INCLUDE_BME680
{ TELEM_BME680_ADDRESS, "BME680", init_bme680, query_bme680 },
#ifdef TELEM_BME680_ADDRESS_2
{ TELEM_BME680_ADDRESS_2, "BME680", init_bme680, query_bme680 },
#endif
#endif
#if ENV_INCLUDE_BME680_BSEC
{ TELEM_BME680_ADDRESS, "BME680+BSEC", init_bme680_bsec, query_bme680_bsec },
#ifdef TELEM_BME680_ADDRESS_2
{ TELEM_BME680_ADDRESS_2, "BME680+BSEC", init_bme680_bsec, query_bme680_bsec },
#endif
#endif
#if ENV_INCLUDE_BME280
{ TELEM_BME280_ADDRESS, "BME280", init_bme280, query_bme280 },
#ifdef TELEM_BME280_ADDRESS_2
{ TELEM_BME280_ADDRESS_2, "BME280", init_bme280, query_bme280 },
#endif
#endif
#if ENV_INCLUDE_BMP280
{ TELEM_BMP280_ADDRESS, "BMP280", init_bmp280, query_bmp280 },
#ifdef TELEM_BMP280_ADDRESS_2
{ TELEM_BMP280_ADDRESS_2, "BMP280", init_bmp280, query_bmp280 },
#endif
#endif
#if ENV_INCLUDE_SHTC3
{ 0x70, "SHTC3", init_shtc3, query_shtc3 },
@@ -41,7 +41,6 @@ public:
#else
EnvironmentSensorManager(){};
#endif
bool i2c_probe(TwoWire& wire, uint8_t addr) override;
bool begin() override;
bool querySensors(uint8_t requester_permissions, CayenneLPP& telemetry) override;
#if ENV_INCLUDE_GPS || defined(ENV_INCLUDE_BME680_BSEC)
-9
View File
@@ -63,15 +63,6 @@ void ST7735Display::turnOff() {
#else
digitalWrite(PIN_TFT_LEDA_CTL, LOW);
#endif
// Prevent back-powering to save 2.8 mA
pinMode(PIN_TFT_CS, INPUT);
pinMode(PIN_TFT_DC, INPUT);
pinMode(PIN_TFT_SDA, INPUT);
pinMode(PIN_TFT_SCL, INPUT);
pinMode(PIN_TFT_RST, INPUT);
pinMode(PIN_TFT_LEDA_CTL, INPUT);
_isOn = false;
if (_peripher_power) _peripher_power->release();