GR5x系列BLE知识及应用专题(3) - 初步构建BLE APP (上)

  • 前言1:
  • 通过  "GR5x系列BLE知识及应用专题" 系统介绍一些 BLE 涉及的知识概念, 以及如何使用 Goodix GR5xx 系列芯片的SDK进行BLE应用开发。
  • 可以从下面网页获得 GR5xx 系列蓝牙芯片的介绍和选型参考.
  • 如果博客有内容引用自网络, 会在文末添加参考来源.

 

  • 前言2:

本文主要介绍了如何基于汇顶(goodix.com) GR5x SDK, 从无到有在工程中引入BLE功能。主要分为以下几步:

  1. 自定义服务;
  2. 添加服务相关文件;
  3. 实现用户代码,如初始化gap参数、服务初始化和相关事件处理函数等;
  4. 协议栈初始化;

上篇会说明如何自定义服务及添加服务文件;下篇会介绍实现用户代码及协议栈初始化. 可以从汇顶官网(www.goodix.com)下载 GR5526 SDK进行代码对照. 

1. 自定义服务

为了保证各类蓝牙设备间的兼容性 ,Bluetooth SIG规定了很多通用的service,但还是无法覆盖所有应用场景,所以有时候需要我们自定义服务来满足使用需求。接下来以GUS service为例,介绍如何自定义服务。

自定义服务包含如下步骤:

  • 确定该服务需要包含什么特性,以及每个特性的读写属性、安全要求和是否必须等;
  • 确定服务和各特性的UUID;
  • 构造该服务的事件类型;
  • 基于特性构建属性表;

1.1 确定服务特性表

GUS(Goodix UART Service)主要用于传输数据以及更新BLE数据流控制状态,所以它需要以下特性:

  • RX characteristic:接收发起设备写入的数据;
  • TX characteristic:发送来自串口的数据至发起设备;
  • Flow Control Characteristic:更新接收和发起设备的接收BLE数据能力的状态(0x00表示设备无法接受更多BLE数据,0x01表示设备还能继续接收BLE数据);

由上可以整理出GUS的特性表如下所示:

Characteristic

UUID

Type

Support

Security

Properties

Service

A6ED0101-D344-460A-8075-B9E8EC90D71B

128bits

Mandatory

None

-

RX characteristic

A6ED0103-D344-460A-8075-B9E8EC90D71B

128bits

Mandatory

None

Write

TX Characteristic

A6ED0102-D344-460A-8075-B9E8EC90D71B

128bits

Mandatory

None

Notify

TX Characteristic Client Characteristic Configuration descriptor

-

-

Mandatory

None

Read, Write

Flow Control

A6ED0204-D344-460A-8075-B9E8EC90D71B

128bits

Mandatory

None

Notify, Write

Flow Control Client Characteristic Configuration descriptor

-

-

Mandatory

None

Read, Write

 

1.2 设置特性UUID

gus.h中设置GUS服务UUID,在gus.c中设置特性UUID:

/**@brief The UUIDs of GUS characteristics. */

#define GUS_SERVER_TX_UUID {0x1B, 0xD7, 0x90, 0xEC, 0xE8, 0xB9, 0x75, 0x80, 0x0A, 0x46, 0x44, 0xD3, 0x02, 0x02, 0xED, 0xA6}

#define GUS_SERVER_RX_UUID {0x1B, 0xD7, 0x90, 0xEC, 0xE8, 0xB9, 0x75, 0x80, 0x0A, 0x46, 0x44, 0xD3, 0x03, 0x02, 0xED, 0xA6}

#define GUS_FLOW_CTRL_UUID {0x1B, 0xD7, 0x90, 0xEC, 0xE8, 0xB9, 0x75, 0x80, 0x0A, 0x46, 0x44, 0xD3, 0x04, 0x02, 0xED, 0xA6}

1.3 创建索引枚举

基于上述服务特性表,可以创建如下的属性索引枚举,该枚举主要是为了构建特性属性描述表。

/**@brief Goodix UART Service Attributes Indexes. */

enum gus_attr_idx_t

{

   GUS_IDX_SVC, // GUS Service

   

   GUS_IDX_TX_CHAR, // TX Characteristic Declaration

   GUS_IDX_TX_VAL, // TX Characteristic Value

