您的位置:首页 > 其它

uC/OS-II源码解析(os_q.c)

2017-05-17 17:00 405 查看
/*
** ver   : 2.52
** file  : os_q.c
** brief : 消息队列相关操作 C 文件
*/

#ifndef  OS_MASTER_FILE
#include "includes.h"            /* 包含头文件 */
#endif

#if (OS_Q_EN > 0) && (OS_MAX_QS > 0)
/*
**********************************************************************************************
*                                      无等待的请求消息队列
*
* breif    : 该函数用于无等待的请求消息队列中的消息.
*
* pevent   : 指向事件控制块的指针
*
* Returns  : != (void *)0  队列中有可用消息
*            == (void *)0  未获得消息
**********************************************************************************************
*/

#if OS_Q_ACCEPT_EN > 0
void  *OSQAccept (OS_EVENT *pevent)
{
#if OS_CRITICAL_METHOD == 3
4000

OS_CPU_SR  cpu_sr;
#endif
void      *msg;
OS_Q      *pq;

#if OS_ARG_CHK_EN > 0
if (pevent == (OS_EVENT *)0) {               /* 无效的事件控制块指针 */
return ((void *)0);
}
if (pevent->OSEventType != OS_EVENT_TYPE_Q) {/* 错误的事件类型       */
return ((void *)0);
}
#endif
OS_ENTER_CRITICAL();
pq = (OS_Q *)pevent->OSEventPtr;             /* 获得队列控制块       */
if (pq->OSQEntries > 0) {                    /* 判断队列中是否有消息 */
msg = *pq->OSQOut++;                     /* 将消息取出来返回     */
pq->OSQEntries--;                        /* 消息数减1            */
if (pq->OSQOut == pq->OSQEnd) {          /* 调整已实现循环队列   */
pq->OSQOut = pq->OSQStart;
}
} else {
msg = (void *)0;                         /* 队列为空             */
}
OS_EXIT_CRITICAL();
return (msg);
}
#endif
/*$PAGE*/
/*
*****************************************************************************************
*                                        创建消息队列
*
* brief   : 该函数用于创建消息队列.
*
* start   : 消息队列的基地址.该数组必须被声明为void类型
*
*             void *MessageStorage[size]
*
* size    : 消息数组的大小
*
* Returns : != (OS_EVENT *)0  消息队列创建成功
*           == (OS_EVENT *)0  消息队列创建失败
*****************************************************************************************
*/

OS_EVENT  *OSQCreate (void **start, INT16U size)
{
#if OS_CRITICAL_METHOD == 3
OS_CPU_SR  cpu_sr;
#endif
OS_EVENT  *pevent;
OS_Q      *pq;

if (OSIntNesting > 0) {                      /* 不允许中断内创建消息队列 */
return ((OS_EVENT *)0);
}
OS_ENTER_CRITICAL();
pevent = OSEventFreeList;                    /* 获取事件控制块           */
if (OSEventFreeList != (OS_EVENT *)0) {      /* 调整剩余事件控制块链表   */
OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr;
}
OS_EXIT_CRITICAL();
if (pevent != (OS_EVENT *)0) {
OS_ENTER_CRITICAL();
pq = OSQFreeList;                        /* 获取队列控制块      */
if (pq != (OS_Q *)0) {                   /* 存在剩余队列控制块  */
OSQFreeList         = OSQFreeList->OSQPtr;/* 调整队列控制块链表 */
OS_EXIT_CRITICAL();
pq->OSQStart        = start;              /* 初始化队列     */
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);             /* 初始化等待任务表 */
} else {                                      /* 无可用队列控制块 */
pevent->OSEventPtr = (void *)OSEventFreeList; /* 返还事件控制块  */
OSEventFreeList    = pevent;
OS_EXIT_CRITICAL();
pevent = (OS_EVENT *)0;
}
}
return (pevent);
}
/*$PAGE*/
/*
****************************************************************************************
*                                        删除消息队列
*
* brief    : 该函数用于删除消息队列.
*
* pevent   : 指向事件控制块的指针
*
* opt      : 删除选项
*              opt == OS_DEL_NO_PEND   无任务等待时删除
*              opt == OS_DEL_ALWAYS    无条件删除,就绪所有等待任务
*
* err      : 指向错误代码的指针,可能取值:
*              OS_NO_ERR               成功
*              OS_ERR_DEL_ISR          不允许在中断中删除队列
*              OS_ERR_INVALID_OPT      无效的删除选项
*              OS_ERR_TASK_WAITING     有任务正在等待队列中的消息
*              OS_ERR_EVENT_TYPE       错误的时间类型
*              OS_ERR_PEVENT_NULL      I无效的事件控制块指针
*
* Returns    : pevent        删除失败
*              (OS_EVENT *)0 删除成功
*
*****************************************************************************************
*/

#if OS_Q_DEL_EN > 0
OS_EVENT  *OSQDel (OS_EVENT *pevent, INT8U opt, INT8U *err)
{
#if OS_CRITICAL_METHOD == 3
OS_CPU_SR  cpu_sr;
#endif
BOOLEAN    tasks_waiting;
OS_Q      *pq;

if (OSIntNesting > 0) {                        /* 不允许中断内删除      */
*err = OS_ERR_DEL_ISR;
return ((OS_EVENT *)0);
}
#if OS_ARG_CHK_EN > 0
if (pevent == (OS_EVENT *)0) {                 /* 无效的事件控制块指针  */
*err = OS_ERR_PEVENT_NULL;
return (pevent);
}
if (pevent->OSEventType != OS_EVENT_TYPE_Q) {  /* 错误的事件类型        */
*err = OS_ERR_EVENT_TYPE;
return (pevent);
}
#endif
OS_ENTER_CRITICAL();
if (pevent->OSEventGrp != 0x00) {                      /* 是否有任务等待消息 */
tasks_waiting = TRUE;                              /* 有任务等待         */
} else {
tasks_waiting = FALSE;                             /* 无任务等待         */
}
switch (opt) {
case OS_DEL_NO_PEND:                               /* 无任务等待删除    */
if (tasks_waiting == FALSE) {
pq                  = (OS_Q *)pevent->OSEventPtr;  /* 返还队列控制块 */
pq->OSQPtr          = OSQFreeList;
OSQFreeList         = pq;
pevent->OSEventType = OS_EVENT_TYPE_UNUSED;
pevent->OSEventPtr  = OSEventFreeList;    /* 返还事件控制块  */
OSEventFreeList     = pevent;
OS_EXIT_CRITICAL();
*err = OS_NO_ERR;
return ((OS_EVENT *)0);
} else {
OS_EXIT_CRITICAL();
*err = OS_ERR_TASK_WAITING;
return (pevent);
}

case OS_DEL_ALWAYS:                                /* 无条件删除       */
while (pevent->OSEventGrp != 0x00) {          /* 就绪所有等待任务 */
OS_EventTaskRdy(pevent, (void *)0, OS_STAT_Q);
}
pq                  = (OS_Q *)pevent->OSEventPtr;/* 返还队列控制块 */
pq->OSQPtr          = OSQFreeList;
OSQFreeList         = pq;
pevent->OSEventType = OS_EVENT_TYPE_UNUSED;
pevent->OSEventPtr  = OSEventFreeList;        /* 返还事件控制块 */
OSEventFreeList     = pevent;
OS_EXIT_CRITICAL();
if (tasks_waiting == TRUE) {
OS_Sched();                               /* 任务调度 */
}
*err = OS_NO_ERR;
return ((OS_EVENT *)0);

default:
OS_EXIT_CRITICAL();
*err = OS_ERR_INVALID_OPT;
return (pevent);
}
}
#endif

/*$PAGE*/
/*
*******************************************************************************************
*                                           清空消息队列
*
* brief       : 该函数用于清空队列内的消息
*
* pevent      : 指向事件控制块的指针
*
* Returns     : OS_NO_ERR           成功
*               OS_ERR_EVENT_TYPE   错误的事件类型
*               OS_ERR_PEVENT_NULL  无效的事件控制块指针
********************************************************************************************
*/

#if OS_Q_FLUSH_EN > 0
INT8U  OSQFlush (OS_EVENT *pevent)
{
#if OS_CRITICAL_METHOD == 3
OS_CPU_SR  cpu_sr;
#endif
OS_Q      *pq;

#if OS_ARG_CHK_EN > 0
if (pevent == (OS_EVENT *)0) {                    /* 无效的事件控制块指针          */
return (OS_ERR_PEVENT_NULL);
}
if (pevent->OSEventType != OS_EVENT_TYPE_Q) {     /* 错误的事件类型                */
return (OS_ERR_EVENT_TYPE);
}
#endif
OS_ENTER_CRITICAL();
pq             = (OS_Q *)pevent->OSEventPtr;      /* 获取队列控制块               */
pq->OSQIn      = pq->OSQStart;                    /* 清空队列                     */
pq->OSQOut     = pq->OSQStart;
pq->OSQEntries = 0;
OS_EXIT_CRITICAL();
return (OS_NO_ERR);
}
#endif

