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

Commit 48bf8655 authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge changes I62acf212,I4bf1b50b into main

* changes:
  floss: Complete Floss to BTIF GATT attribute type conversions
  floss: Add a sample GATT service with btclient
parents 078e2012 c68a22c6
Loading
Loading
Loading
Loading
+78 −6
Original line number Diff line number Diff line
@@ -16,7 +16,8 @@ use bt_topshim::profiles::{gatt::LePhy, ProfileConnectionState};
use btstack::battery_manager::IBatteryManager;
use btstack::bluetooth::{BluetoothDevice, IBluetooth};
use btstack::bluetooth_gatt::{
    BluetoothGattService, GattDbElementType, GattWriteType, IBluetoothGatt,
    BluetoothGattCharacteristic, BluetoothGattDescriptor, BluetoothGattService, GattDbElementType,
    GattWriteType, IBluetoothGatt,
};
use btstack::bluetooth_media::{IBluetoothMedia, IBluetoothTelephony};
use btstack::bluetooth_qa::IBluetoothQA;
@@ -28,9 +29,19 @@ 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";
const GATT_SERVER_APP_UUID: &str = "12345678123456781234567812345679";
const HEART_RATE_SERVICE_UUID: &str = "0000180D-0000-1000-8000-00805F9B34FB";
const HEART_RATE_MEASUREMENT_UUID: &str = "00002A37-0000-1000-8000-00805F9B34FB";
const GENERIC_UUID: &str = "00000000-0000-1000-8000-00805F9B34FB";
const CCC_DESCRIPTOR_UUID: &str = "00002902-0000-1000-8000-00805F9B34FB";
const BATTERY_SERVICE_UUID: &str = "0000180F-0000-1000-8000-00805F9B34FB";

const PROPERTY_WRITE: i32 = 1 << 3;
const PROPERTY_NOTIFY: i32 = 1 << 4;
const PERMISSION_READ: i32 = 1 << 0;
const PERMISSION_WRITE: i32 = 1 << 1;

enum CommandError {
    // Command not handled due to invalid arguments.
@@ -227,13 +238,19 @@ fn build_commands() -> HashMap<String, CommandOption> {
                String::from("gatt unregister-server <server_id>"),
                String::from("gatt server-connect <server_id> <client_address>"),
                String::from("gatt server-disconnect <server_id> <client_address>"),
                String::from("gatt server-add-heartrate-service <server_id>"),
                String::from("gatt server-add-basic-service <server_id>"),
                String::from("gatt server-add-service <server_id> <incl_service_instance_id>"),
                String::from("gatt server-remove-service <server_id> <service_handle>"),
                String::from("gatt server-clear-all-services <server_id>"),
                String::from("gatt server-set-direct-connect <true|false>"),
                String::from("gatt server-set-connect-transport <Bredr|LE|Auto>"),
            ],
            description: String::from("GATT tools"),
            description: String::from(
                "GATT tools\n\n
                Creating a GATT Server:\n
                Register a server, then add a basic (battery) service. After, a more complex\n
                (heartrate) service can be created with previously created services included.",
            ),
            function_pointer: CommandHandler::cmd_gatt,
        },
    );
