服务中新建特性

从新建私人服务的过程中我们知道,我们并不关心服务中特性建立的具体细节,而是把官方已经写好的服务添加到我们的工程中,并根据自己的需求对其中的参数进行了修改。而如果要在一个服务中获取多个特性的值,或对多个特性进行写入数据操作,就需要新建多个特性。这里使用的还是ble_lbs.c这个文件,将在上一节的基础上分析这个文件。


在ble_lbs_init()函数中,添加一个特性这样表示:

err_code = button_char_add(p_lbs, p_lbs_init);

VERIFY_SUCCESS(err_code);

我们通过编写xxx_char_add()这个函数来添加一个特性,这里是添加一个按键的通知特性,所以函数命名为button_char_add()。

在xxx_char_add()函数中,主要完成了两个工作:

(1)特性参数配置:

ble_gatts_char_md_t char_md; //特性参数结构体定义,通过设置其中的参数来设置特性参数

ble_gatts_attr_md_t cccd_md; //attr_md结构体定义,用来配置cccd参数

//配置特性参数

  //配置ccmd的安全级别和储存位置

    memset(&cccd_md, 0, sizeof(cccd_md));

    BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm);            //可读

    BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.write_perm);          //可写

    cccd_md.vloc = BLE_GATTS_VLOC_STACK;                          //储存在堆栈中

    memset(&char_md, 0, sizeof(char_md));

    char_md.char_props.read  = 1;                      //该特性可读

    char_md.char_props.notify = 1;                      //该特性可通知

    char_md.p_char_user_desc  = NULL;                  //不使用描述符

    char_md.p_char_pf        = NULL;                  //不使用CPF

    char_md.p_user_desc_md    = NULL;                  //无属性元数据

    char_md.p_cccd_md        = &cccd_md;              //使用cccd描述符

    char_md.p_sccd_md        = NULL;                  //不使用服务端描述符

(2)GATT属性配置

ble_gatts_attr_t           attr_char_value;

ble_uuid_t                    ble_uuid;

 ble_gatts_attr_md_t    attr_md;    //GATT属性结构体定义

//配置GATT属性

    memset(&attr_md, 0, sizeof(attr_md));

    BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.read_perm);       //可读

    BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&attr_md.write_perm);//不可写

    attr_md.vloc    = BLE_GATTS_VLOC_STACK;                        //储存在堆栈中

    attr_md.rd_auth = 0;                                            //读写无需应用程序授权

    attr_md.wr_auth = 0;                                            //

    attr_md.vlen    = 0;                                            //读写长度不可变

    memset(&attr_char_value, 0, sizeof(attr_char_value));

   ble_uuid.type = p_lbs->uuid_type;                  //uuid类型    

   ble_uuid.uuid =   LBS_UUID_BUTTON_CHAR;       //uuid

    attr_char_value.p_uuid    = &ble_uuid;  //配置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  = sizeof(uint8_t);      //最大长度

    attr_char_value.p_value  = NULL;                   //属性数据指针

(3)在特性参数和GATT参数设定后,要设置操作句柄。在xxx_char_add()的输入参数中,第一个输入参数是该服务的结构体指针,可以跳转到该结构体的定义中查看:

struct ble_lbs_s

{

    uint16_t                    service_handle;    

    ble_gatts_char_handles_t    led_char_handles;   

    ble_gatts_char_handles_t    button_char_handles;    //需添加的操作句柄

    uint8_t                    uuid_type;         

    ble_lbs_led_write_handler_t led_write_handler; 

};

(4)句柄设置完成后,需要把上面设置好的特性和GATT添加到协议栈中GATT层中作为数据接口,使用sd_ble_gatts_characteristic_add()函数,及xxx_char_add()的最后一部分。

return sd_ble_gatts_characteristic_add(p_lbs->service_handle,

                                          &char_md,

                                          &attr_char_value,

                                          &p_lbs->button_char_handles);

第1个参数是特性要加入的服务的句柄,指向你定义的这个点灯的服务。

第2个参数是特性的结构体&char_ md,它是-一个全局变量,它包含了前面特性设置的参数(读,写,通知等)。

第3个参数是值属性的描述结构体&attr _char_ value, 它包含了它的UUID,长度和初始值。

第4个参数是返回的特性和描述符的唯一句柄,这个句柄可以在以后用于区别服务里不同的特性。比如本例里返回变量button_ char_ handles (按键特性的句柄)作为唯一的按键通知的句柄。如果这个服务里有其他特性,则每种特性都有自己唯一声明的操作句柄。

(5)最后在服务初始化函数中调用,这个在最前面已经说了。


完成了新特性的建立后,我们还需要完善回调函数。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容