/*
 * Temperature_control_and_monitoring_system.c
 *
 *      Author: Martin Mitter
 */
#include "Temperature_control_and_monitoring_system.h"

void Temp_regulation(temperature_t Temp_in) {
	T_Settings[TEMP_SET_INDEX]=read_flash(TEMP_SET_INDEX);
	T_Settings[HYS_UP_INDEX]=read_flash(HYS_UP_INDEX);
	T_Settings[HYS_DWN_INDEX]=read_flash(HYS_DWN_INDEX);

	if (Temp_in<(T_Settings[TEMP_SET_INDEX]-T_Settings[HYS_DWN_INDEX])) {
		action_flag=2;
		HAL_GPIO_WritePin(cooler_act_GPIO_Port, cooler_act_Pin, 1);
		HAL_GPIO_WritePin(heater_act_GPIO_Port, heater_act_Pin, 0);
		HAL_GPIO_WritePin(LED_1_GPIO_Port, LED_1_Pin, 1);
		HAL_GPIO_WritePin(LED_0_GPIO_Port, LED_0_Pin, 0);
	}
	else if (Temp_in>(T_Settings[TEMP_SET_INDEX]+T_Settings[HYS_UP_INDEX])) {
		action_flag=1;
		HAL_GPIO_WritePin(cooler_act_GPIO_Port, cooler_act_Pin, 0);
		HAL_GPIO_WritePin(heater_act_GPIO_Port, heater_act_Pin, 1);
		HAL_GPIO_WritePin(LED_1_GPIO_Port, LED_1_Pin, 0);
		HAL_GPIO_WritePin(LED_0_GPIO_Port, LED_0_Pin, 1);
	}
	else if ((Temp_in>=T_Settings[TEMP_SET_INDEX] && action_flag==2) ||
			 (Temp_in<=T_Settings[TEMP_SET_INDEX] && action_flag==1) ||
			 action_flag==0) {
		action_flag=0;
		HAL_GPIO_WritePin(cooler_act_GPIO_Port, cooler_act_Pin, 1);
		HAL_GPIO_WritePin(heater_act_GPIO_Port, heater_act_Pin, 1);
		HAL_GPIO_WritePin(LED_1_GPIO_Port, LED_1_Pin, 0);
		HAL_GPIO_WritePin(LED_0_GPIO_Port, LED_0_Pin, 0);
	}
}

void Set_temp_output() {
	lcd_clear();
	lcd_put_cur(0,0);
	lcd_send_string("TEMPin :");
	lcd_put_cur(1,0);
	lcd_send_string("TEMPout:");
}

void write_flash(temperature_t *T_settings) {
	HAL_StatusTypeDef ret;
	uint32_t mem_error;
	FLASH_EraseInitTypeDef erase;

    erase.TypeErase   = FLASH_TYPEERASE_PAGES;
    erase.PageAddress = START_ADR;
    erase.NbPages     = 1;

	ret = HAL_FLASH_Unlock();
	if (ret != HAL_OK ) {
		error(0);
		return;
	}
	//FLASH_TYPEERASE_PAGES		FLASH_TYPEERASE_MASSERASE
	ret=HAL_FLASHEx_Erase(&erase, &mem_error);
	if (ret != HAL_OK ) {
		error(2);
		return;
	}//FLASH_TYPEPROGRAM_WORD (32b),	DOUBLEWORD (64b),	HALFWORD (16b)
	ret=HAL_FLASH_Program (FLASH_TYPEPROGRAM_WORD, START_ADR+(4*TEMP_SET_INDEX), T_Settings[TEMP_SET_INDEX]);
	if (ret != HAL_OK ) {
		error(3);
		return;
	}
	ret=HAL_FLASH_Program (FLASH_TYPEPROGRAM_WORD, START_ADR+(4*HYS_UP_INDEX), T_Settings[HYS_UP_INDEX]);
	if (ret != HAL_OK ) {
		error(3);
		return;
	}
	ret=HAL_FLASH_Program (FLASH_TYPEPROGRAM_WORD, START_ADR+(4*HYS_DWN_INDEX), T_Settings[HYS_DWN_INDEX]);
	if (ret != HAL_OK ) {
		error(3);
		return;
	}
	ret=HAL_FLASH_Lock();
	if (ret != HAL_OK ) {
		error(1);
		return;
	}
}

