/*
 * @Author: ybzhou yibo.zhou@lnxall.com
 * @Date: 2025-07-16 12:47:52
 * @LastEditors: ybzhou yibo.zhou@lnxall.com
 * @LastEditTime: 2025-11-24 13:56:40
 * @FilePath: /2025.07.09/proto_forward/src/automatic_north/iec104_create.c
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
#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 "xlsx_api.h"
#include "iec104_create.h"

static home_page_t _iec_home_page[] = {
	{"EMS",  1, 1, ""},
	{"PCS",  2,  33, "the maximum support is 32"},
	{"BMS", 34, 97, "the maximum support is 64"},
	{"CELL", 98, 161, "the maximum support is 64"},
	{"GRID_METER", 162, 162, "the maximum support is 64"},
	{"PCS_METER", 163, 163, "the maximum support is 64"},
	{"TRAS_LV_METER", 164, 164, "the maximum support is 64"},
	{"LOAD_METER", 165, 165, "the maximum support is 64"},
	{"PV_METER", 166, 166, "the maximum support is 64"},
	{"DG_METER", 167, 167, "the maximum support is 64"},
	{"OTHERS_METER", 168, 168, "the maximum support is 64"},
	{"DIDO", 169, 169, "the maximum support is 64"},
	{"AIRCOND", 170, 170, "the maximum support is 64"},
	{"TMS", 171, 171, "the maximum support is 64"},
	{"PV", 172, 172, "the maximum support is 64"},
	{"DG", 173, 173, "the maximum support is 64"},
	{"FIRE", 174, 174, "the maximum support is 64"},
	{"OTHERS", 175, 175, "the maximum support is 64"},
};
static int num_iec = sizeof(_iec_home_page) / sizeof(_iec_home_page[0]);


/*
       本协议适用于简捷物联科技有限公司EMS北向与104主站之间的通信。采用 Ethernet(IEC104规约2002版)通信规约。				
设备名称	起始地址码	最大地址码	设备数量	                     备注
EMS        	 1	          1	        1	
PCS	         2	          17	    最大支持16个	
主控        	 18	          33	    最大支持16个		
电芯	         49	          64	    最大支持16个		
关口表	         64	          64	    	
储能电表	     65	          65	    
干接点          66           66        
空调           67           67        
其他           68           68        最大支持32个
*/
static iec_proto_info_t iec104_proto_info = {
    .ver = 2,
	.server_port = 2404,
	.periodReportEnable = 0,	
	.reportInterval = 60,
	.start_RemotePoint = 1,
	.start_RemoteMeas = 16385,
	.start_RemoteCtrl = 24577,
	.start_RemoteRegu = 25089,
	.iec_class_info = {
	    {ems_compatible,  1, 1, 0, 0, 0, 0},
	    {pcs_compatible,  2, 33, 0, 0, 0, 0},
		{bms_compatible,  34, 97, 0, 0, 0, 0},
		{cell_compatible, 98, 161, 0, 0, 0, 0},
		{grid_meter_compatible, 162, 162, 0, 0, 0, 0},
		{pcs_meter_compatible, 163, 163, 0, 0, 0, 0},
		{tras_lv_meter_compatible, 164, 164, 0, 0, 0, 0},
		{load_meter_compatible, 165, 165, 0, 0, 0, 0},
		{pv_meter_compatible, 166, 166, 0, 0, 0, 0},
		{dg_meter_compatible, 167, 167, 0, 0, 0, 0},
		{other_meter_compatible, 168, 168, 0, 0, 0, 0},
		{dido_compatible, 169, 169, 0, 0, 0, 0},
		{ac_compatible, 170, 170, 0, 0, 0, 0},
		{tms_compatible, 171, 171, 0, 0, 0, 0},
		{pv_compatible, 172, 172, 0, 0, 0, 0},
		{dg_compatible, 173, 173, 0, 0, 0, 0},
		{fire_compatible, 174, 174, 0, 0, 0, 0},
		{others_compatible, 175, 175, 0, 0, 0, 0}
	}
};

iec_proto_info_t *get_iec104_proto_info(void){
    return &iec104_proto_info;
}


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

	for (int i = 0; i < CLASS_NUM; i++) {
        char **pp = iec_class_info[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 - iec_class_info[i].compatible;
				snprintf(*class_type, 32, "%s", _class_name[i].compatible[0]);
				return ret;
			}
			pp++;
		}
	}
    return -1;
}

static void iec_write_worksheet_item(lxw_worksheet *worksheet, int row, lxw_format *format, mq_north_tag_t *mq_north_tag, iec_code_t iec_code) {

	// 防御性检查，防止空指针崩溃
	if (worksheet == NULL || format == NULL || mq_north_tag == NULL) {
	    return;
	}
	
	if (mq_north_tag->tag == NULL) {
	    return;
	}
	
	iec_north_tag_t *iec_north_tag = mq_north_tag->proto_ptr;
	if (iec_north_tag == NULL) {
	    return;
	}

    if (iec_code == RM_CODE)
	    write_number_cell(worksheet, row, 0, (double)iec_north_tag->addr_S, format);
	else if (iec_code == RP_CODE)
	    write_number_cell(worksheet, row, 0, (double)iec_north_tag->addr_P, format);
	else
	    write_number_cell(worksheet, row, 0, (double)iec_north_tag->addr, format);
	
	// 确保disp_name有效
	const char *disp_name = mq_north_tag->tag->disp_name;
	if (disp_name == NULL || disp_name[0] == '\0') {
	    disp_name = "unknown";
	}
	write_string_cell(worksheet, row, 1, disp_name, format);
	
	if (iec_code == RP_CODE || iec_code == RM_CODE)
	    write_string_cell(worksheet, row, 2, "RO", format);
	else
	    write_string_cell(worksheet, row, 2, "WO", format);
	
	// 确保data_type有效
	if (iec_north_tag->data_type >= 0 && iec_north_tag->data_type < TYPE_MAX) {
	    write_string_cell(worksheet, row, 3, xlsx_data_type[iec_north_tag->data_type], format);
	} else {
	    write_string_cell(worksheet, row, 3, "unknown", format);
	}
	
	write_number_cell(worksheet, row, 4, iec_north_tag->coefficient, format);
    
	// 确保property有效
	if (mq_north_tag->tag->property >= 0 && mq_north_tag->tag->property < PROPERTY_MAX) {
	    write_string_cell(worksheet, row, 5, property_name[mq_north_tag->tag->property], format);
	} else {
	    write_string_cell(worksheet, row, 5, "unknown", format);
	}
    
	// 处理描述字段
	if (mq_north_tag->tag->desc != NULL && strlen(mq_north_tag->tag->desc) > 0){
		write_string_cell(worksheet, row, 6, mq_north_tag->tag->desc, format);
	}
	else
	{
		char *dynamic_desc = add_dynamic_desc(mq_north_tag->tag->name);
		if (dynamic_desc != NULL) {
			write_string_cell(worksheet, row, 6, dynamic_desc, format);
			free(dynamic_desc);
		}
	}
	
	// 处理有效标志
	if (mq_north_tag->tag->active){ // 无效
	    write_string_cell(worksheet, row, 7, _("Invalid"), format);
	    write_string_cell(worksheet, row, 1, _("Reserved"), format);
	}
}
// 比较函数：用于IEC104 EMS遥测点按addr_S排序
static int iec_compare_rm_tag_by_addr_S(const void *a, const void *b) {
    mq_north_tag_t *tag_a = *(mq_north_tag_t **)a;
    mq_north_tag_t *tag_b = *(mq_north_tag_t **)b;
    
    if (tag_a == NULL || tag_b == NULL) return 0;
    
    iec_north_tag_t *iec_tag_a = (iec_north_tag_t *)tag_a->proto_ptr;
    iec_north_tag_t *iec_tag_b = (iec_north_tag_t *)tag_b->proto_ptr;
    
    if (iec_tag_a == NULL || iec_tag_b == NULL) return 0;
    
    // 按addr_S升序排序
    if (iec_tag_a->addr_S < iec_tag_b->addr_S) return -1;
    if (iec_tag_a->addr_S > iec_tag_b->addr_S) return 1;
    return 0;
}
static void iec_write_worksheet_title(lxw_worksheet *worksheet, int row, lxw_format *format, iec_code_t iec_code) {

	char buff[32] = {0};
	switch (iec_code) {
		case RP_CODE:
			snprintf(buff, 32, "%s", _("Teleindication address"));  // 遥信地址
			break;
		case RM_CODE:
			snprintf(buff, 32, "%s", _("Telemeasurement address")); // 遥测地址
			break;
		case RC_CODE:
			snprintf(buff, 32, "%s", _("Telecommand address"));     // 遥控地址
			break;
		case RR_CODE:
			snprintf(buff, 32, "%s", _("Teleadjusting address"));   // 遥调地址
			break;
		default:
			snprintf(buff, 32, "%s", _("Not supported"));   // 不支持 
			break;
	}
	write_string_cell(worksheet, row, 0, buff, format);
	write_string_cell(worksheet, row, 1, _("Name"),   format);     // 名称
	write_string_cell(worksheet, row, 2, _("Permission"), format); // 权限
	write_string_cell(worksheet, row, 3, _("Data type"), format);  // 数据类型
	write_string_cell(worksheet, row, 4, _("Precision"), format);  // 精度
	write_string_cell(worksheet, row, 5, _("Attribute"), format);  // 属性
	write_string_cell(worksheet, row, 6, _("Description"), format);// 描述
	write_string_cell(worksheet, row, 7, _("Is it valid (default: valid)"), format); // 是否有效（默认：有效）
}

