Skip to content

Develop 2.8 merge to master#10777

Open
thebentern wants to merge 415 commits into
masterfrom
develop
Open

Develop 2.8 merge to master#10777
thebentern wants to merge 415 commits into
masterfrom
develop

Conversation

@thebentern

Copy link
Copy Markdown
Contributor

Master branch has been forked to 2.7 for maintenance

thebentern and others added 30 commits May 12, 2026 16:32
…y efficiency (#10464)

* Added NodeDB fixtures and refactored to use std maps for better efficiency

* Defer NodeDB save during xmodem transfer to prevent mid-transfer fsFormat
…10460)

Move WiFi.onEvent(WiFiEvent) registration before createSSLCert() to
prevent a race where the ESP32 auto-reconnects during cert generation
and fires GOT_IP before the handler is attached, causing
onNetworkConnected() to never run and the TCP/HTTP API services to
never initialize when booting without USB serial.

Also call onNetworkConnected() from reconnectWiFi() on all platforms
(not just RP2040) as a safety net; it is already guarded by
APStartupComplete so it only runs once.
* Drop unneeded Sizeof() instances

* Use SimpleBanner for BLE pin

* Support for different font sizes on notification banner

* Fix NRF52 BLE cppcheck shadow warning

Agent-Logs-Url: https://github.com/meshtastic/firmware/sessions/de12b52c-49d5-452a-b3fb-344724649270

Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com>

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
Co-authored-by: HarukiToreda <116696711+HarukiToreda@users.noreply.github.com>
Co-authored-by: Jason P <applewiz@mac.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com>
)

* Fix position precision for direct sends

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Clarify zero position precision logging

* Use const channel reference for position precision

* Use C linkage for position precision test entrypoints

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
* feat: add Nordic nRF54L15-DK variant (Zephyr + BLE + LoRa)

Adds a community hardware variant for the Nordic nRF54L15-DK (PCA10156)
with an external EBYTE E22-900M30S (SX1262) LoRa module. First Meshtastic
port running on the Zephyr RTOS; all other Nordic targets use the nRF5
SoftDevice stack.

Scope
-----
- New Zephyr-based platform layer under src/platform/nrf54l15/ providing
  Arduino-compatible shims (Arduino.h, SPI, Wire, Print, Stream) over the
  Zephyr APIs plus a LittleFS-backed InternalFileSystem on SPIM20.
- Bluetooth LE peripheral (NRF54L15Bluetooth.*) built on the Zephyr BT
  host stack, exposing the Meshtastic GATT service with legacy
  connectable advertising, just-works pairing, dynamic MTU exchange
  (up to 247 bytes), and iOS connection-parameter tweaks.
- Variant directory variants/nrf54l15/nrf54l15dk/ with pin map for the
  E22 module on connector J1, PlatformIO env (nrf54l15dk), Zephyr
  DT overlay and a wiring README.
- Zephyr project config (zephyr/prj.conf + board overlay) tuned for
  BT + LoRa: 16 KB main stack, 4 KB BT RX thread, RTT logging in
  immediate mode, newlib-nano heap sized to leave room for the GATT
  pools while still allowing ATT MTU=247.
- extra_scripts/nrf54l15_linker.py works around a PlatformIO + old Ninja
  issue where Zephyr's two-pass linker script generation does not run
  automatically; the post-script parses build.ninja and invokes the
  gcc -E step directly before the final link.
- boards/nrf54l15dk.json board definition (PlatformIO needs it for the
  DK; the Seeed platform only ships the XIAO variants).
- variants/rp2350/rp2350.ini excludes platform/nrf54l15/ from RP2350
  build_src_filter so the shared platform tree does not leak between
  targets.
- .gitignore: add nRF J-Link / RTT debug artifacts (flash.jlink,
  rtt_*.txt).

Shared source changes
---------------------
- src/main.{cpp,h}, src/RedirectablePrint.cpp, src/FSCommon.{cpp,h},
  src/mesh/{Channels,NodeDB,RadioLibInterface,MeshService,PhoneAPI}.cpp,
  src/mesh/RadioLibInterface.h, src/modules/AdminModule.cpp: add small
  guards / helpers so the Zephyr build compiles alongside the Arduino
  targets. Behavior on existing boards is unchanged.

Hardware model
--------------
HW_VENDOR maps to meshtastic_HardwareModel_PRIVATE_HW until a dedicated
protobuf enum value is assigned upstream. The variant declares
custom_meshtastic_hw_model = 132 so the maintainers can wire the new
enum value through the protobufs repo after merge.

Hardware note
-------------
The E22-900M30S does not connect its DIO2 pin to TXEN internally — a
wire/solder bridge between DIO2 and TXEN on the module is required for
TX to work. Details and full pin map are in the variant README.

Validation
----------
Built clean against develop. On real hardware (April 2026) the port
passes end-to-end: iOS companion app pairs and connects, configuration
round-trip works, LoRa TX/RX reaches a canonical tbeam on the same mesh
channel, NodeDB updates propagate both ways, and traceroute completes.

