μCOS-II源码文件之OS_Q.C

/*
*********************************************************************************************************
*                                                uC/OS-II
*                                          The Real-Time Kernel
*                                        MESSAGE QUEUE MANAGEMENT
*
*                          (c) Copyright 1992-2002, Jean J. Labrosse, Weston, FL
*                                           All Rights Reserved
*
* File : OS_Q.C
* By   : Jean J. Labrosse
* 翻译: likee
*********************************************************************************************************
*/

#ifndef  OS_MASTER_FILE//防止编译器包含一些代码
#include "includes.h"
#endif

#if (OS_Q_EN > 0) && (OS_MAX_QS > 0)
/*
*********************************************************************************************************
*                                      ACCEPT MESSAGE FROM QUEUE
*
* Description: This function checks the queue to see if a message is available.  Unlike OSQPend(),
*              OSQAccept() does not suspend the calling task if a message is not available.
*
* Arguments  : pevent        is a pointer to the event control block
*
* Returns    : != (void *)0  is the message in the queue if one is available.  The message is removed
*                            from the so the next time OSQAccept() is called, the queue will contain
*                            one less entry.
*              == (void *)0  if the queue is empty or,
*                            if 'pevent' is a NULL pointer or,
*                            if you passed an invalid event type

*********************************************************************************************************
*/

#if OS_Q_ACCEPT_EN > 0
void  *OSQAccept (OS_EVENT *pevent)
{
#if OS_CRITICAL_METHOD == 3                      /* Allocate storage for CPU status register           */
    OS_CPU_SR  cpu_sr;
#endif
    void      *msg;
    OS_Q      *pq;


#if OS_ARG_CHK_EN > 0
    if (pevent == (OS_EVENT *)0) {               /* Validate 'pevent'                                  */
        return ((void *)0);
    }
    if (pevent->OSEventType != OS_EVENT_TYPE_Q) {/* Validate event block type                          */
        return ((void *)0);
    }
#endif
    OS_ENTER_CRITICAL();
    pq = (OS_Q *)pevent->OSEventPtr;             /* Point at queue control block                       */
    if (pq->OSQEntries > 0) {                    /* See if any messages in the queue                   */
        msg = *pq->OSQOut++;                     /* Yes, extract oldest message from the queue         */
        pq->OSQEntries--;                        /* Update the number of entries in the queue          */
        if (pq->OSQOut == pq->OSQEnd) {          /* Wrap OUT pointer if we are at the end of the queue */
            pq->OSQOut = pq->OSQStart;
        }
    } else {
        msg = (void *)0;                         /* Queue is empty                                     */
    }
    OS_EXIT_CRITICAL();
    return (msg);                                /* Return message received (or NULL)                  */
}
#endif
/*$PAGE*/
/*
*********************************************************************************************************
*                                        CREATE A MESSAGE QUEUE
*
* Description: This function creates a message queue if free event control blocks are available.
*
* Arguments  : start         is a pointer to the base address of the message queue storage area.  The
*                            storage area MUST be declared as an array of pointers to 'void' as follows
*
*                            void *MessageStorage[size]
*
*              size          is the number of elements in the storage area
*
* Returns    : != (OS_EVENT *)0  is a pointer to the event control clock (OS_EVENT) associated with the
*                                created queue
*              == (OS_EVENT *)0  if no event control blocks were available or an error was detected
                                                      建立一个消息队列
描述:如果有空余事件控制块,就建立一个消息队列
参数:start:指向消息队列存储空间基地址。存储空间必须定义成void 型的
                            一系列指针,形式如右:void *MessageStorage[size]
                 size:存储空间内单元的数目
返回:!= (OS_EVENT *)0  是指向结合建立的队列的事件控制时钟(OS_EVENT)的指针
                 == (OS_EVENT *)0如果没有适合的事件控制块或者有错误
*********************************************************************************************************
*/

