/******************************************************************************
 * file    Core/Src/RS485_debug.c 
 * author  YuLiang
 * version 1.0.0
 * date    17-Jun-2022
 * brief   This file provides all the RS485 debug 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 "stdio.h"
#include "string.h"

#include "usart.h"

#include "common.h"
#include "dev_config.h"
#include "RS485_debug.h"
#include "ADC_collect.h"
#include "wireless.h"
#include "flash_if.h"
#include "RS485_sensor.h"
#include "recording_wave.h"
#include "flash_log.h"
#include "position.h"

/* Private define ------------------------------------------------------------*/
#define DEBUG_FLASH_BUF_SIZE DEBUG_DATA_SIZE

/* Private typedef -----------------------------------------------------------*/
/* RS485调试通讯协议器件信息. */
typedef struct
{
    /* 设备信息. 36byte */
    uint8_t type_m;
    uint8_t type_s;
    uint8_t mac[6];
    uint32_t id;
    uint8_t ip[4];
    uint8_t ip_mask[4];
    uint8_t ip_gw[4];
    uint8_t server_ip[4];
    uint8_t wireless_server_ip[4];
    uint16_t server_port;
    uint16_t wireless_server_port;
    /* 版本信息. 224byte */
    uint8_t boot_version[DEV_VERSION_STR_LEN];
    uint8_t boot_compile_time[DEV_COMPILE_TIME_LEN];
    uint8_t img_version[DEV_VERSION_STR_LEN];
    uint8_t img_compile_time[DEV_COMPILE_TIME_LEN];
    uint8_t hardware_version[DEV_VERSION_STR_LEN];
    uint8_t FPGA_version[DEV_VERSION_STR_LEN];
    uint8_t factory_time[DEV_COMPILE_TIME_LEN];
    /* 设备其他信息. 128byte */
    uint8_t name[DEV_NAME_LEN];
    uint8_t csg_id[8];
    uint16_t csg_version;
    uint8_t csg_card[6];
} debug_info_t;

/* RS485 调试通讯协议配置信息. */
typedef struct
{
    uint16_t flag;
    uint8_t energy_mode;
    uint8_t is_voltage_col;
    uint8_t sensor_id[SENSOR_SUM];
    uint16_t collect_interval;
    uint16_t wave_interval;
    uint16_t collect_threshold;
    uint16_t wave_threshold;
    uint8_t main_cable;
    uint8_t normal_sleep;
    uint8_t is_temp_col;
    uint8_t is_wave_col;
    uint8_t APN[DEV_APN_LEN];
    uint8_t APN_long[DEV_APN_LEN_LONG];
} debug_config_t;

/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* 收法报文 buffer. */
usart_buf_t debug_buf;
/* RS485 通讯串口. */
static UART_HandleTypeDef *debug_uart = &huart4;
/* 自动校准仪器通讯串口. */
static UART_HandleTypeDef *debug_adj_uart = &huart1;
/* 判断收包是否开始, 用于处理粘包. */
static uint8_t debug_state = 0;
/* 远程升级 flash 数据校验使用. */
static uint8_t debug_flash[DEBUG_FLASH_BUF_SIZE];

/* Private function prototypes -----------------------------------------------*/
/* Internal functions --------------------------------------------------------*/
/* 报文头校验. */
static int32_t _debug_pkt_check(void)
{
    proto_head_t *head = (proto_head_t*)debug_buf.buf;

    /* 设备进入复位状态后不再处理报文. */
    if (IS_MONITOR_BIT_SET(system_init_flag, SYS_INIT_RESET))
    {
        vty_print("@0\r\n");
        return HAL_ERROR;
    }

    /* 对主次设备号进行识别, 次设备号可以是广播. */
    if (head->dev_type_m != dev_info.type_m)
    {
        vty_print("@1\r\n");
        return HAL_ERROR;
    }

    /* 对设备 id 进行识别, 可以是广播. */
    //if (head->dev_id != (*(uint32_t*)dev_info.id) && head->dev_id != 0xFFFFFFFF)
    //{
    //    vty_print("@2\r\n");
    //    return HAL_ERROR;
    //}

    /* 验证 CRC32. */
    if (crc32(debug_buf.buf, head->len) != (*(uint32_t*)(debug_buf.buf + head->len)))
    {
        vty_print("@3: %x %x\r\n", crc32(debug_buf.buf, head->len), *(uint32_t*)(debug_buf.buf + head->len));
        return HAL_ERROR;
    }

    return HAL_OK;
}

/* 封装报文头. */
void _debug_pkt_head_init(uint16_t len, uint8_t cmdType)
{
    proto_head_t *head = (proto_head_t*)debug_buf.buf;

    /* 封装报文头. */
    head->len = len;
    head->dev_type_m = dev_info.type_m;
    head->dev_type_s= dev_info.type_s;
    head->dev_id = *(uint32_t*)dev_info.id;
    head->cmd_type = cmdType;
}

/* 发送数据.. */
void _debug_pkt_send(uint16_t len, uint8_t debug_len)
{
    /* 发送报文 */
    HAL_GPIO_WritePin(RS485_DBG_EN_GPIO_Port, RS485_DBG_EN_Pin, GPIO_PIN_SET);
    HAL_UART_Transmit_DMA(debug_uart, debug_buf.buf, len);
    /* 调试打印. */
    DBG(DBG_M_RS485_DEBUG, "Send(%d):\r\n", len);
    if (dbg_stat_get(DBG_M_RS485_DEBUG))
    {
        buf_print(debug_buf.buf, debug_len);
    }
}

/* 设备信息获取报文处理 */
static void _debug_pkt_info_get(void)
{
    proto_head_t *head = (proto_head_t*)debug_buf.buf;
    debug_info_t *data = (debug_info_t*)(debug_buf.buf + sizeof(proto_head_t));
    uint32_t *crc = NULL;

    /* 封装报文头. */
    _debug_pkt_head_init(sizeof(proto_head_t) + sizeof(debug_info_t), DEBUG_CT_REPLY);

    /* 封装数据. */
    memcpy(data, &dev_info.type_m, sizeof(debug_info_t) - DEV_NAME_LEN);
    memcpy(data->name, dev_config.host, DEV_NAME_LEN);
    snprintf((char*)data->csg_id, 8, "%s", dev_info.csg_id);
    data->csg_version = dev_info.csg_version;
    memcpy(data->csg_card, dev_info.csg_card, 6);

    /* 计算校验和. */
    crc = (uint32_t*)(debug_buf.buf + head->len);
    *crc = crc32(debug_buf.buf, head->len);

    /* 发送报文 */
    _debug_pkt_send(head->len + 4, 20);
    
    return;
}

/* 配置设备信息. */
static void _debug_pkt_info_set(void)
{
    proto_head_t *head = (proto_head_t*)debug_buf.buf;
    debug_info_t *data = (debug_info_t*)(debug_buf.buf + sizeof(proto_head_t));
    uint32_t *crc = NULL;

    /* 保存数据. */
    memcpy(&dev_info.type_m, data, 260);
    memcpy(dev_config.host, data->name, DEV_NAME_LEN);
    snprintf((char*)dev_info.csg_id, 8, "%s", data->csg_id);
    dev_info.csg_version = data->csg_version;
    memcpy(dev_info.csg_card, data->csg_card, 6);

    /* 封装报文头. */
    _debug_pkt_head_init(sizeof(proto_head_t), DEBUG_CT_REPLY);

    /* 计算校验和. */
    crc = (uint32_t*)(debug_buf.buf + head->len);
    *crc = crc32(debug_buf.buf, head->len);

    /* 发送报文 */
    _debug_pkt_send(head->len + 4, 20);

    /* 保存配置. */
    common_sys_set(COM_SYS_SAVE_INFO, 0);
    common_sys_set(COM_SYS_SAVE_CONFIG, 0);
    
    return;
}