/*$PAGE*/
/*
**********************************************************************************************
*                                     请求消息
*
* brief     : 该函数用于从消息队列中请求一则消息
*
* pevent    : 指向事件控制块的指针
*
* timeout   : 超时时限
*
*  err      : 指向错误代码的指针,可能取值:
*
*               OS_NO_ERR           成功
*               OS_TIMEOUT          超时
*               OS_ERR_EVENT_TYPE   错误的事件类型
*               OS_ERR_PEVENT_NULL  无效的事件控制块指针
*               OS_ERR_PEND_ISR     不能再中断中请求
*
* Returns    : != (void *)0  请求成功
*              == (void *)0  请求失败
***********************************************************************************************
*/

void  *OSQPend (OS_EVENT *pevent, INT16U timeout, INT8U *err)
{
#if OS_CRITICAL_METHOD == 3
OS_CPU_SR  cpu_sr;
#endif
void      *msg;
OS_Q      *pq;

if (OSIntNesting > 0) {                      /* 不允许中断中请求消息 */
*err = OS_ERR_PEND_ISR;
return ((void *)0);
}
#if OS_ARG_CHK_EN > 0
if (pevent == (OS_EVENT *)0) {               /* 无效的事件控制块     */
*err = OS_ERR_PEVENT_NULL;
return ((void *)0);
}
if (pevent->OSEventType != OS_EVENT_TYPE_Q) {/* 错误的事件类型       */
*err = OS_ERR_EVENT_TYPE;
return ((void *)0);
}
#endif
OS_ENTER_CRITICAL();
pq = (OS_Q *)pevent->OSEventPtr;             /* 获取队列控制块       */
if (pq->OSQEntries > 0) {                    /* 队列中是否有消息     */
msg = *pq->OSQOut++;                     /* 取出消息             */
pq->OSQEntries--;                        /* 消息数减1            */
if (pq->OSQOut == pq->OSQEnd) {          /* 调整指针实现循环队列 */
pq->OSQOut = pq->OSQStart;
}
OS_EXIT_CRITICAL();
*err = OS_NO_ERR;
return (msg);
}
OSTCBCur->OSTCBStat |= OS_STAT_Q;            /* 等待消息状态  */
OSTCBCur->OSTCBDly   = timeout;              /* 记录超时时限  */
OS_EventTaskWait(pevent);                    /* 使任务进入等待状态 */
OS_EXIT_CRITICAL();
OS_Sched();                                  /* 任务调度      */
OS_ENTER_CRITICAL();
msg = OSTCBCur->OSTCBMsg;
if (msg != (void *)0) {                      /* 是否收到了消息 */
OSTCBCur->OSTCBMsg      = (void *)0;     /* 请空消息       */
OSTCBCur->OSTCBStat     = OS_STAT_RDY;   /* 就绪态         */
OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0; /* 取消关联       */
OS_EXIT_CRITICAL();
*err                    = OS_NO_ERR;
return (msg);
}
OS_EventTO(pevent);                          /* 超时使任务就绪 */
OS_EXIT_CRITICAL();
*err = OS_TIMEOUT;                           /* Indicate a timeout       */
return ((void *)0);
}
/*$PAGE*/
/*
**********************************************************************************************
*                                        向队列发送一则消息
*
* breif    : 该函数用于向队列发送一则消息,由.OSQIn插入,先进先出
*
* pevent   : 指向事件控制块的指针
*
* msg      : 指向消息的指针
*
* Returns  : OS_NO_ERR             成功
*            OS_Q_FULL             队列已满
*            OS_ERR_EVENT_TYPE     错误的事件类型
*            OS_ERR_PEVENT_NULL    无效的事件控制块指针
*            OS_ERR_POST_NULL_PTR  发送的消息不能为空
***********************************************************************************************
*/

