阅读 27

os_mbox.c(全)

本篇介绍以下内容:

  • 简单介绍邮箱机制

  • 从邮箱中接收消息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)\

邮箱机制简单介绍一下:

  1. 在uc/os-ii中,完成一次两个任务间的消息传递,只需要一个邮箱,并且邮箱中只能存放一个消息。在消息没有取走前,不能在邮箱中存放新的消息。
  2. uc/os-ii中存放和传递的是消息内容缓冲区的指针。
  3. 在uc/os-ii中,调度系统不能自动通知某个任务邮箱中已经有消息,需要任务主动去取邮件(调用函数OSMboxPend())。
  4. 邮箱操作过程:uc/os-ii邮箱通信的过程首先建立一个数据缓冲区,即创建邮箱。一个系统中或者一个任务可以建立多个邮箱。不同邮箱通过邮箱指针来识别,该指针在建立邮箱时产生。邮箱由使用邮箱的任务函数建立,也可在系统初始化函数中建立。邮箱一旦建立,建立后将得到“OS_EVENT”类型的结构指针,任务函数通过该指针可对邮箱进行存取操作。
  5. 一个系统中可以存在多个邮箱,对于接收消息的任务函数来说,应该知道从那个邮箱中取消息,邮箱的识别是创建邮箱时“OSMboxCreate()”函数的返回值来得到的。互相发送和接收消息的2个任务使用同一个全局变量(“OS_EVENT”类型)来标识一个邮箱。
  6. 和邮箱相关的数据结构主要是“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等判断的。具体看代码即可。


\

文章分类
代码人生
文章标签