#include "bsp_flash.h"
#include "lwutil.h"
#include "bsp_rtc.h"
// #include "bsp_wdg.h"
#include "bsp_hr.h"
#include "at_device_nt26k.h"
#include <rtthread.h>
#include <rthw.h>
#include "user_sys.h"

#define LOG_TAG "bsp_flash"
#define LOG_LVL LOG_LVL_DBG
#include <ulog.h>

#include <stdlib.h>

#define GETATTR(info, id) ((id) == kHwVerId                ? (&(info)->hw_ver)               \
                           : (id) == kSwVerId              ? (&(info)->sw_ver)               \
                           : (id) == kAlarmLValueId        ? (&(info)->alarm_l_value)        \
                           : (id) == kAlarmHValueId        ? (&(info)->alarm_h_value)        \
                           : (id) == kTempAlarmThresholdId ? (&(info)->temp_alarm_threshold) \
                           : (id) == kIotUploadCycleId     ? (&(info)->iot_upload_cycle)     \
                           : (id) == kIotRetryId           ? (&(info)->iot_retry)            \
                           : (id) == kEmagneticSwitchId    ? (&(info)->emagnetic_switch)     \
                           : (id) == kRelaySwitchId        ? (&(info)->relay_switch)         \
                           : (id) == kIotImeiId            ? ((info)->iot_imei)              \
                           : (id) == kIotImsiId            ? ((info)->iot_imsi)              \
                           : (id) == kIotIccidId           ? ((info)->iot_iccid)             \
                                                           : NULL)

TsTotalRecords TotalRecords;

const rt_uint32_t hr_start_addr[7] = {FLASH_HR_ALARM_START_ADDR,
                                      FLASH_HR_ALARM_RCY_START_ADDR,
                                      FLASH_HR_FAULT_START_ADDR, FLASH_HR_FAULT_RCY_START_ADDR,
                                      FLASH_HR_POWER_FAILURE_START_ADDR, FLASH_HR_POWER_ON_START_ADDR,
                                      FLASH_HR_SENSOR_FAILURE_START_ADDR};

const rt_uint8_t hr_record_max_num[7] = {HR_ALARM_MAX_NUM,
                                         HR_ALARM_RCY_MAX_NUM,
                                         HR_FAULT_MAX_NUM, HR_FAULT_RCY_MAX_NUM,
                                         HR_POWER_FAILURE_MAX_NUM, HR_POWER_ON_MAX_NUM,
                                         HR_SENSOR_FAILURE_MAX_NUM};

const rt_uint8_t hr_record_pages[7] = {HR_ALARM_PAGES, HR_ALARM_RCY_PAGES,
                                       HR_FAULT_PAGES, HR_FAULT_RCY_PAGES,
                                       HR_POWER_FAILURE_PAGES, HR_POWER_ON_PAGES,
                                       HR_SENSOR_FAILURE_PAGES};

const rt_uint32_t hr_sys_cfg_info_addr[kCnt] = {
    FLASH_HW_VER_ADDR,
    FLASH_SW_VER_ADDR,
    FLASH_ALARM_L_VALUE_ADDR,
    FLASH_ALARM_H_VALUE_ADDR,
    FLASH_IOT_UPLOAD_CYCLE_ADDR,
    FLASH_IOT_RETRY_ADDR,
    FLASH_TEMP_ALARM_THRESHOLD_ADDR,
    FLASH_EMAGNETIC_SWITCH_ADDR,
    FLASH_RELAY_SWITCH_ADDR,
    FLASH_IOT_IMEI_ADDR,
    FLASH_IOT_IMSI_ADDR,
    FLASH_IOT_ICCID_ADDR,
};

const rt_uint32_t hr_sys_cfg_info_len[kCnt] = {
    FLASH_HW_VER_LEN,
    FLASH_SW_VER_LEN,
    FLASH_ALARM_L_VALUE_LEN,
    FLASH_ALARM_H_VALUE_LEN,
    FLASH_IOT_UPLOAD_CYCLE_LEN,
    FLASH_IOT_RETRY_LEN,
    FLASH_TEMP_ALARM_THRESHOLD_LEN,
    FLASH_EMAGNETIC_SWITCH_LEN,
    FLASH_RELAY_SWITCH_LEN,
    FLASH_IOT_IMEI_LEN,
    FLASH_IOT_IMSI_LEN,
    FLASH_IOT_ICCID_LEN,
};

static rt_base_t interrupt_value;

/*默认的系统配置*/
struct flash_sever_info sever_info =
    {
        .server_url = SYS_IOT_URL,
        .server_port = SYS_IOT_PORT,
};

static void BSP_Flash_UnLock (void)
{
#if (SystemCoreClock > SYSCLK_FREQ_96MHz_HSE)
    RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV2;
#endif
    interrupt_value = rt_hw_interrupt_disable();

    FLASH_Unlock();
}