#if OS_Q_POST_EN > 0
INT8U  OSQPost (OS_EVENT *pevent, void *msg)
{
#if OS_CRITICAL_METHOD == 3
OS_CPU_SR  cpu_sr;
#endif
OS_Q      *pq;

#if OS_ARG_CHK_EN > 0
if (pevent == (OS_EVENT *)0) {                    /* 无效的事件控制块指针 */
return (OS_ERR_PEVENT_NULL);
}
if (msg == (void *)0) {                           /* 发送的消息不能为空   */
return (OS_ERR_POST_NULL_PTR);
}
if (pevent->OSEventType != OS_EVENT_TYPE_Q) {     /* 错误的事件类型       */
return (OS_ERR_EVENT_TYPE);
}
#endif
OS_ENTER_CRITICAL();
if (pevent->OSEventGrp != 0x00) {                 /* 是否有任务等待       */
OS_EventTaskRdy(pevent, msg, OS_STAT_Q);      /* 就绪最高优先级任务   */
OS_EXIT_CRITICAL();
OS_Sched();                                   /* 任务调度             */
return (OS_NO_ERR);
}
pq = (OS_Q *)pevent->OSEventPtr;                  /* 获取队列控制块       */
if (pq->OSQEntries >= pq->OSQSize) {              /* 队列已满             */
OS_EXIT_CRITICAL();
return (OS_Q_FULL);
}
*pq->OSQIn++ = msg;                               /* 插入消息             */
pq->OSQEntries++;                                 /* 消息数加1            */
if (pq->OSQIn == pq->OSQEnd) {                    /* 调整指针实现循环队列 */
pq->OSQIn = pq->OSQStart;
}
OS_EXIT_CRITICAL();
return (OS_NO_ERR);
}
#endif
/*$PAGE*/
/*
*******************************************************************************************
*                                   向队列发送一则消息
*
* breif   : 该函数用于向队列发送一则消息,由.OSQOut插入,先进后出
*
* pevent  : 指向事件控制块的指针
*
* msg     : 指向消息的指针
*
* Returns : OS_NO_ERR             成功
*           OS_Q_FULL             队列已满
*           OS_ERR_EVENT_TYPE     错误的时间类型
*           OS_ERR_PEVENT_NULL    无效的事件控制块指针
*           OS_ERR_POST_NULL_PTR  发送的消息不能为空
*******************************************************************************************
*/

#if OS_Q_POST_FRONT_EN > 0
INT8U  OSQPostFront (OS_EVENT *pevent, void *msg)
{
#if OS_CRITICAL_METHOD == 3
OS_CPU_SR  cpu_sr;
#endif
OS_Q      *pq;

#if OS_ARG_CHK_EN > 0
if (pevent == (OS_EVENT *)0) {                    /* 无效的事件控制块指针 */
return (OS_ERR_PEVENT_NULL);
}
if (msg == (void *)0) {                           /* 发送的消息不能为空  */
return (OS_ERR_POST_NULL_PTR);
}
if (pevent->OSEventType != OS_EVENT_TYPE_Q) {     /* 错误的事件类型       */
return (OS_ERR_EVENT_TYPE);
}
#endif
OS_ENTER_CRITICAL();
if (pevent->OSEventGrp != 0x00) {                 /* 是否有任务在等待消息 */
OS_EventTaskRdy(pevent, msg, OS_STAT_Q);      /* 就绪最高级等待任务   */
OS_EXIT_CRITICAL();
OS_Sched();                                   /* 任务调度             */
return (OS_NO_ERR);
}
pq = (OS_Q *)pevent->OSEventPtr;                  /* 获取队列控制块       */
if (pq->OSQEntries >= pq->OSQSize) {              /* 队列已满             */
OS_EXIT_CRITICAL();
return (OS_Q_FULL);
}
if (pq->OSQOut == pq->OSQStart) {                 /* 调整指针    */
pq->OSQOut = pq->OSQEnd;
}
pq->OSQOut--;
*pq->OSQOut = msg;                                /* 插入消息    */
pq->OSQEntries++;                                 /* 消息数加1   */
OS_EXIT_CRITICAL();
return (OS_NO_ERR);
}
#endif
/*$PAGE*/
/*
*******************************************************************************************
*                                        向队列发送一则消息
*
* breif     : 该函数用于向队列发送一则消息
*
* pevent    : 指向事件控制块的指针
*
* msg       : 指向消息的指针
*
* opt       : 发送选项,可能取值:
*               OS_POST_OPT_NONE         先进先出
*               OS_POST_OPT_BROADCAST    广播
*               OS_POST_OPT_FRONT        先进后出
*
* Returns   : OS_NO_ERR             成功
*             OS_Q_FULL             队列已满
*             OS_ERR_EVENT_TYPE     错误的事件类型
*             OS_ERR_PEVENT_NULL    无效的事件控制块指针
*             OS_ERR_POST_NULL_PTR  发送的消息不能为空
*******************************************************************************************
*/

