/**
******************************************************************************
* @file upp_errors.c
* @brief Формирование ошибок в ПУИ
******************************************************************************
* @details
******************************************************************************/
#include "upp_main.h" // УПП
#include "upp_errors.h" // всё остальное по работе с УПП
UPP_Errors_t errors;

static UPP_ErrorType_t UPP_SelectCommonError(void);
static int setError(int condition, int flag, int *timer, int delay);
void UPP_Errors_Program(void);
void UPP_Errors_Power(void);
void UPP_Errors_Ranges(void);
void UPP_Errors_LossPhase(void);
void UPP_Errors_Other(void);



void UPP_Errors_Handle(void)
{
  /*====== Программные ошибки ======*/
  UPP_Errors_Program();
  /*====== Ошибки питания плат ======*/
  UPP_Errors_Power();
  /*====== Ошибки выхода за допустимые пределы ======*/
  UPP_Errors_Ranges();
  /*====== Потери фазы ======*/
  UPP_Errors_LossPhase();
  /*====== Остальные ======*/
  UPP_Errors_Other();
  
  
  
  
  
  errors.common = UPP_SelectCommonError();
}

void UPP_Errors_Program(void)
{
  
}

void UPP_Errors_Power(void)
{
  //read discrete inputs
}

void UPP_Errors_Ranges(void)
{
  /* Преобразуем уставки в нормальные тики */
  float ticksTiMax = to_float(PARAM_PUI.TiMax, 1)/PM_SLOW_PERIOD_US;
  /* Счетчики для отсчитывания задержки выставления ошибки */
  static int IMaxCnt = 0;
  static int UMaxCnt = 0;
  static int UMinCnt = 0;
  static int FMaxCnt = 0;
  static int FMinCnt = 0;
  static int TMaxCnt = 0;
  
  /* Напряжения */  
  errors.pui.err.OverVoltage = setError(errors.prvt.f.err.uamp_max,
                                        errors.pui.err.OverVoltage,
                                        &UMaxCnt,
                                        ticksTiMax); 
  errors.pui.err.UnderVoltage = setError(errors.prvt.f.err.uamp_min,
                                        errors.pui.err.UnderVoltage,
                                        &UMinCnt,
                                        ticksTiMax); 
  
  
  /* Токи */
  int i_max = ( errors.prvt.f.err.iamp_max ||
                errors.prvt.f.err.ia_max ||
                errors.prvt.f.err.ib_max ||
                errors.prvt.f.err.ic_max);
  errors.pui.err.OverCurrent = setError(i_max,
                                        errors.pui.err.OverCurrent,
                                        &IMaxCnt,
                                        ticksTiMax); 
  
  
  /* Частота */
  int f_max = ( errors.prvt.f.err.fac_max ||
                errors.prvt.f.err.fba_max ||
                errors.prvt.f.err.fbc_max);
  int f_min = ( errors.prvt.f.err.fac_max ||
                errors.prvt.f.err.fba_max ||
                errors.prvt.f.err.fbc_max);  
  errors.pui.err.OverFrequency = setError(f_max,
                                          errors.pui.err.OverFrequency,
                                          &FMaxCnt,
                                          ERRORS_DELAY_TICKS_DEFAULT);
  
  errors.pui.err.UnderFrequency = setError( f_min,
                                            errors.pui.err.UnderFrequency,
                                            &FMinCnt,
                                            ERRORS_DELAY_TICKS_DEFAULT);
  
  
  /* Температуры */
  errors.pui.err.OverTemperature = setError(errors.prvt.f.err.temp_err,
                                            errors.pui.err.OverTemperature,
                                            &TMaxCnt,
                                            ERRORS_DELAY_TICKS_DEFAULT);
}

void UPP_Errors_LossPhase(void)
{
  /* Счетчики для отсчитывания задержки выставления ошибки */
  static int LossPhaseAllCnt = 0;
  static int LossPhaseACnt = 0;
  static int LossPhaseBCnt = 0;
  static int LossPhaseCCnt = 0;
  
  int loss_phases_all = ( errors.prvt.f.err.ia_min &&
                          errors.prvt.f.err.ib_min &&
                          errors.prvt.f.err.ic_min );
  
  errors.pui.err.LossPhaseAll = setError( loss_phases_all,
                                        errors.pui.err.LossPhaseAll,
                                        &LossPhaseAllCnt,
                                        ERRORS_DELAY_TICKS_DEFAULT);
  
  /* Если хотя бы одна фаза есть проверяем фазы отдельно */
  if(!errors.pui.err.LossPhaseAll)
  {
    errors.pui.err.LossPhaseA = setError( errors.prvt.f.err.ia_min,
                                          errors.pui.err.LossPhaseA,
                                          &LossPhaseACnt,
                                          ERRORS_DELAY_TICKS_DEFAULT);
    
    errors.pui.err.LossPhaseB = setError( errors.prvt.f.err.ib_min,
                                          errors.pui.err.LossPhaseB,
                                          &LossPhaseBCnt,
                                          ERRORS_DELAY_TICKS_DEFAULT);
    
    errors.pui.err.LossPhaseC = setError( errors.prvt.f.err.ic_min,
                                          errors.pui.err.LossPhaseC,
                                          &LossPhaseCCnt,
                                          ERRORS_DELAY_TICKS_DEFAULT);
  }
  /* Если всех фаз нет, то отдельные не смотрим */
  else
  {
    errors.pui.err.LossPhaseA = 0;
    errors.pui.err.LossPhaseB = 0;
    errors.pui.err.LossPhaseC = 0;
  }
}

void UPP_Errors_Other(void)
{
  static int InterlaceCnt = 0;
  
  if(errors.prvt.f.err.longstart)
    errors.pui.err.LongStart = 1;
  else
    errors.pui.err.LongStart = 0;
  
  errors.pui.err.Interlace = setError(errors.prvt.f.err.interlance,
                                      errors.pui.err.Interlace,
                                      &InterlaceCnt,
                                      ERRORS_DELAY_TICKS_DEFAULT);
  //Interlance
}

static UPP_ErrorType_t UPP_SelectCommonError(void)
{
  // Пока нет ошибки
  UPP_ErrorType_t best = Err_None;
  // Приоритет отсутствия ошибок
  uint8_t best_prio = UPP_ErrorPriority[Err_None];

  // Перебираем все возможные ошибки по enum
  for (int e = Err_None + 1; e <= Err_UnderFrequency; e++)
  {
    // Проверяем: установлен ли соответствующий бит в pui.all
    // e-1, потому что ошибка №1 = бит 0, ошибка №2 = бит 1 и т.д.
    if (errors.pui.all & (1u << (e - 1)))
    {
      // Получаем приоритет этой ошибки
      uint8_t pr = UPP_ErrorPriority[e];

      // Если её приоритет лучше (меньше число) — запоминаем
      if (pr < best_prio)
      {
        best_prio = pr;
        best = (UPP_ErrorType_t)e;
      }
    }
  }

  // Возвращаем самую важную (наивысшего приоритета) ошибку
  return best;
}


static int setError(int condition, int flag, int *timer, int delay)
{
  if (condition) {
    if (*timer < delay)
      (*timer)++;
    else
      flag = 1;
  } else {
    if (*timer > 0)
      (*timer)--;
    else
      flag = 0;
  }

  return flag;
}