- 简单介绍邮箱机制
- 从邮箱中接收消息void *OSMboxAccept (OS_EVENT *pevent
- 建立并初始化一个邮箱OS_EVENT *OSMboxCreate (void *pmsg)
- 删除邮箱OS_EVENT *OSMboxDel (OS_EVENT *pevent,INT8U opt,INT8U *perr)
- 取消等待消息的任务OSMboxPendAbort (OS_EVENT *pevent,INT8U opt,INT8U *perr)
- 通过消息邮箱向任务发送消息OSMboxPost (OS_EVENT *pevent,void *pmsg)
- 通过邮箱向(多)任务发送消息OSMboxPostOpt (OS_EVENT *pevent,void *pmsg,INT8U opt)
- 取得邮箱中的信息OSMboxQuery (OS_EVENT *pevent, OS_MBOX_DATA *p_mbox_data)
邮箱机制简单介绍一下:
- 在uc/os-ii中,完成一次两个任务间的消息传递,只需要一个邮箱,并且邮箱中只能存放一个消息。在消息没有取走前,不能在邮箱中存放新的消息。
- uc/os-ii中存放和传递的是消息内容缓冲区的指针。
- 在uc/os-ii中,调度系统不能自动通知某个任务邮箱中已经有消息,需要任务主动去取邮件(调用函数OSMboxPend())。
- 邮箱操作过程:uc/os-ii邮箱通信的过程首先建立一个数据缓冲区,即创建邮箱。一个系统中或者一个任务可以建立多个邮箱。不同邮箱通过邮箱指针来识别,该指针在建立邮箱时产生。邮箱由使用邮箱的任务函数建立,也可在系统初始化函数中建立。邮箱一旦建立,建立后将得到“OS_EVENT”类型的结构指针,任务函数通过该指针可对邮箱进行存取操作。
- 一个系统中可以存在多个邮箱,对于接收消息的任务函数来说,应该知道从那个邮箱中取消息,邮箱的识别是创建邮箱时“OSMboxCreate()”函数的返回值来得到的。互相发送和接收消息的2个任务使用同一个全局变量(“OS_EVENT”类型)来标识一个邮箱。
- 和邮箱相关的数据结构主要是“OS_EVENT”,另外一个结构“OS_MBOX_DATA”在函数中作为局部变量使用。在先收后发的情况下,使用“OS_TCB”的“OSTCBMsg”分量来存储消息指针。消息邮箱的数据结构为:
typedef struct os_mbox_data {
void *OSMsg; /* Pointer to message in mailbox指向邮箱中消息的指针 */
OS_PRIO OSEventTbl[OS_EVENT_TBL_SIZE]; /* List of tasks waiting for event to occur消息的等待任务列表 */
OS_PRIO OSEventGrp; /* Group corresponding to tasks waiting for event to occur消息的等待任务所在的组 */
} OS_MBOX_DATA;
typedef struct os_event {
INT8U OSEventType;/* Type of event control block (see OS_EVENT_TYPE_xxxx)事件类型 */
void *OSEventPtr;/* Pointer to message or queue structure 指向消息或者队列结构的指针 */
INT16U OSEventCnt;/* Semaphore Count (not used if other EVENT type)*/
OS_PRIO OSEventGrp; /* Group corresponding to tasks waiting for event to occur */
OS_PRIO OSEventTbl[OS_EVENT_TBL_SIZE]; /* List of tasks waiting for event to occur任务等待列表*/
#if OS_EVENT_NAME_EN > 0u
INT8U *OSEventName;
#endif
} OS_EVENT;
OS_EVENT结构中的OSEventType用来表示事件类型,包括:
邮箱事件:OS_EVENT_TYPE_MBOX;
消息列表事件:OS_EVENT_TYPE_Q;
信号量事件:OS_EVENT_TYPE_SEM;
对于邮箱通信,我们只需要OS_EVENT中的”OSEventTb1“和”OSEventGrp“还有”OSEventPtr“就可以了。
7.邮箱的容量:在邮箱创建时,系统并不分配邮箱的大小,邮箱的存储空间实际上是发信任务定义的。消息传递过程中,只传递所发消息的指针,函数OSMboxPost()将消息指针传递给“OS_EVENT”中的“OSEventPtr”。
8.注意一点:对于使用消息的任务函数来说,由于是指针传递,使用局部变量来储存发送消息,消息可能会在被收到前消失,所以,最好用全局变量来存储发送消息。
===============================================================
===============================================================
以上关于邮箱机制的介绍很清楚了,下面是uc/os-ii中os_mbox.c的部分代码(代码只做简单的语句注释,不赘述其他)。
从邮箱中接收消息void *OSMboxAccept (OS_EVENT *pevent):(部分代码)
#if OS_MBOX_EN > 0u
/*
*********************************************************************************************************
* ACCEPT MESSAGE FROM MAILBOX
* 从邮箱中接收消息
* Description: This function checks the mailbox to see if a message is available. Unlike OSMboxPend(),
* OSMboxAccept() does not suspend the calling task if a message is not available.
*描述:该功能检查邮箱看是否有可以获得的消息。与OSMboxPend()不同的是,如果消息不可获得,OSMboxAccept()下任务不会被挂起。
* Arguments : pevent is a pointer to the event control block
*参数: --pevent:指向事件控制块的指针
* Returns : != (void *)0 is the message in the mailbox if one is available. The mailbox is cleared
* so the next time OSMboxAccept() is called, the mailbox will be empty.
* == (void *)0 if the mailbox is empty or,
* if 'pevent' is a NULL pointer or,
* if you didn't pass the proper event pointer.
返回值:!= (void *)0:如果有消息可以获得,返回该消息。邮箱被清除,当下一次调用OSMboxAccept()时,邮箱状态为空
*********************************************************************************************************
*/
#if OS_MBOX_ACCEPT_EN > 0u
void *OSMboxAccept (OS_EVENT *pevent)
{
void *pmsg;/*指向消息的指针*/
OS_ENTER_CRITICAL();/*进入中断*/
pmsg = pevent->OSEventPtr;
pevent->OSEventPtr = (void *)0;/*清空邮箱*/
OS_EXIT_CRITICAL();/*退出中断*/
return (pmsg); /* 返回收到的消息或null*/
建立并初始化一个邮箱OS_EVENT *OSMboxCreate (void *pmsg):(部分代码)
/*$PAGE*/
/*
*********************************************************************************************************
* CREATE A MESSAGE MAILBOX
* 建立并初始化一个邮箱
* Description: This function creates a message mailbox if free event control blocks are available.
*描述:如果有空闲的事件控制块,创建一个邮箱。
* Arguments : pmsg is a pointer to a message that you wish to deposit in the mailbox. If
* you set this value to the NULL pointer (i.e. (void *)0) then the mailbox
* will be considered empty.
*参数: --pmsg:指向你将要存储在邮箱的消息的指针。如果该指针为空,默认邮箱为空。
* Returns : != (OS_EVENT *)0 is a pointer to the event control clock (OS_EVENT) associated with the
* created mailbox
* == (OS_EVENT *)0 if no event control blocks were available
返回值:!= (OS_EVENT *)0:指向与创建的邮箱关联的事件控制块的指针。
== (OS_EVENT *)0:没有可用的事件控制块。
*********************************************************************************************************
*/
OS_EVENT *OSMboxCreate (void *pmsg)
{
OS_EVENT *pevent;
OS_ENTER_CRITICAL();/*进入中断*/
pevent = OSEventFreeList;/*得到空闲的事件控制块 */
if (OSEventFreeList != (OS_EVENT *)0) /*如果有空闲的事件控制块*/
{
OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr;/*更新空闲列表*/
}
OS_EXIT_CRITICAL();/*退出中断*/
if (pevent != (OS_EVENT *)0)/*如果得到了空闲的事件控制块*/
{
pevent->OSEventType = OS_EVENT_TYPE_MBOX;/*将OS_EVENT结构中的事件类型设置为邮箱事件*/
pevent->OSEventCnt = 0u;
pevent->OSEventPtr = pmsg; /*将消息存储在事件控制块中 */
#if OS_EVENT_NAME_EN > 0u
pevent->OSEventName = (INT8U *)(void *)"?";
#endif
OS_EventWaitListInit(pevent);/*初始化事件等待列表*/
}
return (pevent);/* 返回指向事件控制块的指针*/
删除邮箱OS_EVENT *OSMboxDel (OS_EVENT *pevent,INT8U opt,INT8U *perr):
/*$PAGE*/
/*2018/2/21
*********************************************************************************************************
* DELETE A MAIBOX
* 删除邮箱
* Description: This function deletes a mailbox and readies all tasks pending on the mailbox.
*描述:该函数是删除邮箱并将所有在该邮箱挂起的任务设置为就绪态
* Arguments : pevent is a pointer to the event control block associated with the desired mailbox.
*参数: --pevent:指向邮箱消息对应的事件控制块的指针
* opt determines delete options as follows:
* opt == OS_DEL_NO_PEND Delete the mailbox ONLY if no task pending
* opt == OS_DEL_ALWAYS Deletes the mailbox even if tasks are waiting.
* In this case, all the tasks pending will be readied.
* --opt:删除方式选择:
opt == OS_DEL_NO_PEND:当没有任务挂起时才能删除;
opt == OS_DEL_ALWAYS:即使有任务等待也将邮箱删除。这种情况下,所有等待的任务都转为就绪态。
* perr is a pointer to an error code that can contain one of the following values:
* OS_ERR_NONE The call was successful and the mailbox was deleted
* OS_ERR_DEL_ISR If you attempted to delete the mailbox from an ISR
* OS_ERR_INVALID_OPT An invalid option was specified
* OS_ERR_TASK_WAITING One or more tasks were waiting on the mailbox
* OS_ERR_EVENT_TYPE If you didn't pass a pointer to a mailbox
* OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer.
* --perr:指向错误码的指针:
OS_ERR_NONE:成功调用,邮箱被删除;
OS_ERR_DEL_ISR:从中断服务子程序中删除邮箱;
OS_ERR_INVALID_OPT:无效的选择方式;
OS_ERR_TASK_WAITING:一个或多个任务正在等待;
OS_ERR_EVENT_TYPE:没有指向邮箱的指针;
OS_ERR_PEVENT_NULL:pevent为空指针。
* Returns : pevent upon error
* (OS_EVENT *)0 if the mailbox was successfully deleted.
*返回值:如果成功删除,返回值为空。如果没有成功,返回pevent。
* Note(s) : 1) This function must be used with care. Tasks that would normally expect the presence of
* the mailbox MUST check the return code of OSMboxPend().
* 2) OSMboxAccept() callers will not know that the intended mailbox has been deleted!
* 3) This call can potentially disable interrupts for a long time. The interrupt disable
* time is directly proportional to the number of tasks waiting on the mailbox.
* 4) Because ALL tasks pending on the mailbox will be readied, you MUST be careful in
* applications where the mailbox is used for mutual exclusion because the resource(s)
* will no longer be guarded by the mailbox.
注释:1)该功能需要小心使用。等待邮箱消息的任务必须先检查OSMboxPend()函数的返回值。
2)调用OSMboxAccept()的任务无法知道要邮箱是否已经被删除。
3)该函数调用会中断很长时间,时间与等待邮箱的任务的数量相关。
4)因为所有挂起的任务都会被转为就绪态,所以如果邮箱中的消息是互斥型信号量就需要特别注意了,因为此时资源是开放的。
*********************************************************************************************************
*/
#if OS_MBOX_DEL_EN > 0u
OS_EVENT *OSMboxDel (OS_EVENT *pevent,
INT8U opt,
INT8U *perr)
{
BOOLEAN tasks_waiting;/*检测是否有正在等待的任务*/
OS_EVENT *pevent_return;/*返回指针*/
#if OS_CRITICAL_METHOD == 3u
OS_CPU_SR cpu_sr = 0u;
#endif
#ifdef OS_SAFETY_CRITICAL
if (perr == (INT8U *)0) {
OS_SAFETY_CRITICAL_EXCEPTION();
}
#endif
#if OS_ARG_CHK_EN > 0u
if (pevent == (OS_EVENT *)0) {
*perr = OS_ERR_PEVENT_NULL;
return (pevent);
}
#endif
if (pevent->OSEventType != OS_EVENT_TYPE_MBOX) {
*perr = OS_ERR_EVENT_TYPE;
return (pevent);
}
if (OSIntNesting > 0u) {
*perr = OS_ERR_DEL_ISR;
return (pevent);
}
OS_ENTER_CRITICAL();/*进入中断*/
if (pevent->OSEventGrp != 0u)/*检测是否有任务正在等待*/
{
tasks_waiting = OS_TRUE; /*有任务等待,将等待标志设置为true*/
}
else
{
tasks_waiting = OS_FALSE; /* 没有任务等待,将等待标志设置为false*/
}
switch (opt) /*选择删除方式并进行相应操作*/
{
case OS_DEL_NO_PEND: /* 无挂起才删除*/
if (tasks_waiting == OS_FALSE) /*没有任务等待*/
{
#if OS_EVENT_NAME_EN > 0u
pevent->OSEventName = (INT8U *)(void *)"?";/*名字设为未命名*/
#endif
pevent->OSEventType = OS_EVENT_TYPE_UNUSED;/*事件类型设置为未使用类型*/
pevent->OSEventPtr = OSEventFreeList; /*将事件控制块返还给空闲列表*/
pevent->OSEventCnt = 0u;
OSEventFreeList = pevent;/*更新空闲列表 */
OS_EXIT_CRITICAL();/*退出中断*/
*perr = OS_ERR_NONE;
pevent_return = (OS_EVENT *)0; /*返回值设为空,邮箱已经被删除*/
}
else/*有任务正在等待*/
{
OS_EXIT_CRITICAL();/*退出中断*/
*perr = OS_ERR_TASK_WAITING;/*设置错误类型*/
pevent_return = pevent;/*将事件控制块指针返回*/
}
break;
case OS_DEL_ALWAYS: /* 无论怎样都删除邮箱*/
while (pevent->OSEventGrp != 0u)
{
(void)OS_EventTaskRdy(pevent, (void *)0, OS_STAT_MBOX, OS_STAT_PEND_OK);/*将所有的任务都设置为就绪态*/
}
#if OS_EVENT_NAME_EN > 0u
pevent->OSEventName = (INT8U *)(void *)"?";
#endif
pevent->OSEventType = OS_EVENT_TYPE_UNUSED;/*事件类型设置为未使用类型*/
pevent->OSEventPtr = OSEventFreeList;/* 将事件控制块返回给空闲列表 */
pevent->OSEventCnt = 0u;
OSEventFreeList = pevent;/* 更新空闲列表 */
OS_EXIT_CRITICAL();/*退出中断*/
if (tasks_waiting == OS_TRUE) /*有任务正在等待*/
{
OS_Sched(); /* 找到就绪任务中优先级最高的任务进行调度*/
}
*perr = OS_ERR_NONE;
pevent_return = (OS_EVENT *)0;/*邮箱被删除,返回空指针*/
break;
default:/*两种删除情况都不是*/
OS_EXIT_CRITICAL();/*退出中断*/
*perr = OS_ERR_INVALID_OPT;/*设置错误类型*/
pevent_return = pevent;/*将事件控制块指针返回*/
break;
}
return (pevent_return);
}
#endif
等待消息进入邮箱void *OSMboxPend (OS_EVENT *pevent,INT32U timeout,INT8U *perr):
/*$PAGE*/
/*2018/2/21
*********************************************************************************************************
* PEND ON MAILBOX FOR A MESSAGE
* 等待消息进入邮箱
* Description: This function waits for a message to be sent to a mailbox
*描述:该功能用来等地啊消息进入邮箱。
* Arguments : pevent is a pointer to the event control block associated with the desired mailbox
*参数: --pevent:指向事件控制块的指针
* timeout is an optional timeout period (in clock ticks). If non-zero, your task will
* wait for a message to arrive at the mailbox up to the amount of time
* specified by this argument. If you specify 0, however, your task will wait
* forever at the specified mailbox or, until a message arrives.
* --timeout:时间片。如果不为0,任务将等待消息到来,直到时间到达设定的值。如果设置为0,任务将无限等待,
直到有消息到来。
* perr is a pointer to where an error message will be deposited. Possible error
* messages are:
* OS_ERR_NONE The call was successful and your task received a
* message.
* OS_ERR_TIMEOUT A message was not received within the specified 'timeout'.
* OS_ERR_PEND_ABORT The wait on the mailbox was aborted.
* OS_ERR_EVENT_TYPE Invalid event type
* OS_ERR_PEND_ISR If you called this function from an ISR and the result
* would lead to a suspension.
* OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer
* OS_ERR_PEND_LOCKED If you called this function when the scheduler is locked
* --perr:指向错误码的指针:
OS_ERR_NONE:成功调用,任务收到消息;
OS_ERR_TIMEOUT:在规定时间内没有收到消息(超时错);
OS_ERR_PEND_ABORT:取消了正在等待的任务;
OS_ERR_EVENT_TYPE:无效的事件类型;
OS_ERR_PEND_ISR:从中断服务子程序中调用该函数;
OS_ERR_PEVENT_NULL:pevent为空指针;
OS_ERR_PEND_LOCKED:调度器上锁时进行调用。
* Returns : != (void *)0 is a pointer to the message received
* == (void *)0 if no message was received or,
* if 'pevent' is a NULL pointer or,
* if you didn't pass the proper pointer to the event control block.
返回值:!= (void *)0:指向收到的消息的指针;
== (void *)0:没有收到消息或者pevnet为空指针或者没有指向事件控制块的指针时返回空。
*********************************************************************************************************
*/
/*$PAGE*/
void *OSMboxPend (OS_EVENT *pevent,
INT32U timeout,
INT8U *perr)
{
void *pmsg;/*指向消息的指针*/
#if OS_CRITICAL_METHOD == 3u
OS_CPU_SR cpu_sr = 0u;
#endif
#ifdef OS_SAFETY_CRITICAL
if (perr == (INT8U *)0) {
OS_SAFETY_CRITICAL_EXCEPTION();
}
#endif
#if OS_ARG_CHK_EN > 0u
if (pevent == (OS_EVENT *)0) {
*perr = OS_ERR_PEVENT_NULL;
return ((void *)0);
}
#endif
if (pevent->OSEventType != OS_EVENT_TYPE_MBOX) {
*perr = OS_ERR_EVENT_TYPE;
return ((void *)0);
}
if (OSIntNesting > 0u) {
*perr = OS_ERR_PEND_ISR;
return ((void *)0);
}
if (OSLockNesting > 0u) {
*perr = OS_ERR_PEND_LOCKED;
return ((void *)0);
}
OS_ENTER_CRITICAL();/*进入中断*/
pmsg = pevent->OSEventPtr;/*指向消息*/
if (pmsg != (void *)0)/*如果有消息存在*/
{
pevent->OSEventPtr = (void *)0; /* 清除邮箱 */
OS_EXIT_CRITICAL();/*退出中断*/
*perr = OS_ERR_NONE;
return (pmsg); /*返回消息*/
}
/*如果没有消息*/
OSTCBCur->OSTCBStat |= OS_STAT_MBOX; /*将任务挂起*/
OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK;
OSTCBCur->OSTCBDly = timeout;/*最长等待时间=timeout,递减式*/
OS_EventTaskWait(pevent); /* 将任务挂起,直到有消息到来或者时间到*/
OS_EXIT_CRITICAL();/*退出中断*/
OS_Sched(); /*选择优先级高的任务进行调度*/
OS_ENTER_CRITICAL();/*进入中断*/
switch (OSTCBCur->OSTCBStatPend) /*检查挂起状态原因,是超时还是任务被取消*/
{
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;
break;
case OS_STAT_PEND_TO:/*超时*/
default:/*其他情况*/
OS_EventTaskRemove(OSTCBCur, pevent);/*将任务移除*/
pmsg = (void *)0;/*返回空*/
*perr = OS_ERR_TIMEOUT;
break;
}
OSTCBCur->OSTCBStat = OS_STAT_RDY; /* 将当前任务状态设置为就绪态*/
OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK; /*清除挂起状态*/
OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0; /*清除事件指针*/
#if (OS_EVENT_MULTI_EN > 0u)
OSTCBCur->OSTCBEventMultiPtr = (OS_EVENT **)0;
#endif
OSTCBCur->OSTCBMsg = (void *)0;/*清除收到的消息*/
OS_EXIT_CRITICAL();/*退出中断*/
return (pmsg);/*返回收到的消息*/
}
取消等待消息的任务OSMboxPendAbort (OS_EVENT *pevent,INT8U opt,INT8U *perr):
/*$PAGE*/
/*2018/2/21
*********************************************************************************************************
* ABORT WAITING ON A MESSAGE MAILBOX
* 取消等待消息的任务
* Description: This function aborts & readies any tasks currently waiting on a mailbox. This function
* should be used to fault-abort the wait on the mailbox, rather than to normally signal
* the mailbox via OSMboxPost() or OSMboxPostOpt().
*描述:该函数将正在等待邮箱消息的任务取消。该函数不需要通过OSMboxPost()或者OSMboxPostOpt()函数来通知邮箱进行删除,
是默认取消。
* Arguments : pevent is a pointer to the event control block associated with the desired mailbox.
*参数:--pevent:指向事件控制块的指针。
* opt determines the type of ABORT performed:
* OS_PEND_OPT_NONE ABORT wait for a single task (HPT) waiting on the
* mailbox
* OS_PEND_OPT_BROADCAST ABORT wait for ALL tasks that are waiting on the
* mailbox
* --opt:取消方式:
OS_PEND_OPT_NONE:取消一个;
OS_PEND_OPT_BROADCAST:全部取消;
* perr is a pointer to where an error message will be deposited. Possible error
* messages are:
* OS_ERR_NONE No tasks were waiting on the mailbox.
* OS_ERR_PEND_ABORT At least one task waiting on the mailbox was readied
* and informed of the aborted wait; check return value
* for the number of tasks whose wait on the mailbox
* was aborted.
* OS_ERR_EVENT_TYPE If you didn't pass a pointer to a mailbox.
* OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer.
* --perr:错误码指针:
OS_ERR_NONE:没有任务在等待;
OS_ERR_PEND_ABORT:至少一个被通知取消等待的任务是就绪态。
OS_ERR_EVENT_TYPE:没有指向邮箱的指针;
OS_ERR_PEVENT_NULL:pevent为空指针。
* Returns : == 0 if no tasks were waiting on the mailbox, or upon error.
* > 0 if one or more tasks waiting on the mailbox are now readied and informed.
返回值: == 0:没有任务在等待,返回空;
> 0:一个或者多个正在等待邮箱并且已经被通知取消的任务是就绪态。
*********************************************************************************************************
*/
#if OS_MBOX_PEND_ABORT_EN > 0u
INT8U OSMboxPendAbort (OS_EVENT *pevent,
INT8U opt,
INT8U *perr)
{
INT8U nbr_tasks;
#if OS_CRITICAL_METHOD == 3u
OS_CPU_SR cpu_sr = 0u;
#endif
#ifdef OS_SAFETY_CRITICAL
if (perr == (INT8U *)0) {
OS_SAFETY_CRITICAL_EXCEPTION();
}
#endif
#if OS_ARG_CHK_EN > 0u
if (pevent == (OS_EVENT *)0) {
*perr = OS_ERR_PEVENT_NULL;
return (0u);
}
#endif
if (pevent->OSEventType != OS_EVENT_TYPE_MBOX) {
*perr = OS_ERR_EVENT_TYPE;
return (0u);
}
OS_ENTER_CRITICAL();/*进入中断*/
if (pevent->OSEventGrp != 0u) /*有任务正在等待邮箱*/
{
nbr_tasks = 0u;
switch (opt)/*选择取消的方式并进行相关操作*/
{
case OS_PEND_OPT_BROADCAST:/*所有任务都清除*/
while (pevent->OSEventGrp != 0u)
{
(void)OS_EventTaskRdy(pevent, (void *)0, OS_STAT_MBOX, OS_STAT_PEND_ABORT);/*所有任务设为就绪态*/
nbr_tasks++;
}
break;
case OS_PEND_OPT_NONE:/*只清除一个*/
default: /*其他情况 */
(void)OS_EventTaskRdy(pevent, (void *)0, OS_STAT_MBOX, OS_STAT_PEND_ABORT);/*将最高优先级的任务设为就绪态*/
nbr_tasks++;
break;
}
OS_EXIT_CRITICAL();/*退出中断*/
OS_Sched(); /*对最高优先级任务进行任务调度*/
*perr = OS_ERR_PEND_ABORT;
return (nbr_tasks);
}
OS_EXIT_CRITICAL();/*退出中断*/
*perr = OS_ERR_NONE;
return (0u);/*没有任务等待返回空 */
}
#endif
通过消息邮箱向任务发送消息OSMboxPost (OS_EVENT *pevent,void *pmsg):
/*$PAGE*/
/*2018/2/21
*********************************************************************************************************
* POST MESSAGE TO A MAILBOX
* 通过消息邮箱向任务发送消息
* Description: This function sends a message to a mailbox
*描述:该功能是将消息发送给邮箱。
* Arguments : pevent is a pointer to the event control block associated with the desired mailbox
*参数: --pevent:指向事件控制块的指针。
* pmsg is a pointer to the message to send. You MUST NOT send a NULL pointer.
* --pmsg:指向要发送的消息的指针,不可以为空
* Returns : OS_ERR_NONE The call was successful and the message was sent
* OS_ERR_MBOX_FULL If the mailbox already contains a message. You can can only send one
* message at a time and thus, the message MUST be consumed before you
* are allowed to send another one.
* OS_ERR_EVENT_TYPE If you are attempting to post to a non mailbox.
* OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer
* OS_ERR_POST_NULL_PTR If you are attempting to post a NULL pointer
*返回值:OS_ERR_NONE:成功调用,消息被发出。
OS_ERR_MBOX_FULL:邮箱已经包含了消息,一次只能给邮箱放一个消息。在邮箱消息没有发送出去前不能再往里面放消息了。
OS_ERR_EVENT_TYPE:不是给邮箱发消息;
OS_ERR_PEVENT_NULL:pevent为空指针
OS_ERR_POST_NULL_PTR:发送的是个空消息(空指针)
* Note(s) : 1) HPT means Highest Priority Task
注释:1)HPT表示最高优先级任务。
*********************************************************************************************************
*/
#if OS_MBOX_POST_EN > 0u
INT8U OSMboxPost (OS_EVENT *pevent,
void *pmsg)
{
#if OS_CRITICAL_METHOD == 3u
OS_CPU_SR cpu_sr = 0u;
#endif
#if OS_ARG_CHK_EN > 0u
if (pevent == (OS_EVENT *)0) {
return (OS_ERR_PEVENT_NULL);
}
if (pmsg == (void *)0) {
return (OS_ERR_POST_NULL_PTR);
}
#endif
if (pevent->OSEventType != OS_EVENT_TYPE_MBOX) {
return (OS_ERR_EVENT_TYPE);
}
OS_ENTER_CRITICAL();/*进入中断*/
if (pevent->OSEventGrp != 0u) /*如果有任务正在等邮箱*/
{
(void)OS_EventTaskRdy(pevent, pmsg, OS_STAT_MBOX, OS_STAT_PEND_OK);/*将所有任务设置为就绪态*/
OS_EXIT_CRITICAL();/*退出中断*/
OS_Sched(); /*找到最高优先级任务进行调度*/
return (OS_ERR_NONE);
}
if (pevent->OSEventPtr != (void *)0) /*邮箱不为空,里面已经有消息存在*/
{
OS_EXIT_CRITICAL();/*退出中断*/
return (OS_ERR_MBOX_FULL);
}
pevent->OSEventPtr = pmsg;/* 将消息放在邮箱中 */
OS_EXIT_CRITICAL();/*退出中断*/
return (OS_ERR_NONE);
}
#endif
通过邮箱向(多)任务发送消息OSMboxPostOpt (OS_EVENT *pevent,void *pmsg,INT8U opt):
/*$PAGE*/
/*2018/2/21
*********************************************************************************************************
* POST MESSAGE TO A MAILBOX
* 通过邮箱向(多)任务发送消息
* Description: This function sends a message to a mailbox
*描述:该功能是通过邮箱向多任务发送消息。
* Arguments : pevent is a pointer to the event control block associated with the desired mailbox
*参数: --pevent:指向事件控制块的指针。
* pmsg is a pointer to the message to send. You MUST NOT send a NULL pointer.
* --pmsg:指向要发送的消息的指针,不可以为空。
* opt determines the type of POST performed:
* OS_POST_OPT_NONE POST to a single waiting task
* (Identical to OSMboxPost())
* OS_POST_OPT_BROADCAST POST to ALL tasks that are waiting on the mailbox
*
* OS_POST_OPT_NO_SCHED Indicates that the scheduler will NOT be invoked
* --opt:发送类型:
OS_POST_OPT_NONE:只给一个任务发送;
OS_POST_OPT_BROADCAST:给所有等待消息的任务都发送
OS_POST_OPT_NO_SCHED:调度程序不会被调用
* Returns : OS_ERR_NONE The call was successful and the message was sent
* OS_ERR_MBOX_FULL If the mailbox already contains a message. You can can only send one
* message at a time and thus, the message MUST be consumed before you
* are allowed to send another one.
* OS_ERR_EVENT_TYPE If you are attempting to post to a non mailbox.
* OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer
* OS_ERR_POST_NULL_PTR If you are attempting to post a NULL pointer
*返回值:OS_ERR_NONE:调用成功,消息被发出
OS_ERR_MBOX_FULL:邮箱中已经有消息存在,
OS_ERR_EVENT_TYPE:发送对象不是邮箱。
OS_ERR_PEVENT_NULL:pevent为空指针
OS_ERR_POST_NULL_PTR:消息为空。
* Note(s) : 1) HPT means Highest Priority Task
*注释:1)HPT是最高优先级任务的意思
* Warning : Interrupts can be disabled for a long time if you do a 'broadcast'. In fact, the
* interrupt disable time is proportional to the number of tasks waiting on the mailbox.
警告:如果选择了给全部等待任务发消息,会中断很长时间。中断事件与等待的任务数量有关系。
*********************************************************************************************************
*/
#if OS_MBOX_POST_OPT_EN > 0u
INT8U OSMboxPostOpt (OS_EVENT *pevent,
void *pmsg,
INT8U opt)
{
#if OS_CRITICAL_METHOD == 3u
OS_CPU_SR cpu_sr = 0u;
#endif
#if OS_ARG_CHK_EN > 0u
if (pevent == (OS_EVENT *)0) {
return (OS_ERR_PEVENT_NULL);
}
if (pmsg == (void *)0) {
return (OS_ERR_POST_NULL_PTR);
}
#endif
if (pevent->OSEventType != OS_EVENT_TYPE_MBOX) {
return (OS_ERR_EVENT_TYPE);
}
OS_ENTER_CRITICAL();/*进入中断*/
if (pevent->OSEventGrp != 0u)/*看是否有任务正在等待*/
{
if ((opt & OS_POST_OPT_BROADCAST) != 0x00u) /*给所有等待任务发消息*/
{
while (pevent->OSEventGrp != 0u)
{
(void)OS_EventTaskRdy(pevent, pmsg, OS_STAT_MBOX, OS_STAT_PEND_OK);
}
}
else/*给一个等待任务发消息*/
{
(void)OS_EventTaskRdy(pevent, pmsg, OS_STAT_MBOX, OS_STAT_PEND_OK);
}
OS_EXIT_CRITICAL();/*退出中断*/
if ((opt & OS_POST_OPT_NO_SCHED) == 0u) /*看是否需要唤醒调度程序*/
{
OS_Sched(); /*选择优先级最高的任务进行调度*/
}
return (OS_ERR_NONE);
}
/*没有任务正在等待*/
if (pevent->OSEventPtr != (void *)0)/*邮箱中有消息存在*/
{
OS_EXIT_CRITICAL();/*退出中断*/
return (OS_ERR_MBOX_FULL);
}
pevent->OSEventPtr = pmsg;/*将消息放在邮箱中*/
OS_EXIT_CRITICAL();/*退出中断*/
return (OS_ERR_NONE);
}
#endif
取得消息邮箱的信息 OSMboxQuery (OS_EVENT *pevent,OS_MBOX_DATA *p_mbox_data):
/*$PAGE*/
/*2018/2/21
*********************************************************************************************************
* QUERY A MESSAGE MAILBOX
* 取得消息邮箱的信息
* Description: This function obtains information about a message mailbox.
*描述:该函数是获得邮箱中的消息
* Arguments : pevent is a pointer to the event control block associated with the desired mailbox
*参数: --pevent:指向事件控制块的指针
* p_mbox_data is a pointer to a structure that will contain information about the message
* mailbox.
* --p_mbox_data:指向p_mbox_data结构体的指针。
* Returns : OS_ERR_NONE The call was successful and the message was sent
* OS_ERR_EVENT_TYPE If you are attempting to obtain data from a non mailbox.
* OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer
* OS_ERR_PDATA_NULL If 'p_mbox_data' is a NULL pointer
返回值:OS_ERR_NONE:调用成功,消息被发出;
OS_ERR_EVENT_TYPE:不是从邮箱中获得消息;
OS_ERR_PEVENT_NULL:pevent为空指针;
OS_ERR_PDATA_NULL:p_mbox_data为空指针。
*********************************************************************************************************
*/
#if OS_MBOX_QUERY_EN > 0u
INT8U OSMboxQuery (OS_EVENT *pevent,
OS_MBOX_DATA *p_mbox_data)
{
INT8U i;
OS_PRIO *psrc;
OS_PRIO *pdest;
#if OS_CRITICAL_METHOD == 3u
OS_CPU_SR cpu_sr = 0u;
#endif
#if OS_ARG_CHK_EN > 0u
if (pevent == (OS_EVENT *)0) {
return (OS_ERR_PEVENT_NULL);
}
if (p_mbox_data == (OS_MBOX_DATA *)0) {
return (OS_ERR_PDATA_NULL);
}
#endif
if (pevent->OSEventType != OS_EVENT_TYPE_MBOX) {
return (OS_ERR_EVENT_TYPE);
}
OS_ENTER_CRITICAL();/*进入中断*/
/*将事件(邮箱)结构中的等待任务列表复制到pdata数据结构中*/
p_mbox_data->OSEventGrp = pevent->OSEventGrp;/*等待事件的任务组中的内容传送到状态数据结构中*/
psrc = &pevent->OSEventTbl[0];/*保存pevent->OSEventTbl[0]对应的地址,源*/
pdest = &p_mbox_data->OSEventTbl[0];/*保存pdata->OSEventTbl[0]对应的地址,目的*/
for (i = 0u; i < OS_EVENT_TBL_SIZE; i++)
{
*pdest++ = *psrc++;/*地址指针下移一个类型地址,获取消息邮箱的值*/
}
p_mbox_data->OSMsg = pevent->OSEventPtr;/*将邮箱中的当前消息从事件数据结构复制到OS_MBOX_DATA数据结构 */
OS_EXIT_CRITICAL();/*退出中断*/
return (OS_ERR_NONE);
}
#endif /* OS_MBOX_QUERY_EN */
#endif /* OS_MBOX_EN */
文章到这里就结束了。
uc/os-ii中的os_mbox.c文件全部读完。重点是了解邮箱机制,还要清楚相关的结构体。看邮箱有没有消息什么的都是通过事件控制块中的OSEventGrp等判断的。具体看代码即可。