use crate::engine::{FASTPACKET_MAX_SIZE, FramePacketType};
include!("fastpacket_generated.rs");
pub const CANBOAT_PGN_START: u32 = 0x40000;
pub fn packet_type(pgn: u32) -> FramePacketType {
if (FASTPACKET_MIXED_START..FASTPACKET_MIXED_END).contains(&pgn) {
return if FASTPACKET_MIXED[(pgn - FASTPACKET_MIXED_START) as usize] {
FramePacketType::Fast
} else {
FramePacketType::Single
};
}
if (0x10000..FASTPACKET_MIXED_START).contains(&pgn) {
return FramePacketType::Fast;
}
if pgn >= CANBOAT_PGN_START {
return FramePacketType::Fast;
}
FramePacketType::Single
}
pub fn fragment(seq: u8, data: &[u8]) -> Option<Vec<[u8; 8]>> {
if data.len() > FASTPACKET_MAX_SIZE {
return None;
}
let mut out = Vec::with_capacity(data.len() / 7 + 1);
let mut index: u8 = 0;
let mut remaining = data.len();
let mut offset = 0;
while remaining > 0 || index == 0 {
let mut frame = [0xffu8; 8];
frame[0] = (seq << 5) | (index & 0x1f);
let (payload_start, chunk) = if index == 0 {
frame[1] = data.len() as u8;
(2, remaining.min(6))
} else {
(1, remaining.min(7))
};
frame[payload_start..payload_start + chunk].copy_from_slice(&data[offset..offset + chunk]);
out.push(frame);
offset += chunk;
remaining -= chunk;
index = index.wrapping_add(1);
if remaining == 0 {
break;
}
}
Some(out)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn fragment_fills_32_frames_and_refuses_more() {
let data = [0xab; FASTPACKET_MAX_SIZE];
let frames = fragment(5, &data).expect("223 bytes fit");
assert_eq!(frames.len(), 32);
assert_eq!(frames[0][..2], [5 << 5, 223]);
assert_eq!(frames[31][0], (5 << 5) | 31);
assert_eq!(frames[31][1..], [0xab; 7]);
assert_eq!(fragment(5, &[0xab; FASTPACKET_MAX_SIZE + 1]), None);
}
#[test]
fn pgn_127508_battery_status_is_single() {
assert_eq!(packet_type(127508), FramePacketType::Single);
}
#[test]
fn pgn_127506_dc_detailed_is_fast() {
assert_eq!(packet_type(127506), FramePacketType::Fast);
}
#[test]
fn pgn_126996_product_info_is_fast() {
assert_eq!(packet_type(126996), FramePacketType::Fast);
}
#[test]
fn pgn_60928_address_claim_is_single() {
assert_eq!(packet_type(60928), FramePacketType::Single);
}
#[test]
fn pgn_126993_heartbeat_is_single() {
assert_eq!(packet_type(126993), FramePacketType::Single);
}
}