#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/select.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include "signal.h"
#include <poll.h>
#include "modbus_tcp_ser.h"
#include "common.h"
#include <semaphore.h>
#include <math.h>
#include "proto_forward.h"
#include "ems/jsonct.h"
#include "libmodbus/modbus.h"
#include "north_mqtt/north_jsonct.h"
#include "log_module/log_module.h"
#include "../business_log/business_log.h"

static int parse_addr_map(char *info_str, int parse_port);

#define EXT_MODBUS_TCP_INDEX (0)
#define EXT_MODBUS_TCP_ADDR (1)

static modbus_tcp_ser_t *modbus_tcp_ser_info;

// static int change_float_to_int(float data_f)
// {
//     int data_tmp = 0;
//     data_tmp = data_f;
//     if((data_tmp+1 - data_f)<0.5f)
//     data_tmp = data_tmp+1;
//     return data_tmp;
// }


#define GETDATA_COEFFICIENT(dest_data, point_info, tag)                         \
    do                                                                          \
    {                                                                           \
        if (tag->data_type == TYPE_TAG_INT)                                     \
        {                                                                       \
            if (check_float_is_1(point_info->coefficient))                      \
                dest_data = tag->read_cache.to_int;                             \
            else                                                                \
                dest_data = tag->read_cache.to_int * point_info->coefficient;   \
        }                                                                       \
        else                                                                    \
        {                                                                       \
            if (check_float_is_1(point_info->coefficient))                      \
                dest_data = tag->read_cache.to_float;                           \
            else                                                                \
                dest_data = tag->read_cache.to_float * point_info->coefficient; \
        }                                                                       \
    } while (0);


unsigned short Reverse16(unsigned short sVal) // 高低反转
{
    unsigned short sRtn;

    sRtn = (((sVal >> 8) & 0x00FF) | ((sVal << 8) & 0xFF00));

    return sRtn;
}

unsigned int Reverse32(unsigned int iVal) // 完全反转
{
    unsigned int iRtn;

    iRtn = (((iVal >> 24) & 0x000000FF) | ((iVal >> 8) & 0x0000FF00) | ((iVal << 8) & 0x00FF0000) | ((iVal << 24) & 0xFF000000));

    return iRtn;
}

unsigned int Reverse16with32(unsigned int iVal) // 双字节反转
{
    unsigned int iRtn;

    iRtn = (((iVal >> 8) & 0x000000FF) | ((iVal << 8) & 0x0000FF00) | ((iVal >> 8) & 0x00FF0000) | ((iVal << 8) & 0xFF000000));

    return iRtn;
}

void set_float_abcd(float f, uint16_t *dest)
{
    uint32_t i;

    memcpy(&i, &f, sizeof(uint32_t));
    i = bswap_32(htonl(i));
    dest[0] = (uint16_t)(i >> 16);
    dest[1] = (uint16_t)i;
}

int check_reg_num(DATA_ORDER data_order) //如果以后有4字节需要再添加
{
    if (data_order < ORDER_ABCD)
        return 1;
    else
        return 2;
}

// static char* get_log_filename(void) {
//     static char filename[256];
//     time_t now;
//     struct tm *tm_now;
    
//     time(&now);
//     tm_now = localtime(&now);
//     strftime(filename, sizeof(filename), MODBUS_LOG_PATH, tm_now);
    
//     return filename;
// }

// static void ensure_log_directory(void) {
//     char cmd[256];
//     snprintf(cmd, sizeof(cmd), "mkdir -p %s", MODBUS_LOG_BASE);
//     system(cmd);
// }

// static void compress_old_log(void) {
//     char cmd[512];
//     char yesterday[64];
//     time_t now = time(NULL);
//     struct tm *tm_now;
    
//     // 获取昨天的日期
//     now -= 24 * 60 * 60;
//     tm_now = localtime(&now);
//     strftime(yesterday, sizeof(yesterday), "%Y%m%d", tm_now);
    
//     // 压缩昨天的日志
//     snprintf(cmd, sizeof(cmd), 
//         "if [ -f %s/modbus_%s.log ]; then "
//         "tar -czf %s/modbus_%s.tar.gz %s/modbus_%s.log && "
//         "rm %s/modbus_%s.log; "
//         "fi",
//         MODBUS_LOG_BASE, yesterday,
//         MODBUS_LOG_BASE, yesterday,
//         MODBUS_LOG_BASE, yesterday,
//         MODBUS_LOG_BASE, yesterday);
//     system(cmd);
// }

// static void delete_old_archives(void) {
//     char cmd[512];
//     char old_date[64];
//     time_t old = time(NULL);
//     struct tm *tm_old;
    
//     // 获取3天前的日期
//     old -= 3 * 24 * 60 * 60;
//     tm_old = localtime(&old);
//     strftime(old_date, sizeof(old_date), "%Y%m%d", tm_old);
    
//     // 删除3天前的压缩文件
//     snprintf(cmd, sizeof(cmd),
//         "if [ -f %s/modbus_%s.tar.gz ]; then "
//         "rm %s/modbus_%s.tar.gz; "
//         "fi",
//         MODBUS_LOG_BASE, old_date,
//         MODBUS_LOG_BASE, old_date);
//     system(cmd);
// }

// static void check_log_maintenance(void) {
//     time_t now;
//     struct tm *tm_now;
//     static int last_day = 0;
    
//     time(&now);
//     tm_now = localtime(&now);
    
//     // 如果日期变化了
//     if (tm_now->tm_mday != last_day) {
//         if (last_day != 0) {  // 不是程序第一次启动
//             compress_old_log();  // 压缩昨天的日志
//             delete_old_archives();  // 删除过期的压缩文件
//         }
//         last_day = tm_now->tm_mday;
//     }
// }

// static const char * modbus_systime(char * tbuf, size_t tlen)
// {
//     int ret;
//     time_t nowt;
//     struct timespec spec;
//     struct tm tim, * ptm;

//     spec.tv_sec = 0;
//     spec.tv_nsec = 0;
//     ret = clock_gettime(CLOCK_REALTIME, &spec);
//     if (ret == -1) {
//         tbuf[0] = '\0';
//         return tbuf;
//     }

//     nowt = spec.tv_sec;
//     ptm = localtime_r(&nowt, &tim);

