/* Includes ------------------------------------------------------------------*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

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

#include "cmd.h"
#include "mtimer.h"
#include "process.h"
#include "hwgpio.h"
#include "fifo.h"
#include "debug.h"
#include "ca_dbg.h"
#include "ca_csg.h"
#include "ca_cau.h"
#include "ca_param.h"
#include "ca_network.h"


/* Private define ------------------------------------------------------------*/
#define DEBUG_HEAD 0x55AA
#define DEBUG_TAIL 0x5AA5

#define DEBUG_CMD_LEN 10 * 1024 * 1024

//#define DEBUG_CMU_FILE "PDMonitor"
//#define DEBUG_CMU_FILE_BAK "PDMonitor.bak"

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

/* Private typedef -----------------------------------------------------------*/

/* Private variables ---------------------------------------------------------*/
debug_ctrl_t debug_ctrl;
static char buf_cmd[DEBUG_CMD_LEN];

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

/* Internal functions --------------------------------------------------------*/
void _debug_pkt_head_int(debug_pkt_head_t *head, uint16_t cmd, uint32_t len)
{
    head->head = DEBUG_HEAD;
    head->cmd = cmd;
    head->len = len;
}


/*  回复报文处理. */
int32_t _debug_pkt_common_send(char *buf, uint16_t cmd, uint32_t data_len)
{
    debug_pkt_head_t *head = (debug_pkt_head_t*)buf;
    uint16_t *tail = (uint16_t*)(buf + sizeof(debug_pkt_head_t) + data_len);

    _debug_pkt_head_int(head, cmd, data_len);
    *tail = DEBUG_TAIL;

    if (write(debug_ctrl.fd_client, buf, sizeof(debug_pkt_head_t) + data_len + 2) <= 0)
    {
        DBG(DBG_M_CA_DBG, "Write cmd %x ERROR\r\n", head->cmd);
        return E_SYS_CALL;
    }

    return E_NONE;
}

/* 报文校验. */
int32_t _debug_pkt_check(char *buf, int len)
{
    debug_pkt_head_t *head = (debug_pkt_head_t*)buf;
    uint16_t *tail = (uint16_t*)(buf + len - 2);
    
    if (*tail != DEBUG_TAIL)
    {
        LOG("++++++++++++111");
        return E_ERROR;
    }
    
    if(head->head != DEBUG_HEAD)
    {
        LOG("++++++++++++222");
        return E_ERROR;
    }

    return E_NONE;
}

int _dbg_pkt_config_get(debug_msg_info_t *msg)
{
    int i;
    debug_pkt_device_cfg_t cfg = {0};
    char *pdata = NULL;
    struct in_addr addr;
    
    if (msg == NULL)
        return -1;

    //sprintf((char *)pparam_config->gateway.DeviceNum, "%04d%04d", 
    //        device_info.id_major, device_info.id_minor);
    strncpy((char *)pparam_config->gateway.DeviceNum, host.name, 15);
    
    //sysctrl.dev_hex_id = sysctrl.dev_hex_id;
    
    inet_pton(AF_INET, device_info.host_ip, &addr);
    memcpy(pparam_config->gateway.LocalIP1, &addr.s_addr, 4);

    memcpy(pparam_config->gateway.ServerIP1, &csg.server.sin_addr.s_addr, 4);
    pparam_config->gateway.ServerIP1_Port = csg.server_port;
    LOG("serverip=0x%x", csg.server_ip);
    LOG("%d %d %d %d", csg.server_ip & 0xff, (csg.server_ip >> 8) & 0xff, 
    (csg.server_ip >> 16) & 0xff, (csg.server_ip >> 24) & 0xff);
    
    memcpy(&cfg.gateway, &pparam_config->gateway, sizeof(GateWay_t));
    char buf[64] = {0};
    sprintf(buf, "V%s", host.version);
    LOG("version=%s\n", host.version);
    strcpy((char *)cfg.gateway.reserved, buf);
    memcpy(&cfg.landDevCfg, &pparam_config->landHexCfg, sizeof(LandDevCfg_t));
    for (i = 0; i < 24; i++)
    {
        cfg.CAUInit[i].Range = pparam_config->cauParam[i].Range;
        cfg.CAUInit[i].Ratio = pparam_config->cauParam[i].Ratio;
        cfg.CAUInit[i].ZeroPoint = pparam_config->cauParam[i].ZeroPoint;
        cfg.CAUInit[i].ChangeThreshold = pparam_config->cauParam[i].ChangeThreshold;
        cfg.CAUInit[i].HighLimit = pparam_config->cauParam[i].HighLimit;
        cfg.CAUInit[i].LowLimit = pparam_config->cauParam[i].LowLimit;
    }

    /* copy data */
    pdata = msg->pbuf + sizeof(debug_pkt_head_t);
    memcpy(pdata, &cfg, sizeof(cfg));
    _debug_pkt_common_send((char *)msg->pbuf, msg->cmd, sizeof(cfg));
    return 0;
}