/* 设备复位. */
static void _debug_pkt_reset(void)
{
    proto_head_t *head = (proto_head_t*)debug_buf.buf;
    uint32_t *crc = NULL;
    uint32_t reset_delay = 2;

    /* 封装报文头. */
    _debug_pkt_head_init(sizeof(proto_head_t), DEBUG_CT_REPLY);

    /* 计算校验和. */
    crc = (uint32_t*)(debug_buf.buf + head->len);
    *crc = crc32(debug_buf.buf, head->len);

    /* 发送报文 */
    _debug_pkt_send(head->len + 4, 20);

    /* 设备重启, 这里延迟 2s 保证回复报文能发出. */
    flash_log_write(FLASH_LOG_TYPE_INFO, "Debug system reset!\r\n");
    common_sys_set(COM_SYS_RESET, (void*)&reset_delay);
    
    return;
}

/* 设备恢复默认配置. */
static void _debug_pkt_default(void)
{
    proto_head_t *head = (proto_head_t*)debug_buf.buf;
    uint32_t *crc = NULL;

    /* 封装报文头. */
    _debug_pkt_head_init(sizeof(proto_head_t), DEBUG_CT_REPLY);

    /* 计算校验和. */
    crc = (uint32_t*)(debug_buf.buf + head->len);
    *crc = crc32(debug_buf.buf, head->len);

    /* 发送报文 */
    _debug_pkt_send(head->len + 4, 20);

    /* 恢复默认配置. */
    dev_config_defaults_set();
    
    return;
}

/* 擦除内部 IAP, 并升级 IAP. */
static int32_t _debug_updata_iap(void)
{
    uint32_t spi_flash_address = TFTP_IAP_ADDRESS;
    uint32_t flash_write_address = IAP_ADDRESS;
    uint32_t fireware_size = SPI_FLASH_BLOCK_SIZE;
    uint16_t write_size = 0;
    uint16_t write_flash_size = 0;

    vty_print("\r\nEntry updata.\r\n");

    /* 擦除内部flash. */
    if (FLASH_If_Erase() != HAL_OK)
        goto UPDATA_ERROR;

    /* 循环写入内部flash. */
    while(fireware_size > 0)
    {
        /* 计算每次写入的数据大小. */
        if (fireware_size > DEBUG_FLASH_BUF_SIZE)
            write_size = DEBUG_FLASH_BUF_SIZE;
        else
            write_size = fireware_size;

        /* 从spi flash复制到内部flash. */
        if (spi_flash_read(spi_flash_address, debug_flash, write_size) != HAL_OK)
            goto UPDATA_ERROR;

        /* 因为内部flash是4byte写的,如果img不是4byte对齐的可能最后几个字节写漏了,这里保证最后几个字节可以写入. */
        write_flash_size = write_size / 4;
        if (write_size % 4 != 0)
            write_flash_size++;
        
        if (FLASH_If_Write(flash_write_address, (uint32_t*)(debug_flash), write_flash_size) != HAL_OK)
            goto UPDATA_ERROR;

        /* 重新计算flash地址和剩余数据大小. */
        spi_flash_address += write_size;
        flash_write_address += write_size;
        fireware_size -= write_size;
    }

    /* 打印升级信息. */
    vty_print(" Programming completed.\r\n");
    return HAL_OK;

UPDATA_ERROR:
    vty_print(" Programming failure!\n\r");
    return HAL_ERROR;
}

/* 将 APP 烧写到 SPI FLASH, 真正升级动作是在 IAP 中完成. */
static void _debug_pkt_update_app(void)
{
    proto_head_t *head = (proto_head_t*)debug_buf.buf;
    mul_head_t *m_head = (mul_head_t*)(debug_buf.buf + sizeof(proto_head_t));
    uint8_t *data = (uint8_t*)(debug_buf.buf + sizeof(proto_head_t) + sizeof(mul_head_t));
    uint32_t addr = TFTP_APP_ADDRESS;
    uint32_t *crc = NULL;

    /* index 为 0 表示是首保, 需要擦除 FLASH. */
    if (0 == m_head->index)
    {
        while(addr != TFTP_APP_ADDRESS_END)
        {
            if (spi_flash_erase(addr, SPI_CMD_BLOCK64_ERASE) != HAL_OK)
            {
                return;
            }
            
            addr += SPI_FLASH_BLOCK64_SIZE;
        }
    }
    
    /* 计算写 FLASH 地址, 并写入 FLASH. */
    addr = TFTP_APP_ADDRESS + m_head->index * DEBUG_FLASH_BUF_SIZE;
    if (addr >= TFTP_APP_ADDRESS_END)
    {
        return;
    }
    if (m_head->len > 0)
    {
        if (spi_flash_write(addr, data, m_head->len) != HAL_OK)
        {
            return;
        }
    }

    /* 长度小于 DEBUG_FLASH_BUF_SIZE 则认为是最后一包. */
    if(m_head->len < DEBUG_FLASH_BUF_SIZE)
    {
        /* 校验数据. */
        if (debug_app_check(TFTP_APP_ADDRESS, addr - TFTP_APP_ADDRESS + m_head->len, 2) != HAL_OK)
        {
            return;
        }

        /* 保存信息并重启设备进入 IAP 升级 APP. */
        dev_info_fireware_size_set(addr - TFTP_APP_ADDRESS + m_head->len);
        dev_info_magic_set(UPDATE_MAGIC);
        common_sys_set(COM_SYS_SAVE_INFO, 0);
        addr = 2;
        flash_log_write(FLASH_LOG_TYPE_INFO, "Update APP system reset!\r\n");
        common_sys_set(COM_SYS_RESET, (void*)&addr);
    }

    /* 封装报文头. */
    _debug_pkt_head_init(sizeof(proto_head_t) + sizeof(mul_head_t), DEBUG_CT_REPLY);

    /* 计算校验和. */
    crc = (uint32_t*)(debug_buf.buf + head->len);
    *crc = crc32(debug_buf.buf, head->len);

    /* 发送报文 */
    _debug_pkt_send(head->len + 4, 28);
    
    return;
}

/* 升级 IAP 报文处理. */
static void _debug_pkt_update_iap(void)
{
    proto_head_t *head = (proto_head_t*)debug_buf.buf;
    mul_head_t *m_head = (mul_head_t*)(debug_buf.buf + sizeof(proto_head_t));
    uint8_t *data = (uint8_t*)(debug_buf.buf + sizeof(proto_head_t) + sizeof(mul_head_t));
    uint32_t addr = TFTP_IAP_ADDRESS;
    uint32_t *crc = NULL;

    /* index 为 0 表示是首保, 需要擦除 FLASH. */
    if (0 == m_head->index)
    {
        while(addr != TFTP_IAP_ADDRESS_END)
        {
            if (spi_flash_erase(addr, SPI_CMD_BLOCK32_ERASE) != HAL_OK)
            {
                vty_print("*1*\r\n");
                return;
            }
            
            addr += SPI_FLASH_BLOCK_SIZE;
        }
    }

    /* 计算写 FLASH 地址, 并写入 FLASH. */
    addr = TFTP_IAP_ADDRESS + m_head->index * DEBUG_FLASH_BUF_SIZE;
    if (addr >= TFTP_IAP_ADDRESS_END)
    {
        return;
    }
    if (m_head->len > 0)
    {
        if (spi_flash_write(addr, data, m_head->len) != HAL_OK)
        {
            vty_print("*1*\r\n");
            return;
        }
    }

    /* 长度小于 DEBUG_FLASH_BUF_SIZE 则认为是最后一包. */
    if(m_head->len < DEBUG_FLASH_BUF_SIZE)
    {
        /* 校验报文. */
        if (debug_app_check(TFTP_IAP_ADDRESS, addr - TFTP_IAP_ADDRESS + m_head->len, 1) != HAL_OK)
        {
            return;
        }

        /* 升级 IAP. */
        if (_debug_updata_iap() != HAL_OK)
        {
            return;
        }
    }

    /* 封装报文头. */
    _debug_pkt_head_init(sizeof(proto_head_t) + sizeof(mul_head_t), DEBUG_CT_REPLY);

    /* 计算校验和. */
    crc = (uint32_t*)(debug_buf.buf + head->len);
    *crc = crc32(debug_buf.buf, head->len);

    /* 发送报文 */
    _debug_pkt_send(head->len + 4, 28);
    
    return;
}

