@@ -29,15 +29,15 @@ use crate::{
29
29
} ;
30
30
use embedded_can:: StandardId ;
31
31
use hex:: FromHex ;
32
+ use lazy_static:: lazy_static;
32
33
use libc:: canid_t;
33
- use std:: { fs, io, path, str} ;
34
-
35
- // cannot be generic, because from_str_radix is not part of any Trait
36
- fn parse_raw ( bytes : & [ u8 ] , radix : u32 ) ->Option < u64 > {
37
- str:: from_utf8 ( bytes)
38
- . ok ( )
39
- . and_then ( |s| u64:: from_str_radix ( s, radix) . ok ( ) )
40
- }
34
+ use regex:: Regex ;
35
+ use std:: {
36
+ fs:: File ,
37
+ io:: { self , BufRead , BufReader } ,
38
+ path:: Path ,
39
+ str,
40
+ } ;
41
41
42
42
#[ derive( Debug ) ]
43
43
/// A CAN log reader.
@@ -48,21 +48,18 @@ pub struct Reader<R> {
48
48
49
49
impl < R : io:: Read > Reader < R > {
50
50
/// Creates an I/O buffered reader from a CAN log reader.
51
- pub fn from_reader ( rdr : R ) ->Reader < io :: BufReader < R > > {
51
+ pub fn from_reader ( rdr : R ) ->Reader < BufReader < R > > {
52
52
Reader {
53
- rdr : io :: BufReader :: new ( rdr) ,
53
+ rdr : BufReader :: new ( rdr) ,
54
54
line_buf : Vec :: new ( ) ,
55
55
}
56
56
}
57
57
}
58
58
59
- impl Reader < fs :: File > {
59
+ impl Reader < File > {
60
60
/// Creates an I/O buffered reader from a file.
61
- pub fn from_file < P > ( path : P ) -> io:: Result < Reader < io:: BufReader < fs:: File > > >
62
- where
63
- P : AsRef < path:: Path > ,
64
- {
65
- Ok ( Reader :: from_reader ( fs:: File :: open ( path) ?) )
61
+ pub fn from_file < P : AsRef < Path > > ( path : P ) -> io:: Result < Reader < BufReader < File > > > {
62
+ Ok ( Reader :: from_reader ( File :: open ( path) ?) )
66
63
}
67
64
}
68
65
@@ -112,7 +109,14 @@ impl From<ConstructionError> for ParseError {
112
109
}
113
110
}
114
111
115
- impl < R : io:: BufRead > Reader < R > {
112
+ lazy_static ! {
113
+ // Matches a candump line
114
+ static refRE_DUMP : Regex =Regex :: new(
115
+ r"\s*\((?P<t_num>[0-9]+)\.(?P<t_mant>[0-9]*)\)\s+(?P<iface>\w+)\s+(?P<can_id>[0-9A-Fa-f]+)(((?P<fd_sep>\#\#)(?P<fd_flags>[0-9A-Fa-f]))|(?P<sep>\#))(?P<data>[0-9A-Fa-f\s]*)"
116
+ ) . unwrap( ) ;
117
+ }
118
+
119
+ impl < R : BufRead > Reader < R > {
116
120
/// Returns an iterator over all records
117
121
pub fn records ( & mut self ) ->CanDumpRecords < R > {
118
122
CanDumpRecords { src : self }
@@ -123,83 +127,65 @@ impl<R: io::BufRead> Reader<R> {
123
127
self . line_buf . clear ( ) ;
124
128
let bytes_read =self . rdr . read_until ( b'\n' , & mut self . line_buf ) ?;
125
129
126
- // reached EOF
127
130
if bytes_read ==0 {
128
131
return Ok ( None ) ;
129
132
}
130
133
131
- let mut field_iter =self . line_buf . split ( |& c| c ==b' ' ) ;
134
+ let line = str:: from_utf8 ( & self . line_buf [ ..bytes_read] )
135
+ . map_err ( |_|ParseError :: InvalidCanFrame ) ?;
132
136
133
- // parse time field
134
- let f = field_iter. next ( ) . ok_or ( ParseError :: UnexpectedEndOfLine ) ?;
137
+ let caps =RE_DUMP
138
+ . captures ( line)
139
+ . ok_or ( ParseError :: UnexpectedEndOfLine ) ?;
135
140
136
- if f. len ( ) <3 || f[ 0 ] !=b'(' || f[ f. len ( ) -1 ] !=b')' {
137
- return Err ( ParseError :: InvalidTimestamp ) ;
138
- }
139
-
140
- let inner =& f[ 1 ..f. len ( ) -1 ] ;
141
-
142
- // split at dot, read both parts
143
- let dot = inner
144
- . iter ( )
145
- . position ( |& c| c ==b'.' )
141
+ let t_num: u64 = caps
142
+ . name ( "t_num" )
143
+ . and_then ( |m| m. as_str ( ) . parse :: < u64 > ( ) . ok ( ) )
146
144
. ok_or ( ParseError :: InvalidTimestamp ) ?;
147
145
148
- let ( num, mant) = inner. split_at ( dot) ;
149
-
150
- // parse number and multiply
151
- let n_num: u64 =parse_raw ( num, 10 ) . ok_or ( ParseError :: InvalidTimestamp ) ?;
152
- let n_mant: u64 =parse_raw ( & mant[ 1 ..] , 10 ) . ok_or ( ParseError :: InvalidTimestamp ) ?;
153
- let t_us = n_num. saturating_mul ( 1_000_000 ) . saturating_add ( n_mant) ;
146
+ let t_mant: u64 = caps
147
+ . name ( "t_mant" )
148
+ . and_then ( |m| m. as_str ( ) . parse :: < u64 > ( ) . ok ( ) )
149
+ . ok_or ( ParseError :: InvalidTimestamp ) ?;
154
150
155
- let f =field_iter . next ( ) . ok_or ( ParseError :: UnexpectedEndOfLine ) ? ;
151
+ let t_us =t_num . saturating_mul ( 1_000_000 ) . saturating_add ( t_mant ) ;
156
152
157
- // device name
158
- let device = str:: from_utf8 ( f) . map_err ( |_|ParseError :: InvalidDeviceName ) ?;
153
+ let device = caps
154
+ . name ( "iface" )
155
+ . map ( |m| m. as_str ( ) )
156
+ //.map(String::from)
157
+ . ok_or ( ParseError :: InvalidDeviceName ) ?;
159
158
160
- // parse packet
161
- let can_raw = field_iter. next ( ) . ok_or ( ParseError :: UnexpectedEndOfLine ) ?;
159
+ let is_fd_frame = caps. name ( "fd_sep" ) . is_some ( ) ;
162
160
163
- let sep_idx = can_raw
164
- . iter ( )
165
- . position ( | & c| c == b'#' )
161
+ let mut can_id : canid_t = caps
162
+ . name ( "can_id" )
163
+ . and_then ( |m| canid_t :: from_str_radix ( m . as_str ( ) , 16 ) . ok ( ) )
166
164
. ok_or ( ParseError :: InvalidCanFrame ) ?;
167
- let ( can_id_str, mut can_data) = can_raw. split_at ( sep_idx) ;
168
-
169
- // determine frame type (FD or classical) and skip separator(s)
170
- let mut fd_flags =FdFlags :: empty ( ) ;
171
- let is_fd_frame =if let Some ( & b'#' ) = can_data. get ( 1 ) {
172
- fd_flags =FdFlags :: from_bits_truncate ( can_data[ 2 ] ) ;
173
- can_data =& can_data[ 3 ..] ;
174
- true
175
- } else {
176
- can_data =& can_data[ 1 ..] ;
177
- false
178
- } ;
179
165
180
- // cut of linefeed
181
- if let Some ( & b'\n' ) = can_data. last ( ) {
182
- can_data =& can_data[ ..can_data. len ( ) -1 ] ;
183
- } ;
184
- // cut off \r
185
- if let Some ( & b'\r' ) = can_data. last ( ) {
186
- can_data =& can_data[ ..can_data. len ( ) -1 ] ;
187
- } ;
166
+ let can_data = caps
167
+ . name ( "data" )
168
+ . map ( |m| m. as_str ( ) . trim ( ) )
169
+ . ok_or ( ParseError :: InvalidCanFrame ) ?;
188
170
189
- let mut can_id =( parse_raw ( can_id_str, 16 ) . ok_or ( ParseError :: InvalidCanFrame ) ?) as canid_t ;
190
171
let mut id_flags =IdFlags :: empty ( ) ;
191
- id_flags. set ( IdFlags :: RTR , b "R" == can_data) ;
172
+ id_flags. set ( IdFlags :: RTR , "R" == can_data) ;
192
173
id_flags. set ( IdFlags :: EFF , can_id >=StandardId :: MAX . as_raw ( ) as canid_t ) ;
193
174
// TODO: How are error frames saved?
194
175
can_id |= id_flags. bits ( ) ;
195
176
196
- let data =if id_flags. contains ( IdFlags :: RTR ) {
197
- vec ! [ ]
198
- } else {
199
- Vec :: from_hex ( can_data) . map_err ( |_|ParseError :: InvalidCanFrame ) ?
177
+ let data =match id_flags. contains ( IdFlags :: RTR ) {
178
+ true =>vec ! [ ] ,
179
+ false =>Vec :: from_hex ( can_data) . map_err ( |_|ParseError :: InvalidCanFrame ) ?,
200
180
} ;
201
181
202
182
let frame: CanAnyFrame =if is_fd_frame{
183
+ let fd_flags: FdFlags = caps
184
+ . name ( "fd_flags" )
185
+ . and_then ( |m| u8:: from_str_radix ( m. as_str ( ) , 16 ) . ok ( ) )
186
+ . map ( FdFlags :: from_bits_truncate)
187
+ . ok_or ( ParseError :: InvalidCanFrame ) ?;
188
+
203
189
CanFdFrame :: init ( can_id, & data, fd_flags) . map ( CanAnyFrame :: Fd )
204
190
} else {
205
191
CanDataFrame :: init ( can_id, & data)
@@ -215,7 +201,7 @@ impl<R: io::BufRead> Reader<R> {
215
201
}
216
202
}
217
203
218
- impl < R : io:: Read > Iterator for CanDumpRecords < ' _ , io :: BufReader < R > > {
204
+ impl < R : io:: Read > Iterator for CanDumpRecords < ' _ , BufReader < R > > {
219
205
type Item =Result < ( u64 , CanAnyFrame ) , ParseError > ;
220
206
221
207
fn next ( & mut self ) ->Option < Self :: Item > {