1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
use std::fmt::{Display, Formatter, Write};
use isotp_rs::IsoTpFrame;
use crate::identifier::Id;

#[repr(C)]
#[derive(Debug, Copy, Clone, Eq, PartialEq, Default)]
pub enum Direct {
    #[default]
    Transmit,
    Receive,
}

/// CAN 2.0
pub trait Frame {
    type Channel: Display;
    
    fn new(id: impl Into<Id>, data: &[u8]) -> Option<Self>
    where
        Self: Sized;
    
    fn new_remote(id: impl Into<Id>, len: usize) -> Option<Self>
        where Self: Sized;

    fn from_iso_tp(id: impl Into<Id>, frame: impl IsoTpFrame, padding: Option<u8>) -> Option<Self>
    where
        Self: Sized {
        let data = frame.encode(padding);
        Self::new(id, data.as_slice())
    }
    
    fn timestamp(&self) -> u64;
    
    fn set_timestamp(&mut self, value: Option<u64>) -> &mut Self
        where Self: Sized;

    /// Prioritizes returning J1939Id if j1939 is true.
    fn id(&self, j1939: bool) -> Id;
    
    fn is_can_fd(&self) -> bool;
    
    fn set_can_fd(&mut self, value: bool) -> &mut Self
    where
        Self: Sized;
    
    fn is_remote(&self) -> bool;
    
    fn is_extended(&self) -> bool;
    
    fn direct(&self) -> Direct;
    
    fn set_direct(&mut self, direct: Direct) -> &mut Self
    where
        Self: Sized;
    
    fn is_bitrate_switch(&self) -> bool;
    
    fn set_bitrate_switch(&mut self, value: bool) -> &mut Self
    where
        Self: Sized;
    
    fn is_error_frame(&self) -> bool;
    
    fn set_error_frame(&mut self, value: bool) -> &mut Self
    where
        Self: Sized;

    /// Error state indicator
    fn is_esi(&self) -> bool;

    /// Set error state indicator
    fn set_esi(&mut self, value: bool) -> &mut Self
    where
        Self: Sized;
    
    fn channel(&self) -> Self::Channel;
    
    fn set_channel(&mut self, value: Self::Channel) -> &mut Self
    where
        Self: Sized;

    /// ensure return the actual length of data.
    fn data(&self) -> &[u8];
    
    fn dlc(&self) -> Option<usize>;
    
    fn length(&self) -> usize;
}

impl<T: Display> Display for dyn Frame<Channel = T> {
    /// Output Frame as `asc` String.
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        let data_str = if self.is_remote() {
            " ".to_owned()
        } else {
            self.data()
                .iter()
                .fold(String::new(), |mut out, &b| {
                    let _ = write!(out, "{b:02x} ");
                    out
                })
        };

        if self.is_can_fd() {
            let mut flags = 1 << 12;
            write!(f, "{:.3} CANFD {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {}",
                   self.timestamp() as f64 / 1000.,
                   self.channel(),
                   direct(self.direct()),
                   // if self.is_rx() { "Rx" } else { "Tx" },
                   format!("{: >8x}", self.id(false).as_raw()),
                   if self.is_bitrate_switch() {
                       flags |= 1 << 13;
                       1
                   } else { 0 },
                   if self.is_esi() {
                       flags |= 1 << 14;
                       1
                   } else { 0 },
                   format!("{: >2}", self.dlc().unwrap_or_default()),
                   format!("{: >2}", self.length()),
                   data_str,
                   format!("{: >8}", 0),       // message_duration
                   format!("{: <4}", 0),       // message_length
                   format!("{: >8x}", flags),
                   format!("{: >8}", 0),       // crc
                   format!("{: >8}", 0),       // bit_timing_conf_arb
                   format!("{: >8}", 0),       // bit_timing_conf_data
                   format!("{: >8}", 0),       // bit_timing_conf_ext_arb
                   format!("{: >8}", 0),       // bit_timing_conf_ext_data
            )
        }
        else {
            write!(f, "{:.3} {} {}{: <4} {} {} {} {}",
                   self.timestamp() as f64 / 1000.,
                   self.channel(),
                   format!("{: >8x}", self.id(false).as_raw()),
                   if self.is_extended() { "x" } else { "" },
                   direct(self.direct()),
                   // if self.is_rx() { "Rx" } else { "Tx" },
                   if self.is_remote() { "r" } else { "d" },
                   format!("{: >2}", self.length()),
                   data_str,
            )
        }
    }
}

#[inline]
fn direct<'a>(direct: Direct) -> &'a str {
    match direct {
        Direct::Transmit => "Tx",
        Direct::Receive => "Rx",
    }
}