static void BSP_Flash_Lock (void)
{
    FLASH_Lock();

#if (SystemCoreClock > SYSCLK_FREQ_96MHz_HSE)
    RCC->CFGR0 &= ~(uint32_t)RCC_HPRE_DIV2;
#endif
    rt_hw_interrupt_enable (interrupt_value);
}

static void BSP_Flash_FastUnLock (void)
{
#if (SystemCoreClock > SYSCLK_FREQ_96MHz_HSE)
    RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV2;
#endif
    interrupt_value = rt_hw_interrupt_disable();

    FLASH_Unlock_Fast();
}

static void BSP_Flash_FastLock (void)
{
    FLASH_Lock_Fast();

#if (SystemCoreClock > SYSCLK_FREQ_96MHz_HSE)
    RCC->CFGR0 &= ~(uint32_t)RCC_HPRE_DIV2;
#endif
    rt_hw_interrupt_enable (interrupt_value);
}

static rt_size_t Flash_Read (rt_uint32_t addr, rt_uint8_t *buf, rt_size_t len)
{
    rt_size_t read_len = 0;

    for (rt_size_t i = 0; i < len; i++, buf++, addr++, read_len++)
    {
        *buf = *(rt_uint8_t *)addr;
    }

    return read_len;
}

int Get_IotImei (char *buf, rt_size_t len)
{

    if ((*(rt_uint8_t *)FLASH_IOT_IMEI_ADDR != 0xE3) && (*(rt_uint8_t *)FLASH_IOT_IMEI_ADDR != 0x39))
    {
        char imei_buf[FLASH_IOT_IMEI_LEN]={0};
        Flash_Read(FLASH_IOT_IMEI_ADDR, imei_buf, len);
        LOG_D ("read imei: %s", imei_buf);
        rt_memcpy(buf, imei_buf, len);
        return 0;
    }
    else
    {
        /*如果没有写进去，则全部是0*/
        for (rt_uint8_t i = 0; i < len; i++)
        {
            buf[i] = '0';
        }
        LOG_D ("IOT IMSI: %s", buf);
        return -1;
    }
}

int Get_IotImsi (char *buf, rt_size_t len)
{
    if ((*(rt_uint8_t *)FLASH_IOT_IMSI_ADDR != 0xE3) && (*(rt_uint8_t *)FLASH_IOT_IMSI_ADDR != 0x39))
    {
        char imsi_buf[FLASH_IOT_IMSI_LEN]={0};
        Flash_Read(FLASH_IOT_IMSI_ADDR, imsi_buf, len);
        LOG_D ("read imsi: %s", imsi_buf);
        rt_memcpy(buf, imsi_buf, len);

        return 0;
    }
    else
    {
        /*如果没有写进去，则全部是0*/
        for (rt_uint8_t i = 0; i < len; i++)
        {
            buf[i] = '0';
        }
        LOG_D ("IOT IMSI: %s", buf);
        return -1;
    }
}

int Get_IotIccid (char *buf, rt_size_t len)
{
    if ((*(rt_uint8_t *)FLASH_IOT_ICCID_ADDR != 0xE3) && (*(rt_uint8_t *)FLASH_IOT_ICCID_ADDR != 0x39))
    {
        char iccid_buf[FLASH_IOT_ICCID_LEN]={0};
        Flash_Read(FLASH_IOT_ICCID_ADDR, iccid_buf, len);
        LOG_D ("read iccid: %s", iccid_buf);
        rt_memcpy(buf, iccid_buf, len);
        return 0;
    }
    else
    {
        /*如果没有写进去，则全部是0*/
        for (rt_uint8_t i = 0; i < len; i++)
        {
            buf[i] = '0';
        }
        LOG_D ("IOT ICCID: %s", buf);
        return -1;
    }
}

/**
 * @description:
 * @param {uint32_t} addr
 * @param {uint8_t} *buf
 * @param {size_t} len
 * @return {*}
 */
static rt_size_t Flash_Write (rt_uint32_t addr, rt_uint8_t *buf, rt_size_t len)
{
    rt_size_t i = 0;
    __attribute__ ((aligned (2))) rt_uint16_t write_data;

    if (addr % 2 != 0)
        return 0;

    FLASH_ClearFlag (FLASH_FLAG_BSY | FLASH_FLAG_EOP | FLASH_FLAG_WRPRTERR);

    BSP_Flash_UnLock();

    for (i = 0; i < len; i += 2, buf += 2, addr += 2)
    {
        rt_memcpy (&write_data, buf, 2);
        FLASH_ProgramHalfWord (addr, write_data);

        /* You can add your code under here. */
        if (*(rt_uint16_t *)addr != write_data)
        {
            BSP_Flash_Lock();
            LOG_E ("Flash_Write Error");
            return 0;
        }
    }

    BSP_Flash_Lock();

    return i;
}

