基于CH585的蓝牙主机快连程序修改说明_可拿到特定handle值进行定向通讯
一般地,如果蓝牙从机设备是自己开发的程序,并且可以拿到关键的notify的句柄值,便可以跳过枚举流程,连接后直接进行通讯测试(一般用于产测环节)。
一、准备工作
1、在不知道从机设备的通知句柄时,以CH585的HID_Keyboard例程为例,找到HidDev_WriteAttrCB函数,在其中增加打印:
如果从机使用的是Peripheral例程,则可以在simpleProfile_WriteAttrCB中添加句柄打印,方法同下;

2、从机程序中可以看到有两个notify特征属性,在烧录从机固件后,配对电脑时,可在HidDev_WriteAttrCB中获取到handle值,便于下文在编写主机程序时定向打开notify权限,并且接收notify数据;


二、编写主机程序
1、定向连接,可通过广播包数据匹配,找到GAP_DEVICE_INFO_EVENT事件进行改写,
①定义目标数组用于比对(参照从机例程):
// Advertising data
static uint8_t advertData[] = {
// flags
0x02, // length of this data
GAP_ADTYPE_FLAGS,
GAP_ADTYPE_FLAGS_LIMITED | GAP_ADTYPE_FLAGS_BREDR_NOT_SUPPORTED,
// appearance
0x03, // length of this data
GAP_ADTYPE_APPEARANCE,
LO_UINT16(GAP_APPEARE_HID_KEYBOARD),
HI_UINT16(GAP_APPEARE_HID_KEYBOARD),
};
②改写centralEventCB函数,定义设备类型变量
static uint8_t PeerAddrType = 0; //!< Address Type: @ref GAP_ADDR_TYPE_DEFINES
/*********************************************************************
* @fn centralEventCB
*
* @brief Central event callback function.
*
* @param pEvent - pointer to event structure
*
* @return none
*/
static void centralEventCB(gapRoleEvent_t *pEvent)
{
switch(pEvent->gap.opcode)
{
case GAP_DEVICE_INIT_DONE_EVENT:
{
PRINT("Discovering...\n");
GAPRole_CentralStartDiscovery(DEFAULT_DISCOVERY_MODE,
DEFAULT_DISCOVERY_ACTIVE_SCAN,
DEFAULT_DISCOVERY_WHITE_LIST);
}
break;
case GAP_DEVICE_INFO_EVENT:
{
if(tmos_memcmp(advertData, pEvent->deviceInfo.pEvtData, 7))//比对扫描到的设备广播数据是否符合目标设备
{
for(uint8_t i=0;i<6;i++)
{
PRINT("%x ",pEvent->deviceInfo.addr[i]);
}
PRINT("\n");
if( pEvent->deviceInfo.rssi > (-50))//限制RSSI,只允许连接一定距离内的设备,约1m
{
PeerAddrType = pEvent->deviceInfo.addrType;
tmos_memcpy(PeerAddrDef, pEvent->deviceInfo.addr, 6);//将地址赋值
GAPRole_CentralCancelDiscovery();//停止主机扫描
}
else {
PRINT("Device %d - Addr %x %x %x %x %x %x \n", pEvent->deviceInfo.rssi,
centralDevList[centralScanRes - 1].addr[0],
centralDevList[centralScanRes - 1].addr[1],
centralDevList[centralScanRes - 1].addr[2],
centralDevList[centralScanRes - 1].addr[3],
centralDevList[centralScanRes - 1].addr[4],
centralDevList[centralScanRes - 1].addr[5]);
}
}
}
break;
case GAP_DEVICE_DISCOVERY_EVENT:
{
// Peer device not found
if(tmos_isbufset(PeerAddrDef, 0, 6))//如果地址为全0,则代表设备未搜寻到
{
PRINT("Device not found...\n");
centralScanRes = 0;
GAPRole_CentralStartDiscovery(DEFAULT_DISCOVERY_MODE,
DEFAULT_DISCOVERY_ACTIVE_SCAN,
DEFAULT_DISCOVERY_WHITE_LIST);
PRINT("Discovering...\n");
}
// Peer device found
else
{
PRINT("Device found...\n");
GAPRole_CentralEstablishLink(DEFAULT_LINK_HIGH_DUTY_CYCLE,
DEFAULT_LINK_WHITE_LIST,
PeerAddrType,
PeerAddrDef);
//找到目标设备,发起连接
// Start establish link timeout event
tmos_start_task(centralTaskId, ESTABLISH_LINK_TIMEOUT_EVT, ESTABLISH_LINK_TIMEOUT);
PRINT("Connecting...\n");
}
}
break;
case GAP_LINK_ESTABLISHED_EVENT:
{
tmos_memset(PeerAddrDef, 0, 6);
tmos_stop_task(centralTaskId, ESTABLISH_LINK_TIMEOUT_EVT);
if(pEvent->gap.hdr.status == SUCCESS)
{
centralState = BLE_STATE_CONNECTED;
centralConnHandle = pEvent->linkCmpl.connectionHandle;
centralProcedureInProgress = FALSE;// See if start RSSI polling
if(centralRssi)
{
tmos_start_task(centralTaskId, START_READ_RSSI_EVT, DEFAULT_RSSI_PERIOD);
}
PRINT("Connected...\n");
}
else
{
PRINT("Connect Failed...Reason:%X\n", pEvent->gap.hdr.status);
PRINT("Discovering...\n");
centralScanRes = 0;
GAPRole_CentralStartDiscovery(DEFAULT_DISCOVERY_MODE,
DEFAULT_DISCOVERY_ACTIVE_SCAN,
DEFAULT_DISCOVERY_WHITE_LIST);
}
}
break;
case GAP_LINK_TERMINATED_EVENT:
{
centralState = BLE_STATE_IDLE;
centralConnHandle = GAP_CONNHANDLE_INIT;
centralDiscState = BLE_DISC_STATE_IDLE;
centralScanRes = 0;
centralProcedureInProgress = FALSE;
tmos_stop_task(centralTaskId, START_READ_RSSI_EVT);
PRINT("Disconnected...Reason:%x\n", pEvent->linkTerminate.reason);
PRINT("Discovering...\n");
tmos_memset(PeerAddrDef, 0, 6);
GAPRole_CentralStartDiscovery(DEFAULT_DISCOVERY_MODE,
DEFAULT_DISCOVERY_ACTIVE_SCAN,
DEFAULT_DISCOVERY_WHITE_LIST);
}
break;
case GAP_LINK_PARAM_UPDATE_EVENT:
{
PRINT("Param Update...\n");
}
break;
case GAP_PHY_UPDATE_EVENT:
{
PRINT("PHY Update...\n");
}
break;
case GAP_EXT_ADV_DEVICE_INFO_EVENT:
{
// // Display device addr
// PRINT("Recv ext adv \n");
// // Add device to list
// centralAddDeviceInfo(pEvent->deviceExtAdvInfo.addr, pEvent->deviceExtAdvInfo.addrType);
}
break;
case GAP_DIRECT_DEVICE_INFO_EVENT:
{
// Display device addr
PRINT("Recv direct adv \n");
// Add device to list
centralAddDeviceInfo(pEvent->deviceDirectInfo.addr, pEvent->deviceDirectInfo.addrType);
}
break;
default:
break;
}
}
2、可将其中的START_WRITE_CCCD_EVT任务改写为如下所示,并在centralPairStateCB中开启循环执行:

