z-stack协议栈sampleapp分析介绍(二)

接着上面的写,下面就说到整个协议栈的主循环来了,一个osal_start_system()函数,进入这个函数可以看到是一个死循环

for(;;) 

以后,整个程序就一直在这里面不停的轮询查找,进行各种处理操作。
我们跳转到osal_run_system()函数,看看里面的内容

void osal_run_system( void )
{
  uint8 idx = 0;

  osalTimeUpdate();//见1.1
  Hal_ProcessPoll();  // This replaces MT_SerialPoll() and osal_check_timer().
  //这部分是对串口啊这些进行处理,暂时不做介绍//这部分

  do {
    if (tasksEvents[idx])  // Task is highest priority that is ready.
    {
      break;
    }
  } while (++idx < tasksCnt);//见1.2

  if (idx < tasksCnt)
  {
    uint16 events;
    halIntState_t intState;

    HAL_ENTER_CRITICAL_SECTION(intState);
    events = tasksEvents[idx];
    tasksEvents[idx] = 0;  // Clear the Events for this task.
    HAL_EXIT_CRITICAL_SECTION(intState);

    events = (tasksArr[idx])( idx, events );

    HAL_ENTER_CRITICAL_SECTION(intState);
    tasksEvents[idx] |= events;  // Add back unprocessed events to the current task.
    HAL_EXIT_CRITICAL_SECTION(intState);
  }
#if defined( POWER_SAVING )
  else  // Complete pass through all task events with no activity?
  {
    osal_pwrmgr_powerconserve();  // Put the processor/system into sleep
  }
#endif

  /* Yield in case cooperative scheduling is being used. */
#if defined (configUSE_PREEMPTION) && (configUSE_PREEMPTION == 0)
  {
    osal_task_yield();
  }
#endif
}

1.1、函数osalTimeUpdate()

void osalTimeUpdate( void )
{
  uint32 tmp;
  uint32 ticks320us;
  uint16 elapsedMSec = 0;

  // Get the free-running count of 320us timer ticks
  tmp = macMcuPrecisionCount();
  //每320us定时器2溢出一次,tmp里计的溢出次数

  if ( tmp != previousMacTimerTick )
  {
    // Calculate the elapsed ticks of the free-running timer.
    ticks320us = tmp - previousMacTimerTick;

    // Store the MAC Timer tick count for the next time through this function.
    previousMacTimerTick = tmp;

    // update converted number with remaining ticks from loop and the 
    // accumulated remainder from loop
    tmp = (ticks320us * 8) + remUsTicks;//*8/25其实是*320/1000,转换成ms

    // Convert the 320 us ticks into milliseconds and a remainder
    CONVERT_320US_TO_MS_ELAPSED_REMINDER( tmp, elapsedMSec, remUsTicks );
    //这个里面除以25了。temp是被除数,elapsedMSec商,remUsTicks是余数

    // Update OSAL Clock and Timers
//判断时间是否到了1ms,如果等于或者超过1ms(elapsedMSec  >= 1),则需要轮询任务列表
    {
      osalClockUpdate( elapsedMSec );
      osalTimerUpdate( elapsedMSec );
    }
  }
}

在上面代码部分,大部分已经做出注释了,大家可以结合cc2530的T2定时器看看,涉及到具体的硬件。下面我们需要知道的是上面代码结束时候的函数:

      osalTimerUpdate( elapsedMSec );

这个部分涉及到osal中一个非常重要的数据链表,是对每个任务的时间操作计时。当有一个事件触发的时候,该事件对应的数据就被添加到这个数据链表中,包括它的任务id,轮询时间,以及事件id,重新加载时间,以及next
这里写图片描述
OK,现在我们看看osalTimerUpdata里的内容:

