iso14229_1/response/
session_ctrl.rs

1//! response of Service 10
2
3
4use std::collections::HashSet;
5use lazy_static::lazy_static;
6use crate::{Configuration, constant::{P2_MAX, P2_STAR_MAX, P2_STAR_MAX_MS}, error::Error, response::Code, ResponseData, SessionType, utils};
7
8lazy_static!(
9    pub static ref SESSION_CTRL_NEGATIVES: HashSet<Code> = HashSet::from([
10        Code::SubFunctionNotSupported,
11        Code::IncorrectMessageLengthOrInvalidFormat,
12        Code::ConditionsNotCorrect,
13    ]);
14);
15
16#[derive(Debug, Default, Clone, Eq, PartialEq)]
17pub struct SessionTiming {
18    pub(crate) p2:      u16,
19    pub(crate) p2_star: u16,
20}
21
22impl SessionTiming {
23    #[inline]
24    pub fn new(
25        p2_ms: u16,
26        p2_star_ms: u32,
27    ) -> Result<Self, Error> {
28        if p2_ms > P2_MAX || p2_star_ms > P2_STAR_MAX_MS {
29            return Err(Error::InvalidData(format!("P2: {} or P2*: {}", p2_ms, p2_star_ms)));
30        }
31        let p2_star = (p2_star_ms / 10) as u16;
32        Ok(Self { p2: p2_ms, p2_star })
33    }
34
35    #[inline]
36    pub fn p2_ms(&self) -> u16 {
37        self.p2
38    }
39
40    #[inline]
41    pub fn p2_star_ms(&self) -> u32 {
42        self.p2_star as u32 * 10
43    }
44}
45
46impl<'a> TryFrom<&'a [u8]> for SessionTiming {
47    type Error = Error;
48    #[allow(unused_mut)]
49    fn try_from(data: &'a [u8]) -> Result<Self, Self::Error> {
50        let data_len = data.len();
51        utils::data_length_check(data_len, 4, true)?;
52
53        let mut offset = 0;
54
55        let mut p2 = u16::from_be_bytes([data[offset], data[offset + 1]]);
56        offset += 2;
57        let mut p2_star = u16::from_be_bytes([data[offset], data[offset + 1]]);
58
59        #[cfg(not(feature = "session_data_check"))]
60        if p2 > P2_MAX || p2_star > P2_STAR_MAX {
61            log::warn!("UDS - invalid session data P2: {}, P2*: {}", p2, p2_star);
62            if p2 > P2_MAX { p2 = P2_MAX; }
63            if p2_star > P2_STAR_MAX { p2_star = P2_STAR_MAX; }
64        }
65        #[cfg(feature = "session_data_check")]
66        if p2 > P2_MAX || p2_star > P2_STAR_MAX {
67            return Err(Error::InvalidSessionData(format!("P2: {}, P2*: {}", p2, p2_star)));
68        }
69
70        Ok(Self { p2, p2_star })
71    }
72}
73
74impl Into<Vec<u8>> for SessionTiming {
75    fn into(self) -> Vec<u8> {
76        let mut result = self.p2.to_be_bytes().to_vec();
77        result.extend(self.p2_star.to_be_bytes());
78        result
79    }
80}
81
82impl ResponseData for SessionTiming {
83    type SubFunc = SessionType;
84    #[inline]
85    fn try_parse(data: &[u8], _: Option<Self::SubFunc>, _: &Configuration) -> Result<Self, Error> {
86        Self::try_from(data)
87    }
88    #[inline]
89    fn to_vec(self, _: &Configuration) -> Vec<u8> {
90        self.into()
91    }
92}