本章实验
实现char1具备 notify 通知属性、可发不定长特征值数据
特征值是什么?
特征值是一个变量或者一个数组,它被定义在 server 端,它是 client 端与 server 端之间传输数据的缓冲区
比如添加一个 char1[10],它的值初始化为 0.
当 char1 具有读、写属性时,client 端可以通过 GATT_ReadCharValue、GATT_WriteCharValue进行读、写 server 端的 char1。
当 char1 具有 notify 通知属性时,server 端可以将 char1 的值通知给 client 机。
修改步骤
- 修改 char1 的宏定义(在 simple_gatt_profile.h中部分)
#define SIMPLEPROFILE_CHAR1_LEN 10
extern uint8 charValue1[SIMPLEPROFILE_CHAR1_LEN];
extern bStatus_t UserProfile_Notify(uint8 param, uint8 *pValue, uint8 len);
- 修改char1 的相关参数 (在 simple_gatt_profile.c中部分)
uint8 charValue1[SIMPLEPROFILE_CHAR1_LEN] = {0}; // 特征1值
#define SERVAPP_NUM_ATTR_SUPPORTED 18 // 0~17
//属性在属性表中的偏移值
#define ATTRTBL_CHAR1_IDX 2 // 特征1在属性表的偏移值
#define ATTRTBL_CHAR1_CCC_IDX 3 // 特征1的notify开关在属性表的偏移值
#define ATTRTBL_CHAR4_IDX 12 // 特征4在属性表的偏移值
#define ATTRTBL_CHAR4_CCC_IDX 13 // 特征4的notify开关在属性表的偏移值
- 修改char1的配置属性
// Simple Profile Characteristic 1 Properties
static uint8 simpleProfileChar1Props = GATT_PROP_READ | GATT_PROP_WRITE | GATT_PROP_NOTIFY;
// Characteristic 1 Value
static uint8 simpleProfileChar1[SIMPLEPROFILE_CHAR1_LEN] = {0};
static gattCharCfg_t *simpleProfileChar1Config;
// Simple Profile Characteristic 1 User Description
static uint8 simpleProfileChar1UserDesp[17] = "Characteristic 1";
- 修改属性表(在simple_gatt_profile.c的simpleProfileAttrTbl数组中)
// Characteristic Value 1
{
{ ATT_BT_UUID_SIZE, simpleProfilechar1UUID },
GATT_PERMIT_READ | GATT_PERMIT_WRITE,
0,
simpleProfileChar1
},
// Characteristic 1 configuration
{
{ ATT_BT_UUID_SIZE, clientCharCfgUUID },
GATT_PERMIT_READ | GATT_PERMIT_WRITE,
0,
(uint8 *)&simpleProfileChar1Config
},
// Characteristic 1 User Description
{
{ ATT_BT_UUID_SIZE, charUserDescUUID },
GATT_PERMIT_READ,
0,
simpleProfileChar1UserDesp
},
- 修改char1 的通知开关初始化(在simple_gatt_profile.c的SimpleProfile_AddService函数中)
//只有通知属性的才需要初始化通知开关属性。
bStatus_t SimpleProfile_AddService( uint32 services )
{
uint8 status;
// Allocate Client Characteristic Configuration table
simpleProfileChar1Config = (gattCharCfg_t *)ICall_malloc( sizeof(gattCharCfg_t) *linkDBNumConns );
if ( simpleProfileChar1Config == NULL )
{
return ( bleMemAllocError );
}
simpleProfileChar4Config = (gattCharCfg_t *)ICall_malloc( sizeof(gattCharCfg_t) *linkDBNumConns );
if ( simpleProfileChar4Config == NULL )
{
return ( bleMemAllocError );
}
// Initialize Client Characteristic Configuration attributes
GATTServApp_InitCharCfg( INVALID_CONNHANDLE, simpleProfileChar1Config );
GATTServApp_InitCharCfg( INVALID_CONNHANDLE, simpleProfileChar4Config );
if ( services & SIMPLEPROFILE_SERVICE )
{
// Register GATT attribute list and CBs with GATT Server App
status = GATTServApp_RegisterService( simpleProfileAttrTbl, GATT_NUM_ATTRS( simpleProfileAttrTbl ),
GATT_MAX_ENCRYPT_KEY_SIZE,&simpleProfileCBs );
}
else
{
status = SUCCESS;
}
return ( status );
}
- 修改char1 的数值可设置的处理(在simple_gatt_profile.c的SimpleProfile_SetParameter函数中)
case SIMPLEPROFILE_CHAR1:
if ( len == SIMPLEPROFILE_CHAR1_LEN )
{
VOID memcpy( simpleProfileChar1, value, SIMPLEPROFILE_CHAR1_LEN );
}
else
{
ret = bleInvalidRange;
}
break;
- 修改char1 的数值可获取的处理(在simple_gatt_profile.c的SimpleProfile_GetParameter函数中)
case SIMPLEPROFILE_CHAR1:
VOID memcpy( value, simpleProfileChar1, SIMPLEPROFILE_CHAR1_LEN );
break;
- 修改 char1 的数值读取的处理(在simple_gatt_profile.c的simpleProfile_ReadAttrCB函数中)
case SIMPLEPROFILE_CHAR1_UUID:
*pLen = SIMPLEPROFILE_CHAR1_LEN;
VOID memcpy( pValue, pAttr->pValue, SIMPLEPROFILE_CHAR1_LEN );
break;
- 修改char1 的数值写入的处理(在simple_gatt_profile.c的simpleProfile_WriteAttrCB函数中)
static bStatus_t simpleProfile_WriteAttrCB(uint16_t connHandle,
gattAttribute_t *pAttr,
uint8_t *pValue, uint16_t len,
uint16_t offset, uint8_t method)
{
bStatus_t status = SUCCESS;
uint8 notifyApp = 0xFF;
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 SIMPLEPROFILE_CHAR1_UUID:
if ( offset == 0 )
{
if ( len > SIMPLEPROFILE_CHAR1_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, len );
notifyApp = SIMPLEPROFILE_CHAR1;
}
break;
case SIMPLEPROFILE_CHAR3_UUID:
//Validate the value
// Make sure it's not a blob oper
if ( offset == 0 )
{
if ( len != 1 )
{
status = ATT_ERR_INVALID_VALUE_SIZE;
}
}
else
{
status = ATT_ERR_ATTR_NOT_LONG;
}
//Write the value
if ( status == SUCCESS )
{
uint8 *pCurValue = (uint8 *)pAttr->pValue;
*pCurValue = pValue[0];
// if( pAttr->pValue == &simpleProfileChar1 )
// {
// notifyApp = SIMPLEPROFILE_CHAR1;
// }
// else
// {
notifyApp = SIMPLEPROFILE_CHAR3;
// }
}
break;
case GATT_CLIENT_CHAR_CFG_UUID:
//CHAR1 的通知开关
if(pAttr->handle == simpleProfileAttrTbl[ATTRTBL_CHAR1_CCC_IDX].handle)
{
status = GATTServApp_ProcessCCCWriteReq( connHandle, pAttr, pValue, len,
offset, GATT_CLIENT_CFG_NOTIFY );
}
//CHAR4 的通知开关
else if(pAttr->handle == simpleProfileAttrTbl[ATTRTBL_CHAR4_CCC_IDX].handle)
{
status = GATTServApp_ProcessCCCWriteReq( connHandle, pAttr, pValue, len,
offset, GATT_CLIENT_CFG_NOTIFY );
}
else
{
status = ATT_ERR_INVALID_HANDLE;
}
break;
default:
// Should never get here! (characteristics 2 and 4 do not have write permissions)
status = ATT_ERR_ATTR_NOT_FOUND;
break;
}
}
else //其他情况不打开通知开关
{
// 128-bit UUID
status = ATT_ERR_INVALID_HANDLE;
}
// If a characteristic value changed then callback function to notify application of change
if ( (notifyApp != 0xFF ) && simpleProfile_AppCBs && simpleProfile_AppCBs->pfnSimpleProfileChange )
{
simpleProfile_AppCBs->pfnSimpleProfileChange( notifyApp );
}
return ( status );
}
- 修改char1 的发送通知数据的函数(在simple_gatt_profile.c的UserProfile_Notify函数中)
bStatus_t UserProfile_Notify(uint8 param, uint8 *pValue, uint8 len)
{
attHandleValueNoti_t attHandleValueNoti;
gattCharCfg_t *pItem = simpleProfileChar1Config;
uint16 value;
bStatus_t ret = SUCCESS;
switch(param)
{
// 特征1
case SIMPLEPROFILE_CHAR1:
{
// 读出CCC
value = GATTServApp_ReadCharCfg(pItem->connHandle, simpleProfileChar1Config);
// 判断CCC是否被打开
if(value & GATT_CLIENT_CFG_NOTIFY)
{
// 分配发送数据缓冲区
attHandleValueNoti.pValue = GATT_bm_alloc(pItem->connHandle,
ATT_HANDLE_VALUE_NOTI,
SIMPLEPROFILE_CHAR1_LEN, NULL);
// 分配成功,则发送数据
if(attHandleValueNoti.pValue != NULL)
{
// 填充数据
attHandleValueNoti.handle = simpleProfileAttrTbl[ATTRTBL_CHAR1_IDX].handle;
attHandleValueNoti.len = len;
memcpy(attHandleValueNoti.pValue, pValue, len);
// 发送数据
if(GATT_Notification(pItem->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);
}
修改应用层
- 修改特征值初始化的数值(在simple_gatt_profile.c的SimpleBLEPeripheral_init函数中)
#ifndef FEATURE_OAD_ONCHIP
// Setup the SimpleProfile Characteristic Values
// For more information, see the sections in the User's Guide:
// http://software-dl.ti.com/lprf/ble5stack-docs-latest/html/ble-stack/gatt.html#
// http://software-dl.ti.com/lprf/ble5stack-docs-latest/html/ble-stack/gatt.html#gattservapp-module
{
uint8_t charValue2 = 2;
uint8_t charValue3 = 3;
uint8_t charValue4 = 4;
uint8_t charValue5[SIMPLEPROFILE_CHAR5_LEN] = { 1, 2, 3, 4, 5 };
SimpleProfile_SetParameter(SIMPLEPROFILE_CHAR1, sizeof(uint8_t),&charValue1);
SimpleProfile_SetParameter(SIMPLEPROFILE_CHAR2, sizeof(uint8_t),&charValue2);
SimpleProfile_SetParameter(SIMPLEPROFILE_CHAR3, sizeof(uint8_t),&charValue3);
SimpleProfile_SetParameter(SIMPLEPROFILE_CHAR4, sizeof(uint8_t),&charValue4);
SimpleProfile_SetParameter(SIMPLEPROFILE_CHAR5, SIMPLEPROFILE_CHAR5_LEN,charValue5);
}
- 发蓝牙数据
UserProfile_Notify(SIMPLEPROFILE_CHAR1,pValue,2);//蓝牙发送数据