/**
**************************************************************************
* @file stm32f4xx_matlab_tim.h
* @brief Заголовочный файл для симулятора таймеров.
**************************************************************************
@details
Данный файл содержит объявления всякого для симуляции таймеров STM32F407xx.
**************************************************************************/
#ifndef _MATLAB_TIM_H_
#define _MATLAB_TIM_H_

#include "stm32f4xx_hal.h"
#include "stm32f4xx_it.h"
#include "mcu_wrapper_conf.h"

/**
    * @addtogroup	TIM_SIMULATOR   TIM Simulator
    * @ingroup		MAIN_SIMULATOR
    * @brief 		Симулятор для таймеров
    * @details		Дефайны и функции для симуляции таймеров.
    * @{
    */

/////////////////////////////---DEFINES---/////////////////////////////
/**
  * @brief Дефайн для сдвига между первой и второй половиной CCMRx регистров
  */
#define TIM_OCMODE_SECOND_SHIFT                 (TIM_CCMR1_OC2M_Pos - TIM_CCMR1_OC1M_Pos)

/**
  * @brief    Дефайн для проверки выводить ли канал таймера на GPIO 
  * @details  Данный дефайн проверяет, настроен ли пин GPIO на альтернативную функцию. Если да - то таймер выводиться на этот пин
  */
#define Check_OCx_GPIO_Output(_tims_, _OCx_GPIOx_, _OCx_PIN_SHIFT_)     (_tims_->Channels._OCx_GPIOx_->MODER & (0b11<<(2*_tims_->Channels._OCx_PIN_SHIFT_))) == (0b10<<(2*_tims_->Channels._OCx_PIN_SHIFT_))
/**
  * @brief Дефайн для проверки выводить ли канал 1 на GPIO (настроен ли GPIO на альтернативную функцию) 
  */
#define Check_OC1_GPIO_Output(_tims_)           Check_OCx_GPIO_Output(_tims_, OC1_GPIOx, OC1_PIN_SHIFT)
/**
  * @brief Дефайн для проверки выводить ли канал 2 на GPIO (настроен ли GPIO на альтернативную функцию) 
  */
#define Check_OC2_GPIO_Output(_tims_)           Check_OCx_GPIO_Output(_tims_, OC2_GPIOx, OC2_PIN_SHIFT)
/**
  * @brief Дефайн для проверки выводить ли канал 3 на GPIO (настроен ли GPIO на альтернативную функцию) 
  */
#define Check_OC3_GPIO_Output(_tims_)           Check_OCx_GPIO_Output(_tims_, OC3_GPIOx, OC3_PIN_SHIFT)
/** 
  * @brief Дефайн для проверки выводить ли канал 4 на GPIO (настроен ли GPIO на альтернативную функцию) 
  */
#define Check_OC4_GPIO_Output(_tims_)           Check_OCx_GPIO_Output(_tims_, OC4_GPIOx, OC4_PIN_SHIFT)

/////////////////////////////////////////////////////////////////////



///////////////////////////---STRUCTURES---//////////////////////////
/**
  * @brief Структура для управления Слейв Таймерами 
  */
struct SlaveChannels
{
    unsigned TIM1_TRGO : 1;     ///< Синган синхронизации таймера 1
    unsigned TIM2_TRGO : 1;     ///< Синган синхронизации таймера 2
    unsigned TIM3_TRGO : 1;     ///< Синган синхронизации таймера 3
    unsigned TIM4_TRGO : 1;     ///< Синган синхронизации таймера 4
    unsigned TIM5_TRGO : 1;     ///< Синган синхронизации таймера 5
    unsigned TIM6_TRGO : 1;     ///< Синган синхронизации таймера 6
    unsigned TIM7_TRGO : 1;     ///< Синган синхронизации таймера 7
    unsigned TIM8_TRGO : 1;     ///< Синган синхронизации таймера 8    

};

/**
  * @brief Структура для моделирования каналов таймера 
  */
struct Channels_Sim
{
    // Каналы таймера
    unsigned OC1REF:1;          ///< Первый канал
    unsigned OC2REF:1;          ///< Второй канал
    unsigned OC3REF:1;          ///< Третьий канал
    unsigned OC4REF:1;          ///< Четвертый канал