static int create_iec_external_xlsx(mq_xlsx_book_t *mq_xlsx_book)
{
    chdir(NORTH_EXCEL_FILE_DOWNLOAD_PATH);

    int i = 0, j = 0;
	char dev_info[128] = "";
    mq_xlsx_book->workbook = workbook_new(mq_xlsx_book->name);
    if (mq_xlsx_book->workbook == NULL) {
		ems_syslog(LOG_ERR, "Error in workbook_new()"
               "Error = %s\n", "Failed to create the workbook!!!");
		return -1;
	}

    north_info_t *north_info = get_north_info();
	xlsx_home_page(mq_xlsx_book->workbook, north_info->protocol_type, _iec_home_page, num_iec); // 首表

	lxw_format *merge_format = create_center_bold_bg_format(mq_xlsx_book->workbook, LXW_COLOR_CYAN, 12);
    lxw_format *format1 = create_left_bold_format(mq_xlsx_book->workbook, 12);
	lxw_format *format2 = create_left_format(mq_xlsx_book->workbook, 12);
	for (i = 0; i < mq_xlsx_book->num; i++) {
		mq_xlsx_sheet_t *mq_xlsx_sheet = mq_xlsx_book->mq_xlsx_sheet[i];

	    mq_xlsx_sheet->worksheet = workbook_add_worksheet(mq_xlsx_book->workbook, _(mq_xlsx_sheet->name));
		if (mq_xlsx_sheet->worksheet == NULL){
			ems_syslog(LOG_ERR, "Error in workbook_add_worksheet()"
			        "Name %s，Error = %s\n", mq_xlsx_sheet->name, "Failed to create the worksheet!!!");
			continue;
		}
		/* Make the columns wider for clarity. */
		set_column_width(mq_xlsx_sheet->worksheet, 0, 0, 40);
		set_column_width(mq_xlsx_sheet->worksheet, 1, 1, 40);
		set_column_width(mq_xlsx_sheet->worksheet, 2, 2, 20);
		set_column_width(mq_xlsx_sheet->worksheet, 3, 3, 20);
		set_column_width(mq_xlsx_sheet->worksheet, 4, 4, 20);
		set_column_width(mq_xlsx_sheet->worksheet, 5, 5, 20);
		set_column_width(mq_xlsx_sheet->worksheet, 6, 6, 50);
		set_column_width(mq_xlsx_sheet->worksheet, 7, 7, 50);

		for (j = 0; j < mq_xlsx_sheet->num; j++) {
			mq_xlsx_dev_t *mq_xlsx_dev = mq_xlsx_sheet->mq_xlsx_dev[j];
			iec_xlsx_dev_t *iec_xlsx_dev = mq_xlsx_dev->proto_ptr;

		    snprintf(dev_info, 128, "no:%s  name:%s  commonAddr:%d", mq_xlsx_dev->no, mq_xlsx_dev->disp_name, iec_xlsx_dev->addr);
	        merge_cells(mq_xlsx_sheet->worksheet, mq_xlsx_sheet->cuurent_row, 0, mq_xlsx_sheet->cuurent_row, 6, dev_info, merge_format);
			mq_xlsx_sheet->cuurent_row++;
			
			iec_write_worksheet_title(mq_xlsx_sheet->worksheet, mq_xlsx_sheet->cuurent_row, format1, RP_CODE);
			mq_xlsx_sheet->cuurent_row++;
			for (int m = 0; m < iec_xlsx_dev->nb_rp; m++) {
                 mq_north_tag_t *mq_north_tag = iec_xlsx_dev->rp_tag[m];
                 iec_write_worksheet_item(mq_xlsx_sheet->worksheet, mq_xlsx_sheet->cuurent_row, format2, mq_north_tag, RP_CODE);
			     mq_xlsx_sheet->cuurent_row++;
			}
			mq_xlsx_sheet->cuurent_row++;

			iec_write_worksheet_title(mq_xlsx_sheet->worksheet, mq_xlsx_sheet->cuurent_row, format1, RM_CODE);
			mq_xlsx_sheet->cuurent_row++;	
			// 仅对IEC104 EMS设备的遥测点按addr_S排序
			if (strcmp(mq_xlsx_dev->no, "EMS") == 0 && iec_xlsx_dev->nb_rm > 1) {
				qsort(iec_xlsx_dev->rm_tag, iec_xlsx_dev->nb_rm, sizeof(mq_north_tag_t *), iec_compare_rm_tag_by_addr_S);
			}
			for (int m = 0; m < iec_xlsx_dev->nb_rm; m++) {
                 mq_north_tag_t *mq_north_tag = iec_xlsx_dev->rm_tag[m];
                 iec_write_worksheet_item(mq_xlsx_sheet->worksheet, mq_xlsx_sheet->cuurent_row, format2, mq_north_tag, RM_CODE);
			     mq_xlsx_sheet->cuurent_row++;
			}
			mq_xlsx_sheet->cuurent_row++;

			iec_write_worksheet_title(mq_xlsx_sheet->worksheet, mq_xlsx_sheet->cuurent_row, format1, RC_CODE);
			mq_xlsx_sheet->cuurent_row++;
			for (int m = 0; m < iec_xlsx_dev->nb_rc; m++) {
                 mq_north_tag_t *mq_north_tag = iec_xlsx_dev->rc_tag[m];
                 iec_write_worksheet_item(mq_xlsx_sheet->worksheet, mq_xlsx_sheet->cuurent_row, format2, mq_north_tag, RC_CODE);
			     mq_xlsx_sheet->cuurent_row++;
			}
			mq_xlsx_sheet->cuurent_row++;

			iec_write_worksheet_title(mq_xlsx_sheet->worksheet, mq_xlsx_sheet->cuurent_row, format1, RR_CODE);
			mq_xlsx_sheet->cuurent_row++;	
			for (int m = 0; m < iec_xlsx_dev->nb_rr; m++) {
                 mq_north_tag_t *mq_north_tag = iec_xlsx_dev->rr_tag[m];
                 iec_write_worksheet_item(mq_xlsx_sheet->worksheet, mq_xlsx_sheet->cuurent_row, format2, mq_north_tag, RR_CODE);
			     mq_xlsx_sheet->cuurent_row++;
			}
				
			mq_xlsx_sheet->cuurent_row += DEV_BETWEEN_ROW;
		}
	}   

    /* Close the workbook, save the file and free any memory. */
    lxw_error error = workbook_close(mq_xlsx_book->workbook);

    /* Check if there was any error creating the xlsx file. */
    if (error){
        ems_syslog(LOG_ERR, "Error in workbook_close().\n"
               "Error %d = %s\n", error, lxw_strerror(error));
        return error;
    }

	return 0;

}

