1. 程式人生 > >OS_FLAG.C(3)

OS_FLAG.C(3)

上篇我們介紹了建立和刪除事件標誌組函式,後來在接著看原始碼的時候,發現倒著來更有助於理解。所以後面幾篇我會選擇較為合適的方式來不定期更博,方便大家理解。

1.介紹刪除節點函式OS_FlagUnlink (OS_FLAG_NODE *pnode):

/*$PAGE*/
/*2018/2/13
*********************************************************************************************************
*                                  UNLINK EVENT FLAG NODE FROM WAITING LIST
*									從等待列表中將事件標誌節點取消關聯(刪除節點)
* Description: This function is internal to uC/OS-II and is used to unlink an event flag node from a
*              list of tasks waiting for the event flag.
*描述:該功能為內部函式,用來從等待事件標誌任務列表中解除事件標誌節點
* Arguments  : pnode         is a pointer to a structure which contains data about the task waiting for
*                            event flag bit(s) to be set.
*引數:						--pnode:指向結構體的指標。該結構體中包含等待事件標誌位的任務的資料。
* Returns    : none
*返回值:無
* Called by  : OS_FlagTaskRdy() OS_FLAG.C
*              OSFlagPend()     OS_FLAG.C
*              OSTaskDel()      OS_TASK.C
*可以被:OS_FLAG.C檔案中的OS_FlagTaskRdy()和OSFlagPend()函式還有OS_TASK.C檔案中的OSTaskDel()函式呼叫。
* Note(s)    : 1) This function assumes that interrupts are disabled.
*              2) This function is INTERNAL to uC/OS-II and your application should not call it.
	註釋:1)該功能不可以被中斷。為原子函式
		2)該功能為內部函式,你的應用程式不能呼叫。
*********************************************************************************************************
*/

void  OS_FlagUnlink (OS_FLAG_NODE *pnode)/*pnode為要進行移除的節點*/
{
	#if OS_TASK_DEL_EN > 0u
		OS_TCB       *ptcb;
	#endif
    OS_FLAG_GRP  *pgrp;				/*pgrp指向事件標誌組*/
    OS_FLAG_NODE *pnode_prev;		/*pnode_prev指向前一個節點*/
    OS_FLAG_NODE *pnode_next;		/*pnode_next指向後一個節點*/

    pnode_prev = (OS_FLAG_NODE *)pnode->OSFlagNodePrev;
    pnode_next = (OS_FLAG_NODE *)pnode->OSFlagNodeNext;
    if (pnode_prev == (OS_FLAG_NODE *)0) /*如果前一個節點為空。那麼pnode指向的是等待列表的首節點(相當於刪除首節點)*/
	{                      
        pgrp= (OS_FLAG_GRP *)pnode->OSFlagNodeFlagGrp;	/*pgrp指向要移除節點所在的組*/
        pgrp->OSFlagWaitList = (void *)pnode_next;		/*將該節點的下一個作為pgrp指向等待列表的指標*/
        if (pnode_next != (OS_FLAG_NODE *)0)			/*如果下一個節點不是空*/
		{
            pnode_next->OSFlagNodePrev = (OS_FLAG_NODE *)0;     /* 將下一個節點指向前一個節點的指標設定為空*/
        }
    } 
	else/*如果前一個節點不為空,不是首節點(相當於從中間刪除)*/
	{                                             
        pnode_prev->OSFlagNodeNext = pnode_next;               
        if (pnode_next != (OS_FLAG_NODE *)0) {                  
            pnode_next->OSFlagNodePrev = pnode_prev;            
        }
    }
	#if OS_TASK_DEL_EN > 0u		/*如果允許刪除任務*/
		ptcb = (OS_TCB *)pnode->OSFlagNodeTCB;	/*將該節點指向的TCB節點賦給ptcb指標*/
		ptcb->OSTCBFlagNode = (OS_FLAG_NODE *)0;/*將該指標下的TCB標誌節點設為空,表示刪除*/
	#endif
}
#endif

從這個函式中不難看出,如果要刪除節點,首先要看刪除的是首節點還是中間結點或者尾節點,然後進行刪除。

刪除的方式這裡也不需要贅述了,比較簡單。可以參考上一篇。

2.介紹 是否可以使任務變為就緒態(是否可以被排程)BOOLEAN  OS_FlagTaskRdy (OS_FLAG_NODE *pnode,OS_FLAGS  flags_rdy)函式:

/*$PAGE*/
/*2018/2/13
*********************************************************************************************************
*                              MAKE TASK READY-TO-RUN, EVENT(s) OCCURRED
*				是否可以使任務變為就緒態
* Description: This function is internal to uC/OS-II and is used to make a task ready-to-run because the
*              desired event flag bits have been set.
*描述:該功能函式是內部函式。作用為當事件標誌位被設定後使任務變為就緒態。
* Arguments  : pnode         is a pointer to a structure which contains data about the task waiting for
*                            event flag bit(s) to be set.
*引數:			--pnode:指向結構體的指標。該結構體包括了等待事件標誌位被設定的任務資料。
*              flags_rdy     contains the bit pattern of the event flags that cause the task to become
*                            ready-to-run.
*			--flags_rdy:事件標誌組的位模式
* Returns    : OS_TRUE       If the task has been placed in the ready list and thus needs scheduling
*              OS_FALSE      The task is still not ready to run and thus scheduling is not necessary
*返回值:	OS_TRUE:返回真,說明任務已經被放在了就緒列表中,需要排程;
	OS_FALSE:返回假,說明該任務仍處於等待狀態,不需要進行排程。
* Called by  : OSFlagsPost() OS_FLAG.C
*被OS_FLAG.C檔案中的OSFlagsPost()函式呼叫。
* Note(s)    : 1) This function assumes that interrupts are disabled.
*              2) This function is INTERNAL to uC/OS-II and your application should not call it.
	註釋:1)該功能不可以被中斷‘
		2)該功能為內部函式,你的應用程式不能呼叫。
*********************************************************************************************************
*/