   GUS_IDX_TX_CFG, // TX Characteristic CCCD

   GUS_IDX_RX_CHAR, // TX Characteristic Declaration

   GUS_IDX_RX_VAL, // RX Characteristic Value

   GUS_IDX_FLOW_CTRL_CHAR, // Flow Control Characteristic Declaration

   GUS_IDX_FLOW_CTRL_VAL, // Flow Control Characteristic Value

   GUS_IDX_FLOW_CTRL_CFG, // Flow Control Characteristic CCCD

   GUS_IDX_NB, // Max Number

};

如上述代码所示,服务、特性声明、特性值和特性控制描述符都有一个索引。

1.4 构建特性属性描述表

/**@brief Full GUS Database Description which is used to add attributes into the ATT database. */

static const ble_gatts_attm_desc_128_t gus_attr_tab[GUS_IDX_NB] =

{

   // GUS service

   [GUS_IDX_SVC]            = {ATT_128_PRIMARY_SERVICE, BLE_GATTS_READ_PERM_UNSEC, 0, 0},

   // GUS TX Characteristic Declaration

   [GUS_IDX_TX_CHAR]        = {ATT_128_CHARACTERISTIC, BLE_GATTS_READ_PERM_UNSEC, 0, 0},

   // GUS TX Characteristic Value

   [GUS_IDX_TX_VAL]         = {GUS_SERVER_TX_UUID,

                               BLE_GATTS_NOTIFY_PERM_UNSEC,

                               (BLE_GATTS_ATT_VAL_LOC_USER | BLE_GATTS_ATT_UUID_TYPE_SET(BLE_GATTS_UUID_TYPE_128)),

                               GUS_MAX_DATA_LEN},

   // GUS TX Characteristic - Client Characteristic Configuration Descriptor

   [GUS_IDX_TX_CFG]         = {ATT_128_CLIENT_CHAR_CFG,

                               BLE_GATTS_READ_PERM_UNSEC | BLE_GATTS_WRITE_REQ_PERM_UNSEC,

                               0,

                               0},

   // GUS RX Characteristic Declaration

   [GUS_IDX_RX_CHAR]        = {ATT_128_CHARACTERISTIC, BLE_GATTS_READ_PERM_UNSEC, 0, 0},

   // GUS RX Characteristic Value

   [GUS_IDX_RX_VAL]         = {GUS_SERVER_RX_UUID,

                               BLE_GATTS_WRITE_REQ_PERM_UNSEC | BLE_GATTS_WRITE_CMD_PERM_UNSEC,

                               (BLE_GATTS_ATT_VAL_LOC_USER | BLE_GATTS_ATT_UUID_TYPE_SET(BLE_GATTS_UUID_TYPE_128)),

                               GUS_MAX_DATA_LEN},

   // GUS FLOW_CTRL Characteristic Declaration

   [GUS_IDX_FLOW_CTRL_CHAR] = {ATT_128_CHARACTERISTIC, BLE_GATTS_READ_PERM_UNSEC, 0, 0},

   // GUS FLOW_CTRL Characteristic Value

   [GUS_IDX_FLOW_CTRL_VAL]  = {GUS_FLOW_CTRL_UUID,

                               BLE_GATTS_NOTIFY_PERM_UNSEC | BLE_GATTS_WRITE_REQ_PERM_UNSEC,

                               (BLE_GATTS_ATT_VAL_LOC_USER | BLE_GATTS_ATT_UUID_TYPE_SET(BLE_GATTS_UUID_TYPE_128)),

                               GUS_MAX_DATA_LEN},

   // GUS FLOW_CTRL Characteristic - Client Characteristic Configuration Descriptor

   [GUS_IDX_FLOW_CTRL_CFG]  = {ATT_128_CLIENT_CHAR_CFG,

                               BLE_GATTS_READ_PERM_UNSEC | BLE_GATTS_WRITE_REQ_PERM_UNSEC,

                               0,

                               0},

};

基于GUS服务特性表和索引枚举可以构建特性属性描述表,其中ble_gatts_attm_desc_128_t结构体如下:

/**

* @brief Service(128 bits UUID) description.

*/

typedef struct

