/*****************************************************************************************************************************
  File name     : config.c
  Module        : 
  Author        : 
  Copyright     : 
  Version       : 0.1
  Created on    : 2021-12-30
  Creator       : amir.liang
  Description   :
        Config read/save/check related
*************************************************************************************************************************************/
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include "mw_config.h"
#include "crc32.h"
#include "util.h"
#include "hbase.h"
#include "hmutex.h"
#include "hlog.h"
#include "hal_interface_flash.h"

typedef struct{
    hmutex_t mutex;
    hmutex_t rom_mutex;
    mw_read_cb  read_cb_f;
    mw_write_cb write_cb_f;
    /* Global Configs */
    Mw_CfgSysPart_t cfg_sys_part;
    Mw_CfgUserPart_t cfg_user_part;
    const Mw_CfgSysPart_t sys_part_default;
    const Mw_CfgUserPart_t user_part_default;
    /* Configs relative to ROM */
    uint32_t init_flg;
    uint8_t start_default;
    Mw_CfgStorage_Region_e active_region[CFG_STORAGE_REGION_NUM]; // toggle CFG_STORAGE_REGION_MAIN and CFG_STORAGE_REGION_BACK
}mw_config;

static mw_config s_mw_cfg = {
    .init_flg = 0, 
    .start_default = 0, 
    .sys_part_default=CFG_SYSPART_DEFAULT_TABLE, 
    .user_part_default = CFG_USERPART_DEFAULT_TABLE
};