int _dbg_pkt_config_set(debug_msg_info_t *msg)
{
    int i;
    if (msg == NULL)
        return -1;

    if (msg->len  != sizeof(debug_pkt_device_cfg_t))
    {
        printh("_dbg_pkg_config_set invalid msg reallen:%d expect len:%d\n",
            msg->len, sizeof(debug_pkt_device_cfg_t));
        return -1;
    }
        
    debug_pkt_device_cfg_t *pcfg = (debug_pkt_device_cfg_t *)msg->pbuf;
    if (strncmp((char *)pcfg->gateway.apn, (char *)pparam_config->gateway.apn, 
            sizeof(pparam_config->gateway.apn)) != 0)
    {
        _network_change_apn((char *)pcfg->gateway.apn);
    }

    strncpy(host.name, (char *)pcfg->gateway.DeviceNum, 15);
    sysctrl.dev_hex_id = dev_id_2_hex(host.name);

    sprintf(device_info.host_ip, "%d.%d.%d.%d", pcfg->gateway.LocalIP1[0], 
        pcfg->gateway.LocalIP1[1], pcfg->gateway.LocalIP1[2], pcfg->gateway.LocalIP1[3]);
    LOG("host_ip:%s", device_info.host_ip);

    char serverip[16] = {0};
    sprintf(serverip, "%d.%d.%d.%d", pcfg->gateway.ServerIP1[0], 
        pcfg->gateway.ServerIP1[1], pcfg->gateway.ServerIP1[2], pcfg->gateway.ServerIP1[3]);
    csg.server_ip = inet_addr(serverip);
    LOG("serverip=0x%x", csg.server_ip);
    LOG("%d %d %d %d", csg.server_ip & 0xff, (csg.server_ip >> 8) & 0xff, 
        (csg.server_ip >> 16) & 0xff, (csg.server_ip >> 24) & 0xff);
    csg.server_port = (uint16_t)pcfg->gateway.ServerIP1_Port;
    
    memcpy(&pparam_config->gateway, &pcfg->gateway, sizeof(GateWay_t));
    memcpy(&pparam_config->landHexCfg, &pcfg->landDevCfg, sizeof(LandDevCfg_t));
    for (i = 0; i < 24; i++)
    {
        memcpy(&pparam_config->cauParam[i], &pcfg->CAUInit[i], 24);
        DBG(DBG_M_CA_DBG, "ch%d Range=%f Ratio=%f ZeroPoint=%f ChangeThreshold=%f HighLimit=%f LowLimit=%f\n", 
        i, pcfg->CAUInit[i].Range, pcfg->CAUInit[i].Ratio, pcfg->CAUInit[i].ZeroPoint, pcfg->CAUInit[i].ChangeThreshold, pcfg->CAUInit[i].HighLimit, pcfg->CAUInit[i].LowLimit);
    }
    
    param_save();

    vtysh_config_save();
    uint8_t mac[MAC_ADDR_LEN] = {0};
    mac_generate_from_ip(device_info.host_ip, mac);
    memcpy(device_info.mac, mac, MAC_ADDR_LEN);
    vtysh_eth0_save();
    vtysh_device_save();
    reboot_system(LOG_DEBUG, BOOT_LOCAL_IP_CHANGE);
    return 0;
}

int _dbg_pkt_reboot_system()
{
    reboot_system(LOG_DEBUG, BOOT_LOCAL_RESET);
    return 0;
}

int _dbg_get_current_cau_values(float *fdestArr)
{
    float valist[24] = {0};
    int chswitch;
    int i;

    cau_real_data_t *pval = &cau.real_data;
    memcpy(valist, pval->tag, sizeof(pval->tag));
    
    for (i = 0; i < 11; i++)
    {
        chswitch = pparam_config->cauParam[i].chSwitch;
        if (chswitch > 0)
            fdestArr[chswitch - 1] = valist[i];
    }
    return 0;
}

