use dvb_common::bits::{BitReader, BitWriter};
use super::enums::{
AuxStreamType, PlpCodeRate, PlpFecType, PlpMode, PlpModulation, PlpPayloadType, PlpType,
};
const SUB_SLICES_PER_FRAME_BITS: u32 = 15;
const NUM_PLP_BITS: u32 = 8;
const NUM_AUX_BITS: u32 = 4;
const AUX_CONFIG_RFU_BITS: u32 = 8;
const RF_IDX_BITS: u32 = 3;
const FREQUENCY_BITS: u32 = 32;
const FEF_TYPE_BITS: u32 = 4;
const FEF_LENGTH_BITS: u32 = 22;
const FEF_INTERVAL_BITS: u32 = 8;
const PLP_ID_BITS: u32 = 8;
const PLP_TYPE_BITS: u32 = 3;
const PLP_PAYLOAD_TYPE_BITS: u32 = 5;
const FF_FLAG_BITS: u32 = 1;
const FIRST_RF_IDX_BITS: u32 = 3;
const FIRST_FRAME_IDX_BITS: u32 = 8;
const PLP_GROUP_ID_BITS: u32 = 8;
const PLP_COD_BITS: u32 = 3;
const PLP_MOD_BITS: u32 = 3;
const PLP_ROTATION_BITS: u32 = 1;
const PLP_FEC_TYPE_BITS: u32 = 2;
const PLP_NUM_BLOCKS_MAX_BITS: u32 = 10;
const FRAME_INTERVAL_BITS: u32 = 8;
const TIME_IL_LENGTH_BITS: u32 = 8;
const TIME_IL_TYPE_BITS: u32 = 1;
const IN_BAND_A_FLAG_BITS: u32 = 1;
const IN_BAND_B_FLAG_BITS: u32 = 1;
const PLP_RESERVED_1_BITS: u32 = 11;
const PLP_MODE_BITS: u32 = 2;
const STATIC_FLAG_BITS: u32 = 1;
const STATIC_PADDING_FLAG_BITS: u32 = 1;
const FEF_LENGTH_MSB_BITS: u32 = 2;
const CONF_RESERVED_2_BITS: u32 = 30;
const AUX_STREAM_TYPE_BITS: u32 = 4;
const AUX_PRIVATE_CONF_BITS: u32 = 28;
const FRAME_IDX_BITS: u32 = 8;
const SUB_SLICE_INTERVAL_BITS: u32 = 22;
const TYPE_2_START_BITS: u32 = 22;
const L1_CHANGE_COUNTER_BITS: u32 = 8;
const START_RF_IDX_BITS: u32 = 3;
const DYN_RESERVED_1_BITS: u32 = 8;
const DYN_PLP_ID_BITS: u32 = 8;
const PLP_START_BITS: u32 = 22;
const PLP_NUM_BLOCKS_BITS: u32 = 10;
const DYN_PLP_RESERVED_2_BITS: u32 = 8;
const DYN_RESERVED_3_BITS: u32 = 8;
const AUX_PRIVATE_DYN_BITS: u32 = 48;
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
#[non_exhaustive]
pub struct RfFrequency {
pub rf_idx: u8,
pub frequency: u32,
}
impl RfFrequency {
fn parse(r: &mut BitReader<'_>) -> crate::error::Result<Self> {
let rf_idx = r.read_bits(RF_IDX_BITS)? as u8;
let frequency = r.read_bits(FREQUENCY_BITS)? as u32;
Ok(Self { rf_idx, frequency })
}
fn write(&self, w: &mut BitWriter<'_>) -> crate::error::Result<()> {
w.write_bits(u64::from(self.rf_idx), RF_IDX_BITS)?;
w.write_bits(u64::from(self.frequency), FREQUENCY_BITS)?;
Ok(())
}
const fn bits() -> usize {
(RF_IDX_BITS + FREQUENCY_BITS) as usize
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
#[non_exhaustive]
pub struct FefInfo {
pub fef_type: u8,
pub fef_length: u32,
pub fef_interval: u8,
}
impl FefInfo {
fn parse(r: &mut BitReader<'_>) -> crate::error::Result<Self> {
let fef_type = r.read_bits(FEF_TYPE_BITS)? as u8;
let fef_length = r.read_bits(FEF_LENGTH_BITS)? as u32;
let fef_interval = r.read_bits(FEF_INTERVAL_BITS)? as u8;
Ok(Self {
fef_type,
fef_length,
fef_interval,
})
}
fn write(&self, w: &mut BitWriter<'_>) -> crate::error::Result<()> {
w.write_bits(u64::from(self.fef_type), FEF_TYPE_BITS)?;
w.write_bits(u64::from(self.fef_length), FEF_LENGTH_BITS)?;
w.write_bits(u64::from(self.fef_interval), FEF_INTERVAL_BITS)?;
Ok(())
}
const fn bits() -> usize {
(FEF_TYPE_BITS + FEF_LENGTH_BITS + FEF_INTERVAL_BITS) as usize
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
#[non_exhaustive]
pub struct PlpConfig {
pub plp_id: u8,
pub plp_type: PlpType,
pub plp_payload_type: PlpPayloadType,
pub ff_flag: bool,
pub first_rf_idx: u8,
pub first_frame_idx: u8,
pub plp_group_id: u8,
pub plp_cod: u8,
pub plp_mod: PlpModulation,
pub plp_rotation: bool,
pub plp_fec_type: PlpFecType,
pub plp_num_blocks_max: u16,
pub frame_interval: u8,
pub time_il_length: u8,
pub time_il_type: bool,
pub in_band_a_flag: bool,
pub in_band_b_flag: bool,
pub reserved_1: u16,
pub plp_mode: PlpMode,
pub static_flag: bool,
pub static_padding_flag: bool,
}
impl PlpConfig {
#[must_use]
pub fn code_rate(&self) -> PlpCodeRate {
PlpCodeRate::from_u8(self.plp_cod)
}
fn parse(r: &mut BitReader<'_>) -> crate::error::Result<Self> {
let plp_id = r.read_bits(PLP_ID_BITS)? as u8;
let plp_type = PlpType::from_u8(r.read_bits(PLP_TYPE_BITS)? as u8);
let plp_payload_type = PlpPayloadType::from_u8(r.read_bits(PLP_PAYLOAD_TYPE_BITS)? as u8);
let ff_flag = r.read_bool()?;
let first_rf_idx = r.read_bits(FIRST_RF_IDX_BITS)? as u8;
let first_frame_idx = r.read_bits(FIRST_FRAME_IDX_BITS)? as u8;
let plp_group_id = r.read_bits(PLP_GROUP_ID_BITS)? as u8;
let plp_cod = r.read_bits(PLP_COD_BITS)? as u8;
let plp_mod = PlpModulation::from_u8(r.read_bits(PLP_MOD_BITS)? as u8);
let plp_rotation = r.read_bool()?;
let plp_fec_type = PlpFecType::from_u8(r.read_bits(PLP_FEC_TYPE_BITS)? as u8);
let plp_num_blocks_max = r.read_bits(PLP_NUM_BLOCKS_MAX_BITS)? as u16;
let frame_interval = r.read_bits(FRAME_INTERVAL_BITS)? as u8;
let time_il_length = r.read_bits(TIME_IL_LENGTH_BITS)? as u8;
let time_il_type = r.read_bool()?;
let in_band_a_flag = r.read_bool()?;
let in_band_b_flag = r.read_bool()?;
let reserved_1 = r.read_bits(PLP_RESERVED_1_BITS)? as u16;
let plp_mode = PlpMode::from_u8(r.read_bits(PLP_MODE_BITS)? as u8);
let static_flag = r.read_bool()?;
let static_padding_flag = r.read_bool()?;
Ok(Self {
plp_id,
plp_type,
plp_payload_type,
ff_flag,
first_rf_idx,
first_frame_idx,
plp_group_id,
plp_cod,
plp_mod,
plp_rotation,
plp_fec_type,
plp_num_blocks_max,
frame_interval,
time_il_length,
time_il_type,
in_band_a_flag,
in_band_b_flag,
reserved_1,
plp_mode,
static_flag,
static_padding_flag,
})
}
fn write(&self, w: &mut BitWriter<'_>) -> crate::error::Result<()> {
w.write_bits(u64::from(self.plp_id), PLP_ID_BITS)?;
w.write_bits(u64::from(self.plp_type.to_u8()), PLP_TYPE_BITS)?;
w.write_bits(
u64::from(self.plp_payload_type.to_u8()),
PLP_PAYLOAD_TYPE_BITS,
)?;
w.write_bool(self.ff_flag)?;
w.write_bits(u64::from(self.first_rf_idx), FIRST_RF_IDX_BITS)?;
w.write_bits(u64::from(self.first_frame_idx), FIRST_FRAME_IDX_BITS)?;
w.write_bits(u64::from(self.plp_group_id), PLP_GROUP_ID_BITS)?;
w.write_bits(u64::from(self.plp_cod), PLP_COD_BITS)?;
w.write_bits(u64::from(self.plp_mod.to_u8()), PLP_MOD_BITS)?;
w.write_bool(self.plp_rotation)?;
w.write_bits(u64::from(self.plp_fec_type.to_u8()), PLP_FEC_TYPE_BITS)?;
w.write_bits(u64::from(self.plp_num_blocks_max), PLP_NUM_BLOCKS_MAX_BITS)?;
w.write_bits(u64::from(self.frame_interval), FRAME_INTERVAL_BITS)?;
w.write_bits(u64::from(self.time_il_length), TIME_IL_LENGTH_BITS)?;
w.write_bool(self.time_il_type)?;
w.write_bool(self.in_band_a_flag)?;
w.write_bool(self.in_band_b_flag)?;
w.write_bits(u64::from(self.reserved_1), PLP_RESERVED_1_BITS)?;
w.write_bits(u64::from(self.plp_mode.to_u8()), PLP_MODE_BITS)?;
w.write_bool(self.static_flag)?;
w.write_bool(self.static_padding_flag)?;
Ok(())
}
const fn bits() -> usize {
(PLP_ID_BITS
+ PLP_TYPE_BITS
+ PLP_PAYLOAD_TYPE_BITS
+ FF_FLAG_BITS
+ FIRST_RF_IDX_BITS
+ FIRST_FRAME_IDX_BITS
+ PLP_GROUP_ID_BITS
+ PLP_COD_BITS
+ PLP_MOD_BITS
+ PLP_ROTATION_BITS
+ PLP_FEC_TYPE_BITS
+ PLP_NUM_BLOCKS_MAX_BITS
+ FRAME_INTERVAL_BITS
+ TIME_IL_LENGTH_BITS
+ TIME_IL_TYPE_BITS
+ IN_BAND_A_FLAG_BITS
+ IN_BAND_B_FLAG_BITS
+ PLP_RESERVED_1_BITS
+ PLP_MODE_BITS
+ STATIC_FLAG_BITS
+ STATIC_PADDING_FLAG_BITS) as usize
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
#[non_exhaustive]
pub struct AuxConfig {
pub aux_stream_type: AuxStreamType,
pub aux_private_conf: u32,
}
impl AuxConfig {
fn parse(r: &mut BitReader<'_>) -> crate::error::Result<Self> {
let aux_stream_type = AuxStreamType::from_u8(r.read_bits(AUX_STREAM_TYPE_BITS)? as u8);
let aux_private_conf = r.read_bits(AUX_PRIVATE_CONF_BITS)? as u32;
Ok(Self {
aux_stream_type,
aux_private_conf,
})
}
fn write(&self, w: &mut BitWriter<'_>) -> crate::error::Result<()> {
w.write_bits(
u64::from(self.aux_stream_type.to_u8()),
AUX_STREAM_TYPE_BITS,
)?;
w.write_bits(u64::from(self.aux_private_conf), AUX_PRIVATE_CONF_BITS)?;
Ok(())
}
const fn bits() -> usize {
(AUX_STREAM_TYPE_BITS + AUX_PRIVATE_CONF_BITS) as usize
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
#[non_exhaustive]
pub struct L1PostConfigurable {
pub sub_slices_per_frame: u16,
pub num_plp: u8,
pub num_aux: u8,
pub aux_config_rfu: u8,
pub rf: Vec<RfFrequency>,
pub fef: Option<FefInfo>,
pub plps: Vec<PlpConfig>,
pub fef_length_msb: u8,
pub reserved_2: u32,
pub aux: Vec<AuxConfig>,
}
impl L1PostConfigurable {
pub fn parse(bytes: &[u8], num_rf: u8, fef_present: bool) -> crate::error::Result<Self> {
let mut r = BitReader::new(bytes);
let sub_slices_per_frame = r.read_bits(SUB_SLICES_PER_FRAME_BITS)? as u16;
let num_plp = r.read_bits(NUM_PLP_BITS)? as u8;
let num_aux = r.read_bits(NUM_AUX_BITS)? as u8;
let aux_config_rfu = r.read_bits(AUX_CONFIG_RFU_BITS)? as u8;
let mut rf = Vec::with_capacity(num_rf as usize);
for _ in 0..num_rf {
rf.push(RfFrequency::parse(&mut r)?);
}
let fef = if fef_present {
Some(FefInfo::parse(&mut r)?)
} else {
None
};
let mut plps = Vec::with_capacity(num_plp as usize);
for _ in 0..num_plp {
plps.push(PlpConfig::parse(&mut r)?);
}
let fef_length_msb = r.read_bits(FEF_LENGTH_MSB_BITS)? as u8;
let reserved_2 = r.read_bits(CONF_RESERVED_2_BITS)? as u32;
let mut aux = Vec::with_capacity(num_aux as usize);
for _ in 0..num_aux {
aux.push(AuxConfig::parse(&mut r)?);
}
Ok(Self {
sub_slices_per_frame,
num_plp,
num_aux,
aux_config_rfu,
rf,
fef,
plps,
fef_length_msb,
reserved_2,
aux,
})
}
#[must_use]
pub fn len_bits(&self) -> usize {
let header = (SUB_SLICES_PER_FRAME_BITS + NUM_PLP_BITS + NUM_AUX_BITS + AUX_CONFIG_RFU_BITS)
as usize;
let rf_bits = self.rf.len() * RfFrequency::bits();
let fef_bits = if self.fef.is_some() {
FefInfo::bits()
} else {
0
};
let plp_bits = self.plps.len() * PlpConfig::bits();
let post_loop = (FEF_LENGTH_MSB_BITS + CONF_RESERVED_2_BITS) as usize;
let aux_bits = self.aux.len() * AuxConfig::bits();
header + rf_bits + fef_bits + plp_bits + post_loop + aux_bits
}
pub fn serialize_bits(&self, w: &mut BitWriter<'_>) -> crate::error::Result<()> {
w.write_bits(
u64::from(self.sub_slices_per_frame),
SUB_SLICES_PER_FRAME_BITS,
)?;
w.write_bits(u64::from(self.num_plp), NUM_PLP_BITS)?;
w.write_bits(u64::from(self.num_aux), NUM_AUX_BITS)?;
w.write_bits(u64::from(self.aux_config_rfu), AUX_CONFIG_RFU_BITS)?;
for rf in &self.rf {
rf.write(w)?;
}
if let Some(fef) = &self.fef {
fef.write(w)?;
}
for plp in &self.plps {
plp.write(w)?;
}
w.write_bits(u64::from(self.fef_length_msb), FEF_LENGTH_MSB_BITS)?;
w.write_bits(u64::from(self.reserved_2), CONF_RESERVED_2_BITS)?;
for aux in &self.aux {
aux.write(w)?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
#[non_exhaustive]
pub struct PlpDynamic {
pub plp_id: u8,
pub plp_start: u32,
pub plp_num_blocks: u16,
pub reserved_2: u8,
}
impl PlpDynamic {
fn parse(r: &mut BitReader<'_>) -> crate::error::Result<Self> {
let plp_id = r.read_bits(DYN_PLP_ID_BITS)? as u8;
let plp_start = r.read_bits(PLP_START_BITS)? as u32;
let plp_num_blocks = r.read_bits(PLP_NUM_BLOCKS_BITS)? as u16;
let reserved_2 = r.read_bits(DYN_PLP_RESERVED_2_BITS)? as u8;
Ok(Self {
plp_id,
plp_start,
plp_num_blocks,
reserved_2,
})
}
fn write(&self, w: &mut BitWriter<'_>) -> crate::error::Result<()> {
w.write_bits(u64::from(self.plp_id), DYN_PLP_ID_BITS)?;
w.write_bits(u64::from(self.plp_start), PLP_START_BITS)?;
w.write_bits(u64::from(self.plp_num_blocks), PLP_NUM_BLOCKS_BITS)?;
w.write_bits(u64::from(self.reserved_2), DYN_PLP_RESERVED_2_BITS)?;
Ok(())
}
const fn bits() -> usize {
(DYN_PLP_ID_BITS + PLP_START_BITS + PLP_NUM_BLOCKS_BITS + DYN_PLP_RESERVED_2_BITS) as usize
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
#[non_exhaustive]
pub struct AuxDynamic {
pub aux_private_dyn: u64,
}
impl AuxDynamic {
fn parse(r: &mut BitReader<'_>) -> crate::error::Result<Self> {
let aux_private_dyn = r.read_bits(AUX_PRIVATE_DYN_BITS)?;
Ok(Self { aux_private_dyn })
}
fn write(&self, w: &mut BitWriter<'_>) -> crate::error::Result<()> {
w.write_bits(self.aux_private_dyn, AUX_PRIVATE_DYN_BITS)?;
Ok(())
}
const fn bits() -> usize {
AUX_PRIVATE_DYN_BITS as usize
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
#[non_exhaustive]
pub struct L1PostDynamic {
pub frame_idx: u8,
pub sub_slice_interval: u32,
pub type_2_start: u32,
pub l1_change_counter: u8,
pub start_rf_idx: u8,
pub reserved_1: u8,
pub plps: Vec<PlpDynamic>,
pub reserved_3: u8,
pub aux: Vec<AuxDynamic>,
}
impl L1PostDynamic {
pub fn parse(bytes: &[u8], num_plp: u8, num_aux: u8) -> crate::error::Result<Self> {
let mut r = BitReader::new(bytes);
let frame_idx = r.read_bits(FRAME_IDX_BITS)? as u8;
let sub_slice_interval = r.read_bits(SUB_SLICE_INTERVAL_BITS)? as u32;
let type_2_start = r.read_bits(TYPE_2_START_BITS)? as u32;
let l1_change_counter = r.read_bits(L1_CHANGE_COUNTER_BITS)? as u8;
let start_rf_idx = r.read_bits(START_RF_IDX_BITS)? as u8;
let reserved_1 = r.read_bits(DYN_RESERVED_1_BITS)? as u8;
let mut plps = Vec::with_capacity(num_plp as usize);
for _ in 0..num_plp {
plps.push(PlpDynamic::parse(&mut r)?);
}
let reserved_3 = r.read_bits(DYN_RESERVED_3_BITS)? as u8;
let mut aux = Vec::with_capacity(num_aux as usize);
for _ in 0..num_aux {
aux.push(AuxDynamic::parse(&mut r)?);
}
Ok(Self {
frame_idx,
sub_slice_interval,
type_2_start,
l1_change_counter,
start_rf_idx,
reserved_1,
plps,
reserved_3,
aux,
})
}
#[must_use]
pub fn len_bits(&self) -> usize {
let header = (FRAME_IDX_BITS
+ SUB_SLICE_INTERVAL_BITS
+ TYPE_2_START_BITS
+ L1_CHANGE_COUNTER_BITS
+ START_RF_IDX_BITS
+ DYN_RESERVED_1_BITS) as usize;
let plp_bits = self.plps.len() * PlpDynamic::bits();
let post = DYN_RESERVED_3_BITS as usize;
let aux_bits = self.aux.len() * AuxDynamic::bits();
header + plp_bits + post + aux_bits
}
pub fn serialize_bits(&self, w: &mut BitWriter<'_>) -> crate::error::Result<()> {
w.write_bits(u64::from(self.frame_idx), FRAME_IDX_BITS)?;
w.write_bits(u64::from(self.sub_slice_interval), SUB_SLICE_INTERVAL_BITS)?;
w.write_bits(u64::from(self.type_2_start), TYPE_2_START_BITS)?;
w.write_bits(u64::from(self.l1_change_counter), L1_CHANGE_COUNTER_BITS)?;
w.write_bits(u64::from(self.start_rf_idx), START_RF_IDX_BITS)?;
w.write_bits(u64::from(self.reserved_1), DYN_RESERVED_1_BITS)?;
for plp in &self.plps {
plp.write(w)?;
}
w.write_bits(u64::from(self.reserved_3), DYN_RESERVED_3_BITS)?;
for aux in &self.aux {
aux.write(w)?;
}
Ok(())
}
}
const L1_EXT_BLOCK_TYPE_BITS: u32 = 8;
const L1_EXT_DATA_LEN_BITS: u32 = 16;
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
#[non_exhaustive]
pub struct L1ExtBlock {
pub block_type: u8,
pub data_bit_len: u16,
pub data: Vec<u8>,
}
impl L1ExtBlock {
fn bits(&self) -> usize {
(L1_EXT_BLOCK_TYPE_BITS + L1_EXT_DATA_LEN_BITS) as usize + self.data_bit_len as usize
}
fn parse(r: &mut BitReader<'_>) -> crate::error::Result<Self> {
let block_type = r.read_bits(L1_EXT_BLOCK_TYPE_BITS)? as u8;
let data_bit_len = r.read_bits(L1_EXT_DATA_LEN_BITS)? as u16;
let n = data_bit_len as usize;
let mut data = vec![0u8; n.div_ceil(8)];
let mut done = 0usize;
for byte in data.iter_mut() {
let take = (n - done).min(8) as u32;
let v = r.read_bits(take)? as u8;
*byte = if take < 8 { v << (8 - take) } else { v };
done += take as usize;
}
Ok(Self {
block_type,
data_bit_len,
data,
})
}
fn write(&self, w: &mut BitWriter<'_>) -> crate::error::Result<()> {
w.write_bits(u64::from(self.block_type), L1_EXT_BLOCK_TYPE_BITS)?;
w.write_bits(u64::from(self.data_bit_len), L1_EXT_DATA_LEN_BITS)?;
let n = self.data_bit_len as usize;
let mut done = 0usize;
for &byte in &self.data {
let take = (n - done).min(8) as u32;
let v = if take < 8 {
u64::from(byte >> (8 - take))
} else {
u64::from(byte)
};
w.write_bits(v, take)?;
done += take as usize;
}
Ok(())
}
}
fn parse_ext_blocks(bytes: &[u8], total_bits: usize) -> crate::error::Result<Vec<L1ExtBlock>> {
let mut r = BitReader::new(bytes);
let header_bits = (L1_EXT_BLOCK_TYPE_BITS + L1_EXT_DATA_LEN_BITS) as usize;
let mut blocks = Vec::new();
while r.bits_read() + header_bits <= total_bits {
blocks.push(L1ExtBlock::parse(&mut r)?);
}
Ok(blocks)
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
#[non_exhaustive]
pub struct L1Post {
pub configurable: L1PostConfigurable,
pub dynamic_current: L1PostDynamic,
pub dynamic_next: Option<L1PostDynamic>,
pub extension: Vec<L1ExtBlock>,
}
impl L1Post {
pub fn to_l1_current_framed(&self) -> crate::error::Result<Vec<u8>> {
serialize_l1_post_framed(self)
}
}
pub(crate) fn parse_l1_post_from_framed(
framed: &[u8],
num_rf: u8,
fef_present: bool,
) -> crate::error::Result<L1Post> {
let mut pos = 0usize;
if framed.len() < pos + 2 {
return Err(crate::Error::BufferTooShort {
need: pos + 2,
have: framed.len(),
what: "L1CONF_LEN",
});
}
let l1conf_len_bits = u16::from_be_bytes([framed[pos], framed[pos + 1]]) as usize;
pos += 2;
let l1conf_bytes = l1conf_len_bits.div_ceil(8);
if framed.len() < pos + l1conf_bytes {
return Err(crate::Error::BufferTooShort {
need: pos + l1conf_bytes,
have: framed.len(),
what: "L1CONF",
});
}
let configurable =
L1PostConfigurable::parse(&framed[pos..pos + l1conf_bytes], num_rf, fef_present)?;
pos += l1conf_bytes;
let num_plp = configurable.num_plp;
let num_aux = configurable.num_aux;
if framed.len() < pos + 2 {
return Err(crate::Error::BufferTooShort {
need: pos + 2,
have: framed.len(),
what: "L1DYN_CURR_LEN",
});
}
let l1dyn_len_bits = u16::from_be_bytes([framed[pos], framed[pos + 1]]) as usize;
pos += 2;
let l1dyn_bytes = l1dyn_len_bits.div_ceil(8);
if framed.len() < pos + l1dyn_bytes {
return Err(crate::Error::BufferTooShort {
need: pos + l1dyn_bytes,
have: framed.len(),
what: "L1DYN_CURR",
});
}
let dynamic_current = L1PostDynamic::parse(&framed[pos..pos + l1dyn_bytes], num_plp, num_aux)?;
pos += l1dyn_bytes;
if framed.len() < pos + 2 {
return Err(crate::Error::BufferTooShort {
need: pos + 2,
have: framed.len(),
what: "L1EXT_LEN",
});
}
let l1ext_len_bits = u16::from_be_bytes([framed[pos], framed[pos + 1]]) as usize;
pos += 2;
let l1ext_bytes = l1ext_len_bits.div_ceil(8);
if framed.len() < pos + l1ext_bytes {
return Err(crate::Error::BufferTooShort {
need: pos + l1ext_bytes,
have: framed.len(),
what: "L1EXT",
});
}
let extension = if l1ext_bytes > 0 {
parse_ext_blocks(&framed[pos..pos + l1ext_bytes], l1ext_len_bits)?
} else {
Vec::new()
};
Ok(L1Post {
configurable,
dynamic_current,
dynamic_next: None, extension,
})
}
fn push_framed_block<F>(out: &mut Vec<u8>, bit_len: usize, write: F) -> crate::error::Result<()>
where
F: FnOnce(&mut BitWriter<'_>) -> crate::error::Result<()>,
{
out.extend_from_slice(&(bit_len as u16).to_be_bytes());
let start = out.len();
out.resize(start + bit_len.div_ceil(8), 0);
let mut w = BitWriter::new(&mut out[start..]);
write(&mut w)?;
Ok(())
}
pub(crate) fn serialize_l1_post_framed(post: &L1Post) -> crate::error::Result<Vec<u8>> {
let mut out = Vec::new();
push_framed_block(&mut out, post.configurable.len_bits(), |w| {
post.configurable.serialize_bits(w)
})?;
push_framed_block(&mut out, post.dynamic_current.len_bits(), |w| {
post.dynamic_current.serialize_bits(w)
})?;
let ext_bits: usize = post.extension.iter().map(L1ExtBlock::bits).sum();
push_framed_block(&mut out, ext_bits, |w| {
for block in &post.extension {
block.write(w)?;
}
Ok(())
})?;
Ok(out)
}
#[cfg(test)]
mod tests {
use super::*;
fn synthetic_conf(
num_rf: u8,
fef_present: bool,
num_plp: u8,
num_aux: u8,
) -> L1PostConfigurable {
let rf = (0..num_rf)
.map(|i| RfFrequency {
rf_idx: i,
frequency: 666_000_000 + u32::from(i) * 8_000_000,
})
.collect();
let fef = if fef_present {
Some(FefInfo {
fef_type: 0,
fef_length: 100,
fef_interval: 4,
})
} else {
None
};
let plps = (0..num_plp)
.map(|i| PlpConfig {
plp_id: i,
plp_type: PlpType::Common,
plp_payload_type: PlpPayloadType::Ts,
ff_flag: false,
first_rf_idx: 0,
first_frame_idx: 0,
plp_group_id: 0,
plp_cod: 0,
plp_mod: PlpModulation::Qam16,
plp_rotation: false,
plp_fec_type: PlpFecType::Ldpc16K,
plp_num_blocks_max: 10,
frame_interval: 1,
time_il_length: 0,
time_il_type: false,
in_band_a_flag: false,
in_band_b_flag: false,
reserved_1: 0,
plp_mode: PlpMode::Normal,
static_flag: false,
static_padding_flag: false,
})
.collect();
let aux = (0..num_aux)
.map(|_| AuxConfig {
aux_stream_type: AuxStreamType::TxSig,
aux_private_conf: 0,
})
.collect();
L1PostConfigurable {
sub_slices_per_frame: 512,
num_plp,
num_aux,
aux_config_rfu: 0,
rf,
fef,
plps,
fef_length_msb: 0,
reserved_2: 0,
aux,
}
}
fn synthetic_dyn(num_plp: u8, num_aux: u8) -> L1PostDynamic {
let plps = (0..num_plp)
.map(|i| PlpDynamic {
plp_id: i,
plp_start: 0x1234,
plp_num_blocks: 5,
reserved_2: 0,
})
.collect();
let aux = (0..num_aux)
.map(|_| AuxDynamic { aux_private_dyn: 0 })
.collect();
L1PostDynamic {
frame_idx: 0,
sub_slice_interval: 0,
type_2_start: 0,
l1_change_counter: 0,
start_rf_idx: 0,
reserved_1: 0,
plps,
reserved_3: 0,
aux,
}
}
#[test]
fn configurable_round_trip() {
let conf = synthetic_conf(1, false, 1, 0);
let bits = conf.len_bits();
let bytes = bits.div_ceil(8);
let mut buf = vec![0u8; bytes];
let mut w = BitWriter::new(&mut buf);
conf.serialize_bits(&mut w).unwrap();
let parsed = L1PostConfigurable::parse(&buf, 1, false).unwrap();
assert_eq!(conf, parsed);
}
#[test]
fn configurable_round_trip_with_fef() {
let conf = synthetic_conf(1, true, 1, 0);
let bits = conf.len_bits();
let bytes = bits.div_ceil(8);
let mut buf = vec![0u8; bytes];
let mut w = BitWriter::new(&mut buf);
conf.serialize_bits(&mut w).unwrap();
let parsed = L1PostConfigurable::parse(&buf, 1, true).unwrap();
assert_eq!(conf, parsed);
}
#[test]
fn dynamic_round_trip() {
let dyn_ = synthetic_dyn(1, 0);
let bits = dyn_.len_bits();
let bytes = bits.div_ceil(8);
let mut buf = vec![0u8; bytes];
let mut w = BitWriter::new(&mut buf);
dyn_.serialize_bits(&mut w).unwrap();
let parsed = L1PostDynamic::parse(&buf, 1, 0).unwrap();
assert_eq!(dyn_, parsed);
}
#[test]
fn plp_config_bits_constant() {
assert_eq!(PlpConfig::bits(), 89);
}
#[test]
fn plp_dynamic_bits_constant() {
assert_eq!(PlpDynamic::bits(), 48);
}
#[test]
fn plp_code_rate_accessor() {
let plp = PlpConfig {
plp_id: 0,
plp_type: PlpType::Common,
plp_payload_type: PlpPayloadType::Ts,
ff_flag: false,
first_rf_idx: 0,
first_frame_idx: 0,
plp_group_id: 0,
plp_cod: 2, plp_mod: PlpModulation::Qam64,
plp_rotation: false,
plp_fec_type: PlpFecType::Ldpc64K,
plp_num_blocks_max: 20,
frame_interval: 1,
time_il_length: 0,
time_il_type: false,
in_band_a_flag: false,
in_band_b_flag: false,
reserved_1: 0,
plp_mode: PlpMode::Normal,
static_flag: false,
static_padding_flag: false,
};
assert_eq!(plp.code_rate(), PlpCodeRate::R2_3);
}
#[test]
fn configurable_header_bits() {
let conf = synthetic_conf(1, false, 1, 0);
assert_eq!(conf.len_bits(), 191);
}
#[test]
fn dynamic_header_bits() {
let dyn_ = synthetic_dyn(1, 0);
assert_eq!(dyn_.len_bits(), 127);
}
#[test]
fn l1post_framed_round_trip() {
let post = L1Post {
configurable: synthetic_conf(1, false, 1, 0),
dynamic_current: synthetic_dyn(1, 0),
dynamic_next: None,
extension: Vec::new(),
};
let framed = post.to_l1_current_framed().unwrap();
assert_eq!(framed.len(), 46);
let parsed = parse_l1_post_from_framed(&framed, 1, false).unwrap();
assert_eq!(post, parsed);
}
#[test]
fn l1post_framed_round_trip_with_nonaligned_ext() {
let post = L1Post {
configurable: synthetic_conf(2, true, 1, 1),
dynamic_current: synthetic_dyn(1, 1),
dynamic_next: None,
extension: vec![L1ExtBlock {
block_type: 0xFF,
data_bit_len: 12,
data: vec![0xAB, 0xC0], }],
};
let framed = post.to_l1_current_framed().unwrap();
let parsed = parse_l1_post_from_framed(&framed, 2, true).unwrap();
assert_eq!(post, parsed);
}
}