diff --git a/release/inc/app_modules.h b/release/inc/app_modules.h index 509635e..cb0be24 100644 --- a/release/inc/app_modules.h +++ b/release/inc/app_modules.h @@ -22,3 +22,4 @@ APP_MODULE(SELF_PTL, self_ptl, app_self_ptl_init1, app_self_ptl_init2, APP_MODULE(IEC61850M, iec61850m, app_iec61850m_init1, app_iec61850m_init2, app_iec61850m ) APP_MODULE(IEC61850S, iec61850s, app_iec61850s_init1, app_iec61850s_init2, app_iec61850s ) APP_MODULE(MODBUS_M, modbus_m, app_modbus_m_init1, app_modbus_m_init2, app_modbus_m ) +APP_MODULE(PLC, plc, app_plc_init1, app_plc_init2, app_plc ) diff --git a/release/linux.mk b/release/linux.mk index 0fb37c0..d345bf4 100644 --- a/release/linux.mk +++ b/release/linux.mk @@ -49,7 +49,7 @@ endif # 编译选项 ifeq ($(CROSS), arm) -C_FLAGS = $(REL_INC) -DRK356x +C_FLAGS = $(REL_INC) -DRK356x -mno-outline-atomics -fno-threadsafe-statics else C_FLAGS = $(REL_INC) endif diff --git a/release/src/system/RTU/makefile b/release/src/system/RTU/makefile index e119424..20c4df8 100644 --- a/release/src/system/RTU/makefile +++ b/release/src/system/RTU/makefile @@ -15,7 +15,7 @@ MakeDirCommand := mkdir -p # 静态库链接(注意顺序很重要,被依赖的库放在后面) # Libs := -lcom_channel -lcom_scan -liec -lself_ptl -lfunc -ltask -lcomm -lshell -lpthread -Libs := -lcom_decode -liec -liec61850m -liec61850s -lmodbus_m -lself_ptl -lweb_server -ldatacenter +Libs := -lplc -lcom_decode -liec -liec61850m -liec61850s -lmodbus_m -lself_ptl -lweb_server -ldatacenter Libs += -l60870 -licp67 -lmms_m -lmms_s -lmongoose -lmodbus Libs += -liec61850 Libs += -lmy_xxhash -lcmd -lmd5 -lxml -lcJSON -lcomm -ltask -lfunc @@ -43,7 +43,9 @@ APP_C_FLAGS += -I $(INC) -g # 如果是静态链接,添加静态链接标志 # STATIC_FLAGS := -static # 完全静态链接(包含libc等) -STATIC_FLAGS := -static-libgcc -static-libstdc++ # 只静态链接gcc相关库 +STATIC_FLAGS := -static-libgcc # 只静态链接gcc库;libstdc++动态链接(目标设备版本无LSE) + + diff --git a/release/src/system/libplc/makefile b/release/src/system/libplc/makefile new file mode 100644 index 0000000..7999949 --- /dev/null +++ b/release/src/system/libplc/makefile @@ -0,0 +1,57 @@ +# 包含外部Makefile +include ./../../../linux.mk + +ProjectName := libplc + +DIR := $(realpath $(CURDIR)/..) +LAST_DIR := $(notdir $(DIR)) + +# 静态库文件目标 +OutputFile := $(LIB_REL)/$(ProjectName).a +ArchiveCommand := ar rcs +MakeDirCommand := mkdir -p + +OBJ := $(DIR)/$(ProjectName)/obj +SRC := $(SRC_ROOT_DIR)/$(LAST_DIR)/$(ProjectName)/src +INC := $(SRC_ROOT_DIR)/$(LAST_DIR)/$(ProjectName)/inc + +SOURCES := $(wildcard $(SRC)/*.c) $(wildcard $(SRC)/*.cpp) +OBJECTS := $(patsubst $(SRC)/%.c, $(OBJ)/%.o,$(filter %.c,$(SOURCES))) +OBJECTSCPP := $(patsubst $(SRC)/%.cpp, $(OBJ)/%.o,$(filter %.cpp,$(SOURCES))) +ALL_OBJECTS := $(OBJECTS) $(OBJECTSCPP) + +APP_C_FLAGS := $(C_FLAGS) +APP_C_FLAGS += -I $(INC) -g -O0 + +.PHONY : all clean veryclean rebuild + +all: $(OutputFile) + +$(OutputFile): $(ALL_OBJECTS) + @$(MakeDirCommand) $(dir $@) + $(ArchiveCommand) $@ $^ + @echo "Static library built: $@" + +rebuild: veryclean all + +clean: + rm -f $(OBJ)/*.o $(OBJ)/*.d $(OutputFile) ./out/*.* + +veryclean: clean + rm -f ./out/$(OutputFile) $(SRC)/*.bak $(INC)/*.bak + +$(OBJECTS): $(OBJ)/%.o: $(SRC)/%.c + @mkdir -p $(dir $@) + $(CC) $(APP_C_FLAGS) -o $@ -c $< + +$(OBJECTSCPP): $(OBJ)/%.o: $(SRC)/%.cpp + @mkdir -p $(dir $@) + $(CPP) $(APP_C_FLAGS) -o $@ -c $< + +$(OBJ)/%.d: $(SRC)/%.c + @mkdir -p $(dir $@) + $(CC) $(APP_C_FLAGS) -MM -MT '$(OBJ)/$*.o' $< > $@ + +$(OBJ)/%.d: $(SRC)/%.cpp + @mkdir -p $(dir $@) + $(CPP) $(APP_C_FLAGS) -MM -MT '$(OBJ)/$*.o' $< > $@ diff --git a/release/src/system/makefile b/release/src/system/makefile index 7be4ac7..3080772 100644 --- a/release/src/system/makefile +++ b/release/src/system/makefile @@ -10,6 +10,7 @@ SUBDIRS += ./libiec61850s SUBDIRS += ./libself_ptl SUBDIRS += ./libweb_server SUBDIRS += ./libmodbus_m +SUBDIRS += ./libplc SUBDIRS += ./RTU diff --git a/src/system/libplc/inc/.gitkeep b/src/system/libplc/inc/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/system/libplc/src/plc.cpp b/src/system/libplc/src/plc.cpp new file mode 100644 index 0000000..d9e8cad --- /dev/null +++ b/src/system/libplc/src/plc.cpp @@ -0,0 +1,742 @@ +#include "myBase.h" +#include "mySystem.h" +#include "myDatacenter.h" +#include "myLog.h" +#include "myCmd.h" +#include "myFunc.h" +#include +#include +#include +#include +#include // ANSI编码支持 +#include // usleep函数实现延时 + + +#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}; + +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 g_plc_cfg={}; + + +// ==================== 常量定义 ==================== +#define MAX_LOGIC_GRAPHS 4 // 最大逻辑图数量 +#define MAX_NODES_PER_GRAPH 20 // 每个逻辑图最大节点数 +#define MAX_LINKS_PER_GRAPH 20 // 每个逻辑图最大链路数 + +// 节点类型标识 +#define NODE_TYPE_HW_OUTPUT 0 // 硬件输出点(dev_in) +#define NODE_TYPE_HW_INPUT 1 // 硬件输入点(dev_out) +#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延时元件(输入1延时输出1,输入0立即输出0) +#define NODE_TYPE_62D_GATE 6 // 62d延时元件(输入1立即输出1,输入0延时输出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脉冲) + +// ==================== 动态链表结构(硬件点) ==================== +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 x; + int y; + int value; + int last_input; +} LogicNode; + +typedef struct { + int src_type; + int src_id; + int dest_type; + int dest_id; +} LogicLink; + +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; + +// ==================== 硬件点操作函数 ==================== +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; +} + +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) { + fprintf(stderr, "内存分配失败:无法创建硬件点ID=%d\n", 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) { + stru_plc_cfg *p = nullptr; + 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) { + for (uint32_t i = 0; i < g_plc_cfg.size(); i++) { + p = &g_plc_cfg.at(i); + if (p->base.inf == node->id) { + default_input_value = *(uint8_t *)p->p_data; + } + } + 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) { + printf("==================== 硬件点列表 ====================\n"); + printf("硬件输入点(dev_out):共%d个\n", hw->input_count); + HWPoint *curr = hw->input_head; + int idx = 1; + while (curr) { + printf(" %d. ID=%d, 值=%d\n", idx++, curr->id, curr->value); + curr = curr->next; + } + printf("硬件输出点(dev_in):共%d个\n", hw->output_count); + curr = hw->output_head; + idx = 1; + while (curr) { + printf(" %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; +} + +// ==================== 逻辑图解析 ==================== +int parse_reclose_logic(const char *file_path, LogicGraph graphs[], int *graph_count) { + FILE *fp = fopen(file_path, "rb"); + if (!fp) { + fprintf(stderr, "错误:无法打开文件 %s\n", file_path); + return -1; + } + + *graph_count = 0; + char buffer[4096]; + size_t bytes_read = fread(buffer, 1, sizeof(buffer) - 1, fp); + buffer[bytes_read] = '\0'; + fclose(fp); + + char *write_ptr = buffer; + char *clean_buffer = buffer; + while (*clean_buffer) { + if (!isspace((unsigned char)*clean_buffer)) { + *write_ptr++ = *clean_buffer; + } + clean_buffer++; + } + *write_ptr = '\0'; + + char *ptr = buffer; + while (ptr && *graph_count < MAX_LOGIC_GRAPHS) { + while (*ptr && *ptr != '"') ptr++; + if (!*ptr) break; + ptr++; + + char key[20]; + int key_len = 0; + while (*ptr && *ptr != '"' && key_len < (int)sizeof(key) - 1) { + key[key_len++] = *ptr++; + } + if (!*ptr) break; + key[key_len] = '\0'; + ptr++; + + while (*ptr && *ptr != ':') ptr++; + if (!*ptr) break; + ptr++; + while (*ptr && *ptr != '"') ptr++; + if (!*ptr) break; + ptr++; + + char graph_data[1024]; + int data_len = 0; + while (*ptr && *ptr != '"' && data_len < (int)sizeof(graph_data) - 1) { + graph_data[data_len++] = *ptr++; + } + if (!*ptr) break; + graph_data[data_len] = '\0'; + ptr++; + + if (strstr(graph_data, "node=") && strstr(graph_data, "link=")) { + LogicGraph *cur_graph = &graphs[*graph_count]; + memset(cur_graph, 0, sizeof(LogicGraph)); + strncpy(cur_graph->key, key, sizeof(cur_graph->key) - 1); + + char *data_ptr = graph_data; + while (*data_ptr) { + char *equals = strchr(data_ptr, '='); + if (!equals) break; + + char param_key[20]; + int pkey_len = equals - data_ptr; + if (pkey_len < (int)sizeof(param_key)) { + strncpy(param_key, data_ptr, pkey_len); + param_key[pkey_len] = '\0'; + } else { + data_ptr = equals + 1; + continue; + } + + char *value_start = equals + 1; + char *value_end = strchr(value_start, '&'); + if (!value_end) value_end = value_start + strlen(value_start); + int value_len = value_end - value_start; + char value[512]; + if (value_len < (int)sizeof(value)) { + strncpy(value, value_start, value_len); + value[value_len] = '\0'; + } else { + data_ptr = value_end + 1; + continue; + } + + if (strcmp(param_key, "name") == 0) { + strncpy(cur_graph->name, value, sizeof(cur_graph->name) - 1); + } else if (strcmp(param_key, "node") == 0) { + char *node_start = strchr(value, '['); + char *node_end = strchr(value, ']'); + if (node_start && node_end) { + node_start++; + *node_end = '\0'; + char *token = strtok(node_start, "{},"); + while (token && cur_graph->node_count < MAX_NODES_PER_GRAPH) { + if (strlen(token) > 0) { + LogicNode node; + if (sscanf(token, "%d:%x:%d:%d", + &node.type, &node.id, &node.x, &node.y) == 4) { + node.value = 0; + cur_graph->nodes[cur_graph->node_count++] = node; + } + } + token = strtok(NULL, "{},"); + } + } + } else if (strcmp(param_key, "link") == 0) { + char *link_start = strchr(value, '['); + char *link_end = strchr(value, ']'); + if (link_start && link_end) { + link_start++; + *link_end = '\0'; + char *token = strtok(link_start, "{},"); + while (token && cur_graph->link_count < MAX_LINKS_PER_GRAPH) { + if (strlen(token) > 0) { + LogicLink link; + if (sscanf(token, "%d:%x-%d:%x", + &link.src_type, &link.src_id, + &link.dest_type, &link.dest_id) == 4) { + cur_graph->links[cur_graph->link_count++] = link; + } + } + token = strtok(NULL, "{},"); + } + } + } + data_ptr = value_end; + if (*data_ptr == '&') data_ptr++; + } + (*graph_count)++; + } + } + return 0; +} + +// ==================== 逻辑运算函数 ==================== + +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) { + input_values[input_count++] = src_node->value; + printf(" 找到输入信号:%d:%d = %d\n", + link->src_type, link->src_id, src_node->value); + } + } + } + return input_count; +} + +static void execute_not_gate(LogicNode *not_node, int input_value) { + not_node->value = !input_value; + printf(" 非门运算:输入=%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]; + } + printf(" 与门运算:输入=["); + for (int i = 0; i < input_count; i++) { + printf("%d%s", input_values[i], (i < input_count - 1) ? "," : ""); + } + printf("] → 输出=%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]; + } + printf(" 或门运算:输入=["); + for (int i = 0; i < input_count; i++) { + printf("%d%s", input_values[i], (i < input_count - 1) ? "," : ""); + } + printf("] → 输出=%d\n", or_node->value); +} + +static void execute_62p_gate(LogicNode *node, int input_value) { + int tp = (node->id >> 8) & 0xFFFFFF; + int component_id = node->id & 0xFF; + if (input_value == 1) { + printf(" 62p延时元件 (ID=%d, 序号=%d):输入=1,开始延时%d毫秒\n", + node->id, component_id, tp); + usleep(tp * 1000); + node->value = 1; + printf(" 62p延时元件 (ID=%d, 序号=%d):延时结束,输出=1\n", + node->id, component_id); + } else { + node->value = 0; + } +} + +static void execute_62d_gate(LogicNode *node, int input_value) { + int td = (node->id >> 8) & 0xFFFFFF; + int component_id = node->id & 0xFF; + if (input_value == 1) { + node->value = 1; + printf(" 62d延时元件 (ID=%d, 序号=%d):输入=1,立即输出=1\n", + node->id, component_id); + } else { + printf(" 62d延时元件 (ID=%d, 序号=%d):输入=0,开始延时%d毫秒\n", + node->id, component_id, td); + usleep(td * 1000); + node->value = 0; + printf(" 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) { + printf(" 上升沿元件 (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) { + printf(" 下降沿元件 (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; + printf(" SR触发器 (ID=%d, 序号=%d):S=%d, R=%d\n", node->id, component_id, s, r); + if (s == 1) { + node->value = 1; + printf(" SR触发器:S=1,置位,输出=1\n"); + } else if (r == 1) { + node->value = 0; + printf(" 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; + printf(" RS触发器 (ID=%d, 序号=%d):R=%d, S=%d\n", node->id, component_id, r, s); + if (r == 1) { + node->value = 0; + printf(" RS触发器:R=1,复位,输出=0\n"); + } else if (s == 1) { + node->value = 1; + printf(" RS触发器:R=0, S=1,置位,输出=1\n"); + } +} + +// ==================== 逻辑图执行 ==================== +int execute_logic_graph(LogicGraph *graph, HardwareManager *hw) { + if (!graph || !hw) return -1; + + printf("\n=====================================================\n"); + printf("执行逻辑图:%s (%s)\n", graph->key, graph->name); + printf("=====================================================\n"); + + // 步骤1:初始化节点值 + printf("\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; + } + printf(" %s (类型=%d, ID=%d): 初始值=%d\n", + type_name, node->type, node->id, node->value); + } + + // 步骤2:执行逻辑元件运算 + printf("\n【逻辑元件运算】\n"); + for (int i = 0; i < graph->node_count; i++) { + LogicNode *node = &graph->nodes[i]; + int input_values[10]; + int input_count; + switch (node->type) { + case NODE_TYPE_NOT_GATE: + printf("\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 { printf(" 警告:非门元件没有输入信号\n"); node->value = 0; } + break; + case NODE_TYPE_OR_GATE: + printf("\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: + printf("\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: + printf("\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 { printf(" 警告:62p延时元件没有输入信号\n"); node->value = 0; } + break; + case NODE_TYPE_62D_GATE: + printf("\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 { printf(" 警告:62d延时元件没有输入信号\n"); node->value = 0; } + break; + case NODE_TYPE_RISING_EDGE: + printf("\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 { printf(" 警告:上升沿元件没有输入信号\n"); node->value = 0; } + break; + case NODE_TYPE_FALLING_EDGE: + printf("\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 { printf(" 警告:下降沿元件没有输入信号\n"); node->value = 0; } + break; + case NODE_TYPE_SR_LATCH: + printf("\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: + printf("\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:处理输出链路 + printf("\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 (dest_node->id < MAX_OUT_NODES) { + g_plc_st_out[dest_node->id] = dest_node->value; + } + printf(" 硬件输出:ID=%d = %d(已同步到硬件管理器)\n", + dest_node->id, dest_node->value); + } + } + + printf("\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; + } + printf(" %s (ID=%d): 最终值=%d\n", type_name, node->id, node->value); + } + return 0; +} + +// ==================== PLC 逻辑入口 ==================== +int PLC_Logic(void) { + char proc_dir[512] = {0}; + if(0 != func_get_process_self_dir(proc_dir, sizeof(proc_dir))) + { + MY_LOG_E("func_get_process_self_dir failed"); + return -1; + } + std::string file_path = std::string(proc_dir) + "config/PLC/Reclose_logic.txt"; + + LogicGraph graphs[MAX_LOGIC_GRAPHS]; + int graph_count = 0; + + if (parse_reclose_logic(file_path.c_str(), graphs, &graph_count) != 0) { + return 2; + } + + HardwareManager hw; + init_hardware_manager(&hw); + + extract_hw_points_from_graphs(graphs, graph_count, &hw, 0); + +#ifdef DEBUG + printf("==================== 文件解析结果 ====================\n"); + printf("共解析到 %d 个逻辑图\n", graph_count); + for (int i = 0; i < graph_count; i++) { + printf(" 逻辑图%d:key=%s, name=%s, 节点数=%d, 链路数=%d\n", + i + 1, graphs[i].key, graphs[i].name, + graphs[i].node_count, graphs[i].link_count); + } + print_hardware_manager(&hw); + + for (int i = 0; i < graph_count; i++) { + execute_logic_graph(&graphs[i], &hw); + } + + printf("\n==================== 最终硬件输出状态 ====================\n"); + printf("硬件输出点(dev_in)最终值:\n"); + HWPoint *curr = hw.output_head; + int idx = 1; + while (curr) { + printf(" %d. ID=%d: %d\n", idx++, curr->id, curr->value); + curr = curr->next; + } +#endif + + destroy_hardware_manager(&hw); + return 0; +} + +// ==================== 模块初始化与线程 ==================== +int app_plc_init1(void *arg) +{ + stru_app *p_app = (stru_app *)arg; + if (NULL == p_app) { + MY_LOG_E("app_plc_init1 arg null"); + return -1; + } + + int ret = 0; + ret |= dc_signal_out("plc.run_cnt", "plc线程计数", DATA_TYPE_U32, &p_app->run_cnt); + + for (int i = 0; i < MAX_OUT_NODES; i++) { + std::string saddr = "plc.st.out." + std::to_string(i); + std::string desc = "plc输出" + std::to_string(i); + ret |= dc_signal_out(saddr.c_str(), desc, DATA_TYPE_U8, &g_plc_st_out[i]); + } + + if (ret != 0) { + MY_LOG_E("app_plc_init1 dc_signal_out failed"); + return -1; + } + + p_plc_cfg = self_ptl_cfg_get(); + if (nullptr == p_plc_cfg) { + MY_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_in("plc.run_cnt_in", "plc.run_cnt_in", "plc.run_cnt", (void **)&gp_run_cnt_in); + + for (uint32_t i = 0; i < g_plc_cfg.size(); i++) { + stru_plc_cfg *p = &g_plc_cfg[i]; + std::string saddr = "plc.st.in." + std::to_string(i); + std::string desc = "plc链接遥信" + std::to_string(i); + ret |= dc_signal_in(saddr.c_str(), desc, p->base.saddr.c_str(), (void **)&p->p_data); + } + if (ret != 0) { + MY_LOG_E("app_plc_init2 dc_signal_in 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; +} diff --git a/test/config/PLC/Reclose_logic.txt b/test/config/PLC/Reclose_logic.txt new file mode 100644 index 0000000..0b7e030 --- /dev/null +++ b/test/config/PLC/Reclose_logic.txt @@ -0,0 +1 @@ +{"840957954":"key=840957954&name=Block Over Current(G)&desc=desc&desc_pos_x=0&desc_pos_y=0&node=[{1:38:-330:-120},{0:1:130:-120},{1:36:-390:-10},{0:2:170:-10},{1:37:-400:80},{0:3:170:110},{3:0:-10:30}]&link=[{1:38-0:1},{3:0-0:2},{3:0-0:3},{1:36-3:0},{1:37-3:0}]","online_cfgId":"3486BE04"} \ No newline at end of file diff --git a/test/config/SYSTEM/app_config.json b/test/config/SYSTEM/app_config.json index 51cc480..0090b38 100644 --- a/test/config/SYSTEM/app_config.json +++ b/test/config/SYSTEM/app_config.json @@ -9,6 +9,7 @@ {"name": "app_self_ptl", "enable": true, "comment": "ICP67 私有规约应用"}, {"name": "app_iec61850m", "enable": false, "comment": "IEC 61850 MMS 客户端"}, {"name": "app_iec61850s", "enable": false, "comment": "IEC 61850 MMS 服务端"}, - {"name": "app_modbus_m", "enable": false, "comment": "Modbus 主站(TCP/RTU 多通道)"} + {"name": "app_modbus_m", "enable": false, "comment": "Modbus 主站(TCP/RTU 多通道)"}, + {"name": "app_plc", "enable": true, "comment": "PLC 就地自动化逻辑"} ] }