use alloc::vec::Vec;
use dvb_common::bits::{BitReader, BitWriter};
use dvb_common::{Parse, Serialize};
use super::enums::{
GuardInterval, L1CodeRate, L1FecType, L1Modulation, PaprReduction, PaprReductionV0,
PaprReductionVn, PilotPattern, T2Version, TxInputStreamType,
};
use crate::payload::fef_null::S1Field;
pub const L1PRE_BITS: usize = 168;
pub const L1PRE_BYTES: usize = L1PRE_BITS / 8; pub const L1PRE_CRC_BYTES: usize = 4;
pub const L1PRE_WITH_CRC_BYTES: usize = L1PRE_BYTES + L1PRE_CRC_BYTES;
const TYPE_BITS: u32 = 8;
const BWT_EXT_BITS: u32 = 1;
const S1_BITS: u32 = 3;
const S2_BITS: u32 = 4;
const L1_REPETITION_FLAG_BITS: u32 = 1;
const GUARD_INTERVAL_BITS: u32 = 3;
const PAPR_BITS: u32 = 4;
const L1_MOD_BITS: u32 = 4;
const L1_COD_BITS: u32 = 2;
const L1_FEC_TYPE_BITS: u32 = 2;
const L1_POST_SIZE_BITS: u32 = 18;
const L1_POST_INFO_SIZE_BITS: u32 = 18;
const PILOT_PATTERN_BITS: u32 = 4;
const TX_ID_AVAILABILITY_BITS: u32 = 8;
const CELL_ID_BITS: u32 = 16;
const NETWORK_ID_BITS: u32 = 16;
const T2_SYSTEM_ID_BITS: u32 = 16;
const NUM_T2_FRAMES_BITS: u32 = 8;
const NUM_DATA_SYMBOLS_BITS: u32 = 12;
const REGEN_FLAG_BITS: u32 = 3;
const L1_POST_EXTENSION_BITS: u32 = 1;
const NUM_RF_BITS: u32 = 3;
const CURRENT_RF_IDX_BITS: u32 = 3;
const T2_VERSION_BITS: u32 = 4;
const L1_POST_SCRAMBLED_BITS: u32 = 1;
const T2_BASE_LITE_BITS: u32 = 1;
const RESERVED_BITS: u32 = 4;
const _: () = assert!(
(TYPE_BITS
+ BWT_EXT_BITS
+ S1_BITS
+ S2_BITS
+ L1_REPETITION_FLAG_BITS
+ GUARD_INTERVAL_BITS
+ PAPR_BITS
+ L1_MOD_BITS
+ L1_COD_BITS
+ L1_FEC_TYPE_BITS
+ L1_POST_SIZE_BITS
+ L1_POST_INFO_SIZE_BITS
+ PILOT_PATTERN_BITS
+ TX_ID_AVAILABILITY_BITS
+ CELL_ID_BITS
+ NETWORK_ID_BITS
+ T2_SYSTEM_ID_BITS
+ NUM_T2_FRAMES_BITS
+ NUM_DATA_SYMBOLS_BITS
+ REGEN_FLAG_BITS
+ L1_POST_EXTENSION_BITS
+ NUM_RF_BITS
+ CURRENT_RF_IDX_BITS
+ T2_VERSION_BITS
+ L1_POST_SCRAMBLED_BITS
+ T2_BASE_LITE_BITS
+ RESERVED_BITS) as usize
== L1PRE_BITS
);
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
#[non_exhaustive]
pub struct L1Pre {
pub type_: TxInputStreamType,
pub bwt_ext: bool,
pub s1: S1Field,
pub s2: u8,
pub l1_repetition_flag: bool,
pub guard_interval: GuardInterval,
pub papr: u8,
pub l1_mod: L1Modulation,
pub l1_cod: L1CodeRate,
pub l1_fec_type: L1FecType,
pub l1_post_size: u32,
pub l1_post_info_size: u32,
pub pilot_pattern: PilotPattern,
pub tx_id_availability: u8,
pub cell_id: u16,
pub network_id: u16,
pub t2_system_id: u16,
pub num_t2_frames: u8,
pub num_data_symbols: u16,
pub regen_flag: u8,
pub l1_post_extension: bool,
pub num_rf: u8,
pub current_rf_idx: u8,
pub t2_version: T2Version,
pub l1_post_scrambled: bool,
pub t2_base_lite: bool,
pub reserved: u8,
}
impl L1Pre {
#[must_use]
pub fn papr_reduction(&self) -> PaprReduction {
if self.t2_version == T2Version::V1_1_1 {
PaprReduction::V0(PaprReductionV0::from_u8(self.papr))
} else {
PaprReduction::Vn(PaprReductionVn::from_u8(self.papr))
}
}
#[must_use]
pub fn crc32(&self) -> u32 {
let bytes = self.to_bytes();
dvb_common::crc32_mpeg2::compute(&bytes)
}
#[must_use]
pub fn to_bytes(&self) -> [u8; L1PRE_BYTES] {
let mut buf = [0u8; L1PRE_BYTES];
self.serialize_into(&mut buf)
.expect("L1Pre::to_bytes: buffer too small");
buf
}
pub fn parse_with_crc(bytes: &[u8]) -> crate::error::Result<L1Pre> {
if bytes.len() < L1PRE_WITH_CRC_BYTES {
return Err(crate::Error::BufferTooShort {
need: L1PRE_WITH_CRC_BYTES,
have: bytes.len(),
what: "L1Pre with CRC",
});
}
let pre = L1Pre::parse(&bytes[..L1PRE_BYTES])?;
let expected = u32::from_be_bytes([
bytes[L1PRE_BYTES],
bytes[L1PRE_BYTES + 1],
bytes[L1PRE_BYTES + 2],
bytes[L1PRE_BYTES + 3],
]);
let computed = pre.crc32();
if computed != expected {
return Err(crate::Error::CrcMismatch { computed, expected });
}
Ok(pre)
}
#[must_use]
pub fn serialize_with_crc(&self) -> Vec<u8> {
let mut out = Vec::with_capacity(L1PRE_WITH_CRC_BYTES);
out.extend_from_slice(&self.to_bytes());
out.extend_from_slice(&self.crc32().to_be_bytes());
out
}
}
impl<'a> Parse<'a> for L1Pre {
type Error = crate::error::Error;
fn parse(bytes: &'a [u8]) -> crate::error::Result<Self> {
if bytes.len() < L1PRE_BYTES {
return Err(crate::Error::BufferTooShort {
need: L1PRE_BYTES,
have: bytes.len(),
what: "L1Pre",
});
}
let mut r = BitReader::new(&bytes[..L1PRE_BYTES]);
let type_ = TxInputStreamType::from_u8(r.read_bits(TYPE_BITS)? as u8);
let bwt_ext = r.read_bits(BWT_EXT_BITS)? != 0;
let s1_raw = r.read_bits(S1_BITS)? as u8;
let s1 = S1Field::try_from(s1_raw).unwrap_or(S1Field::V7);
let s2 = r.read_bits(S2_BITS)? as u8;
let l1_repetition_flag = r.read_bits(L1_REPETITION_FLAG_BITS)? != 0;
let guard_interval = GuardInterval::from_u8(r.read_bits(GUARD_INTERVAL_BITS)? as u8);
let papr = r.read_bits(PAPR_BITS)? as u8;
let l1_mod = L1Modulation::from_u8(r.read_bits(L1_MOD_BITS)? as u8);
let l1_cod = L1CodeRate::from_u8(r.read_bits(L1_COD_BITS)? as u8);
let l1_fec_type = L1FecType::from_u8(r.read_bits(L1_FEC_TYPE_BITS)? as u8);
let l1_post_size = r.read_bits(L1_POST_SIZE_BITS)? as u32;
let l1_post_info_size = r.read_bits(L1_POST_INFO_SIZE_BITS)? as u32;
let pilot_pattern = PilotPattern::from_u8(r.read_bits(PILOT_PATTERN_BITS)? as u8);
let tx_id_availability = r.read_bits(TX_ID_AVAILABILITY_BITS)? as u8;
let cell_id = r.read_bits(CELL_ID_BITS)? as u16;
let network_id = r.read_bits(NETWORK_ID_BITS)? as u16;
let t2_system_id = r.read_bits(T2_SYSTEM_ID_BITS)? as u16;
let num_t2_frames = r.read_bits(NUM_T2_FRAMES_BITS)? as u8;
let num_data_symbols = r.read_bits(NUM_DATA_SYMBOLS_BITS)? as u16;
let regen_flag = r.read_bits(REGEN_FLAG_BITS)? as u8;
let l1_post_extension = r.read_bits(L1_POST_EXTENSION_BITS)? != 0;
let num_rf = r.read_bits(NUM_RF_BITS)? as u8;
let current_rf_idx = r.read_bits(CURRENT_RF_IDX_BITS)? as u8;
let t2_version = T2Version::from_u8(r.read_bits(T2_VERSION_BITS)? as u8);
let l1_post_scrambled = r.read_bits(L1_POST_SCRAMBLED_BITS)? != 0;
let t2_base_lite = r.read_bits(T2_BASE_LITE_BITS)? != 0;
let reserved = r.read_bits(RESERVED_BITS)? as u8;
debug_assert_eq!(r.bits_read(), L1PRE_BITS);
Ok(L1Pre {
type_,
bwt_ext,
s1,
s2,
l1_repetition_flag,
guard_interval,
papr,
l1_mod,
l1_cod,
l1_fec_type,
l1_post_size,
l1_post_info_size,
pilot_pattern,
tx_id_availability,
cell_id,
network_id,
t2_system_id,
num_t2_frames,
num_data_symbols,
regen_flag,
l1_post_extension,
num_rf,
current_rf_idx,
t2_version,
l1_post_scrambled,
t2_base_lite,
reserved,
})
}
}
impl Serialize for L1Pre {
type Error = crate::error::Error;
fn serialized_len(&self) -> usize {
L1PRE_BYTES
}
fn serialize_into(&self, buf: &mut [u8]) -> crate::error::Result<usize> {
if buf.len() < L1PRE_BYTES {
return Err(crate::Error::OutputBufferTooSmall {
need: L1PRE_BYTES,
have: buf.len(),
});
}
buf[..L1PRE_BYTES].fill(0);
let mut w = BitWriter::new(&mut buf[..L1PRE_BYTES]);
w.write_bits(u64::from(self.type_.to_u8()), TYPE_BITS)?;
w.write_bits(u64::from(self.bwt_ext), BWT_EXT_BITS)?;
w.write_bits(u64::from(u8::from(self.s1)), S1_BITS)?;
w.write_bits(u64::from(self.s2), S2_BITS)?;
w.write_bits(u64::from(self.l1_repetition_flag), L1_REPETITION_FLAG_BITS)?;
w.write_bits(u64::from(self.guard_interval.to_u8()), GUARD_INTERVAL_BITS)?;
w.write_bits(u64::from(self.papr), PAPR_BITS)?;
w.write_bits(u64::from(self.l1_mod.to_u8()), L1_MOD_BITS)?;
w.write_bits(u64::from(self.l1_cod.to_u8()), L1_COD_BITS)?;
w.write_bits(u64::from(self.l1_fec_type.to_u8()), L1_FEC_TYPE_BITS)?;
w.write_bits(u64::from(self.l1_post_size), L1_POST_SIZE_BITS)?;
w.write_bits(u64::from(self.l1_post_info_size), L1_POST_INFO_SIZE_BITS)?;
w.write_bits(u64::from(self.pilot_pattern.to_u8()), PILOT_PATTERN_BITS)?;
w.write_bits(u64::from(self.tx_id_availability), TX_ID_AVAILABILITY_BITS)?;
w.write_bits(u64::from(self.cell_id), CELL_ID_BITS)?;
w.write_bits(u64::from(self.network_id), NETWORK_ID_BITS)?;
w.write_bits(u64::from(self.t2_system_id), T2_SYSTEM_ID_BITS)?;
w.write_bits(u64::from(self.num_t2_frames), NUM_T2_FRAMES_BITS)?;
w.write_bits(u64::from(self.num_data_symbols), NUM_DATA_SYMBOLS_BITS)?;
w.write_bits(u64::from(self.regen_flag), REGEN_FLAG_BITS)?;
w.write_bits(u64::from(self.l1_post_extension), L1_POST_EXTENSION_BITS)?;
w.write_bits(u64::from(self.num_rf), NUM_RF_BITS)?;
w.write_bits(u64::from(self.current_rf_idx), CURRENT_RF_IDX_BITS)?;
w.write_bits(u64::from(self.t2_version.to_u8()), T2_VERSION_BITS)?;
w.write_bits(u64::from(self.l1_post_scrambled), L1_POST_SCRAMBLED_BITS)?;
w.write_bits(u64::from(self.t2_base_lite), T2_BASE_LITE_BITS)?;
w.write_bits(u64::from(self.reserved), RESERVED_BITS)?;
debug_assert_eq!(w.bits_written(), L1PRE_BITS);
Ok(L1PRE_BYTES)
}
}
#[cfg(test)]
mod tests {
use super::*;
use dvb_common::Parse;
fn synthetic_pre() -> L1Pre {
L1Pre {
type_: TxInputStreamType::TsOnly,
bwt_ext: false,
s1: S1Field::V0,
s2: 0b0100,
l1_repetition_flag: false,
guard_interval: GuardInterval::G1_8,
papr: 0,
l1_mod: L1Modulation::Qam16,
l1_cod: L1CodeRate::R1_2,
l1_fec_type: L1FecType::Ldpc16K,
l1_post_size: 376,
l1_post_info_size: 318,
pilot_pattern: PilotPattern::Pp3,
tx_id_availability: 0,
cell_id: 0x3003,
network_id: 0x3003,
t2_system_id: 0x3003,
num_t2_frames: 2,
num_data_symbols: 41,
regen_flag: 0,
l1_post_extension: false,
num_rf: 1,
current_rf_idx: 0,
t2_version: T2Version::V1_3_1,
l1_post_scrambled: false,
t2_base_lite: false,
reserved: 0,
}
}
#[test]
fn round_trip_parse_serialize() {
let pre = synthetic_pre();
let mut buf = [0u8; L1PRE_BYTES];
pre.serialize_into(&mut buf).unwrap();
let parsed = L1Pre::parse(&buf).unwrap();
assert_eq!(pre, parsed);
}
#[test]
fn serialize_parse_byte_identical() {
let pre = synthetic_pre();
let mut buf1 = [0u8; L1PRE_BYTES];
pre.serialize_into(&mut buf1).unwrap();
let parsed = L1Pre::parse(&buf1).unwrap();
let mut buf2 = [0u8; L1PRE_BYTES];
parsed.serialize_into(&mut buf2).unwrap();
assert_eq!(buf1, buf2);
}
#[test]
fn crc_with_crc_round_trip() {
let pre = synthetic_pre();
let bytes = pre.serialize_with_crc();
assert_eq!(bytes.len(), L1PRE_WITH_CRC_BYTES);
let parsed = L1Pre::parse_with_crc(&bytes).unwrap();
assert_eq!(pre, parsed);
}
#[test]
fn crc_rejects_corrupted() {
let pre = synthetic_pre();
let mut bytes = pre.serialize_with_crc();
bytes[L1PRE_BYTES] ^= 0xFF;
let err = L1Pre::parse_with_crc(&bytes).unwrap_err();
assert!(matches!(err, crate::Error::CrcMismatch { .. }));
}
#[test]
fn parse_rejects_short_buffer() {
assert!(L1Pre::parse(&[0u8; 20]).is_err());
}
#[test]
fn papr_reduction_v0() {
let mut pre = synthetic_pre();
pre.t2_version = T2Version::V1_1_1;
pre.papr = 2; assert_eq!(
pre.papr_reduction(),
PaprReduction::V0(PaprReductionV0::TrOnly)
);
}
#[test]
fn papr_reduction_vn() {
let mut pre = synthetic_pre();
pre.t2_version = T2Version::V1_3_1;
pre.papr = 1; assert_eq!(
pre.papr_reduction(),
PaprReduction::Vn(PaprReductionVn::L1AceAndAce)
);
}
}