/*****************************************************************************
 * file    lib/process/ca_dbg.c  
 * author  YuLiang
 * version 1.0.0
 * date    30-Nov-2023
 * brief   This file provides all the debug server related operation functions.
 ******************************************************************************
 * Attention
 *
 * <h2><center>&copy; COPYRIGHT(c) 2023 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 LandPower 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 ------------------------------------------------------------------*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#ifdef CFG_DEV_TYPE_LAND_CA
/* 标准C库头文件. */
#include <sys/socket.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <netinet/tcp.h>
#include <sys/types.h>
#include <sys/stat.h>

/* 用户代码头文件. */
#include "cmd.h"
#include "mtimer.h"

#include "process.h"
#include "ca_db.h"
#include "ca_collect.h"
#include "ca_mqtt.h"
#include "ca_land.h"

/* Private define ------------------------------------------------------------*/
#define CA_DBG_TOOL_PORT 20111
#define CA_DBG_BUF_SIZE 1512
#define CA_DBG_CMD_BUF_LEN 3024
#define CA_DBG_CRC32_LEN 4
#define CA_DBG_VERSION_LEN 32
#define CA_DBG_COMPILE_LEN 32
#define CA_DBG_NAME_LEN 128
#define CA_DBG_SHIQUCHA (28800)
#define CA_DBG_DATA_MAX 1024
#define CA_DBG_CMU_FILE "CableMQTT"
#define CA_DBG_CMU_FILE_BAK "CableMQTT.bak"
#define CA_DBG_CMU_FILE_DIR "./bak/CableMQTT"
#define CA_DBG_CABLE_FILE "cableMonitor.bak"
#define CA_DBG_LOG_FILE "PowerIoT.db.bak"
#define CA_DBG_HDATA_FILE "Cable.db.bak"
#define CA_DBG_PPP_FILE "/home/Cable/quectel-chat-connect"
#define CA_DBG_PPP_FILE_ETC "/etc/ppp/peers/quectel-chat-connect"
#define CA_DBG_PPP_FILE_BAK "/home/Cable/bak/quectel-chat-connect"

/* Private macro -------------------------------------------------------------*/

/* Private typedef -----------------------------------------------------------*/
/* 命令类型. */
enum CA_DBG_CMD_TYPE
{
    CA_DBG_CT_REQUEST = 1,
    CA_DBG_CT_REPLY = 2,
    CA_DBG_CT_PRV_REQUEST = 128,
    CA_DBG_CT_PRV_REPLY = 129,
};

/* 共有命令字. */
enum CA_DBG_CMD
{
    CA_DBG_C_DEV_INFO = 1,
    CA_DBG_C_DEV_INFO_SET = 2,
    CA_DBG_C_DEV_RESET = 3,
    CA_DBG_C_DEV_UPDATE = 5,
    CA_DBG_C_DEV_CONFIG = 7,
    CA_DBG_C_DEV_CONFIG_SET = 8
};

/* 私有命令字. */
enum CA_DBG_CMD_PRV
{
    CA_DBG_C_PRV_CABLE_INFO = 1,
    CA_DBG_C_PRV_CABLE_CFG = 2,
    CA_DBG_C_PRV_CABLE_DATA = 3,
    CA_DBG_C_PRV_CABLE_CFG_SET = 4,
    CA_DBG_C_PRV_CABLE_UPDATE = 5,
    CA_DBG_C_PRV_CABLE_UPDATE_RT = 6,
    CA_DBG_C_PRV_CABLE_STATE = 7,
    CA_DBG_C_PRV_CABLE_LOG = 8,
    CA_DBG_C_PRV_CABLE_HDATA = 9,
    CA_DBG_C_PRV_MQTT_INFO = 10,
    CA_DBG_C_PRV_MQTT_INFO_SET = 11,
};

/* 协议头 */
typedef struct
{
    uint16_t len;                       // 报文总长度, 包括报文头, 数据段和报文尾总长度
    uint8_t dev_type_m;                 // 设备主设备号: 有效值 (1-240), 255 表示广播设备号, 表示接收设备无需在意设备号, 其他值暂时预留
    uint8_t dev_type_s;                 // 设备次设备号: 有效值 (1-240), 255 表示广播设备号, 表示接收设备无需在意设备号, 其他值暂时预留
    uint32_t dev_id;                    // 设备 id: 有效值 (1-0xEFFFFFFF), 0xFFFFFFFF 表示广播设备 id, 其他值暂时预留
    uint8_t cmd_type;                   // 命令类型: 有效值(1-240), (1-120) 为共有命令类型, (121-240) 为私有命令类型, 其他值暂时预留
    uint8_t cmd;                        // 命令: 有效值(1-240), 其他值暂时预留
    uint16_t pkt_id;                    // 报文 id, 设备启动后的第一条命令为 1, 依次累加
    uint8_t reserve[8];                 // 预留位
} ca_dbg_proto_head_t;

/* 连续报文头 */
typedef struct
{
    uint32_t index;
    uint32_t len;
} ca_dbg_proto_mul_head_t;

/* bin报文头结构体. */
typedef struct
{
    uint8_t dev_type_m;
    uint8_t dev_type_s;
    uint8_t file_type;
    uint8_t version_m;
    uint16_t version_s;
    int8_t reserve[10];
    uint32_t crc32;
} ca_dbg_bin_tail_t;

/* 联络报文回复. */
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[CA_DBG_VERSION_LEN];
    uint8_t boot_compile_time[CA_DBG_COMPILE_LEN];
    uint8_t img_version[CA_DBG_VERSION_LEN];
    uint8_t img_compile_time[CA_DBG_COMPILE_LEN];
    uint8_t hardware_version[CA_DBG_VERSION_LEN];
    uint8_t FPGA_version[CA_DBG_VERSION_LEN];
    uint8_t factory_time[CA_DBG_COMPILE_LEN];
    /* 设备其他信息. 128byte */
    uint8_t name[CA_DBG_NAME_LEN];
} ca_dbg_dev_info_t;

typedef struct
{
    uint32_t update_index;              // 环流升级报文索引
    bool is_update_cable;               // 环流设备升级中
    bool is_connect;                    // 环流连接状态
    bool is_connect_mqtt;               // MQTT 是否连接
    bool is_connect_land;               // 私有协议是否连接
    uint32_t run_time;                  // 程序运行时长
    bool is_connect_4g;                 // 4G 是否连接
    int8_t reserve[3];
} ca_dbg_state_t;

/* 调试工具全局结构 */
typedef struct{
    int fd;                                 // TCP server 监听使用的 socket
    int fd_client;                          // TCP client 通讯使用的 socket
    int fd_wr;                              // 文件读写描述符
    char buf[CA_DBG_BUF_SIZE];              // 通讯使用收发包 buf
    char buf_send[CA_DBG_BUF_SIZE];         // 通讯使用收发包 buf
    char cmd_buf[CA_DBG_CMD_BUF_LEN];       // 收到的完整报文 buf
} ca_dbg_ctrl_t;

/* Private variables ---------------------------------------------------------*/
ca_dbg_ctrl_t ca_dbg_ctrl;

/* Private function prototypes -----------------------------------------------*/

/* Internal functions --------------------------------------------------------*/
void _ca_dbg_file_bak(char *src, char *dest)
{
    char cmd[256] = {0};
    
    snprintf(cmd, 256, "cp -rf %s %s", src, dest);
    system(cmd);
    system("sync");
    
    return;
}

