/******************************************************************************
*
* @file    outputs.c
* @author  ECS, Falko Jahn
* @version V1.0.0
* @date    2020-05-01
* @brief       
*
******************************************************************************/

//--- INCLUDES -----------------------------------------------------------------
#include "outputs.h"
#include "main.h"
#include "stdio.h"
#include "sysdata.h"
//--- EXTERNE VARIABLEN -------------------------------------------------------- 

//--- LOKALE DEFINES - bitte hier dokumentieren --------------------------------

//--- LOKALE TYPE DEFS - bitte hier dokumentieren-------------------------------

//--- DEFINITIONEN GLOBALER VARIABLEN - Bitte in Header dokumentieren ----------

//--- LOKALE VARIABLEN - bitte hier dokumentieren ------------------------------

//--- LOKALE FUNKTIONS PROTOTYPEN ---------------------------------------------- 
/*
* @brief Heizungssteuerung
* @param	kein
* @retval	kein
*/
void AuxModeHeaterExec(void);


//--- LOKALE FUNKTIONEN - bitte hier dokumentieren -----------------------------



//	--- GLOBALE FUNKTIONEN - bitte in Header dokumentieren------------------------
void OUTPUTS_Init(void)
{
  sys_data.s.values.lvpState = OUTPUTS_LVP_UNKNOWN;
  sys_data.s.values.ovpState = OUTPUTS_OVP_UNKNOWN;

}



void OUTPUTS_OverwriteChargeCtrl_ChargeEnabled(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  GPIO_InitStruct.Pin = OVERWRITE_CHARGE_CTRL_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(OVERWRITE_CHARGE_CTRL_GPIO_Port, &GPIO_InitStruct);
  HAL_GPIO_WritePin(OVERWRITE_CHARGE_CTRL_GPIO_Port, OVERWRITE_CHARGE_CTRL_Pin, OUTPUTS_CHARGE_ALLOWED);


}


void OUTPUTS_OverwriteChargeCtrl_ChargeDisabled(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  GPIO_InitStruct.Pin = OVERWRITE_CHARGE_CTRL_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(OVERWRITE_CHARGE_CTRL_GPIO_Port, &GPIO_InitStruct);

  HAL_GPIO_WritePin(OVERWRITE_CHARGE_CTRL_GPIO_Port, OVERWRITE_CHARGE_CTRL_Pin, OUTPUTS_CHARGE_NOT_ALLOWED);


}


void OUTPUTS_OverwriteChargeCtrl_Disabled(void)
{


  GPIO_InitTypeDef GPIO_InitStruct = {0};
  GPIO_InitStruct.Pin = OVERWRITE_CHARGE_CTRL_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(OVERWRITE_CHARGE_CTRL_GPIO_Port, &GPIO_InitStruct);


}


void OUTPUTS_OverwriteDischargeCtrl_DischargeEnabled(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  GPIO_InitStruct.Pin = OVERWRITE_DISCHARGE_CTRL_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(OVERWRITE_DISCHARGE_CTRL_GPIO_Port, &GPIO_InitStruct);
  HAL_GPIO_WritePin(OVERWRITE_DISCHARGE_CTRL_GPIO_Port, OVERWRITE_DISCHARGE_CTRL_Pin, OUTPUTS_DISCHARGE_ALLOWED);


}


void OUTPUTS_OverwriteDischargeCtrl_DischargeDisabled(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  GPIO_InitStruct.Pin = OVERWRITE_DISCHARGE_CTRL_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(OVERWRITE_DISCHARGE_CTRL_GPIO_Port, &GPIO_InitStruct);

  HAL_GPIO_WritePin(OVERWRITE_DISCHARGE_CTRL_GPIO_Port, OVERWRITE_DISCHARGE_CTRL_Pin, OUTPUTS_CHARGE_NOT_ALLOWED);


}


void OUTPUTS_OverwriteDischargeCtrl_Disabled(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  GPIO_InitStruct.Pin = OVERWRITE_DISCHARGE_CTRL_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(OVERWRITE_DISCHARGE_CTRL_GPIO_Port, &GPIO_InitStruct);


}