static  BOOLEAN  OS_FlagTaskRdy (OS_FLAG_NODE *pnode,OS_FLAGS      flags_rdy)
{
    OS_TCB   *ptcb;			/*指向TCB的指標*/
    BOOLEAN   sched;		/*是否排程的標誌*/

    ptcb = (OS_TCB *)pnode->OSFlagNodeTCB; /*指向正在等待的任務的TCB*/
    ptcb->OSTCBDly       = 0u;				/*將TCB的延遲時間設定為0*/
    ptcb->OSTCBFlagsRdy  = flags_rdy;		
    ptcb->OSTCBStat     &= (INT8U)~(INT8U)OS_STAT_FLAG;
    ptcb->OSTCBStatPend  = OS_STAT_PEND_OK;
    if (ptcb->OSTCBStat == OS_STAT_RDY)		/*如果此時TCB狀態為就緒態*/
	{                
        OSRdyGrp |= ptcb->OSTCBBitY;         /*將任務放在就緒佇列中*/
        OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;	/*得到位掩碼*/
        sched = OS_TRUE;			/*將排程標誌設定為真*/
    } 
	else
	{
        sched = OS_FALSE;			/*將排程標誌設定為假*/
    }
    OS_FlagUnlink(pnode);			/*呼叫刪除節點函式,將已放在就緒列表中的該節點從等待列表中刪除*/
    return (sched);					/*返回是否排程的真假值*/
}

該函式的作用很清楚:判斷任務是否可以轉化為就緒態。如果可以轉化,就將標誌設定為真,不可以,就設定為假,然後返回。

但是這裡面有一個問題,我有點疑惑:

   OS_FlagUnlink(pnode);			/*呼叫刪除節點函式,將已放在就緒列表中的該節點從等待列表中刪除*/

該行語句不在if~else語句中,說明不論是否任務已經準備好從等待態轉化為就緒態,都從等待列表中刪除。這樣對嗎?或者是我哪裡理解錯誤?請高手指點一二。

3.介紹初始化事件標誌函式 OS_FlagInit (void):

/*$PAGE*/
/*2018/2/13
*********************************************************************************************************
*                                    INITIALIZE THE EVENT FLAG MODULE
*										初始化事件標誌
* Description: This function is called by uC/OS-II to initialize the event flag module.  Your application
*              MUST NOT call this function.  In other words, this function is internal to uC/OS-II.
*描述:該功能用來初始化事件標誌模組。你的應用程式不能呼叫該功能。
* Arguments  : none
*引數:無
* Returns    : none
*返回值:無
* WARNING    : You MUST NOT call this function from your code.  This is an INTERNAL function to uC/OS-II.
警告:在你的程式碼中不能呼叫該功能,這是uc/os的內部函式。
*********************************************************************************************************
*/
void  OS_FlagInit (void)
{
	#if OS_MAX_FLAGS == 1u		/*如果只有一個標誌*/
		OSFlagFreeList = (OS_FLAG_GRP *)&OSFlagTbl[0];  /*只有一個事件標誌組,空閒列表指標指向標誌表中第0號內容*/
		OSFlagFreeList->OSFlagType     = OS_EVENT_TYPE_UNUSED;/*將標誌型別設定為未使用型別*/
		OSFlagFreeList->OSFlagWaitList = (void *)0;		/*將等待列表指標置為空*/
		OSFlagFreeList->OSFlagFlags    = (OS_FLAGS)0;	/*將標誌設為0*/
		#if OS_FLAG_NAME_EN > 0u
			OSFlagFreeList->OSFlagName     = (INT8U *)"?";	/*將名字設定為未命名*/
		#endif
	#endif

	#if OS_MAX_FLAGS >= 2u	/*如果不止一個標誌*/
		INT16U        ix;
		INT16U        ix_next;	
		OS_FLAG_GRP  *pgrp1;	/*第一個指向事件標誌組的指標*/
		OS_FLAG_GRP  *pgrp2;	/*第一個指向事件標誌組的指標*/

		OS_MemClr((INT8U *)&OSFlagTbl[0], sizeof(OSFlagTbl));	/* 從記憶體中清除事件標誌組表*/
		for (ix = 0u; ix < (OS_MAX_FLAGS - 1u); ix++)			/*遍歷該表,初始化所有的事件標誌*/
		{            
			ix_next = ix + 1u;
			pgrp1 = &OSFlagTbl[ix];
			pgrp2 = &OSFlagTbl[ix_next];
			pgrp1->OSFlagType = OS_EVENT_TYPE_UNUSED;		/*將標誌型別設定為未使用型別*/
			pgrp1->OSFlagWaitList = (void *)pgrp2;			/*將指向下一個標誌的指標賦給OSFlagWaitList*/
			#if OS_FLAG_NAME_EN > 0u
					pgrp1->OSFlagName     = (INT8U *)(void *)"?"; /*將名稱初始化為未命名*/
			#endif
		}
    pgrp1 = &OSFlagTbl[ix];			/*處理該表的最後一個*/
    pgrp1->OSFlagType     = OS_EVENT_TYPE_UNUSED;
    pgrp1->OSFlagWaitList = (void *)0;
#if OS_FLAG_NAME_EN > 0u
    pgrp1->OSFlagName     = (INT8U *)(void *)"?";       
#endif
    OSFlagFreeList        = &OSFlagTbl[0];
#endif
}

