/********************************* (C) РОТЕК ***********************************
 * @module  ups_monitor
 * @file    ups_monitor.c
 * @version 1.0.0
 * @date    XX.XX.XXXX
 * $brief   Template
 *******************************************************************************
 * @history     Version  Author         Comment
 * XX.XX.XXXX   1.0.0    Telenkov D.A.  First release.
 *******************************************************************************
 */
#pragma GCC diagnostic error "-Wall"
#pragma GCC diagnostic error "-Wextra"
#include "FreeRTOS.h"
#include "task.h"
#include "fr_timers.h"
#include "stm32f4xx.h"
#include "ups_monitor.h"
#include "parameters.h"
#include "settings_api.h"
#include "megatec.h"
#include "led.h"
#include "log.h"
#include "rtc.h"
#include "hal.h"

#include "FreeRTOS.h"
#include "task.h"

#include "trap_api.h"
#include "snmp_api.h"
#include "syslog.h"

#include <stdbool.h>

#ifdef PRINTF_STDLIB
#include <stdio.h>
#endif
#ifdef PRINTF_CUSTOM
#include "tinystdio.h"
#endif


bool flCriticalAlarm = false;
bool flNonCriticalAlarm = false;
bool flLedAlarm = false;

/**
  * @brief  Общая структура настроек
  */
extern SETTINGS_t sSettings;

extern bool flUpdateLog;

extern int test_time;
#if defined(INVERTERHIGHVOLTAGE_MONITOR) || defined(OVERTEMPRATURE_MONITOR)
TimerHandle_t UPSRestartTimer;

void UPSRestartCallback(TimerHandle_t pxTimer) {
  UPScmd(ups_remote_turn_on);
}
#endif
#ifdef INVERTERHIGHVOLTAGE_MONITOR
TimerHandle_t UPSTurnOffTimer;

void UPSTurnOffCallback(TimerHandle_t pxTimer) {
  UPScmd(ups_remote_turn_off);
  xTimerStart(UPSRestartTimer, 0);
}
#endif
/**
  * @brief  Задача мониторинга параметров UPS
  */
void UPS_Monitor(void *params)
{
	(void)params;
#if defined(INVERTERHIGHVOLTAGE_MONITOR) || defined(OVERTEMPRATURE_MONITOR)
  UPSRestartTimer = xTimerCreate("UPSRestartTmr", configTICK_RATE_HZ*10, pdFALSE, ( void * ) 0, UPSRestartCallback);
#endif
#ifdef INVERTERHIGHVOLTAGE_MONITOR
  UPSTurnOffTimer = xTimerCreate("UPSTurnOffTmr", configTICK_RATE_HZ*300, pdFALSE, ( void * ) 0, UPSTurnOffCallback);
#endif
	vTaskDelay(5000);
  for (;;)
  {
		flCriticalAlarm = false;
	  flNonCriticalAlarm = false;
    flLedAlarm = false;

#define XMONITOR(monitor_func, present) if (present) { monitor_func(); }
        MONITOR_TABLE
#undef XMONITOR

#ifdef LED_ALARM
      if(flLedAlarm){
    	  if (UPS.Present == UPS_CONNECTED)
    		  LED_On(LED_ALARM);
    	  else
    		  LED_Toggle(LED_ALARM);
      }
      else{
    	  LED_Off(LED_ALARM);
      }
#endif
    vTaskDelay(1000);
  }
}

#ifdef DINS_ENABLE
/**
  * @brief  Мониторинг бита DI0 state
  */
void UPS_DI0Monitor(void)
{
#ifdef DIN_MONITOR
  static bool isValueRecv = false;
  static uint8_t DI0OldState[INPUTS_TOTAL_COUNT];
  uint8_t DI0StateCurrent;

  for(uint8_t i = 0; i < INPUTS_TOTAL_COUNT; i ++) {
    DI0StateCurrent = get_state_din_outs((DIN1+i)) ^ sSettings.sDINs[i].din_type_act;

    UPS.Alarm = (UPS.Alarm & ~(1 << (4 + i))) | (DI0StateCurrent << (4 + i));

      if (!isValueRecv) {
      DI0OldState[i] = DI0StateCurrent;
      if (DI0StateCurrent){
        log_event_data((LOG_ALARM_DIO + i), "Авария");
        SNMP_SendUserTrap(DI0_ALARM + 2*i);
        flUpdateLog = true;
      }
      else{
        log_event_data((LOG_ALARM_DIO + i), "Норма");
        SNMP_SendUserTrap(DI0_NORM + 2*i);
        flUpdateLog = true;
      }
      if (i == (INPUTS_TOTAL_COUNT - 1)) {
        isValueRecv = true;
        break;
      } 
      continue;
    }

    if (DI0StateCurrent) {
      flLedAlarm = true;
    }
      
    // Значение параметра изменилось
    if (DI0StateCurrent != DI0OldState[i])
    {
      if (!DI0StateCurrent){
        log_event_data((LOG_ALARM_DIO + i), "Норма");
        SNMP_SendUserTrap((DI0_NORM + 2*i));
        flUpdateLog = true;
      }
      else{
        log_event_data((LOG_ALARM_DIO + i), "Авария");
        SNMP_SendUserTrap(DI0_ALARM + 2*i);
        flUpdateLog = true;
      }

    }

    DI0OldState[i] = DI0StateCurrent;
  }
#endif
}
#endif

#ifdef  DOUTS_ENABLE 
void relay_setup_log(uint8_t *curr_source, ro_type_source_t src_act_ro, uint8_t state_relay)
{
	uint8_t i = 0;

	for(i = 0; i < OUTPUTS_TOTAL_COUNT; i ++){
		if(curr_source[i] == src_act_ro){
			  SetROInt(state_relay, i);
			  SNMP_SendUserTrap((DO0_TOGGLED+i));
			  if(state_relay){
				  flUpdateLog = true;
#if	defined RELAY_NC
				  log_event_data((LOG_DO0_STATE + i), "Разомкнуто");
#else
				  log_event_data((LOG_DO0_STATE + i), "Замкнуто");
#endif

			  }
			  else{
				  flUpdateLog = true;
#if	defined RELAY_NC
				  log_event_data((LOG_DO0_STATE + i), "Замкнуто");
#else
				  log_event_data((LOG_DO0_STATE + i), "Разомкнуто");
#endif
			  }
		}
	}
}


void relay_setup_log_change(uint8_t *curr_source, uint8_t *prev_source, ro_type_source_t src_act_ro)
{
	uint8_t i = 0;

	for(i = 0; i < OUTPUTS_TOTAL_COUNT; i ++){
		if(curr_source[i] != prev_source[i] && (prev_source[i] == src_act_ro || curr_source[i] == src_act_ro)){
#if	defined RELAY_NC
			if(curr_source[i] != src_act_ro){
				flUpdateLog = true;
				 SetROInt(0, i);
				 SNMP_SendUserTrap((DO0_TOGGLED+i));
				 log_event_data((LOG_DO0_STATE + i), "Замкнуто");
			  }
			  else{
				  flUpdateLog = true;
				  SetROInt(1, i);
				  SNMP_SendUserTrap((DO0_TOGGLED+i));
				  log_event_data((LOG_DO0_STATE + i), "Разомкнуто");
			  }
#else
			  if(curr_source[i] != src_act_ro){
				  flUpdateLog = true;
				  SetROInt(0, i);
				  SNMP_SendUserTrap((DO0_TOGGLED+i));
				  log_event_data((LOG_DO0_STATE + i), "Разомкнуто");
			  }
			  else{
				  flUpdateLog = true;
				  SetROInt(1, i);
				 SNMP_SendUserTrap((DO0_TOGGLED+i));
				  log_event_data((LOG_DO0_STATE + i), "Замкнуто");
			  }
#endif

		}
	}
}
#endif


#ifdef TYPE_CRITICAL_ALARM_MONITOR
/**
  * @brief  Мониторинг бита CriticalAlarm
  */
