/** ******************************************************************************* * @file flag.c * @version V1.12 * @date 2010.03.01 * @brief Flag management implementation code of coocox CoOS kernel. ******************************************************************************* * @copy * * INTERNAL FILE,DON'T PUBLIC. * *

© COPYRIGHT 2009 CooCox

******************************************************************************* */ /*---------------------------- Include ---------------------------------------*/ #include #if CFG_FLAG_EN > 0 /*---------------------------- Variable Define -------------------------------*/ #define FLAG_MAX_NUM 32 /*!< Define max flag number. */ FCB FlagCrl = {0}; /*!< Flags list struct */ /*---------------------------- Function Declare ------------------------------*/ static void FlagBlock(P_FLAG_NODE pnode,U32 flags,U8 waitType); static P_FLAG_NODE RemoveFromLink(P_FLAG_NODE pnode); /** ******************************************************************************* * @brief Create a flag * @param[in] bAutoReset Reset mode,TRUE(Auto Reset) FLASE(Manual Reset). * @param[in] bInitialState Initial state. * @param[out] None * @retval E_CREATE_FAIL Create flag fail. * @retval others Create flag successful. * * @par Description * @details This function use to create a event flag. * @note ******************************************************************************* */ OS_FlagID CoCreateFlag(BOOL bAutoReset,BOOL bInitialState) { U8 i; OsSchedLock(); for(i=0;i 0) /* If be called from ISR */ { return E_CALL; } #if CFG_PAR_CHECKOUT_EN >0 if((pfcb->flagActive&(1<headNode; while(pnode != NULL) /* Ready all tasks waiting for flags */ { if((pnode->waitFlags&(1<waitType == OPT_WAIT_ALL) { /* If the flag is only required by NODE */ if( pnode->waitFlags == (1<waitFlags &= ~(1<nextNode; } /* Remove the flag from the flags list */ pfcb->flagActive &= ~(1<flagRdy &= ~(1<resetOpt &= ~(1<0 if(id >= FLAG_MAX_NUM) { return E_INVALID_ID; /* Invalid 'id',return error */ } if((pfcb->flagActive&(1<flagRdy&(1<flagRdy &= ~((FlagCrl.resetOpt)&(1<0 if((flags&pfcb->flagActive) != flags ) /* Judge flag is active or not? */ { *perr = E_INVALID_PARAMETER; /* Invalid flags */ return 0; } #endif springFlag = flags & pfcb->flagRdy; OsSchedLock(); /* If any required flags are set */ if( (springFlag != 0) && (waitType == OPT_WAIT_ANY) ) { pfcb->flagRdy &= ~(springFlag & pfcb->resetOpt); /* Clear the flags */ OsSchedUnlock(); *perr = E_OK; return springFlag; } /* If all required flags are set */ if((springFlag == flags) && (waitType == OPT_WAIT_ALL)) { pfcb->flagRdy &= ~(springFlag&pfcb->resetOpt); /* Clear the flags */ OsSchedUnlock(); *perr = E_OK; return springFlag; } OsSchedUnlock(); *perr = E_FLAG_NOT_READY; return 0; } /** ******************************************************************************* * @brief WaitForSingleFlag * @param[in] id Flag ID. * @param[in] timeout The longest time for writting flag. * @param[out] None * @retval E_CALL Error call in ISR. * @retval E_INVALID_ID Invalid event ID. * @retval E_TIMEOUT Flag wasn't received within 'timeout' time. * @retval E_OK The call was successful and your task owns the Flag, * or the event you are waiting for occurred. * * @par Description * @details This function is called to wait for only one flag, * (1) if parameter "timeout" == 0,waiting until flag be set; * (2) when "timeout" != 0,if flag was set or wasn't set but timeout * occured,the task will exit the waiting list,convert to READY * or RUNNING state. * @note ******************************************************************************* */ StatusType CoWaitForSingleFlag(OS_FlagID id,U32 timeout) { FLAG_NODE flagNode; P_FCB pfcb; P_OSTCB curTCB; if(OSIntNesting > 0) /* See if the caller is ISR */ { return E_CALL; } if(OSSchedLock != 0) /* Schedule is lock? */ { return E_OS_IN_LOCK; /* Yes,error return */ } #if CFG_PAR_CHECKOUT_EN >0 if(id >= FLAG_MAX_NUM) /* Judge id is valid or not? */ { return E_INVALID_ID; /* Invalid 'id' */ } if((FlagCrl.flagActive&(1<flagRdy&(1<flagRdy &= ~((pfcb->resetOpt&(1<state = TASK_WAITING; TaskSchedReq = TRUE; OsSchedUnlock(); /* The required flag is set and the task is in running state */ curTCB->pnode = NULL; OsSchedLock(); /* Clear the required flag or not */ pfcb->flagRdy &= ~((1<resetOpt)); OsSchedUnlock(); } else /* If time-out is configured */ { /* Block task until the required flag is set or time-out occurs */ FlagBlock(&flagNode,(1<pnode == NULL) /* If time-out occurred */ { return E_TIMEOUT; } else /* If flag is set */ { curTCB->pnode = NULL; OsSchedLock(); /* Clear the required flag or not */ pfcb->flagRdy &= ~((1<resetOpt)); OsSchedUnlock(); } } } return E_OK; } /** ******************************************************************************* * @brief WaitForMultipleFlags * @param[in] flags Flags that waiting to active task. * @param[in] waitType Flags wait type. * @param[in] timeout The longest time for writting flag. * @param[out] perr A pointer to error code. * @retval 0 * @retval springFlag * * @par Description * @details This function is called to pend a task for waitting multiple flag. * @note ******************************************************************************* */ U32 CoWaitForMultipleFlags(U32 flags,U8 waitType,U32 timeout,StatusType *perr) { U32 springFlag; P_FCB pfcb; FLAG_NODE flagNode; P_OSTCB curTCB; if(OSIntNesting > 0) /* If the caller is ISR */ { *perr = E_CALL; return 0; } if(OSSchedLock != 0) /* Schedule is lock? */ { *perr = E_OS_IN_LOCK; return 0; /* Yes,error return */ } #if CFG_PAR_CHECKOUT_EN >0 if( (flags&FlagCrl.flagActive) != flags ) { *perr = E_INVALID_PARAMETER; /* Invalid 'flags' */ return 0; } #endif OsSchedLock(); pfcb = &FlagCrl; springFlag = flags & pfcb->flagRdy; /* If any required flags are set */ if((springFlag != 0) && (waitType == OPT_WAIT_ANY)) { pfcb->flagRdy &= ~(springFlag & pfcb->resetOpt); /* Clear the flag */ OsSchedUnlock(); *perr = E_OK; return springFlag; } /* If all required flags are set */ if( (springFlag == flags) && (waitType == OPT_WAIT_ALL) ) { pfcb->flagRdy &= ~(springFlag & pfcb->resetOpt); /* Clear the flags */ OsSchedUnlock(); *perr = E_OK; return springFlag; } curTCB = TCBRunning; if(timeout == 0) /* If time-out is not configured */ { /* Block task until the required flag are set */ FlagBlock(&flagNode,flags,waitType); curTCB->state = TASK_WAITING; TaskSchedReq = TRUE; OsSchedUnlock(); curTCB->pnode = NULL; OsSchedLock(); springFlag = flags & pfcb->flagRdy; pfcb->flagRdy &= ~(springFlag & pfcb->resetOpt);/* Clear the flags */ OsSchedUnlock(); *perr = E_OK; return springFlag; } else /* If time-out is configured */ { /* Block task until the required flag are set or time-out occurred */ FlagBlock(&flagNode,flags,waitType); InsertDelayList(curTCB,timeout); OsSchedUnlock(); if(curTCB->pnode == NULL) /* If time-out occurred */ { *perr = E_TIMEOUT; return 0; } else /* If the required flags are set */ { curTCB->pnode = NULL; OsSchedLock(); springFlag = flags & FlagCrl.flagRdy; /* Clear the required ready flags or not */ pfcb->flagRdy &= ~(springFlag & pfcb->resetOpt); OsSchedUnlock(); *perr = E_OK; return springFlag; } } } /** ******************************************************************************* * @brief Clear a Flag * @param[in] id Flag ID. * @param[out] None * @retval E_OK Event deleted successful. * @retval E_INVALID_ID Invalid event ID. * * @par Description * @details This function is called to clear a flag. * * @note ******************************************************************************* */ StatusType CoClearFlag(OS_FlagID id) { P_FCB pfcb; pfcb = &FlagCrl; #if CFG_PAR_CHECKOUT_EN >0 if(id >= FLAG_MAX_NUM) { return E_INVALID_ID; /* Invalid id */ } if((pfcb->flagActive&(1<flagRdy &= ~(1<0 if(id >= FLAG_MAX_NUM) /* Flag is valid or not */ { return E_INVALID_ID; /* Invalid flag id */ } if((pfcb->flagActive&(1<flagRdy&(1<flagRdy |= (1<headNode; while(pnode != NULL) { if(pnode->waitType == OPT_WAIT_ALL) /* Extract all the bits we want */ { if((pnode->waitFlags&pfcb->flagRdy) == pnode->waitFlags) { /* Remove the flag node from the wait list */ pnode = RemoveFromLink(pnode); if((pfcb->resetOpt&(1<waitFlags & pfcb->flagRdy) != 0) { /* Remove the flag node from the wait list */ pnode = RemoveFromLink(pnode); if((pfcb->resetOpt&(1<nextNode; } OsSchedUnlock(); return E_OK; } /** ******************************************************************************* * @brief Set a flag in ISR * @param[in] id Flag ID. * @param[out] None * @retval E_INVALID_ID Invalid event ID. * @retval E_OK Event deleted successful. * * @par Description * @details This function is called in ISR to set a flag. * @note ******************************************************************************* */ #if CFG_MAX_SERVICE_REQUEST > 0 StatusType isr_SetFlag(OS_FlagID id) { if(OSSchedLock > 0) /* If scheduler is locked,(the caller is ISR) */ { /* Insert the request into service request queue */ if(InsertInSRQ(FLAG_REQ,id,NULL) == FALSE) { return E_SEV_REQ_FULL; /* The service requst queue is full */ } else { return E_OK; } } else { return(CoSetFlag(id)); /* The caller is not ISR, set the flag*/ } } #endif /** ******************************************************************************* * @brief Block a task to wait a flag event * @param[in] pnode A node that will link into flag waiting list. * @param[in] flags Flag(s) that the node waiting for. * @param[in] waitType Waiting type of the node. * @param[out] None * @retval None * * @par Description * @details This function is called to block a task to wait a flag event. * @note ******************************************************************************* */ static void FlagBlock(P_FLAG_NODE pnode,U32 flags,U8 waitType) { P_FCB pfcb; pfcb = &FlagCrl; TCBRunning->pnode = pnode; pnode->waitTask = TCBRunning; pnode->waitFlags = flags; /* Save the flags that we need to wait for*/ pnode->waitType = waitType; /* Save the type of wait */ if(pfcb->tailNode == NULL) /* If this is the first NODE to insert? */ { pnode->nextNode = NULL; pnode->prevNode = NULL; pfcb->headNode = pnode; /* Insert the NODE to the head */ } else /* If it is not the first NODE to insert? */ { pfcb->tailNode->nextNode = pnode; /* Insert the NODE to the tail */ pnode->prevNode = pfcb->tailNode; pnode->nextNode = NULL; } pfcb->tailNode = pnode; } /** ******************************************************************************* * @brief Remove a flag node from list * @param[in] pnode A node that will remove from flag waiting list. * @param[out] None * @retval pnode Next node of the node that have removed out. * * @par Description * @details This function is called to remove a flag node from the wait list. * @note ******************************************************************************* */ static P_FLAG_NODE RemoveFromLink(P_FLAG_NODE pnode) { P_OSTCB ptcb; RemoveLinkNode(pnode); /* Remove the flag node from wait list. */ ptcb = pnode->waitTask; /* The task in the delay list */ if(ptcb->delayTick != INVALID_VALUE)/* If the task is in tick delay list */ { RemoveDelayList(ptcb); /* Remove the task from tick delay list */ } ptcb->pnode = (void*)0xffffffff; if(ptcb == TCBRunning) { ptcb->state = TASK_RUNNING; } else { InsertToTCBRdyList(ptcb); /* Insert the task to ready list */ } return (pnode->nextNode); } /** ******************************************************************************* * @brief Remove a flag node from list * @param[in] pnode A node that will remove from flag waiting list. * @param[out] None * @retval None * * @par Description * @details This function is called to remove a flag node from the wait list. * @note ******************************************************************************* */ void RemoveLinkNode(P_FLAG_NODE pnode) { /* If only one NODE in the list*/ if((pnode->nextNode == NULL) && (pnode->prevNode == NULL)) { FlagCrl.headNode = NULL; FlagCrl.tailNode = NULL; } else if(pnode->nextNode == NULL) /* If the NODE is tail */ { FlagCrl.tailNode = pnode->prevNode; pnode->prevNode->nextNode = NULL; } else if(pnode->prevNode == NULL) /* If the NODE is head */ { FlagCrl.headNode = pnode->nextNode; pnode->nextNode->prevNode = NULL; } else /* The NODE is in the middle */ { pnode->nextNode->prevNode = pnode->prevNode; pnode->prevNode->nextNode = pnode->nextNode; } pnode->waitTask->pnode = NULL; } #endif