int _dbg_pkt_realdata_get(debug_msg_info_t *msg)
{
    //printf("%d:%s\n", __LINE__, __FUNCTION__);
    char *pdata = NULL;
    time_t now;

    if (msg == NULL)
        return 0;
        
    time(&now);
    debug_pkt_realdata_t realpack = {0};
    realpack.proVer = 0x00000602;
    realpack.utc = now - SHIQUCHA;
    realpack.vbat = pwr.vbat;
    realpack.vsc = pwr.vsc;
    realpack.vout = pwr.vout;

    //1 填写8相电流 3相电压数据 
    float cauValues[11] = {0};
    _dbg_get_current_cau_values(cauValues);

    RtdPack_t *rtd = &realpack.rtd;//实时数据
    //rtd->StartFlag1 = sysVar.gateway;
    rtd->RunSecCnt = now - sysctrl.start_time;
    //rtd->Local_Vbat = realpack.vbat;
    //rtd->RoomIn_Temp = temp2U16(envVal[0]);
    rtd->RMS_Ia = cauValues[0];
    rtd->RMS_Ib = cauValues[1];
    rtd->RMS_Ic = cauValues[2];
    rtd->RMS_In = cauValues[3];
    rtd->RMS_Ground = cauValues[4];
    rtd->RMS_rIa = cauValues[5];
    rtd->RMS_rIb = cauValues[6];
    rtd->RMS_rIc = cauValues[7];
    //rtd->RoomOut_Temp = temp2U16(envVal[0]);
    //rtd->I16A_Gx = (U16)(tsTag[0]+16000);
    //rtd->I16A_Gy = (U16)(tsTag[1]+16000);
    //rtd->I16A_Gz = (U16)(tsTag[2]+16000);
    //rtd->I16A_Temp1 = temp2U16(tsTag[3]);
    //rtd->I16A_Temp2 = temp2U16(tsTag[4]);
    //rtd->I16B_Gx = (U16)(tsTag[5]+16000);
    //rtd->I16B_Gy = (U16)(tsTag[6]+16000);
    //rtd->I16B_Gz = (U16)(tsTag[7]+16000);
    //rtd->I16B_Temp1 = temp2U16(tsTag[8]);
    //rtd->I16B_Temp2 = temp2U16(tsTag[9]);
    //rtd->I16C_Gx = (U16)(tsTag[10]+16000);
    //rtd->I16C_Gy = (U16)(tsTag[11]+16000);
    //rtd->I16C_Gz = (U16)(tsTag[12]+16000);
    //rtd->I16C_Temp1 = temp2U16(tsTag[13]);
    //rtd->I16C_Temp2 = temp2U16(tsTag[14]);
    //2022-11-08 安靠智能接地箱 三相表面温度
    //if(EartBoxProtocol == pConfigCtrl->gateway.CommunicationMode)
    //{
    //    rtd->I16A_Temp2 = temperPT100[0];
    //    rtd->I16B_Temp2 = temperPT100[1];
    //    rtd->I16C_Temp2 = temperPT100[2];
    //}
    //rtd->RoomOut_Humidity = (U16)(envVal[1]*10);
    //rtd->WaterLevel = (U16)(envVal[2]);
    //rtd->Gas_O2 = (U32)envVal[3];
    //rtd->Gas_CH4 = (U32)envVal[4];
    //rtd->Gas_H2s = (U32)envVal[5];
    //rtd->Gas_CO = (U32)envVal[6];
    rtd->RMS_Va = cauValues[8];
    rtd->RMS_Vb = cauValues[9];
    rtd->RMS_Vc = cauValues[10];
    rtd->endFlag = 0x0A0D;

    /* copy data */
    pdata = msg->pbuf + sizeof(debug_pkt_head_t);
    memcpy(pdata, &realpack, sizeof(realpack));
    _debug_pkt_common_send((char *)msg->pbuf, msg->cmd, sizeof(realpack));
    return 0;
}

