culvert-async
Async typed access to the HDMI 2.1 SCDC register map.
culvert-async is the async companion to culvert: culvert's Scdc client with
async fn methods over an hdmi_hal_async::scdc::ScdcTransport. The register map is
culvert's — every address, bit and protocol check comes from culvert::codec, and
culvert-async only performs the reads and writes — so the sync and async clients always
agree. All register types and error types are re-exported from culvert so callers do not
need both crates.
Usage
Wrap your async transport in Scdc and await typed methods:
use ;
let mut scdc = new;
// Version negotiation
let sink_ver = scdc.read_sink_version.await?;
scdc.write_source_version.await?;
// Enable TMDS scrambling
scdc.write_tmds_config.await?;
// Wait for the sink to be ready, then request an FRL rate
let flags = scdc.read_status_flags.await?;
if flags.flt_ready
// On FLT_Update, read the pattern each lane requests, then acknowledge the flag
let updates = scdc.read_update_flags.await?;
if updates.flt_update
// Read per-lane character error counts
let ced = scdc.read_ced.await?;
if let Some = ced.lane0
To use culvert-async as the SCDC backend for plumbob-async's link training state
machine, enable the plumbob-async feature:
Scdc<T> then implements plumbob_async::ScdcClient automatically.
Training through Scdc<T> can run on a multi-threaded executor when the transport is
Send and Sync and its futures are Send. Code generic over the transport and the PHY
proves that with the Send twins: bound the transport by SendScdcTransport
(re-exported here) and the PHY by SendHdmiPhy (re-exported by plumbob-async), and by the
twins alone. Code bounded by plumbob-async's SendScdcClient needs a small wrapper; see
doc/architecture.md ("Send futures"), which also shows where the
poll interval and a deadline belong (not in the transport).
Register coverage
| Register group | Addresses | Methods |
|---|---|---|
| Version | 0x01–0x02 | read_sink_version, write_source_version |
| Update flags | 0x10 | read_update_flags, clear_update_flags |
| TMDS / scrambling | 0x20–0x21 | write_tmds_config, read_scrambler_status |
| FRL config | 0x30–0x31 | write_config_0, write_frl_config |
| Source test configuration | 0x35 | read_source_test_config |
| Status flags | 0x40 | read_status_flags |
| LTP requests | 0x41–0x42 | read_ltp_requests |
| Character Error Detection | 0x50–0x55, 0x57–0x58 | read_ced |
| RS correction count | 0x59–0x5A | read_rs_correction |
The register map is culvert's (culvert::codec); its sources are described in culvert's
architecture document, and registers not yet covered in culvert's roadmap.
Features
| Feature | Default | Description |
|---|---|---|
plumbob-async |
no | Implements plumbob_async::ScdcClient for Scdc<T> |
no_std
culvert-async is #![no_std] throughout. All output types are stack-allocated; no
allocator is required in any configuration.
Stack position
flowchart LR
dt["display-types"]
hal["hdmi-hal / hdmi-hal-async"]
culvert["culvert"]
culvert_async["culvert-async"]
plumbob_async["plumbob-async"]
integration["integration layer (planned)"]
dt --> culvert
hal --> culvert
hal --> culvert_async
culvert --> culvert_async
culvert_async -->|"implements ScdcClient"| plumbob_async
plumbob_async -.->|"will implement LinkTrainer"| integration
plumbob-async does not depend on culvert-async; culvert-async depends on plumbob-async
only with the optional plumbob-async feature, which makes Scdc<T> implement
plumbob_async::ScdcClient. Any crate that implements ScdcClient is substitutable.
Out of scope
- Sync API — callers on sync transports use
culvertdirectly. - Link training state machine — the sequencing of FRL training belongs in
plumbob-async.culvert-asyncprovides the register operations; the state machine decides when to call them. - PHY configuration —
HdmiPhyoperations are the link training layer's concern. - I²C / DDC transport — platform backends implement
hdmi_hal_async::scdc::ScdcTransport.culvert-asyncnever touches I²C directly.
Documentation
doc/setup.md— build, test, coverage, and example commandsdoc/architecture.md— role, scope, the client, theplumbob-asyncfeature, and design principlesdoc/testing.md— testing strategy, transport harness, and CI expectationsdoc/roadmap.md— deferred register groups and planned API surfaces
Verifying releases
Releases are built on GitHub Actions and attested with
SLSA Build Level 2 provenance (from 0.2.0). To verify a release
.crate against its signed provenance, install the
GitHub CLI and run:
The attested .crate is attached to each
GitHub release.
Releases from 0.2.0 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:
# see .version.trustpub_data
0.1.0 was uploaded by hand with an API token; it carries no provenance and has no GitHub release.
License
Licensed under the Mozilla Public License 2.0.