void _ca_dbg_file_check(char *source, char *dest, char *mode)
{
    struct stat file_stat;
    char cmd[64] = {0};
    int fd = -1;
    off_t size = 0;
    int32_t ret = -1;

    if (!access(source, F_OK))
    {
        fd = open(source, O_RDONLY);
        if (fd != -1)
        {
            ret = fstat(fd, &file_stat);
            if (ret != -1)
            {
                size = file_stat.st_size;
            }
        }
    }

    if (size > 16)
    {
        return;
    }

    log_err(LOG_CA_DBG, "File %s is ERROR, recover %s!", source, dest);
    _ca_dbg_file_bak(dest, source);

    snprintf(cmd, 64, "chmod %s %s", mode, source);
    system(cmd);
    system("sync");
}

int32_t _ca_dbg_apn_change(char *apn)
{
    int32_t i = 0;
    int32_t num = 0;
    char str[100][256] = {0};
    char linedata[256] = {0};
    FILE *fp = NULL;

    fp = fopen(CA_DBG_PPP_FILE, "r");
    if (NULL == fp)
    {
        DBG(DBG_M_CA_DBG_ERR, "Open quectel-chat-connect ERROR\r\n");
        return E_SYS_CALL;
    }

    // "OK \rAT+CGDCONT=1,"IP","3gnet",,0,0"
    while(fgets(linedata, sizeof(linedata) - 1, fp))
    {
        if (strstr(linedata, "AT+CGDCONT") != NULL)
        {
            sprintf(str[i],"OK \\rAT+CGDCONT=1,\"IP\",\"%s\",,0,0\n", apn);
        }
        else
        {
            strcpy(str[i], linedata);
        }
        i++;
    }
    fclose(fp);

    num = i;
    fp = fopen(CA_DBG_PPP_FILE, "w");
    if (NULL == fp)
    {
        DBG(DBG_M_CA_DBG_ERR, "Open quectel-chat-connect ERROR\r\n");
        return E_SYS_CALL;
    }
    
    for(i = 0; i < num; i++)
    {
        fputs(str[i], fp);
    }
    fflush(fp);
    fclose(fp);

    _ca_dbg_file_bak(CA_DBG_PPP_FILE, CA_DBG_PPP_FILE_ETC);
    
    return E_NONE;
}

/* 初始化报文头. */
void _ca_dbg_pkt_head_init(char *buf, uint16_t len, uint8_t cmd_type, uint8_t cmd)
{
    ca_dbg_proto_head_t *head = (ca_dbg_proto_head_t*)buf;
    
    /* 封装报文头. */
    head->len = len;
    head->dev_type_m = device_info.id_major;
    head->dev_type_s = device_info.id_minor;
    head->dev_id = device_info.dev_id;
    head->cmd_type = cmd_type;
    head->cmd = cmd;
}

/* 报文发送 */
int32_t _ca_dbg_pkt_send(char *buf, uint16_t len)
{
    ca_dbg_proto_head_t *head = (ca_dbg_proto_head_t*)buf;
    ca_dbg_proto_mul_head_t *m_head = (ca_dbg_proto_mul_head_t*)(buf + sizeof(ca_dbg_proto_head_t));

    if (write(ca_dbg_ctrl.fd_client, buf, len) < 0)
    {
        DBG(DBG_M_CA_DBG_ERR, "DBG send ERR!\r\n");
        return E_SYS_CALL;
    }
    
    DBG(DBG_M_CA_DBG, "DBG send(%d): %d %d %d %d\r\n", len, time(NULL), head->cmd_type, head->cmd, m_head->index);
    if (dbg_stat_get(DBG_M_CA_DBG))
    {
        buf_print(buf, len > 32 ? 32 : len);
        //buf_print(buf, len);
    }

    return E_NONE;
}

/* 对数据进行校验 */
int32_t _ca_dbg_pkt_dev_update_check(char *file_name)
{
    struct stat file_stat;
    ca_dbg_bin_tail_t *pkt_tail = NULL;
    char *buf = ca_dbg_ctrl.buf;
    uint32_t size = 0;
    uint16_t write_size = 0;
    uint32_t crc32_value = 0xffffffff;

    /* 打开描述符, 读取文件大小 */
    ca_dbg_ctrl.fd_wr = open(file_name, O_RDONLY, 0777);
    if (ca_dbg_ctrl.fd_wr < 0)
    {
        DBG(DBG_M_CA_DBG_ERR, "Open %s ERROR\r\n", file_name);
        return E_SYS_CALL;
    }

    if (fstat(ca_dbg_ctrl.fd_wr, &file_stat) < 0)
    {   
        DBG(DBG_M_CA_DBG_ERR, "fstat %s ERROR\r\n", file_name);
        return E_SYS_CALL;
    }

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

        /* 读取升级包. */
        if (read(ca_dbg_ctrl.fd_wr, buf, write_size) < 0)
        {   
            DBG(DBG_M_CA_DBG_ERR, "read %s ERROR\r\n", file_name);
            return E_SYS_CALL;
        }

        crc32_value = crc32_update(crc32_value, buf, write_size);
        
        /* 重新计算剩余数据大小. */
        size -= write_size;
    }

    /* 读取报文头 */
    lseek(ca_dbg_ctrl.fd_wr, file_stat.st_size - sizeof(ca_dbg_bin_tail_t), SEEK_SET);
    if (read(ca_dbg_ctrl.fd_wr, buf, sizeof(ca_dbg_bin_tail_t)) < 0)
    {   
        DBG(DBG_M_CA_DBG_ERR, "read %s ERROR\r\n", file_name);
        return E_SYS_CALL;
    }

    close(ca_dbg_ctrl.fd_wr);
    ca_dbg_ctrl.fd_wr = 0;

    /* 比较报文头信息 */
    pkt_tail = (ca_dbg_bin_tail_t*)buf;
    if (crc32_value != pkt_tail->crc32
        || device_info.id_major != pkt_tail->dev_type_m
        || pkt_tail->file_type != 3)
    {
        DBG(DBG_M_CA_DBG_ERR, "%d %d 0x%x 0x%x\r\n", pkt_tail->dev_type_m, pkt_tail->file_type, pkt_tail->crc32, crc32_value);
        return E_NOT_IDENTIFY;
    }

    return E_NONE;
}

int32_t _ca_dbg_pkt_dev_update_write(char *cmd)
{
    ca_dbg_proto_mul_head_t *m_head_cmd = (ca_dbg_proto_mul_head_t*)(cmd + sizeof(ca_dbg_proto_head_t));
    char *data = cmd + sizeof(ca_dbg_proto_head_t) + sizeof(ca_dbg_proto_mul_head_t);

    /* 初始化文件描述符 */
    if (0 == m_head_cmd->index || ca_dbg_ctrl.fd_wr <= 0)
    {
        if (ca_dbg_ctrl.fd_wr > 0)
        {
            close(ca_dbg_ctrl.fd_wr);
        }

        ca_dbg_ctrl.fd_wr = open(CA_DBG_CMU_FILE_BAK, O_WRONLY | O_CREAT | O_TRUNC, 0777);
        if (ca_dbg_ctrl.fd_wr < 0)
        {
            DBG(DBG_M_CA_DBG_ERR, "Open " CA_DBG_CMU_FILE_BAK " ERROR\r\n");
            return E_SYS_CALL;
        }
    }

    /* 偏移到相应地址, 只要服务器不出错, 理论上不用偏移 */
    //lseek(ca_dbg_ctrl.fd_wr, m_head_cmd->index << 10, SEEK_SET);
    if (write(ca_dbg_ctrl.fd_wr, data, m_head_cmd->len) < 0)
    {
        close(ca_dbg_ctrl.fd_wr);
        ca_dbg_ctrl.fd_wr = 0;
        DBG(DBG_M_CA_DBG_ERR, "Write " CA_DBG_CMU_FILE_BAK " ERROR\r\n");
        return E_SYS_CALL;
    }

    /* 小于 CA_DBG_DATA_MAX 表示结束 */
    if (m_head_cmd->len < CA_DBG_DATA_MAX)
    {
        /* 关闭描述符 */
        close(ca_dbg_ctrl.fd_wr);
        ca_dbg_ctrl.fd_wr = 0;

        /* 文件检查 */
        LD_E_RETURN(DBG_M_CA_DBG_ERR, _ca_dbg_pkt_dev_update_check(CA_DBG_CMU_FILE_BAK));

        /* 替换文件 */
        if (rename(CA_DBG_CMU_FILE_BAK, CA_DBG_CMU_FILE) < 0)
        {
            DBG(DBG_M_CA_DBG_ERR, "Rename " CA_DBG_CMU_FILE_BAK " ERROR\r\n");
            return E_SYS_CALL;
        }

        /* 备份 img */
        _ca_dbg_file_bak(CA_DBG_CMU_FILE, CA_DBG_CMU_FILE_DIR);
    }

    return E_NONE;
}