//     if (ptm == NULL) {
//         ret = snprintf(tbuf, tlen, "%d.%06d",
//             (int) spec.tv_sec, (int) (spec.tv_nsec / 1000));
//     } else {
//         ret = snprintf(tbuf, tlen, "%d-%02d-%02d %02d:%02d:%02d.%06d",
//             ptm->tm_year + 1900, ptm->tm_mon + 1, ptm->tm_mday,
//             ptm->tm_hour, ptm->tm_min, ptm->tm_sec,
//             (int) (spec.tv_nsec / 1000));
//     }
//     if (ret <= 0) {
//         tbuf[0] = '\0';
//         return tbuf;
//     } else if (ret >= (int) tlen)
//         ret = (int) (tlen - 1);
//     tbuf[ret] = '\0';
//     return tbuf;
// }


static int load_tag_addr_map_file(char *cfg_file)
{
    char *pdata = NULL;
    // char type[32] = {'\0'};

    if(cfg_file == NULL)
    {
        proto_syslog(LOG_ERR, "no config finde .. error");
        return -1;
    }
    proto_syslog(LOG_NOTICE, "cfg_file: %s", cfg_file);
    pdata = read_file_data(cfg_file);
    if (pdata == NULL)
    {
        proto_syslog(LOG_ERR, "read cfg file %s error", cfg_file);
        return -2;
    }

    int ret = parse_addr_map(pdata, 0);//不解析端口
    free(pdata);
    return ret;
}

static int parse_addr_map(char *info_str, int parse_port)//parse_port是否解析server_port字段的控制
{
    int ver = 1;    //tag_addr_map.json文件版本，默认为1，2为多地址码支持
    cJSON *pts = NULL;
    cJSON *root = json_parse_string_with_comments(info_str);
    if (!root)
    {
        proto_syslog(LOG_ERR, "parse pdata %s error", info_str);
        goto out;
    }
    if (parse_port != 0)
    {
        GET_JSON_VALUE_INT(root, "server_port", modbus_tcp_ser_info->server_port);
        proto_syslog(LOG_DEBUG, "server_port:%d", modbus_tcp_ser_info->server_port);
    }
    
    if (cJSON_HasObjectItem(root, "ver"))
    {
        GET_JSON_VALUE_INT(root, "ver", ver);
    }

    int ptscnt = 1;
    if (ver > 1)
    {
        pts = cJSON_GetObjectItem(root, "pts");
        ptscnt = cJSON_GetArraySize(pts);
    }

    modbus_tcp_ser_info->addrmapcnt = ptscnt;
    modbus_tcp_ser_info->addr_map = calloc(sizeof(addr_map_t), ptscnt);
    for (int i = 0; i < ptscnt; i++)
    {
        cJSON *ptsobj = NULL;
        unsigned short modaddr = 0;
        if (ver > 1)
        {
            ptsobj = cJSON_GetArrayItem(pts, i);
            GET_JSON_VALUE_INT(ptsobj, "addr", modaddr);
        }
        else 
        {
            ptsobj = root;
            modaddr = 1;
        }
        modbus_tcp_ser_info->addr_map[i].modaddr = modaddr;

        cJSON *__item = cJSON_GetObjectItem(ptsobj, "start_bits");
        if (__item)
        {
            modbus_tcp_ser_info->addr_map[i].start_bits = analysis_addr(__item->valuestring);
            proto_syslog(LOG_DEBUG, "start_bits:%x", modbus_tcp_ser_info->addr_map[i].start_bits);
        }
        GET_JSON_VALUE_INT(ptsobj, "nb_bits", modbus_tcp_ser_info->addr_map[i].nb_bits);
        proto_syslog(LOG_DEBUG, "nb_bits:%d", modbus_tcp_ser_info->addr_map[i].nb_bits);

        __item = cJSON_GetObjectItem(ptsobj, "start_input_bits");
        if (__item)
        {
            modbus_tcp_ser_info->addr_map[i].start_input_bits = analysis_addr(__item->valuestring);
            proto_syslog(LOG_DEBUG, "start_input_bits:%x", modbus_tcp_ser_info->addr_map[i].start_input_bits);
        }
        GET_JSON_VALUE_INT(ptsobj, "nb_input_bits", modbus_tcp_ser_info->addr_map[i].nb_input_bits);
        proto_syslog(LOG_DEBUG, "nb_input_bits:%d", modbus_tcp_ser_info->addr_map[i].nb_input_bits);

        __item = cJSON_GetObjectItem(ptsobj, "start_registers");
        if (__item)
        {
            modbus_tcp_ser_info->addr_map[i].start_registers = analysis_addr(__item->valuestring);
            proto_syslog(LOG_DEBUG, "start_registers:%x", modbus_tcp_ser_info->addr_map[i].start_registers);
        }
        GET_JSON_VALUE_INT(ptsobj, "nb_registers", modbus_tcp_ser_info->addr_map[i].nb_registers);
        proto_syslog(LOG_DEBUG, "nb_registers:%d", modbus_tcp_ser_info->addr_map[i].nb_registers);

        __item = cJSON_GetObjectItem(ptsobj, "start_input_registers");
        if (__item)
        {
            modbus_tcp_ser_info->addr_map[i].start_input_registers = analysis_addr(__item->valuestring);
            proto_syslog(LOG_DEBUG, "start_input_registers:%x", modbus_tcp_ser_info->addr_map[i].start_input_registers);
        }
        GET_JSON_VALUE_INT(ptsobj, "nb_input_registers", modbus_tcp_ser_info->addr_map[i].nb_input_registers);
        proto_syslog(LOG_DEBUG, "nb_input_registers:%d", modbus_tcp_ser_info->addr_map[i].nb_input_registers);

        cJSON *pointInfo = cJSON_GetObjectItemCaseSensitive(ptsobj, "pointInfo");
        if (!pointInfo)
        {
            proto_syslog(LOG_ERR, "get object pointInfo error");
            goto out;
        }
        int pointInfo_cnt = cJSON_GetArraySize(pointInfo);
        modbus_tcp_ser_info->addr_map[i].point_info_list = calloc(sizeof(point_info_t *), pointInfo_cnt);
        for (int j = 0; j < pointInfo_cnt; j++)
        {
            modbus_tcp_ser_info->addr_map[i].point_info_list[j] = calloc(sizeof(point_info_t), 1);

            cJSON *pointInfo_list_item = cJSON_GetArrayItem(pointInfo, j);
            if (cJSON_GetArraySize(pointInfo_list_item) < POINT_INFO_DEAFIL_NUM)
            {
                proto_syslog(LOG_ERR, "pointInfo error");
                return 1;
            }
            cJSON *p0 = cJSON_GetArrayItem(pointInfo_list_item, 0);
            cJSON *p1 = cJSON_GetArrayItem(pointInfo_list_item, 1);
            cJSON *p2 = cJSON_GetArrayItem(pointInfo_list_item, 2);
            cJSON *p3 = cJSON_GetArrayItem(pointInfo_list_item, 3);
            cJSON *p4 = cJSON_GetArrayItem(pointInfo_list_item, 4);
            cJSON *p5 = cJSON_GetArrayItem(pointInfo_list_item, 5);
            local_strlcpy(modbus_tcp_ser_info->addr_map[i].point_info_list[j]->name, p0->valuestring, TAG_NAME_LEN);
            modbus_tcp_ser_info->addr_map[i].point_info_list[j]->function_code = p1->valueint;
            modbus_tcp_ser_info->addr_map[i].point_info_list[j]->addr = analysis_addr(p2->valuestring);
            modbus_tcp_ser_info->addr_map[i].point_info_list[j]->data_type = get_type_by_string(p3->valuestring);
            modbus_tcp_ser_info->addr_map[i].point_info_list[j]->data_order = get_order_by_string(p4->valuestring);
            modbus_tcp_ser_info->addr_map[i].point_info_list[j]->coefficient = p5->valuedouble;
            proto_syslog(LOG_DEBUG, "name:%s,function_code:%d,addr:%d,data_type:%d,data_order:%d,coefficient:%f",
                    modbus_tcp_ser_info->addr_map[i].point_info_list[j]->name,
                    modbus_tcp_ser_info->addr_map[i].point_info_list[j]->function_code,
                    modbus_tcp_ser_info->addr_map[i].point_info_list[j]->addr,
                    modbus_tcp_ser_info->addr_map[i].point_info_list[j]->data_type,
                    modbus_tcp_ser_info->addr_map[i].point_info_list[j]->data_order,
                    modbus_tcp_ser_info->addr_map[i].point_info_list[j]->coefficient);
            modbus_tcp_ser_info->addr_map[i].point_info_list_num++;
        }
    }
out:
    if (root != NULL)
    {
        cJSON_Delete(root);
    }
    return 0;
}