* fix(nrf54l15): use atomic fs_rename instead of copy fallback

Zephyr LittleFS on nrf54l15 supports fs_rename natively, so route it
through the same atomic path as ESP32. The previous copyFile+remove
fallback truncated the destination before copying, leaving 0-byte files
if interrupted mid-write.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(nrf54l15): expand storage_partition from 36KB to 700KB

LittleFS on the default 9-block (36KB) storage_partition ran out of
space during copy-on-write of config.proto, causing fs_write to return
ENOSPC and pb_encode to surface "io error" when saving configuration
via the mobile app.

Reclaim slot1_partition (the MCUboot secondary slot — unused since we
flash directly via J-Link) and grow storage_partition to span
0xb6000..0x165000 (~175 blocks).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(nrf54l15): drop USERPREFS_LORACONFIG_* so LoRa config stays mutable

NodeDB rewrites LoRa config from USERPREFS_LORACONFIG_* on every boot,
which prevented reconfiguration via the BLE/serial app. Drop the
variant-level defaults; users configure region and modem preset through
the app like every other variant.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(nrf54l15): enforce MITM passkey pairing on GATT service

- Add MESH_PERM_READ/MESH_PERM_WRITE macros (READ_AUTHEN/WRITE_AUTHEN)
  on all mesh service characteristics so clients must complete passkey
  exchange before accessing fromNum/fromRadio/toRadio/logRadio.
- Wire FIXED_PIN mode to bt_passkey_set() so the device advertises a
  known PIN (config.bluetooth.fixed_pin); RANDOM_PIN keeps default
  per-pairing random passkey.
- Reduce BleDeferredThread HARD_WATCHDOG_MS from 3min to 1min.
- prj.conf: CONFIG_BT_SMP_ENFORCE_MITM=y, CONFIG_BT_FIXED_PASSKEY=y,
  CONFIG_BT_SMP_SC_PAIR_ONLY=n (legacy fallback for clients that abort
  SC pairing with reason 0x01 within 150ms).

* fix(nrf54l15): resolve develop-merge conflict + cppcheck warnings

The `Merge branch 'develop'` left two ~RadioLibInterface() declarations
in src/mesh/RadioLibInterface.h: the inline version added upstream by
PR #10254 (which independently applied the same UAF guard this PR was
carrying) and the out-of-line version this PR introduced. GCC rejects
the duplicate, breaking every platform build. Drop the out-of-line
declaration + definition; keep upstream's inline form.

Also silence the 13 cppcheck low warnings introduced by the new
nrf54l15 Arduino shim — Arduino's `String`/`SPISettings` API contract
relies on implicit single-arg constructors used pervasively by
existing Meshtastic code, so suppress `noExplicitConstructor` inline
with a comment instead of breaking the API. The few mechanical wins
(`const tmp[2]`, `const uint32_t *sp`) are applied directly.

* fmt: fix Trunk Check lint issues on nrf54l15-port

- extra_scripts/nrf54l15_linker.py: move regular imports above
  Import("env") to silence E402, add trunk-ignore-all(F821) for the
  PIO/SCons SConstruct injection (matches esp32_pre.py / nrf52_extra.py
  convention)
- src/platform/nrf54l15/NRF54L15Bluetooth.cpp: clang-format 16.0.3
- boards/nrf54l15dk.json + variants/nrf54l15/nrf54l15dk/README.md:
  prettier 3.8.3 (also resolves markdownlint MD060 on README tables)

No behavior change.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(nrf54l15): address Copilot review comments + correct clang-format style

Six review threads from the 2026-04-30 Copilot review:

- src/platform/nrf54l15/nrf54l15_main.cpp: validate PSP against the nRF54L15
  SRAM range (0x20000000..0x20040000) and 4-byte alignment before walking the
  faulting thread's stack, and clamp the walk so it never reads past the end
  of RAM. Prevents a second fault inside the fatal handler when PSP is
  corrupted (common in real faults).

- src/platform/nrf54l15/nrf54l15_arduino.cpp: gate the bring-up printk traces
  in digitalWrite/digitalRead (CS/NRESET toggle log, BUSY-before-NRESET
  snapshot, BUSY periodic timeline) behind a new -DNRF54L15_GPIO_DEBUG flag
  that is off by default. The "dev NOT READY" message stays unconditional —
  it indicates a genuine hardware/DTS misconfig.

- src/modules/AdminModule.cpp: don't mutate config.device.output_gpio_enabled
  from handleGetConfig(). Reflect the live pin state in the response payload
  only — a getter must not write back to disk-persisted state.

- src/platform/nrf54l15/InternalFileSystem.h: derive totalBytes() from
  FIXED_PARTITION_SIZE(storage_partition) at compile time so it tracks the
  DK overlay's ~700 KB partition instead of the stale 36 KB hard-coded value.
  Updated the file header comment accordingly.

