ckpt
Change-Id: If4b07dfb6819276d9d0e506ecfeaed8eb585897a
diff --git a/bin/bluetooth/bt-mgr/src/bond_defs.rs b/bin/bluetooth/bt-mgr/src/bond_defs.rs
index da401ce..86ced23 100644
--- a/bin/bluetooth/bt-mgr/src/bond_defs.rs
+++ b/bin/bluetooth/bt-mgr/src/bond_defs.rs
@@ -101,12 +101,47 @@
#[derive(Serialize, Deserialize)]
pub struct BondMap(HashMap<String, VecBondingData>);
-#[derive(Serialize, Deserialize)]
-struct VecBondingData {
- #[serde(with = "VecBondData")]
- inner: Vec<BondingData>,
+impl BondMap {
+ pub fn inner(&self) -> &HashMap<String, VecBondingData> {
+ &self.0
+ }
+
+ pub fn inner_mut(&mut self) -> &mut HashMap<String, VecBondingData> {
+ &mut self.0
+ }
}
+#[derive(Serialize, Deserialize)]
+pub struct VecBondingData {
+ #[serde(with = "VecBondData")]
+ pub inner: Vec<BondingData>,
+}
+
+//impl VecBondingData {
+// pub fn inner(&self) -> VecBondingData {
+// &self.inner
+// }
+//}
+
+// TODO
+struct VecBondIter {}
+//
+//impl Iterator for VecBondIter {
+// type Item = BondingData;
+//
+// fn next(&mut self) -> Option<Self::Item> {
+// self.inner.iter().next()
+// }
+//}
+//impl IntoIterator for VecBondingData {
+// type Item = BondingData;
+// //type IntoIterator = VecBondIter;
+//
+// //fn into_iter(self) -> Self::IntoIterator {
+//
+// //}
+//}
+
mod VecBondData {
use super::{BondingData, BondingDataDef};
use serde::Serializer;
diff --git a/bin/bluetooth/bt-mgr/src/bond_store.rs b/bin/bluetooth/bt-mgr/src/bond_store.rs
new file mode 100644
index 0000000..5210e17
--- /dev/null
+++ b/bin/bluetooth/bt-mgr/src/bond_store.rs
@@ -0,0 +1,109 @@
+// 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 app::client::App;
+use failure::{Error, ResultExt};
+use futures::future::ok as fok;
+use futures::{Future, FutureExt, StreamExt};
+use std::fs::File;
+use std::fs::OpenOptions;
+use std::io::{Read, Write};
+use std::path::PathBuf;
+use std::sync::{Arc, Mutex};
+use std::{thread, time};
+use toml;
+
+use app::client::Launcher;
+use fidl_bluetooth_bonder::{BonderEvent, BonderEventStream, BonderMarker, BondingData};
+use fidl_bluetooth_control::ControlMarker;
+use fidl_bluetooth_gatt::Server_Marker;
+use fidl_bluetooth_low_energy::{CentralMarker, PeripheralMarker};
+
+use bond_defs::BondMap;
+
+static BT_MGR_DIR: &'static str = "data/bt-mgr";
+
+pub struct BondStore {
+ bonds: BondMap,
+ bond_store: File,
+}
+
+impl BondStore {
+ pub fn load_store() -> Result<Self, Error> {
+ let store_path: PathBuf = [BT_MGR_DIR, "/bonds.toml"].iter().collect();
+
+ let mut bond_store = OpenOptions::new()
+ .read(true)
+ .write(true)
+ .create(true)
+ .open(store_path)?;
+
+ let mut contents = String::new();
+ bond_store
+ .read_to_string(&mut contents)
+ .expect("The bond storage file is corrupted");
+ let bonds: BondMap = toml::from_str(contents.as_str()).unwrap();
+
+ Ok(BondStore { bonds, bond_store })
+ }
+
+ pub fn add(&mut self, local_id: String, bond_data: BondingData) {
+ self.bonds.inner_mut().entry(local_id)
+ // TODO look up syntax, push if not there
+// .or_insert(VecBondingData{inner: vec![]})
+ .and_modify(move |entry| {
+ entry.inner.push(bond_data);
+ });
+ let _ = self.save_state();
+ }
+
+ pub fn bonds(&self) -> &BondMap {
+ &self.bonds
+ }
+
+ pub fn save_state(&mut self) -> Result<(), Error> {
+ let toml = toml::to_string_pretty(&self.bonds)?;
+ self.bond_store.write_all(toml.as_bytes())?;
+ self.bond_store.sync_data()?;
+ Ok(())
+ }
+}
+
+pub fn bond(bond_store: Arc<Mutex<BondStore>>, bt_gap: App) -> Result<(), Error> {
+ let bond_svc = bt_gap.connect_to_service(BonderMarker)?;
+
+ let bond_store = bond_store.lock().unwrap();
+ for (bond_key, bond_data) in bond_store.bonds.inner().iter() {
+ // TODO make the iter work
+ // bond_svc.add_bonded_devices(bond_key, bond_data.into_iter());
+ }
+
+ Ok(())
+}
+
+pub fn watch_bonds(
+ bond_store: Arc<Mutex<BondStore>>,
+) -> impl Future<Item = BonderEventStream, Error = Error> {
+ let launcher = Launcher::new()
+ .context("Failed to open launcher service")
+ .unwrap();
+ let app = launcher
+ .launch(String::from("bt-gap"), None)
+ .context("Failed to launch bt-gap (bluetooth) service")
+ .unwrap();
+ thread::sleep(time::Duration::from_millis(2000));
+ let app = app.connect_to_service(BonderMarker);
+ let stream = app.unwrap().take_event_stream();
+ stream
+ .for_each(move |evt| {
+ match evt {
+ BonderEvent::OnNewBondingData { local_id, data } => {
+ let mut bond_store = bond_store.lock().unwrap();
+ bond_store.add(local_id, data)
+ }
+ }
+ fok(())
+ })
+ .err_into()
+}
diff --git a/bin/bluetooth/bt-mgr/src/main.rs b/bin/bluetooth/bt-mgr/src/main.rs
index 802dea3..12fc077 100644
--- a/bin/bluetooth/bt-mgr/src/main.rs
+++ b/bin/bluetooth/bt-mgr/src/main.rs
@@ -10,9 +10,13 @@
extern crate fidl;
extern crate fidl_bluetooth_bonder;
extern crate fidl_bluetooth_control;
+extern crate fidl_bluetooth_gatt;
+extern crate fidl_bluetooth_low_energy;
extern crate fuchsia_app as app;
extern crate fuchsia_async as async;
extern crate fuchsia_zircon as zx;
+#[macro_use]
+extern crate fuchsia_bluetooth as bt;
extern crate futures;
extern crate parking_lot;
#[macro_use]
@@ -22,73 +26,47 @@
extern crate serde;
extern crate toml;
-use std::io::Read;
-use std::path::PathBuf;
-
use fidl::endpoints2::ServiceMarker;
use std::{thread, time};
use app::client::App;
use std::sync::{Arc, Mutex};
-use std::fs::File;
-use std::fs::OpenOptions;
-
-use std::io::Write;
+use futures::future::ok as fok;
+use futures::{Future, FutureExt, StreamExt};
use app::client::Launcher;
use app::server::ServicesServer;
use failure::{Error, ResultExt};
-use fidl_bluetooth_bonder::BonderMarker;
use fidl_bluetooth_control::ControlMarker;
+use fidl_bluetooth_gatt::Server_Marker;
+use fidl_bluetooth_low_energy::{CentralMarker, PeripheralMarker};
mod bond_defs;
+mod bond_store;
mod logger;
use bond_defs::*;
+use bond_store::BondStore;
const MAX_LOG_LEVEL: log::LevelFilter = log::LevelFilter::Info;
static LOGGER: logger::Logger = logger::Logger;
-static BT_MGR_DIR: &'static str = "data/bt-mgr";
-
-struct BondStore {
- bonds: BondMap,
- bond_store: File,
-}
-
-impl BondStore {
- fn load_store() -> Result<Self, Error> {
- let store_path: PathBuf = [BT_MGR_DIR, "/bonds.toml"].iter().collect();
-
- let mut bond_store = OpenOptions::new()
- .read(true)
- .write(true)
- .create(true)
- .open(store_path)?;
-
- let mut contents = String::new();
- bond_store
- .read_to_string(&mut contents)
- .expect("The bond storage file is corrupted");
- let bonds: BondMap = toml::from_str(contents.as_str()).unwrap();
-
- Ok(BondStore { bonds, bond_store })
- }
-
- fn save_state(&mut self) -> Result<(), Error> {
- let toml = toml::to_string_pretty(&self.bonds)?;
- self.bond_store.write_all(toml.as_bytes())?;
- self.bond_store.sync_data()?;
- Ok(())
- }
-}
-
-fn bond(_bond_store: Arc<Mutex<BondStore>>, bt_gap: App) -> Result<(), Error> {
- let _bond_svc = bt_gap.connect_to_service(BonderMarker)?;
-
- //bond_svc.add_bonded_devices();
- Ok(())
+fn launch_bt_gap<S: ServiceMarker>(
+ marker: S, bond_store: Arc<Mutex<BondStore>>, chan: async::Channel,
+) {
+ let launcher = Launcher::new()
+ .context("Failed to open launcher service")
+ .unwrap();
+ let app = launcher
+ .launch(String::from("bt-gap"), None)
+ .context("Failed to launch bt-gap (bluetooth) service")
+ .unwrap();
+ // TODO check if we need to launch a service?
+ thread::sleep(time::Duration::from_millis(2000));
+ let _ = app.pass_to_service(marker, chan.into());
+ // TODO cap the number of times this is done?
+ let _ = bond_store::bond(bond_store.clone(), app);
}
fn main() -> Result<(), Error> {
@@ -99,25 +77,33 @@
let mut executor = async::Executor::new().context("Error creating executor")?;
let bond_store = Arc::new(Mutex::new(BondStore::load_store()?));
+ make_clones!(bond_store => control_bs, central_bs, peripheral_bs, server_bs, bond_bs);
+
+ let bond_watcher = bond_store::watch_bonds(bond_bs);
+
let server = ServicesServer::new()
.add_service((ControlMarker::NAME, move |chan: async::Channel| {
info!("Passing Control Handle to bt-gap");
- let launcher = Launcher::new()
- .context("Failed to open launcher service")
- .unwrap();
- let app = launcher
- .launch(String::from("bt-gap"), None)
- .context("Failed to launch bt-gap (bluetooth) service")
- .unwrap();
- thread::sleep(time::Duration::from_millis(2000));
- let _ = app.pass_to_service(ControlMarker, chan.into());
- let _ = bond(bond_store.clone(), app);
+ launch_bt_gap(ControlMarker, control_bs.clone(), chan);
+ }))
+ .add_service((CentralMarker::NAME, move |chan: async::Channel| {
+ info!("Passing LE Central Handle to bt-gap");
+ launch_bt_gap(CentralMarker, central_bs.clone(), chan);
+ }))
+ .add_service((PeripheralMarker::NAME, move |chan: async::Channel| {
+ info!("Passing Peripheral Handle to bt-gap");
+ launch_bt_gap(PeripheralMarker, peripheral_bs.clone(), chan);
+ }))
+ .add_service((Server_Marker::NAME, move |chan: async::Channel| {
+ info!("Passing GATT Handle to bt-gap");
+ launch_bt_gap(Server_Marker, server_bs.clone(), chan);
}))
.start()
.map_err(|e| e.context("error starting service server"))?;
executor
- .run_singlethreaded(server)
+ .run_singlethreaded(server.join(bond_watcher))
.context("bt-mgr failed to execute future")
+ .map(|_| ())
.map_err(|e| e.into())
}