Skip to content

DisplayDriver seam: fold the bulge-exclude span into present() #345

Description

@timohueser

Context

From the 2026-07 display/FLPR architecture review (C1).

DisplayDriver::present() takes no bulge-exclude region, so the two backends diverge around the
seam instead of behind it:

  • The FLPR map plane bypasses the seam: MapDisplay::render_present (main.rs) matches on
    overlay_span and calls Ls021Flpr::present_within(exclude) on the concrete type — the one
    place the "board-agnostic" map plane touches a specific backend's inherent API.
  • The ST7789 backend can't clip at all: display/st7789.rs documents an accepted
    "dev-only-best-effort" flash — a dirty.map redraw landing during a live hold pushes clean
    rows over the bulge, blanking it until the overlay task's next ~8 ms tick.

Both problems are the same missing parameter.

Implementation plan

  1. Trait change in obc-fw-nrf54l/src/display/mod.rs:
    fn present(&mut self, exclude: Option<(u16, u16)>) -> boolexclude = Some((y0, rows))
    means "the rows [y0, y0+rows) belong to the overlay plane this frame: update the diff store
    for them (it tracks the clean fb) but do not push them". Document that contract on the trait.
  2. Hoist the shared skeleton into obc-platform: the "diff the whole frame, clip each changed
    span around the exclude interval, emit the clipped spans (+ whole-frame-minus-exclude fallback
    on span overflow)" logic currently lives only in Ls021Flpr::present_within. Move it to
    obc-platform (e.g. RowDiff::diff_clipped(fb, stride, exclude, push_span) composing the
    existing diff + clip_span), with host tests. Both backends then share it verbatim.
  3. FLPR backend (display/ls021_flpr.rs + ls021_flpr.rs): present(exclude) becomes the
    old present_within; delete the public present_within and the match overlay_span in
    MapDisplay::render_present — the map plane calls the seam method unconditionally.
  4. ST7789 backend (display/st7789.rs): present(exclude) runs the same diff_clipped,
    banding only the clipped spans — the mid-hold flash is gone. For the exclude span to be real
    on this backend, give the tft MapDisplay the input_plane handle (the FLPR variant
    already holds it) so poll_overlay returns the live span instead of hardcoded
    (false, None). Its hold_progress() can then also return the real value instead of 0.0
    (fixes the in-screen Reset-bar fill never moving on tft).
  5. Convergence: after 3–4 the two MapDisplay::render_present bodies are identical — shrink
    the cfg surface where it falls out naturally (a full MapDisplay merge is optional stretch,
    not required here).

Semantics note for ST7789: excluded rows keep their on-glass content until the overlay plane's
next bulge repaint / trailing clear (≤ 8 ms away) — exactly the FLPR discipline, and strictly
better than today's flash-then-repaint.

Verification

  • New host tests for diff_clipped: spans clipped around the exclude interval; the store is
    updated for excluded rows (a later present with no exclude does not re-push unchanged
    excluded rows); span-overflow fallback still respects the exclude.
  • Existing clip_span / rowdiff host tests pass unchanged.
  • grep shows no caller of present_within outside the backend, and no
    backend-concrete display call in the map plane.
  • On-glass FLPR: bulge charge/pop/retract during an active map redraw — no flash, trailing
    clear intact (parity with today).
  • On-glass tft: hold a button while the map is redrawing (e.g. zoom during a hold) — the
    bulge no longer blanks; the Reset screen's hold-to-confirm bar now fills.
  • All feature builds compile.

Part of epic #353.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestfirmwareOn-device firmware / board bring-upmaintainabilityReadability, structure, duplicationnrf54-portAbstraction/interface for the nRF54 firmware port

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions