/**************************************************************************
Данный файл содержит функции для симуляции таймеров STM32F407xx.

**************************************************************************/
#include "stm32_matlab_tim.h"



struct SlaveChannels Slave_Channels; // структура для связи и синхронизации таймеров
void TIM_Call_IRQHandller(TIM_TypeDef* TIMx);

//----------------------TIMER BASE FUNCTIONS-----------------------//
/* Базовая функция для симуляции таймера: она вызывается каждый шаг симуляции */
void TIM_Simulation(TIM_TypeDef *TIMx, struct TIM_Sim *TIMS)
{    
  if (!(TIMx->CR1 & TIM_CR1_CEN)) // таймер не включен - возврат
  {
    TIMS->RepititiveCnt = 0;
    return;
  }

    Overflow_Check(TIMx, TIMS);

    // Выбор режима работы таймера
    switch (TIMx->SMCR & TIM_SMCR_SMS) // TIMER MODE
    {
        // обычный счет
        case(TIM_SLAVEMODE_DISABLE):// NORMAL MODE counting
            TIMx_Count(TIMx, TIMS);
            Channels_Simulation(TIMx, TIMS); // CaptureCompare and PWM channels simulation
            Write_TRGO(TIMx, TIMS);
            break;


        // включение слейв таймера по ивенту
        case(TIM_SLAVEMODE_TRIGGER): // SLAVE MODE: TRIGGER MODE
            Slave_Mode_Check_Source(TIMx, TIMS);
            TIMx_Count(TIMx, TIMS);
            Channels_Simulation(TIMx, TIMS); // CaptureCompare and PWM channels simulation 
            Write_TRGO(TIMx, TIMS);
            break;
    }

    // EGR
    TIM_EGR_Simulation(TIMx);

    // Прерывание если какое-то выставлено
    if (TIMx->SR & (TIM_SR_UIF | TIM_SR_CC1IF | TIM_SR_CC2IF | TIM_SR_CC3IF | TIM_SR_CC4IF))
    {
        TIM_Call_IRQHandller(TIMx); // call HANDLER
    }

}
/* Счет таймера за один такт */
void TIMx_Count(TIM_TypeDef* TIMx, struct TIM_Sim* TIMS)
{
    if ((TIMx->CR1 & TIM_CR1_DIR)) // up COUNTER ENABLE
        TIMS->tx_cnt -= TIMS->tx_step / (TIMx->PSC + 1);
    else if (((TIMx->CR1 & TIM_CR1_DIR) == 0)) // down COUNTER ENABLE
        TIMS->tx_cnt += TIMS->tx_step / (TIMx->PSC + 1);
    TIMx->CNT = (uint32_t)TIMS->tx_cnt;
}
/* Проверка на переполнение и дальнейшая его обработка */
void Overflow_Check(TIM_TypeDef* TIMx, struct TIM_Sim* TIMS)
{
    TIMS->Updated = 0;
    // Переполнение таймера: сброс таймера и вызов прерывания
    if ((TIMx->CR1 & TIM_CR1_UDIS) == 0) // UPDATE enable
    {
        if ((TIMx->CR1 & TIM_CR1_ARPE) == 0)  TIMS->RELOAD = TIMx->ARR; // PRELOAD disable - update ARR every itteration
        if (TIMS->tx_cnt > TIMS->RELOAD || TIMS->tx_cnt < 0) // OVERFLOW
        {
          TIMS->RELOAD = TIMx->ARR; // RELOAD ARR

          if (TIMS->tx_cnt > TIMx->ARR) // reset COUNTER
            TIMS->tx_cnt -= TIMS->RELOAD + 1;
          else if (TIMS->tx_cnt < 0)
            TIMS->tx_cnt += TIMS->RELOAD + 1;

          if (TIMS->tx_step > TIMS->RELOAD)
            TIMS->tx_cnt = 0;

          if (!(TIMx->CR1 & TIM_CR1_OPM)) // if no one pulse
          {
            TIMS->Updated = 1;
            if (TIMx->DIER & TIM_DIER_UIE) {
              TIMx->SR |= TIM_SR_UIF;
            }
          }
          else // if one pulse mode enabled
          {
            if (TIMS->RepititiveCnt >= TIMx->RCR)
            {
              TIMS->RepititiveCnt = 0;
              TIMS->Updated = 1;
              TIMx->CR1 &= ~TIM_CR1_CEN;
              if (TIMx->DIER & TIM_DIER_UIE) {
                TIMx->SR |= TIM_SR_UIF;
              }
            }
            else
            {
              TIMS->RepititiveCnt++;
            }
          }

        }
    }
}
//-----------------------------------------------------------------//



