CC2640R2F学习笔记(7)——自定义服务和特征
发布日期:2021-05-06 23:36:51 浏览次数:20 分类:技术文章

本文共 22151 字,大约阅读时间需要 73 分钟。

一、背景

1.1 Profile(规范)

profile 可以理解为一种规范,一个标准的通信协议,它存在于蓝牙从机中(服务端);

蓝牙组织规定了一些标准的 profile,例如 HID OVER GATT,防丢器,心率计等;

每个 profile 中会包含多个 service,每个 service 代表从机的一种能力。

1.2 Service(服务)

service 可以理解为一个服务,在 BLE 从机中有多个服务,例如:电量信息服务、系统信息服务等;

每个 service 中又包含多个 characteristic 特征值;

每个具体的 characteristic 特征值才是 BLE 通信的主题,比如当前的电量是 80%,电量的 characteristic 特征值存在从机的 profile 里,这样主机就可以通过这个 characteristic 来读取 80% 这个数据。

1.3 Characteristic(特征)

characteristic 特征,BLE 主从机的通信均是通过 characteristic 来实现,可以理解为一个标签,通过这个标签可以获取或者写入想要的内容。

1.4 UUID(通用唯一识别码)

uuid 通用唯一识别码,我们刚才提到的 service 和 characteristic 都需要一个唯一的 uuid 来标识;

每个从机都会有一个 profile,不管是自定义的 simpleprofile,还是标准的防丢器 profile,他们都是由一些 service 组成,每个 service 又包含了多个 characteristic,主机和从机之间的通信,均是通过characteristic来实现。

1.5 CCC(Client Characteristic Configuration)

Notify 属性的特征值,会比读、写属性的特征值多一个 CCC。

从机要想使用 Notify 函数时能正常发送出数据,就必须保证 CCC 是被打开的。

1.6 AttrTbl(属性表)

它是一个服务中的数组,用来存放该服务下的服务信息、所有特征值信息。每个特征值一般

为 3 个参数,而 Notify 属性的特征值一般为 4 个参数(多一个 Notify 开关的参数)。

1.7 应用场景

举个例子,假设蓝牙设备中有 2 个服务,温湿度服务(假设 UUID 为 0x1110)和电量

服务(假设 UUID 为 0x2220)。
其中温湿度服务中包含了温度特征(假设 UUID 为 0x1111)、湿度特征(假设 UUID 为
0x1112)。

此时你想用另一个 CC2640R2F 作为主机读取温度值,那么 CC2640R2F 主机会做如下事情:

1)连接设备:扫描并连接你的蓝牙设备从机。
2)发现服务:查找设备的服务中是否包含 UUID 为 0x1110 的服务(温湿度服务)。
3)发现特征:查找 UUID 为 0x1110 的服务(温湿度服务)中是否包含 UUID 为 0x1111 的
特征值(温度特征值)。
4)获得特征句柄:查找到温度特征后,获取问读特征句柄,假设为 0x0038。
5)利用句柄来读取温度值:使用 0x0038 的句柄发送读指令,则此时 CC2640R2F 主机可读取
到 CC2640R2F 从机中的温度值。

二、移植文件

链接: 提取码:8t9u

alm_gatt_profile.calm_gatt_profile.h 两个文件拖拽至CCS工程的PROFILES文件夹下
添加文件过程中,选项选择如下

2.1 alm_gatt_profile.c

