/* Timer device support routines.
 * Filename:    Timer.c
 * Author:      Mark R. Rinfret
 * Date:        11/29/87
 *
 */

#ifndef EXEC_MEMORY_H
#include <exec/memory.h>
#endif

#include "MRTimer.h"

/*  FUNCTION
        CreateTimer - Allocate and initialize a timer request.

    SYNOPSIS
        #include <Timer.h>
        struct timerequest *CreateTimer(vBlank)
                            BOOL vBlank;

    DESCRIPTION
        CreateTimer allocates and initializes an asynchronous timer 
        request structure for later use by StartTimer and StopTimer.
        If the <vBlank> argument is 1, the vertical blanking interval
        timer is used.  Otherwise, the microhertz timer is used.
        CreateTimer returns a pointer to the timer request structure
        if successful, NULL otherwise.

    SEE ALSO
        StartTimer, StopTimer, DeleteTimer

 */

struct timerequest *
CreateTimer(vBlank)
    BOOL vBlank;
{
    int status = 0;
    struct MsgPort  *timerPort = NULL;
    struct timerequest *timeRequest = NULL;
    ULONG timerType;

    timerType = (vBlank ? UNIT_VBLANK : UNIT_MICROHZ);

    if ( timerPort = CreatePort(0L, 0L) ) {
        if ( ! (timeRequest = (struct timerequest *)
            AllocMem((long) sizeof(struct timerequest),
                     MEMF_CLEAR | MEMF_PUBLIC) ) ) {
killport:
            DeletePort(timerPort);
        }
        else {
            timeRequest->tr_node.io_Message.mn_Node.ln_Type = NT_MESSAGE;
            timeRequest->tr_node.io_Message.mn_Node.ln_Pri = 0;
            timeRequest->tr_node.io_Message.mn_ReplyPort = timerPort;
            if ( OpenDevice(TIMERNAME, timerType, 
                            (struct IORequest *) timeRequest, 1L) ) {
                DeleteTimer(timeRequest);
                timeRequest = NULL;
                goto killport;
            }
        }
    }
    return timeRequest;
}

/*  FUNCTION
        DeleteTimer - delete a timer request created by CreateTimer.

    SYNOPSIS
        void DeleteTimer(timeRequest)
             struct timerequest *timeRequest;

    DESCRIPTION
        DeleteTimer is called with a pointer to a timer request
        structure created by CreateTimer.  It aborts any active
        timer started by StartTimer and frees all resources required 
        by the timer.
 */

void
DeleteTimer(timeRequest)
    struct timerequest *timeRequest;
{
    struct MsgPort *msgPort;

    msgPort = timeRequest->tr_node.io_Message.mn_ReplyPort;

    if (timeRequest->tr_node.io_Device) {
        AbortIO((struct IORequest *) timeRequest);
        GetMsg(msgPort);
        CloseDevice((struct IORequest *) timeRequest);
    }
    FreeMem(timeRequest, sizeof(timeRequest));
    DeletePort(msgPort);
}

/*  FUNCTION
        StartTimer - start an asynchronous timer request.

    SYNOPSIS
        void StartTimer(timeRequest, seconds, microseconds)
             struct timerequest *timeRequest;
             ULONG seconds, microseconds;

    DESCRIPTION
        Start an asynchronous timer request.  The user application can
        detect the expiration of the timer with 
            Wait(timeRequest->ReplyPort->mp_SigBit) or
            WaitIO(timeRequest).

        A typical sequence might look like this:

            Start an asynchronous activity (serial read?);
            StartTimer(myTimer);
            bits = Wait(timer bit or other signal);
            if (bits & myTimerBit)
                WaitIO(&myTimer->tr_node);
 */

void
StartTimer(timeRequest, seconds, microSeconds)
    struct timerequest *timeRequest; ULONG seconds, microSeconds;
{
    timeRequest->tr_time.tv_secs = seconds;
    timeRequest->tr_time.tv_micro = microSeconds;
    timeRequest->tr_node.io_Command = TR_ADDREQUEST;
    timeRequest->tr_node.io_Flags = 0;
    timeRequest->tr_node.io_Error = 0;
    SendIO((struct IORequest *) timeRequest);   /* Start the timer. */
}

/*  FUNCTION
        StopTimer - stop an asynchronous timer request.

    SYNOPSIS
        void StopTimer(timeRequest)
             struct timerequest *timeRequest;

    DESCRIPTION
        StopTimer aborts a time request started by StartTimer.

 */

void
StopTimer(timeRequest)
    struct timerequest *timeRequest;
{
    AbortIO((struct IORequest *) timeRequest);
    WaitIO((struct IORequest *) timeRequest);
}

#ifdef DEBUG
#define SHORTBIT (1L<<shortTimer->tr_node.io_Message.mn_ReplyPort->mp_SigBit)
#define LONGBIT  (1L<<longTimer->tr_node.io_Message.mn_ReplyPort->mp_SigBit)
main()
{
    unsigned intervals;
    struct timerequest *shortTimer, *longTimer;
    ULONG signals;

    /* This simple program example sets up two timers of different
     * intervals and reports their expirations.
     */

    puts("This example defines two timers.  The first has an interval of");
    puts("five seconds, while the second has an interval of 10 seconds.");
    puts("The expiration of each timer is reported to the screen until");
    puts("10 intervals have been detected.\n");

    if (! (shortTimer = CreateTimer(0) ) ) {
        puts("Failed to create short interval timer!");
        exit();
    }

    if (! (longTimer = CreateTimer(0) ) ) {
        puts("Failed to create long interval timer!");
        DeleteTimer(shortTimer);
        exit();
    }

    StartTimer(shortTimer, 5L, 0L);
    StartTimer(longTimer, 10L, 0L);
    for (intervals = 0; intervals < 10; ) {
        printf("Begin wait %2d ... ", intervals);
        signals = Wait(SHORTBIT | LONGBIT);
        puts("end wait.");
        if (signals & SHORTBIT) {
            GetMsg(shortTimer->tr_node.io_Message.mn_ReplyPort);
            ++intervals;
            puts("  Short interval timer expired.");
            StartTimer(shortTimer, 5L, 0L);
        }
        if (signals & LONGBIT) {
            GetMsg(longTimer->tr_node.io_Message.mn_ReplyPort);
            ++intervals;
            puts("   Long interval timer expired.");
            StartTimer(longTimer, 10L, 0L);
        }
    }
    DeleteTimer(shortTimer);
    DeleteTimer(longTimer);
    puts("\nEnd of timer demo.\n");
}
#endif

