/*********************************************************************************************************************
 * File Name     : $Source: fdlapp_control.c $
 * Mod. Revision : $Revision: 1.8 $
 * Mod. Date     : $Date: 2014/07/30 13:14:47MESZ $
 * Device(s)     : RV40 Flash based RH850 microcontroller
 * Description   : Application sample program control module
 *********************************************************************************************************************/

/*********************************************************************************************************************
 * DISCLAIMER 
 * This software is supplied by Renesas Electronics Corporation and is only  intended for use with Renesas products. 
 * No other uses are authorized. This software is owned by Renesas Electronics Corporation and is protected under all 
 * applicable laws, including copyright laws. 
 * THIS SOFTWARE IS PROVIDED "AS IS" AND RENESAS MAKES NO WARRANTIES REGARDING THIS SOFTWARE, WHETHER EXPRESS, IMPLIED 
 * OR STATUTORY, INCLUDING BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
 * NON-INFRINGEMENT. ALL SUCH WARRANTIES ARE EXPRESSLY DISCLAIMED. 
 * TO THE MAXIMUM EXTENT PERMITTED NOT PROHIBITED BY LAW, NEITHER RENESAS ELECTRONICS CORPORATION NOR ANY OF ITS 
 * AFFILIATED COMPANIES SHALL BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES FOR ANY 
 * REASON RELATED TO THIS SOFTWARE, EVEN IF RENESAS OR ITS AFFILIATES HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH 
 * DAMAGES.
 * Renesas reserves the right, without notice, to make changes to this software and to discontinue the availability of 
 * this software. By using this software, you agree to the additional terms and conditions found by accessing the
 * following link: 
 * http://www.renesas.com/disclaimer 
 * 
 * Copyright (C) 2014 Renesas Electronics Corporation. All rights reserved.     
 *********************************************************************************************************************/

/*********************************************************************************************************************
 * header files include
 *********************************************************************************************************************/
#include "r_typedefs.h"
#include "r_fdl.h"
#include "fdl_descriptor.h"
#include "target.h"
#include "Watchdog.h"
#include "Emulated_EEPROM_Access.h"
#include "fdl_user.h"
#include <stdint.h>

/*********************************************************************************************************************
 * Module internal function prototypes
 *********************************************************************************************************************/

/*********************************************************************************************************************
   Function name:  SampleApp_FDL_Control
 *********************************************************************************************************************/
/**
    EEL sample function to handle FDL functionality. Executing a set of dummy Flash operations

    @param          ---
    @return         ---
 */
/*********************************************************************************************************************/
#define OFFSET_ADDR 0xFF200000UL

void SampleApp_FDL_Control(void)
{

    r_fdl_status_t fdlRet;
    r_fdl_request_t req;
    uint8_t wBuf_au08[64] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
                             0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
                             0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
                             0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
                             0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
                             0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
                             0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
                             0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f};
    uint32_t rBuf_au32[64]; /* Read buffer must be 32bit aligned as the read operation accesses it 32bit aligned */
    volatile uint16_t data;

    /* 1st initialize the FDL */
    fdlRet = R_FDL_Init(&sampleApp_fdlConfig_enu);
    if (R_FDL_OK != fdlRet)
    {
        /* Error handler */
        while (1)
            ;
    }

#ifndef R_FDL_LIB_V1_COMPATIBILITY
    /* Prepare the environment */
    req.idx_u32 = 0;
    req.command_enu = R_FDL_CMD_PREPARE_ENV;
    req.cnt_u16 = 0;
    req.accessType_enu = R_FDL_ACCESS_NONE;
    R_FDL_Execute(&req);

    while (R_FDL_BUSY == req.status_enu)
    {
        R_FDL_Handler();
    }
    if (R_FDL_OK != req.status_enu)
    {
        /* Error handler */
        while (1)
            ;
    }
