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

Commit 76b69e4b authored by Sonny Sasaka's avatar Sonny Sasaka Committed by Gerrit Code Review
Browse files

Merge "floss: Implement BluetoothGatt::RegisterClient"

parents 116b366d 5d512b09
Loading
Loading
Loading
Loading
+23 −1
Original line number Diff line number Diff line
use btstack::bluetooth_gatt::{
    IBluetoothGatt, IScannerCallback, RSSISettings, ScanFilter, ScanSettings, ScanType,
    IBluetoothGatt, IBluetoothGattCallback, IScannerCallback, RSSISettings, ScanFilter,
    ScanSettings, ScanType,
};
use btstack::RPCProxy;

@@ -19,6 +20,15 @@ use std::sync::Arc;

use crate::dbus_arg::{DBusArg, DBusArgError, RefArgToRust};

#[allow(dead_code)]
struct BluetoothGattCallbackDBus {}

#[dbus_proxy_obj(BluetoothGattCallback, "org.chromium.bluetooth.BluetoothGattCallback")]
impl IBluetoothGattCallback for BluetoothGattCallbackDBus {
    #[dbus_method("OnClientRegistered")]
    fn on_client_registered(&self, _status: i32, _scanner_id: i32) {}
}

#[allow(dead_code)]
struct ScannerCallbackDBus {}