/********************************************************************* * INCLUDES */#include 
#include "bcomdef.h"#include "OSAL.h"#include "linkdb.h"#include "att.h"#include "gatt.h"#include "gatt_uuid.h"#include "gattservapp.h"#include "gapbondmgr.h"#include "alm_gatt_profile.h"/********************************************************************* * DEFINITIONS *///属性表的数据长度#define SERVAPP_NUM_ATTR_SUPPORTED 5 // 每新增一个特征要加3(带Notify的特征要加4) //属性在属性表中的偏移值#define ATTRTBL_ALM_CHAR1_IDX 2 // 特征1在属性表的偏移值#define ATTRTBL_ALM_CHAR1_CCC_IDX 3 // 特征1的notify开关在属性表的偏移值 /********************************************************************* * GLOBAL VARIABLES *//*--------------------- 特征相关 -------------------------*/uint8 g_ALMProfile_Char1Value[ALMPROFILE_CHAR1_LEN] = { 0}; // 特征1值uint8 g_ALMProfile_Char2Value[ALMPROFILE_CHAR2_LEN] = { 0}; // 特征2值uint8 g_ALMProfile_Char3Value[ALMPROFILE_CHAR3_LEN] = { 0}; // 特征3值// ALM GATT Profile 服务 UUID: 0xFFE0CONST uint8 g_ALMProfileServUUID[ATT_BT_UUID_SIZE] ={ LO_UINT16(ALMPROFILE_SERV_UUID), HI_UINT16(ALMPROFILE_SERV_UUID)}; // 特征1 UUID: 0xFFE1CONST uint8 g_ALMProfileChar1UUID[ATT_BT_UUID_SIZE] ={ LO_UINT16(ALMPROFILE_CHAR1_UUID), HI_UINT16(ALMPROFILE_CHAR1_UUID)}; /********************************************************************* * LOCAL VARIABLES */static almProfileCBs_t *s_pALMProfile_AppCBs = NULL; /********************************************************************* * Profile Attributes - variables */ // ALM Profile 服务属性static CONST gattAttrType_t s_ALMProfileService = { ATT_BT_UUID_SIZE, g_ALMProfileServUUID }; // 特征1的权限static uint8 s_ALMProfileChar1Props = GATT_PROP_READ | GATT_PROP_WRITE | GATT_PROP_NOTIFY; // 特征1的值static uint8 s_ALMProfileChar1[ALMPROFILE_CHAR1_LEN] = { 0}; // 特征1的配置static gattCharCfg_t *s_pALMProfileChar1Config; // 特征1的用户描述static uint8 s_ALMProfileChar1UserDesp[10] = "ALM Char1\0"; /********************************************************************* * Profile Attributes - Table */ static gattAttribute_t s_ALMProfileAttrTbl[SERVAPP_NUM_ATTR_SUPPORTED] ={ // ALM Profile 服务 { { ATT_BT_UUID_SIZE, primaryServiceUUID }, /* type */ GATT_PERMIT_READ, /* permissions */ 0, /* handle */ (uint8 *)&s_ALMProfileService /* pValue */ }, // 特征1的权限 { { ATT_BT_UUID_SIZE, characterUUID }, GATT_PERMIT_READ, 0, &s_ALMProfileChar1Props }, // 特征1的值 { { ATT_BT_UUID_SIZE, g_ALMProfileChar1UUID }, GATT_PERMIT_READ | GATT_PERMIT_WRITE, 0, s_ALMProfileChar1 }, // 特征1的配置 { { ATT_BT_UUID_SIZE, clientCharCfgUUID }, GATT_PERMIT_READ | GATT_PERMIT_WRITE, 0, (uint8 *)&s_pALMProfileChar1Config }, // 特征1的用户描述 { { ATT_BT_UUID_SIZE, charUserDescUUID }, GATT_PERMIT_READ, 0, s_ALMProfileChar1UserDesp },}; /********************************************************************* * LOCAL FUNCTIONS *//** @brief 读属性 @param connHandle 连接句柄 @param pAttr 指向属性 @param pValue 指向读出的数据 @param pLen 被读出的数据长度 @param offset 偏移量 @param maxLen 被读出的数据最大长度 @return SUCCESS - 成功;FAILURE - 失败*/static uint8 almProfile_ReadAttrCB(uint16 connHandle, gattAttribute_t *pAttr, uint8 *pValue, uint16 *pLen, uint16 offset, uint16 maxLen, uint8_t method){ bStatus_t status = SUCCESS; // 如果属性没有读的权限,返回错误 if(gattPermitAuthorRead(pAttr->permissions)) { // 权限不足 return (ATT_ERR_INSUFFICIENT_AUTHOR); } // 确保不是错误操作 (没有长属性) if(offset > 0) { return (ATT_ERR_ATTR_NOT_LONG); } if(pAttr->type.len == ATT_BT_UUID_SIZE) { // 16-bit UUID uint16 uuid = BUILD_UINT16(pAttr->type.uuid[0], pAttr->type.uuid[1]); switch(uuid) { // No need for "GATT_SERVICE_UUID" or "GATT_CLIENT_CHAR_CFG_UUID" cases; // gattserverapp handles those reads // 特征1有读权限 case ALMPROFILE_CHAR1_UUID: *pLen = ALMPROFILE_CHAR1_LEN; VOID memcpy(pValue, pAttr->pValue, ALMPROFILE_CHAR1_LEN); break; default: // Should never get here! *pLen = 0; status = ATT_ERR_ATTR_NOT_FOUND; break; } } else { // 128-bit UUID *pLen = 0; status = ATT_ERR_INVALID_HANDLE; } return (status);}/** @brief 写属性,在写入之前验证属性数据 @param connHandle 连接句柄 @param pAttr 指向属性 @param pValue 指向写入的数据 @param len 写入的数据长度 @param offset 偏移量 @return SUCCESS - 成功;FAILURE - 失败*/static bStatus_t almProfile_WriteAttrCB(uint16 connHandle, gattAttribute_t *pAttr, uint8 *pValue, uint16 len, uint16 offset, uint8_t method){ bStatus_t status = SUCCESS; uint8 notifyApp = 0xFF; // 如果属性没有写的权限,返回错误 if(gattPermitAuthorWrite(pAttr->permissions)) { // 权限不足 return (ATT_ERR_INSUFFICIENT_AUTHOR); } if(pAttr->type.len == ATT_BT_UUID_SIZE) { // 16-bit UUID uint16 uuid = BUILD_UINT16(pAttr->type.uuid[0], pAttr->type.uuid[1]); switch(uuid) { case ALMPROFILE_CHAR1_UUID: if(offset == 0) { if(len != ALMPROFILE_CHAR1_LEN) { status = ATT_ERR_INVALID_VALUE_SIZE; } } else { status = ATT_ERR_ATTR_NOT_LONG; } // 将接收到的数据写进特征值中,并且置标志位 if(status == SUCCESS) { VOID memcpy(pAttr->pValue, pValue, ALMPROFILE_CHAR1_LEN); notifyApp = ALMPROFILE_CHAR1; } break; case GATT_CLIENT_CHAR_CFG_UUID: // 特征1通道,则打开notify开关 if(pAttr->handle == s_ALMProfileAttrTbl[ATTRTBL_ALM_CHAR1_CCC_IDX].handle) { status = GATTServApp_ProcessCCCWriteReq(connHandle, pAttr, pValue, len, offset, GATT_CLIENT_CFG_NOTIFY); } else { status = ATT_ERR_INVALID_HANDLE; } break; default: status = ATT_ERR_ATTR_NOT_FOUND; break; } } else { // 128-bit UUID status = ATT_ERR_INVALID_HANDLE; } // 如果特征值被更改,则通过回调函数通知应用程序更改 if((notifyApp != 0xFF) && s_pALMProfile_AppCBs && s_pALMProfile_AppCBs->pfnALMProfileChange) { s_pALMProfile_AppCBs->pfnALMProfileChange(notifyApp); } return (status);}/********************************************************************* * PROFILE CALLBACKS */// ALM Profile 服务回调CONST gattServiceCBs_t almProfileCBs ={ almProfile_ReadAttrCB, // Read callback function pointer almProfile_WriteAttrCB, // Write callback function pointer NULL // Authorization callback function pointer};/********************************************************************* * PUBLIC FUNCTIONS *//** @brief 通过向GATT服务端注册GATT属性来初始化ALM Profile服务 @param services 被添加的服务 @return SUCCESS - 成功;FAILURE - 失败*/bStatus_t ALMProfile_AddService(uint32 services){ uint8 status = SUCCESS; // 为客户端特征配置表分配内存 s_pALMProfileChar1Config = (gattCharCfg_t *)ICall_malloc(sizeof(gattCharCfg_t) * linkDBNumConns); if(s_pALMProfileChar1Config == NULL) { return (bleMemAllocError); } // 初始化客户端特征配置属性 GATTServApp_InitCharCfg(INVALID_CONNHANDLE, s_pALMProfileChar1Config); if(services & ALMPROFILE_SERVICE) { // 向GATT服务端应用注册GATT属性列表和回调 status = GATTServApp_RegisterService(s_ALMProfileAttrTbl, GATT_NUM_ATTRS(s_ALMProfileAttrTbl), GATT_MAX_ENCRYPT_KEY_SIZE, &almProfileCBs); } return (status);}/** @brief 注册应用程序回调函数。只调用这个函数一次 @param callbacks 指向应用程序的回调 @return SUCCESS - 成功;bleAlreadyInRequestedMode - 失败*/bStatus_t ALMProfile_RegisterAppCBs(almProfileCBs_t *appCallbacks){ if(appCallbacks) { s_pALMProfile_AppCBs = appCallbacks; return (SUCCESS); } else { return (bleAlreadyInRequestedMode); }}/** @brief 设置ALM Profile参数 @param param Profile参数ID @param len 写入的数据长度 @param pValue 指向写入的数据 @return SUCCESS - 成功;FAILURE - 失败*/bStatus_t ALMProfile_SetParameter(uint8 param, uint8 len, void *pValue){ bStatus_t ret = SUCCESS; switch(param) { case ALMPROFILE_CHAR1: if(len == ALMPROFILE_CHAR1_LEN) { VOID memcpy(s_ALMProfileChar1, pValue, ALMPROFILE_CHAR1_LEN); } else { ret = bleInvalidRange; } break; default: ret = INVALIDPARAMETER; break; } return (ret);}/** @brief 获取ALM Profile参数 @param param Profile参数ID @param pValue 指向读出的数据 @return SUCCESS - 成功;FAILURE - 失败*/bStatus_t ALMProfile_GetParameter(uint8 param, void *pValue){ bStatus_t ret = SUCCESS; switch(param) { case ALMPROFILE_CHAR1: VOID memcpy(pValue, s_ALMProfileChar1, ALMPROFILE_CHAR1_LEN); break; default: ret = INVALIDPARAMETER; break; } return (ret);}/** @brief Notify发送函数 @param param 特征值通道参数 @param connHandle 连接句柄 @param pValue 指向要通知的数据 @param len 要通知的数据长度,范围为0~SIMPLEPROFILE_CHAR6,最多20个字节 @return SUCCESS - 成功;FAILURE - 失败*/bStatus_t ALMProfile_Notify(uint8 param, uint16 connHandle, uint8 *pValue, uint8 len){ attHandleValueNoti_t attHandleValueNoti; uint16 value; bStatus_t ret = SUCCESS; switch(param) { // 特征1 case ALMPROFILE_CHAR1: // 读出CCC value = GATTServApp_ReadCharCfg(connHandle, s_pALMProfileChar1Config); // 判断CCC是否被打开 if(value & GATT_CLIENT_CFG_NOTIFY) { // 分配发送数据缓冲区 attHandleValueNoti.pValue = GATT_bm_alloc(connHandle, ATT_HANDLE_VALUE_NOTI, ALMPROFILE_CHAR1_LEN, NULL); // 分配成功,则发送数据 if(attHandleValueNoti.pValue != NULL) { // 填充数据 attHandleValueNoti.handle = s_ALMProfileAttrTbl[ATTRTBL_ALM_CHAR1_IDX].handle; attHandleValueNoti.len = len; memcpy(attHandleValueNoti.pValue, value, len); // 发送数据 if(GATT_Notification(connHandle, &attHandleValueNoti, FALSE) != SUCCESS) { GATT_bm_free((gattMsg_t *)&attHandleValueNoti, ATT_HANDLE_VALUE_NOTI); } } else ret = FAILURE; } else ret = FAILURE; break; default: ret = FAILURE; break; } return (ret);}/*************************************END OF FILE*************************************/

