Thanks to visit codestin.com
Credit goes to docs.rs

socketcan/
dump.rs

1// socketcan/src/dump.rs
2//
3// Implements candump format parsing.
4//
5// This file is part of the Rust 'socketcan-rs' library.
6//
7// Licensed under the MIT license:
8//   <LICENSE or http://opensource.org/licenses/MIT>
9// This file may not be copied, modified, or distributed except according
10// to those terms.
11
12//! candump format parsing
13//!
14//! Parses the text log format emitted by the `candump` utility, which is
15//! part of [can-utils](https://github.com/linux-can/can-utils).
16//!
17//! Example:
18//!
19//! ```text
20//! (1735270496.916858) can0 110#00112233
21//! (1735270509.245511) can0 110#44556677
22//! (1735270588.936508) can0 120##500112233445566778899AABB
23//! (1735270606.171980) can0 122##500112233445566778899AABBCC000000
24//! (1735279041.257318) can1 104#R
25//! (1735279048.349278) can1 110#R4
26//! (1469439874.299654) can1 104#
27//! ```
28//!
29//! Can be parsed by a `Reader` object. The API is inspired by the
30//! [csv](https://crates.io/crates/csv) crate.
31
32use crate::{
33    frame::Frame,
34    id::{id_from_raw, FdFlags},
35    CanAnyFrame, CanDataFrame, CanFdFrame, CanFrame, CanRemoteFrame, ConstructionError,
36};
37use embedded_can::Frame as EmbeddedFrame;
38use hex::FromHex;
39use itertools::Itertools;
40use libc::canid_t;
41use std::{
42    fmt,
43    fs::File,
44    io::{self, BufRead, BufReader},
45    path::Path,
46};
47use thiserror::Error;
48
49/// candump line parse error
50#[derive(Error, Debug)]
51pub enum ParseError {
52    /// I/O Error
53    #[error(transparent)]
54    Io(#[from] io::Error),
55    /// Unexpected end of line
56    #[error("Unexpected end of line")]
57    UnexpectedEndOfLine,
58    /// Invalid time stamp
59    #[error("Invalid timestamp")]
60    InvalidTimestamp,
61    /// Invalid device name
62    #[error("Invalid device name")]
63    InvalidDeviceName,
64    /// Invalid CAN frame
65    #[error("Invalid CAN frame")]
66    InvalidCanFrame,
67    /// Error creating the frame
68    #[error(transparent)]
69    ConstructionError(#[from] ConstructionError),
70}
71
72/// Recorded CAN frame.
73/// This corresponds to the information in a line from the candump log.
74#[derive(Debug, Clone)]
75pub struct CanDumpRecord {
76    /// The timestamp
77    pub t_us: u64,
78    /// The name of the device
79    pub device: String,
80    /// The parsed frame
81    pub frame: CanAnyFrame,
82}
83
84impl fmt::Display for CanDumpRecord {
85    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
86        write!(
87            f,
88            "({:.6}) {} {:03X}",
89            1.0e-6 * self.t_us as f64,
90            self.device,
91            self.frame.raw_id()
92        )?;
93
94        use CanAnyFrame::*;
95        match self.frame {
96            Remote(frame) if frame.len() == 0 => f.write_str("#R"),
97            Remote(frame) => write!(f, "#R{}", frame.dlc()),
98            Error(_frame) => f.write_str(""),
99            Normal(frame) => {
100                let mut parts = frame.data().iter().map(|v| format!("{:02X}", v));
101                write!(f, "#{}", parts.join(""))
102            }
103            Fd(frame) => {
104                let mut parts = frame.data().iter().map(|v| format!("{:02X}", v));
105                write!(f, "##{}", parts.join(""))
106            }
107        }
108    }
109}
110
111/////////////////////////////////////////////////////////////////////////////
112// Reader
113
114#[derive(Debug)]
115/// A CAN log reader.
116pub struct Reader<R> {
117    // The underlying reader
118    rdr: R,
119    // The line buffer
120    buf: String,
121}
122
123impl<R: io::Read> Reader<R> {
124    /// Creates an I/O buffered reader from a CAN log reader.
125    pub fn from_reader(rdr: R) -> Reader<BufReader<R>> {
126        Reader {
127            rdr: BufReader::new(rdr),
128            buf: String::with_capacity(256),
129        }
130    }
131}
132
133impl Reader<File> {
134    /// Creates an I/O buffered reader from a file.
135    pub fn from_file<P: AsRef<Path>>(path: P) -> io::Result<Reader<BufReader<File>>> {
136        Ok(Reader::from_reader(File::open(path)?))
137    }
138}
139
140impl<R: BufRead> Reader<R> {
141    /// Returns an iterator over all records
142    #[deprecated(since = "3.5.0", note = "Use `iter()`")]
143    pub fn records(&mut self) -> CanDumpRecords<R> {
144        CanDumpRecords { src: self }
145    }
146
147    /// Advance state, returning next record.
148    pub fn next_record(&mut self) -> Result<Option<CanDumpRecord>, ParseError> {
149        self.buf.clear();
150        let nread = self.rdr.read_line(&mut self.buf)?;
151
152        // reached EOF
153        if nread == 0 {
154            return Ok(None);
155        }
156
157        let line = self.buf[..nread].trim();
158        let mut field_iter = line.split(' ');
159
160        // parse timestamp field
161        let ts = field_iter.next().ok_or(ParseError::UnexpectedEndOfLine)?;
162
163        if ts.len() < 3 || !ts.starts_with('(') || !ts.ends_with(')') {
164            return Err(ParseError::InvalidTimestamp);
165        }
166
167        let ts = &ts[1..ts.len() - 1];
168
169        let t_us = match ts.split_once('.') {
170            Some((num, mant)) => {
171                let num = num
172                    .parse::<u64>()
173                    .map_err(|_| ParseError::InvalidTimestamp)?;
174                let mant = mant
175                    .parse::<u64>()
176                    .map_err(|_| ParseError::InvalidTimestamp)?;
177                num.saturating_mul(1_000_000).saturating_add(mant)
178            }
179            _ => return Err(ParseError::InvalidTimestamp),
180        };
181
182        // device name
183        let device = field_iter
184            .next()
185            .ok_or(ParseError::UnexpectedEndOfLine)?
186            .to_string();
187
188        // parse packet
189        let can_raw = field_iter.next().ok_or(ParseError::UnexpectedEndOfLine)?;
190
191        let (can_id_str, mut can_data) = match can_raw.split_once('#') {
192            Some((id, data)) => (id, data),
193            _ => return Err(ParseError::InvalidCanFrame),
194        };
195
196        // Parse the CAN ID
197        let can_id = canid_t::from_str_radix(can_id_str, 16)
198            .ok()
199            .and_then(id_from_raw)
200            .ok_or(ParseError::InvalidCanFrame)?;
201
202        // Determine frame type (FD or classical) and skip separator(s)
203        // Remember...
204        //   CAN FD: "<canid>##<flags>[data]"
205        //   Remote: "<canid>#R[len]"
206        //   Data;   "<canid>#[data]"
207
208        let frame: CanAnyFrame = if can_data.starts_with('#') {
209            let fd_flags = can_data
210                .get(1..2)
211                .and_then(|s| u8::from_str_radix(s, 16).ok())
212                .map(FdFlags::from_bits_truncate)
213                .ok_or(ParseError::InvalidCanFrame)?;
214            Vec::from_hex(&can_data[2..])
215                .ok()
216                .and_then(|data| CanFdFrame::with_flags(can_id, &data, fd_flags))
217                .map(CanAnyFrame::Fd)
218        } else if can_data.starts_with('R') {
219            can_data = &can_data[1..];
220            let rlen = can_data.parse::<usize>().unwrap_or(0);
221            CanRemoteFrame::new_remote(can_id, rlen)
222                .map(CanFrame::Remote)
223                .map(CanAnyFrame::from)
224        } else {
225            Vec::from_hex(can_data)
226                .ok()
227                .and_then(|data| CanDataFrame::new(can_id, &data))
228                .map(CanFrame::Data)
229                .map(CanAnyFrame::from)
230        }
231        .ok_or(ParseError::InvalidCanFrame)?;
232
233        Ok(Some(CanDumpRecord {
234            t_us,
235            device,
236            frame,
237        }))
238    }
239}
240
241impl<R: BufRead> Iterator for Reader<R> {
242    type Item = Result<CanDumpRecord, ParseError>;
243
244    fn next(&mut self) -> Option<Self::Item> {
245        // lift Option:
246        match self.next_record() {
247            Ok(Some(rec)) => Some(Ok(rec)),
248            Ok(None) => None,
249            Err(e) => Some(Err(e)),
250        }
251    }
252}
253
254/// Original Record iterator
255#[derive(Debug)]
256pub struct CanDumpRecords<'a, R: 'a> {
257    src: &'a mut Reader<R>,
258}
259
260impl<R: io::Read> Iterator for CanDumpRecords<'_, BufReader<R>> {
261    type Item = Result<(u64, CanAnyFrame), ParseError>;
262
263    fn next(&mut self) -> Option<Self::Item> {
264        // lift Option:
265        match self.src.next_record() {
266            Ok(Some(CanDumpRecord { t_us, frame, .. })) => Some(Ok((t_us, frame))),
267            Ok(None) => None,
268            Err(e) => Some(Err(e)),
269        }
270    }
271}
272
273/////////////////////////////////////////////////////////////////////////////
274
275#[cfg(test)]
276mod test {
277    use super::*;
278    use crate::{CanAnyFrame, Frame};
279    use embedded_can::Frame as EmbeddedFrame;
280
281    #[test]
282    fn test_simple_example() {
283        let input: &[u8] = b"(1469439874.299591) can1 080#\n\
284                             (1469439874.299654) can1 701#7F";
285
286        let mut reader = Reader::from_reader(input);
287
288        let rec1 = reader.next_record().unwrap().unwrap();
289
290        assert_eq!(rec1.t_us, 1469439874299591);
291        assert_eq!(rec1.device, "can1");
292
293        if let CanAnyFrame::Normal(frame) = rec1.frame {
294            assert_eq!(frame.raw_id(), 0x080);
295            assert!(!frame.is_remote_frame());
296            assert!(!frame.is_error_frame());
297            assert!(!frame.is_extended());
298            assert_eq!(frame.data(), &[]);
299        } else {
300            panic!("Expected Normal frame, got FD");
301        }
302
303        let rec2 = reader.next_record().unwrap().unwrap();
304        assert_eq!(rec2.t_us, 1469439874299654);
305        assert_eq!(rec2.device, "can1");
306
307        if let CanAnyFrame::Normal(frame) = rec2.frame {
308            assert_eq!(frame.raw_id(), 0x701);
309            assert!(!frame.is_remote_frame());
310            assert!(!frame.is_error_frame());
311            assert!(!frame.is_extended());
312            assert_eq!(frame.data(), &[0x7F]);
313        } else {
314            panic!("Expected Normal frame, got FD");
315        }
316
317        assert!(reader.next_record().unwrap().is_none());
318    }
319
320    #[test]
321    fn test_extended_example() {
322        let input: &[u8] = b"(1469439874.299591) can1 080080#\n\
323                             (1469439874.299654) can1 053701#7F";
324
325        let mut reader = Reader::from_reader(input);
326
327        let rec1 = reader.next_record().unwrap().unwrap();
328
329        assert_eq!(rec1.t_us, 1469439874299591);
330        assert_eq!(rec1.device, "can1");
331
332        if let CanAnyFrame::Normal(frame) = rec1.frame {
333            assert_eq!(frame.raw_id(), 0x080080);
334            assert_eq!(frame.is_remote_frame(), false);
335            assert_eq!(frame.is_error_frame(), false);
336            assert_eq!(frame.is_extended(), true);
337            assert_eq!(frame.data(), &[]);
338        } else {
339            panic!("Expected Normal frame, got FD");
340        }
341
342        let rec2 = reader.next_record().unwrap().unwrap();
343        assert_eq!(rec2.t_us, 1469439874299654);
344        assert_eq!(rec2.device, "can1");
345
346        if let CanAnyFrame::Normal(frame) = rec2.frame {
347            assert_eq!(frame.raw_id(), 0x053701);
348            assert_eq!(frame.is_remote_frame(), false);
349            assert_eq!(frame.is_error_frame(), false);
350            assert_eq!(frame.is_extended(), true);
351            assert_eq!(frame.data(), &[0x7F]);
352        } else {
353            panic!("Expected Normal frame, got FD");
354        }
355
356        assert!(reader.next_record().unwrap().is_none());
357    }
358
359    #[test]
360    fn test_remote() {
361        let input: &[u8] = b"(1469439874.299591) can0 080080#R\n\
362                             (1469439874.299654) can0 053701#R4";
363
364        let mut reader = Reader::from_reader(input);
365
366        let rec1 = reader.next_record().unwrap().unwrap();
367
368        assert_eq!(rec1.t_us, 1469439874299591);
369        assert_eq!(rec1.device, "can0");
370
371        if let CanAnyFrame::Remote(frame) = rec1.frame {
372            assert_eq!(frame.raw_id(), 0x080080);
373            assert!(!frame.is_data_frame());
374            assert!(frame.is_remote_frame());
375            assert!(!frame.is_error_frame());
376            assert!(frame.is_extended());
377            assert_eq!(frame.len(), 0);
378            assert_eq!(frame.data(), &[]);
379        } else {
380            panic!("Expected Remote frame");
381        }
382
383        let rec2 = reader.next_record().unwrap().unwrap();
384        assert_eq!(rec2.t_us, 1469439874299654);
385        assert_eq!(rec2.device, "can0");
386
387        if let CanAnyFrame::Remote(frame) = rec2.frame {
388            assert_eq!(frame.raw_id(), 0x053701);
389            assert!(!frame.is_data_frame());
390            assert!(frame.is_remote_frame());
391            assert!(!frame.is_error_frame());
392            assert!(frame.is_extended());
393            assert_eq!(frame.len(), 4);
394        } else {
395            panic!("Expected Remote frame");
396        }
397
398        assert!(reader.next_record().unwrap().is_none());
399    }
400
401    // Issue #74
402    #[test]
403    fn test_extended_id_fd() {
404        let input: &[u8] = b"(1234.567890) can0 12345678##500112233445566778899AABB";
405
406        let mut reader = Reader::from_reader(input);
407        let rec = reader.next_record().unwrap().unwrap();
408        let frame = CanFdFrame::try_from(rec.frame).unwrap();
409
410        assert!(frame.is_extended());
411        assert_eq!(0x12345678, frame.raw_id());
412        assert_eq!(5, frame.flags().bits());
413        assert_eq!(frame.dlc(), 0x09);
414        assert_eq!(frame.len(), 12);
415        assert_eq!(frame.data().len(), 12);
416        assert_eq!(
417            frame.data(),
418            &[0x0, 0x011, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB]
419        );
420    }
421
422    #[test]
423    fn test_fd() {
424        let input: &[u8] = b"(1469439874.299591) can1 080##0\n\
425                             (1469439874.299654) can1 701##17F";
426
427        let mut reader = Reader::from_reader(input);
428
429        let rec1 = reader.next_record().unwrap().unwrap();
430
431        assert_eq!(rec1.t_us, 1469439874299591);
432        assert_eq!(rec1.device, "can1");
433        if let CanAnyFrame::Fd(frame) = rec1.frame {
434            assert_eq!(frame.raw_id(), 0x080);
435            assert!(!frame.is_remote_frame());
436            assert!(!frame.is_error_frame());
437            assert!(!frame.is_extended());
438            assert!(!frame.is_brs());
439            assert!(!frame.is_esi());
440            assert_eq!(0x04, frame.flags().bits());
441            assert_eq!(frame.dlc(), 0);
442            assert_eq!(frame.len(), 0);
443            assert_eq!(frame.data().len(), 0);
444            assert_eq!(frame.data(), &[]);
445        } else {
446            panic!("Expected FD frame, got Normal");
447        }
448
449        let rec2 = reader.next_record().unwrap().unwrap();
450        assert_eq!(rec2.t_us, 1469439874299654);
451        assert_eq!(rec2.device, "can1");
452        if let CanAnyFrame::Fd(frame) = rec2.frame {
453            assert_eq!(frame.raw_id(), 0x701);
454            assert!(!frame.is_remote_frame());
455            assert!(!frame.is_error_frame());
456            assert!(!frame.is_extended());
457            assert!(frame.is_brs());
458            assert!(!frame.is_esi());
459            assert_eq!(0x05, frame.flags().bits());
460            assert_eq!(frame.dlc(), 1);
461            assert_eq!(frame.len(), 1);
462            assert_eq!(frame.data().len(), 1);
463            assert_eq!(frame.data(), &[0x7F]);
464        } else {
465            panic!("Expected FD frame, got Normal");
466        }
467
468        assert!(reader.next_record().unwrap().is_none());
469    }
470}