1. 程式人生 > >uc/os-ii訊息郵箱

uc/os-ii訊息郵箱

訊息郵箱是一種通訊機制,它能使任務或中斷服務向另一個任務傳送一個指標型的變數,這個指標指向一個包含指定“訊息”的資料結構。訊息郵箱傳送的不是訊息本身,而是訊息的地址指標。使用訊息郵箱之前,必須先建立訊息郵箱,並且要指定指標的初始值。一般情況下,這個初始值是NULL,但也可以在初始化時,就使其在最開始就包含一條訊息。   
訊息郵箱主要用於兩種目的:① 通知一個事件的發生;② 作二值訊號量用。

  • 訊息郵箱初始值的設定方法如下:
    (1) 如果使用訊息郵箱是用於通知一個事件的發生(傳送一條訊息),那麼就要初始化該訊息郵箱為NULL,因為在開始時,事件還沒有發生。  
    (2) 如果作二值訊號量用,即用於共享某些資源,那麼就要初始化該訊息郵箱為一個非NULL的指標。

  • 訊息郵箱具有如下特點:  
    (1) 訊息郵箱中的內容是一個指向訊息的指標,指標指向的內容即是訊息;  
    (2) 訊息郵箱為滿時,訊息郵箱只包含一個指向訊息的指標;訊息郵箱為空時,訊息郵箱的指標指向NULL;  
    (3) 訊息郵箱只能接收和傳送一則訊息,訊息郵箱為滿時,將丟棄新訊息,保留舊訊息。

µC/OS-Ⅱ提供了七種對訊息郵箱的操作,訊息郵箱函式所屬檔案是OS_MBOX.C。
這裡寫圖片描述

  • OSMboxPend()函式用於任務等待訊息郵箱中的訊息。任務或者中斷髮出的訊息是指標型的變數,在不同的應用中訊息的使用也可能不同。該函式具有如下特點:

    1. 如果呼叫時訊息郵箱中已有訊息,那麼該訊息被返回給呼叫者,並從訊息郵箱中清除該訊息。
    2. 呼叫時,如果訊息郵箱中沒有訊息,則OSMboxPend()函式掛起當前任務直到得到需要的訊息或等待超時期滿。
    3. 該函式的呼叫者只能是任務,中斷不能呼叫。
    4. OSMboxPend()函式返回接收的訊息指標。
