/*
** 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
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
uC/OS-II源码解析(os_q.c)
最新推荐文章于 2023-06-06 22:08:48 发布