1pub mod config;
19pub mod constants;
20pub mod control;
21pub mod feedback;
22pub mod ids;
23
24pub use config::*;
26pub use constants::*;
27pub use control::*;
28pub use feedback::*;
29pub use ids::*;
30
31#[derive(Debug, Clone, Copy, PartialEq, Eq)]
80#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
81pub struct PiperFrame {
82 pub id: u32,
84
85 pub data: [u8; 8],
87
88 pub len: u8,
90
91 pub is_extended: bool,
93
94 pub timestamp_us: u64,
96}
97
98impl PiperFrame {
99 pub fn new_standard(id: u16, data: &[u8]) -> Self {
101 Self::new(id as u32, data, false)
102 }
103
104 pub fn new_extended(id: u32, data: &[u8]) -> Self {
106 Self::new(id, data, true)
107 }
108
109 fn new(id: u32, data: &[u8], is_extended: bool) -> Self {
111 let mut fixed_data = [0u8; 8];
112 let len = data.len().min(8);
113 fixed_data[..len].copy_from_slice(&data[..len]);
114
115 Self {
116 id,
117 data: fixed_data,
118 len: len as u8,
119 is_extended,
120 timestamp_us: 0, }
122 }
123
124 pub fn data_slice(&self) -> &[u8] {
126 &self.data[..self.len as usize]
127 }
128
129 pub fn id(&self) -> u32 {
131 self.id
132 }
133
134 pub fn data(&self) -> &[u8; 8] {
136 &self.data
137 }
138}
139
140pub mod can {
141 pub use super::PiperFrame;
142}
143
144use thiserror::Error;
145
146#[derive(Error, Debug)]
148pub enum ProtocolError {
149 #[error("Invalid frame length: expected {expected}, got {actual}")]
150 InvalidLength { expected: usize, actual: usize },
151
152 #[error("Invalid CAN ID: 0x{id:X}")]
153 InvalidCanId { id: u32 },
154
155 #[error("Parse error: {0}")]
156 ParseError(String),
157
158 #[error("Invalid value for field {field}: {value}")]
159 InvalidValue { field: String, value: u8 },
160}
161
162pub fn bytes_to_i32_be(bytes: [u8; 4]) -> i32 {
169 i32::from_be_bytes(bytes)
170}
171
172pub fn bytes_to_i16_be(bytes: [u8; 2]) -> i16 {
174 i16::from_be_bytes(bytes)
175}
176
177pub fn i32_to_bytes_be(value: i32) -> [u8; 4] {
179 value.to_be_bytes()
180}
181
182pub fn i16_to_bytes_be(value: i16) -> [u8; 2] {
184 value.to_be_bytes()
185}
186
187#[cfg(test)]
188mod tests {
189 use super::*;
190
191 #[test]
192 fn test_bytes_to_i32_be() {
193 let bytes = [0x12, 0x34, 0x56, 0x78];
194 let value = bytes_to_i32_be(bytes);
195 assert_eq!(value, 0x12345678);
196 }
197
198 #[test]
199 fn test_bytes_to_i32_be_negative() {
200 let bytes = [0xFF, 0xFF, 0xFF, 0xFF];
201 let value = bytes_to_i32_be(bytes);
202 assert_eq!(value, -1);
203 }
204
205 #[test]
206 fn test_bytes_to_i16_be() {
207 let bytes = [0x12, 0x34];
208 let value = bytes_to_i16_be(bytes);
209 assert_eq!(value, 0x1234);
210 }
211
212 #[test]
213 fn test_bytes_to_i16_be_negative() {
214 let bytes = [0xFF, 0xFF];
215 let value = bytes_to_i16_be(bytes);
216 assert_eq!(value, -1);
217 }
218
219 #[test]
220 fn test_i32_to_bytes_be() {
221 let value = 0x12345678;
222 let bytes = i32_to_bytes_be(value);
223 assert_eq!(bytes, [0x12, 0x34, 0x56, 0x78]);
224 }
225
226 #[test]
227 fn test_i32_to_bytes_be_negative() {
228 let value = -1;
229 let bytes = i32_to_bytes_be(value);
230 assert_eq!(bytes, [0xFF, 0xFF, 0xFF, 0xFF]);
231 }
232
233 #[test]
234 fn test_i16_to_bytes_be() {
235 let value = 0x1234;
236 let bytes = i16_to_bytes_be(value);
237 assert_eq!(bytes, [0x12, 0x34]);
238 }
239
240 #[test]
241 fn test_i16_to_bytes_be_negative() {
242 let value = -1;
243 let bytes = i16_to_bytes_be(value);
244 assert_eq!(bytes, [0xFF, 0xFF]);
245 }
246
247 #[test]
248 fn test_roundtrip_i32() {
249 let original = 0x12345678;
250 let bytes = i32_to_bytes_be(original);
251 let decoded = bytes_to_i32_be(bytes);
252 assert_eq!(original, decoded);
253 }
254
255 #[test]
256 fn test_roundtrip_i16() {
257 let original = 0x1234;
258 let bytes = i16_to_bytes_be(original);
259 let decoded = bytes_to_i16_be(bytes);
260 assert_eq!(original, decoded);
261 }
262}