/*****************************************************************************
 * file    Core/Src/dev_config.c 
 * author  YuLiang
 * version 1.0.0
 * date    13-Jun-2022
 * brief   This file provides all the device config related operation functions.
 ******************************************************************************
 * Attention
 *
 * <h2><center>&copy; COPYRIGHT(c) 2022 LandPower</center></h2>
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *   1. Redistributions of source code must retain the above copyright notice,
 *      this list of conditions and the following disclaimer.
 *   2. Redistributions in binary form must reproduce the above copyright notice,
 *      this list of conditions and the following disclaimer in the documentation
 *      and/or other materials provided with the distribution.
 *   3. Neither the name of WTOE nor the names of its contributors may be used to 
 *      endorse or promote products derived from this software without specific
 *      prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 ******************************************************************************/

/* Includes ------------------------------------------------------------------*/
#include <string.h>
#include <stdio.h>

#include "main.h"
#include "cmsis_os.h"

#include "common.h"
#include "dev_config.h"
#include "flash_if.h"
#include "flash_log.h"

/* Private define ------------------------------------------------------------*/
#define DEV_FLASH_REPETITION 3      // 多次读取 flash 失败才认为失败.
#define DEV_VIN_ADJ_DEFAULT 5000
#define DEV_WARE_ADJ_DEFAULT 7296

/* Private macro -------------------------------------------------------------*/
#define DEV_IS_VERSION_CHG (strncmp((char*)dev_info.img_compile_time, COMPILE_TIME, DEV_COMPILE_TIME_LEN - 1) != 0)

#define CONFIG_E_RETURN_MUTEX(_f_) \
    do { \
        HAL_StatusTypeDef _rv_ = HAL_ERROR; \
        if ((_rv_ = _f_) != HAL_OK) \
        { \
            ERROR_PRINT(_rv_); \
            _dev_config_mutex_unlock(); \
            return _rv_; \
        } \
    } while(0)
    
/* Private typedef -----------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* 配置信息, 设备信息, 运行状态信息. */
dev_config_t dev_config;
dev_record_t dev_record;
dev_info_t dev_info;
st_date_t st_data;

/* 配置互斥锁. */
static osMutexId_t dev_config_mutex;
static const osMutexAttr_t dev_config_mutex_attr =
{
    .name = "dev_config"
};
/* 备份分区完整性记录标志. */
static uint32_t dev_magic;
static uint32_t dev_magic_bak;

/* Private function prototypes -----------------------------------------------*/
/* 获取互斥锁. */
static void _dev_config_mutex_lock(void)
{
    osMutexAcquire(dev_config_mutex, osWaitForever);
}

/* 释放互斥锁. */
static void _dev_config_mutex_unlock(void)
{
    osMutexRelease(dev_config_mutex);
}

/* 判断分区是否完整. */
static int32_t _dev_config_is_intact(uint32_t magic, uint32_t magic_bak)
{
    if (magic != INIT_DONE_MAGIC || magic_bak != INIT_DONE_MAGIC)
        return FALSE;

    return TRUE;
}

/* 保存配置文件. */
static HAL_StatusTypeDef _dev_config_save(uint32_t addr)
{
    uint8_t i = 0;
    HAL_StatusTypeDef rv = HAL_OK;

    /* 存3次失败才算失败. */
    for(i = 0; i < DEV_FLASH_REPETITION; i++)
    {
        /* 擦除flash,2个扇区8K. */
        rv |= spi_flash_erase(addr, SPI_CMD_SECTOR_ERASE);
        /* 保存配置. */
        rv |= spi_flash_write(addr, (uint8_t*)(&dev_config), sizeof(dev_config));
        if (HAL_OK == rv)
            break;
    }

    vty_print("Save config(%x) %d.\r\n", addr, rv);
    return rv;
}

