本帖最后由 lilijin1995 于 2023-3-14 14:34 编辑
背景:
之前有使用过Multicentral还是之前的CH58x_BLE_LIB_V1.41版本,连接两个其他品牌蓝牙芯片FR8012HAQ从机,是可以直接接收到两个从机的notify的。现在两个从机都改成CH582了。然后连接之后,只收到了先连接的那个从机的noti,然后一看Multicentral,只实现了连接0的:如下图
一开始我也是想直接添加连接1的,但第一次添加的时候我应该是忘记调用了,然后才没有成功,我还特意找了WCH的FAE问了,是直接根据连接0的重写一遍就行。
软件说明:
添加连接1的处理之前,我们先来看看BLE Central是怎么启动的:
void Central_Init()
{
centralTaskId = TMOS_ProcessEventRegister(Central_ProcessEvent);
// Setup GAP
GAP_SetParamValue(TGAP_DISC_SCAN, DEFAULT_SCAN_DURATION);
GAP_SetParamValue(TGAP_CONN_EST_INT_MIN, DEFAULT_MIN_CONNECTION_INTERVAL);
GAP_SetParamValue(TGAP_CONN_EST_INT_MAX, DEFAULT_MAX_CONNECTION_INTERVAL);
GAP_SetParamValue(TGAP_CONN_EST_SUPERV_TIMEOUT, DEFAULT_CONNECTION_TIMEOUT);
// Setup the GAP Bond Manager
{
uint32_t passkey = DEFAULT_PASSCODE;
uint8_t pairMode = DEFAULT_PAIRING_MODE;
uint8_t mitm = DEFAULT_MITM_MODE;
uint8_t ioCap = DEFAULT_IO_CAPABILITIES;
uint8_t bonding = DEFAULT_BONDING_MODE;
GAPBondMgr_SetParameter(GAPBOND_CENT_DEFAULT_PASSCODE, sizeof(uint32_t), &passkey);
GAPBondMgr_SetParameter(GAPBOND_CENT_PAIRING_MODE, sizeof(uint8_t), &pairMode);
GAPBondMgr_SetParameter(GAPBOND_CENT_MITM_PROTECTION, sizeof(uint8_t), &mitm);
GAPBondMgr_SetParameter(GAPBOND_CENT_IO_CAPABILITIES, sizeof(uint8_t), &ioCap);
GAPBondMgr_SetParameter(GAPBOND_CENT_BONDING_ENABLED, sizeof(uint8_t), &bonding);
}
// Init Connection Item
centralInitConnItem(centralTaskId, centralConnList);
// Initialize GATT Client
GATT_InitClient();
// Register to receive incoming ATT Indications/Notifications
GATT_RegisterForInd(centralTaskId);
// Setup a delayed profile startup
tmos_set_event(centralTaskId, START_DEVICE_EVT);
}
wch的BLE协议实现好像都是基于TMOS的,在Central_Init这个我们看到最后一行代码这里tmos_set_event(centralTaskId, START_DEVICE_EVT)直接启动设备启动事件,我们直接看事件回调函数Central_ProcessEvent里面的START_DEVICE_EVTuint16_t Central_ProcessEvent(uint8_t task_id, uint16_t events)
{
if(events & SYS_EVENT_MSG)
{
uint8_t *pMsg;
if((pMsg = tmos_msg_receive(centralTaskId)) != NULL)
{
central_ProcessTMOSMsg((tmos_event_hdr_t *)pMsg);
// Release the TMOS message
tmos_msg_deallocate(pMsg);
}
// return unprocessed events
return (events ^ SYS_EVENT_MSG);
}
if(events & START_DEVICE_EVT)
{
// Start the Device
GAPRole_CentralStartDevice(centralTaskId, ¢ralBondCB, ¢ralRoleCB);
return (events ^ START_DEVICE_EVT);
}
}
在GAPRole_CentralStartDevice(centralTaskId, ¢ralBondCB, ¢ralRoleCB)里面又实现了
绑定管理回调函数:
// Bond Manager Callbacks
static gapBondCBs_t centralBondCB = {
centralPasscodeCB,
centralPairStateCB
};
以及GAP角色回调函数
// GAP Role Callbacks
static gapCentralRoleCB_t centralRoleCB = {
centralRssiCB, // RSSI callback
centralEventCB, // Event callback
centralHciMTUChangeCB // MTU change callback
};
centralEventCB这个事件回调函数里面全是GAP连接相关的事件的处理,GAP连接相关的事件可以CH58xBLE_LIB.h里面找到#define GAP_DEVICE_INIT_DONE_EVENT 0x00 //!< Sent when the Device Initialization is complete. This event is sent as an tmos message defined as gapDeviceInitDoneEvent_t.
#define GAP_DEVICE_DISCOVERY_EVENT 0x01 //!< Sent when the Device Discovery Process is complete. This event is sent as an tmos message defined as gapDevDiscEvent_t.
#define GAP_ADV_DATA_UPDATE_DONE_EVENT 0x02 //!< Sent when the Advertising Data or SCAN_RSP Data has been updated. This event is sent as an tmos message defined as gapAdvDataUpdateEvent_t.
#define GAP_MAKE_DISCOVERABLE_DONE_EVENT 0x03 //!< Sent when the Make Discoverable Request is complete. This event is sent as an tmos message defined as gapMakeDiscoverableRspEvent_t.
#define GAP_END_DISCOVERABLE_DONE_EVENT 0x04 //!< Sent when the Advertising has ended. This event is sent as an tmos message defined as gapEndDiscoverableRspEvent_t.
#define GAP_LINK_ESTABLISHED_EVENT 0x05 //!< Sent when the Establish Link Request is complete. This event is sent as an tmos message defined as gapEstLinkReqEvent_t.
#define GAP_LINK_TERMINATED_EVENT 0x06 //!< Sent when a connection was terminated. This event is sent as an tmos message defined as gapTerminateLinkEvent_t.
#define GAP_LINK_PARAM_UPDATE_EVENT 0x07 //!< Sent when an Update Parameters Event is received. This event is sent as an tmos message defined as gapLinkUpdateEvent_t.
我们在GAP_DEVICE_INFO_EVENT里面过滤一下"Simple Peripheral"广播的peripheral如下代码:
case GAP_DEVICE_INFO_EVENT:
{
// Add device to list
if(strstr(pEvent->deviceInfo.pEvtData,"Simple Peripheral")!=NULL)
{
PRINT("%s\r\n",pEvent->deviceInfo.pEvtData);
centralAddDeviceInfo(pEvent->deviceInfo.addr, pEvent->deviceInfo.addrType);
}
// // Add device to list
// centralAddDeviceInfo(pEvent->deviceInfo.addr, pEvent->deviceInfo.addrType);
}
这样MultiCentral就只添加Simple Peripheral了。
接着修改对端设备地址,根据MAC连接的,并且我们只需要2个外设设备,所以这里修改一下对端设备地址和连接数:
#ifndef CENTRAL_MAX_CONNECTION
#define CENTRAL_MAX_CONNECTION 2
#endif
// Peer device address
static peerAddrDefItem_t PeerAddrDef[CENTRAL_MAX_CONNECTION] = {
{0x3d, 0x61, 0x85, 0x26, 0x3b, 0x38 },
{0x34, 0x53, 0x24, 0x7b, 0x54, 0x50 }
};
GAP_LINK_ESTABLISHED_EVENT是建立连接的事件,在这里wch已经实现了连接0的了,如下: // 连接0
if(connItem == CONNECT0_ITEM)
{
centralConnList[connItem].procedureInProgress = TRUE;
// Initiate service discovery
tmos_start_task(centralConnList[connItem].taskID, START_SVC_DISCOVERY_EVT, DEFAULT_SVC_DISCOVERY_DELAY);
// Initiate connect parameter update
tmos_start_task(centralConnList[connItem].taskID, START_PARAM_UPDATE_EVT, DEFAULT_PARAM_UPDATE_DELAY);
// Start RSSI polling
tmos_start_task(centralConnList[connItem].taskID, START_READ_RSSI_EVT, DEFAULT_RSSI_PERIOD);
}
这里直接复制连接0的即可: // 连接1
else if(connItem == CONNECT1_ITEM)
{
centralConnList[connItem].procedureInProgress = TRUE;
// Initiate service discovery
tmos_start_task(centralConnList[connItem].taskID, START_SVC_DISCOVERY_EVT, DEFAULT_SVC_DISCOVERY_DELAY);
// Initiate connect parameter update
tmos_start_task(centralConnList[connItem].taskID, START_PARAM_UPDATE_EVT, DEFAULT_PARAM_UPDATE_DELAY);
// Start RSSI polling
tmos_start_task(centralConnList[connItem].taskID, START_READ_RSSI_EVT, DEFAULT_RSSI_PERIOD);
}
我们可以看到,这里启动了发现服务,参数更新,RSSI任务,那我们对应的也需要修改一下。连接0的是connect0_ProcessEvent处理的,那么我们直接复制修改如下:
static uint16_t connect1_ProcessEvent(uint8_t task_id, uint16_t events)
{
if(events & START_SVC_DISCOVERY_EVT)
{
// start service discovery
centralConnIistStartDiscovery_1();
return (events ^ START_SVC_DISCOVERY_EVT);
}
if(events & START_READ_OR_WRITE_EVT)
{
if(centralConnList[CONNECT1_ITEM].procedureInProgress == FALSE)
{
if(centralDoWrite)
{
// Do a write
attWriteReq_t req;
req.cmd = FALSE;
req.sig = FALSE;
req.handle = centralConnList[CONNECT1_ITEM].charHdl;
req.len = 1;
req.pValue = GATT_bm_alloc(centralConnList[CONNECT1_ITEM].connHandle, ATT_WRITE_REQ, req.len, NULL, 0);
if(req.pValue != NULL)
{
*req.pValue = centralCharVal;
if(GATT_WriteCharValue(centralConnList[CONNECT1_ITEM].connHandle, &req, centralTaskId) == SUCCESS)
{
centralConnList[CONNECT1_ITEM].procedureInProgress = TRUE;
centralDoWrite = !centralDoWrite;
tmos_start_task(centralConnList[CONNECT1_ITEM].taskID, START_READ_OR_WRITE_EVT, DEFAULT_READ_OR_WRITE_DELAY);
}
else
{
GATT_bm_free((gattMsg_t *)&req, ATT_WRITE_REQ);
}
}
}
else
{
// Do a read
attReadReq_t req;
req.handle = centralConnList[CONNECT1_ITEM].charHdl;
if(GATT_ReadCharValue(centralConnList[CONNECT1_ITEM].connHandle, &req, centralTaskId) == SUCCESS)
{
centralConnList[CONNECT1_ITEM].procedureInProgress = TRUE;
centralDoWrite = !centralDoWrite;
}
}
}
return (events ^ START_READ_OR_WRITE_EVT);
}
if(events & START_PARAM_UPDATE_EVT)
{
// start connect parameter update
GAPRole_UpdateLink(centralConnList[CONNECT1_ITEM].connHandle,
DEFAULT_UPDATE_MIN_CONN_INTERVAL,
DEFAULT_UPDATE_MAX_CONN_INTERVAL,
DEFAULT_UPDATE_SLAVE_LATENCY,
DEFAULT_UPDATE_CONN_TIMEOUT);
return (events ^ START_PARAM_UPDATE_EVT);
}
if(events & START_WRITE_CCCD_EVT)
{
if(centralConnList[CONNECT1_ITEM].procedureInProgress == FALSE)
{
// Do a write
attWriteReq_t req;
req.cmd = FALSE;
req.sig = FALSE;
req.handle = centralConnList[CONNECT1_ITEM].cccHdl;
req.len = 2;
req.pValue = GATT_bm_alloc(centralConnList[CONNECT1_ITEM].connHandle, ATT_WRITE_REQ, req.len, NULL, 0);
if(req.pValue != NULL)
{
req.pValue[0] = 1;
req.pValue[1] = 0;
if(GATT_WriteCharValue(centralConnList[CONNECT1_ITEM].connHandle, &req, centralTaskId) == SUCCESS)
{
centralConnList[CONNECT1_ITEM].procedureInProgress = TRUE;
}
else
{
GATT_bm_free((gattMsg_t *)&req, ATT_WRITE_REQ);
}
}
}
return (events ^ START_WRITE_CCCD_EVT);
}
if(events & START_READ_RSSI_EVT)
{
GAPRole_ReadRssiCmd(centralConnList[CONNECT1_ITEM].connHandle);
tmos_start_task(centralConnList[CONNECT1_ITEM].taskID, START_READ_RSSI_EVT, DEFAULT_RSSI_PERIOD);
return (events ^ START_READ_RSSI_EVT);
}
// Discard unknown events
return 0;
}
把CONNECT0_ITEM改成CONNECT1_ITEM,编译一下会发现centralConnIistStartDiscovery_1还没实现,这里也是复制粘贴修改
static void centralConnIistStartDiscovery_1(void)
{
uint8_t uuid[ATT_BT_UUID_SIZE] = {LO_UINT16(SIMPLEPROFILE_SERV_UUID),
HI_UINT16(SIMPLEPROFILE_SERV_UUID)};
// Initialize cached handles
centralConnList[CONNECT1_ITEM].svcStartHdl = centralConnList[CONNECT1_ITEM].svcEndHdl = centralConnList[CONNECT1_ITEM].charHdl = 0;
centralConnList[CONNECT1_ITEM].discState = BLE_DISC_STATE_SVC;
// Discovery simple BLE service
GATT_DiscPrimaryServiceByUUID(centralConnList[CONNECT1_ITEM].connHandle,
uuid,
ATT_BT_UUID_SIZE,
centralTaskId);
}
然后回到,Central_ProcessEvent添加调用
// 连接1的任务处理
else if(task_id == centralConnList[CONNECT1_ITEM].taskID)
{
return connect1_ProcessEvent(task_id, events);
}
如果直接编译下载的话,估计跟我第一次修改实现的一样,还是只能接收先连接的,只有一个外设的noti,
因为我还差了一步:
/*********************************************************************
* @fn centralGATTDiscoveryEvent
*
* [url=home.php?mod=space&uid=247401]@brief[/url] Process GATT discovery event
*
* [url=home.php?mod=space&uid=266161]@return[/url] none
*/
static void centralGATTDiscoveryEvent(uint8_t connItem, gattMsgEvent_t *pMsg)
{
attReadByTypeReq_t req;
// 连接0的枚举
if(connItem == CONNECT0_ITEM)
{
if(centralConnList[connItem].discState == BLE_DISC_STATE_SVC)
{
// Service found, store handles
if(pMsg->method == ATT_FIND_BY_TYPE_VALUE_RSP &&
pMsg->msg.findByTypeValueRsp.numInfo > 0)
{
centralConnList[connItem].svcStartHdl = ATT_ATTR_HANDLE(pMsg->msg.findByTypeValueRsp.pHandlesInfo, 0);
centralConnList[connItem].svcEndHdl = ATT_GRP_END_HANDLE(pMsg->msg.findByTypeValueRsp.pHandlesInfo, 0);
// Display Profile Service handle range
PRINT("Found Profile Service handle : %x ~ %x \n", centralConnList[connItem].svcStartHdl, centralConnList[connItem].svcEndHdl);
}
// If procedure complete
if((pMsg->method == ATT_FIND_BY_TYPE_VALUE_RSP &&
pMsg->hdr.status == bleProcedureComplete) ||
(pMsg->method == ATT_ERROR_RSP))
{
if(centralConnList[connItem].svcStartHdl != 0)
{
// Discover characteristic
centralConnList[connItem].discState = BLE_DISC_STATE_CHAR;
req.startHandle = centralConnList[connItem].svcStartHdl;
req.endHandle = centralConnList[connItem].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);
GATT_ReadUsingCharUUID(centralConnList[connItem].connHandle, &req, centralTaskId);
}
}
}
else if(centralConnList[connItem].discState == BLE_DISC_STATE_CHAR)
{
// Characteristic found, store handle
if(pMsg->method == ATT_READ_BY_TYPE_RSP &&
pMsg->msg.readByTypeRsp.numPairs > 0)
{
centralConnList[connItem].charHdl = BUILD_UINT16(pMsg->msg.readByTypeRsp.pDataList[0],
pMsg->msg.readByTypeRsp.pDataList[1]);
centralConnList[connItem].procedureInProgress = FALSE;
// Start do read or write
tmos_start_task(centralConnList[connItem].taskID, START_READ_OR_WRITE_EVT, DEFAULT_READ_OR_WRITE_DELAY);
// Display Characteristic 1 handle
PRINT("Found Characteristic 1 handle : %x \n", centralConnList[0].charHdl);
}
if((pMsg->method == ATT_READ_BY_TYPE_RSP &&
pMsg->hdr.status == bleProcedureComplete) ||
(pMsg->method == ATT_ERROR_RSP))
{
// Discover characteristic
centralConnList[connItem].discState = BLE_DISC_STATE_CCCD;
req.startHandle = centralConnList[connItem].svcStartHdl;
req.endHandle = centralConnList[connItem].svcEndHdl;
req.type.len = ATT_BT_UUID_SIZE;
req.type.uuid[0] = LO_UINT16(GATT_CLIENT_CHAR_CFG_UUID);
req.type.uuid[1] = HI_UINT16(GATT_CLIENT_CHAR_CFG_UUID);
GATT_ReadUsingCharUUID(centralConnList[connItem].connHandle, &req, centralTaskId);
}
}
else if(centralConnList[connItem].discState == BLE_DISC_STATE_CCCD)
{
// Characteristic found, store handle
if(pMsg->method == ATT_READ_BY_TYPE_RSP &&
pMsg->msg.readByTypeRsp.numPairs > 0)
{
centralConnList[connItem].cccHdl = BUILD_UINT16(pMsg->msg.readByTypeRsp.pDataList[0],
pMsg->msg.readByTypeRsp.pDataList[1]);
centralConnList[connItem].procedureInProgress = FALSE;
// Start do write CCCD
tmos_start_task(centralConnList[connItem].taskID, START_WRITE_CCCD_EVT, DEFAULT_WRITE_CCCD_DELAY);
// Display Characteristic 1 handle
PRINT("Found client characteristic configuration handle : %x \n", centralConnList[connItem].cccHdl);
}
centralConnList[connItem].discState = BLE_DISC_STATE_IDLE;
}
}
// 连接1的枚举
else if(connItem == CONNECT1_ITEM)
{
if(centralConnList[connItem].discState == BLE_DISC_STATE_SVC)
{
// Service found, store handles
if(pMsg->method == ATT_FIND_BY_TYPE_VALUE_RSP &&
pMsg->msg.findByTypeValueRsp.numInfo > 0)
{
centralConnList[connItem].svcStartHdl = ATT_ATTR_HANDLE(pMsg->msg.findByTypeValueRsp.pHandlesInfo, 0);
centralConnList[connItem].svcEndHdl = ATT_GRP_END_HANDLE(pMsg->msg.findByTypeValueRsp.pHandlesInfo, 0);
// Display Profile Service handle range
PRINT("Found Profile Service handle : %x ~ %x \n", centralConnList[connItem].svcStartHdl, centralConnList[connItem].svcEndHdl);
}
// If procedure complete
if((pMsg->method == ATT_FIND_BY_TYPE_VALUE_RSP &&
pMsg->hdr.status == bleProcedureComplete) ||
(pMsg->method == ATT_ERROR_RSP))
{
if(centralConnList[connItem].svcStartHdl != 0)
{
// Discover characteristic
centralConnList[connItem].discState = BLE_DISC_STATE_CHAR;
req.startHandle = centralConnList[connItem].svcStartHdl;
req.endHandle = centralConnList[connItem].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);
GATT_ReadUsingCharUUID(centralConnList[connItem].connHandle, &req, centralTaskId);
}
}
}
else if(centralConnList[connItem].discState == BLE_DISC_STATE_CHAR)
{
// Characteristic found, store handle
if(pMsg->method == ATT_READ_BY_TYPE_RSP &&
pMsg->msg.readByTypeRsp.numPairs > 0)
{
centralConnList[connItem].charHdl = BUILD_UINT16(pMsg->msg.readByTypeRsp.pDataList[0],
pMsg->msg.readByTypeRsp.pDataList[1]);
centralConnList[connItem].procedureInProgress = FALSE;
// Start do read or write
tmos_start_task(centralConnList[connItem].taskID, START_READ_OR_WRITE_EVT, DEFAULT_READ_OR_WRITE_DELAY);
// Display Characteristic 1 handle
PRINT("Found Characteristic 1 handle : %x \n", centralConnList[0].charHdl);
}
if((pMsg->method == ATT_READ_BY_TYPE_RSP &&
pMsg->hdr.status == bleProcedureComplete) ||
(pMsg->method == ATT_ERROR_RSP))
{
// Discover characteristic
centralConnList[connItem].discState = BLE_DISC_STATE_CCCD;
req.startHandle = centralConnList[connItem].svcStartHdl;
req.endHandle = centralConnList[connItem].svcEndHdl;
req.type.len = ATT_BT_UUID_SIZE;
req.type.uuid[0] = LO_UINT16(GATT_CLIENT_CHAR_CFG_UUID);
req.type.uuid[1] = HI_UINT16(GATT_CLIENT_CHAR_CFG_UUID);
GATT_ReadUsingCharUUID(centralConnList[connItem].connHandle, &req, centralTaskId);
}
}
else if(centralConnList[connItem].discState == BLE_DISC_STATE_CCCD)
{
// Characteristic found, store handle
if(pMsg->method == ATT_READ_BY_TYPE_RSP &&
pMsg->msg.readByTypeRsp.numPairs > 0)
{
centralConnList[connItem].cccHdl = BUILD_UINT16(pMsg->msg.readByTypeRsp.pDataList[0],
pMsg->msg.readByTypeRsp.pDataList[1]);
centralConnList[connItem].procedureInProgress = FALSE;
// Start do write CCCD
tmos_start_task(centralConnList[connItem].taskID, START_WRITE_CCCD_EVT, DEFAULT_WRITE_CCCD_DELAY);
// Display Characteristic 1 handle
PRINT("Found client characteristic configuration handle : %x \n", centralConnList[connItem].cccHdl);
}
centralConnList[connItem].discState = BLE_DISC_STATE_IDLE;
}
}
// 连接2的枚举
else if(connItem == CONNECT2_ITEM)
{
}
}
要在这个函数里面实现连接1的枚举。
最后可以看到multicentrl是有接收两个设备的noti
|
此文章已获得独家原创/原创奖标签,著作权归21ic所有,未经允许禁止转载。
|