/*****************************************************************************
* Timer routines.
*****************************************************************************/
#include	<go32.h>
#include	"zstddef.h"
#include	"timer.h"

uint	TmrFrameCounter;			// increment for each frame

static Timer_t	TmrFrameTicks, TmrFrameClock;

/*****************************************************************************
* Initialize timer routines, must be called before timers will work properly.
*
* Set the 8254 to mode 2 and passes the DOS memory selector to the assembly
* level routines.
*
* Called with:
*    NONE
*
* Returns:
*    NONE
*****************************************************************************/
void tmrInit( void)
{
	// Initialize the 8254 timer and send the DOS segement selector to be
	// used by the assembler routines.

	init_8254( _dos_ds);
}

#if 0		// replaced with a define to speed things up
/*****************************************************************************
* Restore the 8254 timer to mode 3.
*
* Sets the 8254 back to it's original DOS programming mode.
* Timer routines will stop functioning after this call.
*
* Called with:
*    NONE
*
* Returns:
*    NONE
*****************************************************************************/
void tmrRestore( void)
{
	// restore timer back to mode 3

	restore_8254();
}
#endif

/*****************************************************************************
* Set frame rate.
*
* This frame rate timer is a special time that times out once a framerate.
* This routine is called with the desired frames per second.  After this
* routine is called, subsequent calls to 'tmrTestFrame()', or 'tmrWaitFrame()'
* can be called to check for end of frame timing.
*
* Called with:
*    rate = Frame rate in frames per second.
*****************************************************************************/
void tmrSetFrameRate( int fps)
{
	if (fps == 0)
		fps = 1;								// if zero, set to one for error

	// calculate the number of ticks needed for given frame rate

	TmrFrameTicks = (TICK_RATE1000 / fps) / 1000;
	TmrFrameClock = readTimer();		// reset the framerate clock
}

/*****************************************************************************
* Test for end of frame.
*
* Returns zero if not end of frame.  If not zero, the returns the number of
* frames skipped, normally this is one, indicating one frame has passed.
*
* If the return value is greater than one, it indicates more than one frame
* has passed since last called.
*
* Resets the frame timer so that subsequent calls will return zero until the
* next frame time has passed.
*
* Called with:
*    NONE
*
* Returns with:
*    0 = Not end of frame. If not zero, then returns frames skipped.
*****************************************************************************/
uint tmrTestFrame( void)
{
	Timer_t	timer;
	uint		frame;

	frame = TmrFrameCounter;				// get current frame count
	timer = readTimer();						// read current time

	// Calculate number of frames that have passed

	while ((timer - TmrFrameClock) >= TmrFrameTicks)
	{	TmrFrameCounter++;					// increment frame counter
		TmrFrameClock += TmrFrameTicks;	// reset framerate clock
	}
	return (TmrFrameCounter - frame);	// return number of frames that have passed
}

/*****************************************************************************
* Wait for end of frame.
*
* Returns when end of frame is reached.
*
* Called with:
*    NONE
*
* Returns with:
*    Number of frames that have passed since last called.
*****************************************************************************/
uint tmrWaitFrame( void)
{
	uint	frames;

	while ((frames = tmrTestFrame()) == 0)
		;

	return (frames);
}

#if 0 	// replaced with #define for speed
/*****************************************************************************
* Read the frame counter
*****************************************************************************/
uint	tmrReadFramesCount( void)
{
	return (TmrFrameCounter);
}
#endif

/*****************************************************************************
* Test to see if a number of frames have passed.
*
* Returns TRUE if number of frames have passed since the 'frameCount' was
* read.  FALSE if number of frames have not passed.
*
* This routine does not update the 'frameCount', so it will continue to
* return TRUE, until 'frameCount' is updated by the calling program.
*
* Called with:
*    frameCount = Frame counter, read at start of delay loop.
*    frames     = Number of frames to test for.
*
* Returns with:
*    TRUE  - if number of 'frames' have passed since 'frameCount' was read.
*    FALSE - if number of 'frames' have not yet passed.
*****************************************************************************/
bool	tmrTestFrameCount( uint frameCount, uint frames)
{
	if (TmrFrameCounter - frameCount < frames)
		return (zFalse);

	return (zTrue);
}

#if 0		// replaced with a define to speed things up
/*****************************************************************************
* Read a timer.
*
* Reads a high resolution timer.  Used to start a background timer.
*
* Called with:
*    NONE
*
* Returns with:
*    Timer Ticks
*****************************************************************************/
Timer_t tmrRead( void)
{
	return (readTimer());				// return timer value
}
#endif

/*****************************************************************************
* Test a timer using 8254 ticks.
*
* Returns a non-zero value when 'ticks' number of 8254 ticks have passed
* since the given timer value was read.
*
* There are	1,193,181.667 8254 ticks in a second.
*
* Called with:
*    timer = Timer value obtained by a previous call to 'tmrRead()'.
*    ticks = Number of 8254 ticks to test for.
*
* Returns with:
*    0 if timer has not timed out, not zero indicates timer has timed out.
*****************************************************************************/
bool tmrTestTicks( Timer_t timer, Timer_t ticks)
{
	// if time passed is less than number of ticks, then return 0

	if ((readTimer() - timer) < ticks)
		return (zFalse);

	return (zTrue);
}

/*****************************************************************************
* Test a timer using milliseconds.
*
* Returns a non-zero value when 'ms' number of milliseconds have passed
* since the given timer value was read.
*
* Called with:
*    timer = Timer value obtained by a previous call to 'tmrRead()'.
*    ms    = Number of milliseconds to test for.
*
* Returns with:
*    0 if timer has not timed out, not zero indicates timer has timed out.
*****************************************************************************/
bool tmrTestms( Timer_t timer, ulong ms)
{
	// if time passed is less than number of ticks, then return 0

	if ((readTimer() - timer) < (ms * TICKS_PER_MS))
		return (zFalse);

	return (zTrue);
}

