日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 综合教程 >内容正文

综合教程

有关zstack的osal机制的理解

發布時間:2023/12/13 综合教程 32 生活家
生活随笔 收集整理的這篇文章主要介紹了 有关zstack的osal机制的理解 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

本文就淺談一下有關osal的事件驅動消息響應的機制。我是菜鳥,沒有做過什么軟件,沒有搞過VC,沒有學過linux,所以理解起來就有點吃力,所以現在感覺沒有不懂軟件的it民工真可怕。ok,切入正題。

一、windows OS的事件驅動消息響應機制

osal是面向多用戶的操作系統,現在活著的操作系統基本上都是多用戶的,所以我們現在先來了解一下windows OS的基于事件驅動消息響應的機制,先以基于windows窗口程序為例吧。

假設現在有一個按鍵按下,windows OS就會首先知道有這個按鍵事件按下,那么這個時候windows OS就會向這個窗口發送消息,告訴這個這個窗口程序現在又按鍵事件發生了,并調用相應的事件處理函數來處理這個事件,并且windows OS會向這個事件發送相應的消息信息,并將這個消息放到這個窗口的消息隊列中。消息信息中包含相關參數信息,比如是哪一個按鍵按下。在這里我們可以看到很多這里有很多的事情是windows OS來為這個窗口程序來處理的,而不是窗口程序本身,也就是說是windows OS為調用了窗口程序而不是窗口程序調用了windows OS的API函數來處理事件。

在windows OS調用了相應事件的處理函數以后,那么就會執行這個函數,并對消息作出相應的處理。當進入到事件處理函數以后,首先會讀取從消息隊列中讀取消息,然后作出處理,看看是鼠標按鍵按下了還是數字鍵按下等等。

二、ZStack中消息響應的過程

有了上面的理解基礎之后,我們來看看zstack中是如何來進行事件驅動消息響應的。

前面的一篇“ZStack任務”文章講過如下一段話:Any OSAL Task must implement two methods:one to perform task initialization and the other to handle task events. 也就是說任何一個任務包含兩個必需成分:初始化和處理。初始化主要是進行任務id,端點的配置等等。處理部分就是一個處理函數,用于處理事件發生的事情。

void osalInitTasks( void )

{

uint8 taskID = 0;

tasksEvents = (uint16 *)osal_mem_alloc( sizeof( uint16 ) * tasksCnt);

osal_memset( tasksEvents, 0, (sizeof( uint16 ) * tasksCnt));

...

SAPI_Init( taskID );

}

這是初始化函數,這里實現了兩個功能,第一個是初始化任務,并且將任務加入到任務隊列中。這里主要是依據后面的一個tasksArr[]數組中對應的順序決定哪一個初始化函數對已哪一個事件處理函數。

接著看下面的。在完成各類初始化以后,系統就調用這個osal_start_system();這就意味著進入到了操作系統的死循環中,也就是任務調度中。先看代碼,親們。

void osal_start_system( void )

{

#if !defined ( ZBIT ) && !defined ( UBIT )

for(;;) // Forever Loop

#endif

{

uint8 idx = 0;

osalTimeUpdate();

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);

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

}

}

首先執行這兩個, osalTimeUpdate(); Hal_ProcessPoll();

第一個函數是進行系統時間更新的,相當于說系統會有自己的一個個時鐘頻率,就是定時來更新,系統不是時刻在蘇醒者,她也要休息,要睡覺,這點可能是為了節能,為了體現zigbee的優勢。第二就是系統醒了之后就來查詢各種資源的使用情況,例如串口,跟蹤進去就看到了如下的代碼:

void Hal_ProcessPoll ()

{

/* Timer Poll */

#if (defined HAL_TIMER) && (HAL_TIMER == TRUE)

HalTimerTick();

#endif

/* UART Poll */

#if (defined HAL_UART) && (HAL_UART == TRUE)

HalUARTPoll();

#endif

/* SPI Poll */

#if (defined HAL_SPI) && (HAL_SPI == TRUE)

HalSpiPoll();

#endif

/* HID poll */

#if (defined HAL_HID) && (HAL_HID == TRUE)

usbHidProcessEvents();

#endif

}

大家看一下就清楚,具體就不糾結了。

現在來看紅色字體的部分,首先從tasksEvents[idx]這個數組中取出事件,并判斷其優先級,如果這個事件已經準備好了,就跳出循環來處理。現在看藍色部分的代碼。

events = tasksEvents[idx];

tasksEvents[idx] = 0; // Clear the Events for this task

首先取出事件,并將這個時間的ID清零。現在大家注意了,最重要的東西來了。

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

這個執行后,就是系統去調用了相應的事件了。大家將這點結合上面講的windows OS的處理機制來理解不很容易了。這里就是osal調用處理事件了。上面那個語句 (tasksArr[idx])( idx, events );實際就是利用一個指向函數的指針來調用相應的事件了。來看看這個tasksArr的定義就清楚了。

const pTaskEventHandlerFn tasksArr[] = {

macEventLoop,

nwk_event_loop,

Hal_ProcessEvent,

#if defined( MT_TASK )

MT_ProcessEvent,

#endif

APS_event_loop,

ZDApp_event_loop,

SAPI_ProcessEvent

};

在這里就看到了我們初始化的函數了,當我們的任務來臨了調用這個函數來執行相應的事件。ok,現在來看看事件是如何利用消息處理的事件的。

UINT16 SAPI_ProcessEvent( byte task_id, UINT16 events )