初始化函式我們之前在OS_CORE.C檔案中也有過介紹。這個函式與那些初始化函式大同小異。此處不贅述。

4.介紹阻塞任務函式 void  OS_FlagBlock (OS_FLAG_GRP  *pgrp,OS_FLAG_NODE *pnode,OS_FLAGS  flags,INT8U         wait_type, INT32U  timeout)

/*$PAGE*/
/*2018/2/13
*********************************************************************************************************
*                         SUSPEND TASK UNTIL EVENT FLAG(s) RECEIVED OR TIMEOUT OCCURS
*							將任務掛起,直到標誌被接收或者超時
* Description: This function is internal to uC/OS-II and is used to put a task to sleep until the desired
*              event flag bit(s) are set.
*描述:該功能為內部函式,用來將任務處於睡眠狀態,知道事件標誌位被設定
* Arguments  : pgrp          is a pointer to the desired event flag group.
*引數:						-pgrp:指向事件標誌組的指標
*              pnode         is a pointer to a structure which contains data about the task waiting for
*                            event flag bit(s) to be set.
*							--pnode:指向結構體的指標。
*              flags         Is a bit pattern indicating which bit(s) (i.e. flags) you wish to check.
*                            The bits you want are specified by setting the corresponding bits in
*                            'flags'.  e.g. if your application wants to wait for bits 0 and 1 then
*                            'flags' would contain 0x03.
*							--flags:存放你想檢測的位。
*              wait_type     specifies whether you want ALL bits to be set/cleared or ANY of the bits
*                            to be set/cleared.
*                            You can specify the following argument:
*                            OS_FLAG_WAIT_CLR_ALL   You will check ALL bits in 'mask' to be clear (0)
*                            OS_FLAG_WAIT_CLR_ANY   You will check ANY bit  in 'mask' to be clear (0)
*                            OS_FLAG_WAIT_SET_ALL   You will check ALL bits in 'mask' to be set   (1)
*                            OS_FLAG_WAIT_SET_ANY   You will check ANY bit  in 'mask' to be set   (1)
*							--timeout:設定等待型別:
								OS_FLAG_WAIT_CLR_ALL
								OS_FLAG_WAIT_CLR_ANY
								OS_FLAG_WAIT_SET_ALL
								OS_FLAG_WAIT_SET_ANY
*              timeout       is the desired amount of time that the task will wait for the event flag
*                            bit(s) to be set.
* Returns    : none
*返回值:無
* Called by  : OSFlagPend()  OS_FLAG.C
*被OS_FLAG.C檔案中的OSFlagPend()呼叫。
* Note(s)    : This function is INTERNAL to uC/OS-II and your application should not call it.
	註釋:該功能為內部函式,你的應用程式不能呼叫。
*********************************************************************************************************
*/
static  void  OS_FlagBlock (OS_FLAG_GRP  *pgrp,
                            OS_FLAG_NODE *pnode,
                            OS_FLAGS      flags,
                            INT8U         wait_type,
                            INT32U        timeout)
{
    OS_FLAG_NODE  *pnode_next;		/*指向下一個節點的指標*/
    INT8U          y;

	/*設定當前TCB的引數*/
    OSTCBCur->OSTCBStat      |= OS_STAT_FLAG;	
    OSTCBCur->OSTCBStatPend   = OS_STAT_PEND_OK;
    OSTCBCur->OSTCBDly        = timeout;             /*TCB延時設定為timeout*/

	/*以下幾行程式碼都是將pnode設定為連結串列的新的頭節點*/
	#if OS_TASK_DEL_EN > 0u
		OSTCBCur->OSTCBFlagNode   = pnode;            /* 將TCB與node聯絡起來 */
	#endif
    pnode->OSFlagNodeFlags    = flags;                /* 儲存我們需要等待的標誌*/
    pnode->OSFlagNodeWaitType = wait_type;            /*儲存等待型別 */
    pnode->OSFlagNodeTCB      = (void *)OSTCBCur;     /*標誌指向的TCB為當前的TCB*/
    pnode->OSFlagNodeNext     = pgrp->OSFlagWaitList; /*將節點的指標指向節點連結串列的頭部*/
    pnode->OSFlagNodePrev     = (void *)0;
    pnode->OSFlagNodeFlagGrp  = (void *)pgrp;         /*連線事件標誌組 */
    pnode_next                = (OS_FLAG_NODE *)pgrp->OSFlagWaitList;/*下一個節點*/
    if (pnode_next != (void *)0)	/*如果為空地址,只有一個節點(就是本節點),如果非空,那麼將該連結串列的頭節點改為現在這個節點*/
	{                 
        pnode_next->OSFlagNodePrev = pnode;         
    }
    pgrp->OSFlagWaitList = (void *)pnode;

    y =  OSTCBCur->OSTCBY;                 /* 將當前的任務掛起(取消該任務的就緒態)更改就緒表和就緒組的相關值*/
    OSRdyTbl[y] &= (OS_PRIO)~OSTCBCur->OSTCBBitX;
    if (OSRdyTbl[y] == 0x00u) 
	{
        OSRdyGrp &= (OS_PRIO)~OSTCBCur->OSTCBBitY;
    }
}

這個函式裡提示一點:

	/*以下幾行程式碼都是將pnode設定為連結串列的新的頭節點*/
	#if OS_TASK_DEL_EN > 0u
		OSTCBCur->OSTCBFlagNode   = pnode;            /* 將TCB與node聯絡起來 */
	#endif
    pnode->OSFlagNodeFlags    = flags;                /* 儲存我們需要等待的標誌*/
    pnode->OSFlagNodeWaitType = wait_type;            /*儲存等待型別 */
    pnode->OSFlagNodeTCB      = (void *)OSTCBCur;     /*標誌指向的TCB為當前的TCB*/
    pnode->OSFlagNodeNext     = pgrp->OSFlagWaitList; /*將節點的指標指向節點連結串列的頭部*/
    pnode->OSFlagNodePrev     = (void *)0;
    pnode->OSFlagNodeFlagGrp  = (void *)pgrp;         /*連線事件標誌組 */
    pnode_next                = (OS_FLAG_NODE *)pgrp->OSFlagWaitList;/*下一個節點*/