/* 恢复出厂设置. */
static HAL_StatusTypeDef _dev_config_default_set(void)
{
    HAL_StatusTypeDef rv = HAL_OK;
    uint8_t i = 0;

    memset(&dev_config, 0, sizeof(dev_config_t));
        
    dev_config.magic = INIT_DONE_MAGIC;
    dev_config.magic_bak = INIT_DONE_MAGIC;

    /* 默认密码初始化. */
    snprintf((char*)dev_config.password, DEV_PASSWORD_LEN, "%s", DEV_DEFAULT_PASSWORD);
    for(i = 0; i < CFG_ADC_CH_CNT; i++)
    {
        if (i < 4)
        {
            dev_config.ADC_ratio[i] = 60;
            dev_config.ADC_base_elec[i][0] = 1000;
            dev_config.ADC_base_elec[i][1] = 2000;
            dev_config.ADC_base_elec[i][2] = 5000;
            dev_config.ADC_base_elec[i][3] = 10000;
            dev_config.ADC_base_elec[i][4] = 30000;
            dev_config.ADC_base[i][0] = 76.9;
            dev_config.ADC_base[i][1] = 159.6;
            dev_config.ADC_base[i][2] = 403;
            dev_config.ADC_base[i][3] = 804.5;
            dev_config.ADC_base[i][4] = 2428.3;
            dev_config.ADC_adj[i][0] = 5023;
            dev_config.ADC_adj[i][1] = 4669;
            dev_config.ADC_adj[i][2] = 4759;
            dev_config.ADC_adj[i][3] = 4810;
            dev_config.ADC_adj[i][4] = 4757;
            dev_config.ADC_turns[i] = 20;
        }
        else
        {
            dev_config.ADC_ratio[i] = 200;
            dev_config.ADC_base_elec[i][0] = 1000;
            dev_config.ADC_base_elec[i][1] = 3000;
            dev_config.ADC_base_elec[i][2] = 10000;
            dev_config.ADC_base_elec[i][3] = 30000;
            dev_config.ADC_base_elec[i][4] = 100000;
            dev_config.ADC_base[i][0] = 22.9;
            dev_config.ADC_base[i][1] = 70.9;
            dev_config.ADC_base[i][2] = 241.4;
            dev_config.ADC_base[i][3] = 726.7;
            dev_config.ADC_base[i][4] = 2433.9;
            dev_config.ADC_adj[i][0] = 5066;
            dev_config.ADC_adj[i][1] = 4828;
            dev_config.ADC_adj[i][2] = 4756;
            dev_config.ADC_adj[i][3] = 4774;
            dev_config.ADC_adj[i][4] = 4751;
            dev_config.ADC_turns[i] = 40;
        }
    }

    dev_config.vin_adj = DEV_VIN_ADJ_DEFAULT;
    dev_config.vin = DEV_VIN_ADJ_DEFAULT;
    dev_config.collect_interval = 10;
    dev_config.wave_interval = 12;
    dev_config.wave_adj = DEV_WARE_ADJ_DEFAULT;
    dev_config.main_cable = 5;
    snprintf((char*)dev_config.APN, DEV_APN_LEN, "CMIOT");
    snprintf((char*)dev_config.APN_long, DEV_APN_LEN_LONG, "CMIOT");

    dev_config.csg_beat_interval = 1;
    for(i = 0; i < CSG_CIPHERTEXT_LEN; i++)
    {
        dev_config.csg_ciphertext[i] = i + 0x31;
    }
    snprintf((char*)dev_config.csg_passwd, 8, "1234");

    rv |= _dev_config_save(CONFIG_ADDRESS);
    rv |= _dev_config_save(CONFIG_ADDRESS_BAK);

    vty_print("Config set default %d.\r\n", rv);
    return rv;
}

/* 读取config主份存储区. */
static HAL_StatusTypeDef _dev_config_read(void)
{
    uint8_t i = 0;
    HAL_StatusTypeDef rv = HAL_ERROR;

    memset(&dev_config, 0, sizeof(dev_config_t));

    /* 读取主存储区. */
    for(i = 0; i < DEV_FLASH_REPETITION; i++)
    {
        rv = spi_flash_read(CONFIG_ADDRESS, (uint8_t*)(&dev_config), sizeof(dev_config_t));
        if (HAL_OK == rv)
            break;

        HAL_Delay(5000);
    }

    return rv;
}

