Skip to content

Generate the crossing animation instead of storing 2 KB of bitmaps - #119

Merged
TheAngryRaven merged 1 commit into
BETAfrom
claude/generate-crossing-pattern
Aug 3, 2026
Merged

Generate the crossing animation instead of storing 2 KB of bitmaps#119
TheAngryRaven merged 1 commit into
BETAfrom
claude/generate-crossing-pattern

Conversation

@TheAngryRaven

Copy link
Copy Markdown
Owner

Summary

Reclaims 2,048 bytes of flash on an image currently sitting at 99.4% of the OTA cap.

The two "calculating" frames drawn while the timer is inside a crossing zone were hand-stored 1 KB PROGMEM bitmaps. Decoding them shows both are pure block patterns — eight 16×16 px cells, confined to the odd 16 px row bands, with the two frames offset by one cell so alternating them scrolls sideways. Spending 2 KB of flash to express that is a bad trade, so they are now emitted by a new host-tested crossing_pattern unit and drawn with eight fillRect() calls.

The bird splash is untouched — that's real artwork, not a pattern, and stays a bitmap.

Equivalence is proven, not assumed: crossing_pattern_test.cpp pins the original 2 KB as goldens, rasterizes the generated rectangles into a 1024-byte 1bpp buffer, and memcmps all 128×64 pixels of both frames. If the geometry ever drifts, the test fails.

One thing worth knowing, since it surprised me: the original bitmaps only ever lit the odd row bands — the top and third 16 px bands were entirely blank in both frames, so it's a two-row block strip rather than a full checkerboard. I reproduced that exactly rather than "fixing" it. If it was meant to be a full checkerboard, that's now a one-character change (cy = 1; cy < rows; cy += 2cy = 0; cy < rows; cy++ with the phase folded in) plus a golden update — say the word.

Type of change

  • Bug fix (no user-visible behavior change beyond the fix)
  • New feature / behavior
  • Refactor (no behavior change)
  • Tests only
  • CI / tooling / docs
  • Breaking change (track files, log format, BLE protocol, or a removed mode)

How it was verified

  • Host unit tests pass (ctest --test-dir tests/build) — 297 cases / 4,269 assertions, 0 failed, including the two golden byte-identity proofs
  • clang-tidy clean — deferred to CI
  • Compiles for the XIAO nRF52840 Sense — deferred to CI (the flash delta will show in the size report)
  • Tested on real hardware — the golden test makes the raster provably identical, but a glance at the crossing animation on-device is still worth it
  • Simulator: full native suite green (6/6 — boot soak, determinism, goldens, both lap oracles, two-session carryover); it compiles the real display_pages.ino, so the new draw path is exercised there.

Checklist

  • CHANGELOG.md updated under [Unreleased] (if user-visible)
  • ARCHITECTURE.md / CLAUDE.md updated (if a module or interface changed) — new pure-unit row, images.h description
  • New testable logic has a matching test in tests/
  • Branch is focused

Related issues

Follow-on from the flash-budget work in #116 / plan 0004 — every KB counts until the staging region goes away.

🤖 Generated with Claude Code

https://claude.ai/code/session_01HnTP6BdA9xjLR5hSWE9frb


Generated by Claude Code

The two 'calculating' frames were hand-stored 1 KB PROGMEM bitmaps, but
decoding them shows both are pure block patterns: eight 16x16 px cells
confined to the odd 16 px row bands, with the two frames offset by one
cell so alternating them scrolls sideways. Storing 2048 bytes of flash
to say that is a bad trade.

They are now emitted by the new host-tested crossing_pattern unit and
drawn with fillRect(). Equivalence is proven, not assumed: the original
2 KB is pinned as goldens in crossing_pattern_test.cpp, which rasterizes
the generated rectangles and memcmps all 128x64 pixels of both frames.
The bird splash is untouched - it is real artwork, not a pattern.

Reclaims 2,048 B of flash on an image that sits at 99.4% of the OTA cap.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HnTP6BdA9xjLR5hSWE9frb
@github-actions

github-actions Bot commented Aug 3, 2026

Copy link
Copy Markdown

Coverage — host-testable units

📂 Overall coverage

Metric Coverage
Lines 🟢 837/847 (98.8%)
Functions 🟢 89/89 (100.0%)
Branches 🟢 677/743 (91.1%)

📄 File coverage

File Lines Functions Branches
BirdsEye/camera_fsm.cpp 🟢 222/230 (96.5%) 🟢 20/20 (100.0%) 🟡 126/144 (87.5%)
BirdsEye/crc32.cpp 🟢 30/30 (100.0%) 🟢 4/4 (100.0%) 🟢 24/24 (100.0%)
BirdsEye/crossing_pattern.cpp 🟢 15/15 (100.0%) 🟢 1/1 (100.0%) 🟢 12/12 (100.0%)
BirdsEye/dovex_header.cpp 🟢 106/107 (99.1%) 🟢 7/7 (100.0%) 🔴 62/88 (70.5%)
BirdsEye/filename_validator.cpp 🟢 14/14 (100.0%) 🟢 1/1 (100.0%) 🟢 30/30 (100.0%)
BirdsEye/gps_stats.cpp 🟢 25/25 (100.0%) 🟢 3/3 (100.0%) 🟢 8/8 (100.0%)
BirdsEye/gps_status_page.cpp 🟢 25/25 (100.0%) 🟢 3/3 (100.0%) 🟢 24/24 (100.0%)
BirdsEye/gps_time.cpp 🟢 45/45 (100.0%) 🟢 6/6 (100.0%) 🟢 30/32 (93.8%)
BirdsEye/gps_validation.cpp 🟢 24/24 (100.0%) 🟢 2/2 (100.0%) 🟢 66/66 (100.0%)
BirdsEye/haversine.cpp 🟢 8/8 (100.0%) 🟢 1/1 (100.0%) ⚫ 0/0 (0.0%)
BirdsEye/insta360_protocol.cpp 🟢 140/140 (100.0%) 🟢 16/16 (100.0%) 🟡 86/98 (87.8%)
BirdsEye/lap_format.cpp 🟢 18/18 (100.0%) 🟢 1/1 (100.0%) 🟢 9/9 (100.0%)
BirdsEye/sat_bars.cpp 🟢 33/33 (100.0%) 🟢 2/2 (100.0%) 🟢 51/54 (94.4%)
BirdsEye/sd_access_policy.cpp 🟢 9/9 (100.0%) 🟢 3/3 (100.0%) 🟢 18/18 (100.0%)
BirdsEye/sd_format_page.cpp 🟢 25/25 (100.0%) 🟢 3/3 (100.0%) 🟢 25/26 (96.2%)
BirdsEye/sensoregg_protocol.cpp 🟢 44/45 (97.8%) 🟢 7/7 (100.0%) 🟢 33/34 (97.1%)
BirdsEye/sprint_select.cpp 🟢 25/25 (100.0%) 🟢 4/4 (100.0%) 🟢 46/48 (95.8%)
BirdsEye/tach_filter.cpp 🟢 15/15 (100.0%) 🟢 3/3 (100.0%) 🟡 7/8 (87.5%)
BirdsEye/wake_cause.cpp 🟢 14/14 (100.0%) 🟢 2/2 (100.0%) 🟢 20/20 (100.0%)

@TheAngryRaven
TheAngryRaven merged commit 31660bf into BETA Aug 3, 2026
8 checks passed
TheAngryRaven added a commit that referenced this pull request Aug 3, 2026
…ster

perf: generate the crossing animation instead of storing 2 KB of bitmaps (backport of #119)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants