Skip to content

Enhance BLE OTA reliability with keepalive and supervision timeout - #121

Merged
zjwhitehead merged 18 commits into
masterfrom
unified-everything-app
Aug 6, 2026
Merged

Enhance BLE OTA reliability with keepalive and supervision timeout#121
zjwhitehead merged 18 commits into
masterfrom
unified-everything-app

Conversation

@zjwhitehead

Copy link
Copy Markdown
Member

This pull request introduces major new beta infrastructure for ESC (Electronic Speed Controller) configuration and firmware update relays, refines BMS (Battery Management System) connection logic, and significantly reduces the enabled LVGL UI components for improved resource usage. It also adds new color definitions and helper functions for the UI, and makes several codebase organization improvements.

ESC Configuration and Firmware Relay:

  • Added a comprehensive ESC configuration relay interface (esc_config_relay.h), including session state machine, parameter set/read-all/batch-write APIs, and status reporting for robust phone-to-ESC configuration over BLE and CAN.
  • Added a full ESC firmware relay interface (esc_flasher_relay.h), supporting buffered BLE-to-CAN firmware updates with state tracking and error codes.
  • Defined the canonical set of ESC parameter IDs for "read all" operations in esc_param_ids.h.
  • Added BLE UUIDs for all new relay services and characteristics in ble_ids.h.
  • Provided a single-threaded CAN adapter accessor for safe relay operation (esc.h), and a BLE notify helper for relay status streaming (config_service.h). [1] [2]

BMS Connection Logic Improvements:

  • Introduced a configurable BMS link timeout, and new logic to ensure BMS "connected" state is only reported after all required CAN frames are received, preventing spurious disconnects and critical alerts at boot.

UI and LVGL Configuration:

  • Significantly reduced enabled LVGL widgets and features in lv_conf.h to minimize memory and code usage, disabling unused components such as arc, button, spinner, flex, grid, and others. [1] [2] [3] [4]
  • Added new dark theme accent color definitions and helper functions for critical border opacity in the main screen header. [1] [2]

Codebase Organization and Cleanup:

  • Updated comments and clarified the purpose of UI refresh time, removed unused variables and functions in lvgl_core.h.

These changes lay the groundwork for robust, safe, and user-friendly ESC configuration and firmware management from the phone app, while optimizing UI resource usage and improving system reliability.

PaulDWhite and others added 18 commits June 8, 2026 12:35
…disconnect

During OTA the firmware suppresses the ~50 Hz FastLink telemetry stream to give
the flash full bandwidth. With no liveness signal a BLE central can tear down
the link mid-flash (HCI 0x13 / disconnect reason 531), aborting the update
partway through (~20-30%).

- fastlink_service.cpp: emit a ~1 Hz FastLink keepalive notify while OTA is in
  progress so the central keeps the link up. The keepalive ships the packet
  already setValue()'d, whose advancing packet_id/uptime_ms the app counts as
  telemetry progress (no app changes needed). At 1 Hz vs the 15 ms OTA interval
  it does not meaningfully slow the flash.
- ble_core.cpp (requestFastConnParams): lengthen the OTA-time supervision
  timeout from 2 s to 8 s so a multi-second flash-erase stall or a sluggish
  phone cannot drop the link at the link-layer level. OTA_TIMEOUT_MS (30 s)
  remains the dead-link backstop.

Reliability over speed: trades negligible flash throughput for a link that
stays up across the whole flash.
Replace hard clamp and magic numbers in the climb-rate vario display with named constants. Introduce kVarioSegment (0.5 m/s per segment) and kVarioDeadzone (0.25 m/s) and compute sectionsToFill from kVarioSegment, capping at 6. Remove the previous ±0.6 m/s clamp and use the deadzone as the neutral threshold so values beyond ±3 m/s pin the gauge to full deflection rather than being clamped.
Reduce display redraws and SPI contention by introducing change-detecting LVGL setters and safer SPI handling. Key changes:

- Add resetLvglUpdateCache() and change-detecting helpers (setLabelText, setBgColor, etc.) to avoid redundant LVGL invalidations and per-frame full redraws.
- Rework many main-screen update paths (battery, power, altitude, climb rate, temps, icons) to compute desired state then diff-apply only changed widgets/styles.
- Add flushSkipped flag: if a display flush is skipped due to SPI busy, mark it and force a full invalidate on next refresh to recover stale pixels.
- Let LVGL read time directly (lv_tick_set_cb) and remove ad-hoc lv_tick_handler/lvgl_last_update; call lv_timer_handler() from updateLvgl().
- Move BMS SPI CS toggling to occur only after acquiring the shared SPI mutex and release the mutex immediately after the CAN library's update() (getters are read-only), preventing mid-transfer deselects and reducing wait times for display flushes.
- Increase UI task frequency to ~30 Hz (33 ms) to match LVGL refresh period.
- Update headers and tests to reflect removed variables/functions and new reset API.

