
// Dieser Modus ist ein Hauptschaltermodus mit Secondary Protection 
// Secondary Protection löst aus, wenn OVP und LVP wegfällt.
// OVP und LVP fällt wegbei:
// - Sehr tiefe Entladung
// - Sehr hohe Spannung
// - Übertemperatur
// - je nach Liproeinstellung möglicherweise auch wenn sowohl Untertemperaturschutz für Ladung und für Last erreicht ist
// - je nach Liproeinstellung möglicherweise auch wenn sowohl Überttemperaturschutz für Ladung und für Last erreicht ist
// - Die letzten beiden Positionen können vielleicht ungewollt sein.


// Hier wird Manuall On nicht erlaubt -> Extra sicher
// Ansonsten wie Modus 1



#include "stdio.h"
#include "mode_secondaryprotection_plus.h"
#include "button.h"
#include "relais.h"
#include "main.h"
#include "leds.h"
#include "buzzer.h"
#include "chip_temperature.h"
#include "voltage_meas.h"


typedef enum SECONDARYPROTECTION_State_enum 
{
  SECONDARYPROTECTION_OFF, 
  SECONDARYPROTECTION_ON,
 // SECONDARYPROTECTION_MANUAL_ON, HIer nicht erlaubt für mehr Sicherheit
  SECONDARYPROTECTION_ERROR
} SECONDARYPROTECTION_state_t;

typedef enum SECONDARYPROTECTION_ErrorState_enum 
{
  ERROR_NONE,
  ERROR_EXTERNAL_FAULT, //z.B Kurzschluss
  ERROR_TEMPERATURE,
  ERROR_VOLTAGE_DROP,
  ERROR_LVP_AND_OVP,	  //z.B. kritische Überspannung, tiefeEntladung
} SECONDARYPROTECTION_ErrorState_t;


static SECONDARYPROTECTION_state_t smState;
static SECONDARYPROTECTION_ErrorState_t smError = ERROR_NONE;
static int autoRetryMode;

static void SECONDARYPROTECTION_SM_Off(void)
{
  int faultInput;
  int lvpAndOvpInput;

  if (HAL_GPIO_ReadPin(GPIO_INPUT_FAULT_GPIO_Port, GPIO_INPUT_FAULT_Pin) == GPIO_PIN_RESET)       
  {
    faultInput = 1;
  }
  else
  {
    faultInput = 0;
  }

  if ((HAL_GPIO_ReadPin(GPIO_INPUT_LVP_GPIO_Port, GPIO_INPUT_LVP_Pin) == GPIO_PIN_SET) &&  (HAL_GPIO_ReadPin(GPIO_INPUT_OVP_GPIO_Port, GPIO_INPUT_OVP_Pin) == GPIO_PIN_SET))
  {
    lvpAndOvpInput = 1;
  }else {
    lvpAndOvpInput = 0;
  }

  


  //Prüfe auf Wechsel des Modus AUTO / SM ON
  if (BUTTON_GetMode() == BUTTON_AUTO)
  {
    if (faultInput == 0) 
    {
      RELAIS_SetPuls();
      BUZZER_Beep(BUZZER_ON_TIME_CONFIRM);
      LEDS_GN_Blink_Start(LED_GN_ON_TIME_ON_MODE, LED_GN_OFF_TIME);
      printf("NEW_STATE: SECONDARYPROTECTION_ON\n");
      smState = SECONDARYPROTECTION_ON;
	  smError = ERROR_NONE;

    }
    else   
    {
      //Wechsel nicht möglich. Fehler Eingang aktiv
      BUZZER_Beep(BUZZER_ON_TIME_REJECT);
      BUTTON_SetModeOff();
      //LEDS_RT_Blink_Start(LED_RT_ON_TIME_WARN_FAULT_INPUT, LED_GN_OFF_TIME); //Fehler Anzeigen
	  LEDS_RT_BlinkCode_Start(BLINK_CODE_ERROR_FAULT_INPUT, LED_RT_ON_TIME_WARN_FAULT_INPUT, LED_RT_OFF_TIME, LED_RT_OFF_TIME *5); //Fehler Anzeigen
      printf("NEW_STATE: SECONDARYPROTECTION_ERROR\n");
      smState = SECONDARYPROTECTION_ERROR;
	  smError = ERROR_EXTERNAL_FAULT;
	
    }
  }


  ////Prüfe auf Wechsel in MANUAL ON Mode
  ////Keine Fehlerüberprüfungen. In diesem Modus werdem alle Alarme ignoriert.
  //if (BUTTON_GetMode() == BUTTON_MANUAL_ON)
  //{
      
  //    RELAIS_SetPuls();
  //    BUZZER_Alarm_Start(BUZZER_ON_TIME_ALARM_MANUAL_MODE, BUZZER_OFF_TIME);
  //    LEDS_GN_On();
  //    LEDS_RT_BlinkCode_Start(BLINK_CODE_WARN_MANUAL, LED_RT_ON_TIME_WARN_MANUAL_MODE, LED_RT_OFF_TIME, LED_RT_OFF_TIME * 5); //Fehler Anzeigen
  //    printf("NEW_STATE: SECONDARYPROTECTION_MANUAL_ON\n");
  //    smState = SECONDARYPROTECTION_MANUAL_ON;
  //}



}