/* 修改配置报文处理. */
static void _debug_pkt_config_get(void)
{
    proto_head_t *head = (proto_head_t*)debug_buf.buf;
    debug_config_t *data = (debug_config_t*)(debug_buf.buf + sizeof(proto_head_t));
    uint32_t *crc = NULL;
    uint8_t i = 0;

    /* 封装报文头. */
    _debug_pkt_head_init(sizeof(proto_head_t) + sizeof(debug_config_t), DEBUG_CT_REPLY);

    /* 封装数据. */
    data->flag = dev_config.flag;
    data->energy_mode = dev_config.energy_mode;
    for(i = 0; i < SENSOR_SUM; i++)
    {
        data->sensor_id[i] = dev_config.sensor_id[i];
    }
    data->collect_interval = dev_config.collect_interval;
    data->wave_interval = dev_config.wave_interval;
    data->collect_threshold = dev_config.threshold;
    data->wave_threshold = dev_config.wave_threshold;
    data->main_cable = dev_config.main_cable;
    data->normal_sleep = dev_config.normal_sleep;
    memcpy(data->APN, dev_config.APN, DEV_APN_LEN);
    memcpy(data->APN_long, dev_config.APN_long, DEV_APN_LEN_LONG);
    data->is_voltage_col = dev_config.is_voltage_col;
    data->is_temp_col = dev_config.is_temp_col;
    data->is_wave_col = dev_config.is_wave_col;

    /* 计算校验和. */
    crc = (uint32_t*)(debug_buf.buf + head->len);
    *crc = crc32(debug_buf.buf, head->len);

    /* 发送报文 */
    _debug_pkt_send(head->len + 4, 20);
    
    return;
}

/* 修改配置报文处理. */
static void _debug_pkt_config_set(void)
{
    proto_head_t *head = (proto_head_t*)debug_buf.buf;
    debug_config_t *data = (debug_config_t*)(debug_buf.buf + sizeof(proto_head_t));
    uint8_t is_reboot = FALSE;
    uint32_t reset_delay = 2;
    uint32_t *crc = NULL;
    uint8_t i = 0;

    /* 保存数据. */
    if (dev_config.flag != data->flag)
    {
        is_reboot = TRUE;
        dev_config_flag_assgin(data->flag);
    }

    dev_config.energy_mode = data->energy_mode;
    for(i = 0; i < SENSOR_SUM; i++)
    {
        dev_config.sensor_id[i] = data->sensor_id[i];
    }
    dev_config.collect_interval = data->collect_interval;
    dev_config.wave_interval = data->wave_interval;
    dev_config.threshold = data->collect_threshold;
    dev_config.wave_threshold = data->wave_threshold;
    dev_config.main_cable = data->main_cable;
    dev_config.normal_sleep = data->normal_sleep;
    memcpy(dev_config.APN, data->APN, DEV_APN_LEN);
    memcpy(dev_config.APN_long, data->APN_long, DEV_APN_LEN_LONG);
    dev_config.is_voltage_col = data->is_voltage_col;
    dev_config.is_temp_col = data->is_temp_col;
    dev_config.is_wave_col = data->is_wave_col;
    position_ctrl.cfg = TRUE;

    /* 封装报文头. */
    _debug_pkt_head_init(sizeof(proto_head_t), DEBUG_CT_REPLY);

    /* 计算校验和. */
    crc = (uint32_t*)(debug_buf.buf + head->len);
    *crc = crc32(debug_buf.buf, head->len);

    /* 发送报文 */
    _debug_pkt_send(head->len + 4, 20);

    /* 保存配置. */
    common_sys_set(COM_SYS_SAVE_CONFIG, 0);
    if (is_reboot)
    {
        /* 设备重启, 这里延迟 2s 保证回复报文能发出. */
        flash_log_write(FLASH_LOG_TYPE_INFO, "Debug config change system reset!\r\n");
        common_sys_set(COM_SYS_RESET, (void*)&reset_delay);
    }
    
    return;
}


/* 校准参数获取报文处理. */
static void _debug_pkt_adj_get(void)
{
    proto_head_t *head = (proto_head_t*)debug_buf.buf;
    dev_adj_t *data = (dev_adj_t*)(debug_buf.buf + sizeof(proto_head_t));
    uint32_t *crc = NULL;

    /* 封装报文头. */
    _debug_pkt_head_init(sizeof(proto_head_t) + sizeof(dev_adj_t), DEBUG_CT_PRV_REPLY);

    /* 封装数据, 这里减 4 是因为结构体最后 4byte 位置特殊. */
    memcpy(data->ADCRatio, dev_config.ADC_ratio, sizeof(dev_config.ADC_ratio));
    memcpy(data->ADCBase_elec, dev_config.ADC_base_elec, sizeof(dev_config.ADC_base_elec));
    memcpy(data->ADCAdj, dev_config.ADC_adj, sizeof(dev_config.ADC_adj));
    memcpy(data->ADCBase, dev_config.ADC_base, sizeof(dev_config.ADC_base));
    data->vin = dev_config.vin;
    data->vin_adj = dev_config.vin_adj;
    memcpy(data->ADC_turns, dev_config.ADC_turns, CFG_ADC_CH_CNT);

    /* 计算校验和. */
    crc = (uint32_t*)(debug_buf.buf + head->len);
    *crc = crc32(debug_buf.buf, head->len);

    /* 发送报文 */
    _debug_pkt_send(head->len + 4, 20);
    
    return;
}

/* 校准参数设置报文处理. */
static void _debug_pkt_adj_set(void)
{
    proto_head_t *head = (proto_head_t*)debug_buf.buf;
    dev_adj_t *data = (dev_adj_t*)(debug_buf.buf + sizeof(proto_head_t));
    uint32_t *crc = NULL;

    /* 配置参数. */
    memcpy(dev_config.ADC_ratio, data->ADCRatio, sizeof(dev_config.ADC_ratio));
    memcpy(dev_config.ADC_base_elec, data->ADCBase_elec, sizeof(dev_config.ADC_base_elec));
    memcpy(dev_config.ADC_adj, data->ADCAdj, sizeof(dev_config.ADC_adj));
    memcpy(dev_config.ADC_base, data->ADCBase, sizeof(dev_config.ADC_base));
    dev_config.vin = data->vin;
    dev_config.vin_adj = data->vin_adj;
    memcpy(dev_config.ADC_turns, data->ADC_turns, CFG_ADC_CH_CNT);

    /* 封装报文头. */
    _debug_pkt_head_init(sizeof(proto_head_t), DEBUG_CT_PRV_REPLY);

    /* 计算校验和. */
    crc = (uint32_t*)(debug_buf.buf + head->len);
    *crc = crc32(debug_buf.buf, head->len);

    /* 发送报文 */
    _debug_pkt_send(head->len + 4, 20);

    /* 保存参数. */
    common_sys_set(COM_SYS_SAVE_CONFIG, 0);
    
    return;
}

