Skip to main content

funcan_rs/
raw.rs

1//! # Raw Module
2//!
3//! The `raw` module provides an abstract interface for working with raw CAN frames.
4
5use crate::machine::*;
6
7/// A structure representing RAW CAN frames.
8///
9/// # Fields
10///
11/// * `can_cobid` - The CAN identifier (COB-ID) of the frame. This is a 32-bit value that uniquely identifies the frame in the CAN network.
12/// * `can_len` - The length of the CAN frame. Number of valid bytes in `can_data`
13/// * `can_data` - The data of the CAN frame. This is an array of 8 bytes containing the payload of the frame.
14///
15#[derive(Debug, Clone, Copy)]
16pub struct CANFrame {
17    /// The CAN identifier (COB-ID) of the frame.
18    ///
19    /// This is a 32-bit value that uniquely identifies the frame in the CAN network.
20    pub can_cobid: u32,
21
22    /// The length of the CAN frame
23    pub can_len: usize,
24
25    /// The data of the CAN frame.
26    ///
27    /// This is an array of 8 bytes containing the payload of the frame.
28    pub can_data: [u8; 8],
29}
30
31impl Default for CANFrame {
32    fn default() -> Self {
33        Self {
34            can_cobid: 0,
35            can_len: 0,
36            can_data: [0; 8],
37        }
38    }
39}
40
41impl CANFrame {   
42    /// Serializes raw CAN frame    
43    pub fn write_to_slice(self: &Self, buffer: &mut [u8]) {
44        assert!(buffer.len() >= 16, "Buffer must be at least 16 bytes long");
45
46        // Write COB-ID as little endian
47        buffer[0..4].copy_from_slice(&self.can_cobid.to_le_bytes());
48
49        // Write length
50        buffer[4] = self.can_len as u8;
51
52        // Fill 3 bytes with zero (padding)
53        buffer[5..8].fill(0);
54
55        // Write CAN data
56        buffer[8..16].copy_from_slice(&self.can_data);
57    }
58}
59
60/// Represents the possible states within a CAN frame processing sequence.
61enum State {
62    Init,
63    Id0,
64    Id1,
65    Id2,
66    Id3,
67    Len,
68    Skip0,
69    Skip1,
70    Skip2,
71    Data,
72    Final,
73}
74
75/// A state machine designed to process and construct raw CAN frames.
76pub struct CANFrameMachine {
77    state: State,
78    can_frame: CANFrame,
79    len: usize,
80    index: usize,
81}
82
83impl Default for CANFrameMachine {
84    fn default() -> Self {
85        Self {
86            state: State::Init,
87            can_frame: CANFrame::default(),
88            len: 0,
89            index: 0,
90        }
91    }
92}
93
94impl CANFrameMachine {
95    /// Processes an incoming data byte, storing it in the CAN frame's data array.
96    ///
97    /// This method updates the state and manages the index where the byte is stored.
98    /// Depending on the remaining length, it sets the next state appropriately.
99    fn get_data_byte(self: &mut Self, x: u8) {
100        if self.len > 1 {
101            self.len = self.len - 1;
102            self.state = State::Data;
103            self.can_frame.can_data[self.index] = x;
104        } else if self.len == 1 {
105            self.len = self.len - 1;
106            self.state = State::Final;
107            self.can_frame.can_data[self.index] = x;
108        } else {
109            self.state = State::Final;
110        }
111
112        self.index = self.index + 1;
113    }
114}
115
116impl MachineTrans<u8> for CANFrameMachine {
117    type Observation = Option<CANFrame>;
118
119    /// Resets the machine's state and the CAN frame data to their initial conditions.
120    fn initial(self: &mut Self) {
121        self.can_frame.can_cobid = 0;
122        self.can_frame.can_data.fill(0);
123        self.can_frame.can_len = 0;
124        self.len = 0;
125        self.index = 0;
126        self.state = State::Init;
127    }
128
129    /// Consumes an input byte and transitions the state machine according to the current state.
130    ///
131    /// Processes the input byte `x` and transitions the state machine to the next state
132    /// as part of building a CAN frame.
133    fn transit(self: &mut Self, x: u8) {
134        match &self.state {
135            State::Init => {
136                self.state = State::Id0;
137                self.can_frame.can_cobid = x.into();
138            }
139
140            State::Id0 => {
141                self.state = State::Id1;
142                self.can_frame.can_cobid = self.can_frame.can_cobid | ((x as u32) << 8);
143            }
144
145            State::Id1 => {
146                self.state = State::Id2;
147                self.can_frame.can_cobid = self.can_frame.can_cobid | ((x as u32) << 16);
148            }
149
150            State::Id2 => {
151                self.state = State::Id3;
152                self.can_frame.can_cobid = self.can_frame.can_cobid | ((x as u32) << 24);
153            }
154
155            State::Id3 => {
156                self.state = State::Len;
157                let len: usize = x.into();
158                self.len = len;
159                self.can_frame.can_len = len;
160            }
161
162            State::Len => {
163                self.state = State::Skip0;
164            }
165
166            State::Skip0 => {
167                self.state = State::Skip1;
168            }
169
170            State::Skip1 => {
171                self.state = State::Skip2;
172            }
173
174            State::Skip2 => {
175                self.get_data_byte(x);
176            }
177
178            State::Data => {
179                self.get_data_byte(x);
180            }
181
182            State::Final => {
183                self.index = self.index + 1;
184            }
185        }
186    }
187
188    /// Observes the current machine state to check for a completed CAN frame.
189    ///
190    /// Returns `Some(CANFrame)` if in a final state with a valid frame, otherwise `None`.
191    fn observe(self: &Self) -> Self::Observation {
192        match self.state {
193            State::Final => {
194                // should consume all input
195                if self.index == 8 {
196                    Some(self.can_frame)
197                } else {
198                    None
199                }
200            }
201            _ => None,
202        }
203    }
204}
205
206impl Final for Option<CANFrame> {
207    type FinalValue = CANFrame;
208
209    /// Determines if an `Option<CANFrame>` contains a final frame.
210    ///
211    /// # Returns
212    ///
213    /// - `Some(CANFrame)` if the option contains a valid frame.
214    /// - `None` if the option is empty.
215    fn is_final(self: Self) -> Option<Self::FinalValue> {
216        self
217    }
218}
219
220#[cfg(test)]
221mod tests {
222    use super::*;
223
224    #[test]
225    fn test_raw_can_frame_parsing() {
226        let frame = [
227            0x02, 0x07, 0x00, 0x00, // cobid
228            0x01, 0x00, 0x00, 0x00, // length with padding
229            0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // data
230        ];
231
232        let mut parser = CANFrameMachine::default();
233
234        for x in frame {
235            parser.transit(x);
236        }
237
238        let result = parser.observe().is_final().unwrap();
239
240        assert_eq!(result.can_cobid, 0x702);
241        assert_eq!(result.can_len, 1);
242        assert_eq!(result.can_data[0], 0x7f);
243    }
244
245    #[test]
246    fn test_raw_can_frame_decode_encode() {
247        let frame0: [u8; 16] = [
248            0x02, 0x07, 0x00, 0x00, // cobid
249            0x08, 0x00, 0x00, 0x00, // length with padding
250            0x7f, 0x7e, 0x7d, 0x7c, 0x00, 0x01, 0x02, 0x03, // data
251        ];
252
253        let mut frame1: [u8; 16] = [0; 16];
254            
255        let mut parser = CANFrameMachine::default();
256
257        for x in frame0 {
258            parser.transit(x);
259        }
260
261        let can_frame = parser.observe().is_final().unwrap();
262
263        can_frame.write_to_slice(&mut frame1);
264
265        assert_eq!(frame0, frame1);
266    }
267}