void osalTimerUpdate( uint16 updateTime )
{
  halIntState_t intState;
  osalTimerRec_t *srchTimer;
  osalTimerRec_t *prevTimer;

  HAL_ENTER_CRITICAL_SECTION( intState );  // Hold off interrupts.
  // Update the system time
  osal_systemClock += updateTime;
  HAL_EXIT_CRITICAL_SECTION( intState );   // Re-enable interrupts.

  // Look for open timer slot
  if ( timerHead != NULL )
  {
    // Add it to the end of the timer list
    srchTimer = timerHead;
    prevTimer = (void *)NULL;

    // Look for open timer slot
    while ( srchTimer )//从头到尾遍历这个链表
    {
      osalTimerRec_t *freeTimer = NULL;

      HAL_ENTER_CRITICAL_SECTION( intState );  // Hold off interrupts.

      if (srchTimer->timeout <= updateTime)
      {
        srchTimer->timeout = 0;//timeout时间置0,下面设置事件
      }
      else
      {
        srchTimer->timeout = srchTimer->timeout - updateTime;//timeout时间减1
      }

      // Check for reloading
      if ( (srchTimer->timeout == 0) && (srchTimer->reloadTimeout) 
      && (srchTimer->event_flag) )//这三个条件都为1
      {
        // Notify the task of a timeout
        osal_set_event( srchTimer->task_id, srchTimer->event_flag );//设置该事件为1

        // Reload the timer timeout value
        srchTimer->timeout = srchTimer->reloadTimeout;
      }

      // When timeout or delete (event_flag == 0)
//该事件不需要看,删除事件
      {
        // Take out of list
        if ( prevTimer == NULL )
          timerHead = srchTimer->next;
        else
          prevTimer->next = srchTimer->next;

        // Setup to free memory
        freeTimer = srchTimer;

        // Next
        srchTimer = srchTimer->next;
      }
      else
      {
        // Get next
        prevTimer = srchTimer;
        srchTimer = srchTimer->next;
      }

      HAL_EXIT_CRITICAL_SECTION( intState ); 
        // Re-enable interrupts.

      if ( freeTimer )
      {
        if ( freeTimer->timeout == 0 )
        {
          osal_set_event( freeTimer->task_id, freeTimer->event_flag );
        }
        osal_mem_free( freeTimer );
      }
    }
  }
}

可以看到,当运行这个函数的时候,会对这个链表进行遍历,对timeout减1,当减到0时,有选择性的重新加载时间或者从该链表中删除该成员,并且将对应的事件置1,以便后边程序处理。
1.2 事件处理操作部分
这里我们先对数组tasksEvents和tasksArr[idx]做出简要介绍。
tasksEvents是一个指针,在z-stack中使用的时候都是当数组使用的,他里面记录的是有没有事件发生,如有有,则相应的位置置1。而taskArr是与tasksEvent里面一一对应的时间处理函数,这部分是一个函数数组。当taskEvents对应位置置1的时候,taskArr相对应的函数进行处理。

在上一篇的叙述的最后,我们提到

 osal_set_event(Hal_TaskID, HAL_KEY_EVENT);

这个部分已经把对应的tasksEvents[Hal_TaskID]置1,然后通过这段代码

  do {
    if (tasksEvents[idx])  // Task is highest priority that is ready.
    {
      break;
    }
  } while (++idx < tasksCnt);

发现已经置1,所以调用

events = (tasksArr[idx])( idx, events );

进入Hal_ProcessEvent函数进行处理。接下来调用这段代码

  if (events & HAL_KEY_EVENT)
  {

#if (defined HAL_KEY) && (HAL_KEY == TRUE)
    /* Check for keys */
    HalKeyPoll();

    /* if interrupt disabled, do next polling */
    if (!Hal_KeyIntEnable)
    {
      osal_start_timerEx( Hal_TaskID, HAL_KEY_EVENT, 100);
    }
#endif // HAL_KEY

    return events ^ HAL_KEY_EVENT;
  }

函数HalKeyPoll()是关于按键读取及回调处理函数