2.2 alm_gatt_profile.h

#ifndef _ALM_GATT_PROFILE_H_#define _ALM_GATT_PROFILE_H_ #ifdef __cplusplusextern "C"{   #endif /********************************************************************* * DEFINITIONS */ // Profile Parameters#define ALMPROFILE_CHAR1                       0  // RW uint8 - Profile Characteristic 1 value // ALM Profile Service UUID#define ALMPROFILE_SERV_UUID                   0xFFE0 // CHAR1 UUID#define ALMPROFILE_CHAR1_UUID                  0xFFE1 // ALM Profile Services bit fields#define ALMPROFILE_SERVICE                     0x00000001 // Length of Characteristic in bytes#define ALMPROFILE_CHAR1_LEN                   8        // CHAR1 LEN#define ALMPROFILE_CHAR2_LEN                   1        // CHAR2 LEN#define ALMPROFILE_CHAR3_LEN                   1        // CHAR3 LEN/********************************************************************* * TYPEDEFS */ /********************************************************************* * Profile Callbacks */// Callback when a characteristic value has changedtypedef void (*almProfileChange_t)(uint8 paramID); typedef struct{       almProfileChange_t  pfnALMProfileChange;  // Called when characteristic value changes} almProfileCBs_t; /********************************************************************* * API FUNCTIONS */extern bStatus_t ALMProfile_AddService(uint32 services);extern bStatus_t ALMProfile_RegisterAppCBs(almProfileCBs_t *appCallbacks);extern bStatus_t ALMProfile_SetParameter(uint8 param, uint8 len, void *pValue);extern bStatus_t ALMProfile_GetParameter(uint8 param, void *pValue);extern bStatus_t ALMProfile_Notify(uint8 param, uint16 connHandle, uint8 *pValue, uint8 len); #ifdef __cplusplus}#endif #endif /* _ALM_GATT_PROFILE_H_ */