int _dbg_pkt_mqtt_config_get(debug_msg_info_t *msg)
{
    printh("%d:%s\r\n", __LINE__, __FUNCTION__);
    char *pdata = NULL;
    if (msg == NULL)
    {
        return -1;
    }
    mqtt_param_t *pmqtt = &pparam_config->mqttCfg;
    
    /* copy data */
    pdata = msg->pbuf + sizeof(debug_pkt_head_t);
    memcpy(pdata, pmqtt, sizeof(mqtt_param_t));
    _debug_pkt_common_send((char *)msg->pbuf, msg->cmd, sizeof(mqtt_param_t));
    return 0;
}

int _dbg_pkt_mqtt_config_set(debug_msg_info_t *msg)
{
    printh("%d:%s\n", __LINE__, __FUNCTION__);
    if (msg == NULL)
    {
        return -1;
    }
    if (msg->len  != sizeof(mqtt_param_t))
    {
        LOG("invalid msg reallen:%d expect len:%d\n", msg->len, sizeof(mqtt_param_t));
        return -1;
    }

    mqtt_param_t *pmqtt = &pparam_config->mqttCfg;
    mqtt_param_t *pnet = (mqtt_param_t *)msg->pbuf;    
    memcpy(pmqtt, pnet, sizeof(mqtt_param_t));    
    param_save();
    reboot_system(LOG_DEBUG, BOOT_LOCAL_IP_CHANGE);
    //system("sync");
    //sleep(3);
    return 0;
}


int _dbg_pkt_auto_calibration(debug_msg_info_t *msg)
{
    if (msg == NULL)
    {
        return -1;
    }
    if (msg->len  != sizeof(Parameters_t))
    {
        printh("_dbg_pkt_auto_calibration invalid msg reallen:%d expect len:%d\n",
            msg->len, sizeof(Parameters_t));
        return -1;
    }
    
    printf("_dbg_pkt_auto_calibration  msg reallen:%d expect len:%d\n",
            msg->len, sizeof(Parameters_t));
    memcpy(&cau.cali_param, msg->pbuf, msg->len);
    Parameters_t *parm = &cau.cali_param;
    printh("inAdjust=%d\n", parm->inAdjust);
    printh("isLink=%d\n", parm->isLink);
    printh("cauBoard=%d\n", parm->cauBoard);
    printh("err=%d\n", parm->err);
    printh("chClose:");
    int i;
    for (i = 0; i < 8; i++)
    {
        printh("%d ", parm->chClose[i]);
    }
    printh("\n");
    printh("isVoltage=%d\n", parm->isVoltage);

    printh("sample:");
    for (i = 0; i < 5; i++)
    {
        printh("%f ", parm->sample[i]);
    }
    printh("\n");
    printh("turns=%f\n", parm->turns);  //????

    cau.ismanual = 0;
    cau.workstat = 0;
    
    return 0;
}

int _dbg_pkt_manual_calibration(debug_msg_info_t *msg)
{
    if (msg == NULL)
    {
        return -1;
    }
    if (msg->len  != sizeof(Parameters_t))
    {
        printh("_dbg_pkt_manual_calibration invalid msg reallen:%d expect len:%d\n",
            msg->len, sizeof(Parameters_t));
        return -1;
    }
    
    printh("_dbg_pkt_manual_calibration  msg reallen:%d expect len:%d\n",
            msg->len, sizeof(Parameters_t));
    memcpy(&cau.cali_param, msg->pbuf, msg->len);
    Parameters_t *parm = &cau.cali_param;
    printh("inAdjust=%d\n", parm->inAdjust);
    printh("isLink=%d\n", parm->isLink);
    printh("cauBoard=%d\n", parm->cauBoard);
    printh("err=%d\n", parm->err);
    printh("chClose:");
    int i;
    for (i = 0; i < 8; i++)
    {
        printf("%d ", parm->chClose[i]);
    }
    printh("\n");
    printh("isVoltage=%d\n", parm->isVoltage);

    printh("sample:");
    for (i = 0; i < 5; i++)
    {
        printh("%f ", parm->sample[i]);
    }
    printh("\n");
    printh("turns=%f\n", parm->turns);  //????

    if (parm->inAdjust == 1)
    {
        cau.ismanual = 1;
    }
    else
    {
        cau.ismanual = 0;
    }
    cau.workstat = 0;
    
    return 0;
}

void _dbg_upgrade_progress_tips(int totalSize, int transSize)
{
    static int per = 1;
    int one_percent = totalSize / 100;

    if (transSize >= totalSize)
    {
        per = 100;
        LOG("transfer %%%d", per);
    }
    else if (transSize > one_percent * per)
    {
        if (++per > 100)
        {
            per = 100;
        }
        LOG("transfer %%%d", per);
    }  
}

int _dbg_pkt_upgrade_arm(debug_msg_info_t *msg)
{
    static FILE *upgradefp = NULL;
    static int file_len = 0;
    char upgrade_file[128] = {0};
    if (msg == NULL)
    {
        return -1;
    }
    if (msg->len  != sizeof(updatePack_t))
    {
        LOG("invalid msg reallen:%d expect len:%d\n", msg->len, sizeof(updatePack_t));
        return -1;
    }
    
    if (upgradefp == NULL)
    {
        sprintf(upgrade_file, "%s/%s", UPDATE_FILE_PATH, UPDATE_TMP_FILE_NAME);
        upgradefp = fopen(upgrade_file, "wb");
        if (upgradefp == NULL)
        {
            printh("open file error[%d]:%s", errno, strerror(errno));
            return -1;
        }
    }

    updatePack_t *ppkt = (updatePack_t *)msg->pbuf;
    char *pdata = (char *)ppkt->dataArea;
    int size = ppkt->currLen;
    int wrlen = fwrite(pdata, 1, size, upgradefp);
    if (wrlen != size)
    {
        size = size - wrlen;
        wrlen = fwrite(pdata+wrlen, 1, size, upgradefp);
        printh("write again:size=%d, wrlen=%d\n", size, wrlen);
        file_len += wrlen;
    }
    file_len += wrlen;

    _dbg_upgrade_progress_tips(ppkt->totalLen, file_len);
    if (file_len == ppkt->totalLen)
    {
        fclose(upgradefp);
        upgradefp = NULL;
        unsigned int errcode = 0;
        pdata = msg->pbuf + sizeof(debug_pkt_head_t);
        memcpy(pdata, &errcode, sizeof(errcode));
        _debug_pkt_common_send((char *)msg->pbuf, msg->cmd, sizeof(errcode));
        LOG("update success!!!");
        char cmd[128] = {0};
        snprintf(cmd, 127, "mv %s/%s %s/%s", UPDATE_FILE_PATH, UPDATE_TMP_FILE_NAME,
                                                UPDATE_FILE_PATH, UPDATE_FILE_NAME);
        system(cmd);
        system("sync");
        printh("ls -l | grep update*\n");
        system("ls -l | grep update*");
        reboot_system(LOG_DEBUG, BOOT_LOCAL_ARM_UPGRADE);
    }
    
    return 0;
}

int _dbg_pkt_csg_mqtt_config_get(debug_msg_info_t *msg)
{
    printh("%d:%s\n", __LINE__, __FUNCTION__);
    //char *pdata = NULL;
    if (msg == NULL)
    {
        return -1;
    }
    csgMQTTCfg_t csgmqtt = {0};
    
    /* copy data */
    //pdata = msg->pbuf + sizeof(debug_pkt_head_t);
    //memcpy(pdata, pmqtt, sizeof(mqtt_param_t));
    //_debug_pkt_common_send((char *)msg->pbuf, msg->cmd, sizeof(mqtt_param_t));
    return 0;
}

int _dbg_pkt_csg_mqtt_config_set(debug_msg_info_t *msg)
{
    printh("%d:%s\n", __LINE__, __FUNCTION__);
    if (msg == NULL)
    {
        return -1;
    }
    if (msg->len  != sizeof(csgMQTTCfg_t))
    {
        LOG("invalid msg reallen:%d expect len:%d\n", msg->len, sizeof(csgMQTTCfg_t));
        return -1;
    }

    //mqtt_param_t *pmqtt = &pparam_config->mqttCfg;
    //mqtt_param_t *pnet = (mqtt_param_t *)msg->pbuf;    
    //memcpy(pmqtt, pnet, sizeof(mqtt_param_t));    
    //param_save();
    //reboot_system(LOG_DEBUG, BOOT_LOCAL_IP_CHANGE);
    //system("sync");
    //sleep(3);
    return 0;
}