- extra_scripts/nrf54l15_linker.py: make _extract_gcc_command() handle the
  POSIX Ninja COMMAND format (no `cmd.exe /C "..."` wrapper) in addition to
  the Windows form, so the script doesn't hard-fail on Linux/macOS hosts.

- src/platform/nrf54l15/NRF54L15Bluetooth.cpp: clamp NO_PIN to RANDOM_PIN
  with a one-shot LOG_WARN. The mesh GATT permissions are declared with
  BT_GATT_PERM_*_AUTHEN and prj.conf sets CONFIG_BT_SMP_ENFORCE_MITM=y, so
  NO_PIN with no auth callbacks would leave every characteristic returning
  BT_ATT_ERR_AUTHENTICATION. Falling back to RANDOM_PIN keeps the link
  usable instead of silently broken. Also re-formatted this file with the
  project's .trunk/configs/.clang-format (Linux braces, 4-space indent,
  130-col) — the previous lint-fix commit a2aca32 accidentally used the
  default LLVM style here, which CI's clang-format would have rejected.

Build verified: pio run -e nrf54l15dk passes, RAM 47.4%, Flash 28.6%.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(nrf54l15): address remaining Copilot review threads

Round 2/3 review fixes — bugs first, then docs/portability:

BLE concurrency (NRF54L15Bluetooth.cpp):
- onNowHasData / sendLog / BleDeferredThread / shutdown: acquire
  active_conn under ble_mutex via new acquire_active_conn() helper so
  disconnected_cb can't free the conn between the null check and
  bt_conn_ref/bt_gatt_notify (use-after-unref).
- write_toradio: reject writes that exceed MAX_TO_FROM_RADIO_SIZE with
  ATT_ERR_INVALID_ATTRIBUTE_LEN instead of returning success and silently
  dropping the payload (would hide failed config writes from the phone).
- start_advertising: truncate the device name to fit the 31-byte legacy
  scan-response limit and switch to BT_DATA_NAME_SHORTENED so
  bt_le_adv_start() doesn't reject the payload when the name approaches
  CONFIG_BT_DEVICE_NAME_MAX=32.

Linker / portability:
- main.h: drop the rp2040Loop() forward declaration that had no
  definition and no callers — would surface as a link error if any RP2040
  build added a call to the symbol.
- nrf54l15_arduino.cpp: transfer16() now uses static __aligned(4) DMA
  buffers (matching transfer()), removing the EasyDMA-reachability hazard
  of caller-stack buffers on this part.

Filesystem (InternalFileSystem.h):
- usedBytes(): return real usage from fs_statvfs() instead of 0 so OTA
  / range-test free-space guards work.
- rewindDirectory(): close the dir before reopening — Zephyr fs_dir_t has
  no rewind, and re-fs_opendir on an open handle leaks LittleFS state.

Crash handler (nrf54l15_main.cpp):
- After the stack walk, busy-wait 50 ms to flush RTT/printk and call
  sys_reboot(SYS_REBOOT_COLD) directly so the saved_crash record is
  actually reported on the next boot. Default Zephyr config has
  RESET_ON_FATAL_ERROR=n, so the previous k_fatal_halt() spun forever.

Generalization / config:
- PhoneAPI.cpp: replace the NRF54L15_DK ifdef with a
  MESHTASTIC_EXCLUDE_FILES_MANIFEST capability flag (defined in the
  nrf54l15dk env) so future variants can opt in/out without touching
  shared code.
- variants/nrf54l15/nrf54l15.ini: parameterize libdeps include paths via
  ${PIOENV} so additional nRF54L15 envs sharing nrf54l15_base don't break.
- prj.conf: drop the stale "36 KB storage_partition" comments — the DK
  overlay reclaims slot1 to ~700 KB and runtime size comes from
  FIXED_PARTITION_SIZE.
- nrf54l15dk overlay: remove the zephyr,console / zephyr,shell-uart
  chosen entries that conflicted with CONFIG_UART_CONSOLE=n + RTT
  console; keep uart30 enabled so swapping the console is one Kconfig
  flip away.

Build: nrf54l15dk SUCCESS (flash 28.6%, RAM 47.4%); wiznet_5500_evb_pico2
SUCCESS (verifies the shared main.h change).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(nrf54l15dk): use PRIVATE_HW (255) for custom_meshtastic_hw_model

Per @thebentern's review: the nRF54L15-DK is a development kit, not a
canonical Meshtastic SKU, so it falls under HardwareModel::PRIVATE_HW
(255) — the same enum value already used at runtime via HW_VENDOR. The
placeholder 132 is removed; no dedicated enum number will be assigned
for DK boards. Slug stays NRF54L15_DK as a human-readable identifier.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(nrf54l15): unstarve bt_long_wq so SC pairing completes

