BlueZ5.45 D-Bus总线 GATT API 分析

        笔者目前做linux系统下bluez蓝牙项目开发,发现网上关于bluez开发的资料很少。对于刚开始接触bluez蓝牙的开发人员来说是非常痛苦的。通过调试bluez源码自带的应用例子和文档说明,对BlueZ5.45 D-Bus总线 GATT API有了一些感悟。笔者不才,愿意将所了解到的一些知识分享给大家,希望能带给大家一些帮助。

一、首先看一下gatt-api说明文档,路径如下:Bluez-5.45/doc/gatt-api.txt

1、Service hierarchy

外部应用首先要用GattManager1中的注册方法注册该服务才能使本地服务生效,而且使这些方法和属性生效,还要在GattService1 接口声明,以下是gatt-api.txt文档中关于Service hierarchy说明

Service        org.bluez

Interface    org.bluez.GattService1

Object path    [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX/serviceXX
Properties    string UUID [read-only]
            128-bit service UUID.
        boolean Primary [read-only]
            Indicates whether or not this GATT service is a
            primary service. If false, the service is secondary.
        object Device [read-only, optional]
            Object path of the Bluetooth device the service
            belongs to. Only present on services from remote
            devices.
        array{object} Includes [read-only]: Not implemented
            Array of object paths representing the included
            services of this service.

为了便于理解以gatt-service.c文档为例说明:

程序开始定义了以下接口:

#define GATT_MGR_IFACE            "org.bluez.GattManager1"
#define GATT_SERVICE_IFACE        "org.bluez.GattService1"
#define GATT_CHR_IFACE            "org.bluez.GattCharacteristic1"
#define GATT_DESCRIPTOR_IFACE        "org.bluez.GattDescriptor1"

其中GATT_SERVICE_IFACE为org.bluez.GattService1接口

然后定义了服务uuid和对应的特征值uuid

/* Immediate Alert Service UUID */
#define IAS_UUID            "ea816b5a-129c-4941-8a20-1c2ae3239f02"
#define ALERT_LEVEL_CHR_UUID        "7df357bb-4f53-49c0-861e-84aa2be57f65"
#define UPDATE_CHR_UUID        "b5635b6e-02cb-4fe8-a4a2-3c0279f53755"

其中#define IAS_UUID            "ea816b5a-129c-4941-8a20-1c2ae3239f02"为服务uuid

然后创建和注册该服务:

create_services()->service_path = register_service(IAS_UUID)->g_dbus_register_interface(connection, path, GATT_SERVICE_IFACE,
                                                                                                                                                                         NULL, NULL, service_properties,
                                                                                                                                                                         g_strdup(uuid), g_free)

为该服务注册两个特征值:

/* Add Alert Level Characteristic to Immediate Alert Service */
    if (!register_characteristic(ALERT_LEVEL_CHR_UUID,
                        &level, sizeof(level),
                        ias_alert_level_props,
                        READ_WRITE_DESCRIPTOR_UUID,
                        desc_props,
                        service_path)) {
        printf("Couldn't register Alert Level characteristic (IAS)\n");
        g_dbus_unregister_interface(connection, service_path,
                            GATT_SERVICE_IFACE);
        g_free(service_path);
        return;
    }

    /* Add update Characteristic to return data */
    if (!register_characteristic(UPDATE_CHR_UUID,
                        &level, sizeof(level),
                        update_props,
                        READ_WRITE_DESCRIPTOR_UUID,
                        desc_props,
                        service_path)) {
        printf("Couldn't register Alert Level characteristic (IAS)\n");
        g_dbus_unregister_interface(connection, service_path,
                            GATT_SERVICE_IFACE);
        g_free(service_path);
        return;
    }

其中ALERT_LEVEL_CHR_UUID,UPDATE_CHR_UUID为特征值uuid,READ_WRITE_DESCRIPTOR_UUID,READ_WRITE_DESCRIPTOR_UUID为定义的描述符uuid

在这里面定义了特征值的属性和描述符的属性

static const char *ias_alert_level_props[] = { "read","write","write-without-response","notify", NULL };

static const char *update_props[] = { "read","write","write-without-response","notify", NULL };
static const char *desc_props[] = { "read", "write", NULL };

2、Characteristic hierarchy

Service        org.bluez

Interface    org.bluez.GattCharacteristic1

Object path    [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX/serviceXX/charYYYY
Methods        array{byte} ReadValue(dict options)
            Issues a request to read the value of the
            characteristic and returns the value if the
            operation was successful.
            Possible options: "offset": uint16 offset "device": Object Device (Server only)
            Possible Errors: org.bluez.Error.Failed org.bluez.Error.InProgress
                     org.bluez.Error.NotPermitted
                     org.bluez.Error.NotAuthorized
                     org.bluez.Error.NotSupported
        void WriteValue(array{byte} value, dict options)
            Issues a request to write the value of the
            characteristic.
            Possible options: "offset": Start offset "device": Device path (Server only)
            Possible Errors: org.bluez.Error.Failed org.bluez.Error.InProgress
                     org.bluez.Error.NotPermitted
                     org.bluez.Error.InvalidValueLength
                     org.bluez.Error.NotAuthorized
                     org.bluez.Error.NotSupported
        void StartNotify()
            Starts a notification session from this characteristic
            if it supports value notifications or indications.
            Possible Errors: org.bluez.Error.Failed org.bluez.Error.InProgress
                     org.bluez.Error.NotSupported
        void StopNotify()
            This method will cancel any previous StartNotify
            transaction. Note that notifications from a
            characteristic are shared between sessions thus
            calling StopNotify will release a single session.
            Possible Errors: org.bluez.Error.Failed
Properties    string UUID [read-only]
            128-bit characteristic UUID.
        object Service [read-only]
            Object path of the GATT service the characteristic
            belongs to.
        array{byte} Value [read-only, optional]
            The cached value of the characteristic. This property
            gets updated only after a successful read request and
            when a notification or indication is received, upon
            which a PropertiesChanged signal will be emitted.
        boolean Notifying [read-only, optional]
            True, if notifications or indications on this
            characteristic are currently enabled.
        array{string} Flags [read-only]
            Defines how the characteristic value can be used. See
            Core spec "Table 3.5: Characteristic Properties bit
            field", and "Table 3.8: Characteristic Extended
            Properties bit field". Allowed values:
                "broadcast"
                "read"
                "write-without-response"
                "write"
                "notify"
                "indicate"
                "authenticated-signed-writes"
                "reliable-write"
                "writable-auxiliaries"
                "encrypt-read"
                "encrypt-write"
                "encrypt-authenticated-read"
                "encrypt-authenticated-write"
                "secure-read" (Server only)
                "secure-write" (Server only)

从上面一段说明可知Characteristic特征值dbus总线接口是org.bluez.GattCharacteristic1,对应的操作函数有ReadValue,WriteValue,StartNotify(),StopNotify()

属性中包括:

string UUID [read-only]

object Service [read-only]

array{byte} Value [read-only, optional]

boolean Notifying [read-only, optional]

array{string} Flags [read-only]

对特征值可以进行以下几种操作:

                "broadcast" "read"
                "write-without-response"
                "write"
                "notify"
                "indicate"
                "authenticated-signed-writes"
                "reliable-write"
                "writable-auxiliaries"
                "encrypt-read"
                "encrypt-write"
                "encrypt-authenticated-read"
                "encrypt-authenticated-write"
                "secure-read" (Server only)
                "secure-write" (Server only)


然后我们看一下register_characteristic()函数:

static gboolean register_characteristic(const char *chr_uuid,
                        const uint8_t *value, int vlen,
                        const char **props,
                        const char *desc_uuid,
                        const char **desc_props,
                        const char *service_path)
{
    struct characteristic *chr;
    struct descriptor *desc;
    static int id = 1;

    chr = g_new0(struct characteristic, 1);
    chr->uuid = g_strdup(chr_uuid);
    chr->value = g_memdup(value, vlen);
    chr->vlen = vlen;
    chr->props = props;
    chr->service = g_strdup(service_path);
    chr->path = g_strdup_printf("%s/characteristic%d", service_path, id++);

    if (!g_dbus_register_interface(connection, chr->path, GATT_CHR_IFACE,
                    chr_methods, NULL, chr_properties,
                    chr, chr_iface_destroy)) {
        printf("Couldn't register characteristic interface\n");
        chr_iface_destroy(chr);
        return FALSE;
    }

    if (!desc_uuid)
        return TRUE;

    desc = g_new0(struct descriptor, 1);
    desc->uuid = g_strdup(desc_uuid);
    desc->chr = chr;
    desc->props = desc_props;
    desc->path = g_strdup_printf("%s/descriptor%d", chr->path, id++);

    if (!g_dbus_register_interface(connection, desc->path,
                    GATT_DESCRIPTOR_IFACE,
                    desc_methods, NULL, desc_properties,
                    desc, desc_iface_destroy)) {
        printf("Couldn't register descriptor interface\n");
        g_dbus_unregister_interface(connection, chr->path,
                            GATT_CHR_IFACE);

        desc_iface_destroy(desc);
        return FALSE;
    }
    
    if (strcmp(chr_uuid,UPDATE_CHR_UUID) == 0)
    {
        chr_update = chr;
        printf("chr_update is OK");
    }

    return TRUE;
}

该段代码首先填充了struct characteristic *chr,然后调用g_dbus_register_interface方法将该特征值注册到GATT_CHR_IFACE,/ "org.bluez.GattCharacteristic1"接口。

参数chr_methods定义了可以对特征值的所做的操作,分别是读操作、写操作、开始通知操作和停止通知操作:

static const GDBusMethodTable chr_methods[] = {
    { GDBUS_ASYNC_METHOD("ReadValue", GDBUS_ARGS({ "options", "a{sv}" }),
                    GDBUS_ARGS({ "value", "ay" }),
                    chr_read_value) },
    { GDBUS_ASYNC_METHOD("WriteValue", GDBUS_ARGS({ "value", "ay" },
                        { "options", "a{sv}" }),
                    NULL, chr_write_value) },
    { GDBUS_ASYNC_METHOD("StartNotify", NULL, NULL, chr_start_notify) },
    { GDBUS_METHOD("StopNotify", NULL, NULL, chr_stop_notify) },
    { }
};

参数chr_properties表示该特征值所具备的属性:

static const GDBusPropertyTable chr_properties[] = {
    { "UUID",    "s", chr_get_uuid },
    { "Service",    "o", chr_get_service },
    { "Value",    "ay", chr_get_value, chr_set_value, NULL },
    { "Flags",    "as", chr_get_props, NULL, NULL },
    { }
};

描述符注册过程跟特征值的注册过程类似,大家可以自己看一下。

做完这些操作以后就可以对注册的特征值进行操作了,具体操作方法就是注册特征值时候注册的方法这里是chr_read_value,chr_write_value,chr_start_notify,chr_stop_notify。

描述符的操作方法跟特征值类似。

这里需要注意的是,对特征值的读操作,写操作是针对特征值的,不区分客户端还是服务端。也就是说服务端,客户端对特征值的读写都会调用chr_read_value,chr_write_value方法,服务端可以调用chr_write/chr_read方法对自己定义的特征值进行读写操作。当特征值定义为通知属性时,服务端如果对该特征值写入数据,就会自动发出通知消息。如果客户端注册了该特征值通知,则会接收到该通知消息。



  • 0
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 10
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值