首页 > 编程语言 >UcOs-III 源码阅读: os_flag.c

UcOs-III 源码阅读: os_flag.c

时间:2024-11-01 18:20:08浏览次数:1  
标签:OPT ERR UcOs III FLAG 源码 grp PEND OS

/*
*********************************************************************************************************
*                                              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

相关文章

  • 基于SpringBoot的考试安排管理系统的设计和实现(源码+LW+调试文档)
     目录:完整视频演示:系统架构:程序运行截图:核心代码参考:   数据库sql:项目技术介绍:java介绍:Mysql数据库介绍:为什么选择我:获取源码:......
  • 基于SpringBoot的高考择校推荐系统的设计和实现(源码+LW+调试文档)
     目录:完整视频演示:系统架构:程序运行截图:核心代码参考:   数据库sql:项目技术介绍:java介绍:Mysql数据库介绍:为什么选择我:获取源码:......
  • NodeJS动漫论坛-计算机毕业设计源码09947
    基于微信小程序的动漫论坛摘 要随着移动互联网的飞速发展,智能手机和移动互联网已经成为人们日常生活中不可或缺的一部分。在这样的背景下,微信小程序应运而生,凭借其无需下载安装、即用即走的特点,迅速成为连接用户与服务的桥梁。动漫作为一种深受年轻人喜爱的文化形式,拥有庞......
  • 基于nodejs+vue基于的农贸市场网站的设计与实现[开题+源码+程序+论文]计算机毕业设计
    本系统(程序+源码+数据库+调试部署+开发环境)带文档lw万字以上,文末可获取源码系统程序文件列表开题报告内容一、选题背景关于农贸市场网站的设计与实现问题的研究,现有研究主要以农贸市场的实体运营、传统管理模式为主,专门针对基于特定功能的农贸市场网站设计与实现的研究较......
  • 基于nodejs+vue基于的汽车租赁系统[开题+源码+程序+论文]计算机毕业设计
    本系统(程序+源码+数据库+调试部署+开发环境)带文档lw万字以上,文末可获取源码系统程序文件列表开题报告内容一、选题背景关于汽车租赁系统的研究,现有研究多集中在系统的基本功能构建与运营模式方面,如迪蒙汽车租赁系统,其主要关注如何通过多网融合来拓展业务模式,提高运营效率......
  • 基于nodejs+vue基于的社区问答网站与设计[开题+源码+程序+论文]计算机毕业设计
    本系统(程序+源码+数据库+调试部署+开发环境)带文档lw万字以上,文末可获取源码系统程序文件列表开题报告内容一、选题背景关于社区问答网站的研究,现有研究多集中在其社交性和信息传播方面1。在国外,社区问答网站发展较早,技术和运营模式相对成熟,注重用户体验和信息的个性化推荐......
  • 给网站添加春节灯笼效果:引入即用,附源码!
    记得之前在别的网站上看到这个喜庆的春节灯笼效果,觉得非常吸引人。虽然网上有一些现成的API可以直接实现,比如这个春节灯笼API,但使用后我发现两个问题:一是手机端访问时灯笼没有自适应,二是灯笼上的“春节快乐”四个字不能自定义。为了解决这些问题,我找到了这篇文章,并“借鉴”了其......
  • RTX5/FreeRTOS全家桶源码工程综合实战模板集成CANopen组件(2024-10-30)
    【前言】之前的视频教程分享了两期CANopen的专题,配套的例子都是基于裸机的,为了方便大家在OS下使用,本期视频带OS下的支持。CANopen协议栈专题,实战方式系统了解NMT,PDO,SDO,时间戳,同步报文,紧急报文等(2023-10-17)https://www.armbbs.cn/forum.php?mod=viewthread&tid=121438CANopen......
  • (附源码)基于WEB的家乡特色农商品仓库管理系统的设计与实现-计算机毕设 26145
    基于WEB的家乡特色农商品仓库管理系统的设计与实现摘 要本论文旨在设计和实现基于WEB和SSM(Spring+SpringMVC+MyBatis)的家乡特色农商品仓库管理系统,以提高农产品仓储管理效率和服务水平。论文首先分析了传统农仓库信息管理存在的问题和需求,包括信息化程度低、管理效率不......
  • 实干派!网易易盾增强版滑块验证码,全方位讲解识别思路(含源码)
    注意,本文只提供学习的思路,严禁违反法律以及破坏信息系统等行为,本文只提供思路如有侵犯,请联系作者下架某盾的增强版滑块已经上线很久了,最近心血来潮想看一下这个验证码是骡子是马,我也翻阅了很多市面上的教程,都对该验证码有一定的简介,部分还停留在理论层面,本文将从浅到深......