{

   uint8_t uuid[16];        /**< 128 bits UUID LSB First. */

   uint16_t perm;           /**< Attribute permissions, see @ref BLE_GATTS_ATTR_PERM. \n

                                 - For Primary/Secondary/Included Services, must be @ref BLE_GATTS_READ_PERM_UNSEC. \n

                                 - For Characteristic Declaration, must be @ref BLE_GATTS_READ_PERM_UNSEC. \n

                                 - For Characteristic Extended Properties, must be @ref BLE_GATTS_READ_PERM_UNSEC. \n

                                 - For Characteristic Presentation Format, must be @ref BLE_GATTS_READ_PERM_UNSEC. \n

                                 - For Characteristic Aggregate Format, must be @ref BLE_GATTS_READ_PERM_UNSEC. */  

                                 

   uint16_t ext_perm;       /**< Attribute extended permissions, see @ref BLE_GATTS_ATTR_EXT_PERM. \n

                                 - For Primary/Secondary/Included Services, this field is not used, set to 0. \n

                                 - For Characteristic Declaration, this field is not used, set to 0. \n

                                 - For Characteristic Extended Properties, this field is not used, set to 0. \n

                                 - For Client Characteristic Configuration and Server Characteristic Configuration, value must                                     be saved in user space,

                                   user needn't to set this value location bit. The UUID length type must be set to 0.*/

                                 

   uint16_t max_size;       /**< Attribute max size. \n

                                 - For Primary/Secondary/Included Services, this field is not used, set to 0. \n

                                 - For Characteristic Declaration, this field is not used, set to 0. \n

                                 - For Characteristic Extended Properties, this field contains 2-byte value. \n

                                 - For Client Characteristic Configuration and Server Characteristic Configuration, this field                                     is not used, set to 0. \n

                                 - For others, this field is attribute max size. */

} ble_gatts_attm_desc_128_t;

uuid表示的是该属性的属性类型:

  • GUS_IDX_SVC是首要服务,所以其对应的UUID为ATT_128_PRIMARY_SERVICE;
  • GUS_IDX_TX_CHAR是特性声明,对应的UUID则为ATT_128_CHARACTERISTIC;
  • GUS_IDX_TX_VAL是TX Characteristic特性,所以对应的UUID为我们自定义的UUID;
  • GUS_IDX_TX_CFG为TX Characteristic的CCCD,则其对应的UUID为ATT_128_CLIENT_CHAR_CFG;
  • 其中ATT_128_PRIMARY_SERVICE等宏需要通过以下代码从16bits扩展到128bits:

/**@brief Macros for conversion of 128bit to 16bit UUID. */
#define ATT_128_PRIMARY_SERVICE BLE_ATT_16_TO_128_ARRAY(BLE_ATT_DECL_PRIMARY_SERVICE)
#define ATT_128_CHARACTERISTIC  BLE_ATT_16_TO_128_ARRAY(BLE_ATT_DECL_CHARACTERISTIC)
#define ATT_128_CLIENT_CHAR_CFG BLE_ATT_16_TO_128_ARRAY(BLE_ATT_DESC_CLIENT_CHAR_CFG)

  • perm指的是该特性的访问许可属性,每个属性按照服务特性表来定义即可:
  • GUS_IDX_SVC的属性类型为首要服务,主要用于对端设备发现服务,则其访问许可属性为只读,即BLE_GATTS_READ_PERM_UNSEC,特性声明同理;
  • GUS_IDX_TX_VAL为TX特性值,根据服务特性表知道该特性的访问许可属性为notify,且对安全无要求,故该处的访问许可属性可以设置为BLE_GATTS_NOTIFY_PERM_UNSEC;若特性对访问的安全性有要求,可以将访问许可属性设置为BLE_GATTS_NOTIFY_PERM(sec_level),其中sec_level根据具体要求来定;
  • GUS_IDX_RX_VAL为RX特性值,在服务特性表中该特性的访问许可属性为write,所以该处的访问许可属性需要设置两个:BLE_GATTS_WRITE_REQ_PERM_UNSEC | BLE_GATTS_WRITE_CMD_PERM_UNSEC;
  • ext_perm主要用于特性的扩展访问许可属性,对于访问读写属性为notify的特性来说,如GUS_IDX_TX_VAL,其扩展属性需要设置为BLE_GATTS_ATT_VAL_LOC_USER,表示数据需要存储在用户空间中,同时因该特性为128bits,所以GUS_IDX_TX_VAL的扩展访问许可属性为(BLE_GATTS_ATT_VAL_LOC_USER | BLE_GATTS_ATT_UUID_TYPE_SET(BLE_GATTS_UUID_TYPE_128));
  • max_size表示属性的最大长度,可以参考注释进行设置,如GUS_IDX_TX_VAL和GUS_IDX_RX_VAL,主要用来传输数据,所以它们的最大长度设置为了传输包的最大长度,即MTU;

