/*****************************************************************************
 * file    lib/process/pd_dbg.c  
 * author  YuLiang
 * version 1.0.0
 * date    01-June-2023
 * brief   This file provides all the debug server related operation functions.
 ******************************************************************************
 * Attention
 *
 * <h2><center>&copy; COPYRIGHT(c) 2021 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_PD
/* 标准C库头文件. */
#include <sys/socket.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <netinet/tcp.h>

/* 用户代码头文件. */
#include "cJSON.h"
#include "main.h"
#include "mtimer.h"
#include "pd_dbg.h"
#include "pd_csg.h"
#include "pd_dau.h"
#include "pd_upgrade.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 "./bak/PDMonitor.bak"
#define DEBUG_CMU_FILE_UPGRADE "PDMonitor.upgrade"

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

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

/* Private variables ---------------------------------------------------------*/
debug_ctrl_t debug_ctrl;
dbg_device_info_t dbg_base_config;
dbg_global_config_t dbg_global_config;
dbg_config_port_t dbg_port_config;

static char buf_cmd[DEBUG_CMD_LEN];

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

/* Internal functions --------------------------------------------------------*/
void _debug_pkt_head_int(dbg_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)
{
    uint16_t total_len;
    dbg_pkt_head_t *head = (dbg_pkt_head_t*)buf;
    head->len = data_len;
    uint16_t *tail = (uint16_t*)(buf + sizeof(dbg_pkt_head_t) + data_len);
    _debug_pkt_head_int(head, cmd, data_len);
    *tail = DEBUG_TAIL;
    total_len = sizeof(dbg_pkt_head_t) + data_len + 2;

    DBG(DBG_M_DEBUG, "数据包 (总长度: %u bytes):\r\n", total_len);
    DBG(DBG_M_DEBUG, "  头部: head=0x%04X, cmd=0x%04X, len=%u\r\n", head->head, head->cmd, head->len);
    DBG(DBG_M_DEBUG, "  尾部: 0x%04X\r\n", *tail);
    if (write(debug_ctrl.fd_client, buf, total_len) <= 0)
    {
        DBG(DBG_M_DEBUG, "Write cmd %x ERROR\r\n", head->cmd);
        return E_SYS_CALL;
    }

    return E_NONE;
}

/* 获取配置报文处理. */
int32_t _debug_pkt_factory_cfg_get(char *buf, int len)
{
    dbg_device_info_t *info = (dbg_device_info_t *)(buf+sizeof(dbg_pkt_head_t));
    
    memset(info, 0, sizeof(dbg_device_info_t));
    info->type_m = device_info.type_m;
    info->type_s = device_info.type_s;
    info->dev_id = device_info.dev_id;
    snprintf((char*)info->hostname, FILE_NAME_LEN, "%s", device_info.hostname);
    info->factory_date = device_info.factory_date;
    info->deployment_date = device_info.deployment_date;
    info->ip = device_info.ip;
    
    memcpy(info->mac, device_info.mac, MAC_ADDR_LEN);
    info->mask = device_info.mask;
    info->gw = device_info.gw;
    strncpy((char*)info->app_version, host.version, 32);
    strncpy((char*)info->app_compile_time, host.compile, 32);
    
    strncpy((char*)info->hardware_version, host.hardversion, 32);
    strncpy((char*)info->FPGA_version, host.FPGAversion, 32);
    
    info->csg_port = csg.server_port;
    info->csg_ipv4 = csg.server_ip;
    info->running_time = start_time;
    
    int32_t ret = _debug_pkt_common_send(buf, DEBUG_CONFIG_FACTORY_GET, sizeof(dbg_device_info_t));
    /* 发送数据. */
    return ret;
}