/* 设备信息报文处理. */
int32_t _ca_dbg_pkt_dev_info_send(void)
{
    char *buf = ca_dbg_ctrl.buf;
    ca_dbg_proto_head_t *head = (ca_dbg_proto_head_t*)buf;
    ca_dbg_dev_info_t *info = (ca_dbg_dev_info_t*)(buf + sizeof(ca_dbg_proto_head_t));
    uint32_t *crc = NULL;
    uint32_t *temp = NULL;
    struct tm *day = NULL;
    time_t utc = 0;
    
    /* 封装报文头 */
    _ca_dbg_pkt_head_init(buf, sizeof(ca_dbg_dev_info_t) + sizeof(ca_dbg_proto_head_t), CA_DBG_CT_REPLY, CA_DBG_C_DEV_INFO);

    /* 封装数据 */
    info->type_m = device_info.id_major;
    info->type_s = device_info.id_minor;
    info->id = device_info.dev_id;
    memcpy(info->mac, device_info.mac, MAC_ADDR_LEN);
    temp = (uint32_t*)info->ip; *temp = inet_addr(device_info.host_ip);
    temp = (uint32_t*)info->ip_mask; *temp = inet_addr(device_info.host_mask);
    temp = (uint32_t*)info->ip_gw; *temp = inet_addr(device_info.host_gw);
    memcpy(info->img_version, host.version, CA_DBG_VERSION_LEN);
    memcpy(info->img_compile_time, host.compile, CA_DBG_COMPILE_LEN);
    utc = device_info.factory_date;
    day = localtime(&utc);
    strftime((char*)info->factory_time, CA_DBG_COMPILE_LEN, "%Y-%m-%d", day);
    memcpy(info->name, host.name, CA_DBG_NAME_LEN);

    /* 计算校验和 */
    crc = (uint32_t*)(buf + head->len);
    *crc = crc32(buf, head->len);
    
    LD_E_RETURN(DBG_M_CA_DBG_ERR, _ca_dbg_pkt_send(buf, head->len + CA_DBG_CRC32_LEN));
    
    return E_NONE;
}

/* 设备信息报文处理. */
int32_t _ca_dbg_pkt_dev_info_set_send(char *cmd)
{
    char *buf = ca_dbg_ctrl.buf;
    ca_dbg_proto_head_t *head = (ca_dbg_proto_head_t*)buf;
    ca_dbg_dev_info_t *info = (ca_dbg_dev_info_t*)(cmd + sizeof(ca_dbg_proto_head_t));
    uint32_t *crc = NULL;
    uint32_t utc = 0;
    
    /* 封装数据 */
    memcpy(host.name, info->name, FILE_NAME_LEN);
    device_info.dev_id = info->id;
    snprintf(device_info.host_ip, INET_ADDRSTRLEN, "%d.%d.%d.%d", info->ip[0], info->ip[1], info->ip[2], info->ip[3]);
    snprintf(device_info.host_mask, INET_ADDRSTRLEN, "%d.%d.%d.%d", info->ip_mask[0], info->ip_mask[1], info->ip_mask[2], info->ip_mask[3]);
    snprintf(device_info.host_gw, INET_ADDRSTRLEN, "%d.%d.%d.%d", info->ip_gw[0], info->ip_gw[1], info->ip_gw[2], info->ip_gw[3]);
    time_str_to_long((char*)info->factory_time, "0:0:0", &utc);
    device_info.factory_date = utc;

    vtysh_device_save();
    vtysh_config_save();
    mac_generate_from_ip(device_info.host_ip, device_info.mac);
    vtysh_eth0_save();
    
    /* 封装报文头 */
    _ca_dbg_pkt_head_init(buf, sizeof(ca_dbg_proto_head_t), CA_DBG_CT_REPLY, CA_DBG_C_DEV_INFO_SET);

    /* 计算校验和 */
    crc = (uint32_t*)(buf + head->len);
    *crc = crc32(buf, head->len);
    
    LD_E_RETURN(DBG_M_CA_DBG_ERR, _ca_dbg_pkt_send(buf, head->len + CA_DBG_CRC32_LEN));

    reboot_system(LOG_CA_DBG, BOOT_REMOTE_CFG_SET);
    
    return E_NONE;
}

/* 设备信息报文处理. */
int32_t _ca_dbg_pkt_dev_reset_send(void)
{
    char *buf = ca_dbg_ctrl.buf;
    ca_dbg_proto_head_t *head = (ca_dbg_proto_head_t*)buf;
    uint32_t *crc = NULL;
    
    /* 封装报文头 */
    _ca_dbg_pkt_head_init(buf, sizeof(ca_dbg_proto_head_t), CA_DBG_CT_REPLY, CA_DBG_C_DEV_RESET);

    /* 计算校验和 */
    crc = (uint32_t*)(buf + head->len);
    *crc = crc32(buf, head->len);
    
    LD_E_RETURN(DBG_M_CA_DBG_ERR, _ca_dbg_pkt_send(buf, head->len + CA_DBG_CRC32_LEN));

    reboot_system(LOG_CA_DBG, BOOT_REMOTE_RESET);
    
    return E_NONE;
}

/* 设备信息报文处理. */
int32_t _ca_dbg_pkt_dev_update_send(char *cmd)
{
    char *buf = ca_dbg_ctrl.buf;
    ca_dbg_proto_head_t *head = (ca_dbg_proto_head_t*)buf;
    ca_dbg_proto_mul_head_t *m_head = (ca_dbg_proto_mul_head_t*)(buf + sizeof(ca_dbg_proto_head_t));
    ca_dbg_proto_mul_head_t *m_head_cmd = (ca_dbg_proto_mul_head_t*)(cmd + sizeof(ca_dbg_proto_head_t));
    int32_t *rt = (int32_t*)(buf + sizeof(ca_dbg_proto_head_t) + sizeof(ca_dbg_proto_mul_head_t));
    uint32_t *crc = NULL;

    /* 复制文件 */
    *rt = _ca_dbg_pkt_dev_update_write(cmd);
    
    /* 封装报文头 */
    _ca_dbg_pkt_head_init(buf, sizeof(ca_dbg_proto_head_t) + sizeof(ca_dbg_proto_mul_head_t) + sizeof(int32_t), CA_DBG_CT_REPLY, CA_DBG_C_DEV_UPDATE);
    m_head->index = m_head_cmd->index;
    m_head->len = m_head_cmd->len;

    /* 计算校验和 */
    crc = (uint32_t*)(buf + head->len);
    *crc = crc32(buf, head->len);
    
    LD_E_RETURN(DBG_M_CA_DBG_ERR, _ca_dbg_pkt_send(buf, head->len + CA_DBG_CRC32_LEN));

    if (m_head_cmd->len < CA_DBG_DATA_MAX && E_NONE == *rt)
    {
        reboot_system(LOG_CA_DBG, BOOT_REMOTE_UPDATE);
    }
    
    return E_NONE;
}