/*
* @brief        Prüfen ob LVP Signal abgeschaltet werden muss
*               LVP Signal kommt vom BMS und schaltet die Lasten ab. Wird hier auch abgeschaltet wenn der Laststrom zu hoch ist,
*               oder wenn die Geräte Temperatur zu hoch oder zu niedrig ist. 
* @param	kein
* @retval	kein
*/
void OUTPUTS_CheckLVP(void)
{
	static uint16_t lastMode;

	if (sys_data.s.parameter.lvpMode == OUTPUTS_LVP_MODE_AUTO)
	{
		if (lastMode != OUTPUTS_LVP_MODE_AUTO)
		{
			sys_data.s.values.lvpState = OUTPUTS_LVP_UNKNOWN;
		}

		if ((sys_data.s.values.lvpState == OUTPUTS_LVP_OK) || (sys_data.s.values.lvpState == OUTPUTS_LVP_UNKNOWN))
		{
			if(sys_data.s.values.batteryVoltage < sys_data.s.parameter.lvpStart)
			{
				printf("OUTPUTS_LVP_BATTERY_UNDERVOLTAGE\n");
				sys_data.s.values.lvpState = OUTPUTS_LVP_BATTERY_UNDERVOLTAGE;
				OUTPUTS_OverwriteDischargeCtrl_DischargeDisabled();
			}
			else if(sys_data.s.values.batteryCurrent < ((int32_t)sys_data.s.parameter.loadCurrentLimit*1000))
			{
				printf("OUTPUTS_LVP_OVERCURRENT\n");
				sys_data.s.values.lvpState = OUTPUTS_LVP_OVERCURRENT;
				OUTPUTS_OverwriteDischargeCtrl_DischargeDisabled();
			}
			else if(sys_data.s.values.shuntTemperature > sys_data.s.parameter.dischargeStopHighTemperatureStart)
			{
				printf("OUTPUTS_LVP_SHUNT_OVERTEMPERATURE\n");
				sys_data.s.values.lvpState = OUTPUTS_LVP_SHUNT_OVERTEMPERATURE;
				OUTPUTS_OverwriteDischargeCtrl_DischargeDisabled();
			}
			else if(sys_data.s.values.chipTemperature > sys_data.s.parameter.dischargeStopHighTemperatureStart)
			{
				printf("OUTPUTS_LVP_CHIP_OVERTEMPERATURE\n");
				sys_data.s.values.lvpState = OUTPUTS_LVP_CHIP_OVERTEMPERATURE;
				OUTPUTS_OverwriteDischargeCtrl_DischargeDisabled();
			}
			else if(sys_data.s.values.shuntTemperature < sys_data.s.parameter.dischargeStopLowTemperatureStart)
			{
				printf("OUTPUTS_LVP_SHUNT_UNDERTEMPERATURE\n");
				sys_data.s.values.lvpState = OUTPUTS_LVP_SHUNT_UNDERTEMPERATURE;
				OUTPUTS_OverwriteDischargeCtrl_DischargeDisabled();
			}
			else if(sys_data.s.values.chipTemperature < sys_data.s.parameter.dischargeStopLowTemperatureStart)
			{
				printf("OUTPUTS_LVP_CHIP_OVERTEMPERATURE\n");
				sys_data.s.values.lvpState = OUTPUTS_LVP_CHIP_UNDERTEMPERATURE;
				OUTPUTS_OverwriteDischargeCtrl_DischargeDisabled();
			}
		}

		if ((sys_data.s.values.lvpState != OUTPUTS_LVP_OK) &&
			(sys_data.s.values.batteryVoltage > sys_data.s.parameter.lvpStop) &&
			(sys_data.s.values.batteryCurrent > ((int32_t)sys_data.s.parameter.loadCurrentLimit * 1000)) &&
			(sys_data.s.values.shuntTemperature < sys_data.s.parameter.dischargeStopHighTemperatureStop) &&
			(sys_data.s.values.chipTemperature < sys_data.s.parameter.dischargeStopHighTemperatureStop) &&
			(sys_data.s.values.shuntTemperature > sys_data.s.parameter.dischargeStopLowTemperatureStop) &&
			(sys_data.s.values.chipTemperature > sys_data.s.parameter.dischargeStopLowTemperatureStop))
		{
			//Abschaltkriterien für LVP liegen nicht mehr vor
			//Wenn Abschaltung aufgrund zu hohem Lade/Lastrom erfolgt ist, muss Fehler durch Geräte Reset zurück gesetzt werden
			//Andere Fehler automatisches Reset, wenn Fehler nicht mehr vorliegt.
			//Kunde könnte automatische Reset verhindern, indem er die Stop Werte anders programmiert
			//z.B. 
			//Temperabschaltung Start 80°C
			//Temperaturabschaltung Stop -99°C
			if ((sys_data.s.values.lvpState != OUTPUTS_LVP_OVERCURRENT) && (sys_data.s.values.lvpState != OUTPUTS_LVP_SHORT_PROTECTION))
			{
				//Andere Fehler, automatisches zurücksetzen, wenn keine Fehlerbedingungen mehr vorliegen
				printf("OUTPUT LVP OK\n");
				sys_data.s.values.lvpState = OUTPUTS_LVP_OK;
#ifndef NO_TRISTATE_OUTPUTS
				OUTPUTS_OverwriteDischargeCtrl_Disabled();
#else
				OUTPUTS_OverwriteDischargeCtrl_DischargeEnabled();
#endif
			}
		}
	}
	else if (sys_data.s.parameter.lvpMode == OUTPUTS_LVP_MODE_MANUAL_ON)
	{
		OUTPUTS_OverwriteDischargeCtrl_DischargeEnabled();
	}
	else if (sys_data.s.parameter.lvpMode == OUTPUTS_LVP_MODE_MANUAL_OFF)
	{
		OUTPUTS_OverwriteDischargeCtrl_DischargeDisabled();
	}
	else 
	{
		OUTPUTS_OverwriteDischargeCtrl_DischargeDisabled();
	}

	lastMode = sys_data.s.parameter.lvpMode;
}

