/*!
 * \file      cfg_drv.c
 * \brief     驱动配置接口
 * \details
 * \author
 * \date
 * \copyright Actions
 */

#include "list.h"
#include <sdfs.h>
#include <device.h>
#include <zephyr/types.h>
#include "drivers/cfg_drv/driver_config.h"
#include "drv_cfg_head.h"


#ifndef bool_t
#define bool_t    int
#endif

#ifndef TRUE
#define TRUE    1
#endif

#ifndef FALSE
#define FALSE   0
#endif

/*!
 * \brief 获取最小值
 */
#define _MIN(_a, _b)  (((_a) < (_b)) ? (_a) : (_b))

/*!
 * \brief 获取最大值
 */
#define _MAX(_a, _b)  (((_a) > (_b)) ? (_a) : (_b))

/*!
 * \brief 获取CFG key中的ID, OFFSET, LEN
 */
#define CFG_KEY_ID(key) 	((key >> 24) & 0xff)
#define CFG_KEY_OFFSET(key) ((key >> 12) & 0xfff)
#define CFG_KEY_LEN(key) 	((key) & 0xfff)

typedef struct
{
    u8_t   format[4];
    u8_t   magic [4];
    u16_t  user_version;
    u8_t   minor_version;
    u8_t   major_version;

    u16_t  total_size;
    u16_t  num_cfg_items;

} drv_config_file_header_t;

typedef struct
{
    u32_t  cfg_id:8;
    u32_t  sub_pos:12;
    u32_t  cfg_len:12;

} drv_config_item_info_t;

typedef struct
{
    struct list_head  node;

	void *file;

    int    num_cfg_items;
    u8_t*  cfg_data;

    drv_config_item_info_t*  cfg_items;

} drv_config_file_info_t;

typedef struct {

    /** item key value, defined by drivers */
	uint32_t item_key_value;

    /** cfg key value, generated by config tools */
	uint32_t cfg_key_value;

} cfg_key_map_t;


/* 最大配置文件数 */
#define MAX_DRV_CFG_FILE	2

drv_config_file_info_t cfg_file_info[MAX_DRV_CFG_FILE];

struct list_head  drv_config_file_list = LIST_HEAD_INIT(drv_config_file_list);

