roco_z21_driver/messages/
xbus_message.rs1use 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]; 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]; let result = XBusMessage::try_from(data.as_slice());
160 assert!(result.is_err());
161 }
162}