#if OS_Q_POST_OPT_EN > 0
INT8U  OSQPostOpt (OS_EVENT *pevent, void *msg, INT8U opt)
{
#if OS_CRITICAL_METHOD == 3
OS_CPU_SR  cpu_sr;
#endif
OS_Q      *pq;

#if OS_ARG_CHK_EN > 0
if (pevent == (OS_EVENT *)0) {                    /* 无效的事件控制块指针 */
return (OS_ERR_PEVENT_NULL);
}
if (msg == (void *)0) {                           /* 发送的消息不能为空   */
return (OS_ERR_POST_NULL_PTR);
}
if (pevent->OSEventType != OS_EVENT_TYPE_Q) {     /* 错误的事件类型        */
return (OS_ERR_EVENT_TYPE);
}
#endif
OS_ENTER_CRITICAL();
if (pevent->OSEventGrp != 0x00) {                 /* 是否有任务等待消息 */
if ((opt & OS_POST_OPT_BROADCAST) != 0x00) {  /* 是否广播消息       */
while (pevent->OSEventGrp != 0x00) {      /* 就绪所有等待任务   */
OS_EventTaskRdy(pevent, msg, OS_STAT_Q);
}
} else {
OS_EventTaskRdy(pevent, msg, OS_STAT_Q);  /* 就绪最高优先级任务  */
}
OS_EXIT_CRITICAL();
OS_Sched();                                   /* 任务调度     */
return (OS_NO_ERR);
}
pq = (OS_Q *)pevent->OSEventPtr;                  /* 或许队列控制块       */
if (pq->OSQEntries >= pq->OSQSize) {              /* 队列已满             */
OS_EXIT_CRITICAL();
return (OS_Q_FULL);
}
if ((opt & OS_POST_OPT_FRONT) != 0x00) {          /* 先进后出         */
if (pq->OSQOut == pq->OSQStart) {
pq->OSQOut = pq->OSQEnd;
}
pq->OSQOut--;
*pq->OSQOut = msg;                            /* 先进先出          */
} else {
*pq->OSQIn++ = msg;
if (pq->OSQIn == pq->OSQEnd) {
pq->OSQIn = pq->OSQStart;
}
}
pq->OSQEntries++;                                 /* 消息数加1         */
OS_EXIT_CRITICAL();
return (OS_NO_ERR);
}
#endif
/*$PAGE*/
/*
***********************************************************************************************
*                                        查询队列
*
* brief     : 该函数用与查询消息队列信息.
*
* pevent    : 指向事件控制块的指针
*
* pdata     : 指向消息队列信息的数据结构指针
*
* Returns   : OS_NO_ERR           成功
*             OS_ERR_EVENT_TYPE   错误的事件类型
*             OS_ERR_PEVENT_NULL  无效的事件控制块指针
************************************************************************************************
*/

#if OS_Q_QUERY_EN > 0
INT8U  OSQQuery (OS_EVENT *pevent, OS_Q_DATA *pdata)
{
#if OS_CRITICAL_METHOD == 3
OS_CPU_SR  cpu_sr;
#endif
OS_Q      *pq;
INT8U     *psrc;
INT8U     *pdest;

#if OS_ARG_CHK_EN > 0
if (pevent == (OS_EVENT *)0) {                         /* 无效的事件控制块指针 */
return (OS_ERR_PEVENT_NULL);
}
if (pevent->OSEventType != OS_EVENT_TYPE_Q) {          /* 错误的时间类型        */
return (OS_ERR_EVENT_TYPE);
}
#endif
OS_ENTER_CRITICAL();
pdata->OSEventGrp = pevent->OSEventGrp;                /* 复制等待任务链表       */
psrc              = &pevent->OSEventTbl[0];
pdest             = &pdata->OSEventTbl[0];
#if OS_EVENT_TBL_SIZE > 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) {
pdata->OSMsg = *pq->OSQOut;                        /* 取出消息       */
} else {
pdata->OSMsg = (void *)0;
}
pdata->OSNMsgs = pq->OSQEntries;                       /* 消息数   */
pdata->OSQSize = pq->OSQSize;                          /* 队列大小 */
OS_EXIT_CRITICAL();
return (OS_NO_ERR);
}
#endif

/*$PAGE*/
/*
***************************************************************************************
*                                      初始化消息队列
*
* brief : 被函数 OSInit() 调用去初始化消息队列,你的应用中不应该调用该函数.
*
****************************************************************************************
*/

void  OS_QInit (void)
{
#if OS_MAX_QS == 1
OSQFreeList         = &OSQTbl[0];            /* 只有一个 */
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++) {    /* 初始化队列控制块为单向量表 */
pq1->OSQPtr = pq2;
pq1++;
pq2++;
}
pq1->OSQPtr = (OS_Q *)0;                    /* 对后一个队列控制块    */
OSQFreeList = &OSQTbl[0];                   /* 空队列控制块链表表头  */
#endif
}
#endif
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  ucos 源码 解析