【WCH蓝牙系列芯片】-基于CH582开发板—蓝牙hid设备进行白名单广播回连操作

------------------------------------------------------------------------------------------------------------------------------------

  当一个BLE设备与蓝牙主机设备连接上,当主机断电重启之后,依然能够和配对过的BLE设备主动连接上,而不需要重新在扫描配对的流程,所以这个过程叫做回连操作。

  这里利用HID_keyborad例程作为蓝牙HID设备,通过手机系统蓝牙进行扫描配对连接,并进行白名单回连操作。接下来在HID_keyborad例程进行修改,添加程序。

  在hiddev.h中,先定义一个结构体,用于设备地址类型、设备地址和绑定参数

  在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中的代码程序。

 

posted on 2024-08-21 09:51  凡仕  阅读(224)  评论(0编辑  收藏  举报