liteos事件(六)

yooooooo發表於2019-05-25

1. 概述

1.1 基本概念

事件是一種實現任務間通訊的機制,可用於實現任務間的同步,但事件通訊只能是事件型別的通訊,無資料傳輸。一個任務可以等待多個事件的發生:可以是任意一個事件發生時喚醒任務進行事件處理;也可以是幾個事件都發生後才喚醒任務進行事件處理。事件集合用32位無符號整型變數來表示,每一位代表一個事件。

多工環境下,任務之間往往需要同步操作,一個等待即是一個同步。事件可以提供一對多、多對多的同步操作。一對多同步模型:一個任務等待多個事件的觸發;多對多同步模型:多個任務等待多個事件的觸發。

任務可以通過建立事件控制塊來實現對事件的觸發和等待操作。 Huawei LiteOS的事件僅用於任務間的同步,不提供資料傳輸功能。

Huawei LiteOS提供的事件具有如下特點:

  • 事件不與任務相關聯,事件相互獨立,一個32位的變數,用於標識該任務發生的事件型別,其中每一位表示一種事件型別(0表示該事件型別未發生、 1表示該事件型別已經發生),一共31種事件型別(第25位保留)。
  • 事件僅用於任務間的同步,不提供資料傳輸功能。
  • 多次向任務傳送同一事件型別,等效於只傳送一次。
  • 允許多個任務對同一事件進行讀寫操作。
  • 支援事件讀寫超時機制。

1.2 事件控制塊

/**
* @ingroup los_event
* Event control structure
*/
typedef struct tagEvent
{
UINT32 uwEventID; /**標識發生的事件型別位*/
LOS_DL_LIST stEventList; /**讀取事件任務連結串列*/
} EVENT_CB_S, *PEVENT_CB_S;

uwEventID:用於標識該任務發生的事件型別,其中每一位表示一種事件型別(0表示該事件型別未發生、 1表示該事件型別已經發生),一共31種事件型別,第25位系統保留。

1.3 事件讀取模式

在讀事件時,可以選擇讀取模式。讀取模式如下:

所有事件(LOS_WAITMODE_AND):讀取掩碼中所有事件型別,只有讀取的所有事件型別都發生了,才能讀取成功。

任一事件(LOS_WAITMODE_OR): 讀取掩碼中任一事件型別,讀取的事件中任意一種事件型別發生了,就可以讀取成功。

清除事件(LOS_WAITMODE_CLR): LOS_WAITMODE_AND|

LOS_WAITMODE_CLR或 LOS_WAITMODE_OR| LOS_WAITMODE_CLR 時表示讀取成功後,對應事件型別位會自動清除。

2. 運作機制

讀事件時,可以根據入參事件掩碼型別uwEventMask讀取事件的單個或者多個事件型別。事件讀取成功後,如果設定LOS_WAITMODE_CLR會清除已讀取到的事件型別,反之不會清除已讀到的事件型別,需顯式清除。可以通過入參選擇讀取模式,讀取事件掩碼型別中所有事件還是讀取事件掩碼型別中任意事件。

寫事件時,對指定事件寫入指定的事件型別,可以一次同時寫多個事件型別。寫事件會觸發任務排程。

清除事件時,根據入參事件和待清除的事件型別,對事件對應位進行清0操作。

liteos事件(六)

3. 開發指導

3.1 使用場景

事件可應用於多種任務同步場合,能夠一定程度替代訊號量。

3.2 功能

Huawei LiteOS系統中的事件模組為使用者提供下面幾個介面。

功能分類 介面名 描述
事件初始化 LOS_EventInit 初始化一個事件控制塊
讀事件 LOS_EventRead 讀取指定事件型別,超時時間為相對時間:單位為Tick
寫事件 LOS_EventWrite 寫指定的事件型別
清除事件 LOS_EventClear 清除指定的事件型別
校驗事件掩碼 LOS_EventPoll 根據使用者傳入的事件值、事件掩碼及校驗模式,返回使用者傳入的事件是否符合預期
銷燬事件 LOS_EventDestroy 銷燬指定的事件控制塊

3.3 開發流程

使用事件模組的典型流程如下:

  1. 呼叫事件初始化LOS_EventInit介面,初始化事件等待佇列。
  2. 寫事件LOS_EventWrite,配置事件掩碼型別。
  3. 讀事件LOS_EventRead,可以選擇讀取模式。
  4. 清除事件LOS_EventClear,清除指定的事件型別。

3.4 Event 錯誤碼

序號 定義 實際值 描述 參考解決方案
1 LOS_ERRNO_EVENT_SETBIT_INVALID 0x02001c00 事件ID的第25個bit不能設定為1,因為該位已經作為錯誤碼使用 事件ID的第25bit置為0
2 LOS_ERRNO_EVENT_READ_TIMEOUT 0x02001c01 讀超時 增加等待時間或者重新讀取
3 LOS_ERRNO_EVENT_EVENTMASK_INVALID 0x02001c02 入參的事件ID是無效的 傳入有效的事件ID引數
4 LOS_ERRNO_EVENT_READ_IN_INTERRUPT 0x02001c03 在中斷中讀取事件 啟動新的任務來獲取事件
5 LOS_ERRNO_EVENT_FLAGS_INVALID 0x02001c04 讀取事件的mode無效 傳入有效的mode引數
6 LOS_ERRNO_EVENT_READ_IN_LOCK 0x02001c05 任務鎖住,不能讀取事件 解鎖任務,再讀取事件
7 LOS_ERRNO_EVENT_PTR_NULL 0x02001c06 傳入的引數為空指標 傳入非空入參

