BLE 怎样添加 Characteristic

来源:互联网 发布:松翰单片机官网 编辑:程序博客网 时间:2024/06/11 18:18

Attribute Protocol (ATT)

BLE protocol如下图

1:ATT is based on  aClient <–> Server relationship

The server  holds一些信息如 sensor value等,这些信息以atable的形式组织起来,也就是 attribute table

table中的每一个attribute 是一个value或者一些相关的属性信息

a client想要获取sensorvalue指的是获取table中的某行的信息

 

Bluetooth Core Specification V4.2解释ATT如下:

ATT(attribute protocol)定义了两个角色:a server and a client;允许 a server 暴露若干attributes client

 

an attribute是一个有如下三个propertiesa value

(1)  an attribute type, defined by a UUID

(2)  an attribute handle

(3)  a set of permissions

(4)  a value

 attribute type表示the attribute代表什么,SIG协会已经定义了。

如下是一个常用的应用:the Heart RateProfile,下图每一行为anattribute,每个attribute包含a handle, a type,a set of permissions, and a value

Attribute Handles

这个AttributeHandle唯一的标明一个server上的一个 attribute,允许a client 在一个read/write请求中引用the Attribute,简言之,Attribute Handle可以被看作是the attribute table的行标,尽管AttributeHandle的值不一定是连续的,Attribute Handle是一个16-bit的值,你将会看到softdevice广泛的用handle来引用attributes,这是一个有效的在functions之间传递值和信息方式,AttributeHandle的值会依赖你拥有多少attributes 

 

Attribute Types (UUIDs)

UUID是一个16-bit or 128bit值,用于表明每一个attributetype,如上图中,有5个不同的types of attributes

one of type “Service Declaration” (0x2800)

two of type “Characteristic Declaration” (0x2803)

one of type “Heart Rate Measurement Characteristic Value”(0x2A37)

one of type “Body Sensor Location Characteristic Value” (0x2A38)

one of type “Descriptor Declaration” (0x2902)

 

AttributePermissions

Permissions定义了你能与一个指定的attribute之间怎么交互,他会定义an attribute是否有readable and/or writeable 和需要什么授权才能交互,注意,Permissions只会应用于attribute value,不会应用于thehandle, type, and the permission,这允许aclient可以全部浏览a server’s attribute table,查看这个server提供了那些Attribute,即使没有对这些Attribute没有read and write权限

 

Attribute Values

这个值可以是anything,一些时候,他包含的信息是在哪获取其他attributes 及其properties

例如上表中,Service Declarationattribute valuea UUID(0x1800),表明这个server的类型, CharacteristicDeclarationattribute value是关于 CharacteristicValue Declaration 这个attribute 的一些信息(Properties, Handle, and Type),最后,Characteristic Value Declaration 这个attributevalue才是每分钟心率的准确值

 

 

The Generic Attribute Profile (GATT)

GATT的概念是:以a veryspecific and logical order(group )组织attributes 形成一个 anattribute table

如上的heart rate profile 就是一个(group)an attribute table

 

ServiceDeclaration attribute

每一个group的最上面你总会看到aService Declarationattribute

这个attributetype总是0x2800,其handle依赖于group中拥有多少个attribute

这个attributepermissions总是Read Only withoutany authentication or authorization required

这个attributevalue是一个UUID表明这个service的类型

 

Characteristic Declarationattribute

Service Declarationattribute下面就是Characteristic Declaration attribute,这个类似于Service Declaration attribute

type总是0x2803

permissions 总是Read Only withoutany authentication or authorization required

value则包含了一些有趣的信息,a handle,a UUID,a set of properties,这三个元素描述了Characteristic Value Declaration attribute

handle指向attribute tableCharacteristic Value Declaration attribute

UUID标明我们可以从CharacteristicValue Declarationattribute找到什么类型的 informationor value,例如,一个温度值等,

properties描述how thecharacteristic value can be interacted with,下表显示一些properties 

这是你可能会疑惑,为什么an attribute有了 read/write permissions,还需要thecharacteristic valueread/write properties

 The properties for thecharacteristic value are actually only guidelines for theclient, used in the GATT and application layers.

The permissions for theattribute (on the ATT layer) will always overrule the characteristic valueproperties (on the GATT layer)

 

Characteristic Value Declarationattribute

这个attribute type is same as CharacteristicDeclaration attributevalue

这个attribute permissionsapplication layer定义

这个attribute value是最终包含值的,也许是atemperature value

 

Descriptor Declaration

Characteristic Value Declaration attribute后面可能会是

1a new Characteristic Declaration (therecan be manycharacteristicsgrouped in aservice).

2a new ServiceDeclaration (there can be many services in a table).

3a DescriptorDeclaration.

 

Descriptor Declaration attribute是包含这个characteristic的额外信息的,有许多类型,本章我们只会处理theClient Characteristic Configuration Descriptor (CCCD)

 

 

 

以下为一个例子

To-do list

Step 1: Add service. This was completed in the last tutorial when we madeour own custom service with a custom base UUID and a service UUID.

Step 2: Declare and configure the characteristic.

Step 3: Add a CCCD to let the characteristic send notifications at regularintervals or whenever the temperature values are changing.

Step 2: Add the Characteristic

调用SoftDevice 的函数sd_ble_gatts_characteristic_add()

这个函数会添加 the CharacteristicDeclaration and the CharacteristicValue Declaration  to our attribute table

sd_ble_gatts_characteristic_add() takes fourparameters:

@param[in] uint16_t                        service_handle.

@param[in] ble_gatts_char_md_t const *     p_char_md

@param[in] ble_gatts_attr_t const*        p_attr_char_value

@param[out]ble_gatts_char_handles_t *      p_handles