/*
* @brief        Prüfen ob OVP Signal abgeschaltet werden muss
*               OVP Signal kommt vom BMS und schaltet die Ladequellen ab. Wird hier auch abgeschaltet wenn der Ladestrom zu hoch ist,
*               oder wenn die Geräte Temperatur zu hoch oder zu niedrig ist. 
* @param	kein
* @retval	kein
*/
void OUTPUTS_CheckOVP(void)
{
	static uint16_t lastMode;

	if (sys_data.s.parameter.ovpMode == OUTPUTS_OVP_MODE_AUTO)
	{
		if (lastMode != OUTPUTS_OVP_MODE_AUTO)
		{
			sys_data.s.values.ovpState = OUTPUTS_OVP_UNKNOWN;
		}

		if ((sys_data.s.values.ovpState == OUTPUTS_OVP_OK) || (sys_data.s.values.ovpState == OUTPUTS_OVP_UNKNOWN))
		{
			if(sys_data.s.values.batteryVoltage > sys_data.s.parameter.ovpStart)
			{
				printf("OUTPUTS_OVP_BATTERY_OVERVOLTAGE\n");
				sys_data.s.values.ovpState = OUTPUTS_OVP_BATTERY_OVERVOLTAGE;
				OUTPUTS_OverwriteChargeCtrl_ChargeDisabled();
			}
			else if(sys_data.s.values.batteryCurrent > ((int32_t) sys_data.s.parameter.chargeCurrentLimit * 1000))
			{
				printf("OUTPUTS_OVP_OVERCURRENT\n");
				sys_data.s.values.ovpState = OUTPUTS_OVP_OVERCURRENT;
				OUTPUTS_OverwriteChargeCtrl_ChargeDisabled();
			}
			else if(sys_data.s.values.shuntTemperature > sys_data.s.parameter.chargeStopHighTemperatureStart)
			{
				printf("OUTPUTS_OVP_SHUNT_OVERTEMPERATURE\n");
				sys_data.s.values.ovpState = OUTPUTS_OVP_SHUNT_OVERTEMPERATURE;
				OUTPUTS_OverwriteChargeCtrl_ChargeDisabled();
			}
			else if(sys_data.s.values.chipTemperature > sys_data.s.parameter.chargeStopHighTemperatureStart)
			{
				printf("OUTPUTS_OVP_CHIP_OVERTEMPERATURE\n");
				sys_data.s.values.ovpState = OUTPUTS_OVP_CHIP_OVERTEMPERATURE;
				OUTPUTS_OverwriteChargeCtrl_ChargeDisabled();
			}
			else if(sys_data.s.values.shuntTemperature < sys_data.s.parameter.chargeStopLowTemperatureStart)
			{
				printf("OUTPUTS_OVP_SHUNT_UNDERTEMPERATURE\n");
				sys_data.s.values.ovpState = OUTPUTS_OVP_SHUNT_UNDERTEMPERATURE;
				OUTPUTS_OverwriteChargeCtrl_ChargeDisabled();
			}
			else if(sys_data.s.values.chipTemperature < sys_data.s.parameter.chargeStopLowTemperatureStart)
			{
				printf("OUTPUTS_OVP_CHIP_UNDETEMPERATURE\n");
				sys_data.s.values.ovpState = OUTPUTS_OVP_CHIP_UNDERTEMPERATURE;
				OUTPUTS_OverwriteChargeCtrl_ChargeDisabled();
			}
		}

		if ((sys_data.s.values.ovpState != OUTPUTS_OVP_OK) &&
			(sys_data.s.values.batteryVoltage < sys_data.s.parameter.ovpStop) &&
			(sys_data.s.values.batteryCurrent < ( (int32_t) sys_data.s.parameter.chargeCurrentLimit*1000)) &&
			(sys_data.s.values.shuntTemperature < sys_data.s.parameter.chargeStopHighTemperatureStop) &&
			(sys_data.s.values.chipTemperature < sys_data.s.parameter.chargeStopHighTemperatureStop) &&
			(sys_data.s.values.shuntTemperature > sys_data.s.parameter.chargeStopLowTemperatureStop) &&
			(sys_data.s.values.chipTemperature > sys_data.s.parameter.chargeStopLowTemperatureStop))
		{
			//Abschaltkriterien für OVP liegen nicht mehr vor
			//Wenn Abschaltung aufgrund zu hohem Lade/Lastrom erfolgt ist, dann muss Rücksetzen durch Reset Button erfolgen 
			//Andere Fehler, automatisches zurücksetzen, wenn keine Fehlerbedingungen mehr vorliegen
			if ((sys_data.s.values.ovpState != OUTPUTS_OVP_OVERCURRENT) && (sys_data.s.values.ovpState != OUTPUTS_OVP_SHORT_PROTECTION) )
			{
				printf("OUTPUT OVP OK\n");
				sys_data.s.values.ovpState = OUTPUTS_OVP_OK;
#ifndef NO_TRISTATE_OUTPUTS
				OUTPUTS_OverwriteChargeCtrl_Disabled();
#else
				OUTPUTS_OverwriteChargeCtrl_ChargeEnabled();
#endif
			}
		}
	}
	else if (sys_data.s.parameter.ovpMode == OUTPUTS_OVP_MODE_MANUAL_ON)
	{
		OUTPUTS_OverwriteChargeCtrl_ChargeEnabled(); //ACHTUNG: Manual On 
	}
	else if (sys_data.s.parameter.ovpMode == OUTPUTS_OVP_MODE_MANUAL_OFF)
	{
		OUTPUTS_OverwriteChargeCtrl_ChargeDisabled();
	}
	else 
	{
	  OUTPUTS_OverwriteChargeCtrl_ChargeDisabled();
	}

	lastMode = sys_data.s.parameter.ovpMode;
}