/* 设备信息报文处理. */
int32_t _ca_dbg_pkt_dev_cfg_send(void)
{
    char *buf = ca_dbg_ctrl.buf;
    ca_dbg_proto_head_t *head = (ca_dbg_proto_head_t*)buf;
    ca_coll_cfg_t *cfg = (ca_coll_cfg_t*)(buf + sizeof(ca_dbg_proto_head_t));
    uint32_t *crc = NULL;
    
    /* 封装报文头 */
    _ca_dbg_pkt_head_init(buf, sizeof(ca_coll_cfg_t) + sizeof(ca_dbg_proto_head_t), CA_DBG_CT_REPLY, CA_DBG_C_DEV_CONFIG);

    /* 封装数据 */
    memcpy(cfg, ca_coll_cfg_get(), sizeof(ca_coll_cfg_t));

    /* 计算校验和 */
    crc = (uint32_t*)(buf + head->len);
    *crc = crc32(buf, head->len);
    
    LD_E_RETURN(DBG_M_CA_DBG_ERR, _ca_dbg_pkt_send(buf, head->len + CA_DBG_CRC32_LEN));
    
    return E_NONE;
}

/* 设备信息报文处理. */
int32_t _ca_dbg_pkt_dev_cfg_set_send(char *cmd)
{
    char *buf = ca_dbg_ctrl.buf;
    ca_dbg_proto_head_t *head = (ca_dbg_proto_head_t*)buf;
    ca_coll_cfg_t *cfg = (ca_coll_cfg_t*)(cmd + sizeof(ca_dbg_proto_head_t));
    uint32_t *crc = NULL;
    
    /* 封装数据 */
    memcpy(ca_coll_cfg_get(), cfg, sizeof(ca_coll_cfg_t));

    vtysh_config_save();
    
    /* 封装报文头 */
    _ca_dbg_pkt_head_init(buf, sizeof(ca_dbg_proto_head_t), CA_DBG_CT_REPLY, CA_DBG_C_DEV_CONFIG_SET);

    /* 计算校验和 */
    crc = (uint32_t*)(buf + head->len);
    *crc = crc32(buf, head->len);
    
    LD_E_RETURN(DBG_M_CA_DBG_ERR, _ca_dbg_pkt_send(buf, head->len + CA_DBG_CRC32_LEN));

    _ca_dbg_file_check(CA_DBG_PPP_FILE, CA_DBG_PPP_FILE_BAK, "600");
    cfg = ca_coll_cfg_get();
    _ca_dbg_apn_change(cfg->apn);
    
    return E_NONE;
}

int32_t _ca_dbg_pkt_cable_update_write(char *cmd)
{
    ca_dbg_proto_mul_head_t *m_head_cmd = (ca_dbg_proto_mul_head_t*)(cmd + sizeof(ca_dbg_proto_head_t));
    char *data = cmd + sizeof(ca_dbg_proto_head_t) + sizeof(ca_dbg_proto_mul_head_t);

    /* 初始化文件描述符 */
    if (0 == m_head_cmd->index || ca_dbg_ctrl.fd_wr <= 0)
    {
        if (ca_dbg_ctrl.fd_wr > 0)
        {
            close(ca_dbg_ctrl.fd_wr);
        }

        ca_dbg_ctrl.fd_wr = open(CA_DBG_CABLE_FILE, O_WRONLY | O_CREAT | O_TRUNC, 0777);
        if (ca_dbg_ctrl.fd_wr < 0)
        {
            DBG(DBG_M_CA_DBG_ERR, "Open " CA_DBG_CABLE_FILE " ERROR\r\n");
            return E_SYS_CALL;
        }
    }

    /* 偏移到相应地址, 只要服务器不出错, 理论上不用偏移 */
    //lseek(ca_dbg_ctrl.fd_wr, m_head_cmd->index << 10, SEEK_SET);
    if (write(ca_dbg_ctrl.fd_wr, data, m_head_cmd->len) < 0)
    {
        DBG(DBG_M_CA_DBG_ERR, "Write " CA_DBG_CABLE_FILE " ERROR\r\n");
        close(ca_dbg_ctrl.fd_wr);
        ca_dbg_ctrl.fd_wr = 0;
        return E_SYS_CALL;
    }

    /* 小于 CA_DBG_DATA_MAX 表示结束 */
    if (m_head_cmd->len < CA_DBG_DATA_MAX)
    {
        /* 关闭描述符 */
        close(ca_dbg_ctrl.fd_wr);
        ca_dbg_ctrl.fd_wr = 0;
    }

    return E_NONE;
}

/* 设备信息报文处理. */
int32_t _ca_dbg_pkt_cable_info_send(void)
{
    char *buf = ca_dbg_ctrl.buf;
    ca_dbg_proto_head_t *head = (ca_dbg_proto_head_t*)buf;
    ca_coll_dev_info_t *info = (ca_coll_dev_info_t*)(buf + sizeof(ca_dbg_proto_head_t));
    uint32_t *crc = NULL;
    
    /* 封装报文头 */
    _ca_dbg_pkt_head_init(buf, sizeof(ca_coll_dev_info_t) + sizeof(ca_dbg_proto_head_t), CA_DBG_CT_PRV_REPLY, CA_DBG_C_PRV_CABLE_INFO);

    /* 封装数据 */
    memcpy(info, ca_coll_cable_info_get(), sizeof(ca_coll_dev_info_t));

    /* 计算校验和 */
    crc = (uint32_t*)(buf + head->len);
    *crc = crc32(buf, head->len);
    
    LD_E_RETURN(DBG_M_CA_DBG_ERR, _ca_dbg_pkt_send(buf, head->len + CA_DBG_CRC32_LEN));
    
    return E_NONE;
}

/* 设备信息报文处理. */
int32_t _ca_dbg_pkt_cable_cfg_send(void)
{
    char *buf = ca_dbg_ctrl.buf;
    ca_dbg_proto_head_t *head = (ca_dbg_proto_head_t*)buf;
    ca_coll_dev_cfg_t *cfg = (ca_coll_dev_cfg_t*)(buf + sizeof(ca_dbg_proto_head_t));
    uint32_t *crc = NULL;
    
    /* 封装报文头 */
    _ca_dbg_pkt_head_init(buf, sizeof(ca_coll_dev_cfg_t) + sizeof(ca_dbg_proto_head_t), CA_DBG_CT_PRV_REPLY, CA_DBG_C_PRV_CABLE_CFG);

    /* 封装数据 */
    memcpy(cfg, ca_coll_cable_cfg_get(), sizeof(ca_coll_dev_cfg_t));

    /* 计算校验和 */
    crc = (uint32_t*)(buf + head->len);
    *crc = crc32(buf, head->len);
    
    LD_E_RETURN(DBG_M_CA_DBG_ERR, _ca_dbg_pkt_send(buf, head->len + CA_DBG_CRC32_LEN));
    
    return E_NONE;
}

