
// ****************************************************************************
//
//                         Page DAC - voltage regulator
//
// ****************************************************************************

#include "../include.h"

int DacSet = DACSET_FAST;	// current DAC set
int DacLevel = DAC_DEF;		// current DAC level

// DAC title
const char* const DacTitle[DACSET_NUM] = {
	"480kHz",	// DACSET_FAST	// DAC 480kHz (fast speed, prescaler = 1, sample rate 480 kHz - voltage RC output)
	"1kHz",		// DACSET_MED,	// DAC 1kHz (medium speed, prescaler = 480, sample rate 1 kHz - engine control)
	"50Hz",		// DACSET_SLOW	// DAC 50Hz (slow speed, prescaler = 9600, sample raze 50 Hz - dimmer control)
};

// prescaler levels
const u16 DacPresc[DACSET_NUM] = {
	1-1,		// DACSET_FAST	// DAC 480kHz (fast speed, prescaler = 1, sample rate 480 kHz - voltage RC output)
	480-1,		// DACSET_MED,	// DAC 1kHz (medium speed, prescaler = 480, sample rate 1 kHz - engine control)
	9600-1,		// DACSET_SLOW	// DAC 50Hz (slow speed, prescaler = 9600, sample raze 50 Hz - dimmer control)
};

// DAC setup
void DAC_Setup()
{
	// get current DAC level
	int level = DacLevel;

	// level 0
	if (level == 0)
	{
		GPIO_Out0(DAC_GPIO);
		GPIO_Mode(DAC_GPIO, GPIO_MODE_OUT);
		return;
	}

	// level 100
	if (level == DAC_LOOP)
	{
		GPIO_Out1(DAC_GPIO);
		GPIO_Mode(DAC_GPIO, GPIO_MODE_OUT);
		return;
	}

	// other levels setup
	GPIO_Mode(DAC_GPIO, GPIO_MODE_AF);

	// setup prescaler
	TIM2_Presc(DacPresc[DacSet]);

	// setup loader
	TIM2_Comp1(level);
}

// DAC initialize
void DAC_Init()
{
	// BAT initialize, initialize ADC single conversion mode, set ADC clock to 750kHz
	BAT_Init();

	// Enable timer clock source
	TIM2_ClkEnable();

	// Reset timer to default setup
	TIM2_Reset();

	// select input from internal clock CK_INT
	TIM2_InMode(TIM_INMODE_INT);

	// enable compare output
	TIM2_CC1Enable();

	// setup prescaler
	TIM2_Presc(DacPresc[DacSet]);
	TIM2_Load(DAC_LOOP-1);

	// direction up
	TIM2_DirUp();

	// enable auto-reload of preload compare register
	TIM2_AutoReloadEnable();

	// setup compare
	TIM2_OC1Mode(TIM_COMP_PWM1);	// set compare mode
	TIM2_OC1PreEnable();		// enable preload compare register

	// enable main output
	TIM2_OCEnable();

	// reload immediately
	TIM2_Update();

	// remap Timer 2
	// Output: PC5, Timer 2 channel 1 mapping 2
	//	2 ... >>> PC5:CH1/ETR <<<, PC2:CH2, PD2:CH3/CH1N, PC1:CH4/CH2N
	GPIO_Remap_TIM2(2);

	// DAC setup
	DAC_Setup();

	// enable timer
	TIM2_Enable();
}

// DAC terminate
void DAC_Term()
{
	// BAT terminate
	BAT_Term();

	// reset GPIO pin
	GPIO_PinReset(DAC_GPIO);

	// reset Timer 2
	TIM2_Reset();

	// Timer 2 clock disable
	RCC_TIM2ClkDisable();
}

// display DAC state
void DAC_Disp()
{
	int level, set;

	// set font 8x12
	SelFont12();

	// get current set
	set = DacSet;

	// display title
	DrawRectClr(PageX, ROW0_Y, WIDTH-1-PageX, FONTH);
	const char* t = DacTitle[set];
	int len = StrLen(t);
	DrawText(t, (WIDTH-1-PageX-len*8)/2 + PageX, ROW0_Y);

	// clear screen
	DrawRectClrFast(0, TITLE_H, WIDTH, HEIGHT-TITLE_H);

	// get level
	level = DacLevel;

	// draw percentage
	u8* s = DecNumBuf;
	len = DecUNum(s, level, 0);
	s[len] = '%';
	s[len+1] = 0;
	DrawText2(s, (WIDTH-16-len*16)/2, ROW1_Y);

	// draw V
	u32 u = (Supply*level + 50)/100;

	// display unsigned value (returns next X coordinate; need to call DispUpdate())
	//  x ... X coordinate
	//  y ... Y coordinate
	//  val ... value
	//  dig ... number of valid digits
	//  ex ... decimal exponent related to base unit, in range -18..+8
	//  unit ... unit character, 0=none
	//  small ... use small unit characters
	UI_DispVal(u, ROW3_Y, 'V');

	// display update
	DispUpdate();
}

// Page DAC (returns key PREV/NEXT)
u8 PageDAC()
{
	u8 key;
	int i, set;

	// DAC initialize
	DAC_Init();

	// display DAC state
	DAC_Disp();

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

		// update battery supply voltage (takes 100ms)
		BAT_Update();

		// input keys
		key = KeyGet();
		switch (key)
		{
		// Prev
		case KEY_PREV:
		// Next
		case KEY_NEXT:
			// DAC terminate
			DAC_Term();
			return key;

		// Slow
		case KEY_SLOW:
			i = DacLevel - 1;
			if (i >= 0)
			{
				DacLevel = i;
				DAC_Setup();
				DAC_Disp();
			}
			break;		

		// Fast
		case KEY_FAST:
			i = DacLevel + 1;
			if (i <= DAC_LOOP)
			{
				DacLevel = i;
				DAC_Setup();
				DAC_Disp();
			}
			break;

		// Hold
		case KEY_HOLD:
			DAC_Term();
			i = DacSet + 1;
			if (i >= DACSET_NUM) i = 0;
			DacSet = i;
			DAC_Init();
			DAC_Disp();
			break;
		}
	}
}
