/**
  *****************************************************************************
  * @file    sys_config.h
  * @author  Solution Team
  * @version V1.00
  * @date    28-February-2023
  * @brief   System configuration header file
  *****************************************************************************
  * @attention 
  *  Copyright (c) 2017 - 2023 Unicmicro Co., Ltd. 
  *  All Rights Reserved. 
  *****************************************************************************
  */
 
#ifndef __SYS_CONFIG_H_
#define __SYS_CONFIG_H_

#include "arch.h"
#include "types.h"

#pragma pack(1)


#define SYNC_SYMBOL_0               (0x4E)
#define SYNC_SYMBOL_1               (0x52)
#define SYNC_SYMBOL_2               (0x41)
#define SYNC_SYMBOL_3               (0x4D)
#define SYNC_SYMBOL_LEN             (4)

/*************************************/
// System level 
#define SYS_CONFIG_TOTAL_SIZE       (512)
#define SYS_CONFIG_NAME_SIZE        (16)
#define SYS_CONFIG_RESV_SIZE        (8)
#define SYS_CONFIG_IDLE_HOLD_TIME   (20)


typedef enum SYS_DEBUG_LEVEL_e
{
    SYS_DEBUG_LEVEL_OFF,    ///< Debug off
    SYS_DEBUG_LEVEL_1,      ///< Debug on, level 1
    SYS_DEBUG_LEVEL_2,      ///< Debug detail, level 2
    SYS_DEBUG_LEVEL_3,      ///< Debug detail+, level 3
    SYS_DEBUG_LEVEL_4,      ///< Debug interrupt
    SYS_DEBUG_LEVEL_END
} SYS_DEBUG_LEVEL_t;


/** System Configuration definition */
typedef struct SYS_CONFIG_s
{
    u8_t sync[SYNC_SYMBOL_LEN];

    /* System information */
    u32_t flash_loaded:1;   ///< 0: default configuration, 1: configuration load from flash
    u32_t debug:3;          ///< 0: debug off, 1: debug on, 2: debug detail, 3: debug detail+; 4: debug interrupt
    u32_t sleep:1;          ///< 0: disable, 1: enable
    u32_t idle_hold_time:8; ///< IDLE hold time then system go to sleep, unit is second
    u32_t auto_wakeup:16;   ///< Auto wakeup time in sleep mode, unit is millisecond
    u32_t rsvd1:3;         ///< Reserved 

    u8_t rsvd[SYS_CONFIG_RESV_SIZE];

    char sys_name[SYS_CONFIG_NAME_SIZE];

} SYS_CONFIG_t;

#pragma pack()

extern u8_t g_sys_cfg_map[SYS_CONFIG_TOTAL_SIZE];
extern volatile SYS_CONFIG_t *gp_sys_cfg;

/** \name  System Configuration Interfaces
 * \{ 
 */

#define sys_cfg_onchange_hook_declarer(type) \
v_func_ptr_t gp_sys_cfg_##type##_onchange_hook = NULL;

#define sys_cfg_onchange_hook_extern(type) \
extern v_func_ptr_t gp_sys_cfg_##type##_onchange_hook;

sys_cfg_onchange_hook_extern(dbg1);
sys_cfg_onchange_hook_extern(dbg2);
sys_cfg_onchange_hook_extern(dbg3);

#define sys_cfg_onchange_hook_set(type,vfunc) \
    do { \
        gp_sys_cfg_##type##_onchange_hook = vfunc; \
    } while(0)

#define sys_cfg_onchange_hook(type,arg) \
    do { \
        if (NULL != gp_sys_cfg_##type##_onchange_hook) \
        { \
            gp_sys_cfg_##type##_onchange_hook(arg); \
        } \
    } while(0)


extern v_func_v_ptr_t gp_sys_cfg_onsaving_hook;

/** Set system configuration on saving callback   */
#define sys_cfg_onsaving_hook_set(vfunc) \
    do { \
        gp_sys_cfg_onsaving_hook = vfunc; \
    } while(0)

/** Call system configuration on saving callback  */
#define sys_cfg_onsaving_hook() \
    do { \
        if (NULL != gp_sys_cfg_onsaving_hook) \
        { \
            gp_sys_cfg_onsaving_hook(); \
        } \
    } while(0)


/** Get configuration load flag
 *  Return      0: default configuration, 1: configuration load from flash
 */
#define sys_cfg_flash_loaded_get() \
    (gp_sys_cfg->flash_loaded)


/** Enable or disable debugging */
#define sys_cfg_dbg_set(val) \
    do { \
        if (gp_sys_cfg->debug != val) { \
            sys_cfg_onchange_hook(dbg1,val); \
            sys_cfg_onchange_hook(dbg2,val); \
            sys_cfg_onchange_hook(dbg3,val); \
        } \
        gp_sys_cfg->debug = val; \
    } while(0)

/** Get debugging state */
#define sys_cfg_dbg_get() \
    (gp_sys_cfg->debug)


/** Enable or disable sleep mode */
#define sys_cfg_sleep_mode_set(val) \
    do { \
        gp_sys_cfg->sleep = val; \
    } while(0)

/** Get sleep mode */
#define sys_cfg_sleep_mode_get() \
    (gp_sys_cfg->sleep)


/** Set IDLE hold time then system go to sleep, unit is second */
#define sys_cfg_idle_hold_time_set(val) \
    do { \
        gp_sys_cfg->idle_hold_time = val; \
    } while(0)

/** Get IDLE hold time then system go to sleep, unit is second */
#define sys_cfg_idle_hold_time_get() \
    (gp_sys_cfg->idle_hold_time)


/** Set auto wakeup time value, unit is millisecond */
#define sys_cfg_auto_wakeup_set(val) \
    do { \
        gp_sys_cfg->auto_wakeup = val; \
    } while(0)

/** Get auto_wakeup time value, unit is millisecond */
#define sys_cfg_auto_wakeup_get() \
    (gp_sys_cfg->auto_wakeup)


/** Set system name string  */
void sys_cfg_sys_name_set(const char *p_val, int len);

/** Get system name string  */
#define sys_cfg_sys_name_get() \
    (&(gp_sys_cfg->sys_name[0]))

/** Check if system name string is NULL  */
#define sys_cfg_sys_name_is_null() \
    ('\0' == gp_sys_cfg->sys_name[0])


/** \}*/


void sys_cfg_init(void);
void sys_cfg_load(void);
void sys_cfg_save(void);
void sys_cfg_erase(void);


#endif /* #ifndef __SYS_CONFIG_H_ */

