• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(&reg_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(&reg_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(&reg_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