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

#include "lmcal.h"


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

#define LMCAL_STR_SIZE_MAX      (32)

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


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

typedef fun_res_t (*lmcal_init_fun_t)(void);

// Порядковый номер драйвера
typedef enum
{
    #ifdef LMCAL_CPU_EN
    LMCAL_DRV_CPU_NUM = 0,
    #endif
    #ifdef LMCAL_GPIO_EN
    LMCAL_DRV_GPIO_NUM,
    #endif
    #ifdef LMCAL_PTIM_EN
    LMCAL_DRV_PTIM_NUM,
    #endif
    #ifdef LMCAL_WDG_EN
    LMCAL_DRV_WDG_NUM,
    #endif
    #ifdef LMCAL_UART_EN
    LMCAL_DRV_UART_NUM,
    #endif
    #ifdef LMCAL_FLASH_EN
    LMCAL_DRV_FLASH_NUM,
    #endif
    #ifdef LMCAL_EXMC_EN
    LMCAL_DRV_EXMC_NUM,
    #endif
    #ifdef LMCAL_SDIO_EN
    LMCAL_DRV_SDIO_NUM,
    #endif
    #ifdef LMCAL_SPI_EN
    LMCAL_DRV_SPI_NUM,
    #endif
    #ifdef LMCAL_ADC_EN
    LMCAL_DRV_ADC_NUM,
    #endif
    #ifdef LMCAL_CAN_EN
    LMCAL_DRV_CAN_NUM,
    #endif
    #ifdef LMCAL_RTC_EN
    LMCAL_DRV_RTC_NUM,
    #endif

    LMCAL_DRV_QTY,
} lmcal_drv_num_t;


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


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

static lmcal_init_fun_t f_init_fun[LMCAL_DRV_QTY] = 
{
    #ifdef LMCAL_CPU_EN
    lmcal_cpu_init,
    #endif

    #ifdef LMCAL_GPIO_EN
    lmcal_gpio_init,
    #endif

    #ifdef LMCAL_PTIM_EN
    lmcal_ptim_init,
    #endif

    #ifdef LMCAL_WDG_EN
    lmcal_wdg_init,
    #endif

    #ifdef LMCAL_UART_EN
    lmcal_uart_init,
    #endif

    #ifdef LMCAL_FLASH_EN
    lmcal_flash_init,
    #endif

    #ifdef LMCAL_EXMC_EN
    lmcal_exmc_init,
    #endif

    #ifdef LMCAL_SDIO_EN
    lmcal_sdio_init,
    #endif

    #ifdef LMCAL_SPI_EN
    lmcal_spi_init,
    #endif

    #ifdef LMCAL_ADC_EN
    lmcal_adc_init,
    #endif

    #ifdef LMCAL_CAN_EN
    lmcal_can_init,
    #endif

    #ifdef LMCAL_RTC_EN
    lmcal_rtc_init,
    #endif
};

static lmcal_init_fun_t f_deinit_fun[LMCAL_DRV_QTY] = 
{
    #ifdef LMCAL_CPU_EN
    0,
    #endif

    #ifdef LMCAL_GPIO_EN
    lmcal_gpio_deinit,
    #endif

    #ifdef LMCAL_PTIM_EN
    lmcal_ptim_deinit,
    #endif

    #ifdef LMCAL_WDG_EN
    0,
    #endif

    #ifdef LMCAL_UART_EN
    lmcal_uart_deinit,
    #endif

    #ifdef LMCAL_FLASH_EN
    lmcal_flash_deinit,
    #endif

    #ifdef LMCAL_EXMC_EN
    lmcal_exmc_deinit,
    #endif

    #ifdef LMCAL_SDIO_EN
    lmcal_sdio_deinit,
    #endif

    #ifdef LMCAL_SPI_EN
    lmcal_spi_deinit,
    #endif

    #ifdef LMCAL_ADC_EN
    lmcal_adc_deinit,
    #endif

    #ifdef LMCAL_CAN_EN
    lmcal_can_deinit,
    #endif

    #ifdef LMCAL_RTC_EN
    0,
    #endif
};


static const char s_fun_info[LMCAL_DRV_QTY][LMCAL_STR_SIZE_MAX] = 
{
    #ifdef LMCAL_CPU_EN
    "lmcal_cpu_init()\0",
    #endif

    #ifdef LMCAL_GPIO_EN
    "lmcal_gpio_init()\0",
    #endif

    #ifdef LMCAL_PTIM_EN
    "lmcal_ptim_init()\0",
    #endif

    #ifdef LMCAL_WDG_EN
    "lmcal_wdg_init()\0",
    #endif
    
    #ifdef LMCAL_UART_EN
    "lmcal_uart_init()\0",
    #endif

    #ifdef LMCAL_FLASH_EN
    "lmcal_flash_init()\0",
    #endif

    #ifdef LMCAL_EXMC_EN
    "lmcal_exmc_init()\0",
    #endif

    #ifdef LMCAL_SDIO_EN
    "lmcal_sdio_init()\0",
    #endif

    #ifdef LMCAL_SPI_EN
    "lmcal_spi_init()\0",
    #endif

    #ifdef LMCAL_ADC_EN
    "lmcal_adc_init()\0",
    #endif
    
    #ifdef LMCAL_CAN_EN
    "lmcal_can_init()\0",
    #endif
    
    #ifdef LMCAL_RTC_EN
    "lmcal_rtc_init()\0",
    #endif
};

static const char s_err_info[ERR_QTY][LMCAL_STR_SIZE_MAX] = 
{
    "OK\0",
    "ASSERT_ERROR\0",
    "RUNTIME_ERROR\0",
    "INVALID_ARGUMENT\0",
    "NOT_IMPLEMENTED\0",
    "TIMEOUT_EXPIRED\0",
};

static fun_res_t last_err_num = ERR_OK;
static u8 last_err_drv = 0;

static const char s_deflt_string[5] = "none\0";

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



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


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

fun_res_t lmcal_init(void)
{
    fun_res_t err = ERR_OK;
    u8 cnt;
    
    // Сервисные переменные:
    last_err_num = 0;
    last_err_drv = 0;

    // Инициализация всех драйверов
    for (cnt = 0; cnt < (LMCAL_DRV_QTY); cnt++)
    {
        if (f_init_fun[cnt]() != 0)
        {
            err = f_init_fun[cnt]();
            L_CHECK_ERR(err);
        }
    }

    L_EXIT;
    if (ERR_OK != err)
    {
        last_err_num = err;
        last_err_drv = cnt;
    }

    return err;
}


void lmcal_deinit(void)
{
    // Деинициализация всех драйверов
    for (u8 cnt = 0; cnt < (LMCAL_DRV_QTY); cnt++)
    {
        if (f_deinit_fun[cnt]() != 0)
        {
            f_deinit_fun[cnt]();
        }
    }
}



const char* lmcal_err_get_last_fun_name (void)
{
    if (last_err_num != ERR_OK)
    {
        return s_fun_info[last_err_drv];
    }
    else
    {
        return s_deflt_string;
    }
}


const char* lmcal_err_get_last_err_name (void)
{
    const char* res;
    
    switch(last_err_num)
    {
        case(ERR_OK):
            res = s_err_info[0];
        break;
        case(ERR_ASSERT_ERROR):
            res = s_err_info[1];
        break;
        case(ERR_RUNTIME_ERROR):
            res = s_err_info[2];
        break;
        case(ERR_INVALID_ARGUMENT):
            res = s_err_info[3];
        break;
        case(ERR_NOT_IMPLEMENTED):
            res = s_err_info[4];
        break;
        case(ERR_TIMEOUT_EXPIRED):
            res = s_err_info[5];
        break;

        default:
            res = s_deflt_string;
        break;
    }

    return res;
}



void lmcal_loop(void)
{
    // Сброс WDG
    #ifdef LMCAL_WDG_EN
    lmcal_wdg_reset();
    #endif
}

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