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

来源:互联网 发布:c语言入门 txt下载 编辑:程序博客网 时间:2024/04/28 13:51

接着上面的写,下面就说到整个协议栈的主循环来了,一个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 0
原创粉丝点击