fix(test): configure clangd and clang-tidy for native test tree (#3)
* fix(test): configure clangd and clang-tidy for native test tree
- Generate compile_commands.json from pio run -e native -t compiledb
so clangd resolves src/ headers in test files without errors.
- Fix .clangd PathMatch regex (relative path, not absolute) and add
-I.pio/build/native/unity_config so unity_config.h resolves.
- Remove overly broad Remove: -I* that was stripping all added paths.
- Add -Wno-format-security and UnusedIncludes: None to test block.
- Add test/.clang-tidy that inherits the root config and:
- Allows test_* functions to use snake_case (FunctionIgnoredRegexp)
- Disables cert-err33-c, cert-dcl50-cpp,
cppcoreguidelines-pro-type-cstyle-cast,
bugprone-argument-comment, bugprone-misplaced-widening-cast,
bugprone-implicit-widening-of-multiplication-result,
misc-unused-using-decls — all false positives in test context.
- Add /* intentionally empty */ comment to all empty setUp()/tearDown()
bodies (28 files) to suppress SonarLint c:S1186.
- Fix test_vault_task: change relative include ../../src/vault/vault_task.h
to vault/vault_task.h (consistent with all other test files; -Isrc
already in compile flags).
- Reorganise test/ into a module-mirroring subtree layout:
test/ble/, test/crypto/, test/hal/, test/ota/, test/platform/,
test/states/, test/totp/, test/ui/, test/vault/, test/web/
(old flat directories removed).
- Add sonar-project.properties exclusion e4: suppress c:S1186 on
test/**/*.cpp at SonarCloud level.
All 468 native unit tests pass (pio test -e native).
* fix(clangd): add -DESP_PLATFORM to global CompileFlags
All Kleidos targets are ESP32/ESP32-S3 (framework = espidf), so
ESP_PLATFORM is always defined at compile time. Without this flag in
the clangd config, the language server was activating #else branches
inside #ifdef ESP_PLATFORM blocks, hiding device code and showing
false diagnostics for src/ files.
The test/** fragment already has Remove: -DESP_PLATFORM, so native
unit-test files continue to compile without the flag.
* revert(clangd): remove incorrect -DESP_PLATFORM from global CompileFlags
Adding -DESP_PLATFORM globally caused 'too many errors' in src/ files
because compile_commands.json was generated from the native env and
lacked all ESP-IDF/Xtensa include paths.
The correct fix is to generate compile_commands.json from a device env:
./scripts/generate_compiledb.sh sticks3
This populates the DB with proper -DESP_PLATFORM and all IDF includes
for every src/ translation unit. The symlink at the project root then
points clangd to the right compilation context.
Make the PIN timing-arc fill animate smoothly again
The dial filled in ~10 coarse blocks because each full repaint took ~300 ms, so
the loop only sampled the continuous fill ~3 times/second. The cost was the AA
ring rendering: isqrt64 ran a Newton-Raphson with a 64-bit divide per iteration
(the ESP32-S3 has no hardware 64-bit divide) once per pixel, over the whole dial
box, twice. The fill VALUE was always correct — only the redraw cadence was slow.
- isqrt64: replace the division-based Newton form with a division-free binary
(digit-by-digit) integer sqrt — only shifts/adds/compares, identical result.
- fillAnnulusSweepAA / strokeCircleAA: gate the per-pixel sqrt behind a cheap d^2
band test, so the inner hole and box corners (most of a thin ring's box) are
skipped without a sqrt; no change to the coverage math.
- Add fillAnnulusGaugeAA: paint the dim track and the bright progress wedge in
one band pass (distance/angle computed once), and use it in the PIN dial.
Net: the dial repaint drops from ~300 ms to ~67 ms, so the arc now fills ~44
frames over a 3 s sweep (was ~10) — a smooth growing bar. Visually identical.
Add a DEBUG_SERIAL_BUTTONS trace at the timing-arc output (elapsed/fill%/digit
per rendered frame) for on-device QA, and native boundary tests asserting the
exact digit slices (e.g. T=3000: 299 ms -> 0, 300 ms -> 1, and the 9 -> 0 wrap).
Refine the PIN dial: A-gauge ring, single moving marker, B-Clear footer
Owner-approved dial refinement (#41). Replaces the busy original (0-9 ring + 10
ticks + double-circle outline all competing) with variant A's clean single-band
gauge that collars the hero digit, and reintroduces orientation without the
overload:
- RING: one thick same-tone gauge (track + bright swept fill, dim outlines),
not the thin double circle.
- NUMERALS: 0-9 around the ring, SMALL, stratified by presence — active digit
cyan-bold, the rest muted — so only one numeral claims attention.
- MARKERS: a single highlight on the marker the sweep is currently at (the
active digit), reverting to dim as it passes (new activeMarker prop) — not the
cumulative 0..digit lit before.
- FOOTER: BtnB physically clears, so the action bar reads 'A Hold / B Clear'
(new PinClear i18n string); the misleading 'B SHAKE' and the redundant
'Shake to clear' gesture-hint line are gone (shake still clears, no on-screen
hint needed now that B Clear is shown).
Adds 3 pin_dial tests (transient marker: only-active, none-at-idle, follows the
value). HW-verified on the StickS3 (MAC by id); text already renders through the
AA atlases. Mockup: docs/design/mockups/pin-entry-aplus.svg.
feat(ui): add in-house QR encoder + scalable drawQr component
Self-contained ISO/IEC 18004 byte-mode QR encoder (no vendoring, no deps):
RS ECC over GF(256), block interleaving, function-pattern placement, the 8
mask patterns scored by the 4 penalty rules, and format/version info. Auto
smallest version (1..10, documented RAM cap), ECC L/M/Q/H, malloc-free.
Fix the data-placement bug from the partial work: the zigzag direction was a
running toggle; the correct rule is per-column ((right & 2) == 0) XOR
(col < 6), and the byte-aligned padding / two-copy format-info mapping were
off. The encoder now matches a trusted generator (segno) module-for-module on
pinned known-answer vectors (HELLO WORLD v1-M mask4, a URL v2-M mask2) and
decodes across versions/ECC levels.
Add ui::drawQr (scalable, quiet zone, theme tokens) + ui::qr::wifi escaped
payload builder, and replace the admin WiFi-QR finder-pattern placeholder with
a real scannable QR. Tests: encoder (known-answer + auto-version + caps),
payload escaping, component rendering.
feat(ui): add in-house QR encoder + scalable drawQr component
Self-contained ISO/IEC 18004 byte-mode QR encoder (no vendoring, no deps):
RS ECC over GF(256), block interleaving, function-pattern placement, the 8
mask patterns scored by the 4 penalty rules, and format/version info. Auto
smallest version (1..10, documented RAM cap), ECC L/M/Q/H, malloc-free.
Fix the data-placement bug from the partial work: the zigzag direction was a
running toggle; the correct rule is per-column ((right & 2) == 0) XOR
(col < 6), and the byte-aligned padding / two-copy format-info mapping were
off. The encoder now matches a trusted generator (segno) module-for-module on
pinned known-answer vectors (HELLO WORLD v1-M mask4, a URL v2-M mask2) and
decodes across versions/ECC levels.
Add ui::drawQr (scalable, quiet zone, theme tokens) + ui::qr::wifi escaped
payload builder, and replace the admin WiFi-QR finder-pattern placeholder with
a real scannable QR. Tests: encoder (known-answer + auto-version + caps),
payload escaping, component rendering.
feat(ui): add Phase 2 stateless reference components (ActionBar/Header/BrandMark/StatusChip)
First catalog components on the Canvas + DeviceProfile foundation
(plan/ui-library-modular-reimpl.md Phase 2). Stateless: props in ->
draw via Canvas -> return, reading the orthogonal DeviceProfile for
device adaptation. Purely additive — no existing screen/state/widget/
Canvas changed.
- ActionBar (action_bar_component): affordance-driven footer hints. The
same ActionBarProps render the device-correct presentation picked from
the profile capabilities — 2-button A/B, 3-button A/B/C, CoreInk dial
^/O/v, keyboard key hints, touch bare labels. Mono1/e-paper path uses a
top divider rule + cell inversion instead of the SURFACE fill + ACCENT
hold-fill.
- Header (header_component): title + subtitle + right-packed status
cluster (battery %, BLE, WiFi, lock). Density/orientation-aware via
LayoutContext; Mono1 uses a bottom divider rule, ink-only tokens.
- BrandMark (brand_mark_component): credential brand badge. Reuses the
brands::findBrand/drawBrand registry+atlas on device; falls back to a
deterministic per-domain letter tile (host-testable). Mono1 outlines.
- StatusChip (status_chip_component): self-sizing status pill using
radius.pill (clamped), token color per ChipStyle, knockout/outline text.
Tests (host, RecordingCanvas): 30 new cases across 4 suites, incl. the
per-affordance ActionBar assertions (2btn/3btn/dial/keyboard/touch), the
Mono1 branches, brand letter-fallback + deterministic color, and chip
sizing/geometry. Shared per-variant DeviceProfile factories in
test/support/device_profiles.h.
Verified: fleet 5/5 -Werror (sticks3/gray/cardputer/tdeck/m5core_ink),
native 720/720 (+30), pio check 3 pre-existing HIGH only, all guards +
pre-commit pass.
fix(test): configure clangd and clang-tidy for native test tree (#3)
* fix(test): configure clangd and clang-tidy for native test tree
- Generate compile_commands.json from pio run -e native -t compiledb
so clangd resolves src/ headers in test files without errors.
- Fix .clangd PathMatch regex (relative path, not absolute) and add
-I.pio/build/native/unity_config so unity_config.h resolves.
- Remove overly broad Remove: -I* that was stripping all added paths.
- Add -Wno-format-security and UnusedIncludes: None to test block.
- Add test/.clang-tidy that inherits the root config and:
- Allows test_* functions to use snake_case (FunctionIgnoredRegexp)
- Disables cert-err33-c, cert-dcl50-cpp,
cppcoreguidelines-pro-type-cstyle-cast,
bugprone-argument-comment, bugprone-misplaced-widening-cast,
bugprone-implicit-widening-of-multiplication-result,
misc-unused-using-decls — all false positives in test context.
- Add /* intentionally empty */ comment to all empty setUp()/tearDown()
bodies (28 files) to suppress SonarLint c:S1186.
- Fix test_vault_task: change relative include ../../src/vault/vault_task.h
to vault/vault_task.h (consistent with all other test files; -Isrc
already in compile flags).
- Reorganise test/ into a module-mirroring subtree layout:
test/ble/, test/crypto/, test/hal/, test/ota/, test/platform/,
test/states/, test/totp/, test/ui/, test/vault/, test/web/
(old flat directories removed).
- Add sonar-project.properties exclusion e4: suppress c:S1186 on
test/**/*.cpp at SonarCloud level.
All 468 native unit tests pass (pio test -e native).
* fix(clangd): add -DESP_PLATFORM to global CompileFlags
All Kleidos targets are ESP32/ESP32-S3 (framework = espidf), so
ESP_PLATFORM is always defined at compile time. Without this flag in
the clangd config, the language server was activating #else branches
inside #ifdef ESP_PLATFORM blocks, hiding device code and showing
false diagnostics for src/ files.
The test/** fragment already has Remove: -DESP_PLATFORM, so native
unit-test files continue to compile without the flag.
* revert(clangd): remove incorrect -DESP_PLATFORM from global CompileFlags
Adding -DESP_PLATFORM globally caused 'too many errors' in src/ files
because compile_commands.json was generated from the native env and
lacked all ESP-IDF/Xtensa include paths.
The correct fix is to generate compile_commands.json from a device env:
./scripts/generate_compiledb.sh sticks3
This populates the DB with proper -DESP_PLATFORM and all IDF includes
for every src/ translation unit. The symlink at the project root then
points clangd to the right compilation context.