/*** BeginHeader */
#ifndef __MCOS_TIME_C
#define __MCOS_TIME_C
/*** EndHeader */


/*
*********************************************************************************************************
*                                                uC/OS-II
*                                          The Real-Time Kernel
*                                             TIME MANAGEMENT
*
*                          (c) Copyright 1992-2001, Jean J. Labrosse, Weston, FL
*                                           All Rights Reserved
*
* File : OS_TIME.C
* By   : Jean J. Labrosse
*********************************************************************************************************
*/

/*** BeginHeader OSTimeDly, OSTimeDlySec, OSTimeDlyHMSM, OSTimeDlyResume, OSTimeGet, OSTimeSet */
void  OSTimeDly (INT16U ticks);
INT8U OSTimeDlySec (INT16U seconds);

#if OS_TIME_DLY_HMSM_EN > 0
INT8U  OSTimeDlyHMSM (INT8U hours, INT8U minutes, INT8U seconds, INT16U milli);
#endif	

#if OS_TIME_DLY_RESUME_EN > 0
INT8U  OSTimeDlyResume (INT8U prio);
#endif	

#if OS_TIME_GET_SET_EN > 0
INT32U OSTimeGet (void);
#endif	

#if OS_TIME_GET_SET_EN > 0
void OSTimeSet (INT32U ticks);
#endif	
/*** EndHeader */

/*
*********************************************************************************************************
*                                DELAY TASK 'n' TICKS   (n from 0 to 65535)
*********************************************************************************************************
*/

/* START FUNCTION DESCRIPTION ********************************************
OSTimeDly                                                   <UCOS.LIB>

SYNTAX:       	void  OSTimeDly (INT16U ticks);

DESCRIPTION:   This function is called to delay execution of the currently
               running task until the specified number of system ticks
               expires. This, of course, directly equates to delaying the
               current task for some time to expire.  No delay will result
               If the specified delay is 0.  If the specified delay is
               greater than 0 then, a context switch will result.

PARAMETER1:    The time delay that the task will be suspended in number of
               clock 'ticks'.  Note that by specifying 0, the task will not
               be delayed.

RETURN VALUE:  None.

END DESCRIPTION **********************************************************/

nodebug
void  OSTimeDly (INT16U ticks)
{
#if OS_CRITICAL_METHOD == 3                      /* Allocate storage for CPU status register           */
    auto OS_CPU_SR  cpu_sr;
#endif    


    if (ticks > 0) {                                                      /* 0 means no delay!         */
        OS_ENTER_CRITICAL();
        if ((OSRdyTbl[OSTCBCur->OSTCBY] &= ~OSTCBCur->OSTCBBitX) == 0) {  /* Delay current task        */
            OSRdyGrp &= ~OSTCBCur->OSTCBBitY;
        }
        OSTCBCur->OSTCBDly = ticks;                                       /* Load ticks in TCB         */
        OS_EXIT_CRITICAL();
        OS_Sched();                                                       /* Find next task to run!    */
    }
}

/*
*********************************************************************************************************
*                                DELAY TASK 'n' SECONDS   (n from 0 to 32768)
*********************************************************************************************************
*/

/* START FUNCTION DESCRIPTION ********************************************
OSTimeDlySec                                                <UCOS.LIB>

SYNTAX:        INT8U OSTimeDlySec (INT16U seconds);

DESCRIPTION:	This function is called to delay execution of the currently 
               running task until seconds expires.  This is a low overhead
               version of OSTimeDlyHMSM for seconds only

PARAMETER1:    Specifies the number of seconds (max. 32768)

RETURN VALUE:  OS_NO_ERR
               OS_TIME_ZERO_DLY
              
END DESCRIPTION **********************************************************/

nodebug INT8U OSTimeDlySec (INT16U seconds)
{
    if(seconds )
        OSTimeDly(seconds * OS_TICKS_PER_SEC);
    else 
        return (OS_TIME_ZERO_DLY);
    return (OS_NO_ERR);
}

