A:Notification连接后,从机向主机发送的数据包,不需要主机确认收到,适合大量数据快速发送。
从机 Notification发送方式有两种,用户根据自身要求选择:
(1)调用GATT_Notification( uint16 connHandle, attHandleValueNoti_t *pNoti, uint8 authenticated );直接发送
(2)调用GATTServApp_ProcessCharCfg函数,这个函数内部最终会导致master那边调用一个read请求,回调到simpleProfile_ReadAttrCB()。用这个函数,只有master向Peripheral的Notification允许位写1,才能使能从机,从而调用GATT_Notification向主机发送Notification。
//声明attHandleValueNoti_t这个结构体
static attHandleValueNoti_t pReport ;
//存放handle
uint16 noti_cHandle;
//读取notification对应的handle
pReport.handle = simpleProfileAttrTbl[11].handle;
//获取Connection Handle
GAPRole_GetParameter( GAPROLE_CONNHANDLE, ¬i_cHandle);
pReport.len = 1; //数据长度
pReport.value[0] = 0x03; //赋值
GATT_Notification(noti_cHandle,&pReport,FALSE);
//!< Connection Handle. Read Only. Size is uint16.
#define GAPROLE_CONNHANDLE 0x30E
//eg:
GAPRole_GetParameter( GAPROLE_CONNHANDLE, &gapConnHandle );
simpleBLECentral
1、添加notification的接收
simpleBLECentralProcessGATTMsg()
类似
if ( ( pMsg->method == ATT_READ_RSP ) || ........)
添加
else if ( ( pMsg->method == ATT_HANDLE_VALUE_NOTI ) ||......)
2、启用notification
simpleProfileAttrTbl 的位置12 是CHAR4 的Client Characteristic Configuration, 发Notification 之前, 通过master设备把这个值设置成 0x0001, 打开notification.这个handle应该是相应的characteristic value的handle的后面一个, 就是characteristic value的handle加 1 .
attWriteReq_t writeReq;
writeReq.handle = 0x002f;
writeReq.len = 2;
writeReq.value[0] = LO_UINT16(GATT_CLIENT_CFG_NOTIFY); //这里是 0x01
writeReq.value[1] = HI_UINT16(GATT_CLIENT_CFG_NOTIFY); //这里是 0x00
writeReq.sig = 0;
writeReq.cmd = 0;
GATT_WriteCharValue( simpleBLEConnHandle, &writeReq, simpleBLETaskId );
这两个值目的是打开Notification功能. CCC的参数有两个, 一个Notification, 一个indication. value[0]就是打开关闭notification, value[1]是打开关闭indication.
3、使用UUID获取simpleBLEConnHandle
a. simpleBLECentralStartDiscovery
b. simpleBLECentralProcessGATTMsg
-> simpleBLEGATTDiscoveryEvent
static void simpleBLECentralStartDiscovery( void )
{
uint8 uuid[ATT_BT_UUID_SIZE] = { LO_UINT16(SIMPLEPROFILE_SERV_UUID),
HI_UINT16(SIMPLEPROFILE_SERV_UUID) };
// Initialize cached handles
simpleBLESvcStartHdl = simpleBLESvcEndHdl = simpleBLECharHdl = 0;
simpleBLEDiscState = BLE_DISC_STATE_SVC;
// Discovery simple BLE service
GATT_DiscPrimaryServiceByUUID( simpleBLEConnHandle,
uuid,
ATT_BT_UUID_SIZE,
simpleBLETaskId );
}
static void simpleBLEGATTDiscoveryEvent( gattMsgEvent_t *pMsg )
{
attReadByTypeReq_t req;
if ( simpleBLEDiscState == BLE_DISC_STATE_SVC )
{
// Service found, store handles
if ( pMsg->method == ATT_FIND_BY_TYPE_VALUE_RSP &&
pMsg->msg.findByTypeValueRsp.numInfo > 0 )
{
simpleBLESvcStartHdl = pMsg->msg.findByTypeValueRsp.handlesInfo[0].handle;
simpleBLESvcEndHdl = pMsg->msg.findByTypeValueRsp.handlesInfo[0].grpEndHandle;
}
// If procedure complete
if ( ( pMsg->method == ATT_FIND_BY_TYPE_VALUE_RSP &&
pMsg->hdr.status == bleProcedureComplete ) ||
( pMsg->method == ATT_ERROR_RSP ) )
{
if ( simpleBLESvcStartHdl != 0 )
{
// Discover characteristic
simpleBLEDiscState = BLE_DISC_STATE_CHAR;
req.startHandle = simpleBLESvcStartHdl;
req.endHandle = simpleBLESvcEndHdl;
req.type.len = ATT_BT_UUID_SIZE;
req.type.uuid[0] = LO_UINT16(SIMPLEPROFILE_CHAR1_UUID);
req.type.uuid[1] = HI_UINT16(SIMPLEPROFILE_CHAR1_UUID);
GATT_ReadUsingCharUUID( simpleBLEConnHandle, &req, simpleBLETaskId );
}
}
}
else if ( simpleBLEDiscState == BLE_DISC_STATE_CHAR )
{
// Characteristic found, store handle
if ( pMsg->method == ATT_READ_BY_TYPE_RSP &&
pMsg->msg.readByTypeRsp.numPairs > 0 )
{
simpleBLECharHdl = BUILD_UINT16( pMsg->msg.readByTypeRsp.dataList[0],
pMsg->msg.readByTypeRsp.dataList[1] );
LCD_WRITE_STRING( "Simple Svc Found", HAL_LCD_LINE_1 );
simpleBLEProcedureInProgress = FALSE;
}
simpleBLEDiscState = BLE_DISC_STATE_IDLE;
}
}
simpleBLEPeripheral
simpleGATTProfile.c
里面有个SimpleProfile_SetParameter(), 这个就是间隔性被调用的函数.里面有
case SIMPLEPROFILE_CHAR4:
调用
GATTServApp_ProcessCharCfg()
这个函数内部最终会回调到
simpleProfile_ReadAttrCB()
1、SimpleProfile_SetParameter
SimpleProfile_SetParameter( uint8 param, uint8 len, void *value ){
case SIMPLEPROFILE_CHAR4:
if ( len == sizeof ( uint8 ) )
{
simpleProfileChar4 = *((uint8*)value);
// See if Notification has been enabled
GATTServApp_ProcessCharCfg( simpleProfileChar4Config, &simpleProfileChar4, FALSE,
simpleProfileAttrTbl, GATT_NUM_ATTRS( simpleProfileAttrTbl ),
INVALID_TASK_ID );
}
else
{
ret = bleInvalidRange;
}
break;
}
2、simpleProfile_ReadAttrCB()
simpleProfile_ReadAttrCB( uint16 connHandle, gattAttribute_t *pAttr,
uint8 *pValue, uint8 *pLen, uint16 offset, uint8 maxLen ){
case SIMPLEPROFILE_CHAR4_UUID:
*pLen = 1;
pValue[0] = *pAttr->pValue;
break;
}