/**
 * @file	IEC60335_B_ClockTest.c
 * @purpose
 * @brief
 * @version 1.0
 * @date	10-sep-2009
 * @author	applhi
*/
/*----------------------------------------------------------------------------
 * Software that is described herein is for illustrative purposes only
 * which provides customers with programming information regarding the
 * products. This software is supplied "AS IS" without any warranties.
 * NXP Semiconductors assumes no responsibility or liability for the
 * use of the software, conveys no license or title under any patent,
 * copyright, or mask work right to the product. NXP Semiconductors
 * reserves the right to make changes in the software without
 * notification. NXP Semiconductors also make no representation or
 * warranty that such application will be suitable for the specified
 * use without further testing or modification.
 **********************************************************************/

#include "IEC60335.h"

typedef struct tag_ClkTest
{		
	// general
	
	UINT32 timerTestThreshold;		/*!< Used in the mainloop function, defines the number of calls to start occurrence test*/
	UINT32 rtcTestThreshold;		/*!< Used in the mainloop function, defines the number of calls to start occurrence test*/
	UINT32 rtcOccCounter;			/*!< Counter variable for the mainloop, if value reached the defined threshold, the occurrence test is started*/
	UINT32 timerOccCounter;			/*!< Counter variable for the mainloop, if value reached the defined threshold, the occurrence test is started*/
	BOOL timerOccured;				/*!< This bool will be set in the timer function, and is reset durring occurrence test*/
	BOOL rtcOccured;				/*!< This bool will be set in the rtc function, and is reset durring occurrence test*/

	UINT32 timerCounter;			/*!< The counter Variable, to test the timer to be within its bounds*/
	UINT32 timerBoundLower;			/*!< The estimated minimum count of cycle occurencies (Threshold for timer test). */
	UINT32 timerBoundUpper;			/*!< The estimated maximum count of cycle occurencies (Threshold for timer test). */
	BOOL timerOutOfBounds;			/*!< within this bool, the rtc timer test signals the error state to the main function*/

	BOOL timerCounterOverflow;		/*!< Reflects, if the TimerCounter was flew over due an error */
} type_ClockTest;

type_ClockTest clkTst = 
{
	0,
	0,
	0,
	0,
	FALSE,
	FALSE,
	0,
	0,
	0,
	FALSE,
	FALSE
};

/*! 
 */
void IEC60335_resetClockTest(void)
{
	// general
	clkTst.rtcOccCounter = 0;			/*!< The counter Variable*/
	clkTst.timerOccCounter = 0;			/*!< The counter Variable*/

	clkTst.timerCounter = 0;

	clkTst.timerOccured = FALSE;
	clkTst.rtcOccured = FALSE;
	clkTst.timerOutOfBounds = FALSE;

	clkTst.timerCounterOverflow = FALSE;
}

/*! 
 */
void IEC60335_initClockTest(UINT32 timerOccThreshold, UINT32 rtcOccThreshold, UINT32 timerLowerBound, UINT32 timerUpperBound)
{
	// general
	clkTst.timerTestThreshold = timerOccThreshold;		/*!< The counter Variable*/
	clkTst.rtcTestThreshold = rtcOccThreshold;			/*!< The counter Variable*/

	clkTst.timerBoundLower = timerLowerBound;			/*!< The estimated minimum count of cycle occurencies (Threshold for MainLoop). */
	clkTst.timerBoundUpper = timerUpperBound;			/*!< The estimated maximum count of cycle occurencies (Threshold for MainLoop). */	

	IEC60335_resetClockTest();
}

/*!
	This function represents the part of the IEC60335 Class B clock test which has to be executed within the main loop.
	It checks several thing:
	- If the clock test timer interrupts are triggered
	- If the clock test rtc interrupt is triggered
	- or, If in any of the two interrupts an error was detected...

	This function must be called once inside the main loop.

	For this function, it is necessary to estimate the count how often this function could be called.
	This is important to find valid threshold values, which are used to test timer and rtc interrupt occurrence.
	 
	\return Tells if passed or failed. See \link #tag_testResult type_testResult \endlink.
 */
type_testResult IEC60335_Clocktest_MainLoopHandler(void)
{
	type_testResult Result = IEC60335_testPassed;

	clkTst.rtcOccCounter = clkTst.rtcOccCounter + 1;
	clkTst.timerOccCounter = clkTst.timerOccCounter + 1;

	if(clkTst.rtcOccCounter == 0)
	{
		Result = IEC60335_testFailed;
	}

	if(clkTst.timerOccCounter == 0)
	{
		Result = IEC60335_testFailed;
	}

	if(clkTst.rtcOccCounter >= clkTst.rtcTestThreshold)
	{
		clkTst.rtcOccCounter = 0;

		if(clkTst.rtcOccured == FALSE)
		{
			Result = IEC60335_testFailed;
		}
		else
		{
			clkTst.rtcOccured = FALSE;

			if(clkTst.timerOutOfBounds == TRUE)
			{
				Result = IEC60335_testFailed;
				clkTst.timerOutOfBounds = FALSE;
			}
		}
	}

	if(clkTst.timerOccCounter >= clkTst.timerTestThreshold)
	{
		clkTst.timerOccCounter = 0;

		if(clkTst.timerOccured == FALSE)
		{
			Result = IEC60335_testFailed;
		}
		else
		{
			clkTst.timerOccured = FALSE;
		}
	}
	
	if(Result == IEC60335_testFailed)
	{
		IEC60335_resetClockTest();
	}

	return Result;
}

/*! 
	This function is intended to use as timer interrupt service handler or to be called once inside the timer interrupt service handler.
*/
void IEC60335_Clocktest_TimerIntHandler(void)
{
	clkTst.timerCounter = clkTst.timerCounter + 1;

	if(clkTst.timerCounter == 0)
	{
		clkTst.timerCounter = 0xFFFFFFFF;
		clkTst.timerCounterOverflow = TRUE;
	}

	clkTst.timerOccured = TRUE;
}

/*! 
	This function is intended to be called once inside the custom rtc interrupt service handler. It can't be used as service handler by itself, because of the 
	return value that has to be evaluated after the call.

	This function tests the timer time frame and in this case the CPU frequency.

	Also, this function checks if the main loop function was called.

	\return Tells if passed or failed. See \link #tag_testResult type_testResult \endlink.
 */
void IEC60335_Clocktest_RTCHandler(void)
{
	clkTst.rtcOccured = TRUE;

/* check if timer is still in frame */
	if((clkTst.timerCounter < clkTst.timerBoundLower) || (clkTst.timerCounter > clkTst.timerBoundUpper))
	{
		clkTst.timerOutOfBounds = TRUE;
	}
	else
	{
		clkTst.timerOutOfBounds = FALSE;
	}

	clkTst.timerCounter = 0;
}