#define	  LVP_DETECTION_LEVEL		6000  //< 6 V
#define	  CHARGE_DETECT_HYSTERESE	10

void AuxModeHeaterExec(void)
{
 static int outputState=0;

 int offv = sys_data.s.parameter.auxOutputSetpointOn - CHARGE_DETECT_HYSTERESE;
 int onv = sys_data.s.parameter.auxOutputSetpointOn + CHARGE_DETECT_HYSTERESE;

	if ((sys_data.s.values.shuntVoltage > onv) && (sys_data.s.values.ovp_sense < LVP_DETECTION_LEVEL) && (outputState == 0))
	{
	  printf("Heater on\r\n");
	  outputState = 1;
	  if (sys_data.s.parameter.auxOutputInverted == 0) 
	  {
		HAL_GPIO_WritePin(AUX_EN_GPIO_Port, AUX_EN_Pin, GPIO_PIN_SET);
	  }
	  else
	  {
		HAL_GPIO_WritePin(AUX_EN_GPIO_Port, AUX_EN_Pin, GPIO_PIN_RESET);
	  }

	}

	//Ausschalten
	//Wenn Spannung am Shunt < setpoint (ladegeräteerkennung 14,8V?) und Entladung 
	//Oder wenn OVP wieder da ist
	//sys_data.s.values.batteryCurrent < sys_data.s.parameter.auxOutputSetpointOff

	if ((sys_data.s.values.shuntVoltage < offv  ) || (sys_data.s.values.ovp_sense > LVP_DETECTION_LEVEL)) 
	{
	  if (outputState == 1)
	  {
    	  printf("Heater off\r\n");
    	  outputState = 0;
    	  if (sys_data.s.parameter.auxOutputInverted == 0) 
      	  {
    		HAL_GPIO_WritePin(AUX_EN_GPIO_Port, AUX_EN_Pin, GPIO_PIN_RESET);
    	  }
    	  else
    	  {
    		HAL_GPIO_WritePin(AUX_EN_GPIO_Port, AUX_EN_Pin, GPIO_PIN_SET);
    	  }
	  }
	}
}