void UPS_CriticalAlarmMonitor(void)
{
  static bool isValueRecv = false;
  static uint8_t CriticalAlarmOldState = 0;
  uint8_t CriticalAlarmCurrent;
  uint8_t i = 0;
  static uint8_t OldROtype_Sourse[OUTPUTS_TOTAL_COUNT] = {0};
  uint8_t CurrROtype_Sourse[OUTPUTS_TOTAL_COUNT] = {0};

  for(i = 0; i < OUTPUTS_TOTAL_COUNT; i ++)
	  CurrROtype_Sourse[i] = sSettings.sRelays[i].ro_type_source;

  CriticalAlarmCurrent = flCriticalAlarm;

  if (!isValueRecv) {
	isValueRecv = true;
	CriticalAlarmOldState = CriticalAlarmCurrent;
	for(i = 0; i < OUTPUTS_TOTAL_COUNT; i ++)
		OldROtype_Sourse[i] = CurrROtype_Sourse[i];
	if(CriticalAlarmCurrent){
	  relay_setup_log(CurrROtype_Sourse, CRITICAL, 1);
	}
	else{
		relay_setup_log(CurrROtype_Sourse, CRITICAL, 0);
	}
	return;
  }

  // Значение параметра изменилось
  if (CriticalAlarmCurrent != CriticalAlarmOldState)
  {
	  if(CriticalAlarmCurrent){
		  relay_setup_log(CurrROtype_Sourse, CRITICAL, 1);
	  }
	  else{
		  relay_setup_log(CurrROtype_Sourse, CRITICAL, 0);
	  }
  }
  else
  {
	  if(CriticalAlarmCurrent)
		  relay_setup_log_change(CurrROtype_Sourse, OldROtype_Sourse, CRITICAL);

  }

	for(i = 0; i < OUTPUTS_TOTAL_COUNT; i ++){
	  OldROtype_Sourse[i] = CurrROtype_Sourse[i];
	}
  CriticalAlarmOldState = CriticalAlarmCurrent;
}

/**
  * @brief  Мониторинг бита NonCriticalAlarm
  */
void UPS_NonCriticalAlarmMonitor(void)
{
  static bool isValueRecv = false;
  static uint8_t NonCriticalAlarmOldState = 0;
  uint8_t NonCriticalAlarmCurrent;
  uint8_t i = 0;
  static uint8_t OldROtype_Sourse[OUTPUTS_TOTAL_COUNT] = {0};
  uint8_t CurrROtype_Sourse[OUTPUTS_TOTAL_COUNT] = {0};

  for(i = 0; i < OUTPUTS_TOTAL_COUNT; i ++)
	  CurrROtype_Sourse[i] = sSettings.sRelays[i].ro_type_source;

  NonCriticalAlarmCurrent = flNonCriticalAlarm;

  if (!isValueRecv) {
	isValueRecv = true;
	NonCriticalAlarmOldState = NonCriticalAlarmCurrent;
	 for(i = 0; i < OUTPUTS_TOTAL_COUNT; i ++)
		 OldROtype_Sourse[i] = CurrROtype_Sourse[i];
	  if(NonCriticalAlarmCurrent)
		  relay_setup_log(CurrROtype_Sourse, NON_CRITICAL, 1);
	  else
		  relay_setup_log(CurrROtype_Sourse, NON_CRITICAL, 0);

	return;
  }

  // Значение параметра изменилось
  if (NonCriticalAlarmCurrent != NonCriticalAlarmOldState)
  {
	  if(NonCriticalAlarmCurrent){
		  relay_setup_log(CurrROtype_Sourse, NON_CRITICAL, 1);
	  }
	  else{
		  relay_setup_log(CurrROtype_Sourse, NON_CRITICAL, 0);
	  }
  }
  else
  {
	  if(NonCriticalAlarmCurrent)
		  relay_setup_log_change(CurrROtype_Sourse, OldROtype_Sourse, NON_CRITICAL);
  }

  for(i = 0; i < OUTPUTS_TOTAL_COUNT; i ++){
  	  OldROtype_Sourse[i] = CurrROtype_Sourse[i];
  }
  NonCriticalAlarmOldState = NonCriticalAlarmCurrent;
}
#endif
static bool test_akb_flag = false;
/**
  * @brief  Мониторинг бита Test in progress
  */
void UPS_TestFinishMonitor(void)
{
#ifdef TEST_AKB_FINISH_MONITOR
  static uint8_t TestFinishState = 0;
  uint8_t TestFinishStateCurrent;
  char log_string[50];
  static uint32_t start_time_test = 0;

  TestFinishStateCurrent = (UPS.Status >> 2) & 0x01;

  // Значение параметра изменилось
  if (TestFinishStateCurrent != TestFinishState)
  {
    if (!TestFinishStateCurrent){
      printf("Test finish\r\n");
#ifdef TEST_ALARM_AKB_MONITOR
      float time_test_actual = ((float)(xTaskGetTickCount() - start_time_test)) / (1000*60);
      UPSReadTestStatus();

#ifdef RELAY_ALARM_AKB
      static uint8_t AKBAlarmState = 0;
      uint8_t i = 0;
      static uint8_t OldROtype_Sourse[OUTPUTS_TOTAL_COUNT] = {0};
      uint8_t CurrROtype_Sourse[OUTPUTS_TOTAL_COUNT] = {0};

      for(i = 0; i < OUTPUTS_TOTAL_COUNT; i ++)
	        CurrROtype_Sourse[i] = sSettings.sRelays[i].ro_type_source;
#endif
      float Uakb_av = voltage_bat_average();
      float Pload_av = power_load_average();
      float k_eff;
      printf("Uakb_av: %0.2f", Uakb_av);
      printf("Pload_av: %0.2f", Pload_av);
      if(UPS.Test_Status != 2 && Pload_av >= 3) {
        GetUPSEfficiencyFactorInt(&k_eff);
        float Ccalc = (sSettings.UPS_Setting.ups_power*Pload_av*time_test_actual)/(100*60*Uakb_av*(k_eff));
        printf("Ccalc: %0.2f", Ccalc);
        float Ccalc_percent = (100*Ccalc)/sSettings.UPS_Setting.common_capacity;
        if (Ccalc_percent >= 80) {
          sprintf(log_string, "Авария(%0.2f Ач)", Ccalc);
          log_event_data(LOG_TEST_ALARM_AKB, log_string);
	        syslog(SYSLOG_INFORMATIONAL, "Ёмкость АКБ: %s", log_string);
#if HARDWARE_BT6711 || HARDWARE_BT6711_V1
          SNMP_SendUserTrap(BATTERY_FAIL);
#endif
#ifdef RELAY_ALARM_AKB
          relay_setup_log(CurrROtype_Sourse, ALARM_AKB, 1);
          AKBAlarmState = 1;
#endif
        } else {
          sprintf(log_string, "Норма(%0.2f Ач)", Ccalc);
          log_event_data(LOG_TEST_ALARM_AKB, log_string);
	        syslog(SYSLOG_INFORMATIONAL, "Ёмкость АКБ: %s", log_string);
#if HARDWARE_BT6711 || HARDWARE_BT6711_V1
          SNMP_SendUserTrap(BATTERY_NORM);
#endif
#ifdef RELAY_ALARM_AKB
          relay_setup_log(CurrROtype_Sourse, ALARM_AKB, 0);
          AKBAlarmState = 0;
#endif
        }
      }
#ifdef RELAY_ALARM_AKB
      if (AKBAlarmState)
          relay_setup_log_change(CurrROtype_Sourse, OldROtype_Sourse, ALARM_AKB);

      for(i = 0; i < OUTPUTS_TOTAL_COUNT; i ++)
          OldROtype_Sourse[i] = CurrROtype_Sourse[i];
#endif
      memset(log_string, 0, sizeof(log_string));
      if(UPS.Test_Status == 2 ||( (time_test_actual <= 0.9*test_time || time_test_actual >= 1.1*test_time) && (test_time != 0 && test_time != 100))){// 
        strcpy(log_string, "Ошибка");
      } else {
        strcpy(log_string, "Завершен");
      }
       uint8_t len1 = strlen(log_string);
       sprintf(&log_string[len1], "(%0.1f мин)", time_test_actual);
       log_event_data(LOG_TEST_UPS, log_string);
       syslog(SYSLOG_INFORMATIONAL, "Тест батареи: %s", log_string);
       test_time = 0;
#if HARDWARE_BT6711 || HARDWARE_BT6711_V1
          SNMP_SendUserTrap(TEST_BAT_STOP);
#endif
#else
      log_event_data(LOG_TEST_UPS, "Завершен");
      syslog_str(SYSLOG_INFORMATIONAL, "Тест батареи: Завершён");
#endif
      flUpdateLog = true;
    } else {
      test_akb_flag = true;
      memset(log_string, 0, sizeof(log_string));
      switch (get_act_source()) {
        case WEB_ACT:
            strcpy(log_string, name_login);
            break;
        case SNMP_ACT:
        case OTHER_ACT:
            strcpy(log_string, "Администратор");
            break;
#ifdef CLI_ENABLE
        case CLI_ACT:
            strcpy(log_string, "Администратор");
            break;
#endif
        case AUTO_ACT:
            strcpy(log_string, "Автоматический");
            break;
        default:
            break;
      }
#ifdef TEST_ALARM_AKB_MONITOR
      start_time_test = xTaskGetTickCount();
     if (test_time == 0) {
       strcat(log_string, " (авто)");
     } else if (test_time == 100) {
        strcat(log_string, " (до разряда)");
     } else {
       uint8_t len = strlen(log_string);
       sprintf(&log_string[len], "(%i мин)", test_time);
     }
#else
       strcat(log_string, " (Запущен)");
#endif
      printf("Test start\r\n");
      log_event_data(LOG_TEST_UPS, log_string);
      syslog(SYSLOG_INFORMATIONAL, "Тест батареи: %s", log_string);
#if HARDWARE_BT6711 || HARDWARE_BT6711_V1
          SNMP_SendUserTrap(TEST_BAT_RUN);
#endif
      flUpdateLog = true;
    }
  }

  TestFinishState = TestFinishStateCurrent;
#endif
}

