久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 6737|回復: 0
打印 上一主題 下一主題
收起左側

z-stack協議棧-數據包接收處理流程

[復制鏈接]
跳轉到指定樓層
樓主
ID:71477 發表于 2015-1-1 19:30 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式
有人對osal處理消息的機制及如果有數據包接收,協議棧到底是怎么來處理得到所需要的數據的有點不清楚,以下我簡單的按照我的理解寫一下。
其實只要觸發SYS_EVENT_MSG事件,首先都會有這樣一個語句:
MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( SampleApp_TaskID );
讓我們一步一步看下函數的意思,首先是osal_msg_receive()這個函數,來看一下原型:
@fn      osal_msg_receive
*
* @brief
*
*    This function is called by a task to retrieve a received command
*    message. The calling task must deallocate the message buffer after
*    processing the message using the osal_msg_deallocate() call.
*函數描述:
該函數通過一個任務調用來檢索收到的命令信息。調用的任務必須在利用osal_msg_deallocate()函數處理信息之后必須釋放消息占用的內存。
* @param   byte task_id - receiving tasks ID
*收到的任務ID
* @return  *byte - message information or NULL if no message
*消息信息或者空指針
byte *osal_msg_receive( byte task_id )
{
  osal_msg_hdr_t *listHdr;
  osal_msg_hdr_t *prevHdr=0;
  halIntState_t   intState;
  // Hold off interrupts
  HAL_ENTER_CRITICAL_SECTION(intState);
這個主要用于暫緩中斷
  // Point to the top of the queue
  listHdr = osal_qHead;
指向消息隊列的頭部
  // Look through the queue for a message that belongs to the asking task
在隊列中查找屬于該任務的消息。
  while ( listHdr != NULL )
  {
    if ( (listHdr - 1)->dest_id == task_id )
    {
      break;
    }
    prevHdr = listHdr;
    listHdr = OSAL_MSG_NEXT( listHdr );
  }
  // Did we find a message?
是否找到消息?
  if ( listHdr == NULL )
  {
    // Release interrupts
釋放中斷
   HAL_EXIT_CRITICAL_SECTION(intState);
    return NULL;
  }
  // Take out of the link list
從鏈接鏈表中拿出。
  osal_msg_extract( &osal_qHead, listHdr, prevHdr );
  // Release interrupts
  HAL_EXIT_CRITICAL_SECTION(intState);
  return ( (byte*) listHdr );
}
這個函數看來主要是提取屬于該任務的消息,osal在后臺維護一個消息隊列,對應的任務可以在該消息隊列中提取到屬于自己的消息,從而判斷是哪個時間需要處理,但這又有一個問題,到底osal怎么把消息送到osal的消息隊列中去呢,看來還有一些問題沒搞清楚,沒事,咱在繼續研究,讓我們在程序中好好找找,這就涉及到osal運行方式了,我們好好看看,一定要弄明白:
我們都知道在開發自己的應用程序時,對于我們開發者來說,一個任務包括最主要的兩個部分:首先要做的是做的是寫任務初始化函數,然后是相應的事件處理函數。當然,最后一步是將自己編寫的任務添加到osal任務隊列中去,這個主要由osalAddTasks()函數來完成。
而對于整個osal運行來說,主要的過程如下:
首先主要是進行一系列的初始化,然后就是進入一個死循環函數osal_start_system()
ZSEG int main( void )
{

  // Turn off interrupts
  osal_int_disable( INTS_ALL );

  // Make sure supply voltage is high enough to run
  zmain_vdd_check();
  // Initialize stack memory
  zmain_ram_init();
  // Initialize board I/O
  InitBoard( OB_COLD );
  // Initialze HAL drivers
  HalDriverInit();
  // Initialize NV System
  osal_nv_init( NULL );
  // Determine the extended address
  zmain_ext_addr();
  // Initialize basic NV items
  zgInit();
  // Initialize the MAC
  ZMacInit();
#ifndef NONWK
  // Since the AF isn't a task, call it's initialization routine
  afInit();
#endif
  // Initialize the operating system
  osal_init_system();
  // Allow interrupts
  osal_int_enable( INTS_ALL );
  // Final board initialization
  InitBoard( OB_READY );
  // Display information about this device
  zmain_dev_info();

#ifdef LCD_SUPPORTED
  zmain_lcd_init();
#endif
  osal_start_system(); // No Return from here
} // main()
osal_start_system()這個函數的原型如下:其主要功能是執行任務隊列中的任務。主要是通過不斷循環來實現。
void osal_start_system( void )
{
  uint16 events;
  uint16 retEvents;
  byte activity;
  halIntState_t intState;
  // Forever Loop
#if !defined ( ZBIT )
  for(;;)
#endif
  {
   
    Hal_ProcessPoll();//
    activity = false;
    activeTask = osalNextActiveTask();
    if ( activeTask )
    {
如果有任務的話就暫緩中斷。
      HAL_ENTER_CRITICAL_SECTION(intState);
      events = activeTask->events;//進入事件
      // Clear the Events for this task
      activeTask->events = 0;//對應事件清0
      HAL_EXIT_CRITICAL_SECTION(intState);
開放總斷。
      if ( events != 0 )
      {
        // Call the task to process the event(s)
        if ( activeTask->pfnEventProcessor )// 調用相應的任務事件處理函數
        {
          retEvents = (activeTask->pfnEventProcessor)( activeTask->taskID, events );
          // Add back unprocessed events to the current task
          HAL_ENTER_CRITICAL_SECTION(intState);
          activeTask->events |= retEvents;
          HAL_EXIT_CRITICAL_SECTION(intState);
          activity = true;
        }
      }
    }
    // Complete pass through all task events with no activity?
    if ( activity == false )//沒有相應的任務需要處理后就進入休眠模式。
    {
#if defined( POWER_SAVING )
      // Put the processor/system into sleep
      osal_pwrmgr_powerconserve();//進入休眠
#endif
    }
  }
整個流程下來,你可能并不知道任務里的事件是怎么觸發的,消息是怎么進行傳遞的,所以得繼續往下看(有點亂是吧,沒辦法,哥們,沒經過整理的東西往往是這么無力,O(∩_∩)O哈哈~)來,繼續:
這個函數里面一個關鍵函數是Hal_ProcessPoll(),不要小看這個函數,這個函數為系統設置了一個"心跳",稱之為心跳的原因主要是因為這個設置了一個定時器作為osal運行的時鐘,現在的關鍵是搞清楚這個時鐘在哪設置,怎樣引導osal工作(好像扯得遠了,沒事,把這些先慢慢搞清楚,然后就知道消息的傳送過程)這個函數調用的是這個函數 HalTimerTick(),這個函數原型如下:
void HalTimerTick (void)
{
  if (!halTimerRecord[HW_TIMER_1].intEnable)
  {
    halProcessTimer1 ();
  }
  if (!halTimerRecord[HW_TIMER_3].intEnable)
  {
    halProcessTimer3 ();
  }
  if (!halTimerRecord[HW_TIMER_4].intEnable)
  {
    halProcessTimer4 ();
  }
}
媽的,出了點問題,我不知道這些計時器的配置函數在哪,到底是哪個定時器作為osal運行的時鐘呢,halTimerRecord[HW_TIMER_1].intEnable到底是在哪配置的我沒找到相應的函數,沒事,等等,繼續找。。。。
按照我的感覺如果在osal任務初始化函數中(初始化我會拿另一節來講,這節就只講講這個)肯定可以找到一些端倪,于是按照思路找下去,有了一個不錯的發現:這個是板級初始化函數,我們來找,
void InitBoard( byte level )
{
  if ( level == OB_COLD )
  {
    // Initialize HAL
    HAL_BOARD_INIT();
    // Interrupts off
    osal_int_disable( INTS_ALL );
    // Turn all LEDs off
    HalLedSet( HAL_LED_ALL, HAL_LED_MODE_OFF );
    // Check for Brown-Out reset
    ChkReset();

   OnboardTimerIntEnable = FALSE;
   HalTimerConfig (OSAL_TIMER,                        // 8bit timer2
                  HAL_TIMER_MODE_CTC,                 // Clear Timer on Compare
                  HAL_TIMER_CHANNEL_SINGLE,           // Channel 1 - default
                  HAL_TIMER_CH_MODE_OUTPUT_COMPARE,   // Output Compare mode
                  OnboardTimerIntEnable,              // Use interrupt
                  Onboard_TimerCallBack);             // Channel Mode
  }
最主要的是這個函數 HalTimerConfig()設置了時鐘。
  else  // !OB_COLD
  {
#ifdef ZTOOL_PORT
    MT_IndReset();
#endif
   
    OnboardKeyIntEnable = HAL_KEY_INTERRUPT_DISABLE;
    HalKeyConfig( OnboardKeyIntEnable, OnBoard_KeyCallback);
  }
來看下HalTimerConfig()的原型:
uint8 HalTimerConfig (uint8 timerId, uint8 opMode, uint8 channel, uint8 channelMode,
                      bool intEnable, halTimerCBack_t cBack)
{
  uint8 hwtimerid;
  hwtimerid = halTimerRemap (timerId);
  if ((opMode & HAL_TIMER_MODE_MASK) && (timerId < HAL_TIMER_MAX) &&
      (channelMode & HAL_TIMER_CHANNEL_MASK) && (channel & HAL_TIMER_CHANNEL_MASK))
  {
    halTimerRecord[hwtimerid].configured    = TRUE;
    halTimerRecord[hwtimerid].opMode        = opMode;
    halTimerRecord[hwtimerid].channel       = channel;
    halTimerRecord[hwtimerid].channelMode   = channelMode;
    halTimerRecord[hwtimerid].intEnable     = intEnable;
    halTimerRecord[hwtimerid].callBackFunc  = cBack;//設置回調函數的指針。
  }
  else
  {
    return HAL_TIMER_PARAMS_ERROR;
  }
  return HAL_TIMER_OK;
}
層層調用我最后找到了這個函數(層層調用的我就不寫出來了,只寫最主要的)
void osal_update_timers( void )
{
  osalTimerUpdate( tmr_decr_time )
;//tmr_decr_time在void osalTimerInit( void )賦值,為:    tmr_decr_time = TIMER_DECR_TIME;define TIMER_DECR_TIME    1  // 1ms - has to be matched with TC_OCC 即是一毫秒即是每隔一毫秒更新一次定時器。但是有一個問題,我在例子中看到這個定時器沒有被打開。
}
osalTimerUpdate( tmr_decr_time )原型:
*********************************************************************
* @fn      osalTimerUpdate
*
* @brief   Update the timer structures for a timer tick.
*更新定時器的數據結構
* @param   none
*
* @return  none
*********************************************************************/
static void osalTimerUpdate( uint16 updateTime )//這個函數真有點讓我有點摸不著頭腦,不知道為啥多出來一個定時器鏈表。
{
  halIntState_t intState;
  osalTimerRec_t *srchTimer;
  osalTimerRec_t *prevTimer;
  osalTimerRec_t *saveTimer;
  HAL_ENTER_CRITICAL_SECTION( intState );  // Hold off interrupts.
  // Update the system time
  osal_systemClock += updateTime;
  // 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 )
    {
      // Decrease the correct amount of time
      if (srchTimer->timeout <= updateTime)
        srchTimer->timeout = 0;
      else
        srchTimer->timeout = srchTimer->timeout - updateTime;
      // When timeout, execute the task
      if ( srchTimer->timeout == 0 )
      {
        osal_set_event( srchTimer->task_id, srchTimer->event_flag );//這個函數又是關鍵。
        // Take out of list
        if ( prevTimer == NULL )
          timerHead = srchTimer->next;
        else
          prevTimer->next = srchTimer->next;
        // Next
        saveTimer = srchTimer->next;
        // Free memory
        osal_mem_free( srchTimer );
        srchTimer = saveTimer;
      }
      else
      {
        // Get next
        prevTimer = srchTimer;
        srchTimer = srchTimer->next;
      }
    }
#ifdef POWER_SAVING
    osal_retune_timers();這個函數以后再說。
#endif
  }
  HAL_EXIT_CRITICAL_SECTION( intState );   // Re-enable interrupts.
}
還是先上一個圖說明定時器數據鏈表吧,該圖來自奧特曼的筆記:
其實就是一個數據結構,沒啥復雜的,不要想復雜了,
typedef struct
{
  void *next;
  UINT16 timeout;
  UINT16 event_flag;
  byte task_id;
} osalTimerRec_t;。

有點暈,先不管上面的了,我不知道上面這個鏈表是怎么更新的,即是上述的鏈表的值是怎么賦值的,為什么要搞個這樣的表出來?(媽的,為了搞清楚開頭的那玩意跑到現在這么遠的地方了,越說越遠,沒辦法了,打破砂鍋問到底吧)先把這個高清楚之后在來看上面函數的具體作用,我看了奧特曼寫的一些東西,感覺有些不是很對,但是他說的一個函數引起了我的注意,這就是

byte osal_start_timerEx( byte taskID, UINT16 event_id, UINT16 timeout_value )
{
  halIntState_t intState;
  osalTimerRec_t *newTimer;
  HAL_ENTER_CRITICAL_SECTION( intState );  // Hold off interrupts.
  // Add timer
  newTimer = osalAddTimer( taskID, event_id, timeout_value );
添加一個新的任務到定時器鏈表中。
  if ( newTimer )
  {
#ifdef POWER_SAVING
    // Update timer registers
    osal_retune_timers();
    (void)timerActive;
#endif
    // Does the timer need to be started?
  //現在如果定時器沒有啟動,那么啟動定時器
    if ( timerActive == FALSE )
    {
      osal_timer_activate( TRUE
);//媽的,原來是在這里啟動的,難怪在osal初始化中可以開始不啟動。搞的我心里惴惴不安,還以為自己看錯了,
    }
  }
  HAL_EXIT_CRITICAL_SECTION( intState );   // Re-enable interrupts.
  return ( (newTimer != NULL) ? ZSUCCESS : NO_TIMER_AVAIL );
}
搞清楚了這個函數,看來這個函數主要的任務是將任務的一個對應事件送到上述的定時器鏈表中,那上面那個函數怎么執行呢,問題又來了,什么樣的情況下才去運行osalTimerUpdate()這個函數呢,在初始化的過程中運行了一次,但是,后來又是怎么運行的呢,如果是靠定時器溢出來運行的,那么這個機制又是怎樣的呢?
繼續看程序,繼續思考,別急。。。。。
查了有關資料,如果定時器溢出會調用這個函數halTimerSendCallBack(),看一下這個函數的原型,
void halTimerSendCallBack (uint8 timerId, uint8 channel, uint8 channelMode)
{
  uint8 hwtimerid;
  hwtimerid = halTimerRemap (timerId);
  if (halTimerRecord[hwtimerid].callBackFunc)
    (halTimerRecord[hwtimerid].callBackFunc) (timerId, channel, channelMode);
}
即如果系統定時器溢出后將調用這個函數(調用機制等下再來看)并找出對應的定時器回調函數,系統定時器的回調函數是這個void Onboard_TimerCallBack ( uint8 timerId, uint8 channel, uint8 channelMode)
{
  if ((timerId == OSAL_TIMER) && (channelMode == HAL_TIMER_CH_MODE_OUTPUT_COMPARE))
  {
    osal_update_timers();
  }
}
這樣就知道了如果定時器每溢出一次將會調用這個osal_update_timers();函數一次,現在我們再回來看看到底他媽的這個函數是干嘛用的:。。。。。。。。
osalTimerUpdate( tmr_decr_time )原型:
*********************************************************************
* @fn      osalTimerUpdate
*
* @brief   Update the timer structures for a timer tick.
*更新定時器的數據結構
* @param   none
*
* @return  none
*********************************************************************/
static void osalTimerUpdate( uint16 updateTime )
{
  halIntState_t intState;
  osalTimerRec_t *srchTimer;
  osalTimerRec_t *prevTimer;
  osalTimerRec_t *saveTimer;//
這些是鏈表的相應指針,不要怕,知道嗎,都學過了,呵呵
  HAL_ENTER_CRITICAL_SECTION( intState );  // Hold off interrupts.
  // Update the system time
  osal_systemClock += updateTime;//
更新系統時間,這個osal_systemClock 是一個非常大的數,static uint32 osal_systemClock;
  // 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 )
    {
      // Decrease the correct amount of time
      if (srchTimer->timeout <= updateTime)
        srchTimer->timeout = 0;
      else
        srchTimer->timeout = srchTimer->timeout - updateTime;
      // When timeout, execute the task
      if ( srchTimer->timeout == 0 )
      {
        osal_set_event( srchTimer->task_id, srchTimer->event_flag );//這個函數又是關鍵。
        // Take out of list
        if ( prevTimer == NULL )
          timerHead = srchTimer->next;
        else
          prevTimer->next = srchTimer->next;
        // Next
        saveTimer = srchTimer->next;
        // Free memory
        osal_mem_free( srchTimer );
        srchTimer = saveTimer;
      }
      else
      {
        // Get next
        prevTimer = srchTimer;
        srchTimer = srchTimer->next;
      }
    }
#ifdef POWER_SAVING
    osal_retune_timers();
這個函數以后再說。
#endif
  }
  HAL_EXIT_CRITICAL_SECTION( intState );   // Re-enable interrupts.
}
這下應該看懂了吧,主要是在timeout的時間后執行
osal_set_event( srchTimer->task_id, srchTimer->event_flag );好的先,把大體流程總結一下在來看,如果假設利用osal_start_timerEx()函數設置了一個事件,并將其加入到定時器鏈表中,這時候定時器啟動,并且如果溢出的時候就會調用osalTimerUpdate()函數,在每次執行后都會檢查時間對應timeout是否等于0,如果等于零的時候就會調用這個函數osal_set_event( srchTimer->task_id, srchTimer->event_flag),現在我們來仔細看一下這個函數,