void HalKeyPoll (void)
{
  uint8 keys = 0;

  if ((HAL_KEY_JOY_MOVE_PORT & HAL_KEY_JOY_MOVE_BIT))  /* Key is active HIGH */
  {
    keys = halGetJoyKeyInput();//按键AD读取,判断是哪个按键
  }

  /* If interrupts are not enabled, previous key status and current key status
   * are compared to find out if a key has changed status.
   */
  if (!Hal_KeyIntEnable)//如果不使用中断
  {
    if (keys == halKeySavedKeys)//如果按键没有变化
    {
      /* Exit - since no keys have changed */
      return;
    }
    /* Store the current keys for comparation next time */
    halKeySavedKeys = keys;
  }
  else
  {
    /* Key interrupt handled here */
  }

  if (HAL_PUSH_BUTTON1())
  {
    keys |= HAL_KEY_SW_6;
  }

  /* Invoke Callback if new keys were depressed */
  if (keys && (pHalKeyProcessFunction))
  {
    (pHalKeyProcessFunction) (keys, HAL_KEY_STATE_NORMAL);//按键回调函数
  }
}

下面就转到回调函数

void OnBoard_KeyCallback ( uint8 keys, uint8 state )
{
  uint8 shift;
  (void)state;

  shift = (keys & HAL_KEY_SW_6) ? true : false;

  if ( OnBoard_SendKeys( keys, shift ) != ZSuccess )
  {
    // Process SW1 here
    if ( keys & HAL_KEY_SW_1 )  // Switch 1
    {
    }
    // Process SW2 here
    if ( keys & HAL_KEY_SW_2 )  // Switch 2
    {
    }
    // Process SW3 here
    if ( keys & HAL_KEY_SW_3 )  // Switch 3
    {
    }
    // Process SW4 here
    if ( keys & HAL_KEY_SW_4 )  // Switch 4
    {
    }
    // Process SW5 here
    if ( keys & HAL_KEY_SW_5 )  // Switch 5
    {
    }
    // Process SW6 here
    if ( keys & HAL_KEY_SW_6 )  // Switch 6
    {
    }
  }
}

需要重点注意的这句代码:

nBoard_SendKeys( keys, shift ) != ZSuccess

这句代码的意思就是发送数据到app层,进行数据处理

uint8 OnBoard_SendKeys( uint8 keys, uint8 state )
{
  keyChange_t *msgPtr;

  if ( registeredKeysTaskID != NO_TASK_ID )
  {
    // Send the address to the task
    msgPtr = (keyChange_t *)osal_msg_allocate( sizeof(keyChange_t) );
    if ( msgPtr )
    {
      msgPtr->hdr.event = KEY_CHANGE;
      msgPtr->state = state;
      msgPtr->keys = keys;

      osal_msg_send( registeredKeysTaskID, (uint8 *)msgPtr );
    }
    return ( ZSuccess );
  }
  else
    return ( ZFailure );
}

可以看到把KEY_CHANGE,state,key保存到结构体msgPtr中,然后通过osal_msg_send传递到另外一个重要的链表中,以便应用层处理。
这个链表是用于对两个进程之间进行任务传递的,相当于信号或者邮箱机制。
通过osal_msg_send()函数调用的osal_msg_enqueue()函数,这部分可以发现这里的链表中存的成员可以是不同结构的成员,这部分代码写的比较牛逼。

void osal_msg_enqueue( osal_msg_q_t *q_ptr, void *msg_ptr )
{
  void *list;
  halIntState_t intState;

  // Hold off interrupts
  HAL_ENTER_CRITICAL_SECTION(intState);

  OSAL_MSG_NEXT( msg_ptr ) = NULL;
  // If first message in queue
  if ( *q_ptr == NULL )
  {
    *q_ptr = msg_ptr;
  }
  else
  {
    // Find end of queue
    for ( list = *q_ptr; OSAL_MSG_NEXT( list ) != NULL; list = OSAL_MSG_NEXT( list ) );

    // Add message to end of queue
    OSAL_MSG_NEXT( list ) = msg_ptr;
  }

  // Re-enable interrupts
  HAL_EXIT_CRITICAL_SECTION(intState);
}

最后通过osal_msg_send()函数将sampleapp的任务置1,实现任务调度。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值