/******************************************************************************
 * file    Core/Src/wireless.c 
 * author  YuLiang
 * version 1.0.0
 * date    14-Jun-2022
 * brief   This file provides all the wireless 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 "time.h"

#include "usart.h"
#include "adc.h"
#include "tim.h"
#include "rtc.h"

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

/* Private define ------------------------------------------------------------*/
#define WL_RX_TIMEOUT 500               // 每 500ms 检查一次收包数据.
#define WL_USART_ERR_TIMEOUT 1000       // 串口发送错误延迟时间.
#define WL_SOFT_INIT_ERR 5              // 软件初始化错误最大次数.
#define WL_DATA_ERR 3                   // 数据发送错误最大次数.
#define WL_PWR_FRE_CH_NUM 4             // 工频录波通道数.

#define WL_FLASH_BUF_SIZE 1024

#define WIR_RX_TIMEOUT 10000            // 有线模式每 10s 检查一次收包数据.

/* Private typedef -----------------------------------------------------------*/
/* 状态机状态. */
typedef enum
{
    WL_STATE_SOFT = 0,
    WL_STATE_AT_ATE,
    WL_STATE_AT_QICSGP,
    WL_STATE_AT_QIACT,
    WL_STATE_AT_CSQ,
    WL_STATE_AT_QICFGTS,
    WL_STATE_AT_QICFGWT,
    WL_STATE_AT_QIOPEN,
    WL_STATE_ADC_WAIT,
    WL_STATE_WAKEUP = 128,
    WL_STATE_REALDATA,
    WL_STATE_PWR_FRE,
    WL_STATE_UPDATE,
    WL_STATE_UPDATE_RT,
    WL_STATE_WAVE,
    WL_STATE_WAVE_MAX,
    WL_STATE_POSITION,
    WL_STATE_POSITION_WAVE,
    WL_STATE_KEEPALIVE,
    CSG_STATE_CONNECT,
    CSG_STATE_TIME,
    CSG_STATE_BEAT,
    CSG_STATE_IDLE,
    CSG_STATE_DATA,
    CSG_STATE_DATA_HIS,
    WL_STATE_END = 255
} WL_STATE_E;

typedef struct {
    uint32_t start;
    uint16_t len;
    uint16_t type;
    uint32_t id;
    uint32_t life_cnt;
    uint16_t num;
    uint16_t num_index;
} wl_proto_head_t;

typedef struct {
    uint32_t checksum;
    uint32_t end;
} wl_proto_tail_t;

/* 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];
} wl_proto_wakeup_t;

/* 实时数据传输结构体. */
typedef struct
{
    int16_t temperature;                    // 设备温度, 单位: 0.1℃.
    uint16_t vbat;                          // 电池电压, 单位: mv.
    int16_t CSQ;                            // 4G 信号质量 > -51dBm 统一显示 -51dBm, < -113 dBm 为无信号.
    uint16_t vin;                           // 工作电压, 单位: mv.
    uint32_t elec[CFG_ADC_CH_CNT];          // 通道电流有效值 mA.
    uint16_t vsc;                           // 超级电容电压, 单位: mv.
    uint16_t sen_temp[SENSOR_SUM];          // 传感器温度: 单位: 0.1℃.
    uint16_t sen_x[SENSOR_SUM];             // 传感器震动 x 轴.
    uint16_t sen_y[SENSOR_SUM];             // 传感器震动 y 轴.
    uint16_t sen_z[SENSOR_SUM];             // 传感器震动 z 轴.
    uint8_t energy_mode;                    // 当前设备工作模式.
    uint8_t sen_short;                      // 传感器是否短路, 0 – 没有短路, 1 – 短路.
    uint8_t sen_valid[SENSOR_SUM];          // 传感器数据是否有效, 0 - 无效, 1 - 有效.
    uint32_t run_time;                      // 设备运行时长, 单位 s.    
    uint8_t fre_valid;                      // 工频数据有效, 有线协议使用.
    uint8_t wave_valid;                     // 高频数据有效, 有线协议使用.
    uint8_t reserve[2];
} wl_proto_realdata_t;

/* 实时数据传输结构体. */
typedef struct
{
    int16_t wave[WAVE_SUM];                 // 高频录波最大值, 0 - 无效, 1 - 有效值.
} wl_proto_wave_max_t;

typedef struct
{
    uint32_t utc;
    uint16_t interval;
    uint8_t wave_force;
    uint8_t wave_interval;    
    uint16_t threshold;
    uint16_t wave_threshold;
    uint8_t is_updata;
    uint8_t main_cable;
    uint8_t normal_sleep;
    uint8_t is_voltage_col;
    uint8_t is_temp_col;
    uint8_t is_wave_col;
    uint8_t reserve[2];		//字节对齐
    uint32_t position_file_s;
    uint32_t position_file_ns;
} wl_proto_config_t;

/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
osThreadId_t WLHandle;
const osThreadAttr_t WL_attributes =
{
    .name = "WIRELESS",
    .stack_size = 160 * 2 * 4,
    .priority = (osPriority_t) osPriorityNormal,
};
wl_buf_list_t wl_buf_list_rx;
static UART_HandleTypeDef *wl_uart = &huart3;
wl_ctrl_t wl_ctrl;
static uint8_t wl_flash[WL_FLASH_BUF_SIZE];
static fd_date_t csg_adc_data;
static position_data_t position_up_data;
static uint64_t csg_data_idx[CSG_PKT_DATA_SUM];

/* Private function prototypes -----------------------------------------------*/
static void _wl_4G_wakeup_send(void);
static void _wl_4G_realdata_send(void);
static void _wl_4G_update_send(void);
static void _wl_4G_update_rt_send(void);
static void _wl_4G_power_fre_send(void);
static void _wl_4G_wave_send(void);
static void _wl_4G_wave_max_send(void);
static void _wl_4G_position_send(void);
static HAL_StatusTypeDef _wl_4G_position_wave_send(void);
static void _wir_data_process(uint8_t *cmd, uint32_t len);
static void _csg_pkt_recv(void);

/* Internal functions --------------------------------------------------------*/
/* 初始化 4G 模块硬件 */
static void _wl_4G_hw_init(void)
{
    /* 4G 模块供电打开.*/
    osDelay(1000);
    HAL_GPIO_WritePin(POWER_EN_4G_GPIO_Port, POWER_EN_4G_Pin, GPIO_PIN_SET);

    /* 4G 模块复位. */
    osDelay(500);
    HAL_GPIO_WritePin(G4G_RST_GPIO_Port, G4G_RST_Pin, GPIO_PIN_SET);
    osDelay(100);
    HAL_GPIO_WritePin(G4G_RST_GPIO_Port, G4G_RST_Pin, GPIO_PIN_RESET);
}

/* 关闭 4G 模块硬件. */
static void _wl_4G_hw_close(uint32_t sleep_time)
{
    HAL_GPIO_WritePin(POWER_EN_4G_GPIO_Port, POWER_EN_4G_Pin, GPIO_PIN_RESET);

    /* 故障定位版本装置不进行高频录波 */
	if (st_data.wave_start && DEV_TYPE_CT_P != dev_info.type_s)
    {
        while(wave_ctrl.state.state != WAVE_STATE_COMPLETION)
        {
            osDelay(3000);
        }
    }

    if (!st_data.wave_start && st_data.wave_up_start
        && st_data.wave_index != wl_ctrl.wave_index)
    {
        st_write(&st_data);
    }
    else if (DEV_TYPE_CT_P == dev_info.type_s
        && position_ctrl.position_wave_up
        && st_data.wave_index != wl_ctrl.wave_index)
    {
        st_data.wave_index = wl_ctrl.wave_index;
        st_write(&st_data);
    }

    if (ADC_ctrl.energy_mode != ADC_ENERGY_NORMAL
        && sleep_time < 1800)
    {
        sleep_time = 1800;
    }
    common_sys_set(COM_SYS_SHUTDOWN, (void*)&sleep_time);

    while(1)
    {
        osDelay(portMAX_DELAY);
    }
}

/* 关闭 4G 模块硬件. */
static void _wl_4G_hw_restart(void)
{
    DBG(DBG_M_4G, "4G restart(%d),\r\n", wl_ctrl.err_cnt);
    
    /* 开启串口空闲中断收包. */
    if (wl_ctrl.err_cnt)
    {
        if (DEV_TYPE_CT_P != dev_info.type_s)
        {
            flash_log_write(FLASH_LOG_TYPE_WARNING, "Server is disconnect system sleep %ds!\r\n", dev_config.collect_interval * 60 - 30);
            _wl_4G_hw_close(dev_config.collect_interval * 60 - 30);
            return;
        }
		/* 故障定位版本设备出现问题时重启不休眠 */
        else
        {
            flash_log_write(FLASH_LOG_TYPE_WARNING, "Server is disconnect system reset!\r\n");
            _wl_4G_hw_close(0);
            return;
        }
    }

    HAL_UART_Abort(wl_uart);
    memset(&wl_buf_list_rx, 0, sizeof(wl_buf_list_t));
    osDelay(200);
    HAL_UARTEx_ReceiveToIdle_DMA(wl_uart, wl_ctrl.dma_rx_buf, WL_DMA_RX_BUF_LEN);

    /* 初始化 4G 模块硬件. */
    HAL_GPIO_WritePin(POWER_EN_4G_GPIO_Port, POWER_EN_4G_Pin, GPIO_PIN_RESET);
    _wl_4G_hw_init();

    /* 20s 内要收到 4G 模块发出的 RDY. */
    wl_ctrl.state = 0;
    wl_ctrl.send_cnt = 0;
    wl_ctrl.mul_idx = 0;
    wl_ctrl.cmd_buf_index = 0;
    wl_ctrl.time_send = HAL_GetTick() + 20000;
    //wl_ctrl.wave_index = dev_record.wave_index;
    wl_ctrl.err_cnt++;
}

/* AT 命令 CSQ 返回数据处理. */
static void _wl_4G_AT_CSQ_process(uint8_t *cmd)
{
    int32_t rssi = 99;
    int32_t ber = 99;

    sscanf((char*)cmd, "+CSQ: %d,%d\r\n", &rssi, &ber);
    if (rssi != 99)
    {
        wl_ctrl.CSQ = -113 + (2 * rssi);
    }
    else
    {
        wl_ctrl.CSQ = -115;
    }    
}

/* AT 命令回复处理. */
static void _wl_4G_AT_process(uint8_t *cmd)
{
    if (0 == strncmp((char*)cmd, "RDY", 3))
    {
        /* 芯片启动后会发送. */
        wl_ctrl.state++;
        wl_ctrl.time_send = 0;
        wl_ctrl.send_cnt = 0;
    }
    else if (0 == strncmp((char*)cmd, "OK", 2))
    {
        /* 命令执行成功. */
        if (wl_ctrl.state < WL_STATE_AT_QIOPEN)
        {
            wl_ctrl.state++;
            wl_ctrl.time_send = 0;
            wl_ctrl.send_cnt = 0;
        }
    }
    else if (0 == strncmp((char*)cmd, "CONNECT", 7))
    {
        /* 软件初始化完成. */
        wl_ctrl.state++;
        wl_ctrl.time_send = 0;
        wl_ctrl.send_cnt = 0;
    }
    else if (0 == strncmp((char*)cmd, "+CSQ", 4))
    {
        /* 获取信号质量. */
        _wl_4G_AT_CSQ_process(cmd);
    }
    else if (0 == strncmp((char*)cmd, "ERROR", 5))
    {
        /* 命令执行失败. */
        wl_ctrl.time_send = HAL_GetTick() + 1000;
    }
}

/* 处理接收到的 AT 指令. */
void _wl_4G_AT_recv(void)
{
    wl_buf_list_t *buf_l = &wl_buf_list_rx;
    uint8_t *buf = NULL;
    uint8_t i = 0;

    /* 遍历所有有效的 buf. */
    while(buf_l->current != buf_l->valid)
    {
        buf = buf_l->buf[buf_l->current];

        /* 将 buf 中的数据解析成命令. */
        for(i = 0; i < buf_l->buf_cnt[buf_l->current]; i++)
        {
            wl_ctrl.cmd_buf[wl_ctrl.cmd_buf_index] = buf[i];
            wl_ctrl.cmd_buf_index++;
            if (buf[i] != 0x0a)
            {
                /* 不是回车继续读取数据. */
                continue;
            }

            /* 命令长度小于 2 为无效命令. */
            if (wl_ctrl.cmd_buf_index <= 2)
            {
                wl_ctrl.cmd_buf_index = 0;
                continue;
            }

            /* 添加结束位, 更新 cmd buf index, 执行命令解析. */
            wl_ctrl.cmd_buf[wl_ctrl.cmd_buf_index] = 0;
            wl_ctrl.cmd_buf_index = 0;
            DBG(DBG_M_4G, "Recv: %s\r\n", wl_ctrl.cmd_buf);
            _wl_4G_AT_process(wl_ctrl.cmd_buf);
        }

        /* 更新 buf index. */
        buf_l->current++;
        if (WL_BUF_LIST_LEN == buf_l->current)
        {
            buf_l->current = 0;
        }
    }
}

static void _wl_4G_pkt_id_update(void)
{
    wl_ctrl.pkt_id++;
}