cfg_key_map_t cfg_key_map_table[]={
	/* UART */
	{ ITEM_UART_TX_PIN , CFG_Console_UART_RX_Pin },
	{ ITEM_UART_RX_PIN , CFG_Console_UART_TX_Pin },
	{ ITEM_UART_BAUDRATE , CFG_Console_UART_Baudrate },
	{ ITEM_UART_PRINT_TIME_STAMP , CFG_Console_UART_Print_Time_Stamp },
	/* LED */
	{ ITEM_LED_LED, CFG_LED_Drives_LED },
	/* ONOFF KEY */
	{ ITEM_ONOFF_USE_INNER_ONOFF_KEY, CFG_ONOFF_Key_Use_Inner_ONOFF_Key },
	{ ITEM_ONOFF_CONTINUE_KEY_FUNCTION_AFTER_WAKE_UP, CFG_ONOFF_Key_Continue_Key_Function_After_Wake_Up },
	{ ITEM_ONOFF_KEY_VALUE, CFG_ONOFF_Key_Key_Value },
	{ ITEM_ONOFF_TIME_PRESS_POWER_ON, CFG_ONOFF_Key_Time_Press_Power_On },
	{ ITEM_ONOFF_TIME_LONG_PRESS_RESET, CFG_ONOFF_Key_Time_Long_Press_Reset },
	{ ITEM_ONOFF_BOOT_HOLD_KEY_FUNC,  CFG_ONOFF_Key_Boot_Hold_Key_Func},
	{ ITEM_ONOFF_BOOT_HOLD_KEY_TIME_MS, CFG_ONOFF_Key_Boot_Hold_Key_Time_Ms },
	{ ITEM_ONOFF_DEBOUNCE_TIME_MS, CFG_ONOFF_Key_Debounce_Time_Ms },
	{ ITEM_ONOFF_REBOOT_AFTER_BOOT_HOLD_KEY_CLEAR_PAIRED_LIST, CFG_ONOFF_Key_Reboot_After_Boot_Hold_Key_Clear_Paired_List },
	/* LRADC KEY */
	{ ITEM_LRADC_KEY, CFG_LRADC_Keys_Key },
	{ ITEM_LRADC_CTRL, CFG_LRADC_Keys_LRADC_Ctrl },
	{ ITEM_LRADC_PULL_UP, CFG_LRADC_Keys_LRADC_Pull_Up },
	{ ITEM_LRADC_KEY_WAKE_UP, CFG_LRADC_Keys_Use_LRADC_Key_Wake_Up },
	{ ITEM_LRADC_VALUE_TEST, CFG_LRADC_Keys_LRADC_Value_Test },
	{ ITEM_LRADC_DEBOUNCE_TIME_MS, CFG_LRADC_Keys_Debounce_Time_Ms },
	/* GPIO KEY */
	{ ITEM_GPIO_KEY, CFG_GPIO_Keys_Key },
	/* TAP KEY */
	{ ITEM_TAP_KEY_CONTROL, CFG_Tap_Key_Tap_Key_Control },
	/* AUDIO */
	{ ITEM_AUDIO_OUT_MODE, CFG_Audio_Settings_Audio_Out_Mode },
	{ ITEM_AUDIO_I2STX_SELECT_GPIO, CFG_Audio_Settings_I2STX_Select_GPIO },
	{ ITEM_AUDIO_CHANNEL_SELECT_MODE, CFG_Audio_Settings_Channel_Select_Mode },
	{ ITEM_AUDIO_CHANNEL_SELECT_GPIO, CFG_Audio_Settings_Channel_Select_GPIO },
	{ ITEM_AUDIO_CHANNEL_SELECT_LRADC, CFG_Audio_Settings_Channel_Select_LRADC },
	{ ITEM_AUDIO_TWS_ALONE_AUDIO_CHANNEL, CFG_Audio_Settings_TWS_Alone_Audio_Channel },
	{ ITEM_AUDIO_L_SPEAKER_OUT, CFG_Audio_Settings_L_Speaker_Out },
	{ ITEM_AUDIO_R_SPEAKER_OUT, CFG_Audio_Settings_R_Speaker_Out },
	{ ITEM_AUDIO_ADC_BIAS_SETTING, CFG_Audio_Settings_ADC_Bias_Setting },
	{ ITEM_AUDIO_DAC_BIAS_SETTING, CFG_Audio_Settings_DAC_Bias_Setting },
	{ ITEM_AUDIO_KEEP_DA_ENABLED_WHEN_PLAY_PAUSE, CFG_Audio_Settings_Keep_DA_Enabled_When_Play_Pause },
	{ ITEM_AUDIO_DISABLE_PA_WHEN_RECONNECT, CFG_Audio_Settings_Disable_PA_When_Reconnect },
	{ ITEM_AUDIO_EXTERN_PA_CONTROL, CFG_Audio_Settings_Extern_PA_Control },
	{ ITEM_AUDIO_ANTIPOP_PROCESS_DISABLE, CFG_Audio_Settings_AntiPOP_Process_Disable },
	{ ITEM_AUDIO_DMIC01_CHANNEL_ALIGNING, CFG_Audio_Settings_DMIC01_Channel_Aligning },
	{ ITEM_AUDIO_DMIC23_CHANNEL_ALIGNING, CFG_Audio_Settings_DMIC23_Channel_Aligning },
	{ ITEM_AUDIO_DMIC_SELECT_GPIO, CFG_Audio_Settings_DMIC_Select_GPIO },
	{ ITEM_AUDIO_ENABLE_ANC, CFG_Audio_Settings_Enable_ANC },
	{ ITEM_AUDIO_ANCDMIC_SELECT_GPIO, CFG_Audio_Settings_ANCDMIC_Select_GPIO },
	{ ITEM_AUDIO_RECORD_ADC_SELECT, CFG_Audio_Settings_Record_Adc_Select },
	{ ITEM_AUDIO_ENABLE_VMIC, CFG_Audio_Settings_Enable_VMIC },
	{ ITEM_AUDIO_HW_AEC_SELECT, CFG_Audio_Settings_Hw_Aec_Select },
	{ ITEM_AUDIO_TM_ADC_SELECT, CFG_Audio_Settings_Tm_Adc_Select },
	{ ITEM_AUDIO_MIC_CONFIG, CFG_Audio_Settings_Mic_Config },
	{ ITEM_AUDIO_ADC_INPUT_SELECT, CFG_Audio_Settings_ADC_Select_INPUT },
	{ ITEM_AUDIO_PA_GAIN, CFG_Audio_Settings_Pa_Gain },
	{ ITEM_AUDIO_DUAL_MIC_EXCHANGE_ENABLE, CFG_Audio_Settings_Dual_MIC_Exchange_Enable },
	{ ITEM_AUDIO_LARGE_CURRENT_PROTOTECT_ENABLE, CFG_Audio_Settings_Large_Current_Protect_Enable},
	{ ITEM_AUDIO_ANALOG_GAIN_SETTINGS, CFG_Audio_Settings_ANALOG_GAIN_Settings },

	/* BATTERY */
	{ ITEM_CHARGE_SELECT_CHARGE_MODE, CFG_Battery_Charge_Select_Charge_Mode },
	{ ITEM_CHARGE_CURRENT, CFG_Battery_Charge_Charge_Current },
	{ ITEM_CHARGE_VOLTAGE, CFG_Battery_Charge_Charge_Voltage },
	{ ITEM_CHARGE_STOP_MODE, CFG_Battery_Charge_Charge_Stop_Mode },
	{ ITEM_CHARGE_STOP_VOLTAGE, CFG_Battery_Charge_Charge_Stop_Voltage },
	{ ITEM_CHARGE_STOP_CURRENT, CFG_Battery_Charge_Charge_Stop_Current },
	{ ITEM_CHARGE_PRECHARGE_STOP_VOLTAGE, CFG_Battery_Charge_Precharge_Stop_Voltage },
	{ ITEM_CHARGE_PRECHARGE_CURRENT, CFG_Battery_Charge_Precharge_Current },
	{ ITEM_CHARGE_PRECHARGE_CURRENT_MIN_LIMIT, CFG_Battery_Charge_Precharge_Current_Min_Limit },
	{ ITEM_CHARGE_FAST_CHARGE_ENABLE, CFG_Battery_Charge_Fast_Charge_Enable },
	{ ITEM_CHARGE_FAST_CHARGE_CURRENT, CFG_Battery_Charge_Fast_Charge_Current },
	{ ITEM_CHARGE_FAST_CHARGE_VOLTAGE_THRESHOLD, CFG_Battery_Charge_Fast_Charge_Voltage_Threshold },
	{ ITEM_CHARGE_ENABLE_BATTERY_RECHARGE, CFG_Battery_Charge_Enable_Battery_Recharge },
	{ ITEM_CHARGE_BATTERY_RECHARGE_THRESHOLD, CFG_Battery_Charge_Enable_Battery_Recharge },	
	{ ITEM_CHARGE_BATTERY_CHARGE_TOTAL_TIME_LIMIT, CFG_Battery_Charge_Charge_Total_Time_Limit },
	{ ITEM_CHARGE_BATTERY_CHECK_PERIOD_SEC, CFG_Battery_Charge_Battery_Check_Period_Sec },
	{ ITEM_CHARGE_CHECK_PERIOD_SEC, CFG_Battery_Charge_Charge_Check_Period_Sec },
	{ ITEM_CHARGE_FULL_CONTINUE_SEC, CFG_Battery_Charge_Charge_Full_Continue_Sec },
	{ ITEM_CHARGE_FRONT_CHARGE_FULL_POWER_OFF_WAIT_SEC, CFG_Battery_Charge_Front_Charge_Full_Power_Off_Wait_Sec },
	{ ITEM_CHARGE_DC5V_DETECT_DEBOUNCE_TIME_MS, CFG_Battery_Charge_DC5V_Detect_Debounce_Time_Ms },
	/* CHARGER BOX*/
	{ ITEM_CHARGEBOX_ENABLE_CHARGER_BOX, CFG_Charger_Box_Enable_Charger_Box },
	{ ITEM_CHARGEBOX_DC5V_PULL_DOWN_CURRENT, CFG_Charger_Box_DC5V_Pull_Down_Current },
	{ ITEM_CHARGEBOX_DC5V_PULL_DOWN_HOLD_MS, CFG_Charger_Box_DC5V_Pull_Down_Hold_Ms },
	{ ITEM_CHARGEBOX_STANDBY_DELAY_MS, CFG_Charger_Box_Charger_Standby_Delay_Ms },
	{ ITEM_CHARGEBOX_STANDBY_VOLTAGE, CFG_Charger_Box_Charger_Standby_Voltage },
	{ ITEM_CHARGEBOX_WAKE_DELAY_MS, CFG_Charger_Box_Charger_Wake_Delay_Ms },
	{ ITEM_CHARGEBOX_BOX_STANDBY_CURRENT, CFG_Charger_Box_Charger_Box_Standby_Current },
	{ ITEM_CHARGEBOX_DC5V_UART_COMM_SETTINGS, CFG_Charger_Box_DC5V_UART_Comm_Settings },
	{ ITEM_CHARGEBOX_DC5V_IO_COMM_SETTINGS, CFG_Charger_Box_DC5V_IO_Comm_Settings },
	/* BATTERY */
	{ ITEM_BATTERY_LEVEL, CFG_Battery_Level_Level },
	{ ITEM_BATTERY_TOO_LOW_VOLTAGE, CFG_Battery_Low_Battery_Too_Low_Voltage },
	{ ITEM_BATTERY_LOW_VOLTAGE, CFG_Battery_Low_Battery_Low_Voltage },
	{ ITEM_BATTERY_LOW_VOLTAGE_EX, CFG_Battery_Low_Battery_Low_Voltage_Ex },
	{ ITEM_BATTERY_LOW_PROMPT_INTERVAL_SEC, CFG_Battery_Low_Battery_Low_Prompt_Interval_Sec },

	/* NTC */
    { ITEM_NTC_SETTING, CFG_NTC_Settings_NTC_Settings },
    { ITEM_NTC_RANGES, CFG_NTC_Settings_NTC_Ranges },
	
	/* OTHER - SYS MORE CONFIG */
	{ ITEM_SYS_SETTINGS_SUPPORT_FEATURES, CFG_System_Settings_Support_Features},
};


