1 //! BLE Advertising types and utilities 2 3 use bt_topshim::btif::Uuid; 4 use bt_topshim::profiles::gatt::{AdvertisingStatus, Gatt, LePhy}; 5 6 use itertools::Itertools; 7 use log::warn; 8 use num_traits::clamp; 9 use std::collections::HashMap; 10 use std::sync::atomic::{AtomicIsize, Ordering}; 11 use tokio::sync::mpsc::Sender; 12 13 use crate::callbacks::Callbacks; 14 use crate::uuid::UuidHelper; 15 use crate::{Message, RPCProxy, SuspendMode}; 16 17 pub type AdvertiserId = i32; 18 pub type CallbackId = u32; 19 pub type RegId = i32; 20 pub type ManfId = u16; 21 22 /// Advertising parameters for each BLE advertising set. 23 #[derive(Debug, Default, Clone)] 24 pub struct AdvertisingSetParameters { 25 /// Whether the advertisement will be connectable. 26 pub connectable: bool, 27 /// Whether the advertisement will be scannable. 28 pub scannable: bool, 29 /// Whether the legacy advertisement will be used. 30 pub is_legacy: bool, 31 /// Whether the advertisement will be anonymous. 32 pub is_anonymous: bool, 33 /// Whether the TX Power will be included. 34 pub include_tx_power: bool, 35 /// Primary advertising phy. Valid values are: 1 (1M), 2 (2M), 3 (Coded). 36 pub primary_phy: LePhy, 37 /// Secondary advertising phy. Valid values are: 1 (1M), 2 (2M), 3 (Coded). 38 pub secondary_phy: LePhy, 39 /// The advertising interval. Bluetooth LE Advertising interval, in 0.625 ms unit. 40 /// The valid range is from 160 (100 ms) to 16777215 (10485.759375 sec). 41 /// Recommended values are: 160 (100 ms), 400 (250 ms), 1600 (1 sec). 42 pub interval: i32, 43 /// Transmission power of Bluetooth LE Advertising, in dBm. The valid range is [-127, 1]. 44 /// Recommended values are: -21, -15, 7, 1. 45 pub tx_power_level: i32, 46 /// Own address type for advertising to control public or privacy mode. 47 /// The valid types are: -1 (default), 0 (public), 1 (random). 48 pub own_address_type: i32, 49 } 50 51 /// Represents the data to be advertised and the scan response data for active scans. 52 #[derive(Debug, Default, Clone)] 53 pub struct AdvertiseData { 54 /// A list of service UUIDs within the advertisement that are used to identify 55 /// the Bluetooth GATT services. 56 pub service_uuids: Vec<Uuid>, 57 /// A list of service solicitation UUIDs within the advertisement that we invite to connect. 58 pub solicit_uuids: Vec<Uuid>, 59 /// A list of transport discovery data. 60 pub transport_discovery_data: Vec<Vec<u8>>, 61 /// A collection of manufacturer Id and the corresponding manufacturer specific data. 62 pub manufacturer_data: HashMap<ManfId, Vec<u8>>, 63 /// A map of 128-bit UUID and its corresponding service data. 64 pub service_data: HashMap<String, Vec<u8>>, 65 /// Whether TX Power level will be included in the advertising packet. 66 pub include_tx_power_level: bool, 67 /// Whether the device name will be included in the advertisement packet. 68 pub include_device_name: bool, 69 } 70 71 /// Parameters of the periodic advertising packet for BLE advertising set. 72 #[derive(Debug, Default)] 73 pub struct PeriodicAdvertisingParameters { 74 /// Whether TX Power level will be included. 75 pub include_tx_power: bool, 76 /// Periodic advertising interval in 1.25 ms unit. Valid values are from 80 (100 ms) to 77 /// 65519 (81.89875 sec). Value from range [interval, interval+20ms] will be picked as 78 /// the actual value. 79 pub interval: i32, 80 } 81 82 /// Interface for advertiser callbacks to clients, passed to 83 /// `IBluetoothGatt::start_advertising_set`. 84 pub trait IAdvertisingSetCallback: RPCProxy { 85 /// Callback triggered in response to `start_advertising_set` indicating result of 86 /// the operation. 87 /// 88 /// * `reg_id` - Identifies the advertising set registered by `start_advertising_set`. 89 /// * `advertiser_id` - ID for the advertising set. It will be used in other advertising methods 90 /// and callbacks. 91 /// * `tx_power` - Transmit power that will be used for this advertising set. 92 /// * `status` - Status of this operation. on_advertising_set_started( &mut self, reg_id: i32, advertiser_id: i32, tx_power: i32, status: AdvertisingStatus, )93 fn on_advertising_set_started( 94 &mut self, 95 reg_id: i32, 96 advertiser_id: i32, 97 tx_power: i32, 98 status: AdvertisingStatus, 99 ); 100 101 /// Callback triggered in response to `get_own_address` indicating result of the operation. on_own_address_read(&mut self, advertiser_id: i32, address_type: i32, address: String)102 fn on_own_address_read(&mut self, advertiser_id: i32, address_type: i32, address: String); 103 104 /// Callback triggered in response to `stop_advertising_set` indicating the advertising set 105 /// is stopped. on_advertising_set_stopped(&mut self, advertiser_id: i32)106 fn on_advertising_set_stopped(&mut self, advertiser_id: i32); 107 108 /// Callback triggered in response to `enable_advertising_set` indicating result of 109 /// the operation. on_advertising_enabled( &mut self, advertiser_id: i32, enable: bool, status: AdvertisingStatus, )110 fn on_advertising_enabled( 111 &mut self, 112 advertiser_id: i32, 113 enable: bool, 114 status: AdvertisingStatus, 115 ); 116 117 /// Callback triggered in response to `set_advertising_data` indicating result of the operation. on_advertising_data_set(&mut self, advertiser_id: i32, status: AdvertisingStatus)118 fn on_advertising_data_set(&mut self, advertiser_id: i32, status: AdvertisingStatus); 119 120 /// Callback triggered in response to `set_scan_response_data` indicating result of 121 /// the operation. on_scan_response_data_set(&mut self, advertiser_id: i32, status: AdvertisingStatus)122 fn on_scan_response_data_set(&mut self, advertiser_id: i32, status: AdvertisingStatus); 123 124 /// Callback triggered in response to `set_advertising_parameters` indicating result of 125 /// the operation. on_advertising_parameters_updated( &mut self, advertiser_id: i32, tx_power: i32, status: AdvertisingStatus, )126 fn on_advertising_parameters_updated( 127 &mut self, 128 advertiser_id: i32, 129 tx_power: i32, 130 status: AdvertisingStatus, 131 ); 132 133 /// Callback triggered in response to `set_periodic_advertising_parameters` indicating result of 134 /// the operation. on_periodic_advertising_parameters_updated( &mut self, advertiser_id: i32, status: AdvertisingStatus, )135 fn on_periodic_advertising_parameters_updated( 136 &mut self, 137 advertiser_id: i32, 138 status: AdvertisingStatus, 139 ); 140 141 /// Callback triggered in response to `set_periodic_advertising_data` indicating result of 142 /// the operation. on_periodic_advertising_data_set(&mut self, advertiser_id: i32, status: AdvertisingStatus)143 fn on_periodic_advertising_data_set(&mut self, advertiser_id: i32, status: AdvertisingStatus); 144 145 /// Callback triggered in response to `set_periodic_advertising_enable` indicating result of 146 /// the operation. on_periodic_advertising_enabled( &mut self, advertiser_id: i32, enable: bool, status: AdvertisingStatus, )147 fn on_periodic_advertising_enabled( 148 &mut self, 149 advertiser_id: i32, 150 enable: bool, 151 status: AdvertisingStatus, 152 ); 153 154 /// When advertising module changes its suspend mode due to system suspend/resume. on_suspend_mode_change(&mut self, suspend_mode: SuspendMode)155 fn on_suspend_mode_change(&mut self, suspend_mode: SuspendMode); 156 } 157 158 // Advertising interval range. 159 const INTERVAL_MAX: i32 = 0xff_ffff; // 10485.759375 sec 160 const INTERVAL_MIN: i32 = 160; // 100 ms 161 const INTERVAL_DELTA: i32 = 50; // 31.25 ms gap between min and max 162 163 // Periodic advertising interval range. 164 const PERIODIC_INTERVAL_MAX: i32 = 65519; // 81.89875 sec 165 const PERIODIC_INTERVAL_MIN: i32 = 80; // 100 ms 166 const PERIODIC_INTERVAL_DELTA: i32 = 16; // 20 ms gap between min and max 167 168 // Device name length. 169 const DEVICE_NAME_MAX: usize = 26; 170 171 // Advertising data types. 172 const COMPLETE_LIST_16_BIT_SERVICE_UUIDS: u8 = 0x03; 173 const COMPLETE_LIST_32_BIT_SERVICE_UUIDS: u8 = 0x05; 174 const COMPLETE_LIST_128_BIT_SERVICE_UUIDS: u8 = 0x07; 175 const SHORTENED_LOCAL_NAME: u8 = 0x08; 176 const COMPLETE_LOCAL_NAME: u8 = 0x09; 177 const TX_POWER_LEVEL: u8 = 0x0a; 178 const LIST_16_BIT_SERVICE_SOLICITATION_UUIDS: u8 = 0x14; 179 const LIST_128_BIT_SERVICE_SOLICITATION_UUIDS: u8 = 0x15; 180 const SERVICE_DATA_16_BIT_UUID: u8 = 0x16; 181 const LIST_32_BIT_SERVICE_SOLICITATION_UUIDS: u8 = 0x1f; 182 const SERVICE_DATA_32_BIT_UUID: u8 = 0x20; 183 const SERVICE_DATA_128_BIT_UUID: u8 = 0x21; 184 const TRANSPORT_DISCOVERY_DATA: u8 = 0x26; 185 const MANUFACTURER_SPECIFIC_DATA: u8 = 0xff; 186 const SERVICE_AD_TYPES: [u8; 3] = [ 187 COMPLETE_LIST_16_BIT_SERVICE_UUIDS, 188 COMPLETE_LIST_32_BIT_SERVICE_UUIDS, 189 COMPLETE_LIST_128_BIT_SERVICE_UUIDS, 190 ]; 191 const SOLICIT_AD_TYPES: [u8; 3] = [ 192 LIST_16_BIT_SERVICE_SOLICITATION_UUIDS, 193 LIST_32_BIT_SERVICE_SOLICITATION_UUIDS, 194 LIST_128_BIT_SERVICE_SOLICITATION_UUIDS, 195 ]; 196 197 // Invalid advertising set id. 198 const INVALID_ADV_ID: i32 = 0xff; 199 200 // Invalid advertising set id. 201 pub const INVALID_REG_ID: i32 = -1; 202 203 impl Into<bt_topshim::profiles::gatt::AdvertiseParameters> for AdvertisingSetParameters { into(self) -> bt_topshim::profiles::gatt::AdvertiseParameters204 fn into(self) -> bt_topshim::profiles::gatt::AdvertiseParameters { 205 let mut props: u16 = 0; 206 if self.connectable { 207 props |= 0x01; 208 } 209 if self.scannable { 210 props |= 0x02; 211 } 212 if self.is_legacy { 213 props |= 0x10; 214 } 215 if self.is_anonymous { 216 props |= 0x20; 217 } 218 if self.include_tx_power { 219 props |= 0x40; 220 } 221 222 let interval = clamp(self.interval, INTERVAL_MIN, INTERVAL_MAX - INTERVAL_DELTA); 223 224 bt_topshim::profiles::gatt::AdvertiseParameters { 225 advertising_event_properties: props, 226 min_interval: interval as u32, 227 max_interval: (interval + INTERVAL_DELTA) as u32, 228 channel_map: 0x07 as u8, // all channels 229 tx_power: self.tx_power_level as i8, 230 primary_advertising_phy: self.primary_phy.into(), 231 secondary_advertising_phy: self.secondary_phy.into(), 232 scan_request_notification_enable: 0 as u8, // false 233 own_address_type: self.own_address_type as i8, 234 } 235 } 236 } 237 238 impl AdvertiseData { append_adv_data(dest: &mut Vec<u8>, ad_type: u8, ad_payload: &[u8])239 fn append_adv_data(dest: &mut Vec<u8>, ad_type: u8, ad_payload: &[u8]) { 240 let len = clamp(ad_payload.len(), 0, 254); 241 dest.push((len + 1) as u8); 242 dest.push(ad_type); 243 dest.extend(&ad_payload[..len]); 244 } 245 append_uuids(dest: &mut Vec<u8>, ad_types: &[u8; 3], uuids: &Vec<Uuid>)246 fn append_uuids(dest: &mut Vec<u8>, ad_types: &[u8; 3], uuids: &Vec<Uuid>) { 247 let mut uuid16_bytes = Vec::<u8>::new(); 248 let mut uuid32_bytes = Vec::<u8>::new(); 249 let mut uuid128_bytes = Vec::<u8>::new(); 250 251 // For better transmission efficiency, we generate a compact 252 // advertisement data byconverting UUIDs into shorter binary forms 253 // and then group them by their length in order. 254 // The data generated for UUIDs looks like: 255 // [16-bit_UUID_LIST, 32-bit_UUID_LIST, 128-bit_UUID_LIST]. 256 for uuid in uuids { 257 let uuid_slice = UuidHelper::get_shortest_slice(&uuid.uu); 258 let id: Vec<u8> = uuid_slice.iter().rev().cloned().collect(); 259 match id.len() { 260 2 => uuid16_bytes.extend(id), 261 4 => uuid32_bytes.extend(id), 262 16 => uuid128_bytes.extend(id), 263 _ => (), 264 } 265 } 266 267 let bytes_list = vec![uuid16_bytes, uuid32_bytes, uuid128_bytes]; 268 for (ad_type, bytes) in 269 ad_types.iter().zip(bytes_list.iter()).filter(|(_, bytes)| bytes.len() > 0) 270 { 271 AdvertiseData::append_adv_data(dest, *ad_type, bytes); 272 } 273 } 274 append_service_uuids(dest: &mut Vec<u8>, uuids: &Vec<Uuid>)275 fn append_service_uuids(dest: &mut Vec<u8>, uuids: &Vec<Uuid>) { 276 AdvertiseData::append_uuids(dest, &SERVICE_AD_TYPES, uuids); 277 } 278 append_solicit_uuids(dest: &mut Vec<u8>, uuids: &Vec<Uuid>)279 fn append_solicit_uuids(dest: &mut Vec<u8>, uuids: &Vec<Uuid>) { 280 AdvertiseData::append_uuids(dest, &SOLICIT_AD_TYPES, uuids); 281 } 282 append_service_data(dest: &mut Vec<u8>, service_data: &HashMap<String, Vec<u8>>)283 fn append_service_data(dest: &mut Vec<u8>, service_data: &HashMap<String, Vec<u8>>) { 284 for (uuid, data) in 285 service_data.iter().filter_map(|(s, d)| UuidHelper::parse_string(s).map(|s| (s, d))) 286 { 287 let uuid_slice = UuidHelper::get_shortest_slice(&uuid.uu); 288 let concated: Vec<u8> = uuid_slice.iter().rev().chain(data).cloned().collect(); 289 match uuid_slice.len() { 290 2 => AdvertiseData::append_adv_data(dest, SERVICE_DATA_16_BIT_UUID, &concated), 291 4 => AdvertiseData::append_adv_data(dest, SERVICE_DATA_32_BIT_UUID, &concated), 292 16 => AdvertiseData::append_adv_data(dest, SERVICE_DATA_128_BIT_UUID, &concated), 293 _ => (), 294 } 295 } 296 } 297 append_device_name(dest: &mut Vec<u8>, device_name: &String)298 fn append_device_name(dest: &mut Vec<u8>, device_name: &String) { 299 if device_name.len() == 0 { 300 return; 301 } 302 303 let (ad_type, name) = if device_name.len() > DEVICE_NAME_MAX { 304 (SHORTENED_LOCAL_NAME, [&device_name.as_bytes()[..DEVICE_NAME_MAX], &[0]].concat()) 305 } else { 306 (COMPLETE_LOCAL_NAME, [device_name.as_bytes(), &[0]].concat()) 307 }; 308 AdvertiseData::append_adv_data(dest, ad_type, &name); 309 } 310 append_manufacturer_data(dest: &mut Vec<u8>, manufacturer_data: &HashMap<ManfId, Vec<u8>>)311 fn append_manufacturer_data(dest: &mut Vec<u8>, manufacturer_data: &HashMap<ManfId, Vec<u8>>) { 312 for (m, data) in manufacturer_data.iter().sorted() { 313 let concated = [&m.to_le_bytes()[..], data].concat(); 314 AdvertiseData::append_adv_data(dest, MANUFACTURER_SPECIFIC_DATA, &concated); 315 } 316 } 317 append_transport_discovery_data( dest: &mut Vec<u8>, transport_discovery_data: &Vec<Vec<u8>>, )318 fn append_transport_discovery_data( 319 dest: &mut Vec<u8>, 320 transport_discovery_data: &Vec<Vec<u8>>, 321 ) { 322 for tdd in transport_discovery_data.iter().filter(|tdd| tdd.len() > 0) { 323 AdvertiseData::append_adv_data(dest, TRANSPORT_DISCOVERY_DATA, &tdd); 324 } 325 } 326 327 /// Creates raw data from the AdvertiseData. make_with(&self, device_name: &String) -> Vec<u8>328 pub fn make_with(&self, device_name: &String) -> Vec<u8> { 329 let mut bytes = Vec::<u8>::new(); 330 if self.include_device_name { 331 AdvertiseData::append_device_name(&mut bytes, device_name); 332 } 333 if self.include_tx_power_level { 334 // Lower layers will fill tx power level. 335 AdvertiseData::append_adv_data(&mut bytes, TX_POWER_LEVEL, &[0]); 336 } 337 AdvertiseData::append_manufacturer_data(&mut bytes, &self.manufacturer_data); 338 AdvertiseData::append_service_uuids(&mut bytes, &self.service_uuids); 339 AdvertiseData::append_service_data(&mut bytes, &self.service_data); 340 AdvertiseData::append_solicit_uuids(&mut bytes, &self.solicit_uuids); 341 AdvertiseData::append_transport_discovery_data(&mut bytes, &self.transport_discovery_data); 342 bytes 343 } 344 } 345 346 impl Into<bt_topshim::profiles::gatt::PeriodicAdvertisingParameters> 347 for PeriodicAdvertisingParameters 348 { into(self) -> bt_topshim::profiles::gatt::PeriodicAdvertisingParameters349 fn into(self) -> bt_topshim::profiles::gatt::PeriodicAdvertisingParameters { 350 let mut p = bt_topshim::profiles::gatt::PeriodicAdvertisingParameters::default(); 351 352 let interval = clamp( 353 self.interval, 354 PERIODIC_INTERVAL_MIN, 355 PERIODIC_INTERVAL_MAX - PERIODIC_INTERVAL_DELTA, 356 ); 357 358 p.enable = true; 359 p.include_adi = false; 360 p.min_interval = interval as u16; 361 p.max_interval = p.min_interval + (PERIODIC_INTERVAL_DELTA as u16); 362 if self.include_tx_power { 363 p.periodic_advertising_properties |= 0x40; 364 } 365 366 p 367 } 368 } 369 370 /// Monotonically increasing counter for reg_id. 371 static REG_ID_COUNTER: AtomicIsize = AtomicIsize::new(0); 372 373 // Keeps information of an advertising set. 374 #[derive(Debug, PartialEq, Copy, Clone)] 375 pub(crate) struct AdvertisingSetInfo { 376 /// Identifies the advertising set when it's started successfully. 377 adv_id: Option<AdvertiserId>, 378 379 /// Identifies callback associated. 380 callback_id: CallbackId, 381 382 /// Identifies the advertising set when it's registered. 383 reg_id: RegId, 384 385 /// Whether the advertising set has been enabled. 386 enabled: bool, 387 388 /// Whether the advertising set has been paused. 389 paused: bool, 390 391 /// Advertising duration, in 10 ms unit. 392 adv_timeout: u16, 393 394 /// Maximum number of extended advertising events the controller 395 /// shall attempt to send before terminating the extended advertising. 396 adv_events: u8, 397 } 398 399 impl AdvertisingSetInfo { new(callback_id: CallbackId, adv_timeout: u16, adv_events: u8) -> Self400 pub(crate) fn new(callback_id: CallbackId, adv_timeout: u16, adv_events: u8) -> Self { 401 let mut reg_id = REG_ID_COUNTER.fetch_add(1, Ordering::SeqCst) as RegId; 402 if reg_id == INVALID_REG_ID { 403 reg_id = REG_ID_COUNTER.fetch_add(1, Ordering::SeqCst) as RegId; 404 } 405 AdvertisingSetInfo { 406 adv_id: None, 407 callback_id, 408 reg_id, 409 enabled: false, 410 paused: false, 411 adv_timeout, 412 adv_events, 413 } 414 } 415 416 /// Gets advertising set registration ID. reg_id(&self) -> RegId417 pub(crate) fn reg_id(&self) -> RegId { 418 self.reg_id 419 } 420 421 /// Gets associated callback ID. callback_id(&self) -> CallbackId422 pub(crate) fn callback_id(&self) -> CallbackId { 423 self.callback_id 424 } 425 426 /// Updates advertiser ID. set_adv_id(&mut self, id: Option<AdvertiserId>)427 pub(crate) fn set_adv_id(&mut self, id: Option<AdvertiserId>) { 428 self.adv_id = id; 429 } 430 431 /// Gets advertiser ID, which is required for advertising |BleAdvertiserInterface|. adv_id(&self) -> u8432 pub(crate) fn adv_id(&self) -> u8 { 433 // As advertiser ID was from topshim originally, type casting is safe. 434 self.adv_id.unwrap_or(INVALID_ADV_ID) as u8 435 } 436 437 /// Updates advertising set status. set_enabled(&mut self, enabled: bool)438 pub(crate) fn set_enabled(&mut self, enabled: bool) { 439 self.enabled = enabled; 440 } 441 442 /// Returns true if the advertising set has been enabled, false otherwise. is_enabled(&self) -> bool443 pub(crate) fn is_enabled(&self) -> bool { 444 self.enabled 445 } 446 447 /// Marks the advertising set as paused or not. set_paused(&mut self, paused: bool)448 pub(crate) fn set_paused(&mut self, paused: bool) { 449 self.paused = paused; 450 } 451 452 /// Returns true if the advertising set has been paused, false otherwise. is_paused(&self) -> bool453 pub(crate) fn is_paused(&self) -> bool { 454 self.paused 455 } 456 457 /// Gets adv_timeout. adv_timeout(&self) -> u16458 pub(crate) fn adv_timeout(&self) -> u16 { 459 self.adv_timeout 460 } 461 462 /// Gets adv_events. adv_events(&self) -> u8463 pub(crate) fn adv_events(&self) -> u8 { 464 self.adv_events 465 } 466 } 467 468 // Manages advertising sets and the callbacks. 469 pub(crate) struct Advertisers { 470 callbacks: Callbacks<dyn IAdvertisingSetCallback + Send>, 471 sets: HashMap<RegId, AdvertisingSetInfo>, 472 suspend_mode: SuspendMode, 473 } 474 475 impl Advertisers { new(tx: Sender<Message>) -> Self476 pub(crate) fn new(tx: Sender<Message>) -> Self { 477 Advertisers { 478 callbacks: Callbacks::new(tx, Message::AdvertiserCallbackDisconnected), 479 sets: HashMap::new(), 480 suspend_mode: SuspendMode::Normal, 481 } 482 } 483 484 /// Adds an advertising set. add(&mut self, s: AdvertisingSetInfo)485 pub(crate) fn add(&mut self, s: AdvertisingSetInfo) { 486 if let Some(old) = self.sets.insert(s.reg_id(), s) { 487 warn!("An advertising set with the same reg_id ({}) exists. Drop it!", old.reg_id); 488 } 489 } 490 491 /// Returns an iterator of valid advertising sets. valid_sets(&self) -> impl Iterator<Item = &AdvertisingSetInfo>492 pub(crate) fn valid_sets(&self) -> impl Iterator<Item = &AdvertisingSetInfo> { 493 self.sets.iter().filter_map(|(_, s)| s.adv_id.map(|_| s)) 494 } 495 496 /// Returns a mutable iterator of valid advertising sets. valid_sets_mut(&mut self) -> impl Iterator<Item = &mut AdvertisingSetInfo>497 pub(crate) fn valid_sets_mut(&mut self) -> impl Iterator<Item = &mut AdvertisingSetInfo> { 498 self.sets.iter_mut().filter_map(|(_, s)| s.adv_id.map(|_| s)) 499 } 500 501 /// Returns an iterator of enabled advertising sets. enabled_sets(&self) -> impl Iterator<Item = &AdvertisingSetInfo>502 pub(crate) fn enabled_sets(&self) -> impl Iterator<Item = &AdvertisingSetInfo> { 503 self.valid_sets().filter(|s| s.is_enabled()) 504 } 505 506 /// Returns a mutable iterator of enabled advertising sets. enabled_sets_mut(&mut self) -> impl Iterator<Item = &mut AdvertisingSetInfo>507 pub(crate) fn enabled_sets_mut(&mut self) -> impl Iterator<Item = &mut AdvertisingSetInfo> { 508 self.valid_sets_mut().filter(|s| s.is_enabled()) 509 } 510 511 /// Returns a mutable iterator of paused advertising sets. paused_sets_mut(&mut self) -> impl Iterator<Item = &mut AdvertisingSetInfo>512 pub(crate) fn paused_sets_mut(&mut self) -> impl Iterator<Item = &mut AdvertisingSetInfo> { 513 self.valid_sets_mut().filter(|s| s.is_paused()) 514 } 515 find_reg_id(&self, adv_id: AdvertiserId) -> Option<RegId>516 fn find_reg_id(&self, adv_id: AdvertiserId) -> Option<RegId> { 517 for (_, s) in &self.sets { 518 if s.adv_id == Some(adv_id) { 519 return Some(s.reg_id()); 520 } 521 } 522 return None; 523 } 524 525 /// Returns a mutable reference to the advertising set with the reg_id specified. get_mut_by_reg_id(&mut self, reg_id: RegId) -> Option<&mut AdvertisingSetInfo>526 pub(crate) fn get_mut_by_reg_id(&mut self, reg_id: RegId) -> Option<&mut AdvertisingSetInfo> { 527 self.sets.get_mut(®_id) 528 } 529 530 /// Returns a shared reference to the advertising set with the reg_id specified. get_by_reg_id(&self, reg_id: RegId) -> Option<&AdvertisingSetInfo>531 pub(crate) fn get_by_reg_id(&self, reg_id: RegId) -> Option<&AdvertisingSetInfo> { 532 self.sets.get(®_id) 533 } 534 535 /// Returns a mutable reference to the advertising set with the advertiser ID specified. get_mut_by_advertiser_id( &mut self, adv_id: AdvertiserId, ) -> Option<&mut AdvertisingSetInfo>536 pub(crate) fn get_mut_by_advertiser_id( 537 &mut self, 538 adv_id: AdvertiserId, 539 ) -> Option<&mut AdvertisingSetInfo> { 540 if let Some(reg_id) = self.find_reg_id(adv_id) { 541 return self.get_mut_by_reg_id(reg_id); 542 } 543 None 544 } 545 546 /// Returns a shared reference to the advertising set with the advertiser ID specified. get_by_advertiser_id(&self, adv_id: AdvertiserId) -> Option<&AdvertisingSetInfo>547 pub(crate) fn get_by_advertiser_id(&self, adv_id: AdvertiserId) -> Option<&AdvertisingSetInfo> { 548 if let Some(reg_id) = self.find_reg_id(adv_id) { 549 return self.get_by_reg_id(reg_id); 550 } 551 None 552 } 553 554 /// Removes the advertising set with the reg_id specified. 555 /// 556 /// Returns the advertising set if found, None otherwise. remove_by_reg_id(&mut self, reg_id: RegId) -> Option<AdvertisingSetInfo>557 pub(crate) fn remove_by_reg_id(&mut self, reg_id: RegId) -> Option<AdvertisingSetInfo> { 558 self.sets.remove(®_id) 559 } 560 561 /// Removes the advertising set with the specified advertiser ID. 562 /// 563 /// Returns the advertising set if found, None otherwise. remove_by_advertiser_id( &mut self, adv_id: AdvertiserId, ) -> Option<AdvertisingSetInfo>564 pub(crate) fn remove_by_advertiser_id( 565 &mut self, 566 adv_id: AdvertiserId, 567 ) -> Option<AdvertisingSetInfo> { 568 if let Some(reg_id) = self.find_reg_id(adv_id) { 569 return self.remove_by_reg_id(reg_id); 570 } 571 None 572 } 573 574 /// Adds an advertiser callback. add_callback( &mut self, callback: Box<dyn IAdvertisingSetCallback + Send>, ) -> CallbackId575 pub(crate) fn add_callback( 576 &mut self, 577 callback: Box<dyn IAdvertisingSetCallback + Send>, 578 ) -> CallbackId { 579 self.callbacks.add_callback(callback) 580 } 581 582 /// Returns callback of the advertising set. get_callback( &mut self, s: &AdvertisingSetInfo, ) -> Option<&mut Box<dyn IAdvertisingSetCallback + Send>>583 pub(crate) fn get_callback( 584 &mut self, 585 s: &AdvertisingSetInfo, 586 ) -> Option<&mut Box<dyn IAdvertisingSetCallback + Send>> { 587 self.callbacks.get_by_id_mut(s.callback_id()) 588 } 589 590 /// Removes an advertiser callback and unregisters all advertising sets associated with that callback. remove_callback(&mut self, callback_id: CallbackId, gatt: &mut Gatt) -> bool591 pub(crate) fn remove_callback(&mut self, callback_id: CallbackId, gatt: &mut Gatt) -> bool { 592 for (_, s) in 593 self.sets.iter().filter(|(_, s)| s.callback_id() == callback_id && s.adv_id.is_some()) 594 { 595 gatt.advertiser.unregister(s.adv_id()); 596 } 597 self.sets.retain(|_, s| s.callback_id() != callback_id); 598 599 self.callbacks.remove_callback(callback_id) 600 } 601 602 /// Update suspend mode. set_suspend_mode(&mut self, suspend_mode: SuspendMode)603 pub(crate) fn set_suspend_mode(&mut self, suspend_mode: SuspendMode) { 604 if suspend_mode != self.suspend_mode { 605 self.suspend_mode = suspend_mode; 606 self.notify_suspend_mode(); 607 } 608 } 609 610 /// Gets current suspend mode. suspend_mode(&mut self) -> SuspendMode611 pub(crate) fn suspend_mode(&mut self) -> SuspendMode { 612 self.suspend_mode.clone() 613 } 614 615 /// Notify current suspend mode to all active callbacks. notify_suspend_mode(&mut self)616 fn notify_suspend_mode(&mut self) { 617 let suspend_mode = &self.suspend_mode; 618 self.callbacks.for_all_callbacks(|callback| { 619 callback.on_suspend_mode_change(suspend_mode.clone()); 620 }); 621 } 622 } 623 624 #[cfg(test)] 625 mod tests { 626 use super::*; 627 use std::collections::HashSet; 628 use std::iter::FromIterator; 629 630 #[test] test_append_ad_data_clamped()631 fn test_append_ad_data_clamped() { 632 let mut bytes = Vec::<u8>::new(); 633 let mut ans = Vec::<u8>::new(); 634 ans.push(255); 635 ans.push(102); 636 ans.extend(Vec::<u8>::from_iter(0..254)); 637 638 let payload = Vec::<u8>::from_iter(0..255); 639 AdvertiseData::append_adv_data(&mut bytes, 102, &payload); 640 assert_eq!(bytes, ans); 641 } 642 643 #[test] test_append_ad_data_multiple()644 fn test_append_ad_data_multiple() { 645 let mut bytes = Vec::<u8>::new(); 646 647 let payload = vec![0 as u8, 1, 2, 3, 4]; 648 AdvertiseData::append_adv_data(&mut bytes, 100, &payload); 649 AdvertiseData::append_adv_data(&mut bytes, 101, &[0]); 650 assert_eq!(bytes, vec![6 as u8, 100, 0, 1, 2, 3, 4, 2, 101, 0]); 651 } 652 653 #[test] test_new_advising_set_info()654 fn test_new_advising_set_info() { 655 let mut uniq = HashSet::new(); 656 for callback_id in 0..256 { 657 let s = AdvertisingSetInfo::new(callback_id, 0, 0); 658 assert_eq!(s.callback_id(), callback_id); 659 assert_eq!(uniq.insert(s.reg_id()), true); 660 } 661 } 662 663 #[test] test_iterate_adving_set_info()664 fn test_iterate_adving_set_info() { 665 let (tx, _rx) = crate::Stack::create_channel(); 666 let mut advertisers = Advertisers::new(tx.clone()); 667 668 let size = 256; 669 for i in 0..size { 670 let callback_id: CallbackId = i as CallbackId; 671 let adv_id: AdvertiserId = i as AdvertiserId; 672 let mut s = AdvertisingSetInfo::new(callback_id, 0, 0); 673 s.set_adv_id(Some(adv_id)); 674 advertisers.add(s); 675 } 676 677 assert_eq!(advertisers.valid_sets().count(), size); 678 for s in advertisers.valid_sets() { 679 assert_eq!(s.callback_id() as u32, s.adv_id() as u32); 680 } 681 } 682 683 #[test] test_append_service_uuids()684 fn test_append_service_uuids() { 685 let mut bytes = Vec::<u8>::new(); 686 let uuid_16 = 687 Uuid::from(UuidHelper::from_string("0000fef3-0000-1000-8000-00805f9b34fb").unwrap()); 688 let uuids = vec![uuid_16.clone()]; 689 let exp_16: Vec<u8> = vec![3, 0x3, 0xf3, 0xfe]; 690 AdvertiseData::append_service_uuids(&mut bytes, &uuids); 691 assert_eq!(bytes, exp_16); 692 693 let mut bytes = Vec::<u8>::new(); 694 let uuid_32 = 695 Uuid::from(UuidHelper::from_string("00112233-0000-1000-8000-00805f9b34fb").unwrap()); 696 let uuids = vec![uuid_32.clone()]; 697 let exp_32: Vec<u8> = vec![5, 0x5, 0x33, 0x22, 0x11, 0x0]; 698 AdvertiseData::append_service_uuids(&mut bytes, &uuids); 699 assert_eq!(bytes, exp_32); 700 701 let mut bytes = Vec::<u8>::new(); 702 let uuid_128 = 703 Uuid::from(UuidHelper::from_string("00010203-0405-0607-0809-0a0b0c0d0e0f").unwrap()); 704 let uuids = vec![uuid_128.clone()]; 705 let exp_128: Vec<u8> = vec![ 706 17, 0x7, 0xf, 0xe, 0xd, 0xc, 0xb, 0xa, 0x9, 0x8, 0x7, 0x6, 0x5, 0x4, 0x3, 0x2, 0x1, 0x0, 707 ]; 708 AdvertiseData::append_service_uuids(&mut bytes, &uuids); 709 assert_eq!(bytes, exp_128); 710 711 let mut bytes = Vec::<u8>::new(); 712 let uuids = vec![uuid_16, uuid_32, uuid_128]; 713 let exp_bytes: Vec<u8> = 714 [exp_16.as_slice(), exp_32.as_slice(), exp_128.as_slice()].concat(); 715 AdvertiseData::append_service_uuids(&mut bytes, &uuids); 716 assert_eq!(bytes, exp_bytes); 717 718 // Interleaved UUIDs. 719 let mut bytes = Vec::<u8>::new(); 720 let uuid_16_2 = 721 Uuid::from(UuidHelper::from_string("0000aabb-0000-1000-8000-00805f9b34fb").unwrap()); 722 let uuids = vec![uuid_16, uuid_128, uuid_16_2, uuid_32]; 723 let exp_16: Vec<u8> = vec![5, 0x3, 0xf3, 0xfe, 0xbb, 0xaa]; 724 let exp_bytes: Vec<u8> = 725 [exp_16.as_slice(), exp_32.as_slice(), exp_128.as_slice()].concat(); 726 AdvertiseData::append_service_uuids(&mut bytes, &uuids); 727 assert_eq!(bytes, exp_bytes); 728 } 729 730 #[test] test_append_solicit_uuids()731 fn test_append_solicit_uuids() { 732 let mut bytes = Vec::<u8>::new(); 733 let uuid_16 = 734 Uuid::from(UuidHelper::from_string("0000fef3-0000-1000-8000-00805f9b34fb").unwrap()); 735 let uuid_32 = 736 Uuid::from(UuidHelper::from_string("00112233-0000-1000-8000-00805f9b34fb").unwrap()); 737 let uuid_128 = 738 Uuid::from(UuidHelper::from_string("00010203-0405-0607-0809-0a0b0c0d0e0f").unwrap()); 739 let uuids = vec![uuid_16, uuid_32, uuid_128]; 740 let exp_16: Vec<u8> = vec![3, 0x14, 0xf3, 0xfe]; 741 let exp_32: Vec<u8> = vec![5, 0x1f, 0x33, 0x22, 0x11, 0x0]; 742 let exp_128: Vec<u8> = vec![ 743 17, 0x15, 0xf, 0xe, 0xd, 0xc, 0xb, 0xa, 0x9, 0x8, 0x7, 0x6, 0x5, 0x4, 0x3, 0x2, 0x1, 744 0x0, 745 ]; 746 let exp_bytes: Vec<u8> = 747 [exp_16.as_slice(), exp_32.as_slice(), exp_128.as_slice()].concat(); 748 AdvertiseData::append_solicit_uuids(&mut bytes, &uuids); 749 assert_eq!(bytes, exp_bytes); 750 } 751 752 #[test] test_append_service_data_good_id()753 fn test_append_service_data_good_id() { 754 let mut bytes = Vec::<u8>::new(); 755 let uuid_str = "0000fef3-0000-1000-8000-00805f9b34fb".to_string(); 756 let mut service_data = HashMap::new(); 757 let data: Vec<u8> = vec![ 758 0x4A, 0x17, 0x23, 0x41, 0x39, 0x37, 0x45, 0x11, 0x16, 0x60, 0x1D, 0xB8, 0x27, 0xA2, 759 0xEF, 0xAA, 0xFE, 0x58, 0x04, 0x9F, 0xE3, 0x8F, 0xD0, 0x04, 0x29, 0x4F, 0xC2, 760 ]; 761 service_data.insert(uuid_str, data.clone()); 762 let mut exp_bytes: Vec<u8> = vec![30, 0x16, 0xf3, 0xfe]; 763 exp_bytes.extend(data); 764 AdvertiseData::append_service_data(&mut bytes, &service_data); 765 assert_eq!(bytes, exp_bytes); 766 } 767 768 #[test] test_append_service_data_bad_id()769 fn test_append_service_data_bad_id() { 770 let mut bytes = Vec::<u8>::new(); 771 let uuid_str = "fef3".to_string(); 772 let mut service_data = HashMap::new(); 773 let data: Vec<u8> = vec![ 774 0x4A, 0x17, 0x23, 0x41, 0x39, 0x37, 0x45, 0x11, 0x16, 0x60, 0x1D, 0xB8, 0x27, 0xA2, 775 0xEF, 0xAA, 0xFE, 0x58, 0x04, 0x9F, 0xE3, 0x8F, 0xD0, 0x04, 0x29, 0x4F, 0xC2, 776 ]; 777 service_data.insert(uuid_str, data.clone()); 778 let exp_bytes: Vec<u8> = Vec::new(); 779 AdvertiseData::append_service_data(&mut bytes, &service_data); 780 assert_eq!(bytes, exp_bytes); 781 } 782 783 #[test] test_append_device_name()784 fn test_append_device_name() { 785 let mut bytes = Vec::<u8>::new(); 786 let complete_name = "abc".to_string(); 787 let exp_bytes: Vec<u8> = vec![5, 0x9, 0x61, 0x62, 0x63, 0x0]; 788 AdvertiseData::append_device_name(&mut bytes, &complete_name); 789 assert_eq!(bytes, exp_bytes); 790 791 let mut bytes = Vec::<u8>::new(); 792 let shortened_name = "abcdefghijklmnopqrstuvwxyz7890".to_string(); 793 let exp_bytes: Vec<u8> = vec![ 794 28, 0x8, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 795 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x0, 796 ]; 797 AdvertiseData::append_device_name(&mut bytes, &shortened_name); 798 assert_eq!(bytes, exp_bytes); 799 } 800 801 #[test] test_append_manufacturer_data()802 fn test_append_manufacturer_data() { 803 let mut bytes = Vec::<u8>::new(); 804 let manufacturer_data = HashMap::from([(0x0123 as u16, vec![0, 1, 2])]); 805 let exp_bytes: Vec<u8> = vec![6, 0xff, 0x23, 0x01, 0x0, 0x1, 0x2]; 806 AdvertiseData::append_manufacturer_data(&mut bytes, &manufacturer_data); 807 assert_eq!(bytes, exp_bytes); 808 } 809 810 #[test] test_append_transport_discovery_data()811 fn test_append_transport_discovery_data() { 812 let mut bytes = Vec::<u8>::new(); 813 let transport_discovery_data = vec![vec![0, 1, 2]]; 814 let exp_bytes: Vec<u8> = vec![0x4, 0x26, 0x0, 0x1, 0x2]; 815 AdvertiseData::append_transport_discovery_data(&mut bytes, &transport_discovery_data); 816 assert_eq!(bytes, exp_bytes); 817 818 let mut bytes = Vec::<u8>::new(); 819 let transport_discovery_data = vec![vec![1, 2, 4, 8], vec![0xa, 0xb]]; 820 let exp_bytes: Vec<u8> = vec![0x5, 0x26, 0x1, 0x2, 0x4, 0x8, 3, 0x26, 0xa, 0xb]; 821 AdvertiseData::append_transport_discovery_data(&mut bytes, &transport_discovery_data); 822 assert_eq!(bytes, exp_bytes); 823 } 824 } 825