#include "pwm.h"


TIM_SettingsTypeDef TIM_CTRL = {0};

// variables for filling arrays
int Numb_Of_Peroids = 2;			// number of periods
int Samples_Per_Peroid = 0;		// how many samples in one period
int Size_Of_Log = 0;					// size of written data to log
int log_ind = 0;							// index of log arrays
int cnt_to_cnt_log = 0;				// counter for log_cnt

int sine_ind_prev = 0;

/** 
	* @brief 	Filling logs.
	* @note 	Заполнение логов: синус, шим, пила.
	* @note		This called from TIM_CTRL_Handler
	*/
void Fill_Logs_with_Data(void)
{	
	// calc pwm duty from timer
	float PWM_Duty;
	if(PWM_Get_Mode(&hpwm1, PWM_DC_MODE) == 0) // if sinus need to be written
	{
		if(PWM_Get_Mode(&hpwm1, PWM_CH_MODE)) // if its signed sine mode (two channels)
		{
			if(hpwm1.Duty_Table_Ind < hpwm1.Duty_Table_Size/2) 	// first half get from channel 1
				PWM_Duty = (((float)PWM_Get_Compare1(&hpwm1))/(PWM_Get_Autoreload(&hpwm1)))+1;
			else																								// second half get from channel 2
				PWM_Duty = 1-(((float)PWM_Get_Compare2(&hpwm1))/(PWM_Get_Autoreload(&hpwm1)));
		}
		else // if its unsigned sine mode (single channel)
		{	// just get current pwm duty
			PWM_Duty = ((float)PWM_Get_Compare1(&hpwm1)/PWM_Get_Autoreload(&hpwm1));
		}
	}
	else // if its dc pwm mode
	{ // just get current pwm duty
		if(PWM_Get_Mode(&hpwm1, PWM_CH_MODE)) // if its second channels mode
			PWM_Duty = ((float)PWM_Get_Compare2(&hpwm1)/PWM_Get_Autoreload(&hpwm1));
		else																	// if its first channel mode
			PWM_Duty = ((float)PWM_Get_Compare1(&hpwm1)/PWM_Get_Autoreload(&hpwm1));
	}
		
		
	
	// WRITE SINUS TO WHOLE ARRAY
//	sine_log[log_ind] = sin_val;	
	if(PWM_Get_Mode(&hpwm1,PWM_DC_MODE) == 0)	// in table mode write PWM Duty (write sine) with scale 1/2 from sin table max value (0xFFFF/2)
		sine_log[log_ind] = PWM_Duty*(0x8000-1);
	else																			// in dc mode write PWM Duty (write sine)
		sine_log[log_ind] = 0;
		
	

	// WRITE PWM
	if(PWM_Get_Mode(&hpwm1,PWM_DC_MODE)) // in DC mode
	{
		// write 1 - if log_ind < Size_Of_Period*PWM_Dury
		// write 0 - otherwise
		pwm_log[log_ind] = (log_ind%(Size_Of_Log/Numb_Of_Peroids) < (Size_Of_Log/Numb_Of_Peroids+1)*hpwm1.PWM_Value/100)? 1: 0;	
	}
	else // in table mode
	{
		// write fill whole pwm array at one interrupt
		int PWM_Period_End_Ind = (Size_Of_Log/Numb_Of_Peroids);
		int PWM_Step_End_Ind;
		if(PWM_Get_Mode(&hpwm1,PWM_CH_MODE))
			PWM_Step_End_Ind = PWM_Period_End_Ind*fabs(PWM_Duty-1);
		else
			PWM_Step_End_Ind = PWM_Period_End_Ind*PWM_Duty;
		for(int i = 0; i <= PWM_Step_End_Ind; i++)
		{
			for (int j = 0; j < Numb_Of_Peroids; j++)
				pwm_log[i+j*PWM_Period_End_Ind] = 1;
		}		
		for(int i = PWM_Step_End_Ind+1; i < PWM_Period_End_Ind; i++)
			for (int j = 0; j < Numb_Of_Peroids; j++)
				pwm_log[i+j*PWM_Period_End_Ind] = 0;
	}
	
	// WRITE COUNTER
	cnt_log[log_ind] = cnt_to_cnt_log;
	cnt_to_cnt_log++;
	if(cnt_to_cnt_log>=Size_Of_Log/2)
		cnt_to_cnt_log = 0;
	
	// INCREMENT AND RESET COUNTER
	log_ind++;
	if(PWM_Get_Mode(&hpwm1,PWM_DC_MODE) == 0) // if its PWM table mode
	{
		// SYNCHRONIZE PERIOD OF SIN IN LOG
		// (это надо, чтобы данные не съезжали из-за несинхронизированного периода)
		
		// wait until period ended
		if(log_ind>Size_Of_Log-1) // if logs are filled
		{	
			if((unsigned)hpwm1.Duty_Table_Ind < sine_ind_prev) // and if new period started
			{	
				log_ind = 0; // reset counter
				sine_ind_prev = (unsigned)hpwm1.Duty_Table_Ind;
			}
		}
		// update prev variable only if log currently writing
		else
			sine_ind_prev = (unsigned)hpwm1.Duty_Table_Ind;
	}
	else // if its PWM DC mode
	{
		// if logs are filled
		if(log_ind>Size_Of_Log-1)
			log_ind = 0;		
	}
		
	
	// if its overflow log array size - reset log_ind
	if(log_ind>LOG_SIZE-1)
	{
		log_ind = 0;
		sine_ind_prev = (unsigned)hpwm1.Duty_Table_Ind;
	}
}

