1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
//! provides asynchronous UDS communication via socketcan.
//!
//! All communication was designed to be used primarily with ISO 14229-1:2013 definition of UDS.
//!
//! # Example
//!
//! For correct behaviour make sure to set-up a CAN interface first.
//! You an you a virtual CAN interface for testing purposes, for example with the following command.
//! To make setting-up a CAN interface easier install [can-utils-rs](https://crates.io/crates/can-utils-rs) package
//! ```bash
//! cargo install can-utils-rs
//! ```
//! Then use the following command:
//! ```bash
//! can-utils-rs
//! ```
//! Then select the interface type you want to use. Then make sure to match the name of the interface (can0 in the example)
//! with the one you have set-up.
//!
//! ```no_run
//! // To run the example make sure to set-up a CAN interface first!
//!
//! use embedded_can::StandardId;
//! use log::{error, info};
//! use uds_rs::{ResetType, UdsClient, UdsError, UdsSocketOptions};
//!
//! #[tokio::main(flavor = "current_thread")]
//! async fn main() -> Result<(), UdsError> {
//! env_logger::init();
//! // Create client wtih default options
//! let c = UdsClient::new(
//! "can0",
//! StandardId::new(0x774).expect("Invalid src id"),
//! StandardId::new(0x70A).expect("Invalid dst id"),
//! UdsSocketOptions::default(),
//! )?;
//!
//! // read data by identifier (ecu VIN)
//! let read_data_result = c.read_data_by_identifier(&[0xf18a]).await;
//! match read_data_result {
//! Ok(x) => info!("Read data by identifier received {:#x?}", x),
//! Err(e) => error!(
//! "Read single data by identifier failed with error: {:#x?}",
//! e
//! ),
//! };
//!
//! // reading dtc
//! let read_dtc_information = c.report_dtc_by_status_mask(0xff).await;
//! match read_dtc_information {
//! Ok(x) => info!("Read dtc by status mask: {:#x?}", x),
//! Err(e) => error!("Read dtc by status mask failed with error: {:#x?}", e),
//! }
//!
//! // clear all stored dtc
//! let clear_dtc_information = c.clear_diagnostic_information(0xffffff).await;
//! match clear_dtc_information {
//! Ok(x) => info!("{:#x?}", x),
//! Err(e) => error!("Clear diagnostic information failed with error: {:#x?}", e),
//! };
//!
//! // ecu reset
//! let ecu_reset_result = c.ecu_reset(ResetType::KeyOffOnReset).await;
//! match ecu_reset_result {
//! Ok(x) => info!("{:#x?}", x),
//! Err(e) => error!("Ecu reset failed with error: {:#x?}", e),
//! };
//!
//! Ok(())
//! }
//! ```
//!
//! ### Example with specific ISO-TP configuration
//!
//! ```no_run
//! // To run the example make sure to set-up a CAN interface first!
//!
//! use embedded_can::StandardId;
//! use log::{error, info};
//! use uds_rs::{ResetType, UdsClient, UdsError, UdsSocketOptions};
//!
//!
//! #[tokio::main(flavor = "current_thread")]
//! async fn main() -> Result<(), UdsError> {
//! env_logger::init();
//! // Create client with VW specific options
//! let socket_options = UdsSocketOptions::vw()?;
//! let c = UdsClient::new(
//! "can0",
//! StandardId::new(0x774).expect("Invalid src id"),
//! StandardId::new(0x70A).expect("Invalid dst id"),
//! socket_options,
//! )?;
//!
//! Ok(())
//!
//! }
//! ```
//!
//! # Notes for development
//! ## Communication architecture
//! Current communication architecture is strictly bounded request-response together. It would be
//! much better to have these two interactions separated into queues and adding one producer for writes and one consumer
//! for reads.
//!
//! Without this functionality the services like ReadDataByPeriodicIdentifier cannot be implemented.
//!
//! ## Hierarchy
//!
//! module __uds__ - top module containing UdsClient trough which all interaction is provided for the user
//! services used by UdsClient are stored in separate modules - see for example read_data_by_identifier.rs,
//! where structure of service module is described
//!
//! module __communication__ - basic communication framework. Purpose of this module is to provide send
//! and receive functionality for UdsClient.
//!
//! ## Services implementation
//! each service consists of three steps
//! __compose function__ - serializing service method arguments and other needed
//! data to Vec\<u8\>
//! __send and receive__ - passing composed vector as slice to the communication backend and returning raw response
//! __parse function__ - parsing received raw response &\[u8\] and serializing it into UdsMessage
//!
//! # Notes
//! For the correct behaviour, you need to have Linux kernel with applied patch:
//! <https://lore.kernel.org/linux-can/20230818114345.142983-1-lukas.magel@posteo.net/#r>
pub use *;