Skip to main content

Crate dvb_common

Crate dvb_common 

Source
Expand description

Shared primitives for the dvb_si / dvb_t2mi / dvb_bbframe family.

See individual modules for documentation: the Parse / Serialize traits every wire type implements, the MPEG-2 crc32_mpeg2 CRC, and the bcd / time codecs.

§Quick start

use dvb_common::{bcd, crc32_mpeg2};

// Binary-coded decimal (as used in MJD/BCD time fields):
assert_eq!(bcd::from_bcd_byte(0x42), Some(42));
assert_eq!(bcd::to_bcd_byte(42), Some(0x42));

// MPEG-2 CRC-32 over a section body (deterministic):
let crc = crc32_mpeg2::compute(&[0xDE, 0xAD, 0xBE, 0xEF]);
assert_eq!(crc, crc32_mpeg2::compute(&[0xDE, 0xAD, 0xBE, 0xEF]));

§Examples

Two runnable examples ship with this crate (cargo run -p dvb-common --example <name>).

§crc_and_bcd

//! Basic: the shared building blocks — MPEG-2 CRC-32 and BCD coding.
//!
//! Run with: `cargo run -p dvb-common --example crc_and_bcd`

use dvb_common::{bcd, crc32_mpeg2};

fn main() {
    // Every CRC-bearing PSI/SI section is protected by this CRC-32/MPEG-2.
    let payload = [0xDE, 0xAD, 0xBE, 0xEF];
    let crc = crc32_mpeg2::compute(&payload);
    println!("CRC-32/MPEG-2 of {payload:02X?} = {crc:#010X}");

    // Appending the CRC and re-running over the whole buffer yields 0 — the
    // standard "is this section intact?" check.
    let mut framed = payload.to_vec();
    framed.extend_from_slice(&crc.to_be_bytes());
    assert_eq!(
        crc32_mpeg2::compute(&framed),
        0,
        "CRC over data+CRC is zero"
    );
    println!(
        "verify (data+CRC) = {:#010X} (0 ⇒ intact)",
        crc32_mpeg2::compute(&framed)
    );

    // BCD is how SI encodes things like service IDs and dates.
    let byte = bcd::to_bcd_byte(42).expect("0..=99 fits one BCD byte");
    println!("42 as BCD       = {byte:#04X}");
    assert_eq!(bcd::from_bcd_byte(byte), Some(42));
}

§implement_parse_serialize

//! Advanced: implement the project's symmetric `Parse` / `Serialize` contract
//! for your own wire type, then round-trip it.
//!
//! Every wire structure in every `dvb-*` crate implements this same pair, and
//! is round-trip tested (parse → serialize → byte-identical). This shows the
//! shape you follow when adding a new type.
//!
//! Run with: `cargo run -p dvb-common --example implement_parse_serialize`

use dvb_common::{Parse, Serialize};

/// A toy 3-byte header: a 1-byte tag and a big-endian 16-bit value.
#[derive(Debug, PartialEq, Eq)]
struct Toy {
    tag: u8,
    value: u16,
}

const LEN: usize = 3;

#[derive(Debug)]
#[allow(dead_code)] // fields are surfaced via Debug in the error path
enum ToyError {
    TooShort { need: usize, have: usize },
}

impl<'a> Parse<'a> for Toy {
    type Error = ToyError;
    fn parse(bytes: &'a [u8]) -> Result<Self, Self::Error> {
        if bytes.len() < LEN {
            return Err(ToyError::TooShort {
                need: LEN,
                have: bytes.len(),
            });
        }
        Ok(Toy {
            tag: bytes[0],
            value: u16::from_be_bytes([bytes[1], bytes[2]]),
        })
    }
}

impl Serialize for Toy {
    type Error = ToyError;
    fn serialized_len(&self) -> usize {
        LEN
    }
    fn serialize_into(&self, buf: &mut [u8]) -> Result<usize, Self::Error> {
        if buf.len() < LEN {
            return Err(ToyError::TooShort {
                need: LEN,
                have: buf.len(),
            });
        }
        buf[0] = self.tag;
        buf[1..3].copy_from_slice(&self.value.to_be_bytes());
        Ok(LEN)
    }
}

fn main() {
    let wire = [0x42, 0x12, 0x34];
    let toy = Toy::parse(&wire).expect("parse");
    println!("parsed: {toy:?}");

    let back = toy.to_bytes();
    println!("re-serialized: {back:02X?}");

    // The hard project invariant: parse → serialize is byte-identical.
    assert_eq!(back, wire);
    assert_eq!(Toy::parse(&back).unwrap(), toy);
    println!("round-trip holds ✔");
}

Re-exports§

pub use traits::Parse;
pub use traits::Serialize;

Modules§

bcd
Binary-coded decimal (BCD) codec for DVB wire fields.
bits
Big-endian, MSB-first bit reader/writer for dense sub-byte wire fields.
crc32_mpeg2
CRC-32 MPEG-2 — Annex C of ETSI EN 300 468, Annex A of ETSI TS 102 773.
time
UTC time and duration codecs for DVB wire fields.
traits
Canonical Parse and Serialize traits for the DVB crate family.

Macros§

impl_spec_display
Generate a core::fmt::Display impl for a spec/field enum that delegates to an inherent fn name(&self) -> &'static str.