#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 <pthread.h>
#include <math.h>
#include <time.h>
#include <locale.h>
#include <libintl.h>
#include <stdbool.h>

#include "iec104_create.h"
#include "modbus_create.h"
#include "mqtt_create.h"

#include "base_tag_sort.h"
#include "north_automatic.h"
#include "../cc_lc_com/collector-api.h"
#include "../north_mqtt/north_mqtt.h"
#include "../north_mqtt/north_jsonct.h"
#include "../cc_lc_com/define.h"
#include "../log_module/log_module.h"
#include "../business_log/business_log.h"

static north_info_t north_info = {0};
int north_conn_status[NORTH_CHANNEL_CONRTOL_CNT] = {0};
extern int north_control;

north_info_t *get_north_info(void){
    return &north_info;
}

char *ems_compatible[] = {"EMS", NULL};
char *pcs_compatible[] = {"PCS", NULL};
char *bms_compatible[] = {"BMS", NULL};
char *cell_compatible[] = {"CELL", NULL};
char *dido_compatible[] = {"DIDO", NULL};
char *ac_compatible[] = {"AC", "AIRCOND", NULL};
char *tms_compatible[] = {"TMS", "LIQUID_COOL", NULL};
char *pv_compatible[] = {"PV", "MPPT", NULL};
char *dg_compatible[] = {"DG", NULL};
char *fire_compatible[] = {"FIRE", NULL};
char *others_compatible[] = {"OTHERS", "OTHER", NULL};
char *pcs_meter_compatible[] = {"PCS_METER", NULL};
char *grid_meter_compatible[] = {"GRID_METER", NULL};
char *tras_lv_meter_compatible[] = {"TRAS_LV_METER", NULL};
char *load_meter_compatible[] = {"LOAD_METER", NULL};
char *pv_meter_compatible[] = {"PV_METER", "MPPT_METER", NULL};
char *dg_meter_compatible[] = {"DG_METER", NULL};
char *other_meter_compatible[] = {"OTHERS_METER", NULL};

//>>北向当前支持的设备类型--可扩展
class_name_t _class_name[] = {
	{ems_compatible, "EMS", 0, {NULL}},      // EMS
	{pcs_compatible, "PCS", 0, {NULL}},      // 变流器
	{bms_compatible, "BMS", 0, {NULL}},      // 主控
	{cell_compatible, "CELL", 0, {NULL}},    // 电芯
	{grid_meter_compatible, "GRID_METER", 0, {NULL}},  // 电网表
	{pcs_meter_compatible, "PCS_METER", 0, {NULL}},    // 储能表
	{tras_lv_meter_compatible, "TRAS_LV_METER", 0, {NULL}},  // 低压变需量表
	{load_meter_compatible, "LOAD_METER", 0, {NULL}},        // 负载表
	{pv_meter_compatible, "PV_METER", 0, {NULL}},            // 光伏表
	{dg_meter_compatible, "DG_METER", 0, {NULL}},            // 柴发表
	{other_meter_compatible, "OTHERS_METER", 0, {NULL}},     // 其他表
	{dido_compatible, "DIDO", 0, {NULL}},  // 干接点
	{ac_compatible, "AIRCOND", 0, {NULL}}, // 空调
	{tms_compatible, "TMS", 0, {NULL}},    // 液冷机
	{pv_compatible, "PV", 0, {NULL}},      // 光伏
	{dg_compatible, "DG", 0, {NULL}},      // 柴发
	{fire_compatible, "FIRE", 0, {NULL}},  // 消防
	{others_compatible, "OTHERS", 0, {NULL}},      // 其他
};
static int num_class = sizeof(_class_name) / sizeof(_class_name[0]);
static bool first_init_iec104 = true;
static bool first_init_modbus = true;

//获取系统语言，返回0代表英语，1代表中文
int get_sys_language(void)
{
    int ret = 0;
    FILE *fp = fopen("/etc/default/locale", "r");
    if (fp == NULL) {
        ems_syslog(LOG_ERR, "open /etc/default/locale failed");
        return ret;
    }

    char buf[128] = {0};
    while (fgets(buf, sizeof(buf), fp)) {
        if (strstr(buf, "zh_CN")) {
            ret = 1;
            break;
        }
    }
    fclose(fp);
    return ret;
}

static int match_by_class_type(char **class_type, int *p_compatible_id, int log_flag) // -1，匹配失败，其他匹配成功
{
    int ret = -1;

	for (int i = 0; i < num_class; i++) {
        char **pp = _class_name[i].compatible;
        if (pp == NULL) {
            continue;
        }
		
        ret = i;
		while (*pp != NULL)
		{
			if (log_flag) ems_syslog(LOG_DEBUG, "compatible = %s", *pp);
			if (strcmp(*pp, *class_type) == 0)
			{
				*p_compatible_id = pp - _class_name[i].compatible;
				snprintf(*class_type, 32, "%s", _class_name[i].compatible[0]);  // **只要可以匹配到，强制使用类型的第一个**
				return ret;
			}
			pp++;
		}
	}

    return -1;
}

char **external_match_by_class_type(char *class_type) 
{
    for (int i = 0; i < num_class; i++) {
        char **pp = _class_name[i].compatible;
        if (pp == NULL) {
            continue;
        }

        while (*pp != NULL)
        {
            if (strcmp(*pp, class_type) == 0)
                return _class_name[i].compatible;
            pp++;
        }
    }
    return NULL;
}

static const char *protocol[] = {"none", "mqtt_north", "modbustcp_north", "iec104_north"};
/*typedef enum
{
    TYPE_ERROR  =   -1,
    TYPE_BOOL,
    TYPE_INT,
    TYPE_UINT,
    TYPE_FLOAT,
    TYPE_BITS,
    TYPE_SHORT,
    TYPE_USHORT,
    TYPE_MAX
}DATA_TYPE; ------------------------------------------------//类型    */
char *xlsx_data_type[] = {  //xlsx表对外展示数据类型
    "BOOL",
    "I32",
    "U32",
    "F32",
    "U8",
    "I16",
    "U16"
};

int check_dir(void) {
    const char *dir_path = NORTH_CONFIG_PATH;
    struct stat st;
    if (stat(dir_path, &st) == -1) {  // 检查目录是否存在
        if (mkdir(dir_path, 0777) == -1) {
            ems_syslog(LOG_ERR, "Error creating directory");
			return -1;
        } else {
            ems_syslog(LOG_NOTICE, "Directory created successfully.");
        }
    } else {
        ems_syslog(LOG_NOTICE, "Directory already exists");
    }
    return 0;
}

int check_file_exist(char *file_name) {
    
    char file_path[128] = "";	
	snprintf(file_path, sizeof(file_path), "%s/%s", NORTH_CONFIG_PATH, file_name);

    if (access(file_path, F_OK) != -1) {  // 检查文件是否存在
        // 文件存在，删除文件
        if (remove(file_path) == 0) {
            ems_syslog(LOG_NOTICE, "File deleted successfully");
        } else {
            ems_syslog(LOG_ERR, "Error deleting file");
            return -1;
        }
    } else {
        ems_syslog(LOG_NOTICE, "File does not exist");
    }

    return 0;
}

int file_exists(const char *file_path) {
    return access(file_path, F_OK) == 0;
}

// 保存点位顺序到JSON文件
static void save_tag_order(mq_north_inside_t *mq_north_inside) {
    if (mq_north_inside == NULL) {
        ems_syslog(LOG_ERR, "save_tag_order: mq_north_inside is NULL");
        return;
    }
    
    char file_path[128] = "";
    // 根据协议类型生成不同的文件名
    if (north_info.protocol_type == N_PROTOCOL_TYPE_MODBUS_TCP) {
        snprintf(file_path, sizeof(file_path), "%s/%s_modbus.json", NORTH_CONFIG_PATH, TAG_ORDER_FILE);
    } else if (north_info.protocol_type == N_PROTOCOL_TYPE_IEC104) {
        snprintf(file_path, sizeof(file_path), "%s/%s_iec104.json", NORTH_CONFIG_PATH, TAG_ORDER_FILE);
    } else {
        snprintf(file_path, sizeof(file_path), "%s/%s", NORTH_CONFIG_PATH, TAG_ORDER_FILE);
    }
    
    // 创建JSON根对象
    cJSON *root = cJSON_CreateObject();
    if (root == NULL) {
        ems_syslog(LOG_ERR, "save_tag_order: failed to create cJSON root object");
        return;
    }
    
    // 创建点位顺序数组
    cJSON *tag_order_array = cJSON_CreateArray();
    if (tag_order_array == NULL) {
        ems_syslog(LOG_ERR, "save_tag_order: failed to create tag_order_array");
        cJSON_Delete(root);
        return;
    }
    cJSON_AddItemToObject(root, "tag_order", tag_order_array);
    
    // 遍历所有类
    for (int i = 0; i < mq_north_inside->num; i++) {
        mq_north_class_t *mq_north_class = mq_north_inside->mq_north_class[i];
        
        // 遍历所有设备
        for (int j = 0; j < mq_north_class->num; j++) {
            mq_north_dev_t *mq_north_dev = mq_north_class->mq_north_dev[j];
            // 为当前设备初始化分类列表
            tag_entry_t **tag_lists[3] = {NULL, NULL, NULL};  // 三个分类列表
            int tag_counts[3] = {0, 0, 0};                    // 每个分类的当前数量
            int tag_capacities[3] = {0, 0, 0};                // 每个分类的容量
            // 遍历所有点位
            for (int m = 0; m < mq_north_dev->num; m++) {
                mq_north_tag_t *mq_north_tag = mq_north_dev->mq_north_tag[m];
                if (mq_north_tag == NULL || mq_north_tag->tag == NULL) continue;
                // 根据property和limit分类存储点位
                // 分类规则：
                // 0 = 告警点位 (property == 2)
                // 1 = 读点位 (property != 2 且 limit == 0)
                // 2 = 写点位 (property != 2 且 limit == 1)
                int category = 0;
                if (mq_north_tag->tag->property == PROPERTY_ALARM) {
                    category = 0;  // 告警点位
                } else if (mq_north_tag->limit == 0) {
                    category = 1;  // 读点位
                } else {
                    category = 2;  // 写点位
                }
                // 扩展对应分类的容量
                if (tag_counts[category] >= tag_capacities[category]) {
                    tag_capacities[category] += 100;
                    tag_lists[category] = (tag_entry_t **)realloc(tag_lists[category],
                        tag_capacities[category] * sizeof(tag_entry_t *));
                    if (tag_lists[category] == NULL) {
                        ems_syslog(LOG_ERR, "save_tag_order: failed to allocate tag_lists[%d]", category);
                        continue;
                    }
                }
                // 分配并存储点位条目
                tag_lists[category][tag_counts[category]] = (tag_entry_t *)malloc(sizeof(tag_entry_t));
                if (tag_lists[category][tag_counts[category]] == NULL) {
                    ems_syslog(LOG_ERR, "save_tag_order: failed to allocate tag_entry");
                    continue;
                }
                tag_lists[category][tag_counts[category]]->mq_north_tag = mq_north_tag;
                tag_lists[category][tag_counts[category]]->mq_north_dev = mq_north_dev;
                tag_counts[category]++;
            }
            // 按照告警、读、写的顺序将当前设备的点位写入文件
            // 分类顺序：0=告警, 1=读, 2=写
            for (int category = 0; category < 3; category++) 
			{
                for (int k = 0; k < tag_counts[category]; k++) 
				{
                    mq_north_tag_t *mq_north_tag = tag_lists[category][k]->mq_north_tag;
                    mq_north_dev_t *mq_north_dev = tag_lists[category][k]->mq_north_dev;

                    // 创建点位对象
                    cJSON *tag_obj = cJSON_CreateObject();
                    if (tag_obj == NULL) {
                        ems_syslog(LOG_ERR, "save_tag_order: failed to create tag_obj");
                        continue;
                    }

                    // 添加点位信息
                    cJSON_AddStringToObject(tag_obj, "tag_name", mq_north_tag->tag->name);
                    cJSON_AddNumberToObject(tag_obj, "active", mq_north_tag->tag->active);
                    cJSON_AddNumberToObject(tag_obj, "protocol_type", north_info.protocol_type);

                    // 根据协议类型获取点位地址
                    if (north_info.protocol_type == N_PROTOCOL_TYPE_MODBUS_TCP) {
                        mo_north_tag_t *mo_north_tag = mq_north_tag->proto_ptr;
                        if (mo_north_tag != NULL) {
                            cJSON_AddNumberToObject(tag_obj, "address", mo_north_tag->addr);
                        }
                    } 
					else if (north_info.protocol_type == N_PROTOCOL_TYPE_IEC104) 
					{
                        iec_north_tag_t *iec_north_tag = mq_north_tag->proto_ptr;
                        if (iec_north_tag != NULL) {
							// 根据点位类型选择不同的地址字段
							if (mq_north_tag->tag->property == 2) {
								cJSON_AddNumberToObject(tag_obj, "address", iec_north_tag->addr_P);
							} else {
								cJSON_AddNumberToObject(tag_obj, "address", iec_north_tag->addr_S);
							}
						}
                    }
                    

                    // 添加设备信息
                    // 始终使用当前的设备信息，确保与mq_tag_add_to_dev中的匹配逻辑一致
                    // 使用tag_order_list中保存的dev_no可能导致设备编号不一致，导致点位地址无法正确恢复
                    cJSON_AddStringToObject(tag_obj, "dev_no", mq_north_dev->no);
                    cJSON_AddStringToObject(tag_obj, "dev_type", mq_north_dev->class_type);

                    // 将点位对象添加到数组
                    cJSON_AddItemToArray(tag_order_array, tag_obj);
                }
            }
            // 释放当前设备的分类列表内存
            for (int p = 0; p < 3; p++) {
                if (tag_lists[p] != NULL) {
                    for (int k = 0; k < tag_counts[p]; k++) {
                        if (tag_lists[p][k] != NULL) {
                            free(tag_lists[p][k]);
                        }
                    }
                    free(tag_lists[p]);
                    tag_lists[p] = NULL;
                }
                tag_counts[p] = 0;
                tag_capacities[p] = 0;
            }
        }
    }
    
    // 生成JSON字符串
    char *json_str = cJSON_Print(root);
    if (json_str == NULL) {
        ems_syslog(LOG_ERR, "save_tag_order: failed to print JSON");
        cJSON_Delete(root);
        return;
    }
    
    // 写入文件
    if (write_file_data(file_path, json_str, strlen(json_str)) != 0) {
        ems_syslog(LOG_ERR, "save_tag_order: failed to write file");
    }
    
    // 清理资源
    cJSON_Delete(root);
    free(json_str);
    
    ems_syslog(LOG_NOTICE, "save_tag_order: saved tag order to %s", file_path);
}

// 读取点位顺序从JSON文件
static void read_tag_order(void) {
    char file_path[128] = "";
    // 根据协议类型生成不同的文件名
    if (north_info.protocol_type == N_PROTOCOL_TYPE_MODBUS_TCP) {
        snprintf(file_path, sizeof(file_path), "%s/%s_modbus.json", NORTH_CONFIG_PATH, TAG_ORDER_FILE);
    } else if (north_info.protocol_type == N_PROTOCOL_TYPE_IEC104) {
        snprintf(file_path, sizeof(file_path), "%s/%s_iec104.json", NORTH_CONFIG_PATH, TAG_ORDER_FILE);
    } else {
        snprintf(file_path, sizeof(file_path), "%s/%s", NORTH_CONFIG_PATH, TAG_ORDER_FILE);
    }
    
    // 检查文件是否存在
    if (!file_exists(file_path)) {
        ems_syslog(LOG_ERR, "read_tag_order: tag_order.json does not exist");
        north_info.tag_order_exist = 0;
        return;
    }
    
    // 打开文件
    FILE *fp = fopen(file_path, "r");
    if (fp == NULL) {
        ems_syslog(LOG_ERR, "read_tag_order: failed to open %s", file_path);
        north_info.tag_order_exist = 0;
        return;
    }
    
    // 获取文件大小
    fseek(fp, 0, SEEK_END);
    long file_size = ftell(fp);
    fseek(fp, 0, SEEK_SET);
    
    // 分配内存
    char *buffer = (char *)malloc(file_size + 1);
    if (buffer == NULL) {
        ems_syslog(LOG_ERR, "read_tag_order: failed to allocate memory");
        fclose(fp);
        north_info.tag_order_exist = 0;
        return;
    }
    
    // 读取文件内容
    size_t read_size = fread(buffer, 1, file_size, fp);
    buffer[read_size] = '\0';
    fclose(fp);
    
    // 解析JSON
    cJSON *root = cJSON_Parse(buffer);
    free(buffer);
    
    if (root == NULL) {
        ems_syslog(LOG_ERR, "read_tag_order: failed to parse JSON");
        north_info.tag_order_exist = 0;
        return;
    }
    
    // 获取点位顺序数组
    cJSON *tag_order_array = cJSON_GetObjectItem(root, "tag_order");
    if (tag_order_array == NULL || !cJSON_IsArray(tag_order_array)) {
        ems_syslog(LOG_ERR, "read_tag_order: tag_order is not an array");
        cJSON_Delete(root);
        north_info.tag_order_exist = 0;
        return;
    }
    
    // 获取数组大小
    int count = cJSON_GetArraySize(tag_order_array);
    if (count == 0) {
        ems_syslog(LOG_NOTICE, "read_tag_order: tag_order array is empty");
        cJSON_Delete(root);
        north_info.tag_order_exist = 0;
        return;
    }
    
    // 分配点位顺序列表
    north_info.tag_order_list = (tag_order_t *)malloc(count * sizeof(tag_order_t));
    if (north_info.tag_order_list == NULL) {
        ems_syslog(LOG_ERR, "read_tag_order: failed to allocate tag_order_list");
        cJSON_Delete(root);
        north_info.tag_order_exist = 0;
        return;
    }
    
    // 初始化点位顺序列表
    north_info.tag_order_count = count;
    north_info.tag_order_exist = 1;
    
    // 遍历数组，填充点位顺序列表
    for (int i = 0; i < count; i++) {
        cJSON *tag_obj = cJSON_GetArrayItem(tag_order_array, i);
        if (tag_obj == NULL || !cJSON_IsObject(tag_obj)) {
            continue;
        }
        
        // 获取点位信息
        cJSON *tag_name = cJSON_GetObjectItem(tag_obj, "tag_name");
        cJSON *address = cJSON_GetObjectItem(tag_obj, "address");
        cJSON *active = cJSON_GetObjectItem(tag_obj, "active");
        cJSON *dev_no = cJSON_GetObjectItem(tag_obj, "dev_no");
        cJSON *dev_type = cJSON_GetObjectItem(tag_obj, "dev_type");
        cJSON *protocol_type = cJSON_GetObjectItem(tag_obj, "protocol_type");
        
        if (tag_name != NULL && cJSON_IsString(tag_name) && 
            address != NULL && cJSON_IsNumber(address)) {
            
            // 填充点位顺序信息
            snprintf(north_info.tag_order_list[i].tag_name, sizeof(north_info.tag_order_list[i].tag_name), "%s", tag_name->valuestring);
            north_info.tag_order_list[i].address = address->valueint;
            north_info.tag_order_list[i].active = (active != NULL && cJSON_IsNumber(active)) ? active->valueint : 0;
            north_info.tag_order_list[i].protocol_type = (protocol_type != NULL && cJSON_IsNumber(protocol_type)) ? protocol_type->valueint : 0;
            
            // 填充设备信息
            if (dev_no != NULL && cJSON_IsString(dev_no)) {
                snprintf(north_info.tag_order_list[i].dev_no, sizeof(north_info.tag_order_list[i].dev_no), "%s", dev_no->valuestring);
            }
            if (dev_type != NULL && cJSON_IsString(dev_type)) {
                snprintf(north_info.tag_order_list[i].dev_type, sizeof(north_info.tag_order_list[i].dev_type), "%s", dev_type->valuestring);
            }
        }
    }
    
    cJSON_Delete(root);
    ems_syslog(LOG_NOTICE, "read_tag_order: successfully read %d tag orders", count);
}

// Check if the JSON file contains version field with value 2
int check_json_version(const char *file_path) {
    FILE *fp = NULL;
    char *buffer = NULL;
    long file_size = 0;
    cJSON *root = NULL;
    int result = 0; // 0: not version 2, 1: is version 2, -1: error
    
    // Check if file exists
    if (!file_exists(file_path)) {
        return 0;
    }
    
    // Open file
    fp = fopen(file_path, "r");
    if (fp == NULL) {
        ems_syslog(LOG_ERR, "Failed to open file: %s", file_path);
        return -1;
    }
    
    // Get file size
    fseek(fp, 0, SEEK_END);
    file_size = ftell(fp);
    fseek(fp, 0, SEEK_SET);
    
    // Allocate buffer
    buffer = (char *)malloc(file_size + 1);
    if (buffer == NULL) {
        ems_syslog(LOG_ERR, "Failed to allocate memory for file: %s", file_path);
        fclose(fp);
        return -1;
    }
    
    // Read file content
    if (fread(buffer, 1, file_size, fp) != (size_t)file_size) {
        ems_syslog(LOG_ERR, "Failed to read file: %s", file_path);
        free(buffer);
        fclose(fp);
        return -1;
    }
    buffer[file_size] = '\0';
    
    // Parse JSON
    root = cJSON_Parse(buffer);
    if (root == NULL) {
        ems_syslog(LOG_ERR, "Failed to parse JSON file: %s", file_path);
        free(buffer);
        fclose(fp);
        return -1;
    }
    
    // Check version field
    cJSON *version = cJSON_GetObjectItem(root, "version");
    if (version != NULL && cJSON_IsNumber(version)) {
        if (version->valueint == 2) {
            result = 1;
        } else {
            result = 0;
        }
    }
    
    // Cleanup
    cJSON_Delete(root);
    free(buffer);
    fclose(fp);
    
    return result;
}


static void free_memory(void *ptr) {
    if (ptr != NULL) {
        free(ptr);
        ptr = NULL;
    }
}

static mq_xlsx_book_t *mq_xlsx_init(void){
	mq_xlsx_book_t *mq_xlsx_book = NULL;
	mq_xlsx_book = calloc(sizeof(mq_xlsx_book_t), 1);
    return mq_xlsx_book;
}

static mq_north_inside_t *mq_north_init(void){
	mq_north_inside_t *mq_north_inside = NULL;
	mq_north_inside = calloc(sizeof(mq_north_inside_t), 1);
    return mq_north_inside;
}

// The dev_addr_info.json file exists and will be called multiple times to regenerate the northbound mapping
static char *much_create_dev_info(north_info_t *north_info)
{
	cJSON *root = NULL;
	char *string = NULL;
	int i = 0, j = 0;
	root = cJSON_CreateObject();
	if (root == NULL)
	{
		ems_syslog(LOG_NOTICE, "cJSON_CreateObject root NULL");
		goto end;
	}

	for (i = 0; i < num_class; i++) {
		class_name_t *class_name = &_class_name[i];
        if (class_name->num == 0) continue;
		
		cJSON *arry = cJSON_CreateArray();
		cJSON_AddItemToObject(root, class_name->compatible[0], arry);

		for (j = 0; j < class_name->num; j++) {
			 dev_cache_info_t *dev_cache_info = class_name->ptr[j];
			 cJSON *item = cJSON_CreateObject();
			 cJSON_AddStringToObject(item, "no", dev_cache_info->no);
			 cJSON_AddNumberToObject(item, "addr", dev_cache_info->addr);
			 cJSON_AddNumberToObject(item, "section_indx", dev_cache_info->section_indx);
			 cJSON_AddItemToArray(arry, item);
		}
	}
	string = cJSON_Print(root);
end:
	if (root != NULL)
	{
		cJSON_Delete(root);
	}
	//ems_syslog(LOG_NOTICE,"%s",string);
	return string;
}

/* It will only be called once 
   unless the dev_addr_info.json file is deleted and the northbound mapping is regenerated*/
static char *single_create_dev_info(mq_north_inside_t *mq_north_inside, north_info_t *north_info)
{
	cJSON *root = NULL;
	char *string = NULL;
	int i = 0, j = 0;
	root = cJSON_CreateObject();
	if (root == NULL)
	{
		ems_syslog(LOG_NOTICE, "cJSON_CreateObject root NULL");
		goto end;
	}				

	for (i = 0; i < mq_north_inside->num; i++) {
		mq_north_class_t *mq_north_class = mq_north_inside->mq_north_class[i];

		int p_compatible_id = 0;
		int index = match_by_class_type(&(mq_north_class->class_type), &p_compatible_id, LOG_FLAG);
		if (index == -1)
			continue;
		else{
			cJSON *arry = cJSON_CreateArray();
			cJSON_AddItemToObject(root, _class_name[index].compatible[0], arry);

	        for (j = 0; j < mq_north_class->num; j++) {
	             mq_north_dev_t *mq_north_dev = mq_north_class->mq_north_dev[j];
                 if (north_info->protocol_type == N_PROTOCOL_TYPE_MODBUS_TCP){	
					 mo_north_dev_t *mo_north_dev = (mo_north_dev_t *)mq_north_dev->proto_ptr;
					 cJSON *item = cJSON_CreateObject();
		             cJSON_AddStringToObject(item, "no", mq_north_dev->no);
		             cJSON_AddNumberToObject(item, "addr", mo_north_dev->addr);
					 cJSON_AddNumberToObject(item, "section_indx", mo_north_dev->section_indx);
		             cJSON_AddItemToArray(arry, item);
                 }
				 else if (north_info->protocol_type == N_PROTOCOL_TYPE_IEC104){
					 iec_north_dev_t *iec_north_dev = (iec_north_dev_t *)mq_north_dev->proto_ptr;
					 cJSON *item = cJSON_CreateObject();
					 cJSON_AddStringToObject(item, "no", mq_north_dev->no);
					 cJSON_AddNumberToObject(item, "addr", iec_north_dev->addr);
					 cJSON_AddNumberToObject(item, "section_indx", iec_north_dev->section_indx);
					 cJSON_AddItemToArray(arry, item);
				 }
	        }
		}
	}
	string = cJSON_Print(root);
end:
	if (root != NULL)
	{
		cJSON_Delete(root);
	}
	//ems_syslog(LOG_NOTICE,"%s",string);
	return string;

}

static void save_dev_addr_info_file(mq_north_inside_t *mq_north_inside){
    //int ret = 0;
	char *json_str = NULL;
	north_info_t *north_info = get_north_info();
	if (north_info->protocol_type == N_PROTOCOL_TYPE_MQTT){
        goto END;
	}

	if (north_info->exist)//
        json_str = much_create_dev_info(north_info);
	else
		json_str = single_create_dev_info(mq_north_inside, north_info);
	if (json_str)
	{
		if (check_file_exist(DEV_ADDR_INFO_FILE) == 0)
			write_file_data(NORTH_CONFIG_PATH"/"DEV_ADDR_INFO_FILE, json_str, strlen(json_str));
	}
	else{
		ems_syslog(LOG_ERR, "create dev_addr_info.json error!!!!");
	}
END:
	if (json_str) {free(json_str); json_str = NULL;}
}


static ProtoHandler _handlers[] = {
     {"mqtt", 1, create_mq_relate_file},
     {"modbus_tcp", 2, create_mo_relate_file}, 
     {"iec104", 3, create_iec_relate_file},
};
int num_handlers = sizeof(_handlers) / sizeof(_handlers[0]);

// 检查配置文件版本并设置 need_add_version 标志
static void check_config_version_and_set_flag() {
	char file_path[128] = "";
	int version_check = 0;

	// Initialize the flag: 1 = need to add version field, 0 = no need
	north_info.need_add_version = 0;

	// Protocol type checking mechanism
	if (north_info.protocol_type == N_PROTOCOL_TYPE_MQTT) {
		// Check MQTT configuration file status
		snprintf(file_path, sizeof(file_path), "%s/%s", NORTH_CONFIG_PATH, MQTT_NORTH_MAP_FILE);
		
		if (file_exists(file_path)) {
			// Check if file contains version 2
			version_check = check_json_version(file_path);
			if (version_check == 1) {
				ems_syslog(LOG_NOTICE, "MQTT configuration file exists and is version 2: %s, will add version field", file_path);
				north_info.need_add_version = 1;
			} else if (version_check == 0) {
				ems_syslog(LOG_NOTICE, "MQTT configuration file exists but is not version 2, will not add version field: %s", file_path);
				north_info.need_add_version = 0;
			} else {
				ems_syslog(LOG_ERR, "Failed to check MQTT configuration file version: %s, will not add version field", file_path);
				north_info.need_add_version = 0;
			}
		} else {
			ems_syslog(LOG_NOTICE, "MQTT configuration file does not exist: %s, will add version field", file_path);
			north_info.need_add_version = 1;
		}
	} else if (north_info.protocol_type == N_PROTOCOL_TYPE_MODBUS_TCP) {
		// Check Modbus TCP configuration file status
		snprintf(file_path, sizeof(file_path), "%s/%s", NORTH_CONFIG_PATH, MODBUSTCP_NORTH_MAP_FILE);
		
		if (file_exists(file_path)) {
			// Check if file contains version 2
			version_check = check_json_version(file_path);
			if (version_check == 1) {
				ems_syslog(LOG_NOTICE, "Modbus TCP configuration file exists and is version 2: %s, will add version field", file_path);
				north_info.need_add_version = 1;
			} else if (version_check == 0) {
				ems_syslog(LOG_NOTICE, "Modbus TCP configuration file exists but is not version 2, will not add version field: %s", file_path);
				north_info.need_add_version = 0;
			} else {
				ems_syslog(LOG_ERR, "Failed to check Modbus TCP configuration file version: %s, will not add version field", file_path);
				north_info.need_add_version = 0;
			}
		} else {
			ems_syslog(LOG_NOTICE, "Modbus TCP configuration file does not exist: %s, will add version field", file_path);
			north_info.need_add_version = 1;
		}
	} else if (north_info.protocol_type == N_PROTOCOL_TYPE_IEC104) {
		// Check IEC104 configuration file status
		snprintf(file_path, sizeof(file_path), "%s/%s", NORTH_CONFIG_PATH, IEC104_NORTH_MAP_FILE);
		
		if (file_exists(file_path)) {
			// Check if file contains version 2
			version_check = check_json_version(file_path);
			if (version_check == 1) {
				ems_syslog(LOG_NOTICE, "IEC104 configuration file exists and is version 2: %s, will add version field", file_path);
				north_info.need_add_version = 1;
			} else if (version_check == 0) {
				ems_syslog(LOG_NOTICE, "IEC104 configuration file exists but is not version 2, will not add version field: %s", file_path);
				north_info.need_add_version = 0;
			} else {
				ems_syslog(LOG_ERR, "Failed to check IEC104 configuration file version: %s, will not add version field", file_path);
				north_info.need_add_version = 0;
			}
		} else {
			ems_syslog(LOG_NOTICE, "IEC104 configuration file does not exist: %s, will add version field", file_path);
			north_info.need_add_version = 1;
		}
	}
}

static int create_relate_file(mq_north_inside_t *mq_north_inside, mq_xlsx_book_t *mq_xlsx_book){
    int ret = 0;
	char *inside_json = NULL;

	if (check_dir() != 0){
		ret = -1;
	    goto end;
	}

	for (int i = 0; i < num_handlers; i++) {
		if (_handlers[i].index == north_info.protocol_type) {
			ems_syslog(LOG_NOTICE, "protocol name: %s", _handlers[i].name);
			inside_json = _handlers[i].handler(mq_north_inside, mq_xlsx_book);
			break;
		}
	}
	
end:        
	FREE_AND_NULL(inside_json);        
	return ret;    
}

static void mq_inside_sync_xlsx(mq_north_inside_t *mq_north_inside, mq_xlsx_book_t *mq_xlsx_book, n_protocol_type_t protocol_type)
{
    int i= 0, j = 0;
	char buffer[64];
	char book_name[BOOK_NAME_LEN] = ""; 
	time_t now = time(NULL);
    
    struct tm target_time = {};  
    localtime_r(&now, &target_time);
    struct tm *tim = &target_time;
	strftime(buffer, 64, "%Y-%m-%d %H:%M:%S", tim);
	//snprintf(book_name, sizeof(book_name), "%s(%s)", protocol[protocol_type], buffer); //带时间
	snprintf(book_name, sizeof(book_name), "%s.xlsx", protocol[protocol_type]);
	local_strlcpy(mq_xlsx_book->name, book_name, sizeof(mq_xlsx_book->name));

	north_info_t *north_info = get_north_info();
	
	for (i = 0; i < mq_north_inside->num; i++) {
		if (mq_xlsx_book->num >= XLSX_SHEET_NUM) break;
		if (mq_xlsx_book->mq_xlsx_sheet[mq_xlsx_book->num] == NULL)
		   mq_xlsx_book->mq_xlsx_sheet[mq_xlsx_book->num] = calloc(sizeof(mq_xlsx_sheet_t), 1);

		if (mq_xlsx_book->mq_xlsx_sheet[mq_xlsx_book->num] == NULL) continue;
		
		mq_north_class_t *mq_north_class = mq_north_inside->mq_north_class[i];
		mq_xlsx_sheet_t *mq_xlsx_sheet = mq_xlsx_book->mq_xlsx_sheet[mq_xlsx_book->num]; //

		local_strlcpy(mq_xlsx_sheet->name, mq_north_class->name, sizeof(mq_xlsx_sheet->name));
        for (j = 0; j < mq_north_class->num; j++) { //设备

			if (mq_xlsx_sheet->num >= SHEET_DEV_NUM) break;
			if (mq_xlsx_sheet->mq_xlsx_dev[mq_xlsx_sheet->num] == NULL)
			   mq_xlsx_sheet->mq_xlsx_dev[mq_xlsx_sheet->num] = calloc(sizeof(mq_xlsx_dev_t), 1);

			if (mq_xlsx_sheet->mq_xlsx_dev[mq_xlsx_sheet->num] == NULL) continue;

			mq_north_dev_t *mq_north_dev = mq_north_class->mq_north_dev[j];
			mq_xlsx_dev_t *mq_xlsx_dev = mq_xlsx_sheet->mq_xlsx_dev[mq_xlsx_sheet->num]; //
			
			if (north_info->protocol_type == N_PROTOCOL_TYPE_MQTT){
				;
			}
			else if (north_info->protocol_type == N_PROTOCOL_TYPE_MODBUS_TCP){

			    mo_xlsx_dev_t *mo_xlsx_dev = calloc(sizeof(mo_xlsx_dev_t), 1);
			    mo_north_dev_t *mo_north_dev = mq_north_dev->proto_ptr;
			    
                mo_xlsx_dev->addr = mo_north_dev->addr;
				mo_xlsx_dev->nb_coil = mo_north_dev->nb_coil;
				for (int m = 0; m < mo_north_dev->nb_coil; m++) {
                     mo_xlsx_dev->coil_tag[m] = mo_north_dev->coil_tag[m];
				}
				mo_xlsx_dev->nb_inputb = mo_north_dev->nb_inputb;
				for (int m = 0; m < mo_north_dev->nb_inputb; m++) {
                     mo_xlsx_dev->inputb_tag[m] = mo_north_dev->inputb_tag[m];
				}
				mo_xlsx_dev->nb_hold = mo_north_dev->nb_hold;
				for (int m = 0; m < mo_north_dev->nb_hold; m++) {
                     mo_xlsx_dev->hold_tag[m] = mo_north_dev->hold_tag[m];
				}
				mo_xlsx_dev->nb_inputr = mo_north_dev->nb_inputr;
				for (int m = 0; m < mo_north_dev->nb_inputr; m++) {
                     mo_xlsx_dev->inputr_tag[m] = mo_north_dev->inputr_tag[m];
				}
				mq_xlsx_dev->proto_ptr = mo_xlsx_dev;
			}
			else if (north_info->protocol_type == N_PROTOCOL_TYPE_IEC104){

				iec_xlsx_dev_t *iec_xlsx_dev = calloc(sizeof(iec_xlsx_dev_t), 1);
				iec_north_dev_t *iec_north_dev = mq_north_dev->proto_ptr;
				
				iec_xlsx_dev->addr = iec_north_dev->addr;
				iec_xlsx_dev->nb_rp = iec_north_dev->nb_rp;
				for (int m = 0; m < iec_north_dev->nb_rp; m++) {
					 iec_xlsx_dev->rp_tag[m] = iec_north_dev->rp_tag[m];
				}
				iec_xlsx_dev->nb_rm = iec_north_dev->nb_rm;
				for (int m = 0; m < iec_north_dev->nb_rm; m++) {
					 iec_xlsx_dev->rm_tag[m] = iec_north_dev->rm_tag[m];
				}
				iec_xlsx_dev->nb_rc = iec_north_dev->nb_rc;
				for (int m = 0; m < iec_north_dev->nb_rc; m++) {
					 iec_xlsx_dev->rc_tag[m] = iec_north_dev->rc_tag[m];
				}
				iec_xlsx_dev->nb_rr = iec_north_dev->nb_rr;
				for (int m = 0; m < iec_north_dev->nb_rr; m++) {
					 iec_xlsx_dev->rr_tag[m] = iec_north_dev->rr_tag[m];
				}
				mq_xlsx_dev->proto_ptr = iec_xlsx_dev;
			}
            local_strlcpy(mq_xlsx_dev->no, mq_north_dev->no, sizeof(mq_xlsx_dev->no));
			local_strlcpy(mq_xlsx_dev->disp_name, mq_north_dev->disp_name, sizeof(mq_xlsx_dev->disp_name));
			for (int m = 0; m < mq_north_dev->num; m++) {

				if (mq_xlsx_dev->num >= ITEM_NUM) break;
				if (mq_xlsx_dev->mq_xlsx_item[mq_xlsx_dev->num] == NULL)
				   mq_xlsx_dev->mq_xlsx_item[mq_xlsx_dev->num] = calloc(sizeof(mq_xlsx_item_t), 1);

				if (mq_xlsx_dev->mq_xlsx_item[mq_xlsx_dev->num] == NULL) continue;

                mq_north_tag_t* mq_north_tag = mq_north_dev->mq_north_tag[m];
                if( mq_north_tag == NULL) continue;
				mq_xlsx_item_t *mq_xlsx_item = mq_xlsx_dev->mq_xlsx_item[mq_xlsx_dev->num];

				if (north_info->protocol_type == N_PROTOCOL_TYPE_MQTT){
					;
				}
				else if (north_info->protocol_type == N_PROTOCOL_TYPE_MODBUS_TCP){
				
					mo_xlsx_item_t *mo_xlsx_item = calloc(sizeof(mo_xlsx_item_t), 1);
					mo_north_tag_t *mo_north_tag = mq_north_tag->proto_ptr;
					
					if (mo_north_tag != NULL) {
						mo_xlsx_item->addr          = mo_north_tag->addr;
						mo_xlsx_item->function_code = mo_north_tag->function_code;
						mo_xlsx_item->data_type     = mo_north_tag->data_type; // 北向数据类型<< 与内部点位数据类型不一定一致
						mo_xlsx_item->coefficient   = mo_north_tag->coefficient;
					} else {
						// 如果 proto_ptr 为 NULL，使用默认值
						mo_xlsx_item->addr          = 0;
						mo_xlsx_item->function_code = B_CODE_TYPE;
						mo_xlsx_item->data_type     = mq_north_tag->tag->data_type;
						mo_xlsx_item->coefficient   = 1.0;
					}
					mq_xlsx_item->proto_ptr = mo_xlsx_item;
				}
				else if (north_info->protocol_type == N_PROTOCOL_TYPE_IEC104){
					iec_xlsx_item_t *iec_xlsx_item = calloc(sizeof(iec_xlsx_item_t), 1);
					iec_north_tag_t *iec_north_tag = mq_north_tag->proto_ptr;
					
					if (iec_north_tag != NULL) {
						iec_xlsx_item->addr        = iec_north_tag->addr;
						iec_xlsx_item->addr_S      = iec_north_tag->addr_S;
						iec_xlsx_item->data_type   = iec_north_tag->data_type; // 北向数据类型<< 与内部点位数据类型不一定一致
						iec_xlsx_item->coefficient = iec_north_tag->coefficient;
					} else {
						// 如果 proto_ptr 为 NULL，使用默认值
						iec_xlsx_item->addr        = 0;
						iec_xlsx_item->addr_S      = 0;
						iec_xlsx_item->data_type   = mq_north_tag->tag->data_type;
						iec_xlsx_item->coefficient = 1.0;
					}
					mq_xlsx_item->proto_ptr = iec_xlsx_item;				}
                snprintf(mq_xlsx_item->name, sizeof(mq_xlsx_item->name), "%s", mq_north_tag->tag->name);
                snprintf(mq_xlsx_item->dev_tag_name, sizeof(mq_xlsx_item->dev_tag_name), "%s", mq_north_tag->tag->dev_tag_name);
                snprintf(mq_xlsx_item->disp_name, sizeof(mq_xlsx_item->disp_name), "%s", mq_north_tag->tag->disp_name);
                mq_xlsx_item->data_type = mq_north_tag->tag->data_type;
                mq_xlsx_item->property  = mq_north_tag->tag->property;
                mq_xlsx_item->limit     = mq_north_tag->limit;
                mq_xlsx_item->scale     = mq_north_tag->tag->scale;
				mq_xlsx_item->active    = mq_north_tag->tag->active;
                if (mq_north_tag->tag->desc != NULL)
                    mq_xlsx_item->desc = strdup(mq_north_tag->tag->desc);
                mq_xlsx_dev->num++;                
            }
			mq_xlsx_sheet->num++;
        }
		mq_xlsx_book->num++;
	}
}

static int _find_addr_max(dev_cache_info_t **dev_cache_ptr, int size) {
	if (size <= 0) {
		ems_syslog(LOG_NOTICE, "Array size must be greater than 0");
		return -1;
	}
	int max = dev_cache_ptr[0]->addr;
	for (int i = 0; i < size; i++) {
		if (dev_cache_ptr[i]->addr > max) {
			max = dev_cache_ptr[i]->addr;
		}
	}
	return max;
}

static int _find_section_indx_max(dev_cache_info_t **dev_cache_ptr, int size) {
	if (size <= 0) {
		ems_syslog(LOG_NOTICE, "Array size must be greater than 0");
		return -1;
	}
	int max = dev_cache_ptr[0]->section_indx;
	for (int i = 0; i < size; i++) {
		if (dev_cache_ptr[i]->section_indx > max) {
			max = dev_cache_ptr[i]->section_indx;
		}
	}
	return max;
}

static int get_dev_cache_by_class_type(mq_north_dev_t *mq_north_dev, dev_cache_info_t **dev_cache_ptr) // -1，匹配失败，0成功
{
    int find = 0;
	int p_compatible_id = 0;
	int index = match_by_class_type(&(mq_north_dev->class_type), &p_compatible_id, 0);
	if (index == -1)
		return -1; //>>类，匹配失败. Already filtered. Impossible
	else{
        for (int i = 0; i < _class_name[index].num; i++) {
			dev_cache_info_t *dev_cache_info = _class_name[index].ptr[i];
            if (strcmp(mq_north_dev->no, dev_cache_info->no) == 0){ // 3.此设备之前添加过，直接获取
                *dev_cache_ptr = dev_cache_info;
				find = 1; 
				break;
			}
        }
	}

	north_info_t *north_info = get_north_info();
	if (find == 0){ // 1.此类第一次添加设备num = 0  2. 此类之前有设备，增加新设备 num > 0
		dev_cache_info_t *dev_cache_info = (dev_cache_info_t *)calloc(sizeof(dev_cache_info_t), 1);
		strncpy(dev_cache_info->no, mq_north_dev->no, DEV_NO_LEN);
        if ((strcmp(mq_north_dev->class_type, "PCS") == 0)	 || (strcmp(mq_north_dev->class_type, "BMS") == 0) || (strcmp(mq_north_dev->class_type, "CELL") == 0)){

			int addr = _find_addr_max(_class_name[index].ptr, _class_name[index].num);
			if (addr == -1){
				mq_north_class_t *mq_north_class = (mq_north_class_t *)mq_north_dev->ptr; // 找到设备所属的类信息
				if (north_info->protocol_type == N_PROTOCOL_TYPE_MODBUS_TCP){
					mo_north_class_t *mo_north_class = (mo_north_class_t *)mq_north_class->proto_ptr;
					dev_cache_info->addr = mo_north_class->mo_class_info->str_addr;
				}
				else if (north_info->protocol_type == N_PROTOCOL_TYPE_IEC104){
					iec_north_class_t *iec_north_class = (iec_north_class_t *)mq_north_class->proto_ptr;
				    dev_cache_info->addr = iec_north_class->iec_class_info->str_addr;
				}
			}
			else{
				 dev_cache_info->addr = addr + 1;
			}
			dev_cache_info->section_indx = 0;
        }
		else{
            int section_indx = _find_section_indx_max(_class_name[index].ptr, _class_name[index].num);
#if 1			
			mq_north_class_t *mq_north_class = (mq_north_class_t *)mq_north_dev->ptr; // 找到设备所属的类信息
			if (north_info->protocol_type == N_PROTOCOL_TYPE_MODBUS_TCP){
				mo_north_class_t *mo_north_class = (mo_north_class_t *)mq_north_class->proto_ptr;
				dev_cache_info->addr = mo_north_class->mo_class_info->str_addr;
			}
			else if (north_info->protocol_type == N_PROTOCOL_TYPE_IEC104){
				iec_north_class_t *iec_north_class = (iec_north_class_t *)mq_north_class->proto_ptr;
				dev_cache_info->addr = iec_north_class->iec_class_info->str_addr;
			}
#endif				
            if (section_indx == -1){
                dev_cache_info->section_indx = 0;
            }
            else{
                dev_cache_info->section_indx = section_indx + 1;
            }
        }
		_class_name[index].ptr[_class_name[index].num] = dev_cache_info; //>>保存dev地址信息
		_class_name[index].num++;
		*dev_cache_ptr = dev_cache_info;
	}

    return 0;
}

static void mq_get_tag_info(mq_north_tag_t* mq_north_tag, char* limit, mo_fun_code_t fun_code, iec_code_t iec_code)
{
    north_info_t* north_info = get_north_info();
#if 1
    if (check_float_is_1(mq_north_tag->tag->scale)){
        mq_north_tag->coefficient = 1;
	}
	else{
        mq_north_tag->coefficient = (double)(1.0 / mq_north_tag->tag->scale); //>>还原精度
    }
#endif
	//mq_north_tag->coefficient = 1;  //>>默认精度为1，此参数不用

    if ((strcmp(limit, "ro") == 0) || (strcmp(limit, "sys") == 0))
        mq_north_tag->limit = 0;
    else
        mq_north_tag->limit = 1;

    /*************/
    if (north_info->protocol_type == N_PROTOCOL_TYPE_MQTT)
    {
        ;
    }
    else if (north_info->protocol_type == N_PROTOCOL_TYPE_MODBUS_TCP)
    {
        // mo_class_info_t *mo_class_info = NULL;
        mq_north_dev_t* mq_north_dev = (mq_north_dev_t*)mq_north_tag->ptr; //找到tag所属的设备信息
        mo_north_tag_t* mo_north_tag = calloc(sizeof(mo_north_tag_t), 1);

        mo_proto_info_t* mo_proto_info = get_mo_proto_info();

        int p_compatible_id = 0;
        int index           = mo_match_by_class_type(&(mq_north_dev->class_type), mo_proto_info->mo_class_info, &p_compatible_id, 0);
        
        // 特殊处理EMS设备，确保即使class_type匹配失败也能设置proto_ptr
        if (index == -1 && strcmp(mq_north_dev->no, "EMS") == 0) {
            // 使用已经分配的mo_north_tag，初始化默认值
            mo_north_tag->function_code  = fun_code;
            mo_north_tag->addr           = 0; // 默认地址，根据需要调整
            mo_north_tag->data_type      = TYPE_FLOAT; // 默认数据类型，根据需要调整
            mo_north_tag->data_order     = ORDER_ABCD;
            mo_north_tag->coefficient    = 1.0;
            
            // 直接设置proto_ptr，跳过class_type匹配
            mq_north_tag->proto_ptr = mo_north_tag;
            goto end;
        }
        
        if (index == -1)
        {
            free(mo_north_tag);
            goto end;
        }
        else
        {
            // mo_class_info = &(mo_proto_info->mo_class_info[index]);
        }
        mo_north_tag->function_code  = fun_code;
        mo_north_dev_t* mo_north_dev = (mo_north_dev_t*)mq_north_dev->proto_ptr;
		if (fun_code == X_CODE_TYPE)
		{
			mo_north_tag->addr        = mo_proto_info->start_bits + mo_north_dev->section_indx * MODBUS_RESERVE + mo_north_dev->nb_bits;
			mo_north_tag->data_type   = TYPE_BOOL;
			mo_north_tag->data_order  = ORDER_A;
			//mo_north_tag->coefficient = 1.0;

			mo_north_dev->nb_bits++;
			//mo_class_info->nb_bits++;//
		}
		else if (fun_code == L_CODE_TYPE)
		{
			mo_north_tag->addr        = mo_proto_info->start_input_bits + mo_north_dev->section_indx * MODBUS_RESERVE + mo_north_dev->nb_input_bits;
			mo_north_tag->data_type   = TYPE_BOOL;
			mo_north_tag->data_order  = ORDER_A;
			//mo_north_tag->coefficient = 1.0;

			mo_north_dev->nb_input_bits++;
			//mo_class_info->nb_input_bits++;//
		}
		else if (fun_code == B_CODE_TYPE)
		{
			mo_north_tag->addr = mo_proto_info->start_registers + mo_north_dev->section_indx * MODBUS_RESERVE + mo_north_dev->nb_registers;
			if (mq_north_tag->tag->data_type == 0){
				mo_north_tag->data_type  = TYPE_INT;
			}
			else if (mq_north_tag->tag->data_type == 1 && (check_float_is_1(mq_north_tag->tag->scale) == TRUE || (mq_north_tag->tag->scale > 1.00001f || mq_north_tag->tag->scale < -1.00001f))){
				mo_north_tag->data_type  = TYPE_FLOAT;
			}
			else if (mq_north_tag->tag->data_type == 1 && ((mq_north_tag->tag->scale > -0.9999f && mq_north_tag->tag->scale < 0.00f) || (mq_north_tag->tag->scale > 0.00f && mq_north_tag->tag->scale < 0.9999f))){
				mo_north_tag->data_type  = TYPE_INT;
			}
			mo_north_tag->data_order = ORDER_ABCD; // 固定2个寄存器
			//mo_north_tag->coefficient = 1.0;

			mo_north_dev->nb_registers += 2;
			//mo_class_info->nb_registers += 2;//
		}
		else if (fun_code == S_CODE_TYPE)
		{
			mo_north_tag->addr = mo_proto_info->start_input_registers + mo_north_dev->section_indx * MODBUS_RESERVE + mo_north_dev->nb_input_registers;
			if (mq_north_tag->tag->data_type == 0){
				mo_north_tag->data_type  = TYPE_INT;
			}
			else if (mq_north_tag->tag->data_type == 1 && (check_float_is_1(mq_north_tag->tag->scale) == TRUE || (mq_north_tag->tag->scale > 1.00001f || mq_north_tag->tag->scale < -1.00001f))){
				mo_north_tag->data_type  = TYPE_FLOAT;
			}
			else if (mq_north_tag->tag->data_type == 1 && ((mq_north_tag->tag->scale > -0.9999f && mq_north_tag->tag->scale < 0.00f) || (mq_north_tag->tag->scale > 0.00f && mq_north_tag->tag->scale < 0.9999f))){
				mo_north_tag->data_type  = TYPE_INT;
			}
			mo_north_tag->data_order = ORDER_ABCD; // 固定2个寄存器
			//mo_north_tag->coefficient = 1.0;

			mo_north_dev->nb_input_registers += 2;
			//mo_class_info->nb_input_registers += 2;//
		}
        mq_north_tag->proto_ptr = mo_north_tag;
    }
    else if (north_info->protocol_type == N_PROTOCOL_TYPE_IEC104)
    {
        // iec_class_info_t *iec_class_info = NULL;
        mq_north_dev_t*  mq_north_dev  = (mq_north_dev_t*)mq_north_tag->ptr; //找到tag所属的设备信息
        iec_north_tag_t* iec_north_tag = calloc(sizeof(iec_north_tag_t), 1);

        iec_proto_info_t* iec_proto_info = get_iec104_proto_info();

        int p_compatible_id = 0;
        int index           = iec_match_by_class_type(&(mq_north_dev->class_type), iec_proto_info->iec_class_info, &p_compatible_id, 0);
        
        // 特殊处理EMS设备，确保即使class_type匹配失败也能设置proto_ptr
        if (index == -1 && strcmp(mq_north_dev->no, "EMS") == 0) {
            // 使用已经分配的iec_north_tag，初始化默认值
            iec_north_tag->addr           = 0; // 默认地址
            iec_north_tag->addr_S         = 0; // 默认遥测地址
            iec_north_tag->addr_P         = 0; // 默认遥信地址
            iec_north_tag->data_type      = TYPE_FLOAT; // 默认数据类型
            iec_north_tag->changeReport   = 1;
            iec_north_tag->coefficient    = 1.0;
            
            // 直接设置proto_ptr，跳过class_type匹配
            mq_north_tag->proto_ptr = iec_north_tag;
            goto end;
        }
        
        if (index == -1)
        {
            free(iec_north_tag);
            goto end;
        }
        else
        {
            // iec_class_info = &(iec_proto_info->iec_class_info[index]);
        }

        iec_north_dev_t* iec_north_dev = (iec_north_dev_t*)mq_north_dev->proto_ptr;
		if (iec_code == RP_CODE)
		{
			iec_north_tag->addr_P       = iec_proto_info->start_RemotePoint + iec_north_dev->section_indx * IEC104_RP_RESERVE + iec_north_dev->nb_rp;
			iec_north_tag->data_type    = TYPE_BOOL;
			iec_north_tag->changeReport = 1;
			iec_north_tag->coefficient  = 1.0;

			iec_north_dev->nb_rp++;
			//iec_class_info->nb_rp++;//
		}
		else if (iec_code == RM_CODE)
		{
			iec_north_tag->addr_S       = iec_proto_info->start_RemoteMeas + iec_north_dev->section_indx * IEC104_RM_RESERVE + iec_north_dev->nb_rm;
			iec_north_tag->data_type    = (mq_north_tag->tag->data_type == 0) ? TYPE_SHORT : TYPE_FLOAT;
			iec_north_tag->changeReport = 1;
			iec_north_tag->coefficient  = 1.0;

			iec_north_dev->nb_rm++;
			//iec_class_info->nb_rm++;//
		}
		else if (iec_code == RC_CODE)
		{
			iec_north_tag->addr         = iec_proto_info->start_RemoteCtrl + iec_north_dev->section_indx * IEC104_RC_RESERVE + iec_north_dev->nb_rc;
			iec_north_tag->data_type    = TYPE_BOOL;
			iec_north_tag->changeReport = 1;
			iec_north_tag->coefficient  = 1.0;

			iec_north_dev->nb_rc++;
			//iec_class_info->nb_rc++;//

			// 遥控点位需在遥信里面占位（上报）
			iec_north_tag->addr_P = iec_proto_info->start_RemotePoint + iec_north_dev->section_indx * IEC104_RP_RESERVE + iec_north_dev->nb_rp;
			iec_north_dev->nb_rp++; //
		}
		else if (iec_code == RR_CODE)
		{
			iec_north_tag->addr         = iec_proto_info->start_RemoteRegu + iec_north_dev->section_indx * IEC104_RR_RESERVE + iec_north_dev->nb_rr;
			iec_north_tag->data_type    = (mq_north_tag->tag->data_type == 0) ? TYPE_SHORT : TYPE_FLOAT;
			iec_north_tag->changeReport = 1;
			iec_north_tag->coefficient  = 1.0;

			iec_north_dev->nb_rr++;
			//iec_class_info->nb_rr++;//

			// **遥调点位需在遥测里面占位（上报）**
			iec_north_tag->addr_S = iec_proto_info->start_RemoteMeas + iec_north_dev->section_indx * IEC104_RM_RESERVE + iec_north_dev->nb_rm;
			iec_north_dev->nb_rm++;
			//iec_class_info->nb_rm++;//
		}
        mq_north_tag->proto_ptr = iec_north_tag;
    }
end:;
    /***********************************************************************/
}