temperature_t read_flash(uint8_t value_sel) {
	return *(temperature_t*)(START_ADR+(value_sel*4));
}

void wifi_init() {
	//modul reset
	sprintf(buff, "AT+RST\r\n");
	HAL_UART_Transmit(&huart1, (uint8_t *)buff, strlen((char*)buff), 500);
	HAL_Delay(1000);
	//set wifi mod-station
	sprintf(buff, "AT+CWMODE=1\r\n"); //1-station mode, 2-AP, 3-1+2
	HAL_UART_Transmit(&huart1, (uint8_t *)buff, strlen((char*)buff), 500);
	HAL_Delay(1000);
	//connect to wifi
	sprintf(buff, "AT+CWJAP=\"%s\",\"%s\"\r\n", SSID, PASSWORD);
	HAL_UART_Transmit(&huart1, (uint8_t *)buff, strlen((char*)buff), 500);
	//single conection
	sprintf(buff, "AT+CIPMUX=0\r\n");
	HAL_UART_Transmit(&huart1, (uint8_t *)buff, strlen((char*)buff), 500);
	HAL_Delay(100);
}

void wifi_send_data(temperature_t *Temperatures, int32_t I_heater, int32_t I_cooler) {
	sprintf(data_out, "GET %sTamb=%li&TinUp=%li&TinDwn=%li&Tset=%li&Hup=%li&Hdwn=%li&Tscale=%i&Iheat=%li&Icool=%li&Iscale=%i&Doors=%u HTTP/1.1\r\n\r\n",
				SERVER_URL,
				Temperatures[TEMP_AMB_INDEX],
				Temperatures[TEMP_IN_UP_INDEX],
				Temperatures[TEMP_IN_DWN_INDEX],
				read_flash(TEMP_SET_INDEX),
				read_flash(HYS_UP_INDEX),
				read_flash(HYS_DWN_INDEX),
				TEMP_SCALE,
				I_heater,
				I_cooler,
				CURRENT_SCALE,
				HAL_GPIO_ReadPin(door_GPIO_Port, door_Pin));
	sprintf(buff, "AT+CIPSTART=\"TCP\",\"%s\",%i\r\n", SERVER_IP, SERVER_PORT);
	HAL_UART_Transmit(&huart1, (uint8_t *)buff, strlen((char*)buff), 500);
	HAL_Delay(1000);
	sprintf(buff, "AT+CIPSEND=%u\r\n", ((uint16_t) strlen((char*)data_out)));
	HAL_UART_Transmit(&huart1, (uint8_t *)buff, strlen((char*)buff), 500);
	HAL_Delay(1000);
	HAL_UART_Transmit(&huart1, (uint8_t *)data_out, strlen((char*)data_out), 500);
	HAL_Delay(1000);
}

void error(uint8_t error) {
	HAL_Delay(500);
	lcd_clear();
	lcd_put_cur(1,0);
	HAL_GPIO_WritePin(error_red_GPIO_Port, error_red_Pin, 1);
	HAL_GPIO_WritePin(error_green_GPIO_Port, error_green_Pin, 0);
	switch (error) {
		case(0):
			lcd_send_string("ErrFLASH-unlock");
			sprintf(buff, "ErrFLASH-unlock\n\r");
			break;
		case(1):
			lcd_send_string("ErrFLASH-lock");
			sprintf(buff, "ErrFLASH-lock\n\r");
			break;
		case(2):
			lcd_send_string("ErrFLASH-erase");
			sprintf(buff, "ErrFLASH-erase\n\r");
			break;
		case(3):
			lcd_send_string("ErrFLASH-prog");
			sprintf(buff, "ErrFLASH-prog\n\r");
			break;
		case(4):
			lcd_send_string("Hrelay stuck");
			sprintf(buff, "Heater relay stuck\n\r");
			break;
		case(5):
			lcd_send_string("Hshortcircuit");
			sprintf(buff, "Heater short circuit\n\r");
			HAL_GPIO_WritePin(heater_act_GPIO_Port, heater_act_Pin, 1);
			break;
		case(6):
			lcd_send_string("HnotConn");
			sprintf(buff, "Heater not connected or bulb thread damaged\n\r");
			break;
		case(7):
			lcd_send_string("Crelay stuck");
			sprintf(buff, "cooler relay stuck\n\r");
			break;
		case(8):
			lcd_send_string("Cshortcircuit");
			sprintf(buff, "cooler short circuit\n\r");
			HAL_GPIO_WritePin(cooler_act_GPIO_Port, cooler_act_Pin, 1);
			break;
		case(9):
			lcd_send_string("HnotConn");
			sprintf(buff, "cooler not connected or compressor winding damaged\n\r");
			break;
	}
	HAL_UART_Transmit(&huart2, (uint8_t *)buff, strlen((char*)buff), 500);
	HAL_Delay(1500);
	Set_temp_output();
}

