blob: d067ddc0235732227e2c6bb84dbb590ad0413ed0 [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::host_dispatcher::HostDispatcher;
use crate::util::clone_host_state;
use fidl;
use fidl::endpoints::ClientEnd;
use fidl_fuchsia_bluetooth;
use fidl_fuchsia_bluetooth::Status;
use fidl_fuchsia_bluetooth_control::AdapterInfo;
use fidl_fuchsia_bluetooth_control::{BondingData, PairingDelegateMarker};
use fidl_fuchsia_bluetooth_control::{InputCapabilityType, OutputCapabilityType};
use fidl_fuchsia_bluetooth_gatt::ClientProxy;
use fidl_fuchsia_bluetooth_host::{HostEvent, HostProxy};
use fidl_fuchsia_bluetooth_le::{CentralMarker, CentralProxy};
use fuchsia_async::{self as fasync,
temp::Either::{Left, Right}};
use fuchsia_bluetooth::{bt_fidl_status, make_clones};
use fuchsia_syslog::{fx_log, fx_log_err, fx_log_info};
use fuchsia_zircon as zx;
use futures::TryFutureExt;
use futures::TryStreamExt;
use futures::{future, Future};
use parking_lot::RwLock;
use std::collections::HashMap;
use std::path::PathBuf;
use std::sync::Arc;
pub struct HostDevice {
pub path: PathBuf,
host: HostProxy,
info: AdapterInfo,
gatt: HashMap<String, (CentralProxy, ClientProxy)>,
}
impl HostDevice {
pub fn new(path: PathBuf, host: HostProxy, info: AdapterInfo) -> Self {
HostDevice {
path,
host,
info,
gatt: HashMap::new(),
}
}
pub fn get_host(&self) -> &HostProxy {
&self.host
}
pub fn set_host_pairing_delegate(
&self, input: InputCapabilityType, output: OutputCapabilityType,
delegate: ClientEnd<PairingDelegateMarker>,
) {
let _ = self
.host
.set_pairing_delegate(input, output, Some(delegate));
}
pub fn get_info(&self) -> &AdapterInfo {
&self.info
}
pub fn store_gatt(&mut self, id: String, central: CentralProxy, client: ClientProxy) {
// TODO(NET-1092): Use Host.Connect instead
self.gatt.insert(id, (central, client));
}
pub fn rm_gatt(&mut self, id: String) -> impl Future<Output = Result<Status, fidl::Error>> {
if let Some((central, _)) = self.gatt.remove(&id) {
Left(
central
.disconnect_peripheral(id.as_str())
.and_then(|res| future::ready(Ok(res))),
)
} else {
Right(future::ready(Ok(bt_fidl_status!(
BluetoothNotAvailable,
"Unknown peripheral"
))))
}
}
pub fn set_name(&self, mut name: String) -> impl Future<Output = Result<Status, fidl::Error>> {
self.host.set_local_name(&mut name)
}
pub fn start_discovery(&mut self) -> impl Future<Output = Result<Status, fidl::Error>> {
self.host.start_discovery()
}
pub fn connect_le_central(&mut self) -> Result<CentralProxy, fidl::Error> {
// TODO map_err
let (service_local, service_remote) = zx::Channel::create().unwrap();
let service_local = fasync::Channel::from_channel(service_local).unwrap();
let server = fidl::endpoints::ServerEnd::<CentralMarker>::new(service_remote);
self.host.request_low_energy_central(server)?;
let proxy = CentralProxy::new(service_local);
Ok(proxy)
}
pub fn close(&self) -> Result<(), fidl::Error> {
self.host.close()
}
pub fn restore_bonds(
&self, mut bonds: Vec<BondingData>,
) -> impl Future<Output = Result<Status, fidl::Error>> {
self.host.add_bonded_devices(&mut bonds.iter_mut())
}
pub fn stop_discovery(&self) -> impl Future<Output = Result<Status, fidl::Error>> {
self.host.stop_discovery()
}
pub fn set_discoverable(
&mut self, discoverable: bool,
) -> impl Future<Output = Result<Status, fidl::Error>> {
self.host.set_discoverable(discoverable)
}
}
pub fn run(
hd: HostDispatcher, host: Arc<RwLock<HostDevice>>,
) -> impl Future<Output = Result<(), fidl::Error>> {
make_clones!(host => host_stream, host);
let stream = host_stream.read().host.take_event_stream();
stream.try_for_each(move |evt| {
match evt {
HostEvent::OnAdapterStateChanged { ref state } => {
host.write().info.state = Some(Box::new(clone_host_state(&state)));
}
// TODO(NET-968): Add integration test for this.
HostEvent::OnDeviceUpdated { mut device } => {
// TODO(NET-1297): generic method for this pattern
for listener in hd.event_listeners().iter() {
let _res = listener
.send_on_device_updated(&mut device)
.map_err(|e| fx_log_err!("Failed to send device updated event: {:?}", e));
}
}
// TODO(NET-1038): Add integration test for this.
HostEvent::OnDeviceRemoved { identifier } => {
for listener in hd.event_listeners().iter() {
let _res = listener
.send_on_device_removed(&identifier)
.map_err(|e| fx_log_err!("Failed to send device removed event: {:?}", e));
}
}
HostEvent::OnNewBondingData { mut data } => {
fx_log_info!("Received Bonding Data: {:#?}", data);
let id = host.read().get_info().identifier.clone();
if let Some(ref bond_events) = hd.bonding_listener() {
let _res = bond_events
.send_on_new_bonding_data(id.as_str(), &mut data)
.map_err(|e| fx_log_err!("Failed to send device bonded event: {:?}", e));
}
}
};
future::ready(Ok(()))
})
}