#include "iap.h"
#include "stm32f4xx_flash.h"
// #include "mcp2515.h"
#include "bootloader.h"
#include "can.h"
#include "dwt.h"
#include "global.h"
#include <string.h>

static u8  iap_index             = 0;
static u16 iap_buf[IAP_BUF_SIZE] = {0};

extern SqQueue CanQueueImportant; // CAN重要数据队列

uint16_t STMFLASH_GetFlashSector(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;
}

u8 iap_init(void)
{
    FLASH_Status status = FLASH_COMPLETE;
    FLASH_Unlock();
    FLASH_DataCacheCmd(DISABLE);
    FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR | FLASH_FLAG_PGSERR);

    status = FLASH_EraseSector(FLASH_Sector_8, VoltageRange_3);
    if (status != FLASH_COMPLETE)
    {
        FLASH_DataCacheCmd(ENABLE); // FLASH擦除结束,开启数据缓存
        FLASH_Lock();               // 上锁
        return 1;
    }
    status = FLASH_EraseSector(FLASH_Sector_9, VoltageRange_3);
    if (status != FLASH_COMPLETE)
    {
        FLASH_DataCacheCmd(ENABLE); // FLASH擦除结束,开启数据缓存
        FLASH_Lock();               // 上锁
        return 1;
    }

    FLASH_DataCacheCmd(ENABLE); // FLASH擦除结束,开启数据缓存
    FLASH_Lock();               // 上锁
    return 0;
}

u8 STMFLASH_ReadByte(u32 faddr)
{
    return *(vu8 *)faddr;
}

u16 STMFLASH_ReadHalfWord(u32 faddr)
{
    return *(vu16 *)faddr;
}

u32 STMFLASH_ReadWord(u32 faddr)
{
    return *(vu32 *)faddr;
}

void copy_to_runaddr(u32 end_addr)
{
    FLASH_Status status      = FLASH_COMPLETE;
    u32          write_addr1 = IAP_RUN_START_SECTOR, read_addr = IAP_DOWN_BEGIN_ADDR;
    // u8  erase_sector = 0, index = 0;
    u32 temp_value = 0;
    // erase_sector = STMFLASH_GetFlashSector(IAP_RUN_START_SECTOR);
    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);

    status = FLASH_EraseSector(FLASH_Sector_4, VoltageRange_3);
    if (status != FLASH_COMPLETE)
    {
        FLASH_DataCacheCmd(ENABLE); // FLASH擦除结束,开启数据缓存
        FLASH_Lock();               // 上锁
        return;
    }
    status = FLASH_EraseSector(FLASH_Sector_5, VoltageRange_3);
    if (status != FLASH_COMPLETE)
    {
        FLASH_DataCacheCmd(ENABLE); // FLASH擦除结束,开启数据缓存
        FLASH_Lock();               // 上锁
        return;
    }

    while (end_addr > read_addr)
    {
        temp_value = STMFLASH_ReadWord(read_addr);
        if (FLASH_ProgramWord(write_addr1, temp_value) != FLASH_COMPLETE) // 写入数据
        {
            break; // 写入异常
        }

        write_addr1 += 4;
        read_addr += 4;
    }

    FLASH_DataCacheCmd(ENABLE); // FLASH擦除结束,开启数据缓存
    FLASH_Lock();               // 上锁
}

void iap_send_dataresp(u8 res, u32 addr, u32 sum)
{
    u8 send_buf[8] = {0};
    send_buf[0]    = IAP_CMD_DOWNLOAD;

    send_buf[1] = addr;
    send_buf[2] = addr >> 8;
    send_buf[3] = addr >> 16;
    send_buf[4] = res;
    send_buf[5] = addr >> 24;
    /*send_buf[1] = addr >> 16;
    send_buf[2] = addr >> 8;
    send_buf[3] = addr;
    send_buf[4] = res;
    send_buf[5] = 0xFF;*/

    send_buf[6] = (u8)(sum >> 8);
    send_buf[7] = (u8)sum;
    CAN2_Send_Msg(send_buf, DLC_8, IAP_MCU_DATA_FRAME);
}

void iap_send_datafinish(u16 page_num)
{
    u8 send_buf[8] = {0};
    send_buf[0]    = IAP_CMD_DOWNLOAD_END;
    send_buf[1]    = (u8)page_num;
    send_buf[2]    = (u8)(page_num >> 8);
    send_buf[3]    = 0xFF;
    send_buf[4]    = 0xFF;
    send_buf[5]    = 0xFF;
    send_buf[6]    = 0xFF;
    send_buf[7]    = 0xFF;
    CAN2_Send_Msg(send_buf, DLC_8, IAP_MCU_DATA_FRAME);
}

