
// ****************************************************************************
//
//                           Page CNT - Counter
//
// ****************************************************************************

#include "../include.h"

Bool CntPause = False;		// pause counter
volatile u32 CntHigh;		// higher value of the counter
u32 CntHold = 0;		// counter hold value

/*
// CNT Timer 1 interrupt handler - overflow of edge counter ... handler located at page_asm.S
//HANDLER void TIM1_UP_IRQHandler()
HANDLER void CNT_Handler()
{
	// clear interrupt flag
	TIM1_UpIntClr();

	// increment counter
	CntHigh++;
}
*/

// CNT initialize
void CNT_Init()
{
	// setup input pin to floating input with pull-up
	GPIO_Mode(IN_GPIO, GPIO_MODE_IN_PU);

	// Enable timer clock source
	TIM1_ClkEnable();

	// Reset timer to default setup
	TIM1_Reset();

	// remap Timer 1
	// Input: PD2, Timer 1 channel 1 mapping 0
	// 0 ... PC5:ETR, >>> PD2:CH1 <<<<, PA1:CH2, PC3:CH3, PC4:CH4, PC2:BKIN, PD0:CH1N, PA2:CH2N, PD1:CH3N
	GPIO_Remap_TIM1(0);

	// setup CH1 as input TI1
	TIM1_CC1Sel(TIM_CCSEL_TI1);

	// no filter
	TIM1_IC1Filter(TIM_FILTER_0);

	// no prescaler
	TIM1_IC1Div(0);

	// max. load period
	TIM1_Load(0xffff);

	// capture on rising edge
	TIM1_IC1Rise();

	// external clock mode 1: TIM1 clockes by TI1 edges
	TIM1_InMode(TIM_INMODE_EDGE);
	TIM1_Trig(TIM_TRIG_TI1FP1);

	// set CNT Timer 1 interrupt handler
	SetHandler(IRQ_TIM1_UP, CNT_Handler);

	// enable update interrupt
	TIM1_UpIntEnable();
	NVIC_IRQEnable(IRQ_TIM1_UP);
	TIM1_UpIntClr();

	// reset high counter
	CntHigh = 0;
	CntHold = 0;
	CntPause = False;

	// enable timer
	TIM1_Enable();
}

// CNT terminate
void CNT_Term()
{
	// interrupt disable
	NVIC_IRQDisable(IRQ_TIM1_UP);
	TIM1_UpIntDisable();
	TIM1_UpIntClr();
	NVIC_IRQClear(IRQ_TIM1_UP);

	// reset input pin
	GPIO_PinReset(IN_GPIO);

	// reset Timer 1
	TIM1_Reset();

	// Timer 1 clock disable
	RCC_TIM1ClkDisable();
}

// load counter value
u32 CNT_Get()
{
	u32 high, high2;
	u16 low;
	while (True)
	{
		cb();
		high = CntHigh;
		cb();
		low = TIM1_GetCnt();
		nop();
		nop(); // - here may come interrupt
		nop();
		cb();
		high2 = CntHigh;
		if (high == high2)
		{
			return (high << 16) | low;
		}
	}
}

// draw one value
void CNT_DispVal(u32 val, int y)
{
	DrawRectClrFast(0, y, WIDTH, FONTH2);
	u8* s = DecNumBuf;
	int len = DecUNum(s, val, '\'');
	if (len > 8)
	{
		DrawText(s, WIDTH-len*8, y+6);
	}
	else
	{
		DrawText2(s, WIDTH-len*16, y);
	}
}

// display current counter value
void CNT_Disp()
{
	// select font 8x12
	SelFont12();

	// display values
	if (!CntPause) CNT_DispVal(CNT_Get(), ROW1_Y);
	CNT_DispVal(CntHold, ROW3_Y);

	// display update
	DispUpdate();
}

// Page CNT (returns key PREV/NEXT)
u8 PageCNT()
{
	u8 key;

	// CNT initialize
	CNT_Init();

	while (True)
	{
		// reload watchdog counter
		IWDG_Reload();

		// display current counter value
		CNT_Disp();

		// keyboard input
		key = KeyGet();
		switch (key)
		{
		// Prev
		case KEY_PREV:
		// Next
		case KEY_NEXT:
			// CNT terminate
			CNT_Term();
			return key;

		// Fast - pause
		case KEY_FAST:
			CntPause = !CntPause;
			break;

		// Slow - hold
		case KEY_SLOW:
			CntHold = CNT_Get();
			break;

		// Hold - reset
		case KEY_HOLD:
			CNT_Term();
			CNT_Init();
			break;
		}
	}
}
