#include "bsp_fdb.h"
#include "bsp_head.h"

#include "kit_data.h"
#include "kit_debug.h"


#define FDB_HEAD_FREE_MARK      (0xFFFFFFFF)
#define FDB_HEAD_VALID_MARK     (0xEEEEEEEE)
#define FDB_DATA_MARK           (0x5A5A5A5A)


//数据结构 FDB_DATA_MARK(4Byte) + 数据索引(2Byte) + 数据长度(2Byte) + 数据(N Byte)
void bsp_fdb_init(FdbItem *item)
{
    uint32_t i, idx, tmp;
    if(ARM_READ_INT32U(item->main_area) != FDB_HEAD_VALID_MARK)
    {
        //可能为旧modbus模型
        tmp = ARM_READ_INT16U(item->main_area);
        if((tmp < 10 * 1024) && kit_check_crc16((uint8_t *)item->main_area, tmp) == 0)
        {
            if(ARM_READ_INT32U(item->sub_area) != FDB_HEAD_FREE_MARK)
            {
                drv_flash_series_erase_page(item->sub_area, 1);
            }
            drv_drv_flash_write_u32(item->sub_area, FDB_HEAD_VALID_MARK);
            drv_drv_flash_write_u32(item->sub_area + 4, FDB_DATA_MARK);
            
            if(tmp % 4 != 0)
            {
                tmp += 4 - (tmp % 4);
            }

            drv_drv_flash_write_u32(item->sub_area + 8, ((tmp + 8) << 16) | 0x0A);
            drv_bsp_flash_write_data_u32(item->sub_area + 12, (uint8_t *)item->main_area, tmp);
            drv_flash_series_erase_page(item->main_area, 1);
            drv_bsp_flash_write_data_u32(item->main_area, (uint8_t *)item->sub_area, tmp + 12);
            
            item->write_addr = item->main_area + tmp + 12;
            item->data_addr[9] = item->main_area + 12;
        }
        //第一次存储
        else
        {
            drv_flash_series_erase_page(item->main_area, 1);
            drv_flash_series_erase_page(item->sub_area, 1);
            drv_drv_flash_write_u32(item->main_area, FDB_HEAD_VALID_MARK);
            item->write_addr = item->main_area + 4;
        }
    }
    else
    {
        tmp = item->main_area + item->area_size;
        for(i = item->main_area + 4; i < tmp; )
        {
            if(ARM_READ_INT32U(i) == FDB_DATA_MARK)
            {
                idx = ARM_READ_INT16U(i + 4);
                if(idx < item->data_cnt)
                {
                    item->data_addr[idx] = i + 8;
                    i += ARM_READ_INT16U(i + 6);
                    continue;
                }
            }
            else if(ARM_READ_INT32U(i) == FDB_HEAD_FREE_MARK)
            {
                break;
            }
            i += 4;
        }
        item->write_addr = i;
    }
}

bool bsp_fdb_write_data(FdbItem *item, uint8_t data_idx, uint8_t *buf, uint16_t len)
{
    kit_ret_e res = kKit_Ret_Ok;
    uint32_t i, tmp, addr;
    if((item != NULL) && (data_idx < item->data_cnt) && (item->write_addr != NULL))
    {
        if(len % 4 != 0)
        {
            len += 4 - (len % 4);
        }
        
        if(item->write_addr + len + 4 + 4 >= item->main_area + item->area_size)
        {
            if(ARM_READ_INT32U(item->sub_area) != FDB_HEAD_FREE_MARK)
            {
                res |= drv_flash_series_erase_page(item->sub_area, 1);
            }
            addr = item->sub_area;

            res |= drv_drv_flash_write_u32(addr, FDB_HEAD_VALID_MARK);
            addr += 4;
            //将数据零时搬到副页
            for(i = 0; i < item->data_cnt; i++)
            {
                if((i != data_idx) && (item->data_addr[i] != NULL))
                {
                    tmp = ARM_READ_INT16U(item->data_addr[i] - 2);
                    drv_bsp_flash_write_data_u32(addr, (uint8_t *)(item->data_addr[i] - 8), tmp);
                    item->data_addr[i] = item->main_area + (addr - item->sub_area + 8);
                    addr += tmp;
                }
            }
            //换完页后擦除主页
            res |= drv_flash_series_erase_page(item->main_area, 1);
            //将数据搬回主页
            tmp = 0;
            if((addr > item->sub_area) && ((addr - item->sub_area) < item->area_size))
            {
                tmp = addr - item->sub_area;
            }
            drv_bsp_flash_write_data_u32(item->main_area, (uint8_t *)item->sub_area, tmp);
            item->write_addr = item->main_area + tmp;
        }
        res |= drv_drv_flash_write_u32(item->write_addr, FDB_DATA_MARK);
        item->write_addr += 4;
        
        tmp = data_idx | ((len + 8) << 16);
        res |= drv_drv_flash_write_u32(item->write_addr, tmp);
        item->write_addr += 4;
        
        item->data_addr[data_idx] = item->write_addr;
        res |= drv_bsp_flash_write_data_u32(item->write_addr, buf, len);
        item->write_addr += len;
    }
    
    return (res == kKit_Ret_Ok);
}

uint16_t bsp_fdb_read_data(FdbItem *item, uint8_t data_idx, uint8_t *buf)
{
    uint16_t len = 0;
    if((item != NULL) && (data_idx < item->data_cnt) && (item->data_addr[data_idx] != NULL))
    {
        len = ARM_READ_INT16U(item->data_addr[data_idx] + 6) - 8;
        kit_copy_buf(buf, (void *)(item->data_addr[data_idx] + 8), len);
    }
    
    return len;
}

uint32_t bsp_fdb_get_data_addr(FdbItem *item, uint8_t data_idx)
{
    uint32_t addr = NULL;
    
    if((item != NULL) && (data_idx < item->data_cnt))
    {
        addr = item->data_addr[data_idx];
    }
    
    return addr;
}