int32_t _debug_pkt_factory_cfg_set(char *buf, int len)
{
    REBOOT_MSG boottype = REBOOT_NONE;
    dbg_device_info_t *info = (dbg_device_info_t *)(buf+sizeof(dbg_pkt_head_t));

    if(device_info.type_m != info->type_m||
        device_info.type_s != info->type_s||
        device_info.dev_id != info->dev_id)
    {
        device_info.type_m = info->type_m;
        device_info.type_s = info->type_s;
        device_info.dev_id = info->dev_id;
        boottype = REBOOT_LOCAL_HOST_NAME_CHANGE;
    }
    snprintf(device_info.hostname, FILE_NAME_LEN, "%s", (const char*)info->hostname);
    device_info.factory_date = info->factory_date;
    device_info.deployment_date = info->deployment_date;
    
    if (device_info.ip != info->ip)
    {
        DBG(DBG_M_DEBUG, "IP 地址变更: %u.%u.%u.%u -> %u.%u.%u.%u\r\n",
            device_info.ip & 0xFF, (device_info.ip >> 8) & 0xFF, (device_info.ip >> 16) & 0xFF, (device_info.ip >> 24) & 0xFF,
            info->ip & 0xFF, (info->ip >> 8) & 0xFF, (info->ip >> 16) & 0xFF, (info->ip >> 24) & 0xFF);
        device_info.ip = info->ip;
        mac_generate_from_ip(device_info.ip, info->mac);
        memcpy(device_info.mac, info->mac, MAC_ADDR_LEN);
        boottype = REBOOT_REMOTE_IP_CHANGE;
        
        vtysh_eth0_save();
    }
    device_info.gw = info->gw;
    device_info.mask = info->mask;
    vtysh_device_save();
    if (csg.server_ip != info->csg_ipv4)
    {
        csg.server_ip = info->csg_ipv4;
        boottype = REBOOT_REMOTE_SERVER_IP_CHANGE;
    }

    if (csg.server_port != info->csg_port)
    {
        csg.server_port = info->csg_port;
        boottype = REBOOT_REMOTE_SERVER_IP_CHANGE;
    }
    vtysh_config_save();

    // 打印接收到的设备信息
    DBG(DBG_M_DEBUG, "================================================\r\n");
    DBG(DBG_M_DEBUG, "接收到的设备信息:\r\n");
    DBG(DBG_M_DEBUG, "  主设备号 (type_m): %u\r\n", info->type_m);
    DBG(DBG_M_DEBUG, "  次设备号 (type_s): %u\r\n", info->type_s);
    DBG(DBG_M_DEBUG, "  设备ID (dev_id): %u\r\n", info->dev_id);
    DBG(DBG_M_DEBUG, "  主机名 (hostname): %s\r\n", info->hostname);
    DBG(DBG_M_DEBUG, "  出厂时间 (factory_date): %u\r\n", info->factory_date);
    DBG(DBG_M_DEBUG, "  部署时间 (deployment_date): %u\r\n", info->deployment_date);
    DBG(DBG_M_DEBUG, "  IP 地址 (ip): %u.%u.%u.%u\r\n",
        (info->ip) & 0xFF, (info->ip >> 8) & 0xFF, (info->ip >> 16) & 0xFF, (info->ip  >> 24) & 0xFF);
    DBG(DBG_M_DEBUG, "  子网掩码 (mask): %u.%u.%u.%u\r\n",
        (info->mask) & 0xFF, (info->mask >> 8) & 0xFF, (info->mask >> 16) & 0xFF, (info->mask >> 24) & 0xFF);
    DBG(DBG_M_DEBUG, "  网关 (gw): %u.%u.%u.%u\r\n",
        (info->gw) & 0xFF, (info->gw >> 8) & 0xFF, (info->gw >> 16) & 0xFF, (info->gw >> 24) & 0xFF);
    DBG(DBG_M_DEBUG, "  MAC 地址 (mac): %02X:%02X:%02X:%02X:%02X:%02X\r\n",
        info->mac[0], info->mac[1], info->mac[2], info->mac[3], info->mac[4], info->mac[5]);
    DBG(DBG_M_DEBUG, "  CSG 端口 (csg_port): %u\r\n", info->csg_port);
    DBG(DBG_M_DEBUG, "  CSG 服务器 IP (csg_ipv4): %u.%u.%u.%u\r\n",
        (info->csg_ipv4 >> 24) & 0xFF, (info->csg_ipv4 >> 16) & 0xFF, (info->csg_ipv4 >> 8) & 0xFF, info->csg_ipv4 & 0xFF);

    if (boottype)
    {
        _debug_pkt_common_send(buf, DEBUG_CONFIG_FACTORY_SET, 0);
        sleep(1);
        reboot_system(LOG_DEBUG, boottype);
    }
    
    return E_NONE;
}

