//******************************************** Включаемые файлы *********************************************

#include "lmcal_cfg.h"
#include "lmcal_ptim_port.h"

#include "at32f403a_407_conf.h"

//******************************************* Локальные константы *******************************************

#if (LMCAL_PTIM_SET_ALT_TIM == 0)

// Настройка источника тактирования таймера
// Доступные значения: SYSTICK_CLOCK_SOURCE_AHBCLK_DIV8, SYSTICK_CLOCK_SOURCE_AHBCLK_NODIV
#define BSP_PTIM_CLK_SRC        (SYSTICK_CLOCK_SOURCE_AHBCLK_DIV8)

#endif

//******************************************* Проверка параметров *******************************************


//******************************************** Определения типов ********************************************


//************************************ Глобальные (публичные) переменные ************************************

// Callback из прерывания таймера
volatile void_fun_t lmcal_ptim_port_callback[LMCAL_PTIM_CALLBACK_QTY] = {NULL};

// Счетчик функций обратного вызова
volatile u8 lmcal_ptim_port_callback_qty = 0;

// Значение системной частоты
extern unsigned int system_core_clock;

//************************************* Локальные (приватные) переменные ************************************

static volatile u32 delay;


//***********************************************************************************************************
//******************************** Определения локальных (приватных) функций ********************************
//***********************************************************************************************************

static inline void ptim_delay_decrement(void)
{
    if (0U != delay){
        delay--;
    }
}


// Операции драйвера, выполняемые в прерывании
static void prim_irq_process(void)
{
    ptim_delay_decrement();

    // Вызов функций обратного вызова
    for(u8 cnt = 0U; cnt < lmcal_ptim_port_callback_qty; cnt++)
    {
        if (lmcal_ptim_port_callback[cnt] != NULL)
        {
            lmcal_ptim_port_callback[cnt]();
        }
    }
}

//***********************************************************************************************************
//******************************** Определения процедур обработки прерываний ********************************
//***********************************************************************************************************

#if (LMCAL_PTIM_SET_ALT_TIM == 0)

void SysTick_Handler(void)
{    
    SysTick->CTRL &= ~SysTick_CTRL_COUNTFLAG_Msk;

    prim_irq_process();
}

#elif (LMCAL_PTIM_SET_ALT_TIM == 1)

void TMR3_GLOBAL_IRQHandler(void)
{
    uint32_t flags;

    //clear flags
    TMR3->ists = ~(flags = TMR3->ists);
    if(flags & TMR_OVF_FLAG)
    {
        prim_irq_process();
    }
}

#endif

//***********************************************************************************************************
//******************************* Определения глобальных (публичных) функций ********************************
//***********************************************************************************************************

fun_res_t lmcal_ptim_port_init(void)
{
    fun_res_t err = ERR_OK;

    lmcal_ptim_port_callback_qty = 0;

    // Сброс функции обратного вызова
    for (u8 cnt = 0U; cnt < LMCAL_PTIM_CALLBACK_QTY; cnt++)
    {
        lmcal_ptim_port_callback[cnt] = NULL;
    }

    #if (LMCAL_PTIM_SET_ALT_TIM == 0)
    // Настройка источника тактирования systick
    systick_clock_source_config(BSP_PTIM_CLK_SRC);

    // Настройка systick и включение прерывания
    if(1 == SysTick_Config((system_core_clock / 1000U) * LMCAL_PTIM_PERIOD))
    {
        /* capture error */
        err = ERR_RUNTIME_ERROR;
    }

    #elif (LMCAL_PTIM_SET_ALT_TIM == 1)

    crm_clocks_freq_type crm_clocks_freq_struct = {0};
    crm_periph_clock_enable(CRM_TMR3_PERIPH_CLOCK, TRUE);
    
    /* enable the tmr3 global interrupt */
    nvic_irq_enable(TMR3_GLOBAL_IRQn, 1, 0);
    tmr_counter_enable(TMR3,FALSE);
    /* get system clock */
    crm_clocks_freq_get(&crm_clocks_freq_struct);
    /* time base configuration */
    /* apb1_clk/12000/10 = 1ms */
    tmr_base_init(TMR3, (10 - 1), (((crm_clocks_freq_struct.ahb_freq) / 10000) - 1));
    tmr_cnt_dir_set(TMR3,TMR_COUNT_UP);
    tmr_interrupt_enable(TMR3,TMR_OVF_INT, TRUE);
    tmr_counter_enable(TMR3,TRUE);

    #endif

    return err;
}



fun_res_t lmcal_ptim_port_deinit(void)
{
    fun_res_t err = ERR_OK;
    
    #if (LMCAL_PTIM_SET_ALT_TIM == 0)
    // Отключение таймера
    SysTick->CTRL = 0U;
    
    #elif (LMCAL_PTIM_SET_ALT_TIM == 1)

    #endif

    return err;
}



fun_res_t lmcal_ptim_port_delay(u32 count)
{
    fun_res_t err = ERR_OK;

    delay = count;
    while(0U != delay);

    return err;
}


//*********************************************** КОНЕЦ ФАЙЛА ***********************************************
