use canlink_hal::{CanError, CanId, CanMessage, MessageFlags, Timestamp};
use canlink_tscan_sys::types::*;
pub fn from_tlibcan(msg: &TLIBCAN) -> CanMessage {
let identifier = msg.FIdentifier;
let properties = msg.FProperties;
let dlc = msg.FDLC;
let time_us = msg.FTimeUs;
let data = msg.FData;
let is_extended = (properties & MASK_CANPROP_EXTEND) != 0;
let id = if is_extended {
CanId::Extended(identifier as u32)
} else {
CanId::Standard((identifier & 0x7FF) as u16)
};
let data_len = (dlc as usize).min(8);
let data_vec = data[..data_len].to_vec();
let is_remote = (properties & MASK_CANPROP_REMOTE) != 0;
let mut message = if is_remote {
CanMessage::new_remote(id, dlc).unwrap()
} else if is_extended {
CanMessage::new_extended(id.raw(), &data_vec).unwrap()
} else {
CanMessage::new_standard(id.raw() as u16, &data_vec).unwrap()
};
if time_us > 0 {
message.set_timestamp(Timestamp::from_micros(time_us as u64));
}
message
}
pub fn to_tlibcan(msg: &CanMessage, channel: u8) -> Result<TLIBCAN, CanError> {
if msg.data().len() > 8 {
return Err(CanError::InvalidDataLength {
expected: 8,
actual: msg.data().len(),
});
}
let mut properties: u8 = 0;
properties |= MASK_CANPROP_DIR_TX;
if msg.id().is_extended() {
properties |= MASK_CANPROP_EXTEND;
}
if msg.flags().contains(MessageFlags::RTR) {
properties |= MASK_CANPROP_REMOTE;
}
let identifier = msg.id().raw() as s32;
let mut data = [0u8; 8];
let data_len = msg.data().len();
data[..data_len].copy_from_slice(msg.data());
Ok(TLIBCAN {
FIdxChn: channel,
FProperties: properties,
FDLC: data_len as u8,
FReserved: 0,
FIdentifier: identifier,
FTimeUs: msg.timestamp().map_or(0, |ts| ts.as_micros() as s64),
FData: data,
})
}
pub fn from_tlibcanfd(msg: &TLIBCANFD) -> CanMessage {
let identifier = msg.FIdentifier;
let properties = msg.FProperties;
let dlc = msg.FDLC;
let time_us = msg.FTimeUs;
let data = msg.FData;
let is_extended = (properties & MASK_CANPROP_EXTEND) != 0;
let id = if is_extended {
CanId::Extended(identifier as u32)
} else {
CanId::Standard((identifier & 0x7FF) as u16)
};
let data_len = dlc_to_len(dlc).min(64);
let data_vec = data[..data_len].to_vec();
let is_remote = (properties & MASK_CANPROP_REMOTE) != 0;
let mut message = if is_remote {
CanMessage::new_remote(id, dlc).unwrap()
} else {
CanMessage::new_fd(id, &data_vec).unwrap()
};
if time_us > 0 {
message.set_timestamp(Timestamp::from_micros(time_us as u64));
}
message
}
pub fn to_tlibcanfd(msg: &CanMessage, channel: u8) -> Result<TLIBCANFD, CanError> {
if msg.data().len() > 64 {
return Err(CanError::InvalidDataLength {
expected: 64,
actual: msg.data().len(),
});
}
let mut properties: u8 = 0;
properties |= MASK_CANPROP_DIR_TX;
if msg.id().is_extended() {
properties |= MASK_CANPROP_EXTEND;
}
if msg.flags().contains(MessageFlags::RTR) {
properties |= MASK_CANPROP_REMOTE;
}
let mut fd_properties: u8 = MASK_CANFDPROP_IS_FD;
if msg.flags().contains(MessageFlags::BRS) {
fd_properties |= MASK_CANFDPROP_IS_BRS;
}
if msg.flags().contains(MessageFlags::ESI) {
fd_properties |= MASK_CANFDPROP_IS_ESI;
}
let identifier = msg.id().raw() as s32;
let mut data = [0u8; 64];
let data_len = msg.data().len();
data[..data_len].copy_from_slice(msg.data());
let dlc = len_to_dlc(data_len as u8);
Ok(TLIBCANFD {
FIdxChn: channel,
FProperties: properties,
FDLC: dlc,
FFDProperties: fd_properties,
FIdentifier: identifier,
FTimeUs: msg.timestamp().map_or(0, |ts| ts.as_micros() as s64),
FData: data,
})
}
fn dlc_to_len(dlc: u8) -> usize {
match dlc {
0..=8 => dlc as usize,
9 => 12,
10 => 16,
11 => 20,
12 => 24,
13 => 32,
14 => 48,
15 => 64,
_ => 0, }
}
fn len_to_dlc(len: u8) -> u8 {
match len {
0..=8 => len,
9..=12 => 9,
13..=16 => 10,
17..=20 => 11,
21..=24 => 12,
25..=32 => 13,
33..=48 => 14,
49..=64 => 15,
_ => 15, }
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_to_tlibcan_standard() {
let msg = CanMessage::new_standard(0x123, &[1, 2, 3, 4]).unwrap();
let libcan = to_tlibcan(&msg, 0).unwrap();
let idx_chn = libcan.FIdxChn;
let identifier = libcan.FIdentifier;
let dlc = libcan.FDLC;
let data = libcan.FData;
let properties = libcan.FProperties;
assert_eq!(idx_chn, 0);
assert_eq!(identifier, 0x123);
assert_eq!(dlc, 4);
assert_eq!(&data[..4], &[1, 2, 3, 4]);
assert_eq!(properties & MASK_CANPROP_EXTEND, 0);
assert_ne!(properties & MASK_CANPROP_DIR_TX, 0);
}
#[test]
fn test_to_tlibcan_extended() {
let msg = CanMessage::new_extended(0x12345678, &[5, 6, 7, 8]).unwrap();
let libcan = to_tlibcan(&msg, 1).unwrap();
let idx_chn = libcan.FIdxChn;
let identifier = libcan.FIdentifier;
let dlc = libcan.FDLC;
let properties = libcan.FProperties;
assert_eq!(idx_chn, 1);
assert_eq!(identifier, 0x12345678);
assert_eq!(dlc, 4);
assert_ne!(properties & MASK_CANPROP_EXTEND, 0);
}
#[test]
fn test_from_tlibcan() {
let libcan = TLIBCAN {
FIdentifier: 0x456,
FDLC: 3,
FProperties: MASK_CANPROP_DIR_TX,
FData: [0xAA, 0xBB, 0xCC, 0, 0, 0, 0, 0],
..Default::default()
};
let msg = from_tlibcan(&libcan);
assert_eq!(msg.id(), CanId::Standard(0x456));
assert_eq!(msg.data(), &[0xAA, 0xBB, 0xCC]);
}
#[test]
fn test_dlc_to_len() {
assert_eq!(dlc_to_len(0), 0);
assert_eq!(dlc_to_len(8), 8);
assert_eq!(dlc_to_len(9), 12);
assert_eq!(dlc_to_len(10), 16);
assert_eq!(dlc_to_len(15), 64);
}
#[test]
fn test_len_to_dlc() {
assert_eq!(len_to_dlc(0), 0);
assert_eq!(len_to_dlc(8), 8);
assert_eq!(len_to_dlc(12), 9);
assert_eq!(len_to_dlc(16), 10);
assert_eq!(len_to_dlc(64), 15);
}
#[test]
fn test_rtr_flag() {
let msg = CanMessage::new_remote(CanId::Standard(0x100), 0).unwrap();
let libcan = to_tlibcan(&msg, 0).unwrap();
let properties = libcan.FProperties;
assert_ne!(properties & MASK_CANPROP_REMOTE, 0);
}
}