use super::PhysicalLayer;
use crate::error::{AutomotiveError, Result};
use crate::types::{Config, Frame};
use std::sync::Arc;
use std::sync::Mutex;
pub type MockFrameHandler = Box<dyn Fn(&Frame) -> Result<Frame> + Send + Sync>;
#[derive(Debug, Default)]
pub struct MockConfig {
pub timeout_ms: u32,
}
impl Config for MockConfig {
fn validate(&self) -> Result<()> {
Ok(())
}
}
pub struct MockPhysical {
config: MockConfig,
frame_handler: Option<MockFrameHandler>,
is_open: bool,
last_frame: Arc<Mutex<Option<Frame>>>,
}
impl MockPhysical {
pub fn new(frame_handler: Option<MockFrameHandler>) -> Self {
Self {
config: MockConfig::default(),
frame_handler,
is_open: false,
last_frame: Arc::new(Mutex::new(None)),
}
}
pub fn new_echo() -> Self {
Self::new(Some(Box::new(|frame: &Frame| Ok(frame.clone()))))
}
pub fn new_error() -> Self {
Self::new(Some(Box::new(|_: &Frame| {
Err(AutomotiveError::NotInitialized)
})))
}
pub fn set_frame_handler(&mut self, handler: Option<MockFrameHandler>) {
self.frame_handler = handler;
}
}
impl PhysicalLayer for MockPhysical {
type Config = MockConfig;
fn new(config: Self::Config) -> Result<Self> {
Ok(Self {
config,
frame_handler: None,
is_open: false,
last_frame: Arc::new(Mutex::new(None)),
})
}
fn open(&mut self) -> Result<()> {
self.is_open = true;
Ok(())
}
fn close(&mut self) -> Result<()> {
self.is_open = false;
Ok(())
}
fn send_frame(&mut self, frame: &Frame) -> Result<()> {
if !self.is_open {
return Err(AutomotiveError::NotInitialized);
}
if let Ok(mut last_frame) = self.last_frame.lock() {
*last_frame = Some(frame.clone());
}
Ok(())
}
fn receive_frame(&mut self) -> Result<Frame> {
if !self.is_open {
return Err(AutomotiveError::NotInitialized);
}
if let Some(handler) = &self.frame_handler {
let last_frame = self.last_frame.lock().unwrap();
if let Some(frame) = last_frame.as_ref() {
let response = handler(frame)?;
return Ok(response);
}
let default_frame = Frame {
id: 0x7E8,
data: vec![0x00, 0x00], timestamp: 0,
is_extended: false,
is_fd: false,
};
return handler(&default_frame);
}
Err(AutomotiveError::NotInitialized)
}
fn set_timeout(&mut self, timeout_ms: u32) -> Result<()> {
if !self.is_open {
return Err(AutomotiveError::NotInitialized);
}
self.config.timeout_ms = timeout_ms;
Ok(())
}
}