/* 设备信息报文处理. */
int32_t _ca_dbg_pkt_cable_data_recv(char *cmd)
{
    uint32_t *utc = (uint32_t*)(cmd + sizeof(ca_dbg_proto_head_t));
    uint32_t t = *utc + CA_DBG_SHIQUCHA;

    if (abs(t - time(NULL)) > 1)
    {
        time_set(t); //北京时间
    }
    
    return E_NONE;
}

/* 设备信息报文处理. */
int32_t _ca_dbg_pkt_cable_data_send(void)
{
    char *buf = ca_dbg_ctrl.buf_send;
    ca_dbg_proto_head_t *head = (ca_dbg_proto_head_t*)buf;
    ca_coll_dev_data_t *data = (ca_coll_dev_data_t*)(buf + sizeof(ca_dbg_proto_head_t));
    uint32_t *crc = NULL;
    
    /* 封装报文头 */
    _ca_dbg_pkt_head_init(buf, sizeof(ca_coll_dev_data_t) + sizeof(ca_dbg_proto_head_t), CA_DBG_CT_PRV_REPLY, CA_DBG_C_PRV_CABLE_DATA);

    /* 封装数据 */
    memcpy(data, ca_coll_cable_data_get(), sizeof(ca_coll_dev_data_t));

    /* 计算校验和 */
    crc = (uint32_t*)(buf + head->len);
    *crc = crc32(buf, head->len);
    
    LD_E_RETURN(DBG_M_CA_DBG_ERR, _ca_dbg_pkt_send(buf, head->len + CA_DBG_CRC32_LEN));
    
    return E_NONE;
}

/* 设备信息报文处理. */
int32_t _ca_dbg_pkt_cable_cfg_set_send(char *cmd)
{
    char *buf = ca_dbg_ctrl.buf;
    ca_dbg_proto_head_t *head = (ca_dbg_proto_head_t*)buf;
    ca_coll_dev_cfg_t *cfg = (ca_coll_dev_cfg_t*)(cmd + sizeof(ca_dbg_proto_head_t));
    uint32_t *crc = NULL;
    
    /* 封装数据 */
    memcpy(ca_coll_cable_cfg_get(), cfg, sizeof(ca_coll_dev_cfg_t));

    vtysh_config_save();
    
    /* 封装报文头 */
    _ca_dbg_pkt_head_init(buf, sizeof(ca_dbg_proto_head_t), CA_DBG_CT_PRV_REPLY, CA_DBG_C_PRV_CABLE_CFG_SET);

    /* 计算校验和 */
    crc = (uint32_t*)(buf + head->len);
    *crc = crc32(buf, head->len);
    
    LD_E_RETURN(DBG_M_CA_DBG_ERR, _ca_dbg_pkt_send(buf, head->len + CA_DBG_CRC32_LEN));
    
    return E_NONE;
}

/* 设备信息报文处理. */
int32_t _ca_dbg_pkt_cable_update_send(char *cmd)
{
    char *buf = ca_dbg_ctrl.buf;
    ca_dbg_proto_head_t *head = (ca_dbg_proto_head_t*)buf;
    ca_dbg_proto_mul_head_t *m_head = (ca_dbg_proto_mul_head_t*)(buf + sizeof(ca_dbg_proto_head_t));
    ca_dbg_proto_mul_head_t *m_head_cmd = (ca_dbg_proto_mul_head_t*)(cmd + sizeof(ca_dbg_proto_head_t));
    int32_t *rt = (int32_t*)(buf + sizeof(ca_dbg_proto_head_t) + sizeof(ca_dbg_proto_mul_head_t));
    uint32_t *crc = NULL;

    /* 复制文件 */
    *rt = _ca_dbg_pkt_cable_update_write(cmd);
    
    /* 封装报文头 */
    _ca_dbg_pkt_head_init(buf, sizeof(ca_dbg_proto_head_t) + sizeof(ca_dbg_proto_mul_head_t) + sizeof(int32_t), CA_DBG_CT_PRV_REPLY, CA_DBG_C_PRV_CABLE_UPDATE);
    m_head->index = m_head_cmd->index;
    m_head->len = m_head_cmd->len;

    /* 计算校验和 */
    crc = (uint32_t*)(buf + head->len);
    *crc = crc32(buf, head->len);
    
    LD_E_RETURN(DBG_M_CA_DBG_ERR, _ca_dbg_pkt_send(buf, head->len + CA_DBG_CRC32_LEN));

    if (m_head_cmd->len < CA_DBG_DATA_MAX && E_NONE == *rt)
    {
        ca_coll_cable_update_set(TRUE);
    }
    
    return E_NONE;
}

/* 设备信息报文处理. */
int32_t _ca_dbg_pkt_cable_state_send(void)
{
    char *buf = ca_dbg_ctrl.buf_send;
    ca_dbg_proto_head_t *head = (ca_dbg_proto_head_t*)buf;
    ca_dbg_state_t *state = (ca_dbg_state_t*)(buf + sizeof(ca_dbg_proto_head_t));
    ca_coll_state_t *ca_coll_state = NULL;
    ca_mqtt_state_t *ca_mqtt_state = NULL;
    ca_land_state_t *ca_land_state = NULL;
    uint32_t *crc = NULL;
    
    /* 封装报文头 */
    _ca_dbg_pkt_head_init(buf, sizeof(ca_dbg_proto_head_t) + sizeof(ca_dbg_state_t), CA_DBG_CT_PRV_REPLY, CA_DBG_C_PRV_CABLE_STATE);

    /* 封装数据 */
    ca_coll_state = ca_coll_cable_state_get();
    state->is_connect = ca_coll_state->send_err_cnt < CA_COLL_ERR_CNT_MAX;
    state->is_update_cable = ca_coll_state->is_update_cable;
    state->update_index = ca_coll_state->update_index;
    state->is_connect_4g = ca_coll_state->is_4g_connect;

    ca_mqtt_state = ca_mqtt_state_get();
    state->is_connect_mqtt = ca_mqtt_state->is_connect;

    ca_land_state = ca_land_state_get();
    state->is_connect_land = ca_land_state->is_connect;

    state->run_time = start_time;

    /* 计算校验和 */
    crc = (uint32_t*)(buf + head->len);
    *crc = crc32(buf, head->len);
    
    LD_E_RETURN(DBG_M_CA_DBG_ERR, _ca_dbg_pkt_send(buf, head->len + CA_DBG_CRC32_LEN));
    
    return E_NONE;
}