@@ -63,4 +73,16 @@ impl IBluetoothGatt for IBluetoothGattDBus {

    #[dbus_method("StopScan")]
    fn stop_scan(&self, scanner_id: i32) {}

    #[dbus_method("RegisterClient")]
    fn register_client(
        &mut self,
        app_uuid: String,
        callback: Box<dyn IBluetoothGattCallback + Send>,
        eatt_support: bool,
    ) {
    }

    #[dbus_method("UnregisterClient")]
    fn unregister_client(&self, client_if: i32) {}
}
+10 −3
Original line number Diff line number Diff line
@@ -63,10 +63,16 @@ fn main() -> Result<(), Box<dyn Error>> {

    let adapter_index = get_adapter_index(&args);

    intf.lock().unwrap().initialize(get_bt_dispatcher(tx), args);
    // Hold locks and initialize all interfaces.
    {
        intf.lock().unwrap().initialize(get_bt_dispatcher(tx.clone()), args);

    bluetooth.lock().unwrap().init_profiles();
    bluetooth.lock().unwrap().enable();
        let mut bluetooth = bluetooth.lock().unwrap();
        bluetooth.init_profiles();
        bluetooth.enable();

        bluetooth_gatt.lock().unwrap().init_profiles(tx.clone());
    }

    topstack::get_runtime().block_on(async {
        // Connect to D-Bus system bus.
@@ -95,6 +101,7 @@ fn main() -> Result<(), Box<dyn Error>> {
        topstack::get_runtime().spawn(Stack::dispatch(
            rx,
            bluetooth.clone(),
            bluetooth_gatt.clone(),
            bluetooth_media.clone(),
        ));

+138 −3
Original line number Diff line number Diff line
//! Anything related to the GATT API (IBluetoothGatt).

use bt_topshim::btif::BluetoothInterface;
use btif_macros::{btif_callback, btif_callbacks_dispatcher};

use bt_topshim::bindings::root::bluetooth::Uuid;
use bt_topshim::btif::{BluetoothInterface, RawAddress};
use bt_topshim::profiles::gatt::{
    Gatt, GattClientCallbacks, GattClientCallbacksDispatcher, GattServerCallbacksDispatcher,
};
use bt_topshim::topstack;

use std::collections::HashMap;
use std::sync::{Arc, Mutex};

use tokio::sync::mpsc::Sender;

use crate::{Message, RPCProxy};

/// Defines the GATT API.
pub trait IBluetoothGatt {
    fn register_scanner(&self, callback: Box<dyn IScannerCallback + Send>);
@@ -12,6 +24,23 @@ pub trait IBluetoothGatt {

    fn start_scan(&self, scanner_id: i32, settings: ScanSettings, filters: Vec<ScanFilter>);
    fn stop_scan(&self, scanner_id: i32);

    /// Registers a GATT Client.
    fn register_client(
        &mut self,
        app_uuid: String,
        callback: Box<dyn IBluetoothGattCallback + Send>,
        eatt_support: bool,
    );

    /// Unregisters a GATT Client.
    fn unregister_client(&self, client_if: i32);
}

/// Callback for GATT Client API.
pub trait IBluetoothGattCallback: RPCProxy {
    /// When the `register_client` request is done.
    fn on_client_registered(&self, status: i32, client_if: i32);
}

/// Interface for scanner callbacks to clients, passed to `IBluetoothGatt::register_scanner`.
@@ -55,16 +84,61 @@ pub struct ScanSettings {
#[derive(Debug, Default)]
pub struct ScanFilter {}

type Uuid128Bit = [u8; 16];

/// Implementation of the GATT API (IBluetoothGatt).
pub struct BluetoothGatt {
    _intf: Arc<Mutex<BluetoothInterface>>,
    intf: Arc<Mutex<BluetoothInterface>>,
    gatt: Option<Gatt>,

    gatt_client_map: HashMap<Uuid128Bit, Box<dyn IBluetoothGattCallback + Send>>,
}

impl BluetoothGatt {
    /// Constructs a new IBluetoothGatt implementation.
    pub fn new(intf: Arc<Mutex<BluetoothInterface>>) -> BluetoothGatt {
        BluetoothGatt { _intf: intf }
        BluetoothGatt { intf: intf, gatt: None, gatt_client_map: HashMap::new() }
    }

    pub fn init_profiles(&mut self, tx: Sender<Message>) {
        self.gatt = Gatt::new(&self.intf.lock().unwrap());
        self.gatt.as_mut().unwrap().initialize(
            GattClientCallbacksDispatcher {
                dispatch: Box::new(move |cb| {
                    let tx_clone = tx.clone();
                    topstack::get_runtime().spawn(async move {
                        let _ = tx_clone.send(Message::GattClient(cb)).await;
                    });
                }),
            },
            GattServerCallbacksDispatcher {
                dispatch: Box::new(move |cb| {
                    // TODO(b/193685149): Implement the callbacks
                    println!("received Gatt server callback: {:?}", cb);
                }),
            },
        );
    }
}

// Temporary util that covers only basic string conversion.
// TODO(b/193685325): Implement more UUID utils by using Uuid from gd/hci/uuid.h with cxx.
fn parse_uuid_string(uuid: String) -> Option<Uuid> {
    if uuid.len() != 32 {
        return None;
    }

    let mut raw = [0; 16];

    for i in 0..16 {
        let byte = u8::from_str_radix(&uuid[i * 2..i * 2 + 2], 16);
        if byte.is_err() {
            return None;
        }
        raw[i] = byte.unwrap();
    }

    Some(Uuid { uu: raw })
}

impl IBluetoothGatt for BluetoothGatt {
@@ -83,4 +157,65 @@ impl IBluetoothGatt for BluetoothGatt {
    fn stop_scan(&self, _scanner_id: i32) {
        // TODO: implement
    }

    fn register_client(
        &mut self,
        app_uuid: String,
        callback: Box<dyn IBluetoothGattCallback + Send>,
        eatt_support: bool,
    ) {
        let uuid = parse_uuid_string(app_uuid).unwrap();
        self.gatt_client_map.insert(uuid.uu, callback);
        self.gatt.as_ref().unwrap().client.register_client(&uuid, eatt_support);
    }

    fn unregister_client(&self, _client_if: i32) {
        // TODO(b/193685325): implement
    }
}

#[btif_callbacks_dispatcher(BluetoothGatt, dispatch_gatt_client_callbacks, GattClientCallbacks)]
pub(crate) trait BtifGattClientCallbacks {
    #[btif_callback(RegisterClient)]
    fn register_client_cb(&mut self, status: i32, client_if: i32, app_uuid: Uuid);

    #[btif_callback(Connect)]
    fn connect_cb(&mut self, conn_id: i32, status: i32, client_if: i32, addr: RawAddress);

    // TODO(b/193685325): Define all callbacks.
}

impl BtifGattClientCallbacks for BluetoothGatt {
    fn register_client_cb(&mut self, status: i32, client_if: i32, app_uuid: Uuid) {
        let callback = self.gatt_client_map.get(&app_uuid.uu);
        if callback.is_none() {
            println!("Warning: Callback not registered for UUID {:?}", app_uuid.uu);
            return;
        }

        callback.unwrap().on_client_registered(status, client_if);
    }

    fn connect_cb(&mut self, _conn_id: i32, _status: i32, _client_if: i32, _addr: RawAddress) {
        // TODO(b/193685325): handle;
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_uuid_from_string() {
        let uuid = parse_uuid_string(String::from("abcdef"));
        assert!(uuid.is_none());

        let uuid = parse_uuid_string(String::from("0123456789abcdef0123456789abcdef"));
        assert!(uuid.is_some());
        let expected: [u8; 16] = [
            0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab,
            0xcd, 0xef,
        ];
        assert_eq!(Uuid { uu: expected }, uuid.unwrap());
    }
}
+16 −0
Original line number Diff line number Diff line
@@ -12,6 +12,8 @@ pub mod bluetooth_media;

use bt_topshim::btif::BaseCallbacks;
use bt_topshim::profiles::a2dp::A2dpCallbacks;
use bt_topshim::profiles::gatt::GattClientCallbacks;
use bt_topshim::profiles::gatt::GattServerCallbacks;

use std::sync::{Arc, Mutex};

@@ -19,6 +21,7 @@ use tokio::sync::mpsc::channel;
use tokio::sync::mpsc::{Receiver, Sender};

use crate::bluetooth::Bluetooth;
use crate::bluetooth_gatt::BluetoothGatt;
use crate::bluetooth_media::BluetoothMedia;

/// Represents a Bluetooth address.
@@ -28,6 +31,8 @@ use crate::bluetooth_media::BluetoothMedia;
pub enum Message {
    A2dp(A2dpCallbacks),
    Base(BaseCallbacks),
    GattClient(GattClientCallbacks),
    GattServer(GattServerCallbacks),
    BluetoothCallbackDisconnected(u32),
}

@@ -44,6 +49,7 @@ impl Stack {
    pub async fn dispatch(
        mut rx: Receiver<Message>,
        bluetooth: Arc<Mutex<Box<Bluetooth>>>,
        bluetooth_gatt: Arc<Mutex<Box<BluetoothGatt>>>,
        bluetooth_media: Arc<Mutex<Box<BluetoothMedia>>>,
    ) {
        loop {
@@ -58,10 +64,20 @@ impl Stack {
                Message::A2dp(a) => {
                    bluetooth_media.lock().unwrap().dispatch_a2dp_callbacks(a);
                }

                Message::Base(b) => {
                    bluetooth.lock().unwrap().dispatch_base_callbacks(b);
                }

                Message::GattClient(m) => {
                    bluetooth_gatt.lock().unwrap().dispatch_gatt_client_callbacks(m);
                }

                Message::GattServer(m) => {
                    // TODO(b/193685149): dispatch GATT server callbacks.
                    println!("Unhandled Message::GattServer: {:?}", m);
                }

                Message::BluetoothCallbackDisconnected(id) => {
                    bluetooth.lock().unwrap().callback_disconnected(id);
                }