u8 stm_flash_write(u32 addr, u16 *array, u32 len)
{
    u8           res   = TRUE;
    u32          index = 0, temp_addr = addr;
    FLASH_Status status = FLASH_COMPLETE;
    FLASH_Unlock();
    FLASH_DataCacheCmd(DISABLE);
    for (index = 0; index < len;)
    {
        if (STMFLASH_ReadHalfWord(temp_addr) != 0xFFFF)
        {
            status = FLASH_EraseSector(STMFLASH_GetFlashSector(temp_addr), VoltageRange_3);
            if (status != FLASH_COMPLETE)
            {
                res = FALSE;
                break;
            }
        }
        else
        {
            index++;
            temp_addr += 2;
        }
    }
    if (status == FLASH_COMPLETE)
    {
        for (index = 0; index < len; index++)
        {
            if (FLASH_ProgramHalfWord(addr, array[index]) != FLASH_COMPLETE) // 写入数据
            {
                res = FALSE;
                break; // 写入异常
            }
            addr += 2;
            // array++;
        }
    }
    FLASH_DataCacheCmd(ENABLE);
    FLASH_Lock();

    return res;
}

void stm_flash_write_word(u32 addr, u32 value)
{
    u32          temp_addr = addr;
    FLASH_Status status    = FLASH_COMPLETE;
    FLASH_Unlock();
    FLASH_DataCacheCmd(DISABLE);

    if (STMFLASH_ReadWord(temp_addr) != 0xFFFFFFFF)
    {
        status = FLASH_EraseSector(STMFLASH_GetFlashSector(temp_addr), VoltageRange_3);
        if (status != FLASH_COMPLETE)
        {
            return;
        }
    }

    if (status == FLASH_COMPLETE)
    {
        if (FLASH_ProgramWord(addr, value) != FLASH_COMPLETE) // 写入数据
        {
            return;
        }
    }
    FLASH_DataCacheCmd(ENABLE);
    FLASH_Lock();
}

void stm_flash_write_byte(u32 addr, u8 value)
{
    u32          temp_addr = addr;
    FLASH_Status status    = FLASH_COMPLETE;
    FLASH_Unlock();
    FLASH_DataCacheCmd(DISABLE);

    if (STMFLASH_ReadByte(temp_addr) != 0xFF)
    {
        status = FLASH_EraseSector(STMFLASH_GetFlashSector(temp_addr), VoltageRange_3);
        if (status != FLASH_COMPLETE)
        {
            return;
        }
    }

    if (status == FLASH_COMPLETE)
    {
        if (FLASH_ProgramByte(addr, value) != FLASH_COMPLETE) // 写入数据
        {
            return;
        }
    }
    FLASH_DataCacheCmd(ENABLE);
    FLASH_Lock();
}