static void iec_write_inside_taginfo(int find, cJSON *g_points, cJSON *points, int flag, mq_north_tag_t *mq_north_tag) {

    // 防御性检查，防止空指针崩溃
    if (mq_north_tag == NULL) {
        ems_syslog(LOG_ERR, "iec_write_inside_taginfo: mq_north_tag is NULL");
        return;
    }
    
    if (mq_north_tag->tag == NULL) {
        ems_syslog(LOG_ERR, "iec_write_inside_taginfo: mq_north_tag->tag is NULL");
        return;
    }
    
    if ((find == 1 && points == NULL) || (find == 0 && g_points == NULL)) {
        return;
    }
    
    char buff[32] = {0};
    iec_north_tag_t *iec_north_tag = mq_north_tag->proto_ptr;
    
    if (iec_north_tag == NULL) {
        return;
    }
    
    cJSON *tag = cJSON_CreateArray();
    if (tag == NULL) {
        ems_syslog(LOG_ERR, "iec_write_inside_taginfo: failed to create cJSON array");
        return;
    }
    
    // 添加dev_tag_name到数组
    if (mq_north_tag->tag->dev_tag_name[0] == '\0') {
        cJSON_AddItemToArray(tag, cJSON_CreateString("unknown_tag"));
    } else {
        cJSON_AddItemToArray(tag, cJSON_CreateString(mq_north_tag->tag->dev_tag_name));
    }

    // 处理addr或addr_S
    if (flag) {
        snprintf(buff, 32, "%d", iec_north_tag->addr_S);
    } else {
        snprintf(buff, 32, "%d", iec_north_tag->addr);
    }
    
    cJSON_AddItemToArray(tag, cJSON_CreateString(buff));
    
    // 添加data_type到数组
    if (iec_north_tag->data_type >= 0 && iec_north_tag->data_type < TYPE_MAX) {
        cJSON_AddItemToArray(tag, cJSON_CreateString(type_string[iec_north_tag->data_type]));
    } else {
        cJSON_AddItemToArray(tag, cJSON_CreateString("unknown_type"));
    }
    
    cJSON_AddItemToArray(tag, cJSON_CreateNumber(iec_north_tag->changeReport));
    cJSON_AddItemToArray(tag, cJSON_CreateNumber(iec_north_tag->coefficient));
    
    // 添加tag到对应的数组
    if (find) {
        cJSON_AddItemToArray(points, tag);
    } else {
        cJSON_AddItemToArray(g_points, tag);
    }
}