bt_pub_key_gen() runs the ECC P256 key generation on bt_long_wq.  At default
prio=10 (preemptible) and stack=1400 it gets starved by Meshtastic app
threads at boot — sc_public_key stays NULL for minutes, smp_public_key()
defers with SMP_FLAG_PKEY_SEND, and every SC pairing attempt stalls right
after the public-key exchange.  iOS shows "Connecting…" forever with no
PIN prompt; bleak/CLI fails the first CCC notify write with
"Protocol Error 0x05: Insufficient Authentication".

Set CONFIG_BT_LONG_WQ_PRIO=0 (highest preemptible, ties with main) and
CONFIG_BT_LONG_WQ_STACK_SIZE=4096 (margin for the P256M driver frames).

Validated E2E with iOS Meshtastic app: bt_smp_pkey_ready fires within ~40 s
of boot, 20 SC Passkey Entry rounds complete with matching pcnf/cfm,
encrypt 0x01 / sec_level 0x04 (Authenticated MITM), bonded=1.

* feat(nrf54l15): hardware I2C bus via TWIM30 + sensor telemetry

Adds the Arduino TwoWire layer for the nRF54L15-DK so Meshtastic's
sensor drivers can talk to external I2C devices over the hardware
TWIM30 peripheral.

Bus binding:
- &uart30 disabled in the board overlay (peripheral instance 30 is
  shared between UARTE30 / TWIM30 / SPIM30 — pick one). Console stays
  on RTT via CONFIG_RTT_CONSOLE.
- New i2c30_default / i2c30_sleep pinctrl with SDA=P0.03 / SCL=P0.04.
  External 4.7 kOhm pull-ups required on both lines.
- &i2c30 enabled at I2C_BITRATE_FAST (400 kHz).
- button_3 (SW3, P0.04) deleted from DTS so the pad can be claimed by
  i2c30 pinctrl; SW3 is still wired to the pad on the DK, do not press
  it during I2C use or it will short SCL to GND.

Arduino layer:
- src/platform/nrf54l15/Wire.cpp resolves the DT node at compile time
  via DEVICE_DT_GET(DT_NODELABEL(i2c30)) and dispatches Arduino's
  beginTransmission / write / endTransmission / requestFrom to
  i2c_write / i2c_write_read / i2c_read. Buffer is sized to 256 bytes
  for forward compatibility with the SE050 secure element on the
  custom PCB.
- Wire.h drops the prior compile-only stubs and exposes the real
  TwoWire surface.