void SetServerMapData(int nb, int type, int addr, unsigned char *pchardata, unsigned short *pshortdata, int who)
{
    proto_syslog(LOG_DEBUG,"num:%d type:%d addr:%d",nb,type,addr);
    int i = 0;
    if ((modbus_tcp_ser_info->addr_map[who].mb_mapping == NULL))
        return;
    switch (type)
    {
    case MODBUS_FC_READ_COILS:
        if (pchardata == NULL)
            return;
        
        addr = addr - modbus_tcp_ser_info->addr_map[who].mb_mapping->start_bits;
        for (i = 0; i < nb; i++)
        {
            proto_syslog(LOG_DEBUG, "COILS %d ", pchardata[i]);
            modbus_tcp_ser_info->addr_map[who].mb_mapping->tab_bits[addr + i] = pchardata[i];
        }
        break;
    case MODBUS_FC_READ_DISCRETE_INPUTS:
        if (pchardata == NULL)
            return;
        
        addr = addr - modbus_tcp_ser_info->addr_map[who].mb_mapping->start_input_bits;
        for (i = 0; i < nb; i++)
        {
            proto_syslog(LOG_DEBUG, "DISCRETE_INPUTS %d", pchardata[i]);
            modbus_tcp_ser_info->addr_map[who].mb_mapping->tab_input_bits[addr + i] = pchardata[i];
        }
        break;
    case MODBUS_FC_READ_HOLDING_REGISTERS:
        if (pshortdata == NULL)
            return;
        
        addr = addr - modbus_tcp_ser_info->addr_map[who].mb_mapping->start_registers;
        for (i = 0; i < nb; i++)
        {
            proto_syslog(LOG_DEBUG, "REGISTERS %d ", pshortdata[i]);
             modbus_tcp_ser_info->addr_map[who].mb_mapping->tab_registers[addr + i] = pshortdata[i];
        }
        break;
    case MODBUS_FC_READ_INPUT_REGISTERS:
        if (pshortdata == NULL)
            return;

        addr = addr - modbus_tcp_ser_info->addr_map[who].mb_mapping->start_input_registers;
        for (i = 0; i < nb; i++)
        {
            proto_syslog(LOG_DEBUG, "INPUT REGISTERS %d ", pshortdata[i]);
            modbus_tcp_ser_info->addr_map[who].mb_mapping->tab_input_registers[addr + i] = pshortdata[i];
        }
        break;
    default:
        break;
    }
    return;
}


void get_data_char(unsigned char *data_c, point_info_t *point_info, tag_t *tag)
{
    GETDATA_COEFFICIENT(data_c[0], point_info, tag);
}

void get_data_short(unsigned short *data_s, point_info_t *point_info, tag_t *tag)
{
    switch (point_info->data_order)
    {
    case ORDER_AB: // 暂时不关心字序
    case ORDER_BA:
    {
        short data_tmp_s = 0;
        GETDATA_COEFFICIENT(data_tmp_s, point_info, tag);
        memcpy(data_s, &data_tmp_s, sizeof(short));
        // data_s[0] = Reverse16(data_s[0]);
    };
    break;
    case ORDER_ABCD:
    case ORDER_BADC:
    case ORDER_CDAB:
    case ORDER_DCBA:
    {
        int data_tmp_i = 0;
        float data_tmp_f = 0.0f;
        if (point_info->data_type == TYPE_FLOAT) // 映射表数据类型判断
        {
            GETDATA_COEFFICIENT(data_tmp_f, point_info, tag);
            set_float_abcd(data_tmp_f, data_s);
        }
        else
        {
            GETDATA_COEFFICIENT(data_tmp_i, point_info, tag);
            data_tmp_i = Reverse16with32(data_tmp_i);
            data_tmp_i = Reverse32(data_tmp_i);
            memcpy(data_s, &data_tmp_i, sizeof(int));
        }
    };
    break;
    default:
        break;
    }
}


