1mod context;
2mod service;
3
4use crate::{constants::LOG_TAG_CLIENT, error::DoCanError, SecurityAlgo};
5use iso14229_1::{
6 request::Request,
7 response::{Code, Response},
8 Configuration, DataIdentifier, Service, TesterPresentType, SUPPRESS_POSITIVE,
9};
10use iso15765_2::{
11 can::{Address, AddressType, CanIsoTp},
12 IsoTp, IsoTpError,
13};
14use rs_can::{CanDevice, CanFrame};
15use rsutil::types::ByteOrder;
16use std::{fmt::Display, hash::Hash};
17
18#[derive(Clone)]
19pub struct DoCanClient<D, C, F>
20where
21 D: CanDevice<Channel = C, Frame = F> + Clone + 'static,
22 C: Display + Clone + Hash + Eq + 'static,
23 F: CanFrame<Channel = C> + Clone + Display + 'static,
24{
25 isotp: CanIsoTp<D, C, F>,
26 context: context::Context,
27}
28
29impl<D, C, F> DoCanClient<D, C, F>
30where
31 D: CanDevice<Channel = C, Frame = F> + Clone + Send + 'static,
32 C: Display + Clone + Hash + Eq + Send + Sync + 'static,
33 F: CanFrame<Channel = C> + Clone + Display + 'static,
34{
35 pub async fn new(
36 device: D,
37 channel: C,
38 addr: Address,
39 byte_order: ByteOrder,
40 p2_offset: Option<u16>,
41 ) -> Self {
42 Self {
43 isotp: CanIsoTp::new(device, channel, addr, false).await,
44 context: context::Context::new(byte_order, p2_offset),
45 }
46 }
47
48 #[inline(always)]
49 pub fn tp_layer(&mut self) -> &mut CanIsoTp<D, C, F> {
50 &mut self.isotp
51 }
52
53 #[inline(always)]
54 pub fn byte_order(&self) -> ByteOrder {
55 self.context.byte_order
56 }
57
58 #[inline(always)]
59 pub async fn update_address(&self, address: Address) {
60 self.isotp.update_address(address).await;
61 }
62
63 #[inline(always)]
64 pub async fn update_security_algo(&self, algo: SecurityAlgo) {
65 self.context.set_security_algo(algo).await;
66 }
67
68 #[inline(always)]
69 pub async fn add_data_identifier(&self, did: DataIdentifier, length: usize) {
70 self.context.add_did(did, length).await;
71 }
72
73 #[inline(always)]
74 pub async fn remove_data_identifier(&self, did: DataIdentifier) {
75 self.context.remove_did(&did).await;
76 }
77
78 #[inline(always)]
79 fn make_request<T: Into<Vec<u8>>>(
80 service: Service,
81 sub_func: Option<u8>,
82 data: T,
83 cfg: &Configuration,
84 ) -> Result<Request, DoCanError> {
85 Request::new::<Vec<_>>(service, sub_func, data.into(), cfg)
86 .map_err(DoCanError::Iso14229Error)
87 }
88
89 #[inline(always)]
90 async fn send_and_parse<T>(
91 &self,
92 addr_type: AddressType,
93 request: Request,
94 sub_check: Option<(u8, Service)>,
95 cfg: &Configuration,
96 ) -> Result<T, DoCanError>
97 where
98 T: iso14229_1::ResponseData,
99 {
100 let response = self
101 .send_and_response(addr_type, request, sub_check, cfg)
102 .await?;
103 response.data::<T>(cfg).map_err(DoCanError::Iso14229Error)
104 }
105
106 fn response_service_check(response: &Response, target: Service) -> Result<bool, DoCanError> {
107 let service = response.service();
108 if response.is_negative() {
109 let nrc_code = response.nrc_code().map_err(DoCanError::Iso14229Error)?;
110 match nrc_code {
111 Code::RequestCorrectlyReceivedResponsePending => Ok(true),
112 _ => Err(DoCanError::NRCError {
113 service,
114 code: nrc_code,
115 }),
116 }
117 } else if service != target {
118 Err(DoCanError::UnexpectedResponse {
119 expect: target,
120 actual: service,
121 })
122 } else {
123 Ok(false)
124 }
125 }
126
127 #[inline(always)]
128 async fn suppress_positive_sr(
129 &self,
130 addr_type: AddressType,
131 request: Request,
132 suppress_positive: bool,
133 sub_check: Option<(u8, Service)>,
134 cfg: &Configuration,
135 ) -> Result<Option<Response>, DoCanError> {
136 match self.send_and_response(addr_type, request, None, cfg).await {
137 Ok(r) => {
138 if let Some((source, service)) = sub_check {
139 Self::sub_func_check(&r, source, service)?;
140 }
141
142 Ok(Some(r))
143 }
144 Err(e) => match e {
145 DoCanError::IsoTpError(e) => match e {
146 IsoTpError::Timeout { .. } => {
147 if suppress_positive {
148 Ok(None)
149 } else {
150 Err(DoCanError::IsoTpError(e))
151 }
152 }
153 _ => Err(DoCanError::IsoTpError(e)),
154 },
155 _ => Err(e),
156 },
157 }
158 }
159
160 async fn send_and_response(
161 &self,
162 addr_type: AddressType,
163 request: Request,
164 sub_check: Option<(u8, Service)>,
165 cfg: &Configuration,
166 ) -> Result<Response, DoCanError> {
167 let service = request.service();
168 let data: Vec<_> = request.into();
169 let timing = self.context.get_session_timing().await;
170 let p2_offset = self.context.p2_offset;
171 let _ = &self
172 .isotp
173 .transmit(addr_type, data)
174 .await
175 .map_err(DoCanError::IsoTpError)?;
176
177 let data = &self
178 .isotp
179 .wait_data(timing.p2_ms() + p2_offset)
180 .await
181 .map_err(DoCanError::IsoTpError)?;
182 let mut response = Response::try_from((data, cfg)).map_err(DoCanError::Iso14229Error)?;
183 while Self::response_service_check(&response, service)? {
184 rsutil::debug!(
185 "{} tester present when {:?}",
186 LOG_TAG_CLIENT,
187 Code::RequestCorrectlyReceivedResponsePending
188 );
189 let (_, request) =
190 Self::tester_present_request(TesterPresentType::Zero, true, cfg).await?;
191 let data: Vec<_> = request.into();
192 let _ = &self
193 .isotp
194 .transmit(addr_type, data)
195 .await
196 .map_err(DoCanError::IsoTpError)?;
197
198 let data = &self
199 .isotp
200 .wait_data(timing.p2_star_ms())
201 .await
202 .map_err(DoCanError::IsoTpError)?;
203
204 response = Response::try_from((data, cfg)).map_err(DoCanError::Iso14229Error)?;
205 }
206
207 if let Some((source, service)) = sub_check {
208 Self::sub_func_check(&response, source, service)?;
209 }
210
211 Ok(response)
212 }
213
214 fn sub_func_check(response: &Response, source: u8, service: Service) -> Result<(), DoCanError> {
215 match response.sub_function() {
216 Some(v) => {
217 let target = v.origin();
219 if target != source {
220 Err(DoCanError::UnexpectedSubFunction {
221 service,
222 expect: source,
223 actual: target,
224 })
225 } else {
226 Ok(())
227 }
228 }
229 None => Err(DoCanError::OtherError(format!(
230 "response of service `{}` got an empty sub-function",
231 service
232 ))),
233 }
234 }
235
236 #[inline(always)]
237 async fn tester_present_request(
238 test_type: TesterPresentType,
239 suppress_positive: bool,
240 cfg: &Configuration,
241 ) -> Result<(Service, Request), DoCanError> {
242 let service = Service::TesterPresent;
243 let mut sub_func = test_type.into();
244 if suppress_positive {
245 sub_func |= SUPPRESS_POSITIVE;
246 }
247 let request = Self::make_request(service, Some(sub_func), vec![], cfg)?;
248
249 Ok((service, request))
250 }
251}