use super::SI_BLOCK_SIZE;
#[cfg(feature = "std")]
use crate::blocks::common::u64_to_usize;
use crate::{
Result,
blocks::common::{
BlockHeader, BlockParse, debug_assert_aligned, read_u8, read_u64, validate_buffer_size,
},
};
#[derive(Debug, Clone)]
pub struct SourceBlock {
pub header: BlockHeader,
pub name_addr: u64,
pub path_addr: u64,
pub comment_addr: u64,
pub source_type: u8,
pub bus_type: u8,
pub flags: u8,
}
impl BlockParse<'_> for SourceBlock {
const ID: &'static str = "##SI";
fn from_bytes(bytes: &[u8]) -> Result<Self> {
let header = Self::parse_header(bytes)?;
let link_count = header.link_count as usize;
let data_start = 24 + link_count * 8;
validate_buffer_size(bytes, data_start + 3)?;
let name_addr = if link_count > 0 {
read_u64(bytes, 24)
} else {
0
};
let path_addr = if link_count > 1 {
read_u64(bytes, 32)
} else {
0
};
let comment_addr = if link_count > 2 {
read_u64(bytes, 40)
} else {
0
};
Ok(Self {
header,
name_addr,
path_addr,
comment_addr,
source_type: read_u8(bytes, data_start),
bus_type: read_u8(bytes, data_start + 1),
flags: read_u8(bytes, data_start + 2),
})
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum SourceType {
Other = 0,
ECU = 1,
Bus = 2,
IO = 3,
Tool = 4,
User = 5,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum BusType {
None = 0,
Other = 1,
CAN = 2,
LIN = 3,
MOST = 4,
FlexRay = 5,
KLine = 6,
Ethernet = 7,
USB = 8,
}
impl SourceBlock {
pub fn new(source_type: SourceType, bus_type: BusType) -> Self {
Self {
header: BlockHeader {
id: alloc::string::String::from("##SI"),
reserved: 0,
length: SI_BLOCK_SIZE as u64,
link_count: 3,
},
name_addr: 0,
path_addr: 0,
comment_addr: 0,
source_type: source_type as u8,
bus_type: bus_type as u8,
flags: 0,
}
}
pub fn can_ecu() -> Self {
Self::new(SourceType::ECU, BusType::CAN)
}
pub fn can_bus() -> Self {
Self::new(SourceType::Bus, BusType::CAN)
}
pub fn ethernet() -> Self {
Self::new(SourceType::Bus, BusType::Ethernet)
}
pub fn lin_bus() -> Self {
Self::new(SourceType::Bus, BusType::LIN)
}
pub fn flexray() -> Self {
Self::new(SourceType::Bus, BusType::FlexRay)
}
pub fn to_bytes(&self) -> Result<alloc::vec::Vec<u8>> {
use alloc::vec::Vec;
let mut buffer = Vec::with_capacity(SI_BLOCK_SIZE);
buffer.extend_from_slice(&self.header.to_bytes()?);
buffer.extend_from_slice(&self.name_addr.to_le_bytes());
buffer.extend_from_slice(&self.path_addr.to_le_bytes());
buffer.extend_from_slice(&self.comment_addr.to_le_bytes());
buffer.push(self.source_type);
buffer.push(self.bus_type);
buffer.push(self.flags);
buffer.extend_from_slice(&[0u8; 5]);
debug_assert_aligned(buffer.len());
Ok(buffer)
}
}
impl Default for SourceBlock {
fn default() -> Self {
Self::can_ecu()
}
}
#[cfg(feature = "std")]
pub fn read_source_block(mmap: &[u8], address: u64) -> Result<SourceBlock> {
let start = u64_to_usize(address, "source block address")?;
validate_buffer_size(mmap, start + 24)?;
let header = BlockHeader::from_bytes(&mmap[start..start + 24])?;
let total_len = u64_to_usize(header.length, "source block length")?;
validate_buffer_size(mmap, start + total_len)?;
let slice = &mmap[start..start + total_len];
SourceBlock::from_bytes(slice)
}