void Temperature_control_and_monitoring_system_init() {
	temperature_t T_Settings_def[3] = {T_SET_DEF, HYS_UP_DEF, HYS_DWN_DEF};

///////////initialize wifi connection//////////////////
	HAL_GPIO_WritePin(cooler_act_GPIO_Port, cooler_act_Pin, 1);
	HAL_GPIO_WritePin(heater_act_GPIO_Port, heater_act_Pin, 1);
	wifi_init();

	lcd_init();
	lcd_clear();
	lcd_put_cur(1,0);
	lcd_send_string("Wait");
	HAL_GPIO_WritePin(error_red_GPIO_Port, error_red_Pin, 0);
	HAL_GPIO_WritePin(error_green_GPIO_Port, error_green_Pin, 1);
	HAL_GPIO_WritePin(relay_3_GPIO_Port, relay_3_Pin, 1);
	HAL_Delay(1500);
	lcd_send_string(".");
	HAL_Delay(1500);
	lcd_send_string(".");
	HAL_Delay(1500);
	lcd_send_string(".");
	HAL_Delay(1500);

	//sests thermometers resolution
	thermometer_set_res(TEMP_IN_UP_ADR, REG_RES_0625);
	thermometer_set_res(TEMP_IN_DWN_ADR, REG_RES_0625);
	thermometer_set_res(TEMP_AMB_ADR, REG_RES_0625);

	//prepare display for temperature output
	Set_temp_output();

///////if no settings in flash->write default values//////
	//read settings form flash
	T_Settings[TEMP_SET_INDEX]=read_flash(TEMP_SET_INDEX);
	T_Settings[HYS_UP_INDEX]=read_flash(HYS_UP_INDEX);
	T_Settings[HYS_DWN_INDEX]=read_flash(HYS_DWN_INDEX);

	//if any settings==0xFFFFFFFF -> settings=settings_def
	if(T_Settings[TEMP_SET_INDEX]==EMPTY_CELL ||
			T_Settings[HYS_UP_INDEX]==EMPTY_CELL ||
			T_Settings[HYS_DWN_INDEX]==EMPTY_CELL) {
		write_flash(T_Settings_def);
	}
}