static int mq_tag_add_to_dev(device_t* dev, mq_north_dev_t* mq_north_dev, mq_north_tag_sort_t* sort_list)
{
    if (dev == NULL || mq_north_dev == NULL) {
        ems_syslog(LOG_ERR, "mq_tag_add_to_dev: dev or mq_north_dev is NULL");
        return -1;
    }

    north_info_t* north_info = get_north_info();
    ems_syslog(LOG_NOTICE, "mq_tag_add_to_dev: processing device '%s' with dev_type '%s'", dev->no, dev->dev_type);
    
    /*************/
    mo_north_dev_t*  mo_north_dev  = NULL;
    iec_north_dev_t* iec_north_dev = NULL;
    if (north_info->protocol_type == N_PROTOCOL_TYPE_MQTT)
    {
        ;
    }
    else if (north_info->protocol_type == N_PROTOCOL_TYPE_MODBUS_TCP)
    {
        mo_north_dev = (mo_north_dev_t*)mq_north_dev->proto_ptr;
        if (mo_north_dev == NULL) {
            ems_syslog(LOG_ERR, "mq_tag_add_to_dev: mo_north_dev is NULL");
            return -1;
        }
    }
    else if (north_info->protocol_type == N_PROTOCOL_TYPE_IEC104)
    {
        iec_north_dev = (iec_north_dev_t*)mq_north_dev->proto_ptr;
        if (iec_north_dev == NULL) {
            ems_syslog(LOG_ERR, "mq_tag_add_to_dev: iec_north_dev is NULL");
            return -1;
        }
    }
    /********* 128 ******** 32 ****** || ********************其他******************************************* 点位规划示意图 */
	// 加载固定点位 (固定点位一定不在黑名单里面)
    if (sort_list != NULL){
        ems_syslog(LOG_NOTICE, "mq_tag_add_to_dev: using sort_list with %d tags for device '%s'", sort_list->size, dev->no);
        
        // 打印所有固定点位名称
        for (int i = 0; i < sort_list->size; i++) {
            ems_syslog(LOG_NOTICE, "mq_tag_add_to_dev: sort_list->sort_tags[%d].name = '%s'", i, sort_list->sort_tags[i].name);
        }
        
		// 1. 固定点位排序 最大128 （读写---> EMS）
        ems_syslog(LOG_NOTICE, "mq_tag_add_to_dev: copying %d fixed tags to mq_north_dev->fix_tags", sort_list->size);
		memcpy(mq_north_dev->fix_tags, sort_list->sort_tags, sort_list->size * sizeof(tag_t));

        for (int i = 0; i < sort_list->size; i++)
        {
            ems_syslog(LOG_DEBUG, "mq_tag_add_to_dev: processing tag[%d] '%s' for device '%s'", i, mq_north_dev->fix_tags[i].name, dev->no);
            
			if (mq_north_dev->num >= TAG_NUM) {
                ems_syslog(LOG_WARNING, "mq_tag_add_to_dev: tag count reached limit %d, breaking", TAG_NUM);
                break;
            }
            
			if (mq_north_dev->mq_north_tag[mq_north_dev->num] == NULL) {
                mq_north_dev->mq_north_tag[mq_north_dev->num] = calloc(sizeof(mq_north_tag_t), 1);
                ems_syslog(LOG_DEBUG, "mq_tag_add_to_dev: allocated new mq_north_tag_t at index %d", mq_north_dev->num);
            }

			if (mq_north_dev->mq_north_tag[mq_north_dev->num] == NULL) {
                ems_syslog(LOG_ERR, "mq_tag_add_to_dev: failed to allocate mq_north_tag_t at index %d", mq_north_dev->num);
                continue;
            }
            
			mq_north_dev->mq_north_tag[mq_north_dev->num]->ptr = mq_north_dev;
			tag_t *tag = &(mq_north_dev->fix_tags[i]);
			snprintf(tag->dev_tag_name, sizeof(tag->dev_tag_name), "%s.%s", mq_north_dev->no, tag->name); //TAG_NAME
			mq_north_dev->mq_north_tag[mq_north_dev->num]->tag = &(mq_north_dev->fix_tags[i]);
            
            ems_syslog(LOG_NOTICE, "mq_tag_add_to_dev: added tag '%s' to mq_north_dev->mq_north_tag[%d]", tag->name, mq_north_dev->num);
            
			mq_north_dev->num++;
        }
        
        ems_syslog(LOG_NOTICE, "mq_tag_add_to_dev: after processing fixed tags, num = %d", mq_north_dev->num);
		mq_north_dev->num = SORT_LIMIT; 
        /*****************************************************************/
        if (sort_list->special_list != NULL){
			// 2. 特殊点位排序 最大32 （只读---> EMS）
			special_list_t *special_list = sort_list->special_list;
			memcpy(&(mq_north_dev->fix_tags[SORT_LIMIT]), special_list->sort_tags, special_list->size * sizeof(tag_t));

			for (int i = 0; i < special_list->size; i++)
			{
				if (mq_north_dev->num >= TAG_NUM) break;
				if (mq_north_dev->mq_north_tag[mq_north_dev->num] == NULL)
					mq_north_dev->mq_north_tag[mq_north_dev->num] = calloc(sizeof(mq_north_tag_t), 1);

				if (mq_north_dev->mq_north_tag[mq_north_dev->num] == NULL) continue;
				mq_north_dev->mq_north_tag[mq_north_dev->num]->ptr = mq_north_dev;
				tag_t *tag = &(mq_north_dev->fix_tags[SORT_LIMIT + i]);
				snprintf(tag->dev_tag_name, sizeof(tag->dev_tag_name), "%s.%s", mq_north_dev->no, tag->name); //TAG_NAME
				mq_north_dev->mq_north_tag[mq_north_dev->num]->tag = &(mq_north_dev->fix_tags[SORT_LIMIT + i]);
				mq_north_dev->num++;
			}
			mq_north_dev->num = SORT_LIMIT + SPECIAL_LIMIT; 
	    }
	}

    // ****************************** 版本2.0：仅使用配置文件中的点位，不再新增其他点位 ***********************************
    if (north_info->need_add_version && strcmp(mq_north_dev->no, "EMS") == 0) {
        ems_syslog(LOG_NOTICE, "mq_tag_add_to_dev: need_add_version is 1 and device is EMS, only using config file tags");
        
        // 激活配置文件中的点位，设置active为0，并从设备中获取disp_name
        for (int i = 0; i < mq_north_dev->num; i++) {
            if (mq_north_dev->mq_north_tag[i] == NULL || mq_north_dev->mq_north_tag[i]->tag == NULL) continue;
            
            // 激活点位
            mq_north_dev->mq_north_tag[i]->tag->active = 0;
            
            // 从设备中查找对应的点位，获取disp_name和desc
            // 遍历只读点位
            for (int j = 0; j < dev->tags.ro_tags_size; j++) {
                if (strcmp(mq_north_dev->mq_north_tag[i]->tag->name, dev->tags.ro_tags[j]->name) == 0) {
                    strncpy(mq_north_dev->mq_north_tag[i]->tag->disp_name, dev->tags.ro_tags[j]->disp_name, sizeof(mq_north_dev->mq_north_tag[i]->tag->disp_name));
                    mq_north_dev->mq_north_tag[i]->tag->desc = dev->tags.ro_tags[j]->desc;
                    break;
                }
            }
            
            // 遍历系统点位
            if (mq_north_dev->mq_north_tag[i]->tag->desc == NULL) {
                for (int j = 0; j < dev->tags.sys_info_tags_size; j++) {
                    if (strcmp(mq_north_dev->mq_north_tag[i]->tag->name, dev->tags.sys_info_tags[j]->name) == 0) {
                        strncpy(mq_north_dev->mq_north_tag[i]->tag->disp_name, dev->tags.sys_info_tags[j]->disp_name, sizeof(mq_north_dev->mq_north_tag[i]->tag->disp_name));
                        mq_north_dev->mq_north_tag[i]->tag->desc = dev->tags.sys_info_tags[j]->desc;
                        break;
                    }
                }
            }
            
            // 遍历读写点位
            if (mq_north_dev->mq_north_tag[i]->tag->desc == NULL) {
                for (int j = 0; j < dev->tags.rw_tags_size; j++) {
                    if (strcmp(mq_north_dev->mq_north_tag[i]->tag->name, dev->tags.rw_tags[j]->name) == 0) {
                        strncpy(mq_north_dev->mq_north_tag[i]->tag->disp_name, dev->tags.rw_tags[j]->disp_name, sizeof(mq_north_dev->mq_north_tag[i]->tag->disp_name));
                        mq_north_dev->mq_north_tag[i]->tag->desc = dev->tags.rw_tags[j]->desc;
                        break;
                    }
                }
            }
        }
        
        // 为EMS标签设置proto_ptr并添加到相应的协议数组中
        for (int i = 0; i < SORT_LIMIT; i++) {
            mq_north_tag_t* t = mq_north_dev->mq_north_tag[i];
            if (t == NULL) continue;
            
            /************0 realdata; 1 system; 2 alarm */
            if (north_info->protocol_type == N_PROTOCOL_TYPE_MQTT) {
                mq_get_tag_info(t, "rw", N_CODE_TYPE, N_CODE);
            } else if (north_info->protocol_type == N_PROTOCOL_TYPE_MODBUS_TCP) {
                // 为Modbus标签设置proto_ptr并添加到hold_tag数组
                mo_north_dev->hold_tag[mo_north_dev->nb_hold] = t;
                mq_get_tag_info(t, "rw", B_CODE_TYPE, N_CODE); // 保持寄存器(可读可写)
                mo_north_dev->nb_hold++;
            } else if (north_info->protocol_type == N_PROTOCOL_TYPE_IEC104) {
                // 先记录当前计数器值，避免mq_get_tag_info内部的遥测占位导致地址间隔
                int current_nb_rm = iec_north_dev->nb_rm;
                
                // 为IEC104标签设置proto_ptr，mq_get_tag_info内部会增加计数器
                mq_get_tag_info(t, "rw", N_CODE_TYPE, RR_CODE); // 遥调
                iec_north_dev->rr_tag[iec_north_dev->nb_rr - 1] = t;
                iec_north_dev->rm_tag[current_nb_rm] = t;
                iec_north_dev->nb_rm = current_nb_rm + 1;
            }
        }

        for (int i = SORT_LIMIT; i < mq_north_dev->num; i++)
        {
            mq_north_tag_t* t = mq_north_dev->mq_north_tag[i];
            if (t == NULL) continue;
            /************0 realdata; 1 system; 2 alarm */
            if (north_info->protocol_type == N_PROTOCOL_TYPE_MQTT)
            {
                mq_get_tag_info(t, "ro", N_CODE_TYPE, N_CODE);
            }
            else if (north_info->protocol_type == N_PROTOCOL_TYPE_MODBUS_TCP)
            {
                if (t->tag->property == 0)
                {
                    mo_north_dev->inputr_tag[mo_north_dev->nb_inputr] = t;
                    mq_get_tag_info(t, "ro", S_CODE_TYPE, N_CODE);  // 输入寄存器
                    mo_north_dev->nb_inputr++;
                }
                if (t->tag->property == 1 || t->tag->property == 2)
                {
                    mo_north_dev->inputb_tag[mo_north_dev->nb_inputb] = t;
                    mq_get_tag_info(t, "ro", L_CODE_TYPE, N_CODE);  // 离散量输入
                    mo_north_dev->nb_inputb++;
                }
            }
            else if (north_info->protocol_type == N_PROTOCOL_TYPE_IEC104)
            {
                if (t->tag->property == 0)
                {
                    iec_north_dev->rm_tag[iec_north_dev->nb_rm] = t;
                    mq_get_tag_info(t, "ro", N_CODE_TYPE, RM_CODE); // 遥测
                }
                if (t->tag->property == 1 || t->tag->property == 2)
                {
                    iec_north_dev->rp_tag[iec_north_dev->nb_rp] = t;
                    mq_get_tag_info(t, "ro", N_CODE_TYPE, RP_CODE); // 遥信
                }
            }
        }
        
        // 直接返回，不再添加其他点位
        return 0;
    }

    // ****************************** 由于EMS固定点位是 RW，需提前创建 *********************************** start
    if (strcmp(mq_north_dev->no, "EMS") == 0)
    { 
        for (int i = 0; i < SORT_LIMIT; i++)
        {
            mq_north_tag_t* t = mq_north_dev->mq_north_tag[i];
            if (t == NULL) continue;

            /************0 realdata; 1 system; 2 alarm */
            if (north_info->protocol_type == N_PROTOCOL_TYPE_MQTT)
            {
                mq_get_tag_info(mq_north_dev->mq_north_tag[i], "rw", N_CODE_TYPE, N_CODE);
            }
            else if (north_info->protocol_type == N_PROTOCOL_TYPE_MODBUS_TCP)
            {
                if (dev->tags.rw_tags[i]->property == 0) // realdata
                {
                    mo_north_dev->hold_tag[mo_north_dev->nb_hold] = mq_north_dev->mq_north_tag[i];
                    mq_get_tag_info(mq_north_dev->mq_north_tag[i], "rw", B_CODE_TYPE, N_CODE); // 保持寄存器(可读可写)
                    mo_north_dev->nb_hold++;
                }
                if (dev->tags.rw_tags[i]->property == 1 || dev->tags.rw_tags[i]->property == 2) // system alarm，当前所有设备模版此条件均不满足（即：设计中无线圈-统一保持寄存器）
                {
                    mo_north_dev->coil_tag[mo_north_dev->nb_coil] = mq_north_dev->mq_north_tag[i];
                    mq_get_tag_info(mq_north_dev->mq_north_tag[i], "rw", X_CODE_TYPE, N_CODE); // 线圈(可读可写)
                    mo_north_dev->nb_coil++;
                }
                else
                    ;
            }
            else if (north_info->protocol_type == N_PROTOCOL_TYPE_IEC104)
            {
                if (dev->tags.rw_tags[i]->property == 0)
                {
                    iec_north_dev->rr_tag[iec_north_dev->nb_rr] = mq_north_dev->mq_north_tag[i];
					//******
                    iec_north_dev->rm_tag[iec_north_dev->nb_rm] = mq_north_dev->mq_north_tag[i];
					//******
                    mq_get_tag_info(mq_north_dev->mq_north_tag[i], "rw", N_CODE_TYPE, RR_CODE); // 遥调
                }
                if (dev->tags.rw_tags[i]->property == 1 || dev->tags.rw_tags[i]->property == 2) // system alarm，当前所有设备模版此条件均不满足（即：设计中无遥控-统一遥调）
                {
                    iec_north_dev->rc_tag[iec_north_dev->nb_rc] = mq_north_dev->mq_north_tag[i];
					//******
                    iec_north_dev->rp_tag[iec_north_dev->nb_rp] = mq_north_dev->mq_north_tag[i];
					//******
                    mq_get_tag_info(mq_north_dev->mq_north_tag[i], "rw", N_CODE_TYPE, RC_CODE); // 遥控
                }
                else
                    ;
            }
        }
    }	
    // ****************************** 由于EMS固定点位是 RW，需提前创建 *********************************** end

    // 只读点位
    for (int i = 0; i < dev->tags.ro_tags_size; i++)
    {
		if (sort_list != NULL){
			int is_blacklist = find_blacklist(sort_list->black_list, dev->tags.ro_tags[i]->name);
			if (is_blacklist) continue;

			int find = 0;
			for (int t = 0; t < sort_list->size; t++)
			{
				if (strcmp(dev->tags.ro_tags[i]->name, sort_list->sort_tags[t].name) == 0){
					mq_north_dev->fix_tags[t].active = 0; // "激活"
					strncpy(mq_north_dev->fix_tags[t].disp_name, dev->tags.ro_tags[i]->disp_name, sizeof(mq_north_dev->fix_tags[t].disp_name));
					mq_north_dev->fix_tags[t].desc = dev->tags.ro_tags[i]->desc;
					find = 1;
					break;
				}
			}
			if (sort_list->special_list != NULL && find == 0){
				special_list_t *special_list = sort_list->special_list;
				for (int t = 0; t < special_list->size; t++)
				{
					if (strcmp(dev->tags.ro_tags[i]->name, special_list->sort_tags[t].name) == 0){
						mq_north_dev->fix_tags[SORT_LIMIT + t].active = 0; // "激活"
						strncpy(mq_north_dev->fix_tags[SORT_LIMIT + t].disp_name, dev->tags.ro_tags[i]->disp_name, sizeof(mq_north_dev->fix_tags[SORT_LIMIT + t].disp_name));
						mq_north_dev->fix_tags[SORT_LIMIT + t].desc = dev->tags.ro_tags[i]->desc;
						find = 1;
						break;
					}
				}				
			}
			if (find) continue;
		}

        if (mq_north_dev->num >= TAG_NUM) break;
        if (mq_north_dev->mq_north_tag[mq_north_dev->num] == NULL)
            mq_north_dev->mq_north_tag[mq_north_dev->num] = calloc(sizeof(mq_north_tag_t), 1);

        if (mq_north_dev->mq_north_tag[mq_north_dev->num] == NULL) continue;
        mq_north_dev->mq_north_tag[mq_north_dev->num]->ptr = mq_north_dev;

        mq_north_dev->mq_north_tag[mq_north_dev->num]->tag = dev->tags.ro_tags[i];
        snprintf(mq_north_dev->mq_north_tag[mq_north_dev->num]->tag->dev_tag_name, sizeof(mq_north_dev->mq_north_tag[mq_north_dev->num]->tag->dev_tag_name), "%s.%s", mq_north_dev->no, mq_north_dev->mq_north_tag[mq_north_dev->num]->tag->name);
        mq_north_dev->num++;
    }

	// 系统点位
    for (int i = 0; i < dev->tags.sys_info_tags_size; i++)
    {
        if (strstr(dev->tags.sys_info_tags[i]->dev_tag_name, STATE_ONLINE) == NULL){
            continue;
		}

		if (sort_list != NULL){
			int is_blacklist = find_blacklist(sort_list->black_list, dev->tags.sys_info_tags[i]->name);
			if (is_blacklist) continue;

			int find = 0;
			for (int t = 0; t < sort_list->size; t++)
			{
				if (strcmp(dev->tags.sys_info_tags[i]->name, sort_list->sort_tags[t].name) == 0){
					mq_north_dev->fix_tags[t].active = 0;
					strncpy(mq_north_dev->fix_tags[t].disp_name, dev->tags.sys_info_tags[i]->disp_name, sizeof(mq_north_dev->fix_tags[t].disp_name));
					mq_north_dev->fix_tags[t].desc =  dev->tags.sys_info_tags[i]->desc;
					find = 1;
					break;
				}
			}
			if (sort_list->special_list != NULL && find == 0){
				special_list_t *special_list = sort_list->special_list;
				for (int t = 0; t < special_list->size; t++)
				{
					if (strcmp(dev->tags.sys_info_tags[i]->name, special_list->sort_tags[t].name) == 0){
						mq_north_dev->fix_tags[SORT_LIMIT + t].active = 0; // "激活"
						strncpy(mq_north_dev->fix_tags[SORT_LIMIT + t].disp_name, dev->tags.sys_info_tags[i]->disp_name, sizeof(mq_north_dev->fix_tags[SORT_LIMIT + t].disp_name));
						mq_north_dev->fix_tags[SORT_LIMIT + t].desc = dev->tags.sys_info_tags[i]->desc;
						find = 1;
						break;
					}
				}				
			}
			if (find) continue;
		}

        if (mq_north_dev->num >= TAG_NUM) break;
        if (mq_north_dev->mq_north_tag[mq_north_dev->num] == NULL)
            mq_north_dev->mq_north_tag[mq_north_dev->num] = calloc(sizeof(mq_north_tag_t), 1);

        if (mq_north_dev->mq_north_tag[mq_north_dev->num] == NULL) continue;
        mq_north_dev->mq_north_tag[mq_north_dev->num]->ptr = mq_north_dev;
        mq_north_dev->mq_north_tag[mq_north_dev->num]->tag = dev->tags.sys_info_tags[i];
		mq_north_dev->num++;
    }

	if (strcmp(mq_north_dev->no, "EMS") != 0){  // 普通设备RW点位需特殊处理
		// 读写点位
		for (int i = 0; i < dev->tags.rw_tags_size; i++)
		{
			if (sort_list != NULL){
				int is_blacklist = find_blacklist(sort_list->black_list, dev->tags.rw_tags[i]->name);
				if (is_blacklist) continue;

				int find = 0;
				for (int t = 0; t < sort_list->size; t++)
				{
					if (strcmp(dev->tags.rw_tags[i]->name, sort_list->sort_tags[t].name) == 0){
						mq_north_dev->fix_tags[t].active = 0;
						strncpy(mq_north_dev->fix_tags[t].disp_name, dev->tags.rw_tags[i]->disp_name, sizeof(mq_north_dev->fix_tags[t].disp_name));
						mq_north_dev->fix_tags[t].desc =  dev->tags.rw_tags[i]->desc;
						find = 1;
						break;
					}
				}
				if (find) continue;
			}

			if (mq_north_dev->num >= TAG_NUM) break;
			if (mq_north_dev->mq_north_tag[mq_north_dev->num] == NULL)
				mq_north_dev->mq_north_tag[mq_north_dev->num] = calloc(sizeof(mq_north_tag_t), 1);

			if (mq_north_dev->mq_north_tag[mq_north_dev->num] == NULL) continue;
			mq_north_dev->mq_north_tag[mq_north_dev->num]->ptr = mq_north_dev;
			mq_north_dev->mq_north_tag[mq_north_dev->num]->tag = dev->tags.rw_tags[i];
			mq_north_dev->num++;
		}
	}

    // 注意::::：普通设备不提供：MODBUS线圈&保持寄存器  和  IEC104遥控&遥调
	int _i = 0;
	if (strcmp(mq_north_dev->no, "EMS") == 0){
        _i = SORT_LIMIT;
	}
	
    for (int i = _i; i < mq_north_dev->num; i++)
    {
        mq_north_tag_t* t = mq_north_dev->mq_north_tag[i];
        if (t == NULL) continue;
        /************0 realdata; 1 system; 2 alarm */
        if (north_info->protocol_type == N_PROTOCOL_TYPE_MQTT)
        {
            mq_get_tag_info(t, "ro", N_CODE_TYPE, N_CODE);
        }
        else if (north_info->protocol_type == N_PROTOCOL_TYPE_MODBUS_TCP)
        {
            if (t->tag->property == 0)
            {
                mo_north_dev->inputr_tag[mo_north_dev->nb_inputr] = t;
                mq_get_tag_info(t, "ro", S_CODE_TYPE, N_CODE);  // 输入寄存器
                mo_north_dev->nb_inputr++;
            }
            if (t->tag->property == 1 || t->tag->property == 2)
            {
                mo_north_dev->inputb_tag[mo_north_dev->nb_inputb] = t;
                mq_get_tag_info(t, "ro", L_CODE_TYPE, N_CODE);  // 离散量输入
                mo_north_dev->nb_inputb++;
            }
        }
        else if (north_info->protocol_type == N_PROTOCOL_TYPE_IEC104)
        {
            if (t->tag->property == 0)
            {
                iec_north_dev->rm_tag[iec_north_dev->nb_rm] = t;
                mq_get_tag_info(t, "ro", N_CODE_TYPE, RM_CODE); // 遥测
            }
            if (t->tag->property == 1 || t->tag->property == 2)
            {
                iec_north_dev->rp_tag[iec_north_dev->nb_rp] = t;
                mq_get_tag_info(t, "ro", N_CODE_TYPE, RP_CODE); // 遥信
            }
        }
    }

#if 1
    //>>>>>>>>>> EMS开放写点位 <<<<<<<<<<<<<   MODBUS开放线圈&保持寄存器   IEC104开放遥控&遥调
    if (strcmp(mq_north_dev->no, "EMS") == 0)
    { 
        for (int i = 0; i < dev->tags.rw_tags_size; i++)
        {
			if (sort_list != NULL){
				int is_blacklist = find_blacklist(sort_list->black_list, dev->tags.rw_tags[i]->name);
				if (is_blacklist) continue;

				int find = 0;
				for (int t = 0; t < sort_list->size; t++)
				{
					if (strcmp(dev->tags.rw_tags[i]->name, sort_list->sort_tags[t].name) == 0){
						mq_north_dev->fix_tags[t].active = 0;
						strncpy(mq_north_dev->fix_tags[t].disp_name, dev->tags.rw_tags[i]->disp_name, sizeof(mq_north_dev->fix_tags[t].disp_name));
						mq_north_dev->fix_tags[t].desc =  dev->tags.rw_tags[i]->desc;
						find = 1;
						break;
					}
				}
				if (find) continue;
			}

            if (mq_north_dev->num >= TAG_NUM) break;
            if (mq_north_dev->mq_north_tag[mq_north_dev->num] == NULL)
                mq_north_dev->mq_north_tag[mq_north_dev->num] = calloc(sizeof(mq_north_tag_t), 1);

            if (mq_north_dev->mq_north_tag[mq_north_dev->num] == NULL) continue;
            mq_north_dev->mq_north_tag[mq_north_dev->num]->ptr = mq_north_dev;
            mq_north_dev->mq_north_tag[mq_north_dev->num]->tag = dev->tags.rw_tags[i];

            /************0 realdata; 1 system; 2 alarm */
            if (north_info->protocol_type == N_PROTOCOL_TYPE_MQTT)
            {
                mq_get_tag_info(mq_north_dev->mq_north_tag[mq_north_dev->num], "rw", N_CODE_TYPE, N_CODE);
            }
            else if (north_info->protocol_type == N_PROTOCOL_TYPE_MODBUS_TCP)
            {
                if (dev->tags.rw_tags[i]->property == 0) // realdata
                {
                    mo_north_dev->hold_tag[mo_north_dev->nb_hold] = mq_north_dev->mq_north_tag[mq_north_dev->num];
                    mq_get_tag_info(mq_north_dev->mq_north_tag[mq_north_dev->num], "rw", B_CODE_TYPE, N_CODE); // 保持寄存器(可读可写)
                    mo_north_dev->nb_hold++;
                }
                if (dev->tags.rw_tags[i]->property == 1 || dev->tags.rw_tags[i]->property == 2) // system alarm，当前所有设备模版此条件均不满足（即：设计中无线圈-统一保持寄存器）
                {
                    mo_north_dev->coil_tag[mo_north_dev->nb_coil] = mq_north_dev->mq_north_tag[mq_north_dev->num];
                    mq_get_tag_info(mq_north_dev->mq_north_tag[mq_north_dev->num], "rw", X_CODE_TYPE, N_CODE); // 线圈(可读可写)
                    mo_north_dev->nb_coil++;
                }
                else
                    ;
            }
            else if (north_info->protocol_type == N_PROTOCOL_TYPE_IEC104)
            {
                if (dev->tags.rw_tags[i]->property == 0)
                {
                    iec_north_dev->rr_tag[iec_north_dev->nb_rr] = mq_north_dev->mq_north_tag[mq_north_dev->num];
					//******
                    iec_north_dev->rm_tag[iec_north_dev->nb_rm] = mq_north_dev->mq_north_tag[mq_north_dev->num];
					//******
                    mq_get_tag_info(mq_north_dev->mq_north_tag[mq_north_dev->num], "rw", N_CODE_TYPE, RR_CODE); // 遥调
                }
                if (dev->tags.rw_tags[i]->property == 1 || dev->tags.rw_tags[i]->property == 2) // system alarm，当前所有设备模版此条件均不满足（即：设计中无遥控-统一遥调）
                {
                    iec_north_dev->rc_tag[iec_north_dev->nb_rc] = mq_north_dev->mq_north_tag[mq_north_dev->num];
					//******
                    iec_north_dev->rp_tag[iec_north_dev->nb_rp] = mq_north_dev->mq_north_tag[mq_north_dev->num];
					//******
                    mq_get_tag_info(mq_north_dev->mq_north_tag[mq_north_dev->num], "rw", N_CODE_TYPE, RC_CODE); // 遥控
                }
                else
                    ;
            }
            /***********************************************************************/
            mq_north_dev->num++;
        }
    }
#endif

    // 如果存在保存的点位顺序，按照保存的顺序重新生成点位地址
    if (north_info->tag_order_exist && north_info->tag_order_list != NULL && north_info->tag_order_count > 0) {
        ems_syslog(LOG_NOTICE, "mq_tag_add_to_dev: reordering tags and addresses according to saved order");
        
        // 创建临时数组来存储按照保存的顺序排序的点位，大小要足够容纳所有保存的点位（包括已删除的）
        // 但不能超过TAG_NUM的限制
        int total_tags = (mq_north_dev->num > north_info->tag_order_count) ? mq_north_dev->num : north_info->tag_order_count;
        if (total_tags > TOTAL_MAX_TAG_NUM) {
            ems_syslog(LOG_WARNING, "mq_tag_add_to_dev: total_tags %d exceeds TAG_NUM limit %d, truncating", total_tags, TAG_NUM);
            total_tags = TOTAL_MAX_TAG_NUM;
        }
        mq_north_tag_t** temp_tags = (mq_north_tag_t**)malloc(total_tags * sizeof(mq_north_tag_t*));
        if (temp_tags == NULL) {
            ems_syslog(LOG_ERR, "mq_tag_add_to_dev: failed to allocate temp_tags");
        } else {
            // 初始化临时数组为NULL
            memset(temp_tags, 0, total_tags * sizeof(mq_north_tag_t*));
            
            // 创建已处理点位标记数组
            int* processed = (int*)malloc(mq_north_dev->num * sizeof(int));
            if (processed == NULL) {
                ems_syslog(LOG_ERR, "mq_tag_add_to_dev: failed to allocate processed");
                free(temp_tags);
            } else {
                memset(processed, 0, mq_north_dev->num * sizeof(int));
                
                // 第一步：按照保存的顺序遍历点位，处理已存在和已删除的点位
                int temp_index = 0;
                for (int i = 0; i < north_info->tag_order_count && temp_index < total_tags; i++) {
                    // 只处理与当前协议类型匹配的点位
                    if (north_info->tag_order_list[i].protocol_type != north_info->protocol_type) {
                        continue;
                    }
                    
                    // 只处理属于当前设备的点位
                    if (strcmp(north_info->tag_order_list[i].dev_no, mq_north_dev->no) != 0) {
                        continue;
                    }
                    
                    const char* saved_tag_name = north_info->tag_order_list[i].tag_name;
                    int saved_address = north_info->tag_order_list[i].address;
                    
                    // 在当前点位列表中查找匹配的点位
                    int found = 0;
                  
                    for (int j = 0; j < mq_north_dev->num; j++) {
                        if (processed[j]) continue;
                        
                        mq_north_tag_t* tag = mq_north_dev->mq_north_tag[j];
                        if (tag != NULL && tag->tag != NULL && strcmp(tag->tag->name, saved_tag_name) == 0) {
                            temp_tags[temp_index++] = tag;
                            processed[j] = 1;
                            found = 1;
                            break;
                        }
                    }
                    
                    // 如果点位不存在（即被删除了），创建一个无效的点位结构，保留其地址
                    if (!found && temp_index < total_tags) {
                        ems_syslog(LOG_NOTICE, "mq_tag_add_to_dev: tag '%s' not found, creating inactive tag with address %d", saved_tag_name, saved_address);
                        
                        // 创建无效点位的tag结构
                        tag_t* inactive_tag = (tag_t*)calloc(sizeof(tag_t), 1);
                        if (inactive_tag != NULL) {
                            strncpy(inactive_tag->name, saved_tag_name, sizeof(inactive_tag->name));
                            
                            // 使用从tag_order.json文件中读取的原始设备信息
                            const char* dev_no = north_info->tag_order_list[i].dev_no;
                            
                            // 如果从tag_order.json文件中读取的设备信息为空，则使用当前设备的信息
                            if (strlen(dev_no) == 0) {
                                dev_no = mq_north_dev->no;
                            }
                            
                            snprintf(inactive_tag->dev_tag_name, sizeof(inactive_tag->dev_tag_name), "%s.%s", dev_no, saved_tag_name);
                            inactive_tag->active = 1; // 标记为无效
                            inactive_tag->property = 0; // 默认属性
                            inactive_tag->data_type = 0; // 默认数据类型
                            inactive_tag->scale = 1.0; // 默认缩放
                            
                            // 创建mq_north_tag_t结构
                            mq_north_tag_t* inactive_mq_tag = (mq_north_tag_t*)calloc(sizeof(mq_north_tag_t), 1);
                            if (inactive_mq_tag != NULL) {
                                inactive_mq_tag->tag = inactive_tag;
                                inactive_mq_tag->ptr = mq_north_dev;
                                inactive_mq_tag->limit = 0; // 只读
                                inactive_mq_tag->coefficient = 1.0;
                                
                                // 根据协议类型创建相应的协议指针结构，并设置保存的地址
                                if (north_info->protocol_type == N_PROTOCOL_TYPE_MODBUS_TCP) {
                                    mo_north_tag_t* mo_north_tag = (mo_north_tag_t*)calloc(sizeof(mo_north_tag_t), 1);
                                    if (mo_north_tag != NULL) {
                                        mo_north_tag->addr = saved_address;
                                        mo_north_tag->function_code = B_CODE_TYPE; // 默认功能码
                                        mo_north_tag->data_type = TYPE_FLOAT; // 默认数据类型
                                        mo_north_tag->data_order = ORDER_ABCD;
                                        mo_north_tag->coefficient = 1.0;
                                        inactive_mq_tag->proto_ptr = mo_north_tag;
                                    }
                                } else if (north_info->protocol_type == N_PROTOCOL_TYPE_IEC104) {
                                    iec_north_tag_t* iec_north_tag = (iec_north_tag_t*)calloc(sizeof(iec_north_tag_t), 1);
                                    if (iec_north_tag != NULL) {
                                        iec_north_tag->addr_S = saved_address;
                                        iec_north_tag->addr_P = saved_address;
                                        iec_north_tag->addr = saved_address;
                                        iec_north_tag->data_type = TYPE_FLOAT; // 默认数据类型
                                        iec_north_tag->changeReport = 1;
                                        iec_north_tag->coefficient = 1.0;
                                        inactive_mq_tag->proto_ptr = iec_north_tag;
                                    }
                                }
                                
                                // 将无效点位添加到临时数组
                                temp_tags[temp_index++] = inactive_mq_tag;
                            }
                        }
                    }
                }
                
                // 第二步：将剩余的未处理点位添加到临时数组末尾（这些是新增的点位）
                for (int j = 0; j < mq_north_dev->num && temp_index < total_tags; j++) {
                    if (!processed[j]) {
                        mq_north_tag_t* tag = mq_north_dev->mq_north_tag[j];
                        if (tag != NULL) {
                            temp_tags[temp_index++] = tag;
                        }
                    }
                }
                
                // 更新mq_north_dev->num为实际处理的点位数量
                int old_num = mq_north_dev->num;
                mq_north_dev->num = temp_index;
                
                // 第三步：将临时数组中的点位复制回原数组
                int valid_num = 0;
                for (int i = 0; i < mq_north_dev->num && i < TAG_NUM; i++) {
                    if (temp_tags[i] != NULL) {
                        if (i < old_num) {
                            // 覆盖原有位置
                            mq_north_dev->mq_north_tag[i] = temp_tags[i];
                        } else {
                            // 扩展原有数组
                            if (i < temp_index) {
                                mq_north_dev->mq_north_tag[i] = temp_tags[i];
                            } else {
                                ems_syslog(LOG_WARNING, "mq_tag_add_to_dev: tag count reached limit %d, truncating", TAG_NUM);
                                break;
                            }
                        }
                        valid_num++;
                    }
                }
                
                // 更新mq_north_dev->num为实际有效的点位数量
                mq_north_dev->num = valid_num;
                
                // 第四步：重置协议相关的点位计数器，准备按照新顺序处理点位
                if (north_info->protocol_type == N_PROTOCOL_TYPE_MODBUS_TCP && mo_north_dev != NULL) {
                    mo_north_dev->nb_hold = 0;
                    mo_north_dev->nb_inputr = 0;
                    mo_north_dev->nb_coil = 0;
                    mo_north_dev->nb_inputb = 0;
                    
                    // 清空协议数组，准备重新填充
                    if (mo_north_dev->hold_tag != NULL) memset(mo_north_dev->hold_tag, 0, sizeof(mo_north_dev->hold_tag));
                    if (mo_north_dev->inputr_tag != NULL) memset(mo_north_dev->inputr_tag, 0, sizeof(mo_north_dev->inputr_tag));
                    if (mo_north_dev->coil_tag != NULL) memset(mo_north_dev->coil_tag, 0, sizeof(mo_north_dev->coil_tag));
                    if (mo_north_dev->inputb_tag != NULL) memset(mo_north_dev->inputb_tag, 0, sizeof(mo_north_dev->inputb_tag));
                } else if (north_info->protocol_type == N_PROTOCOL_TYPE_IEC104 && iec_north_dev != NULL) {
                    iec_north_dev->nb_rp = 0;
                    iec_north_dev->nb_rm = 0;
                    iec_north_dev->nb_rc = 0;
                    iec_north_dev->nb_rr = 0;
                    
                    // 清空协议数组，准备重新填充
                    if (iec_north_dev->rp_tag != NULL) memset(iec_north_dev->rp_tag, 0, sizeof(iec_north_dev->rp_tag));
                    if (iec_north_dev->rm_tag != NULL) memset(iec_north_dev->rm_tag, 0, sizeof(iec_north_dev->rm_tag));
                    if (iec_north_dev->rc_tag != NULL) memset(iec_north_dev->rc_tag, 0, sizeof(iec_north_dev->rc_tag));
                    if (iec_north_dev->rr_tag != NULL) memset(iec_north_dev->rr_tag, 0, sizeof(iec_north_dev->rr_tag));
                }
                
                // 第五步：按照新的顺序处理点位，对于有效点位使用保存的地址，对于无效点位保持原有地址
                for (int i = 0; i < mq_north_dev->num && i < TAG_NUM; i++) {
                    // 检查索引是否超出范围
                    if (i >= TAG_NUM) {
                        ems_syslog(LOG_WARNING, "mq_tag_add_to_dev: index %d exceeds TAG_NUM limit %d", i, TAG_NUM);
                        break;
                    }
                    
                    mq_north_tag_t* tag = mq_north_dev->mq_north_tag[i];
                    
                    // 检查tag指针是否有效
                    if (tag == NULL) {
                        ems_syslog(LOG_WARNING, "mq_tag_add_to_dev: tag at index %d is NULL", i);
                        continue;
                    }
                    
                    // 检查tag->tag指针是否有效
                    if (tag->tag == NULL) {
                        ems_syslog(LOG_WARNING, "mq_tag_add_to_dev: tag->tag at index %d is NULL", i);
                        continue;
                    }
                    
                    // 检查点位是否有效
                    if (tag->tag->active == 1) {
                        // 无效点位，保持原有地址，不添加到协议数组
                        ems_syslog(LOG_DEBUG, "mq_tag_add_to_dev: skipping inactive tag '%s' with address %d", tag->tag->name, 
                            (north_info->protocol_type == N_PROTOCOL_TYPE_MODBUS_TCP && tag->proto_ptr != NULL) ? 
                            ((mo_north_tag_t*)tag->proto_ptr)->addr : 
                            ((north_info->protocol_type == N_PROTOCOL_TYPE_IEC104 && tag->proto_ptr != NULL) ? 
                            ((iec_north_tag_t*)tag->proto_ptr)->addr_S : 0));
                        continue;
                    }
                    
                    // 有效点位，根据点位类型和协议类型处理
                    if (north_info->protocol_type == N_PROTOCOL_TYPE_MODBUS_TCP && mo_north_dev != NULL) {
                        // 从保存的点位顺序中查找对应点位的地址
                        int saved_address = -1;
                        for (int j = 0; j < north_info->tag_order_count; j++) {
                            // 只查找与当前协议类型匹配的点位
                            if (north_info->tag_order_list[j].protocol_type != north_info->protocol_type) {
                                continue;
                            }
                            
                            // 只查找与当前设备匹配的点位
                            if (strcmp(north_info->tag_order_list[j].dev_no, mq_north_dev->no) != 0) {
                                continue;
                            }
                            
                            if (strcmp(north_info->tag_order_list[j].tag_name, tag->tag->name) == 0) {
                                saved_address = north_info->tag_order_list[j].address;
                                break;
                            }
                        }
                        
                        // 设置点位地址为保存的地址
                        if (saved_address != -1 && tag->proto_ptr != NULL) {
                            mo_north_tag_t* mo_north_tag = (mo_north_tag_t*)tag->proto_ptr;
                            mo_north_tag->addr = saved_address;
                            ems_syslog(LOG_DEBUG, "mq_tag_add_to_dev: using saved address %d for tag '%s'", saved_address, tag->tag->name);
                        }
                        
                        if (tag->tag->property == 0) {
                            // realdata
                            if (strcmp(mq_north_dev->no, "EMS") == 0) {
                                // EMS设备的realdata使用保持寄存器
                                if (mo_north_dev->hold_tag != NULL && mo_north_dev->nb_hold < TAG_NUM) {
                                    mo_north_dev->hold_tag[mo_north_dev->nb_hold] = tag;
                                    if (saved_address == -1) {
                                        // 新增点位，调用mq_get_tag_info生成地址
                                        mq_get_tag_info(tag, "rw", B_CODE_TYPE, N_CODE); // 保持寄存器(可读可写)
                                    }
                                    mo_north_dev->nb_hold++;
                                }
                            } else {
                                // 普通设备的realdata使用输入寄存器
                                if (mo_north_dev->inputr_tag != NULL && mo_north_dev->nb_inputr < TAG_NUM) {
                                    mo_north_dev->inputr_tag[mo_north_dev->nb_inputr] = tag;
                                    if (saved_address == -1) {
                                        // 新增点位，调用mq_get_tag_info生成地址
                                        mq_get_tag_info(tag, "ro", S_CODE_TYPE, N_CODE);  // 输入寄存器
                                    }
                                    mo_north_dev->nb_inputr++;
                                }
                            }
                        } else if (tag->tag->property == 1 || tag->tag->property == 2) {
                            // system或alarm
                            if (strcmp(mq_north_dev->no, "EMS") == 0) {
                                // EMS设备的system/alarm使用线圈
                                if (mo_north_dev->coil_tag != NULL && mo_north_dev->nb_coil < TAG_NUM) {
                                    mo_north_dev->coil_tag[mo_north_dev->nb_coil] = tag;
                                    if (saved_address == -1) {
                                        // 新增点位，调用mq_get_tag_info生成地址
                                        mq_get_tag_info(tag, "rw", X_CODE_TYPE, N_CODE); // 线圈(可读可写)
                                    }
                                    mo_north_dev->nb_coil++;
                                }
                            } else {
                                // 普通设备的system/alarm使用离散量输入
                                if (mo_north_dev->inputb_tag != NULL && mo_north_dev->nb_inputb < TAG_NUM) {
                                    mo_north_dev->inputb_tag[mo_north_dev->nb_inputb] = tag;
                                    if (saved_address == -1) {
                                        // 新增点位，调用mq_get_tag_info生成地址
                                        mq_get_tag_info(tag, "ro", L_CODE_TYPE, N_CODE);  // 离散量输入
                                    }
                                    mo_north_dev->nb_inputb++;
                                }
                            }
                        }
                    } else if (north_info->protocol_type == N_PROTOCOL_TYPE_IEC104 && iec_north_dev != NULL) {
                        // 从保存的点位顺序中查找对应点位的地址
                        int saved_address = -1;
                        for (int j = 0; j < north_info->tag_order_count; j++) {
                            // 只查找与当前协议类型匹配的点位
                            if (north_info->tag_order_list[j].protocol_type != north_info->protocol_type) {
                                continue;
                            }
                            
                            // 只查找与当前设备匹配的点位
                            if (strcmp(north_info->tag_order_list[j].dev_no, mq_north_dev->no) != 0) {
                                continue;
                            }
                            
                            if (strcmp(north_info->tag_order_list[j].tag_name, tag->tag->name) == 0) {
                                saved_address = north_info->tag_order_list[j].address;
                                break;
                            }
                        }
                        
                        if (tag->tag->property == 0) {
                            // realdata
                            if (strcmp(mq_north_dev->no, "EMS") == 0) {
                                // EMS设备的realdata使用遥调，并在遥测中占位
                                if (iec_north_dev->rr_tag != NULL && iec_north_dev->nb_rr < TAG_NUM && iec_north_dev->rm_tag != NULL && iec_north_dev->nb_rm < TAG_NUM) {
                                    if(tag->limit == 1)	//写点位，遥测遥调同时加
									{			
										iec_north_dev->rr_tag[iec_north_dev->nb_rr] = tag;
										iec_north_dev->rm_tag[iec_north_dev->nb_rm] = tag;
										if (saved_address == -1) {
											mq_get_tag_info(tag, "rw", N_CODE_TYPE, RR_CODE); // 遥调
										}
										else
										{
											if (tag->proto_ptr != NULL) {
												iec_north_tag_t* iec_north_tag = (iec_north_tag_t*)tag->proto_ptr;
												iec_north_tag->addr_S = saved_address;
												iec_north_tag->addr = 25089 +  iec_north_dev->nb_rr;
											}
											iec_north_dev->nb_rr++;
                                        	iec_north_dev->nb_rm++;
										}
									}
									else
									{
										iec_north_dev->rm_tag[iec_north_dev->nb_rm] = tag;
										if (saved_address == -1) {
											mq_get_tag_info(tag, "ro", N_CODE_TYPE, RM_CODE); // 遥调
										}
										else
										{
											if (tag->proto_ptr != NULL) {
												iec_north_tag_t* iec_north_tag = (iec_north_tag_t*)tag->proto_ptr;
												iec_north_tag->addr_S = saved_address;
											}
                                        	iec_north_dev->nb_rm++;
										}
									}
                                }
                            } else {
                                // 普通设备的realdata使用遥测
                                if (iec_north_dev->rm_tag != NULL && iec_north_dev->nb_rm < TAG_NUM) {
                                    iec_north_dev->rm_tag[iec_north_dev->nb_rm] = tag;
                                    if (saved_address == -1) {
                                        mq_get_tag_info(tag, "ro", N_CODE_TYPE, RM_CODE); // 遥测
                                    } else {
                                        if (tag->proto_ptr != NULL) {
											iec_north_tag_t* iec_north_tag = (iec_north_tag_t*)tag->proto_ptr;
											iec_north_tag->addr_S = saved_address;
										}
                                        iec_north_dev->nb_rm++;
                                    }
                                }
                            }
                        } else if (tag->tag->property == 1 || tag->tag->property == 2) {
                            // system或alarm
                            if (strcmp(mq_north_dev->no, "EMS") == 0) {
                                if (iec_north_dev->rp_tag != NULL && iec_north_dev->nb_rp < TAG_NUM) {
                                    iec_north_dev->rp_tag[iec_north_dev->nb_rp] = tag;
                                    if (saved_address == -1) {
                                        // 新增点位，调用mq_get_tag_info生成地址
                                        mq_get_tag_info(tag, "ro", N_CODE_TYPE, RP_CODE); // 遥信
                                    } else {
                                        // 使用保存的地址，手动递增计数器
										if (tag->proto_ptr != NULL) {
											iec_north_tag_t* iec_north_tag = (iec_north_tag_t*)tag->proto_ptr;
											iec_north_tag->addr_P = saved_address;
										}
                                        iec_north_dev->nb_rp++;
                                    }
                                }
                            } else {
                                // 普通设备的system/alarm使用遥信
                                if (iec_north_dev->rp_tag != NULL && iec_north_dev->nb_rp < TAG_NUM) {
                                    iec_north_dev->rp_tag[iec_north_dev->nb_rp] = tag;
                                    if (saved_address == -1) {
                                        // 新增点位，调用mq_get_tag_info生成地址
                                        mq_get_tag_info(tag, "ro", N_CODE_TYPE, RP_CODE); // 遥信
                                        // 注意：mq_get_tag_info内部已经对iec_north_dev->nb_rp进行了递增
                                    } else {
                                        // 使用保存的地址，手动递增计数器
										if (tag->proto_ptr != NULL) {
											iec_north_tag_t* iec_north_tag = (iec_north_tag_t*)tag->proto_ptr;
											iec_north_tag->addr_P = saved_address;
										}
                                        iec_north_dev->nb_rp++;
                                    }
                                }
                            }
                        }
                    }
                }
                
                // 释放标记数组
                free(processed);
            }
            
            // 释放临时数组
            free(temp_tags);
            
            ems_syslog(LOG_NOTICE, "mq_tag_add_to_dev: finished reordering tags and addresses, total tags: %d", mq_north_dev->num);
        }
    }
    
    if (north_info->protocol_type == N_PROTOCOL_TYPE_MQTT)
    {
        ems_syslog(LOG_NOTICE, "mqtt~~ device no:%s, all tags num: %d", mq_north_dev->no, mq_north_dev->num);
    }
    else if (north_info->protocol_type == N_PROTOCOL_TYPE_MODBUS_TCP)
    {
        mo_proto_info_t *mo_proto_info = get_mo_proto_info();
        mo_class_info_t *mo_class_info = NULL;
        int p_compatible_id = 0;
        int index = mo_match_by_class_type(&(mq_north_dev->class_type), mo_proto_info->mo_class_info, &p_compatible_id, 0);
        if (index == -1) {
            return -1;
        }

        mo_class_info = &(mo_proto_info->mo_class_info[index]);
        mo_class_info->nb_bits       += MODBUS_RESERVE;
        mo_class_info->nb_input_bits += MODBUS_RESERVE;
        mo_class_info->nb_registers  += MODBUS_RESERVE;
        mo_class_info->nb_input_registers += MODBUS_RESERVE;
        ems_syslog(LOG_NOTICE, "modbus tcp~~ device no:%s, nb_bits num:%d  nb_input_bits num:%d nb_registers num:%d nb_input_registers num:%d", mq_north_dev->no, mo_north_dev->nb_bits, mo_north_dev->nb_input_bits, mo_north_dev->nb_registers, mo_north_dev->nb_input_registers);
    }
    else if (north_info->protocol_type == N_PROTOCOL_TYPE_IEC104)
    {
        iec_proto_info_t* iec_proto_info = get_iec104_proto_info();
        iec_class_info_t* iec_class_info = NULL;

        int p_compatible_id = 0;
        int index = iec_match_by_class_type(&(mq_north_dev->class_type), iec_proto_info->iec_class_info, &p_compatible_id, 0);
        if (index == -1) {
            return -1;
        }

        iec_class_info = &(iec_proto_info->iec_class_info[index]);
        iec_class_info->nb_rp += IEC104_RP_RESERVE;
        iec_class_info->nb_rm += IEC104_RM_RESERVE;
        iec_class_info->nb_rc += IEC104_RC_RESERVE;
        iec_class_info->nb_rr += IEC104_RR_RESERVE;
        ems_syslog(LOG_NOTICE, "iec104~~ device no:%s, nb_rp:%d  nb_rm:%d nb_rc num:%d nb_rr num:%d", mq_north_dev->no, iec_north_dev->nb_rp, iec_north_dev->nb_rm, iec_north_dev->nb_rc, iec_north_dev->nb_rr);
    }
    return 0;
}

