From 7833a829992bd042b2ae3f54ebd8009a56db84d6 Mon Sep 17 00:00:00 2001 From: Willem Melching Date: Wed, 20 Mar 2024 20:14:33 +0100 Subject: [PATCH] Clean up API and Errors (#49) * refactor can stuff into own module * clean up api and error types --- README.md | 4 +- examples/can_printer.rs | 2 +- examples/isotp.rs | 2 +- examples/query_fw_versions.rs | 8 +-- examples/uds.rs | 4 +- src/{ => can}/adapter.rs | 2 +- src/{ => can}/async_can.rs | 0 src/{can.rs => can/mod.rs} | 6 ++ src/error.rs | 6 +- src/isotp/mod.rs | 51 ++++++++-------- src/lib.rs | 13 +++-- src/panda/mod.rs | 42 +++++++------ src/socketcan/mod.rs | 2 +- src/uds/mod.rs | 107 ++++++++++++---------------------- tests/adapter_tests.rs | 2 +- tests/isotp_tests.rs | 2 +- tests/uds_tests.rs | 6 +- 17 files changed, 115 insertions(+), 144 deletions(-) rename src/{ => can}/adapter.rs (86%) rename src/{ => can}/async_can.rs (100%) rename src/{can.rs => can/mod.rs} (97%) diff --git a/README.md b/README.md index 89506f6..771b006 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ Welcome to the `automotive` crate documentation. The purpose of this crate is to The following adapter opens the first available adapter on the system, and then receives all frames. ```rust -let adapter = automotive::adapter::get_adapter().unwrap(); +let adapter = automotive::can::get_adapter().unwrap(); let mut stream = adapter.recv(); while let Some(frame) = stream.next().await { @@ -23,7 +23,7 @@ while let Some(frame) = stream.next().await { The automotive crate also supplies interfaces for various diagnostic protocols such as UDS. The adapter is first wrapped to support the ISO Transport Layer, then a UDS Client is created. All methods are fully async, making it easy to communicate with multiple ECUs in parallel. See [https://github.com/I-CAN-hack/automotive/issues/21](https://github.com/I-CAN-hack/automotive/issues/21) for progress on the supported SIDs. ```rust -let adapter = automotive::adapter::get_adapter().unwrap(); +let adapter = automotive::can::get_adapter().unwrap(); let isotp = automotive::isotp::IsoTPAdapter::from_id(&adapter, 0x7a1); let uds = automotive::uds::UDSClient::new(&isotp); diff --git a/examples/can_printer.rs b/examples/can_printer.rs index 714fe06..da7bbde 100644 --- a/examples/can_printer.rs +++ b/examples/can_printer.rs @@ -5,7 +5,7 @@ use tracing_subscriber; async fn main() { tracing_subscriber::fmt::init(); - let adapter = automotive::adapter::get_adapter().unwrap(); + let adapter = automotive::can::get_adapter().unwrap(); let mut stream = adapter.recv(); while let Some(frame) = stream.next().await { diff --git a/examples/isotp.rs b/examples/isotp.rs index 0f14a19..b3f1e13 100644 --- a/examples/isotp.rs +++ b/examples/isotp.rs @@ -7,7 +7,7 @@ use tracing_subscriber; async fn main() { tracing_subscriber::fmt::init(); - let adapter = automotive::adapter::get_adapter().unwrap(); + let adapter = automotive::can::get_adapter().unwrap(); let config = IsoTPConfig::new(0, Identifier::Standard(0x7a1)); let isotp = IsoTPAdapter::new(&adapter, config); diff --git a/examples/query_fw_versions.rs b/examples/query_fw_versions.rs index 10a637e..1fb564f 100644 --- a/examples/query_fw_versions.rs +++ b/examples/query_fw_versions.rs @@ -1,9 +1,9 @@ -use automotive::async_can::AsyncCanAdapter; +use automotive::can::AsyncCanAdapter; use automotive::can::Identifier; -use automotive::error::Error; use automotive::isotp::{IsoTPAdapter, IsoTPConfig}; +use automotive::Error; -use automotive::uds::constants::DataIdentifier; +use automotive::uds::DataIdentifier; use automotive::uds::UDSClient; use bstr::ByteSlice; @@ -43,7 +43,7 @@ async fn get_version(adapter: &AsyncCanAdapter, identifier: u32) -> Result<(), E async fn main() { tracing_subscriber::fmt::init(); - let adapter = automotive::adapter::get_adapter().unwrap(); + let adapter = automotive::can::get_adapter().unwrap(); let standard_ids = 0x700..=0x7ff; let extended_ids = (0x00..=0xff).map(|i| 0x18da0000 + (i << 8) + 0xf1); diff --git a/examples/uds.rs b/examples/uds.rs index 8d1f775..45d223e 100644 --- a/examples/uds.rs +++ b/examples/uds.rs @@ -1,11 +1,11 @@ -use automotive::uds::constants::{DataIdentifier, SessionType}; +use automotive::uds::{DataIdentifier, SessionType}; use bstr::ByteSlice; #[tokio::main] async fn main() -> Result<(), Box> { tracing_subscriber::fmt::init(); - let adapter = automotive::adapter::get_adapter()?; + let adapter = automotive::can::get_adapter()?; let isotp = automotive::isotp::IsoTPAdapter::from_id(&adapter, 0x7a1); let uds = automotive::uds::UDSClient::new(&isotp); diff --git a/src/adapter.rs b/src/can/adapter.rs similarity index 86% rename from src/adapter.rs rename to src/can/adapter.rs index a00dc1c..bcc8286 100644 --- a/src/adapter.rs +++ b/src/can/adapter.rs @@ -1,7 +1,7 @@ //! Convenience functions to get a CAN adapter. /// Convenience function to get the first available adapter on the system. Supports both comma.ai panda, and SocketCAN. -pub fn get_adapter() -> Result { +pub fn get_adapter() -> Result { if let Ok(panda) = crate::panda::Panda::new_async() { return Ok(panda); } diff --git a/src/async_can.rs b/src/can/async_can.rs similarity index 100% rename from src/async_can.rs rename to src/can/async_can.rs diff --git a/src/can.rs b/src/can/mod.rs similarity index 97% rename from src/can.rs rename to src/can/mod.rs index cceccf8..12a6562 100644 --- a/src/can.rs +++ b/src/can/mod.rs @@ -1,7 +1,13 @@ //! Generic CAN types and traits +pub mod adapter; +pub mod async_can; + use std::fmt; +pub use adapter::get_adapter; +pub use async_can::AsyncCanAdapter; + pub static DLC_TO_LEN: &[usize] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 12, 16, 20, 24, 32, 48, 64]; /// Identifier for a CAN frame diff --git a/src/error.rs b/src/error.rs index 6d522d0..7f8b337 100644 --- a/src/error.rs +++ b/src/error.rs @@ -13,13 +13,13 @@ pub enum Error { #[error("Timeout")] Timeout, #[error(transparent)] - IsoTPError(#[from] crate::isotp::error::Error), + IsoTPError(#[from] crate::isotp::Error), #[error(transparent)] LibUsbError(#[from] rusb::Error), #[error(transparent)] - PandaError(#[from] crate::panda::error::Error), + PandaError(#[from] crate::panda::Error), #[error(transparent)] - UDSError(#[from] crate::uds::error::Error), + UDSError(#[from] crate::uds::Error), } impl From for Error { diff --git a/src/isotp/mod.rs b/src/isotp/mod.rs index c7b1a2c..f2f309b 100644 --- a/src/isotp/mod.rs +++ b/src/isotp/mod.rs @@ -3,7 +3,7 @@ //! ```rust //! use futures_util::stream::StreamExt; //! async fn isotp_example() { -//! let adapter = automotive::adapter::get_adapter().unwrap(); +//! let adapter = automotive::can::get_adapter().unwrap(); //! let config = automotive::isotp::IsoTPConfig::new(0, automotive::can::Identifier::Standard(0x7a1)); //! let isotp = automotive::isotp::IsoTPAdapter::new(&adapter, config); //! @@ -13,17 +13,16 @@ //! } //! ``` -pub mod constants; -pub mod error; -pub mod types; +mod constants; +mod error; +mod types; -use crate::async_can::AsyncCanAdapter; -use crate::can::{Frame, Identifier, DLC_TO_LEN}; -use crate::error::Error; -use crate::isotp::constants::FlowStatus; -use crate::isotp::constants::FLOW_SATUS_MASK; -use crate::isotp::constants::{FrameType, FRAME_TYPE_MASK}; +pub use constants::{FlowStatus, FrameType, FLOW_SATUS_MASK, FRAME_TYPE_MASK}; +pub use error::Error; +use crate::can::AsyncCanAdapter; +use crate::can::{Frame, Identifier, DLC_TO_LEN}; +use crate::Result; use async_stream::stream; use futures_core::stream::Stream; use tokio_stream::{StreamExt, Timeout}; @@ -175,7 +174,7 @@ impl<'a> IsoTPAdapter<'a> { } /// Build a CAN frame from the payload. Inserts extended address and padding if needed. - fn frame(&self, data: &[u8]) -> Result { + fn frame(&self, data: &[u8]) -> Result { let mut data = data.to_vec(); if let Some(ext_address) = self.config.ext_address { @@ -185,7 +184,7 @@ impl<'a> IsoTPAdapter<'a> { // Check if the data length is valid if !DLC_TO_LEN.contains(&data.len()) { println!("len {}", data.len()); - return Err(crate::error::Error::MalformedFrame); + return Err(crate::Error::MalformedFrame); } let frame = Frame { @@ -199,7 +198,7 @@ impl<'a> IsoTPAdapter<'a> { Ok(frame) } - pub async fn send_single_frame(&self, data: &[u8]) -> Result<(), Error> { + pub async fn send_single_frame(&self, data: &[u8]) -> Result<()> { let mut buf; if data.len() < 0xf { @@ -220,7 +219,7 @@ impl<'a> IsoTPAdapter<'a> { Ok(()) } - pub async fn send_first_frame(&self, data: &[u8]) -> Result { + pub async fn send_first_frame(&self, data: &[u8]) -> Result { let mut buf; if data.len() <= ISO_TP_MAX_DLEN { let b0: u8 = FrameType::First as u8 | ((data.len() >> 8) & 0xF) as u8; @@ -242,7 +241,7 @@ impl<'a> IsoTPAdapter<'a> { Ok(offset) } - pub async fn send_consecutive_frame(&self, data: &[u8], idx: usize) -> Result<(), Error> { + pub async fn send_consecutive_frame(&self, data: &[u8], idx: usize) -> Result<()> { let idx = ((idx + 1) & 0xF) as u8; let mut buf = vec![FrameType::Consecutive as u8 | idx]; @@ -261,7 +260,7 @@ impl<'a> IsoTPAdapter<'a> { async fn receive_flow_control( &self, stream: &mut std::pin::Pin<&mut Timeout>>, - ) -> Result { + ) -> Result { for _ in 0..MAX_WAIT_FC { let mut frame = stream.next().await.unwrap()?; @@ -296,7 +295,7 @@ impl<'a> IsoTPAdapter<'a> { Err(crate::isotp::error::Error::TooManyFCWait.into()) } - async fn send_multiple(&self, data: &[u8]) -> Result<(), Error> { + async fn send_multiple(&self, data: &[u8]) -> Result<()> { // Stream for receiving flow control let stream = self .adapter @@ -346,7 +345,7 @@ impl<'a> IsoTPAdapter<'a> { } /// Asynchronously send an ISO-TP frame of up to 4095 bytes. Returns [`Error::Timeout`] if the ECU is not responding in time with flow control messages. - pub async fn send(&self, data: &[u8]) -> Result<(), Error> { + pub async fn send(&self, data: &[u8]) -> Result<()> { debug!("TX {}", hex::encode(data)); // Single frame has 1 byte of overhead for CAN, and 2 bytes for CAN-FD with escape sequence @@ -364,7 +363,7 @@ impl<'a> IsoTPAdapter<'a> { Ok(()) } - async fn recv_single_frame(&self, data: &[u8]) -> Result, Error> { + async fn recv_single_frame(&self, data: &[u8]) -> Result> { let mut len = (data[0] & 0xF) as usize; let mut offset = 1; @@ -384,7 +383,7 @@ impl<'a> IsoTPAdapter<'a> { Ok(data[offset..len + offset].to_vec()) } - async fn recv_first_frame(&self, data: &[u8], buf: &mut Vec) -> Result { + async fn recv_first_frame(&self, data: &[u8], buf: &mut Vec) -> Result { let b0 = data[0] as u16; let b1 = data[1] as u16; let mut len = ((b0 << 8 | b1) & 0xFFF) as usize; @@ -422,7 +421,7 @@ impl<'a> IsoTPAdapter<'a> { buf: &mut Vec, len: usize, idx: u8, - ) -> Result { + ) -> Result { let msg_idx = data[0] & 0xF; let remaining_len = len - buf.len(); @@ -462,7 +461,7 @@ impl<'a> IsoTPAdapter<'a> { async fn recv_from_stream( &self, stream: &mut std::pin::Pin<&mut Timeout>>, - ) -> Result, Error> { + ) -> Result> { let mut buf = Vec::new(); let mut len: Option = None; let mut idx: u8 = 1; @@ -478,7 +477,7 @@ impl<'a> IsoTPAdapter<'a> { Some(FrameType::First) => { // If we already received a first frame, something went wrong if len.is_some() { - return Err(Error::IsoTPError(crate::isotp::error::Error::OutOfOrder)); + return Err(Error::OutOfOrder.into()); } len = Some(self.recv_first_frame(data, &mut buf).await?); } @@ -491,12 +490,12 @@ impl<'a> IsoTPAdapter<'a> { return Ok(buf); } } else { - return Err(Error::IsoTPError(crate::isotp::error::Error::OutOfOrder)); + return Err(Error::OutOfOrder.into()); } } Some(FrameType::FlowControl) => {} // Ignore flow control frames, these are from a simultaneous transmission _ => { - return Err(crate::isotp::error::Error::UnknownFrameType.into()); + return Err(Error::UnknownFrameType.into()); } }; } @@ -504,7 +503,7 @@ impl<'a> IsoTPAdapter<'a> { } /// Stream of ISO-TP packets. Can be used if multiple responses are expected from a single request. Returns [`Error::Timeout`] if the timeout is exceeded between individual ISO-TP frames. Note the total time to receive a packet may be longer than the timeout. - pub fn recv(&self) -> impl Stream, Error>> + '_ { + pub fn recv(&self) -> impl Stream>> + '_ { let stream = self .adapter .recv_filter(|frame| { diff --git a/src/lib.rs b/src/lib.rs index 0315ea8..02c22d6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,7 +8,7 @@ //! ```rust //! use futures_util::stream::StreamExt; //! async fn can_example() { -//! let adapter = automotive::adapter::get_adapter().unwrap(); +//! let adapter = automotive::can::get_adapter().unwrap(); //! let mut stream = adapter.recv(); //! //! while let Some(frame) = stream.next().await { @@ -24,12 +24,12 @@ //! //! ```rust //! async fn uds_example() { -//! let adapter = automotive::adapter::get_adapter().unwrap(); +//! let adapter = automotive::can::get_adapter().unwrap(); //! let isotp = automotive::isotp::IsoTPAdapter::from_id(&adapter, 0x7a1); //! let uds = automotive::uds::UDSClient::new(&isotp); //! //! uds.tester_present().await.unwrap(); -//! let response = uds.read_data_by_identifier(automotive::uds::constants::DataIdentifier::ApplicationSoftwareIdentification as u16).await.unwrap(); +//! let response = uds.read_data_by_identifier(automotive::uds::DataIdentifier::ApplicationSoftwareIdentification as u16).await.unwrap(); //! //! println!("Application Software Identification: {}", hex::encode(response)); //! } @@ -40,13 +40,14 @@ //! - comma.ai panda (all platforms) //! -pub mod adapter; -pub mod async_can; pub mod can; -pub mod error; +mod error; pub mod isotp; pub mod panda; pub mod uds; +pub use error::Error; +pub type Result = std::result::Result; + #[cfg(target_os = "linux")] pub mod socketcan; diff --git a/src/panda/mod.rs b/src/panda/mod.rs index c849920..432ba69 100644 --- a/src/panda/mod.rs +++ b/src/panda/mod.rs @@ -1,15 +1,16 @@ //! Panda CAN adapter support mod constants; -pub mod error; +mod error; mod usb_protocol; +pub use error::Error; use std::vec; -use crate::async_can::AsyncCanAdapter; +use crate::can::AsyncCanAdapter; use crate::can::CanAdapter; -use crate::error::Error; use crate::panda::constants::{Endpoint, HwType, SafetyModel}; +use crate::Result; use tracing::{info, warn}; const VENDOR_ID: u16 = 0xbbaa; @@ -35,13 +36,13 @@ unsafe impl Send for Panda {} impl Panda { /// Convenience function to create a new panda adapter and wrap in an [`AsyncCanAdapter`] - pub fn new_async() -> Result { + pub fn new_async() -> Result { let panda = Panda::new()?; Ok(AsyncCanAdapter::new(panda)) } /// Connect to the first available panda. This function will set the safety mode to ALL_OUTPUT and clear all buffers. - pub fn new() -> Result { + pub fn new() -> Result { for device in rusb::devices().unwrap().iter() { let device_desc = device.device_descriptor().unwrap(); @@ -63,9 +64,7 @@ impl Panda { // Check panda firmware version let versions = panda.get_packets_versions()?; if versions.can_version != EXPECTED_CAN_PACKET_VERSION { - return Err(Error::PandaError( - crate::panda::error::Error::WrongFirmwareVersion, - )); + return Err(Error::WrongFirmwareVersion.into()); } panda.set_safety_model(SafetyModel::AllOutput)?; @@ -81,10 +80,10 @@ impl Panda { return Ok(panda); } - Err(Error::NotFound) + Err(crate::Error::NotFound) } - fn flush_rx(&self) -> Result<(), Error> { + fn flush_rx(&self) -> Result<()> { const N: usize = 16384; let mut buf: [u8; N] = [0; N]; @@ -100,27 +99,26 @@ impl Panda { } /// Change the safety model of the panda. This can be useful to switch to Silent mode or open/close the relay in the comma.ai harness - pub fn set_safety_model(&self, safety_model: SafetyModel) -> Result<(), Error> { + pub fn set_safety_model(&self, safety_model: SafetyModel) -> Result<()> { let safety_param: u16 = 0; self.usb_write_control(Endpoint::SafetyModel, safety_model as u16, safety_param) } - fn set_heartbeat_disabled(&self) -> Result<(), Error> { + fn set_heartbeat_disabled(&self) -> Result<()> { self.usb_write_control(Endpoint::HeartbeatDisabled, 0, 0) } - fn set_power_save(&self, power_save_enabled: bool) -> Result<(), Error> { + fn set_power_save(&self, power_save_enabled: bool) -> Result<()> { self.usb_write_control(Endpoint::PowerSave, power_save_enabled as u16, 0) } /// Get the hardware type of the panda. Usefull to detect if it supports CAN-FD. - pub fn get_hw_type(&self) -> Result { + pub fn get_hw_type(&self) -> Result { let hw_type = self.usb_read_control(Endpoint::HwType, 1)?; - HwType::from_repr(hw_type[0]) - .ok_or(Error::PandaError(crate::panda::error::Error::UnknownHwType)) + HwType::from_repr(hw_type[0]).ok_or(Error::UnknownHwType.into()) } - fn get_packets_versions(&self) -> Result { + fn get_packets_versions(&self) -> Result { let versions = self.usb_read_control(Endpoint::PacketsVersions, 3)?; Ok({ Versions { @@ -131,11 +129,11 @@ impl Panda { }) } - fn can_reset_communications(&self) -> Result<(), Error> { + fn can_reset_communications(&self) -> Result<()> { self.usb_write_control(Endpoint::CanResetCommunications, 0, 0) } - fn usb_read_control(&self, endpoint: Endpoint, n: usize) -> Result, Error> { + fn usb_read_control(&self, endpoint: Endpoint, n: usize) -> Result> { let mut buf: Vec = vec![0; n]; let request_type = rusb::request_type( @@ -150,7 +148,7 @@ impl Panda { Ok(buf) } - fn usb_write_control(&self, endpoint: Endpoint, value: u16, index: u16) -> Result<(), Error> { + fn usb_write_control(&self, endpoint: Endpoint, value: u16, index: u16) -> Result<()> { let request_type = rusb::request_type( rusb::Direction::Out, rusb::RequestType::Standard, @@ -170,7 +168,7 @@ impl Panda { impl CanAdapter for Panda { /// Sends a buffer of CAN messages to the panda. - fn send(&mut self, frames: &[crate::can::Frame]) -> Result<(), Error> { + fn send(&mut self, frames: &[crate::can::Frame]) -> Result<()> { if frames.is_empty() { return Ok(()); } @@ -185,7 +183,7 @@ impl CanAdapter for Panda { } /// Reads the current buffer of available CAN messages from the panda. This function will return an empty vector if no messages are available. In case of a recoverable error (e.g. unpacking error), the buffer will be cleared and an empty vector will be returned. - fn recv(&mut self) -> Result, Error> { + fn recv(&mut self) -> Result> { let mut buf: [u8; MAX_BULK_SIZE] = [0; MAX_BULK_SIZE]; let recv: usize = self diff --git a/src/socketcan/mod.rs b/src/socketcan/mod.rs index dd5cece..833fbd7 100644 --- a/src/socketcan/mod.rs +++ b/src/socketcan/mod.rs @@ -1,5 +1,5 @@ //! This module provides a [`CanAdapter`] implementation for the [`socketcan`] crate. -use crate::async_can::AsyncCanAdapter; +use crate::can::AsyncCanAdapter; use crate::can::CanAdapter; use crate::error::Error; diff --git a/src/uds/mod.rs b/src/uds/mod.rs index ac4b7fd..bdecbae 100644 --- a/src/uds/mod.rs +++ b/src/uds/mod.rs @@ -2,24 +2,24 @@ //! ## Example //! ```rust //! async fn uds_example() { -//! let adapter = automotive::adapter::get_adapter().unwrap(); +//! let adapter = automotive::can::get_adapter().unwrap(); //! let isotp = automotive::isotp::IsoTPAdapter::from_id(&adapter, 0x7a1); //! let uds = automotive::uds::UDSClient::new(&isotp); //! //! uds.tester_present().await.unwrap(); -//! let response = uds.read_data_by_identifier(automotive::uds::constants::DataIdentifier::ApplicationSoftwareIdentification as u16).await.unwrap(); +//! let response = uds.read_data_by_identifier(automotive::uds::DataIdentifier::ApplicationSoftwareIdentification as u16).await.unwrap(); //! //! println!("Application Software Identification: {}", hex::encode(response)); //! } -pub mod constants; -pub mod error; -pub mod types; +mod constants; +mod error; +mod types; -use crate::error::Error; use crate::isotp::IsoTPAdapter; -use crate::uds::constants::{ServiceIdentifier, NEGATIVE_RESPONSE, POSITIVE_RESPONSE}; -use crate::uds::error::NegativeResponseCode; +use crate::Result; +pub use constants::*; +pub use error::{Error, NegativeResponseCode}; use tokio_stream::StreamExt; use tracing::info; @@ -40,7 +40,7 @@ impl<'a> UDSClient<'a> { sid: u8, sub_function: Option, data: Option<&[u8]>, - ) -> Result, Error> { + ) -> Result> { let mut request: Vec = vec![sid]; if let Some(sub_function) = sub_function { @@ -68,24 +68,18 @@ impl<'a> UDSClient<'a> { continue; } - return Err(Error::UDSError(crate::uds::error::Error::NegativeResponse( - code, - ))); + return Err(Error::NegativeResponse(code).into()); } // Check service id if response_sid != sid | POSITIVE_RESPONSE { - return Err(Error::UDSError(crate::uds::error::Error::InvalidServiceId( - response_sid, - ))); + return Err(Error::InvalidServiceId(response_sid).into()); } // Check sub function if let Some(sub_function) = sub_function { if response[1] != sub_function { - return Err(Error::UDSError( - crate::uds::error::Error::InvalidSubFunction(response[1]), - )); + return Err(Error::InvalidSubFunction(response[1]).into()); } } @@ -98,7 +92,7 @@ impl<'a> UDSClient<'a> { pub async fn diagnostic_session_control( &self, session_type: u8, - ) -> Result, Error> { + ) -> Result> { let result = self .request( ServiceIdentifier::DiagnosticSessionControl as u8, @@ -126,7 +120,7 @@ impl<'a> UDSClient<'a> { } /// 0x11 - ECU Reset. The `reset_type` parameter can be used to specify the type of reset to perform. Use the [`constants::ResetType`] enum for the reset types defined in the standard. This function returns the power down time when the reset type is [`constants::ResetType::EnableRapidPowerShutDown`]. - pub async fn ecu_reset(&self, reset_type: u8) -> Result, Error> { + pub async fn ecu_reset(&self, reset_type: u8) -> Result> { let result = self .request(ServiceIdentifier::EcuReset as u8, Some(reset_type), None) .await?; @@ -141,11 +135,7 @@ impl<'a> UDSClient<'a> { } /// 0x27 - Security Access. Odd `access_type` values are used to request a seed, even values to send a key. The `data` parameter is optional when requesting a seed. You can use the [`constants::SecurityAccessType`] enum for the default security level. - pub async fn security_access( - &self, - access_type: u8, - data: Option<&[u8]>, - ) -> Result, Error> { + pub async fn security_access(&self, access_type: u8, data: Option<&[u8]>) -> Result> { let send_key = access_type % 2 == 0; if send_key && data.is_none() { panic!("Missing data parameter when sending key"); @@ -163,7 +153,7 @@ impl<'a> UDSClient<'a> { } /// 0x3E - Tester Present - pub async fn tester_present(&self) -> Result<(), Error> { + pub async fn tester_present(&self) -> Result<()> { self.request(ServiceIdentifier::TesterPresent as u8, Some(0), None) .await?; Ok(()) @@ -175,7 +165,7 @@ impl<'a> UDSClient<'a> { memory_address: &[u8], memory_size: &[u8], data: Option<&[u8]>, - ) -> Result, Error> { + ) -> Result> { assert!( sid == ServiceIdentifier::ReadMemoryByAddress || sid == ServiceIdentifier::WriteMemoryByAddress @@ -197,7 +187,7 @@ impl<'a> UDSClient<'a> { } /// 0x22 - Read Data By Identifier. Specify a 16 bit data identifier, or use a constant from [`constants::DataIdentifier`] for standardized identifiers. Reading multiple identifiers simultaneously is possible on some ECUs, but not supported by this function. - pub async fn read_data_by_identifier(&self, data_identifier: u16) -> Result, Error> { + pub async fn read_data_by_identifier(&self, data_identifier: u16) -> Result> { let did = data_identifier.to_be_bytes(); let resp = self .request( @@ -208,16 +198,12 @@ impl<'a> UDSClient<'a> { .await?; if resp.len() < 2 { - return Err(Error::UDSError( - crate::uds::error::Error::InvalidResponseLength, - )); + return Err(Error::InvalidResponseLength.into()); } let did = u16::from_be_bytes([resp[0], resp[1]]); if did != data_identifier { - return Err(Error::UDSError( - crate::uds::error::Error::InvalidDataIdentifier(did), - )); + return Err(Error::InvalidDataIdentifier(did).into()); } Ok(resp[2..].to_vec()) @@ -228,7 +214,7 @@ impl<'a> UDSClient<'a> { &self, memory_address: &[u8], memory_size: &[u8], - ) -> Result, Error> { + ) -> Result> { self.read_write_memory_by_adddress( ServiceIdentifier::ReadMemoryByAddress, memory_address, @@ -243,7 +229,7 @@ impl<'a> UDSClient<'a> { &self, data_identifier: u16, data_record: &[u8], - ) -> Result<(), Error> { + ) -> Result<()> { let mut data: Vec = data_identifier.to_be_bytes().to_vec(); data.extend(data_record); @@ -256,16 +242,12 @@ impl<'a> UDSClient<'a> { .await?; if resp.len() < 2 { - return Err(Error::UDSError( - crate::uds::error::Error::InvalidResponseLength, - )); + return Err(Error::InvalidResponseLength.into()); } let did = u16::from_be_bytes([resp[0], resp[1]]); if did != data_identifier { - return Err(Error::UDSError( - crate::uds::error::Error::InvalidDataIdentifier(did), - )); + return Err(Error::InvalidDataIdentifier(did).into()); } Ok(()) @@ -277,7 +259,7 @@ impl<'a> UDSClient<'a> { memory_address: &[u8], memory_size: &[u8], data: &[u8], - ) -> Result<(), Error> { + ) -> Result<()> { self.read_write_memory_by_adddress( ServiceIdentifier::WriteMemoryByAddress, memory_address, @@ -294,7 +276,7 @@ impl<'a> UDSClient<'a> { routine_control_type: constants::RoutineControlType, routine_identifier: u16, data: Option<&[u8]>, - ) -> Result>, Error> { + ) -> Result>> { let mut buf: Vec = vec![]; buf.extend(routine_identifier.to_be_bytes()); if let Some(data) = data { @@ -310,16 +292,12 @@ impl<'a> UDSClient<'a> { .await?; if resp.len() < 2 { - return Err(Error::UDSError( - crate::uds::error::Error::InvalidResponseLength, - )); + return Err(Error::InvalidResponseLength.into()); } let id = u16::from_be_bytes([resp[0], resp[1]]); if id != routine_identifier { - return Err(Error::UDSError( - crate::uds::error::Error::InvalidDataIdentifier(id), - )); + return Err(Error::InvalidDataIdentifier(id).into()); } Ok(if resp.len() > 2 { @@ -336,7 +314,7 @@ impl<'a> UDSClient<'a> { encryption_method: u8, memory_address: &[u8], memory_size: &[u8], - ) -> Result { + ) -> Result { assert!( sid == ServiceIdentifier::RequestDownload || sid == ServiceIdentifier::RequestUpload ); @@ -357,16 +335,12 @@ impl<'a> UDSClient<'a> { // Ensure the response contains at least a length format if resp.is_empty() { - return Err(Error::UDSError( - crate::uds::error::Error::InvalidResponseLength, - )); + return Err(Error::InvalidResponseLength.into()); } let num_length_bytes = (resp[0] >> 4) as usize; if num_length_bytes == 0 || num_length_bytes > 8 || resp.len() != num_length_bytes + 1 { - return Err(Error::UDSError( - crate::uds::error::Error::InvalidResponseLength, - )); + return Err(Error::InvalidResponseLength.into()); } // Convert the length bytes to a usize @@ -384,7 +358,7 @@ impl<'a> UDSClient<'a> { encryption_method: u8, memory_address: &[u8], memory_size: &[u8], - ) -> Result { + ) -> Result { self.request_download_upload( ServiceIdentifier::RequestDownload, compression_method, @@ -402,7 +376,7 @@ impl<'a> UDSClient<'a> { encryption_method: u8, memory_address: &[u8], memory_size: &[u8], - ) -> Result { + ) -> Result { self.request_download_upload( ServiceIdentifier::RequestUpload, compression_method, @@ -418,7 +392,7 @@ impl<'a> UDSClient<'a> { &self, block_sequence_counter: u8, data: Option<&[u8]>, - ) -> Result>, Error> { + ) -> Result>> { let mut buf: Vec = vec![block_sequence_counter]; if let Some(data) = data { buf.extend(data); @@ -430,16 +404,12 @@ impl<'a> UDSClient<'a> { // Ensure the response contains at least the block sequence counter if resp.is_empty() { - return Err(Error::UDSError( - crate::uds::error::Error::InvalidResponseLength, - )); + return Err(Error::InvalidResponseLength.into()); } // Check block sequence counter if resp[0] != block_sequence_counter { - return Err(Error::UDSError( - crate::uds::error::Error::InvalidBlockSequenceCounter(resp[0]), - )); + return Err(Error::InvalidBlockSequenceCounter(resp[0]).into()); } Ok(if resp.len() > 1 { @@ -450,10 +420,7 @@ impl<'a> UDSClient<'a> { } /// 0x37 - Request Transfer Exit. Used to terminate an upload or download. Has optional `data` parameter for additional information, and can optionally return additional information from the ECU. For example, this can be used to contain a checksum. - pub async fn request_transfer_exit( - &self, - data: Option<&[u8]>, - ) -> Result>, Error> { + pub async fn request_transfer_exit(&self, data: Option<&[u8]>) -> Result>> { let resp = self .request(ServiceIdentifier::RequestTransferExit as u8, None, data) .await?; diff --git a/tests/adapter_tests.rs b/tests/adapter_tests.rs index 3c01349..81244e8 100644 --- a/tests/adapter_tests.rs +++ b/tests/adapter_tests.rs @@ -1,5 +1,5 @@ #![allow(dead_code, unused_imports)] -use automotive::async_can::AsyncCanAdapter; +use automotive::can::AsyncCanAdapter; use automotive::can::{CanAdapter, Frame}; use automotive::panda::Panda; use std::time::Duration; diff --git a/tests/isotp_tests.rs b/tests/isotp_tests.rs index c235997..7873c6e 100644 --- a/tests/isotp_tests.rs +++ b/tests/isotp_tests.rs @@ -1,5 +1,5 @@ #![allow(dead_code, unused_imports)] -use automotive::async_can::AsyncCanAdapter; +use automotive::can::AsyncCanAdapter; use automotive::can::Identifier; use automotive::isotp::{IsoTPAdapter, IsoTPConfig}; use std::process::{Child, Command}; diff --git a/tests/uds_tests.rs b/tests/uds_tests.rs index d1de2b9..78d4847 100644 --- a/tests/uds_tests.rs +++ b/tests/uds_tests.rs @@ -1,9 +1,9 @@ #![allow(dead_code, unused_imports)] -use automotive::async_can::AsyncCanAdapter; +use automotive::can::AsyncCanAdapter; use automotive::can::Identifier; use automotive::isotp::{IsoTPAdapter, IsoTPConfig}; -use automotive::uds::error::Error as UDSError; -use automotive::uds::error::NegativeResponseCode; +use automotive::uds::Error as UDSError; +use automotive::uds::NegativeResponseCode; use automotive::uds::UDSClient; use std::process::{Child, Command}; use tokio_stream::StreamExt;