@@ -11,12 +11,12 @@ use crate::wire::pretty_print::{PrettyIndent, PrettyPrint};
1111/// device.
1212pub struct Tracer < D : Device > {
1313 inner : D ,
14- writer : fn ( Instant , Packet ) ,
14+ writer : fn ( Instant , TracerPacket ) ,
1515}
1616
1717impl < D : Device > Tracer < D > {
1818 /// 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 > {
2020 Tracer { inner, writer }
2121 }
2222
@@ -88,7 +88,7 @@ impl<D: Device> Device for Tracer<D> {
8888#[ doc( hidden) ]
8989pub struct RxToken < Rx : phy:: RxToken > {
9090 token : Rx ,
91- writer : fn ( Instant , Packet ) ,
91+ writer : fn ( Instant , TracerPacket ) ,
9292 medium : Medium ,
9393 timestamp : Instant ,
9494}
@@ -101,10 +101,10 @@ impl<Rx: phy::RxToken> phy::RxToken for RxToken<Rx> {
101101 self . token . consume ( |buffer| {
102102 ( self . writer ) (
103103 self . timestamp ,
104- Packet {
104+ TracerPacket {
105105 buffer,
106106 medium : self . medium ,
107- prefix : "<- " ,
107+ direction : TracerDirection :: RX ,
108108 } ,
109109 ) ;
110110 f ( buffer)
@@ -119,7 +119,7 @@ impl<Rx: phy::RxToken> phy::RxToken for RxToken<Rx> {
119119#[ doc( hidden) ]
120120pub struct TxToken < Tx : phy:: TxToken > {
121121 token : Tx ,
122- writer : fn ( Instant , Packet ) ,
122+ writer : fn ( Instant , TracerPacket ) ,
123123 medium : Medium ,
124124 timestamp : Instant ,
125125}
@@ -133,10 +133,10 @@ impl<Tx: phy::TxToken> phy::TxToken for TxToken<Tx> {
133133 let result = f ( buffer) ;
134134 ( self . writer ) (
135135 self . timestamp ,
136- Packet {
136+ TracerPacket {
137137 buffer,
138138 medium : self . medium ,
139- prefix : "-> " ,
139+ direction : TracerDirection :: TX ,
140140 } ,
141141 ) ;
142142 result
@@ -148,15 +148,34 @@ impl<Tx: phy::TxToken> phy::TxToken for TxToken<Tx> {
148148 }
149149}
150150
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 ,
155169}
156170
157- impl < ' a > fmt:: Display for Packet < ' a > {
171+ impl < ' a > fmt:: Display for TracerPacket < ' a > {
158172 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) ;
160179 match self . medium {
161180 #[ cfg( feature = "medium-ethernet" ) ]
162181 Medium :: Ethernet => crate :: wire:: EthernetFrame :: < & ' static [ u8 ] > :: pretty_print (
@@ -189,3 +208,148 @@ impl<'a> fmt::Display for Packet<'a> {
189208 }
190209 }
191210}
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