/********************************* (C) РОТЕК ***********************************
 * @module  buttons
 * @file    buttons.c
 * @version 1.0.0
 * @date    XX.XX.XXXX
 * $brief   buttons
 *******************************************************************************
 * @history     Version  Author         Comment
 * XX.XX.XXXX   1.0.0    Telenkov D.A.  First release.
 *******************************************************************************
 */

#include "stm32f4xx.h"  
#include "buttons.h"
#include "led.h"
#include "settings_api.h"
#include "web_params_api.h"
#include "log.h"
#include "snmp_api.h"
#include "trap_api.h"
#include "hal.h"

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

BUTTON_NO_FIX_t defButton;

/**
  * @brief  
  * @retval 
  */
void BUTTON_Init(void) 
{
  defButton.id_pin			  = KEY_DEF;
  defButton.timeDelay         = 5;
  defButton.pressHandler      = BUTTON_VoidHandler;
  defButton.unpressHandler    = BUTTON_DEF_DownHandler;
  defButton.counterActivation = 0;
  defButton.timeActivation    = 40;
  defButton.fActivation       = false;
    
  defButton.stateOld     = BUTTON_GetState(&defButton);
	
}

/**
  * @brief   Возвращает сотояние ключа
  */
BUTTON_STATE_t BUTTON_GetState(BUTTON_NO_FIX_t *button)
{
  return (BUTTON_STATE_t)gpio_get(button->id_pin);
}

/**
  * @brief  Обработчик кнопки без фиксации. В обработчике реализована защита
  *         от дребезга с помощью задержки. Защита срабатывает при нажатии 
  *         и при отпускании.
  * @param *button: указатель на структуру типа BUTTON_NO_FIX
  * @retval нет
  */
void BUTTON_NoFixHandler(BUTTON_NO_FIX_t *button)
{
  uint8_t temp;
  
  if (button->stateNew != BUT_NO_DEFINE)
  {  
    temp = gpio_get(button->id_pin);
    
    if (temp == 0)  // определяем текущее (новое) состояние кнопки        
      button->stateNew = BUT_ON;
    else
      button->stateNew = BUT_OFF;
  
    if (button->stateNew != button->stateOld)  // зафиксирован факт нажатия/отжатия
      button->stateNew = BUT_NO_DEFINE;  // переводим кнопку в неопределенное состояние
  }
  else
  {
    button->counterDelay++;             // запускаем счетчик на задержку
    
    if (button->counterDelay > button->timeDelay)  // задержка закончилась
    {
      button->counterDelay = 0;

      temp = gpio_get(button->id_pin);
   	  
      button->counterActivation = 0;
		
      if (temp == 0)  // определяем текущее (новое) состояние кнопки        
      {  
        button->stateNew = BUT_ON;
        button->unpressHandler();
      }  
      else
      {  
        button->stateNew = BUT_OFF;
        button->pressHandler();
      }
	  	
    }
  }
  
  button->stateOld = button->stateNew;

}


/**
  * @brief  Обработчик кнопки без фиксации. Кнопка срабатывает через определеное
            время нажатия.
  * @param *button: указатель на структуру типа BUTTON_NO_FIX
  * @retval нет
  */
void BUTTON_DellayHandler(BUTTON_NO_FIX_t *button)
{
  /* Кнопка нажата. Ведем отсчет времени удержания */
  if (gpio_get(button->id_pin) == 0)  // определяем текущее (новое) состояние кнопки
  {  
	button->counterActivation++;
	button->fActivation = false;
	
	/* Кнопка нажата более необходимого времени - начинаем чаще мигать диодом */
	if (button->counterActivation > button->timeActivation)
	  LED_SetStatusLedFreq(100);
  }
  /* Кнопку отжата. Если до этого она была нажата нужное время - вызываем хендлер */
  else
  {
	if ((button->counterActivation > button->timeActivation) 
	     && button->fActivation == false)
	{  
	  button->fActivation = true;
	  LED_SetStatusLedFreq(1000);
	  button->unpressHandler();
	}  
	else
	  button->counterActivation = 0;
  }		

}

/**
  * @brief  Опрос кнопок
  */
void vTaskButtons(void *pvParameters) 
{
  for (;;) 
  {
	BUTTON_DellayHandler(&defButton);
	
    vTaskDelay(100);  //20
  }
}

/**
  * @brief  Заглушка
  */
void BUTTON_VoidHandler(void)
{
}


/**
  * @brief  Хендлер кнопки DEFAULT. Сброс всех настроек, сохранение и перезагрузка
  */
void BUTTON_DEF_DownHandler(void)
{
  //taskENTER_CRITICAL();
  SNMP_SendUserTrap(DEVICE_RESTORED);
  log_event_data(LOG_SYSTEM_DEFCONFIG, "Администратор");
  vTaskDelay(500);
  SETTINGS_SetDefaultDebug();
  SETTINGS_Save();

  vTaskDelay(1010);
  Reboot();
  
  //taskEXIT_CRITICAL();
}

/**
  * @brief  Хендлер кнопки SET. Переход в bootloader
  */
void BUTTON_SET_DownHandler(void)
{
  HTTP_StartResetTask(true);
}


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