srcs: ["src/lib.rs"],
edition: "2018",
rustlibs: [
+ "libbt_hal",
+ "libbt_hci",
"libbt_facade_rootservice_proto",
"libbt_facade_common_proto",
"libfutures",
pub use bt_facade_common_proto::common;
pub use bt_facade_rootservice_proto::rootservice;
+use bt_hal::rootcanal_hal::{RootcanalConfig, RootcanalHal};
+use bt_hci::facade::hci_facade_server::HciLayerFacadeService;
+use bt_hci::Hci;
+
use tokio::runtime::Runtime;
+use tokio::sync::mpsc::{channel, Sender};
+use tokio::sync::oneshot;
use grpcio::*;
use std::sync::Arc;
+use futures::executor::block_on;
+
/// Bluetooth testing root facade service
#[derive(Clone)]
pub struct RootFacadeService {
/// Tokio runtime
- pub rt: Arc<Runtime>,
+ rt: Arc<Runtime>,
+ manager: FacadeServiceManager,
}
use bt_facade_rootservice_proto::rootservice::*;
impl RootFacadeService {
/// Create a new instance of the root facade service
- pub fn create(rt: Arc<Runtime>) -> grpcio::Service {
- create_root_facade(Self { rt })
+ pub fn create(
+ rt: Arc<Runtime>,
+ grpc_port: u16,
+ rootcanal_port: Option<u16>,
+ ) -> grpcio::Service {
+ create_root_facade(Self {
+ rt: rt.clone(),
+ manager: FacadeServiceManager::create(rt, grpc_port, rootcanal_port),
+ })
}
}
fn start_stack(
&mut self,
_ctx: RpcContext<'_>,
- mut _cmd: StartStackRequest,
- _sink: UnarySink<StartStackResponse>,
+ req: StartStackRequest,
+ sink: UnarySink<StartStackResponse>,
) {
- unimplemented!()
+ self.rt.block_on(self.manager.start(req)).unwrap();
+ sink.success(StartStackResponse::default());
}
fn stop_stack(
&mut self,
_ctx: RpcContext<'_>,
- mut _cmd: StopStackRequest,
- _sink: UnarySink<StopStackResponse>,
+ _req: StopStackRequest,
+ sink: UnarySink<StopStackResponse>,
) {
- unimplemented!()
+ self.rt.block_on(self.manager.stop()).unwrap();
+ sink.success(StopStackResponse::default());
+ }
+}
+
+#[derive(Debug)]
+enum LifecycleCommand {
+ Start {
+ req: StartStackRequest,
+ done: oneshot::Sender<()>,
+ },
+ Stop {
+ done: oneshot::Sender<()>,
+ },
+}
+
+#[derive(Clone)]
+struct FacadeServiceManager {
+ lifecycle_tx: Sender<LifecycleCommand>,
+}
+
+/// Result type
+type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>;
+
+impl FacadeServiceManager {
+ fn create(rt: Arc<Runtime>, grpc_port: u16, rootcanal_port: Option<u16>) -> Self {
+ let (tx, mut rx) = channel::<LifecycleCommand>(1);
+ let local_rt = rt.clone();
+ local_rt.spawn(async move {
+ let mut server: Option<Server> = None;
+ while let Some(cmd) = rx.recv().await {
+ match cmd {
+ LifecycleCommand::Start { req, done } => {
+ server =
+ Some(Self::start_internal(&rt, req, grpc_port, rootcanal_port).await);
+ done.send(()).unwrap();
+ }
+ LifecycleCommand::Stop { done } => {
+ if let Some(s) = &mut server {
+ block_on(s.shutdown()).unwrap();
+ server = None;
+ }
+ done.send(()).unwrap();
+ }
+ }
+ }
+ });
+
+ Self { lifecycle_tx: tx }
+ }
+
+ async fn start(&self, req: StartStackRequest) -> Result<()> {
+ let (tx, rx) = oneshot::channel();
+ self.lifecycle_tx
+ .send(LifecycleCommand::Start { req, done: tx })
+ .await?;
+ rx.await?;
+ Ok(())
+ }
+
+ async fn stop(&self) -> Result<()> {
+ let (tx, rx) = oneshot::channel();
+ self.lifecycle_tx
+ .send(LifecycleCommand::Stop { done: tx })
+ .await?;
+ rx.await?;
+ Ok(())
+ }
+
+ // TODO this is messy and needs to be overhauled to support bringing up the stack to partial
+ // layers. Will be cleaned up soon.
+ async fn start_internal(
+ rt: &Arc<Runtime>,
+ _req: StartStackRequest,
+ grpc_port: u16,
+ rootcanal_port: Option<u16>,
+ ) -> Server {
+ let env = Arc::new(Environment::new(2));
+ let hal_exports = RootcanalHal::start(
+ RootcanalConfig::new(rootcanal_port.unwrap(), "127.0.0.1"),
+ Arc::clone(&rt),
+ )
+ .await
+ .unwrap();
+ let hci_exports = Hci::start(hal_exports, Arc::clone(&rt));
+ let mut server = ServerBuilder::new(env)
+ .register_service(HciLayerFacadeService::create(hci_exports, Arc::clone(&rt)))
+ .bind("0.0.0.0", grpc_port)
+ .build()
+ .unwrap();
+ server.start();
+ server
}
}
let root_server_port = value_t!(matches, "root-server-port", u16).unwrap();
let grpc_port = value_t!(matches, "grpc-port", u16).unwrap();
let signal_port = value_t!(matches, "signal-port", u16).unwrap();
-
- println!(
- "root server port: {}, grpc port: {}, signal port {}",
- root_server_port, grpc_port, signal_port
- );
+ let rootcanal_port = value_t!(matches, "rootcanal-port", u16).ok();
let env = Arc::new(Environment::new(2));
let mut server = ServerBuilder::new(env)
- .register_service(RootFacadeService::create(rt))
+ .register_service(RootFacadeService::create(rt, grpc_port, rootcanal_port))
.bind("0.0.0.0", root_server_port)
.build()
.unwrap();
],
host_supported: true,
}
-
-rust_binary {
- name: "hci_facade_client",
- crate_name: "hci_facade_client",
- srcs: ["src/facade/hci_facade_client.rs"],
- edition: "2018",
- rustlibs: [
- "libbt_hal",
- "libbt_hci",
- "libbytes",
- "libfutures",
- "libgrpcio",
- "libprotobuf",
- "libtokio",
- ],
- host_supported: true,
-}
-
-rust_binary {
- name: "hci_facade_main",
- crate_name: "hci_facade_main",
- srcs: ["src/facade/hci_facade_main.rs"],
- edition: "2018",
- rustlibs: [
- "libbt_hal",
- "libbt_hci",
- "libbytes",
- "libfutures",
- "libgrpcio",
- "libprotobuf",
- "libtokio",
- ],
- host_supported: true,
-}
+++ /dev/null
-//! A client that connects to HciLayerFacadeService
-
-// TODO(qasimj): This client is temporary and is used for testing only.
-// It will be removed later.
-
-use grpcio::*;
-
-use std::sync::Arc;
-
-use futures::TryStreamExt;
-
-use bt_hci as hci;
-use hci::facade::protos::empty::Empty;
-use hci::facade::protos::facade::{CommandMsg, EventCodeMsg};
-use hci::facade::protos::hci_layer_facade_grpc::HciLayerFacadeClient;
-
-fn new_event_code(code: u32) -> EventCodeMsg {
- let mut event_code = EventCodeMsg::default();
- event_code.set_code(code);
- event_code
-}
-
-fn new_command(bytes: Vec<u8>) -> CommandMsg {
- let mut cmd = CommandMsg::default();
- cmd.set_command(bytes);
- cmd
-}
-
-async fn register_event_handler(
- client: &HciLayerFacadeClient,
- event_code: &EventCodeMsg,
-) -> Result<()> {
- let register_event_handler = client.register_event_handler_async(event_code)?;
- register_event_handler.await?;
-
- Ok(())
-}
-
-async fn enqueue_command_with_complete(
- client: &HciLayerFacadeClient,
- cmd: &CommandMsg,
-) -> Result<()> {
- let enqueue = client.enqueue_command_with_complete_async(cmd)?;
- enqueue.await?;
- Ok(())
-}
-
-async fn fetch_events(client: &HciLayerFacadeClient) -> Result<()> {
- let mut fetch_events = client.fetch_events(&Empty::new())?;
- while let Some(event) = fetch_events.try_next().await? {
- println!("Received Event: {:?}", event);
- }
- Ok(())
-}
-
-async fn async_main() -> Result<()> {
- let env = Arc::new(Environment::new(2));
- let channel = ChannelBuilder::new(env).connect("pop-os:8999");
- let client = HciLayerFacadeClient::new(channel);
-
- println!("Registering event handler!");
- register_event_handler(&client, &new_event_code(0x0eu32)).await?;
-
- let handle = fetch_events(&client);
- let cmd = &new_command(vec![0x0du8, 0x08, 0x04, 0x07, 0x00, 0x06, 0x00]);
-
- println!("Enqueue commands");
- enqueue_command_with_complete(&client, cmd).await.unwrap();
-
- enqueue_command_with_complete(&client, cmd).await.unwrap();
-
- println!("Waiting for events...");
- handle.await.unwrap();
-
- Ok(())
-}
-
-fn main() {
- futures::executor::block_on(async_main()).unwrap();
-}
+++ /dev/null
-//! A server providing the HciLayerFacadeService
-
-use bt_hal as hal;
-use bt_hci as hci;
-use futures::channel::oneshot;
-use futures::executor::block_on;
-use grpcio::*;
-use hal::rootcanal_hal::{RootcanalConfig, RootcanalHal};
-use hci::facade::hci_facade_server::HciLayerFacadeService;
-use hci::Hci;
-
-use std::io::{self, Read};
-use std::sync::Arc;
-use std::thread;
-
-use tokio::runtime::Runtime;
-
-async fn async_main(rt: Arc<Runtime>) -> Result<()> {
- let env = Arc::new(Environment::new(2));
- let hal_exports = RootcanalHal::start(RootcanalConfig::new(6402, "127.0.0.1"), Arc::clone(&rt)).await.unwrap();
- let hci_exports = Hci::start(hal_exports, Arc::clone(&rt));
- let mut server = ServerBuilder::new(env)
- .register_service(HciLayerFacadeService::create(hci_exports, Arc::clone(&rt)))
- .bind("0.0.0.0", 8999)
- .build()
- .unwrap();
- server.start();
-
- let (tx, rx) = oneshot::channel();
-
- thread::spawn(move || {
- println!("Press ENTER to exit...");
- let _ = io::stdin().read(&mut [0]).unwrap();
- tx.send(())
- });
- block_on(rx).unwrap();
- block_on(server.shutdown()).unwrap();
-
- Ok(())
-}
-
-fn main() {
- let rt = Arc::new(Runtime::new().unwrap());
- let runtime = Arc::clone(&rt);
- runtime.block_on(async_main(rt)).unwrap();
-}