int BSP_Flash_Write_Info (rt_uint8_t *buf, rt_size_t len)
{
    rt_uint8_t page_buf[FLASH_PAGE_SIZE] = {0};
    rt_uint8_t in_page_offset = (FLASH_HW_VER_ADDR - FLASH_CONFIG_INFO_START_ADDR);

    Flash_ErasePage_ReadConfigInfo (page_buf);

    for (rt_uint8_t i = 0; i < len; i++)
    {
        page_buf[in_page_offset + i] = buf[i];
    }
    return Flash_Write_ConfigInfo (page_buf);
}

rt_uint16_t Flash_Get_WorkDuration (void)
{
    return *(rt_uint16_t *)(FLASH_WORK_TIME_ADDR);
}

int Flash_Set_WorkDuration (rt_uint16_t value)
{
    rt_uint8_t page_buf[FLASH_PAGE_SIZE] = {0};
    rt_uint8_t in_page_offset = (FLASH_WORK_TIME_ADDR - FLASH_CONFIG_INFO_START_ADDR);

    Flash_ErasePage_ReadConfigInfo (page_buf);

    rt_memcpy (page_buf + in_page_offset, &value, FLASH_WORK_TIME_LEN);
    return Flash_Write_ConfigInfo (page_buf);
}

int Flash_Get_Sever_Data (struct flash_sever_info *sever_info)
{
    rt_uint8_t data[FLASH_SERVER_LEN] = {0};
    rt_memcpy (data, (rt_uint8_t *)FLASH_SERVER_ADDR_ADDR, FLASH_SERVER_LEN);
    LOG_D ("data[%d] = %x data[%d] = %x data[%d] = %x data[%d] = %x data[%d] = %x data[%d] = %x", 0, data[0], 1, data[1], 2, data[2], 3, data[3], 4, data[4], 5, data[5]);
    rt_snprintf (sever_info->server_url, sizeof (sever_info->server_url), "%d.%d.%d.%d",
                 data[3], data[2], data[1], data[0]);

    rt_uint16_t port_num = ((data[5] << 8) | data[4]);
    LOG_D ("port_num = %d", port_num);
    rt_snprintf (sever_info->server_port, sizeof (sever_info->server_port), "%d", port_num);

    LOG_D ("server_url:%s, server_port:%s", sever_info->server_url, sever_info->server_port);

    return 0;
}

int Flash_Set_Sever_Data (rt_uint8_t *data)
{
    rt_uint8_t page_buf[FLASH_PAGE_SIZE] = {0};
    rt_uint8_t in_page_offset = (FLASH_SERVER_ADDR_ADDR - FLASH_CONFIG_INFO_START_ADDR);
    if (data == RT_NULL)
    {
        return -RT_ERROR;
    }

    Flash_ErasePage_ReadConfigInfo (page_buf);
    //*将传入的数据写到flash地址中
    for (size_t i = 0; i < FLASH_SERVER_LEN; i++)
    {
        page_buf[in_page_offset++] = data[i];
    }

    return Flash_Write_ConfigInfo (page_buf);
}

/**
 * @description: Flash Erase Page
 * @param {TeRecord} record
 * @param {uint8_t} page
 * @return {*}
 */
static ErrorStatus Flash_ErasePage_Records (TeRecord record,
                                            rt_uint8_t page_offset)
{
    ErrorStatus flag = READY;

    rt_uint8_t erase_page = 0;

    if (page_offset <= hr_record_pages[record] - 1)
    {
        erase_page = page_offset;
    }
    else
    {
        erase_page = hr_record_pages[record] - 1;
    }

    BSP_Flash_FastUnLock();
    FLASH_ErasePage_Fast (hr_start_addr[record] + FLASH_PAGE_SIZE * erase_page);
    BSP_Flash_FastLock();

    for (rt_uint8_t i = 0; i < (FLASH_PAGE_SIZE / 2); i++)
    {
        if (*(rt_uint16_t *)((hr_start_addr[record] + FLASH_PAGE_SIZE * erase_page) + 2 * i) != 0xE339)
        {
            flag = NoREADY;
        }
    }

    LOG_D ("/**Flash_Erase(%d)Page(%d)=%d**/", record, erase_page, flag);

    return flag;
}

void Flash_Erase_Records (TeRecord record)
{
    for (rt_uint8_t erase_page = 0; erase_page < hr_record_pages[record];
         erase_page++)
    {
        Flash_ErasePage_Records (record, erase_page);
    }
    LOG_D ("Flash_Erase_Records(%d)", record);
}

/*
 * @description:
 * @param {TeRecord} record
 * @return {*}
 */