The three input parameters need to be populated with detailsthat will define the characteristicattributes(也就是一个group中的所有attributes

These parameters define the properties, read/write permissions,descriptors, characteristic values

我们所要做的是选择在哪存储thecharacteristic attributes(也就是一个group中的所有attributes并定义

 a characteristic value type using our custom UUID

如下三个变量比较重要

1ble_gatts_attr_md_tattr_mdThe  Attribute  Metadata:这个结构体保存:

访问characteristicvalue attributes要求的授权等级及permissions

同时也保存thecharacteristic value是否有可变长度及其存于memory何处 

 

2ble_gatts_char_md_tchar_mdThe Characteristic Metadata:这个结构体保存:

thecharacteristic valuevalueproperties 

CCCD和可能的其他descriptors

 

3ble_gatts_attr_t attr_char_valueThe Characteristic Value Attribute: 这个结构体保存:

thecharacteristic真实的valuelike thetemperature value

value最大的长度(如4bytes)和UUID

 

Step 2.A, Use custom UUID to define characteristic valuetype:用定制的UUID定义characteristicvalue的类型

类似在Service UUID中一样:

uint32_t            err_code;
ble_uuid_t          char_uuid;
ble_uuid128_t       base_uuid = BLE_UUID_OUR_BASE_UUID;
char_uuid.uuid      = BLE_UUID_OUR_CHARACTERISTC_UUID;
err_code = sd_ble_uuid_vs_add(&base_uuid, &char_uuid.type);

这将会使用与service相同的base UUID,但是不同的16-bitUUID for the characteristic,例如我们定义成0xBEEF

这个base UUID在我们创建定制的service时会加入到 to the vendor specific table

所有的的调用同一个base UUID将会返回对表中相同ID的引用,This way wewill save some memory by not needing to store a large array of 128-bit long IDs

 

Step 2.B, Configure the Attribute Metadata

以下三行是我们需要描述the attributes ofthe characteristic的最低限度

这几行只做了一件事就是决定在哪存储 theattributes,我们将其存储在Softdevice可以控制的memory,因此我们使用BLE_GATTS_VLOC_STACK使用BLE_GATTS_VLOC_USER将属性存储在用户控制的内存部分

ble_gatts_attr_md_t attr_md;
memset(&attr_md, 0, sizeof(attr_md));
attr_md.vloc        = BLE_GATTS_VLOC_STACK;

在attribute metadata structure ble_gatts_attr_md_t中,你可以定义访问characteristicvalue attributes要求的授权等级及permissions

For example if you need Man In The Middleprotection (MITM) or a passkey to access your attribute

 

Step 2.C, Configure the CharacteristicValue Attribute :配置Characteristic Value这个Attribute

此时我们需要创建了自己的UUID,并决定在哪存储 thecharacteristic,我们将会存储到theCharacteristic Value Attribute

ble_gatts_attr_t    attr_char_value;
memset(&attr_char_value, 0, sizeof(attr_char_value));    
attr_char_value.p_uuid      = &char_uuid;
attr_char_value.p_attr_md   = &attr_md;

 

Step 2.D, Add handles for the characteristicto our struct:为我们的结构添加characteristic 的句柄

我们需要添加一个变量来保存我们的service结构体中的characteristic 相关的handles

所以添加如下:

typedef struct
{
    uint16_t                    conn_handle; 
    uint16_t                    service_handle;        
    // OUR_JOB: Step 2.D, Add handles for our characteristic
    ble_gatts_char_handles_t    char_handles;
}ble_os_t;

这个ble_os_t有一个域保存了 servicedeclaration handle

conn_handle这个handle用于当前connection保持track

如果你查看的到ble_gatts_char_handles_t的定义,你可以看到这个变量可以为thecharacteristic value保存16-bit handles,用户的描述,自身的CCCD,其他一些如SCCD

 

Step 2.E, Add the new characteristic to theservice

此时我们就可以增加一个newcharacteristic 到我们的attributetable 中,类似如下

err_code = sd_ble_gatts_characteristic_add(p_our_service->service_handle,
                                   &char_md,
                                   &attr_char_value,
                                   &p_our_service->char_handles);

通过这个我们告诉SofteDevice:这个characteristic依附于那个service(service_handle), theCharacteristic Metadata, and the Characteristic Value Attributes

随后,协议栈就会处理这些参数并初始化这个characteristic,然后将对应的handle存于我们定义的结构体(p_our_service

 

Step 2.F, Add read/write properties to ourcharacteristic value

按上面的操作,可以给我们的service添加新的characteristic ,但是对于characteristic  value既不能读也不能写

添加如下:

ble_gatts_char_md_t char_md;
memset(&char_md, 0, sizeof(char_md));
char_md.char_props.read = 1;
char_md.char_props.write = 1;

此时,仍然对characteristic  value既不能读也不能写,这是因为我们只是设置了 characteristicdeclaration中的properties 

 

 

Step 2.G, Set read/write permissions to ourcharacteristic

基于上,我们将设置简单的可读可写权限,Nosecurity, encryption, or passkey needed

一个简单的方法是使用宏BLE_GAP_CONN_SEC_MODE_SET_OPEN() 添加如下:

BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.read_perm);
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.write_perm);

此时我们会读出value为0,因为我们没有给characteristic  value分配一个value和value length

当你试图写数据进去时,会报错,提示characteristic  value length初始化为0

 

Step 2.H, Set characteristic length

为characteristic  value length初始化

attr_char_value.max_len     = 4;
attr_char_value.init_len    = 4;
uint8_t value[4]            = {0x12,0x34,0x56,0x78};
attr_char_value.p_value     = value;

设置初始化值为12-34-56-78

 

 

Step 3: Client Characteristic Configuration Descriptor (CCCD)

 

 

 

 

 

 

 

原创粉丝点击