/* TIMER - Amiga CIA Timer Control Software

  originally by Paul Higginbottom, Public Domain

  hacked on by karl to produce a monotonically increasing microsecond
  clock, 12/30/88, Public Domain

  second release, 4/27/89

  cc +p ciafinder.c
  ln ciafinder.o -lcl32

  This code locates the data portion of the timer interrupt installed
  on CIA B, timer B to provide a high-precision, high-accuracy elapsed
  time timer.

  It can be used by one of your programs, minus the demo main() routine
  at the end, to get the elapsed time, provided the companion cia timer
  interrupt has been installed, typically by the companion program to
  this one, ciatimer.

*/

#include <exec/types.h>
#include <exec/tasks.h>
#include <functions.h>
#include <exec/interrupts.h>
#include <hardware/cia.h>
#include <hardware/custom.h>
#include <hardware/intbits.h>
#include <resources/cia.h>
#include <stdio.h>

#include "ciatimer.h"

#define MATCH 0

static struct Interrupt
   CIATimerInterrupt,
   *OldCIAInterrupt = (struct Interrupt *)-1;

static struct Library *CIAResource = NULL;

#define ciatlo ciab.ciatblo
#define ciathi ciab.ciatbhi
#define ciacr ciab.ciacrb
#define CIAINTBIT CIAICRB_TB
#define CLEAR 0

void DummyCIAInterrupt()
{
}

/* install and remove a fake interrupt so we can locate the one we want */
struct CIA_Time *LocateCIATimerData()
{
	/* Open the CIA resource */
	if ((CIAResource = (struct Library *)OpenResource(CIABNAME)) == NULL)
	{
		fprintf(stderr,"timer couldn't open cia resource\n");
		return(NULL);
	}

	CIATimerInterrupt.is_Node.ln_Type = NT_INTERRUPT;
	CIATimerInterrupt.is_Node.ln_Pri = 127;
	CIATimerInterrupt.is_Code = DummyCIAInterrupt;
	CIATimerInterrupt.is_Node.ln_Name = "ciafinder dummy interrupt";

	/* install interrupt */
	if ((OldCIAInterrupt = AddICRVector(CIAResource,CIAINTBIT,&CIATimerInterrupt)) == NULL)
	{
		RemICRVector(CIAResource, CIAINTBIT, &CIATimerInterrupt);
		fprintf(stderr,"no CIA timer currently installed!\n");
		return(NULL);
	}

	if (strcmp(OldCIAInterrupt->is_Node.ln_Name,CIATIMER_INTERRUPT_NAME) != MATCH)
	{
		fprintf(stderr,"CIA interrupt routine is '%s' rather than '%s'\n",OldCIAInterrupt->is_Node.ln_Name,CIATIMER_INTERRUPT_NAME);
		return(NULL);
	}

	return((struct CIA_Time *)OldCIAInterrupt->is_Data);
}

/* return the elapsed real time in seconds and microseconds since the
 * cia timer interrupt handler was installed.
 *
 * ElapsedTime(&secs,&microsecs);
 *
 */
void ElapsedTime(tickdata_ptr,sec_ptr,usec_ptr)
struct CIA_Time *tickdata_ptr;
int *sec_ptr,*usec_ptr;
{
	register long seconds, microseconds;
	register long ciahi, cialo;

	Disable();
	ciahi = ciathi;
	cialo = ciatlo;
	seconds = tickdata_ptr->CIA_Seconds;
	microseconds = tickdata_ptr->CIA_Microseconds;
	Enable();
	/* to multiply the timer ticks * 1.397, you can multiply by 1430
	 * and divide by 1024 (or shift right by 10, get it?) 
	 * Note that the timer counts down, so elapsed ticks based
	 * on reading it are computed as CIA_TIME_CLICE minus ticks read
	 */
	ciahi = CIA_TIME_SLICE - ((ciahi << 8) + cialo);
	ciahi = ((ciahi * 1430) >> 10) & 0xffff;

	microseconds += ciahi;
	if (microseconds > 1000000)
	{
		microseconds -= 1000000;
		seconds++;
	}

	*sec_ptr = seconds;
	*usec_ptr = microseconds;
	return;
}

main()
{
	struct CIA_Time *CIA_CurrentTime_ptr;
	long secs, microsecs;

	CIA_CurrentTime_ptr = LocateCIATimerData();
	if (CIA_CurrentTime_ptr == NULL)
		exit(1);

	ElapsedTime(CIA_CurrentTime_ptr,&secs,&microsecs);

	printf("secs %d microsecs %d\n",secs,microsecs);
}


/*
long reference_seconds, reference_microseconds;

void set_wait_ticks(delay_ticks)
long delay_ticks;
{
	register long desired_seconds, desired_microseconds;
	long current_seconds,current_microseconds;

	timer_request->tr_node.io_Command = TR_ADDREQUEST;

	reference_microseconds += microseconds_per_tick * delay_ticks;

	while (reference_microseconds >= 1000000)
	{
		reference_microseconds -= 1000000;
		reference_seconds++;
	}

	ElapsedTime(&current_seconds,&current_microseconds);
	desired_seconds = reference_seconds - current_seconds;
	desired_microseconds = reference_microseconds - current_microseconds;

	if (desired_microseconds < 0)
	{
		desired_microseconds += 1000000;
		desired_seconds--;
	}

	if (desired_seconds >= 0)
	{
		timer_request->tr_time.tv_secs = desired_seconds;
		timer_request->tr_time.tv_micro = desired_microseconds;
	}
	else
	{
		timer_request->tr_time.tv_secs = 0;
		timer_request->tr_time.tv_micro = 1;
	}
	SendIO(timer_request);
}

SetReferenceTime()
{
	ElapsedTime(&reference_seconds,&reference_microseconds);
}

*/