//----------------------------CHANNELS-----------------------------//
/* Симуляция каналов таймера */
void Channels_Simulation(TIM_TypeDef* TIMx, struct TIM_Sim* TIMS)
{
    CC_PWM_Ch1_Simulation(TIMx, TIMS);
    CC_PWM_Ch2_Simulation(TIMx, TIMS);
    CC_PWM_Ch3_Simulation(TIMx, TIMS);
    CC_PWM_Ch4_Simulation(TIMx, TIMS);

    Write_OC_to_GPIO(TIMx, TIMS);
}
//-----------------CAPTURE COPMARE & PWM FUNCTIONS------------------//
/* Выбор режима CaptureCompare или PWM и симуляция для каждого канала */
void CC_PWM_Ch1_Simulation(TIM_TypeDef *TIMx, struct TIM_Sim *TIMS)
{ // определяет режим канала
    switch (TIMx->CCMR1 & TIM_CCMR1_OC1M)
    {
        case (TIM_OCMODE_ACTIVE): // ACTIVE mode
            if (abs(TIMx->CNT - TIMx->CCR1) < 2*TIMS->tx_step) 
                TIMS->Channels.OC1REF = 1;
            break;

        case (TIM_OCMODE_INACTIVE): // INACTIVE mode
            if (abs(TIMx->CNT - TIMx->CCR1) < 2*TIMS->tx_step) 
                TIMS->Channels.OC1REF = 0;
            break;

        case (TIM_OCMODE_TOGGLE): // TOOGLE mode
            if (abs(TIMx->CNT - TIMx->CCR1) < 2*TIMS->tx_step) 
                TIMS->Channels.OC1REF = ~TIMS->Channels.OC1REF;
            break;
        
        case (TIM_OCMODE_PWM1): // PWM MODE 1 mode
            if (TIMx->CNT < TIMx->CCR1) 
                TIMS->Channels.OC1REF = 1;
            else
                TIMS->Channels.OC1REF = 0;
            break;
        
        case (TIM_OCMODE_PWM2): // PWM MODE 2 mode
            if (TIMx->CNT < TIMx->CCR1) 
                TIMS->Channels.OC1REF = 0;
            else
                TIMS->Channels.OC1REF = 1;
            break;
              
        case (TIM_OCMODE_FORCED_ACTIVE): // FORCED ACTIVE mode
            TIMS->Channels.OC1REF = 1; break;
        
        case (TIM_OCMODE_FORCED_INACTIVE): // FORCED INACTIVE mode
            TIMS->Channels.OC1REF = 0; break;

    }
    if (TIMx->DIER & TIM_IT_CC1)
    {
        if (((TIMS->tx_cnt - TIMS->tx_step) < TIMx->CCR1) && (TIMS->tx_cnt >= TIMx->CCR1))
        {
            TIMx->SR |= TIM_SR_CC1IF;
        }
        else if (((TIMS->tx_cnt - TIMS->tx_step) > TIMx->CCR1) && (TIMS->tx_cnt <= TIMx->CCR1))
        {
            TIMx->SR |= TIM_SR_CC1IF;
        }
    }
}
void CC_PWM_Ch2_Simulation(TIM_TypeDef *TIMx, struct TIM_Sim *TIMS)
{ // определяет режим канала
    switch (TIMx->CCMR1 & TIM_CCMR1_OC2M)
    {
        case ((TIM_OCMODE_ACTIVE) << (TIM_OCMODE_SECOND_SHIFT)): // ACTIVE mode
            if (abs(TIMx->CNT - TIMx->CCR2) < 2*TIMS->tx_step) 
                TIMS->Channels.OC2REF = 1;
            break;

        case ((TIM_OCMODE_INACTIVE) << (TIM_OCMODE_SECOND_SHIFT)): // INACTIVE mode
            if (abs(TIMx->CNT - TIMx->CCR2) < 2*TIMS->tx_step) 
                TIMS->Channels.OC2REF = 0;
            break;

        case ((TIM_OCMODE_TOGGLE) << (TIM_OCMODE_SECOND_SHIFT)): // Toogle mode
            if (abs(TIMx->CNT - TIMx->CCR2) < 2*TIMS->tx_step) 
                TIMS->Channels.OC2REF = ~TIMS->Channels.OC2REF;
            break;
        
        case ((TIM_OCMODE_PWM1) << (TIM_OCMODE_SECOND_SHIFT)): // PWM mode 1 mode
            if (TIMx->CNT < TIMx->CCR2) 
                TIMS->Channels.OC2REF = 1;
            else
                TIMS->Channels.OC2REF = 0;
            break;
        
        case ((TIM_OCMODE_PWM2) << (TIM_OCMODE_SECOND_SHIFT)): // PWM mode 2 mode
            if (TIMx->CNT < TIMx->CCR2) 
                TIMS->Channels.OC2REF = 0;
            else
                TIMS->Channels.OC2REF = 1;
            break;
              
        case ((TIM_OCMODE_FORCED_ACTIVE) << (TIM_OCMODE_SECOND_SHIFT)): // FORCED ACTIVE mode
            TIMS->Channels.OC2REF = 1; break;
        
        case ((TIM_OCMODE_FORCED_INACTIVE) << (TIM_OCMODE_SECOND_SHIFT)): // FORCED INACTIVE mode
            TIMS->Channels.OC2REF = 0; break;

    }
    if (TIMx->DIER & TIM_IT_CC2)
    {
        if (((TIMS->tx_cnt - TIMS->tx_step) < TIMx->CCR2) && (TIMS->tx_cnt >= TIMx->CCR2))
        {
            TIMx->SR |= TIM_SR_CC2IF;
        }
        else if (((TIMS->tx_cnt - TIMS->tx_step) > TIMx->CCR2) && (TIMS->tx_cnt <= TIMx->CCR2))
        {
            TIMx->SR |= TIM_SR_CC2IF;
        }
    }
}
void CC_PWM_Ch3_Simulation(TIM_TypeDef *TIMx, struct TIM_Sim *TIMS)
{ // определяет режим канала
    switch (TIMx->CCMR2 & TIM_CCMR2_OC3M)
    {
        case (TIM_OCMODE_ACTIVE): // ACTIVE mode
            if (abs(TIMx->CNT - TIMx->CCR3) < 2*TIMS->tx_step) 
                TIMS->Channels.OC3REF = 1;
            break;

        case (TIM_OCMODE_INACTIVE): // INACTIVE mode
            if (abs(TIMx->CNT - TIMx->CCR3) < 2*TIMS->tx_step) 
                TIMS->Channels.OC3REF = 0;
            break;

        case (TIM_OCMODE_TOGGLE): // Toogle mode
            if (abs(TIMx->CNT - TIMx->CCR3) < 2*TIMS->tx_step) 
                TIMS->Channels.OC3REF = ~TIMS->Channels.OC3REF;
            break;
        
        case (TIM_OCMODE_PWM1): // PWM mode 1 mode
            if (TIMx->CNT < TIMx->CCR3) 
                TIMS->Channels.OC3REF = 1;
            else
                TIMS->Channels.OC3REF = 0;
            break;
        
        case (TIM_OCMODE_PWM2): // PWM mode 2 mode
            if (TIMx->CNT < TIMx->CCR3) 
                TIMS->Channels.OC3REF = 0;
            else
                TIMS->Channels.OC3REF = 1;
            break;
              
        case (TIM_OCMODE_FORCED_ACTIVE): // FORCED ACTIVE mode
            TIMS->Channels.OC3REF = 1; break;
        
        case (TIM_OCMODE_FORCED_INACTIVE): // FORCED INACTIVE mode
            TIMS->Channels.OC3REF = 0; break;

    }
    if (TIMx->DIER & TIM_IT_CC3)
    {
        if (((TIMS->tx_cnt - TIMS->tx_step) < TIMx->CCR3) && (TIMS->tx_cnt >= TIMx->CCR3))
        {
            TIMx->SR |= TIM_SR_CC3IF;
        }
        else if (((TIMS->tx_cnt - TIMS->tx_step) > TIMx->CCR3) && (TIMS->tx_cnt <= TIMx->CCR3))
        {
            TIMx->SR |= TIM_SR_CC3IF;
        }
    }
}
void CC_PWM_Ch4_Simulation(TIM_TypeDef *TIMx, struct TIM_Sim *TIMS)
{ // определяет режим канала
    switch (TIMx->CCMR2 & TIM_CCMR2_OC4M)
    {
        case ((TIM_OCMODE_ACTIVE) << (TIM_OCMODE_SECOND_SHIFT)): // ACTIVE mode
            if (abs(TIMx->CNT - TIMx->CCR4) < 2*TIMS->tx_step) 
                TIMS->Channels.OC4REF = 1;
            break;

        case ((TIM_OCMODE_INACTIVE) << (TIM_OCMODE_SECOND_SHIFT)): // INACTIVE mode
            if (abs(TIMx->CNT - TIMx->CCR4) < 2*TIMS->tx_step) 
                TIMS->Channels.OC4REF = 0;
            break;

        case ((TIM_OCMODE_TOGGLE) << (TIM_OCMODE_SECOND_SHIFT)): // Toogle mode
            if (abs(TIMx->CNT - TIMx->CCR4) < 2*TIMS->tx_step) 
                TIMS->Channels.OC4REF = ~TIMS->Channels.OC4REF;
            break;
        
        case ((TIM_OCMODE_PWM1) << (TIM_OCMODE_SECOND_SHIFT)): // PWM mode 1 mode
            if (TIMx->CNT < TIMx->CCR4) 
                TIMS->Channels.OC4REF = 1;
            else
                TIMS->Channels.OC4REF = 0;
            break;
        
        case ((TIM_OCMODE_PWM2) << (TIM_OCMODE_SECOND_SHIFT)): // PWM mode 2 mode
            if (TIMx->CNT < TIMx->CCR4) 
                TIMS->Channels.OC4REF = 0;
            else
                TIMS->Channels.OC4REF = 1;
            break;
              
        case ((TIM_OCMODE_FORCED_ACTIVE) << (TIM_OCMODE_SECOND_SHIFT)): // FORCED ACTIVE mode
            TIMS->Channels.OC4REF = 1; break;
        
        case ((TIM_OCMODE_FORCED_INACTIVE) << (TIM_OCMODE_SECOND_SHIFT)): // FORCED INACTIVE mode
            TIMS->Channels.OC4REF = 0; break;

    }
    if (TIMx->DIER & TIM_IT_CC4)
    {
        if (((TIMS->tx_cnt - TIMS->tx_step) < TIMx->CCR4) && (TIMS->tx_cnt >= TIMx->CCR4))
        {
            TIMx->SR |= TIM_SR_CC4IF;
        }
        else if (((TIMS->tx_cnt - TIMS->tx_step) > TIMx->CCR4) && (TIMS->tx_cnt <= TIMx->CCR4))
        {
            TIMx->SR |= TIM_SR_CC4IF;
        }
    }
}
/* Запись каналов таймера в порты GPIO */
void Write_OC_to_GPIO(TIM_TypeDef *TIMx, struct TIM_Sim *TIMS)
{
    // write gpio pin if need
    if (Check_OC1_GPIO_Output(TIMS)) // check OC OUTPUT 4 enable (GPIO AF MODE)
    {
        uint32_t temp2 = ~(uint32_t)(1 << (TIMS->Channels.OC1_PIN_SHIFT));
        if (TIMx->CCER & TIM_CCER_CC1P) // POLARITY check
        {   // low POLARITY
            if (TIMS->Channels.OC1REF)
                TIMS->Channels.OC1_GPIOx->ODR &= ~(uint32_t)(1 << (TIMS->Channels.OC1_PIN_SHIFT));
            else
                TIMS->Channels.OC1_GPIOx->ODR |= 1 << (TIMS->Channels.OC1_PIN_SHIFT);
        }
        else
        {   // high POLARITY
            if (TIMS->Channels.OC1REF)
                TIMS->Channels.OC1_GPIOx->ODR |= 1 << (TIMS->Channels.OC1_PIN_SHIFT);
            else
                TIMS->Channels.OC1_GPIOx->ODR &= ~(uint32_t)(1 << (TIMS->Channels.OC1_PIN_SHIFT));
        }
    }
    if (Check_OC2_GPIO_Output(TIMS)) // check OC OUTPUT 4 enable (GPIO AF MODE)
    {
        if (TIMx->CCER & TIM_CCER_CC2P) // POLARITY check
        {   // low POLARITY
            if (TIMS->Channels.OC2REF)
                TIMS->Channels.OC2_GPIOx->ODR &= ~(uint32_t)(1 << (TIMS->Channels.OC2_PIN_SHIFT));
            else
                TIMS->Channels.OC2_GPIOx->ODR |= 1 << (TIMS->Channels.OC2_PIN_SHIFT);
        }
        else
        {   // high POLARITY
            if (TIMS->Channels.OC2REF)
                TIMS->Channels.OC2_GPIOx->ODR |= 1 << (TIMS->Channels.OC2_PIN_SHIFT);
            else
                TIMS->Channels.OC2_GPIOx->ODR &= ~(uint32_t)(1 << (TIMS->Channels.OC2_PIN_SHIFT));
        }
    }
    if (Check_OC3_GPIO_Output(TIMS)) // check OC OUTPUT 4 enable (GPIO AF MODE)
    {
        if (TIMx->CCER & TIM_CCER_CC3P) // POLARITY check
        {   // low POLARITY
            if (TIMS->Channels.OC3REF)
                TIMS->Channels.OC3_GPIOx->ODR &= ~(uint32_t)(1 << (TIMS->Channels.OC3_PIN_SHIFT));
            else
                TIMS->Channels.OC3_GPIOx->ODR |= 1 << (TIMS->Channels.OC3_PIN_SHIFT);
        }
        else
        {   // high POLARITY
            if (TIMS->Channels.OC3REF)
                TIMS->Channels.OC3_GPIOx->ODR |= 1 << (TIMS->Channels.OC3_PIN_SHIFT);
            else
                TIMS->Channels.OC3_GPIOx->ODR &= ~(uint32_t)(1 << (TIMS->Channels.OC3_PIN_SHIFT));
        }
    }
    if (Check_OC4_GPIO_Output(TIMS)) // check OC CHANNEL 4 enable (GPIO AF MODE)
    {
        if (TIMx->CCER & TIM_CCER_CC4P) // POLARITY check
        {   // low POLARITY
            if (TIMS->Channels.OC4REF)
                TIMS->Channels.OC4_GPIOx->ODR &= ~(uint32_t)(1 << (TIMS->Channels.OC4_PIN_SHIFT));
            else
                TIMS->Channels.OC4_GPIOx->ODR |= (1) << (TIMS->Channels.OC4_PIN_SHIFT);
        }
        else
        {   // high POLARITY
            if (TIMS->Channels.OC4REF)
                TIMS->Channels.OC4_GPIOx->ODR |= (1) << (TIMS->Channels.OC4_PIN_SHIFT);
            else
                TIMS->Channels.OC4_GPIOx->ODR &= ~(uint32_t)(1 << (TIMS->Channels.OC4_PIN_SHIFT));
        }
    }
}
/* Запись результата compare в глабальную структуру с TRIGGER OUTPUT */
void Write_TRGO(TIM_TypeDef* TIMx, struct TIM_Sim* TIMS)
{
    // write trigger output from OCxREF pin if need
    unsigned temp_trgo;
    if ((TIMx->CR2 & TIM_CR2_MMS) == (TIM_TRGO_OC1REF))
    {
        temp_trgo = TIMS->Channels.OC1REF;
    }
    else if ((TIMx->CR2 & TIM_CR2_MMS) == (TIM_TRGO_OC2REF))
    {
        temp_trgo = TIMS->Channels.OC2REF;
    }
    else if ((TIMx->CR2 & TIM_CR2_MMS) == (TIM_TRGO_OC3REF))
    {
        temp_trgo = TIMS->Channels.OC3REF;
    }
    else if ((TIMx->CR2 & TIM_CR2_MMS) == (TIM_TRGO_OC4REF))
    {
        temp_trgo = TIMS->Channels.OC4REF;
    }
    else if ((TIMx->CR2 & TIM_CR2_MMS) == (TIM_TRGO_UPDATE))
    {
        temp_trgo = TIMS->Updated;
    }
    else if ((TIMx->CR2 & TIM_CR2_MMS) == (TIM_TRGO_ENABLE))
    {
        temp_trgo = (TIMx->CR1 & TIM_CR1_CEN) ? 1: 0;
    }
    else if ((TIMx->CR2 & TIM_CR2_MMS) == (TIM_TRGO_RESET))
    {
        temp_trgo = 0;
    }

    
    // select TIMx TRGO
    if(0) {}
#ifdef USE_TIM1
    else if (TIMx == TIM1)
        Slave_Channels.TIM1_TRGO = temp_trgo;
#endif
#ifdef USE_TIM2
    else if (TIMx == TIM2)
        Slave_Channels.TIM2_TRGO = temp_trgo;
#endif
#ifdef USE_TIM3
    else if (TIMx == TIM3)
        Slave_Channels.TIM3_TRGO = temp_trgo;
#endif
#ifdef USE_TIM4
    else if (TIMx == TIM4)
        Slave_Channels.TIM4_TRGO = temp_trgo;
#endif
#ifdef USE_TIM5
    else if (TIMx == TIM5)
        Slave_Channels.TIM5_TRGO = temp_trgo;
#endif
#ifdef USE_TIM6
    else if (TIMx == TIM6)
        Slave_Channels.TIM6_TRGO = temp_trgo;
#endif
#ifdef USE_TIM7
    else if (TIMx == TIM7)
        Slave_Channels.TIM7_TRGO = temp_trgo;
#endif
#ifdef USE_TIM8
    else if (TIMx == TIM8)
        Slave_Channels.TIM8_TRGO = temp_trgo;
#endif
    temp_trgo = 0;
}
//------------------------------------------------------------------//