byte osal_set_event( byte task_id, UINT16 event_flag )
{
  osalTaskRec_t *srchTask;
  halIntState_t   intState;
  srchTask = osalFindTask( task_id );//找到這個任務
  if ( srchTask ) {
    // Hold off interrupts
    HAL_ENTER_CRITICAL_SECTION(intState);
    // Stuff the event bit(s)
    srchTask->events |= event_flag;//
設定相應事件的標志。
**************************************
注:這里的events標志可以設定為一個非零值,而這個非零值就是對應的事件,在執行的時候就是根據相應的值來執行相應的事件。
**************************************
    // Release interrupts
    HAL_EXIT_CRITICAL_SECTION(intState);
  }
   else
    return ( INVALID_TASK );
  return ( ZSUCCESS );
}
這下知道了這個函數主要是置位相應的事件,然后傳給系統的處理,系統處理這個主要是經過輪詢
主要靠這個函數實現:
osalTaskRec_t *osalNextActiveTask( void )
{
  osalTaskRec_t *srchTask;
  // Start at the beginning
  srchTask = tasksHead;
  // When found or not
  while ( srchTask )  {
      if (srchTask->events)  {
    // task is highest priority that is ready
          return srchTask;
      }
      srchTask = srchTask->next;
  }
  return NULL;
}
它返回一個指向typedef struct osalTaskRec
{
  struct osalTaskRec  *next;
  pTaskInitFn          pfnInit;
  pTaskEventHandlerFn  pfnEventProcessor;
  byte                 taskID;
  byte                 taskPriority;
  uint16               events;
} osalTaskRec_t;
的指針。
然后將任務交給retEvents = (activeTask->pfnEventProcessor)( activeTask->taskID, events );這個處理, 這還沒有結束,我們在開頭提到的這個還沒有解決;
MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( SampleApp_TaskID );(終于回來了,累啊)
這里涉及到兩個數據結構:
typedef struct
{
  void   *next;
  uint16 len;
  byte   dest_id;
} osal_msg_hdr_t;
typedef struct
{
  uint8  event;
  uint8  status;
} osal_event_hdr_t;
我查了一下有這么一個函數和消息有關的,如下
*********************************************************************
* @fn      osal_msg_send
*
* @brief
*
*    This function is called by a task to send a command message to
*    another task or processing element.  The sending_task field must
*    refer to a valid task, since the task ID will be used
*    for the response message.  This function will also set a message
*    ready event in the destination tasks event list.
*這個函數主要由任務調用發送一個命令消息到另一個任務或是處理元素,同時這個函數將會設定一個消息事件到目的任務的事件列表中
*
* @param   byte destination task - Send msg to?  Task ID
* @param   byte *msg_ptr - pointer to new message buffer
* @param   byte len - length of data in message
*
* @return  ZSUCCESS, INVALID_SENDING_TASK, INVALID_DESTINATION_TASK,
*          INVALID_MSG_POINTER, INVALID_LEN
*/
byte osal_msg_send( byte destination_task, byte *msg_ptr )
{
  if ( msg_ptr == NULL )
    return ( INVALID_MSG_POINTER );
  if ( osalFindTask( destination_task ) == NULL )
  {
    osal_msg_deallocate( msg_ptr );
    return ( INVALID_TASK );
  }
  // Check the message header
  if ( OSAL_MSG_NEXT( msg_ptr ) != NULL ||
       OSAL_MSG_ID( msg_ptr ) != TASK_NO_TASK )
  {
    osal_msg_deallocate( msg_ptr );
    return ( INVALID_MSG_POINTER );
  }
  OSAL_MSG_ID( msg_ptr ) = destination_task;
  // queue message
  osal_msg_enqueue( &osal_qHead, msg_ptr );//入消息隊列,
  // Signal the task that a message is waiting
  osal_set_event( destination_task, SYS_EVENT_MSG );//設定一個系統事件。
  return ( ZSUCCESS );
}
看來,這個osal_msg_send()函數只是發送一個系統事件,而和用戶自定義的事件無關(自己猜想的,以后驗證。)。
現在大家應該豁然開朗了吧,我們終于走到了新的一步了。

分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏 分享淘帖 頂 踩
回復

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規則

手機版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術交流QQ群281945664

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 精品久久久久久亚洲精品 | 亚洲国产一区二区视频 | 一级黄色播放 | 51ⅴ精品国产91久久久久久 | 中日av| 欧美日韩免费在线 | 国产精品自产拍 | 免费高清av | 祝你幸福电影在线观看 | 99色在线| 亚洲日本国产 | 国产91一区| 国产精品日韩欧美一区二区三区 | 亚洲精品aⅴ | 精品久久久久久久久久久久 | 国产精品久久久久久 | 四虎精品在线 | 亚洲视频 欧美视频 | 亚洲最大av | 男女羞羞视频免费 | 色999视频 | 亚洲瑟瑟 | 久久久精品国产 | 国产免费一区 | 日韩精品一区二区久久 | 国产精品视频免费观看 | 日韩av成人在线 | 北条麻妃99精品青青久久主播 | 成人一区二区三区 | 三级黄色片在线观看 | 青青久久 | 日韩成人在线播放 | 国产成人精品999在线观看 | 国产精品毛片久久久久久 | 99热在线观看精品 | 91精品国产91久久久久游泳池 | 久久久久久国产精品 | 亚洲精品日韩在线 | 日韩视频在线观看中文字幕 | 亚洲精品99| 一区中文字幕 |