#define MW_CFG_SIZE_CHECK_COMMON(real_size, type) \
    if ((real_size) != sizeof(type)) \
    { \
        hloge("Mw cfg checksize[%d]!=(sizeof(%s)=[%lu]), fail.", real_size, #type, sizeof(type)); \
        return NG; \
    }
#define MW_CFG_ITEM_COPY_COMMON(dst, src, type)    (void)memcpy((void *)(dst), (void *)(src), sizeof(type))
#define MW_CFG_ITEM_CHECK_SAME(dst, src, type) \
    if (0 == memcmp(dst, src, sizeof(type))) \
    { \
        return MW_SET_SAME; \
    }
#define MW_CFG_COMMON_SET_FUNC(group, name, dst) \
    static uint32_t Mw_Cfg_##group##name##Set(void *data, uint32_t size) \
    { \
        Mw_Cfg##group##_##name##_t *info = (Mw_Cfg##group##_##name##_t *)data; \
        MW_CFG_SIZE_CHECK_COMMON(size, Mw_Cfg##group##_##name##_t); \
        MW_CFG_ITEM_CHECK_SAME(dst, info, Mw_Cfg##group##_##name##_t); \
        MW_CFG_ITEM_COPY_COMMON(dst, info, Mw_Cfg##group##_##name##_t); \
        return OK; \
    }
#define MW_CFG_COMMON_GET_FUNC(group, name, src) \
    static uint32_t Mw_Cfg_##group##name##Get(void *data, uint32_t size) \
    { \
        MW_CFG_SIZE_CHECK_COMMON(size, Mw_Cfg##group##_##name##_t); \
        MW_CFG_ITEM_COPY_COMMON(data, src, Mw_Cfg##group##_##name##_t); \
        return OK; \
    }
#define MW_CFG_COMMON_SET_AND_GET_FUNC(group, name, data) \
    MW_CFG_COMMON_SET_FUNC(group, name, data) \
    MW_CFG_COMMON_GET_FUNC(group, name, data)

#define MW_CFG_COMMON_GROUPSET_FUNC(group, dst) \
    static uint32_t Mw_Cfg_##group##GroupSet(void *data, uint32_t size) \
    { \
        Mw_Cfg##group##Group_t *info = (Mw_Cfg##group##Group_t *)data; \
        MW_CFG_SIZE_CHECK_COMMON(size, Mw_Cfg##group##Group_t); \
        MW_CFG_ITEM_COPY_COMMON(dst, info, Mw_Cfg##group##Group_t); \
        return OK; \
    }
#define MW_CFG_COMMON_GROUPGET_FUNC(group, src) \
    static uint32_t Mw_Cfg_##group##GroupGet(void *data, uint32_t size) \
    { \
        MW_CFG_SIZE_CHECK_COMMON(size, Mw_Cfg##group##Group_t); \
        MW_CFG_ITEM_COPY_COMMON(data, src, Mw_Cfg##group##Group_t); \
        return OK; \
    }
#define MW_CFG_COMMON_GROUP_SET_AND_GET_FUNC(group, data) \
    MW_CFG_COMMON_GROUPSET_FUNC(group, data) \
    MW_CFG_COMMON_GROUPGET_FUNC(group, data)

static uint32_t Mw_Cfg_LoadCfgFromRom(Mw_CfgStorage_Partition_e part, Mw_CfgStorage_Region_e region, char *p_out, const int32_t size)
{
    uint32_t ret = 0;
    hmutex_lock(&s_mw_cfg.mutex);
    ret = s_mw_cfg.read_cb_f(part, region, p_out, size);
    if ( ret != size )
    {
        hloge("%s fail, part[%d], region[%d] size:%u ret:%u", __func__, part, region, size, ret);
     }else hlogi("%s cfg to rom part[%d], region[%d] size:%u ret:%u", __func__, part, region, size, ret);
    hmutex_unlock(&s_mw_cfg.mutex);
    return ret;
}

static uint32_t Mw_Cfg_WriteCfgToRom(Mw_CfgStorage_Partition_e part, Mw_CfgStorage_Region_e region, char *p_in, uint16_t size)
{
     uint32_t ret = 0;
     hmutex_lock(&s_mw_cfg.mutex);
     ret = s_mw_cfg.write_cb_f(part, region, p_in, size);
     if ( ret != size )
     {
         hloge("%s fail, part[%d], region[%d] size:%u ret:%u", __func__, part, region, size, ret);
     }else hlogi("%s cfg to rom part[%d], region[%d] size:%u ret:%u", __func__, part, region, size, ret);
     hmutex_unlock(&s_mw_cfg.mutex);
     return ret;

}

static uint32_t Mw_Cfg_TrySave(Mw_CfgStorage_Partition_e part, Mw_CfgStorage_Region_e region, char *p_in, uint16_t size)
{
    uint32_t ret;
    uint32_t chksum_data;
    Mw_CfgHeader_t *p_header = (Mw_CfgHeader_t *)p_in;

    if (CFG_STORAGE_PARTITION_NUM <= part)
    {
        hloge("Storage part [%d] error.", part);
        return NG;
    }

    ret = hmutex_lock(&s_mw_cfg.mutex);
    if (OK != ret)
    {
        hloge("Take user settings rom mutex, fail, Ret=%d", ret);
        return ret;
    }

    /* Calculate checksum */
    chksum_data = crc32(0, p_in + sizeof(Mw_CfgHeader_t), size - sizeof(Mw_CfgHeader_t));
    if ( chksum_data == p_header->checksum ){
        (void)hmutex_unlock(&s_mw_cfg.mutex);
        hlogi("No save same part[%d] Region[%d] checksum:%X", part, region, p_header->checksum);
        return OK;
    }
    p_header->age++;
    p_header->total_size = size;
    p_header->magic      = CFG_MAGIC_DEFAULT;
    p_header->checksum   = chksum_data;

    (void)hmutex_unlock(&s_mw_cfg.mutex);

    ret = Mw_Cfg_WriteCfgToRom(part, region, p_in, size);
    if (OK != ret)
    {
        hloge("Write user settings to rom fail, Ret=%d.", ret);
        return ret;
    }
    hlogi("Configs  part[%d] Region[%d]  checksum:%X save done.", part, region, p_header->checksum);

    return ret;
}

static uint8_t Mw_Cfg_CheckValid(Mw_CfgStorage_Partition_e part, Mw_CfgStorage_Region_e region, const Mw_CfgHeader_t *p_header, const uint16_t size)
{
    uint32_t chksum_data;
    if(p_header->total_size != size)
    {
        hlogw("Configs part[%d] Region[%d]  header size not match, header size=%d, real size=%d", part, region, p_header->total_size, size);
        return 0;
    }
    if(p_header->magic != CFG_MAGIC_DEFAULT)
    {
        hlogw("Configs part[%d] Region[%d]  Profile magic not match",part, region);
        return 0;
    }
    chksum_data = crc32(0, (char *)p_header + sizeof(Mw_CfgHeader_t), p_header->total_size - sizeof(Mw_CfgHeader_t));
    if(p_header->checksum != chksum_data)
    {
        hlogw("total_size[%d] data checksum not match, data chksum=0x%X, real=0x%X",  p_header->total_size, p_header->checksum, chksum_data);
        return 0;
    }

    hlogi("Configs part[%d] Region[%d] is valid.", part, region);

    return 1;
}

static char *Mw_Cfg_Find_Correct_Cfg(Mw_CfgStorage_Partition_e part, char *main, char *back, uint16_t size)
{
    const Mw_CfgHeader_t *pmain_header = (const Mw_CfgHeader_t *)main;
    const Mw_CfgHeader_t *pback_header = (const Mw_CfgHeader_t *)back;
    char *right_cfg = NULL;
    if ( pmain_header->age > pback_header->age ){
        if ( Mw_Cfg_CheckValid(part, CFG_STORAGE_REGION_MAIN, pmain_header, size) ) {
            s_mw_cfg.active_region[part] = CFG_STORAGE_REGION_MAIN;
            right_cfg = main;
        } else if ( Mw_Cfg_CheckValid(part, CFG_STORAGE_REGION_BACK, pback_header, size) ) {
            s_mw_cfg.active_region[part] = CFG_STORAGE_REGION_BACK;
            right_cfg = back;
        }
    } else {
        if ( Mw_Cfg_CheckValid(part, CFG_STORAGE_REGION_BACK, pback_header, size) ) {
            s_mw_cfg.active_region[part] = CFG_STORAGE_REGION_BACK;
            right_cfg = back;
        } else if ( Mw_Cfg_CheckValid(part, CFG_STORAGE_REGION_MAIN, pmain_header, size) ) {
            s_mw_cfg.active_region[part] = CFG_STORAGE_REGION_MAIN;
            right_cfg = main;
        }
    }
    if ( right_cfg ) {
        hlogi("%s part[%d] Region[%d] size:%u main.age:%u back.age:%u", __func__, part, s_mw_cfg.active_region[part], size, pmain_header->age, pback_header->age);
    }
    return right_cfg;
}
static uint32_t Mw_Cfg_MemoryInit(void)
{   
    char *p_main = NULL;
    char *p_back = NULL;
    char *p_data = NULL;
    uint32_t size = 0, i, j;

    char *parts[CFG_STORAGE_PARTITION_NUM][CFG_STORAGE_REGION_NUM] = {NULL};
    //load data from rom
    for(i=0; i<CFG_STORAGE_PARTITION_NUM; i++)
    {
        for(j=0; j<CFG_STORAGE_REGION_NUM; j++)
        {
            switch(i){
                case CFG_STORAGE_PARTITION_SYS:
                    parts[i][j] = (char *)calloc(1, sizeof(Mw_CfgSysPart_t));
                    Mw_Cfg_LoadCfgFromRom(i, j, parts[i][j], sizeof(Mw_CfgSysPart_t));
                    break;
                case CFG_STORAGE_PARTITION_USER:
                    parts[i][j] = (char *)calloc(1, sizeof(Mw_CfgUserPart_t));
                    Mw_Cfg_LoadCfgFromRom(i, j, parts[i][j], sizeof(Mw_CfgUserPart_t));
                    break;
                default:
                    hloge("unsupport partition:%d", i);
                    break;
            }
        }
    }
    for(i=0; i<CFG_STORAGE_PARTITION_NUM; i++)
    {
        switch(i){
            case CFG_STORAGE_PARTITION_SYS:
                p_main = parts[i][CFG_STORAGE_REGION_MAIN];
                p_back = parts[i][CFG_STORAGE_REGION_BACK];
                size   = sizeof(Mw_CfgSysPart_t);
                p_data = (void *)&s_mw_cfg.cfg_sys_part;
                break;
            case CFG_STORAGE_PARTITION_USER:
                p_main = parts[i][CFG_STORAGE_REGION_MAIN];
                p_back = parts[i][CFG_STORAGE_REGION_BACK];
                size   = sizeof(Mw_CfgUserPart_t);
                p_data = (void *)&s_mw_cfg.cfg_user_part;
                break;
           default:
                hloge("unsupport partition:%d", i);
                break;
        }

        if ( size && p_main && p_back){
            char *cfg = Mw_Cfg_Find_Correct_Cfg(i, p_main, p_back, size);
            if ( cfg ) {
                 memcpy(p_data, cfg, size);
            } else {
                Mw_Cfg_LoadDefault(i);
                s_mw_cfg.start_default = 1;
            }
        }

    }

    
    for(i=0; i<CFG_STORAGE_PARTITION_NUM; i++)
    {
       for(j=0; j<CFG_STORAGE_REGION_NUM; j++)
       {
           if ( parts[i][j] ){
            free(parts[i][j]);
            parts[i][j] = NULL;
           }
       }
    }
    
    hlogi("Configs memory init done.");
    return OK;
}

uint8_t Mw_Cfg_IsLoadFromDefault(void)
{
    return s_mw_cfg.start_default;
}

#define MW_CFG_PRINT(...)  do { \
            hlogi(__VA_ARGS__); \
        } while(0)

static uint32_t Mw_Cfg_BaseLicensePrint(uint32_t id, char *name)
{
    MW_CFG_PRINT("[%d][%s]:", id, name);
    MW_CFG_PRINT("        License = %s",s_mw_cfg.cfg_sys_part.base_info.license_info.audio_license);
    return OK;
}

static uint32_t Mw_Cfg_BaseActiveTimePrint(uint32_t id, char *name)
{
    MW_CFG_PRINT("[%d][%s]:", id, name);
    MW_CFG_PRINT("        ActiveTime = %ld",s_mw_cfg.cfg_sys_part.base_info.active_time.active_time);
    return OK;
}

static uint32_t Mw_Cfg_BaseFactoryAgingInfoPrint(uint32_t id, char *name)
{
    Mw_CfgBase_FactoryAgingInfo_t *pdata = (Mw_CfgBase_FactoryAgingInfo_t *)&s_mw_cfg.cfg_sys_part.base_info.factory_aging_info;
    MW_CFG_PRINT("[%d][%s]:", id, name);
    MW_CFG_PRINT("        AgingFlag = %d, AgingResultFlag = %d", pdata->aging_flag, pdata->aging_result_flag);
    MW_CFG_PRINT("        AgingNums = %d, AgingPeriod = %d", pdata->aging_nums, pdata->aging_period);
    MW_CFG_PRINT("        AgingStartTime = %ld, AgingStopTime = %ld", pdata->aging_start_time, pdata->aging_stop_time);
    MW_CFG_PRINT("        ErrInfo = %s", pdata->error_info);
    return OK;
}

static uint32_t Mw_Cfg_BaseUUIDPrint(uint32_t id, char *name)
{
    MW_CFG_PRINT("[%d][%s]:", id, name);
    MW_CFG_PRINT("        UUID = %s", s_mw_cfg.cfg_sys_part.base_info.product_uuid.uuid);
    return OK;
}

static uint32_t Mw_Cfg_BaseSerialPrint(uint32_t id, char *name)
{
    MW_CFG_PRINT("[%d][%s]:", id, name);
    MW_CFG_PRINT("        Serial = %s", s_mw_cfg.cfg_sys_part.base_info.product_sn.sn);
    return OK;
}

static uint32_t Mw_Cfg_SystemWifiPrint(uint32_t id, char *name)
{
    MW_CFG_PRINT("[%d][%s]:", id, name);
    MW_CFG_PRINT("        Enable = %d, SSID = %s, PASS = %s", s_mw_cfg.cfg_sys_part.system_info.wifi_info.enable,
                 s_mw_cfg.cfg_sys_part.system_info.wifi_info.ap_ssid, s_mw_cfg.cfg_sys_part.system_info.wifi_info.ap_password);
    return OK;
}

static uint32_t Mw_Cfg_OtherLcdPrint(uint32_t id, char *name)
{
    MW_CFG_PRINT("[%d][%s]:", id, name);
    MW_CFG_PRINT("        Time = %d Brightness = %d", s_mw_cfg.cfg_user_part.other_info.lcd_info.time,
                s_mw_cfg.cfg_user_part.other_info.lcd_info.brightness);
    return OK;
}
static uint32_t Mw_Cfg_OtherQcapPrint(uint32_t id, char *name)
{
    MW_CFG_PRINT("[%d][%s]:", id, name);
    MW_CFG_PRINT("        Qcap = %d", s_mw_cfg.cfg_user_part.other_info.quick_cap.enable);
    return OK;
}
static uint32_t Mw_Cfg_CommonCamModePrint(uint32_t id, char *name)
{
    MW_CFG_PRINT("[%d][%s]:", id, name);
    MW_CFG_PRINT("        Mode = %d SubMode = %d",s_mw_cfg.cfg_user_part.common_info.mode.cam_mode,
                 s_mw_cfg.cfg_user_part.common_info.mode.sub_mode);
    return OK;
}

static uint32_t Mw_Cfg_VideoRecord_streamPrint(uint32_t id, char *name)
{
    MW_CFG_PRINT("[%d][%s]:", id, name);
    MW_CFG_PRINT("        Rec_stream = %d (1:main 2:sub 3:both)",s_mw_cfg.cfg_user_part.video_info.stream.rec_stream);
    return OK;
}

static uint32_t Mw_Cfg_VideoRecordSpecPrint(uint32_t id, char *name)
{
    MW_CFG_PRINT("[%d][%s]:", id, name);
    MW_CFG_PRINT("        RecRes = %d Fps = %d",s_mw_cfg.cfg_user_part.video_info.spec.resolution, s_mw_cfg.cfg_user_part.video_info.spec.fps);
    return OK;
}

static uint32_t Mw_Cfg_VideoCodecPrint(uint32_t id, char *name)
{
    MW_CFG_PRINT("[%d][%s]:", id, name);
    MW_CFG_PRINT("        CodecType = %d (0:h264 1:h265)",s_mw_cfg.cfg_user_part.video_info.codec.main_type);
    MW_CFG_PRINT("   Sub  CodecType = %d (0:h264 1:h265)",s_mw_cfg.cfg_user_part.video_info.codec.sub_type);
    return OK;
}


static uint32_t Mw_Cfg_VideoRecordBitratePrint(uint32_t id, char *name)
{
    MW_CFG_PRINT("[%d][%s]:", id, name);
    MW_CFG_PRINT("        MainBitrate = %d Mbps, SubBitrate = %d Mbps", s_mw_cfg.cfg_user_part.video_info.bitrate.value[0], s_mw_cfg.cfg_user_part.video_info.bitrate.value[1]);
    return OK;
}

static uint32_t Mw_Cfg_VideoRecordBrateCtrlPrint(uint32_t id, char *name)
{
    char str[128];
    MW_CFG_PRINT("[%d][%s]:", id, name);
    uint8_t i, idx = 0;
    Mw_CfgVideo_BrateCtrl_t *bctrl = &s_mw_cfg.cfg_user_part.video_info.bratectrl;
    idx += snprintf(str+idx, sizeof(str) - idx, "BrateCtrl: ");
    for (i=0; i<sizeof(bctrl->value)/sizeof(bctrl->value[0]); i++)
    {
        idx += snprintf(str+idx, sizeof(str) - idx, "[%u] ", bctrl->value[i]);
    }
    idx += snprintf(str+idx, sizeof(str) - idx, "(note: 1 CBR, 2 VBR, 3 SMART_VBR)");
    MW_CFG_PRINT("        %s", str);
    return OK;
}
static uint32_t Mw_Cfg_PhotoCapcfgPrint(uint32_t id, char *name)
{
    MW_CFG_PRINT("[%d][%s]:", id, name);
    MW_CFG_PRINT("        SyncEncStart = %d, PicType = %d", s_mw_cfg.cfg_user_part.photo_info.capcfg.syncencstart, s_mw_cfg.cfg_user_part.photo_info.capcfg.pictype);
    MW_CFG_PRINT("        _strmMsk      = %d, CapOnly = %d", s_mw_cfg.cfg_user_part.photo_info.capcfg.strmmsk, s_mw_cfg.cfg_user_part.photo_info.capcfg.caponly);
    MW_CFG_PRINT("        CapType      = %d, LivStop = %d", s_mw_cfg.cfg_user_part.photo_info.capcfg.captype, s_mw_cfg.cfg_user_part.photo_info.capcfg.stopliveview);
    MW_CFG_PRINT("        CapNum       = %d, AebNum  = %d", s_mw_cfg.cfg_user_part.photo_info.capcfg.capnum, s_mw_cfg.cfg_user_part.photo_info.capcfg.aebnum);
    return OK;
}

static uint32_t Mw_Cfg_AudioEncodePrint(uint32_t id, char *name)
{
    MW_CFG_PRINT("[%d][%s]:", id, name);
    MW_CFG_PRINT("        AACbitrate = %d, BitsPerSample = %d", s_mw_cfg.cfg_user_part.audio_info.encode.aac_bitrate, s_mw_cfg.cfg_user_part.audio_info.encode.bits_per_sample);
    MW_CFG_PRINT("        EnableDMIC = %d, Volumn = %d", s_mw_cfg.cfg_user_part.audio_info.encode.enable_DMIC, s_mw_cfg.cfg_user_part.audio_info.encode.volume);
    return OK;
}

static uint32_t Mw_Cfg_ImageAAAPrint(uint32_t id, char *name)
{
    MW_CFG_PRINT("[%d][%s]:", id, name);
    MW_CFG_PRINT("        ExpMode = %d, Shutter = %d, Iso = %d", s_mw_cfg.cfg_user_part.image_info.aaa.exposure_mode,
                 s_mw_cfg.cfg_user_part.image_info.aaa.shutter, s_mw_cfg.cfg_user_part.image_info.aaa.iso);
    MW_CFG_PRINT("        ShutterLimit = %f, IsoLimit = %d", s_mw_cfg.cfg_user_part.image_info.aaa.shutter_limit, s_mw_cfg.cfg_user_part.image_info.aaa.iso_limit);
    MW_CFG_PRINT("        EvBias = %f", s_mw_cfg.cfg_user_part.image_info.aaa.ev_bias);
    MW_CFG_PRINT("        WbMode = %d, WbTemp = %d", s_mw_cfg.cfg_user_part.image_info.aaa.wb_mode, s_mw_cfg.cfg_user_part.image_info.aaa.wb_temp);
    return OK;
}


MW_CFG_COMMON_SET_AND_GET_FUNC(Base, FactoryMode, &s_mw_cfg.cfg_sys_part.base_info.factory_mode);
MW_CFG_COMMON_SET_AND_GET_FUNC(Base, ActiveTime, &s_mw_cfg.cfg_sys_part.base_info.active_time);
MW_CFG_COMMON_SET_AND_GET_FUNC(Base, FactoryAgingInfo, &s_mw_cfg.cfg_sys_part.base_info.factory_aging_info);
MW_CFG_COMMON_SET_AND_GET_FUNC(Base, License, &s_mw_cfg.cfg_sys_part.base_info.license_info);
MW_CFG_COMMON_SET_AND_GET_FUNC(Base, ProductUUID, &s_mw_cfg.cfg_sys_part.base_info.product_uuid);
MW_CFG_COMMON_SET_AND_GET_FUNC(Base, ProductSerial, &s_mw_cfg.cfg_sys_part.base_info.product_sn);
MW_CFG_COMMON_SET_AND_GET_FUNC(System, Wifi, &s_mw_cfg.cfg_sys_part.system_info.wifi_info);
MW_CFG_COMMON_SET_AND_GET_FUNC(System, Bluetooth, &s_mw_cfg.cfg_sys_part.system_info.bt_info);
MW_CFG_COMMON_SET_AND_GET_FUNC(System, Usb, &s_mw_cfg.cfg_sys_part.system_info.usb_info);
MW_CFG_COMMON_SET_AND_GET_FUNC(System, Sensor, &s_mw_cfg.cfg_sys_part.system_info.sensor_info);
MW_CFG_COMMON_SET_AND_GET_FUNC(System, Battery, &s_mw_cfg.cfg_sys_part.system_info.battery_info);
MW_CFG_COMMON_SET_AND_GET_FUNC(System, Led, &s_mw_cfg.cfg_sys_part.system_info.led_info);
MW_CFG_COMMON_SET_AND_GET_FUNC(System, Button, &s_mw_cfg.cfg_sys_part.system_info.button_info);
MW_CFG_COMMON_SET_AND_GET_FUNC(Common, CamMode, &s_mw_cfg.cfg_user_part.common_info.mode);
MW_CFG_COMMON_SET_AND_GET_FUNC(Video, Record_stream, &s_mw_cfg.cfg_user_part.video_info.stream);
MW_CFG_COMMON_SET_AND_GET_FUNC(Video, RecordSpec, &s_mw_cfg.cfg_user_part.video_info.spec);
MW_CFG_COMMON_SET_AND_GET_FUNC(Video, Bitrate, &s_mw_cfg.cfg_user_part.video_info.bitrate);
MW_CFG_COMMON_SET_AND_GET_FUNC(Video, BrateCtrl, &s_mw_cfg.cfg_user_part.video_info.bratectrl);
MW_CFG_COMMON_SET_AND_GET_FUNC(Video, Codec, &s_mw_cfg.cfg_user_part.video_info.codec);
MW_CFG_COMMON_SET_AND_GET_FUNC(Photo, Resolution, &s_mw_cfg.cfg_user_part.photo_info.resolution);
MW_CFG_COMMON_SET_AND_GET_FUNC(Photo, Capcfg, &s_mw_cfg.cfg_user_part.photo_info.capcfg);
MW_CFG_COMMON_SET_AND_GET_FUNC(Audio, Encode, &s_mw_cfg.cfg_user_part.audio_info.encode);
MW_CFG_COMMON_SET_AND_GET_FUNC(Image, Brightness, &s_mw_cfg.cfg_user_part.image_info.brightness);
MW_CFG_COMMON_SET_AND_GET_FUNC(Image, Sharpness, &s_mw_cfg.cfg_user_part.image_info.sharpness);
MW_CFG_COMMON_SET_AND_GET_FUNC(Image, Contrast, &s_mw_cfg.cfg_user_part.image_info.contrast);
MW_CFG_COMMON_SET_AND_GET_FUNC(Image, AAA, &s_mw_cfg.cfg_user_part.image_info.aaa);
MW_CFG_COMMON_SET_AND_GET_FUNC(Image, AntiFlicker, &s_mw_cfg.cfg_user_part.image_info.anti_flicker);
MW_CFG_COMMON_SET_AND_GET_FUNC(Other, Lcd, &s_mw_cfg.cfg_user_part.other_info.lcd_info);
MW_CFG_COMMON_SET_AND_GET_FUNC(Other, Qcap, &s_mw_cfg.cfg_user_part.other_info.quick_cap);
MW_CFG_COMMON_SET_AND_GET_FUNC(App, Gui, &s_mw_cfg.cfg_user_part.app_info.gui);

static Mw_CfgAccess_t s_Mw_CfgAccess[] =
{
    [CFG_BASE_ID_FACTORY_MODE]    = {"CFG_BASE_ID_FACTORY_MODE", Mw_Cfg_BaseFactoryModeSet, Mw_Cfg_BaseFactoryModeGet, NULL, .cb_func_list=LIST_HEAD_INIT(s_Mw_CfgAccess[CFG_BASE_ID_FACTORY_MODE].cb_func_list)},
    [CFG_BASE_ID_ACTIVE_TIME]     = {"CFG_BASE_ID_ACTIVE_TIME", Mw_Cfg_BaseActiveTimeSet, Mw_Cfg_BaseActiveTimeGet, Mw_Cfg_BaseActiveTimePrint, .cb_func_list=LIST_HEAD_INIT(s_Mw_CfgAccess[CFG_BASE_ID_ACTIVE_TIME].cb_func_list)},
    [CFG_BASE_ID_FACTORY_AGING]   = {"CFG_BASE_ID_FACTORY_AGING", Mw_Cfg_BaseFactoryAgingInfoSet, Mw_Cfg_BaseFactoryAgingInfoGet, Mw_Cfg_BaseFactoryAgingInfoPrint, .cb_func_list=LIST_HEAD_INIT(s_Mw_CfgAccess[CFG_BASE_ID_FACTORY_AGING].cb_func_list)},
    [CFG_BASE_ID_PRODUCT_UUID]    = {"CFG_BASE_ID_PRODUCT_UUID", Mw_Cfg_BaseProductUUIDSet, Mw_Cfg_BaseProductUUIDGet, Mw_Cfg_BaseUUIDPrint, .cb_func_list=LIST_HEAD_INIT(s_Mw_CfgAccess[CFG_BASE_ID_PRODUCT_UUID].cb_func_list)},
    [CFG_BASE_ID_PRODUCT_SERIAL]  = {"CFG_BASE_ID_PRODUCT_SERIAL", Mw_Cfg_BaseProductSerialSet, Mw_Cfg_BaseProductSerialGet, Mw_Cfg_BaseSerialPrint, .cb_func_list=LIST_HEAD_INIT(s_Mw_CfgAccess[CFG_BASE_ID_PRODUCT_SERIAL].cb_func_list)},
    [CFG_BASE_ID_LICENSE]         = {"CFG_BASE_ID_LICENSE", Mw_Cfg_BaseLicenseSet, Mw_Cfg_BaseLicenseGet, Mw_Cfg_BaseLicensePrint, .cb_func_list=LIST_HEAD_INIT(s_Mw_CfgAccess[CFG_BASE_ID_LICENSE].cb_func_list)},
    [CFG_SYSTEM_ID_WIFI]          = {"CFG_SYSTEM_ID_WIFI", Mw_Cfg_SystemWifiSet, Mw_Cfg_SystemWifiGet, Mw_Cfg_SystemWifiPrint, .cb_func_list=LIST_HEAD_INIT(s_Mw_CfgAccess[CFG_SYSTEM_ID_WIFI].cb_func_list)},
    [CFG_SYSTEM_ID_BLUETOOTH]     = {"CFG_SYSTEM_ID_BLUETOOTH", Mw_Cfg_SystemBluetoothSet, Mw_Cfg_SystemBluetoothGet, NULL, .cb_func_list=LIST_HEAD_INIT(s_Mw_CfgAccess[CFG_SYSTEM_ID_BLUETOOTH].cb_func_list)},
    [CFG_SYSTEM_ID_USB]           = {"CFG_SYSTEM_ID_USB", Mw_Cfg_SystemUsbSet, Mw_Cfg_SystemUsbGet, NULL, .cb_func_list=LIST_HEAD_INIT(s_Mw_CfgAccess[CFG_SYSTEM_ID_USB].cb_func_list)},
    [CFG_SYSTEM_ID_SENSOR]        = {"CFG_SYSTEM_ID_SENSOR", Mw_Cfg_SystemSensorSet, Mw_Cfg_SystemSensorGet, NULL, .cb_func_list=LIST_HEAD_INIT(s_Mw_CfgAccess[CFG_SYSTEM_ID_SENSOR].cb_func_list)},
    [CFG_SYSTEM_ID_BATTERY]       = {"CFG_SYSTEM_ID_BATTERY", Mw_Cfg_SystemBatterySet, Mw_Cfg_SystemBatteryGet, NULL, .cb_func_list=LIST_HEAD_INIT(s_Mw_CfgAccess[CFG_SYSTEM_ID_BATTERY].cb_func_list)},
    [CFG_SYSTEM_ID_LED]           = {"CFG_SYSTEM_ID_LED", Mw_Cfg_SystemLedSet, Mw_Cfg_SystemLedGet, NULL, .cb_func_list=LIST_HEAD_INIT(s_Mw_CfgAccess[CFG_SYSTEM_ID_LED].cb_func_list)},
    [CFG_SYSTEM_ID_BUTTON]        = {"CFG_SYSTEM_ID_BUTTON", Mw_Cfg_SystemButtonSet, Mw_Cfg_SystemButtonGet, NULL, .cb_func_list=LIST_HEAD_INIT(s_Mw_CfgAccess[CFG_SYSTEM_ID_BUTTON].cb_func_list)},
    [CFG_COMMON_ID_CAMMODE]       = {"CFG_COMMON_ID_CAMMODE", Mw_Cfg_CommonCamModeSet, Mw_Cfg_CommonCamModeGet, Mw_Cfg_CommonCamModePrint, .cb_func_list=LIST_HEAD_INIT(s_Mw_CfgAccess[CFG_COMMON_ID_CAMMODE].cb_func_list)},
    [CFG_VIDEO_ID_RECORD_STREAM]  = {"CFG_VIDEO_ID_RECORD_STREAM", Mw_Cfg_VideoRecord_streamSet, Mw_Cfg_VideoRecord_streamGet, Mw_Cfg_VideoRecord_streamPrint, .cb_func_list=LIST_HEAD_INIT(s_Mw_CfgAccess[CFG_VIDEO_ID_RECORD_STREAM].cb_func_list)},
    [CFG_VIDEO_ID_RECORD_SPEC]    = {"CFG_VIDEO_ID_RECORD_SPEC", Mw_Cfg_VideoRecordSpecSet, Mw_Cfg_VideoRecordSpecGet, Mw_Cfg_VideoRecordSpecPrint, .cb_func_list=LIST_HEAD_INIT(s_Mw_CfgAccess[CFG_VIDEO_ID_RECORD_SPEC].cb_func_list)},
    [CFG_VIDEO_ID_BITRATE]        = {"CFG_VIDEO_ID_BITRATE", Mw_Cfg_VideoBitrateSet, Mw_Cfg_VideoBitrateGet, Mw_Cfg_VideoRecordBitratePrint, .cb_func_list=LIST_HEAD_INIT(s_Mw_CfgAccess[CFG_VIDEO_ID_BITRATE].cb_func_list)},
    [CFG_VIDEO_ID_BRATECTRL]      = {"CFG_VIDEO_ID_BRATECTRL", Mw_Cfg_VideoBrateCtrlSet, Mw_Cfg_VideoBrateCtrlGet, Mw_Cfg_VideoRecordBrateCtrlPrint, .cb_func_list=LIST_HEAD_INIT(s_Mw_CfgAccess[CFG_VIDEO_ID_BRATECTRL].cb_func_list)},
    [CFG_VIDEO_ID_CODEC]          = {"CFG_VIDEO_ID_CODEC", Mw_Cfg_VideoCodecSet, Mw_Cfg_VideoCodecGet, Mw_Cfg_VideoCodecPrint, .cb_func_list=LIST_HEAD_INIT(s_Mw_CfgAccess[CFG_VIDEO_ID_CODEC].cb_func_list)},
    [CFG_PHOTO_ID_RESOLUTION]     = {"CFG_PHOTO_ID_RESOLUTION", Mw_Cfg_PhotoResolutionSet, Mw_Cfg_PhotoResolutionGet, NULL, .cb_func_list=LIST_HEAD_INIT(s_Mw_CfgAccess[CFG_PHOTO_ID_RESOLUTION].cb_func_list)},
    [CFG_PHOTO_ID_CAPCFG]         = {"CFG_PHOTO_ID_CAPCFG", Mw_Cfg_PhotoCapcfgSet, Mw_Cfg_PhotoCapcfgGet, Mw_Cfg_PhotoCapcfgPrint, .cb_func_list=LIST_HEAD_INIT(s_Mw_CfgAccess[CFG_PHOTO_ID_CAPCFG].cb_func_list)},
    [CFG_AUDIO_ID_ENCODE]         = {"CFG_AUDIO_ID_ENCODE", Mw_Cfg_AudioEncodeSet, Mw_Cfg_AudioEncodeGet, Mw_Cfg_AudioEncodePrint, .cb_func_list=LIST_HEAD_INIT(s_Mw_CfgAccess[CFG_AUDIO_ID_ENCODE].cb_func_list)},
    [CFG_IMAGE_ID_BRIGHTNESS]     = {"CFG_IMAGE_ID_BRIGHTNESS", Mw_Cfg_ImageBrightnessSet, Mw_Cfg_ImageBrightnessGet, NULL, .cb_func_list=LIST_HEAD_INIT(s_Mw_CfgAccess[CFG_IMAGE_ID_BRIGHTNESS].cb_func_list)},
    [CFG_IMAGE_ID_CONTRAST]       = {"CFG_IMAGE_ID_CONTRAST", Mw_Cfg_ImageContrastSet, Mw_Cfg_ImageContrastGet, NULL, .cb_func_list=LIST_HEAD_INIT(s_Mw_CfgAccess[CFG_IMAGE_ID_CONTRAST].cb_func_list)},
    [CFG_IMAGE_ID_SHARPNESS]      = {"CFG_IMAGE_ID_SHARPNESS", Mw_Cfg_ImageSharpnessSet, Mw_Cfg_ImageSharpnessGet, NULL, .cb_func_list=LIST_HEAD_INIT(s_Mw_CfgAccess[CFG_IMAGE_ID_SHARPNESS].cb_func_list)},
    [CFG_IMAGE_ID_AAA]            = {"CFG_IMAGE_ID_AAA", Mw_Cfg_ImageAAASet, Mw_Cfg_ImageAAAGet, Mw_Cfg_ImageAAAPrint, .cb_func_list=LIST_HEAD_INIT(s_Mw_CfgAccess[CFG_IMAGE_ID_AAA].cb_func_list)},
    [CFG_IMAGE_ID_ANTI_FLICKER]   = {"CFG_IMAGE_ID_ANTI_FLICKER", Mw_Cfg_ImageAntiFlickerSet, Mw_Cfg_ImageAntiFlickerGet, NULL, .cb_func_list=LIST_HEAD_INIT(s_Mw_CfgAccess[CFG_IMAGE_ID_ANTI_FLICKER].cb_func_list)},
    [CFG_OTHER_ID_LCD]            = {"CFG_OTHER_ID_LCD", Mw_Cfg_OtherLcdSet, Mw_Cfg_OtherLcdGet, Mw_Cfg_OtherLcdPrint, .cb_func_list=LIST_HEAD_INIT(s_Mw_CfgAccess[CFG_OTHER_ID_LCD].cb_func_list)},
    [CFG_OTHER_ID_QCAP]           = {"CFG_OTHER_ID_QCAP", Mw_Cfg_OtherQcapSet, Mw_Cfg_OtherQcapGet, Mw_Cfg_OtherQcapPrint, .cb_func_list=LIST_HEAD_INIT(s_Mw_CfgAccess[CFG_OTHER_ID_QCAP].cb_func_list)},
    [CFG_APP_ID_GUI]              = {"CFG_APP_ID_GUI", Mw_Cfg_AppGuiSet, Mw_Cfg_AppGuiGet, NULL, .cb_func_list=LIST_HEAD_INIT(s_Mw_CfgAccess[CFG_APP_ID_GUI].cb_func_list)},
};

MW_CFG_COMMON_GROUP_SET_AND_GET_FUNC(Base, &s_mw_cfg.cfg_sys_part.base_info);
MW_CFG_COMMON_GROUP_SET_AND_GET_FUNC(System, &s_mw_cfg.cfg_sys_part.system_info);
MW_CFG_COMMON_GROUP_SET_AND_GET_FUNC(Common, &s_mw_cfg.cfg_user_part.common_info);
MW_CFG_COMMON_GROUP_SET_AND_GET_FUNC(Video, &s_mw_cfg.cfg_user_part.video_info);
MW_CFG_COMMON_GROUP_SET_AND_GET_FUNC(Photo, &s_mw_cfg.cfg_user_part.photo_info);
MW_CFG_COMMON_GROUP_SET_AND_GET_FUNC(Audio, &s_mw_cfg.cfg_user_part.audio_info);
MW_CFG_COMMON_GROUP_SET_AND_GET_FUNC(Image, &s_mw_cfg.cfg_user_part.image_info);
MW_CFG_COMMON_GROUP_SET_AND_GET_FUNC(Other, &s_mw_cfg.cfg_user_part.other_info);
MW_CFG_COMMON_GROUP_SET_AND_GET_FUNC(App, &s_mw_cfg.cfg_user_part.app_info);

static Mw_CfgAccess_t s_Mw_CfgGroupAccess[] =
{
    [CFG_GROUP_BASE]        = {"CFG_GROUP_BASE", Mw_Cfg_BaseGroupSet, Mw_Cfg_BaseGroupGet,  NULL, {NULL}},
    [CFG_GROUP_SYSTEM]      = {"CFG_GROUP_SYSTEM", Mw_Cfg_SystemGroupSet, Mw_Cfg_SystemGroupGet,  NULL, {NULL}},
    [CFG_GROUP_COMMON]      = {"CFG_GROUP_COMMON", Mw_Cfg_CommonGroupSet, Mw_Cfg_CommonGroupGet,  NULL, {NULL}},
    [CFG_GROUP_VIDEO]       = {"CFG_GROUP_VIDEO", Mw_Cfg_VideoGroupSet, Mw_Cfg_VideoGroupGet,  NULL, {NULL}},
    [CFG_GROUP_PHOTO]       = {"CFG_GROUP_PHOTO", Mw_Cfg_PhotoGroupSet, Mw_Cfg_PhotoGroupGet,  NULL, {NULL}},
    [CFG_GROUP_AUDIO]       = {"CFG_GROUP_AUDIO", Mw_Cfg_AudioGroupSet, Mw_Cfg_AudioGroupGet,  NULL, {NULL}},
    [CFG_GROUP_IMAGE]       = {"CFG_GROUP_IMAGE", Mw_Cfg_ImageGroupSet, Mw_Cfg_ImageGroupGet,  NULL, {NULL}},
    [CFG_GROUP_OTHER]       = {"CFG_GROUP_OTHER", Mw_Cfg_OtherGroupSet, Mw_Cfg_OtherGroupGet,  NULL, {NULL}},
    [CFG_GROUP_APP]         = {"CFG_GROUP_APP", Mw_Cfg_AppGroupSet, Mw_Cfg_AppGroupGet,  NULL, {NULL}},
};

uint32_t Mw_Cfg_Init(mw_write_cb wb, mw_read_cb rb)
{
    uint32_t ret = 0;
    if(s_mw_cfg.init_flg == 1)
    {
        hlogi("Config already inited");
        return OK;
    }    
    s_mw_cfg.read_cb_f  = rb;
    s_mw_cfg.write_cb_f = wb;
    if (CFG_ID_NUM != ARRAY_SIZE(s_Mw_CfgAccess))
    {
        hloge("Mw cfg Access items number[%lu] error, not equal to %d!",
                 ARRAY_SIZE(s_Mw_CfgAccess), CFG_ID_NUM);
        return NG;
    }

    if (CFG_GROUP_NUM != ARRAY_SIZE(s_Mw_CfgGroupAccess))
    {
        hloge("Mw cfg group Access items number[%lu] error, not equal to %d!",
                 ARRAY_SIZE(s_Mw_CfgGroupAccess), CFG_GROUP_NUM);

        return NG;
    }

    ret = hmutex_init(&s_mw_cfg.mutex);
    if(ret != 0)
    {
        hloge("Mw cfg init mutex create fail[%d].", ret);
        return NG;
    }
    ret = hmutex_init(&s_mw_cfg.rom_mutex);
    if(ret != 0)
    {
        hloge("Mw cfg init rommutex create fail[%d].", ret);
        return NG;
    }

    Mw_Cfg_MemoryInit();
    s_mw_cfg.init_flg = 1;

    hlogi("Configs init done.");

    return OK;
}

uint32_t Mw_Cfg_GetConfig(uint32_t config_id, void *p_out, uint32_t size)
{
    uint32_t ret = hmutex_lock(&s_mw_cfg.mutex);
    if (0 != ret)
    {
        (void)hmutex_unlock(&s_mw_cfg.mutex);
        hloge("Take user settings mutex, fail, Ret=%d", ret);
        return ret;
    }
    ret = Mw_Cfg_GetConfig_NoBlock(config_id, p_out, size);
    (void)hmutex_unlock(&s_mw_cfg.mutex);
    return ret;
}

uint32_t Mw_Cfg_SetConfig(uint32_t config_id, void *p_in, uint32_t size)
{
    uint32_t ret = hmutex_lock(&s_mw_cfg.mutex);
    if (0 != ret)
    {
        (void)hmutex_unlock(&s_mw_cfg.mutex);
        hloge("Take user settings mutex, fail, Ret=%d", ret);
        return ret;
    }
    ret = Mw_Cfg_SetConfig_NoBlock(config_id, p_in, size);
    (void)hmutex_unlock(&s_mw_cfg.mutex);
    return ret;
}

uint32_t Mw_Cfg_GetConfig_NoBlock(uint32_t config_id, void *p_out, uint32_t size)
{
    uint32_t ret = 0;
    hlogd("Mw Cfg get id[%d], size[%d]", config_id, size);

    if ((config_id >= CFG_ID_NUM) || (NULL == p_out) || (0 == size))
    {
        hloge("Mw Cfg input error, id=%d, p_in=%p, size=%d.", config_id, p_out, size);
        return NG;
    }

    if (NULL != s_Mw_CfgAccess[config_id].get_func)
    {

        ret = s_Mw_CfgAccess[config_id].get_func(p_out, size);
        if (0 != ret)
        {
            hloge("Call getting function fail, Ret=%d, Id=%d", ret, config_id);
            return ret;
        }
    }
    else
    {
        hloge("Get function is NULL, Id=%d, fail.", config_id);
        return NG;
    }
    return ret;
}

uint32_t Mw_Cfg_SetConfig_NoBlock(uint32_t config_id, void *p_in, uint32_t size)
{
    uint32_t ret = 0;
    hlogi("Mw Cfg set id[%d], size[%d]", config_id, size);

    if ((config_id >= CFG_ID_NUM) || (NULL == p_in) || (0 == size))
    {
        hloge("Mw Cfg input error, id=%d, p_in=%p, size=%d.", config_id, p_in, size);
        return NG;
    }

    if (NULL != s_Mw_CfgAccess[config_id].set_func)
    {

        ret = s_Mw_CfgAccess[config_id].set_func(p_in, size);
        if (0 != ret && MW_SET_SAME != ret)
        {
            hloge("Call setting function fail, Ret=%d, Id=%d", ret, config_id);
            return ret;
        }
    }
    else
    {
        hloge("Set function is NULL, Id=%d, fail.", config_id);
        return NG;
    }
    return ret;
}

uint32_t Mw_Cfg_PrintId(uint32_t id)
{
    uint32_t ret = 0;
    uint32_t value[64];
    if(s_Mw_CfgAccess[id].print_func != NULL)
    {
        s_Mw_CfgAccess[id].print_func(id, s_Mw_CfgAccess[id].name);
    }
    else
    {
        ret = Mw_Cfg_GetConfig(id, (void *)value, sizeof(int));
        if(0 == ret)
        {
            MW_CFG_PRINT("[%d][%s]............0x%x", id, s_Mw_CfgAccess[id].name, value[0]);
        }
        else
        {
            MW_CFG_PRINT("[%d][%s]............Get Failed!( plz check print_func has been set also )", id, s_Mw_CfgAccess[id].name);
        }
    }
    return ret;
}

uint32_t Mw_Cfg_PrintAll(void)
{
    uint32_t i;
    MW_CFG_PRINT("UserPart Header Version[0x%x] Total Size[%d] Checksum[0x%x]",
                 s_mw_cfg.cfg_user_part.header.version, s_mw_cfg.cfg_user_part.header.total_size, s_mw_cfg.cfg_user_part.header.checksum);
    MW_CFG_PRINT("SysPart Header Version[0x%x] Total Size[%d] Checksum[0x%x]",
                 s_mw_cfg.cfg_sys_part.header.version, s_mw_cfg.cfg_sys_part.header.total_size, s_mw_cfg.cfg_sys_part.header.checksum);
    MW_CFG_PRINT("Cfg id max: %d", CFG_ID_NUM);

    for(i=0; i<CFG_ID_NUM; i++)
    {
        Mw_Cfg_PrintId(i);
    }
    MW_CFG_PRINT("Cfg id max: %d", CFG_ID_NUM);
    return OK;
}

uint32_t Mw_Cfg_SetCallbackRegister(uint32_t config_id, Mw_CfgSetIdCallback_f cb_func)
{
    uint32_t ret = 0;
    hlogi("Mw Cfg Callback register id[%d]", config_id);

    if ((config_id >= CFG_ID_NUM) || (NULL == cb_func))
    {
        hloge("Mw Cfg Callback input error, id=%d, func=%p.", config_id, cb_func);
        return NG;
    }

    ret = hmutex_lock(&s_mw_cfg.mutex);
    if (0 != ret)
    {
        hloge("Take user settings mutex, fail, Ret=%d", ret);
        return ret;
    }
    Mw_CfgSetIdCallback_s *p_cb = (Mw_CfgSetIdCallback_s*)malloc(sizeof(Mw_CfgSetIdCallback_s));
    list_add_tail(&p_cb->link,&s_Mw_CfgAccess[config_id].cb_func_list);
    (void)hmutex_unlock(&s_mw_cfg.mutex);
    return ret;
}

uint32_t Mw_Cfg_SetCallbackUnregister(uint32_t config_id, Mw_CfgSetIdCallback_f cb_func)
{
    uint32_t ret = 0;
    hlogi("Mw Cfg Callback unregister id[%d]", config_id);

    if ((config_id >= CFG_ID_NUM) || (NULL == cb_func))
    {
        hloge("Mw Cfg Callback input error, id=%d, func=%p.", config_id, cb_func);
        return NG;
    }

    ret = hmutex_lock(&s_mw_cfg.mutex);
    if (0 != ret)
    {
        hloge("Take user settings mutex, fail, Ret=%d", ret);
        return ret;
    }
    {
        struct list_head *pos, *n;
        list_for_each_safe(pos, n, &s_Mw_CfgAccess[config_id].cb_func_list){
            Mw_CfgSetIdCallback_s* cb = list_entry(pos, Mw_CfgSetIdCallback_s, link);
            if (cb->cb_func == cb_func){
                list_del(pos);
                free(cb);
            }
        }
    }
    hmutex_unlock(&s_mw_cfg.mutex);
    return ret;
}

uint32_t Mw_Cfg_GetGroupInfo(Mw_CfgGroup_Type_e group_id, void *p_out, uint32_t size)
{
    uint32_t ret = 0;
    hlogi("Mw Cfg get group id[%d], size[%d]", group_id, size);

    if ((group_id >= CFG_GROUP_NUM) || (NULL == p_out) || (0 == size))
    {
        hloge("Mw Cfg input error, id=%d, p_in=%p, size=%d.", group_id, p_out, size);
        return NG;
    }

    if (NULL != s_Mw_CfgGroupAccess[group_id].get_func)
    {
        ret = hmutex_lock(&s_mw_cfg.mutex);
        if (0 != ret)
        {
            (void)hmutex_unlock(&s_mw_cfg.mutex);
            hloge("Take user settings mutex, fail, Ret=%d", ret);
            return ret;
        }

        ret = s_Mw_CfgGroupAccess[group_id].get_func(p_out, size);
        if (0 != ret)
        {
            (void)hmutex_unlock(&s_mw_cfg.mutex);
            hloge("Call getting function fail, Ret=%d, Id=%d", ret, group_id);
            return ret;
        }
        (void)hmutex_unlock(&s_mw_cfg.mutex);
    }
    else
    {
        hloge("Get function is NULL, Id=%d, fail.", group_id);
        return NG;
    }
    return ret;
}

uint32_t Mw_Cfg_SetGroupInfo(Mw_CfgGroup_Type_e group_id, void *p_in, uint32_t size)
{
    uint32_t ret = 0;
    hlogi("Mw Cfg set group id[%d], size[%d]", group_id, size);

    if ((group_id >= CFG_GROUP_NUM) || (NULL == p_in) || (0 == size))
    {
        hloge("Mw Cfg input error, id=%d, p_in=%p, size=%d.", group_id, p_in, size);
        return NG;
    }

    if (NULL != s_Mw_CfgGroupAccess[group_id].set_func)
    {
        ret = hmutex_lock(&s_mw_cfg.mutex);
        if (0 != ret)
        {
            (void)hmutex_unlock(&s_mw_cfg.mutex);
            hloge("Take user settings mutex, fail, Ret=%d", ret);
            return ret;
        }

        ret = s_Mw_CfgGroupAccess[group_id].set_func(p_in, size);
        if(MW_SET_SAME == ret)
        {
            ret = 0; //to avoid warning if same
        }
        else if (0 != ret)
        {
            (void)hmutex_unlock(&s_mw_cfg.mutex);
            hloge("Call setting function fail, Ret=%d, Id=%d", ret, group_id);
            return ret;
        }
        (void)hmutex_unlock(&s_mw_cfg.mutex);
    }
    else
    {
        hloge("Set function is NULL, Id=%d, fail.", group_id);
        return NG;
    }
    return ret;
}

uint32_t Mw_Cfg_LoadDefault(Mw_CfgStorage_Partition_e part)
{
    char *data, *default_data;
    uint16_t size;
    switch ( part ) {
        case CFG_STORAGE_PARTITION_USER:
            data         = (char *)&s_mw_cfg.cfg_user_part;
            size         = sizeof(s_mw_cfg.cfg_user_part);
            default_data = (char *)&s_mw_cfg.user_part_default;
            break;
        case CFG_STORAGE_PARTITION_SYS:
            data         = (char *)&s_mw_cfg.cfg_sys_part;
            size         = sizeof(s_mw_cfg.cfg_sys_part);
            default_data = (char *)&s_mw_cfg.sys_part_default;
            break;
        default:
            hloge("Mw Cfg Undefined storage part[%d]", part);
            return NG;
            break;
    }

    memcpy(data, default_data, size);
    hlogi("Configs part [%d] load default.", part);
    s_mw_cfg.active_region[part] = CFG_STORAGE_REGION_MAIN;
    Mw_Cfg_TrySave(part, CFG_STORAGE_REGION_MAIN, data, size);
    return OK;
}

uint32_t Mw_Cfg_Save(Mw_CfgStorage_Partition_e part)
{
    /* Save to ROM (only save main here, back should be saved at init)*/
    uint32_t ret;
    char *data;
    uint16_t size;
    Mw_CfgStorage_Partition_e active_region = s_mw_cfg.active_region[part] == CFG_STORAGE_REGION_MAIN ? CFG_STORAGE_REGION_BACK : CFG_STORAGE_REGION_MAIN;
    switch ( part ) {
        case CFG_STORAGE_PARTITION_USER:
            data         = (char *)&s_mw_cfg.cfg_user_part;
            size         = sizeof(s_mw_cfg.cfg_user_part);
            break;
        case CFG_STORAGE_PARTITION_SYS:
            data         = (char *)&s_mw_cfg.cfg_sys_part;
            size         = sizeof(s_mw_cfg.cfg_sys_part);
            break;
        default:
            hloge("Mw Cfg Undefined storage part[%d]", part);
            return NG;
    }
    ret =  Mw_Cfg_TrySave(part, active_region, data, size);
    if ( ret == OK ){
        s_mw_cfg.active_region[part] = active_region;
    }
    return ret;
}

/* for unit test */
uint32_t Mw_Cfg_Destroy(Mw_CfgStorage_Partition_e part, Mw_CfgStorage_Region_e region)
{
    uint32_t ret = 0;
    hmutex_lock(&s_mw_cfg.mutex);
    
    for(uint32_t i =0; i<ARRAY_SIZE(s_Mw_CfgAccess);i++){
        struct list_head *pos, *n;
        list_for_each_safe(pos, n, &s_Mw_CfgAccess[i].cb_func_list){
            Mw_CfgSetIdCallback_s* cb = list_entry(pos, Mw_CfgSetIdCallback_s, link);
            list_del(pos);
            free(cb);
        }
    }
    hmutex_unlock(&s_mw_cfg.mutex);
    hlogi("Destroy cfg data part[%d], region[%d]", part, region);
    ret = Mw_Cfg_Save(part);
    return ret;
}


/***********************test***************************/
// path can be file, return size has been writed

void Mw_Cfg_Test()
{
    Mw_Cfg_Init(mw_storage_write, mw_storage_read);
    {
        Mw_CfgBase_ProductUUID_t product_uuid;
        Mw_Cfg_GetConfig(CFG_BASE_ID_PRODUCT_UUID, &product_uuid, sizeof(product_uuid));
        hlogd("read product_uuid:%s", product_uuid.uuid);
    }

    Mw_Cfg_Destroy(CFG_STORAGE_PARTITION_SYS, CFG_STORAGE_REGION_MAIN);

}