/* 自动校准仪器通讯校验和计算. */
static uint8_t _debug_adj_checksum(uint8_t *buf, uint8_t len)
{
    uint8_t sum = 0;
    uint8_t i = 0;

    for(i = 0; i < len; i++)
    {
        sum ^= buf[i];
    }

    return sum;
}

/* 自动校准仪器电压电流报文填充. */
static void _debug_adj_source_set_buf(uint32_t voltage, uint32_t electricity)
{
    debug_adj_head_t *head = (debug_adj_head_t*)&debug_flash[1];
    uint8_t *buf = debug_flash + sizeof(debug_adj_head_t) + 1;
    debug_adj_num_t *data = NULL;

    /* 填充报文. */
    memset(debug_flash, 0, 0x49);
    debug_flash[0] = 0x81;
    head->id_recv = 1;
    head->id_send = 7;
    head->len = 0x49;
    head->cmd = 0xA3;

    *buf = 0x05; buf++;
    *buf = 0x46; buf++;
    *buf = 0x3F; buf++;
    buf += 24;
    *buf = 0xFF; buf++;

    buf += 10;
    data = (debug_adj_num_t*)buf;
    data->data = voltage;
    data->index = -4;
    buf += 5;

    buf += 10;
    data = (debug_adj_num_t*)buf;
    data->data = electricity;
    data->index = -3;
    buf += 5;

    data = (debug_adj_num_t*)buf;
    data->data = 500000;
    data->index = 7;
    buf += 5;

    *buf = 0x07; buf++;
    *buf = 0x3F; buf++;
    *buf = 0x3F; buf++;
    buf++;

    /* 计算校验和. */
    *buf = _debug_adj_checksum((uint8_t*)head, head->len - 2);
}

/* 自动校准仪器电压电流设置. */
static HAL_StatusTypeDef _debug_adj_source_set(uint8_t ch_bitmap, uint8_t index)
{
    debug_adj_head_t *head = (debug_adj_head_t*)&debug_flash[1];
    uint8_t ch = 0;
    uint8_t turn_num = 10;

    /* 以第一个校准通道的校准点为准. */
    for(ch = 0; ch < CFG_ADC_CH_CNT; ch++)
    {
        if (IS_MONITOR_BIT_SET(ch_bitmap, ch))
        {
            break;
        }
    }
    /* 没有通道被选择直接退出. */
    if (CFG_ADC_CH_CNT == ch)
    {
        return HAL_OK;
    }

    turn_num = dev_config.ADC_turns[ch];
    if (0 == turn_num)
    {
        turn_num = 20;
    }

    /* 填充 buf, 设置电流电压. */
    _debug_adj_source_set_buf(2200000, dev_config.ADC_base_elec[ch][index] / turn_num);

    /* 发送报文. */
    DBG(DBG_M_RS485_SEN, "ADJS(%d):\r\n", head->len);
    if (dbg_stat_get(DBG_M_RS485_SEN))
    {
        buf_print(debug_flash, head->len);
    }
    HAL_GPIO_WritePin(RS485_A_DE_GPIO_Port, RS485_A_DE_Pin, GPIO_PIN_SET);
    HAL_E_RETURN(HAL_UART_Transmit(debug_adj_uart, debug_flash, head->len, 300));
    HAL_GPIO_WritePin(RS485_A_DE_GPIO_Port, RS485_A_DE_Pin, GPIO_PIN_RESET);

    /* 接收报文. */
    HAL_UART_Abort(debug_adj_uart);
    HAL_E_RETURN(HAL_UART_Receive(debug_adj_uart, debug_flash, 0x6, 300));
    DBG(DBG_M_RS485_SEN, "ADJS(%d):\r\n", 0x6);
    if (dbg_stat_get(DBG_M_RS485_SEN))
    {
        buf_print(debug_flash, 0x6);
    }

    /* 判断返回值. */
    if (head->cmd != 0x30)
    {
        return HAL_ERROR;
    }

    /* 等待电压电流稳定. */
    osDelay(4000);
    return HAL_OK;
}

/* 自动校准仪器连接. */
static HAL_StatusTypeDef _debug_adj_connect(void)
{
    debug_adj_head_t *head = (debug_adj_head_t*)&debug_flash[1];
    uint8_t *crc = debug_flash + sizeof(debug_adj_head_t) + 1;

    /* 填充报文. */
    debug_flash[0] = 0x81;
    head->id_recv = 1;
    head->id_send = 7;
    head->len = 6;
    head->cmd = 0xc9;
    *crc = _debug_adj_checksum((uint8_t*)head, head->len - 2);

    /* 发送报文. */
    DBG(DBG_M_RS485_SEN, "ADJS(%d):\r\n", head->len);
    if (dbg_stat_get(DBG_M_RS485_SEN))
    {
        buf_print(debug_flash, head->len);
    }

    HAL_GPIO_WritePin(RS485_A_DE_GPIO_Port, RS485_A_DE_Pin, GPIO_PIN_SET);
    HAL_E_RETURN(HAL_UART_Transmit(debug_adj_uart, debug_flash, head->len, 300));
    HAL_GPIO_WritePin(RS485_A_DE_GPIO_Port, RS485_A_DE_Pin, GPIO_PIN_RESET);

    /* 接收报文. */
    HAL_UART_Abort(debug_adj_uart);
    HAL_E_RETURN(HAL_UART_Receive(debug_adj_uart, debug_flash, 0x29, 300));
    DBG(DBG_M_RS485_SEN, "ADJS(%d):\r\n", 0x29);
    if (dbg_stat_get(DBG_M_RS485_SEN))
    {
        buf_print(debug_flash, 0x29);
    }

    /* 判断返回值. */
    if (head->cmd != 0x39)
    {
        return HAL_ERROR;
    }

    return HAL_OK;
}

/* 自动校准仪器输出关闭. */
static HAL_StatusTypeDef _debug_adj_close(void)
{
    debug_adj_head_t *head = (debug_adj_head_t*)&debug_flash[1];

    /* 装填报文. */
    _debug_adj_source_set_buf(0, 0);

    /* 发送报文. */
    DBG(DBG_M_RS485_SEN, "ADJS(%d):\r\n", head->len);
    if (dbg_stat_get(DBG_M_RS485_SEN))
    {
        buf_print(debug_flash, head->len);
    }
    HAL_GPIO_WritePin(RS485_A_DE_GPIO_Port, RS485_A_DE_Pin, GPIO_PIN_SET);
    HAL_E_RETURN(HAL_UART_Transmit(debug_adj_uart, debug_flash, head->len, 300));
    HAL_GPIO_WritePin(RS485_A_DE_GPIO_Port, RS485_A_DE_Pin, GPIO_PIN_RESET);

    /* 接收报文. */
    HAL_UART_Abort(debug_adj_uart);
    HAL_E_RETURN(HAL_UART_Receive(debug_adj_uart, debug_flash, 0x6, 300));
    DBG(DBG_M_RS485_SEN, "ADJS(%d):\r\n", 0x6);
    if (dbg_stat_get(DBG_M_RS485_SEN))
    {
        buf_print(debug_flash, 0x6);
    }

    /* 判断返回值. */
    if (head->cmd != 0x30)
    {
        return HAL_ERROR;
    }

    return HAL_OK;
}

