CC2640之添加一个自定义的特性值
测试环境
协议栈版本:BLE-STACK V2.1
IAR开发环境版本:IAR for Arm 7.40
硬件设备:Amo-SmartRF v2.0 开发板(对应TI官方的SmartRF06EB 开发板)
示例测试Demo工程:simpleBLEPeripheral工程
添加自定义特征值
我们今天一起来了解下,如何在一个现有的profile中添加一个自定义的特征值,而且该特征值具有读、写和通知权限。下面的讲解中,我们以“simpleBLEPeripheral”工程为例,来了解如何在其现有的profile中,添加一个具有读、写和通知功能的特征值char6。
首先,我们先了解下“simpleBLEPeripheral”工程原有的服务和特征值,该工程本身有4个服务,其中“Simple Profile Service”服务是我们可以添加自定义特征值的,该服务本身有5个特征值,UUID分别为FFF1,FFF2,FFF3,FFF4,FFF5,下面我们来实际看一下如何添加一个特征值char6,UUID为FFF6。
1.在“C:\ti\simplelink\ble_cc26xx_2_01_00_44423\Projects\ble\Profiles\SimpleProfile”目录下找到“simpleGATTprofile.h”文件,我们先在这个文件中定义我们要添加的新的特征值的一些声明:
- #define SIMPLEPROFILE_CHAR6 5 // RW uint8 - Profile Characteristic 6 value
- #define SIMPLEPROFILE_CHAR6_UUID 0xFFF6
- // Length of Characteristic 6 in bytes
- #define SIMPLEPROFILE_CHAR6_LEN 19
- // Position of simple char6 value in attribute array
- // char6特性在属性表中的位置,根据实际情况而定,协议栈中的demo添加之后分别是18,19
- #define SIMPLE_MEAS6_VALUE_POS 18
- #define SIMPLE_MEAS6_CCC_POS 19
2.在“C:\ti\simplelink\ble_cc26xx_2_01_00_44423\Projects\ble\Profiles\SimpleProfile\CC26xx”目录下找到“simpleGATTprofile.c”文件。
(1)在该文件全局变量声明UUID的地方,声明我们新添加的特征值的UUID:
- // Characteristic 6 UUID: 0xFFF6
- CONST uint8 simpleProfilechar6UUID[ATT_BT_UUID_SIZE] =
- {
- LO_UINT16(SIMPLEPROFILE_CHAR6_UUID), HI_UINT16(SIMPLEPROFILE_CHAR6_UUID)
- };
(2)在该文件内部变量声明的地方,声明一下我们要添加的新特征值char6的相关变量:
- // Simple Profile Characteristic 6 Properties
- static uint8 simpleProfileChar6Props = GATT_PROP_READ | GATT_PROP_WRITE_NO_RSP | GATT_PROP_NOTIFY;
- // Characteristic 6 Value
- static uint8 simpleProfileChar6[SIMPLEPROFILE_CHAR6_LEN] = { 0, 0, 0, 0, 0 };
- static uint8 simpleProfileChar6Len = 0;
- // Simple Profile Characteristic 6 Configuration Each client has its own
- // instantiation of the Client Characteristic Configuration. Reads of the
- // Client Characteristic Configuration only shows the configuration for
- // that client and writes only affect the configuration of that client.
- static gattCharCfg_t *simpleProfileChar6Config;
- // Simple Profile Characteristic 6 User Description
- static uint8 simpleProfileChar6UserDesp[17] = "Characteristic 6";
(3)在该Profile的属性表
“static gattAttribute_t simpleProfileAttrTbl[SERVAPP_NUM_ATTR_SUPPORTED] =”
中添加char6相关配置,添加的代码如下:
- // 17 Characteristic 6 Declaration
- {
- { ATT_BT_UUID_SIZE, characterUUID },
- GATT_PERMIT_READ,
- 0,
- &simpleProfileChar6Props
- },
- // 18 Characteristic Value 6
- {
- { ATT_BT_UUID_SIZE, simpleProfilechar6UUID },
- GATT_PERMIT_READ | GATT_PERMIT_WRITE,
- 0,
- simpleProfileChar6
- },
- // 19 Characteristic 6 configuration
- {
- { ATT_BT_UUID_SIZE, clientCharCfgUUID },
- GATT_PERMIT_READ | GATT_PERMIT_WRITE,
- 0,
- (uint8 *)&simpleProfileChar6Config
- },
- // 20 Characteristic 6 User Description
- {
- { ATT_BT_UUID_SIZE, charUserDescUUID },
- GATT_PERMIT_READ,
- 0,
- simpleProfileChar6UserDesp
- },
上面代码注释上的标号,是我自己标的,也就是属性表数组的下标,注意是从0开始,上述注释的下标就跟我之前头文件中定义的SIMPLE_MEAS6_VALUE_POS和SIMPLE_MEAS6_CCC_POS的值相对应。
因为增加了这4个数组成员,所以属性表“SERVAPP_NUM_ATTR_SUPPORTED”的值需要由原来的17修改为21,如下:
- /*********************************************************************
- * CONSTANTS
- */
- #define SERVAPP_NUM_ATTR_SUPPORTED 21//17
(4)新添加的特征值char6具有通知功能,所以,我们需要在“SimpleProfile_AddService”函数中进行相应的初始化配置操作:
- // Allocate Client Characteristic Configuration table
- simpleProfileChar6Config = (gattCharCfg_t *)ICall_malloc( sizeof(gattCharCfg_t) *linkDBNumConns );
- if ( simpleProfileChar6Config == NULL )
- {
- // Free already allocated data
- ICall_free( simpleProfileChar6Config );
- return ( bleMemAllocError );
- }
- ......
- GATTServApp_InitCharCfg( INVALID_CONNHANDLE, simpleProfileChar6Config );
(5)“SimpleProfile_SetParameter”方法中参考其他特征值的配置,添加如下代码:
- case SIMPLEPROFILE_CHAR6:
- if ( len <= SIMPLEPROFILE_CHAR6_LEN )
- {
- VOID memcpy( simpleProfileChar6, value, len );
- simpleProfileChar6Len = len;
- // See if Notification has been enabled
- GATTServApp_ProcessCharCfg( simpleProfileChar6Config, simpleProfileChar6, FALSE,
- simpleProfileAttrTbl, GATT_NUM_ATTRS( simpleProfileAttrTbl ),
- INVALID_TASK_ID, simpleProfile_ReadAttrCB );
- }
- else
- {
- ret = bleInvalidRange;
- }
- break;
(6)“SimpleProfile_GetParameter”方法中参考其他特征值的配置,添加新特征值的相关配置:
- case SIMPLEPROFILE_CHAR6:
- VOID memcpy( value, simpleProfileChar6, simpleProfileChar6Len );
- break;
(7)“simpleProfile_ReadAttrCB”函数是调用读之后的回调函数,在其中添加新特征值的相应处理:
- case SIMPLEPROFILE_CHAR6_UUID:
- *pLen = SIMPLEPROFILE_CHAR6_LEN;
- VOID memcpy( pValue, pAttr->pValue, SIMPLEPROFILE_CHAR6_LEN );
- break;
(8)“simpleProfile_WriteAttrCB”函数是调用写操作之后的回调函数,在其中添加新特征值的相应处理:
- case SIMPLEPROFILE_CHAR6_UUID:
- if ( offset == 0 )
- {
- if ( len > SIMPLEPROFILE_CHAR6_LEN )
- {
- status = ATT_ERR_INVALID_VALUE_SIZE;
- }
- }
- else
- {
- status = ATT_ERR_ATTR_NOT_LONG;
- }
- //Write the value
- if ( status == SUCCESS )
- {
- VOID memcpy( pAttr->pValue, pValue, SIMPLEPROFILE_CHAR6_LEN );
- //VOID memcpy( pAttr->pValue, pValue, len );
- //simpleProfileChar6Len = len;
- notifyApp = SIMPLEPROFILE_CHAR6;
- //tx_printf("pValue:%s",pAttr->pValue);
- }
- break;
(9)我们在该文件中封装一个通过通知功能发送数据的接口函数,源码如下:
- /*********************************************************************
- * @fn SimpleProfile_Notification
- *
- * @brief Send a notification containing a ir value
- *
- * @param connHandle - connection handle
- * @param pNoti - pointer to notification structure
- *
- * @return Success or Failure
- */
- bStatus_t SimpleProfile_Notification( uint16 connHandle, attHandleValueNoti_t *pNoti )
- {
- uint16 value = GATTServApp_ReadCharCfg( connHandle, simpleProfileChar6Config );
- // If notifications is enabled
- if ( value & GATT_CLIENT_CFG_NOTIFY )
- {
- // Set the handle
- pNoti->handle = simpleProfileAttrTbl[SIMPLE_MEAS6_VALUE_POS].handle;
- // Send the notification
- return GATT_Notification( connHandle, pNoti, FALSE );
- }
- return bleIncorrectMode;
- }
打开“C:\ti\simplelink\ble_cc26xx_2_01_00_44423\Projects\ble\Profiles\SimpleProfile”目录下的“simpleGATTprofile.h”文件,在其中添加该通知功能接口的声明,便于外部调用:
- /*********************************************************************
- * @fn SimpleProfile_Notification
- *
- * @brief Send a notification containing a ir value
- *
- * @param connHandle - connection handle
- * @param pNoti - pointer to notification structure
- *
- * @return Success or Failure
- */
- extern bStatus_t SimpleProfile_Notification( uint16 connHandle, attHandleValueNoti_t *pNoti );
3.经过上面的配置,我们就在Profile中添加了自定义的特征值char6,下面我们在应用文件中添加测试程序,进行相应测试。
(1)定义两个内部变量,通知功能使用的变量以及连接句柄的变量:
- static attHandleValueNoti_t simpleValue;
- // GAP connection handle
- static uint16 gapConnHandle;
(2)在初始化函数“SimpleBLEPeripheral_init”中对新添加的特征值char6进行初始化:
- uint8_t charValue6[SIMPLEPROFILE_CHAR6_LEN] = { 1, 2, 3, 4, 5 };
- SimpleProfile_SetParameter(SIMPLEPROFILE_CHAR6, SIMPLEPROFILE_CHAR6_LEN,charValue6);
(3)在连接成功的回调函数“SimpleBLEPeripheral_processStateChangeEvt”中添加连接句柄获取的代码:
- GAPRole_GetParameter( GAPROLE_CONNHANDLE, &gapConnHandle );
截图如下:
(4)然后,在写操作回调函数“SimpleBLEPeripheral_processCharValueChangeEvt”中添加char6写操作之后的处理代码:
- case SIMPLEPROFILE_CHAR6:
- SimpleProfile_GetParameter(SIMPLEPROFILE_CHAR6, &newValue);
- LCD_WRITE_STRING_VALUE("Char 6:", (uint16_t)newValue, 16, LCD_PAGE4);
- break;
(5)最后在定期执行的事件中添加通知功能发送数据的操作代码,为了便于测试,我们直接在“SimpleBLEPeripheral_performPeriodicTask”定时执行的函数中将之前的函数内容屏蔽掉,添加如下测试代码:
- simpleValue.pValue = GATT_bm_alloc(gapConnHandle,
- ATT_HANDLE_VALUE_NOTI,
- SIMPLEPROFILE_CHAR6_LEN, NULL);
- if(simpleValue.pValue != NULL)
- {
- uint8_t *p = simpleValue.pValue;
- *p++ = 0x11;
- *p++ = 0x22;
- *p++ = 0x33;
- *p++ = 0x44;
- simpleValue.len = (uint8_t)(p - simpleValue.pValue);
- //tx_printf("notify\r\n");
- if(SimpleProfile_Notification(gapConnHandle,&simpleValue) != SUCCESS)
- {
- GATT_bm_free((gattMsg_t *)&simpleValue, ATT_HANDLE_VALUE_NOTI);
- }
- }
通过上面的应用层设置和调用,我们就可以烧录到板子中通过手机的BLE测试工具进行连接测试了,通过测试,配置正确,大家可以试一下。