static rt_uint16_t Flash_GetMaxIndex_Records (TeRecord record)
{
    rt_uint16_t index_max = 0;

    for (rt_uint8_t page = 0; page < hr_record_pages[record]; page++)
    {
        for (rt_uint8_t i = 0; i < FLASH_PAGE_HR_RECORD_NUM; i++)
        {
            if (*(rt_uint16_t *)(hr_start_addr[record] + FLASH_PAGE_SIZE * page + FLASH_HR_ONE_RECORD_SIZE * i) == HR_RECORD_FRAME_HEADER)
            {
                index_max =
                    LWUTIL_MAX (index_max,
                                *(rt_uint16_t *)(hr_start_addr[record] + FLASH_PAGE_SIZE * page + FLASH_HR_ONE_RECORD_SIZE * i + 2));
            }
        }
    }

    LOG_D ("Flash_Get_Records(%d)MaxNum = %d", record, index_max);

    return index_max;
}

/**
 * @description:
 * @param {TeRecord} record
 * @return {*}
 */
rt_uint8_t Flash_GetNum_Records (TeRecord record)
{
    rt_uint8_t num = 0;
    rt_uint16_t num_max = Flash_GetMaxIndex_Records (record);

    if (num_max <= hr_record_max_num[record])
    {
        num = num_max;
    }
    else
    {
        num = hr_record_max_num[record];
    }

    LOG_D ("Flash_GetNum_(%d)Records = %d", record, num);

    return num;
}

/**
 * @description:
 * @param {TuFlashHrRecordFrame*} pHrRecord
 * @param {TeRecord} record
 * @param {uint8_t} index
 * @return {*}
 */
void Flash_Read_Record (TuFlashHrRecordFrame *pHrRecord, TeRecord record,
                        rt_uint8_t index)
{
    LOG_D ("/*********Flash_Read_(%d)Record(%d)***************/", record, index);
    uint16_t index_max = Flash_GetMaxIndex_Records (record);

    rt_uint8_t page_offset = 0;
    rt_uint8_t in_page_offset = 0;

    if (index <= index_max)
    {
        if (index_max > hr_record_max_num[record])
        {
            if (record < kRecordSensoEndOfLife)
            {
                // index_redirect = index_max - (hr_record_max_num[record] - index);
                uint16_t index_redirect = index_max - (50 - index);
                LOG_D ("index_redirect = %d", index_redirect);
                page_offset = ((index_redirect - 1) / FLASH_PAGE_HR_RECORD_NUM) % hr_record_pages[record];
                in_page_offset = ((index_redirect - 1) % FLASH_PAGE_HR_RECORD_NUM) * FLASH_HR_ONE_RECORD_SIZE;
            }
            else
            {
                page_offset = 0;
                in_page_offset = ((index_max - 1) % FLASH_PAGE_HR_RECORD_NUM) * FLASH_HR_ONE_RECORD_SIZE;
            }
        }
        else
        {
            page_offset = ((index - 1) / FLASH_PAGE_HR_RECORD_NUM) % hr_record_pages[record];
            in_page_offset = ((index - 1) % FLASH_PAGE_HR_RECORD_NUM) * FLASH_HR_ONE_RECORD_SIZE;
        }
        LOG_D ("page_offset = %d", page_offset);
        LOG_D ("in_page_offset = %d", in_page_offset);

        uint32_t addr = (hr_start_addr[record] + FLASH_PAGE_SIZE * page_offset + in_page_offset);
        LOG_D ("addr = %04X", addr);

        Flash_Read (addr, pHrRecord->buf, HR_RECORD_FRAME_LEN);

        LOG_D ("Flash_Read_(%d)Record(%d):%04d-%02d-%02d,%02d:%02d", record,
               index, pHrRecord->Struct.year, pHrRecord->Struct.month,
               pHrRecord->Struct.day, pHrRecord->Struct.hour,
               pHrRecord->Struct.minute);
    }
    else
    {
        rt_memset (pHrRecord->buf, 0, HR_RECORD_FRAME_LEN);
        LOG_E ("Flash_GetMaxNum_(%d)Records Error!: (index_max)%d < %d", record,
               index_max, index);
    }
}

/**
 * @description:
 * @param {TuFlashHrRecordFrame*} pHrRecord
 * @param {uint16_t} index
 * @return {*}
 */
void Flash_Write_RecordIndex (TuFlashHrRecordFrame *pHrRecord, TeRecord record,
                              rt_uint16_t index)
{
    LOG_D ("/*********Flash_Write_RecordIndex***************/");

    rt_uint8_t page_offset = ((index - 1) / FLASH_PAGE_HR_RECORD_NUM) % hr_record_pages[record];
    LOG_D ("page_offset = %d", page_offset);
    rt_uint8_t in_page_offset = ((index - 1) % FLASH_PAGE_HR_RECORD_NUM) * FLASH_HR_ONE_RECORD_SIZE;
    LOG_D ("in_page_offset = %d", in_page_offset);

    rt_uint32_t addr = (hr_start_addr[record] + FLASH_PAGE_SIZE * page_offset + in_page_offset);
    LOG_D ("addr = %04X", addr);
    Flash_Write (addr, pHrRecord->buf, HR_RECORD_FRAME_LEN);

    TuFlashHrRecordFrame pReadRecord;
    Flash_Read (addr, pReadRecord.buf, HR_RECORD_FRAME_LEN);

    LOG_D ("(%04X)Flash_Write_(%d)RecordIndex(%d):%04d-%02d-%02d,%02d:%02d",
           pReadRecord.Struct.header, record, pReadRecord.Struct.index,
           pReadRecord.Struct.year, pReadRecord.Struct.month,
           pReadRecord.Struct.day, pReadRecord.Struct.hour,
           pReadRecord.Struct.minute);
}