if(events & START_WRITE_CCCD_EVT)
{
PRINT("Procedure : %x\n",centralProcedureInProgress);
if(centralProcedureInProgress == FALSE)//等待上一次流程结束
{
// Do a write
attWriteReq_t req;
req.cmd = FALSE;
req.sig = FALSE;
switch (write_count)//有两个notify handle待开启,在打开成功一个后count会自动减一;
{
case 2:
req.handle = 0x37;
break;
case 1:
req.handle = 0x3a;
break;
default:
return (events ^ START_WRITE_CCCD_EVT);
break;
}
req.len = 2;
req.pValue = GATT_bm_alloc(centralConnHandle, ATT_WRITE_REQ, req.len, NULL, 0);
if(req.pValue != NULL)
{
req.pValue[0] = 1;
req.pValue[1] = 0;
if(GATT_WriteCharValue(centralConnHandle, &req, centralTaskId) == SUCCESS)
{
centralProcedureInProgress = TRUE;//执行完一次任务后将标志写1
}
else
{
GATT_bm_free((gattMsg_t *)&req, ATT_WRITE_REQ);
}
}
}
return (events ^ START_WRITE_CCCD_EVT);
}
3、打开通知后进入回调,获取打开是否成功,以及收到的通知数据打印出来

三、测试结果

测试文件可通过网盘获取:
链接: https://pan.baidu.com/s/1iRbtvmBCPFWHTUA48EXfKw?pwd=h6cd 提取码: h6cd

浙公网安备 33010602011771号