blob: 36fd332d410b542238db4bcdf9113c997bf69dbc [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::{Error, err_msg};
use fuchsia_async as fasync;
use fuchsia_bluetooth::host::open_host_channel;
use fuchsia_bluetooth::util::clone_host_info;
use fidl_fuchsia_bluetooth_control::AdapterInfo;
use fidl_fuchsia_bluetooth_host::HostProxy;
//use fidl_fuchsia_bluetooth_control::PairingDelegateMarker;
//use fidl_fuchsia_bluetooth_control::{InputCapabilityType, OutputCapabilityType};
//use fuchsia_syslog::{fx_log, fx_log_err, fx_log_info};
use std::path::{Path, PathBuf};
//use fidl_fuchsia_bluetooth_host::HostEvent::*;
//use fidl_fuchsia_bluetooth_host::HostEvent;
use futures::future::FutureExt;
use futures::channel::oneshot;
use futures::channel::oneshot::Receiver;
use std::fs::File;
//use crate::host_dispatcher::*;
use crate::types::bt;
use crate::types::*;
/// A type that supports controlling discovery
pub trait Discovery {
fn start_discovery(&mut self) -> Receiver<bt::Result<()>>;
fn stop_discovery(&self) -> Receiver<bt::Result<()>>;
}
/// A type that represents the BT Host subsystem
pub trait Host : Discovery {}
/// Type representing a BT Adapter with a loaded Host Device Driver
pub struct FidlHost {
device_path: PathBuf,
proxy: HostProxy,
info: AdapterInfo
}
impl FidlHost {
pub fn get_info(&self) -> AdapterInfo { clone_host_info(&self.info) }
pub fn path(&self) -> &Path { &self.device_path }
}
/// Initialize a HostDevice
pub async fn open_host_fidl(device_path: PathBuf) -> Result<FidlHost, Error> {
// Connect to the host device.
let host = File::open(device_path.clone())
.map_err(|_| err_msg("failed to open bt-host device"))?;
let handle = open_host_channel(&host)?;
let handle = fasync::Channel::from_channel(handle.into())?;
let proxy = HostProxy::new(handle);
// Obtain basic information and create and entry in the disptacher's map.
let info = await!(proxy.get_info())
.map_err(|_| err_msg("failed to obtain bt-host information"))?;
Ok(FidlHost{ device_path, proxy, info })
}
//struct HostListener {}
// TODO - This should perhaps be processed at the dispatcher level? Only the first requires
// modifying the Host, and that could be done by the dispatcher?
// TODO - OR, we could just forward everything that isn't an AdapterStateChanged?
//pub async fn run_host(event: HostEvent, dispatcher: HostDispatcher) -> fidl::Result<()> {
//dispatcher.send(HostMsg(event))
//}
impl Discovery for FidlHost {
fn start_discovery(&mut self) -> Receiver<bt::Result<()>> {
let (sender, receiver) = oneshot::channel::<bt::Result<()>>();
// TODO - what happens if send fails?
fasync::spawn(self.proxy.start_discovery().map(|r| {let _todo = sender.send(r.map_err(fidl_err_to_bt).map(|_| ()));}));
receiver
}
fn stop_discovery(&self) -> Receiver<bt::Result<()>> {
let (sender, receiver) = oneshot::channel::<bt::Result<()>>();
// TODO - what happens if send fails?
fasync::spawn(self.proxy.stop_discovery().map(|r| { let _todo = sender.send(r.map_err(fidl_err_to_bt).map(|_| ()));}));
receiver
}
}
fn fidl_err_to_bt(_err: fidl::Error) -> bt::Error {
bt::Error::BadResponseFromAdapter
}
impl Host for FidlHost {}
#[cfg(test)]
mod Fake {
/// A Fake Host for unit testing
pub struct Host {}
impl Host {
pub fn new() -> Host { Host {} }
}
}
#[cfg(test)]
impl Discovery for Fake::Host {
fn start_discovery(&mut self) -> Receiver<bt::Result<()>> {
let (sender,receiver) = oneshot::channel::<bt::Result<()>>();
let _ = sender.send(Ok(()));
receiver
}
fn stop_discovery(&self) -> Receiver<bt::Result<()>> {
let (sender,receiver) = oneshot::channel::<bt::Result<()>>();
let _ = sender.send(Ok(()));
receiver
}
}
#[cfg(test)]
impl Host for Fake::Host { }
/*
impl FidlHost {
// TODO - what is the right API for creation?
pub async fn open(device_path: PathBuf) -> Result<Self> {}
pub fn path(&self) -> &Path { &self.device_path }
pub fn get_info(&self) -> &AdapterInfo { &self.info }
pub fn set_host_pairing_delegate(
&self,
input: InputCapabilityType,
output: OutputCapabilityType,
delegate: ClientEnd<PairingDelegateMarker>
) {
self.proxy.set_pairing_delegate(input, output, Some(delegate));
}
pub fn connect(remote_device: DeviceId) {
self.proxy.connect(remote_device)
}
pub fn disconnect(remote_device: DeviceId) {
self.proxy.disconnect(remote_device)
}
pub async fn set_name(&self, mut name: String) -> bt::Result<()> {
self.proxy.set_local_name(&mut name)
}
pub fn close(&self) -> bt::Result<()> {
self.proxy.close()
}
pub async fn restore_bonds(&self, mut bonds: Vec<BondingData>) -> bt::Result<()> {
self.proxy.add_bonded_devices(&mut bonds.iter_mut())
}
pub async fn set_connectable(&self, value: bool) -> bt::Result<()> {
self.proxy.set_connectable(value)
}
pub async fn set_discoverable(&self, discoverable: bool) -> bt::Result<()> {
self.proxy.set_discoverable(discoverable)
}
pub fn enable_background_scan(&self, enable: bool) -> bt::Result<()> {
self.proxy.enable_background_scan(enable)
}
}
*/
/*
trait HostLike {
pub fn set_host_pairing_delegate( &self,
input: InputCapabilityType, output: OutputCapabilityType,
delegate: ClientEnd<PairingDelegateMarker>
);
pub fn get_info(&self) -> &AdapterInfo;
pub fn start_discovery(&mut self) -> Receiver<bt::Result<()>>;
pub fn stop_discovery(&self) -> Receiver<bt::Result<()>>;
pub fn connect(remote_device: DeviceId);
pub fn disconnect(remote_device: DeviceId);
pub fn set_name(&self, mut name: String) -> Receiver<bt::Result<()>>;
pub fn close(&self) -> bt::Result<()>;
pub fn restore_bonds(&self, mut bonds: Vec<BondingData>) -> Receiver<bt::Result<()>>;
pub fn set_connectable(&self, value: bool) -> Receiver<bt::Result<()>>;
pub fn set_discoverable(&self, discoverable: bool) -> Receiver<bt::Result<()>>;
pub fn enable_background_scan(&self, enable: bool) -> bt::Result<()>;
}
*/
trait Connectable {
fn connect(remote_device: DeviceId);
fn disconnect(remote_device: DeviceId);
}