/*!
 * \brief 加载驱动配置数据文件
 * \n  注: 使用时必须先加载 defcfg.bin, 再加载 usrcfg.bin
 * \n
 * \n  file_name : 配置文件名
 * \return
 *     成功: TRUE
 * \n  失败: FALSE
 */
static bool_t drv_config_load(    const char* file_name)
{
	struct sd_file *file;

    drv_config_file_info_t*   file_info;
    drv_config_file_header_t  hdr;
    int len = sizeof(drv_config_file_header_t);
	int i;

    if ((file = sd_fopen(file_name)) == NULL)
    {
        goto err;
    }

    if (sd_fread(file, &hdr, sizeof(drv_config_file_header_t)) != len)
    {
        goto err;
    }

    if (memcmp(hdr.format, "CFG", 4) != 0 ||
        memcmp(hdr.magic,  "VER", 4) != 0)
    {
        goto err;
    }

    //file_info = app_mem_malloc(sizeof(drv_config_file_info_t));
	for(i=0; i<MAX_DRV_CFG_FILE; i++)
	{
		if(cfg_file_info[i].file == NULL)
		{
			break;
		}
	}
	if(i >= MAX_DRV_CFG_FILE)
		return FALSE;

	file_info = &cfg_file_info[i];

    file_info->num_cfg_items = hdr.num_cfg_items;

	file_info->file = file;

    list_add_tail(&file_info->node, &drv_config_file_list);

	return TRUE;

err:
	return FALSE;
}