uint8_t UPS_VACinputRangeAlarm(void)
{
#ifdef VAC_IN_MONITOR
  uint8_t flag = 0;
  static uint8_t stateCurrentVACinput_low = HYST_IDLE;
  static uint8_t stateCurrentVACinput_high = HYST_IDLE;
  float VACinputCurrent = UPS.VAC_in;
  static uint8_t cnt = 0;
  if(test_akb_flag) {
   
    if (UPS.VAC_in>255) {
      test_akb_flag = false;
      cnt = 0;
      ups_metac_service_pdu(ups_cancel_test);
      log_event_data(LOG_TEST_UPS, "Ошибка");
    } else {
      if(cnt < 20){
        cnt++;
      } else {
          if (UPS.Mode == 'L') {
            test_akb_flag = false;
          }
        cnt = 0;
      }
    }
  }

  /* Отслеживается переход через нижнию границу */
  if (VACinputCurrent < sSettings.sAlarmManager.ac_input_range.low)
  {
      if (stateCurrentVACinput_low == HYST_IDLE || stateCurrentVACinput_low == HYST_DOWN) {
        stateCurrentVACinput_low = HYST_DOWN;
        flag |= (1 << 1);
      }
  } else  if (VACinputCurrent > (sSettings.sAlarmManager.ac_input_range.low + sSettings.sAlarmManager.ac_input_range.hyst))
  {
      if (stateCurrentVACinput_low == HYST_DOWN)
	    {
        stateCurrentVACinput_low = HYST_IDLE;
        flag &= 0xfd;
      }
  } else {
    if (stateCurrentVACinput_low == HYST_DOWN) {
      flag |= (1 << 1);
    }
  }

  /* Отслеживается переход через верхнюю границу */
  if (VACinputCurrent > sSettings.sAlarmManager.ac_input_range.high)
  {
      if (stateCurrentVACinput_high == HYST_IDLE || stateCurrentVACinput_high == HYST_UP) {
        stateCurrentVACinput_high = HYST_UP;
        flag |= (1 << 2);
      }
  } else  if (VACinputCurrent < (sSettings.sAlarmManager.ac_input_range.high - sSettings.sAlarmManager.ac_input_range.hyst))
  {
      if (stateCurrentVACinput_high == HYST_UP)
	    {
        stateCurrentVACinput_high = HYST_IDLE;
        flag &= 0xfb;
      }
  } else {
    if (stateCurrentVACinput_high == HYST_UP) {
      flag |= (1 << 2);
    }
  }
  return flag;
#endif
}

/**
  * @brief  Мониторинг бита LainFail
  */
void UPS_LineFailMonitor(void)
{
#ifdef LINE_FAIL_MONITOR
  static bool isValueRecv = false;
  static uint8_t lineFailOldState = 0;
  uint8_t lineFailCurrent;
  char log_string[50];
  uint8_t len;

#if defined RELAY_AC_PRESENT
  uint8_t i = 0;
  static uint8_t OldROtype_Sourse[OUTPUTS_TOTAL_COUNT] = {0};
  uint8_t CurrROtype_Sourse[OUTPUTS_TOTAL_COUNT] = {0};

  for(i = 0; i < OUTPUTS_TOTAL_COUNT; i ++)
	  CurrROtype_Sourse[i] = sSettings.sRelays[i].ro_type_source;
#endif
#ifdef VAC_IN_MONITOR
  lineFailCurrent = ((UPS.Status >> 7) & 0x01);
  lineFailCurrent |= UPS_VACinputRangeAlarm();
#else 
  lineFailCurrent = (UPS.Status >> 7) & 0x01;
#endif
  
  if (!isValueRecv) {
    isValueRecv = true;
    lineFailOldState = lineFailCurrent;

    if (lineFailCurrent != 0){
      memset(log_string, 0, sizeof(log_string));
      strcat(log_string, "Авария");
       len = strlen(log_string);
       sprintf(&log_string[len], " (%0.1f В)", UPS.VAC_in);  
    	log_event_data(LOG_ALARM_LINE, log_string);
          SNMP_SendUserTrap(LINE_ALARM);
          syslog(SYSLOG_ERROR, "Авария сети (%0.1f В)", UPS.VAC_in);
          flUpdateLog = true;
#if	defined RELAY_AC_PRESENT
    	relay_setup_log(CurrROtype_Sourse, AC_PRESENT, 1);
#endif
    }
    else{
#if	defined RELAY_AC_PRESENT
      relay_setup_log(CurrROtype_Sourse, AC_PRESENT, 0);
#endif
      log_event_data(LOG_ALARM_LINE, "Норма");
      SNMP_SendUserTrap(LINE_NORM);
      syslog(SYSLOG_NOTICE, "Сеть в норме (%0.1f В)", UPS.VAC_in);
      flUpdateLog = true;
    }

    return;
  }

  if (lineFailCurrent != 0){
    flCriticalAlarm = true;
    flLedAlarm = true;
  }
	  
  // Значение параметра изменилось
  if (lineFailCurrent != lineFailOldState)
  {
    if (lineFailCurrent != 0){
#if	defined RELAY_AC_PRESENT
    	relay_setup_log(CurrROtype_Sourse, AC_PRESENT, 1);
#endif

      memset(log_string, 0, sizeof(log_string));
      strcat(log_string, "Авария");
       len = strlen(log_string);
       sprintf(&log_string[len], " (%0.1f В)", UPS.VAC_in);  
    	log_event_data(LOG_ALARM_LINE, log_string);
    	SNMP_SendUserTrap(LINE_ALARM);
       syslog(SYSLOG_ERROR, "Авария сети (%0.1f В)", UPS.VAC_in);
#ifdef AKB_CHANGE_MONITOR
      if(UPS.Alarm & 0x40) {
        log_event_data(LOG_ALARM_CHANGE_AKB, "Авария");
    	  SNMP_SendUserTrap(BATTERY_CHANGE_ALARM);
      }   
#endif
    	flUpdateLog = true;
    }
    else{
      if (UPS.VAC_in == 0) {
        return;
      }
#if	defined RELAY_AC_PRESENT
      relay_setup_log(CurrROtype_Sourse, AC_PRESENT, 0);
#endif
      log_event_data(LOG_ALARM_LINE, "Норма");
      SNMP_SendUserTrap(LINE_NORM);
      syslog(SYSLOG_NOTICE, "Сеть в норме (%0.1f В)", UPS.VAC_in);
      flUpdateLog = true;
    }
  }

#if defined RELAY_AC_PRESENT
  else{
	  if (lineFailCurrent != 0)
		  relay_setup_log_change(CurrROtype_Sourse, OldROtype_Sourse, AC_PRESENT);
  }

  for(i = 0; i < OUTPUTS_TOTAL_COUNT; i ++){
	  OldROtype_Sourse[i] = CurrROtype_Sourse[i];
  }
#endif

  lineFailOldState = lineFailCurrent;
#endif
}

