測試環境
協定棧版本: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測試工具進行連接配接測試了,通過測試,配置正确,大家可以試一下。