use super::TransportLayer;
use crate::error::{AutomotiveError, Result};
use crate::physical::PhysicalLayer;
use crate::transport::IsoTpTransport;
use crate::types::{Config, Frame};
const SF_PCI: u8 = 0x00; const FF_PCI: u8 = 0x10; const CF_PCI: u8 = 0x20; const FC_PCI: u8 = 0x30;
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum AddressMode {
Normal,
Extended,
Mixed,
}
#[derive(Debug, Clone)]
pub struct IsoTpTiming {
pub n_as: u32, pub n_ar: u32, pub n_bs: u32, pub n_cr: u32, }
impl Default for IsoTpTiming {
fn default() -> Self {
Self {
n_as: 1000, n_ar: 1000,
n_bs: 1000,
n_cr: 1000,
}
}
}
#[derive(Debug, Clone)]
pub struct IsoTpConfig {
pub tx_id: u32,
pub rx_id: u32,
pub block_size: u8,
pub st_min: u8,
pub address_mode: AddressMode,
pub address_extension: u8,
pub use_padding: bool,
pub padding_value: u8,
pub timing: IsoTpTiming,
pub timeout_ms: u32,
}
impl Config for IsoTpConfig {
fn validate(&self) -> Result<()> {
Ok(())
}
}
impl Default for IsoTpConfig {
fn default() -> Self {
Self {
tx_id: 0,
rx_id: 0,
block_size: 0,
st_min: 0,
address_mode: AddressMode::Normal,
address_extension: 0,
use_padding: false,
padding_value: 0x00,
timing: IsoTpTiming::default(),
timeout_ms: 1000,
}
}
}
pub struct IsoTp<P: PhysicalLayer> {
config: IsoTpConfig,
physical: P,
is_open: bool,
}
impl<P: PhysicalLayer> IsoTp<P> {
pub fn with_physical(config: IsoTpConfig, physical: P) -> Self {
Self {
config,
physical,
is_open: false,
}
}
fn send_single_frame(&mut self, data: &[u8]) -> Result<()> {
let mut frame_data = vec![];
if self.config.address_mode == AddressMode::Extended {
frame_data.push(self.config.address_extension);
}
frame_data.push(data.len() as u8);
frame_data.extend_from_slice(data);
if self.config.use_padding {
while frame_data.len() < 8 {
frame_data.push(self.config.padding_value);
}
}
self.write_frame(&Frame {
id: if self.config.address_mode == AddressMode::Mixed {
self.config.tx_id | (self.config.address_extension as u32)
} else {
self.config.tx_id
},
data: frame_data,
timestamp: 0,
is_extended: false,
is_fd: false,
})
}
fn send_multi_frame(&mut self, data: &[u8]) -> Result<()> {
let mut frame_data = vec![];
if self.config.address_mode == AddressMode::Extended {
frame_data.push(self.config.address_extension);
}
frame_data.push(0x10 | ((data.len() >> 8) as u8 & 0x0F));
frame_data.push(data.len() as u8);
let first_data_size = if self.config.address_mode == AddressMode::Extended {
5
} else {
6
};
frame_data.extend_from_slice(&data[0..first_data_size]);
if self.config.use_padding {
while frame_data.len() < 8 {
frame_data.push(self.config.padding_value);
}
}
self.write_frame(&Frame {
id: if self.config.address_mode == AddressMode::Mixed {
self.config.tx_id | (self.config.address_extension as u32)
} else {
self.config.tx_id
},
data: frame_data,
timestamp: 0,
is_extended: false,
is_fd: false,
})?;
let start_time = std::time::SystemTime::now();
loop {
let frame = self.read_frame()?;
if frame.data[0] == 0x30 {
break;
}
if start_time.elapsed().unwrap().as_millis() as u32 > self.config.timing.n_bs {
return Err(AutomotiveError::Timeout);
}
}
let mut index = first_data_size;
let mut sequence = 1;
while index < data.len() {
let remaining = data.len() - index;
let chunk_size = if self.config.address_mode == AddressMode::Extended {
remaining.min(6)
} else {
remaining.min(7)
};
let mut frame_data = vec![];
if self.config.address_mode == AddressMode::Extended {
frame_data.push(self.config.address_extension);
}
frame_data.push(0x20 | (sequence & 0x0F));
frame_data.extend_from_slice(&data[index..index + chunk_size]);
if self.config.use_padding {
while frame_data.len() < 8 {
frame_data.push(self.config.padding_value);
}
}
self.write_frame(&Frame {
id: if self.config.address_mode == AddressMode::Mixed {
self.config.tx_id | (self.config.address_extension as u32)
} else {
self.config.tx_id
},
data: frame_data,
timestamp: 0,
is_extended: false,
is_fd: false,
})?;
if self.config.st_min > 0 {
std::thread::sleep(std::time::Duration::from_millis(self.config.st_min as u64));
}
index += chunk_size;
sequence = (sequence + 1) & 0x0F;
}
Ok(())
}
fn receive_single_frame(&mut self, frame: &Frame) -> Result<Vec<u8>> {
let data_start = if self.config.address_mode == AddressMode::Extended {
1
} else {
0
};
let length = frame.data[data_start] & 0x0F;
if length as usize > frame.data.len() - data_start - 1 {
return Err(AutomotiveError::InvalidParameter);
}
Ok(frame.data[data_start + 1..=data_start + length as usize].to_vec())
}
fn receive_multi_frame(&mut self, frame: &Frame) -> Result<Vec<u8>> {
let data_start = if self.config.address_mode == AddressMode::Extended {
1
} else {
0
};
let length =
((frame.data[data_start] as usize & 0x0F) << 8) | frame.data[data_start + 1] as usize;
let mut data = Vec::with_capacity(length);
data.extend_from_slice(&frame.data[data_start + 2..]);
let mut fc_data = vec![];
if self.config.address_mode == AddressMode::Extended {
fc_data.push(self.config.address_extension);
}
fc_data.extend_from_slice(&[0x30, self.config.block_size, self.config.st_min]);
self.write_frame(&Frame {
id: if self.config.address_mode == AddressMode::Mixed {
self.config.tx_id | (self.config.address_extension as u32)
} else {
self.config.tx_id
},
data: fc_data,
timestamp: 0,
is_extended: false,
is_fd: false,
})?;
let mut sequence = 1;
while data.len() < length {
let frame = self.read_frame()?;
if frame.data.is_empty() {
return Err(AutomotiveError::InvalidParameter);
}
let data_start = if self.config.address_mode == AddressMode::Extended {
1
} else {
0
};
if frame.data[data_start] & 0xF0 != 0x20 {
return Err(AutomotiveError::InvalidParameter);
}
if frame.data[data_start] & 0x0F != sequence {
return Err(AutomotiveError::InvalidParameter);
}
data.extend_from_slice(&frame.data[data_start + 1..]);
sequence = (sequence + 1) & 0x0F;
}
data.truncate(length);
Ok(data)
}
}
impl<P: PhysicalLayer> TransportLayer for IsoTp<P> {
type Config = IsoTpConfig;
fn new(_config: Self::Config) -> Result<Self> {
Err(AutomotiveError::NotInitialized) }
fn open(&mut self) -> Result<()> {
if self.is_open {
return Ok(());
}
self.physical.set_timeout(self.config.timing.n_as)?;
self.is_open = true;
Ok(())
}
fn close(&mut self) -> Result<()> {
self.is_open = false;
Ok(())
}
fn write_frame(&mut self, frame: &Frame) -> Result<()> {
if !self.is_open {
return Err(AutomotiveError::NotInitialized);
}
self.physical.send_frame(frame)
}
fn read_frame(&mut self) -> Result<Frame> {
if !self.is_open {
return Err(AutomotiveError::NotInitialized);
}
self.physical.receive_frame()
}
fn set_timeout(&mut self, timeout_ms: u32) -> Result<()> {
if !self.is_open {
return Err(AutomotiveError::NotInitialized);
}
self.physical.set_timeout(timeout_ms)
}
}
impl<P: PhysicalLayer> IsoTpTransport for IsoTp<P> {
fn send(&mut self, data: &[u8]) -> Result<()> {
if !self.is_open {
return Err(AutomotiveError::NotInitialized);
}
if data.is_empty() {
return Err(AutomotiveError::InvalidParameter);
}
if data.len() <= 7 {
self.send_single_frame(data)
} else {
self.send_multi_frame(data)
}
}
fn receive(&mut self) -> Result<Vec<u8>> {
if !self.is_open {
return Err(AutomotiveError::NotInitialized);
}
let frame = self.read_frame()?;
if frame.data.is_empty() {
return Err(AutomotiveError::InvalidParameter);
}
let data_start = if self.config.address_mode == AddressMode::Extended {
1
} else {
0
};
match frame.data[data_start] & 0xF0 {
0x00 => self.receive_single_frame(&frame),
0x10 => self.receive_multi_frame(&frame),
_ => Err(AutomotiveError::InvalidParameter),
}
}
}