#ifdef VAC_OUT_MONITOR
/**
  * @brief  Мониторинг аварии выходного напряжения по нижней границе
  */
void UPS_VACoutputLowRangeMonitor(void)
{

  static uint8_t stateCurrentVACoutput = HYST_IDLE;
  float VACoutputCurrent;
#if	defined RELAY_DC_PRESENT
  uint8_t i = 0;
  static bool isValueRecv = false;
  static uint8_t OldROtype_Sourse[OUTPUTS_TOTAL_COUNT] = {0};
  uint8_t CurrROtype_Sourse[OUTPUTS_TOTAL_COUNT] = {0};

  for(i = 0; i < OUTPUTS_TOTAL_COUNT; i ++){
	  CurrROtype_Sourse[i] = sSettings.sRelays[i].ro_type_source;
	  if(!isValueRecv)
		  OldROtype_Sourse[i] = CurrROtype_Sourse[i];
  }
#endif

  VACoutputCurrent = UPS.VAC_out;

  /* Отслеживается переход через нижнию границу */
  if (VACoutputCurrent < sSettings.sAlarmManager.ac_output_range.low)
  {
      if (stateCurrentVACoutput == HYST_IDLE)
	    {
          UPS.Alarm |= (1 << 7);
          stateCurrentVACoutput = HYST_DOWN;
#if	defined RELAY_DC_PRESENT
          relay_setup_log(CurrROtype_Sourse, DC_PRESENT, 1);
#endif
	        log_event_data(LOG_ALARM_VAC_LOW_OUTPUT, "Авария");
#if HARDWARE_BT6711 || HARDWARE_BT6711_V1
	        // Отправка трапа о занижении
	        SNMP_SendUserTrap(VAC_LOW_OUTPUT_ALARM);
		syslog(SYSLOG_ERROR, "Низкое выходное напряжение (%0.1f В)", VACoutputCurrent);
#endif
	        flUpdateLog = true;
	    } else {
#if	defined RELAY_DC_PRESENT
    	    relay_setup_log_change(CurrROtype_Sourse, OldROtype_Sourse, DC_PRESENT);
#endif
      }
  }
  /* Отслеживается нормализация */
  else if (VACoutputCurrent > (sSettings.sAlarmManager.ac_output_range.low + sSettings.sAlarmManager.ac_output_range.hyst))
  {
      if (stateCurrentVACoutput == HYST_DOWN)
	    {
          UPS.Alarm &= 0xffffff7f;
    	    stateCurrentVACoutput = HYST_IDLE;
#if	defined RELAY_DC_PRESENT
	        relay_setup_log(CurrROtype_Sourse, DC_PRESENT, 0);
#endif
	        log_event_data(LOG_ALARM_VAC_LOW_OUTPUT, "Норма");
#if HARDWARE_BT6711 || HARDWARE_BT6711_V1
	        // Отправка трапа о нормализации
	        SNMP_SendUserTrap(VAC_LOW_OUTPUT_NORM);
		syslog(SYSLOG_NOTICE, "Выходное напряжение в норме (%0.1f В)", VACoutputCurrent);
#endif
	        flUpdateLog = true;
	    }
  } 
  if (UPS.Alarm & 0x80) {
    flLedAlarm = true;
  }
#if	defined RELAY_DC_PRESENT
  for(i = 0; i < OUTPUTS_TOTAL_COUNT; i ++){
  	  OldROtype_Sourse[i] = CurrROtype_Sourse[i];
    }
#endif
}

/**
  * @brief  Мониторинг аварии выходного напряжения по верхней границе
  */
void UPS_VACoutputHighRangeMonitor(void)
{

  static uint8_t stateCurrentVACoutput = HYST_IDLE;
  float VACoutputCurrent;
#if	defined RELAY_DC_PRESENT
  uint8_t i = 0;
  static bool isValueRecv = false;
  static uint8_t OldROtype_Sourse[OUTPUTS_TOTAL_COUNT] = {0};
  uint8_t CurrROtype_Sourse[OUTPUTS_TOTAL_COUNT] = {0};

  for(i = 0; i < OUTPUTS_TOTAL_COUNT; i ++){
	  CurrROtype_Sourse[i] = sSettings.sRelays[i].ro_type_source;
	  if(!isValueRecv)
		  OldROtype_Sourse[i] = CurrROtype_Sourse[i];
  }
#endif

  VACoutputCurrent = UPS.VAC_out;

  /* Отслеживается переход через верхнюю границу */
  if (VACoutputCurrent > sSettings.sAlarmManager.ac_output_range.high)
  {
      if (stateCurrentVACoutput == HYST_IDLE) {
          UPS.Alarm |= (1 << 7);
          stateCurrentVACoutput = HYST_UP;
#if	defined RELAY_DC_PRESENT
          relay_setup_log(CurrROtype_Sourse, DC_PRESENT, 1);
#endif
	        log_event_data(LOG_ALARM_VAC_HIGH_OUTPUT, "Авария");
#if HARDWARE_BT6711 || HARDWARE_BT6711_V1
	        // Отправка трапа о завышении
	        SNMP_SendUserTrap(VAC_HIGH_OUTPUT_ALARM);
		syslog(SYSLOG_ERROR, "Высокое входное напряжение (%0.1f В)", VACoutputCurrent);
#endif
	        flUpdateLog = true;
	    } else {
#if	defined RELAY_DC_PRESENT
    	    relay_setup_log_change(CurrROtype_Sourse, OldROtype_Sourse, DC_PRESENT);
#endif
      }
  }
  /* Отслеживается нормализация */
  else if (VACoutputCurrent < (sSettings.sAlarmManager.ac_output_range.high - sSettings.sAlarmManager.ac_output_range.hyst))
  {
      if (stateCurrentVACoutput == HYST_UP) {
          UPS.Alarm &= 0xffffff7f;
    	    stateCurrentVACoutput = HYST_IDLE;
#if	defined RELAY_DC_PRESENT
	        relay_setup_log(CurrROtype_Sourse, DC_PRESENT, 0);
#endif
	        log_event_data(LOG_ALARM_VAC_HIGH_OUTPUT, "Норма");
#if HARDWARE_BT6711 || HARDWARE_BT6711_V1       
	        // Отправка трапа о нормализации
	        SNMP_SendUserTrap(VAC_HIGH_OUTPUT_NORM);
		syslog(SYSLOG_NOTICE, "Выходное напряжение в норме (%0.1f В)", VACoutputCurrent);
#endif
	        flUpdateLog = true;
	    }
  }
  if (UPS.Alarm & 0x80) {
    flLedAlarm = true;
  }
#if	defined RELAY_DC_PRESENT
  for(i = 0; i < OUTPUTS_TOTAL_COUNT; i ++){
  	  OldROtype_Sourse[i] = CurrROtype_Sourse[i];
    }
#endif
}

#endif

/**
  * @brief  Мониторинг бита LowBat  
  */
