cid: import and parse

This commit is contained in:
fengzero
2024-10-22 08:53:22 +00:00
parent 2f3462f46b
commit ae30128dd3
27 changed files with 1441 additions and 30 deletions
+7 -2
View File
@@ -54,14 +54,17 @@ add_custom_target(neuron-version
${CMAKE_CURRENT_SOURCE_DIR}/cmake/neuron-version.cmake)
find_package(nng CONFIG REQUIRED)
find_package(LibXml2 REQUIRED)
find_package(Threads)
if (CMAKE_STAGING_PREFIX)
include_directories(${CMAKE_STAGING_PREFIX}/include)
link_directories(${CMAKE_STAGING_PREFIX}/lib)
include_directories(${CMAKE_STAGING_PREFIX}/include/libxml2)
else()
include_directories(/usr/local/include)
link_directories(/usr/local/lib)
include_directories(/usr/local/include/libxml2)
endif()
set(PERSIST_SOURCES
@@ -90,6 +93,7 @@ set(NEURON_BASE_SOURCES
src/utils/base64.c
src/utils/async_queue.c
src/utils/log.c
src/utils/cid.c
${PERSIST_SOURCES})
if (SMART_LINK)
@@ -114,7 +118,7 @@ target_sources(neuron-base PRIVATE ${NEURON_BASE_SOURCES} ${NEURON_SRC_PARSE} ${
target_include_directories(neuron-base
PRIVATE include/neuron src)
target_link_libraries(neuron-base libssl.a libcrypto.a)
target_link_libraries(neuron-base nng libzlog.so jansson jwt
target_link_libraries(neuron-base nng libzlog.so jansson jwt xml2
${CMAKE_THREAD_LIBS_INIT} -lm protobuf-c)
add_dependencies(neuron-base neuron-version)
@@ -150,6 +154,7 @@ set(NEURON_SOURCES
plugins/restful/version_handle.c
plugins/restful/scan_handle.c
plugins/restful/otel_handle.c
plugins/restful/cid_handle.c
plugins/restful/rest.c
plugins/restful/user.c)
@@ -157,7 +162,7 @@ set(CMAKE_BUILD_RPATH ./)
add_executable(neuron)
target_sources(neuron PRIVATE ${NEURON_SOURCES})
target_include_directories(neuron PRIVATE include/neuron src plugins)
target_link_libraries(neuron dl neuron-base sqlite3 -lm)
target_link_libraries(neuron dl neuron-base sqlite3 -lm xml2)
target_link_options(neuron PRIVATE "LINKER:--dynamic-list-data")
#copy file for run
+15
View File
@@ -62,6 +62,21 @@
#define NEU_LOG_LEVEL_ERROR "error"
#define NEU_LOG_LEVEL_FATAL "fatal"
#define NEU_CID_LNCLASS_LEN 8
#define NEU_CID_LNTYPE_LEN 32
#define NEU_CID_IED_NAME_LEN 32
#define NEU_CID_LDEVICE_LEN 32
#define NEU_CID_LNO_NAME_LEN 32
#define NEU_CID_LNO_TYPE_LEN 32
#define NEU_CID_INST_LEN 32
#define NEU_CID_SDI_NAME_LEN 16
#define NEU_CID_DO_NAME_LEN 32
#define NEU_CID_DO_ID_LEN 32
#define NEU_CID_DA_NAME_LEN 32
#define NEU_CID_DATASET_NAME_LEN 32
#define NEU_CID_REPORT_NAME_LEN 32
#define NEU_CID_REPORT_ID_LEN 64
#define CHECK_NODE_NAME_LENGTH_ERR \
do { \
NEU_JSON_RESPONSE_ERROR(NEU_ERR_NODE_NAME_TOO_LONG, { \
+1
View File
@@ -48,6 +48,7 @@ typedef enum {
NEU_ERR_IP_ADDRESS_INVALID = 1015,
NEU_ERR_IP_ADDRESS_IN_USE = 1016,
NEU_ERR_BODY_TOO_BIG = 1017,
NEU_ERR_INVALID_CID = 1018,
NEU_ERR_NODE_EXIST = 2002,
NEU_ERR_NODE_NOT_EXIST = 2003,
+2 -1
View File
@@ -352,9 +352,10 @@ typedef struct neu_resp_get_group {
typedef struct {
char group[NEU_GROUP_NAME_LEN];
int n_tag;
int interval;
int n_tag;
neu_datatag_t *tags;
void * context;
} neu_gdatatag_t;
typedef struct {
+6 -1
View File
@@ -41,6 +41,7 @@ typedef struct {
typedef struct {
uint32_t interval;
char * name;
char * context;
} neu_persist_group_info_t;
typedef struct {
@@ -68,6 +69,9 @@ static inline void neu_persist_node_info_fini(neu_persist_node_info_t *info)
static inline void neu_persist_group_info_fini(neu_persist_group_info_t *info)
{
free(info->name);
if (info->context) {
free(info->context);
}
}
static inline void
@@ -255,7 +259,8 @@ int neu_persister_delete_subscription(const char *app_name,
* @return 0 on success, non-zero otherwise
*/
int neu_persister_store_group(const char * driver_name,
neu_persist_group_info_t *group_info);
neu_persist_group_info_t *group_info,
const char * context);
/**
* Update group config.
+1
View File
@@ -67,6 +67,7 @@ struct neu_plugin_group {
char * group_name;
UT_array *tags;
void * context;
void * user_data;
neu_plugin_group_free group_free;
uint32_t interval;
+144
View File
@@ -0,0 +1,144 @@
/**
* NEURON IIoT System for Industry 4.0
* Copyright (C) 2020-2022 EMQ Technologies Co., Ltd All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
**/
#ifndef _NEU_UTILS_CID_H_
#define _NEU_UTILS_CID_H_
#include "define.h"
#include "msg.h"
typedef enum {
CO = 0,
ST = 1, // boolean
MX = 2, // float
UNKNOWN = 100,
} cid_fc_e;
typedef struct {
char name[NEU_CID_DO_NAME_LEN];
char lnclass[NEU_CID_LNCLASS_LEN];
cid_fc_e fc;
} cid_do_t;
typedef struct {
char name[NEU_CID_DATASET_NAME_LEN];
cid_do_t *dos;
int n_dos;
} cid_dataset_t;
typedef struct {
char name[NEU_CID_REPORT_NAME_LEN];
char id[NEU_CID_REPORT_ID_LEN];
char dataset[NEU_CID_DATASET_NAME_LEN];
bool buffered;
int intg_pd;
} cid_report_t;
typedef struct {
char do_name[NEU_CID_DO_NAME_LEN];
char sdi_name[NEU_CID_SDI_NAME_LEN];
} cid_ctrl_t;
typedef struct {
char lnclass[NEU_CID_LNCLASS_LEN];
char lntype[NEU_CID_LNTYPE_LEN];
cid_dataset_t *datasets;
int n_datasets;
cid_report_t *reports;
int n_reports;
cid_ctrl_t *ctrls;
int n_ctrls;
} cid_ln_t;
typedef struct {
char inst[NEU_CID_INST_LEN];
cid_ln_t *lns;
int n_lns;
} cid_ldevice_t;
typedef struct {
char name[NEU_CID_IED_NAME_LEN];
cid_ldevice_t *ldevices;
int n_ldevices;
} cid_ied_t;
typedef enum {
SPC = 0,
DPC = 1,
} cid_tm_cdc_e;
typedef struct {
char name[NEU_CID_DA_NAME_LEN];
cid_fc_e fc;
} cid_tm_da_t;
typedef struct {
char id[NEU_CID_DO_ID_LEN];
cid_tm_cdc_e cdc;
cid_tm_da_t *das;
int n_das;
} cid_tm_do_t;
typedef struct {
char name[NEU_CID_LNO_NAME_LEN];
char type[NEU_CID_LNO_TYPE_LEN];
} cid_tm_lno_do_t;
typedef struct {
char id[NEU_CID_DO_ID_LEN];
cid_tm_lno_do_t *dos;
int n_dos;
} cid_tm_lno_t;
typedef struct {
cid_tm_do_t *dos;
int n_dos;
cid_tm_lno_t *lnos;
int n_lnos;
} cid_template_t;
typedef struct {
cid_ied_t ied;
cid_template_t template;
} cid_t;
typedef struct {
bool control;
char ied_name[NEU_CID_IED_NAME_LEN];
char ldevice_inst[NEU_CID_LDEVICE_LEN];
char ln_class[NEU_CID_LNCLASS_LEN];
bool buffered;
char report_name[NEU_CID_REPORT_NAME_LEN];
char report_id[NEU_CID_REPORT_ID_LEN];
char dataset_name[NEU_CID_DATASET_NAME_LEN];
} cid_dataset_info_t;
int neu_cid_parse(const char *path, cid_t *cid);
void neu_cid_free(cid_t *cid);
void neu_cid_to_msg(char *driver, cid_t *cid, neu_req_add_gtag_t *cmd);
char * neu_cid_info_to_string(cid_dataset_info_t *info);
cid_dataset_info_t *neu_cid_info_from_string(const char *str);
#endif
+16
View File
@@ -41,4 +41,20 @@ INSERT INTO tags SELECT * FROM temp_tags;
DROP TABLE temp_tags;
ALTER TABLE subscriptions RENAME TO temp_subscriptions;
CREATE TABLE
IF NOT EXISTS subscriptions (
app_name TEXT NOT NULL,
driver_name TEXT NOT NULL,
group_name TEXT NOT NULL,
params TEXT DEFAULT NULL,
CHECK (app_name != driver_name),
UNIQUE (app_name, driver_name, group_name),
FOREIGN KEY (app_name) REFERENCES nodes (name) ON UPDATE CASCADE ON DELETE CASCADE,
FOREIGN KEY (driver_name, group_name) REFERENCES groups (driver_name, name) ON UPDATE CASCADE ON DELETE CASCADE
);
INSERT INTO subscriptions SELECT * FROM temp_subscriptions;
DROP TABLE temp_subscriptions;
COMMIT;
+36
View File
@@ -0,0 +1,36 @@
/**
* NEURON IIoT System for Industry 4.0
* Copyright (C) 2020-2024 EMQ Technologies Co., Ltd All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
**/
BEGIN TRANSACTION;
ALTER TABLE groups RENAME TO temp_groups;
CREATE TABLE IF NOT EXISTS
groups (
driver_name TEXT NOT NULL,
name TEXT NULL check(length(name) <= 32),
interval INTEGER NOT NULL check(interval >= 100),
context TEXT NULL check(length(context) <= 512),
UNIQUE (driver_name, name),
FOREIGN KEY (driver_name) REFERENCES nodes (name) ON UPDATE CASCADE ON DELETE CASCADE
);
INSERT INTO groups SELECT driver_name, name, interval, NULL FROM temp_groups;
DROP TABLE temp_groups;
COMMIT;
+60
View File
@@ -0,0 +1,60 @@
/**
* NEURON IIoT System for Industry 4.0
* Copyright (C) 2020-2024 EMQ Technologies Co., Ltd All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
**/
BEGIN TRANSACTION;
ALTER TABLE tags RENAME TO temp_tags;
CREATE TABLE
IF NOT EXISTS tags (
driver_name TEXT NOT NULL,
group_name TEXT NOT NULL,
name TEXT NULL check (length (name) <= 128),
address TEXT NULL check (length (address) <= 128),
attribute INTEGER NOT NULL check (attribute BETWEEN 0 AND 15),
precision INTEGER NOT NULL check (precision BETWEEN 0 AND 17),
decimal REAL NOT NULL,
bias REAL NOT NULL check (bias BETWEEN -1000 AND 1000),
type INTEGER NOT NULL check (type BETWEEN 0 AND 22),
description TEXT NULL check (length (description) <= 512),
value TEXT,
UNIQUE (driver_name, group_name, name),
FOREIGN KEY (driver_name, group_name) REFERENCES groups (driver_name, name) ON UPDATE CASCADE ON DELETE CASCADE
);
INSERT INTO tags SELECT * FROM temp_tags;
DROP TABLE temp_tags;
ALTER TABLE subscriptions RENAME TO temp_subscriptions;
CREATE TABLE
IF NOT EXISTS subscriptions (
app_name TEXT NOT NULL,
driver_name TEXT NOT NULL,
group_name TEXT NOT NULL,
params TEXT DEFAULT NULL,
CHECK (app_name != driver_name),
UNIQUE (app_name, driver_name, group_name),
FOREIGN KEY (app_name) REFERENCES nodes (name) ON UPDATE CASCADE ON DELETE CASCADE,
FOREIGN KEY (driver_name, group_name) REFERENCES groups (driver_name, name) ON UPDATE CASCADE ON DELETE CASCADE
);
INSERT INTO subscriptions SELECT * FROM temp_subscriptions;
DROP TABLE temp_subscriptions;
COMMIT;
+46
View File
@@ -0,0 +1,46 @@
#include <nng/nng.h>
#include <nng/supplemental/http/http.h>
#include "define.h"
#include "errcodes.h"
#include "handle.h"
#include "utils/cid.h"
#include "utils/http.h"
#include "utils/log.h"
#include "json/neu_json_error.h"
#include "json/neu_json_fn.h"
#include "parser/neu_json_cid.h"
void handle_cid(nng_aio *aio)
{
neu_plugin_t *plugin = neu_rest_get_plugin();
(void) plugin;
NEU_PROCESS_HTTP_REQUEST(
aio, neu_json_upload_cid_t, neu_json_decode_upload_cid_req, {
cid_t cid = { 0 };
int parse_re = neu_cid_parse(req->path, &cid);
if (parse_re == 0) {
neu_reqresp_head_t header = { 0 };
neu_req_add_gtag_t cmd = { 0 };
header.ctx = aio;
header.type = NEU_REQ_ADD_GTAG;
header.otel_trace_type = NEU_OTEL_TRACE_TYPE_REST_COMM;
nlog_notice("cid parse success: %s", req->path);
neu_cid_to_msg(req->driver, &cid, &cmd);
int ret = neu_plugin_op(plugin, header, &cmd);
if (ret != 0) {
NEU_JSON_RESPONSE_ERROR(NEU_ERR_IS_BUSY, {
neu_http_response(aio, NEU_ERR_IS_BUSY, result_error);
});
}
} else {
NEU_JSON_RESPONSE_ERROR(NEU_ERR_INVALID_CID, {
neu_http_response(aio, NEU_ERR_INVALID_CID, result_error);
});
}
neu_cid_free(&cid);
})
}
+26
View File
@@ -0,0 +1,26 @@
/**
* NEURON IIoT System for Industry 4.0
* Copyright (C) 2020-2022 EMQ Technologies Co., Ltd All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
**/
#ifndef _NEU_PLUGIN_REST_CID_HANDLE_H_
#define _NEU_PLUGIN_REST_CID_HANDLE_H_
#include <nng/nng.h>
void handle_cid(nng_aio *aio);
#endif
+10
View File
@@ -25,6 +25,7 @@
#include "plugin.h"
#include "adapter_handle.h"
#include "cid_handle.h"
#include "datatag_handle.h"
#include "global_config_handle.h"
#include "group_config_handle.h"
@@ -131,6 +132,9 @@ static struct neu_http_handler cors_handler[] = {
{
.url = "/api/v2/otel",
},
{
.url = "/api/v2/cid",
},
};
static struct neu_http_handler rest_handlers[] = {
@@ -146,6 +150,12 @@ static struct neu_http_handler rest_handlers[] = {
.url = "/",
.value.path = "/web",
},
{
.method = NEU_HTTP_METHOD_POST,
.type = NEU_HTTP_HANDLER_FUNCTION,
.url = "/api/v2/cid",
.value.handler = handle_cid,
},
{
.method = NEU_HTTP_METHOD_POST,
.type = NEU_HTTP_HANDLER_FUNCTION,
+8 -5
View File
@@ -1066,15 +1066,16 @@ static int adapter_loop(enum neu_event_io_type type, int fd, void *usr_data)
} else {
if (adapter->module->type == NEU_NA_TYPE_DRIVER) {
error.error = neu_adapter_driver_add_group(
(neu_adapter_driver_t *) adapter, cmd->group,
cmd->interval);
(neu_adapter_driver_t *) adapter, cmd->group, cmd->interval,
NULL);
} else {
error.error = NEU_ERR_GROUP_NOT_ALLOW;
}
}
if (error.error == NEU_ERR_SUCCESS) {
adapter_storage_add_group(adapter->name, cmd->group, cmd->interval);
adapter_storage_add_group(adapter->name, cmd->group, cmd->interval,
NULL);
}
neu_msg_exchange(header);
@@ -1465,9 +1466,11 @@ int neu_adapter_add_gtags(neu_adapter_t *adapter, neu_req_add_gtag_t *cmd,
// ensure group created`
neu_adapter_driver_add_group((neu_adapter_driver_t *) adapter,
cmd->groups[group_index].group,
cmd->groups[group_index].interval);
cmd->groups[group_index].interval,
cmd->groups[group_index].context);
adapter_storage_add_group(adapter->name, cmd->groups[group_index].group,
cmd->groups[group_index].interval);
cmd->groups[group_index].interval,
cmd->groups[group_index].context);
for (int tag_index = 0; tag_index < cmd->groups[group_index].n_tag;
tag_index++) {
int add_tag_result = neu_adapter_driver_add_tag(
+13 -4
View File
@@ -467,6 +467,9 @@ int neu_adapter_driver_uninit(neu_adapter_driver_t *driver)
el->grp.group_free(&el->grp);
}
free(el->grp.group_name);
if (el->grp.context) {
free(el->grp.context);
}
free(el->name);
utarray_free(el->grp.tags);
@@ -1377,7 +1380,7 @@ int neu_adapter_driver_write_tag(neu_adapter_driver_t *driver,
name##_TYPE, (init))
int neu_adapter_driver_add_group(neu_adapter_driver_t *driver, const char *name,
uint32_t interval)
uint32_t interval, void *context)
{
UT_icd icd = { sizeof(to_be_write_tag_t), NULL, NULL, NULL };
UT_icd sub_icd = { sizeof(sub_app_t), NULL, NULL, NULL };
@@ -1399,6 +1402,7 @@ int neu_adapter_driver_add_group(neu_adapter_driver_t *driver, const char *name,
find->group = neu_group_new(name, interval);
find->grp.group_name = strdup(name);
find->grp.interval = interval;
find->grp.context = context;
neu_group_split_static_tags(find->group, &find->static_tags,
&find->grp.tags);
@@ -1515,6 +1519,9 @@ int neu_adapter_driver_del_group(neu_adapter_driver_t *driver, const char *name)
}
free(find->grp.group_name);
free(find->name);
if (find->grp.context) {
free(find->grp.context);
}
utarray_foreach(find->static_tags, neu_datatag_t *, tag)
{
@@ -1732,8 +1739,8 @@ int neu_adapter_driver_add_tag(neu_adapter_driver_t *driver, const char *group,
HASH_FIND_STR(driver->groups, group, find);
if (find == NULL) {
neu_adapter_driver_add_group(driver, group, interval);
adapter_storage_add_group(driver->adapter.name, group, interval);
neu_adapter_driver_add_group(driver, group, interval, NULL);
adapter_storage_add_group(driver->adapter.name, group, interval, NULL);
}
HASH_FIND_STR(driver->groups, group, find);
assert(find != NULL);
@@ -2135,9 +2142,11 @@ static void group_change(void *arg, int64_t timestamp, UT_array *static_tags,
.tags = NULL,
.group_free = NULL,
.user_data = NULL,
.context = NULL,
};
grp.tags = other_tags;
grp.context = group->grp.context;
grp.tags = other_tags;
free(group->grp.group_name);
if (group->static_tags != NULL) {
utarray_free(group->static_tags);
+1 -1
View File
@@ -46,7 +46,7 @@ int neu_adapter_driver_write_gtags(neu_adapter_driver_t *driver,
neu_reqresp_head_t * req);
int neu_adapter_driver_add_group(neu_adapter_driver_t *driver, const char *name,
uint32_t interval);
uint32_t interval, void *context);
int neu_adapter_driver_update_group(neu_adapter_driver_t *driver,
const char *name, const char *new_name,
uint32_t interval);
+15 -4
View File
@@ -17,6 +17,7 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
**/
#include "utils/cid.h"
#include "utils/log.h"
#include "adapter_internal.h"
@@ -34,14 +35,19 @@ void adapter_storage_setting(const char *node, const char *setting)
}
void adapter_storage_add_group(const char *node, const char *group,
uint32_t interval)
uint32_t interval, void *context)
{
neu_persist_group_info_t info = {
.name = (char *) group,
.interval = interval,
};
neu_persister_store_group(node, &info);
if (context != NULL) {
char *ctx = neu_cid_info_to_string((cid_dataset_info_t *) context);
neu_persister_store_group(node, &info, ctx);
free(ctx);
} else {
neu_persister_store_group(node, &info, NULL);
}
}
void adapter_storage_update_group(const char *node, const char *group,
@@ -146,7 +152,12 @@ int adapter_load_group_and_tag(neu_adapter_driver_t *driver)
utarray_foreach(group_infos, neu_persist_group_info_t *, p)
{
UT_array *tags = NULL;
neu_adapter_driver_add_group(driver, p->name, p->interval);
if (p->context == NULL) {
neu_adapter_driver_add_group(driver, p->name, p->interval, NULL);
} else {
cid_dataset_info_t *info = neu_cid_info_from_string(p->context);
neu_adapter_driver_add_group(driver, p->name, p->interval, info);
}
rv = neu_persister_load_tags(adapter->name, p->name, &tags);
if (0 != rv) {
+1 -1
View File
@@ -27,7 +27,7 @@
void adapter_storage_state(const char *node, neu_node_running_state_e state);
void adapter_storage_setting(const char *node, const char *setting);
void adapter_storage_add_group(const char *node, const char *group,
uint32_t interval);
uint32_t interval, void *context);
void adapter_storage_update_group(const char *node, const char *group,
const char *new_name, uint32_t interval);
void adapter_storage_del_group(const char *node, const char *group);
+1 -1
View File
@@ -1367,7 +1367,7 @@ static int manager_loop(enum neu_event_io_type type, int fd, void *usr_data)
for (uint16_t j = 0; j < driver->n_group; j++) {
adapter_storage_add_group(driver->node,
driver->groups[j].group,
driver->groups[j].interval);
driver->groups[j].interval, NULL);
adapter_storage_add_tags(
driver->node, driver->groups[j].group,
driver->groups[j].tags, driver->groups[j].n_tag);
+98
View File
@@ -0,0 +1,98 @@
/**
* NEURON IIoT System for Industry 4.0
* Copyright (C) 2020-2022 EMQ Technologies Co., Ltd All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
**/
/*
* DO NOT EDIT THIS FILE MANUALLY!
* It was automatically generated by `json-autotype`.
*/
#include <stdlib.h>
#include <string.h>
#include <jansson.h>
#include "json/json.h"
#include "neu_json_cid.h"
int neu_json_decode_upload_cid_req_json(void * json_obj,
neu_json_upload_cid_t *req)
{
int ret = 0;
neu_json_elem_t req_elems[] = {
{
.name = "driver",
.t = NEU_JSON_STR,
},
{
.name = "path",
.t = NEU_JSON_STR,
},
};
ret = neu_json_decode_by_json(json_obj, NEU_JSON_ELEM_SIZE(req_elems),
req_elems);
if (ret != 0) {
return -1;
}
req->driver = req_elems[0].v.val_str;
req->path = req_elems[1].v.val_str;
return 0;
}
int neu_json_decode_upload_cid_req(char *buf, neu_json_upload_cid_t **result)
{
int ret = 0;
void * json_obj = NULL;
neu_json_upload_cid_t *req = calloc(1, sizeof(neu_json_upload_cid_t));
if (req == NULL) {
return -1;
}
json_obj = neu_json_decode_new(buf);
if (NULL == json_obj) {
free(req);
return -1;
}
ret = neu_json_decode_upload_cid_req_json(json_obj, req);
if (0 == ret) {
*result = req;
} else {
free(req);
}
neu_json_decode_free(json_obj);
return ret;
}
void neu_json_decode_upload_cid_req_fini(neu_json_upload_cid_t *req)
{
free(req->driver);
free(req->path);
}
void neu_json_decode_upload_cid_req_free(neu_json_upload_cid_t *req)
{
if (req) {
neu_json_decode_upload_cid_req_fini(req);
free(req);
}
}
+48
View File
@@ -0,0 +1,48 @@
/**
* NEURON IIoT System for Industry 4.0
* Copyright (C) 2020-2022 EMQ Technologies Co., Ltd All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
**/
/*
* DO NOT EDIT THIS FILE MANUALLY!
* It was automatically generated by `json-autotype`.
*/
#ifndef _NEU_JSON_API_NEU_JSON_CID_H_
#define _NEU_JSON_API_NEU_JSON_CID_H_
#include "define.h"
#include "json/json.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
char *driver;
char *path;
} neu_json_upload_cid_t;
int neu_json_decode_upload_cid_req(char *buf, neu_json_upload_cid_t **result);
void neu_json_decode_upload_cid_req_fini(neu_json_upload_cid_t *req);
void neu_json_decode_upload_cid_req_free(neu_json_upload_cid_t *req);
#ifdef __cplusplus
}
#endif
#endif
+3 -2
View File
@@ -421,9 +421,10 @@ int neu_persister_delete_subscription(const char *app_name,
}
int neu_persister_store_group(const char * driver_name,
neu_persist_group_info_t *group_info)
neu_persist_group_info_t *group_info,
const char * context)
{
return g_impl->vtbl->store_group(g_impl, driver_name, group_info);
return g_impl->vtbl->store_group(g_impl, driver_name, group_info, context);
}
int neu_persister_update_group(const char *driver_name, const char *group_name,
+2 -1
View File
@@ -224,7 +224,8 @@ struct neu_persister_vtbl_s {
* @return 0 on success, non-zero otherwise
*/
int (*store_group)(neu_persister_t *self, const char *driver_name,
neu_persist_group_info_t *group_info);
neu_persist_group_info_t *group_info,
const char * context);
/**
* Update group config.
+15 -6
View File
@@ -958,12 +958,14 @@ int neu_sqlite_persister_delete_subscription(neu_persister_t *self,
int neu_sqlite_persister_store_group(neu_persister_t * self,
const char * driver_name,
neu_persist_group_info_t *group_info)
neu_persist_group_info_t *group_info,
const char * context)
{
return execute_sql(
((neu_sqlite_persister_t *) self)->db,
"INSERT INTO groups (driver_name, name, interval) VALUES (%Q, %Q, %u)",
driver_name, group_info->name, (unsigned) group_info->interval);
return execute_sql(((neu_sqlite_persister_t *) self)->db,
"INSERT INTO groups (driver_name, name, interval, "
"context) VALUES (%Q, %Q, %u, %Q)",
driver_name, group_info->name,
(unsigned) group_info->interval, context);
}
int neu_sqlite_persister_update_group(neu_persister_t * self,
@@ -1017,6 +1019,12 @@ static int collect_group_info(sqlite3_stmt *stmt, UT_array **group_infos)
info.name = name;
info.interval = sqlite3_column_int(stmt, 1);
char *context = (char *) sqlite3_column_text(stmt, 2);
if (NULL != context) {
info.context = strdup(context);
} else {
info.context = NULL;
}
utarray_push_back(*group_infos, &info);
step = sqlite3_step(stmt);
@@ -1036,7 +1044,8 @@ int neu_sqlite_persister_load_groups(neu_persister_t *self,
neu_sqlite_persister_t *persister = (neu_sqlite_persister_t *) self;
sqlite3_stmt *stmt = NULL;
const char *query = "SELECT name, interval FROM groups WHERE driver_name=?";
const char * query =
"SELECT name, interval, context FROM groups WHERE driver_name=?";
utarray_new(*group_infos, &group_info_icd);
+2 -1
View File
@@ -90,7 +90,8 @@ int neu_sqlite_persister_delete_subscription(neu_persister_t *self,
const char * group_name);
int neu_sqlite_persister_store_group(neu_persister_t * self,
const char * driver_name,
neu_persist_group_info_t *group_info);
neu_persist_group_info_t *group_info,
const char * context);
int neu_sqlite_persister_update_group(neu_persister_t * self,
const char * driver_name,
const char * group_name,
+863
View File
@@ -0,0 +1,863 @@
/**
* NEURON IIoT System for Industry 4.0
* Copyright (C) 2020-2022 EMQ Technologies Co., Ltd All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
**/
#include <jansson.h>
#include <libxml/parser.h>
#include <libxml/tree.h>
#include "define.h"
#include "utils/cid.h"
#include "utils/log.h"
#include "json/json.h"
static int parse_ied(xmlNode *xml_ied, cid_ied_t *ied,
cid_template_t *template);
static int parse_template(xmlNode *xml_template, cid_template_t *template);
static int parse_ldevice(xmlNode *xml_server, cid_ied_t *ied,
cid_template_t *template);
static int parse_lnode(xmlNode *xml_ldevice, cid_ldevice_t *ldev,
cid_template_t *template);
static int parse_dataset(xmlNode *xml_dataset, cid_ln_t *ln);
static int parse_report(xmlNode *xml_report, cid_ln_t *ln);
static int parse_doi(xmlNode *xml_doi, cid_ln_t *ln, cid_template_t *template,
int index);
int neu_cid_parse(const char *path, cid_t *cid)
{
memset(cid, 0, sizeof(cid_t));
xmlDoc *doc = xmlReadFile(path, NULL, 0);
if (doc == NULL) {
nlog_warn("Failed to read icd file %s", path);
return -1;
}
xmlNode *root = xmlDocGetRootElement(doc);
if (root == NULL || strcmp((const char *) root->name, "SCL") != 0) {
nlog_warn("Failed to get root element(SCL)");
xmlFreeDoc(doc);
return -1;
}
xmlNode *find = root->children;
bool ied_parsed = false;
bool templates_parsed = false;
while (find != NULL) {
if (find->type == XML_ELEMENT_NODE &&
strcmp((const char *) find->name, "DataTypeTemplates") == 0) {
int ret = parse_template(find, &cid->template);
if (ret == 0) {
templates_parsed = true;
}
}
find = find->next;
}
xmlNode *find_ied = root->children;
while (find_ied != NULL) {
if (find_ied->type == XML_ELEMENT_NODE &&
strcmp((const char *) find_ied->name, "IED") == 0) {
int ret = parse_ied(find_ied, &cid->ied, &cid->template);
if (ret == 0) {
ied_parsed = true;
}
}
find_ied = find_ied->next;
}
if (ied_parsed && templates_parsed) {
xmlFreeDoc(doc);
return 0;
} else {
neu_cid_free(cid);
nlog_warn("Failed to parse IED or DataTypeTemplates, %d, %d",
ied_parsed, templates_parsed);
xmlFreeDoc(doc);
return -1;
}
}
void neu_cid_free(cid_t *cid)
{
for (int i = 0; i < cid->template.n_lnos; i++) {
if (cid->template.lnos[i].n_dos > 0) {
free(cid->template.lnos[i].dos);
}
}
if (cid->template.n_lnos > 0) {
free(cid->template.lnos);
}
for (int i = 0; i < cid->template.n_dos; i++) {
if (cid->template.dos[i].n_das > 0) {
free(cid->template.dos[i].das);
}
}
if (cid->template.n_dos > 0) {
free(cid->template.dos);
}
for (int i = 0; i < cid->ied.n_ldevices; i++) {
for (int j = 0; j < cid->ied.ldevices[i].n_lns; j++) {
if (cid->ied.ldevices[i].lns[j].n_reports > 0) {
free(cid->ied.ldevices[i].lns[j].reports);
}
if (cid->ied.ldevices[i].lns[j].n_ctrls > 0) {
free(cid->ied.ldevices[i].lns[j].ctrls);
}
for (int k = 0; k < cid->ied.ldevices[i].lns[j].n_datasets; k++) {
if (cid->ied.ldevices[i].lns[j].datasets[k].n_dos > 0) {
free(cid->ied.ldevices[i].lns[j].datasets[k].dos);
}
}
if (cid->ied.ldevices[i].lns[j].n_datasets > 0) {
free(cid->ied.ldevices[i].lns[j].datasets);
}
}
if (cid->ied.ldevices[i].n_lns > 0) {
free(cid->ied.ldevices[i].lns);
}
}
if (cid->ied.n_ldevices > 0) {
free(cid->ied.ldevices);
}
return;
}
void neu_cid_to_msg(char *driver, cid_t *cid, neu_req_add_gtag_t *cmd)
{
strcpy(cmd->driver, driver);
cmd->n_group = 0;
cmd->groups = NULL;
cmd->n_group += 1;
cmd->groups = realloc(cmd->groups, cmd->n_group * sizeof(neu_gdatatag_t));
neu_gdatatag_t *ctl_group = &cmd->groups[cmd->n_group - 1];
memset(ctl_group, 0, sizeof(neu_gdatatag_t));
strcpy(ctl_group->group, "Control");
ctl_group->interval = 5000;
cid_dataset_info_t *ctl_info = calloc(1, sizeof(cid_dataset_info_t));
ctl_info->control = true;
strcpy(ctl_info->ied_name, cid->ied.name);
ctl_group->context = ctl_info;
for (int i = 0; i < cid->ied.n_ldevices; i++) {
for (int j = 0; j < cid->ied.ldevices[i].n_lns; j++) {
for (int k = 0; k < cid->ied.ldevices[i].lns[j].n_ctrls; k++) {
ctl_group->n_tag += 1;
ctl_group->tags = realloc(
ctl_group->tags, ctl_group->n_tag * sizeof(neu_datatag_t));
neu_datatag_t *tag = &ctl_group->tags[ctl_group->n_tag - 1];
memset(tag, 0, sizeof(neu_datatag_t));
tag->name = calloc(1, NEU_TAG_NAME_LEN);
snprintf(tag->name, NEU_TAG_NAME_LEN - 1, "%s/%s$%s",
cid->ied.ldevices[i].inst,
cid->ied.ldevices[i].lns[j].ctrls[k].do_name,
cid->ied.ldevices[i].lns[j].ctrls[k].sdi_name);
tag->attribute = NEU_ATTRIBUTE_WRITE;
tag->type = NEU_TYPE_BOOL;
tag->address = calloc(1, NEU_TAG_ADDRESS_LEN);
tag->description = strdup("");
snprintf(tag->address, NEU_TAG_ADDRESS_LEN - 1,
"%s%s/%s$%s$%s$%s", cid->ied.name,
cid->ied.ldevices[i].inst,
cid->ied.ldevices[i].lns[j].lnclass, "CO",
cid->ied.ldevices[i].lns[j].ctrls[k].do_name,
cid->ied.ldevices[i].lns[j].ctrls[k].sdi_name);
}
}
}
for (int i = 0; i < cid->ied.n_ldevices; i++) {
for (int j = 0; j < cid->ied.ldevices[i].n_lns; j++) {
for (int k = 0; k < cid->ied.ldevices[i].lns[j].n_datasets; k++) {
for (int l = 0; l < cid->ied.ldevices[i].lns[j].n_reports;
l++) {
if (strcmp(
cid->ied.ldevices[i].lns[j].datasets[k].name,
cid->ied.ldevices[i].lns[j].reports[l].dataset) ==
0) {
if (cid->ied.ldevices[i].lns[j].datasets[k].n_dos ==
0) {
break;
}
cmd->n_group += 1;
cmd->groups = realloc(
cmd->groups, cmd->n_group * sizeof(neu_gdatatag_t));
neu_gdatatag_t *group = &cmd->groups[cmd->n_group - 1];
memset(group, 0, sizeof(neu_gdatatag_t));
cid_dataset_info_t *info =
calloc(1, sizeof(cid_dataset_info_t));
info->control = false;
info->buffered =
cid->ied.ldevices[i].lns[j].reports[l].buffered;
strcpy(info->ied_name, cid->ied.name);
strcpy(info->ldevice_inst, cid->ied.ldevices[i].inst);
strcpy(info->ln_class,
cid->ied.ldevices[i].lns[j].lnclass);
strcpy(info->report_name,
cid->ied.ldevices[i].lns[j].reports[l].name);
strcpy(info->report_id,
cid->ied.ldevices[i].lns[j].reports[l].id);
strcpy(info->dataset_name,
cid->ied.ldevices[i].lns[j].datasets[k].name);
group->context = info;
snprintf(group->group, NEU_GROUP_NAME_LEN - 1,
"%s_%s_%s", cid->ied.ldevices[i].inst,
cid->ied.ldevices[i].lns[j].lnclass,
cid->ied.ldevices[i].lns[j].datasets[k].name);
group->interval =
cid->ied.ldevices[i].lns[j].reports[l].intg_pd;
group->n_tag =
cid->ied.ldevices[i].lns[j].datasets[k].n_dos;
group->tags =
calloc(group->n_tag, sizeof(neu_datatag_t));
for (int m = 0;
m < cid->ied.ldevices[i].lns[j].datasets[k].n_dos;
m++) {
group->tags[m].name = strdup(cid->ied.ldevices[i]
.lns[j]
.datasets[k]
.dos[m]
.name);
group->tags[m].attribute =
NEU_ATTRIBUTE_READ | NEU_ATTRIBUTE_SUBSCRIBE;
group->tags[m].address =
calloc(1, NEU_TAG_ADDRESS_LEN);
group->tags[m].description = strdup("");
switch (cid->ied.ldevices[i]
.lns[j]
.datasets[k]
.dos[m]
.fc) {
case ST:
group->tags[m].type = NEU_TYPE_BOOL;
snprintf(group->tags[m].address,
NEU_TAG_ADDRESS_LEN - 1,
"%s%s/%s$%s$%s", cid->ied.name,
cid->ied.ldevices[i].inst,
cid->ied.ldevices[i]
.lns[j]
.datasets[k]
.dos[m]
.lnclass,
"ST",
cid->ied.ldevices[i]
.lns[j]
.datasets[k]
.dos[m]
.name);
break;
case MX:
group->tags[m].type = NEU_TYPE_FLOAT;
snprintf(group->tags[m].address,
NEU_TAG_ADDRESS_LEN - 1,
"%s%s/%s$%s$%s", cid->ied.name,
cid->ied.ldevices[i].inst,
cid->ied.ldevices[i]
.lns[j]
.datasets[k]
.dos[m]
.lnclass,
"MX",
cid->ied.ldevices[i]
.lns[j]
.datasets[k]
.dos[m]
.name);
break;
default:
group->tags[m].type = NEU_TYPE_INT16;
break;
}
}
break;
}
}
}
}
}
}
static int parse_ied(xmlNode *xml_ied, cid_ied_t *ied, cid_template_t *template)
{
int ret = -1;
char *ied_name = (char *) xmlGetProp(xml_ied, (const xmlChar *) "name");
if (strlen(ied_name) >= NEU_CID_IED_NAME_LEN) {
xmlFree(ied_name);
nlog_warn("IED name is too long");
return -1;
} else {
strcpy(ied->name, ied_name);
xmlFree(ied_name);
}
xmlNode *access_point = xml_ied->children;
while (access_point != NULL) {
if (access_point->type == XML_ELEMENT_NODE &&
strcmp((const char *) access_point->name, "AccessPoint") == 0) {
xmlNode *server = access_point->children;
while (server != NULL) {
if (server->type == XML_ELEMENT_NODE &&
strcmp((const char *) server->name, "Server") == 0) {
ret = parse_ldevice(server, ied, template);
break;
}
server = server->next;
}
break;
}
access_point = access_point->next;
}
return ret;
}
static int parse_ldevice(xmlNode *xml_server, cid_ied_t *ied,
cid_template_t *template)
{
ied->ldevices = NULL;
ied->n_ldevices = 0;
xmlNode *ldevice = xml_server->children;
while (ldevice != NULL) {
if (ldevice->type == XML_ELEMENT_NODE &&
strcmp((const char *) ldevice->name, "LDevice") == 0) {
ied->n_ldevices++;
ied->ldevices =
realloc(ied->ldevices, ied->n_ldevices * sizeof(cid_ldevice_t));
cid_ldevice_t *ldev = &ied->ldevices[ied->n_ldevices - 1];
ldev->lns = NULL;
ldev->n_lns = 0;
memset(ldev->inst, 0, sizeof(ldev->inst));
char *inst = (char *) xmlGetProp(ldevice, (const xmlChar *) "inst");
if (strlen(inst) >= NEU_CID_INST_LEN) {
xmlFree(inst);
nlog_warn("LDevice inst is too long");
return -1;
} else {
strcpy(ldev->inst, inst);
xmlFree(inst);
}
int ret = parse_lnode(ldevice, ldev, template);
if (ret != 0) {
return ret;
}
}
ldevice = ldevice->next;
}
return 0;
}
static int parse_lnode(xmlNode *xml_ldevice, cid_ldevice_t *ldev,
cid_template_t *template)
{
xmlNode *lnode = xml_ldevice->children;
while (lnode != NULL) {
if (lnode->type == XML_ELEMENT_NODE &&
strncmp((const char *) lnode->name, "LN", 2) == 0) {
char *ln_class =
(char *) xmlGetProp(lnode, (const xmlChar *) "lnClass");
char *ln_type =
(char *) xmlGetProp(lnode, (const xmlChar *) "lnType");
if (strlen(ln_class) >= NEU_CID_LNCLASS_LEN ||
strlen(ln_type) >= NEU_CID_LNTYPE_LEN) {
xmlFree(ln_class);
xmlFree(ln_type);
nlog_warn("LN class/type is too long %d", (int) lnode->line);
return -1;
} else {
ldev->n_lns += 1;
ldev->lns = realloc(ldev->lns, ldev->n_lns * sizeof(cid_ln_t));
cid_ln_t *ln = &ldev->lns[ldev->n_lns - 1];
memset(ln->lnclass, 0, sizeof(ln->lnclass));
memset(ln->lntype, 0, sizeof(ln->lntype));
ln->datasets = NULL;
ln->n_datasets = 0;
ln->reports = NULL;
ln->n_reports = 0;
ln->ctrls = NULL;
ln->n_ctrls = 0;
strcpy(ln->lnclass, ln_class);
strcpy(ln->lntype, ln_type);
xmlFree(ln_class);
xmlFree(ln_type);
xmlNode *child = lnode->children;
while (child != NULL) {
if (child->type == XML_ELEMENT_NODE &&
strcmp((const char *) child->name, "DataSet") == 0) {
int ret = parse_dataset(child, ln);
if (ret != 0) {
return ret;
}
}
if (child->type == XML_ELEMENT_NODE &&
strcmp((const char *) child->name, "ReportControl") ==
0) {
int ret = parse_report(child, ln);
if (ret != 0) {
return ret;
}
}
if (child->type == XML_ELEMENT_NODE &&
strcmp((const char *) child->name, "DOI") == 0) {
for (int i = 0; i < template->n_lnos; i++) {
if (strcmp(template->lnos[i].id, ln->lntype) == 0 &&
template->lnos[i].n_dos > 0) {
int ret = parse_doi(child, ln, template, i);
if (ret != 0) {
return ret;
}
break;
}
}
}
child = child->next;
}
}
}
lnode = lnode->next;
}
return 0;
}
static int parse_dataset(xmlNode *xml_dataset, cid_ln_t *ln)
{
char *dataset_name =
(char *) xmlGetProp(xml_dataset, (const xmlChar *) "name");
if (strlen(dataset_name) >= NEU_CID_DATASET_NAME_LEN) {
xmlFree(dataset_name);
nlog_warn("Dataset name is too long %d", (int) xml_dataset->line);
return -1;
} else {
ln->n_datasets += 1;
ln->datasets =
realloc(ln->datasets, ln->n_datasets * sizeof(cid_dataset_t));
cid_dataset_t *dataset = &ln->datasets[ln->n_datasets - 1];
dataset->n_dos = 0;
dataset->dos = NULL;
memset(dataset->name, 0, sizeof(dataset->name));
strcpy(dataset->name, dataset_name);
xmlFree(dataset_name);
xmlNode *fcda = xml_dataset->children;
while (fcda != NULL) {
if (fcda->type == XML_ELEMENT_NODE &&
strcmp((const char *) fcda->name, "FCDA") == 0) {
dataset->n_dos += 1;
dataset->dos =
realloc(dataset->dos, dataset->n_dos * sizeof(cid_do_t));
cid_do_t *doi = &dataset->dos[dataset->n_dos - 1];
memset(doi->name, 0, sizeof(doi->name));
memset(doi->lnclass, 0, sizeof(doi->lnclass));
char *do_name =
(char *) xmlGetProp(fcda, (const xmlChar *) "doName");
char *lnclass =
(char *) xmlGetProp(fcda, (const xmlChar *) "lnClass");
if (strlen(do_name) >= NEU_CID_DO_NAME_LEN ||
strlen(lnclass) >= NEU_CID_LNCLASS_LEN) {
xmlFree(do_name);
xmlFree(lnclass);
nlog_warn("DO name or lnclass is too long %d",
(int) fcda->line);
return -1;
} else {
strcpy(doi->name, do_name);
strcpy(doi->lnclass, lnclass);
xmlFree(do_name);
xmlFree(lnclass);
}
char *fc = (char *) xmlGetProp(fcda, (const xmlChar *) "fc");
if (fc != NULL && strcmp(fc, "ST") == 0) {
doi->fc = ST;
} else if (fc != NULL && strcmp(fc, "MX") == 0) {
doi->fc = MX;
} else {
doi->fc = UNKNOWN;
nlog_warn("FCDA unknown fc %s, %d", fc, (int) fcda->line);
}
xmlFree(fc);
}
fcda = fcda->next;
}
}
return 0;
}
static int parse_report(xmlNode *xml_report, cid_ln_t *ln)
{
char *report_name =
(char *) xmlGetProp(xml_report, (const xmlChar *) "name");
char *report_id =
(char *) xmlGetProp(xml_report, (const xmlChar *) "rptID");
char *dataset = (char *) xmlGetProp(xml_report, (const xmlChar *) "datSet");
char *buffered =
(char *) xmlGetProp(xml_report, (const xmlChar *) "buffered");
char *intg_pd = (char *) xmlGetProp(xml_report, (const xmlChar *) "intgPd");
if (strlen(report_name) >= NEU_CID_REPORT_NAME_LEN ||
strlen(report_id) >= NEU_CID_REPORT_ID_LEN ||
strlen(dataset) >= NEU_CID_DATASET_NAME_LEN) {
xmlFree(report_name);
xmlFree(report_id);
xmlFree(dataset);
xmlFree(buffered);
xmlFree(intg_pd);
nlog_warn("report name/id/datset too long %d", (int) xml_report->line);
return -1;
} else {
ln->n_reports += 1;
ln->reports =
realloc(ln->reports, ln->n_reports * sizeof(cid_report_t));
cid_report_t *report = &ln->reports[ln->n_reports - 1];
memset(report->name, 0, sizeof(report->name));
memset(report->id, 0, sizeof(report->id));
memset(report->dataset, 0, sizeof(report->dataset));
report->intg_pd = 15000; // default
report->buffered = false;
strcpy(report->name, report_name);
strcpy(report->id, report_id);
strcpy(report->dataset, dataset);
if (buffered != NULL && strcmp(buffered, "true") == 0) {
report->buffered = true;
}
int interval = atoi(intg_pd);
if (interval > 0) {
report->intg_pd = interval;
}
xmlFree(report_name);
xmlFree(report_id);
xmlFree(dataset);
xmlFree(buffered);
xmlFree(intg_pd);
}
return 0;
}
static int parse_doi(xmlNode *xml_doi, cid_ln_t *ln, cid_template_t *template,
int index)
{
char *doi_name = (char *) xmlGetProp(xml_doi, (const xmlChar *) "name");
for (int i = 0; i < template->lnos[index].n_dos; i++) {
if (strcmp(template->lnos[index].dos[i].name, doi_name) == 0) {
for (int k = 0; k < template->n_dos; k++) {
if (strcmp(template->dos[k].id,
template->lnos[index].dos[i].type) == 0) {
for (int j = 0; j < template->dos[k].n_das; j++) {
if (strcmp(template->dos[k].id,
template->lnos[index].dos[i].type) == 0) {
ln->n_ctrls += 1;
ln->ctrls = realloc(
ln->ctrls, ln->n_ctrls * sizeof(cid_ctrl_t));
cid_ctrl_t *ctrl = &ln->ctrls[ln->n_ctrls - 1];
memset(ctrl->do_name, 0, sizeof(ctrl->do_name));
memset(ctrl->sdi_name, 0, sizeof(ctrl->sdi_name));
strcpy(ctrl->do_name, doi_name);
strcpy(ctrl->sdi_name,
template->dos[k].das[j].name);
}
}
break;
}
}
break;
}
}
xmlFree(doi_name);
return 0;
}
static int parse_template(xmlNode *xml_template, cid_template_t *template)
{
template->dos = NULL;
template->lnos = NULL;
template->n_dos = 0;
template->n_lnos = 0;
xmlNode *child = xml_template->children;
while (child != NULL) {
if (child->type == XML_ELEMENT_NODE &&
strcmp((const char *) child->name, "DOType") == 0) {
char *id = (char *) xmlGetProp(child, (const xmlChar *) "id");
char *cdc = (char *) xmlGetProp(child, (const xmlChar *) "cdc");
if (strlen(id) >= NEU_CID_DO_ID_LEN) {
xmlFree(id);
xmlFree(cdc);
nlog_warn("DOType id is too long %d", (int) child->line);
return -1;
} else {
if (strcmp(cdc, "SPC") == 0 || strcmp(cdc, "DPC") == 0) {
template->n_dos += 1;
template->dos = realloc(
template->dos, template->n_dos * sizeof(cid_tm_do_t));
cid_tm_do_t *tm_do = &template->dos[template->n_dos - 1];
memset(tm_do->id, 0, sizeof(tm_do->id));
tm_do->n_das = 0;
tm_do->das = NULL;
strcpy(tm_do->id, id);
if (strcmp(cdc, "SPC") == 0) {
tm_do->cdc = SPC;
} else {
tm_do->cdc = DPC;
}
xmlNode *da = child->children;
while (da != NULL) {
if (da->type != XML_ELEMENT_NODE ||
strcmp((const char *) da->name, "DA") != 0) {
da = da->next;
continue;
}
char *fc =
(char *) xmlGetProp(da, (const xmlChar *) "fc");
if (fc != NULL && strcmp(fc, "CO") == 0) {
char *da_name = (char *) xmlGetProp(
da, (const xmlChar *) "name");
tm_do->n_das += 1;
tm_do->das = realloc(
tm_do->das, tm_do->n_das * sizeof(cid_tm_da_t));
cid_tm_da_t *tm_da = &tm_do->das[tm_do->n_das - 1];
memset(tm_da->name, 0, sizeof(tm_da->name));
tm_da->fc = CO;
strcpy(tm_da->name, da_name);
xmlFree(da_name);
}
xmlFree(fc);
da = da->next;
}
}
xmlFree(id);
xmlFree(cdc);
}
}
child = child->next;
}
xmlNode *child_node = xml_template->children;
while (child_node != NULL) {
if (child_node->type == XML_ELEMENT_NODE &&
strcmp((const char *) child_node->name, "LNodeType") == 0) {
char *id = (char *) xmlGetProp(child_node, (const xmlChar *) "id");
template->n_lnos += 1;
template->lnos = realloc(template->lnos,
template->n_lnos * sizeof(cid_tm_lno_t));
cid_tm_lno_t *tm_lno = &template->lnos[template->n_lnos - 1];
memset(tm_lno->id, 0, sizeof(tm_lno->id));
tm_lno->n_dos = 0;
tm_lno->dos = NULL;
strncpy(tm_lno->id, id, NEU_CID_DO_ID_LEN);
xmlFree(id);
xmlNode *dot = child_node->children;
while (dot != NULL) {
if (dot->type == XML_ELEMENT_NODE &&
strcmp((const char *) dot->name, "DO") == 0) {
char *do_type =
(char *) xmlGetProp(dot, (const xmlChar *) "type");
for (int i = 0; i < template->n_dos; i++) {
if (strcmp(template->dos[i].id, do_type) == 0) {
char *do_name = (char *) xmlGetProp(
dot, (const xmlChar *) "name");
tm_lno->n_dos += 1;
tm_lno->dos = realloc(tm_lno->dos,
tm_lno->n_dos *
sizeof(cid_tm_lno_do_t));
cid_tm_lno_do_t *tm_lno_do =
&tm_lno->dos[tm_lno->n_dos - 1];
memset(tm_lno_do->name, 0, sizeof(tm_lno_do->name));
memset(tm_lno_do->type, 0, sizeof(tm_lno_do->type));
strcpy(tm_lno_do->name, do_name);
strcpy(tm_lno_do->type, do_type);
xmlFree(do_name);
break;
}
}
xmlFree(do_type);
}
dot = dot->next;
}
}
child_node = child_node->next;
}
return 0;
}
char *neu_cid_info_to_string(cid_dataset_info_t *info)
{
neu_json_elem_t elems[] = {
{
.name = "control",
.t = NEU_JSON_BOOL,
.v.val_bool = info->control,
},
{
.name = "buffered",
.t = NEU_JSON_BOOL,
.v.val_bool = info->buffered,
},
{
.name = "ied_name",
.t = NEU_JSON_STR,
.v.val_str = info->ied_name,
},
{
.name = "ldevice_inst",
.t = NEU_JSON_STR,
.v.val_str = info->ldevice_inst,
},
{
.name = "ln_class",
.t = NEU_JSON_STR,
.v.val_str = info->ln_class,
},
{
.name = "report_name",
.t = NEU_JSON_STR,
.v.val_str = info->report_name,
},
{
.name = "report_id",
.t = NEU_JSON_STR,
.v.val_str = info->report_id,
},
{
.name = "dataset_name",
.t = NEU_JSON_STR,
.v.val_str = info->dataset_name,
},
};
char *result = NULL;
void *json = neu_json_encode_new();
neu_json_encode_field(json, elems, NEU_JSON_ELEM_SIZE(elems));
neu_json_encode(json, &result);
neu_json_encode_free(json);
return result;
}
cid_dataset_info_t *neu_cid_info_from_string(const char *str)
{
neu_json_elem_t elems[] = {
{
.name = "control",
.t = NEU_JSON_BOOL,
},
{
.name = "buffered",
.t = NEU_JSON_BOOL,
},
{
.name = "ied_name",
.t = NEU_JSON_STR,
},
{
.name = "ldevice_inst",
.t = NEU_JSON_STR,
},
{
.name = "ln_class",
.t = NEU_JSON_STR,
},
{
.name = "report_name",
.t = NEU_JSON_STR,
},
{
.name = "report_id",
.t = NEU_JSON_STR,
},
{
.name = "dataset_name",
.t = NEU_JSON_STR,
},
};
void *json = neu_json_decode_new(str);
int ret = neu_json_decode_by_json(json, NEU_JSON_ELEM_SIZE(elems), elems);
if (ret != 0) {
neu_json_decode_free(json);
return NULL;
} else {
cid_dataset_info_t *info = calloc(1, sizeof(cid_dataset_info_t));
info->control = elems[0].v.val_bool;
info->buffered = elems[1].v.val_bool;
strcpy(info->ied_name, elems[2].v.val_str);
strcpy(info->ldevice_inst, elems[3].v.val_str);
strcpy(info->ln_class, elems[4].v.val_str);
strcpy(info->report_name, elems[5].v.val_str);
strcpy(info->report_id, elems[6].v.val_str);
strcpy(info->dataset_name, elems[7].v.val_str);
free(elems[2].v.val_str);
free(elems[3].v.val_str);
free(elems[4].v.val_str);
free(elems[5].v.val_str);
free(elems[6].v.val_str);
free(elems[7].v.val_str);
neu_json_decode_free(json);
return info;
}
}
+1
View File
@@ -286,6 +286,7 @@ int neu_http_response(nng_aio *aio, neu_err_code_e code, char *content)
break;
case NEU_ERR_BODY_IS_WRONG:
case NEU_ERR_PARAM_IS_WRONG:
case NEU_ERR_INVALID_CID:
case NEU_ERR_IP_ADDRESS_INVALID:
case NEU_ERR_IP_ADDRESS_IN_USE:
case NEU_ERR_NODE_SETTING_INVALID: