/**
 * *************************************************************************************************************
 * @file Iap.c
 * @author BH_CodeGenerator
 * @version 0.1
 * @date 2022-04-01
 * @warning <!--auto generated by Tools, do not modify or add anything, otherwise, your change will be lost!!! -->
 * @brief all the functions prototypes for Iap firmware library
 * MCU / CFG Ver. :BH66F2475/1.7
 * Version = 1.0.0

 * *************************************************************************************************************
 *  @attention
 *
 *  Firmware Disclaimer Information
 *
 *  1. The customer hereby acknowledges and agrees that the program technical documentation, including the
 *     code, which is supplied by BEST HEALTH ELECTRONIC Inc., (hereinafter referred to as BestHealth) is the
 *     proprietary and confidential intellectual property of BestHealth, and is protected by copyright law and
 *     other intellectual property laws.
 *
 *  2. The customer hereby acknowledges and agrees that the program technical documentation, including the
 *     code, is confidential information belonging to BestHealth, and must not be disclosed to any third parties
 *     other than BestHealth and the customer.
 *
 *  3. The program technical documentation, including the code, is provided and for customer reference
 *     only. After delivery by BestHealth, the customer shall use the program technical documentation, including
 *     the code, at their own risk. BestHealth disclaims any expressed, implied or statutory warranties, including
 *     the warranties of merchantability, satisfactory quality and fitness for a particular purpose.
 *
 *  <h2><center>Copyright (C) BEST HEALTH ELECTRONIC Inc. All rights reserved</center></h2>
 */
#include "Iap.h"
#include "BH66F2455.h"

#define FLASH_PAGE_SIZE 64

#define PAGE_ERASE_MODE  0x90    // Block erase mode
#define READ_FLASH_MODE  0x32    // read flash mode
#define ENABLE_FWEN_MODE 0x68    // Write function enable mode
#define WRITE_FLASH_MODE 0x80    // write flash mode

#define WORD_LO(w) ((uint8_t)(w & 0xff))
#define WORD_HI(w) ((uint8_t)(w >> 8))

/**
 * @brief read one page data from the flash
 *
 * @param address start address
 * @param buf read data
 * @param len read word length
 */
void IAP_Read(uint16_t address, uint8_t *buf, uint8_t wordLen)
{
    _emi = 0;
    GCC_CLRWDT();
    _fc0  = READ_FLASH_MODE;
    _farl = WORD_LO(address);
    _farh = WORD_HI(address);
    uint8_t i;
    for (i = 0; i < wordLen; i++)
    {
        _frd = 1;    // Start reading
        while (_frd);
        *(buf++) = _fd0l;
        *(buf++) = _fd0h;
        _farl++;
    }
    _frden = 0;
    _emi   = 1;
}

/* *
 * @ Brief Flash memory write enable
 *
 * @Return true Success
 * @Return false fail
 */
bool IAP_EraseWrite_Enable(void)
{
    bool EMIStatus;
    EMIStatus = _emi;
    _emi      = 0;
    GCC_CLRWDT();
    _fc0  = ENABLE_FWEN_MODE;    // write function enable mode, start a 300us counter
    _fd1l = 0x00;                // Write the fixed pattern data sequence to the corresponding register in sequence.
    _fd1h = 0x04;
    _fd2l = 0x0D;
    _fd2h = 0x09;
    _fd3l = 0xC3;
    _fd3h = 0x40;
    _emi  = EMIStatus;
    while (_fwpen);    // This hardware is automatically cleared after the write enable is successful.
    return _cfwen;
}

/**
 * @brief erase the page from flash
 *
 * @param address erase address
 * @return true
 * @return false
 */
bool IAP_Erase_Page(uint16_t address)
{
    if (!IAP_EraseWrite_Enable())
        return false;
    _farl = WORD_LO(address);
    _farh = WORD_HI(address);
    _fc0  = PAGE_ERASE_MODE;
    uint8_t i;
    for (i = 0; i < 64; i++)
    {
        _fd0h = 0x00;    // 標記地址
    }
    _fwt = 1;
    while (_fwt)
    {
        GCC_CLRWDT();
    }
    // TODO: should use table read check data is 0x00
    _cfwen = 0;
    return true;
}

/**
 * @brief write one Page data to flash
 *
 * @param address page address
 * @param buf  write buffer
 * @param len write word length
 * @return true Success
 * @return false fail
 */
bool IAP_Write_Page(uint16_t address, uint8_t *buf, uint8_t wordLen)
{
    if (!IAP_EraseWrite_Enable())
        return false;

    _clwb = 1;                   // write Initiate clear write buffer process
    _fc0  = WRITE_FLASH_MODE;    // write mode
    _farl = WORD_LO(address);
    _farh = WORD_HI(address);

    uint8_t i;
    for (i = 0; i < wordLen; i++)
    {
        _fd0l = *buf++;
        _fd0h = *buf++;    // L -->H
        GCC_CLRWDT();
    }

    _fwt = 1;
    while (_fwt)
    {
        GCC_CLRWDT();
    }
    // TODO table read check data is correct
    _cfwen = 0;
    return true;
}