/** 
	* @brief 	Update log parameters.
	* @note 	Проверка надо ли обновлять параметры логов, и если надо - обновляет их.
	* @note		This called from TIM_CTRL_Handler
	*/
void Update_Params_For_Log(void)
{	
	unsigned UpdateLog = 0;

	// READ	NUMB OF PERIOD IN LOGS
	if(Numb_Of_Peroids != log_ctrl[R_LOG_CTRL_LOG_PWM_NUMB])
	{
		Numb_Of_Peroids = log_ctrl[R_LOG_CTRL_LOG_PWM_NUMB];
		// update logs params
		UpdateLog = 1;
	}	
	// READ	SIZE OF LOGS
	if(Size_Of_Log != log_ctrl[R_LOG_CTRL_LOG_SIZE])
	{
		Size_Of_Log = log_ctrl[R_LOG_CTRL_LOG_SIZE];
		// update logs params
		UpdateLog = 1;
	}
	
	// UPDATE LOG PARAMS
	if(UpdateLog)
	{
		// set logs params
		Set_Log_Params();	
	}	
}

/** 
	* @brief 	Set up log parameters.
	* @note 	Устанавливает настройки логов и проверяет их на корректность.
	*/
void Set_Log_Params(void)
{
	// SET LOG PARAMS
	log_ind = 0;
	Samples_Per_Peroid = TIM_CTRL.sTimFreqHz/hpwm1.PWM_Value;
	
	if(Size_Of_Log > LOG_SIZE) // if its too much data in log
	{
		Numb_Of_Peroids = (LOG_SIZE/Samples_Per_Peroid);
		log_ctrl[R_LOG_CTRL_LOG_SIZE] = Numb_Of_Peroids;
		Size_Of_Log = Numb_Of_Peroids*Samples_Per_Peroid;
	}
	
	// clear logs arrays
	for(int i = Size_Of_Log; i < LOG_SIZE; i++)
	{
		sine_log[i] = 0;
		pwm_log[i] = 0;
		cnt_log[i] = 0;
	}
	
}

/** 
	* @brief 	reInitialization of control timer.
	* @note 	Перенастраивает таймер согласно принятным настройкам в log_ctrl.
	* @note		This called from main while
	*/
void Control_Timer_ReInit(TIM_SettingsTypeDef *stim)
{
	TIM_Base_MspDeInit(&stim->htim);
	hpwm1.stim.sTickBaseMHz = TIMER_CTRL_TICKBASE;
	TIM_Base_Init(stim);
	
	HAL_TIM_Base_Start_IT(&stim->htim); // timer for sinus
  HAL_NVIC_SetPriority(TIM8_BRK_TIM12_IRQn, 1, 1);
}
/** 
	* @brief 	First initialization of Control Timer.
	* @note 	Первый управляющего таймера. Таймер записывает логи и обновляет параметры ШИМ.
	* @note		This called from main
	*/
void Control_Timer_FirstInit(void)
{
	//-------CONTROL TIMER INIT----------
	// tim settings
	TIM_CTRL.htim.Instance = TIM12;
	TIM_CTRL.sTimMode = TIM_IT_MODE;
	TIM_CTRL.sTickBaseMHz = TIMER_CTRL_TICKBASE;
	TIM_CTRL.sTimAHBFreqMHz = TIMER_CTRL_AHB_FREQ;
	TIM_CTRL.sTimFreqHz = HZ_TIMER_CTRL;
	
	TIM_Base_Init(&TIM_CTRL);
  HAL_NVIC_SetPriority(TIM8_BRK_TIM12_IRQn, 1, 1);
	
	HAL_TIM_Base_Start_IT(&TIM_CTRL.htim); // timer for sinus
	
	
	// FILL TIME ARRAY WITH TIME
	for(int i = 0; i <= R_TIME_LOG_QNT; i++)
		time_log[i] = i;
	
}

//-------------------------------------------------------------------
//------------------------HANDLERS FUNCTIONS-------------------------
//-------------CONTROL TIMER---------------
void TIM8_BRK_TIM12_IRQHandler(void)
{
	Trace_CTRL_TIM_Enter();
  HAL_TIM_IRQHandler(&TIM_CTRL.htim);
	
	Fill_Logs_with_Data();
	Update_Params_For_Log();
	Update_Params_For_PWM(&hpwm1);
	Trace_CTRL_TIM_Exit();
	
}