void UPS_LowBatMonitor(void)
{
#ifdef LOW_BAT_MONITOR
  static bool isValueRecv = false;
  static uint8_t lowBatOldState = 0;
  static bool flag_alarm_time = false;
  uint8_t lowBatCurrent;

#if defined RELAY_CHARGE_AKB
  uint8_t i = 0;
  static uint8_t OldROtype_Sourse[OUTPUTS_TOTAL_COUNT] = {0};
  uint8_t CurrROtype_Sourse[OUTPUTS_TOTAL_COUNT] = {0};

  for(i = 0; i < OUTPUTS_TOTAL_COUNT; i ++)
	  CurrROtype_Sourse[i] = sSettings.sRelays[i].ro_type_source;
#endif

  if((UPS.Status >> 7) & 0x01)
	  lowBatCurrent = (UPS.Status >> 6) & 0x01;
  else
	  lowBatCurrent = 0;
  
  if (!isValueRecv) {
    isValueRecv = true;
    lowBatOldState = lowBatCurrent;
    if (lowBatCurrent){
    	log_event_data(LOG_ALARM_LOW_BAT, "Авария");
          SNMP_SendUserTrap(LOW_BAT_ALARM);
	  syslog(SYSLOG_ERROR, "Низкий заряд АКБ (%d%%)", UPS.SOC);
          flUpdateLog = true;
#if defined RELAY_CHARGE_AKB
      relay_setup_log(CurrROtype_Sourse, CHARGE_AKB, 1);
#endif
    }
    else{
	  SNMP_SendUserTrap(LOW_BAT_NORM);
	  log_event_data(LOG_ALARM_LOW_BAT, "Норма");
	  syslog(SYSLOG_NOTICE, "Заряд АКБ в норме (%d%%)", UPS.SOC);
	  flUpdateLog = true;
#if defined RELAY_CHARGE_AKB
	  relay_setup_log(CurrROtype_Sourse, CHARGE_AKB, 0);
#endif
	}
    return;
  }
  // Значение параметра изменилось
  if (lowBatCurrent != lowBatOldState)
  {
	if(flag_alarm_time){
		flag_alarm_time = false;
		if (lowBatCurrent){
		  SNMP_SendUserTrap(LOW_BAT_ALARM);
		  syslog(SYSLOG_ERROR, "Низкий заряд АКБ (%d%%)", UPS.SOC);
		  log_event_data(LOG_ALARM_LOW_BAT, "Авария");
		  flUpdateLog = true;
#ifdef RELAY_CHARGE_AKB
		  relay_setup_log(CurrROtype_Sourse, CHARGE_AKB, 1);
#endif
		}
		else{
		  SNMP_SendUserTrap(LOW_BAT_NORM);
		  syslog(SYSLOG_NOTICE, "Заряд АКБ в норме (%d%%)", UPS.SOC);
		  log_event_data(LOG_ALARM_LOW_BAT, "Норма");
		  flUpdateLog = true;
#if defined RELAY_CHARGE_AKB
		  relay_setup_log(CurrROtype_Sourse, CHARGE_AKB, 0);
#endif
		}
	}
	else{
		flag_alarm_time = true;
	}
  }
#if defined RELAY_CHARGE_AKB
  else{
	  flag_alarm_time = false;
	  if (lowBatCurrent)
		  relay_setup_log_change(CurrROtype_Sourse, OldROtype_Sourse, CHARGE_AKB);
  }

  for(i = 0; i < OUTPUTS_TOTAL_COUNT; i ++){
	  OldROtype_Sourse[i] = CurrROtype_Sourse[i];
  }
#endif
  
  if(!flag_alarm_time){
	  if (lowBatCurrent){
		  flNonCriticalAlarm = true;
      flLedAlarm = true;
	  }
	  lowBatOldState = lowBatCurrent;
  }
  else{
	  if (lowBatOldState){
		  flNonCriticalAlarm = true;
      flLedAlarm = true;
	  }
  }
#endif
}

static uint8_t UPS_LoadRangeAlarm(void)
{
#ifdef LOAD_MONITOR
  uint8_t flag = 0;
  static uint8_t stateCurrent = HYST_IDLE;
  float load = UPS.Load;

  /* Отслеживается переход через верхнюю границу */
  if (load > sSettings.sAlarmManager.load_range.high)
  {
     if (stateCurrent == HYST_IDLE || stateCurrent == HYST_UP) {
        stateCurrent = HYST_UP;
        flag = 1;
      }
  } else  if (load < (sSettings.sAlarmManager.load_range.high - sSettings.sAlarmManager.load_range.hyst))
  {
      if (stateCurrent == HYST_UP)
	    {
        stateCurrent = HYST_IDLE;
        flag = 0;
      }
  } else {
    if (stateCurrent == HYST_UP) {
      flag = 1;
    }
  }
  return flag;
#endif
}


/**
  * @brief  Мониторинг нагрузки 
  */
void UPS_PowerMonitor(void)
{
#ifdef LOAD_MONITOR
  uint8_t powerStatusCurrent;
  static uint8_t powerStatusOld = 0;

  if(!get_sync_data()) {
    return;
  }

  powerStatusCurrent = ((UPS.warn_status >> 5) & 0x01);
  powerStatusCurrent |= UPS_LoadRangeAlarm();

  if (powerStatusCurrent)
  {
	  UPS.Alarm = (UPS.Alarm & 0xfffffffe) | (1 << 0);
    if (powerStatusCurrent != powerStatusOld)
	{
#ifdef LED_RED_MINOR
      LED_On(LED_RED_MINOR);
#endif
#ifdef LED_GREEN_MINOR
      LED_On(LED_GREEN_MINOR);
#endif
      
	  log_event_data(LOG_ALARM_POWER, "Авария");
	  // Отправка трапа о завышении 
	  SNMP_SendUserTrap(POWER_ALARM);
	  syslog(SYSLOG_ERROR, "Авария нагрузки (%d%%)", UPS.Load);
	  flUpdateLog = true;
	}
  }
  /* Отслеживается нормализация */
  else {
    UPS.Alarm = (UPS.Alarm & 0xfffffffe);
    if (powerStatusCurrent != powerStatusOld)
    {
#ifdef LED_RED_MINOR
        LED_Off(LED_RED_MINOR);
#endif
#ifdef LED_GREEN_MINOR
        LED_Off(LED_GREEN_MINOR);
#endif 
      log_event_data(LOG_ALARM_POWER, "Норма");
      // Отправка трапа о нормализации 
      SNMP_SendUserTrap(POWER_NORM);
      syslog(SYSLOG_NOTICE, "Авария нагрузки нормализовалась (%d%%)", UPS.Load);
      flUpdateLog = true;
    }
  }

  powerStatusOld = powerStatusCurrent;

  if (UPS.Alarm & 0x00000001) {
    flCriticalAlarm = true;
    flLedAlarm = true;
  }
#endif
}

#ifdef SENSOR_TEMP_MONITOR
/**
  * @brief  Мониторинг аварии датчика температуры
  */
void sensorTemperatureMonitor(void)
{
  float temperature;
  static uint8_t type_sensor[MAX_T_SENSORS];
  static uint8_t alarm[MAX_T_SENSORS]; 
  static uint8_t start_monitor = 0;

  if (start_monitor == 0) {
    start_monitor = 1;
    for(uint8_t i = 0; i < MAX_T_SENSORS; i ++){
      type_sensor[i] = sSettings.sTempControl[i].type_sensor;
    }
  } 

  for(uint8_t i = 0; i < MAX_T_SENSORS; i ++){
    if (alarm[i] && sSettings.sTempControl[i].type_sensor != type_sensor[i]) {
      alarm[i] = 0;
      if (type_sensor[i] == TS_AKB) {
        log_event_data(LOG_ALARM_SENSOR_AKB, "Норма");
        flUpdateLog = true;
      } else if (type_sensor[i] == TS_CABINET) {
        log_event_data(LOG_ALARM_SENSOR_CABINET, "Норма");
        flUpdateLog = true;
      }
    }
    if (sSettings.sTempControl[i].type_sensor == TS_AKB) {
      GetInternalTempInt(&temperature);
      if(temperature == 85) {
        if(!alarm[i]) {
          log_event_data(LOG_ALARM_SENSOR_AKB, "Авария");
          flUpdateLog = true;
          flLedAlarm = true;
          alarm[i] = 1;
        }
      } else {
        if(alarm[i]) {
          log_event_data(LOG_ALARM_SENSOR_AKB, "Норма");
          flUpdateLog = true;
          alarm[i] = 0;
        }
      }
    } else if (sSettings.sTempControl[i].type_sensor == TS_CABINET) {
      GetTempCaseInt(&temperature);
      if(temperature == 85) {
        if(!alarm[i]) {
          log_event_data(LOG_ALARM_SENSOR_CABINET, "Авария");
          flUpdateLog = true;
          flLedAlarm = true;
          alarm[i] = 1;
        }
      } else {
        if(alarm[i]) {
          log_event_data(LOG_ALARM_SENSOR_CABINET, "Норма");
          flUpdateLog = true;
          alarm[i] = 0;
        }
      }
    }
    type_sensor[i] = sSettings.sTempControl[i].type_sensor;
  }
}

#endif

#ifdef TEMP_AKB_MONITOR