OS_EVENT  *OSQCreate (void **start, INT16U size)
{
#if OS_CRITICAL_METHOD == 3                      /* Allocate storage for CPU status register           */
    OS_CPU_SR  cpu_sr;//分配名为cpu_sr 的局部变量,用于支持OS_CRITICAL_METHOD方法3
#endif
    OS_EVENT  *pevent;
    OS_Q      *pq;


    if (OSIntNesting > 0) {                      /* See if called from ISR ...                         */
        return ((OS_EVENT *)0);                  /* ... can't CREATE from an ISR                       */
    }//不能在ISR中建立消息队列
    OS_ENTER_CRITICAL();
    pevent = OSEventFreeList;                    /* Get next free event control block                  */
	//从空余的ECB链表中取得一个事件控制块。对剩下的作相应调整
	//ECB是单向链表
    if (OSEventFreeList != (OS_EVENT *)0) {      /* See if pool of free ECB pool was empty             */
        OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr;
    }//对剩下的进行相应的调整
    OS_EXIT_CRITICAL();
    if (pevent != (OS_EVENT *)0) {               /* See if we have an event control block              */
		//如果我们得到了事件控制块
        OS_ENTER_CRITICAL();
        pq = OSQFreeList;                        /* Get a free queue control block                     */
		//得到一块新的队列控制块
        if (pq != (OS_Q *)0) {                   /* Were we able to get a queue control block ?        */
			//如果得到的不为空,即真正得到了。
            OSQFreeList         = OSQFreeList->OSQPtr;    /* Yes, Adjust free list pointer to next free*/
			//调整表头
            OS_EXIT_CRITICAL();
			//初始化新得到的队列控制块
            pq->OSQStart        = start;                  /*      Initialize the queue                 */
            pq->OSQEnd          = &start[size];
            pq->OSQIn           = start;
            pq->OSQOut          = start;
            pq->OSQSize         = size;
            pq->OSQEntries      = 0;//初始化消息数为零
            pevent->OSEventType = OS_EVENT_TYPE_Q;//设置事件控制块类型
            pevent->OSEventCnt  = 0;//信号量
            pevent->OSEventPtr  = pq;//将此块指向消息队列结构指针
            OS_EventWaitListInit(pevent);   /*      Initalize the wait list  *///初始化等待列表
        } else {//如果没有得到队列控制块
            pevent->OSEventPtr = (void *)OSEventFreeList; /* No,  Return event control block on error  */
			//以错误形式返回队列控制块
            OSEventFreeList    = pevent;//退回事件控制块,不用了。
            OS_EXIT_CRITICAL();
            pevent = (OS_EVENT *)0;//清零,给下一次使用。
        }
    }
    return (pevent);//如果消息队列建立成功,则会返回一个指针,否则,就返回空指针。
    //消息队列成功后返回的这个指针用于以后对消息队列的操作因此,该指针
    //可以看作是相应消息队列的句柄。
}
/*$PAGE*/
/*
*********************************************************************************************************
*                                        DELETE A MESSAGE QUEUE
*
* Description: This function deletes a message queue and readies all tasks pending on the queue.
*
* Arguments  : pevent        is a pointer to the event control block associated with the desired
*                            queue.
*
*              opt           determines delete options as follows:
*                            opt == OS_DEL_NO_PEND   Delete the queue ONLY if no task pending
*                            opt == OS_DEL_ALWAYS    Deletes the queue even if tasks are waiting.
*                                                    In this case, all the tasks pending will be readied.
*
*              err           is a pointer to an error code that can contain one of the following values:
*                            OS_NO_ERR               The call was successful and the queue was deleted
*                            OS_ERR_DEL_ISR          If you tried to delete the queue from an ISR
*                            OS_ERR_INVALID_OPT      An invalid option was specified
*                            OS_ERR_TASK_WAITING     One or more tasks were waiting on the queue
*                            OS_ERR_EVENT_TYPE       If you didn't pass a pointer to a queue
*                            OS_ERR_PEVENT_NULL      If 'pevent' is a NULL pointer.
*
* Returns    : pevent        upon error
*              (OS_EVENT *)0 if the queue was successfully deleted.
*
* Note(s)    : 1) This function must be used with care.  Tasks that would normally expect the presence of
*                 the queue MUST check the return code of OSQPend().
*              2) OSQAccept() callers will not know that the intended queue has been deleted unless
*                 they check 'pevent' to see that it's a NULL pointer.
*              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 queue.
*              4) Because ALL tasks pending on the queue will be readied, you MUST be careful in
*                 applications where the queue is used for mutual exclusion because the resource(s)
*                 will no longer be guarded by the queue.
*              5) If the storage for the message queue was allocated dynamically (i.e. using a malloc()
*                 type call) then your application MUST release the memory storage by call the counterpart
*                 call of the dynamic allocation scheme used.  If the queue storage was created statically
*                 then, the storage can be reused.
                                                  删除一个消息队列
描述:删除一个队列,使在队列上挂起的任务全部就绪
参数:pevent :指向事件控制块和目标队列的指针
                 opt:决定删除选项,如下:
*                            opt == OS_DEL_NO_PEND   没有任务挂起才删除
*                            opt == OS_DEL_ALWAYS    有任务挂起也删,挂起的任务全部就绪
*              err          指向包含如下错误信息的指针
*                            OS_NO_ERR              调用成功,队列删除
*                            OS_ERR_DEL_ISR         如果想从ISR中删除
*                            OS_ERR_INVALID_OPT      指定了非法选项
*                            OS_ERR_TASK_WAITING     有任务在队列中等待
*                            OS_ERR_EVENT_TYPE      如果你没有传递消息给队列
*                            OS_ERR_PEVENT_NULL     如果pevent是一个空指针
返回:pevent;有错
                 (OS_EVENT *)0如果队列成功删除
备注:1、此函数要小心使用,任务希望现场队列检查OSQPend()的返回代码,什么意思,不知道
                2、OSQAccept()的调用者不知道目标队列是否删除了,除非检查pevent'是否为空指针
                3、此调用将潜在关中断一段时间,时间长短与队列中任务多少成正比
                4、因为所有队列中挂起的任务就绪,在多任务的时候要小心,因为这些资源
                       队列不再看管(因为删除了)。
                5、如果消息存储用动态分配(比如用malloc()),那么应用程序必须通过
                        调用相应的动态配置去释放内存空间,如果队列存储是静态建立,则可以再次
                利用
*********************************************************************************************************
*/

