blob: 3f9270e3872e9c981f1dcbf017127cd0bdafb8cb [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 crate::server::Facade;
use anyhow::{format_err, Error};
use async_trait::async_trait;
use fidl_fuchsia_bluetooth_gatt::ServiceInfo;
use fidl_fuchsia_bluetooth_le::ScanFilter;
use parking_lot::RwLock;
use serde_json::{to_value, Value};
// Bluetooth-related functionality
use crate::bluetooth::avdtp_facade::AvdtpFacade;
use crate::bluetooth::ble_advertise_facade::BleAdvertiseFacade;
use crate::bluetooth::bt_sys_facade::BluetoothSysFacade;
use crate::bluetooth::facade::BluetoothFacade;
use crate::bluetooth::gatt_client_facade::GattClientFacade;
use crate::bluetooth::gatt_server_facade::GattServerFacade;
use crate::bluetooth::profile_server_facade::ProfileServerFacade;
use crate::bluetooth::types::{
BleAdvertiseResponse, BleConnectPeripheralResponse, GattcDiscoverCharacteristicResponse,
};
use crate::common_utils::common::{
parse_identifier, parse_max_bytes, parse_offset, parse_psm, parse_service_identifier,
parse_u64_identifier, parse_write_value,
};
use crate::common_utils::common::macros::parse_arg;
// Takes a serde_json::Value and converts it to arguments required for a FIDL
// ble_scan command
fn ble_scan_to_fidl(args_raw: Value) -> Result<Option<ScanFilter>, Error> {
let scan_filter_raw = match args_raw.get("filter") {
Some(f) => Some(f).unwrap().clone(),
None => return Err(format_err!("Scan filter missing.")),
};
let name_substring: Option<String> =
scan_filter_raw["name_substring"].as_str().map(String::from);
// For now, no scan profile, so default to empty ScanFilter
let filter = Some(ScanFilter {
service_uuids: None,
service_data_uuids: None,
manufacturer_identifier: None,
connectable: None,
name_substring: name_substring,
max_path_loss: None,
});
Ok(filter)
}
fn ble_publish_service_to_fidl(args_raw: Value) -> Result<(ServiceInfo, String), Error> {
let id = parse_arg!(args_raw, as_u64, "id")?;
let primary = parse_arg!(args_raw, as_bool, "primary")?;
let type_ = parse_arg!(args_raw, as_str, "type")?;
let local_service_id = parse_arg!(args_raw, as_str, "local_service_id")?;
// TODO(fxbug.dev/883): Add support for GATT characterstics and includes
let characteristics = None;
let includes = None;
let service_info =
ServiceInfo { id, primary, type_: type_.to_string(), characteristics, includes };
Ok((service_info, local_service_id.to_string()))
}
#[async_trait(?Send)]
impl Facade for BleAdvertiseFacade {
async fn handle_request(&self, method: String, args: Value) -> Result<Value, Error> {
// TODO(armansito): Once the facade supports multi-advertising it should generate and
// return a unique ID for each instance. For now we return this dummy ID for the
// singleton advertisement.
let id = to_value(BleAdvertiseResponse::new(Some("singleton-instance".to_string())))?;
match method.as_ref() {
"BleAdvertise" => {
self.start_adv(args).await?;
}
"BleStopAdvertise" => {
self.stop_adv();
}
_ => return Err(format_err!("Invalid BleAdvertise FIDL method: {:?}", method)),
};
Ok(id)
}
fn cleanup(&self) {
Self::cleanup(self)
}
fn print(&self) {
Self::print(self)
}
}
#[async_trait(?Send)]
impl Facade for RwLock<BluetoothFacade> {
async fn handle_request(&self, method: String, args: Value) -> Result<Value, Error> {
match method.as_ref() {
"BlePublishService" => {
let (service_info, local_service_id) = ble_publish_service_to_fidl(args)?;
publish_service_async(self, service_info, local_service_id).await
}
_ => return Err(format_err!("Invalid BLE FIDL method: {:?}", method)),
}
}
fn cleanup(&self) {
BluetoothFacade::cleanup(self)
}
fn print(&self) {
self.read().print()
}
}
#[async_trait(?Send)]
impl Facade for BluetoothSysFacade {
async fn handle_request(&self, method: String, args: Value) -> Result<Value, Error> {
match method.as_ref() {
"BluetoothAcceptPairing" => {
let input = parse_arg!(args, as_str, "input")?;
let output = parse_arg!(args, as_str, "output")?;
let result = self.accept_pairing(&input.to_string(), &output.to_string()).await?;
Ok(to_value(result)?)
}
"BluetoothInitSys" => {
let result = self.init_access_proxy().await?;
Ok(to_value(result)?)
}
"BluetoothGetKnownRemoteDevices" => {
let result = self.get_known_remote_devices().await?;
Ok(to_value(result)?)
}
"BluetoothSetDiscoverable" => {
let discoverable = parse_arg!(args, as_bool, "discoverable")?;
let result = self.set_discoverable(discoverable).await?;
Ok(to_value(result)?)
}
"BluetoothSetName" => {
let name = parse_arg!(args, as_str, "name")?;
let result = self.set_name(name.to_string()).await?;
Ok(to_value(result)?)
}
"BluetoothForgetDevice" => {
let identifier = parse_arg!(args, as_u64, "identifier")?;
let result = self.forget(identifier).await?;
Ok(to_value(result)?)
}
"BluetoothConnectDevice" => {
let identifier = parse_arg!(args, as_u64, "identifier")?;
let result = self.connect(identifier).await?;
Ok(to_value(result)?)
}
"BluetoothDisconnectDevice" => {
let identifier = parse_arg!(args, as_u64, "identifier")?;
let result = self.disconnect(identifier).await?;
Ok(to_value(result)?)
}
"BluetoothRequestDiscovery" => {
let discovery = parse_arg!(args, as_bool, "discovery")?;
let result = self.start_discovery(discovery).await?;
Ok(to_value(result)?)
}
"BluetoothInputPairingPin" => {
let pin = parse_arg!(args, as_str, "pin")?;
let result = self.input_pairing_pin(pin.to_string()).await?;
Ok(to_value(result)?)
}
"BluetoothGetPairingPin" => {
let result = self.get_pairing_pin().await?;
Ok(to_value(result)?)
}
"BluetoothGetActiveAdapterAddress" => {
let result = self.get_active_adapter_address().await?;
Ok(to_value(result)?)
}
"BluetoothPairDevice" => {
let identifier = parse_arg!(args, as_u64, "identifier")?;
let pairing_security_level =
match parse_arg!(args, as_u64, "pairing_security_level") {
Ok(v) => Some(v),
Err(_e) => None,
};
let non_bondable = match parse_arg!(args, as_bool, "non_bondable") {
Ok(v) => Some(v),
Err(_e) => None,
};
let transport = parse_arg!(args, as_u64, "transport")?;
let result =
self.pair(identifier, pairing_security_level, non_bondable, transport).await?;
Ok(to_value(result)?)
}
_ => bail!("Invalid Bluetooth control FIDL method: {:?}", method),
}
}
fn cleanup(&self) {
Self::cleanup(self)
}
fn print(&self) {
Self::print(self)
}
}
#[async_trait(?Send)]
impl Facade for GattClientFacade {
async fn handle_request(&self, method: String, args: Value) -> Result<Value, Error> {
match method.as_ref() {
"BleStartScan" => {
let filter = ble_scan_to_fidl(args)?;
start_scan_async(&self, filter).await
}
"BleStopScan" => stop_scan_async(self).await,
"BleGetDiscoveredDevices" => le_get_discovered_devices_async(self).await,
"BleConnectPeripheral" => {
let id = parse_identifier(args)?;
connect_peripheral_async(self, id).await
}
"BleDisconnectPeripheral" => {
let id = parse_identifier(args)?;
disconnect_peripheral_async(self, id).await
}
"GattcConnectToService" => {
let periph_id = parse_identifier(args.clone())?;
let service_id = parse_service_identifier(args)?;
gattc_connect_to_service_async(self, periph_id, service_id).await
}
"GattcDiscoverCharacteristics" => gattc_discover_characteristics_async(self).await,
"GattcWriteCharacteristicById" => {
let id = parse_u64_identifier(args.clone())?;
let value = parse_write_value(args)?;
gattc_write_char_by_id_async(self, id, value).await
}
"GattcWriteLongCharacteristicById" => {
let id = parse_u64_identifier(args.clone())?;
let offset_as_u64 = parse_offset(args.clone())?;
let offset = offset_as_u64 as u16;
let value = parse_write_value(args.clone())?;
let reliable_mode = parse_arg!(args, as_bool, "reliable_mode")?;
gattc_write_long_char_by_id_async(self, id, offset, value, reliable_mode).await
}
"GattcWriteCharacteristicByIdWithoutResponse" => {
let id = parse_u64_identifier(args.clone())?;
let value = parse_write_value(args)?;
gattc_write_char_by_id_without_response_async(self, id, value).await
}
"GattcEnableNotifyCharacteristic" => {
let id = parse_u64_identifier(args.clone())?;
gattc_toggle_notify_characteristic_async(self, id, true).await
}
"GattcDisableNotifyCharacteristic" => {
let id = parse_u64_identifier(args.clone())?;
gattc_toggle_notify_characteristic_async(self, id, false).await
}
"GattcReadCharacteristicById" => {
let id = parse_u64_identifier(args.clone())?;
gattc_read_char_by_id_async(self, id).await
}
"GattcReadCharacteristicByType" => {
let uuid = parse_arg!(args, as_str, "uuid")?;
let result = self.gattc_read_char_by_type(uuid.to_string()).await?;
Ok(to_value(result)?)
}
"GattcReadLongCharacteristicById" => {
let id = parse_u64_identifier(args.clone())?;
let offset_as_u64 = parse_offset(args.clone())?;
let offset = offset_as_u64 as u16;
let max_bytes_as_u64 = parse_max_bytes(args)?;
let max_bytes = max_bytes_as_u64 as u16;
gattc_read_long_char_by_id_async(self, id, offset, max_bytes).await
}
"GattcReadLongDescriptorById" => {
let id = parse_u64_identifier(args.clone())?;
let offset_as_u64 = parse_offset(args.clone())?;
let offset = offset_as_u64 as u16;
let max_bytes_as_u64 = parse_max_bytes(args)?;
let max_bytes = max_bytes_as_u64 as u16;
gattc_read_long_desc_by_id_async(self, id, offset, max_bytes).await
}
"GattcWriteDescriptorById" => {
let id = parse_u64_identifier(args.clone())?;
let value = parse_write_value(args)?;
gattc_write_desc_by_id_async(self, id, value).await
}
"GattcWriteLongDescriptorById" => {
let id = parse_u64_identifier(args.clone())?;
let offset_as_u64 = parse_offset(args.clone())?;
let offset = offset_as_u64 as u16;
let value = parse_write_value(args)?;
gattc_write_long_desc_by_id_async(self, id, offset, value).await
}
"GattcReadDescriptorById" => {
let id = parse_u64_identifier(args.clone())?;
gattc_read_desc_by_id_async(self, id.clone()).await
}
"GattcListServices" => {
let id = parse_identifier(args)?;
list_services_async(self, id).await
}
_ => return Err(format_err!("Invalid Gatt Client FIDL method: {:?}", method)),
}
}
fn cleanup(&self) {
Self::cleanup(self)
}
fn print(&self) {
Self::print(self)
}
}
#[async_trait(?Send)]
impl Facade for GattServerFacade {
async fn handle_request(&self, method: String, args: Value) -> Result<Value, Error> {
match method.as_ref() {
"GattServerPublishServer" => {
let result = self.publish_server(args).await?;
Ok(to_value(result)?)
}
"GattServerCloseServer" => {
let result = self.close_server().await;
Ok(to_value(result)?)
}
_ => return Err(format_err!("Invalid Gatt Server FIDL method: {:?}", method)),
}
}
fn cleanup(&self) {
Self::cleanup(self)
}
fn print(&self) {
Self::print(self)
}
}
#[async_trait(?Send)]
impl Facade for ProfileServerFacade {
async fn handle_request(&self, method: String, args: Value) -> Result<Value, Error> {
match method.as_ref() {
"ProfileServerInit" => {
let result = self.init_profile_server_proxy().await?;
Ok(to_value(result)?)
}
"ProfileServerAddSearch" => {
let result = self.add_search(args).await?;
Ok(to_value(result)?)
}
"ProfileServerAddService" => {
let result = self.add_service(args).await?;
Ok(to_value(result)?)
}
"ProfileServerCleanup" => {
let result = self.cleanup().await?;
Ok(to_value(result)?)
}
"ProfileServerConnectL2cap" => {
let id = parse_identifier(args.clone())?;
let psm = parse_psm(args.clone())?;
let mode = parse_arg!(args, as_str, "mode")?;
let result = self.connect(id, psm as u16, &mode.to_string()).await?;
Ok(to_value(result)?)
}
"ProfileServerRemoveService" => {
let service_id = parse_u64_identifier(args)? as usize;
let result = self.remove_service(service_id).await?;
Ok(to_value(result)?)
}
_ => return Err(format_err!("Invalid Profile Server FIDL method: {:?}", method)),
}
}
}
#[async_trait(?Send)]
impl Facade for AvdtpFacade {
async fn handle_request(&self, method: String, args: Value) -> Result<Value, Error> {
match method.as_ref() {
"AvdtpInit" => {
let role = parse_arg!(args, as_str, "role")?;
let result = self.init_avdtp_service_proxy(role.to_string()).await?;
Ok(to_value(result)?)
}
"AvdtpGetConnectedPeers" => {
let result = self.get_connected_peers().await?;
Ok(to_value(result)?)
}
"AvdtpSetConfiguration" => {
let peer_id = parse_u64_identifier(args)?;
let result = self.set_configuration(peer_id).await?;
Ok(to_value(result)?)
}
"AvdtpGetConfiguration" => {
let peer_id = parse_u64_identifier(args)?;
let result = self.get_configuration(peer_id).await?;
Ok(to_value(result)?)
}
"AvdtpGetCapabilities" => {
let peer_id = parse_u64_identifier(args)?;
let result = self.get_capabilities(peer_id).await?;
Ok(to_value(result)?)
}
"AvdtpGetAllCapabilities" => {
let peer_id = parse_u64_identifier(args)?;
let result = self.get_all_capabilities(peer_id).await?;
Ok(to_value(result)?)
}
"AvdtpReconfigureStream" => {
let peer_id = parse_u64_identifier(args)?;
let result = self.reconfigure_stream(peer_id).await?;
Ok(to_value(result)?)
}
"AvdtpSuspendStream" => {
let peer_id = parse_u64_identifier(args)?;
let result = self.suspend_stream(peer_id).await?;
Ok(to_value(result)?)
}
"AvdtpSuspendAndReconfigure" => {
let peer_id = parse_u64_identifier(args)?;
let result = self.suspend_and_reconfigure(peer_id).await?;
Ok(to_value(result)?)
}
"AvdtpReleaseStream" => {
let peer_id = parse_u64_identifier(args)?;
let result = self.release_stream(peer_id).await?;
Ok(to_value(result)?)
}
"AvdtpEstablishStream" => {
let peer_id = parse_u64_identifier(args)?;
let result = self.establish_stream(peer_id).await?;
Ok(to_value(result)?)
}
"AvdtpStartStream" => {
let peer_id = parse_u64_identifier(args)?;
let result = self.start_stream(peer_id).await?;
Ok(to_value(result)?)
}
"AvdtpAbortStream" => {
let peer_id = parse_u64_identifier(args)?;
let result = self.abort_stream(peer_id).await?;
Ok(to_value(result)?)
}
"AvdtpRemoveService" => {
let result = self.remove_service().await;
Ok(to_value(result)?)
}
_ => bail!("Invalid AVDTP FIDL method: {:?}", method),
}
}
}
async fn start_scan_async(
facade: &GattClientFacade,
filter: Option<ScanFilter>,
) -> Result<Value, Error> {
let start_scan_result = facade.start_scan(filter).await?;
Ok(to_value(start_scan_result)?)
}
async fn stop_scan_async(facade: &GattClientFacade) -> Result<Value, Error> {
let central = facade.get_central_proxy().clone().expect("No central proxy.");
if let Err(e) = central.stop_scan() {
return Err(format_err!("Error stopping scan: {}", e));
} else {
// Get the list of devices discovered by the scan.
let devices = facade.get_devices();
match to_value(devices) {
Ok(dev) => Ok(dev),
Err(e) => Err(e.into()),
}
}
}
async fn le_get_discovered_devices_async(facade: &GattClientFacade) -> Result<Value, Error> {
// Get the list of devices discovered by the scan.
match to_value(facade.get_devices()) {
Ok(dev) => Ok(dev),
Err(e) => Err(e.into()),
}
}
async fn connect_peripheral_async(facade: &GattClientFacade, id: String) -> Result<Value, Error> {
let connect_periph_result = facade.connect_peripheral(id).await?;
Ok(to_value(connect_periph_result)?)
}
async fn disconnect_peripheral_async(
facade: &GattClientFacade,
id: String,
) -> Result<Value, Error> {
let value = facade.disconnect_peripheral(id).await?;
Ok(to_value(value)?)
}
// Uses the same return type as connect_peripheral_async -- Returns subset of
// fidl::ServiceInfo
async fn list_services_async(facade: &GattClientFacade, id: String) -> Result<Value, Error> {
let list_services_result = facade.list_services(id).await?;
Ok(to_value(BleConnectPeripheralResponse::new(list_services_result))?)
}
async fn gattc_connect_to_service_async(
facade: &GattClientFacade,
periph_id: String,
service_id: u64,
) -> Result<Value, Error> {
let connect_to_service_result = facade.gattc_connect_to_service(periph_id, service_id).await?;
Ok(to_value(connect_to_service_result)?)
}
async fn gattc_discover_characteristics_async(facade: &GattClientFacade) -> Result<Value, Error> {
let discover_characteristics_results = facade.gattc_discover_characteristics().await?;
Ok(to_value(GattcDiscoverCharacteristicResponse::new(discover_characteristics_results))?)
}
async fn gattc_write_char_by_id_async(
facade: &GattClientFacade,
id: u64,
write_value: Vec<u8>,
) -> Result<Value, Error> {
let write_char_status = facade.gattc_write_char_by_id(id, write_value).await?;
Ok(to_value(write_char_status)?)
}
async fn gattc_write_long_char_by_id_async(
facade: &GattClientFacade,
id: u64,
offset: u16,
write_value: Vec<u8>,
reliable_mode: bool,
) -> Result<Value, Error> {
let write_char_status =
facade.gattc_write_long_char_by_id(id, offset, write_value, reliable_mode).await?;
Ok(to_value(write_char_status)?)
}
async fn gattc_write_char_by_id_without_response_async(
facade: &GattClientFacade,
id: u64,
write_value: Vec<u8>,
) -> Result<Value, Error> {
let write_char_status = facade.gattc_write_char_by_id_without_response(id, write_value).await?;
Ok(to_value(write_char_status)?)
}
async fn gattc_read_char_by_id_async(facade: &GattClientFacade, id: u64) -> Result<Value, Error> {
let read_char_status = facade.gattc_read_char_by_id(id).await?;
Ok(to_value(read_char_status)?)
}
async fn gattc_read_long_char_by_id_async(
facade: &GattClientFacade,
id: u64,
offset: u16,
max_bytes: u16,
) -> Result<Value, Error> {
let read_long_char_status = facade.gattc_read_long_char_by_id(id, offset, max_bytes).await?;
Ok(to_value(read_long_char_status)?)
}
async fn gattc_read_long_desc_by_id_async(
facade: &GattClientFacade,
id: u64,
offset: u16,
max_bytes: u16,
) -> Result<Value, Error> {
let read_long_desc_status = facade.gattc_read_long_desc_by_id(id, offset, max_bytes).await?;
Ok(to_value(read_long_desc_status)?)
}
async fn gattc_read_desc_by_id_async(facade: &GattClientFacade, id: u64) -> Result<Value, Error> {
let read_desc_status = facade.gattc_read_desc_by_id(id).await?;
Ok(to_value(read_desc_status)?)
}
async fn gattc_write_desc_by_id_async(
facade: &GattClientFacade,
id: u64,
write_value: Vec<u8>,
) -> Result<Value, Error> {
let write_desc_status = facade.gattc_write_desc_by_id(id, write_value).await?;
Ok(to_value(write_desc_status)?)
}
async fn gattc_write_long_desc_by_id_async(
facade: &GattClientFacade,
id: u64,
offset: u16,
write_value: Vec<u8>,
) -> Result<Value, Error> {
let write_desc_status = facade.gattc_write_long_desc_by_id(id, offset, write_value).await?;
Ok(to_value(write_desc_status)?)
}
async fn gattc_toggle_notify_characteristic_async(
facade: &GattClientFacade,
id: u64,
value: bool,
) -> Result<Value, Error> {
let toggle_notify_result = facade.gattc_toggle_notify_characteristic(id, value).await?;
Ok(to_value(toggle_notify_result)?)
}
async fn publish_service_async(
facade: &RwLock<BluetoothFacade>,
service_info: ServiceInfo,
local_service_id: String,
) -> Result<Value, Error> {
let publish_service_result =
BluetoothFacade::publish_service(&facade, service_info, local_service_id).await?;
Ok(to_value(publish_service_result)?)
}