1mod trait_impl;
2
3use crate::{
4 client::context::{Context, IsoTpListener},
5 error::DoCanError,
6 SecurityAlgo,
7};
8use iso14229_1::{
9 request::Request,
10 response::{Code, Response},
11 DidConfig, Service, TesterPresentType, SUPPRESS_POSITIVE,
12};
13use iso15765_2::{Address, AddressType, CanAdapter, CanIsoTp, IsoTpError, IsoTpEventListener};
14use rs_can::{CanDevice, CanFrame};
15use rsutil::types::ByteOrder;
16use std::{collections::HashMap, fmt::Display, hash::Hash};
17
18#[derive(Clone)]
19pub struct DoCanClient<D, C, F>
20where
21 C: Clone + Eq,
22{
23 adapter: CanAdapter<D, C, F>,
24 context: HashMap<C, Context<C, F>>,
25 p2_offset: u64,
26}
27unsafe impl<D, C, F> Send for DoCanClient<D, C, F>
28where
29 D: CanDevice<Channel = C, Frame = F> + Clone + Send + Sync + 'static,
30 C: Display + Clone + Hash + Eq + Send + Sync + 'static,
31 F: CanFrame<Channel = C> + Clone + Display + Send + Sync + 'static,
32{
33}
34unsafe impl<D, C, F> Sync for DoCanClient<D, C, F>
35where
36 D: CanDevice<Channel = C, Frame = F> + Clone + Send + 'static,
37 C: Display + Clone + Hash + Eq + Send + Sync + 'static,
38 F: CanFrame<Channel = C> + Clone + Send + Display + 'static,
39{
40}
41
42impl<D, C, F> DoCanClient<D, C, F>
43where
44 D: CanDevice<Channel = C, Frame = F> + Clone + Send + 'static,
45 C: Display + Clone + Hash + Eq + Send + Sync + 'static,
46 F: CanFrame<Channel = C> + Clone + Send + Display + 'static,
47{
48 pub fn new(adapter: CanAdapter<D, C, F>, p2_offset: Option<u16>) -> Self {
49 Self {
50 adapter,
51 context: Default::default(),
52 p2_offset: p2_offset.unwrap_or_default() as u64,
53 }
54 }
55
56 pub async fn init_channel(
57 &mut self,
58 channel: C,
59 address: Address,
60 byte_order: ByteOrder,
61 ) -> Result<(), DoCanError> {
62 let listener = IsoTpListener::new(Default::default(), self.p2_offset);
63 let iso_tp = CanIsoTp::new(
64 channel.clone(),
65 address,
66 self.adapter.sender(),
67 Box::new(listener.clone()),
68 );
69
70 self.adapter
71 .register_listener(format!("DoCANClient-{}", channel), Box::new(iso_tp.clone()))
72 .await;
73 self.context.insert(
74 channel,
75 Context {
76 iso_tp,
77 listener,
78 did: Default::default(),
79 security_algo: Default::default(),
80 byte_order,
81 },
82 );
83
84 Ok(())
85 }
86
87 #[inline(always)]
88 pub fn adapter(&self) -> &CanAdapter<D, C, F> {
89 &self.adapter
90 }
91
92 #[inline(always)]
93 pub fn byte_order(&self, channel: C) -> Option<ByteOrder> {
94 self.context.get(&channel).map(|v| v.byte_order)
95 }
96
97 #[inline(always)]
98 async fn with_context<R, Func, Fut>(&self, channel: C, callback: Func) -> Result<R, DoCanError>
99 where
100 Func: Fn(IsoTpListener, CanIsoTp<C, F>, DidConfig) -> Fut + Send,
101 Fut: std::future::Future<Output = Result<R, DoCanError>> + Send,
102 {
103 match self.context.get(&channel) {
104 Some(ctx) => {
105 let guard = ctx.did.lock().await;
106 let did = guard.clone();
107 drop(guard);
108 callback(ctx.listener.clone(), ctx.iso_tp.clone(), did).await
109 }
110 None => Err(DoCanError::OtherError(format!(
111 "channel: {} is not initialized",
112 channel
113 ))),
114 }
115 }
116
117 #[inline(always)]
118 async fn with_security_algo_ctx<R, Func, Fut>(
119 &self,
120 channel: C,
121 callback: Func,
122 ) -> Result<R, DoCanError>
123 where
124 Func: Fn(IsoTpListener, CanIsoTp<C, F>, DidConfig, SecurityAlgo) -> Fut + Send,
125 Fut: std::future::Future<Output = Result<R, DoCanError>> + Send,
126 {
127 match self.context.get(&channel) {
128 Some(ctx) => {
129 let guard = ctx.did.lock().await;
130 let did = guard.clone();
131 drop(guard);
132 let algo = ctx.security_algo.lock().await.clone();
133 match algo {
134 Some(algo) => {
135 callback(ctx.listener.clone(), ctx.iso_tp.clone(), did, algo).await
136 }
137 None => Err(DoCanError::OtherError("security algorithm required".into())),
138 }
139 }
140 None => Err(DoCanError::OtherError(format!(
141 "channel: {} is not initialized",
142 channel
143 ))),
144 }
145 }
146
147 #[inline(always)]
148 async fn context_util<R, Func, Fut>(&self, channel: C, callback: Func) -> Result<R, DoCanError>
149 where
150 Func: Fn(Context<C, F>) -> Fut + Send,
151 Fut: std::future::Future<Output = Result<R, DoCanError>> + Send,
152 {
153 match self.context.get(&channel) {
154 Some(ctx) => callback(ctx.clone()).await,
155 None => Err(DoCanError::OtherError(format!(
156 "channel: {} is not initialized",
157 channel
158 ))),
159 }
160 }
161
162 fn response_service_check(response: &Response, target: Service) -> Result<bool, DoCanError> {
163 let service = response.service();
164 if response.is_negative() {
165 let nrc_code = response.nrc_code().map_err(DoCanError::ISO14229Error)?;
166 match nrc_code {
167 Code::RequestCorrectlyReceivedResponsePending => Ok(true),
168 _ => Err(DoCanError::NRCError {
169 service,
170 code: nrc_code,
171 }),
172 }
173 } else if service != target {
174 Err(DoCanError::UnexpectedResponse {
175 expect: target,
176 actual: service,
177 })
178 } else {
179 Ok(false)
180 }
181 }
182
183 async fn suppress_positive_sr(
184 listener: &IsoTpListener,
185 iso_tp: &CanIsoTp<C, F>,
186 did: &DidConfig,
187 addr_type: AddressType,
188 request: Request,
189 suppress_positive: bool,
190 ) -> Result<Option<Response>, DoCanError> {
191 match Self::send_and_response(listener, iso_tp, did, addr_type, request).await {
192 Ok(r) => Ok(Some(r)),
193 Err(e) => match e {
194 DoCanError::IsoTpError(e) => match e {
195 IsoTpError::Timeout { .. } => {
196 if suppress_positive {
197 Ok(None)
198 } else {
199 Err(DoCanError::IsoTpError(e))
200 }
201 }
202 _ => Err(DoCanError::IsoTpError(e)),
203 },
204 _ => Err(e),
205 },
206 }
207 }
208
209 async fn send_and_response(
210 listener: &IsoTpListener,
211 iso_tp: &CanIsoTp<C, F>,
212 did: &DidConfig,
213 addr_type: AddressType,
214 request: Request,
215 ) -> Result<Response, DoCanError> {
216 listener.clear_buffer().await;
217 let service = request.service();
218 iso_tp
219 .write(addr_type, request.into())
220 .await
221 .map_err(DoCanError::IsoTpError)?;
222
223 let data = listener
224 .async_timer(false)
225 .await
226 .map_err(DoCanError::IsoTpError)?;
227 let mut response = Response::try_from((data, did)).map_err(DoCanError::ISO14229Error)?;
229 while Self::response_service_check(&response, service)? {
230 rsutil::debug!(
231 "DoCANClient - tester present when {:?}",
232 Code::RequestCorrectlyReceivedResponsePending
233 );
234 let (_, request) =
235 Self::tester_present_request(&did, TesterPresentType::Zero, true).await?;
236 iso_tp
237 .write(addr_type, request.into())
238 .await
239 .map_err(DoCanError::IsoTpError)?;
240
241 let data = listener
242 .async_timer(true)
243 .await
244 .map_err(DoCanError::IsoTpError)?;
245
246 response = Response::try_from((data, did)).map_err(DoCanError::ISO14229Error)?;
247 }
248
249 Ok(response)
250 }
251
252 fn sub_func_check(response: &Response, source: u8, service: Service) -> Result<(), DoCanError> {
253 match response.sub_function() {
254 Some(v) => {
255 let target = v.origin();
257 if target != source {
258 Err(DoCanError::UnexpectedSubFunction {
259 service,
260 expect: source,
261 actual: target,
262 })
263 } else {
264 Ok(())
265 }
266 }
267 None => Err(DoCanError::OtherError(format!(
268 "response of service `{}` got an empty sub-function",
269 service
270 ))),
271 }
272 }
273
274 #[inline(always)]
275 async fn tester_present_request(
276 did: &DidConfig,
277 test_type: TesterPresentType,
278 suppress_positive: bool,
279 ) -> Result<(Service, Request), DoCanError> {
280 let service = Service::TesterPresent;
281 let mut sub_func = test_type.into();
282 if suppress_positive {
283 sub_func |= SUPPRESS_POSITIVE;
284 }
285 let request = Request::new(service, Some(sub_func), vec![], &did)
286 .map_err(DoCanError::ISO14229Error)?;
287
288 Ok((service, request))
289 }
290}