void AuxModeSOCExec(void)
{
 static int outputState=0;


	if ((sys_data.s.values.soc > (sys_data.s.parameter.auxOutputSetpointOn*1000)) &&  (outputState == 0))
	{
	  printf("AUX on (SOC Mode)\r\n");
	  outputState = 1;
	  if (sys_data.s.parameter.auxOutputInverted == 0) 
	  {
		HAL_GPIO_WritePin(AUX_EN_GPIO_Port, AUX_EN_Pin, GPIO_PIN_SET);
	  }
	  else
	  {
		HAL_GPIO_WritePin(AUX_EN_GPIO_Port, AUX_EN_Pin, GPIO_PIN_RESET);
	  }

	}


	if ((sys_data.s.values.soc < (sys_data.s.parameter.auxOutputSetpointOff*1000)) &&  (outputState == 1))
	{
	  printf("AUX off (SOC Mode)\r\n");
	  outputState = 0;
	  if (sys_data.s.parameter.auxOutputInverted == 0) 
	  {
		HAL_GPIO_WritePin(AUX_EN_GPIO_Port, AUX_EN_Pin, GPIO_PIN_RESET);
	  }
	  else
	  {
		HAL_GPIO_WritePin(AUX_EN_GPIO_Port, AUX_EN_Pin, GPIO_PIN_SET);
	  }
	}

	
}


	int16_t loadCurrentLimit;													// 30	maximaler Laststrom in A wenn der Strom grer ist als der eingestelle Wert dann wird die Laststrom Protection aktiv, darf nicht unsigned sein, da Entladestrom mit Minus angegeben [A] Default -500 A
	int16_t chargeCurrentLimit;													// 31	maximaler Ladestrom in A wenn der Strom grer ist als der eingestelle Wert dann wird die Ladestrom Protection aktiv [A] Default:500A


	int16_t chargeStopHighTemperatureStart;										// 32	Abschalttemperatur Ladung wegen zu hoher Temperatur [C * 100]
	int16_t chargeStopHighTemperatureStop;										// 33	Wiedereinschalttemperatur [C * 100]

	int16_t chargeStopLowTemperatureStart;										// 34	Abschalttemperatur Ladung wegen zu niedriger Temperatur [C * 100]
	int16_t chargeStopLowTemperatureStop;										// 35	Wiedereinschalttemperatur [C * 100]

	int16_t dischargeStopHighTemperatureStart;									// 36	Abschalttemperatur Entladung wegen zu hoher Temperatur [C * 100]
	int16_t dischargeStopHighTemperatureStop;									// 37	Wiedereinschalttemperatur[C * 100]

	int16_t dischargeStopLowTemperatureStart;									// 38	Abschalttemperatur EntLadung wegen zu niedriger Temperatur
	int16_t dischargeStopLowTemperatureStop;									// 39	Wiedereinschalttemperatur