/*
*********************************************************************************************************
*                                     DELAY TASK FOR SPECIFIED TIME
*********************************************************************************************************
*/

/* START FUNCTION DESCRIPTION ********************************************
OSTimeDlyHMSM                                                 <UCOS.LIB>

SYNTAX:       	INT8U  OSTimeDlyHMSM (INT8U hours, INT8U minutes,
                                     INT8U seconds, INT16U milli)

DESCRIPTION:   This function is called to delay execution of the currently
               running task until some time expires.  This call allows you
               to specify the delay time in HOURS, MINUTES, SECONDS and
               MILLISECONDS instead of ticks. Note that the resolution on
               the milliseconds depends on the tick rate.  For example, you
               can't do a 10 mS delay if the ticker interrupts every 100
               mS.  In this case, the delay would be set to 0.  The actual
               delay is rounded to the nearest tick.

PARAMETER1:    hours     specifies the number of hours that the task will
                         be delayed (max. is 255)
PARAMETER2:    minutes   specifies the number of minutes (max. 59)

PARAMETER3:    seconds   specifies the number of seconds (max. 59)

PARAMETER4:    milli     specifies the number of milliseconds (max. 999) 

RETURN VALUE:  OS_NO_ERR
               OS_TIME_INVALID_MINUTES
               OS_TIME_INVALID_SECONDS
               OS_TIME_INVALID_MS
               OS_TIME_ZERO_DLY

END DESCRIPTION **********************************************************/

#if OS_TIME_DLY_HMSM_EN > 0
nodebug
INT8U  OSTimeDlyHMSM (INT8U hours, INT8U minutes, INT8U seconds, INT16U milli)
{
    auto INT32U ticks;
    auto INT16U loops;


    if (hours > 0 || minutes > 0 || seconds > 0 || milli > 0) {
        if (minutes > 59) {
            return (OS_TIME_INVALID_MINUTES);    /* Validate arguments to be within range              */
        }
        if (seconds > 59) {
            return (OS_TIME_INVALID_SECONDS);
        }
        if (milli > 999) {
            return (OS_TIME_INVALID_MILLI);
        }
                                                 /* Compute the total number of clock ticks required.. */
                                                 /* .. (rounded to the nearest tick)                   */
        ticks = ((INT32U)hours * 3600L + (INT32U)minutes * 60L + (INT32U)seconds) * OS_TICKS_PER_SEC
              + OS_TICKS_PER_SEC * ((INT32U)milli + 500L / OS_TICKS_PER_SEC) / 1000L;
        loops = (INT16U)(ticks / 65536L);        /* Compute the integral number of 65536 tick delays   */
        ticks = ticks % 65536L;                  /* Obtain  the fractional number of ticks             */
        OSTimeDly((INT16U)ticks);
        while (loops > 0) {
            OSTimeDly(32768);
            OSTimeDly(32768);
            loops--;
        }
        return (OS_NO_ERR);
    }
    return (OS_TIME_ZERO_DLY);
}
#endif

/*
*********************************************************************************************************
*                                         RESUME A DELAYED TASK
*********************************************************************************************************
*/


/* START FUNCTION DESCRIPTION ********************************************
OSTimeDlyResume                                               <UCOS.LIB>

SYNTAX:       	INT8U  OSTimeDlyResume (INT8U prio);

DESCRIPTION:   This function is used resume a task that has been delayed
               through a call to either OSTimeDly() or OSTimeDlyHMSM().
               Note that you MUST NOT call this function to resume a task
               that is waiting for an event with timeout.  This situation
               would make the task look like a timeout occurred (unless you
               desire this effect).  Also, you cannot resume a task that
               has called OSTimeDlyHMSM() with a combined time that exceeds
               65535 clock ticks.  In other words, if the clock tick runs
               at 100 Hz then, you will not be able to resume a delayed
               task that called OSTimeDlyHMSM(0, 10, 55, 350) or higher.

                  (10 Minutes * 60 + 55 Seconds + 0.35) * 100 ticks/second.


PARAMETER1:    specifies the priority of the task to resume

RETURN VALUE:  OS_NO_ERR                 Task has been resumed
               OS_PRIO_INVALID           if the priority you specify is
                                         higher that the maximum allowed
                                         (i.e. >= OS_LOWEST_PRIO)
               OS_TIME_NOT_DLY           Task is not waiting for time to
                                         expire
               OS_TASK_NOT_EXIST         The desired task has not been
                                         created

END DESCRIPTION **********************************************************/

