/*
*********************************************************************************************************
* uC/OS-III
* The Real-Time Kernel
*
* Copyright 2009-2022 Silicon Laboratories Inc. www.silabs.com
*
* SPDX-License-Identifier: APACHE-2.0
*
* This software is subject to an open source license and is distributed by
* Silicon Laboratories Inc. pursuant to the terms of the Apache License,
* Version 2.0 available at www.apache.org/licenses/LICENSE-2.0.
*
*********************************************************************************************************
*/
/*
*********************************************************************************************************
* 事件标志管理
*
* 文件: os_flag.c
* 版本: V3.08.02
*********************************************************************************************************
*/
#define MICRIUM_SOURCE
#include "os.h"
#ifdef VSC_INCLUDE_SOURCE_FILE_NAMES
const CPU_CHAR *os_flag__c = "$Id: $";
#endif
#if (OS_CFG_FLAG_EN > 0u)
/*
************************************************************************************************************************
* 创建事件标志
*
* 描述: 此函数用于创建一个事件标志组。
*
* 参数: p_grp 是指向要创建的事件标志组的指针
*
* p_name 是事件标志组的名称
*
* flags 包含要存储在事件标志组中的初始值(通常为 0)。
*
* p_err 是指向错误代码的指针,该错误代码将返回给您的应用程序:
*
* OS_ERR_NONE 如果调用成功
* OS_ERR_CREATE_ISR 如果您尝试从 ISR 中创建事件标志
* OS_ERR_ILLEGAL_CREATE_RUN_TIME 如果在调用 OSSafetyCriticalStart() 后尝试创建事件标志
* OS_ERR_OBJ_PTR_NULL 如果 'p_grp' 是 NULL 指针
* OS_ERR_OBJ_CREATED 如果事件标志已创建
*
* 返回: 无
************************************************************************************************************************
*/
void OSFlagCreate(OS_FLAG_GRP *p_grp, CPU_CHAR *p_name, OS_FLAGS flags, OS_ERR *p_err)
{
CPU_SR_ALLOC();
#ifdef OS_SAFETY_CRITICAL
if (p_err == (OS_ERR *)0) {
OS_SAFETY_CRITICAL_EXCEPTION();
return;
}
#endif
#ifdef OS_SAFETY_CRITICAL_IEC61508
if (OSSafetyCriticalStartFlag == OS_TRUE) {
*p_err = OS_ERR_ILLEGAL_CREATE_RUN_TIME;
return;
}
#endif
#if (OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u)
if (OSIntNestingCtr > 0u) { /* 检查是否从 ISR 调用 ... */
*p_err = OS_ERR_CREATE_ISR; /* ... 不能从 ISR 中创建 */
return;
}
#endif
#if (OS_CFG_ARG_CHK_EN > 0u)
if (p_grp == (OS_FLAG_GRP *)0) { /* 验证 'p_grp' */
*p_err = OS_ERR_OBJ_PTR_NULL;
return;
}
#endif
CPU_CRITICAL_ENTER();
#if (OS_OBJ_TYPE_REQ > 0u)
#if (OS_CFG_OBJ_CREATED_CHK_EN > 0u)
if (p_grp->Type == OS_OBJ_TYPE_FLAG) {
CPU_CRITICAL_EXIT();
*p_err = OS_ERR_OBJ_CREATED;
return;
}
#endif
p_grp->Type = OS_OBJ_TYPE_FLAG; /* 设置为事件标志组类型 */
#endif
#if (OS_CFG_DBG_EN > 0u)
p_grp->NamePtr = p_name;
#else
(void)p_name;
#endif
p_grp->Flags = flags; /* 设置为所需的初始值 */
#if (OS_CFG_TS_EN > 0u)
p_grp->TS = 0u;
#endif
OS_PendListInit(&p_grp->PendList);
#if (OS_CFG_DBG_EN > 0u)
OS_FlagDbgListAdd(p_grp);
OSFlagQty++;
#endif
OS_TRACE_FLAG_CREATE(p_grp, p_name);
CPU_CRITICAL_EXIT();
*p_err = OS_ERR_NONE;
}
/*
************************************************************************************************************************
* 删除事件标志组
*
* 描述: 此函数删除一个事件标志组,并准备好所有等待该事件标志组的任务。
*
* 参数: p_grp 是指向所需事件标志组的指针。
*
* opt 确定删除选项,如下所示:
*
* OS_OPT_DEL_NO_PEND 仅在没有任务等待时删除事件标志组
* OS_OPT_DEL_ALWAYS 即使有任务在等待,也删除事件标志组。
* 在这种情况下,所有等待的任务都将被准备好。
*
* p_err 是指向错误代码的指针,可以包含以下值之一:
*
* OS_ERR_NONE 调用成功且事件标志组已被删除
* OS_ERR_DEL_ISR 如果您尝试从 ISR 中删除事件标志组
* OS_ERR_ILLEGAL_DEL_RUN_TIME 如果在调用 OSStart() 后尝试删除事件标志组
* OS_ERR_OBJ_PTR_NULL 如果 'p_grp' 是 NULL 指针
* OS_ERR_OBJ_TYPE 如果传递的不是事件标志组的指针
* OS_ERR_OPT_INVALID 指定了无效的选项
* OS_ERR_OS_NOT_RUNNING 如果 uC/OS-III 尚未运行
* OS_ERR_TASK_WAITING 有一个或多个任务正在等待事件标志组
*
* 返回: == 0 如果没有任务在等待事件标志组,或者发生错误。
* > 0 如果一个或多个等待事件标志组的任务现在已被准备好并通知。
*
* 注意: 1) 使用此函数时必须小心。通常期望事件标志组存在的任务必须检查 OSFlagPost 和 OSFlagPend() 的返回代码。
************************************************************************************************************************
*/
#if (OS_CFG_FLAG_DEL_EN > 0u)
OS_OBJ_QTY OSFlagDel(OS_FLAG_GRP *p_grp, OS_OPT opt, OS_ERR *p_err)
{
OS_OBJ_QTY nbr_tasks;
OS_PEND_LIST *p_pend_list;
OS_TCB *p_tcb;
CPU_TS ts;
CPU_SR_ALLOC();
#ifdef OS_SAFETY_CRITICAL
if (p_err == (OS_ERR *)0) {
OS_SAFETY_CRITICAL_EXCEPTION();
return (0u);
}
#endif
OS_TRACE_FLAG_DEL_ENTER(p_grp, opt);
#ifdef OS_SAFETY_CRITICAL_IEC61508
if (OSSafetyCriticalStartFlag == OS_TRUE) {
OS_TRACE_FLAG_DEL_EXIT(OS_ERR_ILLEGAL_DEL_RUN_TIME);
*p_err = OS_ERR_ILLEGAL_DEL_RUN_TIME;
return (0u);
}
#endif
#if (OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u)
if (OSIntNestingCtr > 0u) { /* 检查是否从 ISR 调用 ... */
*p_err = OS_ERR_DEL_ISR; /* ... 不能从 ISR 中删除 */
OS_TRACE_FLAG_DEL_EXIT(OS_ERR_DEL_ISR);
return (0u);
}
#endif
#if (OS_CFG_INVALID_OS_CALLS_CHK_EN > 0u)
if (OSRunning != OS_STATE_OS_RUNNING) { /* 内核是否在运行? */
OS_TRACE_FLAG_DEL_EXIT(OS_ERR_OS_NOT_RUNNING);
*p_err = OS_ERR_OS_NOT_RUNNING;
return (0u);
}
#endif
#if (OS_CFG_ARG_CHK_EN > 0u)
if (p_grp == (OS_FLAG_GRP *)0) { /* 验证 'p_grp' */
OS_TRACE_FLAG_DEL_EXIT(OS_ERR_OBJ_PTR_NULL);
*p_err = OS_ERR_OBJ_PTR_NULL;
return (0u);
}
#endif
#if (OS_CFG_OBJ_TYPE_CHK_EN > 0u)
if (p_grp->Type != OS_OBJ_TYPE_FLAG) { /* 验证事件标志组对象 */
OS_TRACE_FLAG_DEL_EXIT(OS_ERR_OBJ_TYPE);
*p_err = OS_ERR_OBJ_TYPE;
return (0u);
}
#endif
CPU_CRITICAL_ENTER();
p_pend_list = &p_grp->PendList;
nbr_tasks = 0u;
switch (opt) {
case OS_OPT_DEL_NO_PEND: /* 仅在没有任务等待时删除事件标志组 */
if (p_pend_list->HeadPtr == (OS_TCB *)0) {
#if (OS_CFG_DBG_EN > 0u)
OS_FlagDbgListRemove(p_grp);
OSFlagQty--;
#endif
OS_TRACE_FLAG_DEL(p_grp);
OS_FlagClr(p_grp);
CPU_CRITICAL_EXIT();
*p_err = OS_ERR_NONE;
} else {
CPU_CRITICAL_EXIT();
*p_err = OS_ERR_TASK_WAITING;
}
break;
case OS_OPT_DEL_ALWAYS: /* 始终删除事件标志组 */
#if (OS_CFG_TS_EN > 0u)
ts = OS_TS_GET(); /* 获取本地时间戳,以便所有任务获得相同的时间 */
#else
ts = 0u;
#endif
while (p_pend_list->HeadPtr != (OS_TCB *)0) { /* 从等待列表中移除所有任务 */
p_tcb = p_pend_list->HeadPtr;
OS_PendAbort(p_tcb, ts, OS_STATUS_PEND_DEL);
nbr_tasks++;
}
#if (OS_CFG_DBG_EN > 0u)
OS_FlagDbgListRemove(p_grp);
OSFlagQty--;
#endif
OS_TRACE_FLAG_DEL(p_grp);
OS_FlagClr(p_grp);
CPU_CRITICAL_EXIT();
OSSched(); /* 查找最高优先级的就绪任务 */
*p_err = OS_ERR_NONE;
break;
default:
CPU_CRITICAL_EXIT();
*p_err = OS_ERR_OPT_INVALID;
break;
}
OS_TRACE_FLAG_DEL_EXIT(*p_err);
return (nbr_tasks);
}
#endif
/*
************************************************************************************************************************
* 等待事件标志组
*
* 描述: 此函数用于等待事件标志组中的某个位组合被设置。您的应用程序可以等待任意一位被设置或所有位都被设置。
*
* 参数: p_grp 是指向所需事件标志组的指针。
*
* flags 是一个位模式,表示您希望等待哪些位(即标志)。您希望的位通过在 'flags' 中设置相应的位来指定。
* 例如,如果您的应用程序希望等待位 0 和 1,则 'flags' 将包含 0x03。
*
* timeout 是一个可选的超时时间(以时钟滴答为单位),您的任务将等待所需的位组合。如果您指定 0,
* 则您的任务将在指定的事件标志组中无限期等待,直到消息到达。
*
* opt 指定您希望所有位都被设置还是任意一位被设置。您可以指定以下参数之一:
*
* OS_OPT_PEND_FLAG_CLR_ALL 您将等待 'flags' 中的所有位都清零 (0)
* OS_OPT_PEND_FLAG_CLR_ANY 您将等待 'flags' 中的任意一位清零 (0)
* OS_OPT_PEND_FLAG_SET_ALL 您将等待 'flags' 中的所有位都置位 (1)
* OS_OPT_PEND_FLAG_SET_ANY 您将等待 'flags' 中的任意一位置位 (1)
*
* 如果您希望事件标志被“消费”,可以添加 OS_OPT_PEND_FLAG_CONSUME。例如,如果您希望等待组中的任意标志
* 并清除存在的标志,可以将 'wait_opt' 设置为:
*
* OS_OPT_PEND_FLAG_SET_ANY + OS_OPT_PEND_FLAG_CONSUME
*
* 您还可以通过添加以下两个选项之一来指定等待类型:
*
* OS_OPT_PEND_NON_BLOCKING 如果标志不可用,任务不会阻塞
* OS_OPT_PEND_BLOCKING 如果标志不可用,任务会阻塞
*
* p_ts 是一个指向变量的指针,该变量将接收事件标志组被发布、中止或删除的时间戳。如果您传递一个空指针(即 (CPU_TS *)0),
* 则不会获取时间戳。换句话说,传递空指针是有效的,表示您不需要时间戳。
*
* p_err 是一个指向错误代码的指针,可以是以下值之一:
*
* OS_ERR_NONE 所需的位在指定的 'timeout' 内已设置
* OS_ERR_OBJ_DEL 事件组已被删除
* OS_ERR_OBJ_PTR_NULL 如果 'p_grp' 是空指针
* OS_ERR_OBJ_TYPE 您指向的不是一个事件标志组
* OS_ERR_OPT_INVALID 您没有指定正确的 'opt' 参数
* OS_ERR_OS_NOT_RUNNING 如果 uC/OS-III 尚未运行
* OS_ERR_PEND_ABORT 对标志的等待被中止
* OS_ERR_PEND_ISR 如果您尝试从 ISR 中等待
* OS_ERR_PEND_WOULD_BLOCK 如果您指定了非阻塞但标志不可用
* OS_ERR_SCHED_LOCKED 如果您在调度器锁定时调用此函数
* OS_ERR_STATUS_INVALID 如果等待状态有无效值
* OS_ERR_TIMEOUT 所需的位在指定的 'timeout' 内未设置
* OS_ERR_TICK_DISABLED 如果内核时钟被禁用且指定了超时
*
* 返回: 使任务准备好的事件标志组中的标志,如果超时或发生错误则返回 0。
*
* 注意: 此 API “不得” 从定时器回调函数中调用。
************************************************************************************************************************
*/
OS_FLAGS OSFlagPend (OS_FLAG_GRP *p_grp,
OS_FLAGS flags,
OS_TICK timeout,
OS_OPT opt,
CPU_TS *p_ts,
OS_ERR *p_err)
{
CPU_BOOLEAN consume; // 是否需要消费事件标志
OS_FLAGS flags_rdy; // 已就绪的事件标志
OS_OPT mode; // 挂起操作的模式
CPU_SR_ALLOC(); // 分配中断状态寄存器
#ifdef OS_SAFETY_CRITICAL
if (p_err == (OS_ERR *)0)
{ // 检查错误指针是否为 NULL
OS_SAFETY_CRITICAL_EXCEPTION(); // 安全关键异常处理
return (0u); // 返回 0 表示失败
}
#endif
OS_TRACE_FLAG_PEND_ENTER(p_grp, flags, timeout, opt, p_ts); // 记录事件标志挂起进入
#if (OS_CFG_TICK_EN == 0u)
if (timeout != 0u)
{ // 检查是否禁用了系统节拍
*p_err = OS_ERR_TICK_DISABLED; // 设置错误代码为系统节拍禁用
OS_TRACE_FLAG_PEND_FAILED(p_grp); // 记录事件标志挂起失败
OS_TRACE_FLAG_PEND_EXIT(OS_ERR_TICK_DISABLED); // 记录事件标志挂起退出
return ((OS_FLAGS)0); // 返回 0 表示失败
}
#endif
#if (OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u)
if (OSIntNestingCtr > 0u)
{ // 检查是否从 ISR 中调用
if ((opt & OS_OPT_PEND_NON_BLOCKING) != OS_OPT_PEND_NON_BLOCKING)
{
*p_err = OS_ERR_PEND_ISR; // 设置错误代码为不能从 ISR 中挂起
OS_TRACE_FLAG_PEND_FAILED(p_grp); // 记录事件标志挂起失败
OS_TRACE_FLAG_PEND_EXIT(OS_ERR_PEND_ISR); // 记录事件标志挂起退出
return ((OS_FLAGS)0); // 返回 0 表示失败
}
}
#endif
#if (OS_CFG_INVALID_OS_CALLS_CHK_EN > 0u)
if (OSRunning != OS_STATE_OS_RUNNING)
{ // 检查内核是否正在运行
OS_TRACE_FLAG_PEND_EXIT(OS_ERR_OS_NOT_RUNNING); // 记录事件标志挂起退出
*p_err = OS_ERR_OS_NOT_RUNNING; // 设置错误代码为内核未运行
return (0u); // 返回 0 表示失败
}
#endif
#if (OS_CFG_ARG_CHK_EN > 0u)
if (p_grp == (OS_FLAG_GRP *)0)
{ // 检查事件标志组指针是否为 NULL
OS_TRACE_FLAG_PEND_FAILED(p_grp); // 记录事件标志挂起失败
OS_TRACE_FLAG_PEND_EXIT(OS_ERR_OBJ_PTR_NULL); // 记录事件标志挂起退出
*p_err = OS_ERR_OBJ_PTR_NULL; // 设置错误代码为对象指针为空
return (0u); // 返回 0 表示失败
}
#endif
switch (opt)
{ // 验证 'opt'
case OS_OPT_PEND_FLAG_CLR_ALL:
case OS_OPT_PEND_FLAG_CLR_ANY:
case OS_OPT_PEND_FLAG_SET_ALL:
case OS_OPT_PEND_FLAG_SET_ANY:
case OS_OPT_PEND_FLAG_CLR_ALL | OS_OPT_PEND_FLAG_CONSUME:
case OS_OPT_PEND_FLAG_CLR_ANY | OS_OPT_PEND_FLAG_CONSUME:
case OS_OPT_PEND_FLAG_SET_ALL | OS_OPT_PEND_FLAG_CONSUME:
case OS_OPT_PEND_FLAG_SET_ANY | OS_OPT_PEND_FLAG_CONSUME:
case OS_OPT_PEND_FLAG_CLR_ALL | OS_OPT_PEND_NON_BLOCKING:
case OS_OPT_PEND_FLAG_CLR_ANY | OS_OPT_PEND_NON_BLOCKING:
case OS_OPT_PEND_FLAG_SET_ALL | OS_OPT_PEND_NON_BLOCKING:
case OS_OPT_PEND_FLAG_SET_ANY | OS_OPT_PEND_NON_BLOCKING:
case OS_OPT_PEND_FLAG_CLR_ALL | (OS_OPT)(OS_OPT_PEND_FLAG_CONSUME | OS_OPT_PEND_NON_BLOCKING):
case OS_OPT_PEND_FLAG_CLR_ANY | (OS_OPT)(OS_OPT_PEND_FLAG_CONSUME | OS_OPT_PEND_NON_BLOCKING):
case OS_OPT_PEND_FLAG_SET_ALL | (OS_OPT)(OS_OPT_PEND_FLAG_CONSUME | OS_OPT_PEND_NON_BLOCKING):
case OS_OPT_PEND_FLAG_SET_ANY | (OS_OPT)(OS_OPT_PEND_FLAG_CONSUME | OS_OPT_PEND_NON_BLOCKING):
break;
default:
OS_TRACE_FLAG_PEND_FAILED(p_grp); // 记录事件标志挂起失败
OS_TRACE_FLAG_PEND_EXIT(OS_ERR_OPT_INVALID); // 记录事件标志挂起退出
*p_err = OS_ERR_OPT_INVALID; // 设置错误代码为无效选项
return (0u); // 返回 0 表示失败
}
#if (OS_CFG_OBJ_TYPE_CHK_EN > 0u)
if (p_grp->Type != OS_OBJ_TYPE_FLAG)
{ // 验证指向的是事件标志
OS_TRACE_FLAG_PEND_FAILED(p_grp); // 记录事件标志挂起失败
OS_TRACE_FLAG_PEND_EXIT(OS_ERR_OBJ_TYPE); // 记录事件标志挂起退出
*p_err = OS_ERR_OBJ_TYPE; // 设置错误代码为对象类型错误
return (0u); // 返回 0 表示失败
}
#endif
if ((opt & OS_OPT_PEND_FLAG_CONSUME) != 0u)
{ // 检查是否需要消费事件标志
consume = OS_TRUE;
}
else
{
consume = OS_FALSE;
}
if (p_ts != (CPU_TS *)0)
{
*p_ts = 0u; // 初始化返回的时间戳
}
mode = opt & OS_OPT_PEND_FLAG_MASK;
CPU_CRITICAL_ENTER(); // 进入临界区
switch (mode)
{
case OS_OPT_PEND_FLAG_SET_ALL: // 检查所有所需的标志是否已设置
flags_rdy = (p_grp->Flags & flags); // 提取所需的位
if (flags_rdy == flags)
{ // 必须匹配所有所需的位
if (consume == OS_TRUE)
{ // 检查是否需要消费事件标志
p_grp->Flags &= ~flags_rdy; // 清除所需的位
}
OSTCBCurPtr->FlagsRdy = flags_rdy; // 保存已就绪的标志
#if (OS_CFG_TS_EN > 0u)
if (p_ts != (CPU_TS *)0)
{
*p_ts = p_grp->TS; // 设置时间戳
}
#endif
CPU_CRITICAL_EXIT(); // 条件满足,返回给调用者
OS_TRACE_FLAG_PEND(p_grp); // 记录事件标志挂起成功
OS_TRACE_FLAG_PEND_EXIT(OS_ERR_NONE); // 记录事件标志挂起退出
*p_err = OS_ERR_NONE; // 设置错误代码为无错误
return (flags_rdy); // 返回已就绪的标志
}
else
{ // 阻塞任务直到事件发生或超时
if ((opt & OS_OPT_PEND_NON_BLOCKING) != 0u)
{
CPU_CRITICAL_EXIT();
OS_TRACE_FLAG_PEND_FAILED(p_grp); // 记录事件标志挂起失败
OS_TRACE_FLAG_PEND_EXIT(OS_ERR_PEND_WOULD_BLOCK); // 记录事件标志挂起退出
*p_err = OS_ERR_PEND_WOULD_BLOCK; // 设置错误代码为任务会阻塞
return ((OS_FLAGS)0); // 返回 0 表示失败
}
else
{ // 指定了阻塞,检查调度器是否锁定
if (OSSchedLockNestingCtr > 0u)
{ // 检查调度器是否锁定
CPU_CRITICAL_EXIT();
OS_TRACE_FLAG_PEND_FAILED(p_grp); // 记录事件标志挂起失败
OS_TRACE_FLAG_PEND_EXIT(OS_ERR_SCHED_LOCKED); // 记录事件标志挂起退出
*p_err = OS_ERR_SCHED_LOCKED; // 设置错误代码为调度器锁定
return (0u); // 返回 0 表示失败
}
}
OS_FlagBlock(p_grp, flags, opt, timeout); // 阻塞任务
CPU_CRITICAL_EXIT();
}
break;
case OS_OPT_PEND_FLAG_SET_ANY: // 检查任何所需的标志是否已设置
flags_rdy = (p_grp->Flags & flags); // 提取所需的位
if (flags_rdy != 0u)
{ // 检查是否有任何标志已设置
if (consume == OS_TRUE)
{ // 检查是否需要消费事件标志
p_grp->Flags &= ~flags_rdy; // 清除已获取的位
}
OSTCBCurPtr->FlagsRdy = flags_rdy; // 保存已就绪的标志
#if (OS_CFG_TS_EN > 0u)
if (p_ts != (CPU_TS *)0)
{
*p_ts = p_grp->TS; // 设置时间戳
}
#endif
CPU_CRITICAL_EXIT(); // 条件满足,返回给调用者
OS_TRACE_FLAG_PEND(p_grp); // 记录事件标志挂起成功
OS_TRACE_FLAG_PEND_EXIT(OS_ERR_NONE); // 记录事件标志挂起退出
*p_err = OS_ERR_NONE; // 设置错误代码为无错误
return (flags_rdy); // 返回已就绪的标志
}
else
{ // 阻塞任务直到事件发生或超时
if ((opt & OS_OPT_PEND_NON_BLOCKING) != 0u)
{
CPU_CRITICAL_EXIT();
OS_TRACE_FLAG_PEND_EXIT(OS_ERR_PEND_WOULD_BLOCK); // 记录事件标志挂起退出
*p_err = OS_ERR_PEND_WOULD_BLOCK; // 设置错误代码为任务会阻塞
return ((OS_FLAGS)0); // 返回 0 表示失败
}
else
{ // 指定了阻塞,检查调度器是否锁定
if (OSSchedLockNestingCtr > 0u)
{ // 检查调度器是否锁定
CPU_CRITICAL_EXIT();
OS_TRACE_FLAG_PEND_EXIT(OS_ERR_SCHED_LOCKED); // 记录事件标志挂起退出
*p_err = OS_ERR_SCHED_LOCKED; // 设置错误代码为调度器锁定
return ((OS_FLAGS)0); // 返回 0 表示失败
}
}
OS_FlagBlock(p_grp, flags, opt, timeout); // 阻塞任务
CPU_CRITICAL_EXIT();
}
break;
#if (OS_CFG_FLAG_MODE_CLR_EN > 0u)
case OS_OPT_PEND_FLAG_CLR_ALL: // 检查所有所需的标志是否已清除
flags_rdy = (OS_FLAGS)(~p_grp->Flags & flags); // 提取所需的位
if (flags_rdy == flags)
{ // 必须匹配所有所需的位
if (consume == OS_TRUE)
{ // 检查是否需要消费事件标志
p_grp->Flags |= flags_rdy; // 设置所需的位
}
OSTCBCurPtr->FlagsRdy = flags_rdy; // 保存已就绪的标志
#if (OS_CFG_TS_EN > 0u)
if (p_ts != (CPU_TS *)0)
{
*p_ts = p_grp->TS; // 设置时间戳
}
#endif
CPU_CRITICAL_EXIT(); // 条件满足,返回给调用者
OS_TRACE_FLAG_PEND(p_grp); // 记录事件标志挂起成功
OS_TRACE_FLAG_PEND_EXIT(OS_ERR_NONE); // 记录事件标志挂起退出
*p_err = OS_ERR_NONE; // 设置错误代码为无错误
return (flags_rdy); // 返回已就绪的标志
}
else
{ // 阻塞任务直到事件发生或超时
if ((opt & OS_OPT_PEND_NON_BLOCKING) != 0u)
{
CPU_CRITICAL_EXIT();
OS_TRACE_FLAG_PEND_EXIT(OS_ERR_PEND_WOULD_BLOCK); // 记录事件标志挂起退出
*p_err = OS_ERR_PEND_WOULD_BLOCK; // 设置错误代码为任务会阻塞
return ((OS_FLAGS)0); // 返回 0 表示失败
}
else
{ // 指定了阻塞,检查调度器是否锁定
if (OSSchedLockNestingCtr > 0u)
{ // 检查调度器是否锁定
CPU_CRITICAL_EXIT();
OS_TRACE_FLAG_PEND_EXIT(OS_ERR_SCHED_LOCKED); // 记录事件标志挂起退出
*p_err = OS_ERR_SCHED_LOCKED; // 设置错误代码为调度器锁定
return (0u); // 返回 0 表示失败
}
}
OS_FlagBlock(p_grp, flags, opt, timeout); // 阻塞任务
CPU_CRITICAL_EXIT();
}
break;
case OS_OPT_PEND_FLAG_CLR_ANY: // 检查任何所需的标志是否已清除
flags_rdy = (~p_grp->Flags & flags); // 提取所需的位
if (flags_rdy != 0u)
{ // 检查是否有任何标志已清除
if (consume == OS_TRUE)
{ // 检查是否需要消费事件标志
p_grp->Flags |= flags_rdy; // 设置已获取的位
}
OSTCBCurPtr->FlagsRdy = flags_rdy; // 保存已就绪的标志
#if (OS_CFG_TS_EN > 0u)
if (p_ts != (CPU_TS *)0)
{
*p_ts = p_grp->TS; // 设置时间戳
}
#endif
CPU_CRITICAL_EXIT(); // 条件满足,返回给调用者
OS_TRACE_FLAG_PEND(p_grp); // 记录事件标志挂起成功
OS_TRACE_FLAG_PEND_EXIT(OS_ERR_NONE); // 记录事件标志挂起退出
*p_err = OS_ERR_NONE; // 设置错误代码为无错误
return (flags_rdy); // 返回已就绪的标志
}
else
{ // 阻塞任务直到事件发生或超时
if ((opt & OS_OPT_PEND_NON_BLOCKING) != 0u)
{
CPU_CRITICAL_EXIT();
OS_TRACE_FLAG_PEND_EXIT(OS_ERR_PEND_WOULD_BLOCK); // 记录事件标志挂起退出
*p_err = OS_ERR_PEND_WOULD_BLOCK; // 设置错误代码为任务会阻塞
return ((OS_FLAGS)0); // 返回 0 表示失败
}
else
{ // 指定了阻塞,检查调度器是否锁定
if (OSSchedLockNestingCtr > 0u)
{ // 检查调度器是否锁定
CPU_CRITICAL_EXIT();
OS_TRACE_FLAG_PEND_EXIT(OS_ERR_SCHED_LOCKED); // 记录事件标志挂起退出
*p_err = OS_ERR_SCHED_LOCKED; // 设置错误代码为调度器锁定
return (0u); // 返回 0 表示失败
}
}
OS_FlagBlock(p_grp, flags, opt, timeout); // 阻塞任务
CPU_CRITICAL_EXIT();
}
break;
#endif
default:
CPU_CRITICAL_EXIT(); // 退出临界区
OS_TRACE_FLAG_PEND_FAILED(p_grp); // 记录事件标志挂起失败
OS_TRACE_FLAG_PEND_EXIT(OS_ERR_OPT_INVALID); // 记录事件标志挂起退出
*p_err = OS_ERR_OPT_INVALID; // 设置错误代码为无效选项
return (0u); // 返回 0 表示失败
}
OS_TRACE_FLAG_PEND_BLOCK(p_grp); // 记录事件标志挂起
OSSched(); // 查找下一个最高优先级的就绪任务
CPU_CRITICAL_ENTER(); // 进入临界区
switch (OSTCBCurPtr->PendStatus)
{
case OS_STATUS_PEND_OK: // 获取了事件标志
#if (OS_CFG_TS_EN > 0u)
if (p_ts != (CPU_TS *)0)
{
*p_ts = OSTCBCurPtr->TS; // 设置时间戳
}
#endif
OS_TRACE_FLAG_PEND(p_grp); // 记录事件标志挂起成功
*p_err = OS_ERR_NONE; // 设置错误代码为无错误
break;
case OS_STATUS_PEND_ABORT: // 挂起被中止
#if (OS_CFG_TS_EN > 0u)
if (p_ts != (CPU_TS *)0)
{
*p_ts = OSTCBCurPtr->TS; // 设置时间戳
}
#endif
CPU_CRITICAL_EXIT(); // 退出临界区
OS_TRACE_FLAG_PEND_FAILED(p_grp); // 记录事件标志挂起失败
*p_err = OS_ERR_PEND_ABORT; // 设置错误代码为挂起中止
break;
case OS_STATUS_PEND_TIMEOUT: // 在超时时间内未获取到事件标志
if (p_ts != (CPU_TS *)0)
{
*p_ts = 0u; // 设置时间戳为 0
}
CPU_CRITICAL_EXIT(); // 退出临界区
OS_TRACE_FLAG_PEND_FAILED(p_grp); // 记录事件标志挂起失败
*p_err = OS_ERR_TIMEOUT; // 设置错误代码为超时
break;
case OS_STATUS_PEND_DEL: // 挂起的对象已被删除
#if (OS_CFG_TS_EN > 0u)
if (p_ts != (CPU_TS *)0)
{
*p_ts = OSTCBCurPtr->TS; // 设置时间戳
}
#endif
CPU_CRITICAL_EXIT(); // 退出临界区
OS_TRACE_FLAG_PEND_FAILED(p_grp); // 记录事件标志挂起失败
*p_err = OS_ERR_OBJ_DEL; // 设置错误代码为对象已删除
break;
default:
CPU_CRITICAL_EXIT(); // 退出临界区
OS_TRACE_FLAG_PEND_FAILED(p_grp); // 记录事件标志挂起失败
*p_err = OS_ERR_STATUS_INVALID; // 设置错误代码为无效状态
break;
}
if (*p_err != OS_ERR_NONE)
{
OS_TRACE_FLAG_PEND_EXIT(*p_err); // 记录事件标志挂起退出
return (0u); // 返回 0 表示失败
}
flags_rdy = OSTCBCurPtr->FlagsRdy; // 获取已就绪的事件标志
if (consume == OS_TRUE)
{ // 检查是否需要消费事件标志
switch (mode)
{
case OS_OPT_PEND_FLAG_SET_ALL:
case OS_OPT_PEND_FLAG_SET_ANY: // 清除我们获取的事件标志
p_grp->Flags &= ~flags_rdy;
break;
#if (OS_CFG_FLAG_MODE_CLR_EN > 0u)
case OS_OPT_PEND_FLAG_CLR_ALL:
case OS_OPT_PEND_FLAG_CLR_ANY: // 设置我们获取的事件标志
p_grp->Flags |= flags_rdy;
break;
#endif
default:
CPU_CRITICAL_EXIT(); // 退出临界区
OS_TRACE_FLAG_PEND_EXIT(OS_ERR_OPT_INVALID); // 记录事件标志挂起退出
*p_err = OS_ERR_OPT_INVALID; // 设置错误代码为无效选项
return (0u); // 返回 0 表示失败
}
}
CPU_CRITICAL_EXIT(); // 退出临界区
OS_TRACE_FLAG_PEND_EXIT(OS_ERR_NONE); // 记录事件标志挂起退出
*p_err = OS_ERR_NONE; // 设置错误代码为无错误
return (flags_rdy); // 返回已就绪的事件标志
}
/*
************************************************************************************************************************
* 中止等待事件标志组
*
* 描述: 此函数中止并准备好当前正在等待事件标志组的任何任务。此函数应用于故障中止对事件标志组的等待,
* 而不是正常地向事件标志组发布事件(使用 OSFlagPost())。
*
* 参数: p_grp 指向事件标志组的指针
*
* opt 确定执行的中止类型:
*
* OS_OPT_PEND_ABORT_1 中止单个任务(最高优先级任务)对事件标志的等待
* OS_OPT_PEND_ABORT_ALL 中止所有正在等待事件标志的任务
* OS_OPT_POST_NO_SCHED 不调用调度器
*
* p_err 指向一个变量的指针,该变量将包含此函数返回的错误代码。
*
* OS_ERR_NONE 至少有一个任务在等待事件标志组,并且已经被准备好并被告知等待已中止;
* 请检查返回值以获取等待事件标志组的任务数量
* OS_ERR_OBJ_PTR_NULL 如果 'p_grp' 是空指针
* OS_ERR_OBJ_TYPE 如果 'p_grp' 指向的不是一个事件标志组
* OS_ERR_OPT_INVALID 如果指定了无效的选项
* OS_ERR_OS_NOT_RUNNING 如果 uC/OS-III 尚未运行
* OS_ERR_PEND_ABORT_ISR 如果从 ISR 中调用了此函数
* OS_ERR_PEND_ABORT_NONE 没有任务在等待
*
* 返回值: == 0 如果没有任务在等待事件标志组,或者发生错误。
* > 0 如果一个或多个等待事件标志组的任务现在已被准备好并被告知。
*
* 注意: 无
************************************************************************************************************************
*/
#if (OS_CFG_FLAG_PEND_ABORT_EN > 0u)
OS_OBJ_QTY OSFlagPendAbort (OS_FLAG_GRP *p_grp,
OS_OPT opt,
OS_ERR *p_err)
{
OS_PEND_LIST *p_pend_list;
OS_TCB *p_tcb;
CPU_TS ts;
OS_OBJ_QTY nbr_tasks;
CPU_SR_ALLOC();
// 安全关键检查
#ifdef OS_SAFETY_CRITICAL
if (p_err == (OS_ERR *)0) {
OS_SAFETY_CRITICAL_EXCEPTION();
return ((OS_OBJ_QTY)0u);
}
#endif
// 检查是否从 ISR 中调用
#if (OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u)
if (OSIntNestingCtr > 0u) { // 不允许从 ISR 中中止等待
*p_err = OS_ERR_PEND_ABORT_ISR;
return (0u);
}
#endif
// 检查内核是否正在运行
#if (OS_CFG_INVALID_OS_CALLS_CHK_EN > 0u)
if (OSRunning != OS_STATE_OS_RUNNING) { // 内核是否正在运行?
*p_err = OS_ERR_OS_NOT_RUNNING;
return (0u);
}
#endif
// 参数检查
#if (OS_CFG_ARG_CHK_EN > 0u)
if (p_grp == (OS_FLAG_GRP *)0) { // 验证 'p_grp'
*p_err = OS_ERR_OBJ_PTR_NULL;
return (0u);
}
switch (opt) { // 验证 'opt'
case OS_OPT_PEND_ABORT_1:
case OS_OPT_PEND_ABORT_ALL:
case OS_OPT_PEND_ABORT_1 | OS_OPT_POST_NO_SCHED:
case OS_OPT_PEND_ABORT_ALL | OS_OPT_POST_NO_SCHED:
break;
default:
*p_err = OS_ERR_OPT_INVALID;
return (0u);
}
#endif
// 对象类型检查
#if (OS_CFG_OBJ_TYPE_CHK_EN > 0u)
if (p_grp->Type != OS_OBJ_TYPE_FLAG) { // 确保事件标志组已创建
*p_err = OS_ERR_OBJ_TYPE;
return (0u);
}
#endif
CPU_CRITICAL_ENTER();
p_pend_list = &p_grp->PendList;
if (p_pend_list->HeadPtr == (OS_TCB *)0) { // 有任何任务在等待事件标志组吗?
CPU_CRITICAL_EXIT(); // 没有
*p_err = OS_ERR_PEND_ABORT_NONE;
return (0u);
}
nbr_tasks = 0u;
#if (OS_CFG_TS_EN > 0u)
ts = OS_TS_GET(); // 获取本地时间戳,以便所有任务获得相同的时间
#else
ts = 0u;
#endif
while (p_pend_list->HeadPtr != (OS_TCB *)0) {
p_tcb = p_pend_list->HeadPtr;
OS_PendAbort(p_tcb,
ts,
OS_STATUS_PEND_ABORT);
nbr_tasks++;
if (opt != OS_OPT_PEND_ABORT_ALL) { // 是否中止所有等待的任务?
break; // 否
}
}
CPU_CRITICAL_EXIT();
if ((opt & OS_OPT_POST_NO_SCHED) == 0u) {
OSSched(); // 运行调度器
}
*p_err = OS_ERR_NONE;
return (nbr_tasks);
}
#endif
/*
************************************************************************************************************************
* 获取导致任务就绪的标志
*
* 描述: 此函数用于获取导致任务变为可运行状态的标志。换句话说,此函数允许你确定“是谁导致的!”。
*
* 参数: p_err 指向错误代码的指针
*
* OS_ERR_NONE 如果调用成功
* OS_ERR_OS_NOT_RUNNING 如果 uC/OS-III 尚未运行
* OS_ERR_PEND_ISR 如果从 ISR 中调用
*
* 返回值: 导致任务就绪的标志。
*
* 注意: 无
************************************************************************************************************************
*/
OS_FLAGS OSFlagPendGetFlagsRdy (OS_ERR *p_err)
{
OS_FLAGS flags;
CPU_SR_ALLOC();
// 安全关键检查
#ifdef OS_SAFETY_CRITICAL
if (p_err == (OS_ERR *)0) {
OS_SAFETY_CRITICAL_EXCEPTION();
return ((OS_FLAGS)0);
}
#endif
// 检查内核是否正在运行
#if (OS_CFG_INVALID_OS_CALLS_CHK_EN > 0u)
if (OSRunning != OS_STATE_OS_RUNNING) { // 内核是否正在运行?
*p_err = OS_ERR_OS_NOT_RUNNING;
return (0u);
}
#endif
// 检查是否从 ISR 中调用
#if (OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u)
if (OSIntNestingCtr > 0u) { // 是否从 ISR 中调用 ...
*p_err = OS_ERR_PEND_ISR; // ... 不能从 ISR 中获取
return (0u);
}
#endif
CPU_CRITICAL_ENTER();
flags = OSTCBCurPtr->FlagsRdy; // 获取当前任务的就绪标志
CPU_CRITICAL_EXIT();
*p_err = OS_ERR_NONE;
return (flags);
}
/*
************************************************************************************************************************
* 发布事件标志位
*
* 描述: 此函数用于设置或清除事件标志组中的某些位。要设置或清除的位由一个“位掩码”指定。
*
* 参数: p_grp 指向所需的事件标志组的指针。
*
* flags 如果 'opt'(见下文)为 OS_OPT_POST_FLAG_SET,则 'flags' 中每个设置的位将设置事件标志组中相应的位。
* 例如,要设置第 0、4 和 5 位,你可以将 'flags' 设置为:
*
* 0x31 (注意,第 0 位是最不显著的位)
*
* 如果 'opt'(见下文)为 OS_OPT_POST_FLAG_CLR,则 'flags' 中每个设置的位将清除事件标志组中相应的位。
* 例如,要清除第 0、4 和 5 位,你可以将 'flags' 设置为:
*
* 0x31 (注意,第 0 位是最不显著的位)
*
* opt 指示标志将被:
*
* OS_OPT_POST_FLAG_SET 设置
* OS_OPT_POST_FLAG_CLR 清除
*
* 你还可以添加 OS_OPT_POST_NO_SCHED 以防止调度器被调用。
*
* p_err 指向错误代码的指针,可以是:
*
* OS_ERR_NONE 调用成功
* OS_ERR_OBJ_PTR_NULL 传递了空指针
* OS_ERR_OBJ_TYPE 指向的不是一个事件标志组
* OS_ERR_OPT_INVALID 指定了无效的选项
* OS_ERR_OS_NOT_RUNNING 如果 uC/OS-III 尚未运行
*
* 返回值: 仍然设置的事件标志位的新值。
*
* 注意: 1) 该函数的执行时间取决于等待事件标志组的任务数量。
************************************************************************************************************************
*/
OS_FLAGS OSFlagPost (OS_FLAG_GRP *p_grp,
OS_FLAGS flags,
OS_OPT opt,
OS_ERR *p_err)
{
OS_FLAGS flags_cur;
OS_FLAGS flags_rdy;
OS_OPT mode;
OS_PEND_LIST *p_pend_list;
OS_TCB *p_tcb;
OS_TCB *p_tcb_next;
CPU_TS ts;
CPU_SR_ALLOC();
#ifdef OS_SAFETY_CRITICAL
if (p_err == (OS_ERR *)0) {
OS_SAFETY_CRITICAL_EXCEPTION();
return (0u);
}
#endif
OS_TRACE_FLAG_POST_ENTER(p_grp, flags, opt);
#if (OS_CFG_INVALID_OS_CALLS_CHK_EN > 0u)
if (OSRunning != OS_STATE_OS_RUNNING) { // 内核是否正在运行?
OS_TRACE_FLAG_POST_EXIT(OS_ERR_OS_NOT_RUNNING);
*p_err = OS_ERR_OS_NOT_RUNNING;
return (0u);
}
#endif
#if (OS_CFG_ARG_CHK_EN > 0u)
if (p_grp == (OS_FLAG_GRP *)0) { // 验证 'p_grp'
OS_TRACE_FLAG_POST_FAILED(p_grp);
OS_TRACE_FLAG_POST_EXIT(OS_ERR_OBJ_PTR_NULL);
*p_err = OS_ERR_OBJ_PTR_NULL;
return (0u);
}
#endif
#if (OS_CFG_OBJ_TYPE_CHK_EN > 0u)
if (p_grp->Type != OS_OBJ_TYPE_FLAG) { // 确保指向的是事件标志组
OS_TRACE_FLAG_POST_FAILED(p_grp);
OS_TRACE_FLAG_POST_EXIT(OS_ERR_OBJ_TYPE);
*p_err = OS_ERR_OBJ_TYPE;
return (0u);
}
#endif
#if (OS_CFG_TS_EN > 0u)
ts = OS_TS_GET(); // 获取时间戳
#else
ts = 0u;
#endif
OS_TRACE_FLAG_POST(p_grp);
switch (opt) {
case OS_OPT_POST_FLAG_SET:
case OS_OPT_POST_FLAG_SET | OS_OPT_POST_NO_SCHED:
CPU_CRITICAL_ENTER();
p_grp->Flags |= flags; // 设置组中指定的标志
break;
case OS_OPT_POST_FLAG_CLR:
case OS_OPT_POST_FLAG_CLR | OS_OPT_POST_NO_SCHED:
CPU_CRITICAL_ENTER();
p_grp->Flags &= ~flags; // 清除组中指定的标志
break;
default:
*p_err = OS_ERR_OPT_INVALID; // 无效的选项
OS_TRACE_FLAG_POST_EXIT(*p_err);
return (0u);
}
#if (OS_CFG_TS_EN > 0u)
p_grp->TS = ts;
#endif
p_pend_list = &p_grp->PendList;
if (p_pend_list->HeadPtr == (OS_TCB *)0) { // 任何任务在等待事件标志组吗?
CPU_CRITICAL_EXIT(); // 没有
*p_err = OS_ERR_NONE;
OS_TRACE_FLAG_POST_EXIT(*p_err);
return (p_grp->Flags);
}
p_tcb = p_pend_list->HeadPtr;
while (p_tcb != (OS_TCB *)0) { // 遍历所有等待事件标志的任务
p_tcb_next = p_tcb->PendNextPtr;
mode = p_tcb->FlagsOpt & OS_OPT_PEND_FLAG_MASK;
switch (mode) {
case OS_OPT_PEND_FLAG_SET_ALL: // 检查当前节点的所有请求标志是否已设置
flags_rdy = (p_grp->Flags & p_tcb->FlagsPend);
if (flags_rdy == p_tcb->FlagsPend) {
OS_FlagTaskRdy(p_tcb, // 使任务准备好,事件已接收
flags_rdy,
ts);
}
break;
case OS_OPT_PEND_FLAG_SET_ANY: // 检查是否有任何标志已设置
flags_rdy = (p_grp->Flags & p_tcb->FlagsPend);
if (flags_rdy != 0u) {
OS_FlagTaskRdy(p_tcb, // 使任务准备好,事件已接收
flags_rdy,
ts);
}
break;
#if (OS_CFG_FLAG_MODE_CLR_EN > 0u)
case OS_OPT_PEND_FLAG_CLR_ALL: // 检查当前节点的所有请求标志是否已清除
flags_rdy = (OS_FLAGS)(~p_grp->Flags & p_tcb->FlagsPend);
if (flags_rdy == p_tcb->FlagsPend) {
OS_FlagTaskRdy(p_tcb, // 使任务准备好,事件已接收
flags_rdy,
ts);
}
break;
case OS_OPT_PEND_FLAG_CLR_ANY: // 检查是否有任何标志已清除
flags_rdy = (OS_FLAGS)(~p_grp->Flags & p_tcb->FlagsPend);
if (flags_rdy != 0u) {
OS_FlagTaskRdy(p_tcb, // 使任务准备好,事件已接收
flags_rdy,
ts);
}
break;
#endif
default:
CPU_CRITICAL_EXIT();
*p_err = OS_ERR_FLAG_PEND_OPT;
OS_TRACE_FLAG_POST_EXIT(*p_err);
return (0u);
}
p_tcb = p_tcb_next; // 指向下一个等待事件标志的任务
}
CPU_CRITICAL_EXIT();
if ((opt & OS_OPT_POST_NO_SCHED) == 0u) {
OSSched();
}
CPU_CRITICAL_ENTER();
flags_cur = p_grp->Flags;
CPU_CRITICAL_EXIT();
*p_err = OS_ERR_NONE;
OS_TRACE_FLAG_POST_EXIT(*p_err);
return (flags_cur);
}
/*
************************************************************************************************************************
* 挂起任务直到接收到事件标志或超时发生
*
* 描述: 此函数是 uC/OS-III 的内部函数,用于将任务挂起,直到所需的事件标志位被设置。
*
* 参数: p_grp 指向所需的事件标志组的指针。
* -----
*
* flags 是一个位模式,表示你希望检查哪些位(即标志)。你希望检查的位通过在 'flags' 中设置相应的位来指定。
* 例如,如果你的应用程序希望等待第 0 和 1 位,则 'flags' 应包含 0x03。
*
* opt 指定你是希望所有位都被设置/清除,还是任何位被设置/清除。
* 你可以指定以下参数:
*
* OS_OPT_PEND_FLAG_CLR_ALL 检查 'mask' 中的所有位是否都为清零 (0)
* OS_OPT_PEND_FLAG_CLR_ANY 检查 'mask' 中的任何一位是否为清零 (0)
* OS_OPT_PEND_FLAG_SET_ALL 检查 'mask' 中的所有位是否都为设置 (1)
* OS_OPT_PEND_FLAG_SET_ANY 检查 'mask' 中的任何一位是否为设置 (1)
*
* timeout 是任务等待事件标志位被设置的期望时间。
*
* 返回值: 无
*
* 注意: 此函数是 uC/OS-III 的内部函数,你的应用程序不应调用它。
************************************************************************************************************************
*/
void OS_FlagBlock (OS_FLAG_GRP *p_grp,
OS_FLAGS flags,
OS_OPT opt,
OS_TICK timeout)
{
OSTCBCurPtr->FlagsPend = flags; // 保存我们需要等待的标志
OSTCBCurPtr->FlagsOpt = opt; // 保存我们正在执行的等待类型
OSTCBCurPtr->FlagsRdy = 0u; // 初始化已就绪的标志为 0
OS_Pend((OS_PEND_OBJ *)((void *)p_grp), // 挂起当前任务
OSTCBCurPtr,
OS_TASK_PEND_ON_FLAG, // 指定任务挂起的原因是等待事件标志
timeout); // 指定超时时间
}
/*
************************************************************************************************************************
* 清除事件标志组的内容
*
* 描述: 此函数由 OSFlagDel() 调用,用于清除事件标志组的内容。
*
* 参数: p_grp 指向要清除的事件标志组的指针。
* -----
*
* 返回值: 无
*
* 注意: 此函数是 uC/OS-III 的内部函数,你的应用程序不应调用它。
************************************************************************************************************************
*/
void OS_FlagClr (OS_FLAG_GRP *p_grp)
{
OS_PEND_LIST *p_pend_list;
#if (OS_OBJ_TYPE_REQ > 0u)
p_grp->Type = OS_OBJ_TYPE_NONE;
#endif
#if (OS_CFG_DBG_EN > 0u)
p_grp->NamePtr = (CPU_CHAR *)((void *)"?FLAG"); /* Unknown name */
#endif
p_grp->Flags = 0u;
p_pend_list = &p_grp->PendList;
OS_PendListInit(p_pend_list);
}
/*
************************************************************************************************************************
* 添加/移除事件标志组到/从调试列表
*
* 描述: 这些函数由 uC/OS-III 调用,用于将事件标志组添加到或从事件标志调试列表中移除。
*
* 参数: p_grp 指向要添加或移除的事件标志组的指针。
*
* 返回值: 无
*
* 注意: 这些函数是 uC/OS-III 的内部函数,你的应用程序不应调用它们。
************************************************************************************************************************
*/
#if (OS_CFG_DBG_EN > 0u)
void OS_FlagDbgListAdd (OS_FLAG_GRP *p_grp)
{
p_grp->DbgNamePtr = (CPU_CHAR *)((void *)" ");
p_grp->DbgPrevPtr = (OS_FLAG_GRP *)0;
if (OSFlagDbgListPtr == (OS_FLAG_GRP *)0) {
p_grp->DbgNextPtr = (OS_FLAG_GRP *)0;
} else {
p_grp->DbgNextPtr = OSFlagDbgListPtr;
OSFlagDbgListPtr->DbgPrevPtr = p_grp;
}
OSFlagDbgListPtr = p_grp;
}
void OS_FlagDbgListRemove (OS_FLAG_GRP *p_grp)
{
OS_FLAG_GRP *p_grp_next;
OS_FLAG_GRP *p_grp_prev;
p_grp_prev = p_grp->DbgPrevPtr;
p_grp_next = p_grp->DbgNextPtr;
if (p_grp_prev == (OS_FLAG_GRP *)0) {
OSFlagDbgListPtr = p_grp_next;
if (p_grp_next != (OS_FLAG_GRP *)0) {
p_grp_next->DbgPrevPtr = (OS_FLAG_GRP *)0;
}
p_grp->DbgNextPtr = (OS_FLAG_GRP *)0;
} else if (p_grp_next == (OS_FLAG_GRP *)0) {
p_grp_prev->DbgNextPtr = (OS_FLAG_GRP *)0;
p_grp->DbgPrevPtr = (OS_FLAG_GRP *)0;
} else {
p_grp_prev->DbgNextPtr = p_grp_next;
p_grp_next->DbgPrevPtr = p_grp_prev;
p_grp->DbgNextPtr = (OS_FLAG_GRP *)0;
p_grp->DbgPrevPtr = (OS_FLAG_GRP *)0;
}
}
#endif
/*
************************************************************************************************************************
* 使任务准备好运行,事件发生
*
* 描述: 此函数是 uC/OS-III 的内部函数,用于在所需事件标志位被设置后使任务准备好运行。
*
* 参数: p_tcb 指向要移除的任务的 OS_TCB 的指针。
* -----
*
* flags_rdy 包含导致任务变为准备好运行的事件标志的位模式。
*
* ts 与事件发布相关的时间戳。
*
* 返回值: 无
*
* 注意: 此函数是 uC/OS-III 的内部函数,你的应用程序不应调用它。
************************************************************************************************************************
*/
void OS_FlagTaskRdy (OS_TCB *p_tcb,
OS_FLAGS flags_rdy,
CPU_TS ts)
{
#if (OS_CFG_TS_EN == 0u)
(void)ts; // 防止编译器警告未使用 'ts'
#endif
p_tcb->FlagsRdy = flags_rdy; // 设置任务的就绪标志
p_tcb->PendStatus = OS_STATUS_PEND_OK; // 清除挂起状态
p_tcb->PendOn = OS_TASK_PEND_ON_NOTHING; // 表示不再挂起
#if (OS_CFG_TS_EN > 0u)
p_tcb->TS = ts; // 设置时间戳
#endif
switch (p_tcb->TaskState) {
case OS_TASK_STATE_PEND:
case OS_TASK_STATE_PEND_TIMEOUT:
#if (OS_CFG_TICK_EN > 0u)
if (p_tcb->TaskState == OS_TASK_STATE_PEND_TIMEOUT) {
OS_TickListRemove(p_tcb); // 从计时器列表中移除任务
}
#endif
OS_RdyListInsert(p_tcb); // 将任务插入就绪列表
p_tcb->TaskState = OS_TASK_STATE_RDY; // 更新任务状态为就绪
break;
case OS_TASK_STATE_PEND_SUSPENDED:
case OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED:
#if (OS_CFG_TICK_EN > 0u)
if (p_tcb->TaskState == OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED) {
OS_TickListRemove(p_tcb); // 从计时器列表中移除任务
}
#endif
p_tcb->TaskState = OS_TASK_STATE_SUSPENDED; // 更新任务状态为挂起
break;
case OS_TASK_STATE_RDY:
case OS_TASK_STATE_DLY:
case OS_TASK_STATE_DLY_SUSPENDED:
case OS_TASK_STATE_SUSPENDED:
default:
// 默认情况
break;
}
OS_PendListRemove(p_tcb); // 从挂起列表中移除任务
}
#endif
标签:OPT,ERR,UcOs,III,FLAG,源码,grp,PEND,OS
From: https://www.cnblogs.com/lanlincmos/p/18521017