static uint8_t UPS_TempHighRangeAlarm(void)
{
  uint8_t flag = 0;
  float temperature;
  static uint8_t stateCurrent = HYST_IDLE;
    
  GetInternalTempInt(&temperature);

  if(temperature == 85) {
    if (stateCurrent == HYST_UP) {
      stateCurrent = HYST_IDLE;
      flag = 0;
    }
    return flag;
  }

  /* Отслеживается переход через верхнюю границу */
  if (temperature > sSettings.sAlarmManager.Temprature_range.high)
  {
     if (stateCurrent == HYST_IDLE || stateCurrent == HYST_UP) {
        stateCurrent = HYST_UP;
        flag = 1;
      }
  } else  if (temperature < (sSettings.sAlarmManager.Temprature_range.high - sSettings.sAlarmManager.Temprature_range.hyst))
  {
      if (stateCurrent == HYST_UP)
	    {
        stateCurrent = HYST_IDLE;
        flag = 0;
      }
  } else {
    if (stateCurrent == HYST_UP) {
      flag = 1;
    }
  }
  return flag;
}
/**
  * @brief  Мониторинг температуры по верхней границе
  */
void UPS_TemperatureHighRangeMonitor(void)
{
  float temperature;
  uint8_t tempStatusCurrent;
  static uint8_t tempStatusOld = 0;
    
  GetInternalTempInt(&temperature);

  tempStatusCurrent = ((UPS.warn_status >> 6) & 0x01);
  tempStatusCurrent |= UPS_TempHighRangeAlarm();

  if (tempStatusCurrent)
  {
    UPS.Alarm = (UPS.Alarm & 0xfffffffd) | (1 << 1);
    if (tempStatusCurrent != tempStatusOld) {
      log_event_data(LOG_ALARM_HIGH_TEMP, "Авария");
      // Отправка трапа о завышении 
      SNMP_SendUserTrap(BATTERY_HIGH_TEMPERATURE_ALARM);
      syslog(SYSLOG_ERROR, "Высокая температура (%0.1f C)", temperature);
      flUpdateLog = true;
    }
  }
  /* Отслеживается нормализация */
  else {
    UPS.Alarm = (UPS.Alarm & 0xfffffffd);
    if (tempStatusCurrent != tempStatusOld) {
	    log_event_data(LOG_ALARM_HIGH_TEMP, "Норма");
	  // Отправка трапа о нормализации 
	    SNMP_SendUserTrap(BATTERY_HIGH_TEMPERATURE_NORM);
	    syslog(SYSLOG_NOTICE, "Температура в норме (%0.1f C)", temperature);
	    flUpdateLog = true;
	  }
  }
  tempStatusOld = tempStatusCurrent;
  if (UPS.Alarm & 0x00000002) {
    flCriticalAlarm = true;
    flLedAlarm = true;
  }
}

/**
  * @brief  Мониторинг температуры по нижней границе
  */
void UPS_TemperatureLowRangeMonitor(void)
{
  float temperature;
  static uint8_t stateCurrent = HYST_IDLE;

  GetInternalTempInt(&temperature);

  if(temperature == 85) {
    UPS.Alarm = (UPS.Alarm & 0xfffffeff) | (1 << 8);
    if (stateCurrent == HYST_DOWN) {
      stateCurrent = HYST_IDLE;
      log_event_data(LOG_ALARM_LOW_TEMP, "Норма");
      // Отправка трапа о нормализации
	    SNMP_SendUserTrap(BATTERY_LOW_TEMPERATURE_NORM);
	    syslog(SYSLOG_NOTICE, "Температура в норме (%0.1f C)", temperature);
      flUpdateLog = true;
    }
    return;
  } else {
    if (stateCurrent == HYST_IDLE) {
      UPS.Alarm = (UPS.Alarm & 0xfffffeff);
    }
  }

  /* Отслеживается переход через нипжнюю границу */
  if (temperature < sSettings.sAlarmManager.Temprature_range.low)
  {
    if (stateCurrent == HYST_IDLE)
	{
	  stateCurrent = HYST_DOWN;
    UPS.Alarm = (UPS.Alarm & 0xfffffeff) | (1 << 8);

	  log_event_data(LOG_ALARM_LOW_TEMP, "Авария");
	  // Отправка трапа о занижении
	  SNMP_SendUserTrap(BATTERY_LOW_TEMPERATURE_ALARM);
	  syslog(SYSLOG_ERROR, "Низкая температура (%0.1f C)", temperature);
	  flUpdateLog = true;
	}
  }
  /* Отслеживается нормализация */
  else if (temperature > (sSettings.sAlarmManager.Temprature_range.low + sSettings.sAlarmManager.Temprature_range.hyst))
  {
    if (stateCurrent == HYST_DOWN)
	{
	  stateCurrent = HYST_IDLE;
    UPS.Alarm = (UPS.Alarm & 0xfffffeff);
	  log_event_data(LOG_ALARM_LOW_TEMP, "Норма");
	  // Отправка трапа о нормализации
	  SNMP_SendUserTrap(BATTERY_LOW_TEMPERATURE_NORM);
	  syslog(SYSLOG_NOTICE, "Температура в норме (%0.1f C)", temperature);
	  flUpdateLog = true;
	}
  }
  if (UPS.Alarm & 0x00000100) {
    flCriticalAlarm = true;
    flLedAlarm = true;
  }
}
#endif

#ifdef TEMP_CABINET_MONITOR
/**
  * @brief  Мониторинг температуры шкафа по верхней границе
  */
void Cabinet_TemperatureHighRangeMonitor(void)
{
  float temperature;
  static uint8_t stateCurrent = HYST_IDLE;
    
  GetTempCaseInt(&temperature);

  if(temperature == 85) {
    UPS.Alarm = (UPS.Alarm & 0xfffffdff) | (1 << 9);
    if (stateCurrent == HYST_UP) {
      stateCurrent = HYST_IDLE;
      log_event_data(LOG_ALARM_HIGH_CABINET_TEMP, "Норма");
      // Отправка трапа о нормализации
	    SNMP_SendUserTrap(CABINET_HIGH_TEMPERATURE_NORM);
      flUpdateLog = true;
    }
    return;
  } else {
    if (stateCurrent == HYST_IDLE) {
      UPS.Alarm = (UPS.Alarm & 0xfffffdff);
    }
  }
  /* Отслеживается переход через верхнюю границу */
  if (temperature > sSettings.sAlarmManager.Temprature_cabinet_range.high)
  {
	
    if (stateCurrent == HYST_IDLE)
	  {
      UPS.Alarm = (UPS.Alarm & 0xfffffdff) | (1 << 9);
	    stateCurrent = HYST_UP;
      

	  log_event_data(LOG_ALARM_HIGH_CABINET_TEMP, "Авария");
	  // Отправка трапа о завышении 
	  SNMP_SendUserTrap(CABINET_HIGH_TEMPERATURE_ALARM);
	  flUpdateLog = true;
	}
  }
  /* Отслеживается нормализация */
  else if (temperature < (sSettings.sAlarmManager.Temprature_cabinet_range.high - sSettings.sAlarmManager.Temprature_cabinet_range.hyst))
  {
    if (stateCurrent == HYST_UP)
	  {
      UPS.Alarm = (UPS.Alarm & 0xfffffdff);
	    stateCurrent = HYST_IDLE;
      
	  log_event_data(LOG_ALARM_HIGH_CABINET_TEMP, "Норма");
	  // Отправка трапа о нормализации 
	  SNMP_SendUserTrap(CABINET_HIGH_TEMPERATURE_NORM);
	  flUpdateLog = true;
	}
  }
  if (UPS.Alarm & 0x00000200) {
    flLedAlarm = true;
  }
}

/**
  * @brief  Мониторинг температуры шкафа по нижней границе
  */