static int32_t _wl_4G_pkt_check(uint8_t *cmd, uint32_t len)
{
    proto_head_t *head = (proto_head_t*)cmd;

    /* 设备进入复位状态后不再处理报文. */
    if (IS_MONITOR_BIT_SET(system_init_flag, SYS_INIT_RESET))
    {
        vty_print("@0\r\n");
        /* 这里挂住线程是因为重启时如果有收包, 会导致收包出错, 从而让设备进入休眠状态. */
        osDelay(portMAX_DELAY);
        return HAL_ERROR;
    }

    /* 对主次设备号进行识别, 次设备号可以是广播. */
    if ((head->dev_type_m != dev_info.type_m)
        || (head->dev_type_s != dev_info.type_s && head->dev_type_s != 0xFF))
    {
        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(cmd, head->len) != (*(uint32_t*)(cmd + head->len)))
    {
        vty_print("@3: %x %x\r\n", crc32(cmd, head->len), *(uint32_t*)(cmd + head->len));
        return HAL_ERROR;
    }

    /* pkt_id 验证. */
    if (head->pkt_id != wl_ctrl.pkt_id
        && dev_info.type_s != DEV_TYPE_ACDC)
    {
        vty_print("@4: %d %d\r\n", head->pkt_id, wl_ctrl.pkt_id);
        return HAL_ERROR;
    }

    return HAL_OK;
}

/* 设备信息获取报文处理. */
static void _wl_4G_pkt_reply(void)
{
    wl_ctrl.state = WL_STATE_PWR_FRE;
    wl_ctrl.time_send = 0;
    wl_ctrl.send_cnt = 0;

    if (dev_info.type_s != DEV_TYPE_ACDC)
    {
        _wl_4G_pkt_id_update();
    }
    else
    {
        _wl_4G_realdata_send();
    }

    if (dev_info.type_s == DEV_TYPE_CT_P)
    {
        position_ctrl.offline = FALSE;
    }
    
    return;
}

/* 设备信息回复. */
static void _wl_4G_dev_info_reply(uint8_t *cmd, uint32_t len)
{
    wl_proto_config_t *cfg = (wl_proto_config_t*)(cmd + sizeof(proto_head_t));
    uint8_t is_cfg_save = FALSE;
    uint8_t i = 0;

    if (cfg->interval != dev_config.collect_interval)
    {
        is_cfg_save = TRUE;
        dev_config_collect_interval_set(cfg->interval);
    }

    if (cfg->wave_interval != dev_config.wave_interval)
    {
        is_cfg_save = TRUE;
        dev_config_wave_interval_set(cfg->wave_interval);
    }

    if (cfg->threshold != dev_config.threshold)
    {
        is_cfg_save = TRUE;
        dev_config.threshold = cfg->threshold;
    }

    if (cfg->wave_threshold != dev_config.wave_threshold)
    {
        is_cfg_save = TRUE;
        dev_config.wave_threshold = cfg->wave_threshold;
        position_ctrl.cfg = TRUE;
    }

    if (cfg->main_cable != dev_config.main_cable)
    {
        is_cfg_save = TRUE;
        dev_config.main_cable = cfg->main_cable;
    }

    if (cfg->normal_sleep != dev_config.normal_sleep)
    {
        is_cfg_save = TRUE;
        dev_config.normal_sleep = cfg->normal_sleep;
    }

    if (cfg->is_voltage_col != dev_config.is_voltage_col)
    {
        is_cfg_save = TRUE;
        dev_config.is_voltage_col = cfg->is_voltage_col;
    }

    if (cfg->is_temp_col != dev_config.is_temp_col)
    {
        is_cfg_save = TRUE;
        dev_config.is_temp_col = cfg->is_temp_col;
    }

    if (cfg->is_wave_col != dev_config.is_wave_col)
    {
        is_cfg_save = TRUE;
        dev_config.is_wave_col = cfg->is_wave_col;
    }

    if (is_cfg_save)
    {
        common_sys_set(COM_SYS_SAVE_CONFIG, 0);
    }

    is_cfg_save = FALSE;
    if (cfg->wave_force != st_data.wave_force)
    {
         st_data.wave_force = cfg->wave_force;
         is_cfg_save = TRUE;
    }

    /* 强制录波或者间隔时间到了, 并且当前录波上传已完成. */
    if ((cfg->wave_force || abs_cal_u(cfg->utc, st_data.wave_time) > (dev_config.wave_interval * 3600))
        && !st_data.wave_up_start && DEV_TYPE_CT_P != dev_info.type_s)
    {
        st_data.wave_time = cfg->utc;
        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;
        }
        wl_ctrl.wave_index = 0;
        is_cfg_save = TRUE;
    }

    if (DEV_TYPE_CT_P == dev_info.type_s)
    {
        if (cfg->wave_force && !position_ctrl.position_wave_up && cfg->position_file_s != 0)
        {
            position_ctrl.position_wave_up = TRUE;
            position_ctrl.position_file_s = cfg->position_file_s;
            position_ctrl.position_file_ns = cfg->position_file_ns;
        }
        else if (!cfg->wave_force && position_ctrl.position_wave_up)
        {
            position_ctrl.position_wave_up = FALSE;
        }
    }

    if (is_cfg_save)
    {
        st_write(&st_data);
    }

    /* 更新 RTC 时间. */
    rtc_time_set(cfg->utc);

    wl_ctrl.state = WL_STATE_REALDATA;
    wl_ctrl.time_send = 0;
    wl_ctrl.send_cnt = 0;
    wl_ctrl.is_update = cfg->is_updata;

    if (dev_info.type_s != DEV_TYPE_ACDC)
    {
        _wl_4G_pkt_id_update();
    }
    else
    {
        _wl_4G_wakeup_send();
    }
    
    return;
}

/* 设备 APP 升级回复. */
static void _wl_4G_update_reply(uint8_t *cmd, uint32_t len)
{
    mul_head_t *m_head = (mul_head_t*)(cmd + sizeof(proto_head_t));
    uint8_t *data = (uint8_t*)(cmd + sizeof(proto_head_t) + sizeof(mul_head_t));
    uint32_t addr = TFTP_APP_ADDRESS;
    uint32_t app_len = 0; 

    /* index 为 0 表示是首保, 需要擦除 FLASH. */
    if (0 == m_head->index)
    {
        /* 开始时置升级结果为错误. */
        wl_ctrl.update_rt = HAL_ERROR;
        
        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_DATA_SIZE;
    if (m_head->len > DEBUG_DATA_SIZE)
    {
        return;
    }
    else 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_DATA_SIZE)
    {
        /* 校验数据. */
        app_len = addr - TFTP_APP_ADDRESS + m_head->len;
        if (HAL_OK == debug_app_check(TFTP_APP_ADDRESS, app_len, 2))
        {
            /* 保存信息并重启设备进入 IAP 升级 APP. */
            dev_info_fireware_size_set(app_len);
            dev_info_magic_set(UPDATE_MAGIC);
            common_sys_set(COM_SYS_SAVE_INFO, 0);
            wl_ctrl.update_rt = HAL_OK;
        }

        wl_ctrl.state = WL_STATE_UPDATE_RT;
        wl_ctrl.mul_idx = 0;
        wl_ctrl.update_len = 0;
    }
    else
    {
        wl_ctrl.mul_idx = m_head->index + 1;
        wl_ctrl.update_len = m_head->len;
    }

    wl_ctrl.time_send = 0;
    wl_ctrl.send_cnt = 0;

    if (dev_info.type_s != DEV_TYPE_ACDC)
    {
        _wl_4G_pkt_id_update();
    }
    else
    {
        wl_ctrl.mul_idx = m_head->index;
        wl_ctrl.update_len = m_head->len;
        wl_ctrl.state = WL_STATE_UPDATE;
        _wl_4G_update_send();
    }
    
    return;
}

/* 设备信息获取报文处理. */
static void _wl_4G_update_rt_reply(void)
{
    /* 有线设备需要回复报文后再休眠. */
    if (DEV_TYPE_ACDC == dev_info.type_s)
    {
        _wl_4G_update_rt_send();
    }

    if (wl_ctrl.update_rt != HAL_OK)
    {
        if (DEV_TYPE_CT_P == dev_info.type_s)
        {
            wl_ctrl.state = WL_STATE_POSITION;
        }
        else
        {
            wl_ctrl.state = WL_STATE_WAVE;
        }
    }
    else
    {
        /* 延迟 1s 等待串口回复报文发送完成. */
        osDelay(1000);
        flash_log_write(FLASH_LOG_TYPE_INFO, "Update APP system sleep 0s!\r\n");
        _wl_4G_hw_close(0);
    }

    wl_ctrl.is_update = 0;
    wl_ctrl.time_send = 0;
    wl_ctrl.send_cnt = 0;

    if (dev_info.type_s != DEV_TYPE_ACDC)
    {
        _wl_4G_pkt_id_update();
    }

    return;
}

/* 工频数据回复. */
static void _wl_4G_power_fre_reply(uint8_t *cmd, uint32_t len)
{
    mul_head_t *m_head = (mul_head_t*)(cmd + sizeof(proto_head_t));
    mul_head_t *m_head_send = (mul_head_t*)(wl_ctrl.dma_tx_buf + sizeof(proto_head_t));

    if (m_head->len < DEBUG_DATA_SIZE)
    {
        wl_ctrl.state = WL_STATE_UPDATE;
        wl_ctrl.mul_idx = 0;
        ADC_ctrl.up_finish = TRUE;
        ADC_ctrl.is_ADC_thr = FALSE;
    }
    else
    {
        wl_ctrl.mul_idx = m_head->index;
    }
    
    wl_ctrl.time_send = 0;
    wl_ctrl.send_cnt = 0;

    if (dev_info.type_s != DEV_TYPE_ACDC)
    {
        _wl_4G_pkt_id_update();
    }
    else
    {
        _wl_4G_power_fre_send();
        /* 发送完成需要通知 ADC继续采集. */
        if (m_head_send->len < DEBUG_DATA_SIZE)
        {
            wl_ctrl.mul_idx = 0;
            ADC_ctrl.up_finish = TRUE;
            ADC_ctrl.is_ADC_thr = FALSE;
        }
    }
    
    return;
}

/* 高频数据回复. */
static void _wl_4G_wave_reply(uint8_t *cmd, uint32_t len)
{
    mul_head_t *m_head = (mul_head_t*)(cmd + sizeof(proto_head_t));
    mul_head_t *m_head_send = (mul_head_t*)(wl_ctrl.dma_tx_buf + sizeof(proto_head_t));

    if (m_head->len < DEBUG_DATA_SIZE)
    {
        wl_ctrl.state = WL_STATE_WAVE_MAX;
        st_data.wave_up_start = FALSE;
        st_data.wave_index = 0;
    }
    else
    {
        st_data.wave_index = m_head->index;
    }

    if (!ADC_ctrl.up_finish)
    {
        wl_ctrl.state = WL_STATE_WAKEUP;
    }
    
    wl_ctrl.time_send = 0;
    wl_ctrl.send_cnt = 0;

    if (dev_info.type_s != DEV_TYPE_ACDC)
    {
        _wl_4G_pkt_id_update();
    }
    else
    {
        _wl_4G_wave_send();
        /* 发送完成需要通知 ADC继续采集. */
        if (m_head_send->len < DEBUG_DATA_SIZE)
        {
            st_data.wave_up_start = FALSE;
            st_data.wave_index = 0;
        }
    }
    
    return;
}

/* 高频数据回复. */
static void _wl_4G_wave_max_reply(uint8_t *cmd, uint32_t len)
{   
    wl_ctrl.state = WL_STATE_END;
    wl_ctrl.time_send = 0;
    wl_ctrl.send_cnt = 0;

    _wl_4G_pkt_id_update();
    if (dev_info.type_s != DEV_TYPE_ACDC)
    {
        _wl_4G_pkt_id_update();
        st_data.wave_max[0] = 0;
        st_data.wave_max[1] = 0;
        st_data.wave_max[2] = 0;
        st_data.wave_max[3] = 0;
    }
    else
    {
        _wl_4G_wave_max_send();
    }

    st_write(&st_data);
    
    return;
}

/* 故障定位波形回复 */
static void _wl_4G_position_wave_reply(uint8_t *cmd, uint32_t len)
{
    position_head_t *p_head = (position_head_t*)(cmd + sizeof(proto_head_t));

    if (p_head->len < DEBUG_DATA_SIZE)
    {
        wl_ctrl.state = WL_STATE_END;
        position_ctrl.position_wave_up = FALSE;
        wl_ctrl.wave_index = 0;
    }
    else
    {
        wl_ctrl.wave_index = p_head->index;
    }

    if (!ADC_ctrl.up_finish)
    {
        wl_ctrl.state = WL_STATE_WAKEUP;
    }

    wl_ctrl.time_send = 0;
    wl_ctrl.send_cnt = 0;
    
    _wl_4G_pkt_id_update();
    return;
}

/* 故障定位行波数据回复. */
static void _wl_4G_position_reply(uint8_t *cmd, uint32_t len)
{
    wl_ctrl.time_send = 0;
    wl_ctrl.send_cnt = 0;
	
    st_data.position_up_id++;
    st_write(&st_data);
	
	if (st_data.position_up_id == position_id)
    {
        wl_ctrl.state = WL_STATE_POSITION_WAVE;
    }
	
	if (!ADC_ctrl.up_finish)
    {
        wl_ctrl.state = WL_STATE_WAKEUP;
    }
    
    _wl_4G_pkt_id_update();
    return;
}

/* 保活报文回复. */
static void _wl_4G_wave_keepalive_reply(void)
{
    wl_ctrl.state = WL_STATE_END;
    wl_ctrl.time_send = 0;
    wl_ctrl.send_cnt = 0;

    _wl_4G_pkt_id_update();
    return;
}

