1 use std::collections::HashMap;
2 use std::fmt::{Display, Formatter};
3 use std::slice::SliceIndex;
4 use std::sync::{Arc, Mutex};
5 use std::time::Duration;
6 
7 use crate::bt_adv::AdvSet;
8 use crate::bt_gatt::AuthReq;
9 use crate::callbacks::{BtGattCallback, BtGattServerCallback};
10 use crate::ClientContext;
11 use crate::{console_red, console_yellow, print_error, print_info};
12 use bt_topshim::btif::{
13     BtConnectionState, BtDiscMode, BtStatus, BtTransport, RawAddress, Uuid, INVALID_RSSI,
14 };
15 use bt_topshim::profiles::gatt::{GattStatus, LePhy};
16 use bt_topshim::profiles::hid_host::BthhReportType;
17 use bt_topshim::profiles::sdp::{BtSdpMpsRecord, BtSdpRecord};
18 use bt_topshim::profiles::ProfileConnectionState;
19 use bt_topshim::syslog::Level;
20 use btstack::battery_manager::IBatteryManager;
21 use btstack::bluetooth::{BluetoothDevice, IBluetooth};
22 use btstack::bluetooth_gatt::{
23     BluetoothGattCharacteristic, BluetoothGattDescriptor, BluetoothGattService, GattDbElementType,
24     GattWriteType, IBluetoothGatt,
25 };
26 use btstack::bluetooth_logging::IBluetoothLogging;
27 use btstack::bluetooth_media::{IBluetoothMedia, IBluetoothTelephony};
28 use btstack::bluetooth_qa::IBluetoothQA;
29 use btstack::socket_manager::{IBluetoothSocketManager, SocketResult};
30 use btstack::uuid::{Profile, UuidHelper};
31 use manager_service::iface_bluetooth_manager::IBluetoothManager;
32 
33 const INDENT_CHAR: &str = " ";
34 const BAR1_CHAR: &str = "=";
35 const BAR2_CHAR: &str = "-";
36 const MAX_MENU_CHAR_WIDTH: usize = 72;
37 
38 const GATT_CLIENT_APP_UUID: &str = "12345678123456781234567812345678";
39 const GATT_SERVER_APP_UUID: &str = "12345678123456781234567812345679";
40 const HEART_RATE_SERVICE_UUID: &str = "0000180D-0000-1000-8000-00805F9B34FB";
41 const HEART_RATE_MEASUREMENT_UUID: &str = "00002A37-0000-1000-8000-00805F9B34FB";
42 const GENERIC_UUID: &str = "00000000-0000-1000-8000-00805F9B34FB";
43 const CCC_DESCRIPTOR_UUID: &str = "00002902-0000-1000-8000-00805F9B34FB";
44 const BATTERY_SERVICE_UUID: &str = "0000180F-0000-1000-8000-00805F9B34FB";
45 
46 enum CommandError {
47     // Command not handled due to invalid arguments.
48     InvalidArgs,
49     // Command handled but failed with the given reason.
50     Failed(String),
51 }
52 
53 impl From<&str> for CommandError {
from(s: &str) -> CommandError54     fn from(s: &str) -> CommandError {
55         CommandError::Failed(String::from(s))
56     }
57 }
58 
59 impl From<String> for CommandError {
from(s: String) -> CommandError60     fn from(s: String) -> CommandError {
61         CommandError::Failed(s)
62     }
63 }
64 
65 type CommandResult = Result<(), CommandError>;
66 
67 type CommandFunction = fn(&mut CommandHandler, &[String]) -> CommandResult;
68 
_noop(_handler: &mut CommandHandler, _args: &[String]) -> CommandResult69 fn _noop(_handler: &mut CommandHandler, _args: &[String]) -> CommandResult {
70     // Used so we can add options with no direct function
71     // e.g. help and quit
72     Ok(())
73 }
74 
75 pub struct CommandOption {
76     rules: Vec<String>,
77     description: String,
78     function_pointer: CommandFunction,
79 }
80 
81 /// Handles string command entered from command line.
82 pub(crate) struct CommandHandler {
83     context: Arc<Mutex<ClientContext>>,
84     command_options: HashMap<String, CommandOption>,
85 }
86 
87 /// Define what to do when a socket connects. Mainly for qualification purposes.
88 /// Specifically, after a socket is connected/accepted, we will do
89 /// (1) send a chunk of data every |send_interval| time until |num_frame| chunks has been sent.
90 /// (2) wait another |disconnect_delay| time. any incoming data will be dumpted during this time.
91 /// (3) disconnect the socket.
92 #[derive(Copy, Clone)]
93 pub struct SocketSchedule {
94     /// Number of times to send data
95     pub num_frame: u32,
96     /// Time interval between each sending
97     pub send_interval: Duration,
98     /// Extra time after the last sending. Any incoming data will be printed during this time.
99     pub disconnect_delay: Duration,
100 }
101 
102 struct DisplayList<T>(Vec<T>);
103 
104 impl<T: Display> Display for DisplayList<T> {
fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result105     fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
106         let _ = writeln!(f, "[");
107         for item in self.0.iter() {
108             let _ = writeln!(f, "  {}", item);
109         }
110 
111         write!(f, "]")
112     }
113 }
114 
wrap_help_text(text: &str, max: usize, indent: usize) -> String115 fn wrap_help_text(text: &str, max: usize, indent: usize) -> String {
116     let remaining_count = std::cmp::max(
117         // real_max
118         std::cmp::max(max, text.chars().count())
119         // take away char count
120          - text.chars().count()
121         // take away real_indent
122          - (
123              if std::cmp::max(max, text.chars().count())- text.chars().count() > indent {
124                  indent
125              } else {
126                  0
127              }),
128         0,
129     );
130 
131     format!("|{}{}{}|", INDENT_CHAR.repeat(indent), text, INDENT_CHAR.repeat(remaining_count))
132 }
133 
134 // This should be called during the constructor in order to populate the command option map
build_commands() -> HashMap<String, CommandOption>135 fn build_commands() -> HashMap<String, CommandOption> {
136     let mut command_options = HashMap::<String, CommandOption>::new();
137     command_options.insert(
138         String::from("adapter"),
139         CommandOption {
140             rules: vec![
141                 String::from("adapter enable"),
142                 String::from("adapter disable"),
143                 String::from("adapter show"),
144                 String::from("adapter discoverable <on|limited|off> <duration>"),
145                 String::from("adapter connectable <on|off>"),
146                 String::from("adapter set-name <name>"),
147             ],
148             description: String::from(
149                 "Enable/Disable/Show default bluetooth adapter. (e.g. adapter enable)\n
150                  Discoverable On/Limited/Off (e.g. adapter discoverable on 60)\n
151                  Connectable On/Off (e.g. adapter connectable on)",
152             ),
153             function_pointer: CommandHandler::cmd_adapter,
154         },
155     );
156     command_options.insert(
157         String::from("battery"),
158         CommandOption {
159             rules: vec![
160                 String::from("battery status <address>"),
161                 String::from("battery track <address>"),
162                 String::from("battery untrack <address>"),
163             ],
164             description: String::from(
165                 "
166                 status: Current battery status of a given device.\n
167                 track: Track a given device to monitor battery updates.\n
168                 untrack: Stop tracking a device for battery updates.
169             ",
170             ),
171             function_pointer: CommandHandler::cmd_battery,
172         },
173     );
174     command_options.insert(
175         String::from("bond"),
176         CommandOption {
177             rules: vec![String::from("bond <add|remove|cancel> <address>")],
178             description: String::from("Creates a bond with a device."),
179             function_pointer: CommandHandler::cmd_bond,
180         },
181     );
182     command_options.insert(
183         String::from("device"),
184         CommandOption {
185             rules: vec![
186                 String::from("device <connect|disconnect|info> <address>"),
187                 String::from("device set-pairing-confirmation <address> <accept|reject>"),
188                 String::from("device set-pairing-pin <address> <pin|reject>"),
189                 String::from("device set-pairing-passkey <address> <passkey|reject>"),
190                 String::from("device set-alias <address> <new-alias>"),
191                 String::from("device get-rssi <address>"),
192             ],
193             description: String::from("Take action on a remote device. (i.e. info)"),
194             function_pointer: CommandHandler::cmd_device,
195         },
196     );
197     command_options.insert(
198         String::from("discovery"),
199         CommandOption {
200             rules: vec![String::from("discovery <start|stop>")],
201             description: String::from("Start and stop device discovery. (e.g. discovery start)"),
202             function_pointer: CommandHandler::cmd_discovery,
203         },
204     );
205     command_options.insert(
206         String::from("floss"),
207         CommandOption {
208             rules: vec![String::from("floss <enable|disable>")],
209             description: String::from("Enable or disable Floss for dogfood."),
210             function_pointer: CommandHandler::cmd_floss,
211         },
212     );
213     command_options.insert(
214         String::from("gatt"),
215         CommandOption {
216             rules: vec![
217                 String::from("gatt register-client"),
218                 String::from("gatt client-connect <address>"),
219                 String::from("gatt client-read-phy <address>"),
220                 String::from("gatt client-discover-services <address>"),
221                 String::from("gatt client-discover-service-by-uuid-pts <address> <uuid>"),
222                 String::from("gatt client-disconnect <address>"),
223                 String::from("gatt configure-mtu <address> <mtu>"),
224                 String::from("gatt set-direct-connect <true|false>"),
225                 String::from("gatt set-connect-transport <Bredr|LE|Auto>"),
226                 String::from("gatt set-connect-opportunistic <true|false>"),
227                 String::from("gatt set-connect-phy <Phy1m|Phy2m|PhyCoded>"),
228                 String::from("gatt set-auth-req <NONE|EncNoMitm|EncMitm|SignedNoMitm|SignedMitm>"),
229                 String::from(
230                     "gatt write-characteristic <address> <handle> <NoRsp|Write|Prepare> <value>",
231                 ),
232                 String::from("gatt read-characteristic <address> <handle>"),
233                 String::from(
234                     "gatt read-characteristic-by-uuid <address> <uuid> <start_handle> <end_handle>",
235                 ),
236                 String::from("gatt register-notification <address> <handle> <enable|disable>"),
237                 String::from("gatt register-server"),
238                 String::from("gatt unregister-server <server_id>"),
239                 String::from("gatt server-connect <server_id> <client_address>"),
240                 String::from("gatt server-disconnect <server_id> <client_address>"),
241                 String::from("gatt server-add-basic-service <server_id>"),
242                 String::from("gatt server-add-service <server_id> <incl_service_instance_id>"),
243                 String::from("gatt server-remove-service <server_id> <service_handle>"),
244                 String::from("gatt server-clear-all-services <server_id>"),
245                 String::from("gatt server-send-response <server_id> <success|fail>"),
246                 String::from("gatt server-set-direct-connect <true|false>"),
247                 String::from("gatt server-set-connect-transport <Bredr|LE|Auto>"),
248             ],
249             description: String::from(
250                 "GATT tools\n\n
251                 Creating a GATT Server:\n
252                 Register a server, then add a basic (battery) service. After, a more complex\n
253                 (heartrate) service can be created with previously created services included.",
254             ),
255             function_pointer: CommandHandler::cmd_gatt,
256         },
257     );
258     command_options.insert(
259         String::from("le-scan"),
260         CommandOption {
261             rules: vec![
262                 String::from("le-scan register-scanner"),
263                 String::from("le-scan unregister-scanner <scanner-id>"),
264                 String::from("le-scan start-scan <scanner-id>"),
265                 String::from("le-scan stop-scan <scanner-id>"),
266             ],
267             description: String::from("LE scanning utilities."),
268             function_pointer: CommandHandler::cmd_le_scan,
269         },
270     );
271     command_options.insert(
272         String::from("advertise"),
273         CommandOption {
274             rules: vec![
275                 String::from("advertise <on|off|ext>"),
276                 String::from("advertise set-interval <ms>"),
277                 String::from("advertise set-scan-rsp <enable|disable>"),
278                 String::from("advertise set-raw-data <raw-adv-data> <adv-id>"),
279                 String::from("advertise set-connectable <on|off> <adv-id>"),
280             ],
281             description: String::from("Advertising utilities."),
282             function_pointer: CommandHandler::cmd_advertise,
283         },
284     );
285     command_options.insert(
286         String::from("sdp"),
287         CommandOption {
288             rules: vec![String::from("sdp search <address> <uuid>")],
289             description: String::from("Service Discovery Protocol utilities."),
290             function_pointer: CommandHandler::cmd_sdp,
291         },
292     );
293     command_options.insert(
294         String::from("socket"),
295         CommandOption {
296             rules: vec![
297                 String::from("socket listen <auth-required> <Bredr|LE>"),
298                 String::from("socket listen-rfcomm <scn>"),
299                 String::from("socket send-msc <dlci> <address>"),
300                 String::from(
301                     "socket connect <address> <l2cap|rfcomm> <psm|uuid> <auth-required> <Bredr|LE>",
302                 ),
303                 String::from("socket close <socket_id>"),
304                 String::from("socket set-on-connect-schedule <send|resend|dump>"),
305             ],
306             description: String::from("Socket manager utilities."),
307             function_pointer: CommandHandler::cmd_socket,
308         },
309     );
310     command_options.insert(
311         String::from("hid"),
312         CommandOption {
313             rules: vec![
314                 String::from("hid get-report <address> <Input|Output|Feature> <report_id>"),
315                 String::from("hid set-report <address> <Input|Output|Feature> <report_value>"),
316                 String::from("hid send-data <address> <data>"),
317                 String::from("hid virtual-unplug <address>"),
318             ],
319             description: String::from("Socket manager utilities."),
320             function_pointer: CommandHandler::cmd_hid,
321         },
322     );
323     command_options.insert(
324         String::from("get-address"),
325         CommandOption {
326             rules: vec![String::from("get-address")],
327             description: String::from("Gets the local device address."),
328             function_pointer: CommandHandler::cmd_get_address,
329         },
330     );
331     command_options.insert(
332         String::from("qa"),
333         CommandOption {
334             rules: vec![String::from("qa add-media-player <name> <browsing_supported>")],
335             description: String::from("Methods for testing purposes"),
336             function_pointer: CommandHandler::cmd_qa,
337         },
338     );
339     command_options.insert(
340         String::from("help"),
341         CommandOption {
342             rules: vec![String::from("help")],
343             description: String::from("Shows this menu."),
344             function_pointer: CommandHandler::cmd_help,
345         },
346     );
347     command_options.insert(
348         String::from("list"),
349         CommandOption {
350             rules: vec![String::from("list <bonded|found|connected>")],
351             description: String::from(
352                 "List bonded or found remote devices. Use: list <bonded|found>",
353             ),
354             function_pointer: CommandHandler::cmd_list_devices,
355         },
356     );
357     command_options.insert(
358         String::from("telephony"),
359         CommandOption {
360             rules: vec![
361                 String::from("telephony set-network <on|off>"),
362                 String::from("telephony set-roaming <on|off>"),
363                 String::from("telephony set-signal <strength>"),
364                 String::from("telephony set-battery <level>"),
365                 String::from("telephony set-phone-opss <on|off>"),
366                 String::from("telephony <enable|disable>"),
367                 String::from("telephony <incoming-call|dialing-call> <number>"),
368                 String::from("telephony <answer-call|hangup-call>"),
369                 String::from("telephony <set-memory-call|set-last-call> [<number>]"),
370                 String::from(
371                     "telephony <release-held|release-active-accept-held|hold-active-accept-held>",
372                 ),
373                 String::from("telephony <audio-connect|audio-disconnect> <address>"),
374             ],
375             description: String::from("Set device telephony status."),
376             function_pointer: CommandHandler::cmd_telephony,
377         },
378     );
379     command_options.insert(
380         String::from("media"),
381         CommandOption {
382             rules: vec![String::from("media log")],
383             description: String::from("Audio tools."),
384             function_pointer: CommandHandler::cmd_media,
385         },
386     );
387     command_options.insert(
388         String::from("quit"),
389         CommandOption {
390             rules: vec![String::from("quit")],
391             description: String::from("Quit out of the interactive shell."),
392             function_pointer: _noop,
393         },
394     );
395     command_options.insert(
396         String::from("dumpsys"),
397         CommandOption {
398             rules: vec![String::from("dumpsys")],
399             description: String::from("Get diagnostic output."),
400             function_pointer: CommandHandler::cmd_dumpsys,
401         },
402     );
403     command_options.insert(
404         String::from("log"),
405         CommandOption {
406             rules: vec![
407                 String::from("log set-level <info|debug|verbose>"),
408                 String::from("log get-level"),
409             ],
410             description: String::from("Get/set log level"),
411             function_pointer: CommandHandler::cmd_log,
412         },
413     );
414     command_options
415 }
416 
417 // Helper to index a vector safely. The same as `args.get(i)` but converts the None into a
418 // CommandError::InvalidArgs.
419 //
420 // Use this to safely index an argument and conveniently return the error if the argument does not
421 // exist.
get_arg<I>( args: &[String], index: I, ) -> Result<&<I as SliceIndex<[String]>>::Output, CommandError> where I: SliceIndex<[String]>,422 fn get_arg<I>(
423     args: &[String],
424     index: I,
425 ) -> Result<&<I as SliceIndex<[String]>>::Output, CommandError>
426 where
427     I: SliceIndex<[String]>,
428 {
429     args.get(index).ok_or(CommandError::InvalidArgs)
430 }
431 
432 impl CommandHandler {
433     /// Creates a new CommandHandler.
new(context: Arc<Mutex<ClientContext>>) -> CommandHandler434     pub fn new(context: Arc<Mutex<ClientContext>>) -> CommandHandler {
435         CommandHandler { context, command_options: build_commands() }
436     }
437 
438     /// Entry point for command and arguments
process_cmd_line(&mut self, command: &str, args: &[String]) -> bool439     pub fn process_cmd_line(&mut self, command: &str, args: &[String]) -> bool {
440         // Ignore empty line
441         match command {
442             "" => false,
443             _ => match self.command_options.get(command) {
444                 Some(cmd) => {
445                     let rules = cmd.rules.clone();
446                     match (cmd.function_pointer)(self, args) {
447                         Ok(()) => true,
448                         Err(CommandError::InvalidArgs) => {
449                             print_error!("Invalid arguments. Usage:\n{}", rules.join("\n"));
450                             false
451                         }
452                         Err(CommandError::Failed(msg)) => {
453                             print_error!("Command failed: {}", msg);
454                             false
455                         }
456                     }
457                 }
458                 None => {
459                     println!("'{}' is an invalid command!", command);
460                     self.cmd_help(args).ok();
461                     false
462                 }
463             },
464         }
465     }
466 
lock_context(&self) -> std::sync::MutexGuard<ClientContext>467     fn lock_context(&self) -> std::sync::MutexGuard<ClientContext> {
468         self.context.lock().unwrap()
469     }
470 
471     // Common message for when the adapter isn't ready
adapter_not_ready(&self) -> CommandError472     fn adapter_not_ready(&self) -> CommandError {
473         format!(
474             "Default adapter {} is not enabled. Enable the adapter before using this command.",
475             self.lock_context().default_adapter
476         )
477         .into()
478     }
479 
cmd_help(&mut self, args: &[String]) -> CommandResult480     fn cmd_help(&mut self, args: &[String]) -> CommandResult {
481         if let Some(command) = args.first() {
482             match self.command_options.get(command) {
483                 Some(cmd) => {
484                     println!(
485                         "\n{}{}\n{}{}\n",
486                         INDENT_CHAR.repeat(4),
487                         command,
488                         INDENT_CHAR.repeat(8),
489                         cmd.description
490                     );
491                 }
492                 None => {
493                     println!("'{}' is an invalid command!", command);
494                     self.cmd_help(&[]).ok();
495                 }
496             }
497         } else {
498             // Build equals bar and Shave off sides
499             let equal_bar = format!(" {} ", BAR1_CHAR.repeat(MAX_MENU_CHAR_WIDTH));
500 
501             // Build empty bar and Shave off sides
502             let empty_bar = format!("|{}|", INDENT_CHAR.repeat(MAX_MENU_CHAR_WIDTH));
503 
504             // Header
505             println!(
506                 "\n{}\n{}\n+{}+\n{}",
507                 equal_bar,
508                 wrap_help_text("Help Menu", MAX_MENU_CHAR_WIDTH, 2),
509                 // Minus bar
510                 BAR2_CHAR.repeat(MAX_MENU_CHAR_WIDTH),
511                 empty_bar
512             );
513 
514             // Print commands
515             for (key, val) in self.command_options.iter() {
516                 println!(
517                     "{}\n{}\n{}",
518                     wrap_help_text(key, MAX_MENU_CHAR_WIDTH, 4),
519                     wrap_help_text(&val.description, MAX_MENU_CHAR_WIDTH, 8),
520                     empty_bar
521                 );
522             }
523 
524             // Footer
525             println!("{}\n{}", empty_bar, equal_bar);
526         }
527 
528         Ok(())
529     }
530 
cmd_adapter(&mut self, args: &[String]) -> CommandResult531     fn cmd_adapter(&mut self, args: &[String]) -> CommandResult {
532         if !self.lock_context().manager_dbus.get_floss_enabled() {
533             return Err("Floss is not enabled. First run, `floss enable`".into());
534         }
535 
536         let default_adapter = self.lock_context().default_adapter;
537 
538         let command = get_arg(args, 0)?;
539 
540         if matches!(&command[..], "show" | "discoverable" | "connectable" | "set-name") {
541             if !self.lock_context().adapter_ready {
542                 return Err(self.adapter_not_ready());
543             }
544         }
545 
546         match &command[..] {
547             "enable" => {
548                 if self.lock_context().is_restricted {
549                     return Err("You are not allowed to toggle adapter power".into());
550                 }
551                 self.lock_context().manager_dbus.start(default_adapter);
552             }
553             "disable" => {
554                 if self.lock_context().is_restricted {
555                     return Err("You are not allowed to toggle adapter power".into());
556                 }
557                 self.lock_context().manager_dbus.stop(default_adapter);
558             }
559             "show" => {
560                 let enabled = self.lock_context().enabled;
561                 let address = self.lock_context().adapter_address.unwrap_or_default();
562                 let context = self.lock_context();
563                 let adapter_dbus = context.adapter_dbus.as_ref().unwrap();
564                 let qa_dbus = context.qa_dbus.as_ref().unwrap();
565                 let name = adapter_dbus.get_name();
566                 let modalias = qa_dbus.get_modalias();
567                 let uuids = adapter_dbus.get_uuids();
568                 let is_discoverable = adapter_dbus.get_discoverable();
569                 let discoverable_timeout = adapter_dbus.get_discoverable_timeout();
570                 let cod = adapter_dbus.get_bluetooth_class();
571                 let multi_adv_supported = adapter_dbus.is_multi_advertisement_supported();
572                 let le_ext_adv_supported = adapter_dbus.is_le_extended_advertising_supported();
573                 let wbs_supported = adapter_dbus.is_wbs_supported();
574                 let le_audio_supported = adapter_dbus.is_le_audio_supported();
575                 let supported_profiles = UuidHelper::get_supported_profiles();
576                 let connected_profiles: Vec<(Profile, ProfileConnectionState)> = supported_profiles
577                     .iter()
578                     .map(|&prof| {
579                         if let Some(&uuid) = UuidHelper::get_profile_uuid(&prof) {
580                             (prof, adapter_dbus.get_profile_connection_state(uuid))
581                         } else {
582                             (prof, ProfileConnectionState::Disconnected)
583                         }
584                     })
585                     .filter(|(_prof, state)| state != &ProfileConnectionState::Disconnected)
586                     .collect();
587                 qa_dbus.fetch_connectable();
588                 qa_dbus.fetch_alias();
589                 qa_dbus.fetch_discoverable_mode();
590                 print_info!("Address: {}", address.to_string());
591                 print_info!("Name: {}", name);
592                 print_info!("Modalias: {}", modalias);
593                 print_info!("State: {}", if enabled { "enabled" } else { "disabled" });
594                 print_info!("Discoverable: {}", is_discoverable);
595                 print_info!("DiscoverableTimeout: {}s", discoverable_timeout);
596                 print_info!("Class: {:#06x}", cod);
597                 print_info!("IsMultiAdvertisementSupported: {}", multi_adv_supported);
598                 print_info!("IsLeExtendedAdvertisingSupported: {}", le_ext_adv_supported);
599                 print_info!("Connected profiles: {:?}", connected_profiles);
600                 print_info!("IsWbsSupported: {}", wbs_supported);
601                 print_info!("IsLeAudioSupported: {}", le_audio_supported);
602                 print_info!(
603                     "Uuids: {}",
604                     DisplayList(
605                         uuids
606                             .iter()
607                             .map(|&x| UuidHelper::known_uuid_to_string(&x))
608                             .collect::<Vec<String>>()
609                     )
610                 );
611             }
612             "discoverable" => match &get_arg(args, 1)?[..] {
613                 "on" => {
614                     let duration = String::from(get_arg(args, 2)?)
615                         .parse::<u32>()
616                         .or(Err("Failed parsing duration."))?;
617 
618                     let discoverable = self
619                         .lock_context()
620                         .adapter_dbus
621                         .as_mut()
622                         .unwrap()
623                         .set_discoverable(BtDiscMode::GeneralDiscoverable, duration);
624                     print_info!(
625                         "Set discoverable for {} seconds: {}",
626                         duration,
627                         if discoverable { "succeeded" } else { "failed" }
628                     );
629                 }
630                 "limited" => {
631                     let duration = String::from(get_arg(args, 2)?)
632                         .parse::<u32>()
633                         .or(Err("Failed parsing duration."))?;
634 
635                     let discoverable = self
636                         .lock_context()
637                         .adapter_dbus
638                         .as_mut()
639                         .unwrap()
640                         .set_discoverable(BtDiscMode::LimitedDiscoverable, duration);
641                     print_info!(
642                         "Set limited discoverable for {} seconds: {}",
643                         duration,
644                         if discoverable { "succeeded" } else { "failed" }
645                     );
646                 }
647                 "off" => {
648                     let discoverable = self
649                         .lock_context()
650                         .adapter_dbus
651                         .as_mut()
652                         .unwrap()
653                         .set_discoverable(BtDiscMode::NonDiscoverable, 0 /*not used*/);
654                     print_info!(
655                         "Turn discoverable off: {}",
656                         if discoverable { "succeeded" } else { "failed" }
657                     );
658                 }
659                 other => println!("Invalid argument for adapter discoverable '{}'", other),
660             },
661             "connectable" => match &get_arg(args, 1)?[..] {
662                 "on" => {
663                     self.lock_context().qa_dbus.as_mut().unwrap().set_connectable(true);
664                 }
665                 "off" => {
666                     self.lock_context().qa_dbus.as_mut().unwrap().set_connectable(false);
667                 }
668                 other => println!("Invalid argument for adapter connectable '{}'", other),
669             },
670             "set-name" => {
671                 if let Some(name) = args.get(1) {
672                     self.lock_context().adapter_dbus.as_ref().unwrap().set_name(name.to_string());
673                 } else {
674                     println!("usage: adapter set-name <name>");
675                 }
676             }
677 
678             _ => return Err(CommandError::InvalidArgs),
679         };
680 
681         Ok(())
682     }
683 
cmd_get_address(&mut self, _args: &[String]) -> CommandResult684     fn cmd_get_address(&mut self, _args: &[String]) -> CommandResult {
685         if !self.lock_context().adapter_ready {
686             return Err(self.adapter_not_ready());
687         }
688 
689         let address = self.lock_context().update_adapter_address();
690         print_info!("Local address = {}", address.to_string());
691         Ok(())
692     }
693 
cmd_discovery(&mut self, args: &[String]) -> CommandResult694     fn cmd_discovery(&mut self, args: &[String]) -> CommandResult {
695         if !self.lock_context().adapter_ready {
696             return Err(self.adapter_not_ready());
697         }
698 
699         let command = get_arg(args, 0)?;
700 
701         match &command[..] {
702             "start" => {
703                 self.lock_context().adapter_dbus.as_mut().unwrap().start_discovery();
704             }
705             "stop" => {
706                 self.lock_context().adapter_dbus.as_mut().unwrap().cancel_discovery();
707             }
708             _ => return Err(CommandError::InvalidArgs),
709         }
710 
711         Ok(())
712     }
713 
cmd_battery(&mut self, args: &[String]) -> CommandResult714     fn cmd_battery(&mut self, args: &[String]) -> CommandResult {
715         if !self.lock_context().adapter_ready {
716             return Err(self.adapter_not_ready());
717         }
718 
719         let command = get_arg(args, 0)?;
720         let addr = RawAddress::from_string(get_arg(args, 1)?).ok_or("Invalid Address")?;
721         let address = addr.to_string();
722 
723         match &command[..] {
724             "status" => {
725                 match self
726                     .lock_context()
727                     .battery_manager_dbus
728                     .as_ref()
729                     .unwrap()
730                     .get_battery_information(addr)
731                 {
732                     None => println!("Battery status for device {} could not be fetched", address),
733                     Some(set) => {
734                         if set.batteries.is_empty() {
735                             println!("Battery set for device {} is empty", set.address.to_string());
736                             return Ok(());
737                         }
738 
739                         println!(
740                             "Battery data for '{}' from source '{}' and uuid '{}':",
741                             set.address.to_string(),
742                             set.source_uuid.clone(),
743                             set.source_info.clone()
744                         );
745                         for battery in set.batteries {
746                             println!("   {}%, variant: '{}'", battery.percentage, battery.variant);
747                         }
748                     }
749                 }
750             }
751             "track" => {
752                 if self.lock_context().battery_address_filter.contains(&address) {
753                     println!("Already tracking {}", address);
754                     return Ok(());
755                 }
756                 self.lock_context().battery_address_filter.insert(address);
757 
758                 println!("Currently tracking:");
759                 for addr in self.lock_context().battery_address_filter.iter() {
760                     println!("{}", addr);
761                 }
762             }
763             "untrack" => {
764                 if !self.lock_context().battery_address_filter.remove(&address) {
765                     println!("Not tracking {}", address);
766                     return Ok(());
767                 }
768                 println!("Stopped tracking {}", address);
769 
770                 if self.lock_context().battery_address_filter.is_empty() {
771                     println!("No longer tracking any addresses for battery status updates");
772                     return Ok(());
773                 }
774 
775                 println!("Currently tracking:");
776                 for addr in self.lock_context().battery_address_filter.iter() {
777                     println!("{}", addr);
778                 }
779             }
780             _ => return Err(CommandError::InvalidArgs),
781         }
782         Ok(())
783     }
784 
cmd_bond(&mut self, args: &[String]) -> CommandResult785     fn cmd_bond(&mut self, args: &[String]) -> CommandResult {
786         if !self.lock_context().adapter_ready {
787             return Err(self.adapter_not_ready());
788         }
789 
790         let command = get_arg(args, 0)?;
791 
792         match &command[..] {
793             "add" => {
794                 let device = BluetoothDevice {
795                     address: RawAddress::from_string(get_arg(args, 1)?).ok_or("Invalid Address")?,
796                     name: String::from("Classic Device"),
797                 };
798 
799                 let bonding_attempt = &self.lock_context().bonding_attempt.as_ref().cloned();
800 
801                 if bonding_attempt.is_some() {
802                     return Err(format!(
803                         "Already bonding [{}]. Cancel bonding first.",
804                         bonding_attempt.as_ref().unwrap().address.to_string(),
805                     )
806                     .into());
807                 }
808 
809                 let status = self
810                     .lock_context()
811                     .adapter_dbus
812                     .as_mut()
813                     .unwrap()
814                     .create_bond(device.clone(), BtTransport::Auto);
815 
816                 if status == BtStatus::Success {
817                     self.lock_context().bonding_attempt = Some(device);
818                 }
819             }
820             "remove" => {
821                 let device = BluetoothDevice {
822                     address: RawAddress::from_string(get_arg(args, 1)?).ok_or("Invalid Address")?,
823                     name: String::from("Classic Device"),
824                 };
825 
826                 self.lock_context().adapter_dbus.as_mut().unwrap().remove_bond(device);
827             }
828             "cancel" => {
829                 let device = BluetoothDevice {
830                     address: RawAddress::from_string(get_arg(args, 1)?).ok_or("Invalid Address")?,
831                     name: String::from("Classic Device"),
832                 };
833 
834                 self.lock_context().adapter_dbus.as_mut().unwrap().cancel_bond_process(device);
835             }
836             other => {
837                 println!("Invalid argument '{}'", other);
838             }
839         }
840 
841         Ok(())
842     }
843 
cmd_device(&mut self, args: &[String]) -> CommandResult844     fn cmd_device(&mut self, args: &[String]) -> CommandResult {
845         if !self.lock_context().adapter_ready {
846             return Err(self.adapter_not_ready());
847         }
848 
849         let command = &get_arg(args, 0)?;
850 
851         match &command[..] {
852             "connect" => {
853                 let device = BluetoothDevice {
854                     address: RawAddress::from_string(get_arg(args, 1)?).ok_or("Invalid Address")?,
855                     name: String::from("Classic Device"),
856                 };
857 
858                 let status = self
859                     .lock_context()
860                     .adapter_dbus
861                     .as_mut()
862                     .unwrap()
863                     .connect_all_enabled_profiles(device.clone());
864 
865                 if status == BtStatus::Success {
866                     println!("Connecting to {}", &device.address.to_string());
867                 } else {
868                     println!("Can't connect to {}", &device.address.to_string());
869                 }
870             }
871             "disconnect" => {
872                 let device = BluetoothDevice {
873                     address: RawAddress::from_string(get_arg(args, 1)?).ok_or("Invalid Address")?,
874                     name: String::from("Classic Device"),
875                 };
876 
877                 let success = self
878                     .lock_context()
879                     .adapter_dbus
880                     .as_mut()
881                     .unwrap()
882                     .disconnect_all_enabled_profiles(device.clone());
883 
884                 if success {
885                     println!("Disconnecting from {}", &device.address.to_string());
886                 } else {
887                     println!("Can't disconnect from {}", &device.address.to_string());
888                 }
889             }
890             "info" => {
891                 let device = BluetoothDevice {
892                     address: RawAddress::from_string(get_arg(args, 1)?).ok_or("Invalid Address")?,
893                     name: String::from("Classic Device"),
894                 };
895 
896                 let (
897                     name,
898                     alias,
899                     device_type,
900                     addr_type,
901                     class,
902                     appearance,
903                     modalias,
904                     bonded,
905                     connection_state,
906                     uuids,
907                     wake_allowed,
908                     dual_mode_audio,
909                 ) = {
910                     let ctx = self.lock_context();
911                     let adapter = ctx.adapter_dbus.as_ref().unwrap();
912 
913                     let name = adapter.get_remote_name(device.clone());
914                     let device_type = adapter.get_remote_type(device.clone());
915                     let addr_type = adapter.get_remote_address_type(device.clone());
916                     let alias = adapter.get_remote_alias(device.clone());
917                     let class = adapter.get_remote_class(device.clone());
918                     let appearance = adapter.get_remote_appearance(device.clone());
919                     let modalias =
920                         adapter.get_remote_vendor_product_info(device.clone()).to_string();
921                     let bonded = adapter.get_bond_state(device.clone());
922                     let connection_state = match adapter.get_connection_state(device.clone()) {
923                         BtConnectionState::NotConnected => "Not Connected",
924                         BtConnectionState::ConnectedOnly => "Connected",
925                         _ => "Connected and Paired",
926                     };
927                     let uuids = adapter.get_remote_uuids(device.clone());
928                     let wake_allowed = adapter.get_remote_wake_allowed(device.clone());
929                     let dual_mode_audio = adapter.is_dual_mode_audio_sink_device(device.clone());
930 
931                     (
932                         name,
933                         alias,
934                         device_type,
935                         addr_type,
936                         class,
937                         appearance,
938                         modalias,
939                         bonded,
940                         connection_state,
941                         uuids,
942                         wake_allowed,
943                         dual_mode_audio,
944                     )
945                 };
946 
947                 print_info!("Address: {}", &device.address.to_string());
948                 print_info!("Name: {}", name);
949                 print_info!("Alias: {}", alias);
950                 print_info!("Device Type: {:?}", device_type);
951                 print_info!("Address Type: {:?}", addr_type);
952                 print_info!("Class: {}", class);
953                 print_info!("Appearance: {}", appearance);
954                 print_info!("Modalias: {}", modalias);
955                 print_info!("Wake Allowed: {}", wake_allowed);
956                 print_info!("Bond State: {:?}", bonded);
957                 print_info!("Connection State: {}", connection_state);
958                 print_info!("Dual Mode Audio Device: {}", dual_mode_audio);
959                 print_info!(
960                     "Uuids: {}",
961                     DisplayList(
962                         uuids
963                             .iter()
964                             .map(|&x| UuidHelper::known_uuid_to_string(&x))
965                             .collect::<Vec<String>>()
966                     )
967                 );
968             }
969             "set-alias" => {
970                 let new_alias = get_arg(args, 2)?;
971                 let device = BluetoothDevice {
972                     address: RawAddress::from_string(get_arg(args, 1)?).ok_or("Invalid Address")?,
973                     name: String::from(""),
974                 };
975                 let old_alias = self
976                     .lock_context()
977                     .adapter_dbus
978                     .as_ref()
979                     .unwrap()
980                     .get_remote_alias(device.clone());
981                 println!(
982                     "Updating alias for {}: {} -> {}",
983                     get_arg(args, 1)?,
984                     old_alias,
985                     new_alias
986                 );
987                 self.lock_context()
988                     .adapter_dbus
989                     .as_mut()
990                     .unwrap()
991                     .set_remote_alias(device.clone(), new_alias.clone());
992             }
993             "set-pairing-confirmation" => {
994                 let device = BluetoothDevice {
995                     address: RawAddress::from_string(get_arg(args, 1)?).ok_or("Invalid Address")?,
996                     name: String::from(""),
997                 };
998                 let accept = match &get_arg(args, 2)?[..] {
999                     "accept" => true,
1000                     "reject" => false,
1001                     other => {
1002                         return Err(format!("Failed to parse '{}'", other).into());
1003                     }
1004                 };
1005 
1006                 self.lock_context()
1007                     .adapter_dbus
1008                     .as_mut()
1009                     .unwrap()
1010                     .set_pairing_confirmation(device.clone(), accept);
1011             }
1012             "set-pairing-pin" => {
1013                 let device = BluetoothDevice {
1014                     address: RawAddress::from_string(get_arg(args, 1)?).ok_or("Invalid Address")?,
1015                     name: String::from(""),
1016                 };
1017                 let pin = get_arg(args, 2)?;
1018 
1019                 let (accept, pin) = match (&pin[..], pin) {
1020                     ("reject", _) => (false, vec![]),
1021                     (_, p) => (true, p.as_bytes().to_vec()),
1022                 };
1023 
1024                 self.lock_context().adapter_dbus.as_mut().unwrap().set_pin(
1025                     device.clone(),
1026                     accept,
1027                     pin,
1028                 );
1029             }
1030             "set-pairing-passkey" => {
1031                 let device = BluetoothDevice {
1032                     address: RawAddress::from_string(get_arg(args, 1)?).ok_or("Invalid Address")?,
1033                     name: String::from(""),
1034                 };
1035                 let passkey = get_arg(args, 2)?;
1036                 let (accept, passkey) = match (&passkey[..], String::from(passkey).parse::<u32>()) {
1037                     (_, Ok(p)) => (true, Vec::from(p.to_ne_bytes())),
1038                     ("reject", _) => (false, vec![]),
1039                     _ => {
1040                         return Err(format!("Failed to parse '{}'", passkey).into());
1041                     }
1042                 };
1043 
1044                 self.lock_context().adapter_dbus.as_mut().unwrap().set_passkey(
1045                     device.clone(),
1046                     accept,
1047                     passkey,
1048                 );
1049             }
1050             "get-rssi" => {
1051                 let device = BluetoothDevice {
1052                     address: RawAddress::from_string(get_arg(args, 1)?).ok_or("Invalid Address")?,
1053                     name: String::from(""),
1054                 };
1055 
1056                 match self
1057                     .lock_context()
1058                     .adapter_dbus
1059                     .as_mut()
1060                     .unwrap()
1061                     .get_remote_rssi(device.clone())
1062                 {
1063                     INVALID_RSSI => {
1064                         println!("Invalid RSSI");
1065                     }
1066                     rssi => {
1067                         println!("RSSI: {}", rssi);
1068                     }
1069                 };
1070             }
1071             other => {
1072                 println!("Invalid argument '{}'", other);
1073             }
1074         }
1075 
1076         Ok(())
1077     }
1078 
cmd_floss(&mut self, args: &[String]) -> CommandResult1079     fn cmd_floss(&mut self, args: &[String]) -> CommandResult {
1080         let command = get_arg(args, 0)?;
1081 
1082         match &command[..] {
1083             "enable" => {
1084                 self.lock_context().manager_dbus.set_floss_enabled(true);
1085             }
1086             "disable" => {
1087                 self.lock_context().manager_dbus.set_floss_enabled(false);
1088             }
1089             "show" => {
1090                 let (major, minor) = self.lock_context().get_floss_api_version();
1091                 print_info!("Floss API version: {}.{}", major, minor);
1092                 print_info!(
1093                     "Floss enabled: {}",
1094                     self.lock_context().manager_dbus.get_floss_enabled()
1095                 );
1096             }
1097             _ => return Err(CommandError::InvalidArgs),
1098         }
1099 
1100         Ok(())
1101     }
1102 
cmd_gatt(&mut self, args: &[String]) -> CommandResult1103     fn cmd_gatt(&mut self, args: &[String]) -> CommandResult {
1104         if !self.lock_context().adapter_ready {
1105             return Err(self.adapter_not_ready());
1106         }
1107 
1108         let command = get_arg(args, 0)?;
1109 
1110         match &command[..] {
1111             "register-client" => {
1112                 let dbus_connection = self.lock_context().dbus_connection.clone();
1113                 let dbus_crossroads = self.lock_context().dbus_crossroads.clone();
1114 
1115                 self.lock_context().gatt_dbus.as_mut().unwrap().register_client(
1116                     String::from(GATT_CLIENT_APP_UUID),
1117                     Box::new(BtGattCallback::new(
1118                         String::from("/org/chromium/bluetooth/client/bluetooth_gatt_callback"),
1119                         self.context.clone(),
1120                         dbus_connection,
1121                         dbus_crossroads,
1122                     )),
1123                     false,
1124                 );
1125             }
1126             "client-connect" => {
1127                 let client_id = self
1128                     .lock_context()
1129                     .gatt_client_context
1130                     .client_id
1131                     .ok_or("GATT client is not yet registered.")?;
1132 
1133                 let addr = RawAddress::from_string(get_arg(args, 1)?).ok_or("Invalid Address")?;
1134                 let is_direct = self.lock_context().gatt_client_context.is_connect_direct;
1135                 let transport = self.lock_context().gatt_client_context.connect_transport;
1136                 let oppurtunistic = self.lock_context().gatt_client_context.connect_opportunistic;
1137                 let phy = self.lock_context().gatt_client_context.connect_phy;
1138 
1139                 println!("Initiating GATT client connect. client_id: {}, addr: {}, is_direct: {}, transport: {:?}, oppurtunistic: {}, phy: {:?}", client_id, addr.to_string(), is_direct, transport, oppurtunistic, phy);
1140                 self.lock_context().gatt_dbus.as_ref().unwrap().client_connect(
1141                     client_id,
1142                     addr,
1143                     is_direct,
1144                     transport,
1145                     oppurtunistic,
1146                     phy,
1147                 );
1148             }
1149             "client-disconnect" => {
1150                 let client_id = self
1151                     .lock_context()
1152                     .gatt_client_context
1153                     .client_id
1154                     .ok_or("GATT client is not yet registered.")?;
1155 
1156                 let addr = RawAddress::from_string(get_arg(args, 1)?).ok_or("Invalid Address")?;
1157                 self.lock_context().gatt_dbus.as_ref().unwrap().client_disconnect(client_id, addr);
1158             }
1159             "client-read-phy" => {
1160                 let client_id = self
1161                     .lock_context()
1162                     .gatt_client_context
1163                     .client_id
1164                     .ok_or("GATT client is not yet registered.")?;
1165                 let addr = RawAddress::from_string(get_arg(args, 1)?).ok_or("Invalid Address")?;
1166                 self.lock_context().gatt_dbus.as_mut().unwrap().client_read_phy(client_id, addr);
1167             }
1168             "client-discover-services" => {
1169                 let client_id = self
1170                     .lock_context()
1171                     .gatt_client_context
1172                     .client_id
1173                     .ok_or("GATT client is not yet registered.")?;
1174 
1175                 let addr = RawAddress::from_string(get_arg(args, 1)?).ok_or("Invalid Address")?;
1176                 self.lock_context().gatt_dbus.as_ref().unwrap().discover_services(client_id, addr);
1177             }
1178             "client-discover-service-by-uuid-pts" => {
1179                 let client_id = self
1180                     .lock_context()
1181                     .gatt_client_context
1182                     .client_id
1183                     .ok_or("GATT client is not yet registered.")?;
1184                 let addr = RawAddress::from_string(get_arg(args, 1)?).ok_or("Invalid Address")?;
1185                 let uuid = String::from(get_arg(args, 2)?);
1186                 self.lock_context()
1187                     .gatt_dbus
1188                     .as_ref()
1189                     .unwrap()
1190                     .btif_gattc_discover_service_by_uuid(client_id, addr, uuid);
1191             }
1192             "configure-mtu" => {
1193                 let client_id = self
1194                     .lock_context()
1195                     .gatt_client_context
1196                     .client_id
1197                     .ok_or("GATT client is not yet registered.")?;
1198 
1199                 let addr = RawAddress::from_string(get_arg(args, 1)?).ok_or("Invalid Address")?;
1200                 let mtu =
1201                     String::from(get_arg(args, 2)?).parse::<i32>().or(Err("Failed parsing mtu"))?;
1202 
1203                 self.lock_context().gatt_dbus.as_ref().unwrap().configure_mtu(client_id, addr, mtu)
1204             }
1205             "set-direct-connect" => {
1206                 let is_direct = String::from(get_arg(args, 1)?)
1207                     .parse::<bool>()
1208                     .or(Err("Failed to parse is_direct"))?;
1209 
1210                 self.lock_context().gatt_client_context.is_connect_direct = is_direct;
1211             }
1212             "set-connect-transport" => {
1213                 let transport = match &get_arg(args, 1)?[..] {
1214                     "Bredr" => BtTransport::Bredr,
1215                     "LE" => BtTransport::Le,
1216                     "Auto" => BtTransport::Auto,
1217                     _ => {
1218                         return Err("Failed to parse transport".into());
1219                     }
1220                 };
1221                 self.lock_context().gatt_client_context.connect_transport = transport;
1222             }
1223             "set-connect-opportunistic" => {
1224                 let opportunistic = String::from(get_arg(args, 1)?)
1225                     .parse::<bool>()
1226                     .or(Err("Failed to parse opportunistic"))?;
1227 
1228                 self.lock_context().gatt_client_context.connect_opportunistic = opportunistic;
1229             }
1230             "set-connect-phy" => {
1231                 let phy = match &get_arg(args, 1)?[..] {
1232                     "Phy1m" => LePhy::Phy1m,
1233                     "Phy2m" => LePhy::Phy2m,
1234                     "PhyCoded" => LePhy::PhyCoded,
1235                     _ => {
1236                         return Err("Failed to parse phy".into());
1237                     }
1238                 };
1239 
1240                 self.lock_context().gatt_client_context.connect_phy = phy;
1241             }
1242             "set-auth-req" => {
1243                 let flag = match &get_arg(args, 1)?[..] {
1244                     "NONE" => AuthReq::NoEnc,
1245                     "EncNoMitm" => AuthReq::EncNoMitm,
1246                     "EncMitm" => AuthReq::EncMitm,
1247                     "SignedNoMitm" => AuthReq::SignedNoMitm,
1248                     "SignedMitm" => AuthReq::SignedMitm,
1249                     _ => {
1250                         return Err("Failed to parse auth-req".into());
1251                     }
1252                 };
1253 
1254                 self.lock_context().gatt_client_context.auth_req = flag;
1255                 println!("AuthReq: {:?}", self.lock_context().gatt_client_context.get_auth_req());
1256             }
1257             "write-characteristic" => {
1258                 let addr = RawAddress::from_string(get_arg(args, 1)?).ok_or("Invalid Address")?;
1259                 let handle = String::from(get_arg(args, 2)?)
1260                     .parse::<i32>()
1261                     .or(Err("Failed to parse handle"))?;
1262 
1263                 let write_type = match &get_arg(args, 3)?[..] {
1264                     "NoRsp" => GattWriteType::WriteNoRsp,
1265                     "Write" => GattWriteType::Write,
1266                     "Prepare" => GattWriteType::WritePrepare,
1267                     _ => {
1268                         return Err("Failed to parse write-type".into());
1269                     }
1270                 };
1271 
1272                 let value = hex::decode(get_arg(args, 4)?).or(Err("Failed to parse value"))?;
1273 
1274                 let client_id = self
1275                     .lock_context()
1276                     .gatt_client_context
1277                     .client_id
1278                     .ok_or("GATT client is not yet registered.")?;
1279 
1280                 let auth_req = self.lock_context().gatt_client_context.get_auth_req().into();
1281 
1282                 self.lock_context()
1283                     .gatt_dbus
1284                     .as_mut()
1285                     .unwrap()
1286                     .write_characteristic(client_id, addr, handle, write_type, auth_req, value);
1287             }
1288             "read-characteristic" => {
1289                 let addr = RawAddress::from_string(get_arg(args, 1)?).ok_or("Invalid Address")?;
1290                 let handle = String::from(get_arg(args, 2)?)
1291                     .parse::<i32>()
1292                     .or(Err("Failed to parse handle"))?;
1293                 let client_id = self
1294                     .lock_context()
1295                     .gatt_client_context
1296                     .client_id
1297                     .ok_or("GATT client is not yet registered.")?;
1298 
1299                 let auth_req = self.lock_context().gatt_client_context.get_auth_req().into();
1300 
1301                 self.lock_context()
1302                     .gatt_dbus
1303                     .as_ref()
1304                     .unwrap()
1305                     .read_characteristic(client_id, addr, handle, auth_req);
1306             }
1307             "read-characteristic-by-uuid" => {
1308                 let addr = RawAddress::from_string(get_arg(args, 1)?).ok_or("Invalid Address")?;
1309                 let uuid = String::from(get_arg(args, 2)?);
1310                 let start_handle = String::from(get_arg(args, 3)?)
1311                     .parse::<i32>()
1312                     .or(Err("Failed to parse start handle"))?;
1313                 let end_handle = String::from(get_arg(args, 4)?)
1314                     .parse::<i32>()
1315                     .or(Err("Failed to parse end handle"))?;
1316 
1317                 let client_id = self
1318                     .lock_context()
1319                     .gatt_client_context
1320                     .client_id
1321                     .ok_or("GATT client is not yet registered.")?;
1322 
1323                 let auth_req = self.lock_context().gatt_client_context.get_auth_req().into();
1324 
1325                 self.lock_context().gatt_dbus.as_ref().unwrap().read_using_characteristic_uuid(
1326                     client_id,
1327                     addr,
1328                     uuid,
1329                     start_handle,
1330                     end_handle,
1331                     auth_req,
1332                 );
1333             }
1334             "register-notification" => {
1335                 let addr = RawAddress::from_string(get_arg(args, 1)?).ok_or("Invalid Address")?;
1336                 let handle = String::from(get_arg(args, 2)?)
1337                     .parse::<i32>()
1338                     .or(Err("Failed to parse handle"))?;
1339                 let enable = match &get_arg(args, 3)?[..] {
1340                     "enable" => true,
1341                     "disable" => false,
1342                     _ => {
1343                         return Err("Failed to parse enable".into());
1344                     }
1345                 };
1346 
1347                 let client_id = self
1348                     .lock_context()
1349                     .gatt_client_context
1350                     .client_id
1351                     .ok_or("GATT client is not yet registered.")?;
1352 
1353                 self.lock_context()
1354                     .gatt_dbus
1355                     .as_ref()
1356                     .unwrap()
1357                     .register_for_notification(client_id, addr, handle, enable);
1358             }
1359             "register-server" => {
1360                 let dbus_connection = self.lock_context().dbus_connection.clone();
1361                 let dbus_crossroads = self.lock_context().dbus_crossroads.clone();
1362 
1363                 self.lock_context().gatt_dbus.as_mut().unwrap().register_server(
1364                     String::from(GATT_SERVER_APP_UUID),
1365                     Box::new(BtGattServerCallback::new(
1366                         String::from(
1367                             "/org/chromium/bluetooth/client/bluetooth_gatt_server_callback",
1368                         ),
1369                         self.context.clone(),
1370                         dbus_connection,
1371                         dbus_crossroads,
1372                     )),
1373                     false,
1374                 );
1375             }
1376             "unregister-server" => {
1377                 let server_id = String::from(get_arg(args, 1)?)
1378                     .parse::<i32>()
1379                     .or(Err("Failed parsing server id"))?;
1380 
1381                 self.lock_context().gatt_dbus.as_mut().unwrap().unregister_server(server_id);
1382             }
1383             "server-connect" => {
1384                 let server_id = String::from(get_arg(args, 1)?)
1385                     .parse::<i32>()
1386                     .or(Err("Failed to parse server_id"))?;
1387                 let client_addr =
1388                     RawAddress::from_string(get_arg(args, 2)?).ok_or("Invalid Address")?;
1389                 let is_direct = self.lock_context().gatt_server_context.is_connect_direct;
1390                 let transport = self.lock_context().gatt_server_context.connect_transport;
1391 
1392                 if !self.lock_context().gatt_dbus.as_mut().unwrap().server_connect(
1393                     server_id,
1394                     client_addr,
1395                     is_direct,
1396                     transport,
1397                 ) {
1398                     return Err("Connection was unsuccessful".into());
1399                 }
1400             }
1401             "server-disconnect" => {
1402                 let server_id = String::from(get_arg(args, 1)?)
1403                     .parse::<i32>()
1404                     .or(Err("Failed to parse server_id"))?;
1405                 let client_addr =
1406                     RawAddress::from_string(get_arg(args, 2)?).ok_or("Invalid Address")?;
1407 
1408                 if !self
1409                     .lock_context()
1410                     .gatt_dbus
1411                     .as_mut()
1412                     .unwrap()
1413                     .server_disconnect(server_id, client_addr)
1414                 {
1415                     return Err("Disconnection was unsuccessful".into());
1416                 }
1417             }
1418             "server-add-basic-service" => {
1419                 let service_uuid = Uuid::from_string(BATTERY_SERVICE_UUID).unwrap();
1420 
1421                 let server_id = String::from(get_arg(args, 1)?)
1422                     .parse::<i32>()
1423                     .or(Err("Failed to parse server_id"))?;
1424 
1425                 let service = BluetoothGattService::new(
1426                     service_uuid,
1427                     0, // libbluetooth assigns this handle once the service is added
1428                     GattDbElementType::PrimaryService.into(),
1429                 );
1430 
1431                 self.lock_context().gatt_dbus.as_mut().unwrap().add_service(server_id, service);
1432             }
1433             "server-add-service" => {
1434                 let service_uuid = Uuid::from_string(HEART_RATE_SERVICE_UUID).unwrap();
1435                 let characteristic_uuid = Uuid::from_string(HEART_RATE_MEASUREMENT_UUID).unwrap();
1436                 let descriptor_uuid = Uuid::from_string(GENERIC_UUID).unwrap();
1437                 let ccc_descriptor_uuid = Uuid::from_string(CCC_DESCRIPTOR_UUID).unwrap();
1438                 let included_service_uuid = Uuid::from_string(BATTERY_SERVICE_UUID).unwrap();
1439 
1440                 let server_id = String::from(get_arg(args, 1)?)
1441                     .parse::<i32>()
1442                     .or(Err("Failed to parse server_id"))?;
1443                 let included_service_instance_id =
1444                     String::from(get_arg(args, 2)?)
1445                         .parse::<i32>()
1446                         .or(Err("Failed to parse included service instance id"))?;
1447 
1448                 let mut service = BluetoothGattService::new(
1449                     service_uuid,
1450                     0,
1451                     GattDbElementType::PrimaryService.into(),
1452                 );
1453                 let included_service = BluetoothGattService::new(
1454                     included_service_uuid,
1455                     included_service_instance_id,
1456                     GattDbElementType::IncludedService.into(),
1457                 );
1458                 let mut characteristic = BluetoothGattCharacteristic::new(
1459                     characteristic_uuid,
1460                     0,
1461                     BluetoothGattCharacteristic::PROPERTY_READ
1462                         | BluetoothGattCharacteristic::PROPERTY_WRITE
1463                         | BluetoothGattCharacteristic::PROPERTY_NOTIFY,
1464                     BluetoothGattCharacteristic::PERMISSION_READ
1465                         | BluetoothGattCharacteristic::PERMISSION_WRITE,
1466                 );
1467                 let descriptor = BluetoothGattDescriptor::new(
1468                     descriptor_uuid,
1469                     0,
1470                     BluetoothGattCharacteristic::PERMISSION_READ
1471                         | BluetoothGattCharacteristic::PERMISSION_WRITE,
1472                 );
1473                 let ccc_descriptor = BluetoothGattDescriptor::new(
1474                     ccc_descriptor_uuid,
1475                     0,
1476                     BluetoothGattCharacteristic::PERMISSION_READ
1477                         | BluetoothGattCharacteristic::PERMISSION_WRITE,
1478                 );
1479 
1480                 service.included_services.push(included_service);
1481                 characteristic.descriptors.push(ccc_descriptor);
1482                 characteristic.descriptors.push(descriptor);
1483                 service.characteristics.push(characteristic);
1484 
1485                 self.lock_context().gatt_dbus.as_mut().unwrap().add_service(server_id, service);
1486             }
1487             "server-remove-service" => {
1488                 let server_id = String::from(get_arg(args, 1)?)
1489                     .parse::<i32>()
1490                     .or(Err("Failed to parse server_id"))?;
1491                 let service_handle = String::from(get_arg(args, 1)?)
1492                     .parse::<i32>()
1493                     .or(Err("Failed to parse service handle"))?;
1494 
1495                 self.lock_context()
1496                     .gatt_dbus
1497                     .as_mut()
1498                     .unwrap()
1499                     .remove_service(server_id, service_handle);
1500             }
1501             "server-clear-all-services" => {
1502                 let server_id = String::from(get_arg(args, 1)?)
1503                     .parse::<i32>()
1504                     .or(Err("Failed to parse server_id"))?;
1505                 self.lock_context().gatt_dbus.as_mut().unwrap().clear_services(server_id);
1506             }
1507             "server-send-response" => {
1508                 let server_id = String::from(get_arg(args, 1)?)
1509                     .parse::<i32>()
1510                     .or(Err("Failed to parse server_id"))?;
1511                 let status = match String::from(get_arg(args, 2)?).as_str() {
1512                     "success" => GattStatus::Success,
1513                     "fail" => GattStatus::Error,
1514                     _ => return Err("{} is not one of the following: `success`, `fail`".into()),
1515                 };
1516 
1517                 let request = match self.lock_context().pending_gatt_request.clone() {
1518                     None => return Err("No pending request to send response to".into()),
1519                     Some(r) => r,
1520                 };
1521                 self.lock_context().gatt_dbus.as_mut().unwrap().send_response(
1522                     server_id,
1523                     request.address,
1524                     request.id,
1525                     status,
1526                     request.offset,
1527                     request.value.clone(),
1528                 );
1529 
1530                 self.lock_context().pending_gatt_request = None;
1531             }
1532             "server-set-direct-connect" => {
1533                 let is_direct = String::from(get_arg(args, 1)?)
1534                     .parse::<bool>()
1535                     .or(Err("Failed to parse is_direct"))?;
1536 
1537                 self.lock_context().gatt_server_context.is_connect_direct = is_direct;
1538             }
1539             "server-set-connect-transport" => {
1540                 let transport = match &get_arg(args, 1)?[..] {
1541                     "Bredr" => BtTransport::Bredr,
1542                     "LE" => BtTransport::Le,
1543                     "Auto" => BtTransport::Auto,
1544                     _ => {
1545                         return Err("Failed to parse transport".into());
1546                     }
1547                 };
1548                 self.lock_context().gatt_server_context.connect_transport = transport;
1549             }
1550             _ => return Err(CommandError::InvalidArgs),
1551         }
1552         Ok(())
1553     }
1554 
cmd_le_scan(&mut self, args: &[String]) -> CommandResult1555     fn cmd_le_scan(&mut self, args: &[String]) -> CommandResult {
1556         if !self.lock_context().adapter_ready {
1557             return Err(self.adapter_not_ready());
1558         }
1559 
1560         let command = get_arg(args, 0)?;
1561 
1562         match &command[..] {
1563             "register-scanner" => {
1564                 let scanner_callback_id = self
1565                     .lock_context()
1566                     .scanner_callback_id
1567                     .ok_or("Cannot register scanner before registering scanner callback")?;
1568 
1569                 let uuid = self
1570                     .lock_context()
1571                     .gatt_dbus
1572                     .as_mut()
1573                     .unwrap()
1574                     .register_scanner(scanner_callback_id);
1575 
1576                 print_info!("Scanner to be registered with UUID = {}", uuid);
1577             }
1578             "unregister-scanner" => {
1579                 let scanner_id = String::from(get_arg(args, 1)?)
1580                     .parse::<u8>()
1581                     .or(Err("Failed parsing scanner id"))?;
1582 
1583                 self.lock_context().gatt_dbus.as_mut().unwrap().unregister_scanner(scanner_id);
1584             }
1585             "start-scan" => {
1586                 let scanner_id = String::from(get_arg(args, 1)?)
1587                     .parse::<u8>()
1588                     .or(Err("Failed parsing scanner id"))?;
1589 
1590                 self.lock_context().gatt_dbus.as_mut().unwrap().start_scan(
1591                     scanner_id,
1592                     // TODO(b/254870159): Construct real settings and filters depending on
1593                     // command line options.
1594                     None,
1595                     Some(btstack::bluetooth_gatt::ScanFilter {
1596                         rssi_high_threshold: 0,
1597                         rssi_low_threshold: 0,
1598                         rssi_low_timeout: 0,
1599                         rssi_sampling_period: 0,
1600                         condition: btstack::bluetooth_gatt::ScanFilterCondition::Patterns(vec![]),
1601                     }),
1602                 );
1603 
1604                 self.lock_context().active_scanner_ids.insert(scanner_id);
1605             }
1606             "stop-scan" => {
1607                 let scanner_id = String::from(get_arg(args, 1)?)
1608                     .parse::<u8>()
1609                     .or(Err("Failed parsing scanner id"))?;
1610 
1611                 self.lock_context().gatt_dbus.as_mut().unwrap().stop_scan(scanner_id);
1612                 self.lock_context().active_scanner_ids.remove(&scanner_id);
1613             }
1614             _ => return Err(CommandError::InvalidArgs),
1615         }
1616 
1617         Ok(())
1618     }
1619 
1620     // TODO(b/233128828): More options will be implemented to test BLE advertising.
1621     // Such as setting advertising parameters, starting multiple advertising sets, etc.
cmd_advertise(&mut self, args: &[String]) -> CommandResult1622     fn cmd_advertise(&mut self, args: &[String]) -> CommandResult {
1623         if !self.lock_context().adapter_ready {
1624             return Err(self.adapter_not_ready());
1625         }
1626 
1627         if self.lock_context().advertiser_callback_id.is_none() {
1628             return Err("No advertiser callback registered".into());
1629         }
1630 
1631         let callback_id = self.lock_context().advertiser_callback_id.unwrap();
1632 
1633         let command = get_arg(args, 0)?;
1634 
1635         match &command[..] {
1636             "on" => {
1637                 print_info!("Creating legacy advertising set...");
1638                 let s = AdvSet::new(true); // legacy advertising
1639                 AdvSet::start(self.context.clone(), s, callback_id);
1640             }
1641             "off" => {
1642                 AdvSet::stop_all(self.context.clone());
1643             }
1644             "ext" => {
1645                 print_info!("Creating extended advertising set...");
1646                 let s = AdvSet::new(false); // extended advertising
1647                 AdvSet::start(self.context.clone(), s, callback_id);
1648             }
1649             "set-interval" => {
1650                 let ms = String::from(get_arg(args, 1)?).parse::<i32>();
1651                 if ms.is_err() {
1652                     return Err("Failed parsing interval".into());
1653                 }
1654                 let interval = ms.unwrap() * 8 / 5; // in 0.625 ms.
1655 
1656                 let mut context = self.lock_context();
1657                 context.adv_sets.iter_mut().for_each(|(_, s)| s.params.interval = interval);
1658 
1659                 // To avoid borrowing context as mutable from an immutable borrow.
1660                 // Required information is collected in advance and then passed
1661                 // to the D-Bus call which requires a mutable borrow.
1662                 let advs: Vec<(_, _)> = context
1663                     .adv_sets
1664                     .iter()
1665                     .filter_map(|(_, s)| s.adv_id.map(|adv_id| (adv_id, s.params.clone())))
1666                     .collect();
1667                 for (adv_id, params) in advs {
1668                     print_info!("Setting advertising parameters for {}", adv_id);
1669                     context.gatt_dbus.as_mut().unwrap().set_advertising_parameters(adv_id, params);
1670                 }
1671             }
1672             "set-connectable" => {
1673                 let connectable = match &get_arg(args, 1)?[..] {
1674                     "on" => true,
1675                     "off" => false,
1676                     _ => false,
1677                 };
1678 
1679                 let adv_id = String::from(get_arg(args, 2)?)
1680                     .parse::<i32>()
1681                     .or(Err("Failed parsing adv_id"))?;
1682 
1683                 let mut context = self.context.lock().unwrap();
1684 
1685                 let advs: Vec<(_, _)> = context
1686                     .adv_sets
1687                     .iter_mut()
1688                     .filter_map(|(_, s)| {
1689                         if !(s.adv_id.map_or(false, |id| id == adv_id)) {
1690                             return None;
1691                         }
1692                         s.params.connectable = connectable;
1693                         Some((s.params.clone(), s.data.clone()))
1694                     })
1695                     .collect();
1696 
1697                 for (params, data) in advs {
1698                     print_info!("Setting advertising parameters for {}", adv_id);
1699                     context.gatt_dbus.as_mut().unwrap().set_advertising_parameters(adv_id, params);
1700 
1701                     // renew the flags
1702                     print_info!("Setting advertising data for {}", adv_id);
1703                     context.gatt_dbus.as_mut().unwrap().set_advertising_data(adv_id, data);
1704                 }
1705             }
1706             "set-scan-rsp" => {
1707                 let enable = match &get_arg(args, 1)?[..] {
1708                     "enable" => true,
1709                     "disable" => false,
1710                     _ => false,
1711                 };
1712 
1713                 let mut context = self.lock_context();
1714                 context.adv_sets.iter_mut().for_each(|(_, s)| s.params.scannable = enable);
1715 
1716                 let advs: Vec<(_, _, _)> = context
1717                     .adv_sets
1718                     .iter()
1719                     .filter_map(|(_, s)| {
1720                         s.adv_id.map(|adv_id| (adv_id, s.params.clone(), s.scan_rsp.clone()))
1721                     })
1722                     .collect();
1723                 for (adv_id, params, scan_rsp) in advs {
1724                     print_info!("Setting scan response data for {}", adv_id);
1725                     context.gatt_dbus.as_mut().unwrap().set_scan_response_data(adv_id, scan_rsp);
1726                     print_info!("Setting parameters for {}", adv_id);
1727                     context.gatt_dbus.as_mut().unwrap().set_advertising_parameters(adv_id, params);
1728                 }
1729             }
1730             "set-raw-data" => {
1731                 let data = hex::decode(get_arg(args, 1)?).or(Err("Failed parsing data"))?;
1732 
1733                 let adv_id = String::from(get_arg(args, 2)?)
1734                     .parse::<i32>()
1735                     .or(Err("Failed parsing adv_id"))?;
1736 
1737                 let mut context = self.context.lock().unwrap();
1738                 if !context.adv_sets.iter().any(|(_, s)| s.adv_id.map_or(false, |id| id == adv_id))
1739                 {
1740                     return Err("Failed to find advertising set".into());
1741                 }
1742 
1743                 print_info!("Setting advertising data for {}", adv_id);
1744                 context.gatt_dbus.as_mut().unwrap().set_raw_adv_data(adv_id, data);
1745             }
1746             _ => return Err(CommandError::InvalidArgs),
1747         }
1748 
1749         Ok(())
1750     }
1751 
cmd_sdp(&mut self, args: &[String]) -> CommandResult1752     fn cmd_sdp(&mut self, args: &[String]) -> CommandResult {
1753         if !self.lock_context().adapter_ready {
1754             return Err(self.adapter_not_ready());
1755         }
1756 
1757         let command = get_arg(args, 0)?;
1758 
1759         match &command[..] {
1760             "search" => {
1761                 let device = BluetoothDevice {
1762                     address: RawAddress::from_string(get_arg(args, 1)?).ok_or("Invalid Address")?,
1763                     name: String::from(""),
1764                 };
1765                 let uuid = Uuid::from_string(get_arg(args, 2)?).ok_or("Invalid UUID")?;
1766                 let success =
1767                     self.lock_context().adapter_dbus.as_ref().unwrap().sdp_search(device, uuid);
1768                 if !success {
1769                     return Err("Unable to execute SDP search".into());
1770                 }
1771             }
1772             _ => return Err(CommandError::InvalidArgs),
1773         }
1774         Ok(())
1775     }
1776 
cmd_socket(&mut self, args: &[String]) -> CommandResult1777     fn cmd_socket(&mut self, args: &[String]) -> CommandResult {
1778         if !self.lock_context().adapter_ready {
1779             return Err(self.adapter_not_ready());
1780         }
1781 
1782         let callback_id = match self.lock_context().socket_manager_callback_id {
1783             Some(id) => id,
1784             None => {
1785                 return Err("No socket manager callback registered.".into());
1786             }
1787         };
1788 
1789         let command = get_arg(args, 0)?;
1790 
1791         match &command[..] {
1792             "set-on-connect-schedule" => {
1793                 let schedule = match &get_arg(args, 1)?[..] {
1794                     "send" => SocketSchedule {
1795                         num_frame: 1,
1796                         send_interval: Duration::from_millis(0),
1797                         disconnect_delay: Duration::from_secs(30),
1798                     },
1799                     "resend" => SocketSchedule {
1800                         num_frame: 3,
1801                         send_interval: Duration::from_millis(100),
1802                         disconnect_delay: Duration::from_secs(30),
1803                     },
1804                     "dump" => SocketSchedule {
1805                         num_frame: 0,
1806                         send_interval: Duration::from_millis(0),
1807                         disconnect_delay: Duration::from_secs(30),
1808                     },
1809                     _ => {
1810                         return Err("Failed to parse schedule".into());
1811                     }
1812                 };
1813 
1814                 self.context.lock().unwrap().socket_test_schedule = Some(schedule);
1815             }
1816             "send-msc" => {
1817                 let dlci =
1818                     String::from(get_arg(args, 1)?).parse::<u8>().or(Err("Failed parsing DLCI"))?;
1819                 let addr = RawAddress::from_string(get_arg(args, 2)?).ok_or("Invalid Address")?;
1820                 self.context.lock().unwrap().qa_dbus.as_mut().unwrap().rfcomm_send_msc(dlci, addr);
1821             }
1822             "listen-rfcomm" => {
1823                 let scn = String::from(get_arg(args, 1)?)
1824                     .parse::<i32>()
1825                     .or(Err("Failed parsing Service Channel Number"))?;
1826                 let SocketResult { status, id } = self
1827                     .context
1828                     .lock()
1829                     .unwrap()
1830                     .socket_manager_dbus
1831                     .as_mut()
1832                     .unwrap()
1833                     .listen_using_rfcomm(callback_id, Some(scn), None, None, None);
1834                 if status != BtStatus::Success {
1835                     return Err(format!(
1836                         "Failed to request for listening using rfcomm, status = {:?}",
1837                         status,
1838                     )
1839                     .into());
1840                 }
1841                 print_info!("Requested for listening using rfcomm on socket {}", id);
1842             }
1843             "listen" => {
1844                 let auth_required = String::from(get_arg(args, 1)?)
1845                     .parse::<bool>()
1846                     .or(Err("Failed to parse auth-required"))?;
1847                 let is_le = match &get_arg(args, 2)?[..] {
1848                     "LE" => true,
1849                     "Bredr" => false,
1850                     _ => {
1851                         return Err("Failed to parse socket type".into());
1852                     }
1853                 };
1854 
1855                 let SocketResult { status, id } = {
1856                     let mut context_proxy = self.context.lock().unwrap();
1857                     let proxy = context_proxy.socket_manager_dbus.as_mut().unwrap();
1858                     if auth_required {
1859                         if is_le {
1860                             proxy.listen_using_l2cap_le_channel(callback_id)
1861                         } else {
1862                             proxy.listen_using_l2cap_channel(callback_id)
1863                         }
1864                     } else if is_le {
1865                         proxy.listen_using_insecure_l2cap_le_channel(callback_id)
1866                     } else {
1867                         proxy.listen_using_insecure_l2cap_channel(callback_id)
1868                     }
1869                 };
1870 
1871                 if status != BtStatus::Success {
1872                     return Err(format!(
1873                         "Failed to request for listening using l2cap channel, status = {:?}",
1874                         status,
1875                     )
1876                     .into());
1877                 }
1878                 print_info!("Requested for listening using l2cap channel on socket {}", id);
1879             }
1880             "connect" => {
1881                 let (addr, sock_type, psm_or_uuid) =
1882                     (&get_arg(args, 1)?, &get_arg(args, 2)?, &get_arg(args, 3)?);
1883                 let device = BluetoothDevice {
1884                     address: RawAddress::from_string(*addr).ok_or("Invalid Address")?,
1885                     name: String::from("Socket Connect Device"),
1886                 };
1887 
1888                 let auth_required = String::from(get_arg(args, 4)?)
1889                     .parse::<bool>()
1890                     .or(Err("Failed to parse auth-required"))?;
1891 
1892                 let is_le = match &get_arg(args, 5)?[..] {
1893                     "LE" => true,
1894                     "Bredr" => false,
1895                     _ => {
1896                         return Err("Failed to parse socket type".into());
1897                     }
1898                 };
1899 
1900                 let SocketResult { status, id } = {
1901                     let mut context_proxy = self.context.lock().unwrap();
1902                     let proxy = context_proxy.socket_manager_dbus.as_mut().unwrap();
1903 
1904                     match &sock_type[0..] {
1905                         "l2cap" => {
1906                             let psm = match psm_or_uuid.parse::<i32>() {
1907                                 Ok(v) => v,
1908                                 Err(e) => {
1909                                     return Err(CommandError::Failed(format!(
1910                                         "Bad PSM given. Error={}",
1911                                         e
1912                                     )));
1913                                 }
1914                             };
1915 
1916                             if auth_required {
1917                                 if is_le {
1918                                     proxy.create_l2cap_le_channel(callback_id, device, psm)
1919                                 } else {
1920                                     proxy.create_l2cap_channel(callback_id, device, psm)
1921                                 }
1922                             } else if is_le {
1923                                 proxy.create_insecure_l2cap_le_channel(callback_id, device, psm)
1924                             } else {
1925                                 proxy.create_insecure_l2cap_channel(callback_id, device, psm)
1926                             }
1927                         }
1928                         "rfcomm" => {
1929                             let uuid = match Uuid::from_string(*psm_or_uuid) {
1930                                 Some(uu) => uu,
1931                                 None => {
1932                                     return Err(CommandError::Failed(
1933                                         "Could not parse given uuid.".to_string(),
1934                                     ));
1935                                 }
1936                             };
1937 
1938                             if auth_required {
1939                                 proxy.create_rfcomm_socket_to_service_record(
1940                                     callback_id,
1941                                     device,
1942                                     uuid,
1943                                 )
1944                             } else {
1945                                 proxy.create_insecure_rfcomm_socket_to_service_record(
1946                                     callback_id,
1947                                     device,
1948                                     uuid,
1949                                 )
1950                             }
1951                         }
1952                         _ => {
1953                             return Err(CommandError::Failed(format!(
1954                                 "Unknown socket type: {}",
1955                                 sock_type
1956                             )));
1957                         }
1958                     }
1959                 };
1960 
1961                 if status != BtStatus::Success {
1962                     return Err(CommandError::Failed(format!("Failed to create socket with status={:?} against {}, type {}, with psm/uuid {}",
1963                         status, addr, sock_type, psm_or_uuid)));
1964                 } else {
1965                     print_info!("Called create socket with result ({:?}, {}) against {}, type {}, with psm/uuid {}",
1966                     status, id, addr, sock_type, psm_or_uuid);
1967                 }
1968             }
1969             "close" => {
1970                 let sockid = String::from(get_arg(args, 1)?)
1971                     .parse::<u64>()
1972                     .or(Err("Failed parsing socket ID"))?;
1973                 let status = self
1974                     .context
1975                     .lock()
1976                     .unwrap()
1977                     .socket_manager_dbus
1978                     .as_mut()
1979                     .unwrap()
1980                     .close(callback_id, sockid);
1981                 if status != BtStatus::Success {
1982                     return Err(format!(
1983                         "Failed to close the listening socket, status = {:?}",
1984                         status,
1985                     )
1986                     .into());
1987                 }
1988             }
1989 
1990             _ => return Err(CommandError::InvalidArgs),
1991         };
1992 
1993         Ok(())
1994     }
1995 
cmd_hid(&mut self, args: &[String]) -> CommandResult1996     fn cmd_hid(&mut self, args: &[String]) -> CommandResult {
1997         if !self.context.lock().unwrap().adapter_ready {
1998             return Err(self.adapter_not_ready());
1999         }
2000 
2001         let command = get_arg(args, 0)?;
2002 
2003         match &command[..] {
2004             "get-report" => {
2005                 let addr = RawAddress::from_string(get_arg(args, 1)?).ok_or("Invalid Address")?;
2006                 let report_type = match &get_arg(args, 2)?[..] {
2007                     "Input" => BthhReportType::InputReport,
2008                     "Output" => BthhReportType::OutputReport,
2009                     "Feature" => BthhReportType::FeatureReport,
2010                     _ => {
2011                         return Err("Failed to parse report type".into());
2012                     }
2013                 };
2014                 let report_id = String::from(get_arg(args, 3)?)
2015                     .parse::<u8>()
2016                     .or(Err("Failed parsing report_id"))?;
2017 
2018                 self.context.lock().unwrap().qa_dbus.as_mut().unwrap().get_hid_report(
2019                     addr,
2020                     report_type,
2021                     report_id,
2022                 );
2023             }
2024             "set-report" => {
2025                 let addr = RawAddress::from_string(get_arg(args, 1)?).ok_or("Invalid Address")?;
2026                 let report_type = match &get_arg(args, 2)?[..] {
2027                     "Input" => BthhReportType::InputReport,
2028                     "Output" => BthhReportType::OutputReport,
2029                     "Feature" => BthhReportType::FeatureReport,
2030                     _ => {
2031                         return Err("Failed to parse report type".into());
2032                     }
2033                 };
2034                 let report_value = String::from(get_arg(args, 3)?);
2035 
2036                 self.context.lock().unwrap().qa_dbus.as_mut().unwrap().set_hid_report(
2037                     addr,
2038                     report_type,
2039                     report_value,
2040                 );
2041             }
2042             "send-data" => {
2043                 let addr = RawAddress::from_string(get_arg(args, 1)?).ok_or("Invalid Address")?;
2044                 let data = String::from(get_arg(args, 2)?);
2045 
2046                 self.context.lock().unwrap().qa_dbus.as_mut().unwrap().send_hid_data(addr, data);
2047             }
2048             "virtual-unplug" => {
2049                 let addr = RawAddress::from_string(get_arg(args, 1)?).ok_or("Invalid Address")?;
2050                 self.context
2051                     .lock()
2052                     .unwrap()
2053                     .qa_dbus
2054                     .as_mut()
2055                     .unwrap()
2056                     .send_hid_virtual_unplug(addr);
2057             }
2058             _ => return Err(CommandError::InvalidArgs),
2059         };
2060 
2061         Ok(())
2062     }
2063 
2064     /// Get the list of rules of supported commands
get_command_rule_list(&self) -> Vec<String>2065     pub fn get_command_rule_list(&self) -> Vec<String> {
2066         self.command_options.values().flat_map(|cmd| cmd.rules.clone()).collect()
2067     }
2068 
cmd_list_devices(&mut self, args: &[String]) -> CommandResult2069     fn cmd_list_devices(&mut self, args: &[String]) -> CommandResult {
2070         if !self.lock_context().adapter_ready {
2071             return Err(self.adapter_not_ready());
2072         }
2073 
2074         let command = get_arg(args, 0)?;
2075 
2076         match &command[..] {
2077             "bonded" => {
2078                 print_info!("Known bonded devices:");
2079                 let devices =
2080                     self.lock_context().adapter_dbus.as_ref().unwrap().get_bonded_devices();
2081                 for device in devices.iter() {
2082                     print_info!("[{}] {}", device.address.to_string(), device.name);
2083                 }
2084             }
2085             "found" => {
2086                 print_info!("Devices found in most recent discovery session:");
2087                 for (key, val) in self.lock_context().found_devices.iter() {
2088                     print_info!("[{:17}] {}", key, val.name);
2089                 }
2090             }
2091             "connected" => {
2092                 print_info!("Connected devices:");
2093                 let devices =
2094                     self.lock_context().adapter_dbus.as_ref().unwrap().get_connected_devices();
2095                 for device in devices.iter() {
2096                     print_info!("[{}] {}", device.address.to_string(), device.name);
2097                 }
2098             }
2099             other => {
2100                 println!("Invalid argument '{}'", other);
2101             }
2102         }
2103 
2104         Ok(())
2105     }
2106 
cmd_telephony(&mut self, args: &[String]) -> CommandResult2107     fn cmd_telephony(&mut self, args: &[String]) -> CommandResult {
2108         if !self.context.lock().unwrap().adapter_ready {
2109             return Err(self.adapter_not_ready());
2110         }
2111 
2112         match &get_arg(args, 0)?[..] {
2113             "set-network" => {
2114                 self.context
2115                     .lock()
2116                     .unwrap()
2117                     .telephony_dbus
2118                     .as_mut()
2119                     .unwrap()
2120                     .set_network_available(match &get_arg(args, 1)?[..] {
2121                         "on" => true,
2122                         "off" => false,
2123                         other => {
2124                             return Err(format!("Invalid argument '{}'", other).into());
2125                         }
2126                     });
2127             }
2128             "set-roaming" => {
2129                 self.context.lock().unwrap().telephony_dbus.as_mut().unwrap().set_roaming(
2130                     match &get_arg(args, 1)?[..] {
2131                         "on" => true,
2132                         "off" => false,
2133                         other => {
2134                             return Err(format!("Invalid argument '{}'", other).into());
2135                         }
2136                     },
2137                 );
2138             }
2139             "set-signal" => {
2140                 let strength = String::from(get_arg(args, 1)?)
2141                     .parse::<i32>()
2142                     .or(Err("Failed parsing signal strength"))?;
2143                 if !(0..=5).contains(&strength) {
2144                     return Err(
2145                         format!("Invalid signal strength, got {}, want 0 to 5", strength).into()
2146                     );
2147                 }
2148                 self.context
2149                     .lock()
2150                     .unwrap()
2151                     .telephony_dbus
2152                     .as_mut()
2153                     .unwrap()
2154                     .set_signal_strength(strength);
2155             }
2156             "set-battery" => {
2157                 let level = String::from(get_arg(args, 1)?)
2158                     .parse::<i32>()
2159                     .or(Err("Failed parsing battery level"))?;
2160                 if !(0..=5).contains(&level) {
2161                     return Err(format!("Invalid battery level, got {}, want 0 to 5", level).into());
2162                 }
2163                 self.context
2164                     .lock()
2165                     .unwrap()
2166                     .telephony_dbus
2167                     .as_mut()
2168                     .unwrap()
2169                     .set_battery_level(level);
2170             }
2171             "enable" => {
2172                 let mut context = self.lock_context();
2173                 context.telephony_dbus.as_mut().unwrap().set_mps_qualification_enabled(true);
2174                 if context.mps_sdp_handle.is_none() {
2175                     let success = context
2176                         .adapter_dbus
2177                         .as_mut()
2178                         .unwrap()
2179                         .create_sdp_record(BtSdpRecord::Mps(BtSdpMpsRecord::default()));
2180                     if !success {
2181                         return Err("Failed to create SDP record".to_string().into());
2182                     }
2183                 }
2184             }
2185             "disable" => {
2186                 let mut context = self.lock_context();
2187                 context.telephony_dbus.as_mut().unwrap().set_mps_qualification_enabled(false);
2188                 if let Some(handle) = context.mps_sdp_handle.take() {
2189                     let success = context.adapter_dbus.as_mut().unwrap().remove_sdp_record(handle);
2190                     if !success {
2191                         return Err("Failed to remove SDP record".to_string().into());
2192                     }
2193                 }
2194             }
2195             "set-phone-ops" => {
2196                 let on_or_off = match &get_arg(args, 1)?[..] {
2197                     "on" => true,
2198                     "off" => false,
2199                     _ => {
2200                         return Err("Failed to parse on|off".into());
2201                     }
2202                 };
2203                 self.context
2204                     .lock()
2205                     .unwrap()
2206                     .telephony_dbus
2207                     .as_mut()
2208                     .unwrap()
2209                     .set_phone_ops_enabled(on_or_off);
2210             }
2211             "incoming-call" => {
2212                 let success = self
2213                     .context
2214                     .lock()
2215                     .unwrap()
2216                     .telephony_dbus
2217                     .as_mut()
2218                     .unwrap()
2219                     .incoming_call(String::from(get_arg(args, 1)?));
2220                 if !success {
2221                     return Err("IncomingCall failed".into());
2222                 }
2223             }
2224             "dialing-call" => {
2225                 let success = self
2226                     .context
2227                     .lock()
2228                     .unwrap()
2229                     .telephony_dbus
2230                     .as_mut()
2231                     .unwrap()
2232                     .dialing_call(String::from(get_arg(args, 1)?));
2233                 if !success {
2234                     return Err("DialingCall failed".into());
2235                 }
2236             }
2237             "answer-call" => {
2238                 let success =
2239                     self.context.lock().unwrap().telephony_dbus.as_mut().unwrap().answer_call();
2240                 if !success {
2241                     return Err("AnswerCall failed".into());
2242                 }
2243             }
2244             "hangup-call" => {
2245                 let success =
2246                     self.context.lock().unwrap().telephony_dbus.as_mut().unwrap().hangup_call();
2247                 if !success {
2248                     return Err("HangupCall failed".into());
2249                 }
2250             }
2251             "set-memory-call" => {
2252                 let success = self
2253                     .context
2254                     .lock()
2255                     .unwrap()
2256                     .telephony_dbus
2257                     .as_mut()
2258                     .unwrap()
2259                     .set_memory_call(get_arg(args, 1).ok().map(String::from));
2260                 if !success {
2261                     return Err("SetMemoryCall failed".into());
2262                 }
2263             }
2264             "set-last-call" => {
2265                 let success = self
2266                     .context
2267                     .lock()
2268                     .unwrap()
2269                     .telephony_dbus
2270                     .as_mut()
2271                     .unwrap()
2272                     .set_last_call(get_arg(args, 1).ok().map(String::from));
2273                 if !success {
2274                     return Err("SetLastCall failed".into());
2275                 }
2276             }
2277             "release-held" => {
2278                 let success =
2279                     self.context.lock().unwrap().telephony_dbus.as_mut().unwrap().release_held();
2280                 if !success {
2281                     return Err("ReleaseHeld failed".into());
2282                 }
2283             }
2284             "release-active-accept-held" => {
2285                 let success = self
2286                     .context
2287                     .lock()
2288                     .unwrap()
2289                     .telephony_dbus
2290                     .as_mut()
2291                     .unwrap()
2292                     .release_active_accept_held();
2293                 if !success {
2294                     return Err("ReleaseActiveAcceptHeld failed".into());
2295                 }
2296             }
2297             "hold-active-accept-held" => {
2298                 let success = self
2299                     .context
2300                     .lock()
2301                     .unwrap()
2302                     .telephony_dbus
2303                     .as_mut()
2304                     .unwrap()
2305                     .hold_active_accept_held();
2306                 if !success {
2307                     return Err("HoldActiveAcceptHeld failed".into());
2308                 }
2309             }
2310             "audio-connect" => {
2311                 let success =
2312                     self.context.lock().unwrap().telephony_dbus.as_mut().unwrap().audio_connect(
2313                         RawAddress::from_string(get_arg(args, 1)?).ok_or("Invalid Address")?,
2314                     );
2315                 if !success {
2316                     return Err("ConnectAudio failed".into());
2317                 }
2318             }
2319             "audio-disconnect" => {
2320                 self.context.lock().unwrap().telephony_dbus.as_mut().unwrap().audio_disconnect(
2321                     RawAddress::from_string(get_arg(args, 1)?).ok_or("Invalid Address")?,
2322                 );
2323             }
2324             other => {
2325                 return Err(format!("Invalid argument '{}'", other).into());
2326             }
2327         }
2328         Ok(())
2329     }
2330 
cmd_qa(&mut self, args: &[String]) -> CommandResult2331     fn cmd_qa(&mut self, args: &[String]) -> CommandResult {
2332         if !self.context.lock().unwrap().adapter_ready {
2333             return Err(self.adapter_not_ready());
2334         }
2335 
2336         let command = get_arg(args, 0)?;
2337 
2338         match &command[..] {
2339             "add-media-player" => {
2340                 let name = String::from(get_arg(args, 1)?);
2341                 let browsing_supported = String::from(get_arg(args, 2)?)
2342                     .parse::<bool>()
2343                     .or(Err("Failed to parse browsing_supported"))?;
2344                 self.context
2345                     .lock()
2346                     .unwrap()
2347                     .qa_dbus
2348                     .as_mut()
2349                     .unwrap()
2350                     .add_media_player(name, browsing_supported);
2351             }
2352             _ => return Err(CommandError::InvalidArgs),
2353         };
2354 
2355         Ok(())
2356     }
2357 
cmd_media(&mut self, args: &[String]) -> CommandResult2358     fn cmd_media(&mut self, args: &[String]) -> CommandResult {
2359         if !self.context.lock().unwrap().adapter_ready {
2360             return Err(self.adapter_not_ready());
2361         }
2362 
2363         match &get_arg(args, 0)?[..] {
2364             "log" => {
2365                 self.context.lock().unwrap().media_dbus.as_mut().unwrap().trigger_debug_dump();
2366             }
2367             other => {
2368                 return Err(format!("Invalid argument '{}'", other).into());
2369             }
2370         }
2371 
2372         Ok(())
2373     }
2374 
cmd_dumpsys(&mut self, _args: &[String]) -> CommandResult2375     fn cmd_dumpsys(&mut self, _args: &[String]) -> CommandResult {
2376         if !self.lock_context().adapter_ready {
2377             return Err(self.adapter_not_ready());
2378         }
2379 
2380         let contents = self.lock_context().adapter_dbus.as_mut().unwrap().get_dumpsys();
2381         println!("{}", contents);
2382 
2383         Ok(())
2384     }
2385 
cmd_log(&mut self, args: &[String]) -> CommandResult2386     fn cmd_log(&mut self, args: &[String]) -> CommandResult {
2387         if !self.lock_context().adapter_ready {
2388             return Err(self.adapter_not_ready());
2389         }
2390 
2391         let command = get_arg(args, 0)?;
2392 
2393         match &command[..] {
2394             "set-level" => {
2395                 let level = match &get_arg(args, 1)?[..] {
2396                     "info" => Level::Info,
2397                     "debug" => Level::Debug,
2398                     "verbose" => Level::Verbose,
2399                     _ => {
2400                         return Err("Failed to parse log level".into());
2401                     }
2402                 };
2403                 self.lock_context().logging_dbus.as_mut().unwrap().set_log_level(level);
2404             }
2405 
2406             "get-level" => {
2407                 let level = self.lock_context().logging_dbus.as_ref().unwrap().get_log_level();
2408 
2409                 print_info!("log level: {:?}", level);
2410             }
2411 
2412             other => {
2413                 return Err(format!("Invalid argument '{}'", other).into());
2414             }
2415         }
2416 
2417         Ok(())
2418     }
2419 }
2420 
2421 #[cfg(test)]
2422 mod tests {
2423 
2424     use super::*;
2425 
2426     #[test]
test_wrap_help_text()2427     fn test_wrap_help_text() {
2428         let text = "hello";
2429         let text_len = text.chars().count();
2430         // ensure no overflow
2431         assert_eq!(format!("|{}|", text), wrap_help_text(text, 4, 0));
2432         assert_eq!(format!("|{}|", text), wrap_help_text(text, 5, 0));
2433         assert_eq!(format!("|{}{}|", text, " "), wrap_help_text(text, 6, 0));
2434         assert_eq!(format!("|{}{}|", text, " ".repeat(2)), wrap_help_text(text, 7, 0));
2435         assert_eq!(
2436             format!("|{}{}|", text, " ".repeat(100 - text_len)),
2437             wrap_help_text(text, 100, 0)
2438         );
2439         assert_eq!(format!("|{}{}|", " ", text), wrap_help_text(text, 4, 1));
2440         assert_eq!(format!("|{}{}|", " ".repeat(2), text), wrap_help_text(text, 5, 2));
2441         assert_eq!(format!("|{}{}{}|", " ".repeat(3), text, " "), wrap_help_text(text, 6, 3));
2442         assert_eq!(
2443             format!("|{}{}{}|", " ".repeat(4), text, " ".repeat(7 - text_len)),
2444             wrap_help_text(text, 7, 4)
2445         );
2446         assert_eq!(format!("|{}{}|", " ".repeat(9), text), wrap_help_text(text, 4, 9));
2447         assert_eq!(format!("|{}{}|", " ".repeat(10), text), wrap_help_text(text, 3, 10));
2448         assert_eq!(format!("|{}{}|", " ".repeat(11), text), wrap_help_text(text, 2, 11));
2449         assert_eq!(format!("|{}{}|", " ".repeat(12), text), wrap_help_text(text, 1, 12));
2450         assert_eq!("||", wrap_help_text("", 0, 0));
2451         assert_eq!("| |", wrap_help_text("", 1, 0));
2452         assert_eq!("|  |", wrap_help_text("", 1, 1));
2453         assert_eq!("| |", wrap_help_text("", 0, 1));
2454     }
2455 }
2456