- Arduino.h: BitOrder becomes an enum (not #define) so Adafruit_BusIO's
  `typedef BitOrder BusIOBitOrder;` compiles.

Variant + build flags:
- nrf54l15.ini flips HAS_WIRE / HAS_SENSOR / HAS_TELEMETRY from 0 to 1
  and cherry-picks the sensor libs Meshtastic needs (BusIO, Sensor,
  BMP280, BME280, INA219/226/260/3221, SHT4X). The full
  environmental_base group is avoided because it pulls
  Adafruit_SSD1306 / Adafruit_GFX which rely on Arduino pin macros the
  Zephyr shim does not implement.
- nrf54l15dk variant.h defines PIN_WIRE_SDA / PIN_WIRE_SCL for parity
  with the Arduino convention used by other variants. The actual bus
  wiring is fixed by the overlay pinctrl above.

Validated 2026-05-14/15 on the DK with BMP280 @ 0x76 (temperature +
barometric pressure) and INA3221 @ 0x42 (rail voltage / current);
EnvironmentTelemetry / PowerTelemetry packets transmit successfully
over LoRa.

Footprint cost on nrf54l15dk: +45 KB flash, +1.7 KB RAM.

* feat(nodedb): honor USERPREFS for environment telemetry on first boot

installDefaultConfig() now respects two new compile-time prefs:

  USERPREFS_CONFIG_ENV_TELEM_UPDATE_INTERVAL
  USERPREFS_CONFIG_ENVIRONMENT_MEASUREMENT_ENABLED

The mobile apps enforce a 30 min floor on environment_update_interval
in the settings UI, which makes short-interval bring-up testing of new
sensor hardware painful — you have to wait half an hour for the first
LoRa packet to confirm wiring + driver. With these prefs baked into
the variant, the firmware can ship a freshly-flashed device that
broadcasts on a shorter cadence (e.g. 900 s) the moment storage_partition
is empty.

Both prefs are gated on #ifdef so the behavior is unchanged for any
variant that does not opt in. Documented in userPrefs.jsonc with the
existing telemetry-interval pref block.

* fix(nrf54l15): allow multiple bonded BLE peers

CONFIG_BT_MAX_PAIRED defaults to 1, so once the first peer (e.g. an
iOS phone) has paired and bonded, every subsequent pairing attempt
from a different MAC fails inside bt_keys_get_addr() with no free
key slot — the host returns BT_SECURITY_ERR_KEY_DOES_NOT_EXIST and
the second peer never gets past SMP.

Raise the slot count to 4 so the device can simultaneously hold an
iOS phone, a Windows host, a Linux host, and one spare bond. Add
BT_KEYS_OVERWRITE_OLDEST so that once the table fills, the LRU peer
is evicted on the next pairing rather than rejecting the new peer.
This matches the behavior other Meshtastic ports already provide
(nRF52 uses CONFIG_BT_PERIPHERAL_PRIO_CONN with similar semantics).

Discovered while bringing up the Python CLI on Windows alongside
the existing iOS bond.

* fix(nrf54l15): zero-initialize TwoWire buffers + clang-format Wire

cppcheck on every CI target (esp32s3, rp2040, rp2350, nrf52840, ...) was
failing the build with two `uninitMemberVar` warnings on TwoWire's
constructor: `txBuf` and `rxBuf` (256-byte arrays) were not initialized.
Even though the buffers are only read after txLen/rxLen is set, leaving
them uninitialized is a footgun if any future caller bypasses the
len-set step. Use C++11 value-initialization in the member initializer
list — costs ~512 B of memset at boot, gains a clean cppcheck pass and
defensive-against-future-changes semantics.

Also reformat Wire.{cpp,h} with the project's `.trunk/configs/.clang-format`
config so the Trunk Check Runner passes — clang-format moved the
`<errno.h>` include before the Zephyr-namespaced ones in Wire.cpp and
collapsed two inline overloads to single lines in Wire.h.

* fix(AdminModule): remove dead OUTPUT_GPIO_PIN/GpioOutputModule references

OUTPUT_GPIO_PIN is never defined and modules/GpioOutputModule.h doesn't
exist in the codebase; all #ifdef OUTPUT_GPIO_PIN branches were dead code
introduced by the nRF54L15-DK variant commit. Strips the include, the
output_gpio_enabled OFF→ON/ON→OFF transition logic in handleSetConfig(),
and the digitalRead() reflection in handleGetConfig().

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
* Migrate esp32 families to pioarduino platform

* ESP32c6 align text.handler_execute same as C3

* Use pioarduino `develop`

The latest fixes and the latest bugs!

* preliminary esp32p4.ini

* pioarduino: Update LovyanGFX

Includes Manuel's recent commit

* pioarduino 3.3.6

* pioarduino 3.3.6 *release*

chasing the release

* pioarduino: Fix OG ESP32 duplicate libs

* pioarduino: T-Beam 1W CDC mode

* pioarduino: disable network provisioning (wifiprov)

* pioarduino: use legacy esptoolpy naming (forward-compatible)

* Update lovyangfx from `develop` commit to 1.2.19

* fix esp32p4.ini

* check for esp32 w/ wifi

* esp32-p4 specific adaptations

* Switch to meshtastic/esp32_https_server fork (idf5 branch)

* don't ignore esp_lcd

* config for MUI

* fix/workaround SDMMC

* revert a6f6175, update to 3.3.8

* enable esp_hosted for esp32-p4 (experimental)

* Pioarduino 55.03.38-1

* NimBLE-Arduino -> Arduino "BLE" (3.3.x) migration (#10164)

* NimBLE-Arduino -> Arduino "BLE" (3.3.x) migration

* More NimBLE

* Fix Device Name in ATT Read Request (0x2A00).

Device Name is exposed in two places:

- Advertisement data: this is set properly in startAdvertising.
- GATT attribute Device Name (0x2A00). This one is handled internally in NimBLE
  and comes from ble_svc_gap_device_name_set. This is set initially, but then
  BLEDevice::createServer calls ble_svc_gap_init which resets the device name.
  This causes the device to apparently "change name after pairing":

< ACL Data TX:... flags 0x00 dlen 7  #113 [hci0] 14.241149
      ATT: Read Request (0x0a) len 2
        Handle: 0x0003 Type: Device Name (0x2a00)
> ACL Data RX: Handle 2048 flags 0x02 dlen 11             #115 [hci0] 14.269050
      ATT: Read Response (0x0b) len 6
        Value[6]: 6e696d626c65   # "nimble"

Workaround this by setting the device name once again after
BLEDevice::createServer.

* Temporarily lower CORE_DEBUG_LEVEL to INFO to avoid triggering an apparent ESP-IDF Bluetooth bug when re-connecting to Pixel 8 Android devices.

Initial pairing works, but after ESP32 is rebooted, phone fails to reconnect. Meshtastic app shows it as disconnecting immediately. LightBlue shows a more detailed error "Peripheral Connection - Warning: onConnectionStatusChange: status 61" (0x3D - MIC Failure).

Bug report to Espresssif: espressif/esp-idf#18126 (comment)

* Temporarily disable ble_gap_set_data_len, causes crash with Pixel 8 Android reconnect.

Crash looks like this:
  [ 11966][E][BLEAdvertising.cpp:341] setScanResponseData(): ble_gap_adv_rsp_set_data: 22
  [ 11975][E][BLEAdvertising.cpp:1554] start(): Host reset, wait for sync.
  ERROR | ??:??:?? 11 BLE failed to start advertising
  Guru Meditation Error: Core  0 panic'ed (LoadProhibited). Exception was unhandled.

  Core  0 register dump:
  PC      : 0x420e6190  PS      : 0x00060730  A0      : 0x820e158b  A1      : 0x3fce50c0
  A2      : 0x00000000  A3      : 0x3fcb8600  A4      : 0x3fcb85cc  A5      : 0x00000000
  A6      : 0x00000000  A7      : 0x00000c03  A8      : 0x00000000  A9      : 0x3fce50b0
  A10     : 0x0000000e  A11     : 0x00000000  A12     : 0x00000010  A13     : 0x3fce50e0
  A14     : 0x00000c03  A15     : 0x00000001  SAR     : 0x0000001e  EXCCAUSE: 0x0000001c
  EXCVADDR: 0x00000000  LBEG    : 0x400570e8  LEND    : 0x400570f3  LCOUNT  : 0x00000000

  Backtrace: 0x420e618d:0x3fce50c0 0x420e1588:0x3fce5110 0x420dfe87:0x3fce5200 0x420dfefb:0x3fce5220 0x420dff3f:0x3fce5240 0x4219602b:0x3fce5260 0x4037b0e5:0x3fce5280 0x4201edf3:0x3fce52a0

Connection seems fast enough even without this. We'll investigate the
reason for the crash and re-enable once it's safe.

---------

Co-authored-by: Catalin Patulea <cronos586@gmail.com>

* Add extension from pioarduino nag
"Jason2866.esp-decoder"

* Cleanup after merge

* ESP32: Disable classic bluetooth

* Cleanup: Fix ADC channels on new variants

* InkHUD: Fix type casting for message size in saveToFlash method

inkhud compiles again!

* update p4 esp_hosted for BT

* I thought I fixed this

* fix linker error using response file (p4 only)

* fix infinite loop

* Fix Power.cpp check warning

Local variable 'config' shadows outer variable [shadowVariable]

* Build ESP32 original with NimBLE ('custom_sdkconfig' approach). (#10235)

* Re-enable littlefs json manifest

This works locally again :)
Not sure what changed

* Re-add tool-mklittlefs

* sensecap indicator fixes after upgrade arduino-esp & lovyanGFX libs

* hackaday fix

* robot tbeam cache error fix

Co-authored-by: Copilot <copilot@github.com>

* trunk fmt

* ignore trunk

* BLEDevice::deinit() added

Co-authored-by: Copilot <copilot@github.com>

* platformio-custom: Modify mtjson target dependency to prevent fake-success. (#10291)

Co-authored-by: Copilot <copilot@github.com>

* Fix ESP32-C6 linker errors.

Align .text.handler_execute section to 4 bytes and update watchdog timer core mask configuration

Co-authored-by: Copilot <copilot@github.com>

* tlora-c6: Disable Screen

MESHTASTIC_EXCLUDE_SCREEN=1 on tlora-c6.

It doesn't have a screen, and this gets it compiling again (saving flash).

* Use mverch's iram_memset hack for all OG-ESP32

* Refactor watchdog timer initialization and handling

* use adc_channel_t in variant.h

* Fix variant headers

* More idiomatic default ethernet that doesn't break the build

* Elecrows: Delete problematic variant.cpp

Not needed after USE_ETHERNET_DEFAULT

---------

Co-authored-by: mverch67 <manuel.verch@gmx.de>
Co-authored-by: Manuel <71137295+mverch67@users.noreply.github.com>
Co-authored-by: Catalin Patulea <cronos586@gmail.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: vidplace7 <1779290+vidplace7@users.noreply.github.com>
Co-authored-by: Copilot <copilot@github.com>
Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com>
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
Co-authored-by: caveman99 <25002+caveman99@users.noreply.github.com>
* Enabled SX_LNA_EN by default
* Update I2C configuration for IO direction and pull settings

---------

Co-authored-by: Thomas Göttgens <tgoettgens@gmail.com>
Ethan-chen1234-zy and others added 13 commits July 2, 2026 08:01
TAP V2 has a TFT screen and belongs to the same device category as
T-Deck / T-Watch S3 / HELTEC_V4_TFT -- Bluetooth should default to OFF
to avoid unwanted BLE connections and reduce power consumption. Users
can re-enable BT via the TFT settings menu when needed.
* exclude the variant from LTO

* address CI build failure
clod helped
Audit of the XEdDSA packet-signing implementation (#10478) surfaced several
issues in when unsigned packets are accepted on receive or emitted on send.
This fixes them and adds regression coverage.

- Unicast NodeInfo exchange no longer breaks against signer nodes: the
  NodeInfoModule downgrade drop is gated to broadcasts, since senders never
  sign unicast (want_response replies, directed exchanges).
- Replace the payload-size sign heuristic with an exact encoded-size gate
  (signedDataFits) and mirror it on the receive side, removing a dead band
  where 167-168 B broadcasts were signed then failed TOO_LARGE.
- Extract the receive policy into checkXeddsaReceivePolicy() and apply it to
  plaintext-MQTT decoded downlink, which previously skipped signature
  verification and downgrade protection entirely.
- Reject signatures whose length is neither 0 nor 64 as malformed, so a
  crafted partial signature can't inflate the size estimate and dodge the
  unsigned-downgrade drop.
- Hold cryptLock on the MQTT verify path (shared Ed25519 key cache).
- Clear any client-preset signature on packets we originate, on all builds.
- Randomized (hedged) signing per the Signal XEdDSA spec: bump the
  meshtastic/Crypto pin to the build where XEdDSA::sign mixes 32 bytes of
  caller randomness into the nonce as Z (meshtastic/Crypto#3), and seed those
  bytes in xeddsa_sign from HardwareRNG (checked, with a seeded-CSPRNG
  fallback). test_crypto pins that repeated signs differ and both verify.

Adds test coverage: test_packet_signing groups A-E (receive matrix, send
policy, NodeInfo backstop, encoding invariants, decoded-ingress policy),
test_mqtt end-to-end downlink cases, and a test_crypto randomization check.
Makes the linter work on my machine
This is breaking builds. Should be safe to keep.
* Add define for screen I2C frequency

* Add functions to get I2C screen frequency and port

* Make reclock function aware of screen-set I2C speeds

* Refurbish ReClockI2C API

* Make ReClockI2C API class
* Use new API in AirQualityTelemetry module
* Minor changes on some logs

* Update esp8266-oled library

* Fix esp8266 library

* Minor logging changes

* Improve setClock and restoreClock cases

* Make getter functions const, fix capitalisaiton of new functions

* Minor typo, remove pragma once

* Low prio debug fixes

* Mark getter functions as const (properly)

* Fix LOG based on coderabbit feedback

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
The Python MCP server + hardware test harness that lived under mcp-server/
now has its own home at https://github.com/meshtastic/meshtastic-mcp
(published, versioned independently). Remove the in-tree copy and wire the
firmware repo to the standalone server externally.

- Delete mcp-server/ (96 files) and the 8 harness-coupled AI workflow files
  under .claude/commands/ and .github/prompts/ that drove ./mcp-server/
  run-tests.sh — those workflows now ship with meshtastic-mcp as skills.
- .mcp.json: register the server via
  `uvx --from git+https://github.com/meshtastic/meshtastic-mcp meshtastic-mcp`
  instead of a local ./mcp-server/.venv, keeping MESHTASTIC_FIRMWARE_ROOT="."
  so the MCP tools still work from this checkout with no local build.
- Repoint the remaining references (AGENTS.md, CLAUDE.md,
  .github/copilot-instructions.md, bin/regen-*.sh, docs, Screen.h,
  userPrefs.jsonc, test/fixtures/nodedb/README.md, .trunk/configs/.bandit)
  at the standalone repo. The MCP tool surface is unchanged — only the
  pytest harness moves out; run it from a meshtastic-mcp checkout with
  MESHTASTIC_FIRMWARE_ROOT pointed here.

No build/CI/platformio coupling existed, so nothing in the firmware build
changes.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Audit and fuzzing of the RF-packet decode -> dispatch -> display/phone paths for
the "crash a node or phone with a crafted packet" surface, beyond the XEdDSA
authenticity work.

Crash fixes (reproduced under AddressSanitizer / UBSan):
- GeoCoord::latLongToUTM/latLongToMGRS read fixed letter tables out of bounds on
  extreme latitude_i/longitude_i from a received Position, and narrowed
  out-of-range easting/northing doubles to unsigned (float-cast-overflow UB).
  Clamp the UTM zone, the easting/northing narrowing, and the band/col/row
  indices. Regression: test_geocoord_extreme_coords_no_oob.
- EnvironmentTelemetry/AirQualityTelemetry render attacker floats via
  String(float), which on nRF52/RP2040/STM32/portduino formats into a fixed
  char[33] (dtostrf) and overflows near FLT_MAX. Clamp the rendered metrics via
  UnitConversions::displaySafeFloat (finite + magnitude <= 1e9), unit-tested in
  test_type_conversions.

Defense-in-depth + robustness:
- TraceRouteModule::printRoute: fix an snr_back[-1] OOB read (wrong count in the
  guard) and stop formatting the INT8_MIN "unknown SNR" sentinel as a dB value.
- WaypointModule/NodeDB: sanitize untrusted strings before the OLED renderer and
  the phone-facing ClientNotification (belt-and-suspenders vs PB_VALIDATE_UTF8).
- MeshService::sendToPhone: withhold NODEINFO/WAYPOINT packets whose nested string
  won't cleanly decode, protecting strict phone protobuf decoders without
  affecting mesh relay.

Tests: new test_fuzz_decode (protobuf decode + UTF-8 sanitizer fuzz) and
test_fuzz_packets (perhapsDecode / module-handler / traceroute / phone-gate fuzz),
all under AddressSanitizer; native-suite-count 25 -> 27. Full suite 515/515 green.
* second pass adding beacons admin

* Bump protobufs submodule to merged MESHBEACON_CONFIG (PR #970)

clod helped.

* Gate MeshBeacon module config behind admin auth in PhoneAPI

The FromRadio module-config sync copied moduleConfig.mesh_beacon unconditionally. MeshBeaconConfig embeds two ChannelSettings (broadcast_offer_channel, broadcast_on_channel) that carry PSKs, so an unauthorized client could exfiltrate channel PSKs when MESHTASTIC_PHONEAPI_ACCESS_CONTROL is enabled - bypassing the redaction already applied to mqtt/network/security config.
Gate the payload copy on getAdminAuthorized(), mirroring the mqtt case; unauth clients now receive an empty MeshBeaconConfig.

clod helped
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
* GPS improvements

* Update

* Update MenuApplet.cpp

* Remove fixed position

* Update MenuApplet.cpp
* XEdDSA packet signing UI (BaseUI)

* Move Pixels around for TFT
Removed conditional compilation for timeout check on supported architectures.
vidplace7 and others added 8 commits July 3, 2026 10:00
# Conflicts:
#	src/graphics/Screen.cpp
#	src/modules/Telemetry/Sensor/PMSA003ISensor.h
#	src/modules/Telemetry/Sensor/SCD30Sensor.h
#	src/modules/Telemetry/Sensor/SCD4XSensor.h
#	src/modules/Telemetry/Sensor/SEN5XSensor.cpp
#	src/modules/Telemetry/Sensor/SEN5XSensor.h
#	src/modules/Telemetry/Sensor/SFA30Sensor.h
ScanI2CTwoWire is compiled out on builds that define
MESHTASTIC_EXCLUDE_I2C (e.g. native-wasm/portduino), while the
AirQuality module still builds there. Skip the re-scan when I2C is
excluded; there is nothing to scan.
* Update LovyanGFX to v1.2.24

* Remove note on LovyanGFX version compatibility

Removed note about version v1.2.7 breaking display functionality.

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Manuel <71137295+mverch67@users.noreply.github.com>
jp-bennett and others added 5 commits July 3, 2026 22:59
* Use upstream fusion library
* Update Fusion dependency to new repository and version
* Fix ESP32 paxcounter startup with Bluetooth disabled

* Address paxcounter startup review feedback
* nrf52_lto: fix variant LTO exclusion (match srcnode, not mirrored path) + post-link guard

The CI-fix follow-up in #10829 anchored _is_board_variant() to
<PROJECT_DIR>/variants/ using node.get_abspath() -- but build middleware
receives nodes from the SCons variant-dir mirror, whose abspath is
$BUILD_DIR/variants/.../variant.cpp. The anchor never matched, so the
variant silently went back into whole-image LTO: the shipped ELF has
initVariant() resolved to the core's weak empty stub (bare `bx lr`),
PIN_3V3_EN is never driven, and the SX1262 probe fails with
CHIP_NOT_FOUND again -- while the build stays green, because the
post-link guard only checked IRQ handlers.

Fix: match against node.srcnode().get_abspath(), which undoes the
variant-dir mirror (the same trick piobuild.py uses for middleware
pattern matching).

Add a second post-link guard so this failure mode is a red build, not a
field failure: the linked variant.cpp.o must contain no .gnu.lto_*
sections (proves the -fno-lto recompile fired), and any override the
object defines strong (initVariant) must resolve strong in the ELF.
Verified both ways on nrf52_promicro_diy_tcxo: clean build is green with
T _Z11initVariantv and a real initVariant body in the ELF; re-breaking
the matcher turns the build FAILED with both guard checks firing.

clod helped a lot

* address comments

* nrf52_lto: defer variant CCFLAGS so APP_VERSION is present

The variant -fno-lto recompile snapshotted projenv["CCFLAGS"] inside the
build middleware, which fires during $BUILD_SCRIPT. But -DAPP_VERSION... is
appended to projenv by bin/platformio-custom.py, an unprefixed extra_script
that PlatformIO runs as a POST script -- after the middleware. The frozen
override therefore lacked APP_VERSION, so recompiling any board variant whose
variant.cpp includes configuration.h (rak_wismeshtag via sleep.h,
seeed_xiao_nrf52840_kit, seeed_mesh_tracker_X1) failed with
'APP_VERSION must be set by the build environment'.

Defer the CCFLAGS read to a callable construction variable: SCons invokes it
during command substitution, after every SConscript (post-scripts included),
so projenv now carries the version flags. -fno-lto is appended last so it
still wins over the inherited -flto.

Verified clean builds of rak_wismeshtag, seeed_xiao_nrf52840_kit, and rak4631
(regression) -- all green with the variant guard reporting the board variant
kept out of LTO.

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>

@github-advanced-security github-advanced-security AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Semgrep OSS found more than 20 potential problems in the proposed changes. Check the Files changed tab for more details.

* compression improvement

* Update MapTile.h

* t-echo-inkhud  fix
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request needs-review Needs human review

Projects

None yet

Development

Successfully merging this pull request may close these issues.