Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 84692c29 authored by Ying Hsu's avatar Ying Hsu Committed by Gerrit Code Review
Browse files

Merge "floss: Add advertise set-interval command"

parents 5a294e79 8b4b83cf
Loading
Loading
Loading
Loading
+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 }
    }
}
+8 −12
Original line number Diff line number Diff line
@@ -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(&reg_id);
            return;
        }
        if let Some(s) = self.context.lock().unwrap().adv_sets.get_mut(&reg_id) {
            s.adv_id = Some(advertiser_id);
        } else {
            print_error!("on_advertising_set_started: invalid callback for reg_id={}", reg_id);
        }
    }

@@ -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) {
+66 −46
Original line number Diff line number Diff line
@@ -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,
};
@@ -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,
        },
@@ -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(&reg_id)
                        .unwrap()
                        .params
                        .interval = interval;

                    let adv_id = self.context.lock().unwrap().adv_sets[&reg_id].adv_id.clone();
                    if let Some(adv_id) = adv_id {
                        let params = self.context.lock().unwrap().adv_sets[&reg_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]);
+4 −2
Original line number Diff line number Diff line
@@ -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,
@@ -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;
@@ -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>,
+2 −2
Original line number Diff line number Diff line
@@ -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,
@@ -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