feat: 集成 PLC 就地自动化逻辑模块 + SIGILL 编译修复

## PLC 模块 (libplc)
- 新增 libplc 模块: 解析 Reclose_logic.txt 逻辑图,支持与/或/非/延时/SR等多种节点类型
- PLC_Logic() 配置文件路径改为 func_get_process_self_dir 动态拼接
- app_modules.h 注册 APP_MODULE(PLC, plc, ...)
- system makefile 增加 libplc 子目录
- RTU makefile 链接 -lplc

## SIGILL 编译修复
- linux.mk: ARM 编译加 -mno-outline-atomics -fno-threadsafe-statics,禁用 LSE 原子指令
- RTU makefile: STATIC_FLAGS 去掉 -static-libstdc++,避免工具链预编译 libstdc++ 中的 LSE 指令触发 RK3568 SIGILL

## 配置
- app_config.json 新增 app_plc 条目(默认 enable: false)
- PLC/Reclose_logic.txt 逻辑配置文件占位
This commit is contained in:
ypc 2026-07-01 15:56:12 +08:00
parent cb60d687e3
commit b176d957df
9 changed files with 809 additions and 4 deletions

View File

@ -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 )

View File

@ -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

View File

@ -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)

View File

@ -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' $< > $@

View File

@ -10,6 +10,7 @@ SUBDIRS += ./libiec61850s
SUBDIRS += ./libself_ptl
SUBDIRS += ./libweb_server
SUBDIRS += ./libmodbus_m
SUBDIRS += ./libplc
SUBDIRS += ./RTU

View File

View File

@ -0,0 +1,742 @@
#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 <ctype.h>
#include <locale.h> // ANSI编码支持
#include <unistd.h> // 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<stru_plc_cfg> 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(" 逻辑图%dkey=%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;
}

View File

@ -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"}

View File

@ -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 就地自动化逻辑"}
]
}