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:
parent
cb60d687e3
commit
b176d957df
|
|
@ -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(IEC61850M, iec61850m, app_iec61850m_init1, app_iec61850m_init2, app_iec61850m )
|
||||||
APP_MODULE(IEC61850S, iec61850s, app_iec61850s_init1, app_iec61850s_init2, app_iec61850s )
|
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(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 )
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@ endif
|
||||||
|
|
||||||
# 编译选项
|
# 编译选项
|
||||||
ifeq ($(CROSS), arm)
|
ifeq ($(CROSS), arm)
|
||||||
C_FLAGS = $(REL_INC) -DRK356x
|
C_FLAGS = $(REL_INC) -DRK356x -mno-outline-atomics -fno-threadsafe-statics
|
||||||
else
|
else
|
||||||
C_FLAGS = $(REL_INC)
|
C_FLAGS = $(REL_INC)
|
||||||
endif
|
endif
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ MakeDirCommand := mkdir -p
|
||||||
# 静态库链接(注意顺序很重要,被依赖的库放在后面)
|
# 静态库链接(注意顺序很重要,被依赖的库放在后面)
|
||||||
# Libs := -lcom_channel -lcom_scan -liec -lself_ptl -lfunc -ltask -lcomm -lshell -lpthread
|
# 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 += -l60870 -licp67 -lmms_m -lmms_s -lmongoose -lmodbus
|
||||||
Libs += -liec61850
|
Libs += -liec61850
|
||||||
Libs += -lmy_xxhash -lcmd -lmd5 -lxml -lcJSON -lcomm -ltask -lfunc
|
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 # 完全静态链接(包含libc等)
|
||||||
STATIC_FLAGS := -static-libgcc -static-libstdc++ # 只静态链接gcc相关库
|
STATIC_FLAGS := -static-libgcc # 只静态链接gcc库;libstdc++动态链接(目标设备版本无LSE)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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' $< > $@
|
||||||
|
|
@ -10,6 +10,7 @@ SUBDIRS += ./libiec61850s
|
||||||
SUBDIRS += ./libself_ptl
|
SUBDIRS += ./libself_ptl
|
||||||
SUBDIRS += ./libweb_server
|
SUBDIRS += ./libweb_server
|
||||||
SUBDIRS += ./libmodbus_m
|
SUBDIRS += ./libmodbus_m
|
||||||
|
SUBDIRS += ./libplc
|
||||||
|
|
||||||
|
|
||||||
SUBDIRS += ./RTU
|
SUBDIRS += ./RTU
|
||||||
|
|
|
||||||
|
|
@ -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(" 逻辑图%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;
|
||||||
|
}
|
||||||
|
|
@ -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"}
|
||||||
|
|
@ -9,6 +9,7 @@
|
||||||
{"name": "app_self_ptl", "enable": true, "comment": "ICP67 私有规约应用"},
|
{"name": "app_self_ptl", "enable": true, "comment": "ICP67 私有规约应用"},
|
||||||
{"name": "app_iec61850m", "enable": false, "comment": "IEC 61850 MMS 客户端"},
|
{"name": "app_iec61850m", "enable": false, "comment": "IEC 61850 MMS 客户端"},
|
||||||
{"name": "app_iec61850s", "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 就地自动化逻辑"}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue