use bitflags::bitflags;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum CanId {
Standard(u16),
Extended(u32),
}
impl CanId {
#[must_use]
pub fn raw(&self) -> u32 {
match self {
Self::Standard(id) => u32::from(*id),
Self::Extended(id) => *id,
}
}
#[must_use]
pub fn is_standard(&self) -> bool {
matches!(self, Self::Standard(_))
}
#[must_use]
pub fn is_extended(&self) -> bool {
matches!(self, Self::Extended(_))
}
}
bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct MessageFlags: u8 {
const RTR = 0b0000_0001;
const FD = 0b0000_0010;
const BRS = 0b0000_0100;
const ESI = 0b0000_1000;
}
}
impl Default for MessageFlags {
fn default() -> Self {
Self::empty()
}
}
impl Serialize for MessageFlags {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
self.bits().serialize(serializer)
}
}
impl<'de> Deserialize<'de> for MessageFlags {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let bits = u8::deserialize(deserializer)?;
Ok(MessageFlags::from_bits_truncate(bits))
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub struct Timestamp {
micros: u64,
}
impl Timestamp {
#[must_use]
pub const fn from_micros(micros: u64) -> Self {
Self { micros }
}
#[must_use]
pub const fn as_micros(&self) -> u64 {
self.micros
}
#[must_use]
pub const fn as_millis(&self) -> u64 {
self.micros / 1000
}
#[must_use]
pub const fn as_secs(&self) -> u64 {
self.micros / 1_000_000
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct CanMessage {
id: CanId,
data: Vec<u8>,
timestamp: Option<Timestamp>,
flags: MessageFlags,
}
impl CanMessage {
pub fn new_standard(id: u16, data: &[u8]) -> Result<Self, crate::error::CanError> {
if id > 0x7FF {
return Err(crate::error::CanError::InvalidId {
value: u32::from(id),
max: 0x7FF,
});
}
if data.len() > 8 {
return Err(crate::error::CanError::InvalidDataLength {
expected: 8,
actual: data.len(),
});
}
Ok(Self {
id: CanId::Standard(id),
data: data.to_vec(),
timestamp: None,
flags: MessageFlags::default(),
})
}
pub fn new_extended(id: u32, data: &[u8]) -> Result<Self, crate::error::CanError> {
if id > 0x1FFF_FFFF {
return Err(crate::error::CanError::InvalidId {
value: id,
max: 0x1FFF_FFFF,
});
}
if data.len() > 8 {
return Err(crate::error::CanError::InvalidDataLength {
expected: 8,
actual: data.len(),
});
}
Ok(Self {
id: CanId::Extended(id),
data: data.to_vec(),
timestamp: None,
flags: MessageFlags::default(),
})
}
pub fn new_fd(id: CanId, data: &[u8]) -> Result<Self, crate::error::CanError> {
if data.len() > 64 {
return Err(crate::error::CanError::InvalidDataLength {
expected: 64,
actual: data.len(),
});
}
Ok(Self {
id,
data: data.to_vec(),
timestamp: None,
flags: MessageFlags::FD | MessageFlags::BRS,
})
}
pub fn new_remote(id: CanId, dlc: u8) -> Result<Self, crate::error::CanError> {
if dlc > 8 {
return Err(crate::error::CanError::InvalidDataLength {
expected: 8,
actual: dlc as usize,
});
}
Ok(Self {
id,
data: vec![],
timestamp: None,
flags: MessageFlags::RTR,
})
}
#[must_use]
pub const fn id(&self) -> CanId {
self.id
}
#[must_use]
pub fn data(&self) -> &[u8] {
&self.data
}
#[must_use]
pub const fn timestamp(&self) -> Option<Timestamp> {
self.timestamp
}
#[must_use]
pub const fn flags(&self) -> MessageFlags {
self.flags
}
pub fn set_timestamp(&mut self, timestamp: Timestamp) {
self.timestamp = Some(timestamp);
}
#[must_use]
pub fn is_remote(&self) -> bool {
self.flags.contains(MessageFlags::RTR)
}
#[must_use]
pub fn is_fd(&self) -> bool {
self.flags.contains(MessageFlags::FD)
}
#[must_use]
pub fn is_brs(&self) -> bool {
self.flags.contains(MessageFlags::BRS)
}
#[must_use]
pub fn is_esi(&self) -> bool {
self.flags.contains(MessageFlags::ESI)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_can_id_standard() {
let id = CanId::Standard(0x123);
assert!(id.is_standard());
assert!(!id.is_extended());
assert_eq!(id.raw(), 0x123);
}
#[test]
fn test_can_id_extended() {
let id = CanId::Extended(0x1234_5678);
assert!(!id.is_standard());
assert!(id.is_extended());
assert_eq!(id.raw(), 0x1234_5678);
}
#[test]
fn test_message_flags() {
let flags = MessageFlags::FD | MessageFlags::BRS;
assert!(flags.contains(MessageFlags::FD));
assert!(flags.contains(MessageFlags::BRS));
assert!(!flags.contains(MessageFlags::RTR));
}
#[test]
fn test_timestamp() {
let ts = Timestamp::from_micros(1_500_000);
assert_eq!(ts.as_micros(), 1_500_000);
assert_eq!(ts.as_millis(), 1_500);
assert_eq!(ts.as_secs(), 1);
}
#[test]
fn test_can_message_standard() {
let msg = CanMessage::new_standard(0x123, &[1, 2, 3, 4]).unwrap();
assert_eq!(msg.id(), CanId::Standard(0x123));
assert_eq!(msg.data(), &[1, 2, 3, 4]);
assert!(!msg.is_remote());
assert!(!msg.is_fd());
}
#[test]
fn test_can_message_extended() {
let msg = CanMessage::new_extended(0x1234_5678, &[1, 2, 3, 4]).unwrap();
assert_eq!(msg.id(), CanId::Extended(0x1234_5678));
assert_eq!(msg.data(), &[1, 2, 3, 4]);
}
#[test]
fn test_can_message_fd() {
let msg = CanMessage::new_fd(CanId::Standard(0x123), &[1; 64]).unwrap();
assert_eq!(msg.data().len(), 64);
assert!(msg.is_fd());
assert!(msg.is_brs());
}
#[test]
fn test_can_message_remote() {
let msg = CanMessage::new_remote(CanId::Standard(0x123), 4).unwrap();
assert!(msg.is_remote());
assert_eq!(msg.data().len(), 0);
}
#[test]
fn test_invalid_standard_id() {
let result = CanMessage::new_standard(0x800, &[1, 2, 3]);
assert!(result.is_err());
}
#[test]
fn test_invalid_data_length() {
let result = CanMessage::new_standard(0x123, &[1; 9]);
assert!(result.is_err());
}
#[test]
fn test_invalid_fd_data_length() {
let result = CanMessage::new_fd(CanId::Standard(0x123), &[1; 65]);
assert!(result.is_err());
}
}