/* 读取config备份存储区. */
static HAL_StatusTypeDef _dev_config_read_bak(void)
{
    uint8_t i = 0;
    HAL_StatusTypeDef rv = HAL_ERROR;

    memset(&dev_config, 0, sizeof(dev_config_t));

    /* 读取主存储区. */
    for(i = 0; i < DEV_FLASH_REPETITION; i++)
    {
        rv = spi_flash_read(CONFIG_ADDRESS_BAK, (uint8_t*)(&dev_config), sizeof(dev_config_t));
        if (HAL_OK == rv)
            break;

        HAL_Delay(5000);
    }

    if (HAL_OK == rv)
    {
        dev_magic = dev_config.magic;
        dev_magic_bak = dev_config.magic_bak;
    }

    return rv;
}

/* 配置分区初始化. */
static HAL_StatusTypeDef _dev_config_init(void)
{
    HAL_StatusTypeDef rv = HAL_OK;

    /* 检查结构体大小. */
    if (sizeof(dev_config_t) != DEV_CONFIG_SIZE)
    {
        vty_print("Config size(%d) is not 1K.\r\n", sizeof(dev_config_t));
        while(1)
        {
            HAL_GPIO_TogglePin(LED_RUN_GPIO_Port, LED_RUN_Pin);
            HAL_Delay(50);
        }
    }

    /* 读取主备分区. */
    _dev_config_read_bak();
    _dev_config_read();

    /* 主备存储区都正常,什么都不做. */
    if (_dev_config_is_intact(dev_config.magic, dev_config.magic_bak)
        && _dev_config_is_intact(dev_magic, dev_magic_bak))
    {
        NULL;
    }
    /* 主正常,备不正常,使用主配置覆盖备配置. */
    else if(_dev_config_is_intact(dev_config.magic, dev_config.magic_bak)
        && !(_dev_config_is_intact(dev_magic, dev_magic_bak)))
    {
        rv = _dev_config_save(CONFIG_ADDRESS_BAK);
    }
    /* 主不正常,备正常,使用备配置覆盖主配置. */
    else if(!(_dev_config_is_intact(dev_config.magic, dev_config.magic_bak))
        && _dev_config_is_intact(dev_magic, dev_magic_bak))
    {
        /* 如果读取备失败,恢复出厂配置. */
        if (_dev_config_read_bak() != HAL_OK)
        {
            rv = HAL_ERROR;
            _dev_config_default_set();
        }
        else
            rv = _dev_config_save(CONFIG_ADDRESS);
    }
    /* 其他情况一律视为flash没有被初始化. */
    else
        rv = _dev_config_default_set();
    
    return rv;
}

/* 设置启动信息保存. */
static void _dev_record_reset_set(void)
{
    uint8_t i = 0;

    i = dev_record.reset_index;
    if (i >= DEV_RESET_INFO_NUM)
        i = 0;

    dev_record.reset_info[i].state = dev_record.reset_type;
    dev_record.reset_type = RESET_RESET;
        
    dev_record.reset_index = ++i;
}

/* 保存设备运行状态信息. */
static HAL_StatusTypeDef _dev_record_save(uint32_t addr)
{
    uint8_t i = 0;
    HAL_StatusTypeDef rv = HAL_OK;

    /* 存3次失败才算失败. */
    for(i = 0; i < DEV_FLASH_REPETITION; i++)
    {
        rv = spi_flash_erase(addr, SPI_CMD_SECTOR_ERASE);
        rv = spi_flash_write(addr, (uint8_t*)(&dev_record), sizeof(dev_record));
        if (HAL_OK == rv)
            break;
    }

    vty_print("Save record(%x) %d.\r\n", addr, rv);
    return rv;
}

/* 读取设备运行状态信息. */
static HAL_StatusTypeDef _dev_record_read(void)
{
    uint8_t i = 0;
    HAL_StatusTypeDef rv = HAL_ERROR;

    memset(&dev_record, 0, sizeof(dev_record_t));

    /* 读取主存储区. */
    for(i = 0; i < DEV_FLASH_REPETITION; i++)
    {
        rv = spi_flash_read(RECORD_ADDRESS, (uint8_t*)(&dev_record), sizeof(dev_record_t));
        if (HAL_OK == rv)
            break;

        HAL_Delay(5000);
    }

    return rv;
}