void flush_data(proto_forward_t *var, int who)
{
    unsigned char data_c[10] = {0};
    unsigned short data_s[10] = {0};
    proto_syslog(LOG_DEBUG, "flush_data\n");
    for (size_t i = 0; i < modbus_tcp_ser_info->addr_map[who].point_info_list_num; i++)
    {   // 找tag
        tag_t *tag_finded = NULL;
        if (hash_intptr_findptr(var->tag_map_hash, modbus_tcp_ser_info->addr_map[who].point_info_list[i]->name, strlen(modbus_tcp_ser_info->addr_map[who].point_info_list[i]->name), (void **)&tag_finded) < 0)
            continue;
        proto_syslog(LOG_DEBUG, " find read tag:%s\n", tag_finded->name);
        // 格式化数据
        if ((modbus_tcp_ser_info->addr_map[who].point_info_list[i]->function_code == MODBUS_FC_READ_COILS) || ((modbus_tcp_ser_info->addr_map[who].point_info_list[i]->function_code == MODBUS_FC_READ_DISCRETE_INPUTS)))
            get_data_char(data_c, modbus_tcp_ser_info->addr_map[who].point_info_list[i], tag_finded);
        else
            get_data_short(data_s, modbus_tcp_ser_info->addr_map[who].point_info_list[i], tag_finded);
        // 写表
        SetServerMapData(check_reg_num(modbus_tcp_ser_info->addr_map[who].point_info_list[i]->data_order), \
        modbus_tcp_ser_info->addr_map[who].point_info_list[i]->function_code, modbus_tcp_ser_info->addr_map[who].point_info_list[i]->addr, data_c, data_s, who);
    }
}

// 根据 地址映射表获取数据
int get_data_to_write(point_info_t *point_info_list, long *data_l, double *data_d, unsigned short *value, int count, int number) // 返回值 0 int 1 float
{
    float data_f;
	int data_i;
    int data_type = TYPE_TAG_INT;
    unsigned int data_tmp = 0;
    short val_s_tmp;
    if (point_info_list->function_code == MODBUS_FC_READ_COILS) // 写线圈
    {
        *data_l = value[0];
        proto_syslog(LOG_DEBUG, "get int oil data:%ld", *data_l);
    }
    else if (point_info_list->function_code == MODBUS_FC_READ_HOLDING_REGISTERS)
    {
        if ((check_reg_num(point_info_list->data_order) == 1) && (count == 1))
        {
            if (point_info_list->data_type == TYPE_USHORT)
            {
                *data_l = value[number];
            }
            else
            {
                memcpy(&val_s_tmp, &value[number], sizeof(short));
                *data_l = val_s_tmp;
            }
            proto_syslog(LOG_DEBUG, "get int data:%ld", *data_l);
        }
        else if ((check_reg_num(point_info_list->data_order) == 2) && (count == 2))
        {
            if (point_info_list->data_type == TYPE_FLOAT)
            {
                memcpy(&data_tmp, &value[number], sizeof(data_tmp));
                data_tmp = Reverse16with32(data_tmp);
                data_tmp = Reverse32(data_tmp);
                memcpy(&data_f, &data_tmp, sizeof(data_f));
                proto_syslog(LOG_DEBUG, "get float data:%f", data_f);
                data_type = TYPE_TAG_FLOAT; // 返回值  0 int   1 float
                *data_d = data_f;
				*data_d = round((*data_d) * 10) / 10.0;
            }
            else
            {
                memcpy(&data_tmp, &value[number], sizeof(data_tmp));
                data_tmp = Reverse16with32(data_tmp);
                data_tmp = Reverse32(data_tmp);
                memcpy(&data_i, &data_tmp, sizeof(data_i));
                proto_syslog(LOG_DEBUG, "get int data:%d", data_i);
				*data_l = data_i;
            }
        }
        else
        {
            proto_syslog(LOG_DEBUG, "get data's reg count error\n");
            return -1;
        }
    }
//这儿没办法计算倍率，如果底层是整形，ua中为浮点型，会损失精度，比如传上来的数据为1234，倍率为10，
//如果ua中类型配置为浮点型那么在ua中应该为123.4，但是按下面的逻辑就只能再ua中显示123
//执行这一条:*data_i = *data_i / point_info_list->coefficient;
#if 0
    if ((point_info_list->coefficient != 0.0f) && !check_float_is_1(point_info_list->coefficient)) // 不为1计算
    {
        if (point_info_list->data_type == TYPE_FLOAT) // 计算倍率
        {
            *data_f = *data_f / point_info_list->coefficient;
        }
        else
        {        
            *data_i = *data_i / point_info_list->coefficient;
        }
    }

    if (point_info_list->data_type == TYPE_FLOAT)
    {
        proto_syslog(LOG_DEBUG, "get float lastest data:%f\n", *data_f);
    }
    else
    {
        proto_syslog(LOG_DEBUG, "get int lastest data:%d\n", *data_i);
    }
#endif
    return data_type;
}

void write_mul_data(proto_forward_t *var, int need_function_code, unsigned short addr, unsigned short *value, int count, int who)
{
    proto_syslog(LOG_DEBUG, "get addr:%d count:%d need_function_code:%d\n", addr, count, need_function_code);
    int curaddr = 0;
    for(int j = 0; j < (count / 2); j++)
    {
        curaddr = addr + j * 2;
        for (size_t i = 0; i < modbus_tcp_ser_info->addr_map[who].point_info_list_num; i++)
        {
            // proto_syslog(LOG_DEBUG,"addr:%d function_code:%d\n",modbus_tcp_ser_info->addr_map[who].point_info_list[i]->addr,modbus_tcp_ser_info->addr_map[who].point_info_list[i]->function_code);
            if ((modbus_tcp_ser_info->addr_map[who].point_info_list[i]->addr != curaddr) || (modbus_tcp_ser_info->addr_map[who].point_info_list[i]->function_code != need_function_code)) // 找地址和功能码对应tag_name
                continue;
            // 转换成表格映射的值
            tag_value_t tag_val;
            tag_val.type = get_data_to_write(modbus_tcp_ser_info->addr_map[who].point_info_list[i], &tag_val.value.to_int, &tag_val.value.to_float, value, 2, j * 2);
            if (tag_val.type < 0)
                return;

            proto_syslog(LOG_DEBUG, "tag_val type:%d, to_int:%ld to_float:%f", tag_val.type, tag_val.value.to_int, tag_val.value.to_float);
            // write_data_to_tag_by_name(var,modbus_tcp_ser_info->addr_map[who].point_info_list[i]->name,&tag_val);
            tag_t *find_tag = find_tag_by_name(var, modbus_tcp_ser_info->addr_map[who].point_info_list[i]->name);
            if (find_tag != NULL)
            {
                if (find_tag->data_type != tag_val.type)
                {
                    if (tag_val.type == TYPE_TAG_INT)
                    {
                        tag_val.type = TYPE_TAG_FLOAT;
                        tag_val.value.to_float = tag_val.value.to_int;
                    }
                    else
                    {
                        tag_val.type = TYPE_TAG_INT;
                        tag_val.value.to_int = tag_val.value.to_float;
                    }
                }
                write_data_to_tag_by_p(find_tag, &tag_val, modbus_tcp_ser_info->addr_map[who].point_info_list[i]->coefficient);
            }
            break;
        }
    }
}

