【WCH蓝牙系列芯片】-基于CH582开发板—蓝牙hid设备进行白名单广播回连操作
------------------------------------------------------------------------------------------------------------------------------------
这里利用HID_keyborad例程作为蓝牙HID设备,通过手机系统蓝牙进行扫描配对连接,并进行白名单回连操作。接下来在HID_keyborad例程进行修改,添加程序。
在hidkbd.c文件中,找到BLE状态回调函数hidEmuStateCB中,在连接建立事件中,获取到设备地址和设备的地址类型。
在hiddev.c文件中,找到hidDevPairStateCB用作配对状态的回调函数中,在配对信息是否保存的判断下,添加程序,将主机设备的地址信息(remote_addr)以及地址类型(addr_type)进行绑定操作;然后定义绑定的标志位。
static void hidDevPairStateCB(uint16_t connHandle, uint8_t state, uint8_t status) //用作配对状态的回调函数 { if(state == GAPBOND_PAIRING_STATE_COMPLETE) //配对过程是否已完成 { if(status == SUCCESS) { hidDevConnSecure = TRUE; //表示当前连接是安全 } pairingStatus = status; // 将pairingStatus变量更新为当前的status值,以便记录或后续处理。 } else if(state == GAPBOND_PAIRING_STATE_BONDED) //设备是否已经成功配对并保持配对状态 { if(status == SUCCESS) //设备已配对 { hidDevConnSecure = TRUE; //配对成功 #if DEFAULT_SCAN_PARAM_NOTIFY_TEST == TRUE ScanParam_RefreshNotify(gapConnHandle); //通知系统更新扫描参数 #endif } } else if(state == GAPBOND_PAIRING_STATE_BOND_SAVED) // 配对信息是否已保存 { /******************************添加代码***************************************/ gapBondRec_t bond_info; //用于存储读取的绑定记录信息 uint8_t addr_type; //用于存储设备地址类型 tmos_snv_read(mainRecordNvID(0), sizeof(gapBondRec_t), &bond_info); //从非易失性存储器中读取绑定记录 //打印绑定地址 PRINT("identity addr ("); for(int i = 0 ; i < 6; i ++) { PRINT("%#x ", bond_info.publicAddr[i]); } PRINT(")\n"); tmos_memcpy(mydevinfo.remote_addr, bond_info.publicAddr, 6);//将此次绑定的地址赋值到自己定义的地址数组中去,以便定向广播或者白名单回连使用 //为identity address, 可能为public address,也可能是random static address if( (bond_info.publicAddr[5] & 0xC0) == 0x80 ) { addr_type = 0; } else { addr_type = 1; } extern uint8_t devAddrType; (devAddrType)?1:(addr_type = 0); if(devAddrType == 3) addr_type |= devAddrType<<4; mydevinfo.remote_addr_type = addr_type;//获取主机的地址类型 mydevinfo.isbond = 1;//此次设备绑定生效 /*****************************END*************************************/ } }
在hidkbd.c文件中,找到HidEmu_Init初始化函数中,先将原先程序中开启蓝牙广播的函数注释不用,添加新的函数,利用白名单回连的方式进行连接设备。
通过绑定的标志位,只能在配置的白名单设备里面进行扫描和连接。
uint8_t initial_advertising_enable = TRUE; uint16 advInt =32; //0.625us * 32 = 20ms,20ms一包广播包 GAP_SetParamValue(TGAP_DISC_ADV_INT_MIN, advInt); GAP_SetParamValue(TGAP_DISC_ADV_INT_MAX, advInt); GAPRole_SetParameter(GAPROLE_ADVERT_DATA, sizeof(advertData), advertData); //设置广播包 GAPRole_SetParameter(GAPROLE_SCAN_RSP_DATA, sizeof(scanRspData), scanRspData); //设置扫描应答包 if(mydevinfo.isbond) //已经完成配对,mydevinfo.isbond这标志为1 { uint8 syncWL = TRUE; GAPBondMgr_SetParameter( GAPBOND_AUTO_SYNC_RL, sizeof( uint8 ), &syncWL ); //配对绑定自动同步 uint8 filter_policy = GAP_FILTER_POLICY_WHITE; //只允许白名单设备扫描和连接,GAP_FILTER_POLICY_WHITE表示只有在白名单中的设备才能进行扫描和连接。 GAPRole_SetParameter( GAPROLE_ADV_FILTER_POLICY, sizeof( uint8 ), &filter_policy );//设置白名单,广播数据只能被白名单中的设备进行扫描到 } else { uint8_t policy = GAP_FILTER_POLICY_ALL; //GAP_FILTER_POLICY_ALL表示不进行过滤,任何设备都可以扫描和连接 GAPRole_SetParameter(GAPROLE_ADV_FILTER_POLICY, sizeof(policy), &policy); //意味着设备的广播数据可以被所有设备接受,不进行过滤 }
在hidkbd.c文件中,找到BLE状态回调函数hidEmuStateCB中,找到GAPROLE_WAITING状态中,表示设备处于等待状态中。在这个分支里面是对蓝牙有时连接不上,分析出蓝牙出问题的原因,所以在这个地方再次添加上白名单的配对标志的函数,然后再次开关广播,这样能保持在不知道什么原因的情况下断开蓝牙后,再次连接时能够在按照白名单去连接蓝牙。
这里用手机系统蓝牙连接HID设备,观察功能现象。
但是程序中有个问题,就是当一台手机通过白名单连接上设备之后,当想要切换另一个手机去连接设备时,是搜索不到设备的,因为在程序中做过白名单处理,记住了手机的MAC地址,进行绑定过。针对这个问题,这里采用一个按键去解除蓝牙绑定,并更换HID设备的MAC地址,从而成功一个新的HID设备,这样通过其他手机就可以进行扫描建立连接。
在程序中,先添加按键的子函数,
#include "CH58x_common.h" void Key_Init(void) { SetSysClock(CLK_SOURCE_PLL_60MHz); //配置系统时钟源和时钟频率 //初始化GPIO口 GPIOB_ModeCfg(GPIO_Pin_2, GPIO_ModeIN_PU); ////上拉输入 GPIOB_ModeCfg(GPIO_Pin_3, GPIO_ModeIN_PU); GPIOB_ModeCfg(GPIO_Pin_5, GPIO_ModeIN_PU); } //读取KEY的值 uint8_t Key_GetNum(void) { uint8_t KeyNum = 0; //按键1 if (GPIOB_ReadPortPin(GPIO_Pin_2) == 0) //读取PB2的电平状态 { DelayMs(20);//软件按键消抖 while (GPIOB_ReadPortPin(GPIO_Pin_2) == 0); DelayMs(20); KeyNum = 1; } //按键2 if (GPIOB_ReadPortPin(GPIO_Pin_3) == 0) //读取PB3的电平状态 { DelayMs(20);//软件按键消抖 while (GPIOB_ReadPortPin(GPIO_Pin_3) == 0); DelayMs(20); KeyNum = 2; } //按键3 if (GPIOB_ReadPortPin(GPIO_Pin_5) == 0) //读取PB3的电平状态 { DelayMs(20);//软件按键消抖 while (GPIOB_ReadPortPin(GPIO_Pin_5) == 0); DelayMs(20); KeyNum = 3; } return KeyNum; }
再写一个切换不用主机连接HID设备的任务事件,500mS循环一次。
在任务事件里面,先是将绑定的标志位清空,断开当前的连接,调用递增MAC地址的函数,重新再初始化蓝牙协议栈,库函数,再打开广播。就是一个新的HID设备,其他手机系统蓝牙就可以进行搜索连接。
/******************************添加代码***************************************/ if(events & START_KEY_EVT) //切换不同的主机连接HID设备 { KEY_num = Key_GetNum(); if (KEY_num == 1) { printf("KEY_num = %d\r\n",KEY_num); mydevinfo.isbond = 0; KEY_num = 0; GAPRole_TerminateLink(hidEmuConnHandle); //断开当前连接 IncrementMacAddress(); // 递增 MAC 地址的函数 printf("Updated MAC Address: %02X:%02X:%02X:%02X:%02X:%02X\r\n", MacAddr[0], MacAddr[1], MacAddr[2], MacAddr[3], MacAddr[4], MacAddr[5]); CH58X_BLEInit(); HAL_Init(); GAPRole_PeripheralInit(); HidDev_Init(); HidEmu_Init(); uint8_t initial_advertising_enable = TRUE; //定义广播开启 GAPRole_SetParameter(GAPROLE_ADVERT_ENABLED, sizeof(uint8_t), &initial_advertising_enable); //开启广播 } tmos_start_task(hidEmuTaskId, START_KEY_EVT, 800); return (events ^ START_KEY_EVT); }
// 递增 MAC 地址的函数 static void IncrementMacAddress(void) { uint8_t i; uint8_t carry = 1; // 进位标志 // 从最低位开始递增 for (i = 5; i > 0; i--) { if (carry) { MacAddr[i]++; if (MacAddr[i] == 0) { carry = 1; // 继续进位 } else { carry = 0; // 递增完成 } } } }
在MacAddr 数组中原先的数值定义为
const uint8_t MacAddr[6] ={0x84, 0xC2, 0xE4, 0x03, 0x02, 0x02};
其中const 限定符,这意味着在程序的执行过程中,不能通过对数组元素的直接赋值来修改数组的内容。const 限定符表示该数组是只读的。
因此需要改为:uint8_t MacAddr[6] ={0x84, 0xC2, 0xE4, 0x03, 0x02, 0x02};
在公共文件中,Config.h中需要重新定义一个数据变量。但是更改这里的公共文件,会导致其他工程文件也会更改,所以需要像文章开头讲的那样,建立独立工程,将公共文件包含在内,这样就能随意更改Config.h中的代码程序。