void Flash_Write_Record (TeRecord record)
{
    LOG_D ("/*********Flash_Write_Record***************/");

    rt_uint16_t index_max = Flash_GetMaxIndex_Records (record);
    rt_uint16_t index_new = index_max + 1;
    LOG_D ("index_new = %d", index_new);

    rt_uint16_t index_start;
    rt_uint8_t index_start_page_offset;

    rt_uint8_t index_max_page_offset;
    rt_uint8_t index_max_in_page_offset;

    if (index_max <= hr_record_max_num[record])
    {
        index_start = 0;
        index_start_page_offset = 0;
        index_max_page_offset = ((index_max - 1) / FLASH_PAGE_HR_RECORD_NUM) % hr_record_pages[record];
        LOG_D ("index_max_page_offset = %d", index_max_page_offset);
    }
    else
    {
        index_start = index_max - (hr_record_max_num[record] - 1);
        LOG_D ("index_start = %d", index_start);

        index_start_page_offset = ((index_start - 1) / FLASH_PAGE_HR_RECORD_NUM) % hr_record_pages[record];
        LOG_D ("index_start_page_offset = %d", index_start_page_offset);

        index_max_page_offset = ((index_max - 1) / FLASH_PAGE_HR_RECORD_NUM) % hr_record_pages[record];
    }
    index_max_in_page_offset = (index_max - 1) % FLASH_PAGE_HR_RECORD_NUM;
    LOG_D ("index_max_in_page_offset = %d", index_max_in_page_offset);

    if ((index_max_in_page_offset + 1) == (FLASH_PAGE_HR_RECORD_NUM - 1) && index_max_page_offset == (hr_record_pages[record] - 1))
    {
        Flash_ErasePage_Records (record, 0);
    }
    else if ((index_max_in_page_offset + 1) == (FLASH_PAGE_HR_RECORD_NUM - 1) && index_max_page_offset == index_start_page_offset - 1)
    {
        Flash_ErasePage_Records (record, index_max_page_offset + 1);
    }

    RTC_GetTime();

    TuFlashHrRecordFrame HrRecord;
    HrRecord.Struct.header = HR_RECORD_FRAME_HEADER;
    HrRecord.Struct.index = index_new;
    HrRecord.Struct.year = RtcDateTime.year;
    HrRecord.Struct.month = RtcDateTime.month;
    HrRecord.Struct.day = RtcDateTime.day;
    HrRecord.Struct.hour = RtcDateTime.hour;
    HrRecord.Struct.minute = RtcDateTime.minute;

    Flash_Write_RecordIndex (&HrRecord, record, index_new);
}

void Flash_ErasePage_ConfigInfo (void)
{
    BSP_Flash_FastUnLock();
    FLASH_ErasePage_Fast (FLASH_CONFIG_INFO_START_ADDR);
    BSP_Flash_FastLock();
}

void Flash_ErasePage_ReadConfigInfo (rt_uint8_t *page_buf)
{
    Flash_Read (FLASH_CONFIG_INFO_START_ADDR, page_buf, FLASH_PAGE_SIZE);
    rt_thread_mdelay (10);
    Flash_ErasePage_ConfigInfo();
    rt_thread_mdelay (10);
}

int Flash_Write_ConfigInfo (rt_uint8_t *page_buf)
{
    return Flash_Write (FLASH_CONFIG_INFO_START_ADDR, page_buf, FLASH_PAGE_SIZE);
}

ErrorStatus Flash_GetProductTimeLimit (TuFlashProductTimeLimitFrame *pLimitTime,
                                       TeFlashProductTimeLimitId id)
{
    ErrorStatus flag = NoREADY;
    rt_uint32_t addr = 0;

    if (id == kFactoryTimeId)
    {
        addr = FLASH_FACTORY_TIME_START_ADDR;
    }
    else if (id == kExpirationTimeId)
    {
        addr = FLASH_EXPIRATION_TIME_START_ADDR;
    }
    if (addr != 0)
    {
        Flash_Read (addr, pLimitTime->buf, sizeof (TuFlashProductTimeLimitFrame));

        if (pLimitTime->Struct.header == FLASH_PRODUCT_TIME_FRAME_HEADER)
        {
            flag = READY;
            LOG_D ("Flash_GetProductTimeLimit(%d):%04d-%02d-%02d,%02d:%02d:%02d",
                   id, pLimitTime->Struct.year, pLimitTime->Struct.month,
                   pLimitTime->Struct.day, pLimitTime->Struct.hour,
                   pLimitTime->Struct.minute, pLimitTime->Struct.second);
        }
        else
        {
            LOG_E ("Flash_GetProductTimeLimit Error!");
        }
    }

    return flag;
}