註釋裡提到了:這幾行就是將當前的節點pnode設定為等待列表的新的頭節點,取消其就緒狀態,設定為掛起狀態。

在這個的基礎上理解上面幾行語句就很簡單了。

5.OSFlagQuery (OS_FLAG_GRP  *pgrp,INT8U  *perr)查詢事件標誌函式:

/*$PAGE*/
/*2018/2/13
*********************************************************************************************************
*                                           QUERY EVENT FLAG
*											查詢事件標誌
* Description: This function is used to check the value of the event flag group.
*描述:該功能用來檢測事件標誌組的值
* Arguments  : pgrp         is a pointer to the desired event flag group.
*引數:						--pgrp:指向事件標誌組的指標
*              perr          is a pointer to an error code returned to the called:
*                            OS_ERR_NONE                The call was successfull
*                            OS_ERR_FLAG_INVALID_PGRP   You passed a NULL pointer
*                            OS_ERR_EVENT_TYPE          You are not pointing to an event flag group
*							--perr錯誤碼指標:
								OS_ERR_NONE:無錯誤;
								OS_ERR_FLAG_INVALID_PGRP:pgrp為空指標;
								OS_ERR_EVENT_TYPE:沒有指向事件標誌組的指標。
* Returns    : The current value of the event flag group.
*返回值:事件標誌組的當前值
* Called From: Task or ISR
任務或者中斷呼叫。
*********************************************************************************************************
*/

#if OS_FLAG_QUERY_EN > 0u
OS_FLAGS  OSFlagQuery (OS_FLAG_GRP  *pgrp,
                       INT8U        *perr)
{
    OS_FLAGS   flags;				/*定義一個“當前位”狀態*/
	#if OS_CRITICAL_METHOD == 3u                     
		OS_CPU_SR  cpu_sr = 0u;
	#endif

	#ifdef OS_SAFETY_CRITICAL			/*安全中斷*/
		if (perr == (INT8U *)0) 
		{
			OS_SAFETY_CRITICAL_EXCEPTION();
		}
	#endif

	#if OS_ARG_CHK_EN > 0u				/*檢查引數*/
		if (pgrp == (OS_FLAG_GRP *)0) 
		{             
			*perr = OS_ERR_FLAG_INVALID_PGRP;
			return ((OS_FLAGS)0);
		}
	#endif
    if (pgrp->OSFlagType != OS_EVENT_TYPE_FLAG) /*有效化事件標誌塊型別*/
	{ 
        *perr = OS_ERR_EVENT_TYPE;
        return ((OS_FLAGS)0);
    }
    OS_ENTER_CRITICAL();		/*進入中斷*/
    flags = pgrp->OSFlagFlags;	/*獲取事件標誌組的當前的事件標誌位值*/
    OS_EXIT_CRITICAL();			/*關閉中斷*/
    *perr = OS_ERR_NONE;		/*將錯誤碼指標設定為成功呼叫*/
    return (flags);             /*返回當前事件標誌狀態*/
}
#endif

該函式關鍵語句就是上面標紅的那一行。

6.設定或清除事件標誌組OSFlagPost (OS_FLAG_GRP  *pgrp,OS_FLAGS  flags,INT8U  opt,INT8U  *perr)函式:

