Expand description
Pure-Rust EN 50221 DVB Common Interface runtime — the driver loop over
the dvb_ci codecs.
dvb_ci is no_std and owns the wire layer (TPDU / SPDU / APDU
parse+serialize, CA_PMT building, CI Plus extensions). This crate adds the
runtime: device I/O, the TPDU poll loop, SPDU session management, and the
per-resource state machines that together drive a physical CAM, per
ETSI EN 50221 and TS 101 699.
§Design
The whole runtime is written against the CaDevice trait (the
hardware-abstraction boundary), so it runs against either:
- a real Linux CA device (
/dev/dvb/adapterN/caM, thelinuxfeature), or - the in-memory
MockCaDevice, which makes the state machines testable without hardware and enables differential testing against an external reference (drive both with the same scripted mock CAM and assert the emittedwrite/ioctl byte sequences match).
Implemented from the EN 50221 specification.
§What’s implemented
-
Transport (TPDU, §A.4):
Create_T_Chandshake, empty-T_Data_Lastpoll cadence,T_SBdata-available →T_RCV,T_Data_More/Lastreassembly, reply timeout. -
Session (SPDU, §7.2): session table;
open_session_request/response, host-initiatedcreate_session,close_session;session_number+ APDU routing. -
Resources (§8): Resource Manager handshake (profile exchange →
Notification::CamReady, then opens module resources), application_information, conditional_access (ca_pmt/ca_pmt_reply), date_time (MJD + BCD), and mmi (surfaces module menus/enquiries asNotification::Mmi). -
Descramble helper:
Driver::descramble/HostRequest::Descrambleruns the fullca_pmtquery → reply → ok_descrambling sequence, CAID-filtered to the CAM’sca_info. -
Devices: the in-memory
MockCaDevice+MockCiDataDevice, and the Linux/dev/dvb/adapterN/caM(control) +ciM(TS data-plane) devices behind thelinuxfeature. The data plane (CiDataDevice) carries the scrambled-in / descrambled-out TS for separate-CI hardware. -
Diagnostics:
RecordingCaDevicecaptures the link in both directions;trace::decode_frame/decode_logannotate a capture (TPDU → SPDU → APDU) for live-CAM debugging.
§Managed CAS layer (#763)
A single-slot CA orchestration layer sits on top of the raw ca_pmt /
ca_pmt_reply surface, fed parsed dvb-si structs (never raw bytes):
Driver::add_service/remove_service— build + send theca_pmtfrom advb_si::tables::pmt::PmtSectionand track the slot’s active service set (multi-programme list-management handled internally).Driver::set_cat— feed the CAT; the EMM-PID set becomes the CAT’s EMM PIDs ∩ the CAM’s advertisedca_infoCAIDs.Driver::emm_pids/descramble_pids/ca_pids/required_pids— the PIDs to route into theci0data plane (EMM ∪ ES ∪ ECM ∪ PCR =required_pids).Driver::set_requery_interval— a periodicca_pmtre-query (cmd_id = query) so a card entitled after the initialca_pmtstill refreshes; a per-programme status transition surfaces as an edge-triggeredNotification::Entitlement.CaDescrambler— a turnkey wrapper that additionally owns theci0CiDataDevice:feed_tsfilters a scrambled TS chunk torequired_pids()and returns the descrambled TS. OneCaDescrambler= one CI slot = one TS path (multi-tuner ⇒ one per slot).
§ci-probe
With the linux feature this crate also builds a ci-probe binary that
discovers and engages an installed CAM: ci-probe list / info /
descramble <pmt> / mmi, with --trace for an annotated link dump.
Roadmap: the host_control resource and a differential test harness against
an external reference.
§Example
Drive a CAM with the MockCaDevice — the same Driver API works against
the real Linux device:
use std::time::Duration;
use dvb_ci_runtime::{Driver, HotPlug, MockCaDevice, Notification};
use dvb_ci_runtime::dvb_ci::tpdu::tags;
// Script a module that accepts the transport connection.
let dev = MockCaDevice::new([vec![tags::C_T_C_REPLY, 0x01, 0x01]]);
let mut driver = Driver::new(dev);
driver.init()?; // reset + open the transport connection
// Pump the device: reads frames when readable, otherwise advances the
// EN 50221 poll cadence by the timeout.
for _ in 0..4 {
driver.pump(Duration::from_millis(100))?;
}
// Host-facing events (CamReady, ApplicationInfo, CaInfo, Mmi, HotPlug, …)
// surface here — either poll-drained:
for note in driver.take_notifications() {
match note {
Notification::CamReady => { /* now safe to send a ca_pmt */ }
other => { let _ = other; }
}
}
// …or, since this crate is sync/sans-IO (no channels), delivered by a
// closure callback per pump — `pump_with` for every notification, or
// `pump_hotplug` to react only to CAM/card hot-plug transitions:
driver.pump_hotplug(Duration::from_millis(100), |hp| match hp {
HotPlug::CamPresent => { /* CAM (re)inserted — re-send any pending ca_pmt */ }
HotPlug::CamRemoved => { /* CAM removed — stop descrambling */ }
_ => {}
})?;Re-exports§
pub use dataplane::CiDataDevice;pub use dataplane::MockCiDataDevice;pub use dataplane::TS_PACKET_LEN;pub use descrambler::CaDescrambler;pub use device::CaDevice;pub use device::DeviceOp;pub use device::LinkEvent;pub use device::MockCaDevice;pub use device::RecordingCaDevice;pub use device::SlotInfo;pub use driver::Driver;pub use event::Action;pub use event::Event;pub use event::HostRequest;pub use event::HotPlug;pub use event::Notification;pub use linux::LinuxCaDevice;pub use linux::LinuxCiDataDevice;pub use managed::CaError;pub use managed::ManagedCa;pub use managed::ManagedService;pub use managed::REQUERY_DEFAULT;pub use stack::CiStack;pub use dvb_ci;
Modules§
- dataplane
- The CI TS data-plane device:
CiDataDevice. - descrambler
- Turnkey CAS descrambler — #763 Layer 2.
- device
- The hardware-abstraction boundary:
CaDevice. - driver
- The driver — the one place I/O happens. It pumps a
CaDeviceagainst the sans-IOCiStack: reads frames in, executes the stack’sActions (writes/ioctls) out, tracks the requested poll timer, and collectsNotifications for the host application. - event
- The sans-IO event/action model.
- linux
- Linux
/dev/dvb/adapterN/caMCaDeviceimplementation (thelinuxfeature). - managed
- Managed CAS-layer state (#763) — the
Driver’s owned view of the slot’s active descrambled-service set. - resource
- The resource layer — application-layer state machines (ETSI EN 50221 §8), one per resource, driven by the session layer’s APDUs.
- session
- SPDU session layer — a sans-IO mechanism over the transport layer (ETSI EN 50221 §7.2).
- stack
- The CI protocol stack — composes the transport + session layers (and, as they land, the resource state machines) into one sans-IO core.
- trace
- Human-readable decoding of CI link frames, for diagnosing live-CAM exchanges (e.g. issue #337).
- transport
- TPDU transport layer — a sans-IO state machine for the single transport connection per CI slot (ETSI EN 50221 §A.4).