CoOS Demonstrator adapted to mbed Hardware.

Dependencies:   mbed

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>&copy; 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