nrf52832 学习笔记蓝牙从机Proflies开发

Posted 不咸不要钱

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了nrf52832 学习笔记蓝牙从机Proflies开发相关的知识,希望对你有一定的参考价值。

nrf52832 学习笔记(八)蓝牙从机Proflies开发

所谓开发蓝牙应用程序,其实就是开发service和characteristic。通过API,添加自己需要的characteristic和service,你自己的蓝牙设备就诞生了。只要characteristic和service是符合GATT规范的,你可以随意添加任何characteristic和service,并将他们组合成一个专门的蓝牙设备。由于这个蓝牙设备是按照规范来定义的,所以它可以与任何其他蓝牙设备,比如手机,互联互通,并完成所要求的的交互动作。

这里的蓝牙设备,我们还可以进一步细分为蓝牙profile设备和非profile蓝牙设备。profile就是一个子规范,蓝牙profile设备包含的所有实际service和characteristic都是按照profile规格来添加和定义的,比如说心率计profile,就是一个蓝牙联盟定义的蓝牙设备,蓝牙联盟有一份专门的spec来定义心率计profile,在这份spec中规定了心率计profile除了包含心率service,还包含电池service,设备信息service等。

从这可以看出,心率profile和心率service是包含关系,前者包含后者。Nordic开发了很多蓝牙profile应用,如果你的应用就是一个profile,那么可以完全使用这些现成的例子而不做任何修改,这样做还有一个好处:BQB认证流程将大为简化,你只需做一些文档声明工作,不再需要出具测试报告,就可以获得BQB认证证书。

如果要使用Nordic 编写的profile 需要在SDK中使能对应的服务

以便开启代码中的宏定义

这里强调一下,如果你的设备没有完全按照心率profile来,但也包含心率service,这个时候你就不能说你的设备是一个心率profile设备,虽然你的设备不是心率profile设备,但是它提供的功能基本上跟心率profile设备差不多,因为它包含心率service。这种情况下,你的设备还是一个标准的蓝牙设备,还是可以去过BQB认证的,而且过BQB认证的流程也不复杂,就是比profile设备多了一个自测报告而已。这种设备跟手机通信,是没有任何兼容性或者互联互通问题的。最后强调一下,目前大部分人开发的蓝牙应用程序,其实都是非profile蓝牙应用程序(也叫私有proflie设备),比如手环、共享单车、蓝牙透传等。

添加UUID

UUID 为2字节或者16字节长。在BLE中我们使用UUID来定义数据的类型,UUID是128 bit的,所以我们有足够的UUID来表达万事万物。其中有一个UUID非常特殊,它被蓝牙联盟采用为官方UUID,这个UUID如下所示:

由于这个UUID众所周知,蓝牙联盟将自己定义的attribute或者数据只用16bit UUID来表示,比如0x1234,其实它也是128bit,完整表示为:

使用公共UUID

在Nordic SDK中,如果想要使用SIG定义的服务,例如心跳服务,可以使用如下宏定义初始化UUID

ble_uuid_t            ble_uuid;
BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_HEART_RATE_SERVICE);

添加自定义UUID

在Nordic SDK中,如果想要使用自定义的服务,需要添加自定义UUID

#define LBS_UUID_BASE        0x23, 0xD1, 0xBC, 0xEA, 0x5F, 0x78, 0x23, 0x15, \\
                              0xDE, 0xEF, 0x12, 0x12, 0x00, 0x00, 0x01, 0x01
#define LBS_UUID_SERVICE     0x1523

ble_uuid_t            ble_uuid;
uint8_t               uuid_type;
ble_uuid128_t base_uuid = LBS_UUID_BASE;
//添加自定义UUID
err_code = sd_ble_uuid_vs_add(&base_uuid, &uuid_type);
VERIFY_SUCCESS(err_code);

ble_uuid.type = uuid_type;
ble_uuid.uuid = LBS_UUID_SERVICE;

添加服务

蓝牙中的数据根据ATT和GATT协议,可以看成如下表格,添加服务其实就是如下图添加了一列数据,数据类型为Primary Service

	//添加服务
    err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY, &ble_uuid, &p_lbs->service_handle);
    VERIFY_SUCCESS(err_code);

添加特征

蓝牙中的数据根据ATT和GATT协议,可以看成如下表格,添加特征其实就是如下图在服务列下添加特征列数据:

应用层可以对特征(Characteristic)进行读、写、通知、指示操作。以下以SDK中 ble_app_blinky例子说明