void Temperature_control_and_monitoring_system() {
	sprintf(buff, "\nnew loop\n\r");
	HAL_UART_Transmit(&huart2, (uint8_t *)buff, strlen((char*)buff), 500);


//////////////////read settings from flash////////////////////////////////
	T_Settings[TEMP_SET_INDEX]=read_flash(TEMP_SET_INDEX);
	T_Settings[HYS_UP_INDEX]=read_flash(HYS_UP_INDEX);
	T_Settings[HYS_DWN_INDEX]=read_flash(HYS_DWN_INDEX);

//////////////////get temperatures and print them/////////////////////////
	Temperatures[TEMP_IN_UP_INDEX]=get_temp(TEMP_IN_UP_ADR);
	Temperatures[TEMP_IN_DWN_INDEX]=get_temp(TEMP_IN_DWN_ADR);
	Temperatures[TEMP_AMB_INDEX]=get_temp(TEMP_AMB_ADR);

	if (Temperatures[TEMP_IN_UP_INDEX]==666*TEMP_SCALE) {
	  Temperatures[TEMP_IN_INDEX]=Temperatures[TEMP_IN_DWN_INDEX];
	}
	else if(Temperatures[TEMP_IN_DWN_INDEX]==666*TEMP_SCALE) {
	  Temperatures[TEMP_IN_INDEX]=Temperatures[TEMP_IN_UP_INDEX];
	}
	else {
	  Temperatures[TEMP_IN_INDEX]=(Temperatures[TEMP_IN_UP_INDEX]+Temperatures[TEMP_IN_DWN_INDEX])/2;
	}
	print_temp(Temperatures[TEMP_IN_INDEX], 0, 8);
	print_temp(Temperatures[TEMP_AMB_INDEX], 1, 8);

	///////////////////////////print for debug//////////////////////////////
	sprintf(buff, "upper inside temperature: %s%2li,%02lu °C\n\r",
			((Temperatures[TEMP_IN_UP_INDEX] < 0) ? ("-") : ("+")),
			((Temperatures[TEMP_IN_UP_INDEX] < 0) ? (-Temperatures[TEMP_IN_UP_INDEX]  / TEMP_SCALE) : Temperatures[TEMP_IN_UP_INDEX] / TEMP_SCALE),
			((Temperatures[TEMP_IN_UP_INDEX] < 0) ? (-Temperatures[TEMP_IN_UP_INDEX]  % TEMP_SCALE) : Temperatures[TEMP_IN_UP_INDEX] % TEMP_SCALE));
	HAL_UART_Transmit(&huart2, (uint8_t *)buff, strlen((char*)buff), 500);
	sprintf(buff, "lower inside temperature: %s%2li,%02lu °C\n\r",
			((Temperatures[TEMP_IN_DWN_INDEX] < 0) ? ("-") : ("+")),
			((Temperatures[TEMP_IN_DWN_INDEX] < 0) ? (-Temperatures[TEMP_IN_DWN_INDEX]  / TEMP_SCALE) : Temperatures[TEMP_IN_DWN_INDEX] / TEMP_SCALE),
			((Temperatures[TEMP_IN_DWN_INDEX] < 0) ? (-Temperatures[TEMP_IN_DWN_INDEX]  % TEMP_SCALE) : Temperatures[TEMP_IN_DWN_INDEX] % TEMP_SCALE));
	HAL_UART_Transmit(&huart2, (uint8_t *)buff, strlen((char*)buff), 500);
	sprintf(buff, "ambient temperature: %s%2li,%02lu °C\n\r",
			((Temperatures[TEMP_AMB_INDEX] < 0) ? ("-") : ("+")),
			((Temperatures[TEMP_AMB_INDEX] < 0) ? (-Temperatures[TEMP_AMB_INDEX]  / TEMP_SCALE) : Temperatures[TEMP_AMB_INDEX] / TEMP_SCALE),
			((Temperatures[TEMP_AMB_INDEX] < 0) ? (-Temperatures[TEMP_AMB_INDEX]  % TEMP_SCALE) : Temperatures[TEMP_AMB_INDEX] % TEMP_SCALE));
	HAL_UART_Transmit(&huart2, (uint8_t *)buff, strlen((char*)buff), 500);

/////////////////////////// menu routine//////////////////////////////
	if (!HAL_GPIO_ReadPin(control_menu_GPIO_Port, control_menu_Pin)) {
	//////////////////////menu-1st level//////////////////////////////
		HAL_GPIO_WritePin(cooler_act_GPIO_Port, cooler_act_Pin, 1);
		HAL_GPIO_WritePin(heater_act_GPIO_Port, heater_act_Pin, 1);
		HAL_GPIO_WritePin(LED_1_GPIO_Port, LED_1_Pin, 0);
		HAL_GPIO_WritePin(LED_0_GPIO_Port, LED_0_Pin, 0);
		state = 0;
		menu_countdown=MENU_COUNTDOWN_MAX;
		change_flag = 1;
		HAL_Delay(1000);
		do {
			if (change_flag) {
				change_flag=0;
				lcd_clear();
				switch (state) {
				case 0:
					lcd_put_cur(0,0);
					lcd_send_string("*Set Temperature");
					lcd_put_cur(1,0);
					lcd_send_string(" Hysteresis upp");
					break;
				case 1:
					lcd_put_cur(0,0);
					lcd_send_string("*Hysteresis upp");
					lcd_put_cur(1,0);
					lcd_send_string(" Hysteresis dwn");
					break;
				case 2:
					lcd_put_cur(0,0);
					lcd_send_string("*Hysteresis dwn");
					lcd_put_cur(1,0);
					lcd_send_string(" Set Temperature");
					break;
				}
			}
			if (!HAL_GPIO_ReadPin(control_plus_GPIO_Port, control_plus_Pin)) {
				state--;
				menu_countdown=MENU_COUNTDOWN_MAX;
				change_flag=1;
			}
			if (!HAL_GPIO_ReadPin(control_minus_GPIO_Port, control_minus_Pin)) {
				state++;
				menu_countdown=MENU_COUNTDOWN_MAX;
				change_flag=1;
			}
			if (state>STATE_MAX) {state=0;}
			if (state<0) {state=STATE_MAX;}
			menu_countdown--;

	/////////////////////////menu-2nd level///////////////////////////////
			if (!HAL_GPIO_ReadPin(control_set_GPIO_Port, control_set_Pin)) {
				lcd_clear();
				change_flag=1;
				menu_countdown=MENU_COUNTDOWN_MAX;
				set_flag=1;
				HAL_Delay(1000);
				Tset_tmp=T_Settings[TEMP_SET_INDEX];
				Hys_up_tmp=T_Settings[HYS_UP_INDEX];
				Hys_dwn_tmp=T_Settings[HYS_DWN_INDEX];

				switch (state) {
					case 0:
						lcd_put_cur(0,0);
						lcd_send_string("Set Temperature");
						break;
					case 1:
						lcd_put_cur(0,0);
						lcd_send_string("Hysteresis upp");
						break;
					case 2:
						lcd_put_cur(0,0);
						lcd_send_string("Hysteresis dwn");
						break;
					}

				do {
					switch (state) {
					case 0:
						if (!HAL_GPIO_ReadPin(control_plus_GPIO_Port, control_plus_Pin)) {
							Tset_tmp+=0.1*TEMP_SCALE;
							menu_countdown=MENU_COUNTDOWN_MAX;
						}
						if (!HAL_GPIO_ReadPin(control_minus_GPIO_Port, control_minus_Pin)) {
							Tset_tmp-=0.1*TEMP_SCALE;
							menu_countdown=MENU_COUNTDOWN_MAX;
						}
						print_temp(Tset_tmp, 1, 4);
						break;
					case 1:
						if (!HAL_GPIO_ReadPin(control_plus_GPIO_Port, control_plus_Pin)) {
							Hys_up_tmp+=0.1*TEMP_SCALE;
							menu_countdown=MENU_COUNTDOWN_MAX;
						}
						if (!HAL_GPIO_ReadPin(control_minus_GPIO_Port, control_minus_Pin)) {
							Hys_up_tmp-=0.1*TEMP_SCALE;
							menu_countdown=MENU_COUNTDOWN_MAX;
						}
						print_temp(Hys_up_tmp, 1, 4);
						break;
					case 2:
						if (!HAL_GPIO_ReadPin(control_plus_GPIO_Port, control_plus_Pin)) {
							Hys_dwn_tmp+=0.1*TEMP_SCALE;
							menu_countdown=MENU_COUNTDOWN_MAX;
						}
						if (!HAL_GPIO_ReadPin(control_minus_GPIO_Port, control_minus_Pin)) {
							Hys_dwn_tmp-=0.1*TEMP_SCALE;
							menu_countdown=MENU_COUNTDOWN_MAX*2;
						}
						print_temp(Hys_dwn_tmp, 1, 4);
						break;
					}
					HAL_Delay(200);
					menu_countdown--;
					if (!HAL_GPIO_ReadPin(control_set_GPIO_Port, control_set_Pin)) {
///////////////////////////save new settings to flash memory//////////////////////////
						T_Settings[TEMP_SET_INDEX]=Tset_tmp;
						T_Settings[HYS_UP_INDEX]=Hys_up_tmp;
						T_Settings[HYS_DWN_INDEX]=Hys_dwn_tmp;
						write_flash(T_Settings);
						menu_countdown=MENU_COUNTDOWN_MAX;
						set_flag=0;
					}
				} while (HAL_GPIO_ReadPin(control_menu_GPIO_Port, control_menu_Pin) && menu_countdown && set_flag);
	/////////////////////////menu-2nd level-end///////////////////////////////////////
			}
			HAL_Delay(200);
		} while ((HAL_GPIO_ReadPin(control_menu_GPIO_Port, control_menu_Pin)) && menu_countdown);
	////////////////////////menu-1st level-end//////////////////////////////////////
		HAL_Delay(500);
		Set_temp_output();
	}


///////////////////////////temperature regulation////////////////////////////////
	Temp_regulation(Temperatures[TEMP_IN_INDEX]);


////////////////////////check action elements state//////////////////////////////
	raw_heater=0;
	raw_cooler=0;
	/////get 1000 samples, store peak values//////
	for(int i=0; i<1000; i++ ) {
		HAL_ADC_Start(&hadc1);
		HAL_ADC_Start(&hadc2);
		HAL_ADC_PollForConversion(&hadc1,50);
		tmp = HAL_ADC_GetValue(&hadc1);
		if ((abs(tmp-2048)-OFFSET)>raw_heater) {
			raw_heater=abs(tmp-2048)-OFFSET;
		}
		HAL_ADC_PollForConversion(&hadc2,50);
		tmp = HAL_ADC_GetValue(&hadc2);
		if ((abs(tmp-2048)-OFFSET)>raw_cooler) {
			raw_cooler=abs(tmp-2048)-OFFSET;
		}
	}
	/////////convert raw values to data///////////
	U_heater=(raw_heater*((3.3*CURRENT_SCALE)/0xFFF))/1.414;
	I_heater=(U_heater*1000)/330;
	U_cooler=(raw_cooler*((3.3*CURRENT_SCALE)/0xFFF))/1.414;
	I_cooler=(U_cooler*1000)/330;

	////////load action elements settings////////
	heater_state=!HAL_GPIO_ReadPin(heater_act_GPIO_Port, heater_act_Pin);
	cooler_state=!HAL_GPIO_ReadPin(cooler_act_GPIO_Port, cooler_act_Pin);

	/////check action element health//////////////
	if (heater_state && I_heater>=100 && I_heater<=2500) {
		sprintf(buff, "Heater OK\n\r");
		HAL_UART_Transmit(&huart2, (uint8_t *)buff, strlen((char*)buff), 500);
	}
	else if (!heater_state && I_heater>=100 && I_heater<=2500) {
		error(4);
	}
	else if (I_heater>=3000) {
		error(5);
	}
	else if (heater_state && I_heater<=30) {
		error(6);
	}
	else if (!heater_state && I_heater<=30) {
		sprintf(buff, "Heater OK\n\r");
		HAL_UART_Transmit(&huart2, (uint8_t *)buff, strlen((char*)buff), 500);
	}

	if (cooler_state && I_cooler>=300 /*&& I_cooler<=3300*/) {
		sprintf(buff, "cooler OK\n\r");
		HAL_UART_Transmit(&huart2, (uint8_t *)buff, strlen((char*)buff), 500);
	}
	else if (!cooler_state && I_cooler>=300 /*&& I_cooler<=3300*/) {
		error(7);
	}/*
	else if (I_cooler>=3300) {
		error(8);
	}*/
	else if (cooler_state && I_cooler<=30) {
		error(9);
	}
	else if (!cooler_state && I_cooler<=30) {
		sprintf(buff, "cooler OK\n\r");
		HAL_UART_Transmit(&huart2, (uint8_t *)buff, strlen((char*)buff), 500);
	}

	/////////send data to debug///////////////////
	sprintf(buff, "current through the heater: %li,%03li mA\n\r",
			(I_heater / CURRENT_SCALE),
			(I_heater % CURRENT_SCALE));
	HAL_UART_Transmit(&huart2, (uint8_t *)buff, strlen((char*)buff), 500);
	sprintf(buff, "current through the cooler: %li,%03li mA\n\r",
			(I_cooler / CURRENT_SCALE),
			(I_cooler % CURRENT_SCALE));
	HAL_UART_Transmit(&huart2, (uint8_t *)buff, strlen((char*)buff), 500);


////////////////////////////send data to server//////////////////////////////////
	wifi_send_data(Temperatures, I_heater, I_cooler);//T_Settings-flash, doors-gpio_read

	HAL_Delay(500);
}