//--------------------MISC (temporary) FUNCTIONS--------------------//
void TIM_EGR_Simulation(TIM_TypeDef* TIMx, struct TIM_Sim* TIMS)
{
    // Update
    if (TIMx->EGR & TIM_EGR_UG) {
        TIMx->EGR &= ~TIM_EGR_UG;
        if (TIMx->DIER & TIM_DIER_UIE) {
            TIMx->SR |= TIM_SR_UIF;
        }
    }
    // Channels
    if (TIMx->EGR & TIM_EGR_CC1G) {
        TIMx->EGR &= ~TIM_EGR_CC1G;
        if (TIMx->DIER & TIM_IT_CC1) {
            TIMx->SR |= TIM_SR_CC1IF;
        }
    }
    if (TIMx->EGR & TIM_EGR_CC2G) {
        TIMx->EGR &= ~TIM_EGR_CC2G;
        if (TIMx->DIER & TIM_IT_CC2) {
            TIMx->SR |= TIM_SR_CC2IF;
        }
    }
    if (TIMx->EGR & TIM_EGR_CC3G) {
        TIMx->EGR &= ~TIM_EGR_CC3G;
        if (TIMx->DIER & TIM_IT_CC3) {
            TIMx->SR |= TIM_SR_CC3IF;
        }
    }
    if (TIMx->EGR & TIM_EGR_CC4G) {
        TIMx->EGR &= ~TIM_EGR_CC4G;
        if (TIMx->DIER & TIM_IT_CC4) {
            TIMx->SR |= TIM_SR_CC4IF;
        }
    }
}

