#include "lks32mc09x_flash.h"

/**
 * @brief 向指定地址写入数据
 * @param adr 目标地址
 * @param data 数据缓冲区指针
 * @param len 数据长度
 * @note 触发掉电检测后，对flash的操作无效，掉电检测的配置参考SYS_SetPowerFailureDetection
 */
void FLASH_Write(uint32_t adr, uint8_t *data, uint32_t len)
{
    uint8_t *p   = data;
    uint32_t flg = __get_PRIMASK();
    __disable_irq();
    SYS_WR_PROTECT = 0x7a83;
    SYS_FLSP       = 0x8f35;
    FLASH->CFG |= BIT27 | BIT23;
    FLASH->ADDR = adr;
    len &= ~3; // 低两位值忽略
    for (; len > 0; len -= 4)
    {
        FLASH->WDATA = p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
        p += 4;
    }
    SYS_FLSP = 0;
    FLASH->CFG &= ~(BIT27 | BIT23);
    SYS_WR_PROTECT = 0;
    __set_PRIMASK(flg);
}

/**
 * @brief 从指定地址读取数据
 *
 * @param adr 目标地址
 * @param buf 数据缓冲区指针
 * @param len 数据长度
 */
void FLASH_Read(uint32_t adr, uint8_t *data, uint32_t len)
{
    uint32_t i;
    for (i = 0; i < len; i++)
    {
        data[i] = REG8(adr + i);
    }
}

/**
 * @brief 擦除指定扇区
 *
 * @param adr 目标地址
 * @note 触发掉电检测后，对flash的操作无效，掉电检测的配置参考SYS_SetPowerFailureDetection
 */
void FLASH_Erase(uint32_t adr)
{
    uint32_t flg = __get_PRIMASK();
    __disable_irq();
    SYS_WR_PROTECT = 0x7a83;
    SYS_FLSE       = 0x8fca;
    FLASH->CFG |= BIT31;
    FLASH->CFG &= ~BIT15;
    FLASH->ADDR  = adr;
    FLASH->ERASE = 0x7654DCBA;
    SYS_FLSE     = 0;
    FLASH->CFG &= ~BIT31;
    __set_PRIMASK(flg);
}

/**
 * @brief 向指定地址写入数据(NVR区域)
 * @param adr 目标地址
 * @param data 数据缓冲区指针
 * @param len 数据长度
 * @note 触发掉电检测后，对flash的操作无效，掉电检测的配置参考SYS_SetPowerFailureDetection
 */
void FLASH_WriteNvr(uint32_t adr, uint8_t *data, uint32_t len)
{
    uint8_t *p   = data;
    uint32_t flg = __get_PRIMASK();
    __disable_irq();
    SYS_WR_PROTECT = 0x7a83;
    SYS_FLSP       = 0x8f35;
    FLASH->CFG |= BIT27 | BIT23 | BIT11;
    FLASH->ADDR = adr;
    len &= ~3; // 低两位值忽略
    for (; len > 0; len -= 4)
    {
        FLASH->WDATA = p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
        p += 4;
    }
    SYS_FLSP = 0;
    FLASH->CFG &= ~(BIT27 | BIT23 | BIT11);
    SYS_WR_PROTECT = 0;
    __set_PRIMASK(flg);
}

/**
 * @brief 擦除指定扇区(NVR区域)
 *
 * @param adr 目标地址
 * @note 触发掉电检测后，对flash的操作无效，掉电检测的配置参考SYS_SetPowerFailureDetection
 */
void FLASH_EraseNvr(uint32_t adr)
{
    uint32_t flg = __get_PRIMASK();
    __disable_irq();
    SYS_WR_PROTECT = 0x7a83;
    SYS_FLSE       = 0x8fca;
    FLASH->CFG |= BIT31 | BIT11;
    FLASH->CFG &= ~BIT15;
    FLASH->ADDR  = adr;
    FLASH->ERASE = 0x7654DCBA;
    SYS_FLSE     = 0;
    FLASH->CFG &= ~(BIT31 | BIT11);
    __set_PRIMASK(flg);
}
/**
 * @brief 从指定地址读取数据(NVR区域)
 *
 * @param adr 目标地址
 * @param buf 数据缓冲区指针
 * @param len 数据长度
 */
void FLASH_ReadNvr(uint32_t adr, uint8_t *data, uint32_t len)
{
    uint32_t i;
    uint32_t flg = __get_PRIMASK();
    __disable_irq();
    FLASH->CFG |= BIT11;
    FLASH->ADDR = adr;
    for (i = 0; i < len; i += 4)
    {
        uint32_t val = FLASH_RDATA;
        data[i]      = val;
        data[i + 1]  = val >> 8;
        data[i + 2]  = val >> 16;
        data[i + 3]  = val >> 24;
    }
    FLASH->CFG &= ~BIT11;
    __set_PRIMASK(flg);
}
