Loading system/gd/rust/linux/client/Cargo.toml +2 −0 Original line number Diff line number Diff line Loading @@ -22,6 +22,8 @@ num-traits = "*" tokio = { version = "1", features = ['bytes', 'fs', 'io-util', 'libc', 'macros', 'memchr', 'mio', 'net', 'num_cpus', 'rt', 'rt-multi-thread', 'sync', 'time', 'tokio-macros'] } clap = "2.33.3" bitflags = "1.2" hex = "0.4.3" [build-dependencies] pkg-config = "0.3.19" Loading system/gd/rust/linux/client/src/bt_gatt.rs 0 → 100644 +44 −0 Original line number Diff line number Diff line use bitflags::bitflags; use bt_topshim::btif::BtTransport; use bt_topshim::profiles::gatt::LePhy; bitflags! { pub(crate) struct AuthReq: i32 { // reference to system/stack/include/gatt_api.h const MITM = 0x01; const SIGNED = 0x10; } } /// User preferenece of GATT operations pub(crate) struct GattClientContext { /// If set, the registered GATT client id. None otherwise. pub(crate) client_id: Option<i32>, /// Type of authentication requirement pub(crate) auth_req: AuthReq, /// Is connection going to be directed? pub(crate) is_connect_direct: bool, /// Transport of connection pub(crate) connect_transport: BtTransport, /// Is connection going to be opportunistic? pub(crate) connect_opportunistic: bool, /// Type of connect phy pub(crate) connect_phy: LePhy, } impl GattClientContext { pub(crate) fn new() -> Self { GattClientContext { client_id: None, auth_req: AuthReq::empty(), is_connect_direct: false, connect_transport: BtTransport::Le, connect_opportunistic: false, connect_phy: LePhy::Phy1m, } } pub(crate) fn get_auth_req_bits(&self) -> i32 { self.auth_req.bits() } } system/gd/rust/linux/client/src/callbacks.rs +1 −1 Original line number Diff line number Diff line Loading @@ -579,7 +579,7 @@ impl BtGattCallback { impl IBluetoothGattCallback for BtGattCallback { fn on_client_registered(&self, status: GattStatus, client_id: i32) { print_info!("GATT Client registered status = {}, client_id = {}", status, client_id); self.context.lock().unwrap().gatt_client_id = Some(client_id); self.context.lock().unwrap().gatt_client_context.client_id = Some(client_id); } fn on_client_connection_state( Loading system/gd/rust/linux/client/src/command_handler.rs +225 −80 Original line number Diff line number Diff line Loading @@ -4,13 +4,14 @@ use std::slice::SliceIndex; use std::sync::{Arc, Mutex}; use crate::bt_adv::AdvSet; use crate::bt_gatt::AuthReq; use crate::callbacks::BtGattCallback; use crate::ClientContext; use crate::{console_red, console_yellow, print_error, print_info}; use bt_topshim::btif::{BtConnectionState, BtStatus, BtTransport}; use bt_topshim::profiles::gatt::LePhy; use btstack::bluetooth::{BluetoothDevice, IBluetooth, IBluetoothQA}; use btstack::bluetooth_gatt::{IBluetoothGatt, ScanSettings, ScanType}; use btstack::bluetooth_gatt::{GattWriteType, IBluetoothGatt, ScanSettings, ScanType}; use btstack::socket_manager::{IBluetoothSocketManager, SocketResult}; use btstack::uuid::{Profile, UuidHelper, UuidWrapper}; use manager_service::iface_bluetooth_manager::IBluetoothManager; Loading @@ -28,6 +29,18 @@ enum CommandError { Failed(String), } impl From<&str> for CommandError { fn from(s: &str) -> CommandError { CommandError::Failed(String::from(s)) } } impl From<String> for CommandError { fn from(s: String) -> CommandError { CommandError::Failed(s) } } type CommandResult = Result<(), CommandError>; type CommandFunction = fn(&mut CommandHandler, &Vec<String>) -> CommandResult; Loading Loading @@ -147,6 +160,15 @@ fn build_commands() -> HashMap<String, CommandOption> { String::from("gatt client-discover-services <address>"), String::from("gatt client-disconnect <address>"), String::from("gatt configure-mtu <address> <mtu>"), String::from("gatt set-direct-connect <true|false>"), String::from("gatt set-connect-transport <Bredr|LE|Auto>"), String::from("gatt set-connect-opportunistic <true|false>"), String::from("gatt set-connect-phy <Phy1m|Phy2m|PhyCoded>"), String::from("gatt set-auth-req <MITM|SIGNED> <enable|disable>"), String::from( "gatt write-characteristic <address> <handle> <NoRsp|Write|Prepare> <value>", ), String::from("gatt read-characteristic <address> <handle>"), ], description: String::from("GATT tools"), function_pointer: CommandHandler::cmd_gatt, Loading Loading @@ -271,10 +293,11 @@ impl CommandHandler { // Common message for when the adapter isn't ready fn adapter_not_ready(&self) -> CommandError { CommandError::Failed(format!( format!( "Default adapter {} is not enabled. Enable the adapter before using this command.", self.context.lock().unwrap().default_adapter )) ) .into() } fn cmd_help(&mut self, args: &Vec<String>) -> CommandResult { Loading Loading @@ -330,9 +353,7 @@ impl CommandHandler { fn cmd_adapter(&mut self, args: &Vec<String>) -> CommandResult { if !self.context.lock().unwrap().manager_dbus.get_floss_enabled() { return Err(CommandError::Failed( "Floss is not enabled. First run, `floss enable`".into(), )); return Err("Floss is not enabled. First run, `floss enable`".into()); } let default_adapter = self.context.lock().unwrap().default_adapter; Loading @@ -342,17 +363,13 @@ impl CommandHandler { match &command[..] { "enable" => { if self.context.lock().unwrap().is_restricted { return Err(CommandError::Failed( "You are not allowed to toggle adapter power".into(), )); return Err("You are not allowed to toggle adapter power".into()); } self.context.lock().unwrap().manager_dbus.start(default_adapter); } "disable" => { if self.context.lock().unwrap().is_restricted { return Err(CommandError::Failed( "You are not allowed to toggle adapter power".into(), )); return Err("You are not allowed to toggle adapter power".into()); } self.context.lock().unwrap().manager_dbus.stop(default_adapter); } Loading Loading @@ -529,13 +546,11 @@ impl CommandHandler { &self.context.lock().unwrap().bonding_attempt.as_ref().cloned(); if bonding_attempt.is_some() { return Err(CommandError::Failed( format!( return Err(format!( "Already bonding [{}]. Cancel bonding first.", bonding_attempt.as_ref().unwrap().address, ) .into(), )); .into()); } let success = self Loading Loading @@ -734,7 +749,7 @@ impl CommandHandler { "accept" => true, "reject" => false, other => { return Err(CommandError::Failed(format!("Failed to parse '{}'", other))); return Err(format!("Failed to parse '{}'", other).into()); } }; Loading @@ -756,7 +771,7 @@ impl CommandHandler { (_, Ok(p)) => (true, Vec::from(p.to_ne_bytes())), ("reject", _) => (false, vec![]), _ => { return Err(CommandError::Failed(format!("Failed to parse '{}'", pin))); return Err(format!("Failed to parse '{}'", pin).into()); } }; Loading @@ -776,7 +791,7 @@ impl CommandHandler { (_, Ok(p)) => (true, Vec::from(p.to_ne_bytes())), ("reject", _) => (false, vec![]), _ => { return Err(CommandError::Failed(format!("Failed to parse '{}'", passkey))); return Err(format!("Failed to parse '{}'", passkey).into()); } }; Loading Loading @@ -840,30 +855,39 @@ impl CommandHandler { ); } "client-connect" => { let client_id = self.context.lock().unwrap().gatt_client_id; if client_id.is_none() { return Err(CommandError::Failed(format!( "GATT client is not yet registered." ))); } let client_id = self .context .lock() .unwrap() .gatt_client_context .client_id .ok_or("GATT client is not yet registered.")?; let addr = String::from(get_arg(args, 1)?); let is_direct = self.context.lock().unwrap().gatt_client_context.is_connect_direct; let transport = self.context.lock().unwrap().gatt_client_context.connect_transport; let oppurtunistic = self.context.lock().unwrap().gatt_client_context.connect_opportunistic; let phy = self.context.lock().unwrap().gatt_client_context.connect_phy; println!("Initiating GATT client connect. client_id: {}, addr: {}, is_direct: {}, transport: {:?}, oppurtunistic: {}, phy: {:?}", client_id, addr, is_direct, transport, oppurtunistic, phy); self.context.lock().unwrap().gatt_dbus.as_ref().unwrap().client_connect( client_id.unwrap(), client_id, addr, false, BtTransport::Le, false, LePhy::Phy1m, is_direct, transport, oppurtunistic, phy, ); } "client-disconnect" => { let client_id = self.context.lock().unwrap().gatt_client_id; if client_id.is_none() { return Err(CommandError::Failed(format!( "GATT client is not yet registered." ))); } let client_id = self .context .lock() .unwrap() .gatt_client_context .client_id .ok_or("GATT client is not yet registered.")?; let addr = String::from(get_arg(args, 1)?); self.context Loading @@ -872,16 +896,16 @@ impl CommandHandler { .gatt_dbus .as_ref() .unwrap() .client_disconnect(client_id.unwrap(), addr); .client_disconnect(client_id, addr); } "client-read-phy" => { let client_id = self.context.lock().unwrap().gatt_client_id; if client_id.is_none() { return Err(CommandError::Failed(format!( "GATT client is not yet registered." ))); } let client_id = self .context .lock() .unwrap() .gatt_client_context .client_id .ok_or("GATT client is not yet registered.")?; let addr = String::from(get_arg(args, 1)?); self.context .lock() Loading @@ -889,15 +913,16 @@ impl CommandHandler { .gatt_dbus .as_mut() .unwrap() .client_read_phy(client_id.unwrap(), addr); .client_read_phy(client_id, addr); } "client-discover-services" => { let client_id = self.context.lock().unwrap().gatt_client_id; if client_id.is_none() { return Err(CommandError::Failed(format!( "GATT client is not yet registered." ))); } let client_id = self .context .lock() .unwrap() .gatt_client_context .client_id .ok_or("GATT client is not yet registered.")?; let addr = String::from(get_arg(args, 1)?); self.context Loading @@ -906,31 +931,150 @@ impl CommandHandler { .gatt_dbus .as_ref() .unwrap() .discover_services(client_id.unwrap(), addr); .discover_services(client_id, addr); } "configure-mtu" => { let client_id = self.context.lock().unwrap().gatt_client_id; if client_id.is_none() { return Err(CommandError::Failed(format!( "GATT client is not yet registered." ))); } let client_id = self .context .lock() .unwrap() .gatt_client_context .client_id .ok_or("GATT client is not yet registered.")?; let addr = String::from(get_arg(args, 1)?); let mtu = String::from(get_arg(args, 2)?).parse::<i32>(); if let Ok(m) = mtu { self.context.lock().unwrap().gatt_dbus.as_ref().unwrap().configure_mtu( client_id.unwrap(), addr, m, let mtu = String::from(get_arg(args, 2)?).parse::<i32>().or(Err("Failed parsing mtu"))?; self.context .lock() .unwrap() .gatt_dbus .as_ref() .unwrap() .configure_mtu(client_id, addr, mtu) } "set-direct-connect" => { let is_direct = String::from(get_arg(args, 1)?) .parse::<bool>() .or(Err("Failed to parse is_direct"))?; self.context.lock().unwrap().gatt_client_context.is_connect_direct = is_direct; } "set-connect-transport" => { let transport = match &get_arg(args, 1)?[..] { "Bredr" => BtTransport::Bredr, "LE" => BtTransport::Le, "Auto" => BtTransport::Auto, _ => { return Err("Failed to parse transport".into()); } }; self.context.lock().unwrap().gatt_client_context.connect_transport = transport; } "set-connect-opportunistic" => { let opportunistic = String::from(get_arg(args, 1)?) .parse::<bool>() .or(Err("Failed to parse opportunistic"))?; self.context.lock().unwrap().gatt_client_context.connect_opportunistic = opportunistic; } "set-connect-phy" => { let phy = match &get_arg(args, 1)?[..] { "Phy1m" => LePhy::Phy1m, "Phy2m" => LePhy::Phy2m, "PhyCoded" => LePhy::PhyCoded, _ => { return Err("Failed to parse phy".into()); } }; self.context.lock().unwrap().gatt_client_context.connect_phy = phy; } "set-auth-req" => { let flag = match &get_arg(args, 1)?[..] { "MITM" => AuthReq::MITM, "SIGNED" => AuthReq::SIGNED, _ => { return Err("Failed to parse auth-req".into()); } }; let enable = match &get_arg(args, 2)?[..] { "enable" => true, "disable" => false, _ => { return Err("Failed to parse enable".into()); } }; self.context.lock().unwrap().gatt_client_context.auth_req.set(flag, enable); println!( "AuthReq: {:?}", self.context.lock().unwrap().gatt_client_context.auth_req ); } else { return Err(CommandError::Failed(format!("Failed parsing mtu"))); } "write-characteristic" => { let addr = String::from(get_arg(args, 1)?); let handle = String::from(get_arg(args, 2)?) .parse::<i32>() .or(Err("Failed to parse handle"))?; let write_type = match &get_arg(args, 3)?[..] { "NoRsp" => GattWriteType::WriteNoRsp, "Write" => GattWriteType::Write, "Prepare" => GattWriteType::WritePrepare, _ => { return Err("Failed to parse write-type".into()); } _ => return Err(CommandError::InvalidArgs), }; let value = hex::decode(&get_arg(args, 4)?).or(Err("Failed to parse value"))?; let client_id = self .context .lock() .unwrap() .gatt_client_context .client_id .ok_or("GATT client is not yet registered.")?; let auth_req = self.context.lock().unwrap().gatt_client_context.get_auth_req_bits(); self.context .lock() .unwrap() .gatt_dbus .as_ref() .unwrap() .write_characteristic(client_id, addr, handle, write_type, auth_req, value); } "read-characteristic" => { let addr = String::from(get_arg(args, 1)?); let handle = String::from(get_arg(args, 2)?) .parse::<i32>() .or(Err("Failed to parse handle"))?; let client_id = self .context .lock() .unwrap() .gatt_client_context .client_id .ok_or("GATT client is not yet registered.")?; let auth_req = self.context.lock().unwrap().gatt_client_context.get_auth_req_bits(); self.context .lock() .unwrap() .gatt_dbus .as_ref() .unwrap() .read_characteristic(client_id, addr, handle, auth_req); } _ => return Err(CommandError::InvalidArgs), } Ok(()) } Loading Loading @@ -964,7 +1108,7 @@ impl CommandHandler { if let Ok(id) = scanner_id { self.context.lock().unwrap().gatt_dbus.as_mut().unwrap().unregister_scanner(id); } else { return Err(CommandError::Failed(format!("Failed parsing scanner id"))); return Err("Failed parsing scanner id".into()); } } "start-scan" => { Loading @@ -988,7 +1132,7 @@ impl CommandHandler { ); self.context.lock().unwrap().active_scanner_ids.insert(id); } else { return Err(CommandError::Failed(format!("Failed parsing scanner id"))); return Err("Failed parsing scanner id".into()); } } "stop-scan" => { Loading @@ -998,7 +1142,7 @@ impl CommandHandler { self.context.lock().unwrap().gatt_dbus.as_mut().unwrap().stop_scan(id); self.context.lock().unwrap().active_scanner_ids.remove(&id); } else { return Err(CommandError::Failed(format!("Failed parsing scanner id"))); return Err("Failed parsing scanner id".into()); } } _ => return Err(CommandError::InvalidArgs), Loading @@ -1015,7 +1159,7 @@ impl CommandHandler { } if self.context.lock().unwrap().advertiser_callback_id == None { return Err(CommandError::Failed("No advertiser callback registered".into())); return Err("No advertiser callback registered".into()); } let callback_id = self.context.lock().unwrap().advertiser_callback_id.clone().unwrap(); Loading @@ -1039,7 +1183,7 @@ impl CommandHandler { "set-interval" => { let ms = String::from(get_arg(args, 1)?).parse::<i32>(); if !ms.is_ok() { return Err(CommandError::Failed(format!("Failed parsing interval"))); return Err("Failed parsing interval".into()); } let interval = ms.unwrap() * 8 / 5; // in 0.625 ms. Loading Loading @@ -1098,7 +1242,7 @@ impl CommandHandler { let callback_id = match self.context.lock().unwrap().socket_manager_callback_id.clone() { Some(id) => id, None => { return Err(CommandError::Failed("No socket manager callback registered.".into())); return Err("No socket manager callback registered.".into()); } }; Loading @@ -1116,10 +1260,11 @@ impl CommandHandler { .listen_using_l2cap_channel(callback_id); if status != BtStatus::Success { return Err(CommandError::Failed(format!( return Err(format!( "Failed to request for listening using l2cap channel, status = {:?}", status, ))); ) .into()); } print_info!("Requested for listening using l2cap channel on socket {}", id); } Loading system/gd/rust/linux/client/src/main.rs +6 −4 Original line number Diff line number Diff line Loading @@ -12,6 +12,7 @@ use dbus_crossroads::Crossroads; use tokio::sync::mpsc; use crate::bt_adv::AdvSet; use crate::bt_gatt::GattClientContext; use crate::callbacks::{ AdminCallback, AdvertisingSetCallback, BtCallback, BtConnectionCallback, BtManagerCallback, BtSocketManagerCallback, ScannerCallback, SuspendCallback, Loading @@ -28,6 +29,7 @@ use btstack::suspend::ISuspend; use manager_service::iface_bluetooth_manager::IBluetoothManager; mod bt_adv; mod bt_gatt; mod callbacks; mod command_handler; mod console; Loading Loading @@ -68,9 +70,6 @@ pub(crate) struct ClientContext { /// List of bonded devices. pub(crate) bonded_devices: HashMap<String, BluetoothDevice>, /// If set, the registered GATT client id. None otherwise. pub(crate) gatt_client_id: Option<i32>, /// Proxy for manager interface. pub(crate) manager_dbus: BluetoothManagerDBus, Loading Loading @@ -121,6 +120,9 @@ pub(crate) struct ClientContext { /// Is btclient running in restricted mode? is_restricted: bool, /// Data of GATT client preference. gatt_client_context: GattClientContext, } impl ClientContext { Loading @@ -144,7 +146,6 @@ impl ClientContext { discovering_state: false, found_devices: HashMap::new(), bonded_devices: HashMap::new(), gatt_client_id: None, manager_dbus, adapter_dbus: None, qa_dbus: None, Loading @@ -162,6 +163,7 @@ impl ClientContext { adv_sets: HashMap::new(), socket_manager_callback_id: None, is_restricted, gatt_client_context: GattClientContext::new(), } } Loading Loading
system/gd/rust/linux/client/Cargo.toml +2 −0 Original line number Diff line number Diff line Loading @@ -22,6 +22,8 @@ num-traits = "*" tokio = { version = "1", features = ['bytes', 'fs', 'io-util', 'libc', 'macros', 'memchr', 'mio', 'net', 'num_cpus', 'rt', 'rt-multi-thread', 'sync', 'time', 'tokio-macros'] } clap = "2.33.3" bitflags = "1.2" hex = "0.4.3" [build-dependencies] pkg-config = "0.3.19" Loading
system/gd/rust/linux/client/src/bt_gatt.rs 0 → 100644 +44 −0 Original line number Diff line number Diff line use bitflags::bitflags; use bt_topshim::btif::BtTransport; use bt_topshim::profiles::gatt::LePhy; bitflags! { pub(crate) struct AuthReq: i32 { // reference to system/stack/include/gatt_api.h const MITM = 0x01; const SIGNED = 0x10; } } /// User preferenece of GATT operations pub(crate) struct GattClientContext { /// If set, the registered GATT client id. None otherwise. pub(crate) client_id: Option<i32>, /// Type of authentication requirement pub(crate) auth_req: AuthReq, /// Is connection going to be directed? pub(crate) is_connect_direct: bool, /// Transport of connection pub(crate) connect_transport: BtTransport, /// Is connection going to be opportunistic? pub(crate) connect_opportunistic: bool, /// Type of connect phy pub(crate) connect_phy: LePhy, } impl GattClientContext { pub(crate) fn new() -> Self { GattClientContext { client_id: None, auth_req: AuthReq::empty(), is_connect_direct: false, connect_transport: BtTransport::Le, connect_opportunistic: false, connect_phy: LePhy::Phy1m, } } pub(crate) fn get_auth_req_bits(&self) -> i32 { self.auth_req.bits() } }
system/gd/rust/linux/client/src/callbacks.rs +1 −1 Original line number Diff line number Diff line Loading @@ -579,7 +579,7 @@ impl BtGattCallback { impl IBluetoothGattCallback for BtGattCallback { fn on_client_registered(&self, status: GattStatus, client_id: i32) { print_info!("GATT Client registered status = {}, client_id = {}", status, client_id); self.context.lock().unwrap().gatt_client_id = Some(client_id); self.context.lock().unwrap().gatt_client_context.client_id = Some(client_id); } fn on_client_connection_state( Loading
system/gd/rust/linux/client/src/command_handler.rs +225 −80 Original line number Diff line number Diff line Loading @@ -4,13 +4,14 @@ use std::slice::SliceIndex; use std::sync::{Arc, Mutex}; use crate::bt_adv::AdvSet; use crate::bt_gatt::AuthReq; use crate::callbacks::BtGattCallback; use crate::ClientContext; use crate::{console_red, console_yellow, print_error, print_info}; use bt_topshim::btif::{BtConnectionState, BtStatus, BtTransport}; use bt_topshim::profiles::gatt::LePhy; use btstack::bluetooth::{BluetoothDevice, IBluetooth, IBluetoothQA}; use btstack::bluetooth_gatt::{IBluetoothGatt, ScanSettings, ScanType}; use btstack::bluetooth_gatt::{GattWriteType, IBluetoothGatt, ScanSettings, ScanType}; use btstack::socket_manager::{IBluetoothSocketManager, SocketResult}; use btstack::uuid::{Profile, UuidHelper, UuidWrapper}; use manager_service::iface_bluetooth_manager::IBluetoothManager; Loading @@ -28,6 +29,18 @@ enum CommandError { Failed(String), } impl From<&str> for CommandError { fn from(s: &str) -> CommandError { CommandError::Failed(String::from(s)) } } impl From<String> for CommandError { fn from(s: String) -> CommandError { CommandError::Failed(s) } } type CommandResult = Result<(), CommandError>; type CommandFunction = fn(&mut CommandHandler, &Vec<String>) -> CommandResult; Loading Loading @@ -147,6 +160,15 @@ fn build_commands() -> HashMap<String, CommandOption> { String::from("gatt client-discover-services <address>"), String::from("gatt client-disconnect <address>"), String::from("gatt configure-mtu <address> <mtu>"), String::from("gatt set-direct-connect <true|false>"), String::from("gatt set-connect-transport <Bredr|LE|Auto>"), String::from("gatt set-connect-opportunistic <true|false>"), String::from("gatt set-connect-phy <Phy1m|Phy2m|PhyCoded>"), String::from("gatt set-auth-req <MITM|SIGNED> <enable|disable>"), String::from( "gatt write-characteristic <address> <handle> <NoRsp|Write|Prepare> <value>", ), String::from("gatt read-characteristic <address> <handle>"), ], description: String::from("GATT tools"), function_pointer: CommandHandler::cmd_gatt, Loading Loading @@ -271,10 +293,11 @@ impl CommandHandler { // Common message for when the adapter isn't ready fn adapter_not_ready(&self) -> CommandError { CommandError::Failed(format!( format!( "Default adapter {} is not enabled. Enable the adapter before using this command.", self.context.lock().unwrap().default_adapter )) ) .into() } fn cmd_help(&mut self, args: &Vec<String>) -> CommandResult { Loading Loading @@ -330,9 +353,7 @@ impl CommandHandler { fn cmd_adapter(&mut self, args: &Vec<String>) -> CommandResult { if !self.context.lock().unwrap().manager_dbus.get_floss_enabled() { return Err(CommandError::Failed( "Floss is not enabled. First run, `floss enable`".into(), )); return Err("Floss is not enabled. First run, `floss enable`".into()); } let default_adapter = self.context.lock().unwrap().default_adapter; Loading @@ -342,17 +363,13 @@ impl CommandHandler { match &command[..] { "enable" => { if self.context.lock().unwrap().is_restricted { return Err(CommandError::Failed( "You are not allowed to toggle adapter power".into(), )); return Err("You are not allowed to toggle adapter power".into()); } self.context.lock().unwrap().manager_dbus.start(default_adapter); } "disable" => { if self.context.lock().unwrap().is_restricted { return Err(CommandError::Failed( "You are not allowed to toggle adapter power".into(), )); return Err("You are not allowed to toggle adapter power".into()); } self.context.lock().unwrap().manager_dbus.stop(default_adapter); } Loading Loading @@ -529,13 +546,11 @@ impl CommandHandler { &self.context.lock().unwrap().bonding_attempt.as_ref().cloned(); if bonding_attempt.is_some() { return Err(CommandError::Failed( format!( return Err(format!( "Already bonding [{}]. Cancel bonding first.", bonding_attempt.as_ref().unwrap().address, ) .into(), )); .into()); } let success = self Loading Loading @@ -734,7 +749,7 @@ impl CommandHandler { "accept" => true, "reject" => false, other => { return Err(CommandError::Failed(format!("Failed to parse '{}'", other))); return Err(format!("Failed to parse '{}'", other).into()); } }; Loading @@ -756,7 +771,7 @@ impl CommandHandler { (_, Ok(p)) => (true, Vec::from(p.to_ne_bytes())), ("reject", _) => (false, vec![]), _ => { return Err(CommandError::Failed(format!("Failed to parse '{}'", pin))); return Err(format!("Failed to parse '{}'", pin).into()); } }; Loading @@ -776,7 +791,7 @@ impl CommandHandler { (_, Ok(p)) => (true, Vec::from(p.to_ne_bytes())), ("reject", _) => (false, vec![]), _ => { return Err(CommandError::Failed(format!("Failed to parse '{}'", passkey))); return Err(format!("Failed to parse '{}'", passkey).into()); } }; Loading Loading @@ -840,30 +855,39 @@ impl CommandHandler { ); } "client-connect" => { let client_id = self.context.lock().unwrap().gatt_client_id; if client_id.is_none() { return Err(CommandError::Failed(format!( "GATT client is not yet registered." ))); } let client_id = self .context .lock() .unwrap() .gatt_client_context .client_id .ok_or("GATT client is not yet registered.")?; let addr = String::from(get_arg(args, 1)?); let is_direct = self.context.lock().unwrap().gatt_client_context.is_connect_direct; let transport = self.context.lock().unwrap().gatt_client_context.connect_transport; let oppurtunistic = self.context.lock().unwrap().gatt_client_context.connect_opportunistic; let phy = self.context.lock().unwrap().gatt_client_context.connect_phy; println!("Initiating GATT client connect. client_id: {}, addr: {}, is_direct: {}, transport: {:?}, oppurtunistic: {}, phy: {:?}", client_id, addr, is_direct, transport, oppurtunistic, phy); self.context.lock().unwrap().gatt_dbus.as_ref().unwrap().client_connect( client_id.unwrap(), client_id, addr, false, BtTransport::Le, false, LePhy::Phy1m, is_direct, transport, oppurtunistic, phy, ); } "client-disconnect" => { let client_id = self.context.lock().unwrap().gatt_client_id; if client_id.is_none() { return Err(CommandError::Failed(format!( "GATT client is not yet registered." ))); } let client_id = self .context .lock() .unwrap() .gatt_client_context .client_id .ok_or("GATT client is not yet registered.")?; let addr = String::from(get_arg(args, 1)?); self.context Loading @@ -872,16 +896,16 @@ impl CommandHandler { .gatt_dbus .as_ref() .unwrap() .client_disconnect(client_id.unwrap(), addr); .client_disconnect(client_id, addr); } "client-read-phy" => { let client_id = self.context.lock().unwrap().gatt_client_id; if client_id.is_none() { return Err(CommandError::Failed(format!( "GATT client is not yet registered." ))); } let client_id = self .context .lock() .unwrap() .gatt_client_context .client_id .ok_or("GATT client is not yet registered.")?; let addr = String::from(get_arg(args, 1)?); self.context .lock() Loading @@ -889,15 +913,16 @@ impl CommandHandler { .gatt_dbus .as_mut() .unwrap() .client_read_phy(client_id.unwrap(), addr); .client_read_phy(client_id, addr); } "client-discover-services" => { let client_id = self.context.lock().unwrap().gatt_client_id; if client_id.is_none() { return Err(CommandError::Failed(format!( "GATT client is not yet registered." ))); } let client_id = self .context .lock() .unwrap() .gatt_client_context .client_id .ok_or("GATT client is not yet registered.")?; let addr = String::from(get_arg(args, 1)?); self.context Loading @@ -906,31 +931,150 @@ impl CommandHandler { .gatt_dbus .as_ref() .unwrap() .discover_services(client_id.unwrap(), addr); .discover_services(client_id, addr); } "configure-mtu" => { let client_id = self.context.lock().unwrap().gatt_client_id; if client_id.is_none() { return Err(CommandError::Failed(format!( "GATT client is not yet registered." ))); } let client_id = self .context .lock() .unwrap() .gatt_client_context .client_id .ok_or("GATT client is not yet registered.")?; let addr = String::from(get_arg(args, 1)?); let mtu = String::from(get_arg(args, 2)?).parse::<i32>(); if let Ok(m) = mtu { self.context.lock().unwrap().gatt_dbus.as_ref().unwrap().configure_mtu( client_id.unwrap(), addr, m, let mtu = String::from(get_arg(args, 2)?).parse::<i32>().or(Err("Failed parsing mtu"))?; self.context .lock() .unwrap() .gatt_dbus .as_ref() .unwrap() .configure_mtu(client_id, addr, mtu) } "set-direct-connect" => { let is_direct = String::from(get_arg(args, 1)?) .parse::<bool>() .or(Err("Failed to parse is_direct"))?; self.context.lock().unwrap().gatt_client_context.is_connect_direct = is_direct; } "set-connect-transport" => { let transport = match &get_arg(args, 1)?[..] { "Bredr" => BtTransport::Bredr, "LE" => BtTransport::Le, "Auto" => BtTransport::Auto, _ => { return Err("Failed to parse transport".into()); } }; self.context.lock().unwrap().gatt_client_context.connect_transport = transport; } "set-connect-opportunistic" => { let opportunistic = String::from(get_arg(args, 1)?) .parse::<bool>() .or(Err("Failed to parse opportunistic"))?; self.context.lock().unwrap().gatt_client_context.connect_opportunistic = opportunistic; } "set-connect-phy" => { let phy = match &get_arg(args, 1)?[..] { "Phy1m" => LePhy::Phy1m, "Phy2m" => LePhy::Phy2m, "PhyCoded" => LePhy::PhyCoded, _ => { return Err("Failed to parse phy".into()); } }; self.context.lock().unwrap().gatt_client_context.connect_phy = phy; } "set-auth-req" => { let flag = match &get_arg(args, 1)?[..] { "MITM" => AuthReq::MITM, "SIGNED" => AuthReq::SIGNED, _ => { return Err("Failed to parse auth-req".into()); } }; let enable = match &get_arg(args, 2)?[..] { "enable" => true, "disable" => false, _ => { return Err("Failed to parse enable".into()); } }; self.context.lock().unwrap().gatt_client_context.auth_req.set(flag, enable); println!( "AuthReq: {:?}", self.context.lock().unwrap().gatt_client_context.auth_req ); } else { return Err(CommandError::Failed(format!("Failed parsing mtu"))); } "write-characteristic" => { let addr = String::from(get_arg(args, 1)?); let handle = String::from(get_arg(args, 2)?) .parse::<i32>() .or(Err("Failed to parse handle"))?; let write_type = match &get_arg(args, 3)?[..] { "NoRsp" => GattWriteType::WriteNoRsp, "Write" => GattWriteType::Write, "Prepare" => GattWriteType::WritePrepare, _ => { return Err("Failed to parse write-type".into()); } _ => return Err(CommandError::InvalidArgs), }; let value = hex::decode(&get_arg(args, 4)?).or(Err("Failed to parse value"))?; let client_id = self .context .lock() .unwrap() .gatt_client_context .client_id .ok_or("GATT client is not yet registered.")?; let auth_req = self.context.lock().unwrap().gatt_client_context.get_auth_req_bits(); self.context .lock() .unwrap() .gatt_dbus .as_ref() .unwrap() .write_characteristic(client_id, addr, handle, write_type, auth_req, value); } "read-characteristic" => { let addr = String::from(get_arg(args, 1)?); let handle = String::from(get_arg(args, 2)?) .parse::<i32>() .or(Err("Failed to parse handle"))?; let client_id = self .context .lock() .unwrap() .gatt_client_context .client_id .ok_or("GATT client is not yet registered.")?; let auth_req = self.context.lock().unwrap().gatt_client_context.get_auth_req_bits(); self.context .lock() .unwrap() .gatt_dbus .as_ref() .unwrap() .read_characteristic(client_id, addr, handle, auth_req); } _ => return Err(CommandError::InvalidArgs), } Ok(()) } Loading Loading @@ -964,7 +1108,7 @@ impl CommandHandler { if let Ok(id) = scanner_id { self.context.lock().unwrap().gatt_dbus.as_mut().unwrap().unregister_scanner(id); } else { return Err(CommandError::Failed(format!("Failed parsing scanner id"))); return Err("Failed parsing scanner id".into()); } } "start-scan" => { Loading @@ -988,7 +1132,7 @@ impl CommandHandler { ); self.context.lock().unwrap().active_scanner_ids.insert(id); } else { return Err(CommandError::Failed(format!("Failed parsing scanner id"))); return Err("Failed parsing scanner id".into()); } } "stop-scan" => { Loading @@ -998,7 +1142,7 @@ impl CommandHandler { self.context.lock().unwrap().gatt_dbus.as_mut().unwrap().stop_scan(id); self.context.lock().unwrap().active_scanner_ids.remove(&id); } else { return Err(CommandError::Failed(format!("Failed parsing scanner id"))); return Err("Failed parsing scanner id".into()); } } _ => return Err(CommandError::InvalidArgs), Loading @@ -1015,7 +1159,7 @@ impl CommandHandler { } if self.context.lock().unwrap().advertiser_callback_id == None { return Err(CommandError::Failed("No advertiser callback registered".into())); return Err("No advertiser callback registered".into()); } let callback_id = self.context.lock().unwrap().advertiser_callback_id.clone().unwrap(); Loading @@ -1039,7 +1183,7 @@ impl CommandHandler { "set-interval" => { let ms = String::from(get_arg(args, 1)?).parse::<i32>(); if !ms.is_ok() { return Err(CommandError::Failed(format!("Failed parsing interval"))); return Err("Failed parsing interval".into()); } let interval = ms.unwrap() * 8 / 5; // in 0.625 ms. Loading Loading @@ -1098,7 +1242,7 @@ impl CommandHandler { let callback_id = match self.context.lock().unwrap().socket_manager_callback_id.clone() { Some(id) => id, None => { return Err(CommandError::Failed("No socket manager callback registered.".into())); return Err("No socket manager callback registered.".into()); } }; Loading @@ -1116,10 +1260,11 @@ impl CommandHandler { .listen_using_l2cap_channel(callback_id); if status != BtStatus::Success { return Err(CommandError::Failed(format!( return Err(format!( "Failed to request for listening using l2cap channel, status = {:?}", status, ))); ) .into()); } print_info!("Requested for listening using l2cap channel on socket {}", id); } Loading
system/gd/rust/linux/client/src/main.rs +6 −4 Original line number Diff line number Diff line Loading @@ -12,6 +12,7 @@ use dbus_crossroads::Crossroads; use tokio::sync::mpsc; use crate::bt_adv::AdvSet; use crate::bt_gatt::GattClientContext; use crate::callbacks::{ AdminCallback, AdvertisingSetCallback, BtCallback, BtConnectionCallback, BtManagerCallback, BtSocketManagerCallback, ScannerCallback, SuspendCallback, Loading @@ -28,6 +29,7 @@ use btstack::suspend::ISuspend; use manager_service::iface_bluetooth_manager::IBluetoothManager; mod bt_adv; mod bt_gatt; mod callbacks; mod command_handler; mod console; Loading Loading @@ -68,9 +70,6 @@ pub(crate) struct ClientContext { /// List of bonded devices. pub(crate) bonded_devices: HashMap<String, BluetoothDevice>, /// If set, the registered GATT client id. None otherwise. pub(crate) gatt_client_id: Option<i32>, /// Proxy for manager interface. pub(crate) manager_dbus: BluetoothManagerDBus, Loading Loading @@ -121,6 +120,9 @@ pub(crate) struct ClientContext { /// Is btclient running in restricted mode? is_restricted: bool, /// Data of GATT client preference. gatt_client_context: GattClientContext, } impl ClientContext { Loading @@ -144,7 +146,6 @@ impl ClientContext { discovering_state: false, found_devices: HashMap::new(), bonded_devices: HashMap::new(), gatt_client_id: None, manager_dbus, adapter_dbus: None, qa_dbus: None, Loading @@ -162,6 +163,7 @@ impl ClientContext { adv_sets: HashMap::new(), socket_manager_callback_id: None, is_restricted, gatt_client_context: GattClientContext::new(), } } Loading