void Cabinet_TemperatureLowRangeMonitor(void)
{
  float temperature;
  static uint8_t stateCurrent = HYST_IDLE;

  GetTempCaseInt(&temperature);

  if(temperature == 85) {
    UPS.Alarm = (UPS.Alarm & 0xfffffbff) | (1 << 10);
    if (stateCurrent == HYST_DOWN) {
      stateCurrent = HYST_IDLE;
      log_event_data(LOG_ALARM_LOW_CABINET_TEMP, "Норма");
      // Отправка трапа о нормализации
	    SNMP_SendUserTrap(CABINET_LOW_TEMPERATURE_NORM);
      flUpdateLog = true;
    }
    return;
  } else {
    if (stateCurrent == HYST_IDLE) {
      UPS.Alarm = (UPS.Alarm & 0xfffffbff);
    }
  }

  /* Отслеживается переход через нипжнюю границу */
  if (temperature < sSettings.sAlarmManager.Temprature_cabinet_range.low)
  {
    if (stateCurrent == HYST_IDLE)
	  {
	    stateCurrent = HYST_DOWN;
      UPS.Alarm = (UPS.Alarm & 0xfffffbff) | (1 << 10);

	  log_event_data(LOG_ALARM_LOW_CABINET_TEMP, "Авария");
	  // Отправка трапа о занижении
	  SNMP_SendUserTrap(CABINET_LOW_TEMPERATURE_ALARM);
	  flUpdateLog = true;
	}
  }
  /* Отслеживается нормализация */
  else if (temperature > (sSettings.sAlarmManager.Temprature_cabinet_range.low + sSettings.sAlarmManager.Temprature_cabinet_range.hyst))
  {
    if (stateCurrent == HYST_DOWN)
	  {
      UPS.Alarm = (UPS.Alarm & 0xfffffbff);
	    stateCurrent = HYST_IDLE;

	  log_event_data(LOG_ALARM_LOW_CABINET_TEMP, "Норма");
	  // Отправка трапа о нормализации
	  SNMP_SendUserTrap(CABINET_LOW_TEMPERATURE_NORM);
	  flUpdateLog = true;
	}
  }
  if (UPS.Alarm & 0x00000400) {
    flLedAlarm = true;
  }
}
#endif

/**
  * @brief  Мониторинг параметра upsParams.connect
  */
void UPS_ConnectMonitor(void)
{
#ifdef UPS_CONNECT_MONITOR
  static bool isValueRecv = false;
  static ups_state_connection_t connectOldState;
  ups_state_connection_t connectCurrent;
  
  connectCurrent = UPS.Present;

  if(connectCurrent == UPS_WAIT_CONNECT) {
    return;
  }
  
  UPS.Alarm = (UPS.Alarm & 0xfffffffb) | ((connectCurrent^1) << 2);

  if (!isValueRecv) {
    isValueRecv = true;
    connectOldState = connectCurrent;
    if (connectCurrent == UPS_FAIL_CONNECT){
    	log_event_data(LOG_ALARM_UPS, "Авария");
    	SNMP_SendUserTrap(CONNECT_MONITOR_ALARM);
	syslog_str(SYSLOG_ERROR, "Потеряна связь с ИБП");
    }
    else{
    	log_event_data(LOG_ALARM_UPS, "Норма");
		SNMP_SendUserTrap(CONNECT_MONITOR_NORM);
		syslog_str(SYSLOG_NOTICE, "Восстановлена связь с ИБП");
		flUpdateLog = true;
    }
    return;
  }
  if (connectCurrent == UPS_FAIL_CONNECT){
    flCriticalAlarm = true;
    flLedAlarm = true;
  }
  // Значение параметра изменилось
  if (connectCurrent != connectOldState)
  {
    if (connectCurrent == UPS_CONNECTED){
      log_event_data(LOG_ALARM_UPS, "Норма");
      SNMP_SendUserTrap(CONNECT_MONITOR_NORM);
      syslog_str(SYSLOG_NOTICE, "Восстановлена связь с ИБП");
      flUpdateLog = true;
    }
    else{
      log_event_data(LOG_ALARM_UPS, "Авария");
      SNMP_SendUserTrap(CONNECT_MONITOR_ALARM);
      syslog_str(SYSLOG_ERROR, "Потеряна связь с ИБП");
    }
  }
  
  connectOldState = connectCurrent;
#endif
}

/**
  * @brief  Мониторинг параметра upsParams.connect
  */
void UPS_BatteryConnectMonitor(void)
{
#ifdef BAT_CONNECT_MONITOR
  static bool isValueRecv = false;
  static bool flag_alarm_time = false;
  static uint8_t AKBconnectOldState = 0;
  uint8_t AKBconnectCurrent;

#if defined RELAY_OFF_AKB
  uint8_t i = 0;
  static uint8_t OldROtype_Sourse[OUTPUTS_TOTAL_COUNT] = {0};
  uint8_t CurrROtype_Sourse[OUTPUTS_TOTAL_COUNT] = {0};

  for(i = 0; i < OUTPUTS_TOTAL_COUNT; i ++)
	  CurrROtype_Sourse[i] = sSettings.sRelays[i].ro_type_source;
#endif

  if(((UPS.Status >> 7) & 0x01) == 0)
	  AKBconnectCurrent = (UPS.Status >> 6) & 0x01;
  else{
	  AKBconnectCurrent = 0;
  }
  AKBconnectCurrent |= UPS.warn_status & 0x01;

  UPS.Alarm = (UPS.Alarm & 0xfffffff7) | (AKBconnectCurrent << 3);

  if (!isValueRecv) {
    isValueRecv = true;
    AKBconnectOldState = AKBconnectCurrent;
    if (AKBconnectCurrent){
      log_event_data(LOG_ALARM_AKB, "Авария");
	  SNMP_SendUserTrap(BATTERY_CONNECT_ALARM);
	  syslog_str(SYSLOG_ERROR, "Авария связи с АКБ");
	  flUpdateLog = true;
#if defined RELAY_OFF_AKB
      relay_setup_log(CurrROtype_Sourse, OFF_AKB, 1);
#endif
    }
    else{
    	log_event_data(LOG_ALARM_AKB, "Норма");
		  SNMP_SendUserTrap(BATTERY_CONNECT_NORM);
		  syslog_str(SYSLOG_NOTICE, "Связь с АКБ восстановлена");
		  flUpdateLog = true;
#if	defined RELAY_OFF_AKB
		  relay_setup_log(CurrROtype_Sourse, OFF_AKB, 0);
#endif
    }
    return;
  }
  // Значение параметра изменилось
  if (AKBconnectCurrent != AKBconnectOldState)
  {
	if(flag_alarm_time){
		flag_alarm_time = false;
		if (!AKBconnectCurrent){
		  log_event_data(LOG_ALARM_AKB, "Норма");
		  SNMP_SendUserTrap(BATTERY_CONNECT_NORM);
		  syslog_str(SYSLOG_NOTICE, "Связь с АКБ восстановлена");
		  flUpdateLog = true;
#if defined RELAY_OFF_AKB
		  relay_setup_log(CurrROtype_Sourse, OFF_AKB, 0);
#endif
		}
		else{
		  log_event_data(LOG_ALARM_AKB, "Авария");
		  SNMP_SendUserTrap(BATTERY_CONNECT_ALARM);
		  syslog_str(SYSLOG_ERROR, "Авария связи с АКБ");
		  flUpdateLog = true;
#if defined RELAY_OFF_AKB
		  relay_setup_log(CurrROtype_Sourse, OFF_AKB, 1);
#endif
		}
	}
	else{
		flag_alarm_time = true;
	}
  }
#if defined RELAY_OFF_AKB
  else{
	  flag_alarm_time = false;
	  if (AKBconnectCurrent)
		  relay_setup_log_change(CurrROtype_Sourse, OldROtype_Sourse, OFF_AKB);
  }

  for(i = 0; i < OUTPUTS_TOTAL_COUNT; i ++){
	  OldROtype_Sourse[i] = CurrROtype_Sourse[i];
  }
#endif

  if(!flag_alarm_time){
	  if (AKBconnectCurrent){
      flCriticalAlarm = true;
      flLedAlarm = true;
	  }
	  AKBconnectOldState = AKBconnectCurrent;
  }
  else{
	  if (AKBconnectOldState){
      flCriticalAlarm = true;
      flLedAlarm = true;
	  }
  }
#endif
}

#ifdef AKB_CHANGE_MONITOR
/**
  * @brief  Мониторинг параметра замены АКБ
  */
