iso14229_1/request/
communication_ctrl.rs

1//! request of Service 28
2
3
4use crate::{CommunicationCtrlType, CommunicationType, Configuration, Error, RequestData, utils};
5
6#[derive(Debug, Copy, Clone, Eq, PartialEq)]
7pub struct NodeId(u16);
8
9impl TryFrom<u16> for NodeId {
10    type Error = Error;
11    fn try_from(value: u16) -> Result<Self, Self::Error> {
12        match value {
13            0x0001..=0xFFFF => Ok(Self(value)),
14            v => Err(Error::InvalidParam(utils::err_msg(v))),
15        }
16    }
17}
18
19impl Into<u16> for NodeId {
20    fn into(self) -> u16 {
21        self.0
22    }
23}
24
25#[derive(Debug, Clone)]
26pub struct CommunicationCtrl {
27    pub comm_type: CommunicationType,
28    pub node_id: Option<NodeId>,
29}
30
31impl CommunicationCtrl {
32    pub fn new(
33        ctrl_type: CommunicationCtrlType,
34        comm_type: CommunicationType,
35        node_id: Option<NodeId>,
36    ) -> Result<Self, Error> {
37        match ctrl_type {
38            CommunicationCtrlType::EnableRxAndDisableTxWithEnhancedAddressInformation |
39            CommunicationCtrlType::EnableRxAndTxWithEnhancedAddressInformation => {
40                match node_id {
41                    Some(v) => Ok(Self { comm_type, node_id: Some(v), }),
42                    None => Err(Error::InvalidParam("`nodeIdentificationNumber` is required".to_string())),
43                }
44            },
45            _ => Ok(Self {  comm_type, node_id: None, })
46        }
47    }
48}
49
50impl RequestData for CommunicationCtrl {
51    type SubFunc = CommunicationCtrlType;
52    fn try_parse(data: &[u8], sub_func: Option<Self::SubFunc>, _: &Configuration) -> Result<Self, Error> {
53        match sub_func {
54            Some(v) => {
55                let data_len = data.len();
56                utils::data_length_check(data_len, 1, false)?;
57
58                let mut offset = 0;
59                let comm_type = data[offset];
60                offset += 1;
61
62                let node_id = match v {
63                    CommunicationCtrlType::EnableRxAndDisableTxWithEnhancedAddressInformation |
64                    CommunicationCtrlType::EnableRxAndTxWithEnhancedAddressInformation => {
65
66                        utils::data_length_check(data_len, offset + 2, true)?;
67
68                        Some(NodeId::try_from(
69                            u16::from_be_bytes([data[offset], data[offset + 1]])
70                        )?)
71                    },
72                    _ => None,
73                };
74
75                Ok(Self {
76                    comm_type: CommunicationType(comm_type),
77                    node_id,
78                })
79            },
80            None => panic!("Sub-function required"),
81        }
82    }
83    #[inline]
84    fn to_vec(self, _: &Configuration) -> Vec<u8> {
85        self.into()
86    }
87}
88
89impl Into<Vec<u8>> for CommunicationCtrl {
90    fn into(self) -> Vec<u8> {
91        let mut result = vec![self.comm_type.0];
92        if let Some(v) = self.node_id {
93            let v: u16 = v.into();
94            result.extend(v.to_be_bytes());
95        }
96
97        result
98    }
99}
100
101#[cfg(test)]
102mod tests {
103    use crate::{CommunicationCtrlType, CommunicationType, Configuration, RequestData};
104    use super::CommunicationCtrl;
105
106    #[test]
107    fn new() -> anyhow::Result<()> {
108        let source = hex::decode("280203")?;
109
110        let request = CommunicationCtrl::new(
111            CommunicationCtrlType::DisableRxAndEnableTx,
112            CommunicationType::NormalCommunicationMessages |
113                CommunicationType::NetworkManagementCommunicationMessages,
114            None,
115        )?;
116        let result: Vec<_> = request.into();
117        assert_eq!(result, source[2..].to_vec());
118
119        let cfg = Configuration::default();
120        let request = CommunicationCtrl::try_parse(
121            &source[2..],
122            Some(CommunicationCtrlType::DisableRxAndEnableTx),
123            &cfg,
124        )?;
125        
126        assert_eq!(request.comm_type, CommunicationType(0x03));
127        assert_eq!(request.node_id, None);
128
129        Ok(())
130    }
131}