/**
 * @file flash_store.c
 * @brief Flash IAP 读写实现
 *
 * DDL 函数说明（HC32F003 标准驱动库）：
 *   Flash_SectorErase(addr)   — 擦除包含 addr 的 Sector（512字节）
 *   Flash_WordWrite(addr, w)  — 向 addr 写入 32 位字（addr 须 4 字节对齐）
 *   Flash_Read(addr, buf, n)  — 从 addr 读取 n 字节（也可直接指针访问）
 *
 * 注意：写 Flash 前必须先擦除（擦除后全 0xFF），Flash 不支持覆盖写。
 */

#include "flash_store.h"
#include "hc32f003_config.h"
#include <string.h>

/* =========================================================
 * CRC32 实现（标准以太网多项式，无表查找，节省 SRAM）
 * ========================================================= */
uint32_t CRC32_Calc(const uint8_t *data, uint32_t len)
{
    uint32_t crc = 0xFFFFFFFFUL;
    for (uint32_t i = 0; i < len; i++) {
        crc ^= (uint32_t)data[i];
        for (int bit = 0; bit < 8; bit++) {
            if (crc & 1) {
                crc = (crc >> 1) ^ 0xEDB88320UL;  /* 以太网反射多项式 */
            } else {
                crc >>= 1;
            }
        }
    }
    return crc ^ 0xFFFFFFFFUL;
}

/* =========================================================
 * Flash 操作封装（调用 HC32F003 DDL 函数）
 * ========================================================= */

/**
 * @brief 擦除 LUT 存储 Sector
 * DDL 调用：Flash_SectorErase(FLASH_LUT_ADDR)
 *   该函数擦除包含地址 FLASH_LUT_ADDR 的整个 Sector（512字节）
 */
static void Flash_EraseLutSector(void)
{
    /* HC32F003 DDL：Flash_SectorErase 函数声明（用户链接 DDL 库时需包含头文件）
     * extern void Flash_SectorErase(uint32_t addr);
     * 调用：Flash_SectorErase(FLASH_LUT_ADDR);
     *
     * 此处用宏/弱函数形式供用户替换，编译时链接实际 DDL 库 */
    extern void Flash_SectorErase(uint32_t addr);
    Flash_SectorErase(FLASH_LUT_ADDR);
}

/**
 * @brief 向 Flash 写入一个 32 位字
 * DDL 调用：Flash_WriteWord(addr, word)
 *   addr 必须 4 字节对齐
 */
static void Flash_Write32(uint32_t addr, uint32_t word)
{
    /* HC32F003 DDL 实际函数名：Flash_WriteWord */
    extern en_result_t Flash_WriteWord(uint32_t u32Addr, uint32_t u32Data);
    Flash_WriteWord(addr, word);
}

/* =========================================================
 * FlashStore_Save：写入 LutTable_t 到 Flash
 * ========================================================= */
int FlashStore_Save(const LutTable_t *lut)
{
    /* 1. 构建带 CRC 的完整结构体（在 SRAM 中操作） */
    LutTable_t tmp;
    memcpy(&tmp, lut, sizeof(LutTable_t));

    /* 2. 计算 CRC（覆盖 layer 数组，不含 crc 字段本身） */
    uint32_t data_len = offsetof(LutTable_t, crc);
    tmp.crc = CRC32_Calc((const uint8_t *)&tmp, data_len);

    /* 3. 擦除目标 Sector */
    Flash_EraseLutSector();

    /* 4. 按 32 位字逐字写入
     *    sizeof(LutTable_t) 必须 ≤ FLASH_SECTOR_SIZE(512)，确认：
     *    2层 × 20点 × 7字节 + 4字节CRC = 284 字节，满足 */
    const uint8_t *src = (const uint8_t *)&tmp;
    uint32_t total = sizeof(LutTable_t);
    uint32_t addr  = FLASH_LUT_ADDR;

    for (uint32_t offset = 0; offset < total; offset += 4, addr += 4) {
        uint32_t word = 0;
        /* 处理末尾不足 4 字节的情况（用 0xFF 填充，与擦后状态一致） */
        uint32_t remain = total - offset;
        if (remain >= 4) {
            memcpy(&word, src + offset, 4);
        } else {
            uint8_t buf[4] = {0xFF, 0xFF, 0xFF, 0xFF};
            memcpy(buf, src + offset, remain);
            memcpy(&word, buf, 4);
        }
        Flash_Write32(addr, word);
    }

    return 1;  /* 成功（DDL 通常有返回值，此处简化） */
}

/* =========================================================
 * FlashStore_Load：从 Flash 读取并校验 CRC
 * ========================================================= */
int FlashStore_Load(LutTable_t *lut)
{
    /* Flash 可直接通过指针读取（M0+ 内存映射） */
    const LutTable_t *flash_lut = (const LutTable_t *)FLASH_LUT_ADDR;

    /* 计算实际 CRC */
    uint32_t data_len = offsetof(LutTable_t, crc);
    uint32_t calc_crc = CRC32_Calc((const uint8_t *)flash_lut, data_len);

    if (calc_crc != flash_lut->crc) {
        return 0;  /* CRC 校验失败 */
    }

    /* 校验通过，拷贝到目标 */
    memcpy(lut, flash_lut, sizeof(LutTable_t));
    return 1;
}

/* =========================================================
 * FlashStore_UpdateLayer：更新单层并重新保存
 * ========================================================= */
int FlashStore_UpdateLayer(uint8_t layer_idx, const uint8_t *data)
{
    if (layer_idx >= LUT_LAYER_COUNT) {
        return 0;  /* 层索引越界 */
    }

    /* 将 140 字节数据解析为 20 个 LutPoint_t 并写入全局表 */
    for (int i = 0; i < LUT_POINTS_PER_LAYER; i++) {
        g_lut.layer[layer_idx][i].w1 = data[i * 7 + 0];
        g_lut.layer[layer_idx][i].c1 = data[i * 7 + 1];
        g_lut.layer[layer_idx][i].r  = data[i * 7 + 2];
        g_lut.layer[layer_idx][i].g  = data[i * 7 + 3];
        g_lut.layer[layer_idx][i].b  = data[i * 7 + 4];
        g_lut.layer[layer_idx][i].w  = data[i * 7 + 5];
        g_lut.layer[layer_idx][i].c  = data[i * 7 + 6];
    }

    /* 重新写入 Flash */
    return FlashStore_Save(&g_lut);
}