    // связанные с каналами GPIO порты и пины
    GPIO_TypeDef *OC1_GPIOx;    ///< Порт первого канала
    uint32_t OC1_PIN_SHIFT;     ///< Пин первого канала

    GPIO_TypeDef *OC2_GPIOx;    ///< Порт второго канала
    uint32_t OC2_PIN_SHIFT;     ///< Пин второго канала

    GPIO_TypeDef *OC3_GPIOx;    ///< Порт третьего канала
    uint32_t OC3_PIN_SHIFT;     ///< Пин третьего канала

    GPIO_TypeDef *OC4_GPIOx;    ///< Порт четвертого канала
    uint32_t OC4_PIN_SHIFT;     ///< Пин четвертого канала

};

/**
  * @brief Структура для моделирования таймера 
  */
struct TIM_Sim
{
    double tx_cnt;                  ///< Счетчик таймера (double, т.к. кол-во тактов за шаг симуляции может быть дробным)
    double tx_step;                 ///< Шаг счета за один шаг симуляции (double, т.к. кол-во тактов за шаг симуляции может быть дробным)
    int RELOAD;                     ///< Буфер для периода таймера (для реализации функции PRELOAD)
    struct Channels_Sim Channels;   ///< Структура для симуляции каналов
};
/////////////////////////////////////////////////////////////////////



///////////////////////////---FUNCTIONS---///////////////////////////

//----------------------TIMER BASE FUNCTIONS-----------------------//
/* Базовая функция для симуляции таймера: она вызывается каждый шаг симуляции */
void TIM_Simulation(TIM_TypeDef *TIMx, struct TIM_Sim *TIMS);
/* Счет таймера за один такт */
void TIMx_Count(TIM_TypeDef* TIMx, struct TIM_Sim* TIMS);
/* Проверка на переполнение и дальнейшая его обработка */
void Overflow_Check(TIM_TypeDef* TIMx, struct TIM_Sim* TIMS);
/* Вызов прерывания */
void call_IRQHandller(TIM_TypeDef *TIMx);
//-----------------------------------------------------------------//


//------------------------CHANNELS FUNCTIONS-----------------------//
/* Симуляция каналов таймера */
void Channels_Simulation(TIM_TypeDef *TIMx, struct TIM_Sim *TIMS);
/*---------------- - CAPTURE COPMARE & PWM FUNCTIONS------------------*/
/* Выбор режима CaptureCompare или PWM и симуляция для каждого канала */
void CC_PWM_Ch1_Simulation(TIM_TypeDef* TIMx, struct TIM_Sim* TIMS);
void CC_PWM_Ch2_Simulation(TIM_TypeDef* TIMx, struct TIM_Sim* TIMS);
void CC_PWM_Ch3_Simulation(TIM_TypeDef* TIMx, struct TIM_Sim* TIMS);
void CC_PWM_Ch4_Simulation(TIM_TypeDef* TIMx, struct TIM_Sim* TIMS);
/* Запись каналов таймера в порты GPIO */
void Write_OC_to_GPIO(TIM_TypeDef* TIMx, struct TIM_Sim* TIMS);
/* Запись результата compare в глабальную структуру с TRIGGER OUTPUT */
void Write_OC_to_TRGO(TIM_TypeDef* TIMx, struct TIM_Sim* TIMS);
//------------------------------------------------------------------//


//--------------------MISC (temporary) FUNCTIONS--------------------//
/* Определение источника для запуска таймера в SLAVE MODE */
void Slave_Mode_Check_Source(TIM_TypeDef* TIMx);
//------------------------------------------------------------------//


//------------------------SIMULINK FUNCTIONS------------------------//
// Симулирование выбранных таймеров
void Simulate_TIMs(void);
// Деинициализирование выбранных таймеров (вызывается в конце симуляции)
void TIM_SIM_DEINIT(void);
//------------------------------------------------------------------//
/** TIM_SIMULATOR
  * @}
  */
#endif // _MATLAB_TIM_H_