/* 设备信息报文处理. */
int32_t _ca_dbg_pkt_log_send(char *cmd)
{
    char *buf = ca_dbg_ctrl.buf;
    ca_dbg_proto_head_t *head = (ca_dbg_proto_head_t*)buf;
    ca_dbg_proto_mul_head_t *m_head = (ca_dbg_proto_mul_head_t*)(buf + sizeof(ca_dbg_proto_head_t));
    ca_dbg_proto_mul_head_t *m_head_cmd = (ca_dbg_proto_mul_head_t*)(cmd + sizeof(ca_dbg_proto_head_t));
    char *data = buf + sizeof(ca_dbg_proto_head_t) + sizeof(ca_dbg_proto_mul_head_t);
    uint32_t *crc = NULL;
    int32_t len = 0;

    /* 初始化文件描述符 */
    if (0 == m_head_cmd->index || ca_dbg_ctrl.fd_wr <= 0)
    {
        _ca_dbg_file_bak(LOG_FILE, CA_DBG_LOG_FILE);
        
        if (ca_dbg_ctrl.fd_wr > 0)
        {
            close(ca_dbg_ctrl.fd_wr);
        }

        ca_dbg_ctrl.fd_wr = open(CA_DBG_LOG_FILE, O_RDONLY, 0777);
        if (ca_dbg_ctrl.fd_wr < 0)
        {
            DBG(DBG_M_CA_DBG_ERR, "Open " CA_DBG_LOG_FILE " ERROR\r\n");
            return E_SYS_CALL;
        }
    }

    /* 偏移到相应地址, 只要服务器不出错, 理论上不用偏移 */
    lseek(ca_dbg_ctrl.fd_wr, m_head_cmd->index << 10, SEEK_SET);
    len = read(ca_dbg_ctrl.fd_wr, data, CA_DBG_DATA_MAX);
    if (len < 0)
    {
        DBG(DBG_M_CA_DBG_ERR, "Read " CA_DBG_LOG_FILE " ERROR\r\n");
        close(ca_dbg_ctrl.fd_wr);
        ca_dbg_ctrl.fd_wr = 0;
        return E_SYS_CALL;
    }

    /* 封装报文头 */
    _ca_dbg_pkt_head_init(buf, sizeof(ca_dbg_proto_head_t), CA_DBG_CT_PRV_REPLY, CA_DBG_C_PRV_CABLE_LOG);
    m_head->index = m_head_cmd->index;
    m_head->len = len;
    head->len += sizeof(ca_dbg_proto_mul_head_t) + m_head->len;

    /* 计算校验和 */
    crc = (uint32_t*)(buf + head->len);
    *crc = crc32(buf, head->len);
    
    LD_E_RETURN(DBG_M_CA_DBG_ERR, _ca_dbg_pkt_send(buf, head->len + CA_DBG_CRC32_LEN));

    if (len < CA_DBG_DATA_MAX)
    {
        close(ca_dbg_ctrl.fd_wr);
        ca_dbg_ctrl.fd_wr = 0;
        remove(CA_DBG_LOG_FILE);
    }
    
    return E_NONE;
}

/* 设备信息报文处理. */
int32_t _ca_dbg_pkt_hdata_send(char *cmd)
{
    char *buf = ca_dbg_ctrl.buf;
    ca_dbg_proto_head_t *head = (ca_dbg_proto_head_t*)buf;
    ca_dbg_proto_mul_head_t *m_head = (ca_dbg_proto_mul_head_t*)(buf + sizeof(ca_dbg_proto_head_t));
    ca_dbg_proto_mul_head_t *m_head_cmd = (ca_dbg_proto_mul_head_t*)(cmd + sizeof(ca_dbg_proto_head_t));
    char *data = buf + sizeof(ca_dbg_proto_head_t) + sizeof(ca_dbg_proto_mul_head_t);
    uint32_t *crc = NULL;
    int32_t len = 0;

    /* 初始化文件描述符 */
    if (0 == m_head_cmd->index || ca_dbg_ctrl.fd_wr <= 0)
    {
        _ca_dbg_file_bak(CA_DB_FILE, CA_DBG_HDATA_FILE);
        
        if (ca_dbg_ctrl.fd_wr > 0)
        {
            close(ca_dbg_ctrl.fd_wr);
        }

        ca_dbg_ctrl.fd_wr = open(CA_DBG_HDATA_FILE, O_RDONLY, 0777);
        if (ca_dbg_ctrl.fd_wr < 0)
        {
            DBG(DBG_M_CA_DBG_ERR, "Open " CA_DBG_HDATA_FILE " ERROR\r\n");
            return E_SYS_CALL;
        }
    }

    /* 偏移到相应地址, 只要服务器不出错, 理论上不用偏移 */
    lseek(ca_dbg_ctrl.fd_wr, m_head_cmd->index << 10, SEEK_SET);
    len = read(ca_dbg_ctrl.fd_wr, data, CA_DBG_DATA_MAX);
    if (len < 0)
    {
        DBG(DBG_M_CA_DBG_ERR, "Read " CA_DBG_HDATA_FILE " ERROR\r\n");
        close(ca_dbg_ctrl.fd_wr);
        ca_dbg_ctrl.fd_wr = 0;
        return E_SYS_CALL;
    }

    /* 封装报文头 */
    _ca_dbg_pkt_head_init(buf, sizeof(ca_dbg_proto_head_t), CA_DBG_CT_PRV_REPLY, CA_DBG_C_PRV_CABLE_HDATA);
    m_head->index = m_head_cmd->index;
    m_head->len = len;
    head->len += sizeof(ca_dbg_proto_mul_head_t) + m_head->len;

    /* 计算校验和 */
    crc = (uint32_t*)(buf + head->len);
    *crc = crc32(buf, head->len);
    
    LD_E_RETURN(DBG_M_CA_DBG_ERR, _ca_dbg_pkt_send(buf, head->len + CA_DBG_CRC32_LEN));

    if (len < CA_DBG_DATA_MAX)
    {
        close(ca_dbg_ctrl.fd_wr);
        ca_dbg_ctrl.fd_wr = 0;
        remove(CA_DBG_HDATA_FILE);
    }
    
    return E_NONE;
}

/* 设备信息报文处理. */
int32_t _ca_dbg_pkt_mqtt_info_send(void)
{
    char *buf = ca_dbg_ctrl.buf;
    ca_dbg_proto_head_t *head = (ca_dbg_proto_head_t*)buf;
    ca_mqtt_dev_info_t *info = (ca_mqtt_dev_info_t*)(buf + sizeof(ca_dbg_proto_head_t));
    uint32_t *crc = NULL;
    
    /* 封装报文头 */
    _ca_dbg_pkt_head_init(buf, sizeof(ca_mqtt_dev_info_t) + sizeof(ca_dbg_proto_head_t), CA_DBG_CT_PRV_REPLY, CA_DBG_C_PRV_MQTT_INFO);

    /* 封装数据 */
    memcpy(info, &device_info.mqtt, sizeof(ca_mqtt_dev_info_t));

    /* 计算校验和 */
    crc = (uint32_t*)(buf + head->len);
    *crc = crc32(buf, head->len);
    
    LD_E_RETURN(DBG_M_CA_DBG_ERR, _ca_dbg_pkt_send(buf, head->len + CA_DBG_CRC32_LEN));
    
    return E_NONE;
}

int32_t _ca_dbg_pkt_mqtt_info_set_send(char *cmd)
{
    char *buf = ca_dbg_ctrl.buf;
    ca_dbg_proto_head_t *head = (ca_dbg_proto_head_t*)buf;
    ca_mqtt_dev_info_t *info = (ca_mqtt_dev_info_t*)(cmd + sizeof(ca_dbg_proto_head_t));
    uint32_t *crc = NULL;
    
    /* 封装数据 */
    memcpy(&device_info.mqtt, info, sizeof(ca_mqtt_dev_info_t));

    vtysh_device_save();
    
    /* 封装报文头 */
    _ca_dbg_pkt_head_init(buf, sizeof(ca_dbg_proto_head_t), CA_DBG_CT_PRV_REPLY, CA_DBG_C_PRV_MQTT_INFO_SET);

    /* 计算校验和 */
    crc = (uint32_t*)(buf + head->len);
    *crc = crc32(buf, head->len);
    
    LD_E_RETURN(DBG_M_CA_DBG_ERR, _ca_dbg_pkt_send(buf, head->len + CA_DBG_CRC32_LEN));
    
    return E_NONE;
}

