blob: 235a6fc05ef1cc0fc45fa1fbf68c8d614b21d5cd [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use failure::{bail, Error, ResultExt};
use fidl_fuchsia_bluetooth_le::{AdvertisingData, PeripheralMarker, PeripheralProxy};
use fuchsia_app as app;
use fuchsia_bluetooth::error::Error as BTError;
use fuchsia_syslog::macros::*;
use parking_lot::RwLock;
// Sl4f-Constants and Ble advertising related functionality
use crate::bluetooth::constants::DEFAULT_BLE_ADV_INTERVAL_MS;
use crate::bluetooth::types::BleAdvertiseResponse;
#[derive(Debug)]
struct InnerBleAdvertiseFacade {
/// Advertisement ID of device, only one advertisement at a time.
// TODO(NET-1290): Potentially scale up to a list/set of adv_id's for concurrent advertisement
// tests.
adv_id: Option<String>,
///PeripheralProxy used for Bluetooth Connections
peripheral: Option<PeripheralProxy>,
}
/// Starts and stops device BLE advertisement(s).
//
/// Note this object is shared among all threads created by server.
//
#[derive(Debug)]
pub struct BleAdvertiseFacade {
inner: RwLock<InnerBleAdvertiseFacade>,
}
impl BleAdvertiseFacade {
pub fn new() -> BleAdvertiseFacade {
BleAdvertiseFacade {
inner: RwLock::new(InnerBleAdvertiseFacade {
adv_id: None,
peripheral: None,
}),
}
}
// Set the advertisement ID if none exists already
pub fn set_adv_id(&self, adv_id: Option<String>) {
self.inner.write().adv_id = adv_id.clone();
fx_log_info!(tag: "set_adv_id", "Advertisement ID set to: {:?}", adv_id)
}
pub fn get_adv_id(&self) -> BleAdvertiseResponse {
BleAdvertiseResponse::new(self.inner.read().adv_id.clone())
}
pub fn print(&self) {
fx_log_info!(tag: "print",
"BleAdvertiseFacade: Adv_id: {:?}, Peripheral: {:?}",
self.get_adv_id(),
self.get_peripheral_proxy(),
);
}
// Set the peripheral proxy only if none exists, otherwise, use existing
pub fn set_peripheral_proxy(&self) {
let new_peripheral = match self.inner.read().peripheral.clone() {
Some(p) => {
fx_log_warn!(tag: "set_peripheral_proxy",
"Current peripheral: {:?}",
p,
);
Some(p)
}
None => {
let peripheral_svc: PeripheralProxy =
app::client::connect_to_service::<PeripheralMarker>()
.context("Failed to connect to BLE Peripheral service.")
.unwrap();
Some(peripheral_svc)
}
};
self.inner.write().peripheral = new_peripheral
}
pub async fn start_adv(
&self, adv_data: Option<AdvertisingData>, interval: Option<u32>, connectable: bool,
) -> Result<(), Error> {
// Default interval (ms) to 1 second
let intv: u32 = interval.unwrap_or(DEFAULT_BLE_ADV_INTERVAL_MS);
let mut ad = match adv_data {
Some(ad) => ad,
None => AdvertisingData {
name: None,
tx_power_level: None,
appearance: None,
service_uuids: None,
service_data: None,
manufacturer_specific_data: None,
solicited_service_uuids: None,
uris: None,
},
};
// Create peripheral proxy if necessary
self.set_peripheral_proxy();
let periph = &self.inner.read().peripheral.clone();
match &periph {
Some(p) => {
let (status, adv_id) =
await!(p.start_advertising(&mut ad, None, connectable, intv, false))?;
match status.error {
None => {
fx_log_info!(tag: "start_adv", "Started advertising id: {:?}", adv_id);
self.set_adv_id(adv_id.clone());
Ok(())
}
Some(e) => {
let err = BTError::from(*e);
fx_log_err!(tag: "start_adv", "Failed to start adveritising: {:?}", err);
Err(err.into())
}
}
}
None => {
fx_log_err!(tag: "start_adv", "No peripheral created.");
bail!("No peripheral proxy created.")
}
}
}
pub async fn stop_adv(&self, adv_id: String) -> Result<(), Error> {
fx_log_info!(tag: "stop_adv", "stop_adv with adv_id: {:?}", adv_id);
let periph = &self.inner.read().peripheral.clone();
match &periph {
Some(p) => {
await!(p.stop_advertising(&adv_id))?;
self.set_adv_id(None);
Ok(())
}
None => {
fx_log_err!(tag: "stop_adv", "No peripheral proxy created!");
bail!("No peripheral proxy created.")
}
}
}
pub fn get_peripheral_proxy(&self) -> Option<PeripheralProxy> {
self.inner.read().peripheral.clone()
}
pub fn cleanup_adv_id(&self) {
self.inner.write().adv_id = None
}
// Close peripheral proxy
pub fn cleanup_peripheral_proxy(&self) {
self.inner.write().peripheral = None;
}
// Close both central and peripheral proxies
pub fn cleanup(&self) {
self.cleanup_adv_id();
self.cleanup_peripheral_proxy();
}
}