Files
clawdmeter/docs/porting/capability-flags.md
T
tobby168andClaude Opus 4.7 20351212b2 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>
2026-05-20 18:27:24 -07:00

2.3 KiB

Capability flags

Each board's board.h declares these. They're consumed in two places:

  1. caps.cpp — copies them into the BoardCaps instance so shared code (ui.cpp, main.cpp) can query them at runtime via board_caps().
  2. The per-board source files#if BOARD_HAS_* lets the linker dead-strip entire functions on boards that don't need them.

Keep the two in sync. The pattern in caps.cpp does this for you:

.button_count = (uint8_t)(1 + BOARD_HAS_SECONDARY_BUTTON),
.has_rotation = (bool)BOARD_HAS_ROTATION,

The flags

Macro Default What it gates
BOARD_HAS_SECONDARY_BUTTON 0 A second physical button (HID Shift+Tab on the reference ports). caps.button_count = 1 + this. UI uses caps.button_count >= 2 to decide whether to poll/handle the secondary button — there is no #ifdef in shared code.
BOARD_HAS_ROTATION 0 IMU-driven auto-rotation via CPU strip transformation in display_hal_draw_bitmap. When 0, display_hal_tick is a no-op and the rotation buffer in display.cpp doesn't get allocated.
BOARD_HAS_IMU 0 Whether the accelerometer is populated and initialized. Distinct from BOARD_HAS_ROTATION — the AMOLED-1.8 has the QMI8658 (so HAS_IMU=1) but the kit's enclosure mounts the panel at a fixed orientation, so rotation is off.
BOARD_HAS_BATTERY 0 Whether PMU battery measurement is meaningful on this board. UI hides the battery indicator when false.
BOARD_HAS_IO_EXPANDER 0 Whether an IO expander gates display / touch reset lines. Doesn't directly gate any code path — but signals to the porter that board_init() must release the expander before display_hal_init().

Future capabilities

Add a new flag when:

  • A shared-code decision currently uses if (caps.has_<thing>) and you want to extend it (e.g. add BOARD_HAS_HAPTIC for vibration feedback).
  • A per-board file conditionally compiles a block of code (e.g. audio amp init under BOARD_HAS_AUDIO).

Don't add a flag for a one-off detail. If only one board cares about it and shared code never queries it, leave it as a constant in that board's board.h and use it only in that board's .cpp files.