/* 自动校准开始设置 */
static HAL_StatusTypeDef _debug_adj_start(void)
{
    MONITOR_BITMAP_SET(system_init_flag, SYS_INIT_ADJ);
    HAL_UART_Abort(debug_adj_uart);
    HAL_GPIO_WritePin(SENSOR_EN_GPIO_Port, SENSOR_EN_Pin, GPIO_PIN_SET);
    osDelay(1000);
    HAL_E_RETURN(_debug_adj_connect());

    return HAL_OK;
}

/* 自动校准处理. */
static HAL_StatusTypeDef _debug_adj_auto(uint8_t bitmap)
{
    uint8_t i = 0;
    uint8_t j = 0;
    uint8_t bitmap_new = 0;

    if (!bitmap)
    {
        return HAL_OK;
    }

    /* 设置开始操作. */
    HAL_E_RETURN(_debug_adj_start());

    for(i = 0; i < CFG_ADC_CH_CNT; i++)
    {
        /* 过滤不需要的通道. */
        if (!IS_MONITOR_BIT_SET(bitmap, i) || 0 == dev_config.ADC_ratio[i])
        {
            continue;
        }

        /* 将变比相同的通道归到同一个 bitmap 中. */
        bitmap_new = 0;
        for (j = i; j < CFG_ADC_CH_CNT; j++)
        {
            if (!IS_MONITOR_BIT_SET(bitmap, j)
                || dev_config.ADC_ratio[i] != dev_config.ADC_ratio[j])
            {
                continue;
            }

            MONITOR_BITMAP_RESET(bitmap, j);
            MONITOR_BITMAP_SET(bitmap_new, j);
        }

        /* 开始自动校准, 注意不同变比的通道不能一起校准. */
        for (j = 0; j < CFG_ADC_ADJ_CNT; j++)
        {
            HAL_E_RETURN(_debug_adj_source_set(bitmap_new, j));
            HAL_E_RETURN(ADC_base_auto(bitmap_new, j + 1));
        }        
    }

    /* 关闭校准. */
    HAL_E_RETURN(_debug_adj_close());

    return HAL_OK;
}

/* 自动校准报文处理. */
static void _debug_pkt_adj_auto(void)
{
    proto_head_t *head = (proto_head_t*)debug_buf.buf;
    debug_adj_set *data = (debug_adj_set*)(debug_buf.buf + sizeof(proto_head_t));
    uint32_t *rt = (uint32_t*)(debug_buf.buf + sizeof(proto_head_t));
    uint32_t *crc = NULL;
    HAL_StatusTypeDef rv = HAL_ERROR;

    if (IS_MONITOR_BIT_SET(dev_config.flag, DEV_FLAG_ADJ))
    {
        /* 开始自动校准. */
        rv = _debug_adj_auto(data->ch_selecet);
        if (rv == HAL_OK)
        {
            /* 完成后保存配置. */
            common_sys_set(COM_SYS_SAVE_CONFIG, 0);
        }

        /* 电池电压自动校准. */
        if (data->is_voltage_sel)
        {
            ADCi_vbat_auto(dev_config.vin);
        }
    }
    else
    {
        rv = HAL_ERROR;
    }
    *rt = rv;

    /* 封装报文头. */
    _debug_pkt_head_init(sizeof(proto_head_t) + 4, DEBUG_CT_PRV_REPLY);

    /* 计算校验和. */
    crc = (uint32_t*)(debug_buf.buf + head->len);
    *crc = crc32(debug_buf.buf, head->len);

    /* 发送报文 */
    _debug_pkt_send(head->len + 4, 20);
    
    return;
}

/* 实时数据获取报文处理. */
static void _debug_pkt_data_get(void)
{
    proto_head_t *head = (proto_head_t*)debug_buf.buf;
    debug_real_data_t *data = (debug_real_data_t*)(debug_buf.buf + sizeof(proto_head_t));
    uint32_t *crc = NULL;
    uint8_t i = 0;

    /* 封装报文头. */
    _debug_pkt_head_init(sizeof(proto_head_t) + sizeof(debug_real_data_t), DEBUG_CT_PRV_REPLY);

    /* 装填数据. */
    data->temperature = ADC_ctrl.ADCi_temp;
    data->vbat = ADC_ctrl.ADCi_vbat;
    data->vin = ADC_ctrl.ADCi_vin;
    data->vsc = ADC_ctrl.ADCi_vsc;
    data->CSQ = wl_ctrl.CSQ;
    for(i = 0; i < CFG_ADC_CH_CNT; i++)
    {
        data->elec[i] = ADC_ctrl.ADC_elec[i];
    }
    for(i = 0; i < SENSOR_SUM; i++)
    {
        data->sen_valid[i] = sensor_value[i].is_valid;
        data->sen_temp[i] = sensor_value[i].temp;
        data->sen_x[i] = sensor_value[i].joint_attitude_x;
        data->sen_y[i] = sensor_value[i].joint_attitude_y;
        data->sen_z[i] = sensor_value[i].joint_attitude_z;
    }
    data->energy_mode = ADC_ctrl.energy_mode;
    data->sen_short = sensor_short;

    /* 计算校验和. */
    crc = (uint32_t*)(debug_buf.buf + head->len);
    *crc = crc32(debug_buf.buf, head->len);

    /* 发送报文 */
    _debug_pkt_send(head->len + 4, 20);
    
    return;
}

/* 工频采样数据获取报文处理. */
static void _debug_pkt_power_fre_get(void)
{
    proto_head_t *head = (proto_head_t*)debug_buf.buf;
    mul_head_t *m_head = (mul_head_t*)(debug_buf.buf + sizeof(proto_head_t));
    uint8_t *data = (uint8_t*)(debug_buf.buf + sizeof(proto_head_t) + sizeof(mul_head_t));
    int32_t data_len = 0;
    uint32_t *crc = NULL;

    /* 封装报文头. */
    _debug_pkt_head_init(sizeof(proto_head_t), DEBUG_CT_PRV_REPLY);

    /* 填充数据, 计算数据长度和报文长度. */
    data_len = ADC_COLLECT_CNT * 5 * 2 - m_head->index * DEBUG_DATA_SIZE;
    if (data_len < 0)
    {
        return;
    }
    else if (data_len > DEBUG_DATA_SIZE)
    {
        m_head->len = DEBUG_DATA_SIZE;
    }
    else
    {
        m_head->len = data_len;
    }
    head->len = sizeof(proto_head_t) + sizeof(mul_head_t) + m_head->len;

    if (m_head->len > 0)
    {
        memcpy(data, (uint8_t*)(&ADC_ctrl.ADC_value_elec[0][0]) + m_head->index * DEBUG_DATA_SIZE, m_head->len);
    }

    /* 计算校验和. */
    crc = (uint32_t*)(debug_buf.buf + head->len);
    *crc = crc32(debug_buf.buf, head->len);

    /* 发送报文 */
    _debug_pkt_send(head->len + 4, 28);
    
    return;
}