/*$PAGE*/
/*2018/2/13
*********************************************************************************************************
*                                         POST EVENT FLAG BIT(S)
*											設定或清除事件標誌組
* Description: This function is called to set or clear some bits in an event flag group.  The bits to
*              set or clear are specified by a 'bit mask'.
*描述:該功能用來設定或者清除事件標誌組中的一些位。這些位由位掩碼來指定。
* Arguments  : pgrp          is a pointer to the desired event flag group.
*引數:						--pgrp:指向事件標誌組的指標
*              flags         If 'opt' (see below) is OS_FLAG_SET, each bit that is set in 'flags' will
*                            set the corresponding bit in the event flag group.  e.g. to set bits 0, 4
*                            and 5 you would set 'flags' to:
*                                0x31     (note, bit 0 is least significant bit)
*							--flags:如果opt是OS_FLAG_SET,那麼在flags中的每一位將在事件標誌組中的相應位上也進行設定。
									例如:如果要將事件標誌組中的位設定為0,4,5位為1,那麼你就得將flags設定為00110001。
									(註釋:0位是最低有效位)
*                            If 'opt' (see below) is OS_FLAG_CLR, each bit that is set in 'flags' will
*                            CLEAR the corresponding bit in the event flag group.  e.g. to clear bits 0,
*                            4 and 5 you would specify 'flags' as:
								0x31     (note, bit 0 is least significant bit)
*							--如果opt為OS_FLAG_CLR,那麼在flags中設定的每一位對應在事件標誌組中的對應位將被清除掉。
								例如:如果要清除掉事件標誌組中的第0,4,5位,你的flags就應該被指定為00110001
								(註釋:0是最低有效位)
*                                
*              opt           indicates whether the flags will be:
*                                set     (OS_FLAG_SET) or
*                                cleared (OS_FLAG_CLR)
*							--opt:有以下兩種選擇:
								set(OS_FLAG_SET)設定或者 cleared (OS_FLAG_CLR)清除。這兩個不同的選擇對flags有影響。
*              perr          is a pointer to an error code and can be:
*                            OS_ERR_NONE                The call was successfull
*                            OS_ERR_FLAG_INVALID_PGRP   You passed a NULL pointer
*                            OS_ERR_EVENT_TYPE          You are not pointing to an event flag group
*                            OS_ERR_FLAG_INVALID_OPT    You specified an invalid option
*							--perr:指向錯誤碼的指標,可以為以下值:
								OS_ERR_NONE:無錯誤;
								OS_ERR_FLAG_INVALID_PGRP:pgrp為空指標;
								OS_ERR_EVENT_TYPE:沒有指向事件標誌組的指標;
								OS_ERR_FLAG_INVALID_OPT:opt引數選擇錯誤。
* Returns    : the new value of the event flags bits that are still set.
*返回值:flags被修改後的值
* Called From: Task or ISR
*由任務或者中斷呼叫。
* WARNING(s) : 1) The execution time of this function depends on the number of tasks waiting on the event
*                 flag group.
*              2) The amount of time interrupts are DISABLED depends on the number of tasks waiting on
*                 the event flag group.
	警告:1)該功能的執行時間取決於事件標誌組中的等待任務數量;
			2)時間中斷無效的數目取決於事件標誌組中的等待任務數。
*********************************************************************************************************
*///置位或清0事件標誌組中的標誌位(指標、標誌位、條件值、錯誤碼)
OS_FLAGS  OSFlagPost (OS_FLAG_GRP  *pgrp,
                      OS_FLAGS      flags,
                      INT8U         opt,
                      INT8U        *perr)
{
    OS_FLAG_NODE *pnode;				/*指向標誌節點的指標*/
    BOOLEAN       sched;				/*是否被排程變數*/
    OS_FLAGS      flags_cur;			/*當前的標誌值(flags)*/
    OS_FLAGS      flags_rdy;			/*就緒的標誌值(flags)*/
    BOOLEAN       rdy;					/*是否就緒變數*/

	#if OS_CRITICAL_METHOD == 3u       /*中斷被設定為型別3*/
		OS_CPU_SR     cpu_sr = 0u;
	#endif

	#ifdef OS_SAFETY_CRITICAL			/*定義安全中斷*/
		if (perr == (INT8U *)0) 
		{
			OS_SAFETY_CRITICAL_EXCEPTION();
		}
	#endif

	#if OS_ARG_CHK_EN > 0u				/*檢查引數*/
		if (pgrp == (OS_FLAG_GRP *)0)	/*有效化pgrp*/
		{               
			*perr = OS_ERR_FLAG_INVALID_PGRP;
			return ((OS_FLAGS)0);
		}
	#endif
    if (pgrp->OSFlagType != OS_EVENT_TYPE_FLAG) /*確定我們指向的是事件標誌組*/
	{   
        *perr = OS_ERR_EVENT_TYPE;
        return ((OS_FLAGS)0);
    }
/*$PAGE*/
    OS_ENTER_CRITICAL();	/*進入中斷*/
    switch (opt) 
	{
        case OS_FLAG_CLR:	/*opt為OS_FLAG_CLR*/
             pgrp->OSFlagFlags &= (OS_FLAGS)~flags;  /*清除在事件標誌組中設定的位*/
             break;

        case OS_FLAG_SET:	/*opt為OS_FLAG_SET*/
             pgrp->OSFlagFlags |=  flags;            /* 設定在事件標誌組中設定的位*/
             break;

        default:									/*無效的選擇*/
             OS_EXIT_CRITICAL();                     /*關中斷*/
             *perr = OS_ERR_FLAG_INVALID_OPT;		/*將中斷碼設定為OS_ERR_FLAG_INVALID_OPT*/
             return ((OS_FLAGS)0);					/*返回值為0*/
    }
    sched = OS_FALSE;							 /*將排程標誌設定為false,表示不需要排程*/
    pnode = (OS_FLAG_NODE *)pgrp->OSFlagWaitList;
    while (pnode != (OS_FLAG_NODE *)0)			 /*瀏覽等待事件標誌的所有任務*/
	{            
        switch (pnode->OSFlagNodeWaitType)		/*根據等待型別不同執行不同的程式碼*/
		{
            case OS_FLAG_WAIT_SET_ALL:          /*要求所有的位都被設定*/
                 flags_rdy = (OS_FLAGS)(pgrp->OSFlagFlags & pnode->OSFlagNodeFlags);
                 if (flags_rdy == pnode->OSFlagNodeFlags)  /*所有的位都被設定*/
				 {
                     rdy = OS_FlagTaskRdy(pnode, flags_rdy);  /*得到該節點對應的任務是否就緒標誌*/
                     if (rdy == OS_TRUE)				/*該節點對應的任務已經就緒*/
					 {
                         sched = OS_TRUE;              /*可以進行排程*/
                     }
                 }
                 break;

            case OS_FLAG_WAIT_SET_ANY:               /*任意一位被設定*/
                 flags_rdy = (OS_FLAGS)(pgrp->OSFlagFlags & pnode->OSFlagNodeFlags);
                 if (flags_rdy != (OS_FLAGS)0)	/*有任何一個標誌位被設定*/
				 {
                     rdy = OS_FlagTaskRdy(pnode, flags_rdy);   /*得到該節點對應的任務是否就緒標誌*/
                     if (rdy == OS_TRUE)					 /*該節點對應的任務已經就緒*/
					 {
                         sched = OS_TRUE;                  /*可以進行排程*/  
                     }
                 }
                 break;
			/*下面兩個case參考上文即可*/
			#if OS_FLAG_WAIT_CLR_EN > 0u
            case OS_FLAG_WAIT_CLR_ALL:            
                 flags_rdy = (OS_FLAGS)~pgrp->OSFlagFlags & pnode->OSFlagNodeFlags;
                 if (flags_rdy == pnode->OSFlagNodeFlags) {
                     rdy = OS_FlagTaskRdy(pnode, flags_rdy);  
                     if (rdy == OS_TRUE) {
                         sched = OS_TRUE;                    
                     }
                 }
                 break;

            case OS_FLAG_WAIT_CLR_ANY:          
                 flags_rdy = (OS_FLAGS)~pgrp->OSFlagFlags & pnode->OSFlagNodeFlags;
                 if (flags_rdy != (OS_FLAGS)0) {
                     rdy = OS_FlagTaskRdy(pnode, flags_rdy); 
                     if (rdy == OS_TRUE) {
                         sched = OS_TRUE;                 
                     }
                 }
                 break;
			#endif
            default:						   /*這四種情況都不是*/
                 OS_EXIT_CRITICAL();		   /*退出中斷*/
                 *perr = OS_ERR_FLAG_WAIT_TYPE;/*設定錯誤碼為OS_ERR_FLAG_WAIT_TYPE*/
                 return ((OS_FLAGS)0);		   /*返回0*/
        }
        pnode = (OS_FLAG_NODE *)pnode->OSFlagNodeNext; /* 指向下一個等待事件標誌的任務節點*/
    }
    OS_EXIT_CRITICAL();			/*退出中斷*/
    if (sched == OS_TRUE) {		/*如果可以進行任務排程*/
        OS_Sched();				/*排程任務*/
    }
    OS_ENTER_CRITICAL();		/*進入中斷*/
    flags_cur = pgrp->OSFlagFlags;/*獲取事件標誌組的事件標誌位值作為當前的標誌值*/
    OS_EXIT_CRITICAL();			/*退出中斷*/
    *perr     = OS_ERR_NONE;	/*成功呼叫*/
    return (flags_cur);			/*返回當前的標誌值*/
}

