use super::CG_BLOCK_SIZE;
use crate::{
Result,
blocks::{
channel_block::ChannelBlock,
common::{
BlockHeader, BlockParse, debug_assert_aligned, read_u16, read_u32, read_u64,
validate_block_id, validate_block_length, validate_buffer_size,
},
},
};
use alloc::string::String;
use alloc::vec::Vec;
#[derive(Debug, Clone)]
pub struct ChannelGroupBlock {
pub header: BlockHeader,
pub next_cg_addr: u64,
pub first_ch_addr: u64,
pub acq_name_addr: u64,
pub acq_source_addr: u64,
pub first_sample_reduction_addr: u64,
pub comment_addr: u64,
pub record_id: u64,
pub cycle_count: u64,
pub flags: u16,
pub path_separator: u16,
pub record_size: u32,
pub invalidation_size: u32,
}
impl BlockParse<'_> for ChannelGroupBlock {
const ID: &'static str = "##CG";
fn from_bytes(bytes: &[u8]) -> Result<Self> {
let header = Self::parse_header(bytes)?;
validate_buffer_size(bytes, CG_BLOCK_SIZE)?;
Ok(Self {
header,
next_cg_addr: read_u64(bytes, 24),
first_ch_addr: read_u64(bytes, 32),
acq_name_addr: read_u64(bytes, 40),
acq_source_addr: read_u64(bytes, 48),
first_sample_reduction_addr: read_u64(bytes, 56),
comment_addr: read_u64(bytes, 64),
record_id: read_u64(bytes, 72),
cycle_count: read_u64(bytes, 80),
flags: read_u16(bytes, 88),
path_separator: read_u16(bytes, 90),
record_size: read_u32(bytes, 96),
invalidation_size: read_u32(bytes, 100),
})
}
}
impl ChannelGroupBlock {
pub fn to_bytes(&self) -> Result<Vec<u8>> {
validate_block_id(&self.header, "##CG")?;
validate_block_length(&self.header, CG_BLOCK_SIZE as u64)?;
let mut buffer = Vec::with_capacity(CG_BLOCK_SIZE);
buffer.extend_from_slice(&self.header.to_bytes()?);
buffer.extend_from_slice(&self.next_cg_addr.to_le_bytes());
buffer.extend_from_slice(&self.first_ch_addr.to_le_bytes());
buffer.extend_from_slice(&self.acq_name_addr.to_le_bytes());
buffer.extend_from_slice(&self.acq_source_addr.to_le_bytes());
buffer.extend_from_slice(&self.first_sample_reduction_addr.to_le_bytes());
buffer.extend_from_slice(&self.comment_addr.to_le_bytes());
buffer.extend_from_slice(&self.record_id.to_le_bytes());
buffer.extend_from_slice(&self.cycle_count.to_le_bytes());
buffer.extend_from_slice(&self.flags.to_le_bytes());
buffer.extend_from_slice(&self.path_separator.to_le_bytes());
buffer.extend_from_slice(&[0u8; 4]); buffer.extend_from_slice(&self.record_size.to_le_bytes());
buffer.extend_from_slice(&self.invalidation_size.to_le_bytes());
debug_assert_aligned(buffer.len());
Ok(buffer)
}
pub fn read_channels(&mut self, mmap: &[u8]) -> Result<Vec<ChannelBlock>> {
let mut channels = Vec::new();
let mut current_ch_addr = self.first_ch_addr;
while current_ch_addr != 0 {
let ch_offset = current_ch_addr as usize;
let mut channel = ChannelBlock::from_bytes(&mmap[ch_offset..])?;
channel.resolve_conversion(mmap)?;
current_ch_addr = channel.next_ch_addr;
channels.push(channel);
}
Ok(channels)
}
}
impl Default for ChannelGroupBlock {
fn default() -> Self {
Self {
header: BlockHeader {
id: String::from("##CG"),
reserved: 0,
length: CG_BLOCK_SIZE as u64,
link_count: 6,
},
next_cg_addr: 0,
first_ch_addr: 0,
acq_name_addr: 0,
acq_source_addr: 0,
first_sample_reduction_addr: 0,
comment_addr: 0,
record_id: 0,
cycle_count: 0,
flags: 0,
path_separator: 0,
record_size: 0,
invalidation_size: 0,
}
}
}