#include "main.h"
#include "speck.h"
#include "modbus_crc.h"

csa_t csa;


uint8_t flash_erase(uint32_t addr, uint32_t len)
{
    uint8_t err = 0xff;
    uint32_t ofs = addr & ~0x08000000;
    uint32_t s_page = ofs / ONCE_PAGE_SIZE;
    int n_page = (ofs + len) / ONCE_PAGE_SIZE - s_page;
    if ((ofs + len) % ONCE_PAGE_SIZE)
        n_page++;

    FLASH_Unlock();
    FLASH_UnOnlyReadMode();
    for (int i = 0; i < n_page; i++)
    {
        err = FLASH_ErasePage(0x08000000 + ONCE_PAGE_SIZE * (s_page + i));
        if (err != FLASH_COMPLETE)
            break;
    }
    FLASH_OnlyReadMode();
    FLASH_Lock();
    return err;
}


uint8_t flash_write(uint32_t addr, uint32_t len, uint8_t *buf)
{
    uint8_t err = 0xff;
    uint32_t write_cnt = (len + 3) / 4;
    uint32_t *src_addr = (uint32_t *) buf;
    uint32_t src_data;

    FLASH_Unlock();
    FLASH_UnOnlyReadMode();

    for (uint32_t i = 0; i < write_cnt; i++)
    {
        src_data = get_unaligned32((uint8_t *)(src_addr + i));
        err = FLASH_ProgramWord(addr + i * 4, src_data);
        if (err != FLASH_COMPLETE)
            break;
    }
    FLASH_OnlyReadMode();
    FLASH_Lock();
    return err;
}


void load_conf(void)
{
    uint16_t magic_code = *(uint16_t *)APP_CONF_ADDR;
    uint16_t conf_ver = *(uint16_t *)(APP_CONF_ADDR + 2);
    csa.magic_code = 0x4b50;
    csa.conf_ver = APP_CONF_VER;
    csa.mac = 0x01;

    if (magic_code == 0x4b50 && (conf_ver >> 8) == (APP_CONF_VER >> 8))
    {
        memcpy(&csa, (void *)APP_CONF_ADDR, offsetof(csa_t, _end_save));
        csa.conf_from = 1;
        memset(&csa.do_reboot, 0, 3);
    }
}

bool app_valid(void)
{
    bool ret = false;
    uint32_t len = *(uint32_t *)(APP_ADDR + APP_LEN_OFFSET);
    uint32_t crc = *(uint32_t *)(APP_ADDR + len);
    if (len > 0 && len < APP_MAX_LEN && crc == crc16((uint8_t *)APP_ADDR, len))
        ret = true;
    return ret;
}

void save_conf(void)
{
    flash_erase(APP_CONF_ADDR, ONCE_PAGE_SIZE);
    flash_write(APP_CONF_ADDR, offsetof(csa_t, _end_save), (uint8_t *)&csa);
}