@@ -1367,20 +1384,75 @@ impl CommandHandler {
                    return Err("Disconnection was unsuccessful".into());
                }
            }
            "server-add-heartrate-service" => {
                let uuid = Uuid::from(UuidHelper::from_string(HEART_RATE_SERVICE_UUID).unwrap());
            "server-add-basic-service" => {
                let service_uuid =
                    Uuid::from(UuidHelper::from_string(BATTERY_SERVICE_UUID).unwrap());

                let server_id = String::from(get_arg(args, 1)?)
                    .parse::<i32>()
                    .or(Err("Failed to parse server_id"))?;

                let service = BluetoothGattService::new(
                    uuid.into(),
                    service_uuid.into(),
                    0, // libbluetooth assigns this handle once the service is added
                    GattDbElementType::PrimaryService.into(),
                );

                self.lock_context().gatt_dbus.as_mut().unwrap().add_service(server_id, service);
            }
            "server-add-service" => {
                let service_uuid =
                    Uuid::from(UuidHelper::from_string(HEART_RATE_SERVICE_UUID).unwrap());
                let characteristic_uuid =
                    Uuid::from(UuidHelper::from_string(HEART_RATE_MEASUREMENT_UUID).unwrap());
                let descriptor_uuid = Uuid::from(UuidHelper::from_string(GENERIC_UUID).unwrap());
                let ccc_descriptor_uuid =
                    Uuid::from(UuidHelper::from_string(CCC_DESCRIPTOR_UUID).unwrap());
                let included_service_uuid =
                    Uuid::from(UuidHelper::from_string(BATTERY_SERVICE_UUID).unwrap());

                let server_id = String::from(get_arg(args, 1)?)
                    .parse::<i32>()
                    .or(Err("Failed to parse server_id"))?;
                let included_service_instance_id =
                    String::from(get_arg(args, 2)?)
                        .parse::<i32>()
                        .or(Err("Failed to parse included service instance id"))?;

                let mut service = BluetoothGattService::new(
                    service_uuid.into(),
                    0,
                    GattDbElementType::PrimaryService.into(),
                );
                let included_service = BluetoothGattService::new(
                    included_service_uuid.into(),
                    included_service_instance_id,
                    GattDbElementType::IncludedService.into(),
                );
                let mut characteristic = BluetoothGattCharacteristic::new(
                    characteristic_uuid.into(),
                    0,
                    PROPERTY_WRITE + PROPERTY_NOTIFY,
                    PERMISSION_READ + PERMISSION_WRITE,
                );
                let descriptor = BluetoothGattDescriptor::new(
                    descriptor_uuid.into(),
                    0,
                    PERMISSION_READ + PERMISSION_WRITE,
                );
                let ccc_descriptor = BluetoothGattDescriptor::new(
                    ccc_descriptor_uuid.into(),
                    0,
                    PERMISSION_READ + PERMISSION_WRITE,
                );

                service.included_services.push(included_service);
                characteristic.descriptors.push(ccc_descriptor);
                characteristic.descriptors.push(descriptor);
                service.characteristics.push(characteristic);

                self.lock_context().gatt_dbus.as_mut().unwrap().add_service(server_id, service);
            }
            "server-remove-service" => {
                let server_id = String::from(get_arg(args, 1)?)
                    .parse::<i32>()
+29 −16
Original line number Diff line number Diff line
@@ -705,11 +705,7 @@ pub struct BluetoothGattDescriptor {
}

impl BluetoothGattDescriptor {
    pub(crate) fn new(
        uuid: Uuid128Bit,
        instance_id: i32,
        permissions: i32,
    ) -> BluetoothGattDescriptor {
    pub fn new(uuid: Uuid128Bit, instance_id: i32, permissions: i32) -> BluetoothGattDescriptor {
        BluetoothGattDescriptor { uuid, instance_id, permissions }
    }
}
@@ -747,7 +743,7 @@ impl BluetoothGattCharacteristic {
    pub const PERMISSION_WRITE_SIGNED: i32 = 1 << 7;
    pub const PERMISSION_WRITE_SIGNED_MITM: i32 = 1 << 8;

    pub(crate) fn new(
    pub fn new(
        uuid: Uuid128Bit,
        instance_id: i32,
        properties: i32,
@@ -859,7 +855,10 @@ impl BluetoothGattService {
        db_out
    }

    fn into_db(service: BluetoothGattService) -> Vec<BtGattDbElement> {
    fn into_db(
        service: BluetoothGattService,
        services: &Vec<BluetoothGattService>,
    ) -> Vec<BtGattDbElement> {
        let mut db_out: Vec<BtGattDbElement> = vec![];
        db_out.push(BtGattDbElement {
            id: service.instance_id as u16,
@@ -883,7 +882,7 @@ impl BluetoothGattService {
                end_handle: 0,
                properties: char.properties as u8,
                extended_properties: 0,
                permissions: char.permissions as u16,
                permissions: (((char.key_size - 7) << 12) + char.permissions) as u16,
            });

            for desc in char.descriptors {
@@ -896,12 +895,22 @@ impl BluetoothGattService {
                    end_handle: 0,
                    properties: 0,
                    extended_properties: 0,
                    permissions: desc.permissions as u16,
                    permissions: (((char.key_size - 7) << 12) + desc.permissions) as u16,
                });
            }
        }

        for included_service in service.included_services {
            if !services.iter().any(|s| {
                s.instance_id == included_service.instance_id && s.uuid == included_service.uuid
            }) {
                log::error!(
                    "Included service with uuid {} not found",
                    Uuid::from(included_service.uuid)
                );
                continue;
            }

            db_out.push(BtGattDbElement {
                id: included_service.instance_id as u16,
                uuid: Uuid::from(included_service.uuid),
@@ -2801,13 +2810,17 @@ impl IBluetoothGatt for BluetoothGatt {
    }

    fn add_service(&self, server_id: i32, service: BluetoothGattService) {
        if let Some(server) = self.server_context_map.get_by_server_id(server_id) {
            self.gatt
                .as_ref()
                .unwrap()
                .lock()
                .unwrap()
                .server
            .add_service(server_id, &BluetoothGattService::into_db(service));
                .add_service(server_id, &BluetoothGattService::into_db(service, &server.services));
        } else {
            log::error!("Server id {} is not valid", server_id);
        }
    }

    fn remove_service(&self, server_id: i32, handle: i32) {