/* 设置报文处理. */
int32_t _debug_pkt_global_cfg_set(char *pkt, int len)
{
    dau_t * dau_node = dau[0];
    dbg_global_config_t *config = (dbg_global_config_t *)(pkt + sizeof(csg_pkt_head_t));
    pd_config.config.sample_frequency = config->sample_frequency;
    pd_config.config.trigger_sample_nums = config->trigger_sample_numbers;
    pd_config.config.trig_location = (config->pre_trigger_percent << 4) / 100.00;
    pd_config.config.trig_threshold = config->trigLevel;
    pd_config.config.trend_up_period = config->trend_up_period;
    pd_config.config.heartbeat_period = config->heartbeat_period;
    pd_config.config.ch_en_mask = config->ch_en_mask;
    if (config->sync_mode == 0)
    {
       BITMAP_RESET(pd_config.config.pt_B_sync_mode, PD_BIT_PT);
    }
    else
    {
        BITMAP_SET(pd_config.config.pt_B_sync_mode, PD_BIT_PT);
    }
    pd_config.config.pt_internal_period = 1000000000UL / config->pt_internal_period;

    if(dau_node->is_connect == TRUE)
    {
        dau_node->reg->reg_global.trig_location = pd_config.config.trig_location;
        dau_node->reg->reg_global.trig_threshold = pd_config.config.trig_threshold;
        dau_node->reg->reg_global.trig_gap = pd_config.config.trig_gap;
        dau_node->reg->reg_global.sample_interrupt_intveal_us = pd_config.config.interrupt_interval;
        dau_node->reg->reg_global.pt_B_sync_mode = pd_config.config.pt_B_sync_mode;
        dau_node->reg->reg_global.pt_selfsync_cycle = pd_config.config.pt_internal_period;
    }
    vtysh_config_save();
    return _debug_pkt_common_send(pkt, DEBUG_CONFIG_GLOBAL_SET, 0);
}

/* 查询用户参数查询报文处理. */
int32_t _debug_pkt_global_cfg_get(char *pkt, int len)
{
    dbg_global_config_t *pconfig = (dbg_global_config_t *)(pkt + sizeof(dbg_pkt_head_t));
    pconfig->sample_frequency = pd_config.config.sample_frequency;
    pconfig->trigger_sample_numbers = pd_config.config.trigger_sample_nums;
    pconfig->pre_trigger_percent = (uint32_t)(pd_config.config.trig_location * 100 / 16.00 + 0.5);
    pconfig->trigLevel = pd_config.config.trig_threshold;
    pconfig->trend_up_period = pd_config.config.trend_up_period;
    pconfig->heartbeat_period = pd_config.config.heartbeat_period;
    pconfig->ch_en_mask = pd_config.config.ch_en_mask;
    if (IS_BITMAP_SET(pd_config.config.pt_B_sync_mode, PD_BIT_PT))
    {
        pconfig->sync_mode = 1;
    }
    else
    {
        pconfig->sync_mode = 0;
    }
    pconfig->pt_internal_period = 1000000000UL / pd_config.config.pt_internal_period;
    _debug_pkt_common_send(pkt, DEBUG_CONFIG_GLOBAL_GET, sizeof(dbg_global_config_t));

    return E_NONE;
}

/* 设置报文处理. */
int32_t _debug_pkt_port_cfg_set(char *pkt, int len)
{
    uint8_t unit = 0;
    uint8_t port = 0;
    dbg_config_port_t *pnet = (dbg_config_port_t *)(pkt + sizeof(dbg_pkt_head_t));
    
    if (dau_vport_to_port(pnet->vport, &unit, &port) != E_NONE)
    {
        DBG(DBG_M_DEBUG, "Pkt port %d error!\r\n", pnet->vport);
        return E_ERROR;
    }

    pd_config.config_port[unit][port].vport = pnet->vport;
    pd_config.config_port[unit][port].type = pnet->channel_type;
    pd_config.config_port[unit][port].filter_frequency = pnet->filter_frequency;
    pd_config.config_port[unit][port].rise_time = pnet->rise_time;
    pd_config.config_port[unit][port].peak_time = pnet->peak_time;
    pd_config.config_port[unit][port].fall_time = pnet->fall_time;
    pd_config.config_port[unit][port].pulse_width = pnet->pulse_width;
    pd_config.config_port[unit][port].peak_count = pnet->peak_count;
    pd_config.config_port[unit][port].signal_envelope = pnet->signal_envelope;
    pd_config.config_port[unit][port].signal_mean = pnet->signal_mean;
    pd_config.config_port[unit][port].signal_variance = pnet->signal_variance;
    pd_config.config_port[unit][port].primary_frequency = pnet->primary_frequency;
    pd_config.config_port[unit][port].primary_freq_peak = pnet->primary_freq_peak;
    pd_config.config_port[unit][port].spectral_peak_count = pnet->spectral_peak_count;
    pd_config.config_port[unit][port].spectrum_mean = pnet->spectrum_mean;
    pd_config.config_port[unit][port].spectrum_variance = pnet->spectrum_variance;

    vtysh_config_save();
    _debug_pkt_common_send(pkt, DEBUG_CONFIG_PORT_SET, 0);
    return E_NONE;
}


