/**
 * @file    plc.cpp
 * @brief   PLC 逻辑引擎 — XML 驱动可编程逻辑控制器
 *
 * @details 完整复刻原工程 libplc 模块, 仅在与其他模块交互的接口处做了适配。
 *          其余程序原封不动。
 *
 *          核心能力:
 *          - XML 配置文件驱动 (PLCConfig → Chain → Comb/Gate/Inputs/Outputs)
 *          - 10 种逻辑门: INPUT / OUTPUT / AND / OR / NOT /
 *            T62P(延时导通) / T62D(延时关断) / RISING / FALLING / SR / RS
 *          - 嵌套 Comb 支持递归解析, R/S 引脚属性
 *          - Kahn 拓扑排序 (保证节点按依赖顺序执行, 检测环路)
 *          - 非阻塞定时器 (clock_gettime CLOCK_MONOTONIC)
 *          - mtime 文件变化检测 (stat, 仅在 XML 更新时重新解析)
 *          - 与 self_ptl 遥信联动 (dc_signal_out_link_with_callback 链接到 self_ptl 配置的遥信信号)
 *          - 经 datacenter 写入 out 信号 (dc_set_out_signal_val)
 *
 *          线程模型: X-Macro 框架 app_plc 线程, EV_TIMER3(1s) 触发 PLC_Logic()
 *
 *          配置: config/PLC/Reclose_logic.xml (运行时 func_proc_self_dir 拼接)
 */

#include "plc.h"
#include "self_ptl.h"
#include "self_ptl_cfg.h"
#include "myBase.h"
#include "mySystem.h"
#include "myDatacenter.h"
#include "myLog.h"
#include "myCmd.h"
#include "myFunc.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>      // clock_gettime 非阻塞定时器
#include <sys/stat.h>  // stat() 文件变化检测
#include "tinyxml2.h"  // XML 配置文件解析

/* ==================================================================
 * 调试宏 — 运行时可通过 `plc dbg on|off` 开关
 * ================================================================== */

static int g_plc_dbg_enabled = 0; /**< PLC 调试打印开关, 0=关闭, 1=打开 */

