use crate::error::Result;
use crate::transport::transaction::Request;
use moteus_protocol::CanFdFrame;
use std::time::Duration;
#[cfg(feature = "tokio")]
use crate::transport::async_transport::BoxFuture;
#[non_exhaustive]
#[derive(Debug, Clone)]
pub struct TransportDeviceInfo {
pub id: usize,
pub name: String,
pub serial_number: Option<String>,
pub detail: Option<String>,
pub parent_index: Option<usize>,
pub empty_bus_tx_safe: bool,
}
impl TransportDeviceInfo {
pub fn new(id: usize, name: impl Into<String>) -> Self {
Self {
id,
name: name.into(),
serial_number: None,
detail: None,
parent_index: None,
empty_bus_tx_safe: true,
}
}
#[must_use]
pub fn with_serial(mut self, serial: impl Into<String>) -> Self {
self.serial_number = Some(serial.into());
self
}
#[must_use]
pub fn with_detail(mut self, detail: impl Into<String>) -> Self {
self.detail = Some(detail.into());
self
}
}
impl std::fmt::Display for TransportDeviceInfo {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match &self.detail {
Some(detail) => write!(f, "{}({})", self.name, detail),
None => write!(f, "{}()", self.name),
}
}
}
pub trait TransportDevice: Send {
fn transaction(&mut self, requests: &mut [Request]) -> Result<()>;
fn write(&mut self, frame: &CanFdFrame) -> Result<()>;
fn read(&mut self) -> Result<Option<CanFdFrame>>;
fn flush(&mut self) -> Result<()>;
fn empty_bus_tx_safe(&self) -> bool {
true
}
fn info(&self) -> &TransportDeviceInfo;
fn set_timeout(&mut self, timeout: Duration);
fn timeout(&self) -> Duration;
}
#[cfg(feature = "tokio")]
pub trait AsyncTransportDevice: Send {
fn recover(&mut self) -> BoxFuture<'_, Result<()>> {
Box::pin(async { Ok(()) })
}
fn transaction<'a>(&'a mut self, requests: &'a mut [Request]) -> BoxFuture<'a, Result<()>>;
fn write<'a>(&'a mut self, frame: &'a CanFdFrame) -> BoxFuture<'a, Result<()>>;
fn read(&mut self) -> BoxFuture<'_, Result<Option<CanFdFrame>>>;
fn flush(&mut self) -> BoxFuture<'_, Result<()>>;
fn empty_bus_tx_safe(&self) -> bool {
true
}
fn info(&self) -> &TransportDeviceInfo;
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_transport_device_info() {
let info = TransportDeviceInfo::new(0, "test").with_serial("ABC123");
assert_eq!(info.id, 0);
assert_eq!(info.name, "test");
assert_eq!(info.serial_number, Some("ABC123".to_string()));
}
}