// ###########################################################################
// #
// # OSCATimer - Implementation of OSCA Timer Module
// # Copyright (C) 2009-2011 Tony Friery [DialTone]
// #
// # ALL RIGHTS RESERVED
// #
// ###########################################################################

#pragma hdrstop

#include "OSCATimer.h"
#include "FormDiag.h"

///////////////////////////////////////////////////////////////////////
//
//  FUNCTION: 	TOSCATimer::Tick
//
//  PURPOSE:	Called periodically amidst CPU execution to ensure that
//					the timer is clocked parallel with the CPU core
//
//  INPUTS:		unsigned int		Number of clock cycles to be processed
//
//  OUTPUT:		bool					Timer IRQ status following tick being
//											processed
//
///////////////////////////////////////////////////////////////////////
bool __fastcall TOSCATimer::Tick(unsigned int NumCycles)
{
	// Increment Prescaler accordingly
	this->fPrescaler += NumCycles;

	// Handler an overflowed prescaler
	while (this->fPrescaler >= 256)
	{
		// Increment Timer Count
		this->fPrescaler -= 256;
		this->fTimerValue++;

		// When Timer has Wrapped around to zero
		if (!this->fTimerValue)
		{
			// Timer elapsed
			if (!this->fTimerIRQ)
			{
				this->fTimerIRQ = true;

				if ((DiagForm) && (DiagForm->IsActive(DIAG_TIMER)))
				{
					DiagForm->AddMessage(DIAG_TIMER, L"Timer Elapsed, IRQ Set");
				}
			}

			// Reseed Timer
			this->fTimerValue = this->fTimerSeed;
		}
	}

	return this->fTimerIRQ;
}

///////////////////////////////////////////////////////////////////////
//
//  FUNCTION:	TOSCATimer::SetTimerSeed
//
//  PURPOSE:	Set a new Timer ReSeed Value
//
//
//  INPUTS:		byte					New value to be used as the Timer
//											Re-Seed Value
//
//  OUTPUT:		void
//
//	 NOTES:		This causes the prescaler to be reset, and the
//					current timer count value is immediately assigned
//					the new ReSeed value
//
///////////////////////////////////////////////////////////////////////
void __fastcall TOSCATimer::SetTimerSeed(byte SeedValue)
{
	// TODO: Check if Timer IRQ Flag should be cleared when Timer Reseeded?
	this->fTimerSeed 	= SeedValue;	// Store new seed
	this->fTimerValue = SeedValue;	// Reseed the timer
	this->fPrescaler 	= 0;				// Prescaler gets reset when seed changed

	if ((DiagForm) && (DiagForm->IsActive(DIAG_TIMER)))
	{
		DiagForm->AddMessage(DIAG_TIMER, UnicodeString::Format(
			L"New Seed Value: 0x%2.2x", OPENARRAY(TVarRec, (this->fTimerSeed))));
	}
}

///////////////////////////////////////////////////////////////////////
//
//  FUNCTION:	TOSCATimer::Reset
//
//  PURPOSE:	Perform a Power-On-Reset of the Timer Device
//
//  INPUTS:		void
//
//  OUTPUT:		void
//
///////////////////////////////////////////////////////////////////////
void __fastcall TOSCATimer::Reset(void)
{
	// Clear IRQ, Seed, Value and Prescaler
	this->fTimerIRQ 	= false;
	this->fTimerSeed 	= 0;
	this->fTimerValue = 0;
	this->fPrescaler 	= 0;
}

///////////////////////////////////////////////////////////////////////
//
//  FUNCTION:	TOSCATimer::GetTimerIRQ
//
//  PURPOSE:	Retrieve the current value of the Timer Elapsed
//					IRQ Flag
//
//  INPUTS:		void
//
//  OUTPUT:		bool					IRQ Flag Status (true = Flag set,
//											ie. Timer has Elapsed)
//
///////////////////////////////////////////////////////////////////////
bool __fastcall TOSCATimer::GetTimerIRQ(void)
{
	return this->fTimerIRQ;
}

///////////////////////////////////////////////////////////////////////
//
//  FUNCTION:	TOSCATimer::ClearIRQ
//
//  PURPOSE:	Clear down the Timer Elapsed IRQ Flag
//
//  INPUTS:		void
//
//  OUTPUT:		void
//
///////////////////////////////////////////////////////////////////////
void __fastcall TOSCATimer::ClearIRQ(void)
{
	if ((DiagForm) && (DiagForm->IsActive(DIAG_TIMER)))
	{
		DiagForm->AddMessage(DIAG_TIMER, L"IRQ Cleared");
	}

	// Clear down IRQ
	this->fTimerIRQ = false;
}

///////////////////////////////////////////////////////////////////////
//
//  FUNCTION:	TOSCATimer::TOSCATimer [CONSTRUCTOR]
//
//  PURPOSE:	Constructor for the Timer Class
//
//  INPUTS:		None
//
//  OUTPUT:		None
//
///////////////////////////////////////////////////////////////////////
__fastcall TOSCATimer::TOSCATimer()
{
	// Initial Power-On-Reset
	this->Reset();
}

//---------------------------------------------------------------------------

#pragma package(smart_init)

