Skip to main content

docan_rs/client/
mod.rs

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 source: u8 = session_type.into();
218                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}