use crate::types::J1939Id;
pub fn parse_can_id(can_id: u32) -> J1939Id {
let sa = (can_id & 0xFF) as u8;
let ps = ((can_id >> 8) & 0xFF) as u8;
let pf = ((can_id >> 16) & 0xFF) as u8;
let dp = ((can_id >> 24) & 0x01) as u8;
let priority = ((can_id >> 26) & 0x07) as u8;
let (pgn, destination_address) = if pf >= 240 {
let pgn = ((dp as u32) << 16) | ((pf as u32) << 8) | (ps as u32);
(pgn, 0xFF) } else {
let pgn = ((dp as u32) << 16) | ((pf as u32) << 8);
(pgn, ps)
};
J1939Id {
priority,
pgn,
source_address: sa,
destination_address,
}
}
pub fn build_can_id(id: &J1939Id) -> u32 {
id.to_can_id()
}
pub fn build_request_pgn(
source_address: u8,
destination_address: u8,
requested_pgn: u32,
) -> (u32, [u8; 3]) {
let id = J1939Id {
priority: 6, pgn: 0xEA00, source_address,
destination_address,
};
let can_id = id.to_can_id();
let data = [
(requested_pgn & 0xFF) as u8,
((requested_pgn >> 8) & 0xFF) as u8,
((requested_pgn >> 16) & 0xFF) as u8,
];
(can_id, data)
}
#[inline]
pub fn is_valid_j1939_id(can_id: u32) -> bool {
can_id <= 0x1FFFFFFF
}
#[inline]
pub fn extract_pgn(can_id: u32) -> u32 {
let ps = ((can_id >> 8) & 0xFF) as u8;
let pf = ((can_id >> 16) & 0xFF) as u8;
let dp = ((can_id >> 24) & 0x01) as u8;
if pf >= 240 {
((dp as u32) << 16) | ((pf as u32) << 8) | (ps as u32)
} else {
((dp as u32) << 16) | ((pf as u32) << 8)
}
}
#[inline]
pub fn extract_source_address(can_id: u32) -> u8 {
(can_id & 0xFF) as u8
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_parse_can_id_eec1() {
let id = parse_can_id(0x0CF00400);
assert_eq!(id.priority, 3);
assert_eq!(id.pgn, 61444);
assert_eq!(id.source_address, 0x00);
assert!(id.is_broadcast());
}
#[test]
fn test_parse_can_id_et1() {
let id = parse_can_id(0x18FEEE00);
assert_eq!(id.priority, 6);
assert_eq!(id.pgn, 65262);
assert_eq!(id.source_address, 0x00);
}
#[test]
fn test_parse_can_id_request() {
let id = parse_can_id(0x18EA00FE);
assert_eq!(id.priority, 6);
assert_eq!(id.pgn, 0xEA00);
assert_eq!(id.source_address, 0xFE);
assert_eq!(id.destination_address, 0x00);
assert!(id.is_peer_to_peer());
}
#[test]
fn test_build_can_id_roundtrip() {
let original = 0x0CF00400u32;
let id = parse_can_id(original);
let rebuilt = build_can_id(&id);
assert_eq!(original, rebuilt);
}
#[test]
fn test_build_request_pgn() {
let (can_id, data) = build_request_pgn(0xFE, 0x00, 65253);
assert_eq!(can_id, 0x18EA00FE);
assert_eq!(data[0], 0xE5); assert_eq!(data[1], 0xFE); assert_eq!(data[2], 0x00); }
#[test]
fn test_extract_pgn() {
assert_eq!(extract_pgn(0x0CF00400), 61444);
assert_eq!(extract_pgn(0x18FEEE00), 65262);
assert_eq!(extract_pgn(0x18EA00FE), 0xEA00);
}
#[test]
fn test_extract_source_address() {
assert_eq!(extract_source_address(0x0CF00400), 0x00);
assert_eq!(extract_source_address(0x18EA00FE), 0xFE);
}
}