#include "custom_voltage_and_resistance.h"
#include "custom_led.h"
#include "custom_lcd.h"
#include "cmsis_os.h"
#include "custom_flags.h"

#include <math.h>

extern ADC_HandleTypeDef hadc1;
extern DMA_HandleTypeDef hdma_adc1;
extern int cnt_adc_debug;
unsigned ADC_Store;
long long unsigned ADC_St;
int adc_store_cnt;

int TimerDelay_1 = 1000;
int TimerDelay_2 = 10;


	
unsigned ADC_Current_Position = 0;
//Предупреждающий диапазон для разницы между средними значениями
unsigned Warning_Range = 8; //8 - 30 sec, 7 - near 1 min 
//Аварийный диапазон для разницы между средними значениями
unsigned Emergency_Range = 7;
//(10/9 Emergency/Warning- probably stable range?) From calc (13/11 Emergency/Warning - extra stab) (13/12 last)

//Отладочная переменная-флаг для очистки счетчиков
unsigned RedGreen_Erase = 0;
//Счетчики некорректных показаний за пределами предупреждающим и аварийным диапазоном
unsigned Warning_Range_Counter = 0;
unsigned Emergency_Range_Counter = 0;

//Структура, в которой хранятся показания АЦП и сопутствующие обработке данные
struct var_values VAR_VALUES;
//Структура, в которой хранятся результаты вычисления напряжения и сопротивления
struct var_result VAR_RESULT;
//Структура, в которой хранится информация об ошибках и их количестве.
struct error_of_voltage_and_resistance_calculation ERROR_OF_VAR;
//Структура флагов проекта
extern struct flags FLAGS;

unsigned ADC2_MN;
unsigned ADC2_MX;
unsigned ADC2_DELTA = 0;
unsigned Pause_before_reading_ADC = 1;
unsigned ADC1_MN;
unsigned ADC1_MX;
unsigned ADC1_DELTA = 0;
long long unsigned Counter_of_opert = 0;
unsigned ADC2_BEAST_MN=1999999;
unsigned ADC2_BEAST_MX;
unsigned ADC2_BEAST_DELTA = 0;

unsigned ADC1_BEAST_MN=138542385;
unsigned ADC1_BEAST_MX;
unsigned ADC1_BEAST_DELTA = 0;
unsigned ZAMERKA_MN_MX_ADC = 0;


// ADC2 при 7мОм 1443, то тогда U2_C = 88, U2_B = 0.8093, u1koef = 0.000860000087
// ADC2 при 7мОм 1495, то тогда U2_c = 33.867, U2_B = 0.807, u1koef = 0.00085315
float u1koef = (float) (0.000860000087);  //0.00079869  0.00081425 old:000786139979  // 1mOhm 0.000824999996  0.000829999975
float u2koef = (float) (0.0008);  
float u2shift = (float) (0.0700000077);  //0.068 -> 0.0800000057. Last at 28.02 = 0.0700000077
float err_delta = 0.1;
float U2_A = 2; // 5
float U2_B = 0.8093;//0.81848; //000817; //0.81848;//0,8093
float U2_C = 88; //51.246; //0.0411;// 51.246;//42.409;//88
float toMik = -0.000001;
float Near_procent = 0.98;
unsigned CounterofErrorOfJEOC = 0;

uint16_t VAR_Average(uint16_t *Arry_of_ADC_Values, uint16_t lenght)
{
	//Функция принимает массив данных и его размер. После этого считает среднее значение и возвращает его.
	unsigned Average_Value = 0;
	
	for(int i = 0; i<lenght; i++)
	{
		Average_Value+=Arry_of_ADC_Values[i];
	}

	return (Average_Value/=lenght);
}

void VAR_Average_Uint16(uint16_t *F, uint16_t *S)
{
	// Average of two unsigned int
	uint16_t tmp = *F;
	*F = (*S+*F)/2;
	*S = tmp;
}

void VAR_Cleaning_after_calculations(uint16_t *Arry_of_ADC_Values, uint16_t *lenght)
{
	//Очищается массив
	for(int i = 0; i<(*lenght); i++)
	{
		Arry_of_ADC_Values[i]=0;
	}
	//Обнуляется количество элементов выборки
	*lenght=0;
}