uint32_t ble_lbs_init(ble_lbs_t * p_lbs, const ble_lbs_init_t * p_lbs_init)

    uint32_t              err_code;
    ble_uuid_t            ble_uuid;
    ble_add_char_params_t add_char_params;
    

    // Initialize service structure.
    p_lbs->led_write_handler = p_lbs_init->led_write_handler;

    // 添加UUID
    ble_uuid128_t base_uuid = LBS_UUID_BASE;
    err_code = sd_ble_uuid_vs_add(&base_uuid, &p_lbs->uuid_type);
    VERIFY_SUCCESS(err_code);

    ble_uuid.type = p_lbs->uuid_type;
    ble_uuid.uuid = LBS_UUID_SERVICE;

    //添加服务
    err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY, &ble_uuid, &p_lbs->service_handle);
    VERIFY_SUCCESS(err_code);

    // 添加按键特征
    memset(&add_char_params, 0, sizeof(add_char_params));
    add_char_params.uuid              = LBS_UUID_BUTTON_CHAR; //UUID
    add_char_params.uuid_type         = p_lbs->uuid_type;     //UUID类型,根据类型可以还原出128bit的UUID
    add_char_params.init_len          = sizeof(uint8_t);      //参数初始长度
    add_char_params.max_len           = sizeof(uint8_t);      //参数最大长度
    add_char_params.char_props.read   = 1;                    //允许读
    add_char_params.char_props.notify = 1;                    //允许通知

    add_char_params.read_access       = SEC_OPEN;             //读权限,如果配对绑定中开启了MITM,可以使用MITM
    add_char_params.cccd_write_access = SEC_OPEN;             //通知权限
    
    // 添加按键描述符
    ble_add_char_user_desc_t add_char_desc;
    memset(&add_char_desc, 0, sizeof(add_char_desc));
    add_char_desc.max_size = 32;                              //描述符最大长度
    add_char_desc.size = 32;                                  //描述符长度
    add_char_desc.char_props.read = 1;                        //可读
    add_char_desc.read_access = SEC_OPEN;                     //读权限
    add_char_desc.p_char_user_desc = (uint8_t *)"button";     //描述符
    add_char_params.p_user_descr      = &add_char_desc;       
    err_code = characteristic_add(p_lbs->service_handle,
                                  &add_char_params,
                                  &p_lbs->button_char_handles);
    if (err_code != NRF_SUCCESS)
    
        return err_code;
    
    
    // 添加LED特征
    memset(&add_char_params, 0, sizeof(add_char_params));
    add_char_params.uuid             = LBS_UUID_LED_CHAR;      //UUID  
    add_char_params.uuid_type        = p_lbs->uuid_type;       //UUID类型,根据类型可以还原出128bit的UUID
    add_char_params.init_len         = sizeof(uint8_t);        //参数初始长度
    add_char_params.max_len          = sizeof(uint8_t);        //参数最大长度
    add_char_params.char_props.read  = 1;                      //允许读
    add_char_params.char_props.write = 1;                      //允许写

    add_char_params.read_access  = SEC_OPEN;                   //读权限
    add_char_params.write_access = SEC_OPEN;                   //写权限

    return characteristic_add(p_lbs->service_handle, &add_char_params, &p_lbs->led_char_handles);


客户端读取服务端特征数据。服务端特征数据需要使用 sd_ble_gatts_hvx 函数改变。

客户端将数据写入给服务端。写的时候服务端需要在回调函数中处理

通知

服务端数据上报给客户端,注意不是任何时候服务端都可以上报的,需要客户使能了服务端的CCCD,服务端才可以上报给客户端。
当按键按下时,使用如下API即可将按键状态通知给客户端。

uint32_t ble_lbs_on_button_change(uint16_t conn_handle, ble_lbs_t * p_lbs, uint8_t button_state)

    ble_gatts_hvx_params_t params;
    uint16_t len = sizeof(button_state);

    memset(&params, 0, sizeof(params));
    params.type   = BLE_GATT_HVX_NOTIFICATION;
    params.handle = p_lbs->button_char_handles.value_handle;
    params.p_data = &button_state;
    params.p_len  = &len;

    return sd_ble_gatts_hvx(conn_handle, &params);

以上是关于nrf52832 学习笔记蓝牙从机Proflies开发的主要内容,如果未能解决你的问题,请参考以下文章

nrf52832 学习笔记蓝牙从机Proflies开发

nrf52832 学习笔记蓝牙从机广播

nrf52832 学习笔记蓝牙从机广播

nrf52832 学习笔记蓝牙主机扫描

nrf52832 学习笔记蓝牙主机扫描

nrf52832 学习笔记蓝牙主从机连接和连接参数更新