From 5e52e396930b885d33836cefd806d12684cd2281 Mon Sep 17 00:00:00 2001 From: Elektr0Vodka <211697683+Elektr0Vodka@users.noreply.github.com> Date: Sun, 18 Oct 2026 19:00:46 +0200 Subject: [PATCH 1/4] fix(build): keep DISABLE_DEBUG=1 working on nRF52 disable_debug_flags() passed -UCFG_DEBUG. The Adafruit nRF52 core reads CFG_DEBUG unconditionally (cores/nRF5/rtos.cpp), and the platform builder only adds its CFG_DEBUG=0 default when the flags don't mention the macro, so every nRF52 build with DISABLE_DEBUG=1 failed with "'CFG_DEBUG' was not declared". Pass -DCFG_DEBUG=0 instead, which is the quiet setting the builder would have used. Built with DISABLE_DEBUG=1: LilyGo_T-Echo_companion_radio_ble, WioTrackerL1_companion_radio_usb (both failed before) and heltec_v4_companion_radio_usb_tcp (same size as before). --- build.sh | 6 ++++-- changelog_ev.md | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/build.sh b/build.sh index 3d639c8b..f3645924 100755 --- a/build.sh +++ b/build.sh @@ -158,10 +158,12 @@ for section, options in data: fi } -# disable all debug logging flags if DISABLE_DEBUG=1 is set +# disable all debug logging flags if DISABLE_DEBUG=1 is set. +# CFG_DEBUG is set to 0 rather than undefined: the nRF52 core reads it unconditionally +# (rtos.cpp), and its builder only adds the default when the flags don't mention it. disable_debug_flags() { if [ "$DISABLE_DEBUG" == "1" ]; then - export PLATFORMIO_BUILD_FLAGS="${PLATFORMIO_BUILD_FLAGS} -UMESH_DEBUG -UBLE_DEBUG_LOGGING -UWIFI_DEBUG_LOGGING -UBRIDGE_DEBUG -UGPS_NMEA_DEBUG -UCORE_DEBUG_LEVEL -UESPNOW_DEBUG_LOGGING -UDEBUG_RP2040_WIRE -UDEBUG_RP2040_SPI -UDEBUG_RP2040_CORE -UDEBUG_RP2040_PORT -URADIOLIB_DEBUG_SPI -UCFG_DEBUG -URADIOLIB_DEBUG_BASIC -URADIOLIB_DEBUG_PROTOCOL" + export PLATFORMIO_BUILD_FLAGS="${PLATFORMIO_BUILD_FLAGS} -UMESH_DEBUG -UBLE_DEBUG_LOGGING -UWIFI_DEBUG_LOGGING -UBRIDGE_DEBUG -UGPS_NMEA_DEBUG -UCORE_DEBUG_LEVEL -UESPNOW_DEBUG_LOGGING -UDEBUG_RP2040_WIRE -UDEBUG_RP2040_SPI -UDEBUG_RP2040_CORE -UDEBUG_RP2040_PORT -URADIOLIB_DEBUG_SPI -DCFG_DEBUG=0 -URADIOLIB_DEBUG_BASIC -URADIOLIB_DEBUG_PROTOCOL" fi } diff --git a/changelog_ev.md b/changelog_ev.md index 9b8f5fd2..e9312429 100644 --- a/changelog_ev.md +++ b/changelog_ev.md @@ -35,6 +35,7 @@ Newest first. Each entry names the PR that landed it. ### Fixed +- **`DISABLE_DEBUG=1` builds on nRF52**: `build.sh` undefined `CFG_DEBUG`, which the nRF52 Arduino core reads unconditionally, so every nRF52 build with `DISABLE_DEBUG=1` failed. It now sets `CFG_DEBUG=0`. - **T-Echo Card companions build again** (#16): the ui-tiny UI still took the upstream 1.18 `MultiSerialInterface*`, while meshcomod passes the board's own serial interface. It now takes `BaseSerialInterface*` like ui-new. - **Companion builds on classic ESP32** (#17): the `bootloader` CLI command wrote the RTC force-download bit, which only the S2, S3 and C3 have, so every classic ESP32 companion (Heltec V2, T-Beam, T-LoRa and others) failed to compile. Chips without the bit now reply `bootloader: not supported on this chip`. The ESP32-C6 envs still do not build: they run Arduino core 3.x while `esp32_base` pins NimBLE-Arduino 1.4.3, which needs core 2.x. - **Companion builds on nRF52**: two pieces of upstream meshcomod companion code assumed ESP32 and broke any non-ESP32 companion build. The backup import used the ESP32 PSRAM allocator (`heap_caps_*`); it now uses the default allocator elsewhere. `ota status` read HTTP OTA progress globals that only `ESP32Board.cpp` defines; it now reports `ota: idle` on boards without HTTP OTA. From 51d2ddd028a10eee67856fcc49d1a2232192c71f Mon Sep 17 00:00:00 2001 From: Elektr0Vodka <211697683+Elektr0Vodka@users.noreply.github.com> Date: Sun, 18 Oct 2026 19:38:56 +0200 Subject: [PATCH 2/4] fix(companion): build the ESP32-C6 companions with NimBLE 2.x The C6 envs use pioarduino (Arduino core 3.x) through esp32c6_base but inherited h2zero/NimBLE-Arduino 1.4.3 from esp32_base, which only builds against core 2.x ("syscfg/syscfg.h: No such file"). Every C6 companion failed to compile. esp32c6_base now pulls NimBLE-Arduino 2.3.9. SerialBLEInterface keeps its behaviour but implements both callback APIs: the bodies move into shared helpers and thin overrides match each version's signatures (NimBLEConnInfo, onPassKeyDisplay, onConfirmPassKey with injectConfirmPasskey, enableScanResponse). The version is picked with __has_include(), which only 2.x ships. Core 3.x moved esp_efuse_mac_get_default to esp_mac.h, so include it when present. Built: Xiao_C6, Meshimi, WHY2025_badge and LilyGo_Tlora_C6 BLE companions, M5Stack_Unit_C6L BLE and USB, Xiao_C6_repeater_ (all failed or untested before). The S3 boards stay on 1.4.3: heltec_v4_companion_radio_ble and _usb_tcp build, the latter +136 B from the helper indirection. Not tested on hardware. --- changelog_ev.md | 1 + platformio.ini | 4 + src/helpers/esp32/SerialBLEInterface.cpp | 109 +++++++++++++++++------ src/helpers/esp32/SerialBLEInterface.h | 29 +++++- 4 files changed, 116 insertions(+), 27 deletions(-) diff --git a/changelog_ev.md b/changelog_ev.md index e9312429..3373cf7f 100644 --- a/changelog_ev.md +++ b/changelog_ev.md @@ -35,6 +35,7 @@ Newest first. Each entry names the PR that landed it. ### Fixed +- **ESP32-C6 companions build**: the C6 envs run Arduino core 3.x but inherited NimBLE-Arduino 1.4.3, which only builds against core 2.x. `esp32c6_base` now uses NimBLE-Arduino 2.3.9, and `SerialBLEInterface` implements both callback APIs (picked at compile time), so the S3 boards stay on 1.4.3. All C6 companion envs (Xiao C6, Meshimi, WHY2025 badge, T-LoRa C6, M5Stack Unit C6L) build. Builds, not tested on hardware. - **`DISABLE_DEBUG=1` builds on nRF52**: `build.sh` undefined `CFG_DEBUG`, which the nRF52 Arduino core reads unconditionally, so every nRF52 build with `DISABLE_DEBUG=1` failed. It now sets `CFG_DEBUG=0`. - **T-Echo Card companions build again** (#16): the ui-tiny UI still took the upstream 1.18 `MultiSerialInterface*`, while meshcomod passes the board's own serial interface. It now takes `BaseSerialInterface*` like ui-new. - **Companion builds on classic ESP32** (#17): the `bootloader` CLI command wrote the RTC force-download bit, which only the S2, S3 and C3 have, so every classic ESP32 companion (Heltec V2, T-Beam, T-LoRa and others) failed to compile. Chips without the bit now reply `bootloader: not supported on this chip`. The ESP32-C6 envs still do not build: they run Arduino core 3.x while `esp32_base` pins NimBLE-Arduino 1.4.3, which needs core 2.x. diff --git a/platformio.ini b/platformio.ini index 3fd4eb92..37d16d3e 100644 --- a/platformio.ini +++ b/platformio.ini @@ -83,6 +83,10 @@ lib_deps = [esp32c6_base] extends = esp32_base platform = https://github.com/pioarduino/platform-espressif32/releases/download/53.03.13-1/platform-espressif32.zip +; core 3.x needs NimBLE-Arduino 2.x (1.4.x only builds against core 2.x); the S3 boards +; stay on 1.4.3 via esp32_base. SerialBLEInterface handles both callback APIs. +lib_deps = ${arduino_base.lib_deps} + h2zero/NimBLE-Arduino @ 2.3.9 ; ----------------- NRF52 --------------------- diff --git a/src/helpers/esp32/SerialBLEInterface.cpp b/src/helpers/esp32/SerialBLEInterface.cpp index e080d320..496d51a8 100644 --- a/src/helpers/esp32/SerialBLEInterface.cpp +++ b/src/helpers/esp32/SerialBLEInterface.cpp @@ -1,4 +1,7 @@ #include "SerialBLEInterface.h" +#if __has_include() +#include // esp_efuse_mac_get_default moved here in core 3.x +#endif // See the following for generating UUIDs: // https://www.uuidgenerator.net/ @@ -74,7 +77,11 @@ void SerialBLEInterface::begin(const char* prefix, char* name, uint32_t pin_code // was unidentifiable in a list of peers. The name rides the scan response when // it doesn't fit beside the 128-bit service UUID in the 31-byte adv packet. adv->setName(dev_name); +#ifdef MESHCOMOD_NIMBLE2 + adv->enableScanResponse(true); +#else adv->setScanResponse(true); +#endif } void SerialBLEInterface::startAdvertising() { @@ -82,7 +89,72 @@ void SerialBLEInterface::startAdvertising() { adv_restart_time = 0; } -// -------- NimBLEServerCallbacks: security +// -------- callback bodies shared by both NimBLE APIs + +void SerialBLEInterface::handleAuthComplete(bool encrypted, uint16_t conn_handle) { + if (encrypted) { + BLE_DEBUG_PRINTLN(" - SecurityCallback - Authentication Success"); + deviceConnected = true; + } else { + BLE_DEBUG_PRINTLN(" - SecurityCallback - Authentication Failure*"); + if (pServer) pServer->disconnect(conn_handle); + adv_restart_time = millis() + ADVERT_RESTART_DELAY; + } +} + +void SerialBLEInterface::handleConnect(uint16_t conn_handle, const uint8_t* peer_addr) { + BLE_DEBUG_PRINTLN("onConnect(), conn_id=%d", conn_handle); + last_conn_id = conn_handle; + memcpy(_peer_bda, peer_addr, 6); // NimBLE addr is little-endian + _peer_bda_valid = true; +} + +void SerialBLEInterface::handleDisconnect() { + BLE_DEBUG_PRINTLN("onDisconnect()"); + _peer_bda_valid = false; + if (_isEnabled) { + adv_restart_time = millis() + ADVERT_RESTART_DELAY; + // loop() will detect this on next loop, and set deviceConnected to false + } +} + +#ifdef MESHCOMOD_NIMBLE2 + +// -------- NimBLE 2.x callbacks + +uint32_t SerialBLEInterface::onPassKeyDisplay() { + BLE_DEBUG_PRINTLN("onPassKeyDisplay()"); + return _pin_code; +} + +void SerialBLEInterface::onConfirmPassKey(NimBLEConnInfo& connInfo, uint32_t pass_key) { + BLE_DEBUG_PRINTLN("onConfirmPassKey(%u)", pass_key); + NimBLEDevice::injectConfirmPasskey(connInfo, true); +} + +void SerialBLEInterface::onAuthenticationComplete(NimBLEConnInfo& connInfo) { + handleAuthComplete(connInfo.isEncrypted(), connInfo.getConnHandle()); +} + +void SerialBLEInterface::onConnect(NimBLEServer* pServer, NimBLEConnInfo& connInfo) { + handleConnect(connInfo.getConnHandle(), connInfo.getAddress().getVal()); +} + +void SerialBLEInterface::onMTUChange(uint16_t MTU, NimBLEConnInfo& connInfo) { + BLE_DEBUG_PRINTLN("onMTUChange(), mtu=%d", MTU); +} + +void SerialBLEInterface::onDisconnect(NimBLEServer* pServer, NimBLEConnInfo& connInfo, int reason) { + handleDisconnect(); +} + +void SerialBLEInterface::onWrite(NimBLECharacteristic* pCharacteristic, NimBLEConnInfo& connInfo) { + handleWrite(pCharacteristic); +} + +#else + +// -------- NimBLE 1.4.x callbacks uint32_t SerialBLEInterface::onPassKeyRequest() { BLE_DEBUG_PRINTLN("onPassKeyRequest()"); @@ -95,25 +167,11 @@ bool SerialBLEInterface::onConfirmPIN(uint32_t pass_key) { } void SerialBLEInterface::onAuthenticationComplete(ble_gap_conn_desc* desc) { - if (desc && desc->sec_state.encrypted) { - BLE_DEBUG_PRINTLN(" - SecurityCallback - Authentication Success"); - deviceConnected = true; - } else { - BLE_DEBUG_PRINTLN(" - SecurityCallback - Authentication Failure*"); - if (pServer) pServer->disconnect(desc ? desc->conn_handle : last_conn_id); - adv_restart_time = millis() + ADVERT_RESTART_DELAY; - } + handleAuthComplete(desc && desc->sec_state.encrypted, desc ? desc->conn_handle : last_conn_id); } -// -------- NimBLEServerCallbacks: connection lifecycle - void SerialBLEInterface::onConnect(NimBLEServer* pServer, ble_gap_conn_desc* desc) { - BLE_DEBUG_PRINTLN("onConnect(), conn_id=%d", desc ? desc->conn_handle : -1); - if (desc) { - last_conn_id = desc->conn_handle; - memcpy(_peer_bda, desc->peer_ota_addr.val, 6); // NimBLE addr is little-endian - _peer_bda_valid = true; - } + if (desc) handleConnect(desc->conn_handle, desc->peer_ota_addr.val); } void SerialBLEInterface::onMTUChange(uint16_t MTU, ble_gap_conn_desc* desc) { @@ -121,17 +179,18 @@ void SerialBLEInterface::onMTUChange(uint16_t MTU, ble_gap_conn_desc* desc) { } void SerialBLEInterface::onDisconnect(NimBLEServer* pServer) { - BLE_DEBUG_PRINTLN("onDisconnect()"); - _peer_bda_valid = false; - if (_isEnabled) { - adv_restart_time = millis() + ADVERT_RESTART_DELAY; - // loop() will detect this on next loop, and set deviceConnected to false - } + handleDisconnect(); } -// -------- NimBLECharacteristicCallbacks - void SerialBLEInterface::onWrite(NimBLECharacteristic* pCharacteristic) { + handleWrite(pCharacteristic); +} + +#endif + +// -------- RX characteristic write + +void SerialBLEInterface::handleWrite(NimBLECharacteristic* pCharacteristic) { NimBLEAttValue val = pCharacteristic->getValue(); int len = val.length(); const uint8_t* rxValue = val.data(); diff --git a/src/helpers/esp32/SerialBLEInterface.h b/src/helpers/esp32/SerialBLEInterface.h index 4463362b..ce5b4a1e 100644 --- a/src/helpers/esp32/SerialBLEInterface.h +++ b/src/helpers/esp32/SerialBLEInterface.h @@ -3,6 +3,12 @@ #include "../BaseSerialInterface.h" #include +// NimBLE-Arduino 2.x (needed on Arduino core 3.x boards such as the ESP32-C6) changed the +// callback signatures. Only 2.x ships NimBLEAdvertisementData.h, so use that to tell them apart. +#if __has_include() + #define MESHCOMOD_NIMBLE2 1 +#endif + // NimBLE port of the companion BLE (Nordic UART) transport. Public API is kept // identical to the previous Bluedroid implementation so MultiTransportCompanionInterface // and the plain *_ble envs need no changes. NimBLE's host is ~tens of KB lighter on the @@ -36,8 +42,26 @@ class SerialBLEInterface : public BaseSerialInterface, public NimBLEServerCallba void clearBuffers() { recv_queue_len = 0; send_queue_len = 0; } void startAdvertising(); + // Callback bodies shared by both NimBLE APIs. + void handleConnect(uint16_t conn_handle, const uint8_t* peer_addr); + void handleDisconnect(); + void handleAuthComplete(bool encrypted, uint16_t conn_handle); + void handleWrite(NimBLECharacteristic* pCharacteristic); + protected: - // NimBLEServerCallbacks — connection lifecycle + security +#ifdef MESHCOMOD_NIMBLE2 + // NimBLEServerCallbacks (2.x): connection lifecycle + security + void onConnect(NimBLEServer* pServer, NimBLEConnInfo& connInfo) override; + void onDisconnect(NimBLEServer* pServer, NimBLEConnInfo& connInfo, int reason) override; + void onMTUChange(uint16_t MTU, NimBLEConnInfo& connInfo) override; + uint32_t onPassKeyDisplay() override; + void onConfirmPassKey(NimBLEConnInfo& connInfo, uint32_t pass_key) override; + void onAuthenticationComplete(NimBLEConnInfo& connInfo) override; + + // NimBLECharacteristicCallbacks (2.x) + void onWrite(NimBLECharacteristic* pCharacteristic, NimBLEConnInfo& connInfo) override; +#else + // NimBLEServerCallbacks (1.4.x): connection lifecycle + security void onConnect(NimBLEServer* pServer, ble_gap_conn_desc* desc) override; void onDisconnect(NimBLEServer* pServer) override; void onMTUChange(uint16_t MTU, ble_gap_conn_desc* desc) override; @@ -45,8 +69,9 @@ class SerialBLEInterface : public BaseSerialInterface, public NimBLEServerCallba bool onConfirmPIN(uint32_t pass_key) override; void onAuthenticationComplete(ble_gap_conn_desc* desc) override; - // NimBLECharacteristicCallbacks + // NimBLECharacteristicCallbacks (1.4.x) void onWrite(NimBLECharacteristic* pCharacteristic) override; +#endif public: SerialBLEInterface() { From 7052184872d0279577cc49fb55cff5ab323b1a93 Mon Sep 17 00:00:00 2001 From: Elektr0Vodka <211697683+Elektr0Vodka@users.noreply.github.com> Date: Sun, 18 Oct 2026 18:49:50 +0200 Subject: [PATCH 3/4] docs: bring README, changelog and CAD docs in line with the new boards After #16, #17 and #18: - README: the multi-transport claim only holds for the Wi-Fi boards; add how to flash the nRF52 boards (.uf2, DFU .zip); describe nRF52 build outputs and warn that DISABLE_DEBUG=1 breaks nRF52 builds. - CAD toggle doc: the per-UI board examples now name the released boards (ui-new on the display usb_tcp boards, Wio Tracker L1 and T-Echo; ui-tiny on the T-Echo Card; ui-orig on the ThinkNode M7). - Changelog: tag the Unreleased entries with the PR that landed them. --- README.md | 6 ++++-- changelog_ev.md | 18 +++++++++--------- docs/companion_cad_toggle.md | 6 +++--- 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index b3d302ab..4455d381 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ A build with the receive filter reports it in `ver`, e.g. `v1.18.0.1--dmc-f ## What's different in meshcomod -A single firmware image supports **USB, Bluetooth, and TCP** companion connections at the same time (e.g. Home Assistant on USB, the MeshCore app on BLE, the web client on TCP). Use one, two, or all three; BLE and TCP can be toggled from the device UI. +On the Wi-Fi boards (every ESP32-S3 `_usb_tcp` build), a single firmware image supports **USB, Bluetooth, and TCP** companion connections at the same time (e.g. Home Assistant on USB, the MeshCore app on BLE, the web client on TCP). Use one, two, or all three; BLE and TCP can be toggled from the device UI. - **USB** — always on when the device is powered. - **Bluetooth** — the pairing PIN is shown on the device's **Bluetooth tab** (state + pairing info). **Long-press** the tab to enable/disable BLE; the footer reads "ON: long press" / "OFF: long press". @@ -163,6 +163,8 @@ No local build needed. This fork's builds are published as **GitHub pre-releases 2. Choose **Custom firmware** and upload the `-merged.bin` for your board from the [latest fork pre-release](https://github.com/Elektr0Vodka/meshcomod/releases?q=companion). 3. Connect via USB, BLE (PIN on the display), and/or TCP. +> **nRF52 boards** (Wio Tracker L1, T-Echo, T-Echo Card) do not use the web flasher. Double-tap reset, then copy the `.uf2` for your board onto the USB drive that appears. The `.zip` in the same release is the DFU package for updating over BLE. Pick the `_ble` or `_usb` image for the transport you want. + > If unsure which binary to flash, use **merged** (it includes the bootloader + partition table and writes from `0x0`). Rolling back: flash an upstream build with the flasher's Easy mode, or an older fork pre-release. Upstream pinned versions are in the [Release log (RELEASES.md)](RELEASES.md) and the [upstream GitHub Releases](https://github.com/ALLFATHER-BV/meshcomod/releases). @@ -214,7 +216,7 @@ sh build.sh build-firmware Heltec_v3_companion_radio_usb_tcp Other targets use the same flow with their env name from the [Supported devices](#supported-devices) table. Build all shipped companions at once with `sh build.sh build-meshcomod-companion-firmwares`. -**Outputs** (every target): app-only `out/--.bin` and **merged** `out/---merged.bin` (flash from `0x0`). The merged image is also at `.pio/build//firmware-merged.bin`. The `*_companion_radio_usb_tcp` targets also get `out/.partsig` (partition layout, used by `ota update`) and have the OTA manifest base baked in (`OTA_MANIFEST_BASE_URL` overrides it). +**Outputs** (ESP32 targets): app-only `out/--.bin` and **merged** `out/---merged.bin` (flash from `0x0`). The merged image is also at `.pio/build//firmware-merged.bin`. The `*_companion_radio_usb_tcp` targets also get `out/.partsig` (partition layout, used by `ota update`) and have the OTA manifest base baked in (`OTA_MANIFEST_BASE_URL` overrides it). nRF52 targets produce `out/--.uf2` and a DFU `.zip` instead. Do not set `DISABLE_DEBUG=1` for nRF52 targets: it undefines `CFG_DEBUG`, which the nRF52 Arduino core needs to compile. ### Black screen after flashing diff --git a/changelog_ev.md b/changelog_ev.md index 3373cf7f..d1de58b2 100644 --- a/changelog_ev.md +++ b/changelog_ev.md @@ -16,16 +16,16 @@ Newest first. Each entry names the PR that landed it. ### Added -- **Eight more multi-transport companion boards (experimental)**: `usb_tcp` envs (USB + TCP + WebSocket + BLE, SNMP, manifest OTA) for the Heltec Vision Master E290 and T190, Heltec RC32, LilyGo T-Beam 1W, Meshnology W12, Station G2, Station G3 (ESP32-S3) and Elecrow ThinkNode M9, all added to the release list. All are 16 MB ESP32-S3 boards and reuse the display driver of their stock companion builds. The T-Beam 1W and both Stations default to the 4 MB partition layout, so their envs select `default_16MB.csv`. The ThinkNode M9 `variant.h` macro `DONE` (unused) is renamed `PIN_CHARGE_DONE` because it broke the SNMP library's parser enum. Builds, not tested on hardware. -- **Six more multi-transport companion boards (experimental)**: `usb_tcp` envs (USB + TCP + WebSocket + BLE, SNMP, manifest OTA) for the Heltec Wireless Tracker V2, Heltec Vision Master E213, Seeed Xiao S3, RAK3112, LilyGo T-ETH Elite and LilyGo T-Beam S3 Supreme, all added to the release list. Each is an ESP32-S3 with at least 8 MB flash on its existing partition table and reuses the display driver of the board's stock companion builds (RAK3112 and T-ETH Elite are headless). The T-ETH Elite build runs over Wi-Fi; its Ethernet port is not used, as upstream has no Ethernet companion for it either. Marked experimental in the README: nobody working on the fork owns these boards, so beyond building, nothing board specific (display, buttons, battery, free heap) has been checked. Builds, not tested on hardware. -- **Seeed Wio Tracker L1 / L1 Pro companions**: the existing upstream `WioTrackerL1_companion_radio_ble` and `WioTrackerL1_companion_radio_usb` envs are now in the release list, so the fork builds and releases them (`.uf2` + DFU `.zip`). The nRF52840 has no Wi-Fi, so these are single-transport (BLE or USB) with no TCP, SNMP or manifest OTA. The CAD toggle and receive filter build in. Builds, not tested on hardware. +- **Eight more multi-transport companion boards (experimental)** (#18): `usb_tcp` envs (USB + TCP + WebSocket + BLE, SNMP, manifest OTA) for the Heltec Vision Master E290 and T190, Heltec RC32, LilyGo T-Beam 1W, Meshnology W12, Station G2, Station G3 (ESP32-S3) and Elecrow ThinkNode M9, all added to the release list. All are 16 MB ESP32-S3 boards and reuse the display driver of their stock companion builds. The T-Beam 1W and both Stations default to the 4 MB partition layout, so their envs select `default_16MB.csv`. The ThinkNode M9 `variant.h` macro `DONE` (unused) is renamed `PIN_CHARGE_DONE` because it broke the SNMP library's parser enum. Builds, not tested on hardware. +- **Six more multi-transport companion boards (experimental)** (#15): `usb_tcp` envs (USB + TCP + WebSocket + BLE, SNMP, manifest OTA) for the Heltec Wireless Tracker V2, Heltec Vision Master E213, Seeed Xiao S3, RAK3112, LilyGo T-ETH Elite and LilyGo T-Beam S3 Supreme, all added to the release list. Each is an ESP32-S3 with at least 8 MB flash on its existing partition table and reuses the display driver of the board's stock companion builds (RAK3112 and T-ETH Elite are headless). The T-ETH Elite build runs over Wi-Fi; its Ethernet port is not used, as upstream has no Ethernet companion for it either. Marked experimental in the README: nobody working on the fork owns these boards, so beyond building, nothing board specific (display, buttons, battery, free heap) has been checked. Builds, not tested on hardware. +- **Seeed Wio Tracker L1 / L1 Pro companions** (#14): the existing upstream `WioTrackerL1_companion_radio_ble` and `WioTrackerL1_companion_radio_usb` envs are now in the release list, so the fork builds and releases them (`.uf2` + DFU `.zip`). The nRF52840 has no Wi-Fi, so these are single-transport (BLE or USB) with no TCP, SNMP or manifest OTA. The CAD toggle and receive filter build in. Builds, not tested on hardware. - **LilyGo T-Echo companions** (#16): the existing upstream `LilyGo_T-Echo_companion_radio_ble` and `LilyGo_T-Echo_companion_radio_usb` envs are now in the release list (`.uf2` + DFU `.zip`). Like the Wio Tracker L1 this is an nRF52840 without Wi-Fi, so the builds are single-transport (BLE or USB) with no TCP, SNMP or manifest OTA. The e-ink ui-new UI, CAD toggle and receive filter build in. The T-Echo Lite is not included. Builds, not tested on hardware. - **LilyGo T-Echo Card companions** (#16): `LilyGo_T-Echo_Card_companion_radio_ble` and `_usb` join the release list, single-transport like the T-Echo, with the ui-tiny UI and its CAD page. Builds, not tested on hardware. ### CI and build -- **PR build check covers classic ESP32**: `Heltec_v2_companion_radio_ble` joins the PR matrix so companion code that only builds on the S3, like the `bootloader` register write fixed in #17, is caught before merge. -- **PR build check covers nRF52**: `WioTrackerL1_companion_radio_ble` joins the PR matrix so fork companion code that only builds on ESP32 is caught. +- **PR build check covers classic ESP32** (#21): `Heltec_v2_companion_radio_ble` joins the PR matrix so companion code that only builds on the S3, like the `bootloader` register write fixed in #17, is caught before merge. +- **PR build check covers nRF52** (#14): `WioTrackerL1_companion_radio_ble` joins the PR matrix so fork companion code that only builds on ESP32 is caught. ### Docs @@ -35,12 +35,12 @@ Newest first. Each entry names the PR that landed it. ### Fixed -- **ESP32-C6 companions build**: the C6 envs run Arduino core 3.x but inherited NimBLE-Arduino 1.4.3, which only builds against core 2.x. `esp32c6_base` now uses NimBLE-Arduino 2.3.9, and `SerialBLEInterface` implements both callback APIs (picked at compile time), so the S3 boards stay on 1.4.3. All C6 companion envs (Xiao C6, Meshimi, WHY2025 badge, T-LoRa C6, M5Stack Unit C6L) build. Builds, not tested on hardware. -- **`DISABLE_DEBUG=1` builds on nRF52**: `build.sh` undefined `CFG_DEBUG`, which the nRF52 Arduino core reads unconditionally, so every nRF52 build with `DISABLE_DEBUG=1` failed. It now sets `CFG_DEBUG=0`. +- **ESP32-C6 companions build** (#22): the C6 envs run Arduino core 3.x but inherited NimBLE-Arduino 1.4.3, which only builds against core 2.x. `esp32c6_base` now uses NimBLE-Arduino 2.3.9, and `SerialBLEInterface` implements both callback APIs (picked at compile time), so the S3 boards stay on 1.4.3. All C6 companion envs (Xiao C6, Meshimi, WHY2025 badge, T-LoRa C6, M5Stack Unit C6L) build. Builds, not tested on hardware. +- **`DISABLE_DEBUG=1` builds on nRF52** (#20): `build.sh` undefined `CFG_DEBUG`, which the nRF52 Arduino core reads unconditionally, so every nRF52 build with `DISABLE_DEBUG=1` failed. It now sets `CFG_DEBUG=0`. - **T-Echo Card companions build again** (#16): the ui-tiny UI still took the upstream 1.18 `MultiSerialInterface*`, while meshcomod passes the board's own serial interface. It now takes `BaseSerialInterface*` like ui-new. - **Companion builds on classic ESP32** (#17): the `bootloader` CLI command wrote the RTC force-download bit, which only the S2, S3 and C3 have, so every classic ESP32 companion (Heltec V2, T-Beam, T-LoRa and others) failed to compile. Chips without the bit now reply `bootloader: not supported on this chip`. The ESP32-C6 envs still do not build: they run Arduino core 3.x while `esp32_base` pins NimBLE-Arduino 1.4.3, which needs core 2.x. -- **Companion builds on nRF52**: two pieces of upstream meshcomod companion code assumed ESP32 and broke any non-ESP32 companion build. The backup import used the ESP32 PSRAM allocator (`heap_caps_*`); it now uses the default allocator elsewhere. `ota status` read HTTP OTA progress globals that only `ESP32Board.cpp` defines; it now reports `ota: idle` on boards without HTTP OTA. -- **Docs site deploy**: the Pages workflow no longer writes upstream's `docs.meshcore.nz` CNAME into `gh-pages`, and `mkdocs.yml` points at this fork (`elektr0vodka.github.io/meshcomod`) instead of `meshcore-dev`. GitHub Pages must serve the `gh-pages` branch for the mkdocs site to show; it was serving `main` `/docs` through Jekyll. +- **Companion builds on nRF52** (#14): two pieces of upstream meshcomod companion code assumed ESP32 and broke any non-ESP32 companion build. The backup import used the ESP32 PSRAM allocator (`heap_caps_*`); it now uses the default allocator elsewhere. `ota status` read HTTP OTA progress globals that only `ESP32Board.cpp` defines; it now reports `ota: idle` on boards without HTTP OTA. +- **Docs site deploy** (#12): the Pages workflow no longer writes upstream's `docs.meshcore.nz` CNAME into `gh-pages`, and `mkdocs.yml` points at this fork (`elektr0vodka.github.io/meshcomod`) instead of `meshcore-dev`. GitHub Pages must serve the `gh-pages` branch for the mkdocs site to show; it was serving `main` `/docs` through Jekyll. ## 2026-10-16 diff --git a/docs/companion_cad_toggle.md b/docs/companion_cad_toggle.md index d5d09a17..9329e893 100644 --- a/docs/companion_cad_toggle.md +++ b/docs/companion_cad_toggle.md @@ -22,10 +22,10 @@ The on-device control depends on the UI the board uses: | UI variant | Boards (examples) | CAD control | |-----------|-------------------|-------------| -| ui-new | Heltec V4, Heltec V3 (OLED) | Dedicated CAD page. Swipe to it, ENTER or long-press toggles. Tested on hardware. | +| ui-new | Heltec V4 and V3 (OLED), every other released `_usb_tcp` board with a display, the Wio Tracker L1 and the T-Echo | Dedicated CAD page. Swipe to it, ENTER or long-press toggles. Tested on hardware on the V4 and V3 only. | | ui-touch | Heltec V4 TFT touch | Settings > Experimental > CAD switch, then Save. | -| ui-tiny | LilyGo T-Echo Card | Dedicated CAD page. ENTER toggles. | -| ui-orig | Meshtracker X1, MinewSemi ME25LS01, Muziworks R1 Neo, RAK 3112, and similar | Read-only CAD status on the home screen. No on-device toggle (this UI is gesture-only with no free gesture); change CAD from the app. | +| ui-tiny | LilyGo T-Echo Card (released from this fork) | Dedicated CAD page. ENTER toggles. | +| ui-orig | ThinkNode M7 (released from this fork), Meshtracker X1, MinewSemi ME25LS01, Muziworks R1 Neo, the stock RAK 3112 builds, and similar | Read-only CAD status on the home screen. No on-device toggle (this UI is gesture-only with no free gesture); change CAD from the app. | ## Default and persistence From 56de25fb254f66e1bed32d5a8852f020316cb54f Mon Sep 17 00:00:00 2001 From: Elektr0Vodka <211697683+Elektr0Vodka@users.noreply.github.com> Date: Sun, 18 Oct 2026 19:00:46 +0200 Subject: [PATCH 4/4] docs: drop the nRF52 DISABLE_DEBUG warning, fixed in build.sh --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4455d381..e31f165c 100644 --- a/README.md +++ b/README.md @@ -216,7 +216,7 @@ sh build.sh build-firmware Heltec_v3_companion_radio_usb_tcp Other targets use the same flow with their env name from the [Supported devices](#supported-devices) table. Build all shipped companions at once with `sh build.sh build-meshcomod-companion-firmwares`. -**Outputs** (ESP32 targets): app-only `out/--.bin` and **merged** `out/---merged.bin` (flash from `0x0`). The merged image is also at `.pio/build//firmware-merged.bin`. The `*_companion_radio_usb_tcp` targets also get `out/.partsig` (partition layout, used by `ota update`) and have the OTA manifest base baked in (`OTA_MANIFEST_BASE_URL` overrides it). nRF52 targets produce `out/--.uf2` and a DFU `.zip` instead. Do not set `DISABLE_DEBUG=1` for nRF52 targets: it undefines `CFG_DEBUG`, which the nRF52 Arduino core needs to compile. +**Outputs** (ESP32 targets): app-only `out/--.bin` and **merged** `out/---merged.bin` (flash from `0x0`). The merged image is also at `.pio/build//firmware-merged.bin`. The `*_companion_radio_usb_tcp` targets also get `out/.partsig` (partition layout, used by `ota update`) and have the OTA manifest base baked in (`OTA_MANIFEST_BASE_URL` overrides it). nRF52 targets produce `out/--.uf2` and a DFU `.zip` instead. ### Black screen after flashing