uc/os-ii訊息郵箱
阿新 • • 發佈:2019-02-17
訊息郵箱是一種通訊機制,它能使任務或中斷服務向另一個任務傳送一個指標型的變數,這個指標指向一個包含指定“訊息”的資料結構。訊息郵箱傳送的不是訊息本身,而是訊息的地址指標。使用訊息郵箱之前,必須先建立訊息郵箱,並且要指定指標的初始值。一般情況下,這個初始值是NULL,但也可以在初始化時,就使其在最開始就包含一條訊息。
訊息郵箱主要用於兩種目的:① 通知一個事件的發生;② 作二值訊號量用。
訊息郵箱初始值的設定方法如下:
(1) 如果使用訊息郵箱是用於通知一個事件的發生(傳送一條訊息),那麼就要初始化該訊息郵箱為NULL,因為在開始時,事件還沒有發生。
(2) 如果作二值訊號量用,即用於共享某些資源,那麼就要初始化該訊息郵箱為一個非NULL的指標。訊息郵箱具有如下特點:
(1) 訊息郵箱中的內容是一個指向訊息的指標,指標指向的內容即是訊息;
(2) 訊息郵箱為滿時,訊息郵箱只包含一個指向訊息的指標;訊息郵箱為空時,訊息郵箱的指標指向NULL;
(3) 訊息郵箱只能接收和傳送一則訊息,訊息郵箱為滿時,將丟棄新訊息,保留舊訊息。
µC/OS-Ⅱ提供了七種對訊息郵箱的操作,訊息郵箱函式所屬檔案是OS_MBOX.C。
OSMboxPend()函式用於任務等待訊息郵箱中的訊息。任務或者中斷髮出的訊息是指標型的變數,在不同的應用中訊息的使用也可能不同。該函式具有如下特點:
- 如果呼叫時訊息郵箱中已有訊息,那麼該訊息被返回給呼叫者,並從訊息郵箱中清除該訊息。
- 呼叫時,如果訊息郵箱中沒有訊息,則OSMboxPend()函式掛起當前任務直到得到需要的訊息或等待超時期滿。
- 該函式的呼叫者只能是任務,中斷不能呼叫。
- 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);
}