static msg_proc_t dbg_proc_table[] = 
{
    {DEBUG_CONFIG_GET,      _dbg_pkt_config_get},
    {DEBUG_CONFIG_SET,      _dbg_pkt_config_set},
    {DEBUG_REBOOT,          _dbg_pkt_reboot_system},
    {DEBUG_SET_TIME,        NULL},
    {DEBUG_GET_REALDATA,    _dbg_pkt_realdata_get},
    {DEBUG_GET_HISDATA,     NULL},
    {DEBUG_DAU_WAVE,        NULL},
    {DEBUG_CAU_WAVE,        NULL},
    {DEBUG_ADJUST_TASK,     _dbg_pkt_auto_calibration},
    {DEBUG_ADJUST_RESULT,   NULL},
    {DEBUG_GetHWMQTTCFG,    _dbg_pkt_mqtt_config_get},
    {DEBUG_SetHWMQTTCFG,    _dbg_pkt_mqtt_config_set},
    {DEBUG_ManualAdjust,    _dbg_pkt_manual_calibration},
    {DEBUG_UPGRADE_ARM,     _dbg_pkt_upgrade_arm},
    {DEBUG_LOAD_CSGMQTTCFG, _dbg_pkt_csg_mqtt_config_get},
    {DEBUG_SAVE_CSGMQTTCFG, _dbg_pkt_csg_mqtt_config_set},
    {DEBUG_INVALID,         NULL}
};

/* 调试工具报文数据处理. */
int32_t _debug_pkt_process(char *buf, int32_t len)
{
    debug_pkt_head_t *head = (debug_pkt_head_t*)buf;

    /* 报文格式检查. */
    LD_E_RETURN(DBG_M_CA_DBG, _debug_pkt_check(buf, len));

    msg_proc_t *ptable = &dbg_proc_table[0];
    for (; DEBUG_INVALID != head->cmd; ptable++)
    {
        if (head->cmd == ptable->uiMsgId)
        {
            //printf("cmd = 0x%x\n", head->cmd);
            if (ptable->pfMsgProcFxn)
            {
                debug_msg_info_t msg = {0};
                msg.cmd = head->cmd;
                msg.len = head->len;
                msg.pbuf = buf + DEBUG_PKT_DATA_POS;
                ptable->pfMsgProcFxn(&msg);
                break;
            }
        }
    }
    return E_NONE;
}


/* tcp 连接粘包处理函数. */
int32_t _debug_pkt_recv_adhesion(char *buf, int len, int *len_recv)
{
    debug_pkt_head_t *head = NULL;
    static int len_pkt = 0;
    static int bytes_cnt = 0;
    static int state = 0;

    if (0 == state)
    {
        /* 首包处理. */
        head = (debug_pkt_head_t*)buf;
        bytes_cnt = 0;
        
        if (head->len > 10485000)
        {
            /* 报文太长不处理. */
            return -1;
        }
        else if (0x55aa == head->head)
        {
            /* 报文头处理, 置标志位. */
            state = 1;
            
            /* 计算剩余报文长度, 复制数据, 并计算收包总长度. */
            len_pkt = head->len + 10 - len;
            memcpy(buf_cmd + bytes_cnt, buf, len);
            bytes_cnt += len;
            
            /* 计算下一包应该接收多大的数据. */
            if (len_pkt > DEBUG_BUG_SIZE)
            {
                *len_recv = DEBUG_BUG_SIZE;
            }
            else
            {
                *len_recv = len_pkt;
            }
        }
        else
        {
            /* 在状体 0 下, 收到的报文不是以 0x55aa 开头, 无效报文不处理. */
            return -1;
        }
    }
    else if(1 == state)
    {
        /* 报文内容处理. */
        /* 计算剩余报文长度, 复制数据, 并计算收包总长度. */
        len_pkt -= len;
        memcpy(buf_cmd + bytes_cnt, buf, len);
        bytes_cnt += len;
        
        /* 计算下一包应该接收多大的数据. */
        if (len_pkt > DEBUG_BUG_SIZE)
        {
            *len_recv = DEBUG_BUG_SIZE;
        }
        else
        {
            *len_recv = len_pkt;
        }
    }

    /* 报文没有收全, 继续等待数据. */
    if (len_pkt > 0)
    {
        return 0;
    }

    state = 0;
    return bytes_cnt;
}

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

    /* 超时时间 */
    timeout.tv_sec = 10;
    timeout.tv_usec = 0;
    if (setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)))
    {
        log_err(LOG_DEBUG, "Error setsockopt(SO_SNDTIMEO) failed, return %s!\r\n", safe_strerror(errno));
        return E_SYS_CALL;
    }
    
    return 0;
}