static mq_north_dev_t *mq_device_create(device_t *dev)
{
    mq_north_dev_t *mq_north_dev = calloc(sizeof(mq_north_dev_t), 1);
    if (mq_north_dev == NULL)
		return NULL;
	north_info_t *north_info = get_north_info();
	
	snprintf(mq_north_dev->no, sizeof(mq_north_dev->no), "%s", dev->no);
	snprintf(mq_north_dev->disp_name, sizeof(mq_north_dev->disp_name), "%s", dev->disp_name);
	mq_north_dev->dev_type = strdup(dev->dev_type);
	if ((strcmp(mq_north_dev->dev_type, "METER") == 0) && (dev->dev_child_type != NULL))
		mq_north_dev->dev_child_type = strdup(dev->dev_child_type);	
	mq_north_dev->class_type = calloc(32, sizeof(char));
	
    if (strcmp(mq_north_dev->dev_type, "METER") == 0){
		snprintf(mq_north_dev->class_type, 32, "%s_%s", mq_north_dev->dev_child_type, mq_north_dev->dev_type);
	}
    else
		snprintf(mq_north_dev->class_type, 32, "%s", mq_north_dev->dev_type);

	int p_compatible_id = 0;
	int index = match_by_class_type(&(mq_north_dev->class_type), &p_compatible_id, 1); //>>匹配失败的设备，将会被北向丢弃
    if (index == -1){
		ems_syslog(LOG_NOTICE, "device no:%s parent class:%s no support!!!", mq_north_dev->no, mq_north_dev->class_type);
        if (mq_north_dev->dev_type != NULL) free(mq_north_dev->dev_type);
        if (mq_north_dev->dev_child_type != NULL) free(mq_north_dev->dev_child_type);
		if (mq_north_dev->class_type != NULL) free(mq_north_dev->class_type);
        if (mq_north_dev != NULL)
			free(mq_north_dev);
        return NULL;
	}
	
	/*************/
	if (north_info->protocol_type == N_PROTOCOL_TYPE_MQTT){
        ;
	}
	else if (north_info->protocol_type == N_PROTOCOL_TYPE_MODBUS_TCP){
		mo_north_dev_t *mo_north_dev = calloc(sizeof(mo_north_dev_t), 1);
		mq_north_dev->proto_ptr = mo_north_dev;
	}
	else if (north_info->protocol_type == N_PROTOCOL_TYPE_IEC104){
		iec_north_dev_t *iec_north_dev = calloc(sizeof(iec_north_dev_t), 1);
		mq_north_dev->proto_ptr = iec_north_dev;
	}
    /***********************************************************************/

	return mq_north_dev;
}
static int mq_dev_add_to_class(device_t *dev, mq_north_dev_t *mq_north_dev, mq_north_class_t *class_ptr)
{
    if ((mq_north_dev == NULL) || (class_ptr == NULL))
    {
        return -1;
    }
    north_info_t *north_info = get_north_info();
	
    //proto_forward_t *var = get_proto_forward_var();
    if (class_ptr->num < DEV_NUM)
    {
        mq_north_dev->ptr = class_ptr;
		/************/
	    if (north_info->protocol_type == N_PROTOCOL_TYPE_MQTT){
            ;
	    }
		else if (north_info->protocol_type == N_PROTOCOL_TYPE_MODBUS_TCP){
			mo_north_class_t *mo_north_class = (mo_north_class_t *)class_ptr->proto_ptr;
			mo_north_dev_t *mo_north_dev = (mo_north_dev_t *)mq_north_dev->proto_ptr;
			if ((strcmp(mq_north_dev->class_type, "PCS") == 0)	 || (strcmp(mq_north_dev->class_type, "BMS") == 0) || (strcmp(mq_north_dev->class_type, "CELL") == 0)){
                if (north_info->exist == 0){ 
					mo_north_dev->addr = mo_north_class->mo_class_info->str_addr + class_ptr->num;
					mo_north_dev->section_indx = 0; //地址唯一，不分段
				}
				else{
					dev_cache_info_t *dev_cache_ptr = NULL;
                    get_dev_cache_by_class_type(mq_north_dev, &dev_cache_ptr);  
				    if (dev_cache_ptr != NULL){
	                    mo_north_dev->addr = dev_cache_ptr->addr;
						mo_north_dev->section_indx = dev_cache_ptr->section_indx;
				    }
				}
			}
			else{
				if (north_info->exist == 0){
					mo_north_dev->addr = mo_north_class->mo_class_info->str_addr;
					mo_north_dev->section_indx = class_ptr->num;
				}
				else{
					dev_cache_info_t *dev_cache_ptr = NULL;
					get_dev_cache_by_class_type(mq_north_dev, &dev_cache_ptr);  
				    if (dev_cache_ptr != NULL){
	                    mo_north_dev->addr = dev_cache_ptr->addr;
						mo_north_dev->section_indx = dev_cache_ptr->section_indx;
				    }
				}
			}
		}
		else if (north_info->protocol_type == N_PROTOCOL_TYPE_IEC104){
			iec_north_class_t *iec_north_class = (iec_north_class_t *)class_ptr->proto_ptr;
			iec_north_dev_t *iec_north_dev = (iec_north_dev_t *)mq_north_dev->proto_ptr;
			if ((strcmp(mq_north_dev->class_type, "PCS") == 0)	 || (strcmp(mq_north_dev->class_type, "BMS") == 0) || (strcmp(mq_north_dev->class_type, "CELL") == 0)){
                if (north_info->exist == 0){  
					iec_north_dev->addr = iec_north_class->iec_class_info->str_addr + class_ptr->num;
					iec_north_dev->section_indx = 0; //地址唯一，不分段
                }
				else{
					dev_cache_info_t *dev_cache_ptr = NULL;
                    get_dev_cache_by_class_type(mq_north_dev, &dev_cache_ptr);  
				    if (dev_cache_ptr != NULL){
	                    iec_north_dev->addr = dev_cache_ptr->addr;
						iec_north_dev->section_indx = dev_cache_ptr->section_indx;
				    }
				}
			}
			else{
				if (north_info->exist == 0){
					iec_north_dev->addr = iec_north_class->iec_class_info->str_addr;
					iec_north_dev->section_indx = class_ptr->num;    
				}
				else{
					dev_cache_info_t *dev_cache_ptr = NULL;
					get_dev_cache_by_class_type(mq_north_dev, &dev_cache_ptr);  
				    if (dev_cache_ptr != NULL){
	                    iec_north_dev->addr = dev_cache_ptr->addr;
						iec_north_dev->section_indx = dev_cache_ptr->section_indx;
				    }
				}
			}
		}
		
		mq_tag_add_to_dev(dev, mq_north_dev, get_mq_north_tag_sort(dev->dev_type, north_info->mq_north_info.mq_north_tag_sort_list));
		
		/****************************************************************************/        
        class_ptr->mq_north_dev[class_ptr->num] = mq_north_dev;
        ems_syslog(LOG_NOTICE, "class[%d] created device %s", class_ptr->num, mq_north_dev->no);
        class_ptr->num++;
    }
    else
    {
        ems_syslog(LOG_ERR, "class[%s] created device[%s] error, devs_num=%d", class_ptr->name, mq_north_dev->no, class_ptr->num);
    }

    return 0;
}