/* 读取设备运行状态信息备份分区. */
static HAL_StatusTypeDef _dev_record_read_bak(void)
{
    uint8_t i = 0;
    HAL_StatusTypeDef rv = HAL_ERROR;

    memset(&dev_record, 0, sizeof(dev_record_t));

    /* 读取主存储区. */
    for(i = 0; i < DEV_FLASH_REPETITION; i++)
    {
        rv = spi_flash_read(RECORD_ADDRESS_BAK, (uint8_t*)(&dev_record), sizeof(dev_record_t));
        if (HAL_OK == rv)
            break;

        HAL_Delay(5000);
    }

    if (HAL_OK == rv)
    {
        dev_magic = dev_record.magic;
        dev_magic_bak = dev_record.magic_bak;
    }

    return rv;
}

/* 恢复出厂设置 */
static HAL_StatusTypeDef _dev_record_default_set(void)
{
    HAL_StatusTypeDef rv = HAL_OK;

    memset(&dev_record, 0, sizeof(dev_record_t));
        
    dev_record.magic = INIT_DONE_MAGIC;
    dev_record.reset_type = RESET_RESET;
    dev_record.magic_bak = INIT_DONE_MAGIC;

    rv |= _dev_record_save(RECORD_ADDRESS);
    rv |= _dev_record_save(RECORD_ADDRESS_BAK);

    vty_print("Record set default %d.\r\n", rv);
    return rv;
}

/* 初始化设备运行状态分区. */
static HAL_StatusTypeDef _dev_record_init(void)
{
    HAL_StatusTypeDef rv = HAL_OK;

    /* 检查结构体大小. */
    if (sizeof(dev_record_t) != DEV_RECORD_SIZE)
    {
        vty_print("Config size is not 512.\r\n");
        while(1)
        {
            HAL_GPIO_TogglePin(LED_RUN_GPIO_Port, LED_RUN_Pin);
            HAL_Delay(50);
        }
    }

    _dev_record_read_bak();
    _dev_record_read();

    /* 主备存储区都正常,什么都不做. */
    if (_dev_config_is_intact(dev_record.magic, dev_record.magic_bak)
        && _dev_config_is_intact(dev_magic, dev_magic_bak))
    {
        NULL;
    }
    /* 主正常,备不正常,使用主配置覆盖备配置. */
    else if(_dev_config_is_intact(dev_record.magic, dev_record.magic_bak)
        && !_dev_config_is_intact(dev_magic, dev_magic_bak))
    {
        rv = _dev_record_save(RECORD_ADDRESS_BAK);
    }
    /* 主不正常,备正常,使用备配置覆盖主配置. */
    else if(!_dev_config_is_intact(dev_record.magic, dev_record.magic_bak)
        && _dev_config_is_intact(dev_magic, dev_magic_bak))
    {
        /* 如果读取备失败,恢复出厂配置. */
        if (_dev_record_read_bak() != HAL_OK)
        {
            rv = HAL_ERROR;
            _dev_record_default_set();
        }
        else
        {
            rv = _dev_record_save(RECORD_ADDRESS);
        }
    }
    /* 其他情况一律视为flash没有被初始化. */
    else
        rv = _dev_record_default_set();

    if (RESET_IAP == dev_record.reset_type)
    {
        _dev_record_reset_set();
        _dev_record_save(RECORD_ADDRESS);
    }
    
    return rv;
}

/* 读取设备信息主份存储区. */
static HAL_StatusTypeDef _dev_info_read(void)
{
    uint8_t i = 0;
    HAL_StatusTypeDef rv = HAL_ERROR;

    /* 读取主存储区. */
    for(i = 0; i < DEV_FLASH_REPETITION; i++)
    {
        rv = spi_flash_read(INFO_ADDRESS, (uint8_t*)(&dev_info), sizeof(dev_info_t));
        if (HAL_OK == rv)
            break;

        HAL_Delay(5000);
    }

    return rv;
}

/* 保存设备信息. */
static HAL_StatusTypeDef _dev_info_save(uint32_t addr)
{
    uint8_t i = 0;
    HAL_StatusTypeDef rv = HAL_OK;

    /* 存3次失败才算失败. */
    for(i = 0; i < DEV_FLASH_REPETITION; i++)
    {
        rv = spi_flash_erase(addr, SPI_CMD_SECTOR_ERASE);
        rv = spi_flash_write(addr, (uint8_t*)(&dev_info), sizeof(dev_info));
        if (HAL_OK == rv)
            break;
    }

    vty_print("Save info(%x) %d.\r\n", addr, rv);
    return rv;
}