void VAR_Power_Turn_OnOff(void)
{
	static int Buffer_Cleaning_Counter = 0;
	if(FLAGS.Power_Turn_On)
	{
		for(; Buffer_Cleaning_Counter < buffer_size; Buffer_Cleaning_Counter++)
		{
			VAR_VALUES.ADC1_[Buffer_Cleaning_Counter]=0;
			VAR_VALUES.ADC2_[Buffer_Cleaning_Counter]=0;
			VAR_VALUES.ADC1_Buff[Buffer_Cleaning_Counter]=0;
			VAR_VALUES.ADC2_Buff[Buffer_Cleaning_Counter]=0;
			ADC_Current_Position=0;
		}
		GPIOA->ODR &= ~(1<<11);
		osDelay(100);
		GPIOA->ODR |= (1<<12);
	}
	else
	{
		GPIOA->ODR &= ~(1<<12);
		osDelay(100);
		GPIOA->ODR |= (1<<11);
		Buffer_Cleaning_Counter=0;
	}
}

void VAR_READ_ADC(void)
{
	osDelay(Pause_before_reading_ADC);
	//Считываем значение первого инжектированного канала АЦП
	HAL_ADCEx_InjectedStart_IT(&hadc1);
	VAR_VALUES.ADC1_Buff[ADC_Current_Position] = ADC1->JDR1;
	//Считываем значение второго инжектированного канала АЦП
	osDelay(Pause_before_reading_ADC);
	HAL_ADCEx_InjectedStart_IT(&hadc1);
	VAR_VALUES.ADC2_Buff[ADC_Current_Position] = ADC1->JDR2;
	//Сдвигаем текущую позицию буффера на один шаг
	ADC_Current_Position++;
	
	Counter_of_opert++;
	//Если буффер заполнен, то он проходит первичную обработку
	if(ADC_Current_Position==buffer_size)
	{
		//Вычисляем среднее значение по буфферу первого канала АЦП
		VAR_VALUES.ADC1_BUFF_MID_OLD = VAR_VALUES.ADC1_BUFF_MID;
		VAR_VALUES.ADC1_BUFF_MID = VAR_Average(VAR_VALUES.ADC1_Buff, ADC_Current_Position);
		VAR_Average_Uint16(&VAR_VALUES.ADC1_BUFF_MID, &VAR_VALUES.ADC1_BUFF_MID_OLD);
		//Вычисляем среднее значение по буфферу второго канала АЦП
		VAR_VALUES.ADC2_BUFF_MID_OLD = VAR_VALUES.ADC2_BUFF_MID;
		VAR_VALUES.ADC2_BUFF_MID = VAR_Average(VAR_VALUES.ADC2_Buff, ADC_Current_Position);
		VAR_Average_Uint16(&VAR_VALUES.ADC2_BUFF_MID, &VAR_VALUES.ADC2_BUFF_MID_OLD);
		//Проверяем стабильность показаний каналов АЦП
		VAR_Delta(&VAR_VALUES);
		//Если показания стабильны, то буффер проходит вторичную обработку
		if(FLAGS.STABLE_DELTA_CHECK || FLAGS.REFRESH_LCD_FROM_NONSTABLE_VALUE_ON)
		{
			//Формируем выборки по первому и второму каналам АЦП за исключением значений, выбивающихся из нормы
			for(int i = 0; i<ADC_Current_Position; i++)
			{
				//Первый канал АЦП
				if(abs(VAR_VALUES.ADC1_Buff[i]-VAR_VALUES.ADC1_BUFF_MID) <= VAR_VALUES.ADC1_BUFF_MID*err_delta)
				{
					VAR_VALUES.ADC1_[VAR_VALUES.ADC1_Correct_values_counter]=VAR_VALUES.ADC1_Buff[i];
					VAR_VALUES.ADC1_Correct_values_counter++;
				}
				/*			
				else
					ERROR_OF_VAR.Count_of_incorrect_ADC_JDR1_value++;
				*/
				
				//Второй канал АЦП
				if(abs(VAR_VALUES.ADC2_Buff[i]-VAR_VALUES.ADC2_BUFF_MID) <= VAR_VALUES.ADC2_BUFF_MID*err_delta)
				{
					VAR_VALUES.ADC2_[VAR_VALUES.ADC2_Correct_values_counter]=VAR_VALUES.ADC2_Buff[i];
					VAR_VALUES.ADC2_Correct_values_counter++;
				}
				/*
				else
					ERROR_OF_VAR.Count_of_incorrect_ADC_JDR2_value++;
				*/
			}
			//Расчитываем среднее значение выборки по первому каналу АЦП
			VAR_VALUES.ADC1_MID = VAR_Average(VAR_VALUES.ADC1_, VAR_VALUES.ADC1_Correct_values_counter);
			VAR_Average_Uint16(&VAR_VALUES.ADC1_MID, &VAR_VALUES.ADC1_MID_OLD);
			//Расчитываем среднее значение выборки по второму каналу АЦП
			VAR_VALUES.ADC2_MID = VAR_Average(VAR_VALUES.ADC2_, VAR_VALUES.ADC2_Correct_values_counter);
			VAR_Average_Uint16(&VAR_VALUES.ADC2_MID, &VAR_VALUES.ADC2_MID_OLD);
			//Производим вычисление напряжения и сопротивления
			VAR_Calculations(&VAR_VALUES, &VAR_RESULT);
//			//Производим очистку выборок
//			VAR_Cleaning_after_calculations(VAR_VALUES.ADC1_, &VAR_VALUES.ADC1_Correct_values_counter);
//			VAR_Cleaning_after_calculations(VAR_VALUES.ADC2_, &VAR_VALUES.ADC2_Correct_values_counter);
		}
		//Переходим к первым элементам буфферов
		ADC_Current_Position=0;
		
		if (adc_store_cnt < 5000)
		{
			for (int i = 0; i < VAR_VALUES.ADC2_Correct_values_counter; i++)
			{
				ADC_St+=VAR_VALUES.ADC2_[i];
				//ADC_STORE[adc_store_cnt] = VAR_VALUES.ADC2_[i];
				adc_store_cnt++;
				
				if(ADC2_MX<VAR_VALUES.ADC2_[i]) ADC2_MX = VAR_VALUES.ADC2_[i];
				if(ADC2_MN>VAR_VALUES.ADC2_[i]) ADC2_MN = VAR_VALUES.ADC2_[i];
				if (ADC2_MN == 0)
				{
					__ASM("");
				}
			}
		}
		else
		{
			ADC_Store=ADC_St/adc_store_cnt;
			ADC_St=0;
			adc_store_cnt=0;
			
			
			ADC2_DELTA=ADC2_MX-ADC2_MN;
			ADC2_MN=VAR_VALUES.ADC2_[0];
			ADC2_MX=VAR_VALUES.ADC2_[0];
		}

					//Производим очистку выборок
			VAR_Cleaning_after_calculations(VAR_VALUES.ADC1_, &VAR_VALUES.ADC1_Correct_values_counter);
			VAR_Cleaning_after_calculations(VAR_VALUES.ADC2_, &VAR_VALUES.ADC2_Correct_values_counter);
		
//		ADC_Current_Position&=~(buffer_size);
	
	}
}

