/** 
**************************************************************************
* @file general_tim.h
* @brief Заголовочный файл для модуля инициализации таймеров и работы с ними.
**************************************************************************
* @defgroup GENERAL_TIM      TIM Tools
* @ingroup  STM32_GENERAL
* @brief    Функции и макросы для удобной работы с TIM.
* @details
Модуль предоставляет универсальные инструменты для работы с TIM:
  - @ref  MYLIBS_TIM_GENERAL  — базовая инициализация таймеров и прерываний.
  - @ref  MYLIBS_TIM_DELAY    — функции задержки через таймеры (blocking и non-blocking).
  - @ref  MYLIBS_TIM_OC       — настройка каналов Output Compare и PWM.
  - @ref  MYLIBS_TIM_ENCODER  — работа с энкодерами, чтение положения и кнопки.

*  @note Требуется подключение модуля TIM в библиотеке HAL и GPIO (@ref GENERAL_GPIO) из MyLibs
@code 
#define HAL_TIM_MODULE_ENABLED
@endcode
*************************************************************************/
#ifndef __TIM_GENERAL_H_
#define __TIM_GENERAL_H_

/////////////////////////////////////////////////////////////////////
/////////////////////////---USER SETTINGS---/////////////////////////
/** 
  * @addtogroup TIM_INIT TIM Init defines
  * @ingroup    MYLIBS_TIM_GENERAL
  * @ingroup    GENERAL_CONFIGS Конфигурации STM32 General
  * @brief      Настройка таймеров
  * @{
  */
#define HAL_TIM_MODULE_ENABLED

#define USE_TIM1    ///< Включить TIM1 в @ref TIM_Base_MspInit
#define USE_TIM2    ///< Включить TIM2 в @ref TIM_Base_MspInit
#define USE_TIM3    ///< Включить TIM3 в @ref TIM_Base_MspInit
#define USE_TIM4    ///< Включить TIM4 в @ref TIM_Base_MspInit
#define USE_TIM5    ///< Включить TIM5 в @ref TIM_Base_MspInit
#define USE_TIM6    ///< Включить TIM6 в @ref TIM_Base_MspInit
#define USE_TIM7    ///< Включить TIM7 в @ref TIM_Base_MspInit
#define USE_TIM8    ///< Включить TIM8 в @ref TIM_Base_MspInit
#define USE_TIM9    ///< Включить TIM9 в @ref TIM_Base_MspInit
#define USE_TIM10   ///< Включить TIM10 в @ref TIM_Base_MspInit
#define USE_TIM11   ///< Включить TIM11 в @ref TIM_Base_MspInit
#define USE_TIM12   ///< Включить TIM12 в @ref TIM_Base_MspInit
#define USE_TIM13   ///< Включить TIM13 в @ref TIM_Base_MspInit
#define USE_TIM14   ///< Включить TIM14 в @ref TIM_Base_MspInit
/** TIM_INIT
  * @}
  */
/////////////////////////---USER SETTINGS---/////////////////////////
#include "mylibs_defs.h"
#include "general_gpio.h"

/////////////////////////////////////////////////////////////////////
////////////////////////////---DEFINES---////////////////////////////
#define TIM_IT_CONF_Pos           0
//#define TIM_PWM_CONF_Pos          1
//#define TIM_CLCK_SRC_CONF_Pos     2
//#define TIM_SLAVE_CONF_Pos        3
//#define TIM_MASTER_CONF_Pos       4
//#define TIM_BDTR_CONF_Pos         5

#define TIM_IT_CONF   (1<<(TIM_IT_CONF_Pos))
//#define TIM_PWM_CONF      (1<<(TIM_PWM_Pos))

////////////////////////////---DEFINES---////////////////////////////]



/////////////////////////////////////////////////////////////////////
///////////////////////---STRUCTURES & ENUMS---//////////////////////
/**
  * @brief Режим прерываний таймера
  * @ingroup  MYLIBS_TIM_GENERAL
  */
typedef enum
{
  TIM_DEFAULT =         0,            ///< Прерываний отключены
  TIM_IT_MODE =         TIM_IT_CONF,  ///< Прерываний включены
//  TIM_PWM_MODE =        TIM_PWM_ENABLE,
//  TIM_PWM_IT_MODE =     TIM_PWM_ENABLE | TIM_IT_CONF,
}TIM_ITModeTypeDef;

/**
  * @brief Длительность тика таймера (частота тактирования таймера)
  * @ingroup  MYLIBS_TIM_GENERAL
  * @details  enum дает базовые длительности, но можно выставить другие
  *           (напр 500 - 0.5 мс)
  */
