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

#include ":src/lib/Timer.h"
#include <exec/memory.h>

/* Allocate and prepare a timer request structure. 
 * Called with:
 *		vBlank:	1 => vertical blanking timer, microhertz timer otherwise
 * Returns:
 *		pointer to timer request or NULL (failed)
 */

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, timeRequest, 1L) ) {
				DeleteTimer(timeRequest);
				timeRequest = NULL;
				goto killport;
			}
		}
	}
	return timeRequest;
}

/* Delete a timer request created by CreateTimer().
 * Called with:
 *		timeRequest:	pointer to timer request structure
 */

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

	msgPort = timeRequest->tr_node.io_Message.mn_ReplyPort;

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

/* Start an asynchronous timer request.  The user application detects
 * the expiration of the timer with Wait(timeRequest->ReplyPort->mp_SigBit)
 * or WaitIO(timeRequest).
 * Called with:
 *		timeRequest:	pointer to timer I/O request block
 *		seconds:		number of seconds in time interval
 *		microSeconds:	number of uSecs in time interval
 *
 * Caution:	seconds, microSeconds are ULONG parameters!
 */

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(timeRequest);				/* start the timer */
}

/* Stop an asynchronous timer request.
 * Called with:
 *		timeRequest:	pointer to timer I/O request block
 */

void
StopTimer(timeRequest)
	struct timerequest *timeRequest;
{
	AbortIO(timeRequest);
	WaitIO(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