static void SECONDARYPROTECTION_SM_On(void)
{
  int faultInput = 0;
  int lvpAndOvpInput = 0;
  static int lvpAndOvpInputTimeCounter = 0;
  static int oldtime;

  if (HAL_GPIO_ReadPin(GPIO_INPUT_FAULT_GPIO_Port, GPIO_INPUT_FAULT_Pin) == GPIO_PIN_RESET)       
  {
    faultInput = 1;
  }
  else
  {
    faultInput = 0;
  }
  

  if (faultInput == 1)
  {
    RELAIS_ResetPuls();
    BUZZER_Beep(BUZZER_ON_TIME_REJECT); //Warnung
    LEDS_GN_Off();
    LEDS_RT_BlinkCode_Start(BLINK_CODE_ERROR_FAULT_INPUT, LED_RT_ON_TIME_WARN_FAULT_INPUT, LED_RT_OFF_TIME, LED_RT_OFF_TIME *5); //Fehler Anzeigen
    BUTTON_SetModeOff(); //Damit nicht von alleine wieder eingeschaltet wird
    printf("FAULT INPUT EVENT DETECTED!\n");
    printf("NEW_STATE: SECONDARYPROTECTION_ERROR\n");
    smState = SECONDARYPROTECTION_ERROR;
	smError = ERROR_EXTERNAL_FAULT;
	return;
  }



  if ((HAL_GPIO_ReadPin(GPIO_INPUT_LVP_GPIO_Port, GPIO_INPUT_LVP_Pin) == GPIO_PIN_SET) &&  (HAL_GPIO_ReadPin(GPIO_INPUT_OVP_GPIO_Port, GPIO_INPUT_OVP_Pin) == GPIO_PIN_SET))
  {
    if (HAL_GetTick() != oldtime)
    {
      lvpAndOvpInputTimeCounter++;
      if (lvpAndOvpInputTimeCounter > 30000)
      {
        lvpAndOvpInput = 1;
        lvpAndOvpInputTimeCounter=0;
      }
      oldtime = HAL_GetTick();
    }
  }
  else 
  {
    lvpAndOvpInputTimeCounter = 0;
    lvpAndOvpInput = 0;
  }

  

  // Prüfe Wechsel in off mode
  if (BUTTON_GetMode() == BUTTON_OFF)
  {
    //Ausschalten muss immer möglich sein
    RELAIS_ResetPuls();
    BUZZER_Beep(BUZZER_ON_TIME_CONFIRM); //Bestätigung
    LEDS_GN_Off();
    LEDS_RT_Off();
    printf("NEW_STATE: SECONDARYPROTECTION_OFF\n");
    smState = SECONDARYPROTECTION_OFF;
	smError = ERROR_NONE;
  }

  //Prüfe auf Fehlermode
  if (VOLTAGE_MEAS_GetLimitAlarm() == 1)
  {
	  RELAIS_ResetPuls();
	  BUZZER_Beep(BUZZER_ON_TIME_REJECT); //Warnung
	  LEDS_GN_Off();
	  LEDS_RT_BlinkCode_Start(BLINK_CODE_ERROR_VOLTAGE_DROP, LED_RT_ON_TIME_WARN_VOLTAGE_DROP, LED_RT_OFF_TIME, LED_RT_OFF_TIME *5); //Fehler Anzeigen
	  BUTTON_SetModeOff(); //Damit nicht von alleine wieder eingeschaltet wird
	  printf("FAULT VOLTAGE DROP DETECTED!\n");
	  printf("NEW_STATE: SECONDARYPROTECTION_ERROR\n");
	  smState = SECONDARYPROTECTION_ERROR;  
	  smError = ERROR_VOLTAGE_DROP;
	  VOLTAGE_MEAS_ResetCounter(); // Damit Fehlerzähler bei Neustart auf 0
  }



  if (lvpAndOvpInput == 1)
  {
    RELAIS_ResetPuls();
    BUZZER_Beep(BUZZER_ON_TIME_REJECT); //Warnung
    LEDS_GN_Off();
    LEDS_RT_BlinkCode_Start(BLINK_CODE_ERROR_OVP_LVP, LED_RT_ON_TIME_WARN_OVP_AND_LVP_INPUT, LED_RT_OFF_TIME, LED_RT_OFF_TIME *5); //Fehler Anzeigen
    BUTTON_SetModeOff(); //Damit nicht von alleine wieder eingeschaltet wird
    printf("BMS SECONDARY PROTECTION FAULT EVENT DETECTED (LVP & OVP )!\n");
    printf("NEW_STATE: SECONDARYPROTECTION_ERROR\n");
    smState = SECONDARYPROTECTION_ERROR;
	smError = ERROR_LVP_AND_OVP;
  }

  if (CHIP_TEMPERATURE_GetTemp() > 80)
  {
	RELAIS_ResetPuls();
	BUZZER_Beep(BUZZER_ON_TIME_REJECT); //Warnung
	LEDS_GN_Off();
	LEDS_RT_BlinkCode_Start(BLINK_CODE_ERROR_TEMP, LED_RT_ON_TIME_WARN_TEMP, LED_GN_OFF_TIME, LED_GN_OFF_TIME *5); //Fehler Anzeigen
	BUTTON_SetModeOff(); //Damit nicht von alleine wieder eingeschaltet wird
	printf("NEW_STATE: MAINSWITCH_ERROR, Temp too high\n");
	smState = SECONDARYPROTECTION_ERROR;          
	smError = ERROR_TEMPERATURE;
  }



}