void  *OSMboxPend (OS_EVENT *pevent, INT16U timeout, INT8U *perr)
{
    void      *pmsg;
#if OS_CRITICAL_METHOD == 3                           /* Allocate storage for CPU status register      */
    OS_CPU_SR
cpu_sr = 0; #endif #if OS_ARG_CHK_EN > 0 if (perr == (INT8U *)0) { /* Validate 'perr' */ return ((void *)0); } if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */ *perr = OS_ERR_PEVENT_NULL; return ((void *)0); } #endif if (pevent->OSEventType != OS_EVENT_TYPE_MBOX) { /* Validate event block type */ *perr = OS_ERR_EVENT_TYPE; return ((void *)0); } if (OSIntNesting > 0) { /* See if called from ISR ... */ *perr = OS_ERR_PEND_ISR; /* ... can't PEND from an ISR */ return ((void *)0); } if (OSLockNesting > 0) { /* See if called with scheduler locked ... */ *perr = OS_ERR_PEND_LOCKED; /* ... can't PEND when locked */ return ((void *)0); } OS_ENTER_CRITICAL(); pmsg = pevent->OSEventPtr; if (pmsg != (void *)0) { /* See if there is already a message */ pevent->OSEventPtr = (void *)0; /* Clear the mailbox */ OS_EXIT_CRITICAL(); *perr = OS_ERR_NONE; return (pmsg); /* Return the message received (or NULL) */ } OSTCBCur->OSTCBStat |= OS_STAT_MBOX; /* Message not available, task will pend */ OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK; OSTCBCur->OSTCBDly = timeout; /* Load timeout in TCB */ OS_EventTaskWait(pevent); /* Suspend task until event or timeout occurs */ OS_EXIT_CRITICAL(); OS_Sched(); /* Find next highest priority task ready to run */ OS_ENTER_CRITICAL(); switch (OSTCBCur->OSTCBStatPend) { /* See if we timed-out or aborted */ case OS_STAT_PEND_OK: pmsg = OSTCBCur->OSTCBMsg; *perr = OS_ERR_NONE; break; case OS_STAT_PEND_ABORT: pmsg = (void *)0; *perr = OS_ERR_PEND_ABORT; /* Indicate that we aborted */ break; case OS_STAT_PEND_TO: default: OS_EventTaskRemove(OSTCBCur, pevent); pmsg = (void *)0; *perr = OS_ERR_TIMEOUT; /* Indicate that we didn't get event within TO */ break; } OSTCBCur->OSTCBStat = OS_STAT_RDY; /* Set task status to ready */ OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK; /* Clear pend status */ OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0; /* Clear event pointers */ #if (OS_EVENT_MULTI_EN > 0) OSTCBCur->OSTCBEventMultiPtr = (OS_EVENT **)0; #endif OSTCBCur->OSTCBMsg = (void *)0; /* Clear received message */ OS_EXIT_CRITICAL(); return (pmsg); /* Return received message */ }
  • OSMboxPost()函式通過訊息郵箱向任務傳送訊息,訊息是指標型變數,訊息的資料型別可能會因具體應用的不同而有所差異。該函式具有如下特點:  
    (1) 如果訊息郵箱中已有訊息,返回錯誤程式碼說明訊息郵箱已滿,函式立即返回呼叫者,並丟棄新訊息;
    (2) 如果訊息郵箱無訊息,則:① 如果有任務在等待訊息,最高優先順序的任務將得到這個訊息。如果等待訊息的任務的優先順序比函式的呼叫者優先順序高,則這個高優先順序任務得以恢復執行,呼叫者被掛起,發生一次任務切換。 若從中斷呼叫,則不發生任務切換。② 如果沒有任務在等待訊息,則訊息的指標被儲存在訊息郵箱中。
INT8U  OSMboxPost (OS_EVENT *pevent, void *pmsg)
{
#if OS_CRITICAL_METHOD == 3                           /* Allocate storage for CPU status register      */
    OS_CPU_SR  cpu_sr = 0;
#endif
#if OS_ARG_CHK_EN > 0
    if (pevent == (OS_EVENT *)0) {                    /* Validate 'pevent'                             */
        return (OS_ERR_PEVENT_NULL);
    }
    if (pmsg == (void *)0) {                          /* Make sure we are not posting a NULL pointer   */
        return (OS_ERR_POST_NULL_PTR);
    }
#endif
    if (pevent->OSEventType != OS_EVENT_TYPE_MBOX) {  /* Validate event block type                     */
        return (OS_ERR_EVENT_TYPE);
    }
    OS_ENTER_CRITICAL();
    if (pevent->OSEventGrp != 0) {                    /* See if any task pending on mailbox            */
                                                      /* Ready HPT waiting on event                    */
        (void)OS_EventTaskRdy(pevent, pmsg, OS_STAT_MBOX, OS_STAT_PEND_OK);
        OS_EXIT_CRITICAL();
        OS_Sched();                                   /* Find highest priority task ready to run       */
        return (OS_ERR_NONE);
    }
    if (pevent->OSEventPtr != (void *)0) {            /* Make sure mailbox doesn't already have a msg  */
        OS_EXIT_CRITICAL();
        return (OS_ERR_MBOX_FULL);
    }
    pevent->OSEventPtr = pmsg;                        /* Place message in mailbox                      */
    OS_EXIT_CRITICAL();
    return (OS_ERR_NONE);
}