static void free_device_mem(mq_north_dev_t *mq_north_dev)
{
	if (mq_north_dev != NULL){
		FREE_AND_NULL(mq_north_dev->dev_type);
		FREE_AND_NULL(mq_north_dev->dev_child_type);
	    FREE_AND_NULL(mq_north_dev->class_type);
	    free(mq_north_dev);
        mq_north_dev = NULL;
	}
}

static mq_north_class_t *mq_class_create(proto_forward_t *var, mq_north_inside_t *mq_north_inside, device_t *dev)
{
	int idx = 0;
	mq_north_dev_t *mq_north_dev = NULL;
	mq_north_class_t *class_ptr = NULL;
	north_info_t *north_info = get_north_info();

    if (mq_north_inside->num >= CLASS_NUM)
    {
        ems_syslog(LOG_ERR, "created class[%d] error", idx);
        goto ERR;
    }
	ems_syslog(LOG_NOTICE, " mq_north_inside->num:%d!", mq_north_inside->num);

    mq_north_dev = mq_device_create(dev);
    if (!mq_north_dev)
    {
        ems_syslog(LOG_WARNING, "failed to create mq_north_dev!!!");
        goto ERR;
    }
	
	for (int i = 0; i < mq_north_inside->num; i++)
	{
		if (strcmp(mq_north_dev->class_type, mq_north_inside->mq_north_class[i]->class_type) == 0)
		{
			class_ptr = mq_north_inside->mq_north_class[i];
			ems_syslog(LOG_INFO, "find type:%s as same as others", class_ptr->class_type);
		}
	}
			
	idx = mq_north_inside->num;
	if (!class_ptr)
	{
		if (idx >= CLASS_NUM)
		{
			ems_syslog(LOG_ERR, "created class[%d] error", idx);
			goto ERR;
		}
		// 创建新的结构体
		class_ptr = calloc(sizeof(mq_north_class_t), 1);    

	    int p_compatible_id = 0;
        int index = match_by_class_type(&(mq_north_dev->class_type), &p_compatible_id, 0);
        if (index == -1)
			goto ERR;
		else
            snprintf(class_ptr->name, sizeof(class_ptr->name), "%s", _class_name[index].name);					

		class_ptr->class_type = strdup(mq_north_dev->class_type);
		/************/
		if (north_info->protocol_type == N_PROTOCOL_TYPE_MQTT){
            ;
		}
		else if (north_info->protocol_type == N_PROTOCOL_TYPE_MODBUS_TCP){
			mo_proto_info_t *mo_proto_info = get_mo_proto_info();
            mo_class_info_t *mo_class_info = calloc(sizeof(mo_class_info_t), 1);

			int p_compatible_id = 0;
			int index = mo_match_by_class_type(&(class_ptr->class_type), mo_proto_info->mo_class_info, &p_compatible_id, 1);
			mo_class_info->str_addr = mo_proto_info->mo_class_info[index].str_addr; //modbus_tcp 类信息 {"BMS",  18, 49, 0, 0, 0, 0}
			mo_class_info->end_addr = mo_proto_info->mo_class_info[index].end_addr;
					
            mo_north_class_t *mo_north_class = calloc(sizeof(mo_north_class_t), 1);			
		    mo_north_class->mo_class_info = mo_class_info;

			class_ptr->proto_ptr = mo_north_class;				
		}
		else if (north_info->protocol_type == N_PROTOCOL_TYPE_IEC104){
			iec_proto_info_t *iec_proto_info = get_iec104_proto_info();
			iec_class_info_t *iec_class_info = calloc(sizeof(iec_class_info_t), 1);
			
			int p_compatible_id = 0;
			int index = iec_match_by_class_type(&(class_ptr->class_type), iec_proto_info->iec_class_info, &p_compatible_id, 1);
			iec_class_info->str_addr = iec_proto_info->iec_class_info[index].str_addr; //iec104 类信息 {"BMS",	18, 49, 0, 0, 0, 0}
			iec_class_info->end_addr = iec_proto_info->iec_class_info[index].end_addr;
					
			iec_north_class_t *iec_north_class = calloc(sizeof(iec_north_class_t), 1); 		
			iec_north_class->iec_class_info = iec_class_info;
			
			class_ptr->proto_ptr = iec_north_class;				        
		}
		/****************************************************************************/
		mq_north_inside->mq_north_class[idx] = class_ptr;
		ems_syslog(LOG_NOTICE, "created class[%d-%s] success, name:%s", idx, class_ptr->class_type, class_ptr->name);
		// 存储类信息
		mq_north_inside->num++;
	}
	else
	{
        if (strcmp(class_ptr->class_type, mq_north_dev->class_type) != 0)
        {
            class_ptr = NULL;
        }
	}

	mq_dev_add_to_class(dev, mq_north_dev, class_ptr);	

	return class_ptr;
ERR:
	free_memory(class_ptr);
	free_device_mem(mq_north_dev);
	return NULL;
}

