docan_rs/client/client_impl/
mod.rs

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