#if OS_Q_DEL_EN > 0
OS_EVENT  *OSQDel (OS_EVENT *pevent, INT8U opt, INT8U *err)
{
#if OS_CRITICAL_METHOD == 3                                /* Allocate storage for CPU status register */
    OS_CPU_SR  cpu_sr;
#endif
    BOOLEAN    tasks_waiting;
    OS_Q      *pq;


    if (OSIntNesting > 0) {                                /* See if called from ISR ...               */
        *err = OS_ERR_DEL_ISR;                             /* ... can't DELETE from an ISR             */
        return ((OS_EVENT *)0);
    }//不能在中断服务程序中删除
#if OS_ARG_CHK_EN > 0
    if (pevent == (OS_EVENT *)0) {                         /* Validate 'pevent'                        */
        *err = OS_ERR_PEVENT_NULL;
        return (pevent);//pevent不合理
    }
    if (pevent->OSEventType != OS_EVENT_TYPE_Q) {          /* Validate event block type                */
        *err = OS_ERR_EVENT_TYPE;
        return (pevent);//非法的事件块模式
    }
#endif
    OS_ENTER_CRITICAL();
    if (pevent->OSEventGrp != 0x00) {                      /* See if any tasks waiting on queue        */
		//如果有任务在队列中等待
        tasks_waiting = TRUE;                              /* Yes                                      */
    } else {
        tasks_waiting = FALSE;                             /* No                                       */
    }
    switch (opt) {
        case OS_DEL_NO_PEND:                               /* Delete queue only if no task waiting     */
			//如果只在无任务等待的情况下删除
             if (tasks_waiting == FALSE) {//无任务等待
                 pq                  = (OS_Q *)pevent->OSEventPtr;  /* Return OS_Q to free list        */
                 pq->OSQPtr          = OSQFreeList;
                 OSQFreeList         = pq;//将它加入了空闲链表
                 pevent->OSEventType = OS_EVENT_TYPE_UNUSED;//标记未用
                 pevent->OSEventPtr  = OSEventFreeList;    /* Return Event Control Block to free list  */
                 OSEventFreeList     = pevent; /* Get next free event control block        *///将事件控制块放入空闲链表中
                 OS_EXIT_CRITICAL();
                 *err = OS_NO_ERR;//无错
                 return ((OS_EVENT *)0);                   /* Queue has been deleted                   */
             } else {//有任务等待
                 OS_EXIT_CRITICAL();
                 *err = OS_ERR_TASK_WAITING;
                 return (pevent);
             }

        case OS_DEL_ALWAYS:                                /* Always delete the queue                  */
			//始终要删除队列
             while (pevent->OSEventGrp != 0x00) {          /* Ready ALL tasks waiting for queue        */
			 	//真有任务等待
                 OS_EventTaskRdy(pevent, (void *)0, OS_STAT_Q);//将挂起的任务就绪
             }
             pq                  = (OS_Q *)pevent->OSEventPtr;      /* Return OS_Q to free list        */
             pq->OSQPtr          = OSQFreeList;
             OSQFreeList         = pq;//同上,将队列控制块放入空闲链表
             pevent->OSEventType = OS_EVENT_TYPE_UNUSED;//标记为未用
             pevent->OSEventPtr  = OSEventFreeList;        /* Return Event Control Block to free list  */
             OSEventFreeList     = pevent;                 /* Get next free event control block        */
			 //将事件控制块放入空闲链表
             OS_EXIT_CRITICAL();
             if (tasks_waiting == TRUE) {                  /* Reschedule only if task(s) were waiting  */
                 OS_Sched();                               /* Find highest priority task ready to run  */
				 //因为新任务就绪,所以要重新调度
             }
             *err = OS_NO_ERR;
             return ((OS_EVENT *)0);                       /* Queue has been deleted                   */

        default://其它异常情况
             OS_EXIT_CRITICAL();
             *err = OS_ERR_INVALID_OPT;
             return (pevent);
    }
}
#endif

/*$PAGE*/
/*
*********************************************************************************************************
*                                           FLUSH QUEUE
*
* Description : This function is used to flush the contents of the message queue.
*
* Arguments   : none
*
* Returns     : OS_NO_ERR           upon success
*               OS_ERR_EVENT_TYPE   If you didn't pass a pointer to a queue
*               OS_ERR_PEVENT_NULL  If 'pevent' is a NULL pointer
                                                   清空消息队列
描述:清空消息队列中内容
参数:无
返回:
                 OS_NO_ERR          成功
*               OS_ERR_EVENT_TYPE   没有传递指针给队列
*               OS_ERR_PEVENT_NULL  如果'pevent' 是一个空指针

*********************************************************************************************************
*/

#if OS_Q_FLUSH_EN > 0
INT8U  OSQFlush (OS_EVENT *pevent)
{
#if OS_CRITICAL_METHOD == 3                           /* Allocate storage for CPU status register      */
    OS_CPU_SR  cpu_sr;
#endif
    OS_Q      *pq;


#if OS_ARG_CHK_EN > 0//允许参数检验
    if (pevent == (OS_EVENT *)0) {                    /* Validate 'pevent'                             */
        return (OS_ERR_PEVENT_NULL);
    }//不合理的参数pevent
    if (pevent->OSEventType != OS_EVENT_TYPE_Q) {     /* Validate event block type                     */
        return (OS_ERR_EVENT_TYPE);
    }//不是事件块类型
#endif
    OS_ENTER_CRITICAL();
    pq             = (OS_Q *)pevent->OSEventPtr;      /* Point to queue storage structure              */
	//保存结构指针
    pq->OSQIn      = pq->OSQStart;
    pq->OSQOut     = pq->OSQStart;//将队列的插入指针IN和取出指针OUT复位
    pq->OSQEntries = 0;//初始化入口为零
    OS_EXIT_CRITICAL();
    return (OS_NO_ERR);
}
#endif