void Flash_SetProductTimeLimit (rt_uint16_t year, rt_uint8_t mon, rt_uint8_t day,
                                rt_uint8_t hour, rt_uint8_t min, rt_uint8_t second,
                                TeFlashProductTimeLimitId id)
{
    TuFlashProductTimeLimitFrame LimitTime;

    rt_uint8_t page_buf[FLASH_PAGE_SIZE];
    Flash_ErasePage_ReadConfigInfo (page_buf);

    LimitTime.Struct.header = FLASH_PRODUCT_TIME_FRAME_HEADER;
    LimitTime.Struct.year = year;
    LimitTime.Struct.month = mon;
    LimitTime.Struct.day = day;
    LimitTime.Struct.hour = hour;
    LimitTime.Struct.minute = min;
    LimitTime.Struct.second = second;

    rt_uint8_t in_page_offset = 0;
    if (id == kFactoryTimeId)
    {
        in_page_offset = (FLASH_FACTORY_TIME_START_ADDR - FLASH_CONFIG_INFO_START_ADDR);
    }
    else if (id == kExpirationTimeId)
    {
        in_page_offset = (FLASH_EXPIRATION_TIME_START_ADDR - FLASH_CONFIG_INFO_START_ADDR);
    }

    for (rt_uint8_t i = 0; i < sizeof (TuFlashProductTimeLimitFrame); i++)
    {
        page_buf[in_page_offset + i] = LimitTime.buf[i];
    }

    Flash_Write_ConfigInfo (page_buf);
}

void Set_ExpirationTime (rt_uint16_t days)
{
    uint32_t factory_seconds, expiration_seconds;
    TuFlashProductTimeLimitFrame LimitTime;

    if (Flash_GetProductTimeLimit (&LimitTime, kFactoryTimeId) == READY)
    {
        factory_seconds = DateTime2Seconds (LimitTime.Struct.year,
                                            LimitTime.Struct.month, LimitTime.Struct.day,
                                            LimitTime.Struct.hour, LimitTime.Struct.minute,
                                            LimitTime.Struct.second);

        expiration_seconds = factory_seconds + days * 24 * 3600;

        TsRtcDateTime DateTime;
        Seconds2DateTime (expiration_seconds, &DateTime);
        Flash_SetProductTimeLimit (DateTime.year, DateTime.month, DateTime.day,
                                   DateTime.hour, DateTime.minute, DateTime.second,
                                   kExpirationTimeId);
    }
}

rt_uint8_t Flash_Sys_Cfg (TeFlashCfgInfoId id, rt_uint8_t *buf, rt_size_t len)
{
    rt_uint8_t page_buf[FLASH_PAGE_SIZE] = {0};

    Flash_ErasePage_ReadConfigInfo (page_buf);
    rt_uint8_t in_page_offset = (hr_sys_cfg_info_addr[id] - FLASH_CONFIG_INFO_START_ADDR);

    if (len > hr_sys_cfg_info_len[id])
    {
        LOG_E ("Flash_Sys_Cfg: id value too long ->%d", id);
        LOG_D ("buf len %d > id len[%d]", len, hr_sys_cfg_info_len[id]);
        return -RT_ERROR;
    }

    for (rt_uint8_t i = 0; i < hr_sys_cfg_info_len[id]; i++)
    {
        page_buf[in_page_offset + i] = buf[i];
    }

    return Flash_Write_ConfigInfo (page_buf);
}

/*这个返回一两个字节的数，方便提取*/
size_t Flash_Get_SysCfg (TeFlashCfgInfoId id)
{
    rt_uint8_t iot_upload_cycle[2] = {0};
    rt_uint16_t iot_upload;
    if (id != kIotUploadCycleId)
    {
        return *(rt_uint8_t *)hr_sys_cfg_info_addr[id];
    }
    else
    {
        rt_memcpy (&iot_upload_cycle[0], (rt_uint8_t *)hr_sys_cfg_info_addr[id], 2);
        iot_upload = ((iot_upload_cycle[0] << 8) + iot_upload_cycle[1]);
        LOG_D ("iot_upload: %d", iot_upload);
        return iot_upload;
    }
}

ErrorStatus Flash_GetTotalRecord (TsTotalRecords *pTotalRecords)
{
    ErrorStatus flag = NoREADY;

    pTotalRecords->alarm = Flash_GetNum_Records (kRecordAlarm);
    pTotalRecords->alarm_rcy = Flash_GetNum_Records (kRecordAlarmRcy);
    pTotalRecords->fault = Flash_GetNum_Records (kRecordFault);
    pTotalRecords->fault_rcy = Flash_GetNum_Records (kRecordFaultRcy);
    pTotalRecords->power_failure = Flash_GetNum_Records (kRecordPowerDown);
    pTotalRecords->power_on = Flash_GetNum_Records (kRecordPowerOn);
    pTotalRecords->sensor_failure = Flash_GetNum_Records (kRecordSensoEndOfLife);

    flag = READY;

    return flag;
}

ErrorStatus Flash_GetRecord (TeFrameC2 record_type, rt_uint8_t index,
                             TsRecordsTime *pRecordsTime)
{
    ErrorStatus flag = NoREADY;

    if (kNumOfRecords < record_type && record_type < kGetCurrentTime)
    {
        TuFlashHrRecordFrame pHrReadRecord;
        Flash_Read_Record (&pHrReadRecord, record_type - 1, index);

        LOG_D ("(%d)Flash_GetRecord(%d):%04d-%02d-%02d,%02d:%02d",
               record_type - 1, pHrReadRecord.Struct.index,
               pHrReadRecord.Struct.year, pHrReadRecord.Struct.month,
               pHrReadRecord.Struct.day, pHrReadRecord.Struct.hour,
               pHrReadRecord.Struct.minute);

        pRecordsTime->year_h = pHrReadRecord.Struct.year / 256;
        pRecordsTime->year_l = pHrReadRecord.Struct.year % 256;
        pRecordsTime->month = pHrReadRecord.Struct.month;
        pRecordsTime->day = pHrReadRecord.Struct.day;
        pRecordsTime->hour = pHrReadRecord.Struct.hour;
        pRecordsTime->minute = pHrReadRecord.Struct.minute;

        flag = READY;
    }

    return flag;
}

/**
 * @description:
 * @return {*}
 */
void BSP_Flash_EraseRecodrs (void)
{
    for (rt_uint8_t record = 0; record <= kRecordSensoEndOfLife; record++)
    {
        for (rt_uint8_t i = 0; i < hr_record_pages[record]; i++)
        {
            Flash_ErasePage_Records (record, i);
        }
    }
    Flash_ErasePage_ConfigInfo();
}

int BSP_Flash_Init (void)
{
    if (*(rt_uint16_t *)FLASH_INIT_FLAG_ADDR != FLASH_FIRST_INIT_VALUE)
    {
        LOG_D ("BSP_Flash_EraseRecodrs!");
        rt_uint8_t flash_init_flag[2];
        sys_config_info sci;
        rt_uint8_t sever_data[6] = {0};

        flash_init_flag[0] = FLASH_FIRST_INIT_VALUE % 256;
        flash_init_flag[1] = FLASH_FIRST_INIT_VALUE / 256;

        BSP_Flash_EraseRecodrs();

        Flash_Write (FLASH_INIT_FLAG_ADDR, flash_init_flag,
                     sizeof (flash_init_flag));
        Flash_Set_WorkDuration (work_duration);
        LOG_D ("work_duration:%d", Flash_Get_WorkDuration());

        Convert_To_Hex (&sever_info, sever_data);

        if (Flash_Set_Sever_Data (sever_data) <= 0)
        {
            LOG_D ("Flash_Set_Sever_Data error!");
        }

        Flash_SetProductTimeLimit (2025, 1, 15, 13, 50, 20, kFactoryTimeId);
        Set_ExpirationTime (MAX_EXPIRATION_DAYS);

        sci.hw_ver = SYS_HW_VERSION;
        sci.sw_ver = SYS_SW_VERSION;
        sci.alarm_l_value = SYS_ALARM_VALVE;
        sci.alarm_h_value = SYS_ALARM_VALVE_MAX;
        sci.iot_upload_cycle = SYS_IOT_UPLOAD_CYCLE_MIN;
        sci.iot_retry = SYS_IOT_RETRY;
        sci.temp_alarm_threshold = SYS_TEMP_ALARM_THRESHOLD;
        sci.emagnetic_switch = SYS_EMV_SWITCH;
        sci.relay_switch = SYS_RELAY_SWITCH;

        Flash_Write (FLASH_HW_VER_ADDR, (rt_uint8_t *)&sci,
                     (sizeof (sys_config_info) - 50));
    }
    return 0;
}
#ifdef RT_USING_COMPONENTS_INIT
INIT_PREV_EXPORT (BSP_Flash_Init);
#endif

#ifdef TEST_ENABLE
void TEST_Flash_GetMaxIndex_Records (int argc, char **argv)
{
    if (argc == 2)
    {
        rt_uint8_t record = atoi (argv[1]);
        LOG_D ("Flash_GetMaxIndex_Records(%d) = %d", record,
               Flash_GetMaxIndex_Records (record));
    }
    else
    {
        LOG_E ("TEST_Flash_GetMaxIndex_Records      --use _cmd_ [record](0~6)");
    }
}

