roco_z21_driver/messages/
xbus_message.rs

1use tokio::io;
2
3pub const XBUS_HEADER: u16 = 0x40;
4#[derive(Clone, Debug)]
5pub struct XBusMessage {
6    x_header: u8,
7    dbs: Vec<u8>,
8    xor: u8,
9}
10
11impl XBusMessage {
12    pub fn new_only_header(x_header: u8) -> XBusMessage {
13        XBusMessage {
14            x_header,
15            dbs: Vec::new(),
16            xor: x_header,
17        }
18    }
19    pub fn new_single(x_header: u8, db: u8) -> XBusMessage {
20        let xor = x_header ^ db;
21        XBusMessage {
22            x_header,
23            dbs: vec![db],
24            xor,
25        }
26    }
27    pub fn new_double(x_header: u8, db0: u8, db1: u8) -> XBusMessage {
28        let xor = x_header ^ db0 ^ db1;
29        XBusMessage {
30            x_header,
31            dbs: vec![db0, db1],
32            xor,
33        }
34    }
35    pub fn new_dbs_vec(x_header: u8, dbs: Vec<u8>) -> XBusMessage {
36        let xor_byte = dbs.iter().fold(x_header, |acc, &x| acc ^ x);
37        XBusMessage {
38            x_header,
39            dbs,
40            xor: xor_byte,
41        }
42    }
43    pub fn get_x_header(&self) -> u8 {
44        self.x_header
45    }
46    pub fn get_dbs(&self) -> &Vec<u8> {
47        &self.dbs
48    }
49    pub fn get_xor(&self) -> u8 {
50        self.xor
51    }
52}
53
54impl Into<Vec<u8>> for XBusMessage {
55    fn into(self) -> Vec<u8> {
56        let mut vec = Vec::new();
57        vec.push(self.x_header);
58        vec.extend_from_slice(&self.dbs);
59        vec.push(self.xor);
60        vec
61    }
62}
63
64impl TryFrom<&[u8]> for XBusMessage {
65    type Error = io::Error;
66
67    fn try_from(data: &[u8]) -> Result<Self, Self::Error> {
68        let counts = data.len() as i64 - 2;
69        if counts >= 0 {
70            let counts = counts as usize;
71            let mut vec = Vec::with_capacity(counts);
72            let x_header = data[0];
73            let data_xor = data[counts + 1];
74            vec.extend_from_slice(&data[1..=counts]);
75            let calculated_xor = vec.iter().fold(x_header, |acc, x| acc ^ x);
76            if data_xor != calculated_xor {
77                return Err(io::Error::new(
78                    std::io::ErrorKind::InvalidData,
79                    "XBus message XOR is wrong",
80                ));
81            }
82            Ok(XBusMessage {
83                x_header,
84                dbs: vec,
85                xor: calculated_xor,
86            })
87        } else {
88            Err(io::Error::new(
89                std::io::ErrorKind::InvalidData,
90                "XBus message is too short",
91            ))
92        }
93    }
94}
95
96#[cfg(test)]
97mod tests {
98    use super::*;
99
100    #[test]
101    fn test_new_only_header() {
102        let msg = XBusMessage::new_only_header(0x21);
103        assert_eq!(msg.get_x_header(), 0x21);
104        assert_eq!(msg.get_dbs().len(), 0);
105        assert_eq!(msg.get_xor(), 0x21);
106    }
107
108    #[test]
109    fn test_new_single() {
110        let msg = XBusMessage::new_single(0x21, 0x34);
111        assert_eq!(msg.get_x_header(), 0x21);
112        assert_eq!(msg.get_dbs(), &vec![0x34]);
113        assert_eq!(msg.get_xor(), 0x21 ^ 0x34);
114    }
115
116    #[test]
117    fn test_new_double() {
118        let msg = XBusMessage::new_double(0x21, 0x34, 0x56);
119        assert_eq!(msg.get_x_header(), 0x21);
120        assert_eq!(msg.get_dbs(), &vec![0x34, 0x56]);
121        assert_eq!(msg.get_xor(), 0x21 ^ 0x34 ^ 0x56);
122    }
123
124    #[test]
125    fn test_new_dbs_vec() {
126        let dbs = vec![0x34, 0x56, 0x78];
127        let msg = XBusMessage::new_dbs_vec(0x21, dbs.clone());
128        assert_eq!(msg.get_x_header(), 0x21);
129        assert_eq!(msg.get_dbs(), &dbs);
130        assert_eq!(msg.get_xor(), 0x21 ^ 0x34 ^ 0x56 ^ 0x78);
131    }
132
133    #[test]
134    fn test_into_vec() {
135        let msg = XBusMessage::new_double(0x21, 0x34, 0x56);
136        let vec: Vec<u8> = msg.into();
137        assert_eq!(vec, vec![0x21, 0x34, 0x56, 0x21 ^ 0x34 ^ 0x56]);
138    }
139
140    #[test]
141    fn test_try_from_valid() {
142        let data = vec![0x61, 0x01, 0x61 ^ 0x01];
143        let msg = XBusMessage::try_from(data.as_slice()).unwrap();
144        assert_eq!(msg.get_x_header(), 0x61);
145        assert_eq!(msg.get_dbs(), &vec![0x01]);
146        assert_eq!(msg.get_xor(), 0x61 ^ 0x01);
147    }
148
149    #[test]
150    fn test_try_from_invalid_xor() {
151        let data = vec![0x21, 0x34, 0x56, 0xFF]; // Wrong XOR
152        let result = XBusMessage::try_from(data.as_slice());
153        assert!(result.is_err());
154    }
155
156    #[test]
157    fn test_try_from_too_short() {
158        let data = vec![0x21]; // Too short
159        let result = XBusMessage::try_from(data.as_slice());
160        assert!(result.is_err());
161    }
162}