@@ -9,7 +9,7 @@ use badgemagic::{
9
9
usb_hid:: Device as UsbDevice ,
10
10
} ;
11
11
use base64:: Engine ;
12
- use clap:: Parser ;
12
+ use clap:: { Parser , ValueEnum } ;
13
13
use embedded_graphics:: {
14
14
geometry:: Point ,
15
15
image:: { Image , ImageRawLE } ,
@@ -43,11 +43,16 @@ struct Args {
43
43
#[ clap( long) ]
44
44
transport : TransportProtocol ,
45
45
46
+ /// List all devices visible to a transport and exit
47
+ #[ clap( long) ]
48
+ list_devices : bool ,
49
+
46
50
/// Path to TOML configuration file
47
- config : PathBuf ,
51
+ #[ clap( required_unless_present = "list_devices" ) ]
52
+ config : Option < PathBuf > ,
48
53
}
49
54
50
- #[ derive( Clone , Deserialize , clap :: ValueEnum ) ]
55
+ #[ derive( Clone , Deserialize , ValueEnum ) ]
51
56
#[ serde( rename_all = "kebab-case" ) ]
52
57
enum TransportProtocol {
53
58
Usb ,
@@ -91,16 +96,48 @@ enum Content {
91
96
}
92
97
93
98
fn 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
+ } ?;
97
118
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:?}" ) ) ?;
98
135
let config: Config = {
99
136
let extension = args
100
137
. format
101
138
. as_deref ( )
102
139
. map ( AsRef :: as_ref)
103
- . or ( args . config . extension ( ) )
140
+ . or ( config_path . extension ( ) )
104
141
. context ( "missing file extension for config file" ) ?;
105
142
match extension. to_str ( ) . unwrap_or_default ( ) {
106
143
"json" => serde_json:: from_str ( & config) . context ( "parse config" ) ?,
@@ -189,13 +226,18 @@ fn main() -> Result<()> {
189
226
}
190
227
}
191
228
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 {
193
237
TransportProtocol :: Usb => UsbDevice :: single ( ) ?. write ( payload) ,
194
238
TransportProtocol :: Ble => tokio:: runtime:: Builder :: new_current_thread ( )
195
239
. enable_all ( )
196
240
. build ( ) ?
197
241
. block_on ( async { BleDevice :: single ( ) . await ?. write ( payload) . await } ) ,
198
- } ?;
199
-
200
- Ok ( ( ) )
242
+ }
201
243
}
0 commit comments