錯誤碼定義:錯誤碼是一個32位的儲存單元, 31~24位表示錯誤等級, 23~16位表示錯誤碼標誌, 15~8位代表錯誤碼所屬模組, 7~0位表示錯誤碼序號,如下

#define LOS_ERRNO_OS_ERROR(MID, ERRNO) \
(LOS_ERRTYPE_ERROR | LOS_ERRNO_OS_ID | ((UINT32)(MID) << 8) | (ERRNO))
LOS_ERRTYPE_ERROR: Define critical OS errors
LOS_ERRNO_OS_ID: OS error code flag
MID: OS_MOUDLE_ID
LOS_MOD_EVENT: Event module ID
ERRNO: error ID number

例如:

#define LOS_ERRNO_EVENT_READ_IN_LOCK
LOS_ERRNO_OS_ERROR(LOS_MOD_EVENT, 0x05)

3.5 平臺差異性

4. 注意事項

  • 在系統初始化之前不能呼叫讀寫事件介面。如果呼叫,則系統執行會不正常。
  • 在中斷中,可以對事件物件進行寫操作,但不能讀操作。
  • 在鎖任務排程狀態下,禁止任務阻塞與讀事件。
  • LOS_EventClear 入參值是:要清除的指定事件型別的反碼(~uwEvents)。
  • 事件掩碼的第25位不能使用,原因是為了區別LOS_EventRead介面返回的是事件還是錯誤碼。

5. 程式設計例項

5.1 例項描述

示例中,任務Example_TaskEntry建立一個任務Example_Event, Example_Event讀事件阻塞, Example_TaskEntry向該任務寫事件。

  1. 在任務Example_TaskEntry建立任務Example_Event,其中任務Example_Event優先順序高於Example_TaskEntry。
  2. 在任務Example_Event中讀事件0x00000001,阻塞,發生任務切換,執行任務Example_TaskEntry。
  3. 在任務Example_TaskEntry向任務Example_Event寫事件0x00000001,發生任務切換,執行任務Example_Event。
  4. Example_Event得以執行,直到任務結束。
  5. Example_TaskEntry得以執行,直到任務結束。

5.2 程式設計示例

可以通過列印的先後順序理解事件操作時伴隨的任務切換。

程式碼實現如下:

#include "los_event.h"
#include "los_task.h"
/*任務PID*/
UINT32 g_TestTaskID01;
/*事件控制結構體*/
EVENT_CB_S example_event;
/*等待的事件型別*/
#define event_wait 0x00000001
/*用例任務入口函式*/
VOID Example_Event()
{
    UINT32 uwRet;
    UINT32 uwEvent;
    /*超時 等待方式讀事件,超時時間為100 Tick若100 Tick 後未讀取到指定事件,讀事件超時,任務直接喚醒*/
    printf("Example_Event wait event 0x%x \n",event_wait);
    uwEvent = LOS_EventRead(&example_event, event_wait, LOS_WAITMODE_AND, 100);
    if(uwEvent == event_wait)
    {
        printf("Example_Event,read event :0x%x\n",uwEvent);
    }
    else
        printf("Example_Event,read event timeout\n");
    return;
}
UINT32 Example_TaskEntry()
{
    UINT32 uwRet;
    TSK_INIT_PARAM_S stTask1;
    /*事件初始化*/
    uwRet = LOS_EventInit(&example_event);
    if(uwRet != LOS_OK)
    {
        printf("init event failed .\n");
        return -1;
    }
    /*建立任務*/
    memset(&stTask1, 0, sizeof(TSK_INIT_PARAM_S));
    stTask1.pfnTaskEntry = (TSK_ENTRY_FUNC)Example_Event;
    stTask1.pcName = "EventTsk1";
    stTask1.uwStackSize = OS_TSK_DEFAULT_STACK_SIZE;
    stTask1.usTaskPrio = 5;
    uwRet = LOS_TaskCreate(&g_TestTaskID01, &stTask1);
    if(uwRet != LOS_OK)
    {
        printf("task create failed .\n");
        return LOS_NOK;
    }
    /*寫用例任務等待的事件型別*/
    printf("Example_TaskEntry write event .\n");
    uwRet = LOS_EventWrite(&example_event, event_wait);
    if(uwRet != LOS_OK)
    {
        printf("event write failed .\n");
        return LOS_NOK;
    }
    /*清標誌位*/
    printf("EventMask:%d\n",example_event.uwEventID);
    LOS_EventClear(&example_event, ~example_event.uwEventID);
    printf("EventMask:%d\n",example_event.uwEventID);
    /*刪除任務*/
    uwRet = LOS_TaskDelete(g_TestTaskID01);
    if(uwRet != LOS_OK)
    {
        printf("task delete failed .\n");
        return LOS_NOK;
    }
    return LOS_OK;
}

5.3 結果驗證

編譯執行得到的結果為:

Example_Event wait event 0x1
Example_TaskEntry write event .
Example_Event,read event :0x1
EventMask:1
EventMask:0

相關文章