1
1
use std:: io:: Write ;
2
2
3
3
use crossterm:: { style:: Print , QueueableCommand } ;
4
- use defmt_decoder:: { Frame , Table } ;
5
- use miette:: { bail, Context , Diagnostic , Result } ;
4
+ use defmt_decoder:: {
5
+ log:: format:: { Formatter , FormatterConfig , FormatterFormat } ,
6
+ Frame ,
7
+ Table ,
8
+ } ;
9
+ use log:: warn;
10
+ use miette:: { bail, ensure, Context , Diagnostic , Result } ;
6
11
use thiserror:: Error ;
7
12
8
13
use crate :: cli:: monitor:: parser:: InputParser ;
@@ -22,9 +27,13 @@ pub enum DefmtError {
22
27
NoDefmtData ,
23
28
24
29
#[ error( "Failed to parse defmt data" ) ]
25
- #[ diagnostic( code( espflash:: monitor:: defmt:: parse_failed ) ) ]
30
+ #[ diagnostic( code( espflash:: monitor:: defmt:: table_parse_failed ) ) ]
26
31
TableParseFailed ,
27
32
33
+ #[ error( "Failed to parse defmt location data" ) ]
34
+ #[ diagnostic( code( espflash:: monitor:: defmt:: location_parse_failed) ) ]
35
+ LocationDataParseFailed ,
36
+
28
37
#[ error( "Unsupported defmt encoding: {0:?}. Only rzcobs is supported." ) ]
29
38
#[ diagnostic( code( espflash:: monitor:: defmt:: unsupported_encoding) ) ]
30
39
UnsupportedEncoding ( defmt_decoder:: Encoding ) ,
@@ -101,16 +110,16 @@ impl FrameDelimiter {
101
110
}
102
111
}
103
112
104
- #[ derive( Debug ) ]
105
- pub struct EspDefmt {
106
- delimiter : FrameDelimiter ,
113
+ struct DefmtData {
107
114
table : Table ,
115
+ locs : Option < defmt_decoder:: Locations > ,
116
+ formatter : Formatter ,
108
117
}
109
118
110
- impl EspDefmt {
119
+ impl DefmtData {
111
120
/// Loads symbols from the ELF file (if provided) and initializes the
112
121
/// context.
113
- fn load_table ( elf : Option < & [ u8 ] > ) -> Result < Table > {
122
+ fn load ( elf : Option < & [ u8 ] > , output_format : Option < String > ) -> Result < Self > {
114
123
let Some ( elf) = elf else {
115
124
bail ! ( DefmtError :: NoElf ) ;
116
125
} ;
@@ -125,35 +134,93 @@ impl EspDefmt {
125
134
126
135
// We only support rzcobs encoding because it is the only way to multiplex
127
136
// a defmt stream and an ASCII log stream over the same serial port.
128
- if encoding == defmt_decoder:: Encoding :: Rzcobs {
129
- Ok ( table)
137
+ ensure ! (
138
+ encoding == defmt_decoder:: Encoding :: Rzcobs ,
139
+ DefmtError :: UnsupportedEncoding ( encoding)
140
+ ) ;
141
+
142
+ let locs = table
143
+ . get_locations ( elf)
144
+ . map_err ( |_e| DefmtError :: LocationDataParseFailed ) ?;
145
+
146
+ let locs = if !table. is_empty ( ) && locs. is_empty ( ) {
147
+ warn ! ( "Insufficient DWARF info; compile your program with `debug = 2` to enable location info." ) ;
148
+ None
149
+ } else if table. indices ( ) . all ( |idx| locs. contains_key ( & ( idx as u64 ) ) ) {
150
+ Some ( locs)
130
151
} else {
131
- bail ! ( DefmtError :: UnsupportedEncoding ( encoding ) )
132
- }
133
- }
152
+ warn ! ( "Location info is incomplete; it will be omitted from the output." ) ;
153
+ None
154
+ } ;
134
155
135
- pub fn new ( elf : Option < & [ u8 ] > ) -> Result < Self > {
136
- Self :: load_table ( elf) . map ( |table| Self {
137
- delimiter : FrameDelimiter :: new ( ) ,
156
+ let show_location = locs. is_some ( ) ;
157
+ let has_timestamp = table. has_timestamp ( ) ;
158
+
159
+ let format = match output_format. as_deref ( ) {
160
+ None | Some ( "oneline" ) => FormatterFormat :: OneLine {
161
+ with_location : show_location,
162
+ } ,
163
+ Some ( "full" ) => FormatterFormat :: Default {
164
+ with_location : show_location,
165
+ } ,
166
+ Some ( format) => FormatterFormat :: Custom ( format) ,
167
+ } ;
168
+
169
+ Ok ( Self {
138
170
table,
171
+ locs,
172
+ formatter : Formatter :: new ( FormatterConfig {
173
+ format,
174
+ is_timestamp_available : has_timestamp,
175
+ } ) ,
139
176
} )
140
177
}
141
178
142
- fn handle_raw ( bytes : & [ u8 ] , out : & mut dyn Write ) {
143
- out. write_all ( bytes) . unwrap ( ) ;
144
- }
179
+ fn print ( & self , frame : Frame < ' _ > , out : & mut dyn Write ) {
180
+ let loc = self . locs . as_ref ( ) . and_then ( |locs| locs. get ( & frame. index ( ) ) ) ;
181
+ let ( file, line, module) = if let Some ( loc) = loc {
182
+ (
183
+ Some ( loc. file . display ( ) . to_string ( ) ) ,
184
+ Some ( loc. line . try_into ( ) . unwrap ( ) ) ,
185
+ Some ( loc. module . as_str ( ) ) ,
186
+ )
187
+ } else {
188
+ ( None , None , None )
189
+ } ;
190
+ let s = self
191
+ . formatter
192
+ . format_frame ( frame, file. as_deref ( ) , line, module) ;
145
193
146
- fn handle_defmt ( frame : Frame < ' _ > , out : & mut dyn Write ) {
147
- out. queue ( Print ( frame. display ( true ) . to_string ( ) ) ) . unwrap ( ) ;
194
+ out. queue ( Print ( s) ) . unwrap ( ) ;
148
195
out. queue ( Print ( "\r \n " ) ) . unwrap ( ) ;
149
196
150
197
out. flush ( ) . unwrap ( ) ;
151
198
}
152
199
}
153
200
201
+ pub struct EspDefmt {
202
+ delimiter : FrameDelimiter ,
203
+ defmt_data : DefmtData ,
204
+ }
205
+
206
+ impl std:: fmt:: Debug for EspDefmt {
207
+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
208
+ f. debug_struct ( "EspDefmt" ) . finish ( )
209
+ }
210
+ }
211
+
212
+ impl EspDefmt {
213
+ pub fn new ( elf : Option < & [ u8 ] > , output_format : Option < String > ) -> Result < Self > {
214
+ DefmtData :: load ( elf, output_format) . map ( |defmt_data| Self {
215
+ delimiter : FrameDelimiter :: new ( ) ,
216
+ defmt_data,
217
+ } )
218
+ }
219
+ }
220
+
154
221
impl InputParser for EspDefmt {
155
222
fn feed ( & mut self , bytes : & [ u8 ] , out : & mut dyn Write ) {
156
- let mut decoder = self . table . new_stream_decoder ( ) ;
223
+ let mut decoder = self . defmt_data . table . new_stream_decoder ( ) ;
157
224
158
225
self . delimiter . feed ( bytes, |frame| match frame {
159
226
FrameKind :: Defmt ( frame) => {
@@ -162,12 +229,12 @@ impl InputParser for EspDefmt {
162
229
decoder. received ( FRAME_END ) ;
163
230
164
231
if let Ok ( frame) = decoder. decode ( ) {
165
- Self :: handle_defmt ( frame, out) ;
232
+ self . defmt_data . print ( frame, out) ;
166
233
} else {
167
234
log:: warn!( "Failed to decode defmt frame" ) ;
168
235
}
169
236
}
170
- FrameKind :: Raw ( bytes) => Self :: handle_raw ( bytes, out ) ,
237
+ FrameKind :: Raw ( bytes) => out . write_all ( bytes) . unwrap ( ) ,
171
238
} ) ;
172
239
}
173
240
}
0 commit comments