int32_t _ca_dbg_pkt_check(char *cmd)
{
    ca_dbg_proto_head_t *head = (ca_dbg_proto_head_t*)cmd;

    /* 对主次设备号进行识别, 次设备号可以是广播. */
    if ((head->dev_type_m != 1)
        || (head->dev_type_s != 0xFF && head->dev_type_s != device_info.id_minor))
    {
        DBG(DBG_M_CA_DBG_ERR, "Dev type %d:%d error\r\n", head->dev_type_m, head->dev_type_s);
        return E_NOT_FOUND;
    }

    /* 对设备 id 进行识别, 可以是广播. */
    //if (head->dev_id != 0xFFFFFFFF && head->dev_id != device_info.dev_id)
    //{
    //    DBG(DBG_M_CA_DBG_ERR, "Dev id %x error\r\n", head->dev_id);
    //    return E_NOT_FOUND;
    //}

    /* 验证 CRC32. */
    if (crc32(cmd, head->len) != (*(uint32_t*)(cmd + head->len)))
    {
        DBG(DBG_M_CA_DBG_ERR, "CRC %x:%x error\r\n", crc32(cmd, head->len), *(uint32_t*)(cmd + head->len));
        return E_ERROR;
    }

    return E_NONE;
}

/* 调试工具报文数据处理. */
int32_t _ca_dbg_pkt_process(char *buf)
{
    ca_dbg_proto_head_t *head = (ca_dbg_proto_head_t*)buf;

    /* 报文格式检查. */
    LD_E_RETURN(DBG_M_CA_DBG_ERR, _ca_dbg_pkt_check(buf));

    /* 报文处理. */
    if (CA_DBG_CT_REQUEST == head->cmd_type)
    {
        /* 共有命令处理. */
        switch (head->cmd)
        {
        case CA_DBG_C_DEV_INFO:
            _ca_dbg_pkt_dev_info_send();
            break;
        case CA_DBG_C_DEV_INFO_SET:
            _ca_dbg_pkt_dev_info_set_send(buf);
            break;
        case CA_DBG_C_DEV_RESET:
            _ca_dbg_pkt_dev_reset_send();
            break;
        case CA_DBG_C_DEV_UPDATE:
            _ca_dbg_pkt_dev_update_send(buf);
            break;
        case CA_DBG_C_DEV_CONFIG:
            _ca_dbg_pkt_dev_cfg_send();
            break;
        case CA_DBG_C_DEV_CONFIG_SET:
            _ca_dbg_pkt_dev_cfg_set_send(buf);
            break;
        default:
            DBG(DBG_M_CA_DBG_ERR, "Cmd %d not found\r\n", head->cmd);
            return E_NOT_FOUND;
        }
    }
    else if(CA_DBG_CT_PRV_REQUEST == head->cmd_type)
    {
        /* 私有命令处理. */
        switch (head->cmd)
        {
        case CA_DBG_C_PRV_CABLE_INFO:
            _ca_dbg_pkt_cable_info_send();
            break;
        case CA_DBG_C_PRV_CABLE_CFG:
            _ca_dbg_pkt_cable_cfg_send();
            break;
        case CA_DBG_C_PRV_CABLE_DATA:
            _ca_dbg_pkt_cable_data_recv(buf);
            break;
        case CA_DBG_C_PRV_CABLE_CFG_SET:
            _ca_dbg_pkt_cable_cfg_set_send(buf);
            break;
        case CA_DBG_C_PRV_CABLE_UPDATE:
            _ca_dbg_pkt_cable_update_send(buf);
            break;
        case CA_DBG_C_PRV_CABLE_LOG:
            _ca_dbg_pkt_log_send(buf);
            break;
        case CA_DBG_C_PRV_CABLE_HDATA:
            _ca_dbg_pkt_hdata_send(buf);
            break;
        case CA_DBG_C_PRV_MQTT_INFO:
            _ca_dbg_pkt_mqtt_info_send();
            break;
        case CA_DBG_C_PRV_MQTT_INFO_SET:
            _ca_dbg_pkt_mqtt_info_set_send(buf);
            break;
        default:
            DBG(DBG_M_CA_DBG_ERR, "Cmd %d not found\r\n", head->cmd);
            return E_NOT_FOUND;
        }
    }

    return E_NONE;
}

/* 调试工具报文接收处理线程. */
void *_ca_dbg_pkt_handle_recv(void *arg)
{
    uint8_t state = FALSE;
    uint32_t utc = 0;
    int32_t cmd_buf_index = 0;
    ca_dbg_proto_head_t *head = (ca_dbg_proto_head_t*)ca_dbg_ctrl.cmd_buf;
    ca_dbg_proto_mul_head_t *m_head = (ca_dbg_proto_mul_head_t*)(ca_dbg_ctrl.cmd_buf + sizeof(ca_dbg_proto_head_t));
    char *buf = ca_dbg_ctrl.buf;
    uint32_t now = 0;
    int len = 0;
    
    while(1)
    {
        /* 读取数据. */
        len = read(ca_dbg_ctrl.fd_client, buf, CA_DBG_BUF_SIZE);
        if (len <= 0)
        {
            /* 连接中断, 关闭 socket 和手动采样. */
            DBG(DBG_M_CA_DBG_ERR, "Read len %d, close fd!\r\n", len);
            close(ca_dbg_ctrl.fd_client);
            ca_dbg_ctrl.fd_client = -1;
            break;
        }

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

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

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

        if (!state)
        {
            if (cmd_buf_index < sizeof(ca_dbg_proto_head_t) + CA_DBG_CRC32_LEN)
            {
                continue;
            }
        
            /* 报文长度不对, 重新收包. */
            if (head->len + CA_DBG_CRC32_LEN > CA_DBG_CMD_BUF_LEN)
            {
                cmd_buf_index = 0;
                state = FALSE;
                continue;
            }

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

            state = FALSE;
        }

        DBG(DBG_M_CA_DBG, "Recv(%d): %d %d %d %d\r\n", cmd_buf_index, utc, head->cmd_type, head->cmd, m_head->index);
        if (dbg_stat_get(DBG_M_CA_DBG))
        {
            buf_print(ca_dbg_ctrl.cmd_buf, cmd_buf_index > 32 ? 32 : cmd_buf_index);
            //buf_print(ca_dbg_ctrl.cmd_buf, cmd_buf_index);
        }

        /* 数据处理. */
        while(1)
        {
            _ca_dbg_pkt_process(ca_dbg_ctrl.cmd_buf);

            len = head->len + CA_DBG_CRC32_LEN;
            cmd_buf_index -= len;
            if (cmd_buf_index <= 0)
            {
                cmd_buf_index = 0;
                break;
            }
            
            memcpy(ca_dbg_ctrl.cmd_buf, ca_dbg_ctrl.cmd_buf + len, cmd_buf_index);
            if (cmd_buf_index < sizeof(ca_dbg_proto_head_t) + CA_DBG_CRC32_LEN)
            {
                break;
            }

            /* 报文长度与收包长度不对称, 等待后续报文. */
            if (cmd_buf_index < head->len + CA_DBG_CRC32_LEN)
            {
                break;
            }
        }
        
    }
    
    pthread_exit("thread exit");
    return NULL;
}

