@@ -21,7 +21,7 @@ use std::{
2121
2222use anyhow:: { anyhow, bail} ;
2323use colored:: Colorize as _;
24- use defmt_decoder:: { DecodeError , Frame , Locations , StreamDecoder } ;
24+ use defmt_decoder:: { DecodeError , Encoding , Frame , Locations , StreamDecoder } ;
2525use probe_rs:: {
2626 flashing:: { self , Format } ,
2727 Core ,
@@ -161,7 +161,7 @@ fn start_program(sess: &mut Session, elf: &Elf) -> anyhow::Result<()> {
161161 Ok ( ( ) )
162162}
163163
164- /// Set rtt to blocking mode
164+ /// Set rtt to blocking mode for channel 0
165165fn set_rtt_to_blocking (
166166 core : & mut Core ,
167167 main_fn_address : u32 ,
@@ -201,16 +201,16 @@ fn extract_and_print_logs(
201201 let exit = Arc :: new ( AtomicBool :: new ( false ) ) ;
202202 let sig_id = signal_hook:: flag:: register ( signal:: SIGINT , exit. clone ( ) ) ?;
203203
204- let mut logging_channel = if let Some ( address) = elf. rtt_buffer_address ( ) {
205- Some ( setup_logging_channel ( address, sess. clone ( ) ) ?)
204+ let logging_channels = if let Some ( address) = elf. rtt_buffer_address ( ) {
205+ setup_logging_channels ( address, sess. clone ( ) ) ?
206206 } else {
207207 eprintln ! ( "RTT logs not available; blocking until the device halts.." ) ;
208- None
208+ vec ! [ ]
209209 } ;
210210
211- let use_defmt = logging_channel
212- . as_ref ( )
213- . map_or ( false , |channel| channel . name ( ) == Some ( "defmt" ) ) ;
211+ let use_defmt = logging_channels
212+ . get ( 0 )
213+ . map_or ( false , |c| c . name ( ) == Some ( "defmt" ) ) ;
214214
215215 if use_defmt && opts. no_flash {
216216 bail ! (
@@ -220,49 +220,40 @@ fn extract_and_print_logs(
220220 bail ! ( "\" defmt\" RTT channel is in use, but the firmware binary contains no defmt data" ) ;
221221 }
222222
223- let mut decoder_and_encoding = if use_defmt {
224- elf. defmt_table
225- . as_ref ( )
226- . map ( |table| ( table. new_stream_decoder ( ) , table. encoding ( ) ) )
223+ let mut logging_channels = logging_channels
224+ . into_iter ( )
225+ . enumerate ( )
226+ . map ( |( i, rtt) | LogChannel :: new ( i, rtt, if use_defmt { & elf. defmt_table } else { & None } ) )
227+ . collect :: < Vec < _ > > ( ) ;
228+
229+ print_separator ( ) ;
230+
231+ let mut out_file = if let Some ( path) = & opts. out_file {
232+ let file = fs:: OpenOptions :: new ( )
233+ . append ( true )
234+ . create ( true )
235+ . write ( true )
236+ . read ( false )
237+ . open ( path) ?;
238+
239+ Some ( io:: BufWriter :: new ( file) )
227240 } else {
228241 None
229242 } ;
230243
231- print_separator ( ) ;
232-
233244 let stdout = io:: stdout ( ) ;
234245 let mut stdout = stdout. lock ( ) ;
235- let mut read_buf = [ 0 ; 1024 ] ;
236246 let mut was_halted = false ;
237247 while !exit. load ( Ordering :: Relaxed ) {
238- if let Some ( logging_channel) = & mut logging_channel {
239- let num_bytes_read = match logging_channel. read ( & mut read_buf) {
240- Ok ( n) => n,
241- Err ( e) => {
242- eprintln ! ( "RTT error: {}" , e) ;
243- break ;
244- }
245- } ;
246-
247- if num_bytes_read != 0 {
248- match decoder_and_encoding. as_mut ( ) {
249- Some ( ( stream_decoder, encoding) ) => {
250- stream_decoder. received ( & read_buf[ ..num_bytes_read] ) ;
251-
252- decode_and_print_defmt_logs (
253- & mut * * stream_decoder,
254- elf. defmt_locations . as_ref ( ) ,
255- current_dir,
256- opts. shorten_paths ,
257- encoding. can_recover ( ) ,
258- ) ?;
259- }
260-
261- _ => {
262- stdout. write_all ( & read_buf[ ..num_bytes_read] ) ?;
263- stdout. flush ( ) ?;
264- }
265- }
248+ for logging_channel in logging_channels. iter_mut ( ) . rev ( ) {
249+ if !logging_channel. print_all (
250+ & mut stdout,
251+ & mut out_file,
252+ & elf. defmt_locations ,
253+ current_dir,
254+ opts,
255+ ) ? {
256+ break ;
266257 }
267258 }
268259
@@ -277,6 +268,7 @@ fn extract_and_print_logs(
277268 }
278269
279270 drop ( stdout) ;
271+ drop ( out_file) ;
280272
281273 signal_hook:: low_level:: unregister ( sig_id) ;
282274 signal_hook:: flag:: register_conditional_default ( signal:: SIGINT , exit. clone ( ) ) ?;
@@ -296,15 +288,17 @@ fn extract_and_print_logs(
296288}
297289
298290fn decode_and_print_defmt_logs (
291+ number : usize ,
299292 stream_decoder : & mut dyn StreamDecoder ,
293+ out_file : & mut Option < io:: BufWriter < fs:: File > > ,
300294 locations : Option < & Locations > ,
301295 current_dir : & Path ,
302296 shorten_paths : bool ,
303297 encoding_can_recover : bool ,
304298) -> anyhow:: Result < ( ) > {
305299 loop {
306300 match stream_decoder. decode ( ) {
307- Ok ( frame) => forward_to_logger ( & frame, locations, current_dir, shorten_paths) ,
301+ Ok ( frame) => forward_to_logger ( number , & frame, locations, current_dir, shorten_paths, out_file ) ,
308302 Err ( DecodeError :: UnexpectedEof ) => break ,
309303 Err ( DecodeError :: Malformed ) => match encoding_can_recover {
310304 // if recovery is impossible, abort
@@ -319,13 +313,34 @@ fn decode_and_print_defmt_logs(
319313}
320314
321315fn forward_to_logger (
316+ number : usize ,
322317 frame : & Frame ,
323318 locations : Option < & Locations > ,
324319 current_dir : & Path ,
325320 shorten_paths : bool ,
321+ out_file : & mut Option < io:: BufWriter < fs:: File > > ,
326322) {
327323 let ( file, line, mod_path) = location_info ( frame, locations, current_dir, shorten_paths) ;
328324 defmt_decoder:: log:: log_defmt ( frame, file. as_deref ( ) , line, mod_path. as_deref ( ) ) ;
325+
326+ if let Some ( out_file) = out_file {
327+ let timestamp = frame
328+ . display_timestamp ( )
329+ . map ( |display| display. to_string ( ) )
330+ . unwrap_or_default ( ) ;
331+
332+ writeln ! (
333+ out_file,
334+ "{}|{}|{}|{}:{}|{}|{}" ,
335+ timestamp,
336+ number,
337+ frame. level( ) . map_or( "UNKOWN" , |l| l. as_str( ) ) ,
338+ file. as_deref( ) . unwrap_or_default( ) ,
339+ line. map( |l| l. to_string( ) ) . unwrap_or_default( ) ,
340+ mod_path. unwrap_or_default( ) ,
341+ frame. display_message( )
342+ ) . unwrap ( ) ;
343+ }
329344}
330345
331346fn location_info (
@@ -355,10 +370,10 @@ fn location_info(
355370 . unwrap_or ( ( None , None , None ) )
356371}
357372
358- fn setup_logging_channel (
373+ fn setup_logging_channels (
359374 rtt_buffer_address : u32 ,
360375 sess : Arc < Mutex < Session > > ,
361- ) -> anyhow:: Result < UpChannel > {
376+ ) -> anyhow:: Result < Vec < UpChannel > > {
362377 const NUM_RETRIES : usize = 10 ; // picked at random, increase if necessary
363378
364379 let scan_region = ScanRegion :: Exact ( rtt_buffer_address) ;
@@ -367,12 +382,13 @@ fn setup_logging_channel(
367382 Ok ( mut rtt) => {
368383 log:: debug!( "Successfully attached RTT" ) ;
369384
370- let channel = rtt
371- . up_channels ( )
372- . take ( 0 )
373- . ok_or_else ( || anyhow ! ( "RTT up channel 0 not found" ) ) ?;
385+ let channels = rtt. up_channels ( ) . drain ( ) . collect :: < Vec < _ > > ( ) ;
386+
387+ if channels. len ( ) == 0 {
388+ bail ! ( "RTT up channel 0 not found" ) ;
389+ }
374390
375- return Ok ( channel ) ;
391+ return Ok ( channels ) ;
376392 }
377393
378394 Err ( probe_rs_rtt:: Error :: ControlBlockNotFound ) => {
@@ -393,3 +409,73 @@ fn setup_logging_channel(
393409fn print_separator ( ) {
394410 println ! ( "{}" , "─" . repeat( 80 ) . dimmed( ) ) ;
395411}
412+
413+ struct LogChannel < ' a > {
414+ number : usize ,
415+ rtt : UpChannel ,
416+ buf : [ u8 ; 1024 ] ,
417+ decoder : Option < ( Box < dyn StreamDecoder + ' a > , Encoding ) > ,
418+ }
419+
420+ impl < ' a > LogChannel < ' a > {
421+ pub fn new ( number : usize , rtt : UpChannel , table : & ' a Option < defmt_decoder:: Table > ) -> Self {
422+ Self {
423+ number,
424+ rtt,
425+ buf : [ 0u8 ; 1024 ] ,
426+ decoder : table. as_ref ( ) . map ( |t| ( t. new_stream_decoder ( ) , t. encoding ( ) ) ) ,
427+ }
428+ }
429+
430+ pub fn print_all (
431+ & mut self ,
432+ stdout : & mut io:: StdoutLock ,
433+ out_file : & mut Option < io:: BufWriter < fs:: File > > ,
434+ locations : & Option < std:: collections:: BTreeMap < u64 , defmt_decoder:: Location > > ,
435+ current_dir : & Path ,
436+ opts : & cli:: Opts ,
437+ ) -> anyhow:: Result < bool > {
438+ let Self {
439+ number,
440+ rtt,
441+ buf,
442+ decoder,
443+ } = self ;
444+
445+ let num_bytes_read = match rtt. read ( buf) {
446+ Ok ( n) => n,
447+ Err ( e) => {
448+ eprintln ! ( "RTT error: {}" , e) ;
449+ return Ok ( false ) ;
450+ }
451+ } ;
452+
453+ if num_bytes_read != 0 {
454+ match decoder. as_mut ( ) {
455+ Some ( ( stream_decoder, encoding) ) => {
456+ stream_decoder. received ( & buf[ ..num_bytes_read] ) ;
457+
458+ decode_and_print_defmt_logs (
459+ * number,
460+ & mut * * stream_decoder,
461+ out_file,
462+ locations. as_ref ( ) ,
463+ current_dir,
464+ opts. shorten_paths ,
465+ encoding. can_recover ( ) ,
466+ ) ?;
467+ }
468+
469+ _ => {
470+ stdout. write_all ( & buf[ ..num_bytes_read] ) ?;
471+ stdout. flush ( ) ?;
472+ if let Some ( out_file) = out_file {
473+ out_file. write_all ( & buf[ ..num_bytes_read] ) ?;
474+ }
475+ }
476+ }
477+ }
478+
479+ Ok ( true )
480+ }
481+ }
0 commit comments