/** 调试打印宏 — 仅在 g_plc_dbg_enabled 非零时输出到 stdout */
#define PLC_DBG(fmt, ...) \
	do { if (g_plc_dbg_enabled) { printf(fmt, ##__VA_ARGS__); } } while (0)

/* ==================================================================
 * 模块常量 & 全局变量
 * ================================================================== */

#define MAX_OUT_NODES 20    /**< 最大输出节点数 */

LOCAL uint8_t  g_plc_st_out[MAX_OUT_NODES] = {0};
LOCAL uint32_t *gp_run_cnt_in = NULL;
LOCAL uint8_t  *gp_st[10] = {NULL};

/** PLC 与 self_ptl 遥信的关联配置 */
typedef struct
{
	stru_self_ptl_cfg_base base;
	uint8_t * p_data;
} stru_plc_cfg;

stru_self_ptl_cfg *p_plc_cfg = nullptr;
std::vector<stru_plc_cfg> g_plc_cfg = {};

/* ==================================================================
 * 逻辑引擎常量 & 数据结构
 * ================================================================== */

#define MAX_LOGIC_GRAPHS  4    /**< 最大逻辑图数量 */
#define MAX_NODES_PER_GRAPH 64 /**< 每个逻辑图最大节点数 */
#define MAX_LINKS_PER_GRAPH 64 /**< 每个逻辑图最大链路数 */

/** 节点类型 — 10 种逻辑门 + 硬件点 */
#define NODE_TYPE_HW_OUTPUT    0  /**< 硬件输出点 */
#define NODE_TYPE_HW_INPUT     1  /**< 硬件输入点 */
#define NODE_TYPE_OR_GATE      2  /**< 或门 */
#define NODE_TYPE_AND_GATE     3  /**< 与门 */
#define NODE_TYPE_NOT_GATE     4  /**< 非门 */
#define NODE_TYPE_62P_GATE     5  /**< 62P 延时导通 (IN=1 延时后 OUT=1, IN=0 立即 OUT=0) */
#define NODE_TYPE_62D_GATE     6  /**< 62D 延时关断 (IN=1 立即 OUT=1, IN=0 延时后 OUT=0) */
#define NODE_TYPE_RISING_EDGE  7  /**< 上升沿检测 (0→1 脉冲) */
#define NODE_TYPE_SR_LATCH     8  /**< SR 触发器 (S 优先) */
#define NODE_TYPE_RS_LATCH     9  /**< RS 触发器 (R 优先) */
#define NODE_TYPE_FALLING_EDGE 10 /**< 下降沿检测 (1→0 脉冲) */

/** 动态链表 — 硬件点 (运行时 I/O 状态) */
typedef struct HWPoint
{
	int   id;
	int   value;
	struct HWPoint *next;
} HWPoint;

typedef struct
{
	HWPoint *input_head;
	HWPoint *output_head;
	int      input_count;
	int      output_count;
} HardwareManager;

/** 逻辑节点 — 一个门元件或硬件点 */
typedef struct
{
	int    type;
	int    id;
	int    value;
	int    last_input;           /**< 上一轮输入值 (边沿检测用) */

	/* ---- 非阻塞定时器 (62P/62D) ---- */
	uint8_t        timer_active;         /**< 1=正在计时 */
	struct timespec timer_start;         /**< 计时起点 */
	int            timer_delay_ms;       /**< 延时毫秒数 */
	int            timer_pending_output; /**< 到期后输出值, -1=无待定 */
	int            delay_ms;             /**< XML 配置的延时 (delayMs) */

	/* ---- SR/RS 引脚来源描述 ---- */
	char rs_s_src[32];
	char rs_r_src[32];

	/* ---- 拓扑排序 ---- */
	int indegree;                        /**< 入度 (依赖的前驱节点数) */
} LogicNode;

/** 逻辑链路 — 节点间连线 */
typedef struct
{
	int src_type;
	int src_id;
	int dest_type;
	int dest_id;
	int dst_pin;                         /**< 目标引脚 (0=S, 1=R, -1=默认), 仅 SR/RS 有效 */
} LogicLink;

/** 逻辑图 — 一张完整的 PLC 逻辑图 */
typedef struct
{
	char       key[20];                  /**< 逻辑图标识 */
	char       name[50];                 /**< 逻辑图名称 */
	LogicNode  nodes[MAX_NODES_PER_GRAPH];
	int        node_count;
	LogicLink  links[MAX_LINKS_PER_GRAPH];
	int        link_count;
} LogicGraph;

/* ==================================================================
 * PLC 全局状态
 * ================================================================== */

LOCAL LogicGraph g_cached_graphs[MAX_LOGIC_GRAPHS]; /**< 缓存的逻辑图 */
LOCAL int        g_cached_graph_count = 0;           /**< 缓存的逻辑图数量 */
LOCAL time_t     g_last_file_mtime = 0;              /**< 配置文件最后修改时间 */
LOCAL char       g_plc_config_path[256] = "config/PLC/Reclose_logic.xml";

/* ==================================================================
 * LOCAL 封装 — 简化 datacenter out 信号访问
 * ================================================================== */

/**
 * @brief 通过 out 信号 ID 写入值 (内部封装 dc_get_signal_info_by_id → dc_set_out_signal_val)
 * @param id      out 信号 ID (XML 中 Signal 的 no 属性)
 * @param value   写入值 (0 或 1)
 * @return 0=成功, -1=未找到该信号
 */
LOCAL int plc_set_out_by_id(int id, int value)
{
	char    saddr[128]     = {0};
	char    desc[128]      = {0};
	char    dtype_str[32]  = {0};
	char    link_str[256]  = {0};
	uint8_t ctrl_type;

	if (0 != dc_get_signal_info_by_id("out", (uint32_t)id,
		saddr, sizeof(saddr), desc, sizeof(desc),
		dtype_str, sizeof(dtype_str), &ctrl_type,
		link_str, sizeof(link_str)))
	{
		return -1;
	}

	uint8_t val = (uint8_t)(value ? 1 : 0);
	return dc_set_out_signal_val(saddr, &val, "plc");
}

/**
 * @brief 通过 out 信号 ID 读取当前值
 * @param id   out 信号 ID
 * @return 信号值 (0/1), 未找到时返回 0
 */
LOCAL int plc_get_out_value_by_id(int id)
{
	char    saddr[128]     = {0};
	char    desc[128]      = {0};
	char    dtype_str[32]  = {0};
	char    link_str[256]  = {0};
	uint8_t ctrl_type;

	if (0 != dc_get_signal_info_by_id("out", (uint32_t)id,
		saddr, sizeof(saddr), desc, sizeof(desc),
		dtype_str, sizeof(dtype_str), &ctrl_type,
		link_str, sizeof(link_str)))
	{
		return 0;
	}

	void    *p_data    = NULL;
	uint8_t  data_type = 0;
	char     d2[128]   = {0};

	if (0 != dc_get_out_signal_info(saddr, d2, sizeof(d2), &data_type, &p_data) || NULL == p_data)
	{
		return 0;
	}

	if (data_type == DATA_TYPE_U8)
	{
		return *(uint8_t *)p_data;
	}
	else if (data_type == DATA_TYPE_U16)
	{
		return (*(uint16_t *)p_data) ? 1 : 0;
	}
	else if (data_type == DATA_TYPE_U32)
	{
		return (*(uint32_t *)p_data) ? 1 : 0;
	}
	else if (data_type == DATA_TYPE_F32)
	{
		return (*(float *)p_data > 0.5f) ? 1 : 0;
	}

	return 0;
}

/* ==================================================================
 * 硬件点链表操作
 * ================================================================== */
static HWPoint* create_hw_point(int id, int value)
{
    HWPoint *point = (HWPoint*)malloc(sizeof(HWPoint));
    if (point)
    {
        point->id = id;
        point->value = value;
        point->next = NULL;
    }
    return point;
}

// 计算从 start 到当前时刻经过的毫秒数
static long get_elapsed_ms(struct timespec *start)
{
    struct timespec now;
    clock_gettime(CLOCK_MONOTONIC, &now);
    long sec_diff = now.tv_sec - start->tv_sec;
    long nsec_diff = now.tv_nsec - start->tv_nsec;
    return sec_diff * 1000 + nsec_diff / 1000000;
}

static void destroy_hw_list(HWPoint *head)
{
    HWPoint *tmp;
    while (head)
    {
        tmp = head;
        head = head->next;
        free(tmp);
    }
}

static void init_hardware_manager(HardwareManager *hw)
{
    memset(hw, 0, sizeof(HardwareManager));
}

static void destroy_hardware_manager(HardwareManager *hw)
{
    destroy_hw_list(hw->input_head);
    destroy_hw_list(hw->output_head);
    memset(hw, 0, sizeof(HardwareManager));
}

static int get_hw_point_value(HWPoint *head, int id)
{
	HWPoint *curr = head;

	while (curr)
	{
		if (curr->id == id)
		{
			return curr->value;
		}

		curr = curr->next;
	}

	return 0;
}

static int set_hw_point_value(HWPoint **head, int *count, int id, int value)
{
    HWPoint *curr = *head;
    while (curr)
    {
        if (curr->id == id)
        {
            curr->value = value;
            return 0;
        }
        curr = curr->next;
    }
    HWPoint *new_point = create_hw_point(id, value);
    if (!new_point)
    {
        LOG_E("PLC: 内存分配失败, 无法创建硬件点 ID=%d", id);
        return -1;
    }
    new_point->next = *head;
    *head = new_point;
    (*count)++;
    return 0;
}

// 从逻辑图中提取所有硬件点到管理器
static void extract_hw_points_from_graphs(LogicGraph graphs[], int graph_count,
                                          HardwareManager *hw, int default_input_value) {
    for (int g = 0; g < graph_count; g++)
    {
        LogicGraph *graph = &graphs[g];
        for (int n = 0; n < graph->node_count; n++)
        {
            LogicNode *node = &graph->nodes[n];
		if (node->type == NODE_TYPE_HW_INPUT)
			{
				default_input_value = plc_get_out_value_by_id(node->id);
				set_hw_point_value(&hw->input_head, &hw->input_count,
				                   node->id, default_input_value);
			}
			else if (node->type == NODE_TYPE_HW_OUTPUT)
			{
                set_hw_point_value(&hw->output_head, &hw->output_count, node->id, 0);
            }
        }
    }
}

static void print_hardware_manager(HardwareManager *hw)
{
    PLC_DBG("==================== 硬件点列表 ====================\n");
    PLC_DBG("硬件输入点（dev_out）：共%d个\n", hw->input_count);
    HWPoint *curr = hw->input_head;
    int idx = 1;
    while (curr)
    {
        PLC_DBG("  %d. ID=%d, 值=%d\n", idx++, curr->id, curr->value);
        curr = curr->next;
    }
    PLC_DBG("硬件输出点（dev_in）：共%d个\n", hw->output_count);
    curr = hw->output_head;
    idx = 1;
    while (curr)
    {
        PLC_DBG("  %d. ID=%d, 值=%d\n", idx++, curr->id, curr->value);
        curr = curr->next;
    }
}

/* ==================================================================
 * 节点查找
 * ================================================================== */
static LogicNode* find_node(LogicGraph *graph, int type, int id)
{
    for (int i = 0; i < graph->node_count; i++)
    {
        if ((type == 0) || (type == 1))
        {
            if (graph->nodes[i].type == type && graph->nodes[i].id == id)
            {
                return &graph->nodes[i];
            }
        }
        else
        {
            if (graph->nodes[i].type == type &&
                ((graph->nodes[i].id & 0xFF) == (id & 0xFF))) {
                return &graph->nodes[i];
            }
        }
    }
    return NULL;
}

/* ==================================================================
 * XML 配置文件解析 (Comb 嵌套结构)
 * ================================================================== */

static int gate_type_from_xml_str(const char *type_str)
{
	if (NULL == type_str)
	{
		return -1;
	}

	if (strcmp(type_str, "INPUT") == 0)
	{
		return NODE_TYPE_HW_INPUT;
	}
	if (strcmp(type_str, "OUTPUT") == 0)
	{
		return NODE_TYPE_HW_OUTPUT;
	}
	if (strcmp(type_str, "OR") == 0)
	{
		return NODE_TYPE_OR_GATE;
	}
	if (strcmp(type_str, "AND") == 0)
	{
		return NODE_TYPE_AND_GATE;
	}
	if (strcmp(type_str, "NOT") == 0)
	{
		return NODE_TYPE_NOT_GATE;
	}
	if (strcmp(type_str, "T62P") == 0)
	{
		return NODE_TYPE_62P_GATE;
	}
	if (strcmp(type_str, "T62D") == 0)
	{
		return NODE_TYPE_62D_GATE;
	}
	if (strcmp(type_str, "RISING") == 0)
	{
		return NODE_TYPE_RISING_EDGE;
	}
	if (strcmp(type_str, "SR") == 0)
	{
		return NODE_TYPE_SR_LATCH;
	}
	if (strcmp(type_str, "RS") == 0)
	{
		return NODE_TYPE_RS_LATCH;
	}
	if (strcmp(type_str, "FALLING") == 0)
	{
		return NODE_TYPE_FALLING_EDGE;
	}

	return -1;
}

static int find_node_index(LogicGraph *graph, int type, int id)
{
	for (int i = 0; i < graph->node_count; i++)
	{
		if (graph->nodes[i].type == type)
		{
			if (type <= 1 && graph->nodes[i].id == id)
			{
				return i;
			}
			if (type > 1 && (graph->nodes[i].id & 0xFF) == (id & 0xFF))
			{
				return i;
			}
		}
	}

	return -1;
}

/**
 * @brief Comb 内部信号 — 不存在则先创建
 * @param io_type  节点类型 (NODE_TYPE_HW_INPUT / NODE_TYPE_HW_OUTPUT)
 * @param sig_no   信号编号
 * @return 节点在 nodes[] 中的索引, -1=失败
 */
static int ensure_signal(LogicGraph *graph, int io_type, int sig_no)
{
	int idx = find_node_index(graph, io_type, sig_no);

	if (idx >= 0)
	{
		return idx;
	}

	if (graph->node_count >= MAX_NODES_PER_GRAPH)
	{
		return -1;
	}

	LogicNode &n = graph->nodes[graph->node_count++];
	memset(&n, 0, sizeof(n));
	n.timer_pending_output = -1;
	n.type = io_type;
	n.id   = sig_no;

	return graph->node_count - 1;
}

/**
 * @brief 递归解析 Comb 块: Inputs → [嵌套 Comb] → Gate → Outputs
 * @param comb_el  XML Comb 元素
 * @param graph    逻辑图 (边解析边追加节点/链路)
 * @return 本 Comb 中 Gate 节点的索引, -1=失败
 */
static int parse_xml_comb(tinyxml2::XMLElement *comb_el, LogicGraph *graph)
{
	if (NULL == comb_el || graph->node_count >= MAX_NODES_PER_GRAPH)
	{
		return -1;
	}

	tinyxml2::XMLElement *gate_el = comb_el->FirstChildElement("Gate");

	if (NULL == gate_el)
	{
		LOG_E("Comb缺少Gate");
		return -1;
	}

	LogicNode &gn = graph->nodes[graph->node_count++];
	memset(&gn, 0, sizeof(gn));
	gn.timer_pending_output = -1;
	gn.type = gate_type_from_xml_str(gate_el->Attribute("type"));
	gn.id   = gate_el->IntAttribute("id");

	int gi = graph->node_count - 1;

	/* 读取延时毫秒 (62P/62D) */
	const char *delay_str = gate_el->Attribute("delayMs");

	if (delay_str)
	{
		gn.delay_ms = atoi(delay_str);
	}
	else
	{
		gn.delay_ms = 1000;
	}

	/* 读取 SR/RS 的 R/S 属性 */
	const char *r_attr = gate_el->Attribute("R");
	const char *s_attr = gate_el->Attribute("S");

	if (r_attr)
	{
		strncpy(gn.rs_r_src, r_attr, sizeof(gn.rs_r_src) - 1);
	}
	if (s_attr)
	{
		strncpy(gn.rs_s_src, s_attr, sizeof(gn.rs_s_src) - 1);
	}

	int is_srrs = (gn.type == NODE_TYPE_SR_LATCH || gn.type == NODE_TYPE_RS_LATCH);

	/* 收集嵌套 Comb 的 Gate 索引 (按 id 映射, 用于 R/S 解析) */
	int sub_gate_by_comb_id[16] = {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1};
	int sub_gate_count = 0;

	for (tinyxml2::XMLElement *nc = comb_el->FirstChildElement("Comb");
	     nc; nc = nc->NextSiblingElement("Comb"))
	{
		int up = parse_xml_comb(nc, graph);

		if (up >= 0)
		{
			int cid = nc->IntAttribute("id");

			if (cid >= 0 && cid < 16)
			{
				sub_gate_by_comb_id[cid] = up;
			}

			sub_gate_count++;

			/* 非 SR/RS: 自动创建嵌套 Comb Gate → 当前 Gate 的链接 */
			if (!is_srrs && graph->link_count < MAX_LINKS_PER_GRAPH)
			{
				LogicLink &l = graph->links[graph->link_count++];
				memset(&l, 0, sizeof(l));
				l.dst_pin   = -1;
				l.src_type  = graph->nodes[up].type;
				l.src_id    = graph->nodes[up].id;
				l.dest_type = gn.type;
				l.dest_id   = gn.id;
			}
		}
	}

	/* SR/RS: 根据 R/S 属性创建链接 */
	if (is_srrs)
	{
		/* 解析 "Comb#N" 或 "Input#N" */
		for (int pin = 0; pin < 2; pin++)
		{
			const char *attr = (pin == 0) ? s_attr : r_attr;

			if (!attr || graph->link_count >= MAX_LINKS_PER_GRAPH)
			{
				continue;
			}

			if (strncmp(attr, "Comb#", 5) == 0)
			{
				int cid = atoi(attr + 5);

				if (cid >= 0 && cid < 16 && sub_gate_by_comb_id[cid] >= 0)
				{
					int up = sub_gate_by_comb_id[cid];
					LogicLink &l = graph->links[graph->link_count++];
					memset(&l, 0, sizeof(l));
					l.src_type  = graph->nodes[up].type;
					l.src_id    = graph->nodes[up].id;
					l.dest_type = gn.type;
					l.dest_id   = gn.id;

					/* SR: S=pin0, R=pin1; RS: S=pin1, R=pin0 */
					if (gn.type == NODE_TYPE_SR_LATCH)
					{
						l.dst_pin = pin;
					}
					else
					{
						l.dst_pin = 1 - pin;
					}
				}
			}
			else if (strncmp(attr, "Input#", 6) == 0)
			{
				int ino = atoi(attr + 6);
				int si  = ensure_signal(graph, NODE_TYPE_HW_INPUT, ino);

				if (si >= 0)
				{
					LogicLink &l = graph->links[graph->link_count++];
					memset(&l, 0, sizeof(l));
					l.src_type  = NODE_TYPE_HW_INPUT;
					l.src_id    = graph->nodes[si].id;
					l.dest_type = gn.type;
					l.dest_id   = gn.id;

					if (gn.type == NODE_TYPE_SR_LATCH)
					{
						l.dst_pin = pin;
					}
					else
					{
						l.dst_pin = 1 - pin;
					}
				}
			}
		}
	}

	tinyxml2::XMLElement *ins = comb_el->FirstChildElement("Inputs");

	if (ins && !is_srrs)
	{
		for (tinyxml2::XMLElement *sig = ins->FirstChildElement("Signal");
		     sig; sig = sig->NextSiblingElement("Signal"))
		{
			if (graph->link_count >= MAX_LINKS_PER_GRAPH)
			{
				break;
			}

			int si = ensure_signal(graph, NODE_TYPE_HW_INPUT, sig->IntAttribute("no"));

			if (si >= 0)
			{
				LogicLink &l = graph->links[graph->link_count++];
				memset(&l, 0, sizeof(l));
				l.dst_pin   = -1;
				l.src_type  = NODE_TYPE_HW_INPUT;
				l.src_id    = graph->nodes[si].id;
				l.dest_type = gn.type;
				l.dest_id   = gn.id;
			}
		}
	}

	tinyxml2::XMLElement *ous = comb_el->FirstChildElement("Outputs");

	if (ous)
	{
		for (tinyxml2::XMLElement *sig = ous->FirstChildElement("Signal");
		     sig; sig = sig->NextSiblingElement("Signal"))
		{
			if (graph->link_count >= MAX_LINKS_PER_GRAPH)
			{
				break;
			}

			int si = ensure_signal(graph, NODE_TYPE_HW_OUTPUT, sig->IntAttribute("no"));

			if (si >= 0)
			{
				LogicLink &l = graph->links[graph->link_count++];
				memset(&l, 0, sizeof(l));
				l.dst_pin   = -1;
				l.src_type  = gn.type;
				l.src_id    = gn.id;
				l.dest_type = NODE_TYPE_HW_OUTPUT;
				l.dest_id   = graph->nodes[si].id;
			}
		}
	}

	return gi;
}

int parse_reclose_logic_xml(const char *file_path, LogicGraph graphs[], int *graph_count)
{
	tinyxml2::XMLDocument doc;

	if (doc.LoadFile(file_path) != tinyxml2::XML_SUCCESS)
	{
		LOG_E("XML配置文件解析失败: %s", file_path);
		return -1;
	}

	tinyxml2::XMLElement *root = doc.FirstChildElement("PLCConfig");

	if (NULL == root)
	{
		LOG_E("XML根元素<PLCConfig>未找到");
		return -1;
	}

	*graph_count = 0;
	LogicGraph *cur = &graphs[0];
	memset(cur, 0, sizeof(LogicGraph));

	const char *ka = root->Attribute("key");
	const char *na = root->Attribute("name");

	if (ka)
	{
		strncpy(cur->key, ka, sizeof(cur->key) - 1);
	}
	if (na)
	{
		strncpy(cur->name, na, sizeof(cur->name) - 1);
	}

	/* 第一遍: 收集所有节点 */
	for (tinyxml2::XMLElement *chain = root->FirstChildElement("Chain");
	     chain; chain = chain->NextSiblingElement("Chain"))
	{
		tinyxml2::XMLElement *inputs = chain->FirstChildElement("Inputs");

		if (inputs)
		{
			for (tinyxml2::XMLElement *sig = inputs->FirstChildElement("Signal");
			     sig; sig = sig->NextSiblingElement("Signal"))
			{
				ensure_signal(cur, NODE_TYPE_HW_INPUT, sig->IntAttribute("no"));
			}
		}

		for (tinyxml2::XMLElement *cb = chain->FirstChildElement("Comb");
		     cb; cb = cb->NextSiblingElement("Comb"))
		{
			parse_xml_comb(cb, cur);
		}

		for (tinyxml2::XMLElement *gate = chain->FirstChildElement("Gate");
		     gate; gate = gate->NextSiblingElement("Gate"))
		{
			if (cur->node_count >= MAX_NODES_PER_GRAPH)
			{
				break;
			}

			LogicNode &gn = cur->nodes[cur->node_count++];
			memset(&gn, 0, sizeof(gn));
			gn.timer_pending_output = -1;
			gn.type = gate_type_from_xml_str(gate->Attribute("type"));
			gn.id   = gate->IntAttribute("id");
		}

		tinyxml2::XMLElement *outputs = chain->FirstChildElement("Outputs");

		if (outputs)
		{
			for (tinyxml2::XMLElement *sig = outputs->FirstChildElement("Signal");
			     sig; sig = sig->NextSiblingElement("Signal"))
			{
				ensure_signal(cur, NODE_TYPE_HW_OUTPUT, sig->IntAttribute("no"));
			}
		}
	}

	/* 第二遍: Comb 输出 → 链级 Gate, Gate → Outputs */
	for (tinyxml2::XMLElement *chain = root->FirstChildElement("Chain");
	     chain; chain = chain->NextSiblingElement("Chain"))
	{
		bool has_comb = (chain->FirstChildElement("Comb") != NULL);

		/* 收集链级 Gate (不在 Comb 内) */
		tinyxml2::XMLElement *gate_el = NULL;
		tinyxml2::XMLElement *ins_el  = NULL;
		tinyxml2::XMLElement *ous_el  = NULL;
		tinyxml2::XMLElement *c = chain->FirstChildElement();

		while (c)
		{
			if (strcmp(c->Value(), "Gate") == 0)
			{
				gate_el = c;
			}
			if (strcmp(c->Value(), "Inputs") == 0)
			{
				ins_el = c;
			}
			if (strcmp(c->Value(), "Outputs") == 0)
			{
				ous_el = c;
			}

			c = c->NextSiblingElement();
		}

		if (has_comb)
		{
			/* 收集链级 Gate 的 R/S 属性 (RS/SR 用) */
			const char *gateS = NULL;
			const char *gateR = NULL;
			int isChainSRRS = 0;

			if (gate_el)
			{
				int cgtTmp = gate_type_from_xml_str(gate_el->Attribute("type"));

				if (cgtTmp == NODE_TYPE_SR_LATCH || cgtTmp == NODE_TYPE_RS_LATCH)
				{
					isChainSRRS = cgtTmp;
					gateS = gate_el->Attribute("S");
					gateR = gate_el->Attribute("R");
				}
			}

			/* 收集所有 Comb 的 Gate 索引 (第一遍已解析) → Comb Gate → 链级 Gate */
			if (gate_el)
			{
				int cgt = gate_type_from_xml_str(gate_el->Attribute("type"));
				int cgi = find_node_index(cur, cgt, gate_el->IntAttribute("id"));

				if (cgi >= 0)
				{
					/* 遍历所有顶层 Comb Gate */
					for (c = chain->FirstChildElement("Comb");
					     c; c = c->NextSiblingElement("Comb"))
					{
						tinyxml2::XMLElement *cg = c->FirstChildElement("Gate");

						if (!cg)
						{
							continue;
						}

						int ct = gate_type_from_xml_str(cg->Attribute("type"));
						int ci = find_node_index(cur, ct, cg->IntAttribute("id"));

						if (ci >= 0 && cur->link_count < MAX_LINKS_PER_GRAPH)
						{
							LogicLink &l = cur->links[cur->link_count++];
							memset(&l, 0, sizeof(l));
							l.dst_pin   = -1;
							l.src_type  = cur->nodes[ci].type;
							l.src_id    = cur->nodes[ci].id;
							l.dest_type = cur->nodes[cgi].type;
							l.dest_id   = cur->nodes[cgi].id;

							/* RS/SR: 根据 R/S 属性设置 dst_pin */
							if (isChainSRRS)
							{
								int combId = c->IntAttribute("id");
								char combRef[16];
								snprintf(combRef, sizeof(combRef), "Comb#%d", combId);

								if (gateR && strcmp(gateR, combRef) == 0)
								{
									l.dst_pin = (isChainSRRS == NODE_TYPE_SR_LATCH) ? 1 : 0;
								}
								else if (gateS && strcmp(gateS, combRef) == 0)
								{
									l.dst_pin = (isChainSRRS == NODE_TYPE_SR_LATCH) ? 0 : 1;
								}
							}
						}
					}
				}
			}

			if (gate_el && ous_el)
			{
				int cgt = gate_type_from_xml_str(gate_el->Attribute("type"));
				int cgi = find_node_index(cur, cgt, gate_el->IntAttribute("id"));

				if (cgi >= 0)
				{
					for (tinyxml2::XMLElement *sig = ous_el->FirstChildElement("Signal");
					     sig; sig = sig->NextSiblingElement("Signal"))
					{
						if (cur->link_count >= MAX_LINKS_PER_GRAPH)
						{
							break;
						}

						int si = find_node_index(cur, NODE_TYPE_HW_OUTPUT, sig->IntAttribute("no"));

						if (si >= 0)
						{
							LogicLink &l = cur->links[cur->link_count++];
							memset(&l, 0, sizeof(l));
							l.dst_pin   = -1;
							l.src_type  = cur->nodes[cgi].type;
							l.src_id    = cur->nodes[cgi].id;
							l.dest_type = NODE_TYPE_HW_OUTPUT;
							l.dest_id   = cur->nodes[si].id;
						}
					}
				}
			}

			/* 链级 Inputs → 链级 Gate (RS/SR 直连 Input 信号) */
			if (gate_el && ins_el)
			{
				int cgt = gate_type_from_xml_str(gate_el->Attribute("type"));
				int cgi = find_node_index(cur, cgt, gate_el->IntAttribute("id"));

				if (cgi >= 0)
				{
					for (tinyxml2::XMLElement *sig = ins_el->FirstChildElement("Signal");
					     sig; sig = sig->NextSiblingElement("Signal"))
					{
						if (cur->link_count >= MAX_LINKS_PER_GRAPH)
						{
							break;
						}

						int si = find_node_index(cur, NODE_TYPE_HW_INPUT, sig->IntAttribute("no"));

						if (si >= 0)
						{
							LogicLink &l = cur->links[cur->link_count++];
							memset(&l, 0, sizeof(l));
							l.dst_pin   = -1;
							l.src_type  = NODE_TYPE_HW_INPUT;
							l.src_id    = cur->nodes[si].id;
							l.dest_type = cur->nodes[cgi].type;
							l.dest_id   = cur->nodes[cgi].id;

							/* RS/SR: 根据 R/S 属性设置 dst_pin */
							if (isChainSRRS)
							{
								char inRef[16];
								snprintf(inRef, sizeof(inRef), "Input#%d", sig->IntAttribute("no"));

								if (gateR && strcmp(gateR, inRef) == 0)
								{
									l.dst_pin = (isChainSRRS == NODE_TYPE_SR_LATCH) ? 1 : 0;
								}
								else if (gateS && strcmp(gateS, inRef) == 0)
								{
									l.dst_pin = (isChainSRRS == NODE_TYPE_SR_LATCH) ? 0 : 1;
								}
							}
						}
					}
				}
			}

			/* RS/SR 的 R/S 属性引用的 Input 信号 (仅当无 <Inputs> 块时创建, 避免重复) */
			if (gate_el && !ins_el)
			{
				int cgt = gate_type_from_xml_str(gate_el->Attribute("type"));

				if (cgt == NODE_TYPE_SR_LATCH || cgt == NODE_TYPE_RS_LATCH)
				{
					const char *s_attr2 = gate_el->Attribute("S");
					const char *r_attr2 = gate_el->Attribute("R");
					int cgi2 = find_node_index(cur, cgt, gate_el->IntAttribute("id"));

					if (cgi2 >= 0)
					{
						if (s_attr2 && strncmp(s_attr2, "Input#", 6) == 0)
						{
							int ino = atoi(s_attr2 + 6);
							int si  = ensure_signal(cur, NODE_TYPE_HW_INPUT, ino);

							if (si >= 0 && cur->link_count < MAX_LINKS_PER_GRAPH)
							{
								LogicLink &l = cur->links[cur->link_count++];
								memset(&l, 0, sizeof(l));
								l.dst_pin   = -1;
								l.src_type  = NODE_TYPE_HW_INPUT;
								l.src_id    = cur->nodes[si].id;
								l.dest_type = cur->nodes[cgi2].type;
								l.dest_id   = cur->nodes[cgi2].id;
								l.dst_pin   = (cgt == NODE_TYPE_SR_LATCH) ? 0 : 1;
							}
						}

						if (r_attr2 && strncmp(r_attr2, "Input#", 6) == 0)
						{
							int ino = atoi(r_attr2 + 6);
							int si  = ensure_signal(cur, NODE_TYPE_HW_INPUT, ino);

							if (si >= 0 && cur->link_count < MAX_LINKS_PER_GRAPH)
							{
								LogicLink &l = cur->links[cur->link_count++];
								memset(&l, 0, sizeof(l));
								l.dst_pin   = -1;
								l.src_type  = NODE_TYPE_HW_INPUT;
								l.src_id    = cur->nodes[si].id;
								l.dest_type = cur->nodes[cgi2].type;
								l.dest_id   = cur->nodes[cgi2].id;
								l.dst_pin   = (cgt == NODE_TYPE_SR_LATCH) ? 1 : 0;
							}
						}
					}
				}
			}
		}
		else
		{
		/* 简单链: Inputs → Gate → Outputs */
		if (!gate_el)
		{
			continue;
		}

		int gt = gate_type_from_xml_str(gate_el->Attribute("type"));
		int gi = find_node_index(cur, gt, gate_el->IntAttribute("id"));

		if (gi < 0)
		{
			continue;
		}

		if (ins_el)
		{
			for (tinyxml2::XMLElement *sig = ins_el->FirstChildElement("Signal");
			     sig; sig = sig->NextSiblingElement("Signal"))
			{
				if (cur->link_count >= MAX_LINKS_PER_GRAPH)
				{
					break;
				}

				int si = find_node_index(cur, NODE_TYPE_HW_INPUT, sig->IntAttribute("no"));

				if (si >= 0)
				{
					LogicLink &l = cur->links[cur->link_count++];
					memset(&l, 0, sizeof(l));
					l.dst_pin   = -1;
					l.src_type  = NODE_TYPE_HW_INPUT;
					l.src_id    = cur->nodes[si].id;
					l.dest_type = cur->nodes[gi].type;
					l.dest_id   = cur->nodes[gi].id;

					/* SR/RS: 根据 R/S 属性设置 dst_pin */
					if (gt == NODE_TYPE_SR_LATCH || gt == NODE_TYPE_RS_LATCH)
					{
						const char *sA = gate_el->Attribute("S");
						const char *rA = gate_el->Attribute("R");
						char inRef[16];
						snprintf(inRef, sizeof(inRef), "Input#%d", sig->IntAttribute("no"));

						if (rA && strcmp(rA, inRef) == 0)
						{
							l.dst_pin = (gt == NODE_TYPE_SR_LATCH) ? 1 : 0;
						}
						else if (sA && strcmp(sA, inRef) == 0)
						{
							l.dst_pin = (gt == NODE_TYPE_SR_LATCH) ? 0 : 1;
						}
					}
				}
			}
		}

		if (ous_el)
		{
			for (tinyxml2::XMLElement *sig = ous_el->FirstChildElement("Signal");
			     sig; sig = sig->NextSiblingElement("Signal"))
			{
				if (cur->link_count >= MAX_LINKS_PER_GRAPH)
				{
					break;
				}

				int si = find_node_index(cur, NODE_TYPE_HW_OUTPUT, sig->IntAttribute("no"));

				if (si >= 0)
				{
					LogicLink &l = cur->links[cur->link_count++];
					memset(&l, 0, sizeof(l));
					l.dst_pin   = -1;
					l.src_type  = cur->nodes[gi].type;
					l.src_id    = cur->nodes[gi].id;
					l.dest_type = NODE_TYPE_HW_OUTPUT;
					l.dest_id   = cur->nodes[si].id;
				}
			}
		}
        }
    }

    *graph_count = 1;
    LOG_I("XML配置解析成功: %d节点 %d连线", cur->node_count, cur->link_count);
    return 0;
}

/* ==================================================================
 * 逻辑运算函数 (10 种门)
 * ================================================================== */

static int collect_input_signals(LogicGraph *graph, LogicNode *element_node,
                                  int *input_values, int max_inputs) {
    int input_count = 0;
    for (int i = 0; i < graph->link_count && input_count < max_inputs; i++)
    {
        LogicLink *link = &graph->links[i];
        if (link->dest_type == element_node->type &&
            ((link->dest_id & 0xFF) == (element_node->id & 0xFF))) {
            LogicNode *src_node = find_node(graph, link->src_type, link->src_id);
            if (src_node)
            {
                // SR/RS: 按 dst_pin 填入对应位置
                int is_srrs = (element_node->type == NODE_TYPE_SR_LATCH ||
                               element_node->type == NODE_TYPE_RS_LATCH);
                if (is_srrs && link->dst_pin >= 0)
                {
                    if (input_count < 2)
                    {
                        input_values[link->dst_pin] = src_node->value;
                        if (link->dst_pin >= input_count)
                        {
                            input_count = link->dst_pin + 1;
                        }
                    }
                }
                else
                {
                    input_values[input_count++] = src_node->value;
                }
                PLC_DBG("    找到输入信号：%d:%d = %d (pin=%d)\n",
                       link->src_type, link->src_id, src_node->value, link->dst_pin);
            }
        }
    }
    return input_count;
}

static void execute_not_gate(LogicNode *not_node, int input_value)
{
    not_node->value = !input_value;
    PLC_DBG("  非门运算：输入=%d → 输出=%d\n", input_value, not_node->value);
}

static void execute_and_gate(LogicNode *and_node, int *input_values, int input_count)
{
    and_node->value = (input_count == 0) ? 0 : 1;
    for (int i = 0; i < input_count; i++)
    {
        and_node->value = and_node->value && input_values[i];
    }
    PLC_DBG("  与门运算：输入=[");
    for (int i = 0; i < input_count; i++)
    {
        PLC_DBG("%d%s", input_values[i], (i < input_count - 1) ? "," : "");
    }
    PLC_DBG("] → 输出=%d\n", and_node->value);
}

static void execute_or_gate(LogicNode *or_node, int *input_values, int input_count)
{
    or_node->value = 0;
    for (int i = 0; i < input_count; i++)
    {
        or_node->value = or_node->value || input_values[i];
    }
    PLC_DBG("  或门运算：输入=[");
    for (int i = 0; i < input_count; i++)
    {
        PLC_DBG("%d%s", input_values[i], (i < input_count - 1) ? "," : "");
    }
    PLC_DBG("] → 输出=%d\n", or_node->value);
}

static void execute_62p_gate(LogicNode *node, int input_value)
{
    int delay_ms = node->delay_ms > 0 ? node->delay_ms : 1000;
    int component_id = node->id & 0xFF;
    if (input_value == 1)
    {
        if (!node->timer_active)
        {
            // 启动延时定时器，延时 delay_ms 毫秒后输出 1
            PLC_DBG("  62p延时元件 (ID=%d, 序号=%d)：输入=1，启动非阻塞延时%d毫秒\n",
                   node->id, component_id, delay_ms);
            clock_gettime(CLOCK_MONOTONIC, &node->timer_start);
            node->timer_delay_ms = delay_ms;
            node->timer_pending_output = 1;
            node->timer_active = 1;
            // 保持当前输出值不变，等待定时器到期
        }
        else if (get_elapsed_ms(&node->timer_start) >= node->timer_delay_ms)
        {
            // 定时器到期，输出 1
            node->value = 1;
            node->timer_active = 0;
            node->timer_pending_output = -1;
            PLC_DBG("  62p延时元件 (ID=%d, 序号=%d)：延时结束，输出=1\n",
                   node->id, component_id);
        }
        // 否则仍在延时中，保持当前值
    }
    else
    {
        // 输入为 0，立即输出 0 并取消定时器
        node->value = 0;
        node->timer_active = 0;
        node->timer_pending_output = -1;
    }
}

static void execute_62d_gate(LogicNode *node, int input_value)
{
    int delay_ms = node->delay_ms > 0 ? node->delay_ms : 1000;
    int component_id = node->id & 0xFF;
    if (input_value == 1)
    {
        // 输入为 1，立即输出 1 并取消定时器
        node->value = 1;
        node->timer_active = 0;
        node->timer_pending_output = -1;
        PLC_DBG("  62d延时元件 (ID=%d, 序号=%d)：输入=1，立即输出=1\n",
               node->id, component_id);
    }
    else
    {
        if (!node->timer_active)
        {
            // 启动延时定时器，延时 delay_ms 毫秒后输出 0
            PLC_DBG("  62d延时元件 (ID=%d, 序号=%d)：输入=0，启动非阻塞延时%d毫秒\n",
                   node->id, component_id, delay_ms);
            clock_gettime(CLOCK_MONOTONIC, &node->timer_start);
            node->timer_delay_ms = delay_ms;
            node->timer_pending_output = 0;
            node->timer_active = 1;
            // 保持当前输出值不变，等待定时器到期
        }
        else if (get_elapsed_ms(&node->timer_start) >= node->timer_delay_ms)
        {
            // 定时器到期，输出 0
            node->value = 0;
            node->timer_active = 0;
            node->timer_pending_output = -1;
            PLC_DBG("  62d延时元件 (ID=%d, 序号=%d)：延时结束，输出=0\n",
                   node->id, component_id);
        }
        // 否则仍在延时中，保持当前值
    }
}

static void execute_rising_edge_gate(LogicNode *node, int input_value)
{
    int component_id = node->id & 0xFF;
    if (node->last_input == 0 && input_value == 1)
    {
        PLC_DBG("  上升沿元件 (ID=%d, 序号=%d)：检测到上升沿，输出脉冲\n",
               node->id, component_id);
        node->value = 1;
    }
    else
    {
        node->value = 0;
    }
    node->last_input = input_value;
}

static void execute_falling_edge_gate(LogicNode *node, int input_value)
{
    int component_id = node->id & 0xFF;
    if (node->last_input == 1 && input_value == 0)
    {
        PLC_DBG("  下降沿元件 (ID=%d, 序号=%d)：检测到下降沿，输出脉冲\n",
               node->id, component_id);
        node->value = 1;
    }
    else
    {
        node->value = 0;
    }
    node->last_input = input_value;
}

static void execute_sr_latch(LogicNode *node, int *input_values, int input_count)
{
    int component_id = node->id & 0xFF;
    int s = (input_count >= 1) ? input_values[0] : 0;
    int r = (input_count >= 2) ? input_values[1] : 0;
    PLC_DBG("  SR触发器 (ID=%d, 序号=%d)：S=%d, R=%d\n", node->id, component_id, s, r);
    if (s == 1)
    {
        node->value = 1;
        PLC_DBG("  SR触发器：S=1，置位，输出=1\n");
    }
    else if (r == 1)
    {
        node->value = 0;
        PLC_DBG("  SR触发器：S=0, R=1，复位，输出=0\n");
    }
}

static void execute_rs_latch(LogicNode *node, int *input_values, int input_count)
{
    int component_id = node->id & 0xFF;
    int r = (input_count >= 1) ? input_values[0] : 0;
    int s = (input_count >= 2) ? input_values[1] : 0;
    PLC_DBG("  RS触发器 (ID=%d, 序号=%d)：R=%d, S=%d\n", node->id, component_id, r, s);
    if (r == 1)
    {
        node->value = 0;
        PLC_DBG("  RS触发器：R=1，复位，输出=0\n");
    }
    else if (s == 1)
    {
        node->value = 1;
        PLC_DBG("  RS触发器：R=0, S=1，置位，输出=1\n");
    }
}

/* ==================================================================
 * 拓扑排序 (Kahn 算法)
 * ================================================================== */
// 对逻辑图的节点进行拓扑排序，确保节点按依赖顺序执行
// 返回值：排好序的节点索引数组，由调用者通过 sorted_indices 传出
// 返回实际能排序的节点数（可能小于 node_count 如果有环）
static int topological_sort(LogicGraph *graph, int *sorted_indices)
{
	if (!graph || !sorted_indices)
	{
		return 0;
	}

	int n = graph->node_count;

	if (n == 0)
	{
		return 0;
	}

    // 步骤1：计算每个节点的入度（从非硬件输入点的源节点连接过来的链路数）
    for (int i = 0; i < n; i++)
    {
        graph->nodes[i].indegree = 0;
    }
    for (int i = 0; i < graph->link_count; i++)
    {
        LogicLink *link = &graph->links[i];
        // 找到目标节点
        LogicNode *dest = find_node(graph, link->dest_type, link->dest_id);
        if (dest)
        {
            // 找到源节点（如果不是硬件输入点，则增加目标节点的入度）
            LogicNode *src = find_node(graph, link->src_type, link->src_id);
            if (src && src->type != NODE_TYPE_HW_INPUT)
            {
                dest->indegree++;
            }
        }
    }

    // 步骤2：Kahn算法
    // 将所有入度为0的节点入队（硬件输入点入度始终为0）
    int queue[MAX_NODES_PER_GRAPH];
    int q_head = 0, q_tail = 0;
    for (int i = 0; i < n; i++)
    {
        if (graph->nodes[i].indegree == 0)
        {
            queue[q_tail++] = i;
        }
    }

    int sorted_count = 0;
    while (q_head < q_tail)
    {
        int idx = queue[q_head++];
        sorted_indices[sorted_count++] = idx;

        // 找到当前节点的所有后继节点，减少它们的入度
        for (int i = 0; i < graph->link_count; i++)
        {
            LogicLink *link = &graph->links[i];
            LogicNode *src = find_node(graph, link->src_type, link->src_id);
            if (src == &graph->nodes[idx])
            {
                LogicNode *dest = find_node(graph, link->dest_type, link->dest_id);
                if (dest)
                {
                    dest->indegree--;
                    if (dest->indegree == 0)
                    {
                        queue[q_tail++] = (dest - graph->nodes);
                    }
                }
            }
        }
    }

    if (sorted_count < n)
    {
        LOG_E("逻辑图[%s]存在环路依赖，仅排序了 %d/%d 个节点",
              graph->key, sorted_count, n);
    }
    return sorted_count;
}

/* ==================================================================
 * 逻辑图执行
 * ================================================================== */
int execute_logic_graph(LogicGraph *graph, HardwareManager *hw)
{
	if (!graph || !hw)
	{
		return -1;
	}

    PLC_DBG("\n=====================================================\n");
    PLC_DBG("执行逻辑图：%s (%s)\n", graph->key, graph->name);
    PLC_DBG("=====================================================\n");

    // 步骤1：初始化节点值
    PLC_DBG("\n【节点初始化】\n");
    for (int i = 0; i < graph->node_count; i++)
    {
        LogicNode *node = &graph->nodes[i];
        const char *type_name = "";
        switch (node->type) {
            case NODE_TYPE_HW_INPUT:
                node->value = get_hw_point_value(hw->input_head, node->id);
                type_name = "硬件输入点"; break;
            case NODE_TYPE_HW_OUTPUT: type_name = "硬件输出点"; break;
            case NODE_TYPE_OR_GATE:   type_name = "或门元件"; break;
            case NODE_TYPE_AND_GATE:  type_name = "与门元件"; break;
            case NODE_TYPE_NOT_GATE:  type_name = "非门元件"; break;
            case NODE_TYPE_62P_GATE:  type_name = "62p延时元件"; break;
            case NODE_TYPE_62D_GATE:  type_name = "62d延时元件"; break;
            case NODE_TYPE_RISING_EDGE: type_name = "上升沿元件"; break;
            case NODE_TYPE_SR_LATCH:  type_name = "SR触发器"; break;
            case NODE_TYPE_RS_LATCH:  type_name = "RS触发器"; break;
            case NODE_TYPE_FALLING_EDGE: type_name = "下降沿元件"; break;
            default: type_name = "未知节点"; break;
        }
        PLC_DBG("  %s (类型=%d, ID=%d): 初始值=%d\n",
               type_name, node->type, node->id, node->value);
    }

    // 步骤2：按拓扑顺序执行逻辑元件运算
    PLC_DBG("\n【逻辑元件运算】（拓扑排序执行）\n");
    int sorted_indices[MAX_NODES_PER_GRAPH];
    int sorted_count = topological_sort(graph, sorted_indices);
    for (int si = 0; si < sorted_count; si++)
    {
        LogicNode *node = &graph->nodes[sorted_indices[si]];
        int input_values[10];
        int input_count;
        switch (node->type) {
            case NODE_TYPE_NOT_GATE:
                PLC_DBG("\n  处理非门元件 (ID=%d)\n", node->id);
                input_count = collect_input_signals(graph, node, input_values, 10);
                if (input_count > 0)
                {
                    execute_not_gate(node, input_values[0]);
                }
                else
                {
                	PLC_DBG("    警告：非门元件没有输入信号\n"); node->value = 0; }
                break;
            case NODE_TYPE_OR_GATE:
                PLC_DBG("\n  处理或门元件 (ID=%d)\n", node->id);
                input_count = collect_input_signals(graph, node, input_values, 10);
                execute_or_gate(node, input_values, input_count);
                break;
            case NODE_TYPE_AND_GATE:
                PLC_DBG("\n  处理与门元件 (ID=%d)\n", node->id);
                input_count = collect_input_signals(graph, node, input_values, 10);
                execute_and_gate(node, input_values, input_count);
                break;
            case NODE_TYPE_62P_GATE:
                PLC_DBG("\n  处理62p延时元件 (ID=%d)\n", node->id);
                input_count = collect_input_signals(graph, node, input_values, 10);
                if (input_count > 0)
                {
                    execute_62p_gate(node, input_values[0]);
                }
                else
                {
                	PLC_DBG("    警告：62p延时元件没有输入信号\n"); node->value = 0; }
                break;
            case NODE_TYPE_62D_GATE:
                PLC_DBG("\n  处理62d延时元件 (ID=%d)\n", node->id);
                input_count = collect_input_signals(graph, node, input_values, 10);
                if (input_count > 0)
                {
                    execute_62d_gate(node, input_values[0]);
                }
                else
                {
                	PLC_DBG("    警告：62d延时元件没有输入信号\n"); node->value = 0; }
                break;
            case NODE_TYPE_RISING_EDGE:
                PLC_DBG("\n  处理上升沿元件 (ID=%d)\n", node->id);
                input_count = collect_input_signals(graph, node, input_values, 10);
                if (input_count > 0)
                {
                    execute_rising_edge_gate(node, input_values[0]);
                }
                else
                {
                	PLC_DBG("    警告：上升沿元件没有输入信号\n"); node->value = 0; }
                break;
            case NODE_TYPE_FALLING_EDGE:
                PLC_DBG("\n  处理下降沿元件 (ID=%d)\n", node->id);
                input_count = collect_input_signals(graph, node, input_values, 10);
                if (input_count > 0)
                {
                    execute_falling_edge_gate(node, input_values[0]);
                }
                else
                {
                	PLC_DBG("    警告：下降沿元件没有输入信号\n"); node->value = 0; }
                break;
            case NODE_TYPE_SR_LATCH:
                PLC_DBG("\n  处理SR触发器 (ID=%d)\n", node->id);
                input_count = collect_input_signals(graph, node, input_values, 10);
                execute_sr_latch(node, input_values, input_count);
                break;
            case NODE_TYPE_RS_LATCH:
                PLC_DBG("\n  处理RS触发器 (ID=%d)\n", node->id);
                input_count = collect_input_signals(graph, node, input_values, 10);
                execute_rs_latch(node, input_values, input_count);
                break;
        }
    }

    // 步骤3：处理输出链路
    PLC_DBG("\n【输出链路处理】\n");
    for (int i = 0; i < graph->link_count; i++)
    {
        LogicLink *link = &graph->links[i];
        LogicNode *src_node = find_node(graph, link->src_type, link->src_id);
        LogicNode *dest_node = find_node(graph, link->dest_type, link->dest_id);
        if (src_node && dest_node && dest_node->type == NODE_TYPE_HW_OUTPUT)
        {
            dest_node->value = src_node->value;
			set_hw_point_value(&hw->output_head, &hw->output_count,
			                   dest_node->id, dest_node->value);

			if (0 == plc_set_out_by_id(dest_node->id, src_node->value))
			{
				PLC_DBG("  硬件输出：ID=%d = %d（已同步到datacenter）\n",
				       dest_node->id, src_node->value);
			}
			else
			{
				PLC_DBG("  硬件输出：ID=%d = %d（未找到datacenter信号，跳过写入）\n",
				       dest_node->id, dest_node->value);
			}
        }
    }

    PLC_DBG("\n【逻辑图执行结果】\n");
    for (int i = 0; i < graph->node_count; i++)
    {
        LogicNode *node = &graph->nodes[i];
        const char *type_name = "";
        switch (node->type) {
            case NODE_TYPE_HW_INPUT: type_name = "硬件输入点"; break;
            case NODE_TYPE_HW_OUTPUT: type_name = "硬件输出点"; break;
            case NODE_TYPE_OR_GATE:   type_name = "或门元件"; break;
            case NODE_TYPE_AND_GATE:  type_name = "与门元件"; break;
            case NODE_TYPE_NOT_GATE:  type_name = "非门元件"; break;
            case NODE_TYPE_62P_GATE:  type_name = "62p延时元件"; break;
            case NODE_TYPE_62D_GATE:  type_name = "62d延时元件"; break;
            case NODE_TYPE_RISING_EDGE: type_name = "上升沿元件"; break;
            case NODE_TYPE_SR_LATCH:  type_name = "SR触发器"; break;
            case NODE_TYPE_RS_LATCH:  type_name = "RS触发器"; break;
            case NODE_TYPE_FALLING_EDGE: type_name = "下降沿元件"; break;
            default: type_name = "未知节点"; break;
        }
        PLC_DBG("  %s (ID=%d): 最终值=%d\n", type_name, node->id, node->value);
    }
    return 0;
}

/* ==================================================================
 * PLC 逻辑入口
 * ================================================================== */
int PLC_Logic(void)
{
    // 检查配置文件是否变化，仅在文件修改时重新解析
    struct stat file_stat;
    if (stat(g_plc_config_path, &file_stat) != 0)
    {
        LOG_E("无法获取PLC配置文件状态: %s", g_plc_config_path);
        // 如果之前有缓存，继续使用缓存执行
		if (g_cached_graph_count == 0)
		{
			return 2;
		}
        // fall through to use cached graphs
    }
    else
    {
        if (file_stat.st_mtime == g_last_file_mtime && g_cached_graph_count > 0)
        {
            // 文件未变化，直接使用缓存的逻辑图执行
            HardwareManager hw;
            init_hardware_manager(&hw);
            extract_hw_points_from_graphs(g_cached_graphs, g_cached_graph_count, &hw, 0);

            for (int i = 0; i < g_cached_graph_count; i++)
            {
                execute_logic_graph(&g_cached_graphs[i], &hw);
            }

		/* 同步输出到 datacenter out 信号 */
		HWPoint *curr = hw.output_head;
		while (curr)
		{
			plc_set_out_by_id(curr->id, curr->value);
			curr = curr->next;
		}
            destroy_hardware_manager(&hw);
            return 0;
        }
        g_last_file_mtime = file_stat.st_mtime;
    }

    // 文件已变化或首次加载，重新解析 XML
    int graph_count = 0;
    int parse_ok = parse_reclose_logic_xml(g_plc_config_path, g_cached_graphs, &graph_count);
    if (parse_ok != 0)
    {
        // 解析失败但之前有缓存，继续使用缓存
        if (g_cached_graph_count > 0)
        {
            LOG_E("PLC配置文件重新解析失败，继续使用上次缓存（%d个逻辑图）",
                  g_cached_graph_count);
            graph_count = g_cached_graph_count; // 使用旧缓存
        }
        else
        {
            return 2;
        }
    }
    else
    {
        g_cached_graph_count = graph_count;
    }

    HardwareManager hw;
    init_hardware_manager(&hw);

    extract_hw_points_from_graphs(g_cached_graphs, graph_count, &hw, 0);

    PLC_DBG("==================== 文件解析结果 ====================\n");
    PLC_DBG("配置文件: %s\n", g_plc_config_path);
    PLC_DBG("共解析到 %d 个逻辑图\n", graph_count);
    for (int i = 0; i < graph_count; i++)
    {
        PLC_DBG("  逻辑图%d：key=%s, name=%s, 节点数=%d, 链路数=%d\n",
               i + 1, g_cached_graphs[i].key, g_cached_graphs[i].name,
               g_cached_graphs[i].node_count, g_cached_graphs[i].link_count);
    }
    print_hardware_manager(&hw);

    for (int i = 0; i < graph_count; i++)
    {
        execute_logic_graph(&g_cached_graphs[i], &hw);
    }

    PLC_DBG("\n==================== 最终硬件输出状态 ====================\n");
    PLC_DBG("硬件输出点（dev_in）最终值：\n");
    HWPoint *curr = hw.output_head;
    int idx = 1;
    while (curr)
    {
        PLC_DBG("  %d. ID=%d: %d\n", idx++, curr->id, curr->value);
        curr = curr->next;
    }

    destroy_hardware_manager(&hw);
    return 0;
}

/* ==================================================================
 * 动态配置路径
 * ================================================================== */
// 设置PLC配置文件路径（支持运行时动态修改）
void plc_set_config_path(const char *path)
{
    if (path && path[0] != '\0')
    {
        strncpy(g_plc_config_path, path, sizeof(g_plc_config_path) - 1);
        g_plc_config_path[sizeof(g_plc_config_path) - 1] = '\0';
        // 路径变更后重置缓存，强制下次重新加载
        g_last_file_mtime = 0;
        g_cached_graph_count = 0;
        LOG_I("PLC配置路径已更新: %s", g_plc_config_path);
    }
}

// 获取当前PLC配置文件路径
const char* plc_get_config_path(void)
{
    return g_plc_config_path;
}

/* ==================================================================
 * 模块初始化 & X-Macro 线程入口
 * ================================================================== */
int app_plc_init1(void *arg)
{
    stru_app *p_app = (stru_app *)arg;
    if (NULL == p_app)
    {
        LOG_E("app_plc_init1 arg null");
        return -1;
    }

    // 动态设置 PLC 配置文件路径（proc_dir + 相对文件名）
    char proc_dir[512] = {0};
    if (0 == func_proc_self_dir(proc_dir, sizeof(proc_dir)))
    {
        std::string plc_path = std::string(proc_dir) + "/" + g_plc_config_path;
        plc_set_config_path(plc_path.c_str());
    }

    int ret = 0;
    ret |= dc_signal_out("plc.run_cnt", "plc线程计数", DATA_TYPE_U32, &p_app->run_cnt, "plc");

    for (int i = 0; i < MAX_OUT_NODES; i++)
    {
        char saddr[64];
        char desc[64];
        snprintf(saddr, sizeof(saddr), "plc.st.out.%d", i);
        snprintf(desc, sizeof(desc), "plc输出%d", i);
        ret |= dc_signal_out(saddr, desc, DATA_TYPE_U8, &g_plc_st_out[i], "plc");
    }

    if (ret != 0)
    {
        LOG_E("app_plc_init1 dc_signal_out failed");
        return -1;
    }

    p_plc_cfg = self_ptl_cfg_get();
    if (nullptr == p_plc_cfg)
    {
        LOG_E("app_plc_init1 self_ptl_cfg_get failed");
        return -1;
    }

    for (uint32_t i = 0; i < p_plc_cfg->st_vec.size(); i++)
    {
        stru_self_ptl_cfg_base *p_base = &p_plc_cfg->st_vec.at(i);
        g_plc_cfg.push_back({(*p_base), NULL});
    }

    return 0;
}

int app_plc_init2(void *arg)
{
    int ret = 0;
    ret |= dc_signal_out_link_with_callback("plc.run_cnt", (void **)&gp_run_cnt_in, NULL, "plc");

    for (uint32_t i = 0; i < g_plc_cfg.size(); i++)
    {
        stru_plc_cfg *p = &g_plc_cfg[i];
        ret |= dc_signal_out_link_with_callback(p->base.saddr.c_str(), (void **)&p->p_data, NULL, "plc");
    }
    if (ret != 0)
    {
        LOG_E("app_plc_init2 dc_signal_out_link_with_callback failed");
        return -1;
    }
    return 0;
}

void *app_plc(void *arg)
{
    if (NULL == arg)
    {
        LOG_E("app_plc arg null");
        return NULL;
    }

    stru_app *p_app = (stru_app *)arg;
    uint32_t event;

    while (1)
    {
        task_event_recv(p_app->p_event,
            EV_TIMER1 | EV_TIMER2 | EV_TIMER3,
            TASK_EVENT_FLAG_OR | TASK_EVENT_FLAG_CLEAR,
            TASK_EVENT_WAIT_FOREVER,
            &event);

		if (event & EV_TIMER1)
		{
		}
		if (event & EV_TIMER2)
		{
		}
        if (event & EV_TIMER3)
        {
            p_app->run_cnt++;
            PLC_Logic();
        }
    }
    return NULL;
}

/* ==================================================================
 * 控制台命令 — 调试开关 & 查看状态
 * ================================================================== */

/**
 * @brief PLC 控制台命令补全回调
 */
LOCAL void cmd_plc_complete(const char *buf, char ***completions, int *ncomp)
{
	static const char *subs[] = {"dbg", "info"};

	cmd_sub_complete(buf, completions, ncomp, subs, sizeof(subs) / sizeof(subs[0]));
}

/**
 * @brief PLC 控制台命令
 *
 * @details 子命令:
 *          - `plc dbg on`   打开 PLC 运行时打印 (控制台输出逻辑图执行详情)
 *          - `plc dbg off`  关闭 PLC 运行时打印
 *          - `plc info`     查看 PLC 模块状态 (配置路径、缓存图数、调试开关)
 */
LOCAL void cmd_plc(int argc, char *argv[])
{
	const char *usage =
		"plc dbg  on|off  打开/关闭 PLC 调试打印\n"
		"plc info         查看 PLC 模块状态\n";

	if (argc < 2)
	{
		printf("%s", usage);
		return;
	}

	if (0 == strcmp(argv[1], "dbg"))
	{
		if (argc < 3)
		{
			printf("当前 PLC 调试: %s\n", g_plc_dbg_enabled ? "开启" : "关闭");
			printf("usage: plc dbg on|off\n");
			return;
		}

		if (0 == strcmp(argv[2], "on"))
		{
			g_plc_dbg_enabled = 1;
			LOG_I("PLC 调试打印: 开启");
		}
		else if (0 == strcmp(argv[2], "off"))
		{
			g_plc_dbg_enabled = 0;
			LOG_I("PLC 调试打印: 关闭");
		}
		else
		{
			printf("未知选项: %s\nusage: plc dbg on|off\n", argv[2]);
		}
	}
	else if (0 == strcmp(argv[1], "info"))
	{
		printf("===== PLC Info =====\n");
		printf("配置文件     : %s\n", g_plc_config_path);
		printf("缓存逻辑图数 : %d\n", g_cached_graph_count);
		printf("上次 mtime   : %ld\n", (long)g_last_file_mtime);
		printf("调试打印     : %s\n", g_plc_dbg_enabled ? "开启" : "关闭");
		printf("self_ptl 遥信: %d 个关联\n", (int)g_plc_cfg.size());
	}
	else
	{
		printf("未知子命令: %s\n%s", argv[1], usage);
	}
}

CMD_REGISTER_C("plc", cmd_plc, "PLC调试打印开关", cmd_plc_complete);