void write_a_data(proto_forward_t *var, int need_function_code, unsigned short addr, unsigned short *value, int count, int who) // 只写一个数据 count 对于双寄存器类型是2 线圈和单寄存器是1
{
    proto_syslog(LOG_DEBUG, "get addr:%d count:%d need_function_code:%d\n", addr, count, need_function_code);
    for (size_t i = 0; i < modbus_tcp_ser_info->addr_map[who].point_info_list_num; i++)
    {
        char addtmp[256] = {0};
        // proto_syslog(LOG_DEBUG,"addr:%d function_code:%d\n",modbus_tcp_ser_info->addr_map[who].point_info_list[i]->addr,modbus_tcp_ser_info->addr_map[who].point_info_list[i]->function_code);
        if ((modbus_tcp_ser_info->addr_map[who].point_info_list[i]->addr != addr) || (modbus_tcp_ser_info->addr_map[who].point_info_list[i]->function_code != need_function_code)) // 找地址和功能码对应tag_name
            continue;
        // 转换成表格映射的值
        tag_value_t tag_val;
        tag_val.type = get_data_to_write(modbus_tcp_ser_info->addr_map[who].point_info_list[i], &tag_val.value.to_int, &tag_val.value.to_float, value, count, 0);
        if (tag_val.type < 0)
            return;

		proto_syslog(LOG_DEBUG, "tag_val type:%d, to_int:%ld to_float:%f", tag_val.type, tag_val.value.to_int, tag_val.value.to_float);
        // write_data_to_tag_by_name(var,modbus_tcp_ser_info->addr_map[who].point_info_list[i]->name,&tag_val);
        tag_t *find_tag = find_tag_by_name(var, modbus_tcp_ser_info->addr_map[who].point_info_list[i]->name);
        if (find_tag != NULL)
        {
            if (find_tag->data_type != tag_val.type)
            {
                if (tag_val.type == TYPE_TAG_INT)
                {
                    tag_val.type = TYPE_TAG_FLOAT;
                    tag_val.value.to_float = tag_val.value.to_int;
                }
                else
                {
                    tag_val.type = TYPE_TAG_INT;
                    tag_val.value.to_int = tag_val.value.to_float;
                }
            }
            write_data_to_tag_by_p(find_tag, &tag_val, modbus_tcp_ser_info->addr_map[who].point_info_list[i]->coefficient);
            if(find_tag->data_type == TYPE_TAG_INT)
                snprintf(addtmp, sizeof(addtmp), "%s/:%s/%d", MODBUS_TCP, find_tag->name, (int)(tag_val.value.to_int/modbus_tcp_ser_info->addr_map[who].point_info_list[i]->coefficient));
            else
                snprintf(addtmp, sizeof(addtmp), "%s/:%s/%f", MODBUS_TCP, find_tag->name, tag_val.value.to_float/modbus_tcp_ser_info->addr_map[who].point_info_list[i]->coefficient);
            if((strcmp(find_tag->name,IEC104_HEARTBEAT) == 0) || (strcmp(find_tag->name,MODBUSTCP_HEARTBEAT) == 0)) //心跳切换不记录
                break;
            server_add_new_log(LOG_CODE_NORTH_MQTT_WRITE_POINT, ((device_t*)find_tag->dev_ptr)->no, LOG_MODE_TRIG, 1, addtmp);
        }
        else
        {
            if(tag_val.type == TYPE_TAG_INT)
                snprintf(addtmp, sizeof(addtmp), "%s/:%s/%d", MODBUS_TCP, modbus_tcp_ser_info->addr_map[who].point_info_list[i]->name, (int)(tag_val.value.to_int/modbus_tcp_ser_info->addr_map[who].point_info_list[i]->coefficient));
            else
                snprintf(addtmp, sizeof(addtmp), "%s/:%s/%f", MODBUS_TCP, modbus_tcp_ser_info->addr_map[who].point_info_list[i]->name, tag_val.value.to_float/modbus_tcp_ser_info->addr_map[who].point_info_list[i]->coefficient);
            if((strcmp(modbus_tcp_ser_info->addr_map[who].point_info_list[i]->name,IEC104_HEARTBEAT) == 0) || (strcmp(modbus_tcp_ser_info->addr_map[who].point_info_list[i]->name,MODBUSTCP_HEARTBEAT) == 0)) //心跳切换不记录
                break;
            server_add_new_log(LOG_CODE_NORTH_MQTT_WRITE_POINT, "EMS", LOG_MODE_TRIG, 2, addtmp);
        }
        break;
    }
}

