/****************************************************************************/
/* Copyright 1992 to 1996 MBARI                                             */
/****************************************************************************/
/* Summary  : Timer Library for Microcontroller Board                       */
/* Filename : timer.c                                                       */
/* Author   : Andrew Pearce                                                 */
/* Project  : Tiburon Microcontroller Applications                          */
/* Version  : 2.1                                                           */
/* Created  : 02/24/92                                                      */
/* Modified : 02/12/96                                                      */
/* Archived :                                                               */
/****************************************************************************/
/* Modification History:                                                    */
/* $Header: /usr/tiburon/.cvsroot/micro/lib/timer.c,v 1.2 1997/05/07 15:53:05 pean Exp $
 * $Log: timer.c,v $
 * Revision 1.2  1997/05/07 15:53:05  pean
 * Cleaned up Include files and makefile for new directory structure.
 *
 * Revision 1.1.1.1  1997/05/02 17:16:01  pean
 * Initial release of the microcontroller software after Tiburon
 * Moolpool Dive to test IView, Lapboxes, modified Power can
 * GF/5V using bus capacitance mode.
 *
 * Revision 1.1  92/05/14  09:14:33  09:14:33  pean (Andrew Pearce 408-647-3746)
 * Initial revision
 *
*/
/****************************************************************************/
                                        /* Generate code for the 80C196KB   */
#pragma model(196)
#pragma nosignedchar                    /* Use unsigned char (Char)         */

#include "C:/C96/include/80C196.h"      /* 80196 Register mapping           */
#include "C:/C96/include/stddef.h"      /* C Standard Definitions           */
#include "const.h"                      /* Misc. constants - TRUE/FALSE etc */
#include "types.h"                      /* MBARI style guide declarations   */
#include "malloc.h"                     /* Malloc support definitions       */
#include "list.h"                       /* Linked list library routines     */
#include "timer.h"                      /* Timer library definitions        */
#include "microdef.h"                   /* Microcontroller definitions      */
#include "microlib.h"                   /* Microcontroller Board decls      */

MLocal LstHead timerChainHead;          /* Head of timer chain              */

/****************************************************************************/
/* Function    : initTimerChain                                             */
/* Purpose     : Initializes timer chain functions                          */
/* Inputs      : None                                                       */
/* Outputs     : None                                                       */
/****************************************************************************/
    Void
initTimerChain( Void )
{
    list_init(&timerChainHead);         /* Initialize timer chain list      */
} /* initTimerChain() */

/****************************************************************************/
/* Function    : timerCreate                                                */
/* Purpose     : Create a timer resource using timer chain                  */
/* Inputs      : None                                                       */
/* Outputs     : Return timer resource                                      */
/****************************************************************************/
    timerId
timerCreate( Void )
{
    timerId newTimer;                   /* pointer to timer resource        */

                                        /* Allocate space for timer resource*/
    newTimer = (timerId) malloc(sizeof(Timer));
    if (newTimer != (timerId) NULL)     /* If space for timer was allocated */
                                        /* Set timer status to inactive     */
        newTimer->status = TIMER_INACTIVE;

    return (newTimer);                  /* return pointer to timer          */
} /* timerCreate() */

/****************************************************************************/
/* Function    : timerStart                                                 */
/* Purpose     : Start a timer previously created using timerCreate         */
/* Inputs      : Timer resource, delay in 10 msec ticks, function to call   */
/*               when timer expires and parameter passed to function        */
/* Outputs     : None                                                       */
/****************************************************************************/
    Void
timerStart(Reg timerId timer, Nat16 delay, Void (*routinePtr) (), Int16 param)
{
    intDisable;
    if (timer->status == TIMER_ACTIVE)
    {
        list_get(&timerChainHead, (Node *) timer);
        timer->lst_next = NULL;
        timer->lst_prev = NULL;
    } /* if */
    intEnable;

    timer->delay = delay;               /* Fill in timer structure fields   */
    timer->routinePtr = routinePtr;     /* Pointer to routine to call       */
    timer->parameter = param;           /* Parameter to pass to routine     */
    timer->status = TIMER_ACTIVE;       /* Set timer status to active       */
                                        /* Add timer to timer chain list    */
    intDisable;
    list_add( &timerChainHead, (Node *) timer);
    intEnable;
} /* timerStart */