/*$PAGE*/
/*
*********************************************************************************************************
*                                     PEND ON A QUEUE FOR A MESSAGE
*
* Description: This function waits for a message to be sent to a queue
*
* Arguments  : pevent        is a pointer to the event control block associated with the desired queue
*
*              timeout       is an optional timeout period (in clock ticks).  If non-zero, your task will
*                            wait for a message to arrive at the queue up to the amount of time
*                            specified by this argument.  If you specify 0, however, your task will wait
*                            forever at the specified queue or, until a message arrives.
*
*              err           is a pointer to where an error message will be deposited.  Possible error
*                            messages are:
*
*                            OS_NO_ERR           The call was successful and your task received a
*                                                message.
*                            OS_TIMEOUT          A message was not received within the specified timeout
*                            OS_ERR_EVENT_TYPE   You didn't pass a pointer to a queue
*                            OS_ERR_PEVENT_NULL  If 'pevent' is a NULL pointer
*                            OS_ERR_PEND_ISR     If you called this function from an ISR and the result
*                                                would lead to a suspension.
*
* 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 a pointer to a queue.
                                                 等待消息队列中的消息
描述:等待消息中的队列
参数:pevent:指向事件控制块结合目标队列的指针
                timeout:超时时间选项(按时钟节拍来),如果非零,任务将按照此
                             参数的定时在队列中等待消息到来,如果设置为零,任务将在目标
                             队列中永远等待,直到消息到来。
                err:指向可能的错误消息的指针,可能为:
*                            OS_NO_ERR        调用成功,任务接收到消息
*                            OS_TIMEOUT         定时时间内消息没有来
*                            OS_ERR_EVENT_TYPE   你没有传递指针到队列
*                            OS_ERR_PEVENT_NULL  如果 'pevent' 是一个空指针
*                            OS_ERR_PEND_ISR    如果从ISR中调用,结果将出现异常              
*********************************************************************************************************
*/

void  *OSQPend (OS_EVENT *pevent, INT16U timeout, INT8U *err)
{
#if OS_CRITICAL_METHOD == 3                      /* Allocate storage for CPU status register           */
    OS_CPU_SR  cpu_sr;
#endif
    void      *msg;
    OS_Q      *pq;


    if (OSIntNesting > 0) {                      /* See if called from ISR ...                         */
        *err = OS_ERR_PEND_ISR;                  /* ... can't PEND from an ISR                         */
        return ((void *)0);//不能在ISR中挂起
    }
#if OS_ARG_CHK_EN > 0
    if (pevent == (OS_EVENT *)0) {               /* Validate 'pevent'                                  */
        *err = OS_ERR_PEVENT_NULL;
        return ((void *)0);//不合理的pevent
    }
    if (pevent->OSEventType != OS_EVENT_TYPE_Q) {/* Validate event block type                          */
        *err = OS_ERR_EVENT_TYPE;
        return ((void *)0);//不是事件块类型
    }
#endif
    OS_ENTER_CRITICAL();
    pq = (OS_Q *)pevent->OSEventPtr;             /* Point at queue control block                       */
	//取出队列控制块指针
    if (pq->OSQEntries > 0) {                    /* See if any messages in the queue                   */
//大于零,表示有消息可以用。此时,OSQPend得到事件控制块的.OSQOut域所指
//向的消息,将指向消息的指针复制到msg变量中,并让.OSQOut指针指向
//队列中的下个单元
        msg = *pq->OSQOut++;                     /* Yes, extract oldest message from the queue         */
        pq->OSQEntries--;                        /* Update the number of entries in the queue          */
// 队列中有效消息减一
        if (pq->OSQOut == pq->OSQEnd) {          /* Wrap OUT pointer if we are at the end of the queue */
            pq->OSQOut = pq->OSQStart;
        }//消息队列是一个循环缓冲区,如果超出了队列中最末一个单元,发生
        //这种越界时,就要将.OSQOut重新调整到指向队列的起始单元
        OS_EXIT_CRITICAL();
        *err = OS_NO_ERR;
        return (msg);  /* Return message received      *///返回接收到的消息
    }
    OSTCBCur->OSTCBStat |= OS_STAT_Q;            /* Task will have to pend for a message to be posted  */
	//设置任务的TCB状态标志,以表明等待消息队列消息的任务被挂起
    OSTCBCur->OSTCBDly   = timeout;              /* Load timeout into TCB                              */
	//装载定时器到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();
    msg = OSTCBCur->OSTCBMsg;//任务调度后,任务会检查此函数是不是将消息放到了
    //任务的TCB中。
    if (msg != (void *)0) {                      /* Did we get a message?                              */
		//如果消息确实存在。
        OSTCBCur->OSTCBMsg      = (void *)0;     /* Extract message from TCB (Put there by QPost)      */
		//清除此消息?
        OSTCBCur->OSTCBStat     = OS_STAT_RDY;//就绪
        OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0; /* No longer waiting for event                        */
		//不再等待事件了
        OS_EXIT_CRITICAL();
        *err                    = OS_NO_ERR;
        return (msg);                            /* Return message received                            */
    }
    OS_EventTO(pevent);                          /* Timed out                                          */
	//超时了。
    OS_EXIT_CRITICAL();
    *err = OS_TIMEOUT;                           /* Indicate a timeout occured       */
    return ((void *)0);                          /* No message received      */
}
/*$PAGE*/
/*
*********************************************************************************************************
*                                        POST MESSAGE TO A QUEUE
*
* Description: This function sends a message to a queue
*
* Arguments  : pevent        is a pointer to the event control block associated with the desired queue
*
*              msg           is a pointer to the message to send.  You MUST NOT send a NULL pointer.
*
* Returns    : OS_NO_ERR             The call was successful and the message was sent
*              OS_Q_FULL             If the queue cannot accept any more messages because it is full.
*              OS_ERR_EVENT_TYPE     If you didn't pass a pointer to a queue.
*              OS_ERR_PEVENT_NULL    If 'pevent' is a NULL pointer
*              OS_ERR_POST_NULL_PTR  If you are attempting to post a NULL pointer
                                             向消息队列发送一则消息(FIFO)
描述:发送一则消息到队列
参数:pevent:指向事件控制块联合目标队列的指针
                msg:指向要发送的消息。不能发送NULL
返回:OS_NO_ERR            消息成功发送
*              OS_Q_FULL             如果队列满了,不能接收消息了
*              OS_ERR_EVENT_TYPE     如果没有发送消息到队列
*              OS_ERR_PEVENT_NULL    如果 'pevent' 是空指针
*              OS_ERR_POST_NULL_PTR  如果你发送空消息
*********************************************************************************************************
*/