static char *create_iec_inside_json(mq_north_inside_t *mq_north_inside)
{
	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;
	}
	iec_proto_info_t *iec_proto_info = get_iec104_proto_info();
	
	// Add version field only if needed
	north_info_t *north_info = get_north_info();
	if (north_info->need_add_version) {
		cJSON_AddNumberToObject(root, "version", 2);
	}
	// Keep ver field for backward compatibility
	cJSON_AddNumberToObject(root, "ver", iec_proto_info->ver);
	cJSON_AddNumberToObject(root, "server_port", iec_proto_info->server_port);
	cJSON_AddNumberToObject(root, "periodReportEnable", iec_proto_info->periodReportEnable);
	cJSON_AddNumberToObject(root, "reportInterval", iec_proto_info->reportInterval);
	cJSON *pts = cJSON_CreateArray();
	cJSON_AddItemToObject(root, "pts", pts);

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

        cJSON *g_rp_arry = NULL;
		cJSON *g_rm_arry = NULL;
		cJSON *g_rc_arry = NULL;
		cJSON *g_rr_arry = NULL;
		if ((strcmp(mq_north_class->class_type, "PCS") != 0) && (strcmp(mq_north_class->class_type, "BMS") != 0) && (strcmp(mq_north_class->class_type, "CELL") != 0) && (strcmp(mq_north_class->class_type, "EMS") != 0)){
			cJSON *domain = cJSON_CreateObject();

			// iec_class_info_t *iec_class_info = NULL;
			int p_compatible_id = 0;
			int index = iec_match_by_class_type(&(mq_north_class->class_type), iec_proto_info->iec_class_info, &p_compatible_id, 0);
			if (index == -1){
				continue;
			}else
			{
				// iec_class_info = &(iec_proto_info->iec_class_info[index]);
			}

			iec_north_class_t *iec_north_class = (iec_north_class_t *)mq_north_class->proto_ptr;
			cJSON_AddNumberToObject(domain, "commonAddr", iec_north_class->iec_class_info->str_addr); // 非PCS\BMS\CELL\EMS类型 则设备公共地址固定	common addr		
			cJSON *pointInfo = cJSON_CreateArray();
			cJSON_AddItemToObject(domain, "pointInfo", pointInfo);
			cJSON_AddItemToArray(pts, domain);

			cJSON *rp = cJSON_CreateObject();
			cJSON_AddStringToObject(rp, "type", "RemotePoint");
			g_rp_arry = cJSON_CreateArray();
			cJSON_AddItemToObject(rp, "points", g_rp_arry);
			cJSON_AddItemToArray(pointInfo, rp);

			cJSON *rm = cJSON_CreateObject();
			cJSON_AddStringToObject(rm, "type", "RemoteMeas");
			g_rm_arry = cJSON_CreateArray();
			cJSON_AddItemToObject(rm, "points", g_rm_arry);
			cJSON_AddItemToArray(pointInfo, rm);

			cJSON *rc = cJSON_CreateObject();
			cJSON_AddStringToObject(rc, "type", "RemoteCtrl");
			g_rc_arry = cJSON_CreateArray();
			cJSON_AddItemToObject(rc, "points", g_rc_arry);
			cJSON_AddItemToArray(pointInfo, rc);

			cJSON *rr = cJSON_CreateObject();
			cJSON_AddStringToObject(rr, "type", "RemoteRegu");
			g_rr_arry = cJSON_CreateArray();
			cJSON_AddItemToObject(rr, "points", g_rr_arry);
			cJSON_AddItemToArray(pointInfo, rr);
		}

		for (j = 0; j < mq_north_class->num; j++) {
			mq_north_dev_t *mq_north_dev = mq_north_class->mq_north_dev[j];
			iec_north_dev_t *iec_north_dev = (iec_north_dev_t *)mq_north_dev->proto_ptr;
			int find = 0;
			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) || (strcmp(mq_north_dev->class_type, "EMS") == 0)){
				find = 1;
			}	 

			cJSON *rp_arry = NULL;
			cJSON *rm_arry = NULL;
			cJSON *rc_arry = NULL;
			cJSON *rr_arry = NULL;
			if (find){
				cJSON *domain = cJSON_CreateObject();
							
				cJSON_AddNumberToObject(domain, "commonAddr", iec_north_dev->addr);
				cJSON *pointInfo = cJSON_CreateArray();
				cJSON_AddItemToObject(domain, "pointInfo", pointInfo);
				cJSON_AddItemToArray(pts, domain);
				
				cJSON *rp = cJSON_CreateObject();
				cJSON_AddStringToObject(rp, "type", "RemotePoint");
				rp_arry = cJSON_CreateArray();
				cJSON_AddItemToObject(rp, "points", rp_arry);
				cJSON_AddItemToArray(pointInfo, rp);
				
				cJSON *rm = cJSON_CreateObject();
				cJSON_AddStringToObject(rm, "type", "RemoteMeas");
				rm_arry = cJSON_CreateArray();
				cJSON_AddItemToObject(rm, "points", rm_arry);
				cJSON_AddItemToArray(pointInfo, rm);
				
				cJSON *rc = cJSON_CreateObject();
				cJSON_AddStringToObject(rc, "type", "RemoteCtrl");
				rc_arry = cJSON_CreateArray();
				cJSON_AddItemToObject(rc, "points", rc_arry);
				cJSON_AddItemToArray(pointInfo, rc);
				
				cJSON *rr = cJSON_CreateObject();
				cJSON_AddStringToObject(rr, "type", "RemoteRegu");
				rr_arry = cJSON_CreateArray();
				cJSON_AddItemToObject(rr, "points", rr_arry);
				cJSON_AddItemToArray(pointInfo, rr);
			}
			for (int m = 0; m < iec_north_dev->nb_rp; m++) {
				mq_north_tag_t *mq_north_tag = iec_north_dev->rp_tag[m];		
				if (mq_north_tag != NULL) {
					iec_write_inside_taginfo(find, g_rp_arry, rp_arry, 0, mq_north_tag);
				}
			}
			for (int m = 0; m < iec_north_dev->nb_rm; m++) {
				mq_north_tag_t *mq_north_tag = iec_north_dev->rm_tag[m];  		
				if (mq_north_tag != NULL) {
					iec_write_inside_taginfo(find, g_rm_arry, rm_arry, 1, mq_north_tag);
				}
			}
			for (int m = 0; m < iec_north_dev->nb_rc; m++) {
				mq_north_tag_t *mq_north_tag = iec_north_dev->rc_tag[m];			
				if (mq_north_tag != NULL) {
					iec_write_inside_taginfo(find, g_rc_arry, rc_arry, 0, mq_north_tag);
				}
			}
			for (int m = 0; m < iec_north_dev->nb_rr; m++) {
				mq_north_tag_t *mq_north_tag = iec_north_dev->rr_tag[m];
				if (mq_north_tag != NULL) {
					iec_write_inside_taginfo(find, g_rr_arry, rr_arry, 0, mq_north_tag);
				}
			}
		}
	}

	string = cJSON_Print(root);
