diff --git a/.github/workflows/stale-bot.yml b/.github/workflows/stale-bot.yml deleted file mode 100644 index ec166587..00000000 --- a/.github/workflows/stale-bot.yml +++ /dev/null @@ -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 - \ No newline at end of file diff --git a/SECURITY.md b/SECURITY.md deleted file mode 100644 index a4b2207d..00000000 --- a/SECURITY.md +++ /dev/null @@ -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 diff --git a/build-iotthinks.sh b/build-iotthinks.sh deleted file mode 100644 index 613789d0..00000000 --- a/build-iotthinks.sh +++ /dev/null @@ -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 diff --git a/examples/companion_radio/DataStore.cpp b/examples/companion_radio/DataStore.cpp index fdb924ad..bf2f36c3 100644 --- a/examples/companion_radio/DataStore.cpp +++ b/examples/companion_radio/DataStore.cpp @@ -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(); } diff --git a/examples/companion_radio/MyMesh.cpp b/examples/companion_radio/MyMesh.cpp index 5d1adb46..5fb9bf9d 100644 --- a/examples/companion_radio/MyMesh.cpp +++ b/examples/companion_radio/MyMesh.cpp @@ -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]; diff --git a/examples/companion_radio/MyMesh.h b/examples/companion_radio/MyMesh.h index 0d687cfd..f4190f30 100644 --- a/examples/companion_radio/MyMesh.h +++ b/examples/companion_radio/MyMesh.h @@ -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"); diff --git a/examples/companion_radio/NodePrefs.h b/examples/companion_radio/NodePrefs.h index ecb117bd..48c381ce 100644 --- a/examples/companion_radio/NodePrefs.h +++ b/examples/companion_radio/NodePrefs.h @@ -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]; -}; +}; \ No newline at end of file diff --git a/examples/companion_radio/main.cpp b/examples/companion_radio/main.cpp index f10cb170..ef9b6bfc 100644 --- a/examples/companion_radio/main.cpp +++ b/examples/companion_radio/main.cpp @@ -2,11 +2,6 @@ #include #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 } diff --git a/examples/simple_room_server/MyMesh.cpp b/examples/simple_room_server/MyMesh.cpp index c311c941..12d0b0c3 100644 --- a/examples/simple_room_server/MyMesh.cpp +++ b/examples/simple_room_server/MyMesh.cpp @@ -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; -} diff --git a/examples/simple_room_server/MyMesh.h b/examples/simple_room_server/MyMesh.h index 380e54da..e9e53ec9 100644 --- a/examples/simple_room_server/MyMesh.h +++ b/examples/simple_room_server/MyMesh.h @@ -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; }; diff --git a/examples/simple_room_server/main.cpp b/examples/simple_room_server/main.cpp index ad8aa914..a3798b21 100644 --- a/examples/simple_room_server/main.cpp +++ b/examples/simple_room_server/main.cpp @@ -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 - } } diff --git a/src/MeshCore.h b/src/MeshCore.h index 846b8f05..89e60b1f 100644 --- a/src/MeshCore.h +++ b/src/MeshCore.h @@ -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; } diff --git a/src/helpers/ArduinoHelpers.cpp b/src/helpers/ArduinoHelpers.cpp deleted file mode 100644 index feb77a79..00000000 --- a/src/helpers/ArduinoHelpers.cpp +++ /dev/null @@ -1,6 +0,0 @@ -#include - -extern "C" { - __attribute__((section(".persistent_magic"))) uint32_t persistent_magic; - __attribute__((section(".persistent_data"))) uint32_t persistent_time; -} \ No newline at end of file diff --git a/src/helpers/ArduinoHelpers.h b/src/helpers/ArduinoHelpers.h index 9b50b98c..97596daa 100644 --- a/src/helpers/ArduinoHelpers.h +++ b/src/helpers/ArduinoHelpers.h @@ -3,57 +3,19 @@ #include #include -#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 } }; diff --git a/src/helpers/ArduinoSerialInterface.cpp b/src/helpers/ArduinoSerialInterface.cpp index 6b443974..a01fa586 100644 --- a/src/helpers/ArduinoSerialInterface.cpp +++ b/src/helpers/ArduinoSerialInterface.cpp @@ -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; } diff --git a/src/helpers/ArduinoSerialInterface.h b/src/helpers/ArduinoSerialInterface.h index 4fa2b75d..c4086353 100644 --- a/src/helpers/ArduinoSerialInterface.h +++ b/src/helpers/ArduinoSerialInterface.h @@ -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; -}; +}; \ No newline at end of file diff --git a/src/helpers/BaseChatMesh.h b/src/helpers/BaseChatMesh.h index c6027468..d9878547 100644 --- a/src/helpers/BaseChatMesh.h +++ b/src/helpers/BaseChatMesh.h @@ -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; } diff --git a/src/helpers/BaseSerialInterface.h b/src/helpers/BaseSerialInterface.h index 8ff110eb..e9a3f2ab 100644 --- a/src/helpers/BaseSerialInterface.h +++ b/src/helpers/BaseSerialInterface.h @@ -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; diff --git a/src/helpers/ESP32Board.h b/src/helpers/ESP32Board.h index 48730fdd..a4cbf2a9 100644 --- a/src/helpers/ESP32Board.h +++ b/src/helpers/ESP32Board.h @@ -14,7 +14,6 @@ #include #include "soc/rtc.h" #include "esp_system.h" -#include 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; - } } }; diff --git a/src/helpers/MeshadventurerBoard.h b/src/helpers/MeshadventurerBoard.h index 0325161d..65e11102 100644 --- a/src/helpers/MeshadventurerBoard.h +++ b/src/helpers/MeshadventurerBoard.h @@ -15,6 +15,8 @@ #include "ESP32Board.h" +#include + 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); diff --git a/src/helpers/NRF52Board.cpp b/src/helpers/NRF52Board.cpp index 2c8753d4..17265f04 100644 --- a/src/helpers/NRF52Board.cpp +++ b/src/helpers/NRF52Board.cpp @@ -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 diff --git a/src/helpers/NRF52Board.h b/src/helpers/NRF52Board.h index 96f67dc9..17065cf4 100644 --- a/src/helpers/NRF52Board.h +++ b/src/helpers/NRF52Board.h @@ -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. */ diff --git a/src/helpers/SensorManager.h b/src/helpers/SensorManager.h index d4aa63b7..89a174c2 100644 --- a/src/helpers/SensorManager.h +++ b/src/helpers/SensorManager.h @@ -2,7 +2,6 @@ #include #include "sensors/LocationProvider.h" -#include #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() { } diff --git a/src/helpers/esp32/SerialBLEInterface.cpp b/src/helpers/esp32/SerialBLEInterface.cpp index 50e1501e..dcfa0e1e 100644 --- a/src/helpers/esp32/SerialBLEInterface.cpp +++ b/src/helpers/esp32/SerialBLEInterface.cpp @@ -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? } diff --git a/src/helpers/esp32/SerialBLEInterface.h b/src/helpers/esp32/SerialBLEInterface.h index 19e024b0..965e90fd 100644 --- a/src/helpers/esp32/SerialBLEInterface.h +++ b/src/helpers/esp32/SerialBLEInterface.h @@ -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; diff --git a/src/helpers/esp32/SerialWifiInterface.cpp b/src/helpers/esp32/SerialWifiInterface.cpp index bdecb1a9..462e3ecc 100644 --- a/src/helpers/esp32/SerialWifiInterface.cpp +++ b/src/helpers/esp32/SerialWifiInterface.cpp @@ -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; } diff --git a/src/helpers/esp32/SerialWifiInterface.h b/src/helpers/esp32/SerialWifiInterface.h index 1ff1d83d..19291497 100644 --- a/src/helpers/esp32/SerialWifiInterface.h +++ b/src/helpers/esp32/SerialWifiInterface.h @@ -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; diff --git a/src/helpers/esp32/TBeamBoard.h b/src/helpers/esp32/TBeamBoard.h index 543226d6..98bd16bf 100644 --- a/src/helpers/esp32/TBeamBoard.h +++ b/src/helpers/esp32/TBeamBoard.h @@ -86,6 +86,7 @@ #include #include "XPowersLib.h" #include "helpers/ESP32Board.h" +#include 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(); } diff --git a/src/helpers/nrf52/SerialBLEInterface.cpp b/src/helpers/nrf52/SerialBLEInterface.cpp index a846e744..75a4e3b0 100644 --- a/src/helpers/nrf52/SerialBLEInterface.cpp +++ b/src/helpers/nrf52/SerialBLEInterface.cpp @@ -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); } diff --git a/src/helpers/nrf52/SerialBLEInterface.h b/src/helpers/nrf52/SerialBLEInterface.h index d3cc5055..de103054 100644 --- a/src/helpers/nrf52/SerialBLEInterface.h +++ b/src/helpers/nrf52/SerialBLEInterface.h @@ -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; diff --git a/src/helpers/sensors/EnvironmentSensorManager.cpp b/src/helpers/sensors/EnvironmentSensorManager.cpp index ea57677f..73842d9e 100644 --- a/src/helpers/sensors/EnvironmentSensorManager.cpp +++ b/src/helpers/sensors/EnvironmentSensorManager.cpp @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 }, diff --git a/src/helpers/sensors/EnvironmentSensorManager.h b/src/helpers/sensors/EnvironmentSensorManager.h index b91d2dc3..29147c89 100644 --- a/src/helpers/sensors/EnvironmentSensorManager.h +++ b/src/helpers/sensors/EnvironmentSensorManager.h @@ -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) diff --git a/src/helpers/ui/ST7735Display.cpp b/src/helpers/ui/ST7735Display.cpp index 8983c911..a6087dd8 100644 --- a/src/helpers/ui/ST7735Display.cpp +++ b/src/helpers/ui/ST7735Display.cpp @@ -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();