/* 数据回复处理. */
static void _wl_4G_data_process(uint8_t *cmd, uint32_t len)
{
    proto_head_t *head= (proto_head_t*)cmd;
    
    /* 报文头和 CRC 校验. */
    if (_wl_4G_pkt_check(cmd, len) != HAL_OK)
    {
        wl_ctrl.time_send = 0;
        return;
    }

    if (DEBUG_CT_REQUEST == head->cmd_type)
    {
        /* 共有命令处理. */
        switch (head->cmd)
        {
        case DEBUG_C_DEV_INFO:
            _wl_4G_dev_info_reply(cmd, len);
            break;
        case DEBUG_C_UPDATE_APP:
            _wl_4G_update_reply(cmd, len);
            break;
        case DEBUG_C_UPDATE_APP_RT:
            _wl_4G_update_rt_reply();
            break;
        case DEBUG_C_KEEPALIVE:
            _wl_4G_wave_keepalive_reply();
            break;
        default:
            break;
        }
    }
    else if (DEBUG_CT_PRV_REQUEST == head->cmd_type)
    {
        /* 私有命令处理. */
        switch (head->cmd)
        {
        case DEBUG_PRV_REAL_DATA:
            _wl_4G_pkt_reply();
            break;
        case DEBUG_PRV_POWER_FRE:
            _wl_4G_power_fre_reply(cmd, len);
            break;
        case DEBUG_PRV_WAVE:
            _wl_4G_wave_reply(cmd, len);
            break;
        case DEBUG_PRV_WAVE_MAX:
            _wl_4G_wave_max_reply(cmd, len);
            break;
        case DEBUG_PRV_POSITION_WAVE:
            _wl_4G_position_wave_reply(cmd, len);
            break;
        case DEBUG_PRV_POSITION:
            _wl_4G_position_reply(cmd, len);
        default:
            break;
        }
    }
}

/* 发送数据过程中收数据回复. */
void _wl_4G_data_recv(void)
{
    static uint8_t state = 0;
    static uint32_t time = 0;
    wl_buf_list_t *buf_l = &wl_buf_list_rx;
    proto_head_t *head = (proto_head_t*)wl_ctrl.cmd_buf;
    mul_head_t *m_head = (mul_head_t*)(wl_ctrl.cmd_buf + sizeof(proto_head_t));
    uint8_t *buf = NULL;
    uint16_t len = 0;

    /* 超过 3s 没有收包说明收包超时, 重新开始收包. */
    if (HAL_GetTick() - time > 3000)
    {
        wl_ctrl.cmd_buf_index = 0;
        state = 0;
    }
    time = HAL_GetTick();

    /* 遍历所有有效的 buf. */
    while(buf_l->current != buf_l->valid)
    {
        buf = buf_l->buf[buf_l->current];
        len = buf_l->buf_cnt[buf_l->current];
        
        /* 更新 buf index. */
        buf_l->current++;
        if (WL_BUF_LIST_LEN == buf_l->current)
        {
            buf_l->current = 0;
        }

        /* 如果收包大于协议报文长度或者大于 buf 长度, 认为报文错误. */
        if (wl_ctrl.cmd_buf_index + len > WL_DMA_RX_BUF_LEN
            || (wl_ctrl.cmd_buf_index >= 2 && (wl_ctrl.cmd_buf_index + len) > (head->len + WL_CRC32_LEN)))
        {
            wl_ctrl.cmd_buf_index = 0;
            state = 0;
            continue;
        }

        /* 将 buf 中的数据解析成命令. */
        memcpy(&wl_ctrl.cmd_buf[wl_ctrl.cmd_buf_index], buf, len);
        wl_ctrl.cmd_buf_index += len;

        if (!state)
        {
            /* 报文长度不对, 重新收包. */
            if (head->len + WL_CRC32_LEN > WL_DMA_RX_BUF_LEN)
            {
                wl_ctrl.cmd_buf_index = 0;
                continue;
            }

            /* 报文长度与收包长度不对称, 等待后续报文. */
            if (wl_ctrl.cmd_buf_index < head->len + WL_CRC32_LEN)
            {
                state = TRUE;
                continue;
            }
        }
        else
        {
            /* 报文长度与收包长度不对称, 等待后续报文. */
            if (wl_ctrl.cmd_buf_index < head->len + WL_CRC32_LEN)
            {
                continue;
            }

            state = FALSE;
        }

        DBG(DBG_M_4G, "Recv(%d): %d %d %d %d\r\n", wl_ctrl.cmd_buf_index, HAL_GetTick(), head->cmd_type, head->cmd, m_head->index);
        if (dbg_stat_get(DBG_M_4G))
        {
            buf_print(wl_ctrl.cmd_buf, wl_ctrl.cmd_buf_index > 32 ? 32 : wl_ctrl.cmd_buf_index);
            vty_print("\r\n");
        }
        if (DEV_TYPE_ACDC == dev_info.type_s)
        {
            _wir_data_process(wl_ctrl.cmd_buf, wl_ctrl.cmd_buf_index);
        }
        else
        {
            _wl_4G_data_process(wl_ctrl.cmd_buf, wl_ctrl.cmd_buf_index);
        }
        wl_ctrl.cmd_buf_index = 0;
        wl_ctrl.err_cnt = 0;
    }
}

/* 4G 模块发送数据. */
static HAL_StatusTypeDef _wl_4G_transmit(uint8_t *data, uint16_t len)
{
    HAL_StatusTypeDef rv = HAL_ERROR;

    if (wl_ctrl.state < WL_STATE_WAKEUP)
    {
        DBG(DBG_M_4G, "Send: %s\r\n", data);
    }
    else
    {
        proto_head_t *head = (proto_head_t*)data;
        mul_head_t *m_head = (mul_head_t*)(data + sizeof(proto_head_t));
        DBG(DBG_M_4G, "Send(%d): %d %d %d %d\r\n", len, HAL_GetTick(), head->cmd_type, head->cmd, m_head->index);
        if (dbg_stat_get(DBG_M_4G))
        {
            buf_print(data, len > 32 ? 32 : len);
            vty_print("\r\n");
        }
        /* 每次发送数据更新保活时间. */
        wl_ctrl.keepalive = HAL_GetTick() + 60000;
    }

    /* 开启串口空闲中断收包. */
    HAL_UARTEx_ReceiveToIdle_DMA(wl_uart, wl_ctrl.dma_rx_buf, WL_DMA_RX_BUF_LEN);
    HAL_GPIO_WritePin(RS485_B_DE_GPIO_Port, RS485_B_DE_Pin, GPIO_PIN_SET);
    rv = HAL_UART_Transmit_DMA(wl_uart, data, len);
    
    return rv;
}

/* 4G模块接收数据. */
void _wl_4G_receive(void)
{
    if (wl_ctrl.state < WL_STATE_WAKEUP)
    {
        /* 初始化过程中收 AT 指令. */
        _wl_4G_AT_recv();
    }
    else
    {
        if (DEV_TYPE_CSG == dev_info.type_s)
        {
            /* 南网协议报文处理. */
            _csg_pkt_recv();
        }
        else
        {
            /* 发送数据过程中收数据回复. */
            _wl_4G_data_recv();
        }
    }
}

/* 初始化 4G 模块软件 */
static void _wl_4G_init_cmd_send(uint8_t *cmd, uint32_t timeout)
{
    uint8_t len = strlen((char*)cmd);

    /* 复制并发送 AT 命令. */
    snprintf((char*)wl_ctrl.dma_tx_buf, WL_DMA_TX_BUF_LEN, "%s", cmd);
    if (HAL_OK == _wl_4G_transmit(wl_ctrl.dma_tx_buf, len))
    {
        /* 发送成功, 如果指定时间内没有收到回复, 则根据 timeout 时间重发. */
        wl_ctrl.time_send = HAL_GetTick() + timeout;
    }
    else
    {
        /* 发送失败, 等待 1s 重发. */
        wl_ctrl.time_send = HAL_GetTick() + WL_USART_ERR_TIMEOUT;
    }
}

/* 通过 AT 命令进行模块初始化. */
void _wl_4G_init_soft(void)
{
    uint8_t is_timeout = wl_ctrl.time_send < HAL_GetTick();

    if ((WL_STATE_SOFT == wl_ctrl.state) && is_timeout)
    {
        wl_ctrl.time_send = 0;
        wl_ctrl.send_cnt = 0;
        wl_ctrl.state++;
    }
    else if ((WL_STATE_AT_ATE == wl_ctrl.state) && is_timeout)
    {
        /* 关闭 AT 回显. */
        _wl_4G_init_cmd_send("ATE0\r\n", 1100);
        wl_ctrl.send_cnt++;
    }
    else if ((WL_STATE_AT_QICSGP == wl_ctrl.state) && is_timeout)
    {
        /* 创建场景. */
        snprintf((char*)wl_ctrl.dma_tx_buf, WL_DMA_TX_BUF_LEN, "AT+QICSGP=1,1,\"%s\",\"\",\"\",1\r\n", dev_config.APN_long);
        _wl_4G_init_cmd_send(wl_ctrl.dma_tx_buf, 1100);
        wl_ctrl.send_cnt++;
    }
    else if ((WL_STATE_AT_QIACT == wl_ctrl.state) && is_timeout)
    {
        /* 使能场景. */
        _wl_4G_init_cmd_send("AT+QIACT=1\r\n", 33000);
        wl_ctrl.send_cnt++;
    }
    else if ((WL_STATE_AT_CSQ == wl_ctrl.state) && is_timeout)
    {
        /* 读取网络信号质量. */
        osDelay(5000);
        _wl_4G_init_cmd_send("AT+CSQ\r\n", 1100);
        wl_ctrl.send_cnt++;
    }
    else if ((WL_STATE_AT_QICFGTS == wl_ctrl.state) && is_timeout)
    {
        /* 连接远程服务器. */
        snprintf((char*)wl_ctrl.dma_tx_buf, WL_DMA_TX_BUF_LEN, "AT+QICFG=\"transpktsize\",1460\r\n");
        _wl_4G_init_cmd_send(wl_ctrl.dma_tx_buf, 11000);
        wl_ctrl.send_cnt++;
    }
    else if ((WL_STATE_AT_QICFGWT == wl_ctrl.state) && is_timeout)
    {
        /* 连接远程服务器. */
        snprintf((char*)wl_ctrl.dma_tx_buf, WL_DMA_TX_BUF_LEN, "AT+QICFG=\"transwaittm\",0\r\n");
        _wl_4G_init_cmd_send(wl_ctrl.dma_tx_buf, 11000);
        wl_ctrl.send_cnt++;
    }
    else if ((WL_STATE_AT_QIOPEN == wl_ctrl.state) && is_timeout)
    {
        /* 连接远程服务器. */
        snprintf((char*)wl_ctrl.dma_tx_buf, WL_DMA_TX_BUF_LEN, "AT+QIOPEN=1,0,\"TCP\",\"%d.%d.%d.%d\",%d,19421,2\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], dev_info.wireless_server_port);
        //_wl_4G_init_cmd_send("AT+QIOPEN=1,0,\"TCP\",\"111.47.21.142\",9467,19421,2\r\n", 10000);
        _wl_4G_init_cmd_send(wl_ctrl.dma_tx_buf, 11000);
        wl_ctrl.send_cnt++;
    }
    else if (WL_STATE_ADC_WAIT == wl_ctrl.state)
    {
        if (IS_MONITOR_BIT_SET(system_init_flag, SYS_INIT_ADC))
        {
            /* 软件初始化完成. */
            if (DEV_TYPE_CT_P == dev_info.type_s)
            {
                wl_ctrl.state = WL_STATE_END;
            }
            else
            {
                wl_ctrl.state = WL_STATE_WAKEUP;
            }
            
            wl_ctrl.time_send = 0;
            wl_ctrl.send_cnt = 0;
            wl_ctrl.energy_mode_old = ADC_ctrl.energy_mode;
        }
        else if (is_timeout)
        {
            wl_ctrl.time_send = HAL_GetTick() + 10000;
            wl_ctrl.send_cnt++;
        }
    }
}

/* 初始化报文头. */
static void _wl_4G_data_head_init(uint16_t len, uint8_t cmdType, uint8_t cmd)
{
    proto_head_t *head = (proto_head_t*)wl_ctrl.dma_tx_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;
    head->cmd = cmd;
    if (dev_info.type_s != DEV_TYPE_ACDC)
    {
        head->pkt_id = wl_ctrl.pkt_id;
    }
}

/* 设备唤醒, 发送配置和数据请求. */
static void _wl_4G_wakeup_send(void)
{
    proto_head_t *head = (proto_head_t*)wl_ctrl.dma_tx_buf;
    wl_proto_wakeup_t *data = (wl_proto_wakeup_t*)(wl_ctrl.dma_tx_buf + sizeof(proto_head_t));
    uint32_t *crc = NULL;

    /* 封装报文头. */
    _wl_4G_data_head_init(sizeof(proto_head_t) + sizeof(wl_proto_wakeup_t), DEBUG_CT_REPLY, DEBUG_C_DEV_INFO);

    /* 封装数据. */
    memcpy(data, &dev_info.type_m, sizeof(wl_proto_wakeup_t) - DEV_NAME_LEN);
    memcpy(data->name, dev_config.host, DEV_NAME_LEN);

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

    /* 发送报文 */
    if (HAL_OK == _wl_4G_transmit(wl_ctrl.dma_tx_buf, head->len + 4))
    {
        /* 发送成功, 如果指定时间内没有收到回复, 则根据 timeout 时间重发. */
        wl_ctrl.time_send = HAL_GetTick() + 5500;
    }
    else
    {
        /* 发送失败, 等待 1s 重发. */
        wl_ctrl.time_send = HAL_GetTick() + 1100;
    }
}

/* 实时数据发送. */
static void _wl_4G_realdata_send(void)
{
    proto_head_t *head = (proto_head_t*)wl_ctrl.dma_tx_buf;
    wl_proto_realdata_t *data = (wl_proto_realdata_t*)(wl_ctrl.dma_tx_buf + sizeof(proto_head_t));
    uint32_t *crc = NULL;
    uint8_t i = 0;

    /* 封装报文头. */
    _wl_4G_data_head_init(sizeof(proto_head_t) + sizeof(wl_proto_realdata_t), DEBUG_CT_PRV_REPLY, DEBUG_PRV_REAL_DATA);
    
    /* 装填数据. */
    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_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->sen_valid[i] = sensor_value[i].is_valid;
    }
    data->energy_mode = ADC_ctrl.energy_mode;
    data->sen_short = sensor_short;
    data->run_time = HAL_GetTick() / 1000;
    data->fre_valid = !ADC_ctrl.up_finish && ADC_ctrl.is_ADC_thr;
    if (DEV_TYPE_CT_P == dev_info.type_s)
    {
        /* 故障定位设备本次轮询离线 */
        if (position_ctrl.offline)
        {
            /* 上次状态为在线，上送后台设备离线信息 */
            if (position_ctrl.old_status == TRUE)
            {
                data->wave_valid = FALSE;
                position_ctrl.old_status = FALSE;
            }
            /* 上次状态为离线，状态未改变 */
            else
            {
                data->wave_valid = OTHER;
            }
        }
        /* 故障定位设备本次轮询未离线 */
        else
        {
            /* 上次状态为离线，上送后台设备上线信息 */
            if (position_ctrl.old_status == FALSE)
            {
                data->wave_valid = TRUE;
                position_ctrl.old_status = TRUE;
            }
            /* 上次状态为在线，状态未改变 */
            else
            {
                data->wave_valid = OTHER;
            }
        }
    }
    else
    {
        data->wave_valid = !st_data.wave_start && st_data.wave_up_start;
    }
    /* 有线设备不用发送工频时, 需要重新触发工频采样. 需要发送工频时, 在发送完成后设置该标志位. */
    if (!data->fre_valid
        && DEV_TYPE_ACDC == dev_info.type_s)
    {
        ADC_ctrl.up_finish = TRUE;
    }

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

    /* 发送报文. */
    if (HAL_OK == _wl_4G_transmit(wl_ctrl.dma_tx_buf, head->len + 4))
    {
        /* 发送成功, 如果指定时间内没有收到回复, 则根据 timeout 时间重发. */
        wl_ctrl.time_send = HAL_GetTick() + 5500;
    }
    else
    {
        /* 发送失败, 等待 1s 重发. */
        wl_ctrl.time_send = HAL_GetTick() + 1100;
    }
}