/* 调试工具报文接收处理线程. */
void *_debug_pkt_recv_handle(void *arg)
{
    char *buf = debug_ctrl.buf;
    int len = 0;
    int len_pkt = 0;
    int len_recv = DEBUG_BUG_SIZE;

    while (!is_system_init)
    {
        sleep(1);
    }
    
    while(1)
    {
        /* 连接成功. */
        len_recv = DEBUG_BUG_SIZE;
        
        if (debug_ctrl.fd_client > 0)
        {
            /* 读取数据. */
            len = read(debug_ctrl.fd_client, buf, len_recv);
            if (len <= 0)
            {
                /* 连接中断, 关闭 socket 和手动采样. */
                DBG(DBG_M_CA_DBG, "Read len %d, close fd!\r\n", len);
                debug_ctrl.is_manual_col = FALSE;
                close(debug_ctrl.fd_client);
                debug_ctrl.fd_client = -1;
                break;
            }

            /* 粘包处理. */
            len_pkt = _debug_pkt_recv_adhesion(buf, len, &len_recv);
            if (len_pkt <= 0)
            {
                continue;
            }            

            _debug_pkt_process(buf_cmd, len_pkt);
            len_recv = DEBUG_BUG_SIZE;
        }
        usleep(10*1000);
    }
    pthread_exit("thread exit");
    return NULL;
}

int32_t _debug_create_recv_thread()
{
    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, _debug_pkt_recv_handle, NULL);
    if (rv != 0)
    {
        log_err(LOG_DEBUG, "PD can't create debug pthread %d!", rv);
        return E_SYS_CALL;
    }
    else
    {
        thread_m_add("PD_DEBUG", thread);
    }
    pthread_attr_destroy(&attr);
    return E_NONE;
}

void *_debug_accept_connect_handle()
{
    struct sockaddr_in cliaddr = {0};
    socklen_t clilen;
    int connfd;
    
    /* 监听端口. */
    if ((listen(debug_ctrl.fd, 5)) != 0)
    {
        log_err(LOG_DEBUG, "ERROR at socket listen return %s!", safe_strerror(errno));
        return NULL;
    }
    while (1)
    {
        clilen = sizeof(cliaddr);
        connfd = accept(debug_ctrl.fd, (struct sockaddr*)&cliaddr, &clilen);
        if (connfd < 0)
        {
            log_err(LOG_DEBUG, "ERROR at socket accept return %s!", safe_strerror(errno));
            continue;
        }

        char buf[20] = {0};
        LOG("new client: %s, port: %d\n",
            inet_ntop(AF_INET, &cliaddr.sin_addr, buf, sizeof(buf)),
            ntohs(cliaddr.sin_port));

        if (debug_ctrl.fd_client < 0)
        {
            debug_ctrl.fd_client = connfd;
            _debug_create_recv_thread();
            _debug_keep_alive(debug_ctrl.fd_client);
        }
        else
        {
            LOG("There is a link trying to connect...\n");
            close(connfd);
            connfd = -1;
        }
    }
    return NULL;
}

/* Interface functions -------------------------------------------------------*/
/* 调试工具初始化. */
int32_t debug_handle_init(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_DEBUG, "ERROR at socket create return %s!", safe_strerror(errno));
        return E_SYS_CALL;
    }

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

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

    /* 保存数据. */
    debug_ctrl.fd = fd;
    debug_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, _debug_accept_connect_handle, NULL);
    if (rv != 0)
    {
        log_err(LOG_DEBUG, "PD can't create debug pthread %d!", rv);
        return E_SYS_CALL;
    }
    else
    {
        thread_m_add("PD_DEBUG_ACCEPT", pid);
    }
    pthread_attr_destroy(&attr);

    /* 每秒上传 DAU 状态寄存器. */
    //mtimer_add(_debug_port_state_get, NULL, 1, "DEBUG_PORT_STATE_GET");

    return E_NONE;
}

int _debug_pkt_send_data(int cmd, char *psrc, int len)
{
    char buf[10*1024] = {0};
    char *pdata = NULL;
    
    /* copy data */
    pdata = buf + sizeof(debug_pkt_head_t);
    memcpy(pdata, psrc, len);
    int ret = _debug_pkt_common_send((char *)buf, cmd, len);
    printf("ret = %d len = %d\n", ret, len);
    return 0;
}


