/**********************************************************************/
/*                                                                    */
/* File name: uip_kernel_event.c                                      */
/*                                                                    */
/* Since:     2007-02-25                                              */
/*                                                                    */
/* Version:   uip Kernel v1.09                                        */
/*            Copyright (C) 2006..2018 Wang Baojin.                   */
/*                                                                    */
/* Author:    Designed by Wang Baojin(王保进)                         */
/*                                                                    */
/*                                                                    */
/* Purpose:   Support uip kernel event management                     */
/*                                                                    */
/* Distribution: This file is part of uip kernel.                     */
/*            uip Kernel is free software, you can redistribute it    */
/*            and/or modify it under the terms of the GNU General     */
/*            Public License as published by the Free Software        */
/*            Foundation either version 2, or (at your option)        */
/*            any later version.                                      */
/*                                                                    */
/*            uip Kernel is distributed in the hope that it will be   */
/*            useful, but WITHOUT ANY WARRANTY without even the       */
/*            implied warranty of MERCHANTABILITY or FITNESS FOR A    */
/*            PuipICULAR PURPOSE.  See the GNU General Public         */
/*            License for more details.                               */
/*                                                                    */
/*            You should have received a copy of the GNU General      */
/*            Public License along with gpsim see the file            */
/*            COPYING.txt. If not, write to the Free Software         */
/*            Foundation, 59 Temple Place - Suite 330,                */
/*            Boston, MA 02111-1307, USA.                             */
/*                                                                    */
/*          > A special exception to the GPL can be applied should    */
/*            you wish to distribute a combined work that includes    */
/*            uip Kernel, without being obliged to provide the        */
/*            source code for any proprietary components.             */
/*                                                                    */
/* History:                                                           */
/*   2007/02/25  [WBJ] Create this file.                              */
/*   2012/05/16  [WBJ] 函数uipSetEvent和uipWaitEvent有修改            */
/*                                                                    */
/**********************************************************************/

#include "uip_kernel_api.h"