/*!
 * \brief 读取驱动配置数据
 * \n  配置数据在读取前会被初始化为默认值 0
 * \n
 * \param cfg_id   : 应用配置 ID
 * \param cfg_data : 保存配置数据
 * \param cfg_offs : 读取配置位置偏移
 * \param cfg_len  : 读取配置数据长度
 * \return
 *     配置数据为默认配置时返回 1
 * \n  配置数据非默认配置时返回 2
 * \n  失败返回 0
 */
static int drv_config_read
(
    uint32_t cfg_id, void* cfg_data, uint32_t cfg_offs, uint32_t cfg_len)
{
    int  ret_val = 0;

    drv_config_file_info_t*  file_info;
    drv_config_item_info_t   cfg_item;

    int  file_offs;
    int  i;

    //OSSchedLock();

    memset(cfg_data, 0, cfg_len);

    /* 顺序读取配置文件,
     * 后面读取的新数据覆盖前面读取的数据
     */
    list_for_each_entry(file_info, &drv_config_file_list, node)
    {
        int  start_pos =
            sizeof(drv_config_file_header_t) +
            file_info->num_cfg_items * sizeof(drv_config_item_info_t);

        int  result = 0;

        file_offs = start_pos;

        for (i = 0; i < file_info->num_cfg_items; i++, file_offs += cfg_item.cfg_len)
        {
            int  offs;
            int  len;

                offs = sizeof(drv_config_file_header_t) +
                    i * sizeof(drv_config_item_info_t);


			sd_fseek(file_info->file, offs, FS_SEEK_SET);

			sd_fread(file_info->file, &cfg_item,  sizeof(drv_config_item_info_t));

            if (cfg_item.cfg_id != cfg_id)
            {
                continue;
            }

            /* 只读取覆盖需要的部分数据
             */
            offs = _MAX(cfg_item.sub_pos, cfg_offs);
            len  = _MIN(cfg_item.sub_pos + cfg_item.cfg_len, cfg_offs + cfg_len) - offs;

            if (len <= 0)
            {
                continue;
            }

            int    pos  = file_offs + (offs - cfg_item.sub_pos);
            void*  data = (u8_t*)cfg_data + (offs - cfg_offs);

			sd_fseek(file_info->file, pos, FS_SEEK_SET);

			sd_fread(file_info->file, data,  len);

            result = 1;
        }

        ret_val += result;
    }

    //OSSchedUnlock();

    return ret_val;
}