#if OS_Q_POST_EN > 0
INT8U  OSQPost (OS_EVENT *pevent, void *msg)
{
#if OS_CRITICAL_METHOD == 3                      /* Allocate storage for CPU status register           */
    OS_CPU_SR  cpu_sr;
#endif
    OS_Q      *pq;


#if OS_ARG_CHK_EN > 0
    if (pevent == (OS_EVENT *)0) {                    /* Validate 'pevent'                             */
        return (OS_ERR_PEVENT_NULL);
    }//不合理的pevent
    if (msg == (void *)0) {                           /* Make sure we are not posting a NULL pointer   */
        return (OS_ERR_POST_NULL_PTR);
    }//保证没有发送空指针
    if (pevent->OSEventType != OS_EVENT_TYPE_Q) {     /* Validate event block type                     */
        return (OS_ERR_EVENT_TYPE);
    }//非法的事件块类型
#endif
    OS_ENTER_CRITICAL();
    if (pevent->OSEventGrp != 0x00) {                 /* See if any task pending on queue              */
//如果有任务在等
        OS_EventTaskRdy(pevent, msg, OS_STAT_Q);      /* Ready highest priority task waiting on event  */
//使在事件中等待的最高优先级任务就绪
        OS_EXIT_CRITICAL();
        OS_Sched();                                   /* Find highest priority task ready to run       */
		//任务调度
        return (OS_NO_ERR);
    }
    pq = (OS_Q *)pevent->OSEventPtr;                  /* Point to queue control block                  */
    if (pq->OSQEntries >= pq->OSQSize) {              /* Make sure queue is not full                   */
        OS_EXIT_CRITICAL();
        return (OS_Q_FULL);
    }
    *pq->OSQIn++ = msg;                               /* Insert message into queue                     */
	//将消息插入
    pq->OSQEntries++;                                 /* Update the nbr of entries in the queue        */
	//更新总消息数
    if (pq->OSQIn == pq->OSQEnd) {                    /* Wrap IN ptr if we are at end of queue         */
        pq->OSQIn = pq->OSQStart;//调节消息队列循环缓冲区,当越界时,重新指向新的开头
    }
    OS_EXIT_CRITICAL();
    return (OS_NO_ERR);
}
#endif
/*$PAGE*/
/*
*********************************************************************************************************
*                                   POST MESSAGE TO THE FRONT OF A QUEUE
*
* Description: This function sends a message to a queue but unlike OSQPost(), the message is posted at
*              the front instead of the end of the queue.  Using OSQPostFront() allows you to send
*              'priority' messages.
*
* Arguments  : pevent        is a pointer to the event control block associated with the desired queue
*
*              msg           is a pointer to the message to send.  You MUST NOT send a NULL pointer.
*
* Returns    : OS_NO_ERR             The call was successful and the message was sent
*              OS_Q_FULL             If the queue cannot accept any more messages because it is full.
*              OS_ERR_EVENT_TYPE     If you didn't pass a pointer to a queue.
*              OS_ERR_PEVENT_NULL    If 'pevent' is a NULL pointer
*              OS_ERR_POST_NULL_PTR  If you are attempting to post to a non queue.
                             向消息队列发送一则消息(LIFO)
描述:发送一则消息,但与OSQPost()不同,消息是指向前端而不是队列的后端,
                //用此函数允许你发送优先级消息。
参数:pevent:指向事件控制块联合目标队列的指针
                smg:指向你要发送的消息,不能发送空指针
返回:OS_NO_ERR             调用成功,消息成功发送
*              OS_Q_FULL             如果队列满了,不能接收消息了
*              OS_ERR_EVENT_TYPE     如果没有发送消息到队列
*              OS_ERR_PEVENT_NULL   如果 'pevent' 是空指针
*              OS_ERR_POST_NULL_PTR  如果你想发送到的不是队列
*********************************************************************************************************
*/

