Changes should preserve the separation between vehicle integrations, physical transports, local access control and UI rendering. A new board or protocol should not add board-name branches throughout shared code.
Start with a reproducible change
For a bug, describe the concrete trigger, observed behavior and expected result. Include the board environment, firmware version, integration and transport. For BLE or proxy issues, include controller and phone/app versions. Redact PINs, passwords and other credentials from logs.
Discuss substantial new hardware/protocol support before assuming undocumented wire formats. The supplied reverse-engineered protocol notes record evidence and uncertainties; keep those distinctions visible.
Repository map
| Area | Responsibility |
|---|---|
ui/ |
Shared Slint components, layout, gestures and dialogs. |
firmware/main/ |
Board drivers, runtime ownership, transports, networking and application projection. |
firmware/components/bike/ |
Portable framing, integrations, telemetry and state policies. |
simulator/ |
Desktop, browser and headless previews of the shared UI. |
tests/ |
Portable C++ checks for protocol, state and renderer-related policies. |
scripts/ |
Reproducible configuration, packaging and documentation helpers. |
docs/ |
Rider guides, architecture and maintenance documentation. |
Keep changes reviewable
- Put target capabilities, resolution and GPIOs in the PlatformIO hardware profile. Share settings through
commonrather than inheriting one board from another. - Put package-specific encoding and feature flags in its vehicle integration. Unsupported commands must be gated in both UI and command handling.
- Keep the phone proxy independent of the display's selected main-controller route.
- Invalidate old RX/TX work across connection or transport generations. Do not replay a tuning command after reconnect.
- Keep Slint ownership on the UI task. Communication callbacks should transfer bounded data, not edit UI properties.
- Preserve required third-party notices and source/binary line-ending rules.
Validate the change
Use the checks that establish the behavior you changed. Firmware changes normally need a build and SDK audit:
pio run
python scripts/check_sdkconfig.py --all
Portable protocol/state changes need host tests; see building. UI changes should be checked at 410 × 502 and 502 × 410 with the headless transition checks and actual rendered fixtures. Exercise touch/drag cancellation, safe corners and orientation as relevant.
Run cargo fmt --check --manifest-path simulator/Cargo.toml for Rust changes. C/C++ formatting uses the repository .clang-format plus declaration spacing; CI pins clang-format 23.1.0. Run python scripts/format_cpp.py to format, or add --check to verify without changes. Do not write a test that simply restates the implementation without exercising the failure or behavior that matters.
For docs, build the Pages artifact and inspect desktop and mobile layouts. The browser simulator is a demo: it must never imply that mocked controls operate a real vehicle.
Describe evidence precisely
A useful change description states the problem, resulting behavior and relevant validation. Distinguish a compiler check, host/simulator test, startup log and a real-controller acceptance test. If radio, PIN changes or wired behavior could not be tested, say so and leave the acceptance item open.
Do not claim delivered FPS from a first-frame timing or successful boot. Add reproducible performance measurements to the performance notes.
License
Project contributions use GPL-3.0-only, subject to the existing third-party notices. See LICENSE and THIRD_PARTY.md. Do not copy images, fonts or code into the repository without retaining their applicable permissions and notices.