extern int north_control;
extern usercfg_variant_t g_usercfg_variant;
int modbus_setdata(proto_forward_t *var, unsigned char *pdata, int len)
{
    unsigned short addr[64], value[64];
    unsigned short startaddr, valuenum;

    int i, countA = 0, countK = 0, countM = 0, setplan = 0;
    int need_function_code = 0; // 需要拿去判断的功能码 这个需要和list对比用于区分是哪个

    //proto_syslog_hex(LOG_DEBUG, pdata, len, " <rxlen> %d ", len);
    if (len < 12)
        return 0; // 长度判断
    if(pdata[7] == MODBUS_FC_WRITE_SINGLE_REGISTER || pdata[7] == MODBUS_FC_WRITE_MULTIPLE_REGISTERS || pdata[7] == MODBUS_FC_WRITE_SINGLE_COIL)
    {
        char send_data[256];
        int send_len = 0;
        lnxall_syslog_uid(LOG_DEBUG, MODBUS_LOG_UID, "north_control: %d", north_control);
        for (i = 0; i < len; i++) {
            send_len += snprintf(send_data + send_len, sizeof(send_data) - send_len, "%02X ", pdata[i]);
        }
        if (send_len > 0) {
            lnxall_syslog_uid(LOG_DEBUG, MODBUS_LOG_UID, "Received MODBUS: %s", send_data);
        }
    }
    int who = -1;
    bool found = false; 
    for(int k = 0; k < modbus_tcp_ser_info->addrmapcnt; k++)
    {
        if (modbus_tcp_ser_info->addr_map[k].modaddr == pdata[6])
        {
            who = k;
            found = true;
            break;
        }
    }
    if (!found)
    {
        proto_syslog(LOG_ERR, "modbus addr not supported %d", pdata[6]);
        return -1;
    }

    proto_syslog(LOG_DEBUG, "modbus_server rx data from addr[0x%02x]", pdata[6]);
    if (pdata[7] == MODBUS_FC_WRITE_SINGLE_REGISTER) // 功能码判断
    {
        addr[0] = *(unsigned short *)&pdata[8];
        value[0] = *(unsigned short *)&pdata[10];
        addr[0] = Reverse16(addr[0]);
        value[0] = Reverse16(value[0]);
        countA = 1;
        need_function_code = 3;
    }
    else if (pdata[7] == MODBUS_FC_WRITE_MULTIPLE_REGISTERS) // 地址+数量+长度+数据
    {
        startaddr = *(unsigned short *)&pdata[8];
        valuenum = *(unsigned short *)&pdata[10];
        valuenum = Reverse16(valuenum);
        startaddr = Reverse16(startaddr);
        if(valuenum > 2)
        {
            countM = valuenum;
            if((startaddr >= PLAN_START_ADDR) && (startaddr <= PLAN_END_ADDR))    //起始地址在策略点位内,则判断为设置策略
            {
                setplan = 1;
            }
        }
        else
            countA = valuenum;
        for (i = 0; i < valuenum; i++)
        {
            addr[i] = startaddr + i;
            value[i] = (pdata[13 + 2 * i] << 8) | pdata[13 + 2 * i + 1];
        }
        need_function_code = 3;
    }
    // 00 01 00 00 00 06 01 05 00 03 FF 00
    // 0x0003的线圈设为ON
    else if (pdata[7] == MODBUS_FC_WRITE_SINGLE_COIL) // 写单个线圈
    {
        addr[0] = *(unsigned short *)&pdata[8];
        value[0] = *(unsigned short *)&pdata[10];
        addr[0] = Reverse16(addr[0]);
        value[0] = Reverse16(value[0]);
        countK = 1;
        if (value[0])
        {
            value[0] = 1;
        }
        else
        {
            value[0] = 0;
        }
        need_function_code = 1;
    }
    else if (pdata[7] == MODBUS_FC_WRITE_MULTIPLE_COILS) // 写多个线圈 不用这个 一次只写一个
    {
#if 0
		startaddr = *(unsigned short *)&pdata[8];//开始地址
		valuenum = *(unsigned short *)&pdata[10];//数量
		valuenum = Reverse16(valuenum);
		startaddr = Reverse16(startaddr);
		countK = valuenum;
		for(i = 0;i<valuenum;i++)
		{
			addr[i] = startaddr+i;
			if(CHK_AMASK_BIT(pdata[13],i))
			{
				
				value[i] = 1;
			}
			else
			{
				value[i] = 0;
			}
		}
#endif
    }
    else // 读数据
    {
        flush_data(var, who);
    }
    if(north_control == 1)
    {
        if (countA)
        {
            write_a_data(var, need_function_code, addr[0], value, countA, who); // 模拟写入
        }
        if (countK)
        {
            write_a_data(var, need_function_code, addr[0], value, countK, who); // 开关写入
        }
        if (countM)
        {
            write_mul_data(var,need_function_code,addr[0],value,countM,who);//写多个寄存器
            if(setplan)
            {
                save_modbus_plan_to_file(N_NORTH_MODBUS_CONTROL);
                server_add_new_log(LOG_CODE_NORTH_MQTT_WRITE_PLAN, "EMS", LOG_MODE_TRIG, 1, "ModbusTcp");
            }
        }
    }

    return who;
}

int GetMaxSocket(fd_set *pSet)
{
    int i, iMax = -1;
    for (i = 0; i < FD_SETSIZE; i++)
        if (FD_ISSET(i, pSet))
            iMax = i;
    return iMax;
}

static void add_client_to_list(int socket_fd)
{
    client_connection_t *new_client = calloc(sizeof(client_connection_t), 1);
    if (new_client == NULL) {
        proto_syslog(LOG_ERR, "Failed to allocate memory for new client");
        return;
    }
    
    new_client->socket_fd = socket_fd;
    new_client->last_activity_time = time(NULL);
    new_client->next = modbus_tcp_ser_info->client_list;
    modbus_tcp_ser_info->client_list = new_client;
    
    proto_syslog(LOG_NOTICE, "Client %d added to connection list", socket_fd);
}

static void remove_client_from_list(int socket_fd)
{
    client_connection_t *current = modbus_tcp_ser_info->client_list;
    client_connection_t *prev = NULL;
    
    while (current != NULL) {
        if (current->socket_fd == socket_fd) {
            if (prev == NULL) {
                modbus_tcp_ser_info->client_list = current->next;
            } else {
                prev->next = current->next;
            }
            free(current);
            proto_syslog(LOG_NOTICE, "Client %d removed from connection list", socket_fd);
            return;
        }
        prev = current;
        current = current->next;
    }
}

static void update_client_activity_time(int socket_fd)
{
    client_connection_t *current = modbus_tcp_ser_info->client_list;
    
    while (current != NULL) {
        if (current->socket_fd == socket_fd) {
            current->last_activity_time = time(NULL);
            return;
        }
        current = current->next;
    }
}

static void check_and_clean_timeout_connections(fd_set *setBak)
{
    time_t current_time = time(NULL);
    client_connection_t *current = modbus_tcp_ser_info->client_list;
    client_connection_t *next = NULL;
    int timeout_count = 0;
    int total_count = 0;
    
    proto_syslog(LOG_DEBUG, "开始检查超时连接，当前时间: %ld", current_time);
    
    while (current != NULL) {
        total_count++;
        next = current->next;
        
        double idle_time = difftime(current_time, current->last_activity_time);
        proto_syslog(LOG_DEBUG, "检查连接 %d: 最后活动时间 %ld, 空闲时间 %.0f秒, 超时阈值 %d秒", 
                   current->socket_fd, current->last_activity_time, idle_time, modbus_tcp_ser_info->max_idle_time);
        
        if (idle_time > modbus_tcp_ser_info->max_idle_time) {
            timeout_count++;
            proto_syslog(LOG_NOTICE, "Client %d timeout (idle for %.0f seconds), closing connection", 
                       current->socket_fd, idle_time);
            
            shutdown(current->socket_fd, SHUT_RDWR);
            close(current->socket_fd);
            FD_CLR(current->socket_fd, setBak);
            
            remove_client_from_list(current->socket_fd);
        }
        
        current = next;
    }
    
    proto_syslog(LOG_DEBUG, "超时检查完成: 总共 %d 个连接, 超时 %d 个", total_count, timeout_count);
}