/**********************************************************************/ 
/*                                                                    */ 
/*  Function name                                       Version       */ 
/*                                                                    */ 
/*    UIP_SetEvent                                         1.09       */ 
/*                                                                    */ 
/*  Author                                                            */ 
/*                                                                    */ 
/*    Wang Baojin                                                     */ 
/*                                                                    */ 
/*  Description                                                       */ 
/*                                                                    */ 
/*    The events of task <TaskID> are set according to the event      */
/*    mask <Mask>. Calling UIP_SetEvent causes the task <TaskID> to   */
/*    be transferred to the ready state, if it was waiting for at     */
/*    least one of the events specified in <Mask>.                    */ 
/*                                                                    */ 
/*  Note:                                                             */
/*    Any events not set in the event mask remain unchanged.          */ 
/*                                                                    */ 
/*  Parameter(In)                                                     */ 
/*                                                                    */ 
/*    TaskID                       Reference to the task for which    */
/*                                 one or several events are to be    */
/*                                 set.                               */
/*    Mask                         Mask of the events to be set       */ 
/*                                                                    */ 
/*  Parameter(Out)                                                    */ 
/*                                                                    */ 
/*    None                                                            */ 
/*                                                                    */ 
/*  Return Status                                                     */ 
/*                                                                    */ 
/*    E_OK                        No error                            */ 
/*    E_OS_ID                     Task <TaskID> is invalid            */
/*    E_OS_ACCESS                 Referenced task is not extended task*/ 
/*    E_OS_STATE                  Events can not be set as the        */
/*                                referenced task is in the suspended */
/*                                state,                              */ 
/*  Call functions                                                    */ 
/*                                                                    */ 
/*    None                                                            */ 
/*                                                                    */ 
/*  Called by                                                         */ 
/*                                                                    */ 
/*    ISR, Non preemptable task, Preemptable task                     */ 
/*                                                                    */ 
/*  Conformance:                                                      */
/*                                                                    */ 
/*    ECC1, ECC2                                                      */ 
/*                                                                    */ 
/*  Release                                                           */ 
/*                                                                    */ 
/*  author name         release date              Description         */ 
/*                                                                    */ 
/*  Wang Baojin          2007.02.25            Initial Version 1.0    */ 
/*  Wang Baojin          2012.05.16            增加了对uipWaitEvent   */
/*                                             的复位处理             */ 
/*                                                                    */ 
/**********************************************************************/ 
StatusType UIP_SetEvent(TaskType TaskID, EventMaskType Mask)
{    
    uip_INTERRUPT_STATE_SAVED;
    uipTaskPtr         taskPtr;
    TaskType           taskID;
    UIP_UCHAR          taskPriority;
    
    /* Enter critical area */
    uip_KERNEL_DISABLE_INTS;
    
    /* Check to see if taskId is valid(not larger than 255 and not lesser
       than 0) */
    /* taskId is valid */
    if ((TaskID < uip_TASK_MAX) && (TaskID >= 0))
    {
        /* Get task TCB pointer from task ID */
        taskPtr = (uipTaskPtr)(&uipTCBArray[TaskID]); 

    	/* If it isn't an extended task */
    	if (((taskPtr -> uipTaskState) & uip_TASK_EXTENDED) == 0)
    	{
            /* Leave cirtical area */
            uip_KERNEL_RESTORE_INTS;
            
            /* Return error information */
    	  	return (E_OS_ACCESS);
    	} /* if (((taskPtr -> uipTaskState) & uip_TASK_EXTENDED) == 0) */

        /* If task is in suspend state */
    	if (((taskPtr -> uipTaskState) & uip_TASK_STATE_MASK) == SUSPENDED_STATE)
    	{
            /* Leave cirtical area */
            uip_KERNEL_RESTORE_INTS;
            
            /* Return error information */
    	  	return (E_OS_STATE);
    	} /* if ((taskPtr -> uipTaskState) == SUSPENDED_STATE) */
			
        taskPtr -> UIP_SetEvent |= (EventMaskType)(Mask);
				
        /* If task is in waiting state */
        if (((taskPtr -> uipTaskState) & uip_TASK_STATE_MASK) == WAITING_STATE)
        {
            /* If any event occure */
            if (((taskPtr -> UIP_WaitEvent) & (taskPtr -> UIP_SetEvent)) != 0 )    
            {
                /* reset task's waiting mask to 0 */
                taskPtr -> UIP_WaitEvent = (EventMaskType)uip_MASK_NONE;

				/* Task's status is ready */
                taskPtr -> uipTaskState &= uip_TASK_EXTENDED;
                taskPtr -> uipTaskState |= READY_STATE;

                /* Update ready tasks' array and global variable */
                /* Set ready task's index bit in uipPrioGroup */
                uipPrioGroup |= (taskPtr -> uipRdyPrioGrpBit);
    
                /* Set the ready task's corresponding bit in uipPrioGrpArray[] */
                uipPrioGrpArray[taskPtr -> uipRdyPrioGrpArrayIndex] |= taskPtr -> uipRdyPrioGrpArrayBit;
    
                if ((uipNestedInterrupts == 0) && (uipSchedulerLock == 0))
                {
                    /* Calculate group index value of the highest priority task 
                       in ready tasks table */             
                    taskPriority = uipGetNextPriority(); 

                    /* If taskPriority higher than current running task's dispatch priority */
                    if (taskPriority < uipCurrentTaskPriority)
                    {
                        /* Set current task into ready state */
                        uipCurrentTaskTCBPtr -> uipTaskState &= uip_TASK_EXTENDED;
                        uipCurrentTaskTCBPtr -> uipTaskState |= READY_STATE;

                        /* Get task ID from priority of task */
                        taskID = uipPriorityToTaskID[taskPriority];

                        /* Get task TCB pointer from task ID */
                        uipNextRunningTaskTCBPtr = (uipTaskPtr)(&uipTCBArray[taskID]); 

                        /* Set next running task's priority variable */
                        uipNextRunningTaskPriority = taskPriority;
                
                        /* Need preemption, transfer control to system scheduler, need saving context*/                       
                        uipEnterScheduler();
                        
                    } /* end of if(taskPriority < (taskCurrentPtr -> uipReadyPrio)) */   
                }      
            } /* if ((taskPtr -> UIP_WaitEvent & taskPtr->UIP_SetEvent) != 0 ) */
        } /* end of if ((TaskID < uip_TASK_MAX) && (TaskID >= 0)) */
    
        /* Leave cirtical area */
        uip_KERNEL_RESTORE_INTS;
        
        /* There are some errors */
        return (E_OK);
    } /* if ((TaskID < uip_TASK_MAX) && (TaskID >= 0)) */

    /* Leave cirtical area */
    uip_KERNEL_RESTORE_INTS;
    /* There are some errors */
    return (E_OS_ID);
}