typedef enum
{
  TIM_Base_Disable =      0,      ///< Таймер отключен
  TIM_TickBase_1US =      1,      ///< Таймер тактируется с частотой 1    МГц
  TIM_TickBase_10US =     10,     ///< Таймер тактируется с частотой 100  кГц
  TIM_TickBase_100US =    100,    ///< Таймер тактируется с частотой 10   кГц
  TIM_TickBase_1MS =      1000,   ///< Таймер тактируется с частотой 1    кГц
  TIM_TickBase_10MS =     10000,  ///< Таймер тактируется с частотой 100  Гц
  TIM_TickBase_100MS =    100000, ///< Таймер тактируется с частотой 10   Гц
}TIM_MHzTickBaseTypeDef;

/**
  * @brief Структура инициализации таймера
  * @ingroup  MYLIBS_TIM_GENERAL
  * @details  
  * Содержит все базовые структуры, которые нужны для инициализации таймера.
  * Если структуры настроек не заданы, то они заполнятся сами дефолтными параметрами  
  * 
  * Также высокоуровневые настройки частоты работы таймера. 
  * Если какая-либо высокоуровневая настройка не задана, то 
  * по возможности берется низкоуровневая настройка из структур
  */
typedef struct // struct with settings for custom function
{
  TIM_HandleTypeDef       htim;                         ///< HAL handle таймера
  TIM_ClockConfigTypeDef  sClockSourceConfig;           ///< Настройки тактирования таймера
  TIM_SlaveConfigTypeDef  sSlaveConfig;                 ///< Настройки слейв режима таймера
  TIM_MasterConfigTypeDef sMasterConfig;                ///< Настройки мастер режима таймера
  TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig;  ///< Настройки дедтаймов таймера

  TIM_ITModeTypeDef       sTimMode;                     ///< Настройки прерывания таймера  
  TIM_MHzTickBaseTypeDef  sTickBaseUS;                  ///< Длительность одного тика  
  uint8_t                 sTickBasePrescaler;           ///< Дополнительный делитель, для удобного деления @ref sTickBaseUS
  float                   sTimAHBFreqMHz;               ///< Частота шины тактирования таймера
  float                   sTimFreqHz;                   ///< Желаемая частота таймера
  
}TIM_SettingsTypeDef;


/**
  * @brief Структура инициализации енкодера
  * @ingroup  MYLIBS_TIM_ENCODER
  * @details  
  * Содержит все базовые структуры, которые нужны для инициализации таймера.
  * Если структуры настроек не заданы, то они заполнятся сами дефолтными параметрами  
  * 
  * Также высокоуровневые настройки частоты работы таймера. 
  * Если какая-либо высокоуровневая настройка не задана, то 
  * по возможности берется низкоуровневая настройка из структур
  */
typedef struct // struct with variables for encoder
{
  int16_t                 Encoder_Diff;   ///< Считанная разница
  uint16_t                Encoder_Shdw;   ///< Последние считанные тики
  
  TIM_HandleTypeDef       *htim;          ///< Указатель на HAL handle таймера
  TIM_Encoder_InitTypeDef sConfig;        ///< Указатель на структуру настройки энкодера
  
  GPIO_TypeDef            *GPIOx;         ///< Порт, куда подключается энкодер
  uint32_t                GPIO_PIN_TI1;   ///< Пин, куда подключается канал TI1
  uint32_t                GPIO_PIN_TI2;   ///< Пин, куда подключается канал TI2
  uint32_t                GPIO_PIN_SW;    ///< Пин, куда кнопка энкодера (если есть)

  GPIO_SwitchTypeDef      Sw;             ///< Структура кнопки
  
}TIM_EncoderTypeDef;
///////////////////////---STRUCTURES & ENUMS---//////////////////////

/////////////////////////////////////////////////////////////////////
///////////////////////////---FUNCTIONS---///////////////////////////
/** 
  * @addtogroup MYLIBS_TIM_GENERAL  General tools
  * @ingroup    GENERAL_TIM
  * @brief      Функции для базовой инициализации таймеров
  * @par Пример использования:
    @code
    TIM_SettingsTypeDef tim2Settings;

    void TIM2_Init(void)
    {
        // Настройка таймера TIM2 на 1 кГц с прерываниями с шагом таймера 10 мкс
        tim2Settings.htim.Instance = TIM2;
        tim2Settings.sTimMode = TIM_IT_MODE;
        tim2Settings.sTickBaseUS = TIM_TickBase_10US;
        tim2Settings.sTickBasePrescaler = 1;
        tim2Settings.sTimFreqHz = 1000; // 1 кГц
        tim2Settings.sTimAHBFreqMHz = 72000000; // Hz

        if(TIM_Base_Init(&tim2Settings) != HAL_OK)
        {
            Error_Handler();
        }
    }
    @endcode
  * @{
  */

#define TIM_FreqToTick(_freq_, _timfreqMHz_)    ((1000000*_timfreqMHz_)/_freq_)

