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

#include "lmcal_cfg.h"
#include "lmcal_gpio.h"
#include "lmcal_gpio_port.h"


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

// Макрос, заполняющий структуру конфиграции
#define GPIO_CH_CONFIG_FILL(nChNum)                        \
{                                                          \
    .b_enable    = (bool)LMCAL_GPIO_CH##nChNum##_ENABLE,   \
    .n_port_num  = (u32)LMCAL_GPIO_CH##nChNum##_PORT,      \
    .n_pin_num   = (u32)LMCAL_GPIO_CH##nChNum##_PIN,       \
    .n_mode      = (u32)LMCAL_GPIO_CH##nChNum##_MODE,      \
    .n_out_type  = (u32)LMCAL_GPIO_CH##nChNum##_OUT_TYPE,  \
    .n_pull_type = (u32)LMCAL_GPIO_CH##nChNum##_PULL_TYPE, \
    .n_irq_mode  = (u32)LMCAL_GPIO_CH##nChNum##_IRQ_MODE,  \
    .b_state     = (bool)LMCAL_GPIO_CH##nChNum##_STATE     \
}


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

// Конфигурация канала
typedef struct
{
    bool b_enable;
    u32  n_port_num;
    u32  n_pin_num;
    u32  n_mode;
    u32  n_out_type;
    u32  n_pull_type;
    u32  n_irq_mode;
    bool b_state;
} gpio_ch_config_t;


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

// Массив конфигурации каналов
static const gpio_ch_config_t gpio_st_ch_config[LMCAL_GPIO_CHANNEL_QTY] =
{
    GPIO_CH_CONFIG_FILL(0),
    GPIO_CH_CONFIG_FILL(1),
    GPIO_CH_CONFIG_FILL(2),
    GPIO_CH_CONFIG_FILL(3),
    GPIO_CH_CONFIG_FILL(4),
    GPIO_CH_CONFIG_FILL(5),
    GPIO_CH_CONFIG_FILL(6),
    GPIO_CH_CONFIG_FILL(7),
    GPIO_CH_CONFIG_FILL(8),
    GPIO_CH_CONFIG_FILL(9),
    GPIO_CH_CONFIG_FILL(10),
    GPIO_CH_CONFIG_FILL(11),
    GPIO_CH_CONFIG_FILL(12),
    GPIO_CH_CONFIG_FILL(13),
    GPIO_CH_CONFIG_FILL(14),
    GPIO_CH_CONFIG_FILL(15),
    GPIO_CH_CONFIG_FILL(16),
    GPIO_CH_CONFIG_FILL(17),
    GPIO_CH_CONFIG_FILL(18),
    GPIO_CH_CONFIG_FILL(19),
    GPIO_CH_CONFIG_FILL(20),
    GPIO_CH_CONFIG_FILL(21),
    GPIO_CH_CONFIG_FILL(22),
    GPIO_CH_CONFIG_FILL(23),
    GPIO_CH_CONFIG_FILL(24),
    GPIO_CH_CONFIG_FILL(25),
    GPIO_CH_CONFIG_FILL(26),
    GPIO_CH_CONFIG_FILL(27),
    GPIO_CH_CONFIG_FILL(28),
    GPIO_CH_CONFIG_FILL(29),
    GPIO_CH_CONFIG_FILL(30),
    GPIO_CH_CONFIG_FILL(31),
    GPIO_CH_CONFIG_FILL(32),
    GPIO_CH_CONFIG_FILL(33),
    GPIO_CH_CONFIG_FILL(34),
    GPIO_CH_CONFIG_FILL(35),
    GPIO_CH_CONFIG_FILL(36),
    GPIO_CH_CONFIG_FILL(37),
    GPIO_CH_CONFIG_FILL(38),
    GPIO_CH_CONFIG_FILL(39),
};

#if (LMCAL_DEBUG == 1)
static bool b_init_done = false;
#endif


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

#if (LMCAL_DEBUG == 1)
static fun_res_t f_check_channel(lmcal_gpio_channel_t channel)
{
    fun_res_t err = ERR_OK;

    if (channel > LMCAL_GPIO_CHANNEL_QTY)
    {
        err = ERR_INVALID_ARGUMENT;
    }

    return err;
}
#endif

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


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

fun_res_t lmcal_gpio_init(void)
{
    fun_res_t err = ERR_OK;

    #if (LMCAL_DEBUG == 1)
        err = L_ASSERT(false == b_init_done);
        L_CHECK_ERR(err);
    #endif
    
    err = lmcal_gpio_port_init(GPIO_PRE_OP);
    L_CHECK_ERR(err);

    // Инициализация всех включенных каналов
    for (u8 cnt = 0U; cnt < LMCAL_GPIO_CHANNEL_QTY; cnt++)
    {
        if (gpio_st_ch_config[cnt].b_enable == true)
        {            
            err = lmcal_gpio_port_init_periph(gpio_st_ch_config[cnt].n_port_num,
                                              gpio_st_ch_config[cnt].n_pin_num,
                                              gpio_st_ch_config[cnt].n_mode,
                                              gpio_st_ch_config[cnt].n_out_type,
                                              gpio_st_ch_config[cnt].n_pull_type,
                                              gpio_st_ch_config[cnt].n_irq_mode,
                                              gpio_st_ch_config[cnt].b_state);
            L_CHECK_ERR(err);
        }
    }

    err = lmcal_gpio_port_init(GPIO_POST_OP);
    L_CHECK_ERR(err);

    #if (LMCAL_DEBUG == 1)
    b_init_done = true;
    #endif

    L_EXIT;
    return err;
}



fun_res_t lmcal_gpio_deinit(void)
{
    fun_res_t err = ERR_OK;

    #if (LMCAL_DEBUG == 1)
        err = L_ASSERT(true == b_init_done);
        L_CHECK_ERR(err);
    #endif
    
    err = lmcal_gpio_port_deinit(GPIO_PRE_OP);
    L_CHECK_ERR(err);

    // Выполняем деинициализацию только включенных каналов
    for (u8 cnt = 0U; cnt < LMCAL_GPIO_CHANNEL_QTY; cnt++)
    {
        if (gpio_st_ch_config[cnt].b_enable == true)
        {
            err = lmcal_gpio_port_deinit_periph(gpio_st_ch_config[cnt].n_port_num,
                                                gpio_st_ch_config[cnt].n_pin_num);
            L_CHECK_ERR(err);
        }
    }

    err = lmcal_gpio_port_deinit(GPIO_POST_OP);
    L_CHECK_ERR(err);
    
    #if (LMCAL_DEBUG == 1)
    b_init_done = false;
    #endif

    L_EXIT;
    return err;
}



fun_res_t lmcal_gpio_write_pin(lmcal_gpio_channel_t channel, bool new_state)
{
    fun_res_t err = ERR_OK;

    #if (LMCAL_DEBUG == 1)
        err = L_ASSERT(true == b_init_done);
        L_CHECK_ERR(err);
        err = f_check_channel(channel);
        L_CHECK_ERR(err);
        err = L_ASSERT(true == gpio_st_ch_config[channel].b_enable);
        L_CHECK_ERR(err);
    #endif
    
    err = lmcal_gpio_port_write_pin(gpio_st_ch_config[channel].n_port_num,
                                    gpio_st_ch_config[channel].n_pin_num,
                                    new_state);
    
    #if (LMCAL_DEBUG == 1)
    L_EXIT;
    #endif
    return err;
}



err_or_res_t lmcal_gpio_read_pin(lmcal_gpio_channel_t channel)
{
    fun_res_t err = ERR_OK;
    err_or_res_t res = 0;

    #if (LMCAL_DEBUG == 1)
        err = L_ASSERT(true == b_init_done);
        L_CHECK_ERR(err);
        err = f_check_channel(channel);
        L_CHECK_ERR(err);
        err = L_ASSERT(true == gpio_st_ch_config[channel].b_enable);
        L_CHECK_ERR(err);
    #endif
    
    bool state = false;

    err = lmcal_gpio_port_read_pin(gpio_st_ch_config[channel].n_port_num,
                                   gpio_st_ch_config[channel].n_pin_num,
                                   &state);
    
    #if (LMCAL_DEBUG == 1)
    L_EXIT;
    #endif
    res = (err_or_res_t)((err == ERR_OK) ? (state) : (err));
    return res;                                              
}



fun_res_t lmcal_gpio_set_callback(lmcal_gpio_channel_t channel, void_fun_t function)
{
    fun_res_t err = ERR_OK;

    #if (LMCAL_DEBUG == 1)
        err = L_ASSERT(true == b_init_done);
        L_CHECK_ERR(err);
        err = f_check_channel(channel);
        L_CHECK_ERR(err);
        err = L_ASSERT(true == gpio_st_ch_config[channel].b_enable);
        L_CHECK_ERR(err);
        err = L_ASSERT(NULL != function);
        L_CHECK_ERR(err);
    #endif
    
    err =  lmcal_gpio_port_set_callback(gpio_st_ch_config[channel].n_port_num,
                                            gpio_st_ch_config[channel].n_pin_num,
                                            function);
    #if (LMCAL_DEBUG == 1)
    L_EXIT;
    #endif
    return err;
}


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