三、API调用

需包含头文件 alm_gatt_profile.h

ALMProfile_AddService

功能 通过向GATT服务端注册GATT属性来初始化ALM Profile服务
函数定义 bStatus_t ALMProfile_AddService(uint32 services)
参数 services:被添加的服务
返回 SUCCESS - 成功;FAILURE - 失败

ALMProfile_RegisterAppCBs

功能 注册应用程序回调函数。只调用这个函数一次
函数定义 bStatus_t ALMProfile_RegisterAppCBs(almProfileCBs_t *appCallbacks)
参数 callbacks:指向应用程序的回调
返回 SUCCESS - 成功;FAILURE - 失败

ALMProfile_SetParameter

功能 设置ALM Profile参数
函数定义 bStatus_t ALMProfile_SetParameter(uint8 param, uint8 len, void *pValue)
参数1 param:Profile参数ID
参数2 len:写入的数据长度
参数3 pValue:指向写入的数据
返回 SUCCESS - 成功;FAILURE - 失败

ALMProfile_GetParameter

功能 获取ALM Profile参数
函数定义 bStatus_t ALMProfile_GetParameter(uint8 param, void *pValue)
参数1 param:Profile参数ID
参数2 pValue:指向读出的数据
返回 SUCCESS - 成功;FAILURE - 失败

