@@ -11,12 +11,12 @@ use crate::wire::pretty_print::{PrettyIndent, PrettyPrint};
11
11
/// device.
12
12
pub struct Tracer < D : Device > {
13
13
inner : D ,
14
- writer : fn ( Instant , Packet ) ,
14
+ writer : fn ( Instant , TracerPacket ) ,
15
15
}
16
16
17
17
impl < D : Device > Tracer < D > {
18
18
/// Create a tracer device.
19
- pub fn new ( inner : D , writer : fn ( timestamp : Instant , packet : Packet ) ) -> Tracer < D > {
19
+ pub fn new ( inner : D , writer : fn ( timestamp : Instant , packet : TracerPacket ) ) -> Tracer < D > {
20
20
Tracer { inner, writer }
21
21
}
22
22
@@ -88,7 +88,7 @@ impl<D: Device> Device for Tracer<D> {
88
88
#[ doc( hidden) ]
89
89
pub struct RxToken < Rx : phy:: RxToken > {
90
90
token : Rx ,
91
- writer : fn ( Instant , Packet ) ,
91
+ writer : fn ( Instant , TracerPacket ) ,
92
92
medium : Medium ,
93
93
timestamp : Instant ,
94
94
}
@@ -101,10 +101,10 @@ impl<Rx: phy::RxToken> phy::RxToken for RxToken<Rx> {
101
101
self . token . consume ( |buffer| {
102
102
( self . writer ) (
103
103
self . timestamp ,
104
- Packet {
104
+ TracerPacket {
105
105
buffer,
106
106
medium : self . medium ,
107
- prefix : "<- " ,
107
+ direction : TracerDirection :: RX ,
108
108
} ,
109
109
) ;
110
110
f ( buffer)
@@ -119,7 +119,7 @@ impl<Rx: phy::RxToken> phy::RxToken for RxToken<Rx> {
119
119
#[ doc( hidden) ]
120
120
pub struct TxToken < Tx : phy:: TxToken > {
121
121
token : Tx ,
122
- writer : fn ( Instant , Packet ) ,
122
+ writer : fn ( Instant , TracerPacket ) ,
123
123
medium : Medium ,
124
124
timestamp : Instant ,
125
125
}
@@ -133,10 +133,10 @@ impl<Tx: phy::TxToken> phy::TxToken for TxToken<Tx> {
133
133
let result = f ( buffer) ;
134
134
( self . writer ) (
135
135
self . timestamp ,
136
- Packet {
136
+ TracerPacket {
137
137
buffer,
138
138
medium : self . medium ,
139
- prefix : "-> " ,
139
+ direction : TracerDirection :: TX ,
140
140
} ,
141
141
) ;
142
142
result
@@ -148,15 +148,34 @@ impl<Tx: phy::TxToken> phy::TxToken for TxToken<Tx> {
148
148
}
149
149
}
150
150
151
- pub struct Packet < ' a > {
152
- buffer : & ' a [ u8 ] ,
153
- medium : Medium ,
154
- prefix : & ' static str ,
151
+ /// Packet which is being traced by [Tracer](struct.Tracer.html) device.
152
+ #[ derive( Debug , Clone , Copy ) ]
153
+ pub struct TracerPacket < ' a > {
154
+ /// Packet buffer
155
+ pub buffer : & ' a [ u8 ] ,
156
+ /// Packet medium
157
+ pub medium : Medium ,
158
+ /// Direction in which packet is being traced
159
+ pub direction : TracerDirection ,
160
+ }
161
+
162
+ /// Direction on which packet is being traced
163
+ #[ derive( Debug , Clone , Copy , PartialEq ) ]
164
+ pub enum TracerDirection {
165
+ /// Packet is received by Smoltcp interface
166
+ RX ,
167
+ /// Packet is transmitted by Smoltcp interface
168
+ TX ,
155
169
}
156
170
157
- impl < ' a > fmt:: Display for Packet < ' a > {
171
+ impl < ' a > fmt:: Display for TracerPacket < ' a > {
158
172
fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
159
- let mut indent = PrettyIndent :: new ( self . prefix ) ;
173
+ let prefix = match self . direction {
174
+ TracerDirection :: RX => "<- " ,
175
+ TracerDirection :: TX => "-> " ,
176
+ } ;
177
+
178
+ let mut indent = PrettyIndent :: new ( prefix) ;
160
179
match self . medium {
161
180
#[ cfg( feature = "medium-ethernet" ) ]
162
181
Medium :: Ethernet => crate :: wire:: EthernetFrame :: < & ' static [ u8 ] > :: pretty_print (
@@ -189,3 +208,148 @@ impl<'a> fmt::Display for Packet<'a> {
189
208
}
190
209
}
191
210
}
211
+
212
+ #[ cfg( test) ]
213
+ mod tests {
214
+ use core:: cell:: RefCell ;
215
+ use std:: collections:: VecDeque ;
216
+
217
+ use super :: * ;
218
+
219
+ use crate :: phy:: ChecksumCapabilities ;
220
+ use crate :: {
221
+ phy:: { Device , Loopback , RxToken , TxToken } ,
222
+ time:: Instant ,
223
+ } ;
224
+
225
+ #[ cfg( any(
226
+ feature = "medium-ethernet" ,
227
+ feature = "medium-ip" ,
228
+ feature = "medium-ieee802154"
229
+ ) ) ]
230
+ #[ test]
231
+ fn test_tracer ( ) {
232
+ type TracerEvent = ( Instant , Vec < u8 > , Medium , TracerDirection ) ;
233
+ thread_local ! {
234
+ static TRACE_EVENTS : RefCell <VecDeque <TracerEvent >> = const { RefCell :: new( VecDeque :: new( ) ) } ;
235
+ }
236
+ TRACE_EVENTS . replace ( VecDeque :: new ( ) ) ;
237
+
238
+ let medium = Medium :: default ( ) ;
239
+
240
+ let loopback_device = Loopback :: new ( medium) ;
241
+ let mut tracer_device = Tracer :: new ( loopback_device, |instant, packet| {
242
+ TRACE_EVENTS . with_borrow_mut ( |events| {
243
+ events. push_back ( (
244
+ instant,
245
+ packet. buffer . to_owned ( ) ,
246
+ packet. medium ,
247
+ packet. direction ,
248
+ ) )
249
+ } ) ;
250
+ } ) ;
251
+
252
+ let expected_payload = [ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 ] ;
253
+
254
+ let tx_instant = Instant :: from_secs ( 1 ) ;
255
+ let tx_token = tracer_device. transmit ( tx_instant) . unwrap ( ) ;
256
+
257
+ tx_token. consume ( expected_payload. len ( ) , |buf| {
258
+ buf. copy_from_slice ( & expected_payload)
259
+ } ) ;
260
+ let last_event = TRACE_EVENTS . with_borrow_mut ( |events| events. pop_front ( ) ) ;
261
+ assert_eq ! (
262
+ last_event,
263
+ Some ( (
264
+ tx_instant,
265
+ expected_payload. into( ) ,
266
+ medium,
267
+ TracerDirection :: TX
268
+ ) )
269
+ ) ;
270
+ let last_event = TRACE_EVENTS . with_borrow_mut ( |events| events. pop_front ( ) ) ;
271
+ assert_eq ! ( last_event, None ) ;
272
+
273
+ let rx_instant = Instant :: from_secs ( 2 ) ;
274
+ let ( rx_token, _) = tracer_device. receive ( rx_instant) . unwrap ( ) ;
275
+ let mut rx_pkt = [ 0 ; 8 ] ;
276
+ rx_token. consume ( |buf| rx_pkt. copy_from_slice ( buf) ) ;
277
+
278
+ assert_eq ! ( rx_pkt, expected_payload) ;
279
+
280
+ let last_event = TRACE_EVENTS . with_borrow_mut ( |events| events. pop_front ( ) ) ;
281
+ assert_eq ! (
282
+ last_event,
283
+ Some ( (
284
+ rx_instant,
285
+ expected_payload. into( ) ,
286
+ medium,
287
+ TracerDirection :: RX
288
+ ) )
289
+ ) ;
290
+ let last_event = TRACE_EVENTS . with_borrow_mut ( |events| events. pop_front ( ) ) ;
291
+ assert_eq ! ( last_event, None ) ;
292
+ }
293
+
294
+ #[ cfg( feature = "medium-ethernet" ) ]
295
+ #[ test]
296
+ fn test_tracer_packet_display_ether ( ) {
297
+ use crate :: wire:: { EthernetAddress , EthernetProtocol , EthernetRepr } ;
298
+
299
+ let repr = EthernetRepr {
300
+ src_addr : EthernetAddress ( [ 0 , 1 , 2 , 3 , 4 , 5 ] ) ,
301
+ dst_addr : EthernetAddress ( [ 5 , 4 , 3 , 2 , 1 , 0 ] ) ,
302
+ ethertype : EthernetProtocol :: Unknown ( 0 ) ,
303
+ } ;
304
+ let mut buffer = vec ! [ 0_u8 ; repr. buffer_len( ) ] ;
305
+ {
306
+ use crate :: wire:: EthernetFrame ;
307
+
308
+ let mut frame = EthernetFrame :: new_unchecked ( & mut buffer) ;
309
+ repr. emit ( & mut frame) ;
310
+ }
311
+
312
+ let pkt = TracerPacket {
313
+ buffer : & buffer,
314
+ medium : Medium :: Ethernet ,
315
+ direction : TracerDirection :: RX ,
316
+ } ;
317
+
318
+ let pkt_pretty = pkt. to_string ( ) ;
319
+ assert_eq ! (
320
+ pkt_pretty,
321
+ "<- EthernetII src=00-01-02-03-04-05 dst=05-04-03-02-01-00 type=0x0000"
322
+ ) ;
323
+ }
324
+
325
+ #[ cfg( all( feature = "medium-ip" , feature = "proto-ipv4" ) ) ]
326
+ #[ test]
327
+ fn test_tracer_packet_display_ip ( ) {
328
+ use crate :: wire:: { IpProtocol , Ipv4Address , Ipv4Repr } ;
329
+
330
+ let repr = Ipv4Repr {
331
+ src_addr : Ipv4Address :: new ( 10 , 0 , 0 , 1 ) ,
332
+ dst_addr : Ipv4Address :: new ( 10 , 0 , 0 , 2 ) ,
333
+ next_header : IpProtocol :: Unknown ( 255 ) ,
334
+ payload_len : 0 ,
335
+ hop_limit : 64 ,
336
+ } ;
337
+
338
+ let mut buffer = vec ! [ 0_u8 ; repr. buffer_len( ) ] ;
339
+ {
340
+ use crate :: wire:: Ipv4Packet ;
341
+
342
+ let mut packet = Ipv4Packet :: new_unchecked ( & mut buffer) ;
343
+ repr. emit ( & mut packet, & ChecksumCapabilities :: default ( ) ) ;
344
+ }
345
+
346
+ let pkt = TracerPacket {
347
+ buffer : & buffer,
348
+ medium : Medium :: Ip ,
349
+ direction : TracerDirection :: TX ,
350
+ } ;
351
+
352
+ let pkt_pretty = pkt. to_string ( ) ;
353
+ assert_eq ! ( pkt_pretty, "-> IPv4 src=10.0.0.1 dst=10.0.0.2 proto=0xff" ) ;
354
+ }
355
+ }
0 commit comments