/* 查询用户参数查询报文处理. */
int32_t _debug_pkt_port_cfg_get(char *pkt, int len)
{
    dbg_config_port_t *pnet = (dbg_config_port_t *)(pkt + sizeof(dbg_pkt_head_t));
    uint8_t unit = 0;
    uint8_t port = 0;
    
    if (dau_vport_to_port(pnet->vport, &unit, &port) != E_NONE)
    {
        DBG(DBG_M_DEBUG, "Pkt port %d error!\r\n", pnet->vport);
        return E_ERROR;
    }

    pnet->vport = pd_config.config_port[unit][port].vport;
    pnet->channel_type = pd_config.config_port[unit][port].type;
    pnet->vport = pd_config.config_port[unit][port].vport;
    pnet->channel_type = pd_config.config_port[unit][port].type;
    pnet->filter_frequency = pd_config.config_port[unit][port].filter_frequency;
    pnet->rise_time = pd_config.config_port[unit][port].rise_time;
    pnet->peak_time = pd_config.config_port[unit][port].peak_time;
    pnet->fall_time = pd_config.config_port[unit][port].fall_time;
    pnet->pulse_width = pd_config.config_port[unit][port].pulse_width;
    pnet->peak_count = pd_config.config_port[unit][port].peak_count;
    pnet->signal_envelope = pd_config.config_port[unit][port].signal_envelope;
    pnet->signal_mean = pd_config.config_port[unit][port].signal_mean;
    pnet->signal_variance = pd_config.config_port[unit][port].signal_variance;
    pnet->primary_frequency = pd_config.config_port[unit][port].primary_frequency;
    pnet->primary_freq_peak = pd_config.config_port[unit][port].primary_freq_peak;
    pnet->spectral_peak_count = pd_config.config_port[unit][port].spectral_peak_count;
    pnet->spectrum_mean = pd_config.config_port[unit][port].spectrum_mean;
    pnet->spectrum_variance = pd_config.config_port[unit][port].spectrum_variance;
    _debug_pkt_common_send(pkt, DEBUG_CONFIG_PORT_GET, sizeof(dbg_config_port_t));
    return E_NONE;
}


/* 重启报文处理. */
int32_t _debug_pkt_reboot(char *buf, int len)
{
    /* 发送数据. */
    _debug_pkt_common_send(buf, DEBUG_REBOOT, 0);

    /* 重启. */
    reboot_system(LOG_DEBUG, REBOOT_LOCAL_RESET);
    
    return E_NONE;
}

/* 时间设置报文处理. */
int32_t _debug_pkt_time_set(char *buf, int len)
{
    uint32_t *timestamp = (uint32_t*)(buf + sizeof(dbg_pkt_head_t));

    /* 配置时间. */
    time_set(*timestamp);

    /* 发送数据. */
    _debug_pkt_common_send(buf, DEBUG_TIME_SET, 0);

    return E_NONE;
}

/* 获取运行状态报文处理. */
int32_t _debug_pkt_status_get(char *buf, int len)
{
    debug_pkt_status_t *status = (debug_pkt_status_t*)(buf + sizeof(dbg_pkt_head_t));
    status->utc = time(NULL);
    status->run_time = start_time;
    status->is_server_link = csg.is_connect;
    _debug_pkt_common_send(buf, DEBUG_DEVICE_STATUS, sizeof(debug_pkt_status_t));

    return E_NONE;
}

