iso14229_1/
response.rs

1#![allow(unused_imports)]
2
3/* - Diagnostic and communication management functional unit - */
4mod session_ctrl;           // 0x10
5pub use session_ctrl::*;
6mod ecu_reset;              // 0x11
7pub use ecu_reset::*;
8mod security_access;        // 0x27
9pub use security_access::*;
10mod communication_ctrl;     // 0x28
11pub use communication_ctrl::*;
12#[cfg(any(feature = "std2020"))]
13mod authentication;         // 0x29
14#[cfg(any(feature = "std2020"))]
15pub use authentication::*;
16mod tester_present;         // 0x3E
17pub use tester_present::*;
18#[cfg(any(feature = "std2006", feature = "std2013"))]
19mod access_timing_param;    // 0x83
20#[cfg(any(feature = "std2006", feature = "std2013"))]
21pub use access_timing_param::*;
22mod secured_data_trans;     // 0x84
23pub use secured_data_trans::*;
24mod ctrl_dtc_setting;       // 0x85
25pub use ctrl_dtc_setting::*;
26mod response_on_event;      // 0x86
27pub use response_on_event::*;
28mod link_ctrl;              // 0x87
29pub use link_ctrl::*;
30
31/* - Data transmission functional unit - */
32mod read_did;               // 0x22
33pub use read_did::*;
34mod read_mem_by_addr;       // 0x23
35pub use read_mem_by_addr::*;
36mod read_scaling_did;       // 0x24
37pub use read_scaling_did::*;
38mod read_data_by_pid;       // 0x2A
39pub use read_data_by_pid::*;
40mod dynamically_define_did; // 0x2C
41pub use dynamically_define_did::*;
42mod write_did;              // 0x2E
43pub use write_did::*;
44mod write_mem_by_addr;      // 0x3D
45pub use write_mem_by_addr::*;
46
47/* - Stored data transmission functional unit - */
48mod clear_diagnostic_info;  // 0x14
49pub use clear_diagnostic_info::*;
50mod read_dtc_info;          // 0x19
51pub use read_dtc_info::*;
52
53/* - InputOutput control functional unit - */
54mod io_ctrl;                // 0x2F
55pub use io_ctrl::*;
56
57/* - Remote activation of routine functional unit - */
58mod routine_ctrl;           // 0x31
59pub use routine_ctrl::*;
60
61/* - Upload download functional unit - */
62mod request_load;           // 0x34 | 0x35
63pub use request_load::*;
64mod transfer_data;          // 0x36
65pub use transfer_data::*;
66mod request_transfer_exit;  // 0x37
67pub use request_transfer_exit::*;
68#[cfg(any(feature = "std2013", feature = "std2020"))]
69mod request_file_transfer;  // 0x38
70#[cfg(any(feature = "std2013", feature = "std2020"))]
71pub use request_file_transfer::*;
72
73mod code;
74pub use code::Code;
75
76// #[cfg(any(feature = "std2006", feature = "std2013"))]
77// pub(crate) use crate::response::AccessTimingParam::ACCESS_TIMING_PARAM_NEGATIVES;
78// #[cfg(any(feature = "std2020"))]
79// pub(crate) use crate::response::Authentication::AUTH_NEGATIVES;
80// pub(crate) use crate::response::ClearDiagnosticInfo::CLEAR_DIAGNOSTIC_INFO_NEGATIVES;
81// pub(crate) use crate::response::CommunicationCtrl::COMMUNICATION_CTRL_NEGATIVES;
82// pub(crate) use crate::response::CtrlDTCSetting::CTRL_DTC_SETTING_NEGATIVES;
83// pub(crate) use crate::response::DynamicalDefineDID::DYNAMICAL_DID_NEGATIVES;
84// pub(crate) use crate::response::ECUReset::ECU_RESET_NEGATIVES;
85// pub(crate) use crate::response::IOCtrl::IO_CTRL_NEGATIVES;
86// pub(crate) use crate::response::LinkCtrl::LINK_CTRL_NEGATIVES;
87// pub(crate) use crate::response::ReadDataByPeriodId::READ_DATA_BY_PERIOD_ID_NEGATIVES;
88// pub(crate) use crate::response::ReadDID::READ_DID_NEGATIVES;
89// pub(crate) use crate::response::ReadDTCInfo::READ_DTC_INFO_NEGATIVES;
90// pub(crate) use crate::response::ReadMemByAddr::READ_MEM_BY_ADDR_NEGATIVES;
91// pub(crate) use crate::response::ReadScalingDID::READ_SCALING_DID_NEGATIVES;
92// pub(crate) use crate::response::RequestDownload::REQUEST_DOWNLOAD_NEGATIVES;
93// #[cfg(any(feature = "std2013", feature = "std2020"))]
94// pub(crate) use crate:response::RequestFileTransfer::REQUEST_FILE_TRANSFER_NEGATIVES;
95// pub(crate) use crate:response::RequestTransferExit::REQUEST_TRANSFER_EXIT_NEGATIVES;
96// pub(crate) use crate:response::RequestUpload::REQUEST_UPLOAD_NEGATIVES;
97// pub(crate) use crate:response::ResponseOnEvent::RESPONSE_ON_EVENT_NEGATIVES;
98// pub(crate) use crate:response::RoutineCtrl::ROUTINE_CTRL_NEGATIVES;
99// pub(crate) use crate:response::SecuredDataTrans::SECURED_DATA_TRANS_NEGATIVES;
100// pub(crate) use crate:response::SecurityAccess::SECURITY_ACCESS_NEGATIVES;
101// pub(crate) use crate:response::SessionCtrl::SESSION_CTRL_NEGATIVES;
102// pub(crate) use crate:response::TesterPresent::TESTER_PRESENT_NEGATIVES;
103// pub(crate) use crate:response::TransferData::TRANSFER_DATA_NEGATIVES;
104// pub(crate) use crate:response::WriteDID::WRITE_DID_NEGATIVES;
105// pub(crate) use crate:response::WriteMemByAddr::WRITE_MEM_BY_ADDR_NEGATIVES;
106
107use crate::{Configuration, constant::POSITIVE_OFFSET, Error, ResponseData, Service, utils};
108
109// enum_to_vec! (
110//     /// Defined by ISO-15764. Offset of 0x38 is defined within UDS standard (ISO-14229)
111//     pub enum ISO15764 {
112//         GeneralSecurityViolation = Code::SecureDataTransmissionRequired as u8 + 0,
113//         SecuredModeRequested = Code::SecureDataTransmissionRequired as u8 + 1,
114//         InsufficientProtection = Code::SecureDataTransmissionRequired as u8 + 2,
115//         TerminationWithSignatureRequested = Code::SecureDataTransmissionRequired as u8 + 3,
116//         AccessDenied = Code::SecureDataTransmissionRequired as u8 + 4,
117//         VersionNotSupported = Code::SecureDataTransmissionRequired as u8 + 5,
118//         SecuredLinkNotSupported = Code::SecureDataTransmissionRequired as u8 + 6,
119//         CertificateNotAvailable = Code::SecureDataTransmissionRequired as u8 + 7,
120//         AuditTrailInformationNotAvailable = Code::SecureDataTransmissionRequired as u8 + 8,
121//     }, u8, Error, InvalidParam
122// );
123
124#[derive(Debug, Copy, Clone)]
125pub struct SubFunction<T>(T);
126
127impl<F: Copy> SubFunction<F> {
128    pub fn new(
129        function: F,
130    ) -> Self {
131        Self(function)
132    }
133
134    #[inline]
135    pub fn function(&self) -> F {
136        self.0
137    }
138}
139
140impl<T: Into<u8>> Into<u8> for SubFunction<T> {
141    fn into(self) -> u8 {
142        self.0.into()
143    }
144}
145
146#[derive(Debug, Clone)]
147pub struct Response<F> {
148    service: Service,
149    negative: bool,
150    sub_func: Option<SubFunction<F>>,
151    data: Vec<u8>,  // the NRC code when negative is true
152}
153
154impl<F: Copy> Response<F> {
155    pub fn new(
156        service: Service,
157        negative: bool,
158        sub_func: Option<SubFunction<F>>,
159        data: Vec<u8>,
160    ) -> Self {
161        Self { service, negative, sub_func, data, }
162    }
163
164    #[inline]
165    pub fn service(&self) -> Service {
166        self.service
167    }
168
169    #[inline]
170    pub fn sub_function(&self) -> Option<SubFunction<F>> {
171        self.sub_func
172    }
173
174    #[inline]
175    pub const fn is_negative(&self) -> bool {
176        self.negative
177    }
178
179    #[inline]
180    pub fn nrc_code(&self) -> Result<Code, Error> {
181        if !self.negative {
182            return Err(Error::OtherError("get NRC from positive".into()));
183        }
184
185        if self.data.len() != 1 {
186            return Err(Error::OtherError("invalid data length when getting NRC from negative".into()));
187        }
188
189        Ok(Code::from(self.data[0]))
190    }
191
192    #[inline]
193    pub fn raw_data(&self) -> &[u8] {
194        self.data.as_slice()
195    }
196
197    #[inline]
198    pub fn data<T: ResponseData<SubFunc = F>>(&self, cfg: &Configuration) -> Result<T, Error> {
199        T::try_parse(self.data.as_slice(), match self.sub_func {
200            Some(v) => Some(v.0),
201            None => None,
202        }, cfg)
203    }
204}
205
206impl<F: Into<u8>> Into<Vec<u8>> for Response<F> {
207    fn into(mut self) -> Vec<u8> {
208        let mut result = if self.negative {
209            vec![Service::NRC.into(), ]
210        }
211        else {
212            vec![]
213        };
214
215        let service: u8 = self.service.into();
216        result.push(service | POSITIVE_OFFSET);
217
218        if let Some(sub_func) = self.sub_func {
219            result.push(sub_func.into());
220        }
221
222        result.append(&mut self.data);
223
224        result
225    }
226}
227
228impl<F: TryFrom<u8, Error = Error> + Copy> TryFrom<Vec<u8>> for Response<F> {
229    type Error = Error;
230    fn try_from(data: Vec<u8>) -> Result<Self, Self::Error> {
231        let data_len = data.len();
232        utils::data_length_check(data_len, 1, false)?;
233
234        let mut offset = 0;
235        let service = data[offset];
236        let service = if service == Service::NRC.into() {
237            Ok(Service::NRC)
238        }
239        else {
240            Service::try_from(service & !POSITIVE_OFFSET)
241        }?;
242        offset += 1;
243        match service {
244            Service::SessionCtrl |
245            Service::ECUReset |
246            Service::SecurityAccess |
247            Service::CommunicationCtrl |
248            Service::ReadDTCInfo |
249            Service::RoutineCtrl |
250            Service::CtrlDTCSetting |
251            Service::TesterPresent |
252            Service::LinkCtrl |
253            Service::DynamicalDefineDID => {
254                utils::data_length_check(data_len, offset + 1, false)?;
255
256                let sub_func = F::try_from(data[offset])?;
257                offset += 1;
258                let data = data[offset..].to_vec();
259
260                Ok(Self::new(service, false, Some(SubFunction::new(sub_func)), data))
261            },
262            Service::ClearDiagnosticInfo |
263            Service::ReadDID |
264            Service::ReadMemByAddr |
265            Service::ReadScalingDID |
266            Service::ReadDataByPeriodId |
267            Service::WriteDID |
268            Service::IOCtrl |
269            Service::RequestDownload |
270            Service::RequestUpload |
271            Service::TransferData |
272            Service::RequestTransferExit |
273            Service::WriteMemByAddr |
274            Service::SecuredDataTrans |
275            Service::ResponseOnEvent => {
276                Ok(Self::new(service, false, None, data[offset..].to_vec()))
277            },
278            #[cfg(any(feature = "std2020"))]
279            Service::Authentication => {
280                utils::data_length_check(data_len, offset + 1, false)?;
281
282                let sub_func = F::try_from(data[offset])?;
283                offset += 1;
284                let data = data[offset..].to_vec();
285
286                Ok(Self::new(service, false, Some(SubFunction::new(sub_func)), data))
287            },
288            #[cfg(any(feature = "std2013", feature = "std2020"))]
289            Service::RequestFileTransfer => {
290                utils::data_length_check(data_len, offset + 1, false)?;
291
292                let sub_func = F::try_from(data[offset])?;
293                offset += 1;
294                let data = data[offset..].to_vec();
295
296                Ok(Self::new(service, false, Some(SubFunction::new(sub_func)), data))
297            },
298            #[cfg(any(feature = "std2006", feature = "std2013"))]
299            Service::AccessTimingParam => {
300                utils::data_length_check(data_len, offset + 1, false)?;
301
302                let sub_func = F::try_from(data[offset])?;
303                offset += 1;
304                let data = data[offset..].to_vec();
305
306                Ok(Self::new(service, false, Some(SubFunction::new(sub_func)), data))
307            },
308            Service::NRC => {
309                utils::data_length_check(data_len, offset + 2, true)?;
310                let nrc_service = Service::try_from(data[offset])?;
311                offset += 1;
312
313                let data = data[offset..].to_vec();
314
315                Ok(Self::new(nrc_service, true, None, data))
316            },
317        }
318    }
319}