因GUS使用的UUID为128bits,所以这里使用的属性表结构体为ble_gatts_attm_desc_128_t,若为标准服务则可使用ble_gatts_attm_desc_t。

 

1.5 创建环境变量

/**@brief Goodix UART Service environment variable. */

struct gus_env_t

{

   gus_init_t              gus_init;                               /**< Goodix UART Service initialization variables. */

   uint16_t                start_hdl;                              /**< Start handle of services */

   uint16_t                tx_ntf_cfg[GUS_CONNECTION_MAX];         /**< TX Characteristic Notification configuration of the                                                                              peers. */

   uint16_t                flow_ctrl_ntf_cfg[GUS_CONNECTION_MAX];  /**< Flow Control Characteristic Notification configuration                                                                          of the peers. */

   ble_gatts_create_db_t   gus_gatts_db;                          /**< Goodix UART Service attributs database. */

};

  • 其中gus_init_t是GUS初始化需要的变量,如用户层提供的事件处理函数。
  • 在服务初始化时会调用ble_gatts_prf_add接口,在这个接口中会给start_hdl赋值。
  • tx_ntf_cfg主要用来记录对端设备设置的CCCD的值,因可能存在多连接的情况,所以需要创建多个该变量;
  • flow_control_ntf_cfg和tx_ntf_cfg同理,只要特性的属性中包含了notify,都需要在环境变量中创建如*_ntf_cfg这样的变量;
  • gus_gatts_db为服务描述,具体定义如下:

/**
* @brief Parameter of Added service description.
*/

typedef struct
{

   
uint16_t                            *shdl;                                          /**< Service start handle pointer. If *shdl = 0, it returns a handle using the first available handle (*shdl is modified);  otherwise it verifies if the given start handle can be used to allocate handle range.  */
   const uint8_t                       *uuid;                                          /**< Service UUID pointer. The pointer points to the Service UUID LSB. */
   uint8_t                             *attr_tab_cfg;                                  /**< Attribute table selector pointer. It can be set to NULL to select all items of attribute table.  Each bit matches with an attribute of attribute table. \n EXAMPLE:if attr_tab_cfg points to array {0x3F, 0x03}, it means that the 0.1.2.3.4.5.8.9 items of attribute table will be added to database. */
   uint8_t                              max_nb_attr;                                   /**< Number of attributes in attribute table. */
   union attribute_table                                                               /**< Attribute table. */
   {
       
const ble_gatts_attm_desc_t     *attr_tab_16;                                   /**< 16 bits service  description. The pointer point to attribute table of 16 bits service. See @ref ble_gatts_attm_desc_t. */
       const ble_gatts_attm_desc_128_t *attr_tab_128;                                  /**< 128 bits service  description. The pointer point to attribute table of 128 bits service. See @ref ble_gatts_attm_desc_128_t. */
   } attr_tab;                                                                         /**< Attribute table. */
   uint16_t                            *inc_srvc_handle[BLE_GATTS_MAX_INC_SRVC_NUM];   /**< Pointer array of Included Service start handle's address. */
   uint16_t                             inc_srvc_num;                                  /**< Included Service number for this service. */
   uint8_t                              srvc_perm;                                     /**< Service permission. See @ref BLE_GATTS_SRVC_PERM. */
   ble_gatts_service_type_t             attr_tab_type;                                 /**< Service table type.  See @ref ble_gatts_service_type_t. */
} ble_gatts_create_db_t;

 

  • shdl为指向环境变量中的start_hdl的指针;
  • uuid为指向GUS服务UUID的指针;
  • attr_tab_cfg决定了属性表中哪些项放入数据库中,每一位与属性表中的一个属性相匹配;如GUS的属性索引包含了9项,并且我们希望包含所有的属性项,那这里应设置为指向数组{0xFF, 0x01}的指针;
  • max_nb_attr即为属性表的数目,即GUS_IDX_NB;
  • attr_tab分为attr_tab_16和attr_tab_128,即为上文中定义的属性描述表gus_attr_tab;
  • inc_srvc_handle则在该服务含有别的服务时使用,没有则不需设置;在WSP(Weight Scale Profile)中BCS是WSS的included service,则WSS的inc_srvc_handle[0]需设置为指向BCS的start handle的指针,inc_srvc_num表示包含的服务个数,应设置为1;
  • srvc_perm包含了如下位域,用户需基于服务的实际情况来设置:

如GUS是128bits服务,则此处需设置为BLE_GATTS_SRVC_UUID_TYPE_SET(BLE_GATTS_UUID_TYPE_128);

  • attr_tab_type分为BLE_GATTS_SERVICE_TABLE_TYPE_128和BLE_GATTS_SERVICE_TABLE_TYPE_16,按照实际情况设置即可。

1.6 添加特性应用层返回事件类型

由1.1节服务特性表可知该服务包含了RX、TX、TX CCCD、Flow Control和Flow Control CCCD特性,故对应的应用层返回事件类型可根据特性的访问许可属性(一般会忽略read属性)设置为如下类型:

Characteristic

UUID

Type

Support

Security

Properties

RX characteristic

A6ED0103-D344-460A-8075-B9E8EC90D71B

128bits

Mandatory

None

Write

TX Characteristic

A6ED0102-D344-460A-8075-B9E8EC90D71B

128bits

Mandatory

None

Notify

TX Characteristic Client Characteristic Configuration descriptor

-

-

Mandatory

None

Read, Write

Flow Control

A6ED0204-D344-460A-8075-B9E8EC90D71B

128bits

Mandatory

None

Notify, Write

Flow Control Client Characteristic Configuration descriptor

-

-

Mandatory

None

Read, Write

  • GUS_EVT_INVALID:表示无效GUS事件;
  • RX特性访问许可属性为可写,所以可以设置一个事件类型表示RX特性已经接收完对端发送过来的数据,即GUS_EVT_RX_DATA_RECEIVED;
  • TX特性的访问许可属性为notify,则可以设置一个事件类型表示待发送数据已通过TX特性发送完毕,即GUS_EVT_TX_DATA_SENT;
  • TX CCCD的访问许可属性为可写,所以对端设备可以设置开关CCCD,对应的事件类型即可设置为GUS_EVT_TX_PORT_OPENED和GUS_EVT_TX_PORT_CLOSED;
  • Flow Control的访问许可属性为notify和write,所以当对端设备改变了该特性的值时,可以设置对应事件类型为GUS_EVT_TX_FLOW_OFF和GUS_EVT_TX_FLOW_ON;同时也可以设置一个事件类型表示Flow Control特性已经把数据发送给对端,但该事件在实际使用中意义不大,所以未设置;
  • 同理,Flow Control CCCD特性的访问许可属性为可写,所以对端可以开关CCCD,故对应的事件类型可设置为GUS_EVT_FLOW_CTRL_ENABLE和GUS_EVT_FLOW_CTRL_DISABLE。

 

1.7 实现GATTS事件处理函数

在调用ble_gatts_prf_add接口时,需要传入一个BLE event handler,这个event handler主要处理GATTS相关事件。

static void gus_ble_evt_handler(const ble_evt_t *p_evt)

{

   if (NULL == p_evt)

   {

       return;

   }

   switch (p_evt->evt_id)

   {

       case BLE_GATTS_EVT_READ_REQUEST:

           gus_read_att_evt_handler(p_evt->evt.gatts_evt.index, &p_evt->evt.gatts_evt.params.read_req);

           break;

       case BLE_GATTS_EVT_WRITE_REQUEST:

           gus_write_att_evt_handler(p_evt->evt.gatts_evt.index, &p_evt->evt.gatts_evt.params.write_req);

           break;

       case BLE_GATTS_EVT_NTF_IND:

           gus_ntf_ind_evt_handler(p_evt->evt.gatts_evt.index, p_evt->evt_status, &p_evt->evt.gatts_evt.params.ntf_ind_sended);

           break;

       case BLE_GATTS_EVT_CCCD_RECOVERY:

           gus_cccd_set_evt_handler(p_evt->evt.gatts_evt.index, p_evt->evt.gatts_evt.params.cccd_recovery.handle, p_evt->evt.gatts_evt.params.cccd_recovery.cccd_val);

           break;

   }

}

  • 当client向server发起读请求时,server会收到BLE_GATTS_EVT_READ_REQUEST事件,server需要基于handle确定client想读取的是哪一个属性的值,并把相应的值传递给client,示例代码如下:

static void gus_read_att_evt_handler(uint8_t conn_idx, const ble_gatts_evt_read_t *p_param)
{
   
ble_gatts_read_cfm_t cfm;
   
uint16_t         handle    = p_param->handle;
   
uint8_t          tab_index = 0;

   
tab_index  = prf_find_idx_by_handle(handle, s_gus_env.start_hdl, GUS_IDX_NB, (uint8_t *)&s_char_mask);
   
cfm.handle = handle;
   
cfm.status = BLE_SUCCESS;

   
switch (tab_index)
   {
       
case GUS_IDX_TX_CFG:
           
cfm.length = sizeof(uint16_t);
           
cfm.value  = (uint8_t *)&s_gus_env.tx_ntf_cfg[conn_idx];
           
cfm.status = BLE_SUCCESS;
           
break;

       ......

       
default:
           
cfm.length = 0;
           
cfm.status = BLE_ATT_ERR_INVALID_HANDLE;
           
break;
   }

   
ble_gatts_read_cfm(conn_idx, &cfm);
}

  • 当client向server发起写请求时,server会收到BLE_GATTS_EVT_WRITE_REQUEST,server同样通过handle确定client想要向哪一个属性写值,并将值保存下来,同时通知应用层发生了哪些事件,示例代码如下:

static void gus_write_att_evt_handler(uint8_t conn_idx, const ble_gatts_evt_write_t *p_param)
{
   
uint8_t           handle    = p_param->handle;
   
uint8_t           tab_index = 0;
   
uint16_t          flow_ctrl_state;
   
uint16_t          cccd_value;
   
gus_evt_t         event;
   
ble_gatts_write_cfm_t cfm;

   
tab_index      = prf_find_idx_by_handle(handle,s_gus_env.start_hdl, GUS_IDX_NB, (uint8_t *)&s_char_mask);
   
event.conn_idx = conn_idx;
   
cfm.handle     = handle;
   
cfm.status     = BLE_SUCCESS;
   
   
switch (tab_index)
   {
       
case GUS_IDX_RX_VAL:
           
event.evt_type       = GUS_EVT_RX_DATA_RECEIVED;
           
event.p_data = (uint8_t *)p_param->value;
           
event.length = p_param->length;
           
break;

       
case GUS_IDX_TX_CFG:
           
cccd_value     = le16toh(&p_param->value[0]);
           
event.evt_type = (PRF_CLI_START_NTF == cccd_value) ? GUS_EVT_TX_PORT_OPENED : GUS_EVT_TX_PORT_CLOSED;
           
s_gus_env.tx_ntf_cfg[conn_idx] = cccd_value;
           
break;

       ......

       
case GUS_IDX_FLOW_CTRL_VAL:
           
flow_ctrl_state = p_param->value[0];

           
if (GUS_FLOW_CTRL_STATE_OFF == flow_ctrl_state)
           {
               
event.evt_type = GUS_EVT_TX_FLOW_OFF;
           }
           
else if (GUS_FLOW_CTRL_STATE_ON == flow_ctrl_state)
           {
               
event.evt_type = GUS_EVT_TX_FLOW_ON;
           }
           
break;

       
default:
           
cfm.status = BLE_ATT_ERR_INVALID_HANDLE;
           
break;
   }

   
if (BLE_ATT_ERR_INVALID_HANDLE != cfm.status && GUS_EVT_INVALID != event.evt_type && s_gus_env.gus_init.evt_handler)
   {
       
s_gus_env.gus_init.evt_handler(&event); // 通知应用层
   }

   
ble_gatts_write_cfm(conn_idx, &cfm);
}

  • 当client想要改变server的CCCD时,server会接收到BLE_GATTS_EVT_CCCD_RECOVERY事件,server在该事件中设置CCCD值;
  • 当server发送完一次notification时,会触发BLE_GATTS_EVT_NTF_IND事件,当有多包数据需要发送时,我们可以在这个事件中发下一包数据;
  • 当client需要向server预写入数据时,server会接收到BLE_GATTS_EVT_PREP_WRITE_REQUEST事件,该事件并不常用。