/* 获取运行状态报文处理. */
int32_t _debug_pkt_set_wave_address(char *buf, int len)
{
    dbg_wave_addr_t *wave = (dbg_wave_addr_t*)(buf + sizeof(dbg_pkt_head_t));
    
    bzero(&csg.wave_svr, sizeof(csg.wave_svr));
    csg.wave_svr.sin_family = AF_INET;
    csg.wave_svr.sin_addr.s_addr = inet_addr(wave->ipv4);
    csg.wave_svr.sin_port = htons(wave->port);
    _debug_pkt_common_send(buf, DEBUG_SET_WAVE_ADDRESS, 0);
       
    return E_NONE;
}

int32_t _debug_pkt_upgrade(char *pkt, int len)
{
    static int fd = -1;
    static uint32_t fix_len = 0;
    dbg_upgrade_data_t *head_msg = (dbg_upgrade_data_t*)(pkt + sizeof(dbg_pkt_head_t));
    char *pdata = pkt + sizeof(dbg_pkt_head_t) + sizeof(dbg_upgrade_data_t);
    dbg_upgrade_ack_t *pack = (dbg_upgrade_ack_t*)(pkt + sizeof(dbg_pkt_head_t));
    int32_t size = 0;
    int32_t len_wr = 0;
    uint32_t offset = 0;

    csg.is_connect = FALSE;   //关闭主动上传
    /* 首保处理, 打开文件描述符, 初始化变量 */
    if (head_msg->index == 0)
    {
        if (fd > 0)
        {
            close(fd);
            fd = -1;
        }

        fd = open(PD_UPG_SOFTWARE, O_WRONLY | O_CREAT | O_TRUNC, 0777);
        if (fd < 0)
        {
            DBG(DBG_M_DEBUG, "Open file " PD_UPG_SOFTWARE " error!\r\n");
            return E_SYS_CALL;
        }
        fix_len = head_msg->len;
        
        DBG(DBG_M_DEBUG, "Receive upgrade file start.\r\n");
    }
    DBG(DBG_M_DEBUG,"type=%d,sum=%d,index=%d,len=%d,fix_len=%d\r\n", head_msg->type, head_msg->sum, head_msg->index, head_msg->len, fix_len);

    /* 收包流程 */
    size = head_msg->len;
    offset = head_msg->index * fix_len;
    if (lseek(fd, offset, SEEK_SET) < 0) 
    {
        int error = errno;
        DBG(DBG_M_PD_CSG_ERR, "lseek file " PD_UPG_SOFTWARE " error: %s, fd=%d, offset=%ld\r\n", 
            strerror(error), fd, offset);
        
        // 检查具体错误类型
        switch(error) {
            case EBADF:  // 无效文件描述符
                DBG(DBG_M_DEBUG, "Invalid file descriptor\r\n");
                break;
            case EINVAL: // 无效的 whence 或 offset
                DBG(DBG_M_DEBUG, "Invalid offset or whence\r\n");
                break;
            case EOVERFLOW: // offset 过大
                DBG(DBG_M_DEBUG, "Offset overflow\r\n");
                break;
        }
        return E_SYS_CALL;
    }
    
    len_wr = write(fd, pdata, size);
    if (len_wr != size)
    {
        DBG(DBG_M_DEBUG, "Write file " PD_UPG_SOFTWARE " error!\r\n");
        return E_SYS_CALL;
    }
    
    /* 最后一个报文处理 */
    if (head_msg->sum - 1 == head_msg->index)
    {
        close(fd);
        fd = -1;
        DBG(DBG_M_DEBUG, "Receive upgrade file end.\r\n");
        pd_upg_start(PD_UPG_FROM_CSG, head_msg->type);
    }
    pack->index = head_msg->index;

    /* 发送应答 */
    _debug_pkt_common_send(pkt, DEBUG_UPGRADE_DATA, sizeof(dbg_upgrade_ack_t));
    
    return E_NONE;
}