MSH_CMD_EXPORT (TEST_Flash_GetMaxIndex_Records,
                "TEST_Flash_GetMaxIndex_Records");

static void TEST_Flash_Erase_Records (int argc, char **argv)
{
    if (argc == 2)
    {
        int record = atoi (argv[1]);
        Flash_Erase_Records (record);
    }
    else
    {
        LOG_E ("TEST_Flash_Erase_Records      --use _cmd_ [record](0~6)");
    }
}

MSH_CMD_EXPORT (TEST_Flash_Erase_Records, "TEST_Flash_Erase_Records");

static void TEST_Flash_Write_Record (int argc, char **argv)
{
    if (argc == 3)
    {
        int record = atoi (argv[1]);
        int num = atoi (argv[2]);
        for (rt_uint8_t i = 0; i < num; i++)
        {
            Flash_Write_Record (record);
            rt_thread_mdelay (2);
            // BSP_WDG_Loop();
        }
    }
    else
    {
        LOG_E ("TEST_Flash_Write_Record      --use _cmd_ [record(0~6)] [num]");
    }
}

MSH_CMD_EXPORT (TEST_Flash_Write_Record, "TEST_Flash_Write_Record");

static void TEST_Flash_GetNum_Records (int argc, char **argv)
{
    if (argc == 2)
    {
        int record = atoi (argv[1]);
        if (0 <= record && record <= 6)
        {
            LOG_D ("TEST_Flash_GetNum_Records(%d) = %d", record,
                   Flash_GetNum_Records (record));
        }
        else
        {
            LOG_E ("TEST_Flash_GetNum_Records      --use _cmd_ [record](0~6)");
        }
    }
    else
    {
        LOG_E ("TEST_Flash_GetNum_Records      --use _cmd_ [record](0~6)");
    }
}

MSH_CMD_EXPORT (TEST_Flash_GetNum_Records, "TEST_Flash_GetNum_Records");

static void TEST_Flash_GetProductTimeLimit (int argc, char **argv)
{
    if (argc == 2)
    {
        int id = atoi (argv[1]);
        TuFlashProductTimeLimitFrame LimitTime;
        Flash_GetProductTimeLimit (&LimitTime, id);
    }
    else
    {
        LOG_E (
            "TEST_Flash_GetProductTimeLimit      --use _cmd_ [id(0:FACTORY; 1:EXPIRATION)]");
    }
}

MSH_CMD_EXPORT (TEST_Flash_GetProductTimeLimit,
                "TEST_Flash_GetProductTimeLimit");

static void TEST_Flash_SetProductTimeLimit (int argc, char **argv)
{
    if (argc == 8)
    {
        int year = atoi (argv[1]);
        int mon = atoi (argv[2]);
        int day = atoi (argv[3]);
        int hour = atoi (argv[4]);
        int min = atoi (argv[5]);
        int second = atoi (argv[6]);
        int id = atoi (argv[7]);
        Flash_SetProductTimeLimit (year, mon, day, hour, min, second, id);
    }
    else
    {
        LOG_E (
            "TEST_Flash_SetProductTimeLimit      --use _cmd_ [y] [m] [d] [h] [m] [s] [id(0:FACTORY; 1:EXPIRATION)]");
    }
}

MSH_CMD_EXPORT (TEST_Flash_SetProductTimeLimit,
                "TEST_Flash_SetProductTimeLimit");

void Set_FactoryRtcTime (void)
{
    RTC_GetTime();
    LOG_D ("%4d-%02d-%02d, %02d:%02d:%02d", RtcDateTime.year, RtcDateTime.month,
           RtcDateTime.day, RtcDateTime.hour, RtcDateTime.minute,
           RtcDateTime.second);

    Flash_SetProductTimeLimit (RtcDateTime.year, RtcDateTime.month,
                               RtcDateTime.day, RtcDateTime.hour, RtcDateTime.minute,
                               RtcDateTime.second, kFactoryTimeId);
}

MSH_CMD_EXPORT (Set_FactoryRtcTime, "Use RTC time Set_FactoryRtcTime");

static void TEST_Flash_Set_ExpirationTime (int argc, char **argv)
{
    if (argc == 2)
    {
        int days = atoi (argv[1]);
        Set_ExpirationTime (days);
    }
    else
    {
        LOG_E ("TEST_Flash_Set_ExpirationTime      --use _cmd_ [days]");
    }
}

MSH_CMD_EXPORT (TEST_Flash_Set_ExpirationTime, "TEST_Flash_Set_ExpirationTime");

static void TEST_Flash_Get_Sys_Info (int argc, char **argv)
{
    if (argc == 2)
    {
        int id = atoi (argv[1]);
        Flash_Get_SysCfg (id);
    }
    else
    {
        LOG_E ("TEST_Flash_Get_Sys_Info   ");
    }
}

MSH_CMD_EXPORT (TEST_Flash_Get_Sys_Info, "TEST_Flash_Get_Sys_Info");

#endif