/* 设备信息分区初始化. */
static HAL_StatusTypeDef _dev_info_init(void)
{
    HAL_StatusTypeDef rv = HAL_OK;

    rv |= _dev_info_read();

    /* 保存版本信息. */
    if (DEV_IS_VERSION_CHG)
    {
        snprintf((char*)dev_info.img_version, DEV_VERSION_STR_LEN, "V%d.%d.%d.%d", dev_info.type_m, dev_info.type_s,
            VERSION_MAJOR, VERSION_MINOR);
        snprintf((char*)dev_info.img_compile_time, DEV_COMPILE_TIME_LEN, COMPILE_TIME);

        rv |= _dev_info_save(INFO_ADDRESS);
        rv |= _dev_info_save(INFO_ADDRESS_BAK);
    }

    return rv;
}

/* Internal functions --------------------------------------------------------*/
/* Interface functions -------------------------------------------------------*/
void dev_config_init_os(void)
{
    /* 初始化互斥锁. */
    dev_config_mutex = osMutexNew(&dev_config_mutex_attr);
    /* 致命错误,此处不应该被运行,记录错误log,打印错误信息. */
    if (NULL == dev_config_mutex)
        ERROR_PRINT(-1);
}

/* 初始化配置文件. */
void dev_config_init(void)
{
    _dev_config_mutex_lock();

    if (_dev_info_init() != HAL_OK)
        ERROR_PRINT(-1);

    if (_dev_config_init() != HAL_OK)
        ERROR_PRINT(-1);

    if (_dev_record_init() != HAL_OK)
        ERROR_PRINT(-1);
    
    _dev_config_mutex_unlock();
}

/* 设置器件名字. */
void dev_config_host_name_set(const uint8_t *str)
{
    _dev_config_mutex_lock();
    
    snprintf((char*)dev_config.host, DEV_NAME_LEN, "%s", str);

    _dev_config_mutex_unlock();
}

/* 设置进入命令行的密码. */
void dev_config_password_set(const uint8_t *str)
{
    _dev_config_mutex_lock();

    snprintf((char*)dev_config.password, DEV_PASSWORD_LEN, "%s", str);

    _dev_config_mutex_unlock();
}

void dev_config_flag_assgin(uint16_t flag)
{
    _dev_config_mutex_lock();

    dev_config.flag = flag;

    _dev_config_mutex_unlock();
}

void dev_config_flag_set(uint8_t flag_bit)
{
    _dev_config_mutex_lock();

    MONITOR_BITMAP_SET(dev_config.flag, flag_bit);

    _dev_config_mutex_unlock();
}

void dev_config_flag_unset(uint8_t flag_bit)
{
    _dev_config_mutex_lock();

    MONITOR_BITMAP_RESET(dev_config.flag, flag_bit);

    _dev_config_mutex_unlock();
}

void dev_config_collect_interval_set(uint16_t interval)
{
    _dev_config_mutex_lock();

    dev_config.collect_interval = interval;

    _dev_config_mutex_unlock();
}

void dev_config_wave_interval_set(uint16_t interval)
{
    _dev_config_mutex_lock();

    dev_config.wave_interval = interval;

    _dev_config_mutex_unlock();
}

/* 回复出厂配置. */
void dev_config_defaults_set(void)
{
    uint32_t reset_delay = 2;

    _dev_config_mutex_lock();

    /* 配置初始化. */
    _dev_config_default_set();

    flash_log_write(FLASH_LOG_TYPE_INFO, "Config default system reset!\r\n");
    common_sys_set(COM_SYS_RESET, (void*)&reset_delay);

    _dev_config_mutex_unlock();
}

/* 保存配置文件. */
HAL_StatusTypeDef dev_config_save(void)
{
    _dev_config_mutex_lock();
    
    CONFIG_E_RETURN_MUTEX(_dev_config_save(CONFIG_ADDRESS));
    CONFIG_E_RETURN_MUTEX(_dev_config_save(CONFIG_ADDRESS_BAK));

    _dev_config_mutex_unlock();
    return HAL_OK;
}

