Skip to content

11. Architecture

liu weikai edited this page Jul 16, 2026 · 3 revisions

Architecture

Language: English. Chinese version: 11. Architecture (中文)

Trail Mate architecture serves a defined product: an independent MCU terminal close to a decentralized phone. Anonymous operation, decentralization, offline operation, and TAK are architectural constraints that platform adapters may not redefine. Multiple hardware forms, protocol roles, and application shells must preserve that boundary.

What The Current Architecture Is Trying To Solve

According to docs/ARCHITECTURE.md, the project now has to live with several realities at once:

  • an existing Arduino and PlatformIO line
  • an active ESP-IDF large-screen line
  • reserved structural room for future Linux paths
  • historical risk of creating a second complete source tree

If boundaries are not made explicit, every new platform multiplies the maintenance cost. The central architectural goal is therefore not abstract elegance. It is avoiding multiple near-duplicate codebases.

Current Layering Direction

From both the repository and the architecture notes, Trail Mate is converging toward three broad layers.

Shared business layer

This is mainly represented by modules/*, including:

  • core_chat
  • core_gps
  • core_team
  • core_hostlink
  • core_sys
  • ui_shared

This layer holds the logic that is most valuable to reuse and least appropriate to bind directly to one platform.

Platform adaptation layer

This is mainly represented by platform/*, including:

  • platform/esp/...
  • platform/nrf52/...
  • platform/linux/...

This layer connects the shared business logic to concrete platform capabilities such as BLE, LoRa, GPS hardware, storage, displays, input, and clock behavior.

Application shell layer

This is mainly represented by apps/*, including:

  • apps/esp_pio
  • apps/esp_idf
  • apps/gat562_mesh_evb_pro

This layer is responsible for startup, composition, target selection, and board-specific assembly. It should not regrow large amounts of duplicated business logic.

Why The Project Is Split This Way

Trail Mate’s real problem was never “we need one more abstract interface”. It was “the same chat, map, Team, and HostLink logic should not be rewritten separately inside every platform tree”.

The direct goals of the split are:

  • avoid cloning a full app tree for every platform
  • keep protocol, map, Team, and HostLink logic shared
  • keep board differences concentrated in board and platform layers
  • let future Linux or other targets reuse the same core logic

Protocol Adaptation Layer

One of the most important architectural decisions on the protocol side is the separation between UI and concrete protocol adapters.

The system uses IMeshAdapter as the common interface, and ProtocolFactory instantiates the concrete adapter based on current configuration. The main protocol roles currently documented for users are:

  • Meshtastic
  • MeshCore
  • Reticulum with LXMF
  • RNode/KISS HostLink capability

The product protocols are Meshtastic, MeshCore, and Reticulum. Reticulum interfaces and propagation policy load from SD configuration. RNode/KISS is a modem capability in an explicitly enabled external-host HostLink runtime, not a fourth protocol.

This structure produces several direct benefits:

  • the UI does not need to know which protocol implementation it is talking to
  • the system can choose one protocol cleanly before runtime starts
  • there is no need for runtime auto-detection or mixed-protocol operation

That is not a lack of ambition. It is a deliberate choice for clearer boundaries and simpler troubleshooting.

Device Adaptation Layer

Trail Mate does not run on one board only, so board adaptation has to be treated as a first-class architectural concern.

The current pattern is:

  • boards/<target>/ stores board facts and board runtime
  • variants/<target>/ stores PlatformIO environment differences
  • shared UI and business logic decide visibility through capability gating

This makes it possible to support:

  • keyboard-first handhelds
  • constrained monochrome devices
  • large touch-screen terminals

without duplicating the entire product logic for each form factor.

UI Layer

Trail Mate’s UI is not just a cosmetic top layer. Architecturally it is already split into at least two forms:

  • ui_shared: shared pages and shared startup or menu shell
  • ui_mono_128x64: dedicated UI runtime for monochrome small-screen targets

This shows that the project is not insisting on “one identical UI everywhere”. It is allowing reasonable branches on top of a shared information structure. Without that, a constrained device like GAT562 would either be forced into a touch-oriented shell it cannot use, or require a fully separate product fork.

Data And State Management

Configuration and state are not supposed to be scattered in ad-hoc page callbacks.

Examples include:

  • AppConfig, which carries protocol, GPS, map, privacy, and part of the network defaults
  • the settings pages, which operate through shared state and persistence interfaces
  • HostLink, which has its own protocol model and shared data structures
  • Team, which has its own domain model and port separation

This matters because UI changes should not casually redefine protocol semantics or state boundaries.

Map Resource Architecture

Architecturally, maps are treated as “external resources plus device-side reading”, not as assets compiled into the firmware image. The structure is explicit:

  • the device reads maps/base/... and maps/contour/... from SD
  • routes and tracks live under /routes and /trackers
  • Trail Mate Center handles the parts of caching, export, and resource preparation that fit better on desktop

The benefits are straightforward:

  • the firmware does not turn into a map-making tool
  • the device-side renderer stays simpler
  • the desktop tool can evolve separately without polluting the embedded runtime

Companion Tooling And The Device

Trail Mate Center is not part of the firmware binary, but it is not external to the system boundary either. Architecturally it is the desktop tooling layer responsible for:

  • HostLink connectivity and observation of device-side data
  • offline map preparation
  • raw-frame and event troubleshooting
  • message and situational replay

It belongs to the same workflow, even though it lives in a separate repository.

Transitional Areas That Still Exist

The architecture notes are honest that the project is still in transition. That means the repository still contains:

  • coexistence of the historical src/ tree and newer module boundaries
  • areas where platform-specific logic is not fully extracted yet
  • local mixed zones introduced during newer platform bring-up

So the current architecture should be read as an ongoing convergence effort rather than as a perfectly finished greenfield model.

The Most Important Boundaries To Preserve

If the system keeps evolving, these architectural rules are especially worth protecting:

  1. one main repository, not multiple full platform forks
  2. one shared core with multiple platform shells
  3. platform details should not leak back into shared modules
  4. new hardware should reuse existing protocol, map, Team, and HostLink logic whenever possible

Trail Mate’s maturity depends less on how neat the code looks in isolation and more on whether it can keep adding new boards and shells without splitting back into several drifting systems.

Clone this wiki locally