static int mq_load_device_cfg(proto_forward_t *var, mq_north_inside_t *mq_north_inside)
{
    ems_syslog(LOG_NOTICE, "%s", "mqtt_north_devs load start...");
	
    proto_forward_t *dev_var = get_proto_forward_var();
    for (int i = 0; i < dev_var->channels_size; i++)
    {
        ems_syslog(LOG_DEBUG, "channel:%s", dev_var->channels[i]->channel);
        for (int j = 0; j < dev_var->channels[i]->devs_size; j++)
        {
            device_t *dev = dev_var->channels[i]->devs[j];
            template_t *p = dev->use_template;
            ems_syslog(LOG_DEBUG, "dev: %s->template info:model->%s, adapter->%s", dev->no, p->model, p->adapter);

            // 根据配置信息自动创建类,如果重复不创建
            mq_north_class_t *mq_north_class = mq_class_create(var, mq_north_inside, dev);
            if (!mq_north_class)
            {
                ems_syslog(LOG_ERR, "failed to create mqtt north class!!!");
            }
        }
    }

#ifdef EN_EMS // 检索LC DEV  lc vlc ems -- lc vlc 下属设备在主机上都可见（channels遍历即可录入），ems下属设备在主机上不可见，需特殊处理
	pcs_ctrl_var_t *_var = get_pcs_ctrl_var();
    for (int i = 0; i < _var->lc_list_len; i++)
	{
        lc_it *lc_single = &(_var->lc_list[i]);
        ems_syslog(LOG_DEBUG, "sn: %s no: %s name: %s type: %d (0 lc 1 vlc 2 ems), ipaddr: %s", lc_single->sn, lc_single->no, lc_single->name, lc_single->type, lc_single->ipaddr); 
        
		slave_ems *slave = lc_single->slave;
		if (slave == NULL) continue;  // lc vlc
        for (int j = 0; j < slave->dev_sum; j++)
        {
            device_t *dev = &(slave->devs[j]);
            //template_t *p = dev->use_template;
            //ems_syslog(LOG_DEBUG, "dev: %s->template info:model->%s, adapter->%s", dev->no, p->model, p->adapter);
			ems_syslog(LOG_DEBUG, "dev: %s ", dev->no);

            // 根据配置信息自动创建类,如果重复不创建
            mq_north_class_t *mq_north_class = mq_class_create(var, mq_north_inside, dev);
            if (!mq_north_class)
            {
                ems_syslog(LOG_ERR, "failed to create mqtt north class!!!");
            }
        }
	}
#endif

	return 0;
}

static void mq_free_total(mq_north_info_t *mq_north_info)
{
	int i = 0, j = 0;
	mq_north_inside_t *mq_north_inside = mq_north_info->mq_north_inside;
	mq_xlsx_book_t *mq_xlsx_book = mq_north_info->mq_xlsx_book;

	north_info_t *north_info = get_north_info();
    //-------------------------- free inside-------------------------------- 
	for (i = 0; i < mq_north_inside->num; i++) {
		mq_north_class_t *mq_north_class = mq_north_inside->mq_north_class[i];
		
		free_memory(mq_north_class->class_type);
		if (north_info->protocol_type == N_PROTOCOL_TYPE_MQTT){
            ;
		}
		else if (north_info->protocol_type == N_PROTOCOL_TYPE_MODBUS_TCP){
            mo_north_class_t *mo_north_class = mq_north_class->proto_ptr;
			free_memory(mo_north_class->mo_class_info);
		    free_memory(mo_north_class);
			mq_north_class->proto_ptr = NULL;
		}
		else if (north_info->protocol_type == N_PROTOCOL_TYPE_IEC104){
			iec_north_class_t *iec_north_class = mq_north_class->proto_ptr;
			free_memory(iec_north_class->iec_class_info);
			free_memory(iec_north_class);
			mq_north_class->proto_ptr = NULL;
		}
		
		for (j = 0; j < mq_north_class->num; j++) {
			mq_north_dev_t *mq_north_dev = mq_north_class->mq_north_dev[j];
			
			free_memory(mq_north_dev->dev_type);
			free_memory(mq_north_dev->dev_child_type);
			free_memory(mq_north_dev->class_type);
			if (north_info->protocol_type == N_PROTOCOL_TYPE_MQTT){
				;
			}
			else if (north_info->protocol_type == N_PROTOCOL_TYPE_MODBUS_TCP){
				mo_north_dev_t *mo_north_dev = mq_north_dev->proto_ptr;
				init_mo_north_dev(mo_north_dev);
				free_memory(mo_north_dev);
				mq_north_dev->proto_ptr = NULL;
			}
			else if (north_info->protocol_type == N_PROTOCOL_TYPE_IEC104){
				iec_north_dev_t *iec_north_dev = mq_north_dev->proto_ptr;
				init_iec_north_dev(iec_north_dev);
				free_memory(iec_north_dev);
				mq_north_dev->proto_ptr = NULL;
			}

			for (int m = 0; m < mq_north_dev->num; m++) {
				mq_north_tag_t *mq_north_tag = mq_north_dev->mq_north_tag[m];
				if( mq_north_tag == NULL) continue;
				if (north_info->protocol_type == N_PROTOCOL_TYPE_MQTT){
					;
				}
				else if (north_info->protocol_type == N_PROTOCOL_TYPE_MODBUS_TCP){
					if (mq_north_tag->proto_ptr != NULL) {
						mo_north_tag_t *mo_north_tag = (mo_north_tag_t*)mq_north_tag->proto_ptr;
						free_memory(mo_north_tag);
					    mq_north_tag->proto_ptr = NULL;
					}
				}
				else if (north_info->protocol_type == N_PROTOCOL_TYPE_IEC104){
					if (mq_north_tag->proto_ptr != NULL) {
						iec_north_tag_t *iec_north_tag = (iec_north_tag_t*)mq_north_tag->proto_ptr;
						free_memory(iec_north_tag);
						mq_north_tag->proto_ptr = NULL;
					}
				}
				free_memory(mq_north_tag);
			}
			free_memory(mq_north_dev);
		}
		free_memory(mq_north_class);
	}
	free_memory(mq_north_inside);
	
    //--------------------------- free book-------------------------------	
	for (i = 0; i < mq_xlsx_book->num; i++) {
		mq_xlsx_sheet_t *mq_xlsx_sheet = mq_xlsx_book->mq_xlsx_sheet[i];
		
		for (j = 0; j < mq_xlsx_sheet->num; j++) {
			mq_xlsx_dev_t *mq_xlsx_dev = mq_xlsx_sheet->mq_xlsx_dev[j];
			if (north_info->protocol_type == N_PROTOCOL_TYPE_MQTT){
	            ;
			}
			else if (north_info->protocol_type == N_PROTOCOL_TYPE_MODBUS_TCP){
				mo_xlsx_dev_t *mo_xlsx_dev = mq_xlsx_dev->proto_ptr;
				init_mo_xlsx_dev(mo_xlsx_dev);
			    free_memory(mo_xlsx_dev);
				mq_xlsx_dev->proto_ptr = NULL;
			}
			else if (north_info->protocol_type == N_PROTOCOL_TYPE_IEC104){
				iec_xlsx_dev_t *iec_xlsx_dev = mq_xlsx_dev->proto_ptr;
				init_iec_xlsx_dev(iec_xlsx_dev);
				free_memory(iec_xlsx_dev);
				mq_xlsx_dev->proto_ptr = NULL;
			}
			for (int m = 0; m < mq_xlsx_dev->num; m++) {
				mq_xlsx_item_t *mq_xlsx_item = mq_xlsx_dev->mq_xlsx_item[m];
				
				free_memory(mq_xlsx_item->desc);
				if (north_info->protocol_type == N_PROTOCOL_TYPE_MQTT){
		            ;
				}
				else if (north_info->protocol_type == N_PROTOCOL_TYPE_MODBUS_TCP){
					mo_xlsx_item_t *mo_xlsx_item = mq_xlsx_item->proto_ptr;
				    free_memory(mo_xlsx_item);
				    mq_xlsx_item->proto_ptr = NULL;
				}
				else if (north_info->protocol_type == N_PROTOCOL_TYPE_IEC104){
					iec_xlsx_item_t *iec_xlsx_item = mq_xlsx_item->proto_ptr;
					free_memory(iec_xlsx_item);
					mq_xlsx_item->proto_ptr = NULL;
				}
				free_memory(mq_xlsx_item);
			}
			free_memory(mq_xlsx_dev);
		}
		free_memory(mq_xlsx_sheet);
	}
    free_memory(mq_xlsx_book);

    free_memory(mq_north_info->mq_north_tag_sort_list->list);
    free_memory(mq_north_info->mq_north_tag_sort_list);
}