/* return:
	0 - 匹配失败
	other - 成功
*/
static uint32_t cfg_key_map(uint32_t item_key)
{
	uint32_t cfg_key = 0;
	int i;

	for(i=0; i<sizeof(cfg_key_map_table)/sizeof(cfg_key_map_t); i++)
	{
		if(cfg_key_map_table[i].item_key_value == item_key)
		{
			cfg_key = cfg_key_map_table[i].cfg_key_value;
		}
	}

	return cfg_key;
}

/*!
 * \brief 读取驱动配置数据
 * \n
 * \param item_key : 各驱动定义的item ID, 见driver_config.h
 * \param data : 保存配置数据
 * \param size : data 大小
 * \return
 *     成功: 读取的数据长度
 * \n  失败: 0
 */
int cfg_get_by_key(uint32_t item_key, void *data, int size)
{
	uint32_t cfg_key;
	int ret;

	cfg_key = cfg_key_map(item_key);
	if(cfg_key == 0)
		return 0;

	if(size < CFG_KEY_LEN(cfg_key))
		return 0;

	ret = drv_config_read(CFG_KEY_ID(cfg_key), data, CFG_KEY_OFFSET(cfg_key), CFG_KEY_LEN(cfg_key));
	if(ret == 0)
	{
		return 0;
	}

	return CFG_KEY_LEN(cfg_key);
}

/*!
 * \brief 驱动配置初始化
 * \n
 * \param : void
 * \return
 *     成功: TRUE
 * \n  失败: FALSE
 */
static int cfg_drv_init(const struct device *dev)
{
	int ret;

	memset(&cfg_file_info, 0, sizeof(cfg_file_info));

    /* 需要先加载默认配置文件
     */
    ret = drv_config_load("defcfg.bin");
	if(ret == FALSE)
		return FALSE;

    /* 然后再加载用户配置文件
     */
    ret = drv_config_load("usrcfg.bin");

	printk("%s init ok.\n", __FUNCTION__);
	return TRUE;
}

/* CFG_DRV定义：依赖sdfs，须在sdfs之后初始化，sdfs的proi为80 */
SYS_INIT(cfg_drv_init, PRE_KERNEL_1, 54);

