For developers

Build & install

Set up PlatformIO, install firmware and run the shared simulators.

View source

The firmware uses ESP-IDF through PlatformIO and a pinned Slint compiler/runtime pair. A Rust toolchain is needed for the desktop/browser simulators, not for the firmware build.

Supported hardware

Environment Native resolution Hardware
waveshare_206 410 × 502 Waveshare ESP32-S3 Touch AMOLED 2.06, CO5300 / FT3168, 32 MB flash

PlatformIO configuration is the source of truth. Do not flash a different Waveshare size or revision with this target merely because it also uses an ESP32-S3.

Prepare the tools

Install Python and PlatformIO Core, then use a terminal at the repository root. CI pins PlatformIO Core 6.2.0.

python -m pip install platformio==6.2.0
pio run
python scripts/check_sdkconfig.py --all

pio run builds all supported default_envs. The project pins Espressif platform 6.12.0 / ESP-IDF 5.5.0 and Slint mcu-v1.19.4 / 1.19.0. The Slint compiler and runtime are downloaded together with checksum verification.

The application image is .pio/build/waveshare_206/firmware.bin. The ESP project identity is derived as bike_<hardware-id>; release filenames use the PlatformIO environment name.

First USB installation

Discover the port rather than copying someone else's COM number:

pio device list
pio run -e waveshare_206 -t upload --upload-port YOUR_PORT
pio device monitor --port YOUR_PORT

Replace YOUR_PORT with the detected port, such as COM9 on Windows or /dev/ttyACM0 on Linux. If the board is not detected, use a known USB data cable and enter the board's download mode with BOOT/RESET as described by its manufacturer.

The first installation must include the matching bootloader, partition table, OTA initialization data and application. PlatformIO upload uses the configured target layout. Do not upload only an application image to a factory partition layout. After installation, verify the dashboard, touch, both orientations and the boot log before connecting a bike.

Configure an optional wired interface

BLE is the default. CAN and UART are available only when their pin pairs are defined in the target's build_flags. Choose unused, exposed GPIOs from the actual board schematic; the repository does not guess wiring.

Build flag Default / requirement
CAN_TX, CAN_RX Both required to enable CAN. Connect through an external transceiver.
CAN_BITRATE 500000; supported values 125000, 250000, 500000 and 1000000.
CAN_LOCAL_ID 254; must be unique on the vehicle CAN bus.
UART_TX, UART_RX Both required to enable UART.
UART_BAUD 115200; must match the vehicle.
BIKE_UART_PORT 1; ports 1 and 2 are supported, not the console port 0.

Add the chosen -D definitions to the hardware profile and rebuild. The interfaces then appear in Settings. If a saved interface is unavailable in the current build, the display falls back to BLE. The main motor controller is found through discovery rather than a target CAN-ID build flag.

Editor and live preview

python scripts/sync_slint_lsp.py

This downloads the pinned language server/live preview and writes the machine-specific path to ignored VS Code settings. Reload the editor after initial setup. The tracked shared settings remain portable; do not commit generated absolute tool paths.

Desktop simulator

Install a Rust toolchain, then run:

cargo run --locked --manifest-path simulator/Cargo.toml
cargo run --locked --manifest-path simulator/Cargo.toml -- 502 410
cargo run --locked --manifest-path simulator/Cargo.toml -- --wired
cargo run --locked --manifest-path simulator/Cargo.toml -- --smoke-test

The --wired demo exposes simulated CAN/UART settings. Simulators use fake bike/Wi-Fi data and never drive hardware or download firmware. The browser simulator runs the actual shared Slint UI and software renderer in WebAssembly. Application services remain browser-only mocks: connections, Wi-Fi, OTA, PIN validation and pairing do not reach hardware. Demo PINs/preferences reset on reload; the demo upstream pairing PIN is 123456. Serve the generated site over HTTP rather than opening it with file://.

Host checks

On Linux, or in WSL with a C++ compiler, CMake and Ninja:

cmake -S tests -B .cache/host-tests -G Ninja -DBIKE_SANITIZERS=ON
cmake --build .cache/host-tests
ctest --test-dir .cache/host-tests --output-on-failure

On Windows, use an installed compiler generator and omit sanitizer flags if unsupported. Headless UI checks use the shared Slint screens:

cargo run --locked --manifest-path simulator/Cargo.toml --bin transition-checks -- 410 502
cargo run --locked --manifest-path simulator/Cargo.toml --bin transition-checks -- 502 410

See contributing for choosing checks appropriate to a change and maintenance for release packaging.

Search the guides and implementation notes. Press Esc to close.