ALMProfile_Notify

功能 Notify发送函数
函数定义 bStatus_t ALMProfile_Notify(uint8 param, uint16 connHandle, uint8 *pValue, uint8 len)
参数1 param:特征值通道参数
参数2 connHandle:连接句柄
参数3 pValue:指向要通知的数据
参数4 len:要通知的数据长度
返回 SUCCESS - 成功;FAILURE - 失败

四、新增特征

4.1 添加只读特征

在DEFINITIONS中修改,原来5,新增一个带读的特征+3

#define SERVAPP_NUM_ATTR_SUPPORTED              8  // 原来5,新增一个带读的特征+3

在GLOBAL VARIABLES中新增

// 特征2 UUID: 0xFFE2CONST uint8 g_ALMProfileChar2UUID[ATT_BT_UUID_SIZE] ={       LO_UINT16(ALMPROFILE_CHAR2_UUID), HI_UINT16(ALMPROFILE_CHAR2_UUID)};

在Profile Attributes - variables中新增

/*--------------------- 特征2 ---------------------*/static uint8 s_ALMProfileChar2Props = GATT_PROP_READ;           // 特征权限static uint8 s_ALMProfileChar2[ALMPROFILE_CHAR2_LEN] = {   0};     // 特征值static uint8 s_ALMProfileChar2UserDesp[10] = "ALM Char2\0";     // 特征用户描述

在Profile Attributes - Table中新增

