/**********************************************************************/
/*                                                                    */
/* File name: uip_kernel_resource.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 resources 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.                              */
/*                                                                    */
/**********************************************************************/

#include "uip_kernel_api.h"

/**********************************************************************/ 
/*                                                                    */ 
/*  Function name                                       Version       */ 
/*                                                                    */ 
/*    uipGetResource                                     1.09         */ 
/*                                                                    */ 
/*  Author                                                            */ 
/*                                                                    */ 
/*    Wang Baojin                                                     */ 
/*                                                                    */ 
/*  Description                                                       */ 
/*                                                                    */ 
/*    This call serves to enter critical sections in the code that    */
/*    are assigned to the resource referenced by <ResID>. A critical  */
/*    section shall always be left using uipReleaseResource.          */ 
/*                                                                    */ 
/*  Note:                                                             */
/*    Nested resource occupation is only allowed if the inner         */
/*    critical sections are completely executed within the            */
/*    surrounding critical section.                                   */
/*    Nested occupation of one and the same resource is also          */
/*    forbidden!.                                                     */ 
/*                                                                    */ 
/*    It is recommended that corresponding calls to uipGetResource    */
/*    and uipReleaseResource appear within the same function.         */ 
/*                                                                    */ 
/*    It is not allowed to use services which are points of           */
/*    rescheduling for non preemptable tasks (UIP_TerminateTask,      */
/*    UIP_ChainTask) in critical sections. Additionally, critical     */
/*    sections are to be left before completion of an interrupt       */
/*    service routine.                                                */
/*                                                                    */ 
/*    Generally speaking, critical sections should be short.          */ 
/*                                                                    */ 
/*  Parameter(In)                                                     */ 
/*                                                                    */ 
/*    ResID                       Reference to resource               */ 
/*                                                                    */ 
/*  Parameter(Out)                                                    */ 
/*                                                                    */ 
/*    None                                                            */ 
/*                                                                    */ 
/*  Return Status                                                     */ 
/*                                                                    */ 
/*    E_OS_ID                     Resource <ResID> is invalid         */ 
/*    E_OK                        No error                            */ 
/*    E_OS_ACCESS                 Attempt to get a resource which     */
/*                                is already occupied by any task     */
/*                                or the statically assigned          */
/*                                priority of the calling task or     */
/*                                interrupt routine is higher than    */
/*                                the calculated ceiling priority.    */ 
/*                                                                    */ 
/*  Call functions                                                    */ 
/*                                                                    */ 
/*    None                                                            */ 
/*                                                                    */ 
/*  Called by                                                         */ 
/*                                                                    */ 
/*    ISR, Non preemptable task, Preemptable task                     */ 
/*                                                                    */ 
/*  Conformance:                                                      */
/*                                                                    */ 
/*    BCC1, BCC2, ECC1, ECC2                                          */ 
/*                                                                    */ 
/*  Release                                                           */ 
/*                                                                    */ 
/*  author name         release date              Description         */ 
/*                                                                    */ 
/*  Wang Baojin          2007.02.25            Initial Version 1.0    */ 
/*                                                                    */ 
/**********************************************************************/ 
StatusType UIP_GetResource(ResourceType ResID)
{
    uip_INTERRUPT_STATE_SAVED;    
    uipResPtr          resourcePtr;
    uipTaskPtr         taskCurrentPtr;                                                      
    
    /* There are some nested interrupts */
    if (uipNestedInterrupts != 0)
    {
        /* Return error information */
	  	return (E_OS_CALLEVEL);
    }

    /* Check to see if ResID is valid */
    /* ResID is not valid */
    if (ResID >= uipResNumber)
    {
        /* Return error information */
        return (E_OS_ID);
    }
        
    /* Enter critical area */
    uip_KERNEL_DISABLE_INTS;
    
    /* Get task RCB pointer from resource ID */
    resourcePtr = (uipResPtr)(&uipRCBArray[ResID]);
     
    /* If resource is in use */
    if ((resourcePtr -> uipLock) == 1)
    {
        /* Leave cirtical area */
        uip_KERNEL_RESTORE_INTS;

        /* Return error information */
        return (E_OS_ACCESS);
    }

    taskCurrentPtr = (uipTask *)uipCurrentTaskTCBPtr;    
    
    /* If it is in task level, and current running task's priority is 
       higher than resource's ceiling priority */
    if (uipCurrentTaskPriority < (resourcePtr -> uipCeilingPrio))
    {
        /* Leave cirtical area */
        uip_KERNEL_RESTORE_INTS;

        /* Return error information */
	  	return (E_OS_ACCESS);
    }

    /* Set resource's members */
    resourcePtr -> uipLock = 1;
    resourcePtr -> uipTaskPtr = uipCurrentTaskTCBPtr;             
    resourcePtr -> uipTaskPrio = uipCurrentTaskPriority;             

    resourcePtr -> uipNextRes = taskCurrentPtr -> uipResources;        
    taskCurrentPtr -> uipResources = resourcePtr;

    /* Reset uipPrioGroup and uipPrioGrpArray accord to 
       resource's priority */
    /* Set resource's ceiling priority index bit in uipPrioGroup */
    uipPrioGroup |= (resourcePtr -> uipResCeilingGrpBit);

    /* Set the resource's ceiling priority corresponding bit in uipPrioGrpArray[] */
    uipPrioGrpArray[resourcePtr -> uipResCeilingGrpArrayIndex] |= 
                                                resourcePtr -> uipResCeilingGrpArrayBit;
	  
	/* set corresponding element value in uipPriorityToTaskID[] */
	uipPriorityToTaskID[resourcePtr -> uipCeilingPrio] = taskCurrentPtr->uipTaskID;
	
	uipCurrentTaskPriority = resourcePtr -> uipCeilingPrio;
    
    /* Leave cirtical area */
    uip_KERNEL_RESTORE_INTS;
    
    return (E_OK);
}