/* 设置重启位. */
void dev_record_reset_type_set(uint8_t type)
{
    _dev_config_mutex_lock();

    dev_record.reset_type = type;

    _dev_config_mutex_unlock();
}

/* 保存设备文件. */
HAL_StatusTypeDef dev_record_save(void)
{
    _dev_config_mutex_lock();

    CONFIG_E_RETURN_MUTEX(_dev_record_save(RECORD_ADDRESS));
    CONFIG_E_RETURN_MUTEX(_dev_record_save(RECORD_ADDRESS_BAK));

    _dev_config_mutex_unlock();
    return HAL_OK;
}

/* 设置网络信息. */
void dev_info_ip_set(uint8_t *ip, uint8_t *mask, uint8_t *gw)
{
    _dev_config_mutex_lock();

    memcpy(dev_info.ip, ip, 4);
    memcpy(dev_info.ip_mask, mask, 4);
    memcpy(dev_info.ip_gw, gw, 4);

    _dev_config_mutex_unlock();
}

/* 设置server ip. */
void dev_info_server_ip_set(uint8_t *ip)
{
    _dev_config_mutex_lock();

    memcpy(dev_info.server_ip, ip, 4);

    _dev_config_mutex_unlock();
}

/* 设置 device type. */
void dev_info_type_set(uint8_t id_m, uint8_t id_s)
{
    _dev_config_mutex_lock();

    dev_info.type_m = id_m;
    dev_info.type_s = id_s;

    _dev_config_mutex_unlock();
}

/* 设置 mac. */
void dev_info_mac_set(uint8_t *mac)
{
    _dev_config_mutex_lock();

    memcpy(dev_info.mac, mac, 6);

    _dev_config_mutex_unlock();
}

/* 设置 id. */
void dev_info_id_set(uint32_t id)
{
    _dev_config_mutex_lock();

    memcpy(dev_info.id, &id, 4);

    _dev_config_mutex_unlock();
}

/* 无线server ip. */
void dev_info_wireless_server_ip_set(uint8_t *ip)
{
    _dev_config_mutex_lock();

    memcpy(dev_info.wireless_server_ip, ip, 4);

    _dev_config_mutex_unlock();
}

/* 设置整个能力集. */
void dev_info_capability_set(uint8_t *data)
{
    _dev_config_mutex_lock();

    memcpy(dev_info.capability_set, data, DEV_CAPABILITY_LEN);

    _dev_config_mutex_unlock();
}

/* 设置单个能力. */
void dev_info_capability_add(uint8_t cap)
{
    if (cap >= DEV_CAPABILITY_BIT_LEN)
        return;

    _dev_config_mutex_lock();

    bit_list_set(dev_info.capability_set, cap);

    _dev_config_mutex_unlock();
}

/* 删除单个能力. */
void dev_info_capability_del(uint8_t cap)
{
    if (cap >= DEV_CAPABILITY_BIT_LEN)
        return;
    
    _dev_config_mutex_lock();

    bit_list_clr(dev_info.capability_set, cap);

    _dev_config_mutex_unlock();
}

/* 删除整个能力. */
void dev_info_capability_remove(void)
{
    _dev_config_mutex_lock();

    memset(dev_info.capability_set, 0, DEV_CAPABILITY_LEN);

    _dev_config_mutex_unlock();
}

/* 设置固件大小. */
void dev_info_fireware_size_set(uint32_t size)
{
    _dev_config_mutex_lock();

    dev_info.spi_fireware_size = size;

    _dev_config_mutex_unlock();
}

/* 记录升级 ip 和端口, 用于回复升级结果报文. */
void dev_info_update_ip_set(uint8_t *ip, uint16_t port)
{
    _dev_config_mutex_lock();    

    memcpy(dev_info.update_ip_addr, ip, 4);
    dev_info.update_port = port;

    _dev_config_mutex_unlock();
}

/* 设置设备信息标志头 */
void dev_info_magic_set(uint32_t magic)
{
    _dev_config_mutex_lock();    

    dev_info.magic = magic;

    _dev_config_mutex_unlock();
}