#endif

    /* -----------------------------------------------------------------------
       Example...
       Read a Word --> address 0x0004 of the Data Flash
       1) Do a blank check to distinguish if the read value is based on erased
          data or written data. We can only trust written data
       2) read the data 
       ----------------------------------------------------------------------- */
    req.command_enu = R_FDL_CMD_BLANKCHECK;
    req.idx_u32 = 0; //地址
    req.cnt_u16 = 1; //
    req.accessType_enu = R_FDL_ACCESS_USER;
    R_FDL_Execute(&req);

    while (R_FDL_BUSY == req.status_enu)
    {
        R_FDL_Handler();
    }

    if (R_FDL_OK == req.status_enu)
    {
        /* The half word is blank... we may not read */
    }
    else if (R_FDL_ERR_BLANKCHECK == req.status_enu)
    {
        /* Read the data */
        data = (*(uint16_t *)0xff200004);
    }
    else
    {
        /* Error handler.. on an internal error */
        while (1)
            ;
    }

    /* -----------------------------------------------------------------------
       Example...
       Erase Flash block 0
       ----------------------------------------------------------------------- */
    req.command_enu = R_FDL_CMD_ERASE;
    req.idx_u32 = 0; //起始块///32K
    req.cnt_u16 = 1; //块计数
    req.accessType_enu = R_FDL_ACCESS_USER;
    R_FDL_Execute(&req);

    while (R_FDL_BUSY == req.status_enu)
    {
        R_FDL_Handler();
    }
    if (R_FDL_OK != req.status_enu)
    {
        /* Error handler */
        while (1)
            ;
    }
    /* wBuf_au08[0] = 0xaa;
    wBuf_au08[1] = 0x55;
    wBuf_au08[2] = 0xCC;
    wBuf_au08[3] = 0xFF;

    wBuf_au08[20] = 0xaa;
    wBuf_au08[21] = 0x55;
    wBuf_au08[22] = 0xCC;
    wBuf_au08[23] = 0xFF;*/
    /* -----------------------------------------------------------------------
       Write data:
       addresses 0x00000000 - 0x0000001F
       ----------------------------------------------------------------------- */
    req.command_enu = R_FDL_CMD_WRITE;
    req.idx_u32 = 0x0000; //地址
    req.cnt_u16 = 0x8;    //长度  单位u32
    req.bufAddr_u32 = (uint32_t)(&wBuf_au08[0]);
    req.accessType_enu = R_FDL_ACCESS_USER;
    R_FDL_Execute(&req);
    while (R_FDL_BUSY == req.status_enu)
    {
        R_FDL_Handler();
    }
    if (R_FDL_OK != req.status_enu)
    {
        /* Error handler */
        while (1)
            ;
    }

    /* -----------------------------------------------------------------------
       Read data:
       addresses 0x00000000 - 0x0000001F
       ----------------------------------------------------------------------- */
    req.command_enu = R_FDL_CMD_READ;
    req.idx_u32 = 0x0000; //地址
    req.cnt_u16 = 0x8;    //长度  单位u32
    req.bufAddr_u32 = (uint32_t)(&rBuf_au32[0]);
    req.accessType_enu = R_FDL_ACCESS_USER;
    R_FDL_Execute(&req);
    while (R_FDL_BUSY == req.status_enu)
    {
        R_FDL_Handler();
    }
    if (R_FDL_OK != req.status_enu)
    {
        /* Error handler */
        while (1)
            ;
    }

    /* -----------------------------------------------------------------------
       Read data:
       addresses 0x00000020 - 0x00000023 
       ... Most probably resulting in ECC error
       ----------------------------------------------------------------------- */
    req.command_enu = R_FDL_CMD_READ;
    req.idx_u32 = 0x0020;
    req.cnt_u16 = 0x1;
    req.bufAddr_u32 = (uint32_t)(&rBuf_au32[0]);
    req.accessType_enu = R_FDL_ACCESS_USER;
    R_FDL_Execute(&req);
    while (R_FDL_BUSY == req.status_enu)
    {
        R_FDL_Handler();
    }

    if ((R_FDL_ERR_ECC_SED != req.status_enu) &&
        (R_FDL_ERR_ECC_DED != req.status_enu))
    {
        /* Error handler */
        while (1)
            ;
    }

    return;
}
/*********************************************************************************/
/*********************************************************************************/
/*********************************************************************************/
r_fdl_status_t TYW_FDL_Init(void)
{
    r_fdl_status_t fdlRet;
    r_fdl_request_t req;

    FDL_Open();

    /* 1st initialize the FDL */
    fdlRet = R_FDL_Init(&sampleApp_fdlConfig_enu);
    if (R_FDL_OK != fdlRet)
    {
        /* Error handler */
        return fdlRet;
    }

#ifndef R_FDL_LIB_V1_COMPATIBILITY
    /* Prepare the environment */
    req.command_enu = R_FDL_CMD_PREPARE_ENV;
    req.idx_u32 = 0;
    req.cnt_u16 = 0;
    req.accessType_enu = R_FDL_ACCESS_NONE;
    R_FDL_Execute(&req);

    while (R_FDL_BUSY == req.status_enu)
    {
        R_FDL_Handler();
        WDT_Clear();
    }
    return req.status_enu;
#endif
}