/**********************************************************************/ 
/*                                                                    */ 
/*  Function name                                       Version       */ 
/*                                                                    */ 
/*    UIP_ClearEvent                                       1.09       */ 
/*                                                                    */ 
/*  Author                                                            */ 
/*                                                                    */ 
/*    Wang Baojin                                                     */ 
/*                                                                    */ 
/*  Description                                                       */ 
/*                                                                    */ 
/*    The events of the extended task calling UIP_ClearEvent are      */
/*    cleared according to the event mask <Mask>.                     */ 
/*                                                                    */ 
/*  Note:                                                             */
/*                                                                    */ 
/*    The system service UIP_ClearEvent is restricted to extended     */
/*    tasks which own the event.                                      */ 
/*                                                                    */ 
/*  Parameter(In)                                                     */ 
/*                                                                    */ 
/*    Mask                        Mask of the events to be cleared    */ 
/*                                                                    */ 
/*  Parameter(Out)                                                    */ 
/*                                                                    */ 
/*    None                                                            */ 
/*                                                                    */ 
/*  Return Status                                                     */ 
/*                                                                    */ 
/*    E_OK                        No error                            */ 
/*    E_OS_ACCESS                 Call not from extended task.        */ 
/*    E_OS_CALLEVEL               Call at interrupt level.            */ 
/*                                                                    */ 
/*  Call functions                                                    */ 
/*                                                                    */ 
/*    None                                                            */ 
/*                                                                    */ 
/*  Called by                                                         */ 
/*                                                                    */ 
/*    Non preemptable task, Preemptable task                          */ 
/*                                                                    */ 
/*  Conformance:                                                      */
/*                                                                    */ 
/*    ECC1, ECC2                                                      */ 
/*                                                                    */ 
/*  Release                                                           */ 
/*                                                                    */ 
/*  author name         release date              Description         */ 
/*                                                                    */ 
/*  Wang Baojin          2007.02.25            Initial Version 1.0    */ 
/*                                                                    */ 
/**********************************************************************/ 
StatusType UIP_ClearEvent(EventMaskType Mask)
{   
    uip_INTERRUPT_STATE_SAVED;
    uipTaskPtr         taskCurrentPtr;
    
    /* There are some nested interrupts */
    if (uipNestedInterrupts != 0)
    {
        /* Return error information */
	  	return (E_OS_CALLEVEL);
    }

    /* Scheduler is locked */
    if (uipSchedulerLock != 0)
    {
        /* Return error information */
	  	return (uip_SCHEDULER_LOCKED);
    }	

    /* Enter critical area */
    uip_KERNEL_DISABLE_INTS;

    taskCurrentPtr = uipCurrentTaskTCBPtr; 

	/* If it isn't an extended task */
	if (((taskCurrentPtr -> uipTaskState) & uip_TASK_EXTENDED) == 0)
	{
        /* Leave cirtical area */
        uip_KERNEL_RESTORE_INTS;
        
        /* Return error information */
	  	return (E_OS_ACCESS);
	} /* if (((taskCurrentPtr -> uipTaskState) & uip_TASK_EXTENDED) == 0) */

    /* Clear events according to the event mask <Mask> */
    taskCurrentPtr -> UIP_SetEvent &= (EventMaskType)(~Mask);

    /* Leave cirtical area */
    uip_KERNEL_RESTORE_INTS;

    return (E_OK);
}