//static void SECONDARYPROTECTION_SM_ManualOn(void)
//{
//  // Prüfe Wechsel in off mode
//  if (BUTTON_GetMode() == BUTTON_OFF)
//  {
//    //Ausschalten muss immer möglich sein
//    RELAIS_ResetPuls();
//    BUZZER_Alarm_Stop();
//    LEDS_GN_Off();
//    LEDS_RT_Off();
//    printf("NEW_STATE: SECONDARYPROTECTION_OFF\n");
//    smState = SECONDARYPROTECTION_OFF;
//  }

//}

static void SECONDARYPROTECTION_SM_Error(void)
{
  int faultInput;
  int lvpAndOvpInput;
  static uint32_t retry_counter = 0;
  static uint32_t oldTimeMSTick;

  if (HAL_GPIO_ReadPin(GPIO_INPUT_FAULT_GPIO_Port, GPIO_INPUT_FAULT_Pin) == GPIO_PIN_RESET)       
  {
    faultInput = 1;
  }
  else
  {
    faultInput = 0;
  }



  //Prüfe auf Wechsel des Modus AUTO / SM ON
  if (BUTTON_GetMode() == BUTTON_AUTO) 
  {
    if (faultInput == 0) 
    {
	  retry_counter = 0;
      RELAIS_SetPuls();
      BUZZER_Beep(BUZZER_ON_TIME_CONFIRM);
      LEDS_GN_Blink_Start(LED_GN_ON_TIME_ON_MODE, LED_GN_OFF_TIME);
      LEDS_RT_Off(); //Fehler löschen
      printf("NEW_STATE: SECONDARYPROTECTION_ON\n");
      smState = SECONDARYPROTECTION_ON;
	  smError = ERROR_NONE;
    }
    else
    {
      //Wechsel nicht möglich. Fehler Eingang weiterhin aktiv
      BUZZER_Beep(BUZZER_ON_TIME_REJECT);
      BUTTON_SetModeOff();
    }
  }

  if (autoRetryMode == 1) {

    if (oldTimeMSTick != HAL_GetTick())
    {
  	oldTimeMSTick = HAL_GetTick();
  	retry_counter++;
    }

    if  (retry_counter > 3600000)  // jede stunde
    {
  	BUTTON_SetModeAuto();
  	retry_counter = 0;
    }
  }
  //Prüfe auf Wechsel in MANUAL ON Mode
  //Keine Fehlerüberprüfungen. In diesem Modus werdem alle Alarme ignoriert.
  //if (BUTTON_GetMode() == BUTTON_MANUAL_ON)
  //{
      
  //    RELAIS_SetPuls();
  //    BUZZER_Alarm_Start(BUZZER_ON_TIME_ALARM_MANUAL_MODE, BUZZER_OFF_TIME);
  //    LEDS_GN_On();
  //    LEDS_RT_Off();
  //    LEDS_RT_BlinkCode_Start(BLINK_CODE_WARN_MANUAL, LED_RT_ON_TIME_WARN_MANUAL_MODE, LED_RT_OFF_TIME, LED_RT_OFF_TIME *5); //Fehler Anzeigen
  //    printf("NEW_STATE: SECONDARYPROTECTION_MANUAL_ON\n");
  //    smState = SECONDARYPROTECTION_MANUAL_ON;
  //}



}



void MODE_SECONDARYPROTECTION_PLUS_Exec(int am)
{

  	autoRetryMode = am;

  switch (smState)
  {
    case SECONDARYPROTECTION_OFF:
      SECONDARYPROTECTION_SM_Off();
    break;

    case SECONDARYPROTECTION_ON:
      SECONDARYPROTECTION_SM_On();
    break;

    //case SECONDARYPROTECTION_MANUAL_ON:
      //SECONDARYPROTECTION_SM_ManualOn();
    //break;

    case SECONDARYPROTECTION_ERROR:
      SECONDARYPROTECTION_SM_Error();
    break;

    default:
    break;
  }
}


