MTK timer 小结 3

MTK timer 小结 2 说道最常用的MMI timer 实现机制的初始化过程。今天继续忘下说,下面要说的是创建一个timer。MMI 层,启动一个timer,最终都会调用到 L4StartTimer 这个函数。具体来分析一下这个函数

// 参数  nTimerId 是要自己定义一个timer id,在 timerEvents.h 里的 MMI_TIMER_IDS 定义,用来区分timer
// TimerExpiry 超时的回调函数
// funcArg 回调函数回传的参数
// nTimeDuration 超时时间,单位ms
// alignment alignment或者non-alignment,在 MTK timer 小结 2 说明过
static void L4StartTimer(
        unsigned short nTimerId,
        oslTimerFuncPtr TimerExpiry,
        void *funcArg,
        unsigned long nTimeDuration,
        unsigned char alignment)
{
    /*----------------------------------------------------------------*/
    /* Local Variables                                                */
    /*----------------------------------------------------------------*/
    TIMERTABLE *pTable = NULL;
    U16 i = 0;
    U32 temp;

    /*----------------------------------------------------------------*/
    /* Code Body                                                      */
    /*----------------------------------------------------------------*/
    if (TimerExpiry == NULL)
    {   /* If TimerExpiry is NULL, we don't start the timer */
        MMI_ASSERT(0);
        return;
    }

    MMI_ASSERT(nTimerId < MAX_TIMERS);

    if (L4TimerUsePreciseTick(nTimerId))
    {
        alignment = TIMER_IS_NO_ALIGNMENT;
    }

     // 把 ticks 转化为ms
    // mtk 底层的timer 的单位都是 ticks
    if (nTimeDuration == 1000)
    {
        temp = KAL_TICKS_1_SEC - 4;
    }
    else
    {
        temp = (U32)((nTimeDuration / 5) * MMI_TICKS_5_MSEC);
    }

    if (temp == 0)
    {
        /* Cause by by rounding. If expire immediately, MoDIS boot-up failure because MMI keeps running and block NVRAM task */
        temp = (U32)MMI_TICKS_5_MSEC;
    }

    //取得存放所有MMI timer 的table
    // 在 MTK timer 小结 2 中提到,这个table 是 list + array 组合
    // 如果只用存数组的话,初始化大小不好确定,而且要 array relloc. 如果考虑内存回收还容易引起数组震荡
    // 如果只用list的话,一个timer如果很频繁的话,会不停的malloc 和 free
    pTable = &g_timer_table;

    //判断timer 是否已经 满了
    // 如果满了,那么需要在timer table 后面增加一个timer node
    if (g_timer_table_used >= g_timer_table_size)
    {
        do
        {
            if (pTable->next == NULL)
            {
                pTable->next = OslMalloc(sizeof(TIMERTABLE));
                memset(pTable->next, 0, sizeof(TIMERTABLE));
                g_timer_table_size += SIMULTANEOUS_TIMER_NUM;
                pTable = pTable->next;
                i = 0;
                break;
            }
            pTable = pTable->next;
        } while (pTable != NULL);
    }
    else
    {
        //寻找空的 timer node
        i = 0;
        do
        {
            if (pTable->tm[i].event_id == NULL)
            {   /* find the empty space */
                break;
            }
            i++;
            if (i >= SIMULTANEOUS_TIMER_NUM)
            {
                pTable = pTable->next;
                i = 0;
            }
        } while (pTable != NULL);

        if (pTable == NULL)
        {
            /* Can't find the empty space in TIMERTABLE list, assert!!! */
            MMI_ASSERT(0);
        }
    }   /* if (g_timer_table_used >= g_timer_table_size) */

    // 根据 algigment 属性,分别创建一个 event scheduler timer
    // 把 timer 的信息保存到 timer node 里面
    if (alignment == TIMER_IS_NO_ALIGNMENT)
    {
        /* MSB(Most Significant Bit) is align_timer_mask */
        pTable->tm[i].timer_info = nTimerId | NO_ALIGNMENT_TIMER_MASK;
        pTable->tm[i].event_id = evshed_set_event(
                                    event_scheduler1_ptr,
                                    (kal_timer_func_ptr) L4CallBackTimer,
                                    (void*)&(pTable->tm[i]),
                                    temp);
        pTable->tm[i].arg = funcArg;
        pTable->tm[i].callback_func = TimerExpiry;
        g_timer_table_used++;
    }
    else if (alignment == TIMER_IS_ALIGNMENT)
    {
        /* MSB(Most Significant Bit) is align_timer_mask */
        pTable->tm[i].timer_info = nTimerId | ALIGNMENT_TIMER_MASK;
        pTable->tm[i].event_id = evshed_set_event(
                                    event_scheduler2_ptr,
                                    (kal_timer_func_ptr) L4CallBackTimer,
                                    (void*)&(pTable->tm[i]),
                                    temp);
        pTable->tm[i].arg = funcArg;
        pTable->tm[i].callback_func = TimerExpiry;
        g_timer_table_used++;
    }
}
再说一句 timer table,其实也可以用 timer pool 来实现,把超时或者stop的timer node,放入到free pool 中,需要时再拿出来,也可以避免重复的malloc 和 free。
在 设置 event scheduler timer 中,设置了一个回调函数 L4CallBackTimer, 这个回调函数就是在 stack timer 超时需要回调的函数。
那具体再哪里回调?在 MTK timer 小结 2 提到, event scheduler 还是依赖与 stack timer,在 MTK timer 小结 1 提到 stack timer 超时后是向相应的mod 发送消息。
在初始化L4InitTimer函数中,stack timer 初始化(stack_init_timer(&base_timer1, "MMI_Base_Timer1", MOD_MMI))时mod 是 MOD_MMI,那么超时后,就会像 mmi task 发送超时消息。
MMI 层 在 MMI_task 函数中处理所有的消息,while 消息处理中,可以看到 
case MSG_ID_TIMER_EXPIRY:
{
    kal_uint16 msg_len; 
    EvshedMMITimerHandler(get_local_para_ptr(Message.oslDataPtr, &msg_len));
}
break;
这个就是处理 stack timer 地方。也就是stack timer 超时后,回回调 EvshedMMITimerHandler 函数。
 
void EvshedMMITimerHandler(void *dataPtr)
{
    /*----------------------------------------------------------------*/
    /* Local Variables                                                */
    /*----------------------------------------------------------------*/
    stack_timer_struct *stack_timer_ptr;

    stack_timer_ptr = (stack_timer_struct*) dataPtr;

    /*----------------------------------------------------------------*/
    /* Code Body                                                      */
    /*----------------------------------------------------------------*/
    // 判断是哪个 stack timer
    if (stack_timer_ptr == &base_timer1)
    {
        // 这里需要判断 这 stack timer 是否还是有效,也就是否被stop
        // 这种情况出现环境在 MTK timer 小结 1 中介绍过
        // 如果无效,就不要触发这个timer
        if (stack_is_time_out_valid(&base_timer1))
        { 
            //调用 这个函数,处罚注册的 event scheduler timer
            evshed_timer_handler(event_scheduler1_ptr);
        }
        stack_process_time_out(&base_timer1);
    }
    else if (stack_timer_ptr == &base_timer2)
    {
        if (stack_is_time_out_valid(&base_timer2))
        {
            evshed_timer_handler(event_scheduler2_ptr);
        }
        stack_process_time_out(&base_timer2);
    }
}

这个函数在 调用 evshed_timer_handler 函数是,就会回调 由 evshed_set_event 注册的timer 回调函数 L4CallBackTimer。
 
(未完 待续)

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值