Loading system/gd/rust/linux/client/src/bt_adv.rs 0 → 100644 +53 −0 Original line number Diff line number Diff line use std::collections::HashMap; use bt_topshim::btif::Uuid; use bt_topshim::profiles::gatt::LePhy; use btstack::bluetooth_adv::{AdvertiseData, AdvertiserId, AdvertisingSetParameters}; /// Avertisement parameter and data for a BLE advertising set. #[derive(Debug, Clone)] pub(crate) struct AdvSet { /// ID for the advertising set if it's being started successfully, None otherwise. pub(crate) adv_id: Option<AdvertiserId>, /// Advertising parameters. pub(crate) params: AdvertisingSetParameters, /// Advertising data. pub(crate) data: AdvertiseData, } impl AdvSet { pub(crate) fn new() -> Self { let params = AdvertisingSetParameters { connectable: false, scannable: false, is_legacy: true, is_anonymous: false, include_tx_power: true, primary_phy: LePhy::Phy1m, secondary_phy: LePhy::Phy1m, interval: 100, tx_power_level: 0x7f, // no preference own_address_type: 1, // random }; let data = AdvertiseData { service_uuids: vec![Uuid::from([ 0x00, 0x00, 0xfe, 0xf3, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb, ])], solicit_uuids: Vec::new(), transport_discovery_data: Vec::new(), manufacturer_data: HashMap::from([(0, vec![0, 1, 2])]), service_data: HashMap::from([( "0000fef3-0000-1000-8000-00805f9b34fb".to_string(), vec![0x0a, 0x0b], )]), include_tx_power_level: true, include_device_name: true, }; AdvSet { adv_id: None, params, data } } } system/gd/rust/linux/client/src/callbacks.rs +8 −12 Original line number Diff line number Diff line Loading @@ -436,22 +436,18 @@ impl IAdvertisingSetCallback for AdvertisingSetCallback { tx_power, status ); if status == GattStatus::Success { if let Some(Some(ex_adv_id)) = self.context.lock().unwrap().adv_sets.insert(reg_id, Some(advertiser_id)) { print_error!( "on_advertising_set_started: previous advertising set ({}) registered ({}) is omitted", ex_adv_id, reg_id, ); } } else { if status != GattStatus::Success { print_error!( "on_advertising_set_started: remove advertising set registered ({})", reg_id ); self.context.lock().unwrap().adv_sets.remove(®_id); return; } if let Some(s) = self.context.lock().unwrap().adv_sets.get_mut(®_id) { s.adv_id = Some(advertiser_id); } else { print_error!("on_advertising_set_started: invalid callback for reg_id={}", reg_id); } } Loading @@ -466,7 +462,7 @@ impl IAdvertisingSetCallback for AdvertisingSetCallback { fn on_advertising_set_stopped(&self, advertiser_id: i32) { print_info!("on_advertising_set_stopped: advertiser_id = {}", advertiser_id); self.context.lock().unwrap().adv_sets.retain(|_, val| *val != Some(advertiser_id)); self.context.lock().unwrap().adv_sets.retain(|_, s| s.adv_id != Some(advertiser_id)); } fn on_advertising_enabled(&self, advertiser_id: i32, enable: bool, status: GattStatus) { Loading system/gd/rust/linux/client/src/command_handler.rs +66 −46 Original line number Diff line number Diff line Loading @@ -2,13 +2,14 @@ use std::collections::HashMap; use std::fmt::{Display, Formatter, Result}; use std::sync::{Arc, Mutex}; use crate::bt_adv::AdvSet; use crate::callbacks::BtGattCallback; use crate::ClientContext; use crate::{console_red, console_yellow, print_error, print_info}; use bt_topshim::btif::{BtConnectionState, BtStatus, BtTransport, Uuid}; use bt_topshim::btif::{BtConnectionState, BtStatus, BtTransport}; use bt_topshim::profiles::gatt::LePhy; use btstack::bluetooth::{BluetoothDevice, IBluetooth, IBluetoothQA}; use btstack::bluetooth_adv::{AdvertiseData, AdvertisingSetParameters}; use btstack::bluetooth_adv::{AdvertiserId, RegId}; use btstack::bluetooth_gatt::{ IBluetoothGatt, ScanFilter, ScanFilterCondition, ScanSettings, ScanType, }; Loading Loading @@ -164,7 +165,7 @@ fn build_commands() -> HashMap<String, CommandOption> { command_options.insert( String::from("advertise"), CommandOption { rules: vec![String::from("advertise <on|off>")], rules: vec![String::from("advertise <on|off|set-interval>")], description: String::from("Advertising utilities."), function_pointer: CommandHandler::cmd_advertise, }, Loading Loading @@ -939,67 +940,86 @@ impl CommandHandler { } let callback_id = self.context.lock().unwrap().advertiser_callback_id.clone().unwrap(); enforce_arg_len(args, 1, "advertise <commands>", || match &args[0][0..] { enforce_arg_len(args, 1, "advertise <on|off|set-interval>", || match &args[0][0..] { "on" => { if self.context.lock().unwrap().adv_sets.keys().len() > 0 { print_error!("Already started advertising"); return; } let params = AdvertisingSetParameters { connectable: false, scannable: false, is_legacy: true, is_anonymous: false, include_tx_power: true, primary_phy: LePhy::Phy1m, secondary_phy: LePhy::Phy1m, interval: 160, tx_power_level: -21, own_address_type: 0, // random }; let data = AdvertiseData { service_uuids: vec![Uuid::from([ 0x00, 0x00, 0xfe, 0xf3, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb, ])], solicit_uuids: Vec::new(), transport_discovery_data: Vec::new(), manufacturer_data: HashMap::from([(0, vec![0, 1, 2])]), service_data: HashMap::from([( "0000fef3-0000-1000-8000-00805f9b34fb".to_string(), vec![0x0a, 0x0b], )]), include_tx_power_level: true, include_device_name: true, }; let reg_id = self let s = AdvSet::new(); let reg_id = self.context.lock().unwrap().gatt_dbus.as_mut().unwrap().start_advertising_set( s.params.clone(), s.data.clone(), None, None, None, 0, 0, callback_id, ); print_info!("Starting advertising set for reg_id = {}", reg_id); self.context.lock().unwrap().adv_sets.insert(reg_id, s); } "off" => { let adv_ids: Vec<AdvertiserId> = self .context .lock() .unwrap() .adv_sets .iter() .filter_map(|(_, s)| s.adv_id) .collect(); for adv_id in adv_ids { print_info!("Stopping advertising set {}", adv_id); self.context .lock() .unwrap() .gatt_dbus .as_mut() .unwrap() .start_advertising_set(params, data, None, None, None, 0, 0, callback_id); print_info!("Starting advertising set for reg_id = {}", reg_id); .stop_advertising_set(adv_id); } "off" => { let adv_sets = self.context.lock().unwrap().adv_sets.clone(); for (_, val) in adv_sets.iter() { if let Some(&adv_id) = val.as_ref() { print_info!("Stopping advertising set {}", adv_id); self.context.lock().unwrap().adv_sets.clear(); } "set-interval" => { if args.len() < 2 { println!("usage: advertise set-interval <ms>"); return; } let ms = String::from(&args[1]).parse::<i32>(); if !ms.is_ok() { print_error!("Failed parsing interval"); return; } let interval = ms.unwrap() * 8 / 5; // in 0.625 ms. let reg_ids: Vec<RegId> = self.context.lock().unwrap().adv_sets.keys().copied().collect(); for reg_id in reg_ids { self.context .lock() .unwrap() .adv_sets .get_mut(®_id) .unwrap() .params .interval = interval; let adv_id = self.context.lock().unwrap().adv_sets[®_id].adv_id.clone(); if let Some(adv_id) = adv_id { let params = self.context.lock().unwrap().adv_sets[®_id].params.clone(); print_info!("Setting advertising parameters for {}", adv_id); self.context .lock() .unwrap() .gatt_dbus .as_mut() .unwrap() .stop_advertising_set(adv_id); .set_advertising_parameters(adv_id, params); } } self.context.lock().unwrap().adv_sets.clear(); } _ => { println!("Invalid argument '{}'", args[0]); Loading system/gd/rust/linux/client/src/main.rs +4 −2 Original line number Diff line number Diff line Loading @@ -7,6 +7,7 @@ use dbus::nonblock::SyncConnection; use dbus_crossroads::Crossroads; use tokio::sync::mpsc; use crate::bt_adv::AdvSet; use crate::callbacks::{ AdminCallback, AdvertisingSetCallback, BtCallback, BtConnectionCallback, BtManagerCallback, BtSocketManagerCallback, ScannerCallback, SuspendCallback, Loading @@ -22,6 +23,7 @@ use btstack::bluetooth::{BluetoothDevice, IBluetooth}; use btstack::suspend::ISuspend; use manager_service::iface_bluetooth_manager::IBluetoothManager; mod bt_adv; mod callbacks; mod command_handler; mod console; Loading Loading @@ -107,8 +109,8 @@ pub(crate) struct ClientContext { /// Keeps track of active LE scanners. active_scanner_ids: HashSet<u8>, /// Advertising sets started/registered. Map from reg_id to advertiser_id. adv_sets: HashMap<i32, Option<i32>>, /// Keeps track of advertising sets registered. Map from reg_id to AdvSet. adv_sets: HashMap<i32, AdvSet>, /// Identifies the callback to receive IBluetoothSocketManagerCallback method calls. socket_manager_callback_id: Option<u32>, Loading system/gd/rust/linux/stack/src/bluetooth_adv.rs +2 −2 Original line number Diff line number Diff line Loading @@ -20,7 +20,7 @@ pub type RegId = i32; pub type ManfId = u16; /// Advertising parameters for each BLE advertising set. #[derive(Debug, Default)] #[derive(Debug, Default, Clone)] pub struct AdvertisingSetParameters { /// Whether the advertisement will be connectable. pub connectable: bool, Loading Loading @@ -49,7 +49,7 @@ pub struct AdvertisingSetParameters { } /// Represents the data to be advertised and the scan response data for active scans. #[derive(Debug, Default)] #[derive(Debug, Default, Clone)] pub struct AdvertiseData { /// A list of service UUIDs within the advertisement that are used to identify /// the Bluetooth GATT services. Loading Loading
system/gd/rust/linux/client/src/bt_adv.rs 0 → 100644 +53 −0 Original line number Diff line number Diff line use std::collections::HashMap; use bt_topshim::btif::Uuid; use bt_topshim::profiles::gatt::LePhy; use btstack::bluetooth_adv::{AdvertiseData, AdvertiserId, AdvertisingSetParameters}; /// Avertisement parameter and data for a BLE advertising set. #[derive(Debug, Clone)] pub(crate) struct AdvSet { /// ID for the advertising set if it's being started successfully, None otherwise. pub(crate) adv_id: Option<AdvertiserId>, /// Advertising parameters. pub(crate) params: AdvertisingSetParameters, /// Advertising data. pub(crate) data: AdvertiseData, } impl AdvSet { pub(crate) fn new() -> Self { let params = AdvertisingSetParameters { connectable: false, scannable: false, is_legacy: true, is_anonymous: false, include_tx_power: true, primary_phy: LePhy::Phy1m, secondary_phy: LePhy::Phy1m, interval: 100, tx_power_level: 0x7f, // no preference own_address_type: 1, // random }; let data = AdvertiseData { service_uuids: vec![Uuid::from([ 0x00, 0x00, 0xfe, 0xf3, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb, ])], solicit_uuids: Vec::new(), transport_discovery_data: Vec::new(), manufacturer_data: HashMap::from([(0, vec![0, 1, 2])]), service_data: HashMap::from([( "0000fef3-0000-1000-8000-00805f9b34fb".to_string(), vec![0x0a, 0x0b], )]), include_tx_power_level: true, include_device_name: true, }; AdvSet { adv_id: None, params, data } } }
system/gd/rust/linux/client/src/callbacks.rs +8 −12 Original line number Diff line number Diff line Loading @@ -436,22 +436,18 @@ impl IAdvertisingSetCallback for AdvertisingSetCallback { tx_power, status ); if status == GattStatus::Success { if let Some(Some(ex_adv_id)) = self.context.lock().unwrap().adv_sets.insert(reg_id, Some(advertiser_id)) { print_error!( "on_advertising_set_started: previous advertising set ({}) registered ({}) is omitted", ex_adv_id, reg_id, ); } } else { if status != GattStatus::Success { print_error!( "on_advertising_set_started: remove advertising set registered ({})", reg_id ); self.context.lock().unwrap().adv_sets.remove(®_id); return; } if let Some(s) = self.context.lock().unwrap().adv_sets.get_mut(®_id) { s.adv_id = Some(advertiser_id); } else { print_error!("on_advertising_set_started: invalid callback for reg_id={}", reg_id); } } Loading @@ -466,7 +462,7 @@ impl IAdvertisingSetCallback for AdvertisingSetCallback { fn on_advertising_set_stopped(&self, advertiser_id: i32) { print_info!("on_advertising_set_stopped: advertiser_id = {}", advertiser_id); self.context.lock().unwrap().adv_sets.retain(|_, val| *val != Some(advertiser_id)); self.context.lock().unwrap().adv_sets.retain(|_, s| s.adv_id != Some(advertiser_id)); } fn on_advertising_enabled(&self, advertiser_id: i32, enable: bool, status: GattStatus) { Loading
system/gd/rust/linux/client/src/command_handler.rs +66 −46 Original line number Diff line number Diff line Loading @@ -2,13 +2,14 @@ use std::collections::HashMap; use std::fmt::{Display, Formatter, Result}; use std::sync::{Arc, Mutex}; use crate::bt_adv::AdvSet; use crate::callbacks::BtGattCallback; use crate::ClientContext; use crate::{console_red, console_yellow, print_error, print_info}; use bt_topshim::btif::{BtConnectionState, BtStatus, BtTransport, Uuid}; use bt_topshim::btif::{BtConnectionState, BtStatus, BtTransport}; use bt_topshim::profiles::gatt::LePhy; use btstack::bluetooth::{BluetoothDevice, IBluetooth, IBluetoothQA}; use btstack::bluetooth_adv::{AdvertiseData, AdvertisingSetParameters}; use btstack::bluetooth_adv::{AdvertiserId, RegId}; use btstack::bluetooth_gatt::{ IBluetoothGatt, ScanFilter, ScanFilterCondition, ScanSettings, ScanType, }; Loading Loading @@ -164,7 +165,7 @@ fn build_commands() -> HashMap<String, CommandOption> { command_options.insert( String::from("advertise"), CommandOption { rules: vec![String::from("advertise <on|off>")], rules: vec![String::from("advertise <on|off|set-interval>")], description: String::from("Advertising utilities."), function_pointer: CommandHandler::cmd_advertise, }, Loading Loading @@ -939,67 +940,86 @@ impl CommandHandler { } let callback_id = self.context.lock().unwrap().advertiser_callback_id.clone().unwrap(); enforce_arg_len(args, 1, "advertise <commands>", || match &args[0][0..] { enforce_arg_len(args, 1, "advertise <on|off|set-interval>", || match &args[0][0..] { "on" => { if self.context.lock().unwrap().adv_sets.keys().len() > 0 { print_error!("Already started advertising"); return; } let params = AdvertisingSetParameters { connectable: false, scannable: false, is_legacy: true, is_anonymous: false, include_tx_power: true, primary_phy: LePhy::Phy1m, secondary_phy: LePhy::Phy1m, interval: 160, tx_power_level: -21, own_address_type: 0, // random }; let data = AdvertiseData { service_uuids: vec![Uuid::from([ 0x00, 0x00, 0xfe, 0xf3, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb, ])], solicit_uuids: Vec::new(), transport_discovery_data: Vec::new(), manufacturer_data: HashMap::from([(0, vec![0, 1, 2])]), service_data: HashMap::from([( "0000fef3-0000-1000-8000-00805f9b34fb".to_string(), vec![0x0a, 0x0b], )]), include_tx_power_level: true, include_device_name: true, }; let reg_id = self let s = AdvSet::new(); let reg_id = self.context.lock().unwrap().gatt_dbus.as_mut().unwrap().start_advertising_set( s.params.clone(), s.data.clone(), None, None, None, 0, 0, callback_id, ); print_info!("Starting advertising set for reg_id = {}", reg_id); self.context.lock().unwrap().adv_sets.insert(reg_id, s); } "off" => { let adv_ids: Vec<AdvertiserId> = self .context .lock() .unwrap() .adv_sets .iter() .filter_map(|(_, s)| s.adv_id) .collect(); for adv_id in adv_ids { print_info!("Stopping advertising set {}", adv_id); self.context .lock() .unwrap() .gatt_dbus .as_mut() .unwrap() .start_advertising_set(params, data, None, None, None, 0, 0, callback_id); print_info!("Starting advertising set for reg_id = {}", reg_id); .stop_advertising_set(adv_id); } "off" => { let adv_sets = self.context.lock().unwrap().adv_sets.clone(); for (_, val) in adv_sets.iter() { if let Some(&adv_id) = val.as_ref() { print_info!("Stopping advertising set {}", adv_id); self.context.lock().unwrap().adv_sets.clear(); } "set-interval" => { if args.len() < 2 { println!("usage: advertise set-interval <ms>"); return; } let ms = String::from(&args[1]).parse::<i32>(); if !ms.is_ok() { print_error!("Failed parsing interval"); return; } let interval = ms.unwrap() * 8 / 5; // in 0.625 ms. let reg_ids: Vec<RegId> = self.context.lock().unwrap().adv_sets.keys().copied().collect(); for reg_id in reg_ids { self.context .lock() .unwrap() .adv_sets .get_mut(®_id) .unwrap() .params .interval = interval; let adv_id = self.context.lock().unwrap().adv_sets[®_id].adv_id.clone(); if let Some(adv_id) = adv_id { let params = self.context.lock().unwrap().adv_sets[®_id].params.clone(); print_info!("Setting advertising parameters for {}", adv_id); self.context .lock() .unwrap() .gatt_dbus .as_mut() .unwrap() .stop_advertising_set(adv_id); .set_advertising_parameters(adv_id, params); } } self.context.lock().unwrap().adv_sets.clear(); } _ => { println!("Invalid argument '{}'", args[0]); Loading
system/gd/rust/linux/client/src/main.rs +4 −2 Original line number Diff line number Diff line Loading @@ -7,6 +7,7 @@ use dbus::nonblock::SyncConnection; use dbus_crossroads::Crossroads; use tokio::sync::mpsc; use crate::bt_adv::AdvSet; use crate::callbacks::{ AdminCallback, AdvertisingSetCallback, BtCallback, BtConnectionCallback, BtManagerCallback, BtSocketManagerCallback, ScannerCallback, SuspendCallback, Loading @@ -22,6 +23,7 @@ use btstack::bluetooth::{BluetoothDevice, IBluetooth}; use btstack::suspend::ISuspend; use manager_service::iface_bluetooth_manager::IBluetoothManager; mod bt_adv; mod callbacks; mod command_handler; mod console; Loading Loading @@ -107,8 +109,8 @@ pub(crate) struct ClientContext { /// Keeps track of active LE scanners. active_scanner_ids: HashSet<u8>, /// Advertising sets started/registered. Map from reg_id to advertiser_id. adv_sets: HashMap<i32, Option<i32>>, /// Keeps track of advertising sets registered. Map from reg_id to AdvSet. adv_sets: HashMap<i32, AdvSet>, /// Identifies the callback to receive IBluetoothSocketManagerCallback method calls. socket_manager_callback_id: Option<u32>, Loading
system/gd/rust/linux/stack/src/bluetooth_adv.rs +2 −2 Original line number Diff line number Diff line Loading @@ -20,7 +20,7 @@ pub type RegId = i32; pub type ManfId = u16; /// Advertising parameters for each BLE advertising set. #[derive(Debug, Default)] #[derive(Debug, Default, Clone)] pub struct AdvertisingSetParameters { /// Whether the advertisement will be connectable. pub connectable: bool, Loading Loading @@ -49,7 +49,7 @@ pub struct AdvertisingSetParameters { } /// Represents the data to be advertised and the scan response data for active scans. #[derive(Debug, Default)] #[derive(Debug, Default, Clone)] pub struct AdvertiseData { /// A list of service UUIDs within the advertisement that are used to identify /// the Bluetooth GATT services. Loading