@@ -9,7 +9,7 @@ use badgemagic::{
99 usb_hid:: Device as UsbDevice ,
1010} ;
1111use base64:: Engine ;
12- use clap:: Parser ;
12+ use clap:: { Parser , ValueEnum } ;
1313use embedded_graphics:: {
1414 geometry:: Point ,
1515 image:: { Image , ImageRawLE } ,
@@ -43,11 +43,16 @@ struct Args {
4343 #[ clap( long) ]
4444 transport : TransportProtocol ,
4545
46+ /// List all devices visible to a transport and exit
47+ #[ clap( long) ]
48+ list_devices : bool ,
49+
4650 /// Path to TOML configuration file
47- config : PathBuf ,
51+ #[ clap( required_unless_present = "list_devices" ) ]
52+ config : Option < PathBuf > ,
4853}
4954
50- #[ derive( Clone , Deserialize , clap :: ValueEnum ) ]
55+ #[ derive( Clone , Deserialize , ValueEnum ) ]
5156#[ serde( rename_all = "kebab-case" ) ]
5257enum TransportProtocol {
5358 Usb ,
@@ -91,16 +96,48 @@ enum Content {
9196}
9297
9398fn main ( ) -> Result < ( ) > {
94- let args = Args :: parse ( ) ;
95- let config = fs:: read_to_string ( & args. config )
96- . with_context ( || format ! ( "load config: {:?}" , args. config) ) ?;
99+ let mut args = Args :: parse ( ) ;
100+
101+ if args. list_devices {
102+ return list_devices ( & args. transport ) ;
103+ }
104+
105+ let payload = gnerate_payload ( & mut args) ?;
106+
107+ write_payload ( & args. transport , payload)
108+ }
109+
110+ fn list_devices ( transport : & TransportProtocol ) -> Result < ( ) > {
111+ let devices = match transport {
112+ TransportProtocol :: Usb => UsbDevice :: list_all ( ) ,
113+ TransportProtocol :: Ble => tokio:: runtime:: Builder :: new_current_thread ( )
114+ . enable_all ( )
115+ . build ( ) ?
116+ . block_on ( async { BleDevice :: list_all ( ) . await } ) ,
117+ } ?;
97118
119+ eprintln ! (
120+ "found {} {} devices" ,
121+ devices. len( ) ,
122+ transport. to_possible_value( ) . unwrap( ) . get_name( ) ,
123+ ) ;
124+ for device in devices {
125+ println ! ( "- {device}" ) ;
126+ }
127+
128+ Ok ( ( ) )
129+ }
130+
131+ fn gnerate_payload ( args : & mut Args ) -> Result < PayloadBuffer > {
132+ let config_path = args. config . take ( ) . unwrap_or_default ( ) ;
133+ let config = fs:: read_to_string ( & config_path)
134+ . with_context ( || format ! ( "load config: {config_path:?}" ) ) ?;
98135 let config: Config = {
99136 let extension = args
100137 . format
101138 . as_deref ( )
102139 . map ( AsRef :: as_ref)
103- . or ( args . config . extension ( ) )
140+ . or ( config_path . extension ( ) )
104141 . context ( "missing file extension for config file" ) ?;
105142 match extension. to_str ( ) . unwrap_or_default ( ) {
106143 "json" => serde_json:: from_str ( & config) . context ( "parse config" ) ?,
@@ -189,13 +226,18 @@ fn main() -> Result<()> {
189226 }
190227 }
191228
192- match args. transport {
229+ Ok ( payload)
230+ }
231+
232+ fn write_payload (
233+ transport : & TransportProtocol ,
234+ payload : PayloadBuffer ,
235+ ) -> Result < ( ) , anyhow:: Error > {
236+ match transport {
193237 TransportProtocol :: Usb => UsbDevice :: single ( ) ?. write ( payload) ,
194238 TransportProtocol :: Ble => tokio:: runtime:: Builder :: new_current_thread ( )
195239 . enable_all ( )
196240 . build ( ) ?
197241 . block_on ( async { BleDevice :: single ( ) . await ?. write ( payload) . await } ) ,
198- } ?;
199-
200- Ok ( ( ) )
242+ }
201243}
0 commit comments