Files
trail-mate/docs/engineering/linux-phone-runtime.md
T
Trail Mate Dev 6e613e382e Add CM0 Linux support and share device services across platforms
Compose the CM0 fullscreen application and standard Debian package, align the
Cardputer Zero shell, and share protocol, configuration, audio and storage
services with embedded targets through existing platform seams.

Add the paginated on-device TMAP creator using Center's published producer,
private workspace recovery and direct keyboard shortcuts. Preserve unfinished
management work behind its existing opt-in capability.

Include native, ARM and shared-core regression fixtures, integration records,
packaging helpers and dependency/license updates. Keep local build trees,
device credentials, produced packages and validation logs outside version control.

Validation before integration: ESP stack hygiene, Reticulum scope guard, staged
whitespace checks and GitNexus scope audit. Prior device/build evidence and
remaining hardware/package boundaries are recorded in the acceptance documents.
2026-10-29 10:29:29 +08:00

6.2 KiB

Linux phone protocol and worker runtime

The Linux application service now owns LinuxPhoneRuntime when its composition opts into BLE support. The generic LVGL desktop and default Cardputer compositions opt in; other compositions keep their explicit support policy. Requested enablement is persisted separately from readiness. isBleEnabled() projects successful GATT and advertising registration rather than the requested flag.

The runtime reuses the existing MeshtasticPhoneSession and MeshCorePhoneCore. LinuxPhoneFacade maps their application port to LinuxAppServices, shared config snapshot helpers, ChatService, ContactService and the mesh adapter's optional MeshCore BLE backend. It has no dependency on the legacy UI facade or LVGL. Text sends use ChatService, including its normal store and failure handling. Missing backends return failure rather than synthetic keys or radio success.

Ownership

Application configuration, contacts, shared phone sessions and chat observations remain on the application thread. One worker owns BlueZ discovery, registration, D-Bus callbacks and notification delivery. It does not read a mutable AppConfig or execute domain methods directly.

PhoneDispatchQueue permits at most 16 pending worker requests. Application ticks process at most eight entries per pump. A request that has not started within two seconds is cancelled and cannot mutate state on a later tick. Once an operation has started, its caller retains captured storage until completion. Exceptions return failure. Shutdown cancels queued work before joining the worker, so a callback cannot wait for a UI tick that will never occur.

Incoming text and data are copied from ChatService observations. The phone never polls the radio input queue a second time or removes data belonging to another consumer. The phone's data fan-out has 16 slots and drops the newest observation when full. Disconnect resets its sessions, cached frames and subscription state.

Notifications remain owned by the shared session adapter until transport accepts the complete frame. A token identifies each pending frame/counter generation. After delivery the worker retries acknowledgement without resending the frame if application ticks temporarily pause. Stale acknowledgements cannot remove a newer frame. A failed synchronous notification can still be recovered by a normal FromRadio read. FromRadioSync is explicitly optional and defaults off, matching the ESP production transport.

Composition and capability

LinuxPhoneRuntime derives its controller MAC from the dynamically selected controller address, never from a node number. Controller selection supports a full address or one unambiguous compatible controller. The service options own the selector, advertisement name and optional private bus address.

The active application protocol must match the phone protocol. Reticulum is the product default; requesting BLE does not advertise a misleading Meshtastic service in that mode. MeshCore additionally requires an actual backend public identity. The native mesh worker does not yet expose IMeshCoreBleBackend, so that phone service remains unavailable until the backend port is completed. Transport registration tests for NUS do not override that gate.

Application startup creates the opted-in runtime, normal service ticks update its desired state and pump domain requests, and shutdown destroys it before radio and storage teardown. Changing options invalidates published readiness immediately; registration results from older configuration generations are ignored.

Shutdown flushes already-pending configuration changes before returning. This also preserves an explicit BLE-off change made immediately before exiting; it does not create a save request when none exists. The CM0 cross-package dependency list now includes GIO's libglib2.0-0t64 owner and BlueZ. On the validation device those are GLib 2.84.4 and BlueZ 5.82.

Verification and remaining work

The host application-owned integration test passed a real private D-Bus exchange through BluezPhoneGatt, its worker, the dispatch queue, shared Meshtastic session and actual Linux services. It covered config handshake, changing owner names, draining responses, durable reopen, protocol-requested Device1 disconnect, disabling and shutdown connection cleanup. Reopen verified that BLE stayed off. The protocol test also covered per-protocol node filtering and notification retry ownership. Queue deadline, cancellation, owning-thread and exception checks passed, including AddressSanitizer and UndefinedBehaviorSanitizer for the queue helper. The seven new phone/BlueZ implementation and integration-test translation units also passed an instrumented host run with AddressSanitizer, UndefinedBehaviorSanitizer and leak detection. Existing application-service/core archive objects were linked into that run without rebuilding those older objects with instrumentation. The final native application and full regression targets were rebuilt and all 107 CTest cases passed after the lifecycle/clock follow-up. CM0 passed the armhf protocol, application-owned private-bus runtime, dispatch and GATT tests. Tests isolate settings, cache and SD roots and select an absent radio endpoint, so these do not perform RF peer validation. Both real BlueZ transport registration probes also passed and ActiveInstances returned to zero.

This is not yet a claim of complete phone interoperability. Pairing-agent and Bluetooth/module configuration policy, native MeshCore backend operations and phone-to-radio end-to-end coverage remain. The native clock port now performs the system call and propagates authorization failure; unprivileged clock policy remains a deployment prerequisite. The SDL and compact entrypoints now own graceful application re-execution.

The current CM0 alpha deb has SHA-256 defe319b4abe2e123455654731520bcedb794e5703797e15dcfe979b18d81845. It was installed, passed package-file verification, rendered the P4 UX at 1232 x 568 and exited through compositor-confirmed fullscreen/focused Alt+F4 with code 0 in 0.649 seconds. The prior package was retained as a verified rollback artifact. This package carries the runtime binding and the explicitly incomplete phone-feature status, not a complete phone interoperability claim.