end:
	if (root != NULL)
	{
		cJSON_Delete(root);
	}
	//ems_syslog(LOG_NOTICE,"%s",string);
	return string;

}

char *create_iec_relate_file(mq_north_inside_t *mq_north_inside, mq_xlsx_book_t *mq_xlsx_book){
    //int ret = 0;
	char *iec_inside_json = NULL;

	iec_inside_json = create_iec_inside_json(mq_north_inside);
	if (iec_inside_json)
	{
		if (check_file_exist(IEC104_NORTH_MAP_FILE) == 0)
			write_file_data(NORTH_CONFIG_PATH"/"IEC104_NORTH_MAP_FILE, iec_inside_json, strlen(iec_inside_json));
	}
	else
	{
		ems_syslog(LOG_ERR, "create iec104_north.json error!!!!");
	}

    if (check_file_exist(mq_xlsx_book->name) == 0)
		create_iec_external_xlsx(mq_xlsx_book);

	return iec_inside_json;	
}
void init_iec_north_dev(iec_north_dev_t *dev) {
    for (int i = 0; i < TAG_NUM; i++) {
        dev->rp_tag[i] = NULL;
        dev->rc_tag[i] = NULL;
    }
    for (int i = 0; i < TAG_NUM; i++) {
        dev->rm_tag[i] = NULL;
        dev->rr_tag[i] = NULL;
    }
}

void init_iec_xlsx_dev(iec_xlsx_dev_t *dev) {
    for (int i = 0; i < TAG_NUM; i++) {
        dev->rp_tag[i] = NULL;
        dev->rc_tag[i] = NULL;
    }
    for (int i = 0; i < TAG_NUM; i++) {
        dev->rm_tag[i] = NULL;
        dev->rr_tag[i] = NULL;
    }
}

void clear_iec104_class_nb(iec_class_info_t *iec_class_info){ // iec104清零类，遥信、遥测、遥控、遥调个数
	for (int i = 0; i < CLASS_NUM; i++) {
		iec_class_info[i].nb_rp = 0;
		iec_class_info[i].nb_rm = 0;
        iec_class_info[i].nb_rc = 0;
		iec_class_info[i].nb_rr = 0;
	}
}