/*--------------------- 特征2 ---------------------*/    // 特征2的权限    {           {    ATT_BT_UUID_SIZE, characterUUID },        GATT_PERMIT_READ,        0,        &s_ALMProfileChar2Props    },    // 特征2的值    {           {    ATT_BT_UUID_SIZE, g_ALMProfileChar2UUID },        GATT_PERMIT_READ,        0,        s_ALMProfileChar2    },    // 特征2的用户描述    {           {    ATT_BT_UUID_SIZE, charUserDescUUID },        GATT_PERMIT_READ,        0,        s_ALMProfileChar2UserDesp    },

在almProfile_ReadAttrCB回调函数中,switch(uuid)增加一个case,因为特征2有读权限

case ALMPROFILE_CHAR2_UUID:            *pLen = ALMPROFILE_CHAR2_LEN;            VOID memcpy(pValue, pAttr->pValue, ALMPROFILE_CHAR2_LEN);            break;

在ALMProfile_SetParameter函数中新增

case ALMPROFILE_CHAR2:        if(len == ALMPROFILE_CHAR2_LEN)        {               VOID memcpy(s_ALMProfileChar2, pValue, ALMPROFILE_CHAR2_LEN);        }        else        {               ret = bleInvalidRange;        }        break;

在ALMProfile_GetParameter函数中新增

case ALMPROFILE_CHAR2:        VOID memcpy(pValue, s_ALMProfileChar2, ALMPROFILE_CHAR2_LEN);        break;

在alm_gatt_profile.h头文件中新增

#define ALMPROFILE_CHAR2                       1#define ALMPROFILE_CHAR2_UUID                  0xFFE2   // CHAR2 UUID#define ALMPROFILE_CHAR2_LEN                   1

4.2 添加可读写特征

在DEFINITIONS中修改,原来8,新增一个带读的特征+3

#define SERVAPP_NUM_ATTR_SUPPORTED              11  // 原来8,新增一个带读的特征+3

在GLOBAL VARIABLES中新增

// 特征3 UUID: 0xFFE3CONST uint8 g_ALMProfileChar3UUID[ATT_BT_UUID_SIZE] ={       LO_UINT16(ALMPROFILE_CHAR3_UUID), HI_UINT16(ALMPROFILE_CHAR3_UUID)};

在Profile Attributes - variables中新增

/*--------------------- 特征3 ---------------------*/static uint8 s_ALMProfileChar3Props = GATT_PROP_READ |          // 特征权限                                      GATT_PROP_WRITE;static uint8 s_ALMProfileChar3[ALMPROFILE_CHAR3_LEN] = {   0};     // 特征值static uint8 s_ALMProfileChar3UserDesp[10] = "ALM Char3\0";     // 特征用户描述

在Profile Attributes - Table中新增

/*--------------------- 特征3 ---------------------*/    // 特征3的权限    {           {    ATT_BT_UUID_SIZE, characterUUID },        GATT_PERMIT_READ,        0,        &s_ALMProfileChar3Props    },    // 特征2的值    {           {    ATT_BT_UUID_SIZE, g_ALMProfileChar3UUID },        GATT_PERMIT_READ | GATT_PERMIT_WRITE,        0,        s_ALMProfileChar3    },    // 特征3的用户描述    {           {    ATT_BT_UUID_SIZE, charUserDescUUID },        GATT_PERMIT_READ,        0,        s_ALMProfileChar3UserDesp    },

在almProfile_ReadAttrCB回调函数中,switch(uuid)增加一个case,因为特征3有读权限

case ALMPROFILE_CHAR3_UUID:            *pLen = ALMPROFILE_CHAR3_LEN;            VOID memcpy(pValue, pAttr->pValue, ALMPROFILE_CHAR3_LEN);            break;

在almProfile_WriteAttrCB回调函数中,switch(uuid)增加一个case,因为特征3有写权限

case ALMPROFILE_CHAR3_UUID:            if(offset == 0)            {                   if(len != ALMPROFILE_CHAR3_LEN)                {                       status = ATT_ERR_INVALID_VALUE_SIZE;                }            }            else            {                   status = ATT_ERR_ATTR_NOT_LONG;            }            // 将接收到的数据写进特征值中,并且置标志位            if(status == SUCCESS)            {                   VOID memcpy(pAttr->pValue, pValue, len);    // len - 原ALMPROFILE_CHAR3_LEN                notifyApp = ALMPROFILE_CHAR3;            }            break;

