@@ -13,12 +13,13 @@ use crossbeam_channel::{select, Receiver, Sender};
13
13
use eframe:: egui:: { vec2, ViewportBuilder } ;
14
14
use eframe:: { egui, icon_data} ;
15
15
use egui_plot:: PlotPoint ;
16
+ pub use gumdrop:: Options ;
16
17
use preferences:: AppInfo ;
17
18
use std:: cmp:: max;
18
19
use std:: path:: PathBuf ;
19
20
use std:: sync:: { Arc , RwLock } ;
21
+ use std:: thread;
20
22
use std:: time:: Duration ;
21
- use std:: { env, thread} ;
22
23
23
24
mod color_picker;
24
25
mod custom_highlighter;
@@ -76,6 +77,7 @@ fn main_thread(
76
77
load_rx : Receiver < PathBuf > ,
77
78
load_names_tx : Sender < Vec < String > > ,
78
79
gui_cmd_rx : Receiver < GuiCommand > ,
80
+ cli_column_labels : Vec < String > ,
79
81
) {
80
82
// reads data from mutex, samples and saves if needed
81
83
let mut data = DataContainer :: default ( ) ;
@@ -110,7 +112,7 @@ fn main_thread(
110
112
data. dataset = vec![ vec![ ] ; max( split_data. len( ) , 1 ) ] ;
111
113
if let Ok ( mut gui_data) = data_lock. write( ) {
112
114
gui_data. plots = ( 0 ..max( split_data. len( ) , 1 ) )
113
- . map( |i| ( format!( "Column {i}" ) , vec![ ] ) )
115
+ . map( |i| ( cli_column_labels . get ( i ) . cloned ( ) . unwrap_or_else ( || format!( "Column {i}" ) ) , vec![ ] ) )
114
116
. collect( ) ;
115
117
}
116
118
failed_format_counter = 0 ;
@@ -262,13 +264,114 @@ fn main_thread(
262
264
}
263
265
}
264
266
267
+ fn parse_databits ( s : & str ) -> Result < serialport:: DataBits , String > {
268
+ let d: u8 = s
269
+ . parse ( )
270
+ . map_err ( |_e| format ! ( "databits not a number: {s}" ) ) ?;
271
+ Ok ( serialport:: DataBits :: try_from ( d) . map_err ( |_e| format ! ( "invalid databits: {s}" ) ) ?)
272
+ }
273
+
274
+ fn parse_flow ( s : & str ) -> Result < serialport:: FlowControl , String > {
275
+ match s {
276
+ "none" => Ok ( serialport:: FlowControl :: None ) ,
277
+ "soft" => Ok ( serialport:: FlowControl :: Software ) ,
278
+ "hard" => Ok ( serialport:: FlowControl :: Hardware ) ,
279
+ _ => Err ( format ! ( "invalid flow-control: {s}" ) ) ,
280
+ }
281
+ }
282
+
283
+ fn parse_stopbits ( s : & str ) -> Result < serialport:: StopBits , String > {
284
+ let d: u8 = s
285
+ . parse ( )
286
+ . map_err ( |_e| format ! ( "stopbits not a number: {s}" ) ) ?;
287
+ Ok ( serialport:: StopBits :: try_from ( d) . map_err ( |_e| format ! ( "invalid stopbits: {s}" ) ) ?)
288
+ }
289
+
290
+ fn parse_parity ( s : & str ) -> Result < serialport:: Parity , String > {
291
+ match s {
292
+ "none" => Ok ( serialport:: Parity :: None ) ,
293
+ "odd" => Ok ( serialport:: Parity :: Odd ) ,
294
+ "even" => Ok ( serialport:: Parity :: Even ) ,
295
+ _ => Err ( format ! ( "invalid parity setting: {s}" ) ) ,
296
+ }
297
+ }
298
+
299
+ fn parse_color ( s : & str ) -> Result < egui:: Color32 , String > {
300
+ Ok ( egui:: ecolor:: HexColor :: from_str_without_hash ( s)
301
+ . map_err ( |e| format ! ( "invalid color {s:?}: {e:?}" ) ) ?
302
+ . color ( ) )
303
+ }
304
+
305
+ #[ derive( Debug , Options ) ]
306
+ struct CliOptions {
307
+ /// Serial port device to open on startup
308
+ #[ options( free) ]
309
+ device : Option < String > ,
310
+
311
+ /// Baudrate (default=9600)
312
+ #[ options( short = "b" ) ]
313
+ baudrate : Option < u32 > ,
314
+
315
+ /// Data bits (5, 6, 7, default=8)
316
+ #[ options( short = "d" , parse( try_from_str = "parse_databits" ) ) ]
317
+ databits : Option < serialport:: DataBits > ,
318
+
319
+ /// Flow conrol (hard, soft, default=none)
320
+ #[ options( short = "f" , parse( try_from_str = "parse_flow" ) ) ]
321
+ flow : Option < serialport:: FlowControl > ,
322
+
323
+ /// Stop bits (default=1, 2)
324
+ #[ options( short = "s" , parse( try_from_str = "parse_stopbits" ) ) ]
325
+ stopbits : Option < serialport:: StopBits > ,
326
+
327
+ /// Parity (odd, even, default=none)
328
+ #[ options( short = "p" , parse( try_from_str = "parse_parity" ) ) ]
329
+ parity : Option < serialport:: Parity > ,
330
+
331
+ /// Load data from a file instead of a serial port
332
+ #[ options( short = "F" ) ]
333
+ file : Option < std:: path:: PathBuf > ,
334
+
335
+ /// Column labels, can be specified multiple times for more columns
336
+ #[ options( no_short, long = "column" ) ]
337
+ column_labels : Vec < String > ,
338
+
339
+ /// Column colors (hex color without #), can be specified multiple times for more columns
340
+ #[ options( no_short, long = "color" , parse( try_from_str = "parse_color" ) ) ]
341
+ column_colors : Vec < egui:: Color32 > ,
342
+
343
+ help : bool ,
344
+ }
345
+
265
346
fn main ( ) {
266
347
egui_logger:: builder ( ) . init ( ) . unwrap ( ) ;
267
348
349
+ let args = CliOptions :: parse_args_default_or_exit ( ) ;
350
+
268
351
let gui_settings = load_gui_settings ( ) ;
269
352
let saved_serial_device_configs = load_serial_settings ( ) ;
270
353
271
- let device_lock = Arc :: new ( RwLock :: new ( Device :: default ( ) ) ) ;
354
+ let mut device = Device :: default ( ) ;
355
+ if let Some ( name) = args. device {
356
+ device. name = name;
357
+ }
358
+ if let Some ( baudrate) = args. baudrate {
359
+ device. baud_rate = baudrate;
360
+ }
361
+ if let Some ( databits) = args. databits {
362
+ device. data_bits = databits;
363
+ }
364
+ if let Some ( flow) = args. flow {
365
+ device. flow_control = flow;
366
+ }
367
+ if let Some ( stopbits) = args. stopbits {
368
+ device. stop_bits = stopbits;
369
+ }
370
+ if let Some ( parity) = args. parity {
371
+ device. parity = parity;
372
+ }
373
+
374
+ let device_lock = Arc :: new ( RwLock :: new ( device) ) ;
272
375
let devices_lock = Arc :: new ( RwLock :: new ( vec ! [ gui_settings. device. clone( ) ] ) ) ;
273
376
let data_lock = Arc :: new ( RwLock :: new ( GuiOutputDataContainer :: default ( ) ) ) ;
274
377
let connected_lock = Arc :: new ( RwLock :: new ( false ) ) ;
@@ -316,14 +419,12 @@ fn main() {
316
419
load_rx,
317
420
loaded_names_tx,
318
421
gui_cmd_rx,
422
+ args. column_labels ,
319
423
) ;
320
424
} ) ;
321
425
322
- let args: Vec < String > = env:: args ( ) . collect ( ) ;
323
- if args. len ( ) > 1 {
324
- load_tx
325
- . send ( PathBuf :: from ( & args[ 1 ] ) )
326
- . expect ( "failed to send file" ) ;
426
+ if let Some ( file) = args. file {
427
+ load_tx. send ( file) . expect ( "failed to send file" ) ;
327
428
}
328
429
329
430
let options = eframe:: NativeOptions {
@@ -372,6 +473,7 @@ fn main() {
372
473
loaded_names_rx,
373
474
send_tx,
374
475
gui_cmd_tx,
476
+ args. column_colors ,
375
477
) ) )
376
478
} ) ,
377
479
) {
0 commit comments