/**********************************************************************/ 
/*                                                                    */ 
/*  Function name                                       Version       */ 
/*                                                                    */ 
/*    UIP_GetEvent                                         1.09       */ 
/*                                                                    */ 
/*  Author                                                            */ 
/*                                                                    */ 
/*    Wang Baojin                                                     */ 
/*                                                                    */ 
/*  Description                                                       */ 
/*                                                                    */ 
/*    This service returns the current state of all event bits of     */
/*    the task <TaskID>, not the events that the task is waiting for  */
/*    The current status of the event mask of task <TaskID> is copied */
/*    to <Event>                                                      */ 
/*                                                                    */ 
/*  Note:                                                             */
/*                                                                    */ 
/*    The referenced task shall be an extended task                   */ 
/*                                                                    */ 
/*  Parameter(In)                                                     */ 
/*                                                                    */ 
/*    TaskID                      Task whose event mask is to be      */
/*                                returned                            */ 
/*                                                                    */ 
/*  Parameter(Out)                                                    */ 
/*                                                                    */ 
/*    Event                       Reference to the memory of the      */
/*                                return data                         */ 
/*                                                                    */ 
/*  Return Status                                                     */ 
/*                                                                    */ 
/*    E_OK                        No error                            */ 
/*    E_OS_ID                     Task <TaskID> is invalid            */
/*    E_OS_ACCESS                 Call not from extended task         */ 
/*    E_OS_STATE                  Referenced task <TaskID> is in the  */
/*                                suspended state                     */ 
/*                                                                    */ 
/*  Call functions                                                    */ 
/*                                                                    */ 
/*    None                                                            */ 
/*                                                                    */ 
/*  Called by                                                         */ 
/*                                                                    */ 
/*    ISR, Non preemptable task, Preemptable task                     */ 
/*                                                                    */ 
/*  Conformance:                                                      */
/*                                                                    */ 
/*    ECC1, ECC2                                                      */ 
/*                                                                    */ 
/*  Release                                                           */ 
/*                                                                    */ 
/*  author name         release date              Description         */ 
/*                                                                    */ 
/*  Wang Baojin          2007.02.25            Initial Version 1.0    */ 
/*                                                                    */ 
/**********************************************************************/ 
StatusType UIP_GetEvent(TaskType TaskID, EventMaskRefType Mask)
{
    uip_INTERRUPT_STATE_SAVED;
    uipTaskPtr         taskPtr;
    
    /* Scheduler is locked */
    if (uipSchedulerLock != 0)
    {
        /* Return error information */
	  	return (uip_SCHEDULER_LOCKED);
    }	

    /* Enter critical area */
    uip_KERNEL_DISABLE_INTS;
    
    /* Check to see if taskId is valid(not larger than 255 and not lesser
       than 0) */
    /* taskId is valid */
    if ((TaskID < uip_TASK_MAX) && (TaskID >= 0))
    {
        /* Get task TCB pointer from task ID */
        taskPtr = (uipTaskPtr)(&uipTCBArray[TaskID]); 

    	/* If task is in suspend state */
    	if (((taskPtr -> uipTaskState) & uip_TASK_STATE_MASK) == SUSPENDED_STATE)
    	{
            /* Leave cirtical area */
            uip_KERNEL_RESTORE_INTS;
            
            /* Return error information */
    	  	return (E_OS_STATE);
    	} /* if ((taskPtr -> uipTaskState) == SUSPENDED_STATE) */
    	  
    	/* If it isn't an extended task */
    	if (((taskPtr -> uipTaskState) & uip_TASK_EXTENDED) == 0)
    	{
            /* Leave cirtical area */
            uip_KERNEL_RESTORE_INTS;
            
            /* Return error information */
    	  	return (E_OS_ACCESS);
    	} /* if (((taskPtr -> uipTaskState) & uip_TASK_EXTENDED) == 0) */

        /* Return task's UIP_SetEvent */
        *Mask = taskPtr -> UIP_SetEvent;
        
        /* Leave cirtical area */
        uip_KERNEL_RESTORE_INTS;
        
        /* There are some errors */
        return (E_OK);

    } /* if ((TaskID < uip_TASK_MAX) && (TaskID >= 0)) */

    /* Leave cirtical area */
    uip_KERNEL_RESTORE_INTS;
    
    /* There are some errors */
    return (E_OS_ID);
}