/* 工频采样数据获取报文发送. */
static void _wl_4G_power_fre_send(void)
{
    proto_head_t *head = (proto_head_t*)wl_ctrl.dma_tx_buf;
    mul_head_t *m_head = (mul_head_t*)(wl_ctrl.dma_tx_buf + sizeof(proto_head_t));
    uint8_t *data = (uint8_t*)(wl_ctrl.dma_tx_buf + sizeof(proto_head_t) + sizeof(mul_head_t));
    int32_t data_len = 0;
    uint32_t *crc = NULL;

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

    m_head->index = wl_ctrl.mul_idx;

    /* 填充数据, 计算数据长度和报文长度. */
    data_len = ADC_COLLECT_CNT * 5 * 2 - m_head->index * DEBUG_DATA_SIZE;
    if (data_len < 0)
    {
        m_head->len = 0;
    }
    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*)(wl_ctrl.dma_tx_buf + head->len);
    *crc = crc32(wl_ctrl.dma_tx_buf, head->len);

    /* 发送报文 */
    if (HAL_OK == _wl_4G_transmit(wl_ctrl.dma_tx_buf, head->len + 4))
    {
        /* 发送成功, 如果指定时间内没有收到回复, 则根据 timeout 时间重发. */
        wl_ctrl.time_send = HAL_GetTick() + 5500;
    }
    else
    {
        /* 发送失败, 等待 1s 重发. */
        wl_ctrl.time_send = HAL_GetTick() + 1100;
    }
    
    return;
}