void iap_process(CanData_TypeDef *rx_msg)
{
    // 握手帧回复，最后一个字节为前7个字节累加和
    u8  handle_buf[DLC_8] = {'S', 'U', 'C', 'C', 'E', 'S', 'S', 0x19};
    u8  pc_frame[DLC_8]   = {'A', 'P', 'P', 'L', 'O', 'A', 'D', 0x01};
    u8  index = 0, pc_cmd = 0, pack_num = 0, res = 0;
    u16 rec_page_num = 0;
    u32 temp_addr    = 0;

    // FLASH_Status flash_res = FLASH_COMPLETE;
    static u16 cnt            = 0;
    static u16 total_page_num = 0;
    static u32 iap_sum        = 0;
    static u32 pack_receive   = 0;
    static u32 write_addr = 0, old_write_addr = 0;
    // static u32 write_test = IAP_DOWN_BEGIN_ADDR;

    if (rx_msg->can_id == IAP_PC_BEGINE_FRAME)
    {
        cnt = 0;
        if (memcmp(rx_msg->buf, pc_frame, 7) == 0)
        {
            // res = iap_init();
            total_page_num = 0;
            if (res == 0)
            {
                InitQueue(&CanQueueImportant);
                CAN2_Send_Msg(handle_buf, DLC_8, IAP_MCU_BIGEN_FRAME);
                write_addr = IAP_RUN_START_SECTOR; // IAP_DOWN_BEGIN_ADDR;
            }
            else
            {
                return;
            }
        }
    }
    else if (rx_msg->can_id == IAP_PC_DATA_FRAME)
    {
        cnt    = 0;
        pc_cmd = rx_msg->buf[0];
        switch (pc_cmd)
        {
        case IAP_CMD_DOWNLOAD:
            pack_num = rx_msg->buf[1];
            if (pack_num == 0x01)
            {
                iap_sum      = 0;
                iap_index    = 0;
                pack_receive = 0;
                pack_receive |= (1 << (pack_num - 1));
                write_addr = (rx_msg->buf[6] << 24) + (rx_msg->buf[5] << 16) + (rx_msg->buf[4] << 8) + rx_msg->buf[3];
            }
            else if ((pack_num > 0x01) && (pack_num < 0x17))
            {
                if (((pack_receive & 0x00000001) != 0x00000001) || ((pack_receive & (1 << (pack_num - 1))) == (1 << (pack_num - 1))))
                {
                    break;
                }
                iap_index = (pack_num - 2) * 3;
                for (index = 0; index < 3; index++)
                {
                    if (iap_index < (IAP_BUF_SIZE - 1))
                    {
                        pack_receive |= 1 << (pack_num - 1);
                        iap_buf[iap_index] = ((u16)rx_msg->buf[2 * index + 3] << 8) + rx_msg->buf[2 * index + 2];
                        iap_sum += iap_buf[iap_index];
                        iap_index++;
                    }
                }
            }
            else if (pack_num == 0x17)
            {
                if (((pack_receive & 0x00000001) != 0x00000001) || ((pack_receive & (1 << (pack_num - 1))) == (1 << (pack_num - 1))))
                {
                    break;
                }
                iap_index = 63;
                pack_receive |= 1 << (pack_num - 1);
                iap_buf[iap_index] = ((u16)rx_msg->buf[3] << 8) + rx_msg->buf[2];
                iap_sum += iap_buf[iap_index];
            }
            if ((pack_receive & 0x007FFFFF) == 0x007FFFFF)
            {
                // stm_flash_write(write_test, iap_buf, iap_index+1);
                // write_test += 2 * (iap_index+1);
                temp_addr = write_addr;
                if ((write_addr >= ADDR_FLASH_SECTOR_4) && (write_addr <= ADDR_FLASH_SECTOR_END) && (stm_flash_write(temp_addr, iap_buf, IAP_BUF_SIZE) == TRUE))
                {
                    iap_send_dataresp(MCU_DOWNLOAD_SUCC, write_addr, iap_sum);
                    if (write_addr != old_write_addr)
                    {
                        total_page_num++;
                        old_write_addr = write_addr;
                    }
                }
                else
                {
                    iap_send_dataresp(MCU_DOWNLOAD_FAIL, write_addr, iap_sum);
                }

                iap_sum      = 0;
                iap_index    = 0;
                pack_receive = 0;
            }
            break;
        case IAP_CMD_DOWNLOAD_END:
            rec_page_num = rx_msg->buf[2];
            rec_page_num = (rec_page_num << 8) | rx_msg->buf[1];
            if (rec_page_num != total_page_num)
            {
                break;
            }
            iap_send_datafinish(total_page_num);
            // copy_to_runaddr(write_addr-2);
            // copy_to_runaddr(write_test-2);
            write_addr     = IAP_RUN_START_SECTOR; // IAP_DOWN_BEGIN_ADDR;
            total_page_num = 0;
            bsp_DelayMS(300);
            boot_goto_app(APP_ADDRESS);
            break;
        }
    }
    else
    {
        cnt++;
        bsp_DelayMS(10);
        if (cnt > 50)
        {
            boot_goto_app(APP_ADDRESS);
        }
    }
}

u8 flash_up_is_ok(void)
{
    u32 len = 0;
    len     = STMFLASH_ReadWord(IAP_FLASH_UP_LEN);
    if ((len > 0) && (len < 455680)) // 445K
    {
        return TRUE;
    }
    else
    {
        return FALSE;
    }
}

void Iap_from_Flash(void)
{
    u32 value = 0, read_add = IAP_FLASH_UP_ADDR, write_add = IAP_RUN_START_SECTOR; // IAP_DOWN_BEGIN_ADDR;
    u32 len = 0;

    len = STMFLASH_ReadWord(IAP_FLASH_UP_LEN);
    while (len >= 4)
    {
        value = STMFLASH_ReadWord(read_add);
        stm_flash_write_word(write_add, value);
        read_add += 4;
        write_add += 4;
        len -= 4;
    }
    //    if(len != 0)
    //    {
    //        value = STMFLASH_ReadWord(read_add);
    //        stm_flash_write_word(write_add, value);
    //    }
    for (; len > 0; len--)
    {
        value = STMFLASH_ReadByte(read_add);
        stm_flash_write_byte(write_add, (u8)value);
        write_add++;
    }

    FLASH_Unlock();
    //    FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR
    //                    | FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR | FLASH_FLAG_PGSERR);
    FLASH_DataCacheCmd(DISABLE);
    FLASH_EraseSector(FLASH_Sector_8, VoltageRange_3);
    FLASH_EraseSector(FLASH_Sector_9, VoltageRange_3);
    FLASH_EraseSector(FLASH_Sector_10, VoltageRange_3);
    FLASH_EraseSector(FLASH_Sector_11, VoltageRange_3);
    FLASH_DataCacheCmd(ENABLE);
    FLASH_Lock();
}
