Eric Ebert
/
CoOS
CoOS Demonstrator adapted to mbed Hardware.
Diff: flag.c
- Revision:
- 0:57690853989a
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flag.c Fri Dec 03 19:45:30 2010 +0000 @@ -0,0 +1,712 @@ +/** + ******************************************************************************* + * @file flag.c + * @version V1.1.3 + * @date 2010.04.26 + * @brief Flag management implementation code of coocox CoOS kernel. + ******************************************************************************* + * @copy + * + * INTERNAL FILE,DON'T PUBLIC. + * + * <h2><center>© COPYRIGHT 2009 CooCox </center></h2> + ******************************************************************************* + */ + + + +/*---------------------------- Include ---------------------------------------*/ +#include <coocox.h> + +#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<FLAG_MAX_NUM;i++) + { + /* Assign a free flag control block */ + if((FlagCrl.flagActive&(1<<i)) == 0 ) + { + FlagCrl.flagActive |= (1<<i); /* Initialize active flag */ + FlagCrl.flagRdy |= (bInitialState<<i);/* Initialize ready flag */ + FlagCrl.resetOpt |= (bAutoReset<<i);/* Initialize reset option */ + OsSchedUnlock(); + return i ; /* Return Flag ID */ + } + } + OsSchedUnlock(); + + return E_CREATE_FAIL; /* There is no free flag control block*/ +} + + +/** + ******************************************************************************* + * @brief Delete a flag + * @param[in] id Flag ID. + * @param[in] opt Delete option. + * @param[out] None + * @retval E_CALL Error call in ISR. + * @retval E_INVALID_ID Invalid event ID. + * @retval E_TASK_WAITTING Tasks waitting for the event,delete fail. + * @retval E_OK Event deleted successful. + * + * @par Description + * @details This function is called to delete a event flag. + * @note + ******************************************************************************* + */ +StatusType CoDelFlag(OS_FlagID id,U8 opt) +{ + P_FLAG_NODE pnode; + P_FCB pfcb; + pfcb = &FlagCrl; + if(OSIntNesting > 0) /* If be called from ISR */ + { + return E_CALL; + } +#if CFG_PAR_CHECKOUT_EN >0 + if((pfcb->flagActive&(1<<id)) == 0) /* Flag is valid or not */ + { + return E_INVALID_ID; + } +#endif + OsSchedLock(); + pnode = pfcb->headNode; + + while(pnode != 0) /* Ready all tasks waiting for flags */ + { + if((pnode->waitFlags&(1<<id)) != 0) /* If no task is waiting on flags */ + { + if(opt == OPT_DEL_NO_PEND) /* Delete flag if no task waiting */ + { + OsSchedUnlock(); + return E_TASK_WAITING; + } + else if (opt == OPT_DEL_ANYWAY) /* Always delete the flag */ + { + if(pnode->waitType == OPT_WAIT_ALL) + { + /* If the flag is only required by NODE */ + if( pnode->waitFlags == (1<<id) ) + { + /* Remove the NODE from waiting list */ + pnode = RemoveFromLink(pnode); + continue; + } + else + { + pnode->waitFlags &= ~(1<<id); /* Update waitflags */ + } + } + else + { + pnode = RemoveFromLink(pnode); + continue; + } + } + } + pnode = pnode->nextNode; + } + + /* Remove the flag from the flags list */ + pfcb->flagActive &= ~(1<<id); + pfcb->flagRdy &= ~(1<<id); + pfcb->resetOpt &= ~(1<<id); + OsSchedUnlock(); + return E_OK; +} + + +/** + ******************************************************************************* + * @brief AcceptSingleFlag + * @param[in] id Flag ID. + * @param[out] None + * @retval E_INVALID_ID Invalid event ID. + * @retval E_FLAG_NOT_READY Flag is not in ready state. + * @retval E_OK The call was successful and your task owns the Flag. + * + * @par Description + * @details This fucntion is called to accept single flag + * @note + ******************************************************************************* + */ +StatusType CoAcceptSingleFlag(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',return error */ + } + if((pfcb->flagActive&(1<<id)) == 0) + { + return E_INVALID_ID; /* Flag is deactive,return error */ + } +#endif + if((pfcb->flagRdy&(1<<id)) != 0) /* If the required flag is set */ + { + OsSchedLock() + pfcb->flagRdy &= ~((FlagCrl.resetOpt)&(1<<id)); /* Clear the flag */ + OsSchedUnlock(); + return E_OK; + } + else /* If the required flag is not set */ + { + return E_FLAG_NOT_READY; + } +} + + +/** + ******************************************************************************* + * @brief AcceptMultipleFlags + * @param[in] flags Flags that waiting to active task. + * @param[in] waitType Flags wait type. + * @param[out] perr A pointer to error code. + * @retval 0 + * @retval springFlag + * + * @par Description + * @details This fucntion is called to accept multiple flags. + * @note + ******************************************************************************* + */ +U32 CoAcceptMultipleFlags(U32 flags,U8 waitType,StatusType *perr) +{ + U32 springFlag; + P_FCB pfcb; + pfcb = &FlagCrl; + +#if CFG_PAR_CHECKOUT_EN >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<<id)) == 0 )/* Judge flag is active or not? */ + { + return E_INVALID_ID; /* Flag is deactive ,return error */ + } +#endif + + OsSchedLock(); + pfcb = &FlagCrl; + /* See if the required flag is set */ + if((pfcb->flagRdy&(1<<id)) != 0) /* If the required flag is set */ + { + pfcb->flagRdy &= ~((pfcb->resetOpt&(1<<id))); /* Clear the flag */ + OsSchedUnlock(); + } + else /* If the required flag is not set */ + { + curTCB = TCBRunning; + if(timeout == 0) /* If time-out is not configured */ + { + /* Block task until the required flag is set */ + FlagBlock (&flagNode,(1<<id),OPT_WAIT_ONE); + curTCB->state = TASK_WAITING; + TaskSchedReq = TRUE; + OsSchedUnlock(); + + /* The required flag is set and the task is in running state */ + curTCB->pnode = 0; + OsSchedLock(); + + /* Clear the required flag or not */ + pfcb->flagRdy &= ~((1<<id)&(pfcb->resetOpt)); + OsSchedUnlock(); + } + else /* If time-out is configured */ + { + /* Block task until the required flag is set or time-out occurs */ + FlagBlock(&flagNode,(1<<id),OPT_WAIT_ONE); + InsertDelayList(curTCB,timeout); + + OsSchedUnlock(); + if(curTCB->pnode == 0) /* If time-out occurred */ + { + return E_TIMEOUT; + } + else /* If flag is set */ + { + curTCB->pnode = 0; + OsSchedLock(); + + /* Clear the required flag or not */ + pfcb->flagRdy &= ~((1<<id)&(pfcb->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 = 0; + 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 == 0) /* If time-out occurred */ + { + *perr = E_TIMEOUT; + return 0; + } + else /* If the required flags are set */ + { + curTCB->pnode = 0; + 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<<id)) == 0) + { + return E_INVALID_ID; /* Invalid flag */ + } +#endif + + pfcb->flagRdy &= ~(1<<id); /* Clear the flag */ + return E_OK; +} + + +/** + ******************************************************************************* + * @brief Set a flag + * @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 to set a flag. + * @note + ******************************************************************************* + */ +StatusType CoSetFlag(OS_FlagID id) +{ + P_FLAG_NODE pnode; + P_FCB pfcb; + pfcb = &FlagCrl; + +#if CFG_PAR_CHECKOUT_EN >0 + if(id >= FLAG_MAX_NUM) /* Flag is valid or not */ + { + return E_INVALID_ID; /* Invalid flag id */ + } + if((pfcb->flagActive&(1<<id)) == 0) + { + return E_INVALID_ID; /* Flag is not exist */ + } +#endif + + if((pfcb->flagRdy&(1<<id)) != 0) /* Flag had already been set */ + { + return E_OK; + } + + pfcb->flagRdy |= (1<<id); /* Update the flags ready list */ + + OsSchedLock(); + pnode = pfcb->headNode; + while(pnode != 0) + { + 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<<id)) != 0)/* If the flags is auto-reset*/ + { + break; + } + continue; + } + } + else /* Extract only the bits we want */ + { + if( (pnode->waitFlags & pfcb->flagRdy) != 0) + { + /* Remove the flag node from the wait list */ + pnode = RemoveFromLink(pnode); + if((pfcb->resetOpt&(1<<id)) != 0) + { + break; /* The flags is auto-reset */ + } + continue; + } + } + pnode = pnode->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,0) == 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 == 0) /* If this is the first NODE to insert? */ + { + pnode->nextNode = 0; + pnode->prevNode = 0; + 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 = 0; + } + 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 == 0) && (pnode->prevNode == 0)) + { + FlagCrl.headNode = 0; + FlagCrl.tailNode = 0; + } + else if(pnode->nextNode == 0) /* If the NODE is tail */ + { + FlagCrl.tailNode = pnode->prevNode; + pnode->prevNode->nextNode = 0; + } + else if(pnode->prevNode == 0) /* If the NODE is head */ + { + FlagCrl.headNode = pnode->nextNode; + pnode->nextNode->prevNode = 0; + } + else /* The NODE is in the middle */ + { + pnode->nextNode->prevNode = pnode->prevNode; + pnode->prevNode->nextNode = pnode->nextNode; + } + pnode->waitTask->pnode = 0; +} + +#endif