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 > 0uOS_TCB *ptcb;#endifOS_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從這個函數中不難看出,如果要刪除節點,首先要看刪除的是首節點還是中間結點或者尾節點,然后進行刪除。
刪除的方式這里也不需要贅述了,比較簡單??梢詤⒖忌弦黄?/p>
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 > 0uOSFlagFreeList->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 > 0upgrp1->OSFlagName = (INT8U *)(void *)"?"; /*將名稱初始化為未命名*/#endif}pgrp1 = &OSFlagTbl[ix]; /*處理該表的最后一個*/pgrp1->OSFlagType = OS_EVENT_TYPE_UNUSED;pgrp1->OSFlagWaitList = (void *)0; #if OS_FLAG_NAME_EN > 0upgrp1->OSFlagName = (INT8U *)(void *)"?"; #endifOSFlagFreeList = &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_ALLOS_FLAG_WAIT_CLR_ANYOS_FLAG_WAIT_SET_ALLOS_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 > 0uOSTCBCur->OSTCBFlagNode = pnode; /* 將TCB與node聯系起來 */#endifpnode->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 > 0uOSTCBCur->OSTCBFlagNode = pnode; /* 將TCB與node聯系起來 */#endifpnode->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);}#endifif (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);}#endifif (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 > 0ucase 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;#endifdefault: /*這四種情況都不是*/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:定義等待事件標志位的方式??梢远橐韵聨追N * 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);} #endifif (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 > 0ucase 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; #endifdefault: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 > 0ucase OS_FLAG_WAIT_CLR_ALL:case OS_FLAG_WAIT_CLR_ANY: /* Set ONLY the flags we got */pgrp->OSFlagFlags |= flags_rdy;break; #endifdefault: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文件就介紹完了。中間有幾個函數沒有介紹,設置名稱、獲得名稱函數。大家自行看源碼,很簡單。
下篇將會帶著大家理一下整體的思路。
總結
以上是生活随笔為你收集整理的OS_FLAG.C(3)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: OS_FLAG.C(2)
- 下一篇: os_mutex.c(全)