void AuxModeAlarmExec(void)
{
  static int outputState=0;
  

  if (
	  (sys_data.s.values.shuntTemperature > (chargeStopHighTemperatureStart		- 500))		||
	  (sys_data.s.values.chipTemperature > (chargeStopHighTemperatureStart		- 500))		||
	  (sys_data.s.values.shuntTemperature < (chargeStopLowTemperatureStart		+ 500))		||
	  (sys_data.s.values.chipTemperature < (chargeStopLowTemperatureStart			+ 500))		||
	  (sys_data.s.values.shuntTemperature > (dischargeStopHighTemperatureStart	- 500))		||
	  (sys_data.s.values.chipTemperature > (dischargeStopHighTemperatureStart		- 500))		||
	  (sys_data.s.values.shuntTemperature < (dischargeStopLowTemperatureStart		+ 500))		||
	  (sys_data.s.values.chipTemperature < (dischargeStopLowTemperatureStart		+ 500))		||
	  (sys_data.s.values.batteryCurrent > ((chargeCurrentLimit*1000LL)			- 10000))	||
	  (sys_data.s.values.batteryCurrent < ((loadCurrentLimit*1000LL)				+ 10000))
  
	 )
  {
	if ( outputState == 0)
	{
	  printf("AUX on (Alarm Mode)\r\n");
	  outputState = 1;
	  if (sys_data.s.parameter.auxOutputInverted == 0) 
	  {
		HAL_GPIO_WritePin(AUX_EN_GPIO_Port, AUX_EN_Pin, GPIO_PIN_SET);
	  }
	  else
	  {
		HAL_GPIO_WritePin(AUX_EN_GPIO_Port, AUX_EN_Pin, GPIO_PIN_RESET);
	  }
	}
  }
  else // Alles OK
  {  
	if ( outputState == 0)
	{
	  printf("AUX off (Alarm Mode)\r\n");
	  outputState = 0;
	  if (sys_data.s.parameter.auxOutputInverted == 0) 
	  {
		HAL_GPIO_WritePin(AUX_EN_GPIO_Port, AUX_EN_Pin, GPIO_PIN_RESET);
	  }
	  else
	  {
		HAL_GPIO_WritePin(AUX_EN_GPIO_Port, AUX_EN_Pin, GPIO_PIN_SET);
	  }
	}
  }
}


void OUTPUTS_CheckAUX(void)
{
  
  switch (sys_data.s.parameter.auxOutputMode)
  {
	case AUX_MODE_OFF:
	  HAL_GPIO_WritePin(AUX_EN_GPIO_Port, AUX_EN_Pin, GPIO_PIN_RESET);
	break;

	case AUX_MODE_HEATER:
	  AuxModeHeaterExec();
	break;

	case AUX_MODE_SOC:
	  AuxModeSOCExec();
	break;

	case AUX_MODE_ALARM:
	  AuxModeAlarmExec();
	break;


	default:
	  HAL_GPIO_WritePin(AUX_EN_GPIO_Port, AUX_EN_Pin, GPIO_PIN_RESET);
	break;
	

  }


}

/*************************** End of file ****************************/