diff --git a/docs/cli_commands.md b/docs/cli_commands.md index cced8630d..f6142624f 100644 --- a/docs/cli_commands.md +++ b/docs/cli_commands.md @@ -5612,13 +5612,15 @@ peer is reachable. The statistics pages use these keys: | Default | `rx`: received callback frames; `mesh`: inbound MeshCore packets queued; `tx`: outbound MeshCore packets queued; `sent`: successful frame callbacks. | | `rx` | `frames`: received callback frames; `decoded`: parsed MeshCore packets; `mesh`: queued for mesh processing; `crc`: checksum failures; `bad`: malformed frames; `parse`: packet parse failures. | | `tx` | `req`: mesh TX requests; `queued`: mesh packets queued; `start`: SDK-accepted frames; `ok`: successful frame callbacks; `err`: SDK start failures; `cbfail`: failed frame callbacks; `timeout`: callback timeouts. | -| `drops` | `rxq`: RX queue drops; `foreign`: foreign-group packets; `filter`/`dupe`: inbound filter/duplicate drops; `txq`: total mesh TX drops; `txfilter`/`txdupe`: outbound filter/duplicate drops; `big`: oversize TX drops. | +| `drops` | `rxq`: RX queue drops; `foreign`: foreign-group packets; `filter`/`dupe`: inbound filter/duplicate drops; `txq`: recorded local mesh TX rejection/final-failure decisions; `txfilter`/`txdupe`: outbound filter/duplicate drops; `big`: oversize TX drops. | | `test` | `queued`, `start`, `ok`, `fail`, `timeout`: probe TX stages; `rx`, `bad`: valid/invalid probes received; `txid`, `rxid`: last queued/received IDs in hexadecimal. | Mesh admission means queued for normal processing, not confirmed LoRa forwarding or end-to-end delivery. Packet and frame counters have different units: fragmentation can produce several frames for one mesh packet. Counters survive bridge stop/start; reboot or the explicit reset starts a new window. +Stopping or restarting the bridge clears pending queue work without classifying +its delivery. These counters are not a complete end-to-end delivery ledger. **Local-only actions:** diff --git a/docs/espnow_bridge_setup.md b/docs/espnow_bridge_setup.md index 6d2c0d122..7ef92c461 100644 --- a/docs/espnow_bridge_setup.md +++ b/docs/espnow_bridge_setup.md @@ -198,6 +198,9 @@ Repeat in the opposite direction with a new message. Counters accumulate until `espnow resetstats` or reboot and survive an ESP-NOW stop/start. Inspect changes across the one message, rather than assuming old totals describe the current attempt. +Stopping or restarting clears pending queue work without classifying delivery; +the TX drop counter records local rejection/final-failure decisions, not every +undelivered packet. - **No source-side bridge TX request:** check the configured source. `bridge.source rx` exports LoRa receptions; confirm the board heard the diff --git a/docs/test-results/espnow_bridge_diagnostics_2026-10-22.md b/docs/test-results/espnow_bridge_diagnostics_2026-10-22.md new file mode 100644 index 000000000..4ba30b9ed --- /dev/null +++ b/docs/test-results/espnow_bridge_diagnostics_2026-10-22.md @@ -0,0 +1,95 @@ + + + + +# ESP-NOW bridge diagnostics, 22 October 2026 + +Status: **host tests and both Full repeater builds PASS**. No radio was +flashed or contacted in this work. The reported V4/V4 R8 TFT bridge delivery +failure remains physically unverified; matching saved settings and +`espnow.running on` do not establish peer receipt. + +Clean firmware source +[`400878207`](https://github.com/mikecarper/MeshCore/commit/40087820781b189e0136b0ce73928a717752a5c8) +contains the diagnostics. Both canonical builds used the Full profile, +Cascade runtime defaults, USA Cascade radio preset and version +`v1.18.0.1-halo-keymind-cascade-dev-40087820`. +The [safe build receipt](espnow_bridge_diagnostics_2026-10-22.safe.json) +records source, artifact hashes and linked memory measurements. Later +documentation-only changes do not alter these firmware artifacts. + +## Investigation and changes + +Both V4 variants use the same ESP-NOW bridge implementation. No +display-specific forwarding difference was found. `bridge.source rx` is a +valid choice: it exports LoRa receptions. If both boards directly hear the +same LoRa message, normal mesh duplicate suppression can discard a later +bridged copy. This is a condition to measure, not an established cause of +the reported failure. + +Normal builds previously compiled out the bridge's verbose debug path. +Runtime USB logging/debug can now produce bounded ESP-NOW summaries without +a special build flag. Status exposes the configured and actual 2.4 GHz +channel, SDK state, queue depths and historical error stage/code. Separate +counter pages locate RX decode/admission, TX queue/start/completion and +filter/duplicate decisions. No secret is printed. + +The local-only `espnow test` command sends a single bounded diagnostic +probe. The peer consumes it before mesh allocation or LoRa forwarding. It +has no echo or retry and does not modify saved settings. The probe checks +2.4 GHz reachability only; it is unauthenticated and does not validate the +wrapped secret or normal packet format. Confirm receipt using the peer's +increased `rx` count and matching `rxid`, then test the other direction. +SDK send success alone is not application receipt; see the +[Espressif ESP-NOW documentation](https://docs.espressif.com/projects/esp-idf/en/v4.4.7/esp32s3/api-reference/network/esp_now.html). + +Use [the diagnostic procedure](../espnow_bridge_setup.md#locate-a-mesh-forwarding-failure) +and [CLI reference](../cli_commands.md#bridge-when-bridge-support-is-compiled-in) +for the counters and exact command grammar. The USB summary requires both +`usb.logging on` and `usb.debug on`; record and restore both original values +after a short capture. Counter pages and probes need neither logging gate. + +## Build results + +| Canonical target | Selected Full environment | Available internal bytes | Required heap bytes | Result | +| --- | --- | ---: | ---: | --- | +| `heltec_v4_repeater` | `heltec_v4_repeater_observer_mqtt` | 202,576 | 192,656 | PASS | +| `heltec_v4_r8_tft_repeater` | `heltec_v4_r8_tft_repeater_observer_mqtt` | 200,344 | 190,608 | PASS | + +The largest linked internal regions are 169,808 and 167,576 bytes respectively, +against a required contiguous allocation of 21,184 bytes. These are linked +capacity estimates, not runtime free-heap, fragmentation or maximum-load +measurements. Application and merged packages, memory gates, OTA packaging +and linked capability verification pass for both targets. Both capability +receipts report the Full profile with no feature reductions. + +An initial attempt at source `14682de00` compiled but was rejected by the +immutable-input packaging guard because generation changed the embedded web +page header. That header was committed in `400878207`; both qualifying builds +then passed from clean source. The rejected attempt is retained privately and +is excluded from the safe receipt. + +## Verification and limits + +The host validation passed for: + +- Diagnostic codec and actual bridge runtime: strict input/CRC handling, + legacy parser rejection, SDK callback variants, queue/pool pressure, + one-attempt probes, unchanged normal retries, status and bounded output. +- Diagnostic CLI: strict grammar, local-only actions, response bounds and + bridge selection across role combinations, including sanitizer builds. +- Existing bridge recovery, transport filter wiring, radio lifecycle, + ESP-NOW runtime and bridge ingress regressions. +- Cooperative ESP32 USB output, USB debug/prefs, hosted documentation links + and strict documentation rendering. + +Callback work remains bounded and does not print or allocate. Counter +snapshots and resets use the existing RX/TX locks. Diagnostics are guarded +by ESP-NOW bridge support, including the CLI callbacks, so unrelated firmware +roles do not acquire the new callback interface. + +No physical WiFi coexistence, MQTT coexistence, LoRa delivery, probe exchange +or USB debug capture was performed. Actual pair qualification still requires +the new readings and fresh LoRa traffic in both directions. Stop/restart can +discard pending queue work without classifying delivery; lifetime counters +are not a complete end-to-end delivery ledger. diff --git a/docs/test-results/espnow_bridge_diagnostics_2026-10-22.safe.json b/docs/test-results/espnow_bridge_diagnostics_2026-10-22.safe.json new file mode 100644 index 000000000..c70e93e54 --- /dev/null +++ b/docs/test-results/espnow_bridge_diagnostics_2026-10-22.safe.json @@ -0,0 +1,73 @@ +{ + "schema_version": 1, + "date": "2026-10-22", + "source_commit": "40087820781b189e0136b0ce73928a717752a5c8", + "source_clean_at_build": true, + "firmware_version": "v1.18.0.1-halo-keymind-cascade-dev-40087820", + "runtime_profile": "cascade", + "radio_preset": "usa-cascade-fixed", + "scope": "Host tests and clean canonical build/package checks only. No hardware flashed or contacted. Actual bridge pair failure remains unverified.", + "physical_validation_performed": false, + "builds": [ + { + "requested_target": "heltec_v4_repeater", + "platformio_environment": "heltec_v4_repeater_observer_mqtt", + "build_profile": "full", + "capability_verification_passed": true, + "feature_reductions": [], + "build_recipe_sha256": "44e773e27532c5e1a3e846a86dd1646631a8f7d03a9cbe9119e6237c765ec516", + "capabilities_sha256": "dfb6df721a6051359ea69de83232930104a5e489cda9cc63c66a1f3e73fddcfe", + "memory": { + "passed": true, + "available_internal_bytes": 202576, + "largest_internal_region_bytes": 169808, + "required_heap_bytes": 192656, + "required_contiguous_bytes": 21184, + "scope": "Linked capacity before runtime allocation; physical boot/load/soak validation remains required." + }, + "memory_receipt_sha256": "8ba0fbad37ce56c7b3922dcdc8c76ee6742415bae0b8e7ed540f79224a3b93bf", + "artifacts": [ + { + "file": "heltec_v4_repeater_observer_mqtt-full-usb-wifi-ota-v1.18.0.1-halo-keymind-cascade-dev-40087820-merged.bin", + "bytes": 2378472, + "sha256": "2c3b15b2845cd30d796f42138d6ac0a24dbea4cb3d51f9e67c7e35aef51511f5" + }, + { + "file": "heltec_v4_repeater_observer_mqtt-full-usb-wifi-ota-v1.18.0.1-halo-keymind-cascade-dev-40087820.bin", + "bytes": 2312936, + "sha256": "31cd7feff5ee4db6c9df6a1ef2c73055cbe42e29739d7dbd9f76d4ad036ea8b5" + } + ] + }, + { + "requested_target": "heltec_v4_r8_tft_repeater", + "platformio_environment": "heltec_v4_r8_tft_repeater_observer_mqtt", + "build_profile": "full", + "capability_verification_passed": true, + "feature_reductions": [], + "build_recipe_sha256": "aee9d9999eeed7cecb1d76c6914b80a6ff24ddae7c6a4895ceef50185a193780", + "capabilities_sha256": "258f78349f727a9436ae902b99ce4abf5b666ebdd520622e9d6d017a8928c024", + "memory": { + "passed": true, + "available_internal_bytes": 200344, + "largest_internal_region_bytes": 167576, + "required_heap_bytes": 190608, + "required_contiguous_bytes": 21184, + "scope": "Linked capacity before runtime allocation; physical boot/load/soak validation remains required." + }, + "memory_receipt_sha256": "820bde1809e719cfbd636373f681368b98fd92f592866bbd88a81f236bc889cd", + "artifacts": [ + { + "file": "heltec_v4_r8_tft_repeater_observer_mqtt-full-usb-wifi-ota-v1.18.0.1-halo-keymind-cascade-dev-40087820-merged.bin", + "bytes": 2392424, + "sha256": "dca1c74564b9830e73859d20332a59de3ca0b17456544d4c3102201665577f9c" + }, + { + "file": "heltec_v4_r8_tft_repeater_observer_mqtt-full-usb-wifi-ota-v1.18.0.1-halo-keymind-cascade-dev-40087820.bin", + "bytes": 2326888, + "sha256": "23b827c27b46f5a3c6cae5257ca9940f2eb9bc7ccb0bc815c2d123ff18521e43" + } + ] + } + ] +} diff --git a/docs/test-results/index.md b/docs/test-results/index.md index 47e76a8a4..91c30b625 100644 --- a/docs/test-results/index.md +++ b/docs/test-results/index.md @@ -11,6 +11,7 @@ Completed validation reports, experiments, and test guides are collected here. O ## Radio and RF +- [ESP-NOW bridge diagnostics: V4 and V4 R8 TFT Full build/host validation, 2026-10-22](espnow_bridge_diagnostics_2026-10-22.md) - [V3/V4/T096 radio2 with two fixed witnesses, matched SF7/BW62.5 at preamble 32, 2026-10-22](radio2_simultaneous_receivers_2026-10-22.md) - [SolarXiao Room Server power profiles and history build/host validation, 2026-10-21](solarxiao_room_2026-10-21.md) - [SolarXiao three power profiles build/host validation, 2026-10-21](solarxiao_basic_2026-10-21.md)