use crate::util::*;
use super::display_byte_slice;
#[repr(packed)]
#[derive(Clone, Copy, PartialEq, Debug)]
pub struct Tdt {
lane_status_15_0: u32,
lane_status_23_16: u16,
lane_status_27_24: u8,
timeout_to_start_timeout_start_stop_timeout_in_idle_res2: u8,
res0_lane_starts_violation_res1_transmission_timeout_packet_done: u8,
id: u8,
}
impl Tdt {
pub const ID: u8 = 0xF0;
pub fn reserved0(&self) -> u8 {
self.res0_lane_starts_violation_res1_transmission_timeout_packet_done >> 4
}
pub fn lane_starts_violation(&self) -> bool {
(self.res0_lane_starts_violation_res1_transmission_timeout_packet_done & 0b1000) != 0
}
pub fn reserved1(&self) -> u8 {
self.res0_lane_starts_violation_res1_transmission_timeout_packet_done & 0b0100
}
pub fn transmission_timeout(&self) -> bool {
(self.res0_lane_starts_violation_res1_transmission_timeout_packet_done & 0b0010) != 0
}
pub fn packet_done(&self) -> bool {
(self.res0_lane_starts_violation_res1_transmission_timeout_packet_done & 0b0001) == 1
}
pub fn timeout_to_start(&self) -> bool {
(self.timeout_to_start_timeout_start_stop_timeout_in_idle_res2 & 0b1000_0000) != 0
}
pub fn timeout_start_stop(&self) -> bool {
(self.timeout_to_start_timeout_start_stop_timeout_in_idle_res2 & 0b0100_0000) != 0
}
pub fn timeout_in_idle(&self) -> bool {
(self.timeout_to_start_timeout_start_stop_timeout_in_idle_res2 & 0b0010_0000) != 0
}
pub fn reserved2(&self) -> u8 {
self.timeout_to_start_timeout_start_stop_timeout_in_idle_res2 & 0b0001_1111
}
pub fn lane_status_27_24(&self) -> u8 {
self.lane_status_27_24
}
pub fn lane_status_23_16(&self) -> u16 {
self.lane_status_23_16
}
pub fn lane_status_15_0(&self) -> u32 {
self.lane_status_15_0
}
}
impl fmt::Display for Tdt {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
display_byte_slice(self, f)
}
}
impl StatusWord for Tdt {
fn id(&self) -> u8 {
self.id
}
fn is_reserved_0(&self) -> bool {
self.reserved0() == 0 && self.reserved1() == 0 && self.reserved2() == 0
}
fn from_buf(buf: &[u8]) -> Result<Self, io::Error> {
Ok(Self {
lane_status_15_0: LittleEndian::read_u32(&buf[0..=3]),
lane_status_23_16: LittleEndian::read_u16(&buf[4..=5]),
lane_status_27_24: buf[6],
timeout_to_start_timeout_start_stop_timeout_in_idle_res2: buf[7],
res0_lane_starts_violation_res1_transmission_timeout_packet_done: buf[8],
id: buf[9],
})
}
}
#[cfg(test)]
mod tests {
use super::*;
use pretty_assertions::assert_eq;
#[test]
fn tdt_read_write() {
let raw_data_tdt = [
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x01,
Tdt::ID,
];
let tdt = Tdt::load(&mut raw_data_tdt.as_slice()).unwrap();
assert_eq!(tdt.id(), Tdt::ID);
assert!(tdt.is_reserved_0());
assert!(tdt.packet_done());
let loaded_tdt = Tdt::load(&mut tdt.to_byte_slice()).unwrap();
assert_eq!(tdt, loaded_tdt);
}
#[test]
fn tdt_reporting_errors_read_write() {
const LANE_0_AND_3_IN_WARNING: u8 = 0b0100_0001;
const LANE_4_TO_7_IN_FATAL: u8 = 0b1111_1111;
const LANE_8_TO_11_IN_WARNING: u8 = 0b0101_0101;
const LANE_12_AND_15_IN_ERROR: u8 = 0b1000_0010;
const LANE_16_AND_19_IN_OK: u8 = 0b0000_0000;
const LANE_22_IN_WARNING: u8 = 0b0001_0000;
const LANE_24_AND_25_IN_ERROR: u8 = 0b0000_1010;
const TIMEOUT_TO_START_TIMEOUT_START_STOP_TIMEOUT_IN_IDLE_ALL_SET: u8 = 0xE0;
const LANE_STARTS_VIOLATION_AND_TRANSMISSION_TIMEOUT_SET: u8 = 0x0A;
let raw_data_tdt = [
LANE_0_AND_3_IN_WARNING,
LANE_4_TO_7_IN_FATAL,
LANE_8_TO_11_IN_WARNING,
LANE_12_AND_15_IN_ERROR,
LANE_16_AND_19_IN_OK,
LANE_22_IN_WARNING,
LANE_24_AND_25_IN_ERROR,
TIMEOUT_TO_START_TIMEOUT_START_STOP_TIMEOUT_IN_IDLE_ALL_SET,
LANE_STARTS_VIOLATION_AND_TRANSMISSION_TIMEOUT_SET,
Tdt::ID,
];
let tdt = Tdt::load(&mut raw_data_tdt.as_slice()).unwrap();
println!("{tdt}");
assert_eq!(tdt.id(), Tdt::ID);
println!("tdt.is_reserved_0() = {}", tdt.is_reserved_0());
println!(
"{:x} {:x} {:x}",
tdt.reserved0(),
tdt.reserved1(),
tdt.reserved2()
);
assert!(tdt.is_reserved_0());
assert!(!tdt.packet_done());
assert!(tdt.transmission_timeout());
assert!(tdt.lane_starts_violation());
assert!(tdt.timeout_to_start());
assert!(tdt.timeout_start_stop());
assert!(tdt.timeout_in_idle());
assert_eq!(tdt.lane_status_27_24(), LANE_24_AND_25_IN_ERROR);
let combined_lane_status_23_to_16 =
((LANE_22_IN_WARNING as u16) << 8) | (LANE_16_AND_19_IN_OK as u16);
assert_eq!(tdt.lane_status_23_16(), combined_lane_status_23_to_16);
let combined_lane_status_15_to_0 = ((LANE_12_AND_15_IN_ERROR as u32) << 24)
| ((LANE_8_TO_11_IN_WARNING as u32) << 16)
| ((LANE_4_TO_7_IN_FATAL as u32) << 8)
| (LANE_0_AND_3_IN_WARNING as u32);
assert_eq!(tdt.lane_status_15_0(), combined_lane_status_15_to_0);
let loaded_tdt = Tdt::load(&mut tdt.to_byte_slice()).unwrap();
assert_eq!(tdt, loaded_tdt);
let tdt_ref = &tdt;
println!("{tdt_ref}");
}
}