void VAR_Delta(struct var_values *VAR_VALUES)
{
	//Сохраняем предыдущие значения разницы между двумя средними значениями
	VAR_VALUES->ADC1_DELTA_OLD = VAR_VALUES->ADC1_DELTA;
	VAR_VALUES->ADC2_DELTA_OLD = VAR_VALUES->ADC2_DELTA;
	//Вычисляем разницу между текущим средним значением и предыдущим
	VAR_VALUES->ADC1_DELTA=abs(VAR_VALUES->ADC1_BUFF_MID - VAR_VALUES->ADC1_BUFF_MID_OLD);
	VAR_VALUES->ADC2_DELTA=abs(VAR_VALUES->ADC2_BUFF_MID - VAR_VALUES->ADC2_BUFF_MID_OLD);
	//Функция обнуления счетчиков ошибок для отладки
	if(RedGreen_Erase) {
		Emergency_Range_Counter=0;
		Warning_Range_Counter=0;
	}
	//Если текущая разница отличается от прошлой на значение, выходящее за рамки аварийного диапазона
	if((VAR_VALUES->ADC2_DELTA + VAR_VALUES->ADC2_DELTA_OLD)/2 > Emergency_Range){ 
		//То сигнализируем о нестабильности показаний АЦП на втором канале
		FLAGS.STABLE_DELTA_CHECK=0;
		//Включаем красный светодиод
		GPIOC->ODR &= ~(1<<14);
		GPIOC->ODR |= (1<<15);
		//Увеличиваем счетчики некорректных показаний
		Emergency_Range_Counter++;
		Warning_Range_Counter++;		
		
		if(FLAGS.WAIT_TO_CALC_RANGE) 
			Emergency_Range++;
	}
	//Иначе если текущая разница отличается от прошлой на значение, выходящее за рамки предупреждающего диапазона
	else if((VAR_VALUES->ADC2_DELTA + VAR_VALUES->ADC2_DELTA_OLD)/2 > Warning_Range){ 
		//Сигнализируем о нестабильности показаний АЦП на втором канале
		FLAGS.STABLE_DELTA_CHECK=0;
		//Включаем красный светодиод
		GPIOC->ODR &= ~(1<<14);
		GPIOC->ODR |= (1<<15);
		//Увеличиваем счетчик некорректных показаний
		Warning_Range_Counter++;
		
		if(FLAGS.WAIT_TO_CALC_RANGE) 
			Warning_Range++;
	} 
	//Иначе сигнализируем о стабильном сигнале
	else{
		//Понижаем значение счетчика некорректных показаний
		if(Warning_Range_Counter>2)
		{
			Warning_Range_Counter-=3;
		}
		else if(Warning_Range_Counter>0)
		{
			Warning_Range_Counter--;
		}
		
		if(Emergency_Range_Counter>0) 
		{
			Emergency_Range_Counter--;
		}
		
		//Если счетчик некорректных показаний принимает допустимое значение некорректных данных
		if(Warning_Range_Counter<3)
		{
			//Включаем зелёный светодиод
			GPIOC->ODR &= ~(1<<15 | 1<<14);
			GPIOC->ODR |= (1<<14);
			//Сигнализируем о стабильных показаниях АЦП на втором канале
			FLAGS.STABLE_DELTA_CHECK=1;
		}
	}
}

				
void VAR_Calculations(struct var_values *VAR_VALUES, struct var_result *VAR_RESULT)
{
	// Store ADC measures
	VAR_VALUES->U1=(VAR_VALUES->ADC1_MID * u1koef);	// U1 - Voltage on R1
	//VAR_VALUES->U2= u2koef * VAR_VALUES->ADC2_MID + u2shift;	// U2 - Voltage for measure current
	//VAR_VALUES->U2= U2_A*toMik*VAR_VALUES->ADC2_MID*VAR_VALUES->ADC2_MID+U2_B*VAR_VALUES->ADC2_MID+U2_C;
	VAR_VALUES->U2=U2_B*VAR_VALUES->ADC2_MID+U2_C;
	VAR_VALUES->U2=VAR_VALUES->U2*Near_procent/1000;	
	
	VAR_RESULT->U_ALL_ADC = ((R1 + R2) * (VAR_VALUES->ADC1_MID)) / R1; // Total voltage //U_ALL_ADC
	VAR_RESULT->U_ALL = VAR_RESULT->U_ALL_ADC * u1koef;

	VAR_RESULT->I = (VAR_VALUES->U2 )/ 35130; // Current
	
	VAR_RESULT->R = VAR_RESULT->U_ALL / VAR_RESULT->I; // Total resistance	
	
	//VAR_RESULT->R-=((-0.0175*VAR_RESULT->R)+45309);
	
	LED_Check(VAR_RESULT->R-4535000);
}	

void VAR_To_LCD(void)
{		
	LCD_Check();
	
	LCD_Send_CMD(0x01); // clear display
	osDelay(TimerDelay_2);
	
	LCD_Send_NUMB(VAR_RESULT.U_ALL);
	LCD_Send_STRING(" V");
	LCD_Send_CMD(0xC0);

//	LED_Check(VAR_RESULT->R-4535000);
	
	if((toMega(VAR_RESULT.R)-4.535)<0) 
		LCD_Send_STRING("0.0");
	else if((toMega(VAR_RESULT.R)-4.535)>10)
		LCD_Send_STRING("INF");
	else
		LCD_Send_NUMB(toMega(VAR_RESULT.R)-4.535);

	LCD_Send_STRING(" MOhm");
	LCD_IWDG_Reset();
	osDelay(TimerDelay_1);

}