流程圖為:


7. OSFlagPend (OS_FLAG_GRP  *pgrp,OS_FLAGS  flags, INT8U   wait_type,INT32U timeout,INT8U *perr)等待事件標誌組中的事件標誌函式:

/*$PAGE*/
/*2018/2/12
*********************************************************************************************************
*                                        WAIT ON AN EVENT FLAG GROUP			
*										  等待事件標誌組中的事件標誌
* Description: This function is called to wait for a combination of bits to be set in an event flag
*              group.  Your application can wait for ANY bit to be set or ALL bits to be set.
*描述:任務等待事件標誌組中的事件標誌,可以是多個事件標誌的不同組合方式。
		可以等待任意指定事件標誌位置位或清0,也可以是全部指定事件標誌位置位或清0。
		如果任務等待的事件標誌位條件尚不滿足,則任務會被掛起,直到指定的事件標誌組合發生或指定的等待時間超時。
* Arguments  : pgrp          is a pointer to the desired event flag group.
*引數:						--pgrp:指向事件標誌組的指標
*              flags         Is a bit pattern indicating which bit(s) (i.e. flags) you wish to wait for.
*                            The bits you want are specified by setting the corresponding bits in
*                            'flags'.  e.g. if your application wants to wait for bits 0 and 1 then
*                            'flags' would contain 0x03.
*							--flags:指定需要檢查的事件標誌位。置為1,則檢查對應位;置為0,則忽略對應位。
*              wait_type     specifies whether you want ALL bits to be set or ANY of the bits to be set.
*                            You can specify the following argument:
*							--wait_type:定義等待事件標誌位的方式。可以定為以下幾種
*                            OS_FLAG_WAIT_CLR_ALL   You will wait for ALL bits in 'mask' to be clear (0)
*                            OS_FLAG_WAIT_SET_ALL   You will wait for ALL bits in 'mask' to be set   (1)
*                            OS_FLAG_WAIT_CLR_ANY   You will wait for ANY bit  in 'mask' to be clear (0)
*                            OS_FLAG_WAIT_SET_ANY   You will wait for ANY bit  in 'mask' to be set   (1)
*							--OS_FLAG_WAIT_CLR_ALL:所有指定事件標誌位清0 ;
							  OS_FLAG_WAIT_SET_ALL:任意指定事件標誌位置1 ;
							  OS_FLAG_WAIT_CLR_ANY:所有指定事件標誌位清0 ;
							  OS_FLAG_WAIT_SET_ANY:任意指定事件標誌位置1 ;
*                            NOTE: Add OS_FLAG_CONSUME if you want the event flag to be 'consumed' by
*                                  the call.  Example, to wait for any flag in a group AND then clear
*                                  the flags that are present, set 'wait_type' to:
*                                  OS_FLAG_WAIT_SET_ANY + OS_FLAG_CONSUME
*							--註釋:如果你想在呼叫之後將事件標誌組消耗掉,在等待型別後面加一個OS_FLAG_CONSUME。
*              timeout       is an optional timeout (in clock ticks) that your task will wait for the
*                            desired bit combination.  If you specify 0, however, your task will wait
*                            forever at the specified event flag group or, until a message arrives.
*							--timeout:以時鐘節拍數目的等待超時時限。如果在這一時限得不到事件,任務將恢復執行。
									  timeout的值為0,表示將無限期地等待事件。timeout的最大值是65535個時鐘節拍。
									  timeout的值並不與時鐘節拍同步,timeout計數器在下一個時鐘節拍到來時開始遞減。
									  在這裡,所謂下一個時鐘節拍,也就是立刻就到來了。
*              perr          is a pointer to an error code and can be:
*                            OS_ERR_NONE               The desired bits have been set within the specified
*                                                      'timeout'.
*                            OS_ERR_PEND_ISR           If you tried to PEND from an ISR
*                            OS_ERR_FLAG_INVALID_PGRP  If 'pgrp' is a NULL pointer.
*                            OS_ERR_EVENT_TYPE         You are not pointing to an event flag group
*                            OS_ERR_TIMEOUT            The bit(s) have not been set in the specified
*                                                      'timeout'.
*                            OS_ERR_PEND_ABORT         The wait on the flag was aborted.
*                            OS_ERR_FLAG_WAIT_TYPE     You didn't specify a proper 'wait_type' argument.
*							--perr:指向錯誤碼的指標。可以為以下幾種值:
									OS_ERR_NONE:無錯誤型別
									OS_ERR_PEND_ISR:從中斷中調入該程式
									OS_ERR_FLAG_INVALID_PGRP:pgrp為空指標
									OS_ERR_EVENT_TYPE:沒有指向事件標誌組的指標
									OS_ERR_TIMEOUT:等待事件標誌組的事件標誌超時;
									OS_ERR_PEND_ABORT:等待標誌被取消
									OS_ERR_FLAG_WAIT_TYPE:'wait_type'不是指定的引數之一。
* Returns    : The flags in the event flag group that made the task ready or, 0 if a timeout or an error
*              occurred.
*返回值:	如果任務就緒,返回事件標誌組的標誌。
			如果發生了超時或者其他錯誤,則返回0。
* Called from: Task ONLY
*只能由任務呼叫
* Note(s)    : 1) IMPORTANT, the behavior of this function has changed from PREVIOUS versions.  The
*                 function NOW returns the flags that were ready INSTEAD of the current state of the
*                 event flags.
	註釋:1)該功能與以前版本的功能有些許差別。該版本下這個函式的返回值是是否等待就緒的標誌而不是當前事件標誌的狀態。
*********************************************************************************************************
*///等待事件標誌組的事件標誌位(事件組指標、需要檢查的標誌位、等待事件標誌位的方式、允許等待的時鐘節拍、出錯程式碼的時鐘節拍)
OS_FLAGS  OSFlagPend (OS_FLAG_GRP  *pgrp,
                      OS_FLAGS      flags,
                      INT8U         wait_type,
                      INT32U        timeout,
                      INT8U        *perr)
{
    OS_FLAG_NODE  node;
    OS_FLAGS      flags_rdy;
    INT8U         result;
    INT8U         pend_stat;			  /*掛起狀態*/
    BOOLEAN       consume;				  /*是否為消耗型別標誌*/
#if OS_CRITICAL_METHOD == 3u              /*中斷型別被設定為3*/
    OS_CPU_SR     cpu_sr = 0u;
#endif

#ifdef OS_SAFETY_CRITICAL				/*定義安全中斷*/
    if (perr == (INT8U *)0) 
	{
        OS_SAFETY_CRITICAL_EXCEPTION();
    }
#endif

#if OS_ARG_CHK_EN > 0u					/*檢查引數*/
    if (pgrp == (OS_FLAG_GRP *)0)		
	{                      
        *perr = OS_ERR_FLAG_INVALID_PGRP;
        return ((OS_FLAGS)0);
    }
#endif
    if (OSIntNesting > 0u)				/*如果從中斷中呼叫該函式*/
	{                               
        *perr = OS_ERR_PEND_ISR;        /*將錯誤碼設定為OS_ERR_PEND_ISR*/                
        return ((OS_FLAGS)0);			/*返回值為0*/
    }
    if (OSLockNesting > 0u)				/*如果排程器被上鎖了*/
	{                              
        *perr = OS_ERR_PEND_LOCKED;     /*無法呼叫該函式,將錯誤碼設定為OS_ERR_PEND_LOCKED*/
        return ((OS_FLAGS)0);			/*返回值為0*/
    }
    if (pgrp->OSFlagType != OS_EVENT_TYPE_FLAG) /*有效化事件標誌型別*/
	{        
        *perr = OS_ERR_EVENT_TYPE;
        return ((OS_FLAGS)0);
    }
    result = (INT8U)(wait_type & OS_FLAG_CONSUME);	/*將等待型別和OS_FLAG_CONSUME做邏輯與運算,結果存到result中。*/
    if (result != (INT8U)0) {                       /* 如果不是0,說明是消耗型別 */
        wait_type &= (INT8U)~(INT8U)OS_FLAG_CONSUME;
        consume    = OS_TRUE;
    } 
	else					/*如果result是0,說明不是消耗型別*/
	{
        consume    = OS_FALSE;
    }
/*$PAGE*/
    OS_ENTER_CRITICAL();		/*進入中斷*/
    switch (wait_type)			/*根據wait_type的狀態執行不同的程式*/
	{
        case OS_FLAG_WAIT_SET_ALL:     /*如果是OS_FLAG_WAIT_SET_ALL型別*/
             flags_rdy = (OS_FLAGS)(pgrp->OSFlagFlags & flags);   /*提取出我們需要的位 */
             if (flags_rdy == flags)  /*必須匹配到我們需要的所有的位*/
			 {                    
                 if (consume == OS_TRUE)  /*如果是消耗型別*/
				 {                
                     pgrp->OSFlagFlags &= (OS_FLAGS)~flags_rdy;   /*只清理掉我們需要的位 */
                 }
                 OSTCBCur->OSTCBFlagsRdy = flags_rdy;      /*將就緒標誌儲存到OSTCBFlagsRdy中*/
                 OS_EXIT_CRITICAL();                       /* 退出中斷*/
                 *perr                   = OS_ERR_NONE;	   /*將錯誤碼設定為無錯誤型別*/
                 return (flags_rdy);					   /*返回flags_rdy*/
             } 
			 else /*阻塞任務知道有事件發生或者超時 */
			 {                                     
                 OS_FlagBlock(pgrp, &node, flags, wait_type, timeout);
                 OS_EXIT_CRITICAL();
             }
             break;

        case OS_FLAG_WAIT_SET_ANY:
             flags_rdy = (OS_FLAGS)(pgrp->OSFlagFlags & flags);  
             if (flags_rdy != (OS_FLAGS)0) {           
                 if (consume == OS_TRUE) {              
                     pgrp->OSFlagFlags &= (OS_FLAGS)~flags_rdy;   
                 }
                 OSTCBCur->OSTCBFlagsRdy = flags_rdy;  
                 OS_EXIT_CRITICAL();                      
                 *perr                   = OS_ERR_NONE;
                 return (flags_rdy);
             } 
			 else
			 {                                    
                 OS_FlagBlock(pgrp, &node, flags, wait_type, timeout);
                 OS_EXIT_CRITICAL();
             }
             break;

#if OS_FLAG_WAIT_CLR_EN > 0u
        case OS_FLAG_WAIT_CLR_ALL:                         /* See if all required flags are cleared    */
             flags_rdy = (OS_FLAGS)~pgrp->OSFlagFlags & flags;    /* Extract only the bits we want     */
             if (flags_rdy == flags) {                     /* Must match ALL the bits that we want     */
                 if (consume == OS_TRUE) {                 /* See if we need to consume the flags      */
                     pgrp->OSFlagFlags |= flags_rdy;       /* Set ONLY the flags that we wanted        */
                 }
                 OSTCBCur->OSTCBFlagsRdy = flags_rdy;      /* Save flags that were ready               */
                 OS_EXIT_CRITICAL();                       /* Yes, condition met, return to caller     */
                 *perr                   = OS_ERR_NONE;
                 return (flags_rdy);
             } else {                                      /* Block task until events occur or timeout */
                 OS_FlagBlock(pgrp, &node, flags, wait_type, timeout);
                 OS_EXIT_CRITICAL();
             }
             break;

        case OS_FLAG_WAIT_CLR_ANY:
             flags_rdy = (OS_FLAGS)~pgrp->OSFlagFlags & flags;   /* Extract only the bits we want      */
             if (flags_rdy != (OS_FLAGS)0) {               /* See if any flag cleared                  */
                 if (consume == OS_TRUE) {                 /* See if we need to consume the flags      */
                     pgrp->OSFlagFlags |= flags_rdy;       /* Set ONLY the flags that we got           */
                 }
                 OSTCBCur->OSTCBFlagsRdy = flags_rdy;      /* Save flags that were ready               */
                 OS_EXIT_CRITICAL();                       /* Yes, condition met, return to caller     */
                 *perr                   = OS_ERR_NONE;
                 return (flags_rdy);
             } else {                                      /* Block task until events occur or timeout */
                 OS_FlagBlock(pgrp, &node, flags, wait_type, timeout);
                 OS_EXIT_CRITICAL();
             }
             break;
#endif

        default:
             OS_EXIT_CRITICAL();
             flags_rdy = (OS_FLAGS)0;
             *perr      = OS_ERR_FLAG_WAIT_TYPE;
             return (flags_rdy);
    }
/*$PAGE*/
    OS_Sched();        /*進行排程。找需要執行的最高優先順序任務*/ 
    OS_ENTER_CRITICAL();/*進入中斷*/
    if (OSTCBCur->OSTCBStatPend != OS_STAT_PEND_OK)  /*當前TCB掛起狀態為取消或者超時狀態*/
	{     
        pend_stat                = OSTCBCur->OSTCBStatPend;
        OSTCBCur->OSTCBStatPend  = OS_STAT_PEND_OK;
        OS_FlagUnlink(&node);
        OSTCBCur->OSTCBStat      = OS_STAT_RDY;            /* Yes, make task ready-to-run              */
        OS_EXIT_CRITICAL();
        flags_rdy                = (OS_FLAGS)0;
        switch (pend_stat) {
            case OS_STAT_PEND_ABORT:
                 *perr = OS_ERR_PEND_ABORT;                /* Indicate that we aborted   waiting       */
                 break;

            case OS_STAT_PEND_TO:
            default:
                 *perr = OS_ERR_TIMEOUT;                   /* Indicate that we timed-out waiting       */
                 break;
        }
        return (flags_rdy);
    }
    flags_rdy = OSTCBCur->OSTCBFlagsRdy;
    if (consume == OS_TRUE) {                              /* See if we need to consume the flags      */
        switch (wait_type) {
            case OS_FLAG_WAIT_SET_ALL:
            case OS_FLAG_WAIT_SET_ANY:                     /* Clear ONLY the flags we got              */
                 pgrp->OSFlagFlags &= (OS_FLAGS)~flags_rdy;
                 break;

#if OS_FLAG_WAIT_CLR_EN > 0u
            case OS_FLAG_WAIT_CLR_ALL:
            case OS_FLAG_WAIT_CLR_ANY:                     /* Set   ONLY the flags we got              */
                 pgrp->OSFlagFlags |=  flags_rdy;
                 break;
#endif
            default:
                 OS_EXIT_CRITICAL();
                 *perr = OS_ERR_FLAG_WAIT_TYPE;
                 return ((OS_FLAGS)0);
        }
    }
    OS_EXIT_CRITICAL();
    *perr = OS_ERR_NONE;                                   /* Event(s) must have occurred              */
    return (flags_rdy);
}

流程圖如下:


到這裡,OS_FLAG.C檔案就介紹完了。中間有幾個函式沒有介紹,設定名稱、獲得名稱函式。大家自行看原始碼,很簡單。

下篇將會帶著大家理一下整體的思路。