Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bfa97a39 authored by Zach Johnson's avatar Zach Johnson
Browse files

rusty-gd: most of the HCI shim layer

(command sending not connected yet)

Bug: 171749953
Tag: #gd-refactor
Test: gd/cert/run --rhost SimpleHalTest
Change-Id: I442176d1e29485dab56dcaba53f0975de144a1fb
parent e6bdb186
Loading
Loading
Loading
Loading
+6 −11
Original line number Diff line number Diff line
@@ -87,7 +87,10 @@ pub struct HciExports {
}

impl HciExports {
    async fn send_raw(&mut self, cmd: CommandPacket) -> Result<EventPacket> {
    /// Send a command, but does not automagically associate the expected returning event type.
    ///
    /// Only really useful for facades & shims.
    pub async fn send_raw(&mut self, cmd: CommandPacket) -> Result<EventPacket> {
        let (tx, rx) = oneshot::channel::<EventPacket>();
        self.cmd_tx.send(QueuedCommand { cmd, fut: tx }).await?;
        let event = rx.await?;
@@ -113,11 +116,7 @@ impl HciExports {
            | EventCode::VendorSpecific => panic!("{:?} is a protected event", code),
            _ => {
                assert!(
                    self.evt_handlers
                        .lock()
                        .await
                        .insert(code, sender)
                        .is_none(),
                    self.evt_handlers.lock().await.insert(code, sender).is_none(),
                    "A handler for {:?} is already registered",
                    code
                );
@@ -137,11 +136,7 @@ impl HciExports {
        sender: Sender<LeMetaEventPacket>,
    ) {
        assert!(
            self.le_evt_handlers
                .lock()
                .await
                .insert(code, sender)
                .is_none(),
            self.le_evt_handlers.lock().await.insert(code, sender).is_none(),
            "A handler for {:?} is already registered",
            code
        );
+5 −0
Original line number Diff line number Diff line
@@ -79,4 +79,9 @@ impl Stack {
        let rt = self.rt.clone();
        rt.block_on(self.stop());
    }

    /// Get a clone of the underlying runtime for this stack
    pub fn get_runtime(&self) -> Arc<Runtime> {
        self.rt.clone()
    }
}
+3 −0
Original line number Diff line number Diff line
@@ -29,6 +29,9 @@ rust_ffi_static {
        "libcxx",
        "libtokio",
        "libbt_main",
        "libbt_packets",
        "libfutures",
        "libnum_traits",
    ],
    static_libs: [
        "libbt_callbacks_cxx",
+108 −10
Original line number Diff line number Diff line
//! Hci shim

use bt_packets::hci::{
    AclPacket, CommandPacket, EventCode, EventPacket, LeMetaEventPacket, SubeventCode,
};
use num_traits::FromPrimitive;
use std::sync::Arc;
use tokio::runtime::Runtime;
use tokio::sync::mpsc::{channel, Receiver, Sender};
use tokio::sync::Mutex;

#[cxx::bridge(namespace = bluetooth::shim::rust)]
mod ffi {
    extern "C" {
@@ -11,25 +20,114 @@ mod ffi {
    }

    extern "Rust" {
        fn hci_set_acl_callback(callback: UniquePtr<u8SliceCallback>);
        fn hci_send_command(data: &[u8]);
        fn hci_send_acl(data: &[u8]);
        fn hci_register_event(event: u8, callback: UniquePtr<u8SliceCallback>);
        fn hci_register_le_event(subevent: u8, callback: UniquePtr<u8SliceCallback>);
        type Hci;

        fn hci_set_acl_callback(hci: &mut Hci, callback: UniquePtr<u8SliceCallback>);
        fn hci_set_evt_callback(hci: &mut Hci, callback: UniquePtr<u8SliceCallback>);
        fn hci_set_le_evt_callback(hci: &mut Hci, callback: UniquePtr<u8SliceCallback>);

        fn hci_send_command(hci: &mut Hci, data: &[u8], callback: UniquePtr<u8SliceCallback>);
        fn hci_send_acl(hci: &mut Hci, data: &[u8]);
        fn hci_register_event(hci: &mut Hci, event: u8);
        fn hci_register_le_event(hci: &mut Hci, subevent: u8);
    }
}

// we take ownership when we get the callbacks
unsafe impl Send for ffi::u8SliceCallback {}

pub struct Hci {
    rt: Arc<Runtime>,
    internal: bt_hci::HciExports,
    acl_callback_set: bool,
    evt_callback_set: bool,
    le_evt_callback_set: bool,
    evt_tx: Sender<EventPacket>,
    evt_rx: Arc<Mutex<Receiver<EventPacket>>>,
    le_evt_tx: Sender<LeMetaEventPacket>,
    le_evt_rx: Arc<Mutex<Receiver<LeMetaEventPacket>>>,
}

impl Hci {
    pub fn new(rt: Arc<Runtime>, internal: bt_hci::HciExports) -> Self {
        let (evt_tx, evt_rx) = channel::<EventPacket>(10);
        let (le_evt_tx, le_evt_rx) = channel::<LeMetaEventPacket>(10);
        Self {
            rt,
            internal,
            acl_callback_set: false,
            evt_callback_set: false,
            le_evt_callback_set: false,
            evt_tx,
            evt_rx: Arc::new(Mutex::new(evt_rx)),
            le_evt_tx,
            le_evt_rx: Arc::new(Mutex::new(le_evt_rx)),
        }
    }
}

fn hci_send_command(_data: &[u8]) {
pub fn hci_send_command(
    hci: &mut Hci,
    data: &[u8],
    callback: cxx::UniquePtr<ffi::u8SliceCallback>,
) {
    let packet = CommandPacket::parse(data).unwrap();
    let mut clone_internal = hci.internal.clone();
    hci.rt.spawn(async move {
        let resp = clone_internal.send_raw(packet).await.unwrap();
        callback.Run(&resp.to_bytes());
    });
}

fn hci_send_acl(_data: &[u8]) {
pub fn hci_send_acl(hci: &mut Hci, data: &[u8]) {
    hci.rt.block_on(hci.internal.acl_tx.send(AclPacket::parse(data).unwrap())).unwrap();
}

fn hci_register_event(_event: u8, _callback: cxx::UniquePtr<ffi::u8SliceCallback>) {
pub fn hci_register_event(hci: &mut Hci, event: u8) {
    hci.rt.block_on(
        hci.internal.register_event_handler(EventCode::from_u8(event).unwrap(), hci.evt_tx.clone()),
    );
}

fn hci_register_le_event(_subevent: u8, _callback: cxx::UniquePtr<ffi::u8SliceCallback>) {
pub fn hci_register_le_event(hci: &mut Hci, subevent: u8) {
    hci.rt.block_on(hci.internal.register_le_event_handler(
        SubeventCode::from_u8(subevent).unwrap(),
        hci.le_evt_tx.clone(),
    ));
}

fn hci_set_acl_callback(_callback: cxx::UniquePtr<ffi::u8SliceCallback>) {
pub fn hci_set_acl_callback(hci: &mut Hci, callback: cxx::UniquePtr<ffi::u8SliceCallback>) {
    assert!(!hci.acl_callback_set);
    hci.acl_callback_set = true;

    let stream = hci.internal.acl_rx.clone();
    hci.rt.spawn(async move {
        while let Some(item) = stream.lock().await.recv().await {
            callback.Run(&item.to_bytes());
        }
    });
}

pub fn hci_set_evt_callback(hci: &mut Hci, callback: cxx::UniquePtr<ffi::u8SliceCallback>) {
    assert!(!hci.evt_callback_set);
    hci.evt_callback_set = true;

    let stream = hci.evt_rx.clone();
    hci.rt.spawn(async move {
        while let Some(item) = stream.lock().await.recv().await {
            callback.Run(&item.to_bytes());
        }
    });
}

pub fn hci_set_le_evt_callback(hci: &mut Hci, callback: cxx::UniquePtr<ffi::u8SliceCallback>) {
    assert!(!hci.le_evt_callback_set);
    hci.le_evt_callback_set = true;

    let stream = hci.le_evt_rx.clone();
    hci.rt.spawn(async move {
        while let Some(item) = stream.lock().await.recv().await {
            callback.Run(&item.to_bytes());
        }
    });
}
+18 −7
Original line number Diff line number Diff line
//! Stack management

use crate::hci::Hci;
use bt_common::init_flags;
use bt_main::Stack;
use std::sync::Arc;
use tokio::runtime::Runtime;

#[cxx::bridge(namespace = bluetooth::rust::stack)]
#[cxx::bridge(namespace = bluetooth::shim::rust)]
mod ffi {
    extern "Rust" {
        type Stack;
        type Hci;

        fn create() -> Box<Stack>;
        fn start(stack: &mut Stack);
        fn stop(stack: &mut Stack);
        fn stack_create() -> Box<Stack>;
        fn stack_start(stack: &mut Stack);
        fn stack_stop(stack: &mut Stack);

        fn get_hci(stack: &mut Stack) -> Box<Hci>;
    }
}

pub fn create() -> Box<Stack> {
pub fn stack_create() -> Box<Stack> {
    assert!(init_flags::gd_rust_is_enabled());

    let rt = Arc::new(Runtime::new().unwrap());
@@ -29,7 +33,7 @@ pub fn create() -> Box<Stack> {
    })
}

pub fn start(stack: &mut Stack) {
pub fn stack_start(stack: &mut Stack) {
    assert!(init_flags::gd_rust_is_enabled());

    if init_flags::gd_hci_is_enabled() {
@@ -37,8 +41,15 @@ pub fn start(stack: &mut Stack) {
    }
}

pub fn stop(stack: &mut Stack) {
pub fn stack_stop(stack: &mut Stack) {
    assert!(init_flags::gd_rust_is_enabled());

    stack.stop_blocking();
}

pub fn get_hci(stack: &mut Stack) -> Box<Hci> {
    assert!(init_flags::gd_rust_is_enabled());
    assert!(init_flags::gd_hci_is_enabled());

    Box::new(Hci::new(stack.get_runtime(), stack.get_blocking::<bt_hci::HciExports>()))
}
Loading