Part of Ashlar — a display connection stack in Rust, HDMI 2.1 first: from EDID parsing through mode negotiation to FRL link training.
display-types · piaf · concordance · cartouche · culvert · plumbob · hdmi-hal · hdmi-hal-i2c-dev
Hardware abstraction traits for the HDMI stack.
hdmi-hal defines the behavioral contracts between protocol logic and hardware. It is a
traits-only crate: no implementations live here. Every trait expresses an I/O boundary
that multiple crates in the stack need to cross in a compatible way — raw SCDC register
access over DDC/I²C, and HDMI 2.1 transmitter PHY control (what FRL link training needs:
rate, training patterns, output mode, scrambling and TxFFE levels). Further PHY
configuration is on the roadmap.
cargo add hdmi-halImplement a trait against your hardware backend:
use hdmi_hal::scdc::ScdcTransport;
struct MyI2cBackend { /* ... */ }
impl ScdcTransport for MyI2cBackend {
type Error = MyError;
fn read(&self, reg: u8) -> Result<u8, MyError> { /* ... */ }
fn write(&mut self, reg: u8, value: u8) -> Result<(), MyError> { /* ... */ }
// One DDC transaction for the whole buffer (a length limit, if any, of at least
// 16 bytes). A backend that cannot burst-read
// implements this with `hdmi_hal::scdc::read_block_bytewise(self, reg, buf)` and
// says so: its reads are then one register at a time.
fn read_block(&self, reg: u8, buf: &mut [u8]) -> Result<(), MyError> { /* ... */ }
}Accept a trait bound in consumer code:
use hdmi_hal::scdc::ScdcTransport;
fn configure_frl<T: ScdcTransport>(transport: &mut T) -> Result<(), T::Error> {
transport.write(0x31, 0x01)?; // initiate FRL
Ok(())
}For a complete worked example of both traits with a simulated backend, see
examples/simulate.
hdmi-hal sits between the platform backends and the protocol logic crates. It has no
dependency on the rest of the stack; protocol crates depend on it, not the reverse.
flowchart LR
dt["display-types"]
hal["hdmi-hal"]
culvert["culvert"]
plumbob["plumbob"]
be["platform backends (e.g. hdmi-hal-i2c-dev)"]
dt --> hal
hal --> culvert
hal --> plumbob
hal --> be
Async variants of both traits live in the companion crate hdmi-hal-async, following
the same split as embedded-hal / embedded-hal-async.
- Protocol logic — SCDC register semantics, typed register wrappers, and the FRL
link training state machine belong in the crates that consume
ScdcTransport. - Implementations — concrete platform backends (kernel I²C drivers, simulator harnesses, test doubles) live in the crates that use these traits.
- PHY vendor backends — hardware-specific register sequences belong in platform
crates that implement
HdmiPhy. - CEC or eARC protocol logic — only the wire-access primitive will belong here; protocol state machines are in their own crates.
doc/architecture.md— trait surfaces, design principles, async story, and stack positiondoc/roadmap.md— planned features and future work
Releases are built on GitHub Actions and attested with
SLSA Build Level 2 provenance (from 0.4.0). To verify a release
.crate against its signed provenance, install the
GitHub CLI and run:
gh attestation verify hdmi-hal-X.Y.Z.crate --repo ashlar-display/hdmi-halReleases from before the repository moved to the ashlar-display organization (0.4.0 to
0.5.1) were attested under its previous owner, and verify against it:
gh attestation verify hdmi-hal-X.Y.Z.crate --owner DracoWhitefire \
--signer-repo DracoWhitefire/hdmi-halThe attested .crate is attached to each
GitHub release.
Releases after 0.4.1 are uploaded through crates.io trusted publishing: the publish workflow obtains a short-lived token via OpenID Connect instead of using a stored API token. crates.io can also reject uploads made with an API token for this crate; the badge above shows whether that setting is on. Each version's publishing details, including the workflow run and commit, are available from the crates.io API:
curl -A "your-tool (contact)" https://crates.io/api/v1/crates/hdmi-hal/X.Y.Z
# see .version.trustpub_dataVersions up to 0.3.0 were uploaded with an API token (0.1.0 by hand, 0.2.0 and 0.3.0 from CI) and carry no provenance; 0.4.0 and 0.4.1 carry provenance but were also uploaded with an API token.
Licensed under the Mozilla Public License 2.0.