/**************************************
*  TIMER.C  08/04/90
*  Written by Timm Martin
*  This source code is public domain.
***************************************/

#include <devices/timer.h>
#include <exec/ports.h>
#include <exec/types.h>
#include <clib/exec_protos.h>

#include "timer.h"

/********************
*  SHARED VARIABLES
*********************/

long    timer_error = 1;
struct timerequest timer_req;
struct MsgPort *timer_port = NULL;	/* GLOBAL */

/***************
*  TIMER ABORT
****************/

/*
 * This function cancels an existing time request.
 */

void
timer_abort(void)
{
	AbortIO(&timer_req.tr_node);
	Wait(1L << timer_port->mp_SigBit);
	GetMsg(timer_port);
}

/***************
*  TIMER CLOSE
****************/

/*
 * This function closes the timer device and deletes the timer port.
 */

void
timer_close(void)
{
	if (!timer_error) {
		CloseDevice((struct IORequest *) & timer_req);
		timer_error = NULL;
	}
	if (timer_port) {
		DeletePort(timer_port);
		timer_port = NULL;
	}
}

/**************
*  TIMER OPEN
***************/

/*
 * This function opens the timer device and initializes it.
 */

BOOL
timer_open(void)
{
	if (!(timer_port = (struct MsgPort *)CreatePort(NULL, 0L)) ||
	    (timer_error = OpenDevice(TIMERNAME, UNIT_VBLANK,
				(struct IORequest *) & timer_req, NULL)))
		return (0);

	timer_req.tr_node.io_Message.mn_ReplyPort = timer_port;
	timer_req.tr_node.io_Command = TR_ADDREQUEST;
	timer_req.tr_node.io_Flags = 0;
	return (1);
}

/***************
*  TIMER START
****************/

/*
 * This function issues a request to the timer device to notify the
 * program in the specified number of microseconds.  This function does
 * not wait for a reply from the timer device.
 */

void
timer_start(long micros)
{
	long    secs;

	secs = micros / MICROS_PER_SEC;
	micros %= MICROS_PER_SEC;

	timer_req.tr_time.tv_secs = secs;
	timer_req.tr_time.tv_micro = micros;
	SendIO(&timer_req.tr_node);
}

/**************
*  TIMER TEST
***************/

/*
 * This function returns whether the last timer request has been
 * satisfied.
 */

BOOL
timer_test(void)
{
	return (GetMsg(timer_port) != NULL);
}

/**************
*  TIMER WAIT
***************/

/*
 * This function waits for the specified number of microseconds.
 */

#define MICROS_PER_SEC 1000000L

void
timer_wait(long micros)
{
	long    secs;

	/* a bug in Kickstart v1.3 requires this check */
	if (micros < 2)
		return;

	secs = micros / MICROS_PER_SEC;
	micros %= MICROS_PER_SEC;

	timer_req.tr_time.tv_secs = secs;
	timer_req.tr_time.tv_micro = micros;
	SendIO(&timer_req.tr_node);

	/* wait until time is up */
	Wait(1L << timer_port->mp_SigBit);
	GetMsg(timer_port);
}
