blob: ae700e638c1b4ce212c6bc51dbcb8d620b1175d2 [file] [log] [blame]
//! Implementation of the HAl that talks to BT controller over Android's HIDL
use crate::hal::internal::{InnerHal, RawHal};
use bt_packets::hci::{AclPacket, CommandPacket, EventPacket, IsoPacket, Packet};
use gddi::{module, provides};
use std::sync::Arc;
use std::sync::Mutex;
use tokio::runtime::Runtime;
use tokio::select;
use tokio::sync::mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender};
module! {
hidl_hal_module,
providers {
RawHal => provide_hidl_hal,
}
}
#[provides]
async fn provide_hidl_hal(rt: Arc<Runtime>) -> RawHal {
let (raw_hal, inner_hal) = InnerHal::new();
let (init_tx, mut init_rx) = unbounded_channel();
*CALLBACKS.lock().unwrap() = Some(Callbacks {
init_tx,
evt_tx: inner_hal.evt_tx,
acl_tx: inner_hal.acl_tx,
iso_tx: inner_hal.iso_tx,
});
ffi::start_hal();
init_rx.recv().await.unwrap();
rt.spawn(dispatch_outgoing(inner_hal.cmd_rx, inner_hal.acl_rx, inner_hal.iso_rx));
raw_hal
}
#[cxx::bridge(namespace = bluetooth::hal)]
// TODO Either use or remove these functions, this shouldn't be the long term state
#[allow(dead_code)]
mod ffi {
unsafe extern "C++" {
include!("src/hal/ffi/hidl.h");
fn start_hal();
fn stop_hal();
fn send_command(data: &[u8]);
fn send_acl(data: &[u8]);
fn send_sco(data: &[u8]);
fn send_iso(data: &[u8]);
}
extern "Rust" {
fn on_init_complete();
fn on_event(data: &[u8]);
fn on_acl(data: &[u8]);
fn on_sco(data: &[u8]);
fn on_iso(data: &[u8]);
}
}
struct Callbacks {
init_tx: UnboundedSender<()>,
evt_tx: UnboundedSender<EventPacket>,
acl_tx: UnboundedSender<AclPacket>,
iso_tx: UnboundedSender<IsoPacket>,
}
lazy_static! {
static ref CALLBACKS: Mutex<Option<Callbacks>> = Mutex::new(None);
}
fn on_init_complete() {
let callbacks = CALLBACKS.lock().unwrap();
callbacks.as_ref().unwrap().init_tx.send(()).unwrap();
}
fn on_event(data: &[u8]) {
log::error!("got event: {:02x?}", data);
let callbacks = CALLBACKS.lock().unwrap();
match EventPacket::parse(data) {
Ok(p) => callbacks.as_ref().unwrap().evt_tx.send(p).unwrap(),
Err(e) => log::error!("failure to parse event: {:?} data: {:02x?}", e, data),
}
}
fn on_acl(data: &[u8]) {
let callbacks = CALLBACKS.lock().unwrap();
match AclPacket::parse(data) {
Ok(p) => callbacks.as_ref().unwrap().acl_tx.send(p).unwrap(),
Err(e) => log::error!("failure to parse incoming ACL: {:?} data: {:02x?}", e, data),
}
}
fn on_sco(_data: &[u8]) {}
fn on_iso(data: &[u8]) {
let callbacks = CALLBACKS.lock().unwrap();
match IsoPacket::parse(data) {
Ok(p) => callbacks.as_ref().unwrap().iso_tx.send(p).unwrap(),
Err(e) => log::error!("failure to parse incoming ISO: {:?} data: {:02x?}", e, data),
}
}
async fn dispatch_outgoing(
mut cmd_rx: UnboundedReceiver<CommandPacket>,
mut acl_rx: UnboundedReceiver<AclPacket>,
mut iso_rx: UnboundedReceiver<IsoPacket>,
) {
loop {
select! {
Some(cmd) = cmd_rx.recv() => ffi::send_command(&cmd.to_bytes()),
Some(acl) = acl_rx.recv() => ffi::send_acl(&acl.to_bytes()),
Some(iso) = iso_rx.recv() => ffi::send_iso(&iso.to_bytes()),
else => break,
}
}
}