pub mod config;
pub mod constants;
pub mod control;
pub mod feedback;
pub mod ids;
pub use config::*;
pub use constants::*;
pub use control::*;
pub use feedback::*;
pub use ids::*;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct PiperFrame {
pub id: u32,
pub data: [u8; 8],
pub len: u8,
pub is_extended: bool,
pub timestamp_us: u64,
}
impl PiperFrame {
pub fn new_standard(id: u16, data: &[u8]) -> Self {
Self::new(id as u32, data, false)
}
pub fn new_extended(id: u32, data: &[u8]) -> Self {
Self::new(id, data, true)
}
fn new(id: u32, data: &[u8], is_extended: bool) -> Self {
let mut fixed_data = [0u8; 8];
let len = data.len().min(8);
fixed_data[..len].copy_from_slice(&data[..len]);
Self {
id,
data: fixed_data,
len: len as u8,
is_extended,
timestamp_us: 0, }
}
pub fn data_slice(&self) -> &[u8] {
&self.data[..self.len as usize]
}
pub fn id(&self) -> u32 {
self.id
}
pub fn data(&self) -> &[u8; 8] {
&self.data
}
}
pub mod can {
pub use super::PiperFrame;
}
use thiserror::Error;
#[derive(Error, Debug)]
pub enum ProtocolError {
#[error("Invalid frame length: expected {expected}, got {actual}")]
InvalidLength { expected: usize, actual: usize },
#[error("Invalid CAN ID: 0x{id:X}")]
InvalidCanId { id: u32 },
#[error("Parse error: {0}")]
ParseError(String),
#[error("Invalid value for field {field}: {value}")]
InvalidValue { field: String, value: u8 },
}
pub fn bytes_to_i32_be(bytes: [u8; 4]) -> i32 {
i32::from_be_bytes(bytes)
}
pub fn bytes_to_i16_be(bytes: [u8; 2]) -> i16 {
i16::from_be_bytes(bytes)
}
pub fn i32_to_bytes_be(value: i32) -> [u8; 4] {
value.to_be_bytes()
}
pub fn i16_to_bytes_be(value: i16) -> [u8; 2] {
value.to_be_bytes()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_bytes_to_i32_be() {
let bytes = [0x12, 0x34, 0x56, 0x78];
let value = bytes_to_i32_be(bytes);
assert_eq!(value, 0x12345678);
}
#[test]
fn test_bytes_to_i32_be_negative() {
let bytes = [0xFF, 0xFF, 0xFF, 0xFF];
let value = bytes_to_i32_be(bytes);
assert_eq!(value, -1);
}
#[test]
fn test_bytes_to_i16_be() {
let bytes = [0x12, 0x34];
let value = bytes_to_i16_be(bytes);
assert_eq!(value, 0x1234);
}
#[test]
fn test_bytes_to_i16_be_negative() {
let bytes = [0xFF, 0xFF];
let value = bytes_to_i16_be(bytes);
assert_eq!(value, -1);
}
#[test]
fn test_i32_to_bytes_be() {
let value = 0x12345678;
let bytes = i32_to_bytes_be(value);
assert_eq!(bytes, [0x12, 0x34, 0x56, 0x78]);
}
#[test]
fn test_i32_to_bytes_be_negative() {
let value = -1;
let bytes = i32_to_bytes_be(value);
assert_eq!(bytes, [0xFF, 0xFF, 0xFF, 0xFF]);
}
#[test]
fn test_i16_to_bytes_be() {
let value = 0x1234;
let bytes = i16_to_bytes_be(value);
assert_eq!(bytes, [0x12, 0x34]);
}
#[test]
fn test_i16_to_bytes_be_negative() {
let value = -1;
let bytes = i16_to_bytes_be(value);
assert_eq!(bytes, [0xFF, 0xFF]);
}
#[test]
fn test_roundtrip_i32() {
let original = 0x12345678;
let bytes = i32_to_bytes_be(original);
let decoded = bytes_to_i32_be(bytes);
assert_eq!(original, decoded);
}
#[test]
fn test_roundtrip_i16() {
let original = 0x1234;
let bytes = i16_to_bytes_be(original);
let decoded = bytes_to_i16_be(bytes);
assert_eq!(original, decoded);
}
}