r_fdl_status_t TYW_FDL_Erase(uint32_t u32StartAddr, uint32_t u32EndAddr)
{

    r_fdl_request_t req;
    uint32_t StartBlockIndex = 0U;
    uint32_t EndBlockIndex = 0U;

    StartBlockIndex = ((u32StartAddr - OFFSET_ADDR) / 64U);
    EndBlockIndex = ((u32EndAddr - OFFSET_ADDR) / 64U);

    req.command_enu = R_FDL_CMD_ERASE;
    req.idx_u32 = StartBlockIndex;                       //起始块///32K
    req.cnt_u16 = (EndBlockIndex + 1 - StartBlockIndex); //1; //块计数
    req.accessType_enu = R_FDL_ACCESS_USER;
    R_FDL_Execute(&req);

    while (R_FDL_BUSY == req.status_enu)
    {
        R_FDL_Handler();
        WDT_Clear();
    }
    if (R_FDL_OK == req.status_enu)
    {
        EEPROM_Mem_Access_Complete_Callback();
    }

    return req.status_enu;
}
r_fdl_status_t TYW_FDL_Write(uint32_t u32Addr, uint32_t u32Data[], uint32_t u32Len)
{
    r_fdl_request_t req;

    req.command_enu = R_FDL_CMD_WRITE;
    req.idx_u32 = u32Addr - OFFSET_ADDR; //地址
    req.cnt_u16 = u32Len;                //长度  单位u32
    req.bufAddr_u32 = (uint32_t)(&u32Data[0]);
    req.accessType_enu = R_FDL_ACCESS_USER;
    R_FDL_Execute(&req);
    while (R_FDL_BUSY == req.status_enu)
    {
        R_FDL_Handler();
        WDT_Clear();
    }
    if (R_FDL_OK == req.status_enu)
    {
        EEPROM_Mem_Access_Complete_Callback();
    }

    return req.status_enu;
}
/*
u32StartAddr:需是4的倍数
u32EndAddr:加1之后需是4的倍数
*/
uint32_t TYW_FDL_Blank_Check(uint32_t u32StartAddr, uint32_t u32EndAddr)
{
    r_fdl_request_t req;
    uint32_t u32Addr = 0xFFFFFFFFU;
    uint32_t i;
    uint32_t Result;
    uint32_t Count = (u32EndAddr - u32StartAddr + 1) / 4;
    uint32_t CalBuf = 0U;

    CalBuf = u32EndAddr - (u32EndAddr % 4);

    for (i = 0; i < Count; i++)
    {
        req.command_enu = R_FDL_CMD_BLANKCHECK;
        req.idx_u32 = CalBuf - OFFSET_ADDR; //
        req.cnt_u16 = 1;                    //
        req.accessType_enu = R_FDL_ACCESS_USER;
        R_FDL_Execute(&req);

        while (R_FDL_BUSY == req.status_enu)
        {
            R_FDL_Handler();
            WDT_Clear();
        }

        if (R_FDL_OK == req.status_enu)
        {
            u32Addr = CalBuf - u32StartAddr;
            CalBuf -= 4;
        }
        else
        {
            break;
        }
    }
    return (u32Addr);
}

r_fdl_status_t TYW_FDL_Flash_Read(uint32_t u32Addr, uint32_t u32Data[], uint32_t u32Len)
{
    r_fdl_request_t req;
    uint32_t u32BlankCeck = 0UL;

    u32BlankCeck = TYW_FDL_Blank_Check(u32Addr, (u32Addr + u32Len * 4UL-1UL));
    if (u32BlankCeck == 0xFFFFFFFFU)
    {
        req.command_enu = R_FDL_CMD_READ;
        req.idx_u32 = u32Addr - OFFSET_ADDR; //地址
        req.cnt_u16 = u32Len;                //长度  单位u32
        req.bufAddr_u32 = (uint32_t)(&u32Data[0]);
        req.accessType_enu = R_FDL_ACCESS_USER;
        R_FDL_Execute(&req);
        while (R_FDL_BUSY == req.status_enu)
        {
            R_FDL_Handler();
            WDT_Clear();
        }
        return req.status_enu;
    }
    return R_FDL_ERR_ECC_DED;
}
