@@ -10,24 +10,24 @@ use std::path::{Path, PathBuf};
1010struct Args {
1111 /// Input BBL files or glob patterns (case-insensitive)
1212 files : Vec < String > ,
13-
13+
1414 /// Enable debug output
1515 #[ arg( short, long) ]
1616 debug : bool ,
1717}
1818
1919fn main ( ) -> Result < ( ) > {
2020 let args = Args :: parse ( ) ;
21-
21+
2222 if args. files . is_empty ( ) {
2323 eprintln ! ( "Error: No input files specified" ) ;
2424 eprintln ! ( "Usage: bbl_crate_test [OPTIONS] <FILES>..." ) ;
2525 eprintln ! ( "Example: bbl_crate_test *.BBL *.bbl logs/*.{{BBL,BFL,TXT}}" ) ;
2626 std:: process:: exit ( 1 ) ;
2727 }
28-
28+
2929 let mut all_files = Vec :: new ( ) ;
30-
30+
3131 // Expand glob patterns and collect all matching files
3232 for pattern in & args. files {
3333 match glob ( pattern) {
@@ -41,7 +41,10 @@ fn main() -> Result<()> {
4141 found_files = true ;
4242 }
4343 }
44- Err ( e) => eprintln ! ( "Warning: Error reading path in pattern '{}': {}" , pattern, e) ,
44+ Err ( e) => eprintln ! (
45+ "Warning: Error reading path in pattern '{}': {}" ,
46+ pattern, e
47+ ) ,
4548 }
4649 }
4750 if !found_files {
@@ -64,20 +67,20 @@ fn main() -> Result<()> {
6467 }
6568 }
6669 }
67-
70+
6871 if all_files. is_empty ( ) {
6972 eprintln ! ( "Error: No valid BBL files found" ) ;
7073 std:: process:: exit ( 1 ) ;
7174 }
72-
75+
7376 // Sort files for consistent output
7477 all_files. sort ( ) ;
75-
78+
7679 for file_path in all_files {
7780 process_file ( & file_path, args. debug ) ?;
7881 println ! ( ) ;
7982 }
80-
83+
8184 Ok ( ( ) )
8285}
8386
@@ -94,56 +97,80 @@ fn is_bbl_file(path: &Path) -> bool {
9497/// Process a single BBL file and display information
9598fn process_file ( file_path : & Path , debug : bool ) -> Result < ( ) > {
9699 println ! ( "Processing: {}" , file_path. display( ) ) ;
97-
100+
98101 // Parse all logs in the file
99102 let export_options = ExportOptions :: default ( ) ; // No file exports needed
100103 let logs = parse_bbl_file_all_logs ( file_path, export_options, debug) ?;
101-
104+
102105 for log in logs {
103106 if log. total_logs > 1 {
104107 println ! ( " Log {} of {}" , log. log_number, log. total_logs) ;
105108 }
106-
109+
107110 // Basic flight information
108111 println ! ( " Firmware: {}" , log. header. firmware_revision) ;
109112 println ! ( " Craft: {}" , log. header. craft_name) ;
110-
113+
111114 // Flight duration calculation
112115 let duration = log. duration_seconds ( ) ;
113116 println ! ( " Flight Duration: {:.1} seconds" , duration) ;
114-
117+
115118 // PID settings from header (always shown)
116119 display_pid_settings ( & log. header . all_headers ) ;
117-
120+
118121 if log. total_logs > 1 {
119122 println ! ( ) ;
120123 }
121124 }
122-
125+
123126 Ok ( ( ) )
124127}
125128
126129/// Extract and display PID settings from system configuration
127130fn display_pid_settings ( all_headers : & [ String ] ) {
128131 println ! ( " PID Settings:" ) ;
129-
132+
130133 // First try to parse PID values with potential feedforward (4-value format for iNav)
131134 if let Some ( ( roll_pid, pitch_pid, yaw_pid) ) = parse_pid_with_ff_from_headers ( all_headers) {
132135 // iNav 4-value format: P,I,D,FF
133- println ! ( " Roll: P={}, I={}, D={}, FF={}" , roll_pid. 0 , roll_pid. 1 , roll_pid. 2 , roll_pid. 3 ) ;
134- println ! ( " Pitch: P={}, I={}, D={}, FF={}" , pitch_pid. 0 , pitch_pid. 1 , pitch_pid. 2 , pitch_pid. 3 ) ;
135- println ! ( " Yaw: P={}, I={}, D={}, FF={}" , yaw_pid. 0 , yaw_pid. 1 , yaw_pid. 2 , yaw_pid. 3 ) ;
136+ println ! (
137+ " Roll: P={}, I={}, D={}, FF={}" ,
138+ roll_pid. 0 , roll_pid. 1 , roll_pid. 2 , roll_pid. 3
139+ ) ;
140+ println ! (
141+ " Pitch: P={}, I={}, D={}, FF={}" ,
142+ pitch_pid. 0 , pitch_pid. 1 , pitch_pid. 2 , pitch_pid. 3
143+ ) ;
144+ println ! (
145+ " Yaw: P={}, I={}, D={}, FF={}" ,
146+ yaw_pid. 0 , yaw_pid. 1 , yaw_pid. 2 , yaw_pid. 3
147+ ) ;
136148 } else if let Some ( ( roll_pid, pitch_pid, yaw_pid) ) = parse_pid_from_headers ( all_headers) {
137149 // Check if we have Betaflight feedforward values (ff_weight)
138150 if let Some ( ( roll_ff, pitch_ff, yaw_ff) ) = parse_feedforward_from_headers ( all_headers) {
139151 // Betaflight: P,I,D from rollPID + FF from ff_weight
140- println ! ( " Roll: P={}, I={}, D={}, FF={}" , roll_pid. 0 , roll_pid. 1 , roll_pid. 2 , roll_ff) ;
141- println ! ( " Pitch: P={}, I={}, D={}, FF={}" , pitch_pid. 0 , pitch_pid. 1 , pitch_pid. 2 , pitch_ff) ;
142- println ! ( " Yaw: P={}, I={}, D={}, FF={}" , yaw_pid. 0 , yaw_pid. 1 , yaw_pid. 2 , yaw_ff) ;
152+ println ! (
153+ " Roll: P={}, I={}, D={}, FF={}" ,
154+ roll_pid. 0 , roll_pid. 1 , roll_pid. 2 , roll_ff
155+ ) ;
156+ println ! (
157+ " Pitch: P={}, I={}, D={}, FF={}" ,
158+ pitch_pid. 0 , pitch_pid. 1 , pitch_pid. 2 , pitch_ff
159+ ) ;
160+ println ! (
161+ " Yaw: P={}, I={}, D={}, FF={}" ,
162+ yaw_pid. 0 , yaw_pid. 1 , yaw_pid. 2 , yaw_ff
163+ ) ;
143164 } else {
144165 // EmuFlight or older firmware: P,I,D only
145- println ! ( " Roll: P={}, I={}, D={}" , roll_pid. 0 , roll_pid. 1 , roll_pid. 2 ) ;
146- println ! ( " Pitch: P={}, I={}, D={}" , pitch_pid. 0 , pitch_pid. 1 , pitch_pid. 2 ) ;
166+ println ! (
167+ " Roll: P={}, I={}, D={}" ,
168+ roll_pid. 0 , roll_pid. 1 , roll_pid. 2
169+ ) ;
170+ println ! (
171+ " Pitch: P={}, I={}, D={}" ,
172+ pitch_pid. 0 , pitch_pid. 1 , pitch_pid. 2
173+ ) ;
147174 println ! ( " Yaw: P={}, I={}, D={}" , yaw_pid. 0 , yaw_pid. 1 , yaw_pid. 2 ) ;
148175 }
149176 } else {
@@ -152,11 +179,17 @@ fn display_pid_settings(all_headers: &[String]) {
152179}
153180
154181/// Parse PID values with feedforward from raw header lines (for iNav 4-value format)
155- fn parse_pid_with_ff_from_headers ( all_headers : & [ String ] ) -> Option < ( ( i32 , i32 , i32 , i32 ) , ( i32 , i32 , i32 , i32 ) , ( i32 , i32 , i32 , i32 ) ) > {
182+ fn parse_pid_with_ff_from_headers (
183+ all_headers : & [ String ] ,
184+ ) -> Option < (
185+ ( i32 , i32 , i32 , i32 ) ,
186+ ( i32 , i32 , i32 , i32 ) ,
187+ ( i32 , i32 , i32 , i32 ) ,
188+ ) > {
156189 let mut roll_pid = None ;
157190 let mut pitch_pid = None ;
158191 let mut yaw_pid = None ;
159-
192+
160193 for header in all_headers {
161194 if header. starts_with ( "H rollPID:" ) {
162195 if let Some ( value_str) = header. strip_prefix ( "H rollPID:" ) {
@@ -172,7 +205,7 @@ fn parse_pid_with_ff_from_headers(all_headers: &[String]) -> Option<((i32, i32,
172205 }
173206 }
174207 }
175-
208+
176209 if let ( Some ( r) , Some ( p) , Some ( y) ) = ( roll_pid, pitch_pid, yaw_pid) {
177210 Some ( ( r, p, y) )
178211 } else {
@@ -181,11 +214,13 @@ fn parse_pid_with_ff_from_headers(all_headers: &[String]) -> Option<((i32, i32,
181214}
182215
183216/// Parse PID values from raw header lines (for Betaflight rollPID/pitchPID/yawPID format)
184- fn parse_pid_from_headers ( all_headers : & [ String ] ) -> Option < ( ( i32 , i32 , i32 ) , ( i32 , i32 , i32 ) , ( i32 , i32 , i32 ) ) > {
217+ fn parse_pid_from_headers (
218+ all_headers : & [ String ] ,
219+ ) -> Option < ( ( i32 , i32 , i32 ) , ( i32 , i32 , i32 ) , ( i32 , i32 , i32 ) ) > {
185220 let mut roll_pid = None ;
186221 let mut pitch_pid = None ;
187222 let mut yaw_pid = None ;
188-
223+
189224 for header in all_headers {
190225 if header. starts_with ( "H rollPID:" ) {
191226 if let Some ( value_str) = header. strip_prefix ( "H rollPID:" ) {
@@ -201,7 +236,7 @@ fn parse_pid_from_headers(all_headers: &[String]) -> Option<((i32, i32, i32), (i
201236 }
202237 }
203238 }
204-
239+
205240 if let ( Some ( r) , Some ( p) , Some ( y) ) = ( roll_pid, pitch_pid, yaw_pid) {
206241 Some ( ( r, p, y) )
207242 } else {
@@ -227,14 +262,14 @@ fn parse_feedforward_from_headers(all_headers: &[String]) -> Option<(i32, i32, i
227262fn parse_pid_with_ff_string ( pid_value : & str ) -> Option < ( i32 , i32 , i32 , i32 ) > {
228263 // Remove quotes if present
229264 let cleaned = pid_value. trim_matches ( '"' ) ;
230-
265+
231266 let parts: Vec < & str > = cleaned. split ( ',' ) . collect ( ) ;
232267 if parts. len ( ) == 4 {
233268 if let ( Ok ( p) , Ok ( i) , Ok ( d) , Ok ( ff) ) = (
234269 parts[ 0 ] . trim ( ) . parse :: < i32 > ( ) ,
235270 parts[ 1 ] . trim ( ) . parse :: < i32 > ( ) ,
236271 parts[ 2 ] . trim ( ) . parse :: < i32 > ( ) ,
237- parts[ 3 ] . trim ( ) . parse :: < i32 > ( )
272+ parts[ 3 ] . trim ( ) . parse :: < i32 > ( ) ,
238273 ) {
239274 return Some ( ( p, i, d, ff) ) ;
240275 }
@@ -246,13 +281,13 @@ fn parse_pid_with_ff_string(pid_value: &str) -> Option<(i32, i32, i32, i32)> {
246281fn parse_pid_string ( pid_value : & str ) -> Option < ( i32 , i32 , i32 ) > {
247282 // Remove quotes if present
248283 let cleaned = pid_value. trim_matches ( '"' ) ;
249-
284+
250285 let parts: Vec < & str > = cleaned. split ( ',' ) . collect ( ) ;
251286 if parts. len ( ) >= 3 {
252287 if let ( Ok ( p) , Ok ( i) , Ok ( d) ) = (
253288 parts[ 0 ] . trim ( ) . parse :: < i32 > ( ) ,
254289 parts[ 1 ] . trim ( ) . parse :: < i32 > ( ) ,
255- parts[ 2 ] . trim ( ) . parse :: < i32 > ( )
290+ parts[ 2 ] . trim ( ) . parse :: < i32 > ( ) ,
256291 ) {
257292 return Some ( ( p, i, d) ) ;
258293 // Note: For iNav 4-value format "P,I,D,FF", we ignore the 4th value (feedforward)
0 commit comments