/**********************************************************************/ 
/*                                                                    */ 
/*  Function name                                       Version       */ 
/*                                                                    */ 
/*    uipReleaseResource                                  1.09        */ 
/*                                                                    */ 
/*  Author                                                            */ 
/*                                                                    */ 
/*    Wang Baojin                                                     */ 
/*                                                                    */ 
/*  Description                                                       */ 
/*                                                                    */ 
/*    uipReleaseResource is the counterpuip of uipGetResource and     */
/*    serves to leave critical sections in the code that are assigned */
/*    to the resource referenced by <ResID>.                          */ 
/*                                                                    */ 
/*  Note:                                                             */
/*                                                                    */ 
/*  Parameter(In)                                                     */ 
/*                                                                    */ 
/*    ResID                       Reference to resource               */ 
/*                                                                    */ 
/*  Parameter(Out)                                                    */ 
/*                                                                    */ 
/*    None                                                            */ 
/*                                                                    */ 
/*  Return Status                                                     */ 
/*                                                                    */ 
/*    E_OS_ID                     Resource <ResID> is invalid         */ 
/*    E_OK                        No error                            */ 
/*    E_OS_ACCESS                 Attempt to get a resource which     */
/*                                is already occupied by any task     */
/*                                or the statically assigned          */
/*                                priority of the calling task or     */
/*                                interrupt routine is higher than    */
/*                                the calculated ceiling priority.    */ 
/*    E_OS_NOFUNC                 Attempt to release a resource       */
/*                                which is not occupied by any task   */
/*                                or ISR, or another resource shall   */
/*                                be released before.                 */ 
/*                                                                    */ 
/*  Call functions                                                    */ 
/*                                                                    */ 
/*    None                                                            */ 
/*                                                                    */ 
/*  Called by                                                         */ 
/*                                                                    */ 
/*    ISR, Non preemptable task, Preemptable task                     */ 
/*                                                                    */ 
/*  Conformance:                                                      */
/*                                                                    */ 
/*    BCC1, BCC2, ECC1, ECC2                                          */ 
/*                                                                    */ 
/*  Release                                                           */ 
/*                                                                    */ 
/*  author name         release date              Description         */ 
/*                                                                    */ 
/*  Wang Baojin          2007.02.25            Initial Version 1.0    */ 
/*                                                                    */ 
/*  2013.03 去掉 uipNestedInterrupts == 0 的判断，是冗余的            */
/*                                                                    */ 
/**********************************************************************/ 
StatusType UIP_ReleaseResource(ResourceType ResID)
{    
    uip_INTERRUPT_STATE_SAVED;
    uipResPtr          resourcePtr;
    uipTaskPtr         taskCurrentPtr;
    UIP_UCHAR          taskPriority;
    TaskType           taskID;
                                                    
    /* Check to see if taskId is valid */
    /* taskId is not valid */
    if (ResID >= uipResNumber)
    {
        /* Return error information */
        return (E_OS_ID);
    }
        
    /* Enter critical area */
    uip_KERNEL_DISABLE_INTS;
    
    /* Get task RCB pointer from resource ID */
    resourcePtr = (uipResPtr)(&uipRCBArray[ResID]);
    taskCurrentPtr = (uipTask *)uipCurrentTaskTCBPtr;         

    /* If resource is not in use */
    /* Or, if released resource is difference from reource used by current running task  */    
    if (((resourcePtr -> uipLock) == 0) || ((taskCurrentPtr -> uipResources) != resourcePtr))
    {
        /* Leave cirtical area */
        uip_KERNEL_RESTORE_INTS;

        /* Return error information */
        return (E_OS_NOFUNC);
    }

    /* If it is in task level, and current running task's priority is 
       higher than resource's ceiling priority */
    if (uipCurrentTaskPriority < (resourcePtr -> uipCeilingPrio))
    {
        /* Leave cirtical area */
        uip_KERNEL_RESTORE_INTS;

        /* Return error information */
	  	return (E_OS_ACCESS);
    }

    taskCurrentPtr -> uipResources = resourcePtr -> uipNextRes;

	uipCurrentTaskPriority = resourcePtr -> uipTaskPrio;

    /* Set resource's members */
    resourcePtr -> uipLock = 0;
    resourcePtr -> uipTaskPtr = uip_NULL;             
    resourcePtr -> uipTaskPrio = uipMinPriority;             

    /* Reset uipPrioGroup and uipPrioGrpArray accord to 
       resource's priority */
    /* Clear the resource's ceiling priority corresponding bit in uipPrioGrpArray[] */
    uipPrioGrpArray[resourcePtr -> uipResCeilingGrpArrayIndex] &=
                              ~(resourcePtr -> uipResCeilingGrpArrayBit);
    if (uipPrioGrpArray[resourcePtr -> uipResCeilingGrpArrayIndex] == 0x00)
    {
        /* Clear resource's ceiling priority index bit in uipPrioGroup */
        uipPrioGroup &= ~(resourcePtr -> uipResCeilingGrpBit);
    }
    
	/* reset corresponding element in uipPriorityToTaskID[] */
	uipPriorityToTaskID[resourcePtr -> uipCeilingPrio] = uip_NULL;  
    
    /* There are some nested interrupts */
    if (uipNestedInterrupts != 0)
    {
        /* Leave cirtical area */
        uip_KERNEL_RESTORE_INTS

        /* Return error information */
	  	return (E_OS_CALLEVEL);
    }

    /* 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)) */   

    /* Leave cirtical area */
    uip_KERNEL_RESTORE_INTS;
    
    return (E_OK);
}

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