void AKB_Change_Monitor(void)
{
  uint32_t data_change = sSettings.UPS_Setting.set_data + (31536000*sSettings.UPS_Setting.life_time);
  TM_RTC_t tmp_data;
  static bool isValueRecv = false;
  static uint8_t status_change_akb = 0;
  uint8_t curr_status_change_akb = 0;
  
  TM_RTC_GetDateTime(&tmp_data, TM_RTC_Format_BIN);
  
  if (tmp_data.unix >= data_change) {
    UPS.Alarm |= (1 << 6);
    curr_status_change_akb = 1;
    flCriticalAlarm = true;
    flLedAlarm = true;
  }
  else {
    UPS.Alarm &= 0xffffffbf;
    curr_status_change_akb = 0;
  }

  if (!isValueRecv) {
    isValueRecv = true;
    status_change_akb = curr_status_change_akb;
    if (curr_status_change_akb){
    	log_event_data(LOG_ALARM_CHANGE_AKB, "Авария");
    	SNMP_SendUserTrap(BATTERY_CHANGE_ALARM);
    	flUpdateLog = true;
    }
    else{
    	log_event_data(LOG_ALARM_CHANGE_AKB, "Норма");
      SNMP_SendUserTrap(BATTERY_CHANGE_MORM);
      flUpdateLog = true;
    }
    return;
  }

  // Значение параметра изменилось
  if (status_change_akb != curr_status_change_akb)
  {
    if (curr_status_change_akb){
      log_event_data(LOG_ALARM_CHANGE_AKB, "Авария");
    	SNMP_SendUserTrap(BATTERY_CHANGE_ALARM);
      flUpdateLog = true;
    } else {
      log_event_data(LOG_ALARM_CHANGE_AKB, "Норма");
      SNMP_SendUserTrap(BATTERY_CHANGE_MORM);
      flUpdateLog = true;
    }
  }
  status_change_akb = curr_status_change_akb;
}
#endif

#ifdef UPS_FAILED_MONITOR
void UPS_Failed_Monitor(void)
{
  static bool isValueRecv = false;
  static uint8_t UPSFailOldState = 0;
  uint8_t UPSFailCurrent;

  UPSFailCurrent = (UPS.Status >> 4) & 0x01;
  
  if (!isValueRecv) {
    isValueRecv = true;
    UPSFailOldState = UPSFailCurrent;

    if (UPSFailCurrent){
    	log_event_data(LOG_ALARM_UPS_FAILED, "Авария");
          SNMP_SendUserTrap(UPS_ALARM);
          flUpdateLog = true;
    }
    else{
      log_event_data(LOG_ALARM_UPS_FAILED, "Норма");
      SNMP_SendUserTrap(UPS_NORM);
      flUpdateLog = true;
    }

    return;
  }

  if (UPSFailCurrent){
    flCriticalAlarm = true;
    flLedAlarm = true;
  }
	  
  // Значение параметра изменилось
  if (UPSFailCurrent != UPSFailOldState)
  {
    if (UPSFailCurrent){
    	log_event_data(LOG_ALARM_UPS_FAILED, "Авария");
    	SNMP_SendUserTrap(UPS_ALARM);
    	flUpdateLog = true;
    }
    else{
      log_event_data(LOG_ALARM_UPS_FAILED, "Норма");
      SNMP_SendUserTrap(UPS_NORM);
      flUpdateLog = true;
    }
  }

  UPSFailOldState = UPSFailCurrent;  
}
#endif

#ifdef PHASE_FAIL_MONITOR
void UPS_PhaseFailMonitor(void)
{
  static bool isValueRecv = false;
  uint8_t phaseStatusCurrent;
  static uint8_t phaseStatusOld = 0;

  phaseStatusCurrent = ((UPS.warn_status >> 1) & 0x01);

  if (phaseStatusCurrent != 0){
    flCriticalAlarm = true;
    flLedAlarm = true;
    UPS.Alarm = (UPS.Alarm & 0xfffffeff) | (1 << 8);
  } else {
    UPS.Alarm = (UPS.Alarm & 0xfffffeff);
  }

  if (!isValueRecv) {
    isValueRecv = true;
    phaseStatusOld = phaseStatusCurrent;

    if (phaseStatusCurrent != 0){
      log_event_data(LOG_PHASE_FAIL, "Авария");
      // Отправка трапа о завышении 
      SNMP_SendUserTrap(PHASE_FAIL);
      syslog(SYSLOG_ERROR, "Ошибка подкл. вх. напряжения");
      flUpdateLog = true;
    }
    else{
      log_event_data(LOG_PHASE_FAIL, "Норма");
      // Отправка трапа о нормализации 
      SNMP_SendUserTrap(PHASE_NORM);
      syslog(SYSLOG_NOTICE, "Подкл. вх. напряжения в норме");
      flUpdateLog = true;
    }

    return;
  }

  if (phaseStatusCurrent)
  {
    if (phaseStatusCurrent != phaseStatusOld)
    {
      log_event_data(LOG_PHASE_FAIL, "Авария");
      // Отправка трапа о завышении 
      SNMP_SendUserTrap(PHASE_FAIL);
      syslog(SYSLOG_ERROR, "Ошибка подкл. вх. напряжения");
      flUpdateLog = true;
    }
  }
  /* Отслеживается нормализация */
  else {
    if (phaseStatusCurrent != phaseStatusOld)
    {
      log_event_data(LOG_PHASE_FAIL, "Норма");
      // Отправка трапа о нормализации 
      SNMP_SendUserTrap(PHASE_NORM);
      syslog(SYSLOG_NOTICE, "Подкл. вх. напряжения в норме");
      flUpdateLog = true;
    }
  }

  phaseStatusOld = phaseStatusCurrent;
}
#endif

#ifdef EPO_MONITOR
void UPS_EPOMonitor(void)
{
  static bool isValueRecv = false;
  uint8_t EPOStatusCurrent;
  static uint8_t EPOStatusOld = 0;

  EPOStatusCurrent = ((UPS.warn_status >> 8) & 0x01);

  if (EPOStatusCurrent != 0){
    flCriticalAlarm = true;
    flLedAlarm = true;
    UPS.Alarm = (UPS.Alarm & 0xfffffdff) | (1 << 9);
  } else {
    UPS.Alarm = (UPS.Alarm & 0xfffffdff);
  }

  if (!isValueRecv) {
    isValueRecv = true;
    EPOStatusOld = EPOStatusCurrent;

    if (EPOStatusCurrent != 0){
      log_event_data(LOG_EPO_FAIL, "Авария");
      // Отправка трапа о завышении 
      SNMP_SendUserTrap(EPO_FAIL);
      syslog(SYSLOG_ERROR, "Срабатывание EPO");
      flUpdateLog = true;
    }
    else{
      log_event_data(LOG_EPO_FAIL, "Норма");
      // Отправка трапа о нормализации 
      SNMP_SendUserTrap(EPO_NORM);
      syslog(SYSLOG_NOTICE, "EPO в норме");
      flUpdateLog = true;
    }

    return;
  }

  if (EPOStatusCurrent)
  {
    if (EPOStatusCurrent != EPOStatusOld)
    {
      log_event_data(LOG_EPO_FAIL, "Авария");
      // Отправка трапа о завышении 
      SNMP_SendUserTrap(EPO_FAIL);
      syslog(SYSLOG_ERROR, "Ошибка EPO");
      flUpdateLog = true;
    }
  }
  /* Отслеживается нормализация */
  else {
    if (EPOStatusCurrent != EPOStatusOld)
    {
      log_event_data(LOG_EPO_FAIL, "Норма");
      // Отправка трапа о нормализации 
      SNMP_SendUserTrap(EPO_NORM);
      syslog(SYSLOG_NOTICE, "EPO в норме");
      flUpdateLog = true;
    }
  }

  EPOStatusOld = EPOStatusCurrent;
}
#endif

#ifdef OVERTEMPRATURE_MONITOR
void UPS_OverTempratureMonitor(void)
{
    if ((UPS.fault_type == 0x41) && (UPS.Temp < 55) && ((UPS.Status >> 7) & 0x01)) {
        UPScmd(ups_remote_turn_off);
        xTimerStart(UPSRestartTimer, 0);
        UPS.fault_type = 0;
    }
}
#endif

#ifdef INVERTERHIGHVOLTAGE_MONITOR
void UPS_InventerHighVoltageMonitor(void)
{
    if(UPS.fault_type == 0x12) {
        xTimerStart(UPSTurnOffTimer, 0);
        UPS.fault_type = 0;
    }

}
#endif

/********************************* (C) РОТЕК **********************************/