docan_rs/client/client_impl/
mod.rs

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 data = data.to_vec();
228        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 source: u8 = session_type.into();
256                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}