#if OS_Q_POST_FRONT_EN > 0
INT8U  OSQPostFront (OS_EVENT *pevent, void *msg)
{
#if OS_CRITICAL_METHOD == 3                      /* Allocate storage for CPU status register           */
    OS_CPU_SR  cpu_sr;
#endif
    OS_Q      *pq;


#if OS_ARG_CHK_EN > 0
    if (pevent == (OS_EVENT *)0) {                    /* Validate 'pevent'                             */
        return (OS_ERR_PEVENT_NULL);
    }}//不合理的pevent
    if (msg == (void *)0) {                           /* Make sure we are not posting a NULL pointer   */
        return (OS_ERR_POST_NULL_PTR);
    }//保证没有发送空指针
    if (pevent->OSEventType != OS_EVENT_TYPE_Q) {     /* Validate event block type                     */
        return (OS_ERR_EVENT_TYPE);
    }//非法的事件块类型
#endif
    OS_ENTER_CRITICAL();
    if (pevent->OSEventGrp != 0x00) {                 /* See if any task pending on queue              */
        OS_EventTaskRdy(pevent, msg, OS_STAT_Q);      /* Ready highest priority task waiting on event  */
        OS_EXIT_CRITICAL();
        OS_Sched();                                   /* Find highest priority task ready to run       */
        return (OS_NO_ERR);//解释见上个函数
    }
    pq = (OS_Q *)pevent->OSEventPtr;                  /* Point to queue control block                  */
	//装载队列控制块指针
    if (pq->OSQEntries >= pq->OSQSize) {  /* Make sure queue is not full                   */
		//保证队列还没有满
        OS_EXIT_CRITICAL();
        return (OS_Q_FULL);
    }//OSQOut指针指向的是已经插入了消息指针的单元,所以在插入新的消息指针前,
    //要将OSQOut指针在消息队列中前移一个单元,
    if (pq->OSQOut == pq->OSQStart) {                 /* Wrap OUT ptr if we are at the 1st queue entry */
        pq->OSQOut = pq->OSQEnd;//更新循环缓冲链。如果pq->OSQOut指向的当前单无是队
        //列中的第一个单元,再向前移的话就意味着指向了队列的末尾
    }
    pq->OSQOut--;//OSQEnd指向的是消息队列中最后一个单元的下一个单元,所以,
    //要求将其调整到指向队列的有效范围内。因为OSQPend()函数取出的消息
    //是由此函数刚刚插入的,这样,就实现了后进先出。
    *pq->OSQOut = msg;                                /* Insert message into queue                     */
    pq->OSQEntries++;                                 /* Update the nbr of entries in the queue        */
    OS_EXIT_CRITICAL();
    return (OS_NO_ERR);
}
#endif
/*$PAGE*/
/*
*********************************************************************************************************
*                                        POST MESSAGE TO A QUEUE
*
* Description: This function sends a message to a queue.  This call has been added to reduce code size
*              since it can replace both OSQPost() and OSQPostFront().  Also, this function adds the
*              capability to broadcast a message to ALL tasks waiting on the message queue.
*
* Arguments  : pevent        is a pointer to the event control block associated with the desired queue
*
*              msg           is a pointer to the message to send.  You MUST NOT send a NULL pointer.
*
*              opt           determines the type of POST performed:
*                            OS_POST_OPT_NONE         POST to a single waiting task
*                                                     (Identical to OSQPost())
*                            OS_POST_OPT_BROADCAST    POST to ALL tasks that are waiting on the queue
*                            OS_POST_OPT_FRONT        POST as LIFO (Simulates OSQPostFront())
*
*                            Below is a list of ALL the possible combination of these flags:
*
*                                 1) OS_POST_OPT_NONE
*                                    identical to OSQPost()
*
*                                 2) OS_POST_OPT_FRONT
*                                    identical to OSQPostFront()
*
*                                 3) OS_POST_OPT_BROADCAST
*                                    identical to OSQPost() but will broadcast 'msg' to ALL waiting tasks
*
*                                 4) OS_POST_OPT_FRONT + OS_POST_OPT_BROADCAST  is identical to
*                                    OSQPostFront() except that will broadcast 'msg' to ALL waiting tasks
*
* Returns    : OS_NO_ERR             The call was successful and the message was sent
*              OS_Q_FULL             If the queue cannot accept any more messages because it is full.
*              OS_ERR_EVENT_TYPE     If you didn't pass a pointer to a queue.
*              OS_ERR_PEVENT_NULL    If 'pevent' is a NULL pointer
*              OS_ERR_POST_NULL_PTR  If you are attempting to post a NULL pointer
*
* 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 queue.
                              向消息队列发送一则消息(LIFO或者FIFO)   
描述:以可以替代的,更灵活的方式给消息队列发消息,可以代替LIFO或者FIFO
               允许发送消息给所有消息队列中等待消息的任务(广播方式)
参数:pevent:指向事件控制块联合目标队列的指针
                smg:指向你要发送的消息,不能发送空指针
                opt:确定发送方式:
*                            OS_POST_OPT_NONE        发送给单个任务,相当于OSQPost()
*                            OS_POST_OPT_BROADCAST   发送给队列中所有等待的任务
*                            OS_POST_OPT_FRONT        以LIFO 发送(与 OSQPostFront()相似)
                 下面是所有标志可能的结合情况:  
*                                 1) OS_POST_OPT_NONE
*                                    相当于 OSQPost()
*
*                                 2) OS_POST_OPT_FRONT
*                                    相当于 OSQPostFront()
*
*                                 3) OS_POST_OPT_BROADCAST
*                                    相当于 OSQPost() 但可以以广播方式发送 to ALL waiting tasks
*
*                                 4) OS_POST_OPT_FRONT + OS_POST_OPT_BROADCAST  相当于
*                                    OSQPostFront() 可以以广播方式发送
*********************************************************************************************************
*/

