WCH CH57x 系列芯片有个内置的 TMOS 事件调度系统。其封装于蓝牙静态库中,无法看到对应代码。为了实现对任务的更精细的控制,在这里使用了Ghidra尝试反编译得到对应的逻辑。

反编译后可以看出,TMOS是一个基于轮询的任务事件调度系统,几乎所有的调度操作都是在TMOS_SystemProcess 方法中执行的,其简化后的代码如下:

void TMOS_SystemProcess(void)
{
    /** 高优先级的事件 **/
    // 第0号位是抢占式的事件,只会执行一次
    if (pfnProcessCBs[0]) {
        pfnProcessCBs[0]();
        pfnProcessCBs[0] = 0;
    }
    // 始终执行1号位的事件
    if (pfnProcessCBs[1])
        pfnProcessCBs[1]();
    // 如果有需要处理的中断,根据当前模式选择中断处理器处理
    if (gBleIPPara.hasIRQ) {
        gBleIPPara.hasIRQ = false;
        ll_rx_wait_finish();
        pfnProcessCBs[currentMode]();
    }
    // 处理跳频逻辑
    if (rfInfo.hopFlag & HopRx) {
        RF_FrequencyHoppingChange();
    }
    // 执行2号位的事件
    if (pfnProcessCBs[2])
        pfnProcessCBs[2]();

    /** 处理普通事件 **/
    for (; gTmosPara.evtIndex < gTmosPara.evtNum; gTmosPara.evtIndex++) {
        if (EventsArr[gTmosPara.evtIndex] != 0)
            break;
    }
    if (gTmosPara.evtIndex < gTmosPara.evtNum) {
        EventsArr[gTmosPara.evtIndex] = CallbackArr[gTmosPara.evtIndex](EventsArr[gTmosPara.evtIndex]);
    }

    /** 处理定时事件 **/
    int deltaTime = pfnTimerCBs();
    if (deltaTime) {
        gTmosPara.currentTime += deltaTime;
        tmos_query_time(deltaTime);
    }
}

TMOS_SystemProcess 方法中,会优先执行内置的一系列注册事件。然后再去尝试执行那些已经设定了Event的事件,最后处理定时事件。

这里的 tmos_query_time 方法名字有些怪,但它实际上是用来处理定时事件的方法。简化后的代码如下:

void tmos_query_system_time(uint deltaTime)
{
    // 计算下次事件的时间
    gTmosPara.nextEvtTime = -1;
    for (int i = 0; i < eventNum; i++)
    {
        if (events[i].timeout >= deltaTime)
            events[i].timeout -= deltaTime;
        else
            events[i].timeout = 0;

        if (gTmosPara.nextEvtTime > events[i].timeout)
            gTmosPara.nextEvtTime = events[i].timeout;
        // 如果到点,则执行对应任务
        if (events[i].timeout == 0) {
            if (events[i].event != 0) {
                tmos_set_event(events[i].taskID, events[i].event);
            }
            events[i].timeout = events[i].reloadTime;
        }
    }
    // 准备睡眠
    tmos_query_sleep_time();
}

tmos_query_sleep_time 方法中会根据当前系统状态决定是否要进入睡眠状态,简化代码如下:

void tmos_query_sleep_time()
{
    // 当前有事件没处理,取消睡眠
    for (int i = 0; i < gTmosPara.evtNum; i++)
        if (EventsArr[i] != 0)
            return;
    // 当前处于特定模式,取消睡眠
    if (gBleIPPara.currentMode > 4)
        return;
    // 当前处于跳频接收模式,取消休眠
    if ((rfInfo.hopFlag & FlagHopRx) != FlagNone)
        return;
    // 获取下次连接时间
    int sleepTime = LL_GetNextConnectEventTime(&bleSleepTime);
    if (sleepTime == -1) {
        if (gTmosPara.nextEvtTime == -1)
            return;
        sleepTime = gTmosPara.nextEvtTime * 20;
        if (sleepTime < ble.WakeUpTime)
            return;
        // 计算唤醒时间点
        sleepTime = RTC_Get32KClock() + sleepTime - ble.WakeUpTime;
    } else {
        // 蓝牙相关计算
        if (gTmosPara.nextEvtTime != -1) {
            sleepTime = gTmosPara.nextEvtTime * 20;
            if (sleepTime < bleSleepTime)
                bleSleepTime = sleepTime;
        }
        sleepTime = RTC_Get32KClock() + bleSleepTime - ble.WakeUpTime;
    }
    if (sleepTime == 0)
        return;
    // 执行实际睡眠操作
    int result = ble.sleepCB(sleepTime);
    // 睡眠成功,唤醒后重新初始化寄存器
    if (result == 0) {
        DMA_DevInit();
        LLE_DevInit();
        BB_DevInit();
    }
}
分类: 未分类

0 条评论

发表回复

Avatar placeholder

您的邮箱地址不会被公开。 必填项已用 * 标注