/* 高频采样数据获取报文处理. */
static void _debug_pkt_wave_get(void)
{
    proto_head_t *head = (proto_head_t*)debug_buf.buf;
    mul_head_t *m_head = (mul_head_t*)(debug_buf.buf + sizeof(proto_head_t));
    int16_t *data = (int16_t*)(debug_buf.buf + sizeof(proto_head_t) + sizeof(mul_head_t));
    int32_t data_len = 0;
    uint32_t *crc = NULL;
    uint32_t addr = 0;
    int16_t *wave = NULL;
    uint16_t i = 0;

    /* 封装报文头. */
    _debug_pkt_head_init(sizeof(proto_head_t), DEBUG_CT_PRV_REPLY);
    /* 填充数据, 计算数据长度和报文长度. */
    data_len = 1024000 * 8 - m_head->index * DEBUG_DATA_SIZE;
    if (data_len < 0)
    {
        return;
    }
    else if (data_len > DEBUG_DATA_SIZE)
    {
        m_head->len = DEBUG_DATA_SIZE;
    }
    else
    {
        m_head->len = data_len;
    }
    head->len = sizeof(proto_head_t) + sizeof(mul_head_t) + m_head->len;

    if (m_head->len > 0)
    {
        addr = WARE_ADDRESS + m_head->index * DEBUG_DATA_SIZE;
        spi_flash_read(addr, debug_flash, DEBUG_DATA_SIZE);
        wave = (int16_t*)debug_flash;

        for(i = 0; i < 128; i++)
        {
            *data++ = *wave++;
            *data++ = *wave++;
            data += 2;
        }

        data = (int16_t*)(debug_buf.buf + sizeof(proto_head_t) + sizeof(mul_head_t));
        for(i = 0; i < 128; i++)
        {
            data += 2;
            *data++ = *wave++;
            *data++ = *wave++;
        }
    }

    /* 计算校验和. */
    crc = (uint32_t*)(debug_buf.buf + head->len);
    *crc = crc32(debug_buf.buf, head->len);

    /* 发送报文 */
    _debug_pkt_send(head->len + 4, 28);
    
    return;
}

/* 设备状态获取报文处理. */
static void _debug_pkt_dev_state_get(void)
{
    proto_head_t *head = (proto_head_t*)debug_buf.buf;
    dev_state_t *data = (dev_state_t*)(debug_buf.buf + sizeof(proto_head_t));
    uint32_t *crc = NULL;

    /* 封装报文头. */
    _debug_pkt_head_init(sizeof(proto_head_t) + sizeof(dev_state_t), DEBUG_CT_PRV_REPLY);

    /* 装填数据. */
    data->energy_mode = ADC_ctrl.energy_mode;
    data->is_adc_collect = ADC_ctrl.collect_finish;
    data->is_adc_up = ADC_ctrl.up_finish;
    data->adci_cnt = ADC_ctrl.ADCi_err_cnt;
    data->adci_state = ADC_ctrl.ADCi_state;
    data->adc_cnt = ADC_ctrl.ADC_err_cnt;
    data->adc_state = ADC_ctrl.ADC_state;
    data->is_adc_thr = ADC_ctrl.is_ADC_thr;
    data->wave_state = wave_ctrl.state.state;
    data->wave_time = st_data.wave_time;
    data->wave_start = st_data.wave_start;
    if (dev_info.type_s == DEV_TYPE_CT_P)
    {
        data->wave_up_start = position_ctrl.position_wave_up;
    }
    else
    {
        data->wave_up_start = st_data.wave_up_start;
    }
    data->wave_idx = st_data.wave_index;
    data->wave_rt = wave_ctrl.rt;
    data->wave_force = st_data.wave_force;
    data->wl_state = wl_ctrl.state;
    data->wl_cnt = wl_ctrl.send_cnt;
    data->is_wl_update = wl_ctrl.is_update;
    data->wl_wave_idx = wl_ctrl.wave_index;
    data->force_sleep_up = st_data.force_sleep_up;
    data->is_bat_charge = HAL_GPIO_ReadPin(BAT_CHECK_GPIO_Port, BAT_CHECK_Pin);
    data->wave_adj = dev_config.wave_adj;
    data->wave_min = st_data.wave_min_save;
    data->wave_max = st_data.wave_max_save;
    data->sys_time = HAL_GetTick() / 1000;

    /* 计算校验和. */
    crc = (uint32_t*)(debug_buf.buf + head->len);
    *crc = crc32(debug_buf.buf, head->len);

    /* 发送报文 */
    _debug_pkt_send(head->len + 4, 20);
    
    return;
}

/* 设备状态获取报文处理. */
static void _debug_pkt_wave_col(void)
{
    proto_head_t *head = (proto_head_t*)debug_buf.buf;
    uint32_t *crc = NULL;
    uint32_t reset_delay = 2;
    uint8_t i = 0;

    st_data.wave_time = 0;
    st_data.wave_start = TRUE;
    st_data.wave_up_start = TRUE;
    st_data.wave_index = 0;
    for(i = 0; i < WAVE_SUM; i++)
    {
        st_data.wave_max[i] = 0;
    }

    flash_log_write(FLASH_LOG_TYPE_INFO, "Force wavc collect system reset!\r\n");
    st_write(&st_data);
    common_sys_set(COM_SYS_RESET, (void*)&reset_delay);

    /* 封装报文头. */
    _debug_pkt_head_init(sizeof(proto_head_t), DEBUG_CT_PRV_REPLY);

    /* 计算校验和. */
    crc = (uint32_t*)(debug_buf.buf + head->len);
    *crc = crc32(debug_buf.buf, head->len);

    /* 发送报文 */
    _debug_pkt_send(head->len + 4, 20);
    
    return;
}

/* 校准参数设置报文处理. */
static void _debug_pkt_wave_cal(void)
{
    proto_head_t *head = (proto_head_t*)debug_buf.buf;
    uint16_t *data = (uint16_t*)(debug_buf.buf + sizeof(proto_head_t));
    uint32_t *crc = NULL;

    /* 配置参数. */
    dev_config.wave_adj = *data;

    /* 封装报文头. */
    _debug_pkt_head_init(sizeof(proto_head_t), DEBUG_CT_PRV_REPLY);

    /* 计算校验和. */
    crc = (uint32_t*)(debug_buf.buf + head->len);
    *crc = crc32(debug_buf.buf, head->len);

    /* 发送报文 */
    _debug_pkt_send(head->len + 4, 20);

    /* 保存参数. */
    common_sys_set(COM_SYS_SAVE_CONFIG, 0);
    
    return;
}

/* . */
static void _debug_pkt_log_get(void)
{
    static uint64_t log_id = 0;
    static uint64_t read_id = 0;
    static uint32_t data_sum = 0;
    proto_head_t *head = (proto_head_t*)debug_buf.buf;
    mul_head_t *m_head = (mul_head_t*)(debug_buf.buf + sizeof(proto_head_t));
    uint32_t *data = (uint32_t*)(debug_buf.buf + sizeof(proto_head_t) + sizeof(mul_head_t));
    falsh_log_t *log = NULL;
    int32_t data_len = 0;
    uint32_t *crc = NULL;
    uint16_t real_len = 0;
    uint8_t i = 0;

    /* 封装报文头. */
    _debug_pkt_head_init(sizeof(proto_head_t), DEBUG_CT_PRV_REPLY);
    
    /* 初始化数据. */
    if (0 == m_head->index)
    {
        log_id = flash_log_id;
        data_sum = (*data) * FLASH_LOG_BUF_LEN;
    }

    /* 计算数据长度和报文长度. */
    data_len = data_sum - m_head->index * DEBUG_DATA_SIZE;
    if (data_len < 0)
    {
        return;
    }
    else if (data_len > DEBUG_DATA_SIZE)
    {
        m_head->len = DEBUG_DATA_SIZE;
    }
    else
    {
        m_head->len = data_len;
    }

    /* 填充数据. */
    if (m_head->len > 0)
    {
        for(i = 0; i < m_head->len / FLASH_LOG_BUF_LEN; i++)
        {
            read_id = log_id - 4 * m_head->index - i;
        
            log = (falsh_log_t*)(debug_buf.buf + sizeof(proto_head_t) + sizeof(mul_head_t) + i * FLASH_LOG_BUF_LEN);
            if (flash_log_read(read_id, log) != HAL_OK)
                break;

            /* 读到全F,表示结束了. */
            if (log->id != read_id)
                break;
            
            real_len += FLASH_LOG_BUF_LEN;
        }
    }

    /* 计算校验和. */
    m_head->len = real_len;
    head->len = sizeof(proto_head_t) + sizeof(mul_head_t) + m_head->len;
    crc = (uint32_t*)(debug_buf.buf + head->len);
    *crc = crc32(debug_buf.buf, head->len);

    /* 发送报文 */
    _debug_pkt_send(head->len + 4, 28);
    
    return;
}