void *ModbusServerProc(void *arg)
{
    //pthread_detach(pthread_self());
    proto_syslog(LOG_NOTICE, "modbus tcp server thread start!");
    proto_forward_t *var = arg;
	int i, rc, iRet, sockCnt;
    int map_allocated = 0, server_socket = 0, master_socket = 0;
    modbus_t *ctx = NULL;
    // int header_length;
    unsigned char *query;
    fd_set setRead, setBak;
    int port = (modbus_tcp_ser_info->server_port == 0) ? 502 : modbus_tcp_ser_info->server_port;
    proto_syslog(LOG_NOTICE, "creat server on port:%d", port);

    ctx = modbus_new_tcp("0.0.0.0", port);
    if (ctx == NULL)
    {
        proto_syslog(LOG_ERR, "Failed to creat new tcp server: %s\n",
                  modbus_strerror(errno));
        BUSINESS_LOG(BLOG_ERR, NORTH_ID_0026, NULL, "[北向]:Modbus 创建tcp连接失败 失败原因:[%s]", modbus_strerror(errno));
        return NULL;
    }
    else
    {
        BUSINESS_LOG(BLOG_NOTICE, NORTH_ID_0026, NULL, "[北向]:Modbus 创建tcp连接成功");
    }
    modbus_set_name(ctx, "ModbusServerProc");

    query = (unsigned char *)malloc(MODBUS_TCP_MAX_ADU_LENGTH);
	if (query == NULL) {
		proto_syslog(LOG_ERR, "Failed to allocate modbus query, size: %d", MODBUS_TCP_MAX_ADU_LENGTH);
		modbus_free(ctx);
		return NULL;
	}

    // header_length = modbus_get_header_length(ctx);
    for (i = 0; i < modbus_tcp_ser_info->addrmapcnt; i++) {
		addr_map_t *addr_map = &modbus_tcp_ser_info->addr_map[i];

		addr_map->mb_mapping = modbus_mapping_new_start_address(
			addr_map->start_bits, addr_map->nb_bits,
			addr_map->start_input_bits, addr_map->nb_input_bits,
			addr_map->start_registers, addr_map->nb_registers,
			addr_map->start_input_registers, addr_map->nb_input_registers
		);
		if (addr_map->mb_mapping == NULL) {
			proto_syslog(LOG_ERR, "Failed to allocate the  at %d: %s\n",
						 i, modbus_strerror(errno));
            BUSINESS_LOG(BLOG_ERR, NORTH_ID_0027, NULL, "[北向]:Modbus 地址映射异常");
			goto cleanup;
		}
        else
        {
            BUSINESS_LOG(BLOG_NOTICE, NORTH_ID_0027, NULL, "[北向]:Modbus 地址映射正常");
        }
		map_allocated++;
    }
#if 0 // 只支持单个客户端
	int s = modbus_tcp_listen(ctx, 1);
	//暂时只支持一对一
	while(1)
    {
	    modbus_tcp_accept(ctx, &s);
		while(1)
		{
			rc = modbus_receive(ctx, query);
			if(rc == -1 && errno != EMBBADCRC) 
           		break;
			rc = modbus_reply(ctx, query, rc, mb_mapping);
	        if (rc == -1) 
	            break;
		}
	}
#else // 支持多个客户端
    server_socket = modbus_tcp_listen(ctx, 1);
    if(server_socket < 0) {
        proto_syslog(LOG_ERR, "Failed to creat new tcp server: %s\n",
					 modbus_strerror(errno));
        BUSINESS_LOG(BLOG_ERR, NORTH_ID_0028, NULL, "[北向]:Modbus 创建tcp 服务端socket 失败");
		goto cleanup;
    }
    else
    {
        BUSINESS_LOG(BLOG_NOTICE, NORTH_ID_0028, NULL, "[北向]:Modbus 创建tcp 服务端socket 成功");
    }

    if (modbus_tcp_ser_info->max_idle_time == 0) {
        modbus_tcp_ser_info->max_idle_time = 60; 
    }
    if (modbus_tcp_ser_info->heartbeat_interval == 0) {
        modbus_tcp_ser_info->heartbeat_interval = 10; 
    }
    
    proto_syslog(LOG_NOTICE, "Timeout configuration: max_idle_time=%ds, heartbeat_interval=%ds", 
               modbus_tcp_ser_info->max_idle_time, modbus_tcp_ser_info->heartbeat_interval);
    
    FD_ZERO(&setBak);
    FD_SET(server_socket, &setBak);
    
    time_t last_heartbeat_check = time(NULL);
    
    while (1)
    {
        setRead = setBak;
        
        struct timeval timeout;
        timeout.tv_sec = modbus_tcp_ser_info->heartbeat_interval;
        timeout.tv_usec = 0;
        
        iRet = select(GetMaxSocket(&setRead) + 1, &setRead, NULL, NULL, &timeout);
        
        time_t current_time = time(NULL);
        if (difftime(current_time, last_heartbeat_check) >= modbus_tcp_ser_info->heartbeat_interval) {
            check_and_clean_timeout_connections(&setBak);
            last_heartbeat_check = current_time;
        }
        
        if (iRet < 0)
            break;
            
        if (iRet == 0) {
            continue;
        }
        
        if (FD_ISSET(server_socket, &setRead))
        {
            master_socket = modbus_tcp_accept(ctx, &server_socket);
            if (master_socket < 0)
                break;
            if (master_socket > FD_SETSIZE - 1)
            {
                proto_syslog(LOG_WARNING, "too many connection!");
                shutdown(master_socket, SHUT_RDWR);
                close(master_socket);
            }
            proto_syslog(LOG_NOTICE, "client %d %d connected.\n", master_socket, server_socket);
            FD_SET(master_socket, &setBak);
            
            // 添加新客户端到连接列表
            add_client_to_list(master_socket);
        }
        for (sockCnt = 0; sockCnt < FD_SETSIZE; sockCnt++)
        {
            if (sockCnt != server_socket && FD_ISSET(sockCnt, &setRead))
            {
                modbus_set_socket(ctx, sockCnt);
                rc = modbus_receive(ctx, query);
                if (rc != -1)
                {
                    BUSINESS_LOG(BLOG_NOTICE, NORTH_ID_0029, NULL, "[北向]:Modbus client receive message success");
                    // 更新客户端活动时间
                    update_client_activity_time(sockCnt);
                    
                    int who = modbus_setdata(var, query, rc);
                    if (who >= 0)
                    {
                        modbus_reply(ctx, query, rc, modbus_tcp_ser_info->addr_map[who].mb_mapping);
                    }
                }
                else
                {
                    BUSINESS_LOG(BLOG_WARNING, NORTH_ID_0029, NULL, "[北向]:Modbus client %d %d closed", sockCnt, master_socket);
                    proto_syslog(LOG_NOTICE, "client %d %d closed.\n", sockCnt, master_socket);
                    shutdown(sockCnt, SHUT_RDWR);
                    close(sockCnt);
                    FD_CLR(sockCnt, &setBak);
                    
                    // 从连接列表中移除
                    remove_client_from_list(sockCnt);
                }
            }
        }
    }
#endif
    if (server_socket != -1)
    {
        close(server_socket);
    }

cleanup:
	for (i = 0; i < map_allocated; i++) {
		modbus_mapping_t *mb_mapping = modbus_tcp_ser_info->addr_map[i].mb_mapping;
		if (mb_mapping != NULL) {
			modbus_mapping_free(mb_mapping);
			mb_mapping = NULL;
		}
	}
    free(query);

	if (ctx != NULL) {
		modbus_close(ctx);
		modbus_free(ctx);
	}
    return NULL;
}

