12 KiB
C6 Companion Architecture Specification
Purpose
This specification defines the Trail Mate ESP32-C6 companion boundary for ESP32-P4 targets such as Tab5 and T-Display-P4.
The companion exists so the P4 product can use BLE, ESP-NOW, and later Wi-Fi surfaces without moving Trail Mate business truth onto the C6.
As of 2026-06-09, the active development slice is the first full C6 wireless facade firmware followed by external C6 flashing and P4-C6 validation. The phase is not P4-forced C6 recovery and not runtime slave OTA.
Core Rule
P4 owns meaning.
C6 owns wireless surfaces.
HostLink carries every P4-C6 message.
The C6 is not a second Trail Mate business host. It is a wireless facade and transport peer.
Ownership
P4 owns:
- LoRa, GPS, maps, storage, UI, MeshCore, Meshtastic, Team Mode, and app services.
- Business configuration, channel state, node state, message history, keys, and final team state.
- BLE/ESP-NOW/Wi-Fi runtime configuration decisions.
- The downgrade decision when the C6 is missing, unsupported, or running an incompatible protocol version.
C6 owns:
- BLE GAP/GATT surface mechanics.
- ESP-NOW send/receive mechanics.
- Wi-Fi management facade mechanics.
- Local wireless queues, connection handles, notification state, and short-term peer caches.
- HostLink session state.
- C6-local diagnostic settings that do not change Trail Mate business truth.
The first full facade firmware may implement:
- Meshtastic-compatible BLE GATT raw transport.
- MeshCore/NUS-compatible BLE GATT raw transport.
- Trail Mate private BLE GATT raw transport.
- ESP-NOW raw Team transport send/receive.
- Wi-Fi scan, STA connect/disconnect/get IP, and AP start/stop management.
- Config and diagnostic reports.
This does not grant C6 ownership of Meshtastic packets, MeshCore routing, Team membership, keys, NodeDB, messages, LoRa, GPS, maps, storage, or UI.
Forbidden C6 State
C6 firmware must not persist:
- Meshtastic channel keys.
- MeshCore private keys.
- Team keys.
- Trail Mate user identity keys.
- NodeDB.
- Message history.
- Map cache.
- LoRa configuration authority.
Any temporary key material needed by BLE or ESP-NOW must be supplied by P4 and kept in RAM unless P4 explicitly authorizes persistence.
HostLink C6 Protocol
The C6 HostLink protocol is distinct from the existing Data Exchange HostLink USB/CDC protocol.
The shared C6 wire definitions live in:
modules/core_hostlink/include/hostlink/c6/c6_protocol.h
modules/core_hostlink/include/hostlink/c6/c6_frame_codec.h
modules/core_hostlink/src/c6_frame_codec.cpp
The frame format is binary little-endian, uses magic 0x36434D54, protocol
version 1, a 20-byte header, and CRC32 over the header with the crc32 field
zeroed plus the payload. The default maximum payload is 1024 bytes.
All upper-layer messages must preserve both frame_type and channel so P4
can route BLE Meshtastic, BLE MeshCore, BLE Trail Mate private, ESP-NOW Team,
Wi-Fi, and diagnostics explicitly.
Supported feature bits are compile-time and implementation claims. Enabled
feature bits are runtime configuration results and must only be reported after
P4 sends CONFIG_SET or asks for a configuration report. P4 must not treat
requested_features as C6 capability evidence.
Phase 0 Contract
Phase 0 may provide only:
- Shared protocol definitions and codec tests.
- A P4-side C6 companion abstraction/stub.
- A C6 ESP-IDF project scaffold.
- A bootable C6 firmware shell that waits for P4.
- P4 behavior that survives a missing C6 and reports an explicit missing state.
- A
platform::ui::wireless_companiondiagnostic projection that exposesunsupported,not_started,missing,transport_pending,present, orerrorwithout making the shared UI depend on ESP-IDF C6 headers. - A diagnostics surface on C6-capable P4 targets that can show
C6 transport pendingwhile SDIO/ESP-Hosted HostLink is not implemented.
Phase 0 must not pretend that BLE, ESP-NOW, Wi-Fi, or SDIO HostLink are already operational.
Phase 1 Boundary
Phase 1 HostLink bring-up starts only when both sides have a real transport binding. Protocol definitions, HELLO/PING frame templates, and a bootable C6 firmware shell are necessary but not sufficient.
Before real SDIO or ESP-Hosted transport is bound, P4 must report:
state = transport_pending
present = false
detail = sdio_transport_not_bound
When a real SDIO probe is attempted, P4 may use a more specific pending detail:
state = transport_pending
present = false
detail = sdio_transport_probe_pending
present is reserved for a completed P4-C6 exchange:
P4 sends HELLO
C6 returns HELLO_ACK
P4 sends PING
C6 returns PONG
P4 sends CONFIG_SET
C6 returns CONFIG_REPORT
P4 records protocol, firmware, features, enabled services, service states, and
heap values from C6
Diagnostics may show locally generated HELLO/PING templates in
transport_pending, but those templates are not evidence that C6 is present.
Before HELLO_ACK is decoded, P4 must keep C6 supported_features unknown
or zero. A P4 requested_features mask is only an outbound request and must
not be projected to UI or product logic as C6 capability evidence.
The first real Phase 1 implementation uses ESP-IDF SDIO packet transport:
P4: esp_serial_slave_link over SDMMC slot 1
C6: esp_driver_sdio slave packet mode
The C6 firmware must decode and encode frames with the shared C HostLink codec.
The P4 firmware may use the C++ codec facade, but C/C++ cross-codec smoke tests
must prove that both sides compute the same CRC and preserve frame_type,
channel, seq, ack, flags, and payload bytes.
Startup must remain bounded. If SDIO probe, HELLO_ACK, or PONG fails, P4 must
continue booting the product and report either missing or error with a
specific detail. A failed probe must not block UI, GPS, SD card, LoRa, or other
P4-owned product surfaces. SDIO card probing may retry for a short bounded
window to let the C6 finish reset and slave startup, but it must not become an
unbounded board boot gate.
SDIO enumeration is only transport evidence. An SDIO card with ESP32-C6 I/O
functions and readable CCCR state does not prove that Trail Mate HostLink is
available. If ESSL function-ready or the later HELLO/PING/PONG exchange fails,
P4 must report the failure detail instead of promoting enumeration to
present.
For T-Display-P4, C6 SDIO startup runs before SD card startup because the board family uses SDMMC slot 1 for C6 and SDMMC slot 0 for the SD card. Any later SD card changes must preserve that order or explicitly implement shared SDMMC host ownership. The T-Display-P4 XL9535 IO14 C6 control follows LilyGo's SDIO examples: release high, assert low, release high before probing SDIO. For Tab5, the recorded C6 reset GPIO remains unvalidated and must not be pulsed as a recovery control.
C6 Firmware Update Boundary
There are two different update meanings and they must not be collapsed:
Runtime slave OTA:
P4 and C6 are both running compatible firmware.
The existing ESP-Hosted or HostLink transport is alive.
P4 sends a C6 image to the C6 OTA partition through that transport.
Forced recovery / esptool-style flashing:
C6 may be blank or broken.
P4 must control the C6 download, reset, and boot straps, or an external
programmer/USB path must be used.
Runtime slave OTA is allowed after Phase 1 transport is real and versioned. Forced recovery must not be promised unless the board facts prove that P4 can drive the required C6 reset/download/BOOT lines. Tab5 reset GPIO54 remains unvalidated and overlaps Grove/Port A I2C SCL, so it must not be treated as a validated C6 recovery control.
The current Phase 1 implementation does not yet implement C6 image transfer or
host_performs_slave_ota semantics. The TM_C6_FEATURE_SLAVE_OTA bit is
reserved in the protocol but must not be advertised in requested_features or
supported_features until an OTA frame sequence and image source are
implemented and validated. Product claims must distinguish:
HostLink present:
HELLO_ACK and PONG succeeded over real SDIO packet transport.
C6 runtime OTA available:
HostLink or ESP-Hosted transport is present, an image source is selected,
chunked write/verify/end semantics are implemented, and the C6 OTA partition
activation path is tested.
External First Flash Boundary
The first full C6 facade firmware is validated by external flashing.
For T-Display-P4-class hardware, the C6 UART0 pins exposed on a Qwiic-shaped connector are UART pins, not an I2C Qwiic protocol surface. External flashing requires a 3.3V USB-UART path wired to C6 UART RX/TX/GND and the board's BOOT/EN controls. ESP32-C6 enters the ROM serial bootloader when GPIO9 is held low during reset.
P4 must not promise esptool-style forced C6 flashing unless board facts prove that P4 can drive all required C6 reset, UART, and BOOT strap signals. The known T-Display-P4 schematic facts allow P4-side C6 reset control, but C6 GPIO9/BOOT is controlled by the physical boot switch and is not currently a validated P4-controlled recovery signal.
Missing SD card media does not block P4-C6 SDIO. C6 uses the C6 SDIO link; the SD card is a separate storage surface and must remain a P4-owned feature.
First Full Facade Firmware
The first full C6 facade firmware is a wireless facade, not a second product runtime.
It must:
- Start wireless surfaces only from P4 configuration.
- Preserve HostLink
frame_typeandchannelon every uplink and downlink. - Forward BLE and ESP-NOW payloads as raw bytes.
- Apply BLE pairing mode and passkey mechanics as wireless access control only.
- Report service state through
CONFIG_REPORTand diagnostics. - Keep Wi-Fi credentials in RAM unless P4 explicitly requests persistence.
- Keep the C6 app partition large enough for BLE, ESP-NOW, Wi-Fi, SDIO, and diagnostics.
It must not:
- Parse Meshtastic protobufs.
- Parse MeshCore business messages.
- Decide Team membership or final pairing state.
- Persist product keys or message history.
- Expose Wi-Fi data-plane product behavior unless a future specification grants that surface explicitly.
The current partition policy for the full facade firmware assumes 4MB C6 flash and uses a single 3MB factory app partition. This is compatible with external first flashing and intentionally does not reserve OTA slots for the current phase.
BLE advertisement payloads must stay within legacy advertising size limits. When multiple 128-bit profile services are enabled, C6 may rotate advertised service UUIDs while keeping all enabled GATT services registered.
BLE pairing mode is P4 configuration, not C6 business state. In the first full
facade firmware, P4 may request fixed PIN, random PIN, or debug no-PIN mode.
C6 may enforce encrypted/authenticated GATT access and may keep bond material
in RAM while the firmware is running, but CONFIG_BT_NIMBLE_NVS_PERSIST remains
disabled for this phase. C6 must not log the configured PIN and must not persist
BLE pairing material as product identity, Team state, MeshCore keys, or
Meshtastic channel state.
Firmware Layout
The C6 companion firmware is an in-repository peer project:
firmware/c6_companion/
It is a companion firmware project, not an app shell and not a build entrypoint
for the P4 product firmware. It may consume shared protocol headers from
modules/core_hostlink/include/hostlink/c6.
C6 build, flash, and monitor tasks must remain separate from P4 build, flash, and monitor tasks.
Review Rules
New C6 work must answer:
- Is this wireless surface mechanics, or Trail Mate business meaning?
- Does every P4-C6 byte travel through the C6 HostLink frame?
- Is the HostLink channel preserved?
- Does P4 still own configuration and downgrade decisions?
- Does C6 avoid persisting business state and secrets?
- Does the implementation report missing/unsupported states explicitly?