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

Commit 8bd06ef8 authored by Sonny Sasaka's avatar Sonny Sasaka Committed by Gerrit Code Review
Browse files

Merge changes Iba73140f,Id8481b87,I87afde2b,I5f34aaf9,I33f93326, ...

* changes:
  floss: Add GATT raw tool to btclient
  floss: Move callback handlers away from main.rs
  floss: Synchronize readline with foreground action
  floss: Refactor create_adapter_proxy
  floss: Update TODOs
  floss: Handle service_changed callback
parents e212d35b e135200f
Loading
Loading
Loading
Loading
+282 −0
Original line number Diff line number Diff line
use crate::ClientContext;
use crate::{console_yellow, print_info};
use bt_topshim::btif::BtSspVariant;
use bt_topshim::profiles::gatt::GattStatus;
use btstack::bluetooth::{BluetoothDevice, IBluetoothCallback};
use btstack::bluetooth_gatt::{BluetoothGattService, IBluetoothGattCallback, LePhy};
use btstack::RPCProxy;
use manager_service::iface_bluetooth_manager::IBluetoothManagerCallback;
use std::sync::{Arc, Mutex};

/// Callback context for manager interface callbacks.
pub(crate) struct BtManagerCallback {
    objpath: String,
    context: Arc<Mutex<ClientContext>>,
}

impl BtManagerCallback {
    pub(crate) fn new(objpath: String, context: Arc<Mutex<ClientContext>>) -> Self {
        Self { objpath, context }
    }
}

impl IBluetoothManagerCallback for BtManagerCallback {
    fn on_hci_device_changed(&self, hci_interface: i32, present: bool) {
        print_info!("hci{} present = {}", hci_interface, present);

        if present {
            self.context.lock().unwrap().adapters.entry(hci_interface).or_insert(false);
        } else {
            self.context.lock().unwrap().adapters.remove(&hci_interface);
        }
    }

    fn on_hci_enabled_changed(&self, hci_interface: i32, enabled: bool) {
        print_info!("hci{} enabled = {}", hci_interface, enabled);

        self.context
            .lock()
            .unwrap()
            .adapters
            .entry(hci_interface)
            .and_modify(|v| *v = enabled)
            .or_insert(enabled);

        // When the default adapter's state is updated, we need to modify a few more things.
        // Only do this if we're not repeating the previous state.
        let prev_enabled = self.context.lock().unwrap().enabled;
        let default_adapter = self.context.lock().unwrap().default_adapter;
        if hci_interface == default_adapter && prev_enabled != enabled {
            self.context.lock().unwrap().enabled = enabled;
            self.context.lock().unwrap().adapter_ready = false;
            if enabled {
                self.context.lock().unwrap().create_adapter_proxy(hci_interface);
            } else {
                self.context.lock().unwrap().adapter_dbus = None;
            }
        }
    }
}

impl manager_service::RPCProxy for BtManagerCallback {
    fn register_disconnect(&mut self, _f: Box<dyn Fn() + Send>) {}

    fn get_object_id(&self) -> String {
        self.objpath.clone()
    }
}

/// Callback container for adapter interface callbacks.
pub(crate) struct BtCallback {
    objpath: String,
    context: Arc<Mutex<ClientContext>>,
}

impl BtCallback {
    pub(crate) fn new(objpath: String, context: Arc<Mutex<ClientContext>>) -> Self {
        Self { objpath, context }
    }
}

impl IBluetoothCallback for BtCallback {
    fn on_address_changed(&self, addr: String) {
        print_info!("Address changed to {}", &addr);
        self.context.lock().unwrap().adapter_address = Some(addr);
    }

    fn on_device_found(&self, remote_device: BluetoothDevice) {
        self.context
            .lock()
            .unwrap()
            .found_devices
            .entry(remote_device.address.clone())
            .or_insert(remote_device.clone());

        print_info!("Found device: {:?}", remote_device);
    }

    fn on_discovering_changed(&self, discovering: bool) {
        self.context.lock().unwrap().discovering_state = discovering;

        if discovering {
            self.context.lock().unwrap().found_devices.clear();
        }
        print_info!("Discovering: {}", discovering);
    }