static void clear_dev_info(void){
    int i = 0, j = 0;
	for (i = 0; i < num_class; i++) {
		class_name_t *class_name = &_class_name[i];
		for (j = 0; j < class_name->num; j++) {
            FREE_AND_NULL(class_name->ptr[j]);       
		}
		class_name->num = 0;
	}
}

static int mq_load_dev_addr_info(const char *dev_addr_file)
{
    int ret = 0;
    char *pdata = NULL;
    cJSON *root = NULL;
    cJSON *class_info = NULL;
    ems_syslog(LOG_NOTICE, "dev_addr_info_file: %s", dev_addr_file);

    pdata = read_file_data(dev_addr_file);
    if (pdata == NULL)
    {
        ems_syslog(LOG_ERR, "read dev_addr_info file %s error", dev_addr_file);
        BUSINESS_LOG(BLOG_ERR, NORTH_ID_0038, NULL, "[北向]:加载 北向设备地址表失败!，文件名[%s]", dev_addr_file);
        goto out;
    }
    else
    {
        BUSINESS_LOG(BLOG_NOTICE, NORTH_ID_0038, NULL, "[北向]:加载 北向设备地址表成功!，文件名[%s]", dev_addr_file);
    }

    root = json_parse_string_with_comments(pdata);
    if (!root)
    {
        ems_syslog(LOG_ERR, "parse pdata %s error", pdata);
        BUSINESS_LOG(BLOG_ERR, NORTH_ID_0039, NULL, "[北向]:解析 北向设备地址表失败!，文件名[%s]", dev_addr_file);
        goto out;
    }
    else
    {
        BUSINESS_LOG(BLOG_NOTICE, NORTH_ID_0039, NULL, "[北向]:解析 北向设备地址表失败!，文件名[%s]", dev_addr_file);
    }

    ret = 1;
	for (int i = 0; i < num_class; i++) {
        char *p = _class_name[i].compatible[0]; //固定，取第一个字符串
        if (p == NULL) {
            continue;
        }
		class_info = cJSON_GetObjectItemCaseSensitive(root, p);
	    if (!class_info)
	    {
	        ems_syslog(LOG_WARNING, "get class no exist %s", p);
	        continue;
	    }	
		int num = cJSON_GetArraySize(class_info);
        for (int j = 0; j < num; j++){
            dev_cache_info_t *dev_cache_info = (dev_cache_info_t *)calloc(sizeof(dev_cache_info_t), 1);
			cJSON *dev_item = cJSON_GetArrayItem(class_info, j);  
			GET_JSON_VALUE_STRING(dev_item, "no", dev_cache_info->no);
			GET_JSON_VALUE_INT(dev_item, "addr", dev_cache_info->addr);
			GET_JSON_VALUE_INT(dev_item, "section_indx", dev_cache_info->section_indx);
			_class_name[i].ptr[j] = dev_cache_info;
			ems_syslog(LOG_NOTICE, "dev no: %s, addr: %d section_indx: %d", dev_cache_info->no, dev_cache_info->addr, dev_cache_info->section_indx);
		} 
		_class_name[i].num = num;
	}
out:
	if (root != NULL)
	{
		cJSON_Delete(root);
		root = NULL;
	}
	if (pdata != NULL)
	{
		free(pdata);
		pdata = NULL;
	}
	return ret; // 返回1 解析成功，0 dev_addr_info.json文件不存在/解析失败~~
}

static void automatic_north_start(void)
{
	pthread_detach(pthread_self());

	proto_forward_t *var = get_proto_forward_var();
	north_info.language = get_sys_language(); // 获取系统语言
	mq_north_info_t *mq_north_info = &north_info.mq_north_info;
	
	// 初始化tag_order_exist
	north_info.tag_order_exist = 0;
	north_info.tag_order_list = NULL;
	north_info.tag_order_count = 0;
	
	mq_north_info->mq_north_inside = mq_north_init();
	mq_north_info->mq_xlsx_book = mq_xlsx_init();
    if (mq_north_info->mq_north_inside == NULL || mq_north_info->mq_xlsx_book == NULL)
		return;

	// 1. Check configuration file version and set need_add_version flag
	check_config_version_and_set_flag();
    
	// 2. Read tag order from file
	read_tag_order();
    
	// 3. Initialize tag sort list after setting the flag
	mq_north_info->mq_north_tag_sort_list = init_sort_tag_list();
    if (mq_north_info->mq_north_tag_sort_list == NULL)
		return;

	north_info.exist = mq_load_dev_addr_info(NORTH_CONFIG_PATH "/" DEV_ADDR_INFO_FILE); //dev_addr_info.json
    mq_load_device_cfg(var, mq_north_info->mq_north_inside);
	save_dev_addr_info_file(mq_north_info->mq_north_inside);

    mq_inside_sync_xlsx(mq_north_info->mq_north_inside, mq_north_info->mq_xlsx_book, north_info.protocol_type); //同步
	create_relate_file(mq_north_info->mq_north_inside, mq_north_info->mq_xlsx_book);
    
    // 4. Save tag order to file
    save_tag_order(mq_north_info->mq_north_inside);

    // 释放总内存
    mq_free_total(mq_north_info);
    
	if (north_info.protocol_type == N_PROTOCOL_TYPE_MQTT){
		;
	}else if (north_info.protocol_type == N_PROTOCOL_TYPE_MODBUS_TCP){
		mo_proto_info_t *mo_proto_info = get_mo_proto_info();
		clear_mo_class_nb(mo_proto_info->mo_class_info);
	}else if (north_info.protocol_type == N_PROTOCOL_TYPE_IEC104){
		iec_proto_info_t *iec_proto_info = get_iec104_proto_info();
		clear_iec104_class_nb(iec_proto_info->iec_class_info);
	}
	clear_dev_info();
    
    // 释放点位顺序列表内存
    if (north_info.tag_order_list != NULL) {
        free(north_info.tag_order_list);
        north_info.tag_order_list = NULL;
    }
    north_info.tag_order_exist = 0;
    north_info.tag_order_count = 0;
    
	north_info.protocol_type = N_PROTOCOL_TYPE_NONE;
}

static void north_init(void)
{
    automatic_north_start();
}

int create_north_cfg(int pro, char *data_tmp)
{
    int ret = 0;
    ems_syslog(LOG_NOTICE, "North protocol, pro_typ: %d", pro);
    north_info.protocol_type = pro;
    north_init();
    switch (pro)
    {
        case N_PROTOCOL_TYPE_MQTT:
            sprintf(data_tmp, "{\"result\":\"0\",\"path\":\"mqtt_north.xlsx\"}");
            break;
        case N_PROTOCOL_TYPE_MODBUS_TCP:
            sprintf(data_tmp, "{\"result\":\"0\",\"path\":\"modbustcp_north.xlsx\"}");
            break;
        case N_PROTOCOL_TYPE_IEC104:
            sprintf(data_tmp, "{\"result\":\"0\",\"path\":\"iec104_north.xlsx\"}");
            break;
        default:
            ret = -1;
    }
    return ret;
}	


void *monitor_north_connect_status_task(void *arg)
{
	sleep(5);
	int prev_iec104_heart_bit = dev_get_dev_tag_int(DEV_NO_EMS, IEC104_HEARTBEAT);
	int prev_modbustcp_heart_bit = dev_get_dev_tag_int(DEV_NO_EMS, MODBUSTCP_HEARTBEAT);
	int iec104_error_cnt = 0;
	int modbustcp_error_cnt = 0;
	while(true)
	{
		// 检查iec104 心跳位
		int curr_iec104_heart_bit = dev_get_dev_tag_int(DEV_NO_EMS, IEC104_HEARTBEAT);
		if(curr_iec104_heart_bit != prev_iec104_heart_bit){
			iec104_error_cnt = 0;
			prev_iec104_heart_bit = curr_iec104_heart_bit;
			if(north_conn_status[N_NORTH_IEC104_CONRTOL] == NORTH_COMM_STATUS_DISCONNECT){
				server_add_new_log(LOG_CODE_IEC104_CONNECTION,"EMS",LOG_MODE_TRIG,2,NULL);
				ems_syslog(LOG_ERR, "iec104 connection status [disconnect] -> [connect]!");
                BUSINESS_LOG(BLOG_NOTICE, NORTH_ID_0036, NULL, "[北向]:iec104 connection status [disconnect] -> [connect]!");
			}
			north_conn_status[N_NORTH_IEC104_CONRTOL] = NORTH_COMM_STATUS_CONNECTED;
			int alarm_tmp = dev_get_dev_tag_int(DEV_NO_EMS, IEC104_CONN_ALARM);
			if(alarm_tmp != 0)
			{
				dev_set_dev_tag_int(DEV_NO_EMS, IEC104_CONN_ALARM, 0);
			}
		}
		else {
			iec104_error_cnt++;
		}

		// 检查modbustcp 心跳位
		int curr_modbustcp_heart_bit = dev_get_dev_tag_int(DEV_NO_EMS, MODBUSTCP_HEARTBEAT);
		if(curr_modbustcp_heart_bit != prev_modbustcp_heart_bit){
			modbustcp_error_cnt = 0;
			prev_modbustcp_heart_bit = curr_modbustcp_heart_bit;
			if(north_conn_status[N_NORTH_MODBUS_CONTROL] == NORTH_COMM_STATUS_DISCONNECT){
				server_add_new_log(LOG_CODE_MODBUSTCP_CONNECTION,"EMS",LOG_MODE_TRIG,2,NULL);
				ems_syslog(LOG_ERR, "modbustcp connection status [disconnect] -> [connect]!");
                BUSINESS_LOG(BLOG_NOTICE, NORTH_ID_0037, NULL, "[北向]:modbustcp connection status [disconnect] -> [connect]!");
			}
			north_conn_status[N_NORTH_MODBUS_CONTROL] = NORTH_COMM_STATUS_CONNECTED;
			int alarm_tmp = dev_get_dev_tag_int(DEV_NO_EMS, MODBUSTCP_CONN_ALARM);
			if(alarm_tmp != 0)
			{
				dev_set_dev_tag_int(DEV_NO_EMS, MODBUSTCP_CONN_ALARM, 0);
			}
		}
		else {
			modbustcp_error_cnt++;
		}

		// 更新mqtt 状态
		mqt_north_var_t *mqtt_var = get_mqt_north_var();
		for (int i = 0; i < mqtt_var->channel_cnt; i++){
			mqt_north_channel_t *channel = &mqtt_var->channel[i];
			if (channel->comm_status == COMM_STATUS_LOGIN){
				north_conn_status[i+2] = NORTH_COMM_STATUS_CONNECTED;
			}
			else if(channel->comm_status == COMM_STATUS_CONNECTED){
				north_conn_status[i+2] = NORTH_COMM_STATUS_DISLOGIN;
			}
			else if(channel->comm_status == COMM_STATUS_CONNECTING){
				north_conn_status[i+2] = NORTH_COMM_STATUS_DISCONNECT;
			}
		}

		if(iec104_error_cnt >= 12){
			iec104_error_cnt = 0;

			if(get_proto_forward_var()->iec104_enable)
			{
				// 连接状态从连接转为断开时触发保护机制
				if(north_conn_status[N_NORTH_IEC104_CONRTOL] == NORTH_COMM_STATUS_CONNECTED)
				{
					dev_set_dev_tag_int(DEV_NO_EMS, ON_OFF_STATE, 0);
					dev_set_dev_tag_int(DEV_NO_EMS, CONTROL_MODE, 0);
					dev_set_dev_tag_float(DEV_NO_EMS, SET_ACT_POWER, 0);
					server_add_new_log(LOG_CODE_IEC104_CONNECTION,"EMS",LOG_MODE_TRIG,1,NULL);
					ems_syslog(LOG_ERR, "iec104 connection status [connect] -> [disconnect]!");
                    BUSINESS_LOG(BLOG_NOTICE, NORTH_ID_0036, NULL, "[北向]:iec104 connection status [connect] -> [disconnect]!");
				}
				dev_set_dev_tag_int(DEV_NO_EMS, IEC104_CONN_ALARM, 1);
                if(first_init_iec104)
                {
                    first_init_iec104 = false;
                    server_add_new_log(LOG_CODE_IEC104_CONNECTION,"EMS",LOG_MODE_TRIG,1,NULL);
                }
			}
			else
			{
				int alarm_tmp = dev_get_dev_tag_int(DEV_NO_EMS, IEC104_CONN_ALARM);
				if(alarm_tmp != 0)
				{
					dev_set_dev_tag_int(DEV_NO_EMS, IEC104_CONN_ALARM, 0);
				}
			}
			north_conn_status[N_NORTH_IEC104_CONRTOL] = NORTH_COMM_STATUS_DISCONNECT;
		}
		if(modbustcp_error_cnt >= 12){
			modbustcp_error_cnt = 0;

			if(get_proto_forward_var()->modbus_enable)
			{
				// 连接状态从连接转为断开时触发保护机制
				if(north_conn_status[N_NORTH_MODBUS_CONTROL] == NORTH_COMM_STATUS_CONNECTED)
				{
					dev_set_dev_tag_int(DEV_NO_EMS, ON_OFF_STATE, 0);
					dev_set_dev_tag_int(DEV_NO_EMS, CONTROL_MODE, 0);
					dev_set_dev_tag_float(DEV_NO_EMS, SET_ACT_POWER, 0);
					server_add_new_log(LOG_CODE_MODBUSTCP_CONNECTION,"EMS",LOG_MODE_TRIG,1,NULL);
					ems_syslog(LOG_ERR, "modbustcp connection status [connect] -> [disconnect]!");
                    BUSINESS_LOG(BLOG_NOTICE, NORTH_ID_0037, NULL, "[北向]:modbustcp connection status [connect] -> [disconnect]!");
				}
				dev_set_dev_tag_int(DEV_NO_EMS, MODBUSTCP_CONN_ALARM, 1);
                if(first_init_modbus)
                {
                    first_init_modbus = false;
                    server_add_new_log(LOG_CODE_MODBUSTCP_CONNECTION,"EMS",LOG_MODE_TRIG,1,NULL);
                }
			}
			else 
			{
				int alarm_tmp = dev_get_dev_tag_int(DEV_NO_EMS, MODBUSTCP_CONN_ALARM);
				if(alarm_tmp != 0)
				{
					dev_set_dev_tag_int(DEV_NO_EMS, MODBUSTCP_CONN_ALARM, 0);
				}
			}
			north_conn_status[N_NORTH_MODBUS_CONTROL] = NORTH_COMM_STATUS_DISCONNECT;
		}
		
		sleep(5);  // 每5秒检查一次
	}
}


// 监控北向通道连接状态
int create_monitor_north_connect_status_task(void)
{
    pthread_t tid = PTHREAD_NULL;
    if (pthread_create(&tid, NULL, monitor_north_connect_status_task, NULL) != 0)
    {
        BUSINESS_LOG(BLOG_ERR, NORTH_ID_0035, NULL, "[北向]:检测北向连接状态[心跳点位] 任务启动失败");
        ems_syslog(LOG_ERR, "monitor_north_connect_status_task thread");
        return -1;
    }
    else
    {
        BUSINESS_LOG(BLOG_NOTICE, NORTH_ID_0035, NULL, "[北向]:检测北向连接状态[心跳点位] 任务启动成功");
    }
    pthread_setname_np(tid, "monitor_north_connect_status_task");
    return 0;
}