/* 保存设备信息. */
HAL_StatusTypeDef dev_info_save(void)
{
    _dev_config_mutex_lock();
    
    CONFIG_E_RETURN_MUTEX(_dev_info_save(INFO_ADDRESS));
    CONFIG_E_RETURN_MUTEX(_dev_info_save(INFO_ADDRESS_BAK));

    _dev_config_mutex_unlock();
    return HAL_OK;
}

/* 打印info信息. */
void dev_info_print(void)
{
    int8_t i = 0;
    uint8_t *addr = (uint8_t*)(&dev_info.update_ip_addr);

    vty_print("\r\nWelcome To Intelligent Monitor Application, By WTOE Embed Application Team.\r\n");
    vty_print("Copyright(c) 2019 WTOE. All rights reserved.\r\n");
    vty_print("Boot version %s, compile time is %s.\r\n", dev_info.boot_version, dev_info.boot_compile_time);
    vty_print("Img version %s, compile time is %s.\r\n\n", dev_info.img_version, dev_info.img_compile_time);

    vty_print("Device type %d:%d.\r\n", dev_info.type_m, dev_info.type_s);
    vty_print("Id: %02x%02x%02x%02x\r\n", dev_info.id[3], dev_info.id[2], dev_info.id[1], dev_info.id[0]);
    vty_print("Mac: %02x:%02x:%02x:%02x:%02x:%02x\r\n", dev_info.mac[0], dev_info.mac[1], dev_info.mac[2], dev_info.mac[3], dev_info.mac[4], dev_info.mac[5]);
    vty_print("Ip: %d.%d.%d.%d\r\n", dev_info.ip[0], dev_info.ip[1], dev_info.ip[2], dev_info.ip[3]);
    vty_print("Mask: %d.%d.%d.%d\r\n", dev_info.ip_mask[0], dev_info.ip_mask[1], dev_info.ip_mask[2], dev_info.ip_mask[3]);
    vty_print("Gw: %d.%d.%d.%d\r\n", dev_info.ip_gw[0], dev_info.ip_gw[1], dev_info.ip_gw[2], dev_info.ip_gw[3]);
    vty_print("Server: %d.%d.%d.%d\r\n", dev_info.server_ip[0], dev_info.server_ip[1], dev_info.server_ip[2], dev_info.server_ip[3]);
    vty_print("Wireless server: %d.%d.%d.%d\r\n", dev_info.wireless_server_ip[0], dev_info.wireless_server_ip[1], dev_info.wireless_server_ip[2], dev_info.wireless_server_ip[3]);
    vty_print("Update: %d.%d.%d.%d:%d\r\n", addr[0], addr[1], addr[2], addr[3], dev_info.update_port);
    vty_print("Capability: ");
    for(i = DEV_CAPABILITY_LEN - 1; i >= 0; i--)
        vty_print("%02x ", dev_info.capability_set[i]);

    vty_print("\r\n\nFireware size: %d | Spi fireware size: %d\r\n", dev_info.fireware_size, dev_info.spi_fireware_size);
    vty_print("Config size: %d | Record size: %d | Info size: %d\r\n\n", sizeof(dev_config_t), sizeof(dev_record_t), sizeof(dev_info_t));
}

/* 打印info信息. */
void dev_csg_print(void)
{
    uint8_t temp[CSG_CIPHERTEXT_LEN + 1] = {0};

    vty_print("Id: %s\r\n", dev_info.csg_id);
    vty_print("Card: %01x%02x%02x%02x%02x%02x\r\n", dev_info.csg_card[0], dev_info.csg_card[1], dev_info.csg_card[2],
        dev_info.csg_card[3], dev_info.csg_card[4], dev_info.csg_card[5]);
    vty_print("Version: %04x\r\n", dev_info.csg_version);

    vty_print("Passwd: %s\r\n", dev_config.csg_passwd);
    vty_print("Beat interval: %dm\r\n", dev_config.csg_beat_interval);
    vty_print("Restart ontime: %d %d:%d\r\n", dev_config.csg_reset_time[0], dev_config.csg_reset_time[1], dev_config.csg_reset_time[2]);
    memcpy(temp, dev_config.csg_ciphertext, CSG_CIPHERTEXT_LEN);
    vty_print("Ciphertext: %s\r\n\n", temp);
}
/******************* (C) COPYRIGHT LandPower ***** END OF FILE ****************/
