前面使用CH582作为GATT服务器,实现了read和write的操作,这两个操作都是客户端主动发起的。而服务器使用notify的方式则能主动的上传数据。本文介绍如何通过CH582作为服务器,如何通过notify上传数据。
具有notify权限的特征需要多一个属性:客户特征配置 。这个属性需要具有读写权限,其作用是:用于客户端配置服务器的这个特征是否notify的。因此具有notify权限的特征需要包含以下属性:
- 特征声明
- 特征值
- 客户特征配置
- 特征用户描述(可选)
本实例仍然是在"BLE-Peripheral"工程中修改代码。实现notify功能主要包括以下步骤:
- 在属性表中增加相关的特征
- 实现特征的客户配置文件初始化
- 实现notify发送函数,并加入到定时发送的函数中
1.在属性表中增加相关的特征
static uint8 simpleProfileChar8Props = GATT_PROP_NOTIFY;
static uint8 simpleProfileChar8[SIMPLEPROFILE_CHAR8_LEN] = { 0 }; /*存放特征值的缓存区*/
static gattCharCfg_t simpleProfileChar8Config[4];/*保存客户配置信息,用于客户特征配置属性*/
static uint8 simpleProfileChar8UserDesp[] = "Characteristic 8\0";
/*在属性表中添加*/
// Characteristic 8 Declaration
{
{ ATT_BT_UUID_SIZE, characterUUID },
GATT_PERMIT_READ,
0,
&simpleProfileChar8Props
},
// Characteristic Value 8
{
{ ATT_BT_UUID_SIZE, simpleProfilechar8UUID },
0,
0,
simpleProfileChar8
},
// Characteristic 8 configuration
{
{ ATT_BT_UUID_SIZE, clientCharCfgUUID },
GATT_PERMIT_READ | GATT_PERMIT_WRITE,
0,
(uint8 *)simpleProfileChar8Config
},
// Characteristic 8 User Description
{
{ ATT_BT_UUID_SIZE, charUserDescUUID },
GATT_PERMIT_READ,
0,
simpleProfileChar8UserDesp
},
2.实现特征的客户配置文件初始化
在bStatus_t SimpleProfile_AddService( uint32 services )
函数中增加对“客户特征配置”属性中的值的初始化,GATTServApp_InitCharCfg(INVALID_CONNHANDLE,simpleProfileChar8Config);
。
同时,还要在连接断开的回调函数中增加上面的初始化函数。
完整的 bStatus_t SimpleProfile_AddService( uint32 services )
如下:
bStatus_t SimpleProfile_AddService( uint32 services )
{
uint8 status = SUCCESS;
// Initialize Client Characteristic Configuration attributes
GATTServApp_InitCharCfg( INVALID_CONNHANDLE, simpleProfileChar4Config );
GATTServApp_InitCharCfg(INVALID_CONNHANDLE,simpleProfileChar8Config);/*新增加的用于初始化“客户特征配置”属性中的值*/
// Register with Link DB to receive link status change callback
linkDB_Register( simpleProfile_HandleConnStatusCB );
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 );
}
return ( status );
}
而连接断开的回调函数就是上面代码中的 simpleProfile_HandleConnStatusCB
。其完整代码如下:
static void simpleProfile_HandleConnStatusCB( uint16 connHandle, uint8 changeType )
{
// Make sure this is not loopback connection
if ( connHandle != LOOPBACK_CONNHANDLE )
{
// Reset Client Char Config if connection has dropped
if ( ( changeType == LINKDB_STATUS_UPDATE_REMOVED ) ||
( ( changeType == LINKDB_STATUS_UPDATE_STATEFLAGS ) &&
( !linkDB_Up( connHandle ) ) ) )
{
GATTServApp_InitCharCfg( connHandle, simpleProfileChar4Config );
GATTServApp_InitCharCfg( connHandle, simpleProfileChar8Config );
}
}
}
3. 实现notify发送函数,并加入到定时发送的函数中
//function at peripheral.c
static void periphercalChar8Notify(uint8_t *pValue,uint16_t len)
{
attHandleValueNoti_t noti;
noti.len = len;
noti.pValue = GATT_bm_alloc( peripheralConnList.connHandle, ATT_HANDLE_VALUE_NOTI, noti.len, NULL, 0 );
if( noti.pValue )
{
tmos_memcpy( noti.pValue, pValue, noti.len );
if(get_simple_profile_notify_8(peripheralConnList.connHandle, ¬i)!= SUCCESS){
GATT_bm_free( (gattMsg_t *)¬i, ATT_HANDLE_VALUE_NOTI );
}
}
}
//function at gattprofile.c
bStatus_t get_simple_profile_notify_8(uint16 connHandle,attHandleValueNoti_t *pNoti)
{
uint16 value = GATTServApp_ReadCharCfg( connHandle, simpleProfileChar8Config );
bStatus_t status=0;
if ( value & GATT_CLIENT_CFG_NOTIFY )
{
pNoti->handle = simpleProfileAttrTbl[22].handle;
status = GATT_Notification( connHandle, pNoti, FALSE );
PRINT("NOTIFY_8_1 0x%02Xn",status);
return status;
}
return bleIncorrectMode;
}
注意上面的两个函数没有在一个文件中。函数 bStatus_t get_simple_profile_notify_8(uint16 connHandle,attHandleValueNoti_t *pNoti)
和属性表在同一个文件中,这个函数的主要作用是得到特征值的handle,然后调用 GATT_Notification( connHandle, pNoti, FALSE );
将数据发送出去。
这里还要注意一下 GATT_Notification( connHandle, pNoti, FALSE );
的第2个参数必须是通过函数 GATT_bm_alloc( peripheralConnList.connHandle, ATT_HANDLE_VALUE_NOTI, noti.len, NULL, 0 );
动态申请的内存才能正常工作,否则的话会导致连接一直断开的情况。
下一步就是将发送函数加入到定时发送的函数中,定时发送是用的TMOS。
static void performPeriodicTask( void )
{
uint8 notiData[SIMPLEPROFILE_CHAR4_LEN] = { 0x88 };
uint8_t n8_data[SIMPLEPROFILE_CHAR8_LEN] = {0x12,0x34};
n8_data[0] = my_count;
peripheralChar4Notify( notiData, SIMPLEPROFILE_CHAR4_LEN );
periphercalChar8Notify(n8_data,SIMPLEPROFILE_CHAR8_LEN);
}
4. 效果
从下图中可以看出,当打卡notify后,开始主动上传数据。