#if OS_Q_POST_OPT_EN > 0
INT8U  OSQPostOpt (OS_EVENT *pevent, void *msg, INT8U opt)
{
#if OS_CRITICAL_METHOD == 3                      /* Allocate storage for CPU status register           */
    OS_CPU_SR  cpu_sr;
#endif
    OS_Q      *pq;


#if OS_ARG_CHK_EN > 0
    if (pevent == (OS_EVENT *)0) {                    /* Validate 'pevent'                             */
        return (OS_ERR_PEVENT_NULL);
    }//非法pevent 
    if (msg == (void *)0) {                           /* Make sure we are not posting a NULL pointer   */
        return (OS_ERR_POST_NULL_PTR);
    }//保证没有送空指针
    if (pevent->OSEventType != OS_EVENT_TYPE_Q) {     /* Validate event block type                     */
        return (OS_ERR_EVENT_TYPE);
    }//不是事件块类型
#endif
    OS_ENTER_CRITICAL();
    if (pevent->OSEventGrp != 0x00) {                 /* See if any task pending on queue              */
		//如果有任务在队列中挂起
        if ((opt & OS_POST_OPT_BROADCAST) != 0x00) {  /* Do we need to post msg to ALL waiting tasks ? */
			//向所有任务发送?
            while (pevent->OSEventGrp != 0x00) {      /* Yes, Post to ALL tasks waiting on queue       */
                OS_EventTaskRdy(pevent, msg, OS_STAT_Q);
            }//是的。如果将opt参数中的OS_POST_OPT_BROADCAST位置为1,则所有正在等待消息
            //的任务都能接收到这则消息,并且被OS_EventTaskRdy从等待列表中删除。
        } else {//不要向所有的等待任务发消息
            OS_EventTaskRdy(pevent, msg, OS_STAT_Q);  /* No,  Post to HPT waiting on queue             */
			//那就只发优先级最高的。
        }
        OS_EXIT_CRITICAL();
        OS_Sched();                                   /* Find highest priority task ready to run       */
		//要任务调度
        return (OS_NO_ERR);
    }
    pq = (OS_Q *)pevent->OSEventPtr;                  /* Point to queue control block                  */
	//指向队列控制块
    if (pq->OSQEntries >= pq->OSQSize) {              /* Make sure queue is not full                   */
        OS_EXIT_CRITICAL();//如果满了,返回错误代码
        return (OS_Q_FULL);
    }
    if ((opt & OS_POST_OPT_FRONT) != 0x00) {          /* Do we post to the FRONT of the queue?         */
		//FIFO还是LIFO,如果是LIFO
        if (pq->OSQOut == pq->OSQStart) {             /* Yes, Post as LIFO, Wrap OUT pointer if we ... */
            pq->OSQOut = pq->OSQEnd;                  /*      ... are at the 1st queue entry           */
        }//如果是后进先出,则相当于OSQPostFront 。如果我人在队列第一个,则调整
        pq->OSQOut--;
        *pq->OSQOut = msg;                            /*      Insert message into queue                */
		//插入消息
    } else {                                          /* No,  Post as FIFO                             */
    //如果是FIFO
        *pq->OSQIn++ = msg;                           /*      Insert message into queue                */
        if (pq->OSQIn == pq->OSQEnd) {                /*      Wrap IN ptr if we are at end of queue    */
            pq->OSQIn = pq->OSQStart;//如果在最末尾,则调整
        }
    }
    pq->OSQEntries++;                                 /* Update the nbr of entries in the queue        */
	//更新消息条数
    OS_EXIT_CRITICAL();
    return (OS_NO_ERR);
}
#endif
/*$PAGE*/
/*
*********************************************************************************************************
*                                        QUERY A MESSAGE QUEUE
*
* Description: This function obtains information about a message queue.
*
* Arguments  : pevent        is a pointer to the event control block associated with the desired queue
*
*              pdata         is a pointer to a structure that will contain information about the message
*                            queue.
*
* Returns    : OS_NO_ERR           The call was successful and the message was sent
*              OS_ERR_EVENT_TYPE   If you are attempting to obtain data from a non queue.
*              OS_ERR_PEVENT_NULL  If 'pevent' is a NULL pointer
                                       获取消息队列状态
描述:获取消息队列的信息
参数:pevent:指向事件控制块结合目标队列的指针
                pdata:指向消息队列包含信息的结构指针
返回:OS_NO_ERR           调用成功,消息成功发送
*              OS_ERR_EVENT_TYPE   你想获取非队列的信息
*              OS_ERR_PEVENT_NULL  如果 'pevent' 是一个NULL指针
*********************************************************************************************************
*/

