/************************************************************************************************
 *                                          Include                                              *
 ************************************************************************************************/

#include "flash.h"
#include "stm32f4xx.h"

/************************************************************************************************
 *                                          Config                                                *
 ************************************************************************************************/

/************************************************************************************************
 *                                          Data structs                                         *
 ************************************************************************************************/

/************************************************************************************************
 *                                          implements                                           *
 ************************************************************************************************/
uint16_t fmc_get_flash_sector(u32 addr)
{
    if (addr < ADDR_FLASH_SECTOR_1)
        return FLASH_Sector_0;
    else if (addr < ADDR_FLASH_SECTOR_2)
        return FLASH_Sector_1;
    else if (addr < ADDR_FLASH_SECTOR_3)
        return FLASH_Sector_2;
    else if (addr < ADDR_FLASH_SECTOR_4)
        return FLASH_Sector_3;
    else if (addr < ADDR_FLASH_SECTOR_5)
        return FLASH_Sector_4;
    else if (addr < ADDR_FLASH_SECTOR_6)
        return FLASH_Sector_5;
    else if (addr < ADDR_FLASH_SECTOR_7)
        return FLASH_Sector_6;
    else if (addr < ADDR_FLASH_SECTOR_8)
        return FLASH_Sector_7;
    else if (addr < ADDR_FLASH_SECTOR_9)
        return FLASH_Sector_8;
    else if (addr < ADDR_FLASH_SECTOR_10)
        return FLASH_Sector_9;
    else if (addr < ADDR_FLASH_SECTOR_11)
        return FLASH_Sector_10;
    return FLASH_Sector_11;
}

// 解除写保护，清除fmc特定寄存器
void fmc_clear_flag_star(void)
{
    FLASH_Unlock();              // 解锁
    FLASH_DataCacheCmd(DISABLE); // FLASH擦除期间,必须禁止数据缓存
    FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR | FLASH_FLAG_PGSERR);
}

// 设置写保护，清除fmc特定寄存器
void fmc_clear_flag_end(void)
{
    FLASH_DataCacheCmd(ENABLE); // FLASH擦除结束,开启数据缓存
    FLASH_Lock();               // 上锁
}

// 读取一字节， 读取无需考虑字节对齐
uint8_t fmc_read_byte(uint32_t read_addr)
{
    return *(vu8 *)read_addr;
}

// 读取两字节， 读取需考虑字节对齐
uint16_t fmc_read_half_word(uint32_t read_addr)
{
    return *(vu16 *)read_addr;
}

// 读取N字节， 读取必须需考虑字节对齐
uint8_t fmc_read_n_half_word(uint32_t read_addr, uint16_t *buff, uint16_t count)
{
    uint16_t i = 0;

    vu16 *addr = (vu16 *)read_addr;

    if (read_addr % 2 != 0)
        return 1; // 错误返回

    for (i = 0; i < count; i++)
    {
        *buff++ = *addr++;
    }
    return 0;
}

// 读取1页， 地址必须对齐页首
uint8_t fmc_read_one_page(uint32_t read_addr, uint16_t *buff)
{
    uint16_t i = 0;

    vu16 *addr = (vu16 *)read_addr;

    if (read_addr % FMC_PAGE_SIZE != 0)
        return 1; // 错误返回

    for (i = 0; i < 1024; i++)
    {
        *buff++ = *addr++;
    }
    return 0;
}

// 擦出N页， 地址必须对齐页首
uint8_t fmc_erase_pages(uint32_t erase_addr, uint16_t len)
{
    uint8_t status = 0;
    uint8_t i = 0, j = 0;
    for (i = 0; i < len; i++)
    {
        status = FLASH_EraseSector(fmc_get_flash_sector(erase_addr), VoltageRange_3);
        if (status != FLASH_COMPLETE)
        {
            return 1;
        }
        if ((erase_addr >= ADDR_FLASH_SECTOR_0) && (erase_addr < ADDR_FLASH_SECTOR_4))
        {
            erase_addr += (i * FMC_PAGE_SIZE_16K);
        }
        else if ((erase_addr >= ADDR_FLASH_SECTOR_4) && (erase_addr < ADDR_FLASH_SECTOR_5))
        {
            erase_addr += (i * FMC_PAGE_SIZE_64K);
        }
        else if ((erase_addr >= ADDR_FLASH_SECTOR_4) && (erase_addr < ADDR_FLASH_SECTOR_END))
        {
            erase_addr += (i * FMC_PAGE_SIZE_128K);
        }
        else
        {
            return 0;
        }
    }
    return 0;
    // uint16_t i = 0, j = 0;

    // uint32_t *addr = (uint32_t *)erase_addr;

    // if (erase_addr % FMC_PAGE_SIZE != 0)
    //     return 1; // 错误返回

    // for (i = 0; i < len; i++)
    // {
    //     FLASH_EraseSector(fmc_get_flash_sector(erase_addr), VoltageRange_3);
    //     for (j = 0; j < 512; j++)
    //     {
    //         if (*addr != 0xFFFFFFFF)
    //             return 1;
    //         else
    //             addr++;
    //     }
    // }
    // return 0;
}

// 只写入，写入前需擦除，地址必须两字节对齐
uint8_t fmc_write_n_half_word(uint32_t write_addr, uint16_t *buff, uint16_t len)
{

    uint32_t end_addr = write_addr + len * 2;

    if (write_addr % 2 != 0)
        return 1;

    while (write_addr < end_addr)
    {

        FLASH_ProgramHalfWord(write_addr, *buff); // 写入数据
        if (*(vu16 *)write_addr != *buff)
        {
            return 1;
        }
        write_addr += 2;
        buff++;
    }
    return 0;
}

// uint8_t stm_flash_write(uint32_t write_addr, uint16_t *buff, uint32_t len)
// {
//     uint8_t      res   = 1;
//     uint32_t     index = 0, temp_addr = write_addr;
//     FLASH_Status status = FLASH_COMPLETE;
//     for (index = 0; index < len;)
//     {
//         if (fmc_read_half_word(temp_addr) != 0xFFFF)
//         {
//             status = FLASH_EraseSector(fmc_get_flash_sector(temp_addr), VoltageRange_3);
//             if (status != FLASH_COMPLETE)
//             {
//                 res = 0;
//                 break;
//             }
//         }
//         else
//         {
//             index++;
//             temp_addr += 2;
//         }
//     }
//     if (status == FLASH_COMPLETE)
//     {
//         for (index = 0; index < len; index++)
//         {
//             if (FLASH_ProgramHalfWord(write_addr, buff[index]) != FLASH_COMPLETE) // 写入数据
//             {
//                 res = 0;
//                 // 写入异常
//                 break;
//             }
//             write_addr += 2;
//         }
//     }
//     return res;
// }

uint16_t firmware_crc16_ccitt_false(uint16_t init_value, uint8_t *pbuff, uint32_t len)
{
    uint16_t temp = 0;
    uint16_t crc  = init_value;

    for (int i = 0; i < len; i++)
    {
        for (int j = 0; j < 8; j++)
        {
            temp = ((pbuff[i] << j) & 0x80) ^ ((crc & 0x8000) >> 8);
            crc <<= 1;
            if (temp != 0)
            {
                crc ^= 0x1021;
            }
        }
    }
    return crc;
}