/* Initialize TIM with TIM_SettingsTypeDef structure */
HAL_StatusTypeDef TIM_Base_Init(TIM_SettingsTypeDef* stim);
/* Initialize TIMs clock and interrupt */
void TIM_Base_MspInit(TIM_HandleTypeDef* htim, TIM_ITModeTypeDef it_mode);
/* DeInitialize TIMs clock and interrupt */
void TIM_Base_MspDeInit(TIM_HandleTypeDef* htim);
/** MYLIBS_TIM_GENERAL
  * @}
  */

/** 
  * @addtogroup MYLIBS_TIM_DELAY  Delay tools
  * @ingroup    GENERAL_TIM
  * @brief      Функции для формирования задержек с помощью таймеров
  * @par Пример использования:
    @code
    TIM_HandleTypeDef htim2;

    // блокирующая задержка 500 тиков таймера
    LED_ON();
    TIM_Delay(&htim2, 500);
    LED_OFF();


    while(1)
    {
      // не блокирующая задержка 200 тиков таймера
      if(TIM_Delay_NonBlocking(&htim2, 200) == HAL_OK)
      {
        TIM_Delay_Start(&htim2);
        LED_TOOGLE();
      }
    }
    @endcode
  * @{
  */
/* Start delay via TIM */
HAL_StatusTypeDef TIM_Delay_Start(TIM_HandleTypeDef *htim);
/* Delay via TIM */
HAL_StatusTypeDef TIM_Delay(TIM_HandleTypeDef *htim, uint16_t delay);
/* Wait Delay via TIM without blocking app */
HAL_StatusTypeDef TIM_Delay_NonBlocking(TIM_HandleTypeDef *htim, uint16_t delay);
/** MYLIBS_TIM_DELAY
  * @}
  */

/** 
  * @addtogroup MYLIBS_TIM_OC PWM/OC Channels tools
  * @ingroup    GENERAL_TIM
  * @brief      Функции для инициализации базовых функций каналов таймера
  * @par Пример использования:
    @code
    void PWM_Channel_Init_Example(void)
    {
        TIM_HandleTypeDef htim3;
        TIM_OC_InitTypeDef sConfigOC;
        GPIO_TypeDef *GPIOx = GPIOB;
        uint32_t PWM_PIN = GPIO_PIN_0;

        // Настройка таймера и канала PWM
        TIM_Output_PWM_Init(&htim3, &sConfigOC, TIM_CHANNEL_1, GPIOx, PWM_PIN);

        // Настройка компаратора OC
        TIM_OC_Comparator_Init(&htim3, TIM_CHANNEL_1);
    }
    @endcode
  * @{
  */
/* Initialize PWM Channel and GPIO for output */
HAL_StatusTypeDef TIM_Output_PWM_Init(TIM_HandleTypeDef *htim, TIM_OC_InitTypeDef *sConfigOC, uint32_t TIM_CHANNEL, GPIO_TypeDef *GPIOx, uint32_t PWM_PIN);
/* Initialize OC Comparator */
HAL_StatusTypeDef TIM_OC_Comparator_Init(TIM_HandleTypeDef *htim, uint32_t TIM_CHANNEL);
/** MYLIBS_TIM_ENCODER
  * @}
  */

/** 
  * @addtogroup MYLIBS_TIM_ENCODER Encoder tools
  * @ingroup    GENERAL_TIM
  * @brief      Функции для считывания энкодера
  * @par Пример использования:
    @code
    TIM_EncoderTypeDef henc1;
    TIM_HandleTypeDef htim4;

    // инициализация
    henc1.htim = &htim4;
    henc1.GPIOx = GPIOA;
    henc1.GPIO_PIN_TI1 = GPIO_PIN_0;
    henc1.GPIO_PIN_TI2 = GPIO_PIN_1;
    TIM_Encoder_Init(&henc1, &htim4);

    // считывание энкодера и кнопки
    int16_t delta = TIM_Encoder_Read(&henc1);
    setpoint_tmp += delta;
    if(TIM_Encoder_ReadSwitch(&henc1))
    {
      setpoint = setpoint_tmp; // подтвердить новое значение
    }
    @endcode
  * @{
  */
/* Initialize TIM Encoder functional */
HAL_StatusTypeDef TIM_Encoder_Init(TIM_EncoderTypeDef *henc1, TIM_HandleTypeDef *htim);
/* Считать энкодер */
HAL_StatusTypeDef TIM_Encoder_Read(TIM_EncoderTypeDef *henc);
/* Считать кнопку энкодера */
int TIM_Encoder_ReadSwitch(TIM_EncoderTypeDef *henc);
/** MYLIBS_TIM_ENCODER
  * @}
  */
///////////////////////////---FUNCTIONS---///////////////////////////


#endif // __TIM_GENERAL_H_