/**********************************************************************/ 
/*                                                                    */ 
/*  Function name                                       Version       */ 
/*                                                                    */ 
/*    UIP_WaitEvent                                        1.09       */ 
/*                                                                    */ 
/*  Author                                                            */ 
/*                                                                    */ 
/*    Wang Baojin                                                     */ 
/*                                                                    */ 
/*  Description                                                       */ 
/*                                                                    */ 
/*    The state of the calling task is set to waiting, unless at      */
/*    least one of the events specified in <Mask> has already been    */
/*    set.                                                            */ 
/*                                                                    */ 
/*  Note:                                                             */
/*                                                                    */ 
/*    The system service UIP_ClearEvent is restricted to extended     */
/*    tasks which own the event.                                      */ 
/*                                                                    */ 
/*  Parameter(In)                                                     */ 
/*                                                                    */ 
/*    Mask                        Mask of the events waited for       */ 
/*                                                                    */ 
/*  Parameter(Out)                                                    */ 
/*                                                                    */ 
/*    None                                                            */ 
/*                                                                    */ 
/*  Return Status                                                     */ 
/*                                                                    */ 
/*    E_OK                        No error                            */ 
/*    E_OS_ACCESS                 Call not from extended task.        */ 
/*    E_OS_CALLEVEL               Call at interrupt level.            */ 
/*                                                                    */ 
/*  Call functions                                                    */ 
/*                                                                    */ 
/*    uipClearPrioGrpAndArrayBit                                      */ 
/*                                                                    */ 
/*  Called by                                                         */ 
/*                                                                    */ 
/*    Non preemptable task, Preemptable task                          */ 
/*                                                                    */ 
/*  Conformance:                                                      */
/*                                                                    */ 
/*    ECC1, ECC2                                                      */ 
/*                                                                    */ 
/*  Release                                                           */ 
/*                                                                    */ 
/*  author name         release date              Description         */ 
/*                                                                    */ 
/*  Wang Baojin          2007.02.25            Initial Version 1.0    */ 
/*                                                                    */ 
/*                       2012.05.16            有未处理的修改建议     */ 
/*                       2012.05.16            代码位置有移动:		  */
/*        taskCurrentPtr -> UIP_WaitEvent = (EventMaskType)Mask; 移入：*/
/*		  if (((taskCurrentPtr -> UIP_SetEvent) & Mask) == 0)  以内    */ 
/**********************************************************************/
StatusType UIP_WaitEvent(EventMaskType Mask)
{    
    uip_INTERRUPT_STATE_SAVED;
    uipTaskPtr         taskCurrentPtr;
    
    /* There are some nested interrupts */
    if (uipNestedInterrupts != 0)
    {
        /* Return error information */
	  	return (E_OS_CALLEVEL);
    }

    /* Scheduler is locked */
    if (uipSchedulerLock != 0)
    {
        /* Return error information */
	  	return (uip_SCHEDULER_LOCKED);
    }

    /* Enter critical area */
    uip_KERNEL_DISABLE_INTS;

    taskCurrentPtr = uipCurrentTaskTCBPtr; 

	/* If it isn't an extended task */
	if (((taskCurrentPtr -> uipTaskState) & uip_TASK_EXTENDED) == 0)
	{
        /* Leave cirtical area */
        uip_KERNEL_RESTORE_INTS;
        
        /* Return error information */
	  	return (E_OS_ACCESS);
	} /* if (((taskCurrentPtr -> uipTaskState) & uip_TASK_EXTENDED) == 0) */

	/* Check to see if there are some resources that has not been released */
    if((taskCurrentPtr -> uipResources) != 0)
	{
        /* Leave cirtical area */
        uip_KERNEL_RESTORE_INTS;
        
        /* Return error information */
	  	return (E_OS_RESOURCE);
	} /* end of if((taskPtr -> uipResources) != 0) */
    
    /* If not any event waited occur, The state of the calling task is set 
       to waiting */
    if (((taskCurrentPtr -> UIP_SetEvent) & Mask) == 0)
    {
		/* Set task's waitevent area */
        taskCurrentPtr -> UIP_WaitEvent = (EventMaskType)Mask;

        /* Set task to suspend state */
        taskCurrentPtr -> uipTaskState &= uip_TASK_EXTENDED;
        taskCurrentPtr -> uipTaskState |= WAITING_STATE; 

        /* Clear the ready task's corresponding bit in uipPrioGrpArray[] */
        uipClearPrioGrpAndArrayBit((uipTaskPtr)taskCurrentPtr); 
        
        /* Determine the highest priority in ready tasks table */
        uipGetNextTask();
        
        /* Need preemption, transfer control to system scheduler*/    
        uipEnterScheduler();
                
		/* 此处未来可加入对是否已设置“感兴趣”事件的判断 */
	    
    } /* if (((taskCurrentPtr -> UIP_SetEvent) & Mask) == 0) */
   
    /* Leave cirtical area */
    uip_KERNEL_RESTORE_INTS;

    return (E_OK);
}

/***************************************************************************************/
/*                          End of File : uip_kernel_event.c                           */
/***************************************************************************************/