/* Определение источника для запуска таймера в SLAVE MODE */
void Slave_Mode_Check_Source(TIM_TypeDef* TIMx, struct TIM_Sim* TIMS)
{
    if(0) {}
#ifdef USE_TIM2
    else if (TIMx == TIM2)
    {
        if ((TIMx->SMCR & TIM_SMCR_TS) == TIM_TS_ITR0)
            TIMx->CR1 |= (Slave_Channels.TIM1_TRGO << TIM_CR1_CEN_Pos);
        else if ((TIMx->SMCR & TIM_SMCR_TS) == TIM_TS_ITR1)
            TIMx->CR1 |= (Slave_Channels.TIM1_TRGO << TIM_CR1_CEN_Pos);
        else if ((TIMx->SMCR & TIM_SMCR_TS) == TIM_TS_ITR2)
            TIMx->CR1 |= (Slave_Channels.TIM1_TRGO << TIM_CR1_CEN_Pos);
        else if ((TIMx->SMCR & TIM_SMCR_TS) == TIM_TS_ITR3)
            TIMx->CR1 |= (Slave_Channels.TIM8_TRGO << TIM_CR1_CEN_Pos);
    }
#endif
#ifdef USE_TIM3
    else if (TIMx == TIM3)
    {
        if ((TIMx->SMCR & TIM_SMCR_TS) == TIM_TS_ITR0)
            TIMx->CR1 |= (Slave_Channels.TIM8_TRGO << TIM_CR1_CEN_Pos);
        else if ((TIMx->SMCR & TIM_SMCR_TS) == TIM_TS_ITR1)
            TIMx->CR1 |= (Slave_Channels.TIM2_TRGO << TIM_CR1_CEN_Pos);
        else if ((TIMx->SMCR & TIM_SMCR_TS) == TIM_TS_ITR2)
            TIMx->CR1 |= (Slave_Channels.TIM2_TRGO << TIM_CR1_CEN_Pos);
        else if ((TIMx->SMCR & TIM_SMCR_TS) == TIM_TS_ITR3)
            TIMx->CR1 |= (Slave_Channels.TIM3_TRGO << TIM_CR1_CEN_Pos);
    }
#endif
#ifdef USE_TIM4
    else if (TIMx == TIM4)
    {
        if ((TIMx->SMCR & TIM_SMCR_TS) == TIM_TS_ITR0)
            TIMx->CR1 |= (Slave_Channels.TIM3_TRGO << TIM_CR1_CEN_Pos);
        else if ((TIMx->SMCR & TIM_SMCR_TS) == TIM_TS_ITR1)
            TIMx->CR1 |= (Slave_Channels.TIM5_TRGO << TIM_CR1_CEN_Pos);
        else if ((TIMx->SMCR & TIM_SMCR_TS) == TIM_TS_ITR2)
            TIMx->CR1 |= (Slave_Channels.TIM3_TRGO << TIM_CR1_CEN_Pos);
        else if ((TIMx->SMCR & TIM_SMCR_TS) == TIM_TS_ITR3)
            TIMx->CR1 |= (Slave_Channels.TIM4_TRGO << TIM_CR1_CEN_Pos);
    }
#endif
#ifdef USE_TIM5
    else if (TIMx == TIM5)
    {
        if ((TIMx->SMCR & TIM_SMCR_TS) == TIM_TS_ITR0)
            TIMx->CR1 |= (Slave_Channels.TIM4_TRGO << TIM_CR1_CEN_Pos);
        else if ((TIMx->SMCR & TIM_SMCR_TS) == TIM_TS_ITR1)
            TIMx->CR1 |= (Slave_Channels.TIM4_TRGO << TIM_CR1_CEN_Pos);
        else if ((TIMx->SMCR & TIM_SMCR_TS) == TIM_TS_ITR2)
            TIMx->CR1 |= (Slave_Channels.TIM7_TRGO << TIM_CR1_CEN_Pos);
        else if ((TIMx->SMCR & TIM_SMCR_TS) == TIM_TS_ITR3)
            TIMx->CR1 |= (Slave_Channels.TIM7_TRGO << TIM_CR1_CEN_Pos);
    }
#endif
}
//------------------------------------------------------------------//


