mirror of
https://github.com/emqx/neuron.git
synced 2026-10-18 05:36:19 +08:00
cid: import and parse
This commit is contained in:
+7
-2
@@ -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
|
||||
|
||||
@@ -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, { \
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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);
|
||||
})
|
||||
}
|
||||
@@ -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
|
||||
@@ -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,
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
@@ -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) {
|
||||
|
||||
@@ -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
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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,
|
||||
|
||||
@@ -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
@@ -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);
|
||||
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user