#if OS_Q_QUERY_EN > 0
INT8U  OSQQuery (OS_EVENT *pevent, OS_Q_DATA *pdata)
{
#if OS_CRITICAL_METHOD == 3                      /* Allocate storage for CPU status register           */
    OS_CPU_SR  cpu_sr;
#endif
    OS_Q      *pq;
    INT8U     *psrc;
    INT8U     *pdest;


#if OS_ARG_CHK_EN > 0
    if (pevent == (OS_EVENT *)0) {                         /* Validate 'pevent'     */
        return (OS_ERR_PEVENT_NULL);
    }//非法pevent 
    if (pevent->OSEventType != OS_EVENT_TYPE_Q) {          /* Validate event block type   */
        return (OS_ERR_EVENT_TYPE);
    }//保证没有送空指针
#endif
    OS_ENTER_CRITICAL();
//复制等待任务列表
    pdata->OSEventGrp = pevent->OSEventGrp;           /* Copy message queue wait list  */
    psrc              = &pevent->OSEventTbl[0];
    pdest             = &pdata->OSEventTbl[0];
#if OS_EVENT_TBL_SIZE > 0//从0开始,慢慢复制吧。
    *pdest++          = *psrc++;
#endif

#if OS_EVENT_TBL_SIZE > 1
    *pdest++          = *psrc++;
#endif

#if OS_EVENT_TBL_SIZE > 2
    *pdest++          = *psrc++;
#endif

#if OS_EVENT_TBL_SIZE > 3
    *pdest++          = *psrc++;
#endif

#if OS_EVENT_TBL_SIZE > 4
    *pdest++          = *psrc++;
#endif

#if OS_EVENT_TBL_SIZE > 5
    *pdest++          = *psrc++;
#endif

#if OS_EVENT_TBL_SIZE > 6
    *pdest++          = *psrc++;
#endif

#if OS_EVENT_TBL_SIZE > 7
    *pdest            = *psrc;
#endif
    pq = (OS_Q *)pevent->OSEventPtr;
    if (pq->OSQEntries > 0) {//如果有消息等待,则提取出(并没有删除)队列中最早进入
    //队列的消息,并将其复制到OSMsg中,OSQQuery并没有改动.OSQOut的指针。
        pdata->OSMsg = *pq->OSQOut;                        /* Get next message to return if available  */
    } else {//如果没有任务等待,则返回空指针
        pdata->OSMsg = (void *)0;
    }
    pdata->OSNMsgs = pq->OSQEntries;//队列中消息数
    pdata->OSQSize = pq->OSQSize;//队列容易大小
    OS_EXIT_CRITICAL();
    return (OS_NO_ERR);
}
#endif                                                     /* OS_Q_QUERY_EN                            */

/*$PAGE*/
/*
*********************************************************************************************************
*                                      QUEUE MODULE INITIALIZATION
*
* Description : This function is called by uC/OS-II to initialize the message queue module.  Your
*               application MUST NOT call this function.
*
* Arguments   :  none
*
* Returns     : none
*
* Note(s)    : This function is INTERNAL to uC/OS-II and your application should not call it.
                                                   初始化消息队列
描述:由ucos调用初始化消息队列模型,应用程序不能调用
参数:无
返回:无
备注:由ucos调用初始化消息队列模型,应用程序不能调用
*********************************************************************************************************
*/

void  OS_QInit (void)
{
#if OS_MAX_QS == 1//如果只有一个队列
    OSQFreeList         = &OSQTbl[0];            /* Only ONE queue!     */
    OSQFreeList->OSQPtr = (OS_Q *)0;//前趋为零指针
#endif

#if OS_MAX_QS >= 2
    INT16U  i;
    OS_Q   *pq1;
    OS_Q   *pq2;


    pq1 = &OSQTbl[0];
    pq2 = &OSQTbl[1];
    for (i = 0; i < (OS_MAX_QS - 1); i++) {      /* Init. list of free QUEUE control blocks            */
		//初始化空闲队列控制块,组成一个单向链表
        pq1->OSQPtr = pq2;
        pq1++;
        pq2++;
    }
    pq1->OSQPtr = (OS_Q *)0;//后趋附指向NULL指针
    OSQFreeList = &OSQTbl[0];//空链表指针指向首地址。
#endif
}
#endif                                                     /* OS_Q_EN                                  */


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
\SOFTWARE The main directory from the root where all software-related files are placed. \SOFTWARE\BLOCKS The main directory where all ‘Building Blocks’ are located. With μC/OS-II, I included a ‘building block’ that handles DOS-type compatible functions that are used by the example code. \SOFTWARE\BLOCKS\TO This directory contains the files for the TO utility (see Appendix E, TO). The source file is TO.C and is found in the \SOFTWARE\TO\SOURCE directory. The DOS executable file (TO.EXE) is found in the \SOFTWARE\TO\EXE directory. Note that TO requires a file called TO.TBL which must reside on your root directory. An example of TO.TBL is also found in the \SOFTWARE\TO\EXE directory. You will need to move TO.TBL to the root directory if you are to use TO.EXE. \SOFTWARE\uCOS-II The main directory where all μC/OS-II files are located. \SOFTWARE\uCOS-II\EX1_x86L This directory contains the source code for EXAMPLE #1 (see section 1.07, Example #1) which is intended to run under DOS (or a DOS window under Windows 95). \SOFTWARE\uCOS-II\EX2_x86L This directory contains the source code for EXAMPLE #2 (see section 1.08, Example #2) which is intended to run under DOS (or a DOS window under Windows 95). \SOFTWARE\uCOS-II\EX3_x86L This directory contains the source code for EXAMPLE #3 (see section 1.09, Example #3) which is intended to run under DOS (or a DOS window under Windows 95). \SOFTWARE\uCOS-II\Ix86L This directory contains the source code for the processor dependent code (a.k.a. the port) of μC/OS-II for an 80x86 Real-Mode, Large Model processor. \SOFTWARE\uCOS-II\SOURCE This directory contains the source code for processor independent portion of μC/OS-II. This code is fully portable to other processor architectures.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值