1.8 实现notification/indication发送函数

当TX特性向对端设备发送notification时,需要实现对应的发送函数:

sdk_err_t gus_tx_data_send(uint8_t conn_idx, uint8_t *p_data, uint16_t length)

{

   sdk_err_t            error_code = SDK_ERR_NTF_DISABLED;

   ble_gatts_noti_ind_t send_cmd;

   if (PRF_CLI_START_NTF == s_gus_env.tx_ntf_cfg[conn_idx])

   {

       // Fill in the parameter structure

       send_cmd.type   = BLE_GATT_NOTIFICATION;

       send_cmd.handle = prf_find_handle_by_idx(GUS_IDX_TX_VAL, s_gus_env.start_hdl, (uint8_t *)&s_char_mask);

       // Pack measured value in database

       send_cmd.length = length;

       send_cmd.value  = p_data;

       // Send notification to peer device

       error_code = ble_gatts_noti_ind(conn_idx, &send_cmd);

   }

   return error_code;

}

发送接口为

uint16_t ble_gatts_noti_ind(uint8_t conn_idx, const ble_gatts_noti_ind_t *p_param);

其中ble_gatts_noti_ind_t的定义如下:

typedef struct

{

   ble_gatt_evt_type_t    type;       /**< Request type (Notification/Indication). see @ref ble_gatt_evt_type_t. */

   uint16_t               handle;     /**< Characteristic Value handle to be notified or indicated. */

   uint16_t               length;     /**< Length of Characteristic Value to be sent. */

   uint8_t               *value;      /**< Characteristic Value pointer. */

} ble_gatts_noti_ind_t;

  • type分为BLE_GATT_NOTIFICATION和BLE_GATT_INDICATION,根据发的数据类型来定;
  • handle可以通过属性索引来确定;

1.9 实现服务初始化函数

初始化函数的主要目的是加载应用层事件处理函数,初始化环境变量,同时注册服务。在1.5节中介绍了如何创建环境变量,也简要介绍了如何给它赋值。示例代码如下:

sdk_err_t gus_service_init(gus_init_t *p_gus_init)

{

   if (NULL == p_gus_init)

   {

       return SDK_ERR_POINTER_NULL;

   }

   memcpy(&s_gus_env.gus_init, p_gus_init, sizeof(gus_init_t));

   memset(&s_gus_env.gus_gatts_db, 0, sizeof(ble_gatts_create_db_t));

   s_gus_env.start_hdl  = PRF_INVALID_HANDLE;

   s_gus_env.gus_gatts_db.shdl                  = &s_gus_env.start_hdl;

   s_gus_env.gus_gatts_db.uuid                  = s_gus_svc_uuid;

   s_gus_env.gus_gatts_db.attr_tab_cfg          = (uint8_t *)&s_char_mask;

   s_gus_env.gus_gatts_db.max_nb_attr           = GUS_IDX_NB;

   s_gus_env.gus_gatts_db.srvc_perm             = BLE_GATTS_SRVC_UUID_TYPE_SET(BLE_GATTS_UUID_TYPE_128);

   s_gus_env.gus_gatts_db.attr_tab_type         = BLE_GATTS_SERVICE_TABLE_TYPE_128;

   s_gus_env.gus_gatts_db.attr_tab.attr_tab_128 = gus_attr_tab;

   return ble_gatts_prf_add(&s_gus_env.gus_gatts_db, gus_ble_evt_handler);

}

 

2. 添加服务

BLE service文件位于app\components\profiles中。

  • 添加ble_prf_utils.c文件,该文件位于app\components\profiles\common文件夹中,该文件提供了一些功能函数,如基于句柄搜索属性索引、检查CCCD值是否有效等;
  • 基于实际需要添加相应的ble service文件。

剩余内容,会在下篇中进一步讲解

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值