(原创)RTOS-RTX分析系列之事件

2017/07/23 RTX

简介

事件应该是RTOS系统最基本的通信方式了,在RTX中,事件可以与和或两种方式。

关键结构

事件太简单了,以至于都没有一个结构体,直接在任务控制块OS_TCB中加了两个字段:

  U16    events;                  /* Event flags  当前置位的标志位 */
  U16    waits;                   /* Wait flags   必须等待的标志位   

关键实现

rt_evt_wait

等待事件函数,支持与等待和或等待,以及设定超时时间:

OS_RESULT rt_evt_wait (U16 wait_flags, U16 timeout, BOOL and_wait) {
  /* Wait for one or more event flags with optional time-out.                */
  /* "wait_flags" identifies the flags to wait for.                          */
  /* "timeout" is the time-out limit in system ticks (0xffff if no time-out) */
  /* "and_wait" specifies the AND-ing of "wait_flags" as condition to be met */
  /* to complete the wait. (OR-ing if set to 0).                             */
  U32 block_state;

  if (and_wait) {//如果是与方式等待
    /* Check for AND-connected events */
    if ((os_tsk.run->events & wait_flags) == wait_flags) {//如果标志位已经置位,则直接成功,返回OS_R_EVT
      os_tsk.run->events &= ~wait_flags;
      return (OS_R_EVT);
    }
    block_state = WAIT_AND;//如果标志位还没有完成,则进入等待
  }
  else {//如果是或方式等待
    /* Check for OR-connected events */
    if (os_tsk.run->events & wait_flags) {//如果标志位已经置位,则直接成功,返回OS_R_EVT
      os_tsk.run->waits = os_tsk.run->events & wait_flags;
      os_tsk.run->events &= ~wait_flags;
      return (OS_R_EVT);
    }
    block_state = WAIT_OR;
  }
  /* Task has to wait */
  os_tsk.run->waits = wait_flags;//设置状态
  rt_block (timeout, (U8)block_state);//阻塞当前任务
  return (OS_R_TMO);
}

rt_evt_set

指定任务来设置事件函数:

void rt_evt_set (U16 event_flags, OS_TID task_id) {
  /* Set one or more event flags of a selectable task. */
  P_TCB p_tcb;

  p_tcb = os_active_TCB[task_id-1];
  if (p_tcb == NULL) {//非法任务
    return;
  }
  p_tcb->events |= event_flags;
  event_flags    = p_tcb->waits;
  /* If the task is not waiting for an event, it should not be put */
  /* to ready state. */
  if (p_tcb->state == WAIT_AND) {//如果是与等待
    /* Check for AND-connected events */
    if ((p_tcb->events & event_flags) == event_flags) {//判断事件是否充足,如果是的话直接跳转到wkup标签
      goto wkup;
    }
  }
  if (p_tcb->state == WAIT_OR) {//如果是或等待
    /* Check for OR-connected events */
    if (p_tcb->events & event_flags) {
      p_tcb->waits  &= p_tcb->events;
wkup: p_tcb->events &= ~event_flags;//清除事件标志
      rt_rmv_dly (p_tcb);//从延时任务链表清除该任务
      p_tcb->state   = READY;//状态恢复成就绪
#ifdef __CMSIS_RTOS
      rt_ret_val2(p_tcb, 0x08/*osEventSignal*/, p_tcb->waits); //设置被恢复任务的返回值,如果是或等待的话,这里会把置位的标志位返回。
#else
      rt_ret_val (p_tcb, OS_R_EVT);
#endif
      rt_dispatch (p_tcb);//申请一次任务调度
    }
  }
}

rt_evt_clr

太简单,不解释:

void rt_evt_clr (U16 clear_flags, OS_TID task_id) {
  /* Clear one or more event flags (identified by "clear_flags") of a */
  /* selectable task (identified by "task"). */
  P_TCB task = os_active_TCB[task_id-1];

  if (task == NULL) {
    return;
  }
  task->events &= ~clear_flags;//清除当前获得的标志位
}

isr_evt_set

在中断中设置事件,必须调用该函数,将处理放进队列,延迟到PendSV_Handler中断服务程序中执行:

void isr_evt_set (U16 event_flags, OS_TID task_id) {
  /* Same function as "os_evt_set", but to be called by ISRs. */
  P_TCB p_tcb = os_active_TCB[task_id-1];

  if (p_tcb == NULL) {
    return;
  }
  rt_psq_enq (p_tcb, event_flags);//放入队列 最大支持16级
  rt_psh_req ();
}

知识共享许可协议
本作品采用知识共享署名-非商业性使用 4.0 国际许可协议进行许可。

站内搜索

    撩我备注-博客

    joinee

    目录结构