#if OS_TIME_DLY_RESUME_EN > 0
nodebug
INT8U  OSTimeDlyResume (INT8U prio)
{
#if OS_CRITICAL_METHOD == 3                      /* Allocate storage for CPU status register           */
    auto OS_CPU_SR  cpu_sr;
#endif    
    auto OS_TCB    *ptcb;


    if (prio >= OS_LOWEST_PRIO) {
        return (OS_PRIO_INVALID);
    }
    OS_ENTER_CRITICAL();
    ptcb = (OS_TCB *)OSTCBPrioTbl[prio];                   /* Make sure that task exist                */
    if (ptcb != (OS_TCB *)0) {
        if (ptcb->OSTCBDly != 0) {                         /* See if task is delayed                   */
            ptcb->OSTCBDly  = 0;                           /* Clear the time delay                     */
            if ((ptcb->OSTCBStat & OS_STAT_SUSPEND) == 0x00) {  /* See if task is ready to run         */
                OSRdyGrp               |= ptcb->OSTCBBitY;      /* Make task ready to run              */
                OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
                OS_EXIT_CRITICAL();
                OS_Sched();                                /* See if this is new highest priority      */
            } else {
                OS_EXIT_CRITICAL();                        /* Task may be suspended                    */
            }
            return (OS_NO_ERR);
        } else {
            OS_EXIT_CRITICAL();
            return (OS_TIME_NOT_DLY);                      /* Indicate that task was not delayed       */
        }
    }
    OS_EXIT_CRITICAL();
    return (OS_TASK_NOT_EXIST);                            /* The task does not exist                  */
}
#endif    

/*
*********************************************************************************************************
*                                         GET CURRENT SYSTEM TIME
*********************************************************************************************************
*/

/* START FUNCTION DESCRIPTION ********************************************
OSTimeGet                                                   <UCOS.LIB>

SYNTAX: 			INT32U OSTimeGet ();

DESCRIPTION:	This function is used by an application to obtain the
               current value of the 32-bit counter which keeps track of the
               number of clock ticks.

RETURNS:       The current value of OSTime.
               
END DESCRIPTION **********************************************************/

#if OS_TIME_GET_SET_EN > 0
nodebug
INT32U  OSTimeGet (void)
{
#if OS_CRITICAL_METHOD == 3                      /* Allocate storage for CPU status register           */
    auto OS_CPU_SR  cpu_sr;
#endif    
    auto INT32U     ticks;


    OS_ENTER_CRITICAL();
    ticks = OSTime;
    OS_EXIT_CRITICAL();
    return (ticks);
}
#endif    

/*
*********************************************************************************************************
*                                            SET SYSTEM CLOCK
*********************************************************************************************************
*/

/* START FUNCTION DESCRIPTION ********************************************
OSTimeSet                                                   <UCOS.LIB>

SYNTAX: 			void OSTimeSet (INT32U ticks);

DESCRIPTION:	This function sets the 32-bit counter which keeps track of
               the number of clock ticks.

PARAMETER1:    Specifies the new value that OSTime needs to take.               
                             
END DESCRIPTION **********************************************************/

#if OS_TIME_GET_SET_EN > 0
nodebug
void  OSTimeSet (INT32U ticks)
{
#if OS_CRITICAL_METHOD == 3                      /* Allocate storage for CPU status register           */
    auto OS_CPU_SR  cpu_sr;
#endif    


    OS_ENTER_CRITICAL();
    OSTime = ticks;
    OS_EXIT_CRITICAL();
}
#endif    

/*** BeginHeader */
#endif
/*** EndHeader */