-
Notifications
You must be signed in to change notification settings - Fork 52
11. 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.
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.
From both the repository and the architecture notes, Trail Mate is converging toward three broad layers.
This is mainly represented by modules/*, including:
core_chatcore_gpscore_teamcore_hostlinkcore_sysui_shared
This layer holds the logic that is most valuable to reuse and least appropriate to bind directly to one platform.
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.
This is mainly represented by apps/*, including:
apps/esp_pioapps/esp_idfapps/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.
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
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.
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.
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.
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.
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/...andmaps/contour/...from SD - routes and tracks live under
/routesand/trackers -
Trail Mate Centerhandles 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
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.
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.
If the system keeps evolving, these architectural rules are especially worth protecting:
- one main repository, not multiple full platform forks
- one shared core with multiple platform shells
- platform details should not leak back into shared modules
- 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.
English
- Home
- 0. Why This Exists
- 1. Quick Start
- 2. Supported Hardware
- 3. Installation & Flashing
- 3.5 Configuration Guide
- 4. Protocols & Data
- 4.1 Reticulum, LXMF and RNode Bridge
- 5. Offline Maps
- 6. Trail Mate Center
- 7. Team Features
- 8. UI Overview
- 9. Build from Source
- 10. Codebase Overview
- 11. Architecture
- 12. Design Decisions
- 13. FAQ
- 14. Troubleshooting
- 15. Logging and Debugging
- 16. Roadmap
- 17. Contributing
- 18. License and Third-Party
- 19. GPS Setting Guide
中文
- Home (中文)
- 0. Why This Exists (中文)
- 1. Quick Start (中文)
- 2. Supported Hardware (中文)
- 3. Installation & Flashing (中文)
- 3.5 Configuration Guide (中文)
- 4. Protocols & Data (中文)
- 4.1 Reticulum, LXMF and RNode Bridge (中文)
- 5. Offline Maps (中文)
- 6. Trail Mate Center (中文)
- 7. Team Features (中文)
- 8. UI Overview (中文)
- 9. Build from Source (中文)
- 10. Codebase Overview (中文)
- 11. Architecture (中文)
- 12. Design Decisions (中文)
- 13. FAQ (中文)
- 14. Troubleshooting (中文)
- 15. Logging and Debugging (中文)
- 16. Roadmap (中文)
- 17. Contributing (中文)
- 18. License and Third-Party (中文)