/* 报文校验. */
int32_t _debug_pkt_check(char *buf, int len)
{
    dbg_pkt_head_t *head = (dbg_pkt_head_t*)buf;
    uint16_t *tail = (uint16_t*)(buf + len - 2);
    DBG(DBG_M_DEBUG, "receive data head->head is 0X%X!,tail is 0X%X!\r\n",
                            head->head, *tail);

    if (*tail != DEBUG_TAIL)
    {
        return E_ERROR;
    }
    
    if(head->head != DEBUG_HEAD)
    {
        return E_ERROR;
    }

    return E_NONE;
}

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

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

    /* 报文处理. */
    switch(head->cmd)
    {
    case DEBUG_CONFIG_FACTORY_GET:
        DBG(DBG_M_DEBUG, "get DEBUG_CONFIG_FACTORY_GET data!\r\n");
        _debug_pkt_factory_cfg_get(buf, len);
        break;
    case DEBUG_CONFIG_FACTORY_SET:
        DBG(DBG_M_DEBUG, "set DEBUG_CONFIG_FACTORY_SET data!\r\n");
        _debug_pkt_factory_cfg_set(buf, len);
        break;
    case DEBUG_CONFIG_GLOBAL_GET:
        DBG(DBG_M_DEBUG, "get DEBUG_CONFIG_GLOBAL_GET data!\r\n");
        _debug_pkt_global_cfg_get(buf, len);
        break;
    case DEBUG_CONFIG_GLOBAL_SET:
        DBG(DBG_M_DEBUG, "set DEBUG_CONFIG_GLOBAL_SET data!\r\n");
        _debug_pkt_global_cfg_set(buf, len);
        break;
    case DEBUG_CONFIG_PORT_GET:
        DBG(DBG_M_DEBUG, "get DEBUG_CONFIG_PORT_GET data!\r\n");
        _debug_pkt_port_cfg_get(buf, len);
        break;
    case DEBUG_CONFIG_PORT_SET:
        DBG(DBG_M_DEBUG, "set DEBUG_CONFIG_GLOBAL_SET data!\r\n");
        _debug_pkt_port_cfg_set(buf, len);
        break;
    
    case DEBUG_REBOOT:
        _debug_pkt_reboot(buf, len);
        break;
    case DEBUG_TIME_SET:
        _debug_pkt_time_set(buf, len);
        break;
    
    case DEBUG_DEVICE_STATUS:
        _debug_pkt_status_get(buf, len);
        break;
    case DEBUG_UPGRADE_DATA:
        _debug_pkt_upgrade(buf, len);
        break;
    case DEBUG_SET_WAVE_ADDRESS:
        _debug_pkt_set_wave_address( buf,  len);
        break;
    default:
        DBG(DBG_M_DEBUG, "Debug not support cmd:%x\n", head->cmd);
        break;
    }

    return E_NONE;
}

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

    if (0 == state)
    {
        /* 首包处理. */
        head = (dbg_pkt_head_t*)buf;
        bytes_cnt = 0;
        
        if (head->len > 10485000)
        {
            /* 报文太长不处理. */
            return -1;
        }
        else if (0x55aa == head->head)
        {
                DBG(DBG_M_DEBUG, "pkt datalen head->len is %d\r\n", head->len);
            /* 报文头处理, 置标志位. */
            state = 1;
            
            /* 计算剩余报文长度, 复制数据, 并计算收包总长度. */
            len_pkt = head->len + 32 - 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;
        }
        printf("@2len_pkt=%d\n", 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;
    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;
    }
    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(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_DEBUG, "Read len %d, close fd!\r\n", len);
                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;

    /* 等待初始化完成 */
    while(!is_system_init)
    {
        usleep(100000);
    }
    
    /* 监听端口. */
    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};
        DBG(DBG_M_DEBUG, "new client: %s, port: %d fd_client=%d\n",
            inet_ntop(AF_INET, &cliaddr.sin_addr, buf, sizeof(buf)),
            ntohs(cliaddr.sin_port), debug_ctrl.fd_client);

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

/* Interface functions -------------------------------------------------------*/
/* 调试工具初始化. */
int32_t debug_handle_init(void)
{
    return E_NONE;
}

int32_t debug_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_DEBUG, "ERROR at socket create return %s!", safe_strerror(errno));
        return E_SYS_CALL;
    }
    
    /* 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);
    return E_NONE;
}

/* 升级结果回复处理 */
void debug_upgrade_result_send(int32_t rv, char *buf)
{
    char buffer[32] = {0};
    int32_t *rt = (int32_t*)(buffer + sizeof(dbg_pkt_head_t));
    
    *rt = rv;
    _debug_pkt_common_send(buffer, 0, 4);
}
#endif
/************************ (C) COPYRIGHT LandPower ***** END OF FILE ****************/