/* . */
static void _debug_pkt_history_data_get(void)
{
    static uint64_t data_id = 0;
    static uint64_t read_id = 0;
    static uint32_t data_sum = 0;
    proto_head_t *head = (proto_head_t*)debug_buf.buf;
    mul_head_t *m_head = (mul_head_t*)(debug_buf.buf + sizeof(proto_head_t));
    uint32_t *data = (uint32_t*)(debug_buf.buf + sizeof(proto_head_t) + sizeof(mul_head_t));
    fd_date_t *history = NULL;
    int32_t data_len = 0;
    uint32_t *crc = NULL;
    uint16_t real_len = 0;
    uint8_t i = 0;

    /* 封装报文头. */
    _debug_pkt_head_init(sizeof(proto_head_t), DEBUG_CT_PRV_REPLY);
    
    /* 初始化数据. */
    if (0 == m_head->index)
    {
        data_id = fd_id;
        data_sum = (*data) * FD_BUF_LEN;
    }

    /* 计算数据长度和报文长度. */
    data_len = data_sum - m_head->index * DEBUG_DATA_SIZE;
    if (data_len < 0)
    {
        return;
    }
    else if (data_len > DEBUG_DATA_SIZE)
    {
        m_head->len = DEBUG_DATA_SIZE;
    }
    else
    {
        m_head->len = data_len;
    }

    /* 填充数据. */
    if (m_head->len > 0)
    {
        for(i = 0; i < m_head->len / FD_BUF_LEN; i++)
        {
            read_id = data_id - 4 * m_head->index - i;
        
            history = (fd_date_t*)(debug_buf.buf + sizeof(proto_head_t) + sizeof(mul_head_t) + i * FD_BUF_LEN);
            if (fd_read(read_id, history) != HAL_OK)
                break;

            /* 读到全F,表示结束了. */
            if (history->id != read_id)
                break;
            
            real_len += FD_BUF_LEN;
        }
    }

    /* 计算校验和. */
    m_head->len = real_len;
    head->len = sizeof(proto_head_t) + sizeof(mul_head_t) + m_head->len;
    crc = (uint32_t*)(debug_buf.buf + head->len);
    *crc = crc32(debug_buf.buf, head->len);

    /* 发送报文 */
    _debug_pkt_send(head->len + 4, 28);
    
    return;
}

/* 自动校准处理. */
static HAL_StatusTypeDef _debug_adj_manual(uint8_t bitmap, uint8_t index)
{
    uint8_t i = 0;
    uint8_t j = 0;

    /* 参数检查. */
    if (index >= CFG_ADC_ADJ_CNT)
    {
        vty_print("@E1\r\n");
        return HAL_ERROR;
    }

    if (!bitmap)
    {
        return HAL_OK;
    }

    for(i = 0; i < CFG_ADC_CH_CNT; i++)
    {
        /* 过滤不需要的通道. */
        if (!IS_MONITOR_BIT_SET(bitmap, i) || 0 == dev_config.ADC_ratio[i])
        {
            continue;
        }

        /* 通道分段点不同, 不能同时校准. */
        for (j = i; j < CFG_ADC_CH_CNT; j++)
        {
            if (!IS_MONITOR_BIT_SET(bitmap, j))
            {
                continue;
            }

            if (dev_config.ADC_base_elec[i][index] != dev_config.ADC_base_elec[j][index])
            {
                vty_print("@E2\r\n");
                return HAL_ERROR;
            }
        }   
    }

    HAL_E_RETURN(ADC_base_auto(bitmap, index + 1));

    return HAL_OK;
}

/* 手动校准报文处理. */
static void _debug_pkt_adj_manual(void)
{
    proto_head_t *head = (proto_head_t*)debug_buf.buf;
    debug_adj_set *data = (debug_adj_set*)(debug_buf.buf + sizeof(proto_head_t));
    uint32_t *rt = (uint32_t*)(debug_buf.buf + sizeof(proto_head_t));
    uint32_t *crc = NULL;
    HAL_StatusTypeDef rv = HAL_ERROR;

    if (IS_MONITOR_BIT_SET(dev_config.flag, DEV_FLAG_ADJ))
    {
        /* 开始自动校准. */
        rv = _debug_adj_manual(data->ch_selecet, data->manual_index);
        if (rv == HAL_OK)
        {
            /* 完成后保存配置. */
            common_sys_set(COM_SYS_SAVE_CONFIG, 0);
        }
    }
    else
    {
        rv = HAL_ERROR;
    }
    *rt = rv;

    /* 封装报文头. */
    _debug_pkt_head_init(sizeof(proto_head_t) + 4, DEBUG_CT_PRV_REPLY);

    /* 计算校验和. */
    crc = (uint32_t*)(debug_buf.buf + head->len);
    *crc = crc32(debug_buf.buf, head->len);

    /* 发送报文 */
    _debug_pkt_send(head->len + 4, 20);
    
    return;
}

/* 南网配置获取报文处理. */
static void _debug_pkt_csg_config_get(void)
{
    proto_head_t *head = (proto_head_t*)debug_buf.buf;
    debug_csg_config_t *data = (debug_csg_config_t*)(debug_buf.buf + sizeof(proto_head_t));
    uint32_t *crc = NULL;

    /* 封装报文头. */
    _debug_pkt_head_init(sizeof(proto_head_t) + sizeof(debug_csg_config_t), DEBUG_CT_PRV_REPLY);

    /* 装填数据. */
    memcpy(data->passwd, dev_config.csg_passwd, CSG_PASSWD_LEN);
    data->passwd[CSG_PASSWD_LEN] = 0;
    data->beat_interval = dev_config.csg_beat_interval;
    data->collect_interval = dev_config.collect_interval;
    data->sleep_time = dev_config.csg_sleep;
    data->online_time = HAL_GetTick() / 1000 / 60;
    memcpy(data->reset_time, dev_config.csg_reset_time, 3);
    memcpy(data->ciphertext, dev_config.csg_ciphertext, CSG_CIPHERTEXT_LEN);
    data->ciphertext[CSG_CIPHERTEXT_LEN] = 0;

    /* 计算校验和. */
    crc = (uint32_t*)(debug_buf.buf + head->len);
    *crc = crc32(debug_buf.buf, head->len);

    /* 发送报文 */
    _debug_pkt_send(head->len + 4, 20);
    
    return;
}

/* 修改南网配置报文处理. */
static void _debug_pkt_csg_config_set(void)
{
    proto_head_t *head = (proto_head_t*)debug_buf.buf;
    debug_csg_config_t *data = (debug_csg_config_t*)(debug_buf.buf + sizeof(proto_head_t));
    uint32_t *crc = NULL;

    /* 保存数据. */
    memcpy(dev_config.csg_passwd, data->passwd, CSG_PASSWD_LEN);
    dev_config.csg_passwd[CSG_PASSWD_LEN] = 0;
    dev_config.csg_beat_interval = data->beat_interval;
    dev_config.collect_interval = data->collect_interval;
    dev_config.csg_sleep = data->sleep_time;
    dev_config.csg_online = data->online_time;
    memcpy(dev_config.csg_reset_time, data->reset_time, 3);
    memcpy(dev_config.csg_ciphertext, data->ciphertext, CSG_CIPHERTEXT_LEN);

    /* 封装报文头. */
    _debug_pkt_head_init(sizeof(proto_head_t), DEBUG_CT_PRV_REPLY);

    /* 计算校验和. */
    crc = (uint32_t*)(debug_buf.buf + head->len);
    *crc = crc32(debug_buf.buf, head->len);

    /* 发送报文 */
    _debug_pkt_send(head->len + 4, 20);

    /* 保存配置. */
    common_sys_set(COM_SYS_SAVE_CONFIG, 0);
    
    return;
}

