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