蓝牙消息传输_GATT服务发现
- 1.主机和从机GATT服务的发现
- 2.通知的使用
1.主机和从机GATT服务的发现
GATT服务的发现由主机执行,一共三个阶段
1.处理交换 MTU 请求和响应,启动对 Simple Service 服务的发现。
if (discState == BLE_DISC_STATE_MTU){// MTU size response received, discover simple serviceif (pMsg->method == ATT_EXCHANGE_MTU_RSP){//获取主服务的UUIDuint8_t uuid[ATT_BT_UUID_SIZE] = { LO_UINT16(SIMPLEPROFILE_SERV_UUID),HI_UINT16(SIMPLEPROFILE_SERV_UUID) };discState = BLE_DISC_STATE_SVC;// 通过UUID寻找主服务----simple serviceVOID GATT_DiscPrimaryServiceByUUID(pMsg->connHandle, uuid,ATT_BT_UUID_SIZE, selfEntity);}}
2.处理发现服务的响应,并存储服务的开始和结束句柄。服务发现过程完成后,启动对特定特征(Characteristic)的发现。
else if (discState == BLE_DISC_STATE_SVC){// Service found, store handlesif (pMsg->method == ATT_FIND_BY_TYPE_VALUE_RSP &&pMsg->msg.findByTypeValueRsp.numInfo > 0){//存储服务的开始和结束句柄svcStartHdl = ATT_ATTR_HANDLE(pMsg->msg.findByTypeValueRsp.pHandlesInfo, 0);svcEndHdl = ATT_GRP_END_HANDLE(pMsg->msg.findByTypeValueRsp.pHandlesInfo, 0);}// If procedure completeif (((pMsg->method == ATT_FIND_BY_TYPE_VALUE_RSP) &&(pMsg->hdr.status == bleProcedureComplete)) ||(pMsg->method == ATT_ERROR_RSP)){if (svcStartHdl != 0){attReadByTypeReq_t req;// Discover characteristicdiscState = BLE_DISC_STATE_CHAR;req.startHandle = svcStartHdl;req.endHandle = svcEndHdl;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);//根据服务句柄范围和特征UUID,客户端发现服务器上的服务特征VOID GATT_DiscCharsByUUID(pMsg->connHandle, &req, selfEntity);}}}
3.处理发现特征的响应,并存储特征值的句柄。如果特征发现过程完成,触发相应的操作,比如启动通知。
else if (discState == BLE_DISC_STATE_CHAR){// Characteristic found, store handleif ((pMsg->method == ATT_READ_BY_TYPE_RSP) &&(pMsg->msg.readByTypeRsp.numPairs > 0)){//有多个连接时,获取连接句柄uint8_t connIndex = SimpleCentral_getConnIndex(scConnHandle);// connIndex cannot be equal to or greater than MAX_NUM_BLE_CONNSSIMPLECENTRAL_ASSERT(connIndex < MAX_NUM_BLE_CONNS);// Store the handle of the simpleprofile characteristic 1 value//获取特征句柄connList[connIndex].charHandle= BUILD_UINT16(pMsg->msg.readByTypeRsp.pDataList[3],pMsg->msg.readByTypeRsp.pDataList[4]);Display_printf(dispHandle, SC_ROW_CUR_CONN, 0, "Simple Svc Found");// Now we can use GATT Read/Writetbm_setItemStatus(&scMenuPerConn,SC_ITEM_GATTREAD | SC_ITEM_GATTWRITE, SC_ITEM_NONE);}discState = BLE_DISC_STATE_IDLE;}
通过GATT_Cilent调用三次SimpleCentral_processGATTDiscEvent(gattMsgEvent_t *pMsg)实现。
因为Handle是由协议栈分配的连续的,所以获取其中一个的Handle就能知道其它的。
区分特征与特征值,特征由特征值、特征声明、用户特征描述、客户特征配置组成,每个组成部分有各自的Handle值
比如与一个连接的两个通知类型的特征值进行数据发送时,获取了第一个特征值的句柄,存储在connList[i].charHandle中。
第一个特征的CCC为charHandle+1
第二个特征的CCC为charHandle+5
if(index ==SIMPLEPROFILE_CHAR1)
{req.handle = connList[i].charHandle+1;
}
else if(index ==SIMPLEPROFILE_CHAR2)
{req.handle = connList[i].charHandle+5;
}
主从机发送消息时,需要将APP的信息发送给协议栈来发送,所以APP的信息要和协议栈的信息在发送和接受时完成同步,APP中的消息类似于缓存。
2.通知的使用
主从消息传输可以通过通知的方式,Notification有两种使用情况,都是由从机发起的
1)GATT_Notification
用在通信时,由从机主动通知,且不需要主机发出请求和回应。
2)GATTServApp_ProcessCharCfg
用在通知启动时,需要主机发送一次“通知请求”给从机,从机收到“通知请求”才发送通知。
1.从机完成通知的初始化
// 分配客户端特征配置表simpleProfileChar4Config = (gattCharCfg_t *)ICall_malloc( sizeof(gattCharCfg_t) *MAX_NUM_BLE_CONNS );if ( simpleProfileChar4Config == NULL ){return ( bleMemAllocError );}// Initialize Client Characteristic Configuration attributes//初始化客户端特征配置表CCCGATTServApp_InitCharCfg( CONNHANDLE_INVALID, simpleProfileChar4Config );if ( services & SIMPLEPROFILE_SERVICE ){// Register GATT attribute list and CBs with GATT Server App//注册GATT属性列表和CBs与 GATT Server App回调函数status = GATTServApp_RegisterService( simpleProfileAttrTbl,GATT_NUM_ATTRS( simpleProfileAttrTbl ),GATT_MAX_ENCRYPT_KEY_SIZE,&simpleProfileCBs );}
在GATTServApp_InitCharCfg中,使用给定的 connHandle 在 charCfgTbl 中搜索,以找到与连接相关的特征配置项,并将该CCC初始化为GATT_CFG_NO_OPERATION0.
gattCharCfg_t *pItem = gattServApp_FindCharCfgItem( connHandle, charCfgTbl );if ( pItem != NULL ){pItem->connHandle = CONNHANDLE_INVALID;pItem->value = GATT_CFG_NO_OPERATION;}
2.从机/主机发送一次通知请求,从机开始发送通知,CCC设置为通知:GATT_CLIENT_CFG_NOTIFY
主机发送启动通知命令:
req.len = 2;req.pValue[0] = LO_UINT16(GATT_CLIENT_CFG_NOTIFY); //0x0001为开notify;req.pValue[1] = HI_UINT16(GATT_CLIENT_CFG_NOTIFY);req.sig = 0;req.cmd = 0;uint8_t status = GATT_WriteCharValue(connList[i].connHandle, &req, selfEntity);
从机启动通知:
status = GATTServApp_ProcessCCCWriteReq( connHandle, pAttr, pValue, len,offset, GATT_CLIENT_CFG_NOTIFY );