分类: 嵌入式
2019-01-10 11:05:25
基础为 属性数据库 。
具体分析之前 还需要介绍 属性值访问权限的一点概念。
在属性数据库中介绍了 属性条目的组成为如下形式
句柄 |
UUID |
属性值 |
上面的 形式是在 属性协议(ATT)中定义的
实际使用时,我们访问的就是 这个属性条目中的属性值,实际应用中有时候我们需要 设置一些访问权限,比如只有在链路加密时才能访问其中的属性值。
这就引入了一个访问权限的性质。
句柄 |
UUID |
属性值 |
访问权限 |
比如将 访问权限 设置为写需要加密,而读不需要加密, 那么读这个属性值的操作随时可以进行,但是 写这个属性值的 操作只有在链路加密的情况下才可以,如果未加密的情况下写这个属性值,就会返回权限不足的错误。
这个访问权限的具体如何操作和定义是由厂商自己实现,并未有严格限定。只要行为上符合规范的要求即可(规范只定义了什么情况下返回什么样的安全错误,至于逻辑怎么做厂商自己决定)
属性数据库文档中
说过,我们通常说创建一个特性值,就是一个属性条目,我们利用的是其中的
属性值。
但是特性值 属性条目不是单独存在的, 它是属于特性 的一部分。
特性由几条属性条目组成, 包括一条 特性声明属性条目, 一条特性值属性条目, 几条描述符属性条目。
如下所示例的一个特性组成,包括一个 声明,一个特性值,两个描述符。
特性声明条目 |
特性值条目 |
描述符条目 |
描述符条目 |
Nordic sdk中提供的API就是创建特性api, 根据我们填入的参数协议栈会自动创建 声明,特性值,以及描述符, 并且API会返回 特性值以及一些存在的描述符的句柄,如下图。
API的第一个参数 service_handle为 服务句柄,即添加的特性是添加到哪个服务中的,所以首先要创建在服务后才能再服务下面添加特性,sdk中调用创建服务API函数后,会返回被创建的服务的句柄,如下图
之后第二个参数p_char_md定义了 特性中的 特性值 支持哪些操作,读,些,notify等。以及所需要的描述符的读写权限等信息。
第三个参数p_attr_char_value 定义了 特性值 的UUID,长度等信息。
第四个参数p_handles 为协议栈返回的 创建的特性 中的一些句柄,包括特性值句柄,以及存在的描述符句柄。
static uint32_t rx_char_add(ble_nus_t * p_nus, const ble_nus_init_t * p_nus_init)
{
//这个变量中包含了特性值的支持的读,些,notify等操作,也定义了存在的描述符的一些访问权限等信息
ble_gatts_char_md_t char_md;
//rx特性值是用来将数据发给手机的,所以具有notify功能,所以需要CCCD描述符,这个cccd_md定义了CCCD描述符的访问权限等信息
ble_gatts_attr_md_t cccd_md;
//这个变量定义了我们最终要使用的RX特性值的UUID,大小等信息
ble_gatts_attr_t attr_char_value;
//RX的UUID
ble_uuid_t ble_uuid;
//这个变量会被赋值给 上面的attr_char_value,主要定义了特性值的访问权限,以及存在的位置等信息。
ble_gatts_attr_md_t attr_md;
memset(&cccd_md, 0, sizeof(cccd_md));
//设置CCCD描述符的读写访问权限为可访问,OPEN即为任意访问
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm);
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.write_perm);
//设置CCCD描述符存在于协议栈中,这样协议栈就会自动在协议栈的内存中创建一块ram存放CCCD描述符
cccd_md.vloc = BLE_GATTS_VLOC_STACK;
memset(&char_md, 0, sizeof(char_md));
//工程中通过RX特性值发送数据给手机所以 以下定义了RX特性值 具有notify功能,其他参数赋值为NULL表示不需要或者使用默认值,主要就是一些没有使用的描述符的性质。 因为支持notify性质就需要有CCCD描述符,所以CCCD描述符的性质这里设置了。
char_md.char_props.notify = 1;
char_md.p_char_user_desc = NULL;
char_md.p_char_pf = NULL;
char_md.p_user_desc_md = NULL;
char_md.p_cccd_md = &cccd_md;
char_md.p_sccd_md = NULL;
//设置 RX特性值的UUID
ble_uuid.type = p_nus->uuid_type;
ble_uuid.uuid = BLE_UUID_NUS_RX_CHARACTERISTIC;
memset(&attr_md, 0, sizeof(attr_md));
//设置RX特性值的读写可以随便访问,不需要加密等保护
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.read_perm);
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.write_perm);
//设置RX特性值存在于协议栈中,并且为变长,这样我们就不要自己定义一个全局变量,然后让RX特性值buff指向它了,而是协议栈自动在内部创建一个。
同时定义了读写不需要授权,nordic中定义的授权的意思是每次手机发来读写时,协议栈会先报告上层有读写,用户会同意给协议栈,协议栈才正真执行读写。
attr_md.vloc = BLE_GATTS_VLOC_STACK;
attr_md.rd_auth = 0;
attr_md.wr_auth = 0;
attr_md.vlen = 1;
memset(&attr_char_value, 0, sizeof(attr_char_value));
//将上面定义的UUID,特性值的读写权限等参数赋值。
//设置了特性值的初始值的长度,偏移等,以及最大长度(特性值的存放是在协议栈中的,因为上面定义了其是在协议栈中的)
attr_char_value.p_uuid = &ble_uuid;
attr_char_value.p_attr_md = &attr_md;
attr_char_value.init_len = sizeof(uint8_t);
attr_char_value.init_offs = 0;
attr_char_value.max_len = BLE_NUS_MAX_RX_CHAR_LEN;
//最终调用添加特性API,最后一个参数就是常见成功后返回的特性值句柄,以及可能存在的描述符的句柄
return sd_ble_gatts_characteristic_add(p_nus->service_handle,&char_md,&attr_char_value &p_nus->rx_handles);
}