int32_t _ca_dbg_client_create(void)
{
    struct sched_param param;
    pthread_attr_t attr;
    int32_t rv = 0;
    pthread_t thread;

    /* 初始化报文处理线程. */
    /* 配置线程RR调度, 优先级25. */
    pthread_attr_init(&attr);
    param.sched_priority = 25;
    pthread_attr_setschedpolicy(&attr, SCHED_RR);
    pthread_attr_setschedparam(&attr, &param);
    pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
    rv = pthread_create(&thread, &attr, _ca_dbg_pkt_handle_recv, NULL);
    if (rv != 0)
    {
        DBG(DBG_M_CA_DBG_ERR, "PD can't create debug pthread %d!\r\n", rv);
        return E_SYS_CALL;
    }

    pthread_attr_destroy(&attr);
    
    return E_NONE;
}

int32_t _ca_dbg_keep_alive(int fd)
{
    // 开启保活，保活参数 表示60秒内无交互后，每隔6秒检测一次，40次都没得到响应时会断开连接。
    int keep_alive = 1;
    int keep_idle = 60;
    int keep_interval = 6;
    int keep_count = 10;
    int keep_time = 60000;
    
    if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &keep_alive, sizeof(keep_alive)))
    {
        DBG(DBG_M_CA_DBG_ERR, "Error setsockopt(SO_KEEPALIVE) failed, return %s!\r\n", safe_strerror(errno));
        return E_SYS_CALL;
    }
    if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &keep_idle, sizeof(keep_idle)))
    {
        DBG(DBG_M_CA_DBG_ERR, "Error setsockopt(TCP_KEEPIDLE) failed, return %s!\r\n", safe_strerror(errno));
        return E_SYS_CALL;
    }
    if (setsockopt(fd, SOL_TCP, TCP_KEEPINTVL, (void *)&keep_interval, sizeof(keep_interval)))
    {
        DBG(DBG_M_CA_DBG_ERR, "Error setsockopt(TCP_KEEPINTVL) failed, return %s!\r\n", safe_strerror(errno));
        return E_SYS_CALL;
    }
    if (setsockopt(fd, SOL_TCP, TCP_KEEPCNT, (void *)&keep_count, sizeof(keep_count)))
    {
        DBG(DBG_M_CA_DBG_ERR, "Error setsockopt(TCP_KEEPCNT) failed, return %s!\r\n", safe_strerror(errno));
        return E_SYS_CALL;
    }

    if (setsockopt(fd, SOL_TCP, TCP_USER_TIMEOUT, (void *)&keep_time, sizeof(keep_time)))
    {
        DBG(DBG_M_CA_DBG_ERR, "Error setsockopt(TCP_KEEPCNT) failed, return %s!\r\n", safe_strerror(errno));
        return E_SYS_CALL;
    }
    
    return E_NONE;
}

void *_ca_dbg_accept_handle(void *arg)
{
    struct sockaddr_in cliaddr = {0};
    socklen_t clilen;
    int connfd = 0;

    while (!is_system_init)
    {
        sleep(1);
    }
    
    /* 监听端口. */
    if ((listen(ca_dbg_ctrl.fd, 5)) != 0)
    {
        DBG(DBG_M_CA_DBG_ERR, "ERROR at socket listen return %s!\r\n", safe_strerror(errno));
        return NULL;
    }
    
    while (1)
    {
        clilen = sizeof(cliaddr);
        connfd = accept(ca_dbg_ctrl.fd, (struct sockaddr*)&cliaddr, &clilen);
        if (connfd < 0)
        {
            DBG(DBG_M_CA_DBG_ERR, "ERROR at socket accept return %s!\r\n", safe_strerror(errno));
            continue;
        }

        if (ca_dbg_ctrl.fd_client < 0)
        {
            ca_dbg_ctrl.fd_client = connfd;
            _ca_dbg_keep_alive(ca_dbg_ctrl.fd_client);
            _ca_dbg_client_create();
        }
        else
        {
            DBG(DBG_M_CA_DBG_ERR, "There is a link trying to connect...\r\n");
            close(connfd);
            connfd = -1;
        }
    }
    return NULL;
}

/* 用于定时将数据发送给调试软件. */
void* _ca_dbg_data_send(void *arg)
{
    /* 如果手动采样开启, 则发送数据. */
    if (ca_dbg_ctrl.fd_client > 0)
    {
        _ca_dbg_pkt_cable_data_send();
        _ca_dbg_pkt_cable_state_send();
    }

    /* 重新加入定时器. */
    mtimer_add(_ca_dbg_data_send, NULL, 3, "CA_DBG_DATA_SEND");
    return NULL;
}

/* Interface functions -------------------------------------------------------*/
/* 调试工具初始化. */
int32_t ca_dbg_handle_init_after(void)
{
    struct sockaddr_in server;
    struct sched_param param;
    pthread_attr_t attr;
    pthread_t pid;
    int32_t rv = 0;
    int fd = 0;
    int opt = 1;

    /* 创建 socket */
    fd = socket(AF_INET, SOCK_STREAM, 0);
    if (fd < 0)
    {
        log_err(LOG_CA_DBG, "ERROR at socket create return %s!", safe_strerror(errno));
        return E_SYS_CALL;
    }

    /* 绑定端口 */
    bzero(&server, sizeof(server));
    server.sin_family = AF_INET;
    server.sin_addr.s_addr = htonl(INADDR_ANY);
    server.sin_port = htons(CA_DBG_TOOL_PORT);
    if (bind(fd, (struct sockaddr*)&server, sizeof(server)) < 0)
    {
        log_err(LOG_CA_DBG, "ERROR at socket bind return %s!", safe_strerror(errno));
        close(fd);
        return E_SYS_CALL;
    }

    /* fd 为需要端口复用的套接字 */
    opt = 1;
    setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const void *)&opt, sizeof(opt));

    /* 保存数据. */
    ca_dbg_ctrl.fd = fd;
    ca_dbg_ctrl.fd_client = -1;

    pthread_attr_init(&attr);
    param.sched_priority = 25;
    pthread_attr_setschedpolicy(&attr, SCHED_RR);
    pthread_attr_setschedparam(&attr, &param);
    pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
    rv = pthread_create(&pid, &attr, _ca_dbg_accept_handle, NULL);
    if (rv != 0)
    {
        log_err(LOG_CA_DBG, "Can't create debug pthread %d!", rv);
        return E_SYS_CALL;
    }
    else
    {
        thread_m_add("CA_DBG_ACCEPT", pid);
    }
    pthread_attr_destroy(&attr);
    
    mtimer_add(_ca_dbg_data_send, NULL, 3, "CA_DBG_DATA_SEND");
    
    return E_NONE;
}

int32_t ca_dbg_update_rt_send(int32_t rt)
{
    char buf[128] = {0};
    ca_dbg_proto_head_t *head = (ca_dbg_proto_head_t*)buf;
    int32_t *data = (int32_t*)(buf + sizeof(ca_dbg_proto_head_t));
    uint32_t *crc = NULL;
    
    /* 封装报文头 */
    _ca_dbg_pkt_head_init(buf, sizeof(ca_dbg_proto_head_t) + sizeof(int32_t), CA_DBG_CT_PRV_REPLY, CA_DBG_C_PRV_CABLE_UPDATE_RT);

    /* 封装数据 */
    *data = rt;

    /* 计算校验和 */
    crc = (uint32_t*)(buf + head->len);
    *crc = crc32(buf, head->len);
    
    LD_E_RETURN(DBG_M_CA_DBG_ERR, _ca_dbg_pkt_send(buf, head->len + CA_DBG_CRC32_LEN));

    remove(CA_DBG_CABLE_FILE);
    
    return E_NONE;
}
#endif
/************************ (C) COPYRIGHT LandPower ***** END OF FILE ****************/

