astroboy astroboy
/
CoOS_LWIP
Quick and dirty CoOS + LWIP ( Webserver )
CoOS/kernel/flag.c
- Committer:
- astroboy
- Date:
- 2011-09-10
- Revision:
- 0:94897d537b31
File content as of revision 0:94897d537b31:
/** ******************************************************************************* * @file flag.c * @version V1.1.4 * @date 2011.04.20 * @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,Co_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 != Co_NULL) /* 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 = Co_TRUE; OsSchedUnlock(); /* The required flag is set and the task is in running state */ curTCB->pnode = Co_NULL; 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 == Co_NULL) /* If time-out occurred */ { return E_TIMEOUT; } else /* If flag is set */ { curTCB->pnode = Co_NULL; 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 = Co_TRUE; OsSchedUnlock(); curTCB->pnode = Co_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 == Co_NULL) /* If time-out occurred */ { *perr = E_TIMEOUT; return 0; } else /* If the required flags are set */ { curTCB->pnode = Co_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<<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 != Co_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<<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,Co_NULL) == Co_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