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

#include "lmcal_cfg.h"
#include "lmcal_flash_port.h"
#include "fmc_operation.h"


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

// Размер возможных данных при обращении к Flash (1,2,4 байта)
#define FLASH_OPERATION_WORD_1  (1U)
#define FLASH_OPERATION_WORD_2  (2U)
#define FLASH_OPERATION_WORD_4  (4U)


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


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


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


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


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



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



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


fun_res_t lmcal_flash_port_init(void)
{
    fun_res_t err = ERR_OK;
       
    return err;
}


fun_res_t lmcal_flash_port_deinit(void)
{
    fun_res_t err = ERR_OK;
       
    return err;
}


fun_res_t lmcal_flash_port_write(u32 addres, u8* src, u32 size, void* param)
{
    fun_res_t err = ERR_OK;
    L_UNUSED(param);

    u32 nRemainingLength = size;
    u32 nDataByteCnt = 0;
    u32 nAddressPos = addres;

    fmc_unlock();

    fmc_flag_clear(FMC_FLAG_END | FMC_FLAG_OPERR | FMC_FLAG_WPERR | FMC_FLAG_PGMERR | FMC_FLAG_PGSERR);

    // Выполнение записи
    while(0 != nRemainingLength)
    {
        // Получаем размер одной записи
        if(nRemainingLength >= FLASH_OPERATION_WORD_4)
        {
            // Формируем слово для записи
            u32 nData = *((u32*)(src + nDataByteCnt));

            fmc_word_program(nAddressPos, nData);

            // Смещаем адрес на 4 байта
            nAddressPos += FLASH_OPERATION_WORD_4;
            nDataByteCnt += FLASH_OPERATION_WORD_4;
            nRemainingLength -=FLASH_OPERATION_WORD_4;
        }
        else if (nRemainingLength >= FLASH_OPERATION_WORD_2)
        {
            // Формируем слово для записи
            u16 nData = *((u16*)(src + nDataByteCnt));
            
            fmc_halfword_program(nAddressPos, nData);

            // Смещаем адрес на 2 байта
            nAddressPos += FLASH_OPERATION_WORD_2;
            nDataByteCnt += FLASH_OPERATION_WORD_2;
            nRemainingLength -=FLASH_OPERATION_WORD_2;
        }
        else if (nRemainingLength >= FLASH_OPERATION_WORD_1)
        {
            // Формируем слово для записи
            u8 nData = *((u8*)(src + nDataByteCnt));

            fmc_byte_program(nAddressPos, nData);
            
            // Смещаем адрес на 1 байт
            nAddressPos += FLASH_OPERATION_WORD_1;
            nDataByteCnt += FLASH_OPERATION_WORD_1;
            nRemainingLength -=FLASH_OPERATION_WORD_1;
        }
    } // while()

    fmc_lock();

    return err;
}


fun_res_t lmcal_flash_port_read(u32 addres, u8* dst, u32 size, void* param)
{
    fun_res_t err = ERR_OK;
    L_UNUSED(param);
    u32 nRemainingLength = size;
    u32 nDataByteCnt = 0;
    u32 nAddressPos = addres;

    // Выполнение чтения
    while(0 != nRemainingLength)
    {
        // Получаем размер одной записи
        if(nRemainingLength >= FLASH_OPERATION_WORD_4)
        {
            // Формируем слово для чтения
            u32 nData = *((u32*)(nAddressPos));

            *((u32*)(dst + nDataByteCnt)) = nData;
            
            // Смещаем адрес на 4 байта
            nAddressPos += FLASH_OPERATION_WORD_4;
            nDataByteCnt += FLASH_OPERATION_WORD_4;
            nRemainingLength -=FLASH_OPERATION_WORD_4;
        }
        else if (nRemainingLength >= FLASH_OPERATION_WORD_2)
        {
            // Формируем слово для чтения
            u16 nData = *((u16*)(nAddressPos));

            *((u16*)(dst + nDataByteCnt)) = nData;

            // Смещаем адрес на 2 байта
            nAddressPos += FLASH_OPERATION_WORD_2;
            nDataByteCnt += FLASH_OPERATION_WORD_2;
            nRemainingLength -=FLASH_OPERATION_WORD_2;
        }
        else if (nRemainingLength >= FLASH_OPERATION_WORD_1)
        {
            // Формируем слово для чтения
            u8 nData = *((u8*)(nAddressPos));

            *((u8*)(dst + nDataByteCnt)) = nData;

            // Смещаем адрес на 1 байт
            nAddressPos += FLASH_OPERATION_WORD_1;
            nDataByteCnt += FLASH_OPERATION_WORD_1;
            nRemainingLength -=FLASH_OPERATION_WORD_1;
        }
    } // while()

    return err;
}


fun_res_t lmcal_flash_port_erase(u32 addres, u32 size, void* param)
{
    fun_res_t err = ERR_OK;
    L_UNUSED(param);
    // L_UNUSED(size);

    fmc_flag_clear(FMC_FLAG_END | FMC_FLAG_OPERR | FMC_FLAG_WPERR | FMC_FLAG_PGMERR | FMC_FLAG_PGSERR);

    // Очистка несколько секторов
    fmc_erase_sectors_by_address(addres, (addres + size));

    return err;
}


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