/* 收包报文处理. */
static void _debug_pkt_process(void)
{
    proto_head_t *head = (proto_head_t*)debug_buf.buf;

    /* 报文头和 CRC 校验. */
    if (_debug_pkt_check() != HAL_OK)
    {
        debug_buf.end = 0;
        return;
    }

    if (DEBUG_CT_REQUEST == head->cmd_type)
    {
        /* 共有命令处理. */
        switch (head->cmd)
        {
        case DEBUG_C_DEV_INFO:
            _debug_pkt_info_get();
            break;
        case DEBUG_C_DEV_INFO_SET:
            _debug_pkt_info_set();
            break;
        case DEBUG_C_RESET:
            _debug_pkt_reset();
            break;
        case DEBUG_C_DEFAULT:
            _debug_pkt_default();
            break;
        case DEBUG_C_UPDATE_APP:
            _debug_pkt_update_app();
            break;
        case DEBUG_C_UPDATE_IAP:
            _debug_pkt_update_iap();
            break;
        case DEBUG_C_DEV_CONFIG:
            _debug_pkt_config_get();
            break;
        case DEBUG_C_DEV_CONFIG_SET:
            _debug_pkt_config_set();
            break;
        default:
            break;
        }
    }
    else if (DEBUG_CT_PRV_REQUEST == head->cmd_type)
    {
        /* 私有命令处理. */
        switch (head->cmd)
        {
        case DEBUG_PRV_ADJ_INFO:
            _debug_pkt_adj_get();
            break;
        case DEBUG_PRV_REAL_DATA:
            _debug_pkt_data_get();
            break;
        case DEBUG_PRV_POWER_FRE:
            _debug_pkt_power_fre_get();
            break;
        case DEBUG_PRV_ADJ_INFO_SET:
            _debug_pkt_adj_set();
            break;
        case DEBUG_PRV_ADJ_AUTO:
            _debug_pkt_adj_auto();
            break;
        case DEBUG_PRV_WAVE:
            _debug_pkt_wave_get();
            break;
        case DEBUG_PRV_DEV_STATE:
            _debug_pkt_dev_state_get();
            break;
        case DEBUG_PRV_WAVE_COL:
            _debug_pkt_wave_col();
            break;
        case DEBUG_PRV_WAVE_CAL:
            _debug_pkt_wave_cal();
            break;
        case DEBUG_PRV_LOG:
            _debug_pkt_log_get();
            break;
        case DEBUG_PRV_HISTORY_DATA:
            _debug_pkt_history_data_get();
            break;
        case DEBUG_PRV_ADJ_MANUAL:
            _debug_pkt_adj_manual();
            break;
        case DEBUG_PRV_CSG_CONFIG:
            _debug_pkt_csg_config_get();
            break;
        case DEBUG_PRV_CSG_CONFIG_SET:
            _debug_pkt_csg_config_set();
            break;
        default:
            break;
        }
    }

    debug_buf.end = 0;
    return;
}

/* Interface functions -------------------------------------------------------*/
/* RS485 传感器主任务循环. */
void debug_start(void)
{
    uint32_t notify_value = 0xff;
    proto_head_t *head = (proto_head_t*)debug_buf.buf;

    while(1)
    {
        common_watchdog_set(COM_WDG_CLI);
    
        /* 开启串口空闲中断 DMA 收包. 注意这里会收到空闲中断, DMA 收一半中断, 全收中断, 注意中断处理. */
        if (HAL_OK == HAL_UARTEx_ReceiveToIdle_DMA(debug_uart, debug_buf.buf + debug_buf.end, USART_BUF_SIZE - debug_buf.end))
        {
            debug_buf.is_half = FALSE;
        }
        
        /* 等待收包完成. */
        notify_value = ulTaskNotifyTake(pdTRUE, 3000);
        if (0 == notify_value)
        {
            /* 收包超时, 如果收包开始, 但是又不是一个完整的包, 重新开始收包. */
            if (TRUE == debug_state)
            {
                HAL_UART_Abort(debug_uart);
                debug_buf.end = 0;
                debug_state = FALSE;
            }
            continue;
        }

        /* 如果收包没有开始, 执行以下过程. */
        if (!debug_state)
        {
            /* 报文长度不对直接重新开始收包. */
            if (head->len + 4 > USART_BUF_SIZE)
            {
                HAL_UART_Abort(debug_uart);
                debug_buf.end = 0;
                debug_state = FALSE;
                continue;
            }

            /* 收包不完整, 等待下一次收包. */
            if (debug_buf.end < head->len + 4)
            {
                debug_state = TRUE;
                continue;
            }
        }
        else
        {
            /* 收包不完整, 等待下一次收包. */
            if (debug_buf.end < head->len + 4)
            {
                continue;
            }

            /* 收包完成进入处理流程. */
            debug_state = FALSE;
        }

        /* 调试打印. */
        DBG(DBG_M_RS485_DEBUG, "Recv(%d):\r\n", debug_buf.end);
        if (dbg_stat_get(DBG_M_RS485_DEBUG))
        {
            buf_print(debug_buf.buf, 28);
        }
        
        /* 报文处理. */
        _debug_pkt_process();
    }
}

/* 对需要写入内部flash的数据进行CRC32校验. */
int32_t debug_app_check(uint32_t addr, uint32_t size, uint8_t file_type)
{
    uint16_t write_size = 0;
    uint32_t crc32_value = 0xffffffff;
    bin_pkt_tail_t *pkt_tail = NULL;

    /* 计算crc32. */
    size = size - 4;
    while(size > 0)
    {
        /* 计算每次写入的数据大小. */
        if (size > DEBUG_FLASH_BUF_SIZE)
            write_size = DEBUG_FLASH_BUF_SIZE;
        else
            write_size = size;

        /* 从spi flash读取升级包. */
        if (spi_flash_read(addr, debug_flash, write_size) != HAL_OK)
        {
            goto CRC_CHECK_ERROR;
        }

        crc32_value = crc32_update(crc32_value, (char*)debug_flash, write_size);
        
        /* 重新计算flash地址和剩余数据大小. */
        addr += write_size;
        size -= write_size;
    }

    /* 从spi flash读取报文头. */
    if (spi_flash_read(addr + 4 - sizeof(bin_pkt_tail_t), debug_flash, sizeof(bin_pkt_tail_t)) != HAL_OK)
    {
        goto CRC_CHECK_ERROR;
    }
    pkt_tail = (bin_pkt_tail_t*)debug_flash;

    /* 比较报文头信息 */
    if (crc32_value != pkt_tail->crc32
        || dev_info.type_m != pkt_tail->dev_type_m
        || pkt_tail->file_type != file_type)
    {
        goto CRC_CHECK_ERROR;
    }

    return HAL_OK;
    
CRC_CHECK_ERROR:
    vty_print(" Programming failure start with old APP!\n\r");
    return HAL_ERROR;
}

/* 显示命令 */
void debug_adj_auto(uint8_t bitmap)
{
    /* 开始自动校准. */
    _debug_adj_auto(bitmap);
    /* 关闭校准. */
    _debug_adj_close();
}
/******************* (C) COPYRIGHT LandPower ***** END OF FILE ****************/