/****************************************************************************/
/* Function    : timerRestart                                               */
/* Purpose     : Restart a timer previously created using timerCreate       */
/* Inputs      : Timer resource, delay in 10 msec ticks                     */
/* Outputs     : None                                                       */
/****************************************************************************/
    Void
timerRestart(Reg timerId timer, Nat16 delay)
{
    intDisable;                         /* Disable Interrupts               */
    timer->delay = delay;               /* Fill in timer structure fields   */

    if (timer->status == TIMER_INACTIVE)
    {
        timer->status = TIMER_ACTIVE;   /* Set timer status to active       */
        list_add( &timerChainHead, (Node *) timer);
    } /* if */
    else
        timer->status = TIMER_ACTIVE;   /* Set timer status to active       */

    intEnable;                          /* Re-enable interrupts             */
} /* timerRestart */

/****************************************************************************/
/* Function    : timerReloadDelay                                           */
/* Purpose     : Reload value in milliseconds                               */
/* Inputs      : Timer resource                                             */
/* Outputs     : None                                                       */
/****************************************************************************/
    Void
timerReloadDelay(Reg timerId timer, Nat16 reloadDelay)
{
    intDisable;
    timer->reloadDelay = reloadDelay;
    intEnable;
} /* timerReloadDelay() */

/****************************************************************************/
/* Function    : timerCancel                                                */
/* Purpose     : Cancel a timer                                             */
/* Inputs      : Timer resource                                             */
/* Outputs     : None                                                       */
/****************************************************************************/
    Void
timerCancel(Reg timerId timer)
{
    intDisable;
    if (timer->status == TIMER_ACTIVE)
    {
        timer->status = TIMER_INACTIVE; /* Set timer status to inactive     */
                                        /* delete timer from timer chain    */

        list_get(&timerChainHead, (Node *) timer);
        timer->lst_next = NULL;
        timer->lst_prev = NULL;
    } /* if */

    intEnable;
} /* timerCancel() */

/****************************************************************************/
/* Function    : timerDelete                                                */
/* Purpose     : Delete a timer - reclaim timer resources                   */
/* Inputs      : Timer resource                                             */
/* Outputs     : None                                                       */
/****************************************************************************/
    Void
timerDelete(Reg timerId timer)
{
    timerCancel(timer);                 /* Cancel timer if timer is active  */
    free((Byte *) timer );              /* Reclaim timer resource space     */
} /* timerDelete() */

/****************************************************************************/
/* Function    : timerEvent                                                 */
/* Purpose     : Timer chain event loop. Called from system ticker          */
/* Inputs      : None                                                       */
/* Outputs     : None                                                       */
/****************************************************************************/
    Void
timerEvent( Void )
{
    Reg Node *tp, *ntp;

    for (tp = timerChainHead.lst_head; tp != NULLNODE; tp = ntp)
    {                                   /* for each timer on list           */
        ntp = tp->lst_next;             /* Save pointer to next timer       */

        if (((Timer *)tp)->status == TIMER_ACTIVE)
        {                               /* If timer is active (running)     */
            if (--(((Timer *)tp)->delay) == 0 )
            {                           /* If timer has expired then        */
                                        /* take timer off timer list        */
                ((Timer *)tp)->status = TIMER_INACTIVE;

                                        /* Set timer status to expired      */
                                        /* Call routine with parameter      */
                if (((Timer *)tp)->routinePtr)
                    ((Timer *)tp)->routinePtr(((Timer *)tp)->parameter);
            } /* if */
        } /* if */
    } /* for */

    for (tp = timerChainHead.lst_head; tp != NULLNODE; tp = ntp)
    {                                   /* for each timer on list           */
        ntp = tp->lst_next;             /* Save pointer to next timer       */

        if (((Timer *)tp)->status == TIMER_INACTIVE)
        {                               /* Timer has expired so ...         */
            if (((Timer *)tp)->reloadDelay)
            {                           /* Periodic Timer so restart it     */
                ((Timer *)tp)->delay = ((Timer *)tp)->reloadDelay;
                ((Timer *)tp)->status = TIMER_ACTIVE;
            } /* if */
            else
            {                           /* One-shot timer so delete it      */
                list_get(&timerChainHead, tp);
                tp->lst_next = NULL;    /* Take expired timer off the list  */
                tp->lst_prev = NULL;
            } /* else */
        } /* if */
    } /* for */
} /* timerEvent() */

/****************************************************************************/