/* 高频采样数据获取报文发送. */
static void _wl_4G_wave_send(void)
{
    proto_head_t *head = (proto_head_t*)wl_ctrl.dma_tx_buf;
    mul_head_t *m_head = (mul_head_t*)(wl_ctrl.dma_tx_buf + sizeof(proto_head_t));
    int16_t *data = (int16_t*)(wl_ctrl.dma_tx_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;

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

    m_head->index = st_data.wave_index;

    /* 填充数据, 计算数据长度和报文长度. */
    //data_len = WAVE_ALL_DATA_LEN - m_head->index * DEBUG_DATA_SIZE;
    data_len = WAVE_ALL_DATA_LEN - m_head->index * DEBUG_DATA_SIZE;
    if (data_len < 0)
    {
        m_head->len = 0;
    }
    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;
        if (spi_flash_read(addr, wl_flash, DEBUG_DATA_SIZE) != HAL_OK)
        {
            return;
        }
        wave = (int16_t*)wl_flash;

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

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

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

    /* 发送报文 */
    if (HAL_OK == _wl_4G_transmit(wl_ctrl.dma_tx_buf, head->len + 4))
    {
        /* 发送成功, 如果指定时间内没有收到回复, 则根据 timeout 时间重发. */
        wl_ctrl.time_send = HAL_GetTick() + 5500;
    }
    else
    {
        /* 发送失败, 等待 1s 重发. */
        wl_ctrl.time_send = HAL_GetTick() + 1100;
    }
    
    return;
}

/* 故障定位行波波形文件获取报文发送 */
static HAL_StatusTypeDef _wl_4G_position_wave_send(void)
{
    proto_head_t *head = (proto_head_t*)wl_ctrl.dma_tx_buf;
    position_head_t *p_head = (position_head_t*)(wl_ctrl.dma_tx_buf + sizeof(proto_head_t));
    uint8_t *data = wl_ctrl.dma_tx_buf + sizeof(proto_head_t) + sizeof(position_head_t);
    uint32_t *crc = NULL;

    /* 封装报文头 */
    _wl_4G_data_head_init(sizeof(proto_head_t), DEBUG_CT_PRV_REPLY, DEBUG_PRV_POSITION_WAVE);

    p_head->index = wl_ctrl.wave_index;
    p_head->file_s = position_ctrl.position_file_s;
    p_head->file_ns = position_ctrl.position_file_ns;
    if (HAL_OK != position_wave(data, p_head->index, &(p_head->len), p_head->file_s, p_head->file_ns))
    {
        position_ctrl.send_cnt++;
        return HAL_ERROR;
    }

    head->len = sizeof(proto_head_t) + sizeof(position_head_t) + p_head->len;

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

    /* 发送报文 */
    if (HAL_OK == _wl_4G_transmit(wl_ctrl.dma_tx_buf, head->len + 4))
    {
        /* 发送成功, 如果指定时间内没有收到回复, 则根据 timeout 时间重发. */
        wl_ctrl.time_send = HAL_GetTick() + 5500;
    }
    else
    {
        /* 发送失败, 等待 1s 重发. */
        wl_ctrl.time_send = HAL_GetTick() + 1100;
    }
    
    return HAL_OK;
}

/* 升级请求报文发送. */
static void _wl_4G_update_send(void)
{
    proto_head_t *head = (proto_head_t*)wl_ctrl.dma_tx_buf;
    mul_head_t *m_head = (mul_head_t*)(wl_ctrl.dma_tx_buf + sizeof(proto_head_t));
    uint32_t *crc = NULL;

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

    head->len = sizeof(proto_head_t) + sizeof(mul_head_t);
    m_head->index = wl_ctrl.mul_idx;
    m_head->len = wl_ctrl.update_len;

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

    /* 发送报文 */
    if (HAL_OK == _wl_4G_transmit(wl_ctrl.dma_tx_buf, head->len + 4))
    {
        /* 发送成功, 如果指定时间内没有收到回复, 则根据 timeout 时间重发. */
        wl_ctrl.time_send = HAL_GetTick() + 5500;
    }
    else
    {
        /* 发送失败, 等待 1s 重发. */
        wl_ctrl.time_send = HAL_GetTick() + 1100;
    }
    
    return;
}

/* 升级请求报文发送. */
static void _wl_4G_update_rt_send(void)
{
    proto_head_t *head = (proto_head_t*)wl_ctrl.dma_tx_buf;
    int32_t *rt = (int32_t*)(wl_ctrl.dma_tx_buf + sizeof(proto_head_t));
    uint32_t *crc = NULL;

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

    head->len = sizeof(proto_head_t) + sizeof(int32_t);
    *rt = wl_ctrl.update_rt;

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

    /* 发送报文 */
    if (HAL_OK == _wl_4G_transmit(wl_ctrl.dma_tx_buf, head->len + 4))
    {
        /* 发送成功, 如果指定时间内没有收到回复, 则根据 timeout 时间重发. */
        wl_ctrl.time_send = HAL_GetTick() + 5500;
    }
    else
    {
        /* 发送失败, 等待 1s 重发. */
        wl_ctrl.time_send = HAL_GetTick() + 1100;
    }
    
    return;
}

/* 高频录波最大值数据发送. */
static void _wl_4G_wave_max_send(void)
{
    proto_head_t *head = (proto_head_t*)wl_ctrl.dma_tx_buf;
    wl_proto_wave_max_t *data = (wl_proto_wave_max_t*)(wl_ctrl.dma_tx_buf + sizeof(proto_head_t));
    uint32_t *crc = NULL;
    uint8_t i = 0;

    /* 封装报文头. */
    _wl_4G_data_head_init(sizeof(proto_head_t) + sizeof(wl_proto_wave_max_t), DEBUG_CT_PRV_REPLY, DEBUG_PRV_WAVE_MAX);
    
    /* 装填数据. */
    for(i = 0; i < WAVE_SUM; i ++)
    {
        data->wave[i] = st_data.wave_max[i];
    }

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

    /* 发送报文. */
    if (HAL_OK == _wl_4G_transmit(wl_ctrl.dma_tx_buf, head->len + 4))
    {
        /* 发送成功, 如果指定时间内没有收到回复, 则根据 timeout 时间重发. */
        wl_ctrl.time_send = HAL_GetTick() + 5500;
    }
    else
    {
        /* 发送失败, 等待 1s 重发. */
        wl_ctrl.time_send = HAL_GetTick() + 1100;
    }
}

/* 故障定位时间戳发送. */
static void _wl_4G_position_send(void)
{
    proto_head_t *head = (proto_head_t*)wl_ctrl.dma_tx_buf;
    position_wave_info_t *wave_info = (position_wave_info_t*)(wl_ctrl.dma_tx_buf + sizeof(proto_head_t));
    uint32_t *crc = NULL;

    /* 封装报文头. */
    _wl_4G_data_head_init(sizeof(proto_head_t) + sizeof(position_wave_info_t), DEBUG_CT_PRV_REPLY, DEBUG_PRV_POSITION);
    
    /* 装填数据. */
    if (position_read(st_data.position_up_id, &position_up_data) != HAL_OK)
    {
        if (st_data.position_up_id > position_id)
        {
            st_data.position_up_id = position_id;
        }
        wl_ctrl.state = WL_STATE_POSITION_WAVE;
        return;
    }
    memcpy(wave_info, &(position_up_data.wave_info), sizeof(position_wave_info_t));

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

    /* 发送报文. */
    if (HAL_OK == _wl_4G_transmit(wl_ctrl.dma_tx_buf, head->len + 4))
    {
        /* 发送成功, 如果指定时间内没有收到回复, 则根据 timeout 时间重发. */
        wl_ctrl.time_send = HAL_GetTick() + 5500;
    }
    else
    {
        /* 发送失败, 等待 1s 重发. */
        wl_ctrl.time_send = HAL_GetTick() + 1100;
    }
}

/* 保活报文发送. */
static void _wl_4G_wave_keepalive_send(void)
{
    proto_head_t *head = (proto_head_t*)wl_ctrl.dma_tx_buf;
    uint32_t *crc = NULL;

    /* 封装报文头. */
    _wl_4G_data_head_init(sizeof(proto_head_t), DEBUG_CT_REPLY, DEBUG_C_KEEPALIVE);
    
    /* 计算校验和. */
    crc = (uint32_t*)(wl_ctrl.dma_tx_buf + head->len);
    *crc = crc32(wl_ctrl.dma_tx_buf, head->len);

    /* 发送报文. */
    if (HAL_OK == _wl_4G_transmit(wl_ctrl.dma_tx_buf, head->len + 4))
    {
        /* 发送成功, 如果指定时间内没有收到回复, 则根据 timeout 时间重发. */
        wl_ctrl.time_send = HAL_GetTick() + 5500;
    }
    else
    {
        /* 发送失败, 等待 1s 重发. */
        wl_ctrl.time_send = HAL_GetTick() + 1100;
    }
}

/* 传感器数据发送. */
void _wl_4G_data_send(void)
{
    uint8_t is_timeout = wl_ctrl.time_send < HAL_GetTick();

    /* 循环内只发送一次报文, 没有报文发送的情况下要跳出循环. */
    while(is_timeout)
    {
		if (WL_STATE_WAKEUP == wl_ctrl.state)
        {
            /* 设备唤醒, 发送配置和数据请求. */
            _wl_4G_wakeup_send();
            wl_ctrl.send_cnt++;
            break;
        }
        else if (WL_STATE_REALDATA == wl_ctrl.state)
        {
            /* 实时数据报文. */
            _wl_4G_realdata_send();
            wl_ctrl.send_cnt++;
            break;
        }
        else if (WL_STATE_PWR_FRE == wl_ctrl.state)
        {
            /* 工频录波报文. */
            if (!ADC_ctrl.up_finish && ADC_ctrl.is_ADC_thr)
            {
                _wl_4G_power_fre_send();
                wl_ctrl.send_cnt++;
                break;
            }
            else
            {
                ADC_ctrl.up_finish = TRUE;
                ADC_ctrl.is_ADC_thr = FALSE;
                wl_ctrl.state = WL_STATE_UPDATE;
                wl_ctrl.mul_idx = 0;
                wl_ctrl.time_send = 0;
                wl_ctrl.send_cnt = 0;
            }
        }
        else if (WL_STATE_UPDATE == wl_ctrl.state)
        {
            if (wl_ctrl.is_update)
            {
                _wl_4G_update_send();
                wl_ctrl.send_cnt++;
                break;
            }
            else
            {
                if (DEV_TYPE_CT_P == dev_info.type_s)
                {
                    wl_ctrl.state = WL_STATE_POSITION;
                }
                else
                {
                    wl_ctrl.state = WL_STATE_WAVE;
                }
                wl_ctrl.time_send = 0;
                wl_ctrl.send_cnt = 0;
            }
        }
        else if (WL_STATE_UPDATE_RT == wl_ctrl.state)
        {
            if (wl_ctrl.is_update)
            {
                _wl_4G_update_rt_send();
                wl_ctrl.send_cnt++;
                break;
            }
            else
            {
                if (DEV_TYPE_CT_P == dev_info.type_s)
                {
                    wl_ctrl.state = WL_STATE_POSITION;
                }
                else
                {
                    wl_ctrl.state = WL_STATE_WAVE;
                }
				wl_ctrl.time_send = 0;
                wl_ctrl.send_cnt = 0;
            }
        }
        else if (WL_STATE_WAVE == wl_ctrl.state)
        {
            /* 高频录波报文. */
            if (!st_data.wave_start && st_data.wave_up_start && ADC_ENERGY_NORMAL == ADC_ctrl.energy_mode)
            {
                _wl_4G_wave_send();
                wl_ctrl.send_cnt++;
                break;
            }
            else
            {
                wl_ctrl.state = WL_STATE_WAVE_MAX;
                wl_ctrl.time_send = 0;
                wl_ctrl.send_cnt = 0;
            }
        }
        else if (WL_STATE_WAVE_MAX == wl_ctrl.state)
        {
            /* 高频最大值报文. */
            if ((st_data.wave_max[0] || st_data.wave_max[1] || st_data.wave_max[2] || st_data.wave_max[3])
                && (ADC_ENERGY_NORMAL == ADC_ctrl.energy_mode))
            {
                _wl_4G_wave_max_send();
                wl_ctrl.send_cnt++;
            }
            else
            {
                wl_ctrl.state = WL_STATE_END;
                wl_ctrl.time_send = 0;
                wl_ctrl.send_cnt = 0;
            }
            break;
        }
        else if (WL_STATE_POSITION == wl_ctrl.state)
        {
            if (st_data.position_up_id < position_id)
            {
                _wl_4G_position_send();
                wl_ctrl.send_cnt++;
                break;
            }
            else
            {
                wl_ctrl.state = WL_STATE_POSITION_WAVE;
                wl_ctrl.time_send = 0;
                wl_ctrl.send_cnt = 0;
            }
        }
        else if (WL_STATE_POSITION_WAVE == wl_ctrl.state)
        {
            if (position_ctrl.position_wave_up)
            {
                if (HAL_OK == _wl_4G_position_wave_send())
                {
                    wl_ctrl.send_cnt++;
                }
            }
            else
            {
                wl_ctrl.state = WL_STATE_END;
                wl_ctrl.time_send = 0;
                wl_ctrl.send_cnt = 0;
            }
            break;
        }
        if (WL_STATE_KEEPALIVE == wl_ctrl.state)
        {
            /* 设备保活报文发送. */
            _wl_4G_wave_keepalive_send();
            wl_ctrl.send_cnt++;
            break;
        }
        else
        {
            break;
        }
    }
}

/* 无线模块主任务循环. */
static void _wl_4G_start(void *argument)
{
    uint32_t notify_value = 0;

    /* 等待完成 1 次 ADC 采样. */
    while(1)
    {
        if (IS_MONITOR_BIT_SET(system_init_flag, SYS_INIT_ADC))
        {
            break;
        }

        osDelay(1000);
    }

    if (DEV_TYPE_CT_P == dev_info.type_s)
    {
        /* 完成 1 次 故障定位轮询 */
        position_start();
    }

    /* 开启串口空闲中断收包. */
    HAL_UARTEx_ReceiveToIdle_DMA(wl_uart, wl_ctrl.dma_rx_buf, WL_DMA_RX_BUF_LEN);

    /* 初始化 4G 模块硬件. */
    _wl_4G_hw_init();

    /* 20s 内要收到 4G 模块发出的 RDY. */
    wl_ctrl.time_send = HAL_GetTick() + 20000;
    wl_ctrl.wave_index = st_data.wave_index;
    
    for (;;)
    {    
        /* AT 指令发送失败, 直接退出. */
        if (wl_ctrl.send_cnt > WL_SOFT_INIT_ERR && wl_ctrl.state < WL_STATE_WAKEUP)
        {
            //flash_log_write(FLASH_LOG_TYPE_INFO, "4G module is ERROR system sleep %ds!\r\n", dev_config.collect_interval * 60);
            //_wl_4G_hw_close(dev_config.collect_interval * 60);
            _wl_4G_hw_restart();
        }

        /* 数据发送失败, 重启 4G 模块 1 次. */
        if (wl_ctrl.send_cnt > WL_DATA_ERR && wl_ctrl.state >= WL_STATE_WAKEUP)
        {
            _wl_4G_hw_restart();
        }
    
        if (wl_ctrl.state < WL_STATE_WAKEUP)
        {   
            /* 进入软件初始化. */
            _wl_4G_init_soft();
        }
        else if (wl_ctrl.state != WL_STATE_END)
        {
            /* 进入数据交互模式. */
            _wl_4G_data_send();
        }
        else
        {
            /* 仅在4G通讯闲暇时轮询故障定位 */
		    if (DEV_TYPE_CT_P == dev_info.type_s && !wl_ctrl.send_cnt)
            {
                if (HAL_OK != position_start())
                {
                    /* 将设备离线信息上送后台 */
                    if (position_ctrl.err_cnt == POSITION_ERR_MAX)
                    {
                        wl_ctrl.state = WL_STATE_WAKEUP;
                    }
                    else if (position_ctrl.err_cnt > POSITION_ERR_MAX)
                    {
                        /* 通过 4G 模块重启设备 */
                        flash_log_write(FLASH_LOG_TYPE_WARNING, "Position is disconnect system reset!\r\n");
                        _wl_4G_hw_close(0);
                        return;
                    }
                }
            }
            /* 当状态为 WL_STATE_END 时, 先判断节能模式. */
            if (ADC_ctrl.energy_mode != ADC_ENERGY_NORMAL
                || (dev_config.normal_sleep && DEV_TYPE_CT_P != dev_info.type_s)
                || DEV_TYPE_BAT == dev_info.type_s)
            {
                if (ADC_ctrl.energy_mode != wl_ctrl.energy_mode_old)
                {
                    /* 模式发生转换并不立即休眠, 将状态发送给服务器后再休眠. */
                    wl_ctrl.state = WL_STATE_WAKEUP;
                }
                else if(ADC_ENERGY_NORMAL == ADC_ctrl.energy_mode
                    && DEV_TYPE_BAT == dev_info.type_s
                    && st_data.wave_start
                    && dev_config.is_wave_col != 0
                    && ADC_ctrl.ADCi_vbat >= 3600)
                {
                    /* 电池正常是模式下, 如果有高频采样, 等高频采样完成进行据发送, 不要休眠. */
                    while(wave_ctrl.state.state != WAVE_STATE_COMPLETION)
                    {
                        osDelay(3000);
                    }

                    if (wave_ctrl.rt != WAVE_RT_END)
                    {
                        flash_log_write(FLASH_LOG_TYPE_INFO, "System sleep %ds!\r\n", dev_config.collect_interval * 60 - 30);
                        _wl_4G_hw_close(dev_config.collect_interval * 60 - 30);
                    }

                    if (!st_data.wave_start && st_data.wave_up_start)
                    {
                        wl_ctrl.state = WL_STATE_WAVE;
                    }
                }
                else
                {
                    flash_log_write(FLASH_LOG_TYPE_INFO, "System sleep %ds!\r\n", dev_config.collect_interval * 60 - 30);
                    _wl_4G_hw_close(dev_config.collect_interval * 60 - 30);
                }
            }
            else if (!ADC_ctrl.up_finish)
            {
                wl_ctrl.state = WL_STATE_WAKEUP;
            }
            else if(!st_data.wave_start && st_data.wave_up_start)
            {
                wl_ctrl.state = WL_STATE_WAVE;
            }
            else if(st_data.position_up_id < position_id)
            {
                wl_ctrl.state = WL_STATE_POSITION;
            }
            else if(position_ctrl.position_wave_up)
            {
                wl_ctrl.state = WL_STATE_POSITION_WAVE;
            }
            else if(wl_ctrl.keepalive < HAL_GetTick())
            {
                wl_ctrl.state = WL_STATE_KEEPALIVE;
                /* 每次发送数据更新保活时间. */
                wl_ctrl.keepalive = HAL_GetTick() + 60000;
            }
            
            /* 更新工作模式. */
            wl_ctrl.energy_mode_old = ADC_ctrl.energy_mode;
        }

        /* 喂狗. */
        common_watchdog_set(COM_WDG_WIR);

        /* 等待 DMA 收包中断. */
        notify_value = ulTaskNotifyTake(pdTRUE, WL_RX_TIMEOUT);
        /* 收包超时, 返回循环头部. */
        if (0 == notify_value)
        {
            continue;
        }

        /* 收包处理. */
        _wl_4G_receive();
    }
}

/* 有线数据处理. */
static void _wir_data_process(uint8_t *cmd, uint32_t len)
{
    proto_head_t *head = (proto_head_t*)cmd;
    
    /* 报文头和 CRC 校验. */
    if (_wl_4G_pkt_check(cmd, len) != HAL_OK)
    {
        return;
    }

    if (DEBUG_CT_REQUEST == head->cmd_type)
    {
        /* 共有命令处理. */
        switch (head->cmd)
        {
        case DEBUG_C_DEV_INFO:
            _wl_4G_dev_info_reply(cmd, len);
            break;
        case DEBUG_C_UPDATE_APP:
            _wl_4G_update_reply(cmd, len);
            break;
        case DEBUG_C_UPDATE_APP_RT:
            _wl_4G_update_rt_reply();
            break;
        default:
            break;
        }
    }
    else if (DEBUG_CT_PRV_REQUEST == head->cmd_type)
    {
        /* 私有命令处理. */
        switch (head->cmd)
        {
        case DEBUG_PRV_REAL_DATA:
            _wl_4G_pkt_reply();
            break;
        case DEBUG_PRV_POWER_FRE:
            _wl_4G_power_fre_reply(cmd, len);
            break;
        case DEBUG_PRV_WAVE:
            _wl_4G_wave_reply(cmd, len);
            break;
        case DEBUG_PRV_WAVE_MAX:
            _wl_4G_wave_max_reply(cmd, len);
            break;
        default:
            break;
        }
    }
}

/* 有线模式主任务循环. */
static void _wir_start(void *argument)
{
    uint32_t notify_value = 0;

    /* RS485 供电打开. */
    HAL_GPIO_WritePin(POWER_EN_4G_GPIO_Port, POWER_EN_4G_Pin, GPIO_PIN_SET);
    
    /* 开启串口空闲中断收包. */
    HAL_UARTEx_ReceiveToIdle_DMA(wl_uart, wl_ctrl.dma_rx_buf, WL_DMA_RX_BUF_LEN);
    
    for (;;)
    {
        /* 喂狗. */
        common_watchdog_set(COM_WDG_WIR);

        /* 等待 DMA 收包中断. */
        notify_value = ulTaskNotifyTake(pdTRUE, WIR_RX_TIMEOUT);
        /* 收包超时, 返回循环头部. */
        if (0 == notify_value)
        {
            continue;
        }

        /* 收包处理. */
        _wl_4G_data_recv();
    }
}

/* 4G 模块发送数据. */
static HAL_StatusTypeDef _csg_transmit(uint8_t *data, uint16_t len)
{
    HAL_StatusTypeDef rv = HAL_ERROR;

    if (wl_ctrl.state < WL_STATE_WAKEUP)
    {
        DBG(DBG_M_4G, "Send: %s\r\n", data);
    }
    else
    {
        csg_head_t *head = (csg_head_t*)data;
        DBG(DBG_M_4G, "Send(%d): 0x%x\r\n", len, head->cmd);
        if (dbg_stat_get(DBG_M_4G))
        {
            buf_print(data, len > 32 ? 32 : len);
            //buf_print(data, len);
            vty_print("\r\n");
        }
        /* 每次发送数据更新保活时间. */
        wl_ctrl.keepalive = HAL_GetTick() + 60000;
    }

    rv = HAL_UART_Transmit_DMA(wl_uart, data, len);
    
    return rv;
}

static uint8_t _csg_crc(uint8_t *data, uint16_t len)
{
    uint8_t  crc = 0x00;
    uint32_t sum = 0x0000;
    uint16_t i = 0;
    
    for(i = 0; i < len; i++)
    {
        sum += data[i];
    }

    crc = ~(uint8_t)(sum);
    return crc;
}

/* 初始化报文头. */
static void _csg_data_head_init(uint16_t len, uint8_t cmd)
{
    csg_head_t *head = (csg_head_t*)wl_ctrl.dma_tx_buf;

    /* 封装报文头. */
    head->flag = CSG_START_FLAG;
    memcpy(head->dev_id, dev_info.csg_id, 6);
    head->cmd = cmd;
    head->len = PP_HTONS(len);
}

/* 错误回复报文. */
static void _csg_error_send(uint8_t cmd, uint16_t rt)
{
    uint16_t *data = (uint16_t*)(wl_ctrl.dma_tx_buf + CSG_HEAD_LEN);
    uint8_t *crc = (uint8_t*)(wl_ctrl.dma_tx_buf + CSG_HEAD_LEN + CSG_ERROR_LEN);
    uint8_t *end_flag = (uint8_t*)(wl_ctrl.dma_tx_buf + CSG_HEAD_LEN + CSG_ERROR_LEN + CSG_CRC_LEN);

    /* 封装报文头. */
    _csg_data_head_init(CSG_ERROR_LEN, cmd);

    /* 封装数据. */
    *data = PP_HTONS(rt);

    /* 计算校验和. */
    *crc = _csg_crc(wl_ctrl.dma_tx_buf + 1, CSG_ERROR_LEN + CSG_HEAD_LEN - 1);
    *end_flag = CSG_END_FLAG;

    /* 发送报文 */
    _csg_transmit(wl_ctrl.dma_tx_buf, CSG_ERROR_LEN + CSG_OTHER_LEN);
}

/* 开机联络报文. */
static void _csg_connect_send(uint8_t is_request)
{
    uint16_t *data = (uint16_t*)(wl_ctrl.dma_tx_buf + CSG_HEAD_LEN);
    uint8_t *crc = (uint8_t*)(wl_ctrl.dma_tx_buf + CSG_HEAD_LEN + CSG_CONNECT_LEN);
    uint8_t *end_flag = (uint8_t*)(wl_ctrl.dma_tx_buf + CSG_HEAD_LEN + CSG_CONNECT_LEN + CSG_CRC_LEN);

    /* 封装报文头. */
    _csg_data_head_init(CSG_CONNECT_LEN, CSG_CONNECT);

    /* 封装数据. */
    *data = PP_HTONS(dev_info.csg_version);

    /* 计算校验和. */
    *crc = _csg_crc(wl_ctrl.dma_tx_buf + 1, CSG_CONNECT_LEN + CSG_HEAD_LEN - 1);
    *end_flag = CSG_END_FLAG;

    /* 发送报文 */
    if (is_request)
    {
        _csg_transmit(wl_ctrl.dma_tx_buf, CSG_CONNECT_LEN + CSG_OTHER_LEN);
    }
    else
    {
        if (HAL_OK == _csg_transmit(wl_ctrl.dma_tx_buf, CSG_CONNECT_LEN + CSG_OTHER_LEN))
        {
            /* 发送成功, 如果指定时间内没有收到回复, 则根据 timeout 时间重发. */
            wl_ctrl.time_send = HAL_GetTick() + 5500;
        }
        else
        {
            /* 发送失败, 等待 1s 重发. */
            wl_ctrl.time_send = HAL_GetTick() + 1100;
        }        
    }
}

/* 对时报文. */
static void _csg_time_send(void)
{
    uint8_t *crc = (uint8_t*)(wl_ctrl.dma_tx_buf + CSG_HEAD_LEN);
    uint8_t *end_flag = (uint8_t*)(wl_ctrl.dma_tx_buf + CSG_HEAD_LEN + CSG_CRC_LEN);

    /* 封装报文头. */
    _csg_data_head_init(CSG_TIMING_LEN, CSG_TIMING);

    /* 计算校验和. */
    *crc = _csg_crc(wl_ctrl.dma_tx_buf + 1, CSG_HEAD_LEN - 1);
    *end_flag = CSG_END_FLAG;

    /* 发送报文 */
    if (HAL_OK == _csg_transmit(wl_ctrl.dma_tx_buf, CSG_OTHER_LEN))
    {
        /* 发送成功, 如果指定时间内没有收到回复, 则根据 timeout 时间重发. */
        wl_ctrl.time_send = HAL_GetTick() + 5500;
    }
    else
    {
        /* 发送失败, 等待 1s 重发. */
        wl_ctrl.time_send = HAL_GetTick() + 1100;
    }
}

/* 实时数据报文. */
static void _csg_data_send_his(void)
{
    struct tm *day = NULL;
    csg_data_t *data = (csg_data_t*)(wl_ctrl.dma_tx_buf + CSG_HEAD_LEN);
    uint8_t *crc = (uint8_t*)(wl_ctrl.dma_tx_buf + CSG_HEAD_LEN + CSG_DATA_LEN);
    uint8_t *end_flag = (uint8_t*)(wl_ctrl.dma_tx_buf + CSG_HEAD_LEN + CSG_DATA_LEN + CSG_CRC_LEN);
    uint8_t i = 0;
    uint16_t temp = 0;
    uint32_t time = 0;

    /* 封装报文头. */
    _csg_data_head_init(CSG_DATA_LEN, CSG_DATA);

    /* 封装数据. */
    memcpy(data->Ciphertext, dev_config.csg_ciphertext, CSG_CIPHERTEXT_LEN);
    
    data->flag = 0;
    data->sum = 0;

    csg_adc_data.id = fd_id;
    for(i = 0; i < CSG_PKT_DATA_SUM; i++)
    {
        if (fd_read(csg_adc_data.id, &csg_adc_data) != HAL_OK)
            break;

        /* 读到全F,表示结束了. */
        if (FD_INVALID_ID == csg_adc_data.id)
            break;

        /* 只要历史数据. */
        if (!csg_adc_data.is_not_updata)
        {
            csg_adc_data.id--;
            if (0 == csg_adc_data.id)
            {
                break;
            }
            continue;
        }

        csg_data_idx[data->sum] = csg_adc_data.id;
        data->sum++;
        csg_data_idx[data->sum] = 0;
        vty_print("%d %d\r\n", data->sum, csg_adc_data.id);
        vty_print("%d/%d/%d %d:%d:%d\r\n", data->time[0], data->time[1], data->time[2], data->time[3], data->time[4], data->time[5]);

        time = csg_adc_data.run_time + 28800;
        day = localtime(&time);
        data->time[0] = day->tm_year - 100;
        data->time[1] = day->tm_mon + 1;
        data->time[2] = day->tm_mday;
        data->time[3] = day->tm_hour;
        data->time[4] = day->tm_min;
        data->time[5] = day->tm_sec;

        temp = csg_adc_data.elec[0] / 100;
        data->Ia = PP_HTONS(temp);
        temp = csg_adc_data.elec[1] / 100;
        data->Ib = PP_HTONS(temp);
        temp = csg_adc_data.elec[2] / 100;
        data->Ic = PP_HTONS(temp);
        temp = csg_adc_data.elec[3] / 100;
        data->ground = PP_HTONS(temp);
        temp = csg_adc_data.elec[4] / 100;
        data->rIa = PP_HTONS(temp);
        data->rIb = 0;
        data->rIc = 0;

        break;
    }

    if (0 == data->sum)
    {
        wl_ctrl.state = CSG_STATE_IDLE;
        wl_ctrl.time_send = 0;
        wl_ctrl.send_cnt = 0;
    }
    else
    {
        /* 计算校验和. */
        *crc = _csg_crc(wl_ctrl.dma_tx_buf + 1, CSG_DATA_LEN + CSG_HEAD_LEN - 1);
        *end_flag = CSG_END_FLAG;

        /* 发送报文 */
        if (HAL_OK == _csg_transmit(wl_ctrl.dma_tx_buf, CSG_DATA_LEN + CSG_OTHER_LEN))
        {
            /* 发送成功, 如果指定时间内没有收到回复, 则根据 timeout 时间重发. */
            wl_ctrl.time_send = HAL_GetTick() + 5500;
        }
        else
        {
            /* 发送失败, 等待 1s 重发. */
            wl_ctrl.time_send = HAL_GetTick() + 1100;
        }
    }
}

/* 实时数据上传. */
static void _csg_data_send_realtime(void)
{
    struct tm *day = NULL;
    csg_data_t *data = (csg_data_t*)(wl_ctrl.dma_tx_buf + CSG_HEAD_LEN);
    uint8_t *crc = (uint8_t*)(wl_ctrl.dma_tx_buf + CSG_HEAD_LEN + CSG_DATA_LEN);
    uint8_t *end_flag = (uint8_t*)(wl_ctrl.dma_tx_buf + CSG_HEAD_LEN + CSG_DATA_LEN + CSG_CRC_LEN);
    uint16_t temp = 0;
    uint32_t time = 0;   

    /* 封装报文头. */
    _csg_data_head_init(CSG_DATA_LEN, CSG_DATA);

    /* 封装数据. */
    memcpy(data->Ciphertext, dev_config.csg_ciphertext, CSG_CIPHERTEXT_LEN);
    data->flag = 0x00;
    data->sum = 0x01;

    fd_read(fd_id, &csg_adc_data);
    csg_data_idx[0] = fd_id;
    csg_data_idx[1] = 0;
    time = csg_adc_data.run_time + 28800;
    day = localtime(&time);
    data->time[0] = day->tm_year - 100;
    data->time[1] = day->tm_mon + 1;
    data->time[2] = day->tm_mday;
    data->time[3] = day->tm_hour;
    data->time[4] = day->tm_min;
    data->time[5] = day->tm_sec;

    vty_print("%d/%d/%d %d:%d:%d\r\n", data->time[0], data->time[1], data->time[2], data->time[3], data->time[4], data->time[5]);

    temp = csg_adc_data.elec[0] / 100;
    data->Ia = PP_HTONS(temp);
    temp = csg_adc_data.elec[1] / 100;
    data->Ib = PP_HTONS(temp);
    temp = csg_adc_data.elec[2] / 100;
    data->Ic = PP_HTONS(temp);
    temp = csg_adc_data.elec[3] / 100;
    data->ground = PP_HTONS(temp);
    temp = csg_adc_data.elec[4] / 100;
    data->rIa = PP_HTONS(temp);
    data->rIb = 0;
    data->rIc = 0;

    /* 计算校验和. */
    *crc = _csg_crc(wl_ctrl.dma_tx_buf + 1, CSG_DATA_LEN + CSG_HEAD_LEN - 1);
    *end_flag = CSG_END_FLAG;

    /* 发送报文 */
    if (HAL_OK == _csg_transmit(wl_ctrl.dma_tx_buf, CSG_DATA_LEN + CSG_OTHER_LEN))
    {
        /* 发送成功, 如果指定时间内没有收到回复, 则根据 timeout 时间重发. */
        wl_ctrl.time_send = HAL_GetTick() + 5500;
    }
    else
    {
        /* 发送失败, 等待 1s 重发. */
        wl_ctrl.time_send = HAL_GetTick() + 1100;
    }
}

/* 心跳报文. */
static void _csg_beat_send(void)
{
    csg_beat_t *data = (csg_beat_t*)(wl_ctrl.dma_tx_buf + CSG_HEAD_LEN);
    uint8_t *crc = (uint8_t*)(wl_ctrl.dma_tx_buf + CSG_HEAD_LEN + CSG_BEAT_LEN);
    uint8_t *end_flag = (uint8_t*)(wl_ctrl.dma_tx_buf + CSG_HEAD_LEN + CSG_BEAT_LEN + CSG_CRC_LEN);

    /* 封装报文头. */
    _csg_data_head_init(CSG_BEAT_LEN, CSG_BEAT);

    /* 封装数据. */
    HAL_RTC_GetTime(&hrtc, &time_structure, RTC_FORMAT_BIN);
    HAL_RTC_GetDate(&hrtc, &date_structure, RTC_FORMAT_BIN);
    data->time[0] = date_structure.Year;
    data->time[1] = date_structure.Month;
    data->time[2] = date_structure.Date;
    data->time[3] = time_structure.Hours;
    data->time[4] = time_structure.Minutes;
    data->time[5] = time_structure.Seconds;
    data->CSQ = (wl_ctrl.CSQ + 115) * 100 / 64;
    data->vbat = ADC_ctrl.ADCi_vbat / 100;

    /* 计算校验和. */
    *crc = _csg_crc(wl_ctrl.dma_tx_buf + 1, CSG_BEAT_LEN + CSG_HEAD_LEN - 1);
    *end_flag = CSG_END_FLAG;

    /* 发送报文 */
    if (HAL_OK == _csg_transmit(wl_ctrl.dma_tx_buf, CSG_BEAT_LEN + CSG_OTHER_LEN))
    {
        /* 发送成功, 如果指定时间内没有收到回复, 则根据 timeout 时间重发. */
        wl_ctrl.time_send = HAL_GetTick() + 5500;
    }
    else
    {
        /* 发送失败, 等待 1s 重发. */
        wl_ctrl.time_send = HAL_GetTick() + 1100;
    }
    wl_ctrl.time_beat = HAL_GetTick();
}

/* 服务器信息报文发送. */
static void _csg_server_send(void)
{
    csg_server_get_t *data = (csg_server_get_t*)(wl_ctrl.dma_tx_buf + CSG_HEAD_LEN);
    uint8_t *crc = (uint8_t*)(wl_ctrl.dma_tx_buf + CSG_HEAD_LEN + CSG_SERVER_GET_LEN);
    uint8_t *end_flag = (uint8_t*)(wl_ctrl.dma_tx_buf + CSG_HEAD_LEN + CSG_SERVER_GET_LEN + CSG_CRC_LEN);

    /* 封装报文头. */
    _csg_data_head_init(CSG_SERVER_GET_LEN, CSG_SERVER_GET);

    /* 封装数据. */
    memcpy(data->ip, dev_info.wireless_server_ip, 4);
    data->port = PP_HTONS(dev_info.wireless_server_port);
    memcpy(data->card, dev_info.csg_card, 6);

    /* 计算校验和. */
    *crc = _csg_crc(wl_ctrl.dma_tx_buf + 1, CSG_SERVER_GET_LEN + CSG_HEAD_LEN - 1);
    *end_flag = CSG_END_FLAG;

    /* 发送报文 */
    _csg_transmit(wl_ctrl.dma_tx_buf, CSG_SERVER_GET_LEN + CSG_OTHER_LEN);
}

/* 配饰获取报文发送. */
static void _csg_config_send(void)
{
    uint8_t *data = (uint8_t*)(wl_ctrl.dma_tx_buf + CSG_HEAD_LEN);
    uint8_t *crc = (uint8_t*)(wl_ctrl.dma_tx_buf + CSG_HEAD_LEN + CSG_CONFIG_GET_LEN);
    uint8_t *end_flag = (uint8_t*)(wl_ctrl.dma_tx_buf + CSG_HEAD_LEN + CSG_CONFIG_GET_LEN + CSG_CRC_LEN);

    /* 封装报文头. */
    _csg_data_head_init(CSG_CONFIG_GET_LEN, CSG_CONFIG_GET);

    /* 封装数据. */
    /* 心跳间隔. */
    *data = dev_config.csg_beat_interval;
    data += 1;
    /* 采集间隔. */
    
    *(uint16_t*)data = PP_HTONS(dev_config.collect_interval);
    data += 2;
    
    /* 休眠时间. */
    *(uint16_t*)data = PP_HTONS(dev_config.csg_sleep);
    data += 2;

    /* 在线时间. */
    *(uint16_t*)data = PP_HTONS(HAL_GetTick() / 1000 / 60);
    data += 2;

    /* 重启时间. */
    memcpy(data, dev_config.csg_reset_time, 3);
    data += 3;
    
    memset(data, 0, 10);
    data += 10;
    
    *data = 0x44;

    /* 计算校验和. */
    *crc = _csg_crc(wl_ctrl.dma_tx_buf + 1, CSG_CONFIG_GET_LEN + CSG_HEAD_LEN - 1);
    *end_flag = CSG_END_FLAG;

    /* 发送报文 */
    _csg_transmit(wl_ctrl.dma_tx_buf, CSG_CONFIG_GET_LEN + CSG_OTHER_LEN);
}

/* 时间获取报文. */
static void _csg_time_get_send(void)
{
    uint8_t *data = (uint8_t*)(wl_ctrl.dma_tx_buf + CSG_HEAD_LEN);
    uint8_t *crc = (uint8_t*)(wl_ctrl.dma_tx_buf + CSG_HEAD_LEN + CSG_TIME_GET_LEN);
    uint8_t *end_flag = (uint8_t*)(wl_ctrl.dma_tx_buf + CSG_HEAD_LEN + CSG_TIME_GET_LEN + CSG_CRC_LEN);

    /* 封装报文头. */
    _csg_data_head_init(CSG_TIME_GET_LEN, CSG_TIME_GET);

    /* 封装数据. */
    HAL_RTC_GetTime(&hrtc, &time_structure, RTC_FORMAT_BIN);
    HAL_RTC_GetDate(&hrtc, &date_structure, RTC_FORMAT_BIN);
    data[0] = date_structure.Year;
    data[1] = date_structure.Month;
    data[2] = date_structure.Date;
    data[3] = time_structure.Hours;
    data[4] = time_structure.Minutes;
    data[5] = time_structure.Seconds;

    /* 计算校验和. */
    *crc = _csg_crc(wl_ctrl.dma_tx_buf + 1, CSG_TIME_GET_LEN + CSG_HEAD_LEN - 1);
    *end_flag = CSG_END_FLAG;

    /* 发送报文 */
    _csg_transmit(wl_ctrl.dma_tx_buf, CSG_TIME_GET_LEN + CSG_OTHER_LEN);
}

/* 状态机改变 */
void _csg_state_change(void)
{
    if (wl_ctrl.state != CSG_STATE_IDLE)
    {
        return;
    }

    if (wl_ctrl.data_request)
    {
        if (CSG_DATA_TYPE_HIS == wl_ctrl.data_request)
        {
            wl_ctrl.state = CSG_STATE_DATA_HIS;
            wl_ctrl.send_cnt = 0;    
            wl_ctrl.time_send = 0;
        }
        else
        {
            ADC_restart_force();
        }
        
        wl_ctrl.data_request = CSG_DATA_TYPE_NONE;
    }
    else if ((HAL_GetTick() - wl_ctrl.time_beat) > (dev_config.csg_beat_interval * 60000))
    {
        wl_ctrl.state = CSG_STATE_BEAT;
        wl_ctrl.send_cnt = 0;    
        wl_ctrl.time_send = 0;
    }
    else if (!ADC_ctrl.up_finish)
    {
        wl_ctrl.state = CSG_STATE_DATA;
        ADC_ctrl.up_finish = TRUE;
        wl_ctrl.send_cnt = 0;    
        wl_ctrl.time_send = 0;
    }
}

/* 数据发送. */
void _csg_pkt_send(void)
{
    uint8_t is_timeout = wl_ctrl.time_send < HAL_GetTick();

    _csg_state_change();

    if ((CSG_STATE_CONNECT == wl_ctrl.state) && is_timeout)
    {
        /* 开机联络. */
        _csg_connect_send(FALSE);
        wl_ctrl.send_cnt++;
    }
    else if ((CSG_STATE_TIME == wl_ctrl.state) && is_timeout)
    {
        /* 设备对时. */
        _csg_time_send();
        wl_ctrl.send_cnt++;
    }
    else if ((CSG_STATE_BEAT == wl_ctrl.state) && is_timeout)
    {
        /* 心跳. */
        _csg_beat_send();
        wl_ctrl.send_cnt++;
    }
    else if ((CSG_STATE_DATA == wl_ctrl.state) && is_timeout)
    {
        /* 实时数据. */
        _csg_data_send_realtime();
        wl_ctrl.send_cnt++;
    }
    else if ((CSG_STATE_DATA_HIS == wl_ctrl.state) && is_timeout)
    {
        /* 历史数据. */
        _csg_data_send_his();
        wl_ctrl.send_cnt++;
    }
}

static int32_t _csg_pkt_check(uint8_t *cmd, uint32_t len)
{
    csg_head_t *head = (csg_head_t*)cmd;

    /* 设备进入复位状态后不再处理报文. */
    if (IS_MONITOR_BIT_SET(system_init_flag, SYS_INIT_RESET))
    {
        vty_print("@0\r\n");
        /* 这里挂住线程是因为重启时如果有收包, 会导致收包出错, 从而让设备进入休眠状态. */
        osDelay(portMAX_DELAY);
        return HAL_ERROR;
    }

    if (len < CSG_OTHER_LEN
        || (CSG_OTHER_LEN + PP_HTONS(head->len) != len))
    {
        vty_print("@1\r\n");
        return HAL_ERROR;
    }

    if (head->flag != CSG_START_FLAG || cmd[len - 1] != CSG_END_FLAG)
    {
        vty_print("@2\r\n");
        return HAL_ERROR;
    }

    /* 对主次设备号进行识别, 次设备号可以是广播. */
    if (strncmp((char*)head->dev_id, (char*)dev_info.csg_id, 6))
    {
        vty_print("@3\r\n");
        return HAL_ERROR;
    }

    /* 验证 CRC32. */
    if (_csg_crc(cmd + 1, PP_HTONS(head->len) + CSG_HEAD_LEN - 1) != cmd[len - 2])
    {
        vty_print("@4: %x %x\r\n", _csg_crc(cmd + 1, PP_HTONS(head->len) + CSG_HEAD_LEN - 1), cmd[len - 2]);
        return HAL_ERROR;
    }

    return HAL_OK;
}

/* 开机联络回复. */
static void _csg_connect_reply(uint8_t *cmd, uint32_t len)
{
    csg_head_t *head = (csg_head_t*)cmd;

    if (PP_HTONS(head->len) == 0)
    {
        _csg_connect_send(TRUE);
    }
    else
    {
        wl_ctrl.state = CSG_STATE_TIME;
        wl_ctrl.send_cnt = 0;
        wl_ctrl.time_send = 0;
    }
}

/* 对时回复. */
static void _csg_time_reply(uint8_t *cmd, uint32_t len)
{
    csg_time_t *data = (csg_time_t*)(cmd + CSG_HEAD_LEN);
    time_t temp = 0;

    /* 更新 RTC 时间. */
    tm_structure.tm_year = data->year + 100;
    tm_structure.tm_mon = data->mon - 1;
    tm_structure.tm_mday = data->day;
    tm_structure.tm_hour = data->hour;
    tm_structure.tm_min = data->min;
    tm_structure.tm_sec = data->sec;
    temp = mktime(&tm_structure); 
    rtc_time_set(temp - 28800);

    if (CSG_STATE_TIME == wl_ctrl.state)
    {
        wl_ctrl.state = CSG_STATE_BEAT;
        wl_ctrl.send_cnt = 0;
        wl_ctrl.time_send = 0;
    }
    else
    {
        /* 发送回复报文. */
        _csg_transmit(cmd, len);
    }
}

/* 对时回复. */
static void _csg_passwd_set_reply(uint8_t *cmd, uint32_t len)
{
    csg_passwd_t *data = (csg_passwd_t*)(cmd + CSG_HEAD_LEN);

    if (0 == memcmp(data->passwd_old, dev_config.csg_passwd, CSG_PASSWD_LEN))
    {
        memcpy(dev_config.csg_passwd, data->passwd_new, CSG_PASSWD_LEN);
        dev_config.csg_passwd[CSG_PASSWD_LEN] = 0;
        common_sys_set(COM_SYS_SAVE_CONFIG, 0);
        /* 发送回复报文. */
        _csg_transmit(cmd, len);
    }
    else
    {
        _csg_error_send(CSG_PASSWD_SET, 0xffff);
    }
}

/* 配置设置回复. */
static void _csg_config_set_reply(uint8_t *cmd, uint32_t len)
{
    uint8_t *data = (uint8_t*)(cmd + CSG_HEAD_LEN);

    if (0 == memcmp(data, dev_config.csg_passwd, CSG_PASSWD_LEN))
    {
        /* 心跳间隔. */
        data += 4;
        dev_config.csg_beat_interval = *data;

        /* 采集间隔. */
        data += 1;
        dev_config.collect_interval = *(uint16_t*)data;
        dev_config.collect_interval = PP_HTONS(dev_config.collect_interval);

        /* 休眠时间. */
        data += 2;
        dev_config.csg_sleep = *(uint16_t*)data;
        dev_config.csg_sleep = PP_HTONS(dev_config.csg_sleep);

        /* 在线时间. */
        data += 2;
        dev_config.csg_online = *(uint16_t*)data;
        dev_config.csg_online = PP_HTONS(dev_config.csg_online);

        /* 重启时间. */
        data += 2;
        memcpy(dev_config.csg_reset_time, data, 3);

        /* 验证密文. */
        data += 3;
        memcpy(dev_config.csg_ciphertext, data, 4);
    
        common_sys_set(COM_SYS_SAVE_CONFIG, 0);
        /* 发送回复报文. */
        _csg_transmit(cmd, len);
    }
    else
    {
        _csg_error_send(CSG_CONFIG_SET, 0xffff);
    }
}

/* 心跳回复处理. */
static void _csg_beat_reply(uint8_t *cmd, uint32_t len)
{
    wl_ctrl.state = CSG_STATE_IDLE;
    wl_ctrl.time_send = 0;
    wl_ctrl.send_cnt = 0;
}

/* 服务器设置回复. */
static void _csg_server_set_reply(uint8_t *cmd, uint32_t len)
{
    csg_server_t *data = (csg_server_t*)(cmd + CSG_HEAD_LEN);

    if (0 == memcmp(data->passwd, dev_config.csg_passwd, CSG_PASSWD_LEN))
    {
        if (0 == memcmp(data->ip1, data->ip2, CSG_PASSWD_LEN)
            && 0 == memcmp(data->card1, data->card2, 6)
            && data->port1 == data->port2)
        {
            memcpy(dev_info.wireless_server_ip, data->ip1, 4);
            dev_info.wireless_server_port = PP_HTONS(data->port1);
            memcpy(dev_info.csg_card, data->card1, 6);
            
            common_sys_set(COM_SYS_SAVE_INFO, 0);
            /* 发送回复报文. */
            _csg_transmit(cmd, len);
        }
        else
        {
            _csg_error_send(CSG_SERVER_SET, 0);
        }
    }
    else
    {
        _csg_error_send(CSG_SERVER_SET, 0xffff);
    }
}

/* 服务器设置回复. */
static void _csg_server_get_reply(uint8_t *cmd, uint32_t len)
{
    _csg_server_send();
}

/* 设备重启回复. */
static void _csg_reset_reply(uint8_t *cmd, uint32_t len)
{
    uint8_t *data = (uint8_t*)(cmd + CSG_HEAD_LEN);
    uint32_t reset_delay = 2;

    if (0 == memcmp(data, dev_config.csg_passwd, CSG_PASSWD_LEN))
    {
        /* 发送回复报文. */
        _csg_transmit(cmd, len);

        flash_log_write(FLASH_LOG_TYPE_INFO, "CSG system reset!\r\n");
        common_sys_set(COM_SYS_RESET, (void*)&reset_delay);
        
    }
    else
    {
        _csg_error_send(CSG_RESET, 0xffff);
    }
}

/* 服务器设置回复. */
static void _csg_config_get_reply(uint8_t *cmd, uint32_t len)
{
    _csg_config_send();
}

/* 服务器设置回复. */
static void _csg_time_get_reply(uint8_t *cmd, uint32_t len)
{
    _csg_time_get_send();
}

/* 数据回复处理. */
static void _csg_data_get_reply(uint8_t *cmd, uint32_t len)
{
    csg_head_t *head = (csg_head_t*)cmd;
    
    if (PP_HTONS(head->len) == 0)
    {
        /* 请求历史数据. */
        wl_ctrl.data_request = CSG_DATA_TYPE_HIS;
    }
    else
    {
        /* 请求实时数据. */
        wl_ctrl.data_request = CSG_DATA_TYPE_REAL;
    }

    _csg_transmit(cmd, len);
}

static void _csg_data_reply_id_updata(void)
{
    uint8_t i = 0;

    for(i = 0; i < CSG_PKT_DATA_SUM; i++)
    {
        if (0 == csg_data_idx[i])
        {
            break;
        }

        fd_read(csg_data_idx[i], &csg_adc_data);
        csg_adc_data.is_not_updata = FALSE;
        fd_modify(csg_data_idx[i], &csg_adc_data);
    }
}

/* 数据回复处理. */
static void _csg_data_reply(uint8_t *cmd, uint32_t len)
{
    csg_head_t *head = (csg_head_t*)cmd;
    
    if (PP_HTONS(head->len) == 0)
    {
        _csg_transmit(cmd, len);
    }
    else
    {
        wl_ctrl.state = CSG_STATE_IDLE;
        wl_ctrl.send_cnt = 0;
        wl_ctrl.time_send = 0;

        _csg_data_reply_id_updata();
    }
}

/* 有线数据处理. */
static void _csgp_pkt_process(uint8_t *cmd, uint32_t len)
{
    csg_head_t *head = (csg_head_t*)cmd;
    
    /* 报文头和 CRC 校验. */
    if (_csg_pkt_check(cmd, len) != HAL_OK)
    {
        return;
    }

    /* 共有命令处理. */
    switch (head->cmd)
    {
    case CSG_CONNECT:
        _csg_connect_reply(cmd, len);
        break;
    case CSG_TIMING:
        _csg_time_reply(cmd, len);
        break;
    case CSG_PASSWD_SET:
        _csg_passwd_set_reply(cmd, len);
        break;
    case CSG_CONFIG_SET:
        _csg_config_set_reply(cmd, len);
        break;
    case CSG_BEAT:
        _csg_beat_reply(cmd, len);
        break;
    case CSG_SERVER_SET:
        _csg_server_set_reply(cmd, len);
        break;
    case CSG_SERVER_GET:
        _csg_server_get_reply(cmd, len);
        break;
    case CSG_RESET:
        _csg_reset_reply(cmd, len);
        break;
    case CSG_CONFIG_GET:
        _csg_config_get_reply(cmd, len);
        break;
    case CSG_TIME_GET:
        _csg_time_get_reply(cmd, len);
        break;
    case CSG_DATA_GET:
        _csg_data_get_reply(cmd, len);
        break;
    case CSG_DATA:
        _csg_data_reply(cmd, len);
        break;
    default:
        break;
    }
}

static void _csg_pkt_recv(void)
{
    static uint8_t state = 0;
    static uint32_t time = 0;
    wl_buf_list_t *buf_l = &wl_buf_list_rx;
    csg_head_t *head = (csg_head_t*)wl_ctrl.cmd_buf;
    uint8_t *buf = NULL;
    uint16_t len = 0;
    int16_t i = 0;

    /* 超过 3s 没有收包说明收包超时, 重新开始收包. */
    if (HAL_GetTick() - time > 3000)
    {
        state = 0;
        wl_ctrl.cmd_buf_index = 0;
    }
    time = HAL_GetTick();

    /* 遍历所有有效的 buf. */
    while(buf_l->current != buf_l->valid)
    {
        buf = buf_l->buf[buf_l->current];
        len = buf_l->buf_cnt[buf_l->current];
        
        /* 更新 buf index. */
        buf_l->current++;
        if (WL_BUF_LIST_LEN == buf_l->current)
        {
            buf_l->current = 0;
        }

        /* 如果收包大于 buf 长度, 认为报文错误. */
        if (wl_ctrl.cmd_buf_index + len >= WL_DMA_RX_BUF_LEN)
        {
            wl_ctrl.cmd_buf_index = 0;
            state = FALSE;
            continue;
        }

        /* 将 buf 中的数据解析成命令. */
        memcpy(&wl_ctrl.cmd_buf[wl_ctrl.cmd_buf_index], buf, len);
        wl_ctrl.cmd_buf_index += len;

        /* 不够报文头长度的报文暂时不处理. */
        if (wl_ctrl.cmd_buf_index < CSG_HEAD_LEN)
        {
            state = FALSE;
            continue;
        }

        if (!state)
        {
            /* 报文长度不对或者起始位不对, 重新收包. */
            if (PP_HTONS(head->len) + CSG_OTHER_LEN > WL_DMA_RX_BUF_LEN
                || head->flag != CSG_START_FLAG)
            {
                wl_ctrl.cmd_buf_index = 0;
                continue;
            }

            /* 报文长度与收包长度不对称, 等待后续报文. */
            if (wl_ctrl.cmd_buf_index < PP_HTONS(head->len) + CSG_OTHER_LEN)
            {
                state = TRUE;
                continue;
            }
        }
        else
        {
            /* 报文长度与收包长度不对称, 等待后续报文. */
            if (wl_ctrl.cmd_buf_index < PP_HTONS(head->len) + CSG_OTHER_LEN)
            {
                continue;
            }
            
            state = FALSE;
        }

        len = PP_HTONS(head->len) + CSG_OTHER_LEN;
        wl_ctrl.cmd_buf_index -= len;
        buf = wl_ctrl.cmd_buf + len;
        memcpy(wl_ctrl.csg_buf, wl_ctrl.cmd_buf, len);
        for(i = 0; i < wl_ctrl.cmd_buf_index; i++)
        {
            wl_ctrl.cmd_buf[i] = buf[i];
        }

        DBG(DBG_M_4G, "Recv(%d:%d): 0x%x\r\n", len, wl_ctrl.cmd_buf_index, wl_ctrl.csg_buf[7]);
        if (dbg_stat_get(DBG_M_4G))
        {
            buf_print(wl_ctrl.csg_buf, len > 32 ? 32 : len);
            vty_print("\r\n");
        }

        _csgp_pkt_process(wl_ctrl.csg_buf, len);
    }
}

/* 通过 AT 命令进行模块初始化. */
void _csg_init_soft(void)
{
    uint8_t is_timeout = wl_ctrl.time_send < HAL_GetTick();

    if ((WL_STATE_SOFT == wl_ctrl.state) && is_timeout)
    {
        wl_ctrl.time_send = 0;
        wl_ctrl.send_cnt = 0;
        wl_ctrl.state++;
    }
    else if ((WL_STATE_AT_ATE == wl_ctrl.state) && is_timeout)
    {
        /* 关闭 AT 回显. */
        _wl_4G_init_cmd_send("ATE0\r\n", 1100);
        wl_ctrl.send_cnt++;
    }
    else if ((WL_STATE_AT_QICSGP == wl_ctrl.state) && is_timeout)
    {
        /* 创建场景. */
        snprintf((char*)wl_ctrl.dma_tx_buf, WL_DMA_TX_BUF_LEN, "AT+QICSGP=1,1,\"%s\",\"\",\"\",1\r\n", dev_config.APN_long);
        _wl_4G_init_cmd_send(wl_ctrl.dma_tx_buf, 1100);
        wl_ctrl.send_cnt++;
    }
    else if ((WL_STATE_AT_QIACT == wl_ctrl.state) && is_timeout)
    {
        /* 使能场景. */
        _wl_4G_init_cmd_send("AT+QIACT=1\r\n", 33000);
        wl_ctrl.send_cnt++;
    }
    else if ((WL_STATE_AT_CSQ == wl_ctrl.state) && is_timeout)
    {
        /* 读取网络信号质量. */
        osDelay(5000);
        _wl_4G_init_cmd_send("AT+CSQ\r\n", 1100);
        wl_ctrl.send_cnt++;
    }
    else if ((WL_STATE_AT_QICFGTS == wl_ctrl.state) && is_timeout)
    {
        /* 连接远程服务器. */
        snprintf((char*)wl_ctrl.dma_tx_buf, WL_DMA_TX_BUF_LEN, "AT+QICFG=\"transpktsize\",1460\r\n");
        _wl_4G_init_cmd_send(wl_ctrl.dma_tx_buf, 11000);
        wl_ctrl.send_cnt++;
    }
    else if ((WL_STATE_AT_QICFGWT == wl_ctrl.state) && is_timeout)
    {
        /* 连接远程服务器. */
        snprintf((char*)wl_ctrl.dma_tx_buf, WL_DMA_TX_BUF_LEN, "AT+QICFG=\"transwaittm\",0\r\n");
        _wl_4G_init_cmd_send(wl_ctrl.dma_tx_buf, 11000);
        wl_ctrl.send_cnt++;
    }
    else if ((WL_STATE_AT_QIOPEN == wl_ctrl.state) && is_timeout)
    {
        /* 连接远程服务器. */
        snprintf((char*)wl_ctrl.dma_tx_buf, WL_DMA_TX_BUF_LEN, "AT+QIOPEN=1,0,\"UDP\",\"%d.%d.%d.%d\",%d,19421,2\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], dev_info.wireless_server_port);
        //_wl_4G_init_cmd_send("AT+QIOPEN=1,0,\"TCP\",\"111.47.21.142\",9467,19421,2\r\n", 10000);
        _wl_4G_init_cmd_send(wl_ctrl.dma_tx_buf, 11000);
        wl_ctrl.send_cnt++;
    }
    else if (WL_STATE_ADC_WAIT == wl_ctrl.state)
    {
        if (IS_MONITOR_BIT_SET(system_init_flag, SYS_INIT_ADC))
        {
            /* 软件初始化完成. */
            wl_ctrl.state = CSG_STATE_CONNECT;
            wl_ctrl.time_send = 0;
            wl_ctrl.send_cnt = 0;
            wl_ctrl.energy_mode_old = ADC_ctrl.energy_mode;
        }
        else if (is_timeout)
        {
            wl_ctrl.time_send = HAL_GetTick() + 10000;
            wl_ctrl.send_cnt++;
        }
    }
}

static void _csg_start(void *argument)
{
    uint32_t notify_value = 0;

    /* 等待完成 1 次 ADC 采样. */
    while(1)
    {
        if (IS_MONITOR_BIT_SET(system_init_flag, SYS_INIT_ADC))
        {
            break;
        }

        osDelay(1000);
    }

    /* 开启串口空闲中断收包. */
    HAL_UARTEx_ReceiveToIdle_DMA(wl_uart, wl_ctrl.dma_rx_buf, WL_DMA_RX_BUF_LEN);

    /* 初始化 4G 模块硬件. */
    _wl_4G_hw_init();

    /* 20s 内要收到 4G 模块发出的 RDY. */
    wl_ctrl.time_send = HAL_GetTick() + 20000;
    wl_ctrl.wave_index = st_data.wave_index;
    
    for (;;)
    {    
        /* AT 指令发送失败, 直接退出. */
        if (wl_ctrl.send_cnt > WL_SOFT_INIT_ERR)
        {
            wl_ctrl.err_cnt = 0;
            _wl_4G_hw_restart();
        }
    
        if (wl_ctrl.state < WL_STATE_WAKEUP)
        {   
            /* 进入软件初始化. */
            _csg_init_soft();
        }
        else
        {
            /* 发送数据给 */
            _csg_pkt_send();
        }

        /* 喂狗. */
        common_watchdog_set(COM_WDG_WIR);

        /* 等待 DMA 收包中断. */
        notify_value = ulTaskNotifyTake(pdTRUE, WL_RX_TIMEOUT);
        /* 收包超时, 返回循环头部. */
        if (0 == notify_value)
        {
            continue;
        }

        /* 收包处理. */
        _wl_4G_receive();
    }
}


/* Interface functions -------------------------------------------------------*/
/* 无线通讯任务初始化. */
void wl_init_os(void)
{
    if (DEV_TYPE_CSG == dev_info.type_s)
    {
        WLHandle = osThreadNew(_csg_start, NULL, &WL_attributes);
    }
    else if (DEV_TYPE_ACDC == dev_info.type_s)
    {
        WLHandle = osThreadNew(_wir_start, NULL, &WL_attributes);
    }
    else
    {
        WLHandle = osThreadNew(_wl_4G_start, NULL, &WL_attributes);
    }
}

void wl_show(void)
{
    vty_print("ST\r\n");
    vty_print("%-03d %d\r\n\n", wl_ctrl.state, wl_ctrl.send_cnt);
}
/******************* (C) COPYRIGHT LandPower ***** END OF FILE ****************/
