Device-abstraction refactor: HAL + per-board folders + responsive UI
Replaces the build-flag-driven #ifdef sprawl (~30 blocks across 6 files)
with a small HAL in firmware/src/hal/ and per-board folders under
firmware/src/boards/. Shared code (main.cpp, ui.cpp, splash.cpp) no
longer contains a single `#ifdef BOARD_*` — optional features are
guarded by BoardCaps (runtime) and BOARD_HAS_* macros (compile-time,
inside the board's own files).
Why: lets community contributors port to new ESP32 + AMOLED + touch
combos by dropping in a boards/<name>/ folder + a PlatformIO env,
without touching shared files. See docs/porting/adding-a-board.md.
Highlights:
- New HAL: display_hal, touch_hal, input_hal, power_hal, imu_hal,
board_caps. Each board provides display.cpp, touch.cpp, input.cpp,
power.cpp, imu.cpp, caps.cpp, board_init.cpp + private hardware
drivers (e.g. io_expander.{h,cpp} on AMOLED-1.8).
- PlatformIO build_src_filter selects each board's folder per env.
- ui.cpp picks fonts and layout from board_caps() via compute_layout()
with screen-height breakpoints (>= 460 → large, else compact).
- splash.cpp computes CELL = min(W,H)/20 — responsive instead of two
hardcoded values.
- idle.cpp (from #24) rewired through display_hal + power_hal — no
longer depends on the deleted display_cfg.h / power.h.
- power_hal gains power_hal_is_vbus_in() for idle's
IDLE_SLEEP_WHEN_CHARGING gate.
- boards/template/ + docs/porting/{adding-a-board,hal-contract,
capability-flags}.md to bootstrap new ports.
- display_cfg.h, power.{h,cpp}, imu.{h,cpp}, io_expander.{h,cpp}
deleted from src/ root (moved into boards/<name>/ or hal/).
Verification: both `pio run -e waveshare_amoled_216` and
`pio run -e waveshare_amoled_18` succeed unchanged.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
f3ed2425bf
commit
20351212b2
@@ -0,0 +1,111 @@
|
||||
# Porting Clawdmeter to a new board
|
||||
|
||||
A board port is a folder under `firmware/src/boards/` plus a new
|
||||
`[env:...]` block in `firmware/platformio.ini`. You should never need
|
||||
to edit `firmware/src/main.cpp`, `firmware/src/ui.cpp`, or anything
|
||||
under `firmware/src/hal/`. If you find yourself wanting to, that's a
|
||||
gap in the HAL — open an issue.
|
||||
|
||||
## Hardware you need
|
||||
|
||||
At minimum:
|
||||
|
||||
- An **ESP32-S3** (other ESP32 family members may work; this is what the
|
||||
upstream firmware is tested on). OPI PSRAM is **required** — partial
|
||||
flush buffers and the splash canvas are allocated from PSRAM.
|
||||
- A QSPI **AMOLED panel** with a driver supported by
|
||||
[GFX Library for Arduino](https://github.com/moononournation/Arduino_GFX)
|
||||
(CO5300, SH8601, NV3041A, etc.). Other interfaces aren't supported yet.
|
||||
- A **touch controller** over I2C. The HAL just needs init + read; you
|
||||
can use any driver you can compile.
|
||||
- A **primary button** (typically the BOOT/GPIO 0 push button).
|
||||
|
||||
Optional:
|
||||
|
||||
- A second physical button (e.g. for HID Shift+Tab mode toggle).
|
||||
- An AXP2101 PMU for battery monitoring + a power button.
|
||||
- A QMI8658 (or compatible) IMU for automatic rotation.
|
||||
- An XCA9554 / PCA9554 IO expander if reset / enable lines are routed
|
||||
through one (the AMOLED-1.8 board does this).
|
||||
|
||||
## Step-by-step
|
||||
|
||||
1. **Copy the template folder.**
|
||||
|
||||
```bash
|
||||
cp -r firmware/src/boards/template firmware/src/boards/my_board
|
||||
```
|
||||
|
||||
2. **Fill in `boards/my_board/board.h`.** Replace every `TODO` with your
|
||||
board's pins, I2C addresses, dimensions, and capability flags. The
|
||||
capability flags drive both compile-time dead-stripping in the HAL
|
||||
implementations and runtime UI decisions via `BoardCaps`.
|
||||
|
||||
3. **Implement the per-board sources.** Each one corresponds to a HAL
|
||||
header in `firmware/src/hal/`. Look at one of the reference ports for
|
||||
a worked example:
|
||||
|
||||
| File | Reference port (start here) |
|
||||
|-------------------|----------------------------------------------------------------|
|
||||
| `display.cpp` | `boards/waveshare_amoled_216/display.cpp` (with CPU rotation) or `_18/display.cpp` (no rotation) |
|
||||
| `touch.cpp` | `_216/touch.cpp` (library-based) or `_18/touch.cpp` (vendored I2C reader) |
|
||||
| `input.cpp` | `_216/input.cpp` (two buttons) or `_18/input.cpp` (one button) |
|
||||
| `power.cpp` | `_216/power.cpp` (PMU IRQ) or `_18/power.cpp` (PMU + IO expander button) |
|
||||
| `imu.cpp` | `_216/imu.cpp` (full rotation) or `_18/imu.cpp` (init-only stub) |
|
||||
| `caps.cpp` | either reference — just edit the struct literal |
|
||||
| `board_init.cpp` | `_216/board_init.cpp` (no expander) or `_18/board_init.cpp` (with expander) |
|
||||
|
||||
4. **Add a PlatformIO env.** In `firmware/platformio.ini`, copy one of
|
||||
the existing `[env:waveshare_amoled_*]` blocks and adjust:
|
||||
|
||||
```ini
|
||||
[env:my_board]
|
||||
; ... platform / board / framework as before ...
|
||||
|
||||
build_src_filter =
|
||||
+<*>
|
||||
-<boards/>
|
||||
+<boards/my_board/> ; the only line you change here
|
||||
|
||||
build_flags =
|
||||
-DBOARD_MY_BOARD ; identity-only — the shared code never
|
||||
; branches on this; per-board code may
|
||||
```
|
||||
|
||||
If your panel needs flash > 4 MB (extra animations, larger fonts),
|
||||
copy the `board_upload.*` block from the AMOLED-1.8 env.
|
||||
|
||||
5. **Build.** `pio run -d firmware -e my_board`. The link step is the
|
||||
real verification — any missing HAL symbol or duplicated definition
|
||||
shows up here.
|
||||
|
||||
6. **Flash + smoke test.** The first boot should land on the splash
|
||||
screen. If it doesn't, check `pio device monitor` for HAL init
|
||||
messages — every reference port logs OK / failure for display, touch,
|
||||
PMU, IMU during `setup()`.
|
||||
|
||||
7. **Visual QA.** `./screenshot.sh out.png` over USB serial captures
|
||||
the live framebuffer at the active resolution. The UI is responsive
|
||||
(see [hal-contract.md](hal-contract.md) for breakpoint details);
|
||||
most ports will look acceptable out of the box. If your screen size
|
||||
doesn't match an existing breakpoint, you may want to add one to
|
||||
`compute_layout()` in `firmware/src/ui.cpp`.
|
||||
|
||||
## Common pitfalls
|
||||
|
||||
- **Display stays black, no panic.** Usually one of: OPI PSRAM not enabled
|
||||
in platformio.ini (check `board_build.arduino.memory_type = qio_opi`);
|
||||
IO expander not released before `gfx->begin()` (run `io_expander_init()`
|
||||
from `board_init()`); GFX library version too old to know about your
|
||||
panel chip.
|
||||
- **Touch reads zeros / wrong coordinates.** The HAL hands LVGL whatever
|
||||
the controller reports — apply any axis swap / mirror inside your
|
||||
`touch.cpp`. CST9220 needs `setSwapXY(true)` + `setMirrorXY(true,
|
||||
false)` on the AMOLED-2.16 board; your controller will likely differ.
|
||||
- **GPL warning when picking a touch driver.** The project intentionally
|
||||
avoids copyleft dependencies. If the only available library is GPL,
|
||||
vendor a minimal I2C reader instead (see `_18/touch.cpp`).
|
||||
- **Both boards built fine but one runs and the other doesn't.** The
|
||||
build_src_filter is per-env — re-check you copied the existing env
|
||||
blocks correctly and the `-<boards/>` then `+<boards/your_one/>`
|
||||
ordering is right (filters apply in declaration order).
|
||||
Reference in New Issue
Block a user