1#![deny(clippy::all)]
2#![allow(dead_code)]
3mod communication;
79
80mod clear_diagnostic_information;
81mod ecu_reset;
82mod read_data_by_identifier;
83mod read_dtc_information;
84mod read_memory_by_address;
85mod uds_definitions;
86mod write_data_by_identifier;
87
88pub use crate::uds::clear_diagnostic_information::*;
89pub use crate::uds::communication::*;
90pub use crate::uds::ecu_reset::*;
91pub use crate::uds::read_data_by_identifier::*;
92pub use crate::uds::read_dtc_information::*;
93pub use crate::uds::read_memory_by_address::*;
94pub use crate::uds::uds_definitions::*;
95pub use crate::uds::write_data_by_identifier::*;
96#[allow(unused_imports)]
97use log::{debug, error, info, trace, warn};
98use thiserror::Error;
99
100pub type EcuResponseResult = Result<UdsResponse, UdsError>;
101
102#[derive(Debug, PartialEq)]
105pub enum UdsResponse {
106 EcuReset(DataFormat<EcuResetResponse>),
107 ReadDataByIdentifier(DataFormat<ReadDataByIdentifierResponse>),
108 ReadMemoryByAddress(DataFormat<ReadMemoryByAddressResponse>),
109 ReadDTCInformation(DataFormat<ReadDTCInformationResponse>),
110 ClearDiagnosticInformation,
111 WriteDataByIdentifier(DataFormat<WriteDataByIdentifierResponse>),
112}
113
114#[derive(Debug, PartialEq)]
118pub enum DataFormat<T> {
119 Parsed(T),
120 Raw(Vec<u8>),
121}
122
123#[derive(Error, Debug, PartialEq)]
125pub enum UdsError {
126 #[error(
127 "Response received does not have expected SID. Expected: {expected:x}, Received: {received:x}"
128 )]
129 SidMismatch {
130 expected: u8,
131 received: u8,
132 raw_message: Vec<u8>,
133 },
134 #[error("Sent and received data identifier don't match. Expected: {expected:x}, Received: {received:x}")]
135 DidMismatch {
136 expected: u16,
137 received: u16,
138 raw_message: Vec<u8>,
139 },
140 #[error("Received message doesn't correspond to expected length. Received message: {raw_message:x?}")]
141 InvalidLength { raw_message: Vec<u8> },
142 #[error("Negative response code was received: {nrc:?}")]
143 NRC { nrc: NrcData },
144 #[error("Was not able to represent provided NRC: {unknown_nrc:x} as the valid NRC")]
145 UnknownNRC { rejected_sid: u8, unknown_nrc: u8 },
146 #[error("Received message has length of 0")]
147 ResponseEmpty,
148 #[error("Subfunction {unsupported_subfunction:x} is not supported for used service")]
149 UnsupportedSubfunction { unsupported_subfunction: u8 },
150 #[error("Argument or combination of entered arguments is not valid")]
151 InvalidArgument,
152 #[error("something is not correct with received data the data: {raw_message:x?}")]
153 ResponseIncorrect { raw_message: Vec<u8> },
154 #[error("feature you tried to call is not yet implemented")]
155 NotImplemented,
156 #[error("Request to be sent is empty")]
157 RequestEmpty,
158 #[error("Error from lower layer {error:?}")]
159 CommunicationError { error: UdsCommunicationError },
160}
161
162#[derive(Debug, PartialEq)]
164pub struct NrcData {
165 rejected_sid: u8,
166 nrc: NegativeResponseCode,
167}
168
169impl From<UdsCommunicationError> for UdsError {
170 fn from(error: UdsCommunicationError) -> UdsError {
171 UdsError::CommunicationError { error }
172 }
173}
174
175impl From<communication::Error> for UdsError {
176 fn from(error: communication::Error) -> UdsError {
177 let error: UdsCommunicationError = error.into();
178 UdsError::CommunicationError { error }
179 }
180}
181
182pub struct UdsClient {
185 socket: UdsSocket,
186}
187
188impl UdsClient {
189 pub fn new(
190 canifc: &str,
191 src: impl Into<Id>,
192 dst: impl Into<Id>,
193 ) -> Result<UdsClient, UdsError> {
194 Ok(UdsClient {
195 socket: UdsSocket::new(canifc, src, dst)?,
196 })
197 }
198
199 pub fn new_from_socket(socket: UdsSocket) -> UdsClient {
200 UdsClient { socket }
201 }
202
203 async fn send_and_receive(&self, request: &[u8]) -> Result<Vec<u8>, UdsError> {
204 let mut retry_counter = 0;
205 if request.len() == 0 {
206 return Err(UdsError::RequestEmpty);
207 }
208 self.socket.send(&request).await?;
209 let mut raw_response = self.socket.receive().await?;
210 while let Err(e) = parse_for_error(&raw_response) {
211 match e {
212 UdsError::NRC { nrc } => {
213 if nrc.rejected_sid != request[0] {
214 return Err(UdsError::SidMismatch {
215 expected: request[0],
216 received: nrc.rejected_sid,
217 raw_message: raw_response,
218 });
219 }
220 match nrc.nrc {
221 NegativeResponseCode::BusyRepeatRequest => {
222 retry_counter = retry_counter - 1;
224 if retry_counter == 0 {
225 warn!("Service failed after multiple repeats");
226 return Err(UdsError::NRC { nrc });
227 }
228 info!("Received NRC BusyRepeatRequest, repeating");
229 self.socket.send(&request).await?;
230 raw_response = self.socket.receive().await?;
231 }
232 NegativeResponseCode::RequestCorrectlyReceivedResponsePending => {
233 info!("NRC RequestCorrectlyReceivedResponsePending received, waiting for next response");
234 raw_response = self.socket.receive().await?;
235 break;
236 }
237 _ => return Err(UdsError::NRC { nrc }),
238 }
239 }
240 _ => return Err(e),
241 }
242 }
243 Ok(raw_response)
244 }
245}
246
247fn parse_for_error(raw_response: &[u8]) -> Result<(), UdsError> {
248 let mut response_iter = raw_response.iter();
249 let sid = *response_iter.next().ok_or(UdsError::ResponseEmpty)?;
250 if sid != NEGATIVE_RESPONSE_SID {
251 return Ok(());
252 }
253 let rejected_sid = *response_iter.next().ok_or(UdsError::ResponseEmpty)?;
254 let nrc: NegativeResponseCode =
255 NegativeResponseCode::try_from(*response_iter.next().ok_or(UdsError::ResponseEmpty)?)
256 .map_err(|e| UdsError::UnknownNRC {
257 rejected_sid,
258 unknown_nrc: e.number,
259 })?;
260 let response = UdsError::NRC {
261 nrc: NrcData { rejected_sid, nrc },
262 };
263 Err(response)
264}
265
266#[cfg(test)]
267mod tests {
268 use crate::uds::uds_definitions::NEGATIVE_RESPONSE_SID;
269 use crate::uds::{parse_for_error, UdsError};
270
271 #[test]
272 fn test_parse_for_error_wrong_nrc() {
273 let raw_response = vec![NEGATIVE_RESPONSE_SID, 0x11, 0xff];
274 let expected = UdsError::UnknownNRC {
275 rejected_sid: 0x11,
276 unknown_nrc: 0xff,
277 };
278 let result = parse_for_error(&raw_response);
279 assert_eq!(Err(expected), result);
280 }
281}