//------------------------SIMULINK FUNCTIONS------------------------//
// Симулирование выбранных таймеров
void Simulate_TIMs(void)
{
    //uwTick = hmcu.SystemClock / (MCU_CORE_CLOCK / 1000);
#ifdef USE_TIM1
    TIM_Simulation(TIM1, &tim1s);
#endif
#ifdef USE_TIM2
    TIM_Simulation(TIM2, &tim2s);
#endif
#ifdef USE_TIM3
    TIM_Simulation(TIM3, &tim3s);
#endif
#ifdef USE_TIM4
    TIM_Simulation(TIM4, &tim4s);
#endif
#ifdef USE_TIM5
    TIM_Simulation(TIM5, &tim5s);
#endif
#ifdef USE_TIM6
    TIM_Simulation(TIM6, &tim6s);
#endif
#ifdef USE_TIM7
    TIM_Simulation(TIM7, &tim7s);
#endif
#ifdef USE_TIM8
    TIM_Simulation(TIM8, &tim8s);
#endif
#ifdef USE_TIM9
    TIM_Simulation(TIM9, &tim9s);
#endif
#ifdef USE_TIM10
    TIM_Simulation(TIM10, &tim10s);
#endif
#ifdef USE_TIM11
    TIM_Simulation(TIM11, &tim11s);
#endif
#ifdef USE_TIM12
    TIM_Simulation(TIM12, &tim12s);
#endif
#ifdef USE_TIM13
    TIM_Simulation(TIM13, &tim13s);
#endif
#ifdef USE_TIM14
    TIM_Simulation(TIM14, &tim14s);
#endif
}
// Деинициализирование выбранных таймеров (вызывается в конце симуляции)
void TIM_SIM_DEINIT(void)
{
#ifdef USE_TIM1
    memset(&tim1s, 0, sizeof(tim1s));
#endif
#ifdef USE_TIM2
    memset(&tim2s, 0, sizeof(tim2s));
#endif
#ifdef USE_TIM3
    memset(&tim3s, 0, sizeof(tim3s));
#endif
#ifdef USE_TIM4
    memset(&tim4s, 0, sizeof(tim4s));
#endif
#ifdef USE_TIM5
    memset(&tim5s, 0, sizeof(tim5s));
#endif
#ifdef USE_TIM6
    memset(&tim6s, 0, sizeof(tim6s));
#endif
#ifdef USE_TIM7
    memset(&tim7s, 0, sizeof(tim7s));
#endif
#ifdef USE_TIM8
    memset(&tim8s, 0, sizeof(tim8s));
#endif
#ifdef USE_TIM9
    memset(&tim9s, 0, sizeof(tim9s));
#endif
#ifdef USE_TIM10
    memset(&tim10s, 0, sizeof(tim10s));
#endif
#ifdef USE_TIM11
    memset(&tim11s, 0, sizeof(tim11s));
#endif
#ifdef USE_TIM12
    memset(&tim12s, 0, sizeof(tim12s));
#endif
#ifdef USE_TIM13
    memset(&tim13s, 0, sizeof(tim13s));
#endif
#ifdef USE_TIM14
    memset(&tim14s, 0, sizeof(tim14s));
#endif
}
//------------------------------------------------------------------//

//------------------TIM'S HANDLERS (BETA) FUNCTIONS-----------------//
// Определение обработчиков, которые не используются
// Т.к. в MSVC нет понятия weak function, необходимо объявить все колбеки
// И если какой-то колбек не используется, его надо определить
//#ifndef USE_TIM1_UP_TIM10_HANDLER
__weak void TIM1_UP_TIM10_IRQHandler(void) {}
//#endif
//#ifndef USE_TIM2_HANDLER
__weak void TIM2_IRQHandler(void) {}
//#endif
//#ifndef USE_TIM3_HANDLER
__weak void TIM3_IRQHandler(void) {}
//#endif
//#ifndef USE_TIM4_HANDLER
__weak void TIM4_IRQHandler(void) {}
//#endif
//#ifndef USE_TIM5_HANDLER
__weak void TIM5_IRQHandler(void) {}
//#endif
//#ifndef USE_TIM6_HANDLER
__weak void TIM6_DAC_IRQHandler(void) {}
//#endif
//#ifndef USE_TIM7_HANDLER
__weak void TIM7_IRQHandler(void) {}
//#endif
//#ifndef USE_TIM8_UP_TIM13_HANDLER
__weak void TIM8_UP_TIM13_IRQHandler(void) {}
//#endif
//#ifndef USE_TIM1_BRK_TIM9_HANDLER
__weak void TIM1_BRK_TIM9_IRQHandler(void) {}
//#endif
//#ifndef USE_TIM1_TRG_COM_TIM11_HANDLER
__weak void TIM1_TRG_COM_TIM11_IRQHandler(void) {}
//#endif
//#ifndef USE_TIM8_BRK_TIM12_HANDLER
__weak void TIM8_BRK_TIM12_IRQHandler(void) {}
//#endif
//#ifndef USE_TIM8_TRG_COM_TIM14_HANDLER
__weak void TIM8_TRG_COM_TIM14_IRQHandler(void) {}
//#endif



/* Вызов прерывания */
void TIM_Call_IRQHandller(TIM_TypeDef* TIMx)
{ // calling HANDLER
    SR_STORE(TIMx, SR);

    if ((TIMx == TIM1) || (TIMx == TIM10))
        TIM1_UP_TIM10_IRQHandler();
    else if (TIMx == TIM2)
        TIM2_IRQHandler();
    else if (TIMx == TIM3)
        TIM3_IRQHandler();
    else if (TIMx == TIM4)
        TIM4_IRQHandler();
    else if (TIMx == TIM5)
        TIM5_IRQHandler();
    else if (TIMx == TIM6)
        TIM6_DAC_IRQHandler();
    else if (TIMx == TIM7)
        TIM7_IRQHandler();
    else if (((TIMx == TIM8) && (TIM8->SR & TIM_SR_UIF)) || (TIMx == TIM13))
        TIM8_UP_TIM13_IRQHandler();
    else if (((TIMx == TIM1) && 0) || (TIMx == TIM9))
        TIM1_BRK_TIM9_IRQHandler();
    else if (((TIMx == TIM1) && (TIM1->SR & (TIM_SR_CC1IF|TIM_SR_CC2IF | TIM_SR_CC3IF | TIM_SR_CC4IF))) || (TIMx == TIM11))
        TIM1_TRG_COM_TIM11_IRQHandler();
    else if (((TIMx == TIM8) && 0) || (TIMx == TIM12))
        TIM8_BRK_TIM12_IRQHandler();
    else if (((TIMx == TIM8) && (TIM8->SR & (TIM_SR_CC1IF | TIM_SR_CC2IF | TIM_SR_CC3IF | TIM_SR_CC4IF))) || (TIMx == TIM14))
        TIM8_TRG_COM_TIM14_IRQHandler();

    SR_PROCESS(TIMx, SR);
}
//------------------------------------------------------------------//