在ALMProfile_SetParameter函数中新增

case ALMPROFILE_CHAR3:        if(len == ALMPROFILE_CHAR3_LEN)        {               VOID memcpy(s_ALMProfileChar3, pValue, ALMPROFILE_CHAR3_LEN);        }        else        {               ret = bleInvalidRange;        }        break;

在ALMProfile_GetParameter函数中新增

case ALMPROFILE_CHAR3:        VOID memcpy(pValue, s_ALMProfileChar3, ALMPROFILE_CHAR3_LEN);        break;

在alm_gatt_profile.h头文件中新增

#define ALMPROFILE_CHAR3                       2#define ALMPROFILE_CHAR3_UUID                  0xFFE3   // CHAR3 UUID#define ALMPROFILE_CHAR3_LEN                   1

4.3 添加可读可写可通知特征

如原来的特征1

五、加入服务和特征到工程

5.1 添加头文件

#include "alm_gatt_profile.h"

5.2 添加初始化代码

例在multi_role.c 的 multi_role_init 函数末尾中

ALMProfile_AddService(GATT_ALL_SERVICES);   // 自定义服务// ALM GATT Profile{        // 初始化特征值    ALMProfile_SetParameter(ALMPROFILE_CHAR1, ALMPROFILE_CHAR1_LEN, &g_ALMProfile_Char1Value);    // 初始化特征2    ALMProfile_SetParameter(ALMPROFILE_CHAR2, ALMPROFILE_CHAR2_LEN, &g_ALMProfile_Char2Value);    // 初始化特征3    ALMProfile_SetParameter(ALMPROFILE_CHAR3, ALMPROFILE_CHAR3_LEN, &g_ALMProfile_Char3Value);    // 注册ALM GATT Profile的回调函数    VOID ALMProfile_RegisterAppCBs(&simpleBLEPeripheral_ALMProfileCBs);}

5.3 定义服务的回调函数及处理函数

static void ALM_Profile_ChangeCB(uint8 paramId){       multi_role_enqueueMsg(MR_ALM_CHAR_CHANGE_EVT, paramId);}static void ALM_Profile_CharValueChangeEvt(uint8 paramId){       uint16 connHandle;    uint8 buffer[20] = {   0};    uint8* pValue = buffer;    // 判断是哪个特征值    switch(paramId)    {       // 特征值 1    case ALMPROFILE_CHAR1:    {           // 获取连接句柄,GAPROLE_CONNHANDLE在主从一体工程在multi.h中或从机工程在peripheral.h中        GAPRole_GetParameter(GAPROLE_CONNHANDLE, &connHandle);        // 写一个 20 字节的测试缓冲区的数据        for(uint8 i = 0; i < 20; i++)        {               *(pValue + i) = i;        }        // 发送数据        ALMProfile_Notify(ALMPROFILE_CHAR1, connHandle, pValue, 20);        break;    }    // 特征值 2    case ALMPROFILE_CHAR2:        break;    // 特征值 3    case ALMPROFILE_CHAR3:        break;    // 其他    default:        break;    }}

5.4 声明服务的回调函数和处理函数

static void ALM_Profile_ChangeCB(uint8 paramId);static void ALM_Profile_CharValueChangeEvt(uint8 paramId);

5.5 注册回调函数

static almProfileCBs_t simpleBLEPeripheral_ALMProfileCBs ={     ALM_Profile_ChangeCB    // Charactersitic value change callback};

5.6 添加自定义服务处理事件

① 添加自定义服务处理事件的宏定义

#define MR_ALM_CHAR_CHANGE_EVT               Event_Id_08

② 添加自定义服务处理事件的处理部分

例在multi_role.c的multi_role_processAppMsg函数中添加

case MR_ALM_CHAR_CHANGE_EVT:        ALM_Profile_CharValueChangeEvt(*(pMsg->pData));        break;

5.7 运行结果

参考 中实验结果部分


• 由 写于 2019 年 3 月 13 日

• 参考:

上一篇:解决方法:CC2640R2F从7x7改成5x5封装,主机连接失败
下一篇:CC2640R2F学习笔记(6)——UART串口使用

发表评论

最新留言

初次前来,多多关照!
[***.217.46.12]2025年03月10日 08时01分30秒