These changes reduce unnecessary rendering, avoid lost mid-transfer display updates, and improve responsiveness under SPI contention.
Introduce an ESC configuration relay that forwards app BLE commands to the ESC over CAN and verifies the write across an ESC reboot. Adds BLE UUIDs and two characteristics (command + status), a new esc_config_relay module (header + implementation) implementing a non-blocking state machine (write -> save -> restart -> verify) that runs on the throttle/CAN owner task, and a small API (escAdapter, init/service tick, request/status). Enforce safety: sessions only run when DISARMED and arming is blocked while a session is active. Modified files: BLE service registration and callbacks, ESC init/read loop to integrate the relay, main arming check, and esc.h/ble ids updates.
Implements an ESC configuration relay and firmware flasher relay reachable from the phone app via new BLE characteristics and relayed to the ESC over CAN. Adds BLE UUIDs (ctrl/data/param/notify), new headers (esc_flasher_relay.h, esc_param_ids.h) and a full flasher implementation (esc_flasher_relay.cpp). Extends the config BLE service to expose FW control/data, parameter result fetch, and a notify stream; includes pumpEscRelayNotify() to stream status and paged result blobs. Enhances esc_config_relay with a read-all session (reads ESC_PARAM_IDS into a result blob, longer timeouts for array params, result fetch API, status codes/phases, and telemetry-throttle settle window) and integrates mutual gating with the firmware relay. Integrates both relays into init/read tick paths, adds temporary serial test hooks, and bumps NimBLE CCCD config in platformio.ini to avoid exhaustion during rebonds. Safety: sessions only run while DISARMED and host node switching/restoration is handled; buffer sizes and timeouts are bounded.
Introduce a buffered batch-write feature for ESC config relay so multiple params can be applied with a single Save+Restart and post-reboot verification. Public API added: escConfigRelayBatchBegin(), escConfigRelayBatchAdd(id,data,len), escConfigRelayRequestBatchCommit(). BLE handlers for opcodes 0x40/0x41/0x42 were added to begin, add, and commit batches. Implementation adds a staging buffer and session state, beginBatchSession(), batch tuple helpers, and new phases (BATCH_WRITE, BATCH_VERIFY) driven by escConfigRelayServiceTick() to write all staged params, persist once, restart, and then verify each param across reboot. Also integrates batch pending checks into isActive/request handling and removes some temporary serial debug/test code and prints.
Add FreeRTOS mutexes and locking to serialize OTA state mutations and NVS/settings writes to prevent races/corruption. ota_service.cpp: introduce otaStateMutex and OtaStateLock, guard command/data callbacks, checkOtaTimeout and abortOta, initialize mutex in initOtaBleService, and add explanatory comments to avoid esp_ota_abort/use-after-abort races. device_settings.cpp: add s_prefsMutex and prefsEnsureMutex, create mutex during refreshDeviceData(), and rewrite writeDeviceData() to use the low-level NVS API (nvs_open / nvs_set_* / nvs_commit) so all settings are committed in a single transaction; hold the mutex during the operation to prevent concurrent writers. sdkconfig and sdkconfig.defaults: disable TASK_WDT idle-task checks on both CPUs and add comments explaining the rationale (avoid unexpected panic reboots on a flying device); propagate corresponding config line changes. main.cpp: add note clarifying watchdog initialization behavior given the disabled idle checks. Also add necessary FreeRTOS/NVS includes where required.
8.0 is tagged for release; unified-everything-app now targets 8.1.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Brings the v8.0 release point into the 8.1 line. Notably enables OTA
app rollback (CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE / CONFIG_APP_ROLLBACK_ENABLE),
which shipped in 8.0 but had not yet landed on this branch. The app already
calls esp_ota_mark_app_valid_cancel_rollback() at the end of setup()
(src/sp140/main.cpp), so a fully-booting image marks itself valid and a
crashing OTA image rolls back automatically.

sdkconfig conflict resolved by keeping this branch's config and enabling only
the rollback flags. The WDT idle-task checks (CONFIG_*_TASK_WDT_CHECK_IDLE_TASK_*)
are intentionally left disabled here, matching this branch's prior choice
rather than v8.0's enabled state.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Extract the splash screen into a shared production builder and reuse it from the screenshot tests so the real UI is covered without tying golden images to version bumps. This also tunes dark-mode colors for battery, BLE, armed, and climb/descent indicators to preserve contrast, adds screenshot coverage for max climb and descent states, and fixes core dump task name copying to guarantee null termination.
Refactors the critical alert border from a single full-screen bordered object to four thin edge strips, reducing LVGL invalidation/flush work during flash animation. Adds `setCriticalBorderOpacity`/`getCriticalBorderOpacity` helpers, clears the non-owning `critical_border` pointer before rebuilding the main screen, and updates flash logic and screenshot tests to use the new opacity API without forced full-screen invalidation or immediate refresh calls.
Gate BMS as CONNECTED until a coherent snapshot arrives and add BMS_LINK_TIMEOUT_MS. Add bmsSnapshotCoherent() and bmsTempFrameSeen() helpers and latch first-good-state to avoid spurious pre-data alerts. Defer temp-probe sanitization until a real temp frame and log probe connection transitions. Add a 2s BMS alert grace window so boot/booting-BMS frames don't trigger alarms. Tune high-cell voltage thresholds to avoid zero-reading criticals. LVGL: initialize labels to blank/placeholders and fix charging-icon alignment. Add tests for new BMS behaviors and a Windows mkdir fix; update reference screenshots.
@zjwhitehead
zjwhitehead merged commit 6e195a4 into master Aug 6, 2026
6 of 10 checks passed
@zjwhitehead
zjwhitehead deleted the unified-everything-app branch August 6, 2026 16:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants