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

#include "self_diag.h"
#include "ring_buffer.h"
#include "task_man.h"
#include "lmcal.h"
#include "memtest.h"
#include "dbg_printf.h"


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

#define SDIAG_HEARTBEAT_PERIOD  (500)
#define SDIAG_MAIN_TASK_PERIOD  (1000)
#define SDIAG_ALARM_PERIOD      (400)
#define SDIAG_ALARM_DELAY       (1500)


// Указатель на секцию SDRAM
#define SD_SDRAM_TEST_MEMPTR   (0xC0000000)
// Объем SDRAM
#define SD_SDRAM_TEST_MEMSIZE  (0x02000000)
// Порция, после которой сбрасывается watchdog
#define SD_SDRAM_TEST_BLKSIZE  (0x00100000)


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

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


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

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

static bool b_init_done = false;

static u8 dscr_task_heart_beat = 0;
static u8 dscr_task_alarm_led = 0;
static u8 dscr_task_sdiag = 0;

static ringbuf_t err_fifo;
static u8 err_buf[SDIAG_ERR_BUF_SIZE];

static u8 sdiag_err_num = SD_ERR_OK;


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

static void f_task_heartbeet_led(void)
{
    static bool state = false;

    lmcal_gpio_write_pin(SDIAG_CH_HEARTBEAT_LED, state);
    state = !state;
}



static void f_task_alarm_led(void)
{
    static bool state_alarm = true;

    // Мигаем светодиодом код ошбки (см sdiag_err_t)

    lmcal_gpio_write_pin(SDIAG_CH_ALARM_LED, state_alarm);
    state_alarm = !state_alarm;

    sdiag_err_num--;

    if (sdiag_err_num == 0)
    {
        // Выполнили индикацию
        tm_stop_periodic_task(dscr_task_alarm_led);

        // Запускаем f_task_sdiag с небольшой задержкой
        tm_start_periodic_task(dscr_task_sdiag, SDIAG_MAIN_TASK_PERIOD);
        tm_delay_periodic_task(dscr_task_sdiag, SDIAG_ALARM_DELAY);
    }
}



static void f_task_sdiag(void)
{
    rb_size_t err_qty = rb_get_items_qty(&err_fifo);

    if (err_qty > 0)
    {
        // Получение кода ошибки
        rb_read_item(&err_fifo, &sdiag_err_num, 1);

        // увеличиваем счетчик в 2 раза
        sdiag_err_num += sdiag_err_num;

        // Вывод последнего кода ошибки
        tm_start_periodic_task(dscr_task_alarm_led, SDIAG_ALARM_PERIOD);

        // Не проверяем код ошибок до конца вывода
        tm_stop_periodic_task(dscr_task_sdiag);
    }

    // Отключаем светодиод аварии
    lmcal_gpio_write_pin(SDIAG_CH_ALARM_LED, false);
}



static void f_sdram_test()
{
    t_memtest_result memtest_res = 
        memtest_quick_32bit((void*)SD_SDRAM_TEST_MEMPTR, 
                            SD_SDRAM_TEST_BLKSIZE,
                            SD_SDRAM_TEST_MEMSIZE / SD_SDRAM_TEST_BLKSIZE, 
                            lmcal_loop
                            );

    if (memtest_res.addr != NULL) 
    {
        sdiag_set_err(SD_ERR_SDRAM_TEST_FAILURE);
        
        DBG_LOGE("sdram test error! addr 0x%08X, write 0x%08X, read 0x%08X\n",
                (unsigned)memtest_res.addr, memtest_res.wr_val, memtest_res.rd_val);
    } 
}

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


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

void sdiag_init(void)
{
    if (b_init_done == false)
    {
        b_init_done = true;

        tm_add_periodic_task(&dscr_task_heart_beat, f_task_heartbeet_led);
        tm_add_periodic_task(&dscr_task_alarm_led, f_task_alarm_led);
        tm_add_periodic_task(&dscr_task_sdiag, f_task_sdiag);
        
        tm_start_periodic_task(dscr_task_heart_beat, SDIAG_HEARTBEAT_PERIOD);
        tm_start_periodic_task(dscr_task_sdiag,      SDIAG_MAIN_TASK_PERIOD);

        // Включение светодиода ошибки
        lmcal_gpio_write_pin(SDIAG_CH_ALARM_LED, true);
        lmcal_gpio_write_pin(SDIAG_CH_HEARTBEAT_LED, true);

        // Инициализация очереди ошибок
        err_fifo.item_size = sizeof(u8);
        rb_init(&err_fifo,
                 err_buf,
                 SDIAG_ERR_BUF_SIZE);
        rb_clear(&err_fifo);

        // Test SDRAM
        f_sdram_test();
    }
}



void sdiag_deinit(void)
{
    if (b_init_done == true)
    {
        tm_deinit_periodic_task(dscr_task_heart_beat);
        tm_deinit_periodic_task(dscr_task_alarm_led);
        tm_deinit_periodic_task(dscr_task_sdiag);

        // Выключение светодиода ошибки
        lmcal_gpio_write_pin(SDIAG_CH_ALARM_LED, false);
        lmcal_gpio_write_pin(SDIAG_CH_HEARTBEAT_LED, false);

        b_init_done = false;
    }
}



void sdiag_reset(void)
{
    if (b_init_done == true)
    {
        rb_clear(&err_fifo);
    }
}



sdiag_err_t sdiag_get_last_error(void)
{    
    sdiag_err_t code = SD_ERR_OK;

    if (b_init_done == true)
    {
        // Получение кода ошибки
        rb_read_item(&err_fifo, &code, 1);
    }

    return code;
}



void sdiag_set_err(sdiag_err_t err)
{
    if (b_init_done == true)
    {
        rb_add_item(&err_fifo, &err);
    }
}


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