#include "led.h"
#include "partition.h"
#include "file.h"
#include "bitmap.h"
#include "ff.h"

/* unit of len is byte, len must multiple of 4 */
void file_write_flash_0(uint32_t flash, uint32_t len)
{
    uint32_t i;
    volatile uint32_t *p_flash;

    /* program data */
    FLASH_Unlock();
    FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | \
                FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR|FLASH_FLAG_PGSERR);
    for (i = 0; i < len / 4; i++) {
        if (FLASH_ProgramWord(flash + i * 4, 0) != FLASH_COMPLETE) {
            led_indicate_error();
        }
    }
    FLASH_Lock();
    /* check data */
    p_flash = (volatile uint32_t *)flash;
    for (i = 0; i < len / 4; i++) {
        if (p_flash[i] != 0) {
            led_indicate_error();
        }
    }
}

void file_bitmap_update(uint32_t mask)
{
    FRESULT ret;
    UINT bc;
    uint32_t idx;

    file_secctor_erase(SECTOR_BITMAP);
    if (mask & FILE_MASK_MAIN) {
        /* first open file */
        ret = f_open(&f, file_name[FILE_IDX_MAIN], FA_READ);
        if (ret != FR_OK) {
            led_indicate_error();
        }
        /* second program data to flash */
        idx = 0;
        while (1) {
            ret = f_read(&f, file_buffer, FILE_BUFF_SIZE, &bc);
            if (ret != FR_OK) {
                led_indicate_error();
            }
            file_write_flash(ADDR_MAIN + idx * FILE_BUFF_SIZE, file_buffer, (uint32_t)bc);
            if ((uint32_t)bc != FILE_BUFF_SIZE) {
                f_close(&f);
                break;
            }
            idx++;
        }
    }
    if (mask & FILE_MASK_GAS1) {
        /* first open file */
        ret = f_open(&f, file_name[FILE_IDX_GAS1], FA_READ);
        if (ret != FR_OK) {
            led_indicate_error();
        }
        /* second program data to flash */
        idx = 0;
        while (1) {
            ret = f_read(&f, file_buffer, FILE_BUFF_SIZE, &bc);
            if (ret != FR_OK) {
                led_indicate_error();
            }
            file_write_flash(ADDR_GAS1 + idx * FILE_BUFF_SIZE, file_buffer, (uint32_t)bc);
            if ((uint32_t)bc != FILE_BUFF_SIZE) {
                f_close(&f);
                break;
            }
            idx++;
        }
    } else {
        /* force calibration data as 0 */
        file_write_flash_0(ADDR_GAS1 + BITMAP_CALI_ADDR + 4, BITMAP_CALI_LEN - 4);
    }
    if (mask & FILE_MASK_GAS2) {
        /* first open file */
        ret = f_open(&f, file_name[FILE_IDX_GAS2], FA_READ);
        if (ret != FR_OK) {
            led_indicate_error();
        }
        /* second program data to flash */
        idx = 0;
        while (1) {
            ret = f_read(&f, file_buffer, FILE_BUFF_SIZE, &bc);
            if (ret != FR_OK) {
                led_indicate_error();
            }
            file_write_flash(ADDR_GAS2 + idx * FILE_BUFF_SIZE, file_buffer, (uint32_t)bc);
            if ((uint32_t)bc != FILE_BUFF_SIZE) {
                f_close(&f);
                break;
            }
            idx++;
        }
    } else {
        /* force calibration data as 0 */
        file_write_flash_0(ADDR_GAS2 + BITMAP_CALI_ADDR + 4, BITMAP_CALI_LEN - 4);
    }
    if (mask & FILE_MASK_GAS3) {
        /* first open file */
        ret = f_open(&f, file_name[FILE_IDX_GAS3], FA_READ);
        if (ret != FR_OK) {
            led_indicate_error();
        }
        /* second program data to flash */
        idx = 0;
        while (1) {
            ret = f_read(&f, file_buffer, FILE_BUFF_SIZE, &bc);
            if (ret != FR_OK) {
                led_indicate_error();
            }
            file_write_flash(ADDR_GAS3 + idx * FILE_BUFF_SIZE, file_buffer, (uint32_t)bc);
            if ((uint32_t)bc != FILE_BUFF_SIZE) {
                f_close(&f);
                break;
            }
            idx++;
        }
    } else {
        /* force calibration data as 0 */
        file_write_flash_0(ADDR_GAS3 + BITMAP_CALI_ADDR + 4, BITMAP_CALI_LEN - 4);
    }
    if (mask & FILE_MASK_GAS4) {
        /* first open file */
        ret = f_open(&f, file_name[FILE_IDX_GAS4], FA_READ);
        if (ret != FR_OK) {
            led_indicate_error();
        }
        /* second program data to flash */
        idx = 0;
        while (1) {
            ret = f_read(&f, file_buffer, FILE_BUFF_SIZE, &bc);
            if (ret != FR_OK) {
                led_indicate_error();
            }
            file_write_flash(ADDR_GAS4 + idx * FILE_BUFF_SIZE, file_buffer, (uint32_t)bc);
            if ((uint32_t)bc != FILE_BUFF_SIZE) {
                f_close(&f);
                break;
            }
            idx++;
        }
    } else {
        /* force calibration data as 0 */
        file_write_flash_0(ADDR_GAS4 + BITMAP_CALI_ADDR + 4, BITMAP_CALI_LEN - 4);
    }
}
