Ear geometry and output mapping¶
This component contains bounded, allocation-free geometry helpers and descriptor validation. It has no device, settings, renderer or ESP-IDF dependencies. Board profiles supply immutable mapped geometry and physical routing separately.
EAR_TOPOLOGY_LEGACY retains the existing open-path contract. outer_pixels is
the long-edge length. Logical order starts at the short-edge baseline,
ascends count - outer_pixels samples, then descends the long edge. Zero or the
complete count selects a straight strip.
Each split edge independently spans base to tip, including duplicated tip samples
and one-pixel edges. Empty and one-pixel ears retain their existing behaviour.
Legacy XY describes a canonical outline, not measured physical positions.
EAR_TOPOLOGY_MAPPED supports up to 69 logical pixels per ear. Each pixel has
normalised XY, height, region and path arc. Ordered path indices define logical
traversal independently of array/wire order. Closed paths use arc coordinates in
[0, 1) and at least three pixels; open paths allow [0, 1]. Arc coordinates
increase strictly in path order. Paths have distinct region identities and cover
each non-centre pixel once. At most one centre pixel is allowed, with arc zero
and no path membership or base/tip flags. Optional explicit base/tip flags identify
regional subsets. Optional per-path height bounds let ear_topology_path_height()
span that region without stretching its physical XY; 0/0 retains global height.
Empty mapped ears are valid.
Call ear_topology_valid() before publishing a descriptor. The pixel lookup checks
index/pointer bounds but assumes that mapped values have already been validated.
Keep the descriptor and referenced tables alive and immutable while consumers use
them; no per-frame validation, allocation, file parsing or hardware access is needed.
The board-owned output map assigns each logical pixel a physical chain and offset.
Validate both ears together with ear_output_map_valid() so cross-ear collisions
are rejected too. Four chains, with up to 69 pixels each, are supported by this
data contract. Unmapped fixed physical tails are permitted; the eventual output
owner must still clear them and account for their idle draw. Physical reversal is
represented in routing, never by changing artistic geometry.
The legacy renderer uses the extracted legacy height/path helpers. V2 imports PCB-derived 48+20+1 geometry, with a revision/hash identity and startup validation against the separate four-chain map. Mapped effect adapters consume these descriptors with the same canonical short-edge-first convention. The original host circular fixture stays synthetic and is not physical acceptance.
The versioned layout/export contract also describes saved-direction migration and the independent electrical map.