    fn on_ssp_request(
        &self,
        remote_device: BluetoothDevice,
        _cod: u32,
        variant: BtSspVariant,
        passkey: u32,
    ) {
        if variant == BtSspVariant::PasskeyNotification {
            print_info!(
                "device {}{} would like to pair, enter passkey on remote device: {:06}",
                remote_device.address.to_string(),
                if remote_device.name.len() > 0 {
                    format!(" ({})", remote_device.name)
                } else {
                    String::from("")
                },
                passkey
            );
        }
    }
}

impl RPCProxy for BtCallback {
    fn register_disconnect(&mut self, _f: Box<dyn Fn() + Send>) {}

    fn get_object_id(&self) -> String {
        self.objpath.clone()
    }
}

pub(crate) struct BtGattCallback {
    objpath: String,
    context: Arc<Mutex<ClientContext>>,
}

impl BtGattCallback {
    pub(crate) fn new(objpath: String, context: Arc<Mutex<ClientContext>>) -> Self {
        Self { objpath, context }
    }
}

impl IBluetoothGattCallback for BtGattCallback {
    fn on_client_registered(&self, status: i32, client_id: i32) {
        print_info!("GATT Client registered status = {}, client_id = {}", status, client_id);
        self.context.lock().unwrap().gatt_client_id = Some(client_id);
    }

    fn on_client_connection_state(
        &self,
        status: i32,
        client_id: i32,
        connected: bool,
        addr: String,
    ) {
        print_info!(
            "GATT Client connection state = {}, client_id = {}, connected = {}, addr = {}",
            status,
            client_id,
            connected,
            addr
        );
    }

    fn on_phy_update(&self, addr: String, tx_phy: LePhy, rx_phy: LePhy, status: GattStatus) {
        print_info!(
            "Phy updated: addr = {}, tx_phy = {:?}, rx_phy = {:?}, status = {:?}",
            addr,
            tx_phy,
            rx_phy,
            status
        );
    }

    fn on_phy_read(&self, addr: String, tx_phy: LePhy, rx_phy: LePhy, status: GattStatus) {
        print_info!(
            "Phy read: addr = {}, tx_phy = {:?}, rx_phy = {:?}, status = {:?}",
            addr,
            tx_phy,
            rx_phy,
            status
        );
    }

    fn on_search_complete(&self, addr: String, services: Vec<BluetoothGattService>, status: i32) {
        print_info!(
            "GATT DB Search complete: addr = {}, services = {:?}, status = {}",
            addr,
            services,
            status
        );
    }

    fn on_characteristic_read(&self, addr: String, status: i32, handle: i32, value: Vec<u8>) {
        print_info!(
            "GATT Characteristic read: addr = {}, status = {}, handle = {}, value = {:?}",
            addr,
            status,
            handle,
            value
        );
    }

    fn on_characteristic_write(&self, addr: String, status: i32, handle: i32) {
        print_info!(
            "GATT Characteristic write: addr = {}, status = {}, handle = {}",
            addr,
            status,
            handle
        );
    }

    fn on_execute_write(&self, addr: String, status: i32) {
        print_info!("GATT execute write addr = {}, status = {}", addr, status);
    }

    fn on_descriptor_read(&self, addr: String, status: i32, handle: i32, value: Vec<u8>) {
        print_info!(
            "GATT Descriptor read: addr = {}, status = {}, handle = {}, value = {:?}",
            addr,
            status,
            handle,
            value
        );
    }

    fn on_descriptor_write(&self, addr: String, status: i32, handle: i32) {
        print_info!(
            "GATT Descriptor write: addr = {}, status = {}, handle = {}",
            addr,
            status,
            handle
        );
    }

    fn on_notify(&self, addr: String, handle: i32, value: Vec<u8>) {
        print_info!("GATT Notification: addr = {}, handle = {}, value = {:?}", addr, handle, value);
    }

    fn on_read_remote_rssi(&self, addr: String, rssi: i32, status: i32) {
        print_info!("Remote RSSI read: addr = {}, rssi = {}, status = {}", addr, rssi, status);
    }

    fn on_configure_mtu(&self, addr: String, mtu: i32, status: i32) {
        print_info!("MTU configured: addr = {}, mtu = {}, status = {}", addr, mtu, status);
    }

    fn on_connection_updated(
        &self,
        addr: String,
        interval: i32,
        latency: i32,
        timeout: i32,
        status: i32,
    ) {
        print_info!(
            "Connection updated: addr = {}, interval = {}, latency = {}, timeout = {}, status = {}",
            addr,
            interval,
            latency,
            timeout,
            status
        );
    }

    fn on_service_changed(&self, addr: String) {
        print_info!("Service changed for {}", addr,);
    }
}