MODBUS_SERVER_PARAM *modbus_tcp_ser_init(MODBUS_SERVER_BASE_PARAM *param)
{
    proto_syslog(LOG_NOTICE,"modbus tcp ser init starting...");
    if(param==NULL) 
    {
        proto_syslog(LOG_ERR, "modbus ser param is NULL");
        return NULL;
    }

    MODBUS_SERVER_PARAM *modbus_ser_param=calloc(sizeof(MODBUS_SERVER_PARAM), 1);
    MODBUS_SERVER_BASE_PARAM *modbus_ser_base = calloc(sizeof(MODBUS_SERVER_BASE_PARAM), 1);
    // memcpy(modbus_ser_base,param,sizeof(MODBUS_SERVER_BASE_PARAM));
    modbus_ser_param->modbus_ser_base_data = modbus_ser_base;
    
    modbus_tcp_ser_info = calloc(sizeof(modbus_tcp_ser_t), 1);
    modbus_ser_param->modbus_tcp_ser = modbus_tcp_ser_info;
    modbus_ser_param->modbus_ser_base_data->config_file_pwd = strdup(param->config_file_pwd);
    
    modbus_tcp_ser_info->client_list = NULL;
    modbus_tcp_ser_info->max_idle_time = 60;  
    modbus_tcp_ser_info->heartbeat_interval = 10;  
    
    int err = 0; 

    if (err < 2)
    {
        proto_syslog(LOG_NOTICE,"modbus tcp ser init complete!");
        return modbus_ser_param;
    }

    if(modbus_ser_param!=NULL)
        free(modbus_ser_param);
    if(modbus_ser_base!=NULL)
        free(modbus_ser_base);
    if(modbus_tcp_ser_info!=NULL)
        free(modbus_tcp_ser_info);
    return NULL;
}


int modbus_tcp_ser_start(proto_forward_t *var)
{
    if (load_tag_addr_map_file(MODBUSTCP_CONFIG_FILE) < 0)
    {
        ems_syslog(LOG_CRIT,"[Modbus标准北向]:加载北向设备信息失败,文件名:%s请生成Modbus北向点表后重新启动程序",MODBUSTCP_CONFIG_FILE);
		BUSINESS_LOG(BLOG_ERR, NORTH_ID_0024, NULL, "[北向]:Modbus标准北向加载北向设备信息失败,文件名:%s请生成Modbus北向点表后重新启动程序", MODBUSTCP_CONFIG_FILE);
        return -1;
    }
    else
    {
        BUSINESS_LOG(BLOG_NOTICE, NORTH_ID_0024, NULL, "[北向]:Modbus标准北向加载北向设备信息成功,文件名:%s", MODBUSTCP_CONFIG_FILE);
    }

    if (modbus_tcp_ser_info == NULL)
    {
        BUSINESS_LOG(BLOG_ERR, NORTH_ID_0025, NULL, "[北向]:Modbus 点表结构体指针无效");
        proto_syslog(LOG_ERR, "modbus_tcp_ser_info is NULL");
        return -1;
    }
    else
    {
        BUSINESS_LOG(BLOG_NOTICE, NORTH_ID_0025, NULL, "[北向]:Modbus 点表结构体指针有效");
    }

    if (pthread_create(&modbus_tcp_ser_info->thread, NULL, ModbusServerProc, var) != 0)
    {
        perror("ModbusServerProc thread");
        return -1;
    }
    pthread_setname_np(modbus_tcp_ser_info->thread, "modbus tcp ser");
    return 0;
}


int modbus_tcp_ser_stop(proto_forward_t *var)
{
    if (modbus_tcp_ser_info == NULL)
    {
        proto_syslog(LOG_ERR, "modbus_tcp_ser_info is NULL");
        return -1;
    }

    if (modbus_tcp_ser_info->thread != PTHREAD_NULL)
    {
        int kill_rc = pthread_kill(modbus_tcp_ser_info->thread, 0);
        if (kill_rc == ESRCH)
            proto_syslog(LOG_NOTICE, "the specified thread did not exists or already quit\n");
        else if (kill_rc == EINVAL)
            proto_syslog(LOG_NOTICE, "signal is invalid");
        else
        {
            proto_syslog(LOG_NOTICE, "the modbus tcp server thread is alive");
            pthread_cancel(modbus_tcp_ser_info->thread);
            pthread_join(modbus_tcp_ser_info->thread, NULL);
            modbus_tcp_ser_info = NULL;
        }
        proto_syslog(LOG_NOTICE, "modbus tcp server thread kill success");
    }
    else
    {
        proto_syslog(LOG_NOTICE, "modbus tcp server thread is null");
    }
    return 0;
}
