mod flex_ray_channel;
mod flex_ray_flags;
pub use flex_ray_channel::FlexRayChannel;
pub use flex_ray_flags::FlexRayFlags;
use alloc::vec::Vec;
use crate::bus_logging::BusFrame;
pub const MAX_FLEXRAY_PAYLOAD: usize = 254;
pub const MAX_SLOT_ID: u16 = 2047;
pub const MAX_CYCLE_COUNT: u8 = 63;
#[derive(Debug, Clone)]
pub struct FlexRayFrame {
pub slot_id: u16,
pub cycle: u8,
pub channel: FlexRayChannel,
pub flags: FlexRayFlags,
pub header_crc: u16,
pub payload: Vec<u8>,
}
pub const FLEXRAY_HEADER_SIZE: usize = 8;
impl FlexRayFrame {
pub fn new(slot_id: u16, cycle: u8, channel: FlexRayChannel, payload: Vec<u8>) -> Self {
Self {
slot_id: slot_id.min(MAX_SLOT_ID),
cycle: cycle & MAX_CYCLE_COUNT,
channel,
flags: FlexRayFlags::rx(),
header_crc: 0,
payload: if payload.len() > MAX_FLEXRAY_PAYLOAD {
payload[..MAX_FLEXRAY_PAYLOAD].to_vec()
} else {
payload
},
}
}
pub fn channel_a(slot_id: u16, cycle: u8, payload: Vec<u8>) -> Self {
Self::new(slot_id, cycle, FlexRayChannel::A, payload)
}
pub fn channel_b(slot_id: u16, cycle: u8, payload: Vec<u8>) -> Self {
Self::new(slot_id, cycle, FlexRayChannel::B, payload)
}
pub fn null_frame(slot_id: u16, cycle: u8, channel: FlexRayChannel) -> Self {
let mut frame = Self::new(slot_id, cycle, channel, Vec::new());
frame.flags = frame.flags.with_null_frame(true);
frame
}
pub fn startup(slot_id: u16, cycle: u8, channel: FlexRayChannel, payload: Vec<u8>) -> Self {
let mut frame = Self::new(slot_id, cycle, channel, payload);
frame.flags = frame.flags.with_startup(true).with_sync(true);
frame
}
pub fn with_tx(mut self) -> Self {
self.flags = self.flags.with_tx(true);
self
}
pub fn with_rx(mut self) -> Self {
self.flags = self.flags.with_tx(false);
self
}
pub fn with_dynamic(mut self) -> Self {
self.flags = self.flags.with_dynamic(true);
self
}
pub fn to_bytes(&self) -> Vec<u8> {
let total_size = FLEXRAY_HEADER_SIZE + self.payload.len();
let mut bytes = Vec::with_capacity(total_size);
bytes.extend_from_slice(&self.slot_id.to_le_bytes());
bytes.push(self.cycle);
bytes.push(self.channel as u8);
bytes.extend_from_slice(&self.flags.to_u16().to_le_bytes());
bytes.push((self.header_crc & 0xFF) as u8);
bytes.push(self.payload.len() as u8);
bytes.extend_from_slice(&self.payload);
bytes
}
pub fn from_bytes(bytes: &[u8]) -> Option<Self> {
if bytes.len() < FLEXRAY_HEADER_SIZE {
return None;
}
let slot_id = u16::from_le_bytes([bytes[0], bytes[1]]);
let cycle = bytes[2];
let channel = FlexRayChannel::from_u8(bytes[3]);
let flags = FlexRayFlags::from_u16(u16::from_le_bytes([bytes[4], bytes[5]]));
let header_crc = bytes[6] as u16;
let payload_len = bytes[7] as usize;
if bytes.len() < FLEXRAY_HEADER_SIZE + payload_len {
return None;
}
let payload = bytes[FLEXRAY_HEADER_SIZE..FLEXRAY_HEADER_SIZE + payload_len].to_vec();
Some(Self {
slot_id,
cycle,
channel,
flags,
header_crc,
payload,
})
}
pub fn payload(&self) -> &[u8] {
&self.payload
}
pub fn payload_len(&self) -> usize {
self.payload.len()
}
}
impl Default for FlexRayFrame {
fn default() -> Self {
Self::new(1, 0, FlexRayChannel::A, Vec::new())
}
}
impl BusFrame for FlexRayFrame {
fn to_mdf_bytes(&self) -> Vec<u8> {
self.to_bytes()
}
fn mdf_size(&self) -> usize {
FLEXRAY_HEADER_SIZE + self.payload.len()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_flexray_frame_basic() {
let frame = FlexRayFrame::new(100, 5, FlexRayChannel::A, vec![0x01, 0x02, 0x03, 0x04]);
assert_eq!(frame.slot_id, 100);
assert_eq!(frame.cycle, 5);
assert_eq!(frame.channel, FlexRayChannel::A);
assert_eq!(frame.payload(), &[0x01, 0x02, 0x03, 0x04]);
}
#[test]
fn test_flexray_frame_slot_id_clamping() {
let frame = FlexRayFrame::new(3000, 0, FlexRayChannel::A, vec![]);
assert_eq!(frame.slot_id, MAX_SLOT_ID);
}
#[test]
fn test_flexray_frame_cycle_masking() {
let frame = FlexRayFrame::new(1, 100, FlexRayChannel::A, vec![]);
assert_eq!(frame.cycle, 100 & MAX_CYCLE_COUNT);
}
#[test]
fn test_flexray_flags() {
let flags = FlexRayFlags::tx();
assert!(flags.is_tx());
assert!(flags.is_valid());
let flags = FlexRayFlags::rx();
assert!(flags.is_rx());
assert!(flags.is_valid());
let flags = FlexRayFlags::from_u16(
FlexRayFlags::STARTUP | FlexRayFlags::SYNC | FlexRayFlags::VALID,
);
assert!(flags.is_startup());
assert!(flags.is_sync());
assert!(flags.is_valid());
}
#[test]
fn test_flexray_frame_roundtrip() {
let original = FlexRayFrame::new(100, 10, FlexRayChannel::B, vec![0xAA, 0xBB, 0xCC, 0xDD])
.with_tx()
.with_dynamic();
let bytes = original.to_bytes();
let parsed = FlexRayFrame::from_bytes(&bytes).unwrap();
assert_eq!(parsed.slot_id, original.slot_id);
assert_eq!(parsed.cycle, original.cycle);
assert_eq!(parsed.channel, original.channel);
assert!(parsed.flags.is_tx());
assert!(parsed.flags.is_dynamic());
assert_eq!(parsed.payload(), original.payload());
}
#[test]
fn test_flexray_channel() {
assert_eq!(FlexRayChannel::from_u8(0), FlexRayChannel::A);
assert_eq!(FlexRayChannel::from_u8(1), FlexRayChannel::B);
assert_eq!(FlexRayChannel::from_u8(2), FlexRayChannel::AB);
assert_eq!(FlexRayChannel::from_u8(99), FlexRayChannel::A);
}
#[test]
fn test_null_frame() {
let frame = FlexRayFrame::null_frame(50, 0, FlexRayChannel::A);
assert!(frame.flags.is_null_frame());
assert!(frame.payload.is_empty());
}
#[test]
fn test_startup_frame() {
let frame = FlexRayFrame::startup(1, 0, FlexRayChannel::AB, vec![0x00; 8]);
assert!(frame.flags.is_startup());
assert!(frame.flags.is_sync());
}
}