impl RPCProxy for BtGattCallback {
    fn register_disconnect(&mut self, _f: Box<dyn Fn() + Send>) {}

    fn get_object_id(&self) -> String {
        self.objpath.clone()
    }
}
+97 −0
Original line number Diff line number Diff line
@@ -3,15 +3,18 @@ use std::sync::{Arc, Mutex};

use num_traits::cast::FromPrimitive;

use crate::callbacks::BtGattCallback;
use crate::ClientContext;
use crate::{console_red, console_yellow, print_error, print_info};
use btstack::bluetooth::{BluetoothDevice, BluetoothTransport, IBluetooth};
use btstack::bluetooth_gatt::IBluetoothGatt;
use manager_service::iface_bluetooth_manager::IBluetoothManager;

const INDENT_CHAR: &str = " ";
const BAR1_CHAR: &str = "=";
const BAR2_CHAR: &str = "-";
const MAX_MENU_CHAR_WIDTH: usize = 72;
const GATT_CLIENT_APP_UUID: &str = "12345678123456781234567812345678";

type CommandFunction = fn(&mut CommandHandler, &Vec<String>);

@@ -87,6 +90,13 @@ fn build_commands() -> HashMap<String, CommandOption> {
            function_pointer: CommandHandler::cmd_discovery,
        },
    );
    command_options.insert(
        String::from("gatt"),
        CommandOption {
            description: String::from("GATT tools"),
            function_pointer: CommandHandler::cmd_gatt,
        },
    );
    command_options.insert(
        String::from("get-address"),
        CommandOption {
@@ -276,6 +286,93 @@ impl CommandHandler {
        });
    }

    fn cmd_gatt(&mut self, args: &Vec<String>) {
        if !self.context.lock().unwrap().adapter_ready {
            self.adapter_not_ready();
            return;
        }

        enforce_arg_len(args, 1, "gatt <commands>", || match &args[0][0..] {
            "register-client" => {
                self.context.lock().unwrap().gatt_dbus.as_mut().unwrap().register_client(
                    String::from(GATT_CLIENT_APP_UUID),
                    Box::new(BtGattCallback::new(
                        String::from("/org/chromium/bluetooth/client/bluetooth_gatt_callback"),
                        self.context.clone(),
                    )),
                    false,
                );
            }
            "client-connect" => {
                if args.len() < 2 {
                    println!("usage: gatt client-connect <addr>");
                    return;
                }

                let client_id = self.context.lock().unwrap().gatt_client_id;
                if client_id.is_none() {
                    println!("GATT client is not yet registered.");
                    return;
                }

                let addr = String::from(&args[1]);
                self.context.lock().unwrap().gatt_dbus.as_ref().unwrap().client_connect(
                    client_id.unwrap(),
                    addr,
                    false,
                    2,
                    false,
                    1,
                );
            }
            "client-read-phy" => {
                if args.len() < 2 {
                    println!("usage: gatt client-read-phy <addr>");
                    return;
                }

                let client_id = self.context.lock().unwrap().gatt_client_id;
                if client_id.is_none() {
                    println!("GATT client is not yet registered.");
                    return;
                }

                let addr = String::from(&args[1]);
                self.context
                    .lock()
                    .unwrap()
                    .gatt_dbus
                    .as_mut()
                    .unwrap()
                    .client_read_phy(client_id.unwrap(), addr);
            }
            "client-discover-services" => {
                if args.len() < 2 {
                    println!("usage: gatt client-discover-services <addr>");
                    return;
                }

                let client_id = self.context.lock().unwrap().gatt_client_id;
                if client_id.is_none() {
                    println!("GATT client is not yet registered.");
                    return;
                }

                let addr = String::from(&args[1]);
                self.context
                    .lock()
                    .unwrap()
                    .gatt_dbus
                    .as_ref()
                    .unwrap()
                    .discover_services(client_id.unwrap(), addr);
            }
            _ => {
                println!("Invalid argument '{}'", args[0]);
            }
        });
    }

    /// Get the list of currently supported commands
    pub fn get_command_list(&self) -> Vec<String> {
        self.command_options.keys().map(|key| String::from(key)).collect::<Vec<String>>()
+334 −0
Original line number Diff line number Diff line
//! D-Bus proxy implementations of the APIs.

use bt_topshim::btif::BtSspVariant;
use bt_topshim::profiles::gatt::GattStatus;

use btstack::bluetooth::{BluetoothDevice, BluetoothTransport, IBluetooth, IBluetoothCallback};
use btstack::bluetooth_gatt::{
    BluetoothGattCharacteristic, BluetoothGattDescriptor, BluetoothGattService,
    GattWriteRequestStatus, GattWriteType, IBluetoothGatt, IBluetoothGattCallback,
    IScannerCallback, LePhy, ScanFilter, ScanSettings, Uuid128Bit,
};

use dbus::arg::{AppendAll, RefArg};
use dbus::nonblock::SyncConnection;
@@ -19,6 +25,7 @@ use manager_service::iface_bluetooth_manager::{

use num_traits::{FromPrimitive, ToPrimitive};

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

use crate::dbus_arg::{DBusArg, DBusArgError, RefArgToRust};
@@ -29,6 +36,54 @@ fn make_object_path(idx: i32, name: &str) -> dbus::Path {

impl_dbus_arg_enum!(BluetoothTransport);
impl_dbus_arg_enum!(BtSspVariant);
impl_dbus_arg_enum!(GattStatus);
impl_dbus_arg_enum!(GattWriteType);
impl_dbus_arg_enum!(LePhy);

// Represents Uuid128Bit as an array in D-Bus.
impl DBusArg for Uuid128Bit {
    type DBusType = Vec<u8>;

    fn from_dbus(
        data: Vec<u8>,
        _conn: Option<Arc<SyncConnection>>,
        _remote: Option<dbus::strings::BusName<'static>>,
        _disconnect_watcher: Option<Arc<std::sync::Mutex<DisconnectWatcher>>>,
    ) -> Result<[u8; 16], Box<dyn std::error::Error>> {
        return Ok(data.try_into().unwrap());
    }

    fn to_dbus(data: [u8; 16]) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
        return Ok(data.to_vec());
    }
}

#[dbus_propmap(BluetoothGattDescriptor)]
pub struct BluetoothGattDescriptorDBus {
    uuid: Uuid128Bit,
    instance_id: i32,
    permissions: i32,
}

#[dbus_propmap(BluetoothGattCharacteristic)]
pub struct BluetoothGattCharacteristicDBus {
    uuid: Uuid128Bit,
    instance_id: i32,
    properties: i32,
    permissions: i32,
    key_size: i32,
    write_type: GattWriteType,
    descriptors: Vec<BluetoothGattDescriptor>,
}

#[dbus_propmap(BluetoothGattService)]
pub struct BluetoothGattServiceDBus {
    pub uuid: Uuid128Bit,
    pub instance_id: i32,
    pub service_type: i32,
    pub characteristics: Vec<BluetoothGattCharacteristic>,
    pub included_services: Vec<BluetoothGattService>,
}

#[dbus_propmap(BluetoothDevice)]
pub struct BluetoothDeviceDBus {
@@ -278,3 +333,282 @@ impl IBluetoothManagerCallback for IBluetoothManagerCallbackDBus {
    #[dbus_method("OnHciEnabledChanged")]
    fn on_hci_enabled_changed(&self, hci_interface: i32, enabled: bool) {}
}

pub(crate) struct BluetoothGattDBus {
    client_proxy: ClientDBusProxy,
}

impl BluetoothGattDBus {
    pub(crate) fn new(
        conn: Arc<SyncConnection>,
        cr: Arc<Mutex<Crossroads>>,
        index: i32,
    ) -> BluetoothGattDBus {
        BluetoothGattDBus {
            client_proxy: ClientDBusProxy {
                conn: conn.clone(),
                cr: cr,
                bus_name: String::from("org.chromium.bluetooth"),
                objpath: make_object_path(index, "gatt"),
                interface: String::from("org.chromium.bluetooth.BluetoothGatt"),
            },
        }
    }
}

// TODO: These are boilerplate codes, consider creating a macro to generate.
impl IBluetoothGatt for BluetoothGattDBus {
    fn register_scanner(&self, _callback: Box<dyn IScannerCallback + Send>) {
        // TODO(b/200066804): implement
    }

    fn unregister_scanner(&self, _scanner_id: i32) {
        // TODO(b/200066804): implement
    }

    fn start_scan(&self, _scanner_id: i32, _settings: ScanSettings, _filters: Vec<ScanFilter>) {
        // TODO(b/200066804): implement
    }

    fn stop_scan(&self, _scanner_id: i32) {
        // TODO(b/200066804): implement
    }

    fn register_client(
        &mut self,
        app_uuid: String,
        callback: Box<dyn IBluetoothGattCallback + Send>,
        eatt_support: bool,
    ) {
        let path_string = callback.get_object_id();
        let path = dbus::Path::new(path_string.clone()).unwrap();
        export_bluetooth_gatt_callback_dbus_obj(
            path_string,
            self.client_proxy.conn.clone(),
            &mut self.client_proxy.cr.lock().unwrap(),
            Arc::new(Mutex::new(callback)),
            Arc::new(Mutex::new(DisconnectWatcher::new())),
        );

        self.client_proxy.method_noreturn("RegisterClient", (app_uuid, path, eatt_support))
    }

    fn unregister_client(&mut self, client_id: i32) {
        self.client_proxy.method_noreturn("UnregisterClient", (client_id,))
    }

    fn client_connect(
        &self,
        client_id: i32,
        addr: String,
        is_direct: bool,
        transport: i32,
        opportunistic: bool,
        phy: i32,
    ) {
        self.client_proxy.method_noreturn(
            "ClientConnect",
            (client_id, addr, is_direct, transport, opportunistic, phy),
        )
    }

    fn client_disconnect(&self, client_id: i32, addr: String) {
        self.client_proxy.method_noreturn("ClientDisconnect", (client_id, addr))
    }

    fn client_set_preferred_phy(
        &self,
        client_id: i32,
        addr: String,
        tx_phy: LePhy,
        rx_phy: LePhy,
        phy_options: i32,
    ) {
        self.client_proxy.method_noreturn(
            "ClientSetPreferredPhy",
            (client_id, addr, tx_phy.to_i32().unwrap(), rx_phy.to_i32().unwrap(), phy_options),
        )
    }

    fn client_read_phy(&mut self, client_id: i32, addr: String) {
        self.client_proxy.method_noreturn("ClientReadPhy", (client_id, addr))
    }

    fn refresh_device(&self, client_id: i32, addr: String) {
        self.client_proxy.method_noreturn("RefreshDevice", (client_id, addr))
    }

    fn discover_services(&self, client_id: i32, addr: String) {
        self.client_proxy.method_noreturn("DiscoverServices", (client_id, addr))
    }

    fn discover_service_by_uuid(&self, client_id: i32, addr: String, uuid: String) {
        self.client_proxy.method_noreturn("DiscoverServiceByUuid", (client_id, addr, uuid))
    }

    fn read_characteristic(&self, client_id: i32, addr: String, handle: i32, auth_req: i32) {
        self.client_proxy.method_noreturn("ReadCharacteristic", (client_id, addr, handle, auth_req))
    }

    fn read_using_characteristic_uuid(
        &self,
        client_id: i32,
        addr: String,
        uuid: String,
        start_handle: i32,
        end_handle: i32,
        auth_req: i32,
    ) {
        self.client_proxy.method_noreturn(
            "ReadUsingCharacteristicUuid",
            (client_id, addr, uuid, start_handle, end_handle, auth_req),
        )
    }

    fn write_characteristic(
        &self,
        client_id: i32,
        addr: String,
        handle: i32,
        write_type: GattWriteType,
        auth_req: i32,
        value: Vec<u8>,
    ) -> GattWriteRequestStatus {
        GattWriteRequestStatus::from_i32(self.client_proxy.method(
            "WriteCharacteristic",
            (client_id, addr, handle, write_type.to_i32().unwrap(), auth_req, value),
        ))
        .unwrap()
    }

    fn read_descriptor(&self, client_id: i32, addr: String, handle: i32, auth_req: i32) {
        self.client_proxy.method_noreturn("ReadDescriptor", (client_id, addr, handle, auth_req))
    }

    fn write_descriptor(
        &self,
        client_id: i32,
        addr: String,
        handle: i32,
        auth_req: i32,
        value: Vec<u8>,
    ) {
        self.client_proxy
            .method_noreturn("WriteDescriptor", (client_id, addr, handle, auth_req, value))
    }

    fn register_for_notification(&self, client_id: i32, addr: String, handle: i32, enable: bool) {
        self.client_proxy
            .method_noreturn("RegisterForNotification", (client_id, addr, handle, enable))
    }

    fn begin_reliable_write(&mut self, client_id: i32, addr: String) {
        self.client_proxy.method_noreturn("BeginReliableWrite", (client_id, addr))
    }

    fn end_reliable_write(&mut self, client_id: i32, addr: String, execute: bool) {
        self.client_proxy.method_noreturn("EndReliableWrite", (client_id, addr, execute))
    }

    fn read_remote_rssi(&self, client_id: i32, addr: String) {
        self.client_proxy.method_noreturn("ReadRemoteRssi", (client_id, addr))
    }

    fn configure_mtu(&self, client_id: i32, addr: String, mtu: i32) {
        self.client_proxy.method_noreturn("ConfigureMtu", (client_id, addr, mtu))
    }

    fn connection_parameter_update(
        &self,
        client_id: i32,
        addr: String,
        min_interval: i32,
        max_interval: i32,
        latency: i32,
        timeout: i32,
        min_ce_len: u16,
        max_ce_len: u16,
    ) {
        self.client_proxy.method_noreturn(
            "ConnectionParameterUpdate",
            (client_id, addr, min_interval, max_interval, latency, timeout, min_ce_len, max_ce_len),
        )
    }
}

#[allow(dead_code)]
struct IBluetoothGattCallbackDBus {}

impl btstack::RPCProxy for IBluetoothGattCallbackDBus {
    // Placeholder implementations just to satisfy impl RPCProxy requirements.
    fn register_disconnect(&mut self, _f: Box<dyn Fn() + Send>) {}
    fn get_object_id(&self) -> String {
        String::from("")
    }
}

#[generate_dbus_exporter(
    export_bluetooth_gatt_callback_dbus_obj,
    "org.chromium.bluetooth.BluetoothGattCallback"
)]
impl IBluetoothGattCallback for IBluetoothGattCallbackDBus {
    #[dbus_method("OnClientRegistered")]
    fn on_client_registered(&self, status: i32, client_id: i32) {}

    #[dbus_method("OnClientConnectionState")]
    fn on_client_connection_state(
        &self,
        status: i32,
        client_id: i32,
        connected: bool,
        addr: String,
    ) {
    }

    #[dbus_method("OnPhyUpdate")]
    fn on_phy_update(&self, addr: String, tx_phy: LePhy, rx_phy: LePhy, status: GattStatus) {}

    #[dbus_method("OnPhyRead")]
    fn on_phy_read(&self, addr: String, tx_phy: LePhy, rx_phy: LePhy, status: GattStatus) {}

    #[dbus_method("OnSearchComplete")]
    fn on_search_complete(&self, addr: String, services: Vec<BluetoothGattService>, status: i32) {}

    #[dbus_method("OnCharacteristicRead")]
    fn on_characteristic_read(&self, addr: String, status: i32, handle: i32, value: Vec<u8>) {}

    #[dbus_method("OnCharacteristicWrite")]
    fn on_characteristic_write(&self, addr: String, status: i32, handle: i32) {}

    #[dbus_method("OnExecuteWrite")]
    fn on_execute_write(&self, addr: String, status: i32) {}

    #[dbus_method("OnDescriptorRead")]
    fn on_descriptor_read(&self, addr: String, status: i32, handle: i32, value: Vec<u8>) {}

    #[dbus_method("OnDescriptorWrite")]
    fn on_descriptor_write(&self, addr: String, status: i32, handle: i32) {}

    #[dbus_method("OnNotify")]
    fn on_notify(&self, addr: String, handle: i32, value: Vec<u8>) {}

    #[dbus_method("OnReadRemoteRssi")]
    fn on_read_remote_rssi(&self, addr: String, rssi: i32, status: i32) {}

    #[dbus_method("OnConfigureMtu")]
    fn on_configure_mtu(&self, addr: String, mtu: i32, status: i32) {}

    #[dbus_method("OnConnectionUpdated")]
    fn on_connection_updated(
        &self,
        addr: String,
        interval: i32,
        latency: i32,
        timeout: i32,
        status: i32,
    ) {
    }

    #[dbus_method("OnServiceChanged")]
    fn on_service_changed(&self, addr: String) {}
}
+44 −130

File changed.

Preview size limit exceeded, changes collapsed.

+3 −0
Original line number Diff line number Diff line
@@ -85,6 +85,9 @@ impl IBluetoothGattCallback for BluetoothGattCallbackDBus {
        status: i32,
    ) {
    }

    #[dbus_method("OnServiceChanged")]
    fn on_service_changed(&self, addr: String) {}
}

// Represents Uuid128Bit as an array in D-Bus.
Loading