@@ -6,24 +6,51 @@ extern crate clap;
6
6
extern crate env_logger;
7
7
#[ macro_use]
8
8
extern crate error_chain;
9
+ extern crate heapless;
9
10
extern crate libc;
10
11
#[ macro_use]
11
12
extern crate log;
12
13
extern crate ref_slice;
13
14
14
15
15
16
use clap:: { Arg , App , ArgMatches } ;
17
+ use heapless:: Vec as HVec ;
16
18
use log:: { LogRecord , LogLevelFilter } ;
17
- use ref_slice:: ref_slice_mut;
18
19
use std:: fs:: File ;
19
20
use std:: io:: { Read , Write } ;
20
21
use std:: time:: Duration ;
21
22
use std:: { env, io, process, thread} ;
22
23
23
- use errors:: * ;
24
+ use errors:: { Error , ErrorKind , Result , ResultExt } ;
24
25
25
26
mod errors {
26
- error_chain ! ( ) ;
27
+ error_chain ! {
28
+ foreign_links {
29
+ Io ( :: std:: io:: Error ) ;
30
+ }
31
+
32
+ errors {
33
+ UnknownHeader ( b: u8 ) {
34
+ description( "unknown header byte" ) ,
35
+ display( "unknown header byte: {:x}" , b) ,
36
+ }
37
+ }
38
+ }
39
+ }
40
+
41
+ pub const MAX_PAYLOAD_SIZE : usize = 4 ;
42
+
43
+ // TODO: Probably add a .kind field and Kind enum when we need to handle more
44
+ // kinds of packets.
45
+ struct Packet {
46
+ // The header byte received for this packet.
47
+ pub header : u8 ,
48
+
49
+ /// Data in this packet.
50
+ pub payload : HVec < u8 , [ u8 ; MAX_PAYLOAD_SIZE ] > ,
51
+
52
+ /// Stimuls port this packet was sent from.
53
+ pub port : u8 ,
27
54
}
28
55
29
56
fn main ( ) {
@@ -96,7 +123,7 @@ fn run() -> Result<()> {
96
123
} ) )
97
124
. get_matches ( ) ;
98
125
99
- let stim_port = matches. value_of ( "port" )
126
+ let port = matches. value_of ( "port" )
100
127
. unwrap ( ) // We supplied a default value
101
128
. parse :: < u8 > ( )
102
129
. expect ( "Arg validator should ensure this parses" ) ;
@@ -108,60 +135,40 @@ fn run() -> Result<()> {
108
135
let stdout = io:: stdout ( ) ;
109
136
let mut stdout = stdout. lock ( ) ;
110
137
loop {
111
- let mut header = 0 ;
112
-
113
- if let Err ( e) = ( || {
114
- try!( stream. read_exact ( ref_slice_mut ( & mut header) ) ) ;
115
- let port = header >> 3 ;
116
-
117
- // Ignore packets not from the chosen stimulus port
118
- if port != stim_port {
119
- return Ok ( ( ) ) ;
120
- }
121
-
122
- match header & 0b111 {
123
- 0b01 => {
124
- let mut payload = 0 ;
125
- try!( stream. read_exact ( ref_slice_mut ( & mut payload) ) ) ;
126
- stdout. write_all ( & [ payload] )
127
- }
128
- 0b10 => {
129
- let mut payload = [ 0 ; 2 ] ;
130
- try!( stream. read_exact ( & mut payload) ) ;
131
- stdout. write_all ( & payload)
132
- }
133
- 0b11 => {
134
- let mut payload = [ 0 ; 4 ] ;
135
- try!( stream. read_exact ( & mut payload) ) ;
136
- stdout. write_all ( & payload)
137
- }
138
- _ => {
139
- // We don't know this header type, skip.
140
- debug ! ( "Unhandled header type = {:x}" , header) ;
141
- Ok ( ( ) )
138
+ let p = read_packet ( & mut stream) ;
139
+ match p {
140
+ Ok ( p) => {
141
+ if p. port == port {
142
+ stdout. write_all ( & p. payload ) ?;
142
143
}
143
144
}
144
- } ) ( ) {
145
- // Error caught in main loop as `e`.
146
- if e. kind ( ) == io:: ErrorKind :: UnexpectedEof {
145
+ Err ( e @ Error ( ErrorKind :: UnknownHeader ( _) , _) ) => {
146
+ // We don't know this header type; warn and continue.
147
+ debug ! ( "{}" , e) ;
148
+ } ,
149
+ Err ( Error ( ErrorKind :: Io ( ref e) , _) )
150
+ if e. kind ( ) == io:: ErrorKind :: UnexpectedEof => {
147
151
if follow {
148
- // TODO: There's a bug here where we can lose data.
149
- // UnexpectedEof is returned when read_exact() encounters EOF
150
- // before it fills its buffer, but in that case it may have
151
- // already read _some_ data, which we discard here.
152
+ // TODO: There's a bug here where we can lose
153
+ // data. UnexpectedEof is returned when
154
+ // read_exact() encounters EOF before it fills its
155
+ // buffer, but in that case it may have already
156
+ // read _some_ data, which we discard here.
152
157
//
153
- // We could buffer input until we can read a full packet,
154
- // or turn parsing into a state machine.
158
+ // Instead we could buffer input until we can read
159
+ // a full packet, or turn parsing into a state
160
+ // machine.
155
161
thread:: sleep ( Duration :: from_millis ( 100 ) ) ;
156
162
} else {
157
163
// !follow and EOF. Exit.
158
164
return Ok ( ( ) )
159
165
}
160
- } else {
161
- error ! ( "{}" , e) ;
162
- }
166
+ } ,
167
+ Err ( e) => return Err ( e) ,
163
168
}
164
- }
169
+ } // end of read loop
170
+
171
+ // Unreachable.
165
172
}
166
173
167
174
fn open_read < ' a > ( matches : & ArgMatches ) -> Result < impl io:: Read + ' a > {
@@ -177,3 +184,39 @@ fn open_read<'a>(matches: &ArgMatches) -> Result<impl io::Read + 'a> {
177
184
None => Box :: new ( io:: stdin ( ) ) as Box < io:: Read + ' static > ,
178
185
} )
179
186
}
187
+
188
+ fn read_packet ( input : & mut Read ) -> Result < Packet > {
189
+ let mut header = [ 0 ; 1 ] ;
190
+ input. read_exact ( & mut header) ?;
191
+ let header = header[ 0 ] ;
192
+ let mut packet = Packet {
193
+ header : header,
194
+ payload : HVec :: new ( ) ,
195
+ port : header >> 3 ,
196
+ } ;
197
+ match header & 0b111 {
198
+ 0b01 |0b10 |0b11 => {
199
+ // Data packet.
200
+ let payload_size =
201
+ match header & 0b11 {
202
+ 0b01 => 1 ,
203
+ 0b10 => 2 ,
204
+ 0b11 => 4 ,
205
+ _ => return Err ( Error :: from (
206
+ ErrorKind :: UnknownHeader ( header) ) ) ,
207
+ } ;
208
+ // TODO: payload.resize_default(), would be nice.
209
+ for _ in 0 ..payload_size {
210
+ packet. payload . push ( 0 )
211
+ . expect ( "payload_size <= packet.payload.capacity" ) ;
212
+ }
213
+ input. read_exact ( & mut * packet. payload ) ?;
214
+ Ok ( packet)
215
+ } ,
216
+ _ => {
217
+ return Err ( Error :: from ( ErrorKind :: UnknownHeader ( header) ) ) ;
218
+ }
219
+ }
220
+ }
221
+
222
+ // TODO: Add parse tests.
0 commit comments