{

osal_event_hdr_t *pMsg;

afIncomingMSGPacket_t *pMSGpkt;

afDataConfirm_t *pDataConfirm;

if ( events & SYS_EVENT_MSG )

{

pMsg = (osal_event_hdr_t *) osal_msg_receive( task_id );

while ( pMsg )

{

switch ( pMsg->event )

{

case ZDO_CB_MSG:

SAPI_ProcessZDOMsgs( (zdoIncomingMsg_t *)pMsg );

break;

case AF_DATA_CONFIRM_CMD:

// This message is received as a confirmation of a data packet sent.

// The status is of ZStatus_t type [defined in ZComDef.h]

// The message fields are defined in AF.h

pDataConfirm = (afDataConfirm_t *) pMsg;

SAPI_SendDataConfirm( pDataConfirm->transID, pDataConfirm->hdr.status );

break;

case AF_INCOMING_MSG_CMD:

pMSGpkt = (afIncomingMSGPacket_t *) pMsg;

SAPI_ReceiveDataIndication( pMSGpkt->srcAddr.addr.shortAddr, pMSGpkt->clusterId,

pMSGpkt->cmd.DataLength, pMSGpkt->cmd.Data);

break;

case ZDO_STATE_CHANGE:

// If the device has started up, notify the application

if (pMsg->status == DEV_END_DEVICE ||

pMsg->status == DEV_ROUTER ||

pMsg->status == DEV_ZB_COORD )

{

SAPI_StartConfirm( ZB_SUCCESS );

}

else if (pMsg->status == DEV_HOLD ||

pMsg->status == DEV_INIT)

{

SAPI_StartConfirm( ZB_INIT );

}

break;

case ZDO_MATCH_DESC_RSP_SENT:

SAPI_AllowBindConfirm( ((ZDO_MatchDescRspSent_t *)pMsg)->nwkAddr );

break;

case KEY_CHANGE:

#if ( SAPI_CB_FUNC )

zb_HandleKeys( ((keyChange_t *)pMsg)->state, ((keyChange_t *)pMsg)->keys );

#endif

break;

case SAPICB_DATA_CNF:

SAPI_SendDataConfirm( (uint8)((sapi_CbackEvent_t *)pMsg)->data,

((sapi_CbackEvent_t *)pMsg)->hdr.status );

break;

case SAPICB_BIND_CNF:

SAPI_BindConfirm( ((sapi_CbackEvent_t *)pMsg)->data,

((sapi_CbackEvent_t *)pMsg)->hdr.status );

break;

case SAPICB_START_CNF:

SAPI_StartConfirm( ((sapi_CbackEvent_t *)pMsg)->hdr.status );

break;

default:

// User messages should be handled by user or passed to the application

if ( pMsg->event >= ZB_USER_MSG )

{

}

break;

}

// Release the memory

osal_msg_deallocate( (uint8 *) pMsg );

// Next

pMsg = (osal_event_hdr_t *) osal_msg_receive( task_id );

}

// Return unprocessed events

return (events ^ SYS_EVENT_MSG);

}

if ( events & ZB_ALLOW_BIND_TIMER )

{

afSetMatch(sapi_epDesc.simpleDesc->EndPoint, FALSE);

return (events ^ ZB_ALLOW_BIND_TIMER);

}

if ( events & ZB_BIND_TIMER )

{

// Send bind confirm callback to application

SAPI_BindConfirm( sapi_bindInProgress, ZB_TIMEOUT );

sapi_bindInProgress = 0xffff;

return (events ^ ZB_BIND_TIMER);

}

if ( events & ZB_ENTRY_EVENT )

{

uint8 startOptions;

// Give indication to application of device startup

#if ( SAPI_CB_FUNC )

zb_HandleOsalEvent( ZB_ENTRY_EVENT );

#endif

// LED off cancels HOLD_AUTO_START blink set in the stack

HalLedSet (HAL_LED_4, HAL_LED_MODE_OFF);

zb_ReadConfiguration( ZCD_NV_STARTUP_OPTION, sizeof(uint8), &startOptions );

if ( startOptions & ZCD_STARTOPT_AUTO_START )

{

zb_StartRequest();

}

else

{

// blink leds and wait for external input to config and restart

HalLedBlink(HAL_LED_2, 0, 50, 500);

}

return (events ^ ZB_ENTRY_EVENT );

}

// This must be the last event to be processed

if ( events & ( ZB_USER_EVENTS ) )

{

// User events are passed to the application

#if ( SAPI_CB_FUNC )

zb_HandleOsalEvent( events );

#endif

// Do not return here, return 0 later

}

// Discard unknown events

return 0;

}

在這里先看紅色的語句,

pMsg = (osal_event_hdr_t *) osal_msg_receive( task_id );

這個語句就是利用任務id來從取出消息。接下來的switch語句就是處理消息了,這里有各種消息,看藍色字體的部分。以KEY_CHANGE為例,當消息為按鍵改變的時候,那么就會調用相應的函數去進行處理,調用的函數就是:

zb_HandleKeys( ((keyChange_t *)pMsg)->state, ((keyChange_t *)pMsg)->keys );

當處理完消息之后就會向消息將該消息從消息隊列中刪除:

pMsg = (osal_event_hdr_t *) osal_msg_receive( task_id );

小結:

事件驅動消息響應是為多任務的處理服務的。OSAL首先進行進行處理任務的初始化,并將任務添加到任務隊列中。當任務發生以后,OSAL會首先知道有這個事件發生,并調用相應的處理事件,同時OSAL會向這個OSAL的消息隊列中發送消息。當執行處理事件后,處理事件首先從消息隊列中取出消息,然后對消息進行處理,消息執行完畢后將該消息從消息隊列中刪除。

總結

以上是生活随笔為你收集整理的有关zstack的osal机制的理解的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。