CH587蓝牙HID_Keyboard例程多通道配对修改示例

由于CH587的dataflash最小擦除单位上升到了4K字节,对于一个SNV块只有256字节的BLE来说,如果按照当前例程默认做法,SNV的擦写也被动变为了4K字节擦除;

如果加入多通道配对逻辑,比方说常见的蓝牙键盘含有4个BLE通道,那将是4K*4=16K,原本只需要256*4=1K的占用,白白浪费了15K空间;

对此,可衍生一个思路:划分1Kdataflash区域用于存储4个蓝牙通道SNV信息,每次切通道涉及配对存储动作时,先把1K数据全部读出来,根据当前的BLE_SNV_Index修改其中一个SNV块数据后,再写回去;

例程修改:

①MCU.c文件Lib_Write_Flash:

uint8_t BLE_SNV_Index = 1;//定义一个全局变量,用于通道序号管理,默认蓝牙通道1
#define SNV_NUM 4   //定义SNV块数量->蓝牙通道数量
/*******************************************************************************
 * @fn      Lib_Write_Flash
 *
 * @brief   Callback function used for BLE lib.
 *
 * @param   addr - Write start address
 * @param   num - Number of units to write (unit: 4 bytes)
 * @param   pBuf - Buffer with data to be written
 *
 * @return  None.
 */
uint32_t Lib_Write_Flash(uint32_t addr, uint32_t num, uint32_t *pBuf)
{
#if 1
    //兼容CH585的蓝牙切通道做法,用于多通道信息连续存储
    uint32_t Temp_Buffer[256*SNV_NUM/4] = {0};//定义临时备份区,1K字节
    EEPROM_READ(BLE_SNV_ADDR, Temp_Buffer,256*SNV_NUM);//读出4个块所有的1K字节,存储到临时备份区
    EEPROM_ERASE(BLE_SNV_ADDR, 0x1000);//擦除4K区域,CH587中4K为最小擦除单位
    tmos_memcpy(&Temp_Buffer[(BLE_SNV_Index - 1) * (256 / 4)],pBuf,num * 4);//拷贝回调写入的数据到临时备份区中的对应SNV块
    EEPROM_WRITE(BLE_SNV_ADDR, Temp_Buffer, 0x400);//将拷贝完后的数据写入到dataflash,写入数量4*256=1K字节
#else
    //原先例程做法,每次配对会固定擦除4K单位
    EEPROM_ERASE(addr, num * 4);
    EEPROM_WRITE(addr, pBuf, num * 4);
#endif
    return 0;
}

 

②测试演示:定义了两个tmos任务:

1、可在任意时间点启动START_BLE_DISCON_EVT任务,发起断连用于切换新通道连接;

2、断连后根据当前通道号重新开启广播

image

 

 广播参数重新配置并开启广播:

uint8_t BLE_IRK[KEYLEN]={0};
extern uint8_t BLE_SNV_Index;
extern bStatus_t tmos_snv_write( tmosSnvId_t id, tmosSnvLen_t len, void *pBuf );
extern void tmos_snv_notify( uint8_t enable );
extern bStatus_t tmos_snv_init( void );
void hidEmu_adv_enable(uint8_t enable)
{
    uint8_t ownAddr[6];
    uint8_t initial_advertising_enable = enable;
    uint8_t adv_event_type;

    if(initial_advertising_enable)
    {
        extern bleConfig_t ble;
        ble.SNVAddr =  (BLE_SNV_Index-1)* 0x100 + BLE_SNV_ADDR;//根据当前BLE通道号,切换至对应SNV块
        /* 初始化SNV,用于获取IRK信息 */
        tmos_snv_init();
        if(tmos_snv_read(BLE_NVID_IRK,KEYLEN,BLE_IRK))//读取当前SNV块中是否存有IRK信息,没有则手动赋随机值,赋值一次之后不用再次赋值
        {
            uint32_t rand;
            uint8_t j;
            for(j=0; j<4; j++)
            {
                rand = tmos_rand();
                BLE_IRK[0+4*j] = BREAK_UINT32(rand, 0);
                BLE_IRK[1+4*j] = BREAK_UINT32(rand, 1);
                BLE_IRK[2+4*j] = BREAK_UINT32(rand, 2);
                BLE_IRK[3+4*j] = BREAK_UINT32(rand, 3);
            }
            tmos_snv_write(BLE_NVID_IRK,KEYLEN,BLE_IRK);
            tmos_snv_notify(1);//存储至SNV中
        }

        GAPRole_GetParameter(GAPROLE_BD_ADDR, ownAddr);//获取当前BLE静态地址,唯一
        ownAddr[3]=BLE_SNV_Index;//修改蓝牙地址,防止切通道index后被误连接(每个蓝牙通道地址必须唯一,否则会被主机误连)
        PRINT("MAC %x %x %x %x %x %x\n",ownAddr[5],ownAddr[4],ownAddr[3],ownAddr[2],ownAddr[1],ownAddr[0]);//打印当前的广播地址
        GAP_ConfigDeviceAddr(ADDRTYPE_STATIC, ownAddr);

        PRINT("IRK %x %x %x %x %x %x\n",BLE_IRK[5],BLE_IRK[4],BLE_IRK[3],BLE_IRK[2],BLE_IRK[1],BLE_IRK[0]);//打印当前的部分IRK值
        GAPRole_SetParameter(GAPROLE_IRK, KEYLEN, BLE_IRK);//配置IRK信息
    }

    {
        PRINT("all adv\n");
        uint8_t filter_policy = GAP_FILTER_POLICY_ALL;
        adv_event_type = GAP_ADTYPE_ADV_IND;
        GAPRole_SetParameter(GAPROLE_ADV_FILTER_POLICY, sizeof(uint8_t), &filter_policy);//配置普通广播,所有设备可发现
    }
    GAPRole_SetParameter( GAPROLE_ADV_EVENT_TYPE, sizeof(adv_event_type), &adv_event_type);
    GAPRole_SetParameter(GAPROLE_ADVERT_ENABLED, sizeof(uint8_t), &initial_advertising_enable);//根据ENABLE(开启) or DISABLE(不开/关闭) 广播
}

 

有需要自取:

通过网盘分享的文件:CH587EVT_HIDKeyboard.zip
链接: https://pan.baidu.com/s/1iRDtbRX6msCAdmJYW4NH4g?pwd=24nd 提取码: 24nd

posted @ 2026-07-29 00:07  oTvTo  阅读(29)  评论(0)    收藏  举报