1
0
Fork 0
mirror of https://git.rwth-aachen.de/acs/public/villas/node/ synced 2025-03-09 00:00:00 +01:00

refactoring: json.c => config_helper.c & sample_io_json.c

This commit is contained in:
Steffen Vogel 2017-07-13 22:13:40 +02:00
parent 6369373149
commit 51d80b73ce
19 changed files with 329 additions and 156 deletions

View file

@ -0,0 +1,37 @@
/** Helpers for configuration parsers.
*
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @copyright 2017, Institute for Automation of Complex Power Systems, EONERC
* @license GNU General Public License (version 3)
*
* VILLASnode
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************/
#pragma once
#include <jansson.h>
#include <libconfig.h>
#include "sample.h"
/* Convert a libconfig object to a jansson object */
json_t * config_to_json(config_setting_t *cfg);
/* Convert a jansson object into a libconfig object. */
int json_to_config(json_t *json, config_setting_t *parent);
/* Create a libconfig object from command line parameters. */
int config_parse_cli(config_t *cfg, int argc, char *argv[]);

View file

@ -34,42 +34,13 @@
#pragma once
#include <time.h>
#include <string.h>
#include <stdbool.h>
#include "log_config.h"
#include "queue.h"
#include "list.h"
#include "super_node.h"
#include "hook_type.h"
#include "common.h"
/* Forward declarations */
struct path;
struct hook;
struct sample;
struct super_node;
struct hook_type {
int priority; /**< Default priority of this hook type. */
bool builtin; /**< Should we add this hook by default to every path?. */
size_t size; /**< Size of allocation for struct hook::_vd */
int (*parse)(struct hook *h, config_setting_t *cfg);
int (*init)(struct hook *h); /**< Called before path is started to parseHOOK_DESTROYs. */
int (*destroy)(struct hook *h); /**< Called after path has been stopped to release memory allocated by HOOK_INIT */
int (*start)(struct hook *h); /**< Called whenever a path is started; before threads are created. */
int (*stop)(struct hook *h); /**< Called whenever a path is stopped; after threads are destoyed. */
int (*periodic)(struct hook *h);/**< Called periodically. Period is set by global 'stats' option in the configuration file. */
int (*restart)(struct hook *h); /**< Called whenever a new simulation case is started. This is detected by a sequence no equal to zero. */
int (*read)(struct hook *h, struct sample *smps[], size_t *cnt); /**< Called for every single received samples. */
int (*write)(struct hook *h, struct sample *smps[], size_t *cnt); /**< Called for every single sample which will be sent. */
};
struct list;
/** Descriptor for user defined hooks. See hooks[]. */
struct hook {
@ -96,6 +67,8 @@ int hook_init(struct hook *h, struct hook_type *vt, struct path *p);
*/
int hook_parse(struct hook *h, config_setting_t *cfg);
int hook_parse_cli(struct hook *h, int argc, char *argv[]);
int hook_destroy(struct hook *h);
int hook_start(struct hook *h);

View file

@ -0,0 +1,66 @@
/** Hook funktions
*
* Every path can register a hook function which is called for every received
* message. This can be used to debug the data flow, get statistics
* or alter the message.
*
* This file includes some examples.
*
* @file
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @copyright 2017, Institute for Automation of Complex Power Systems, EONERC
* @license GNU General Public License (version 3)
*
* VILLASnode
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @addtogroup hooks User-defined hook functions
* @ingroup path
* @{
*********************************************************************************/
#pragma once
#include <stdlib.h>
#include <stdbool.h>
#include <libconfig.h>
/* Forward declarations */
struct hook;
struct sample;
struct hook_type {
int priority; /**< Default priority of this hook type. */
bool builtin; /**< Should we add this hook by default to every path?. */
size_t size; /**< Size of allocation for struct hook::_vd */
int (*parse)(struct hook *h, config_setting_t *cfg);
int (*parse_cli)(struct hook *h, int argc, char *argv[]);
int (*init)(struct hook *h); /**< Called before path is started to parseHOOK_DESTROYs. */
int (*destroy)(struct hook *h); /**< Called after path has been stopped to release memory allocated by HOOK_INIT */
int (*start)(struct hook *h); /**< Called whenever a path is started; before threads are created. */
int (*stop)(struct hook *h); /**< Called whenever a path is stopped; after threads are destoyed. */
int (*periodic)(struct hook *h);/**< Called periodically. Period is set by global 'stats' option in the configuration file. */
int (*restart)(struct hook *h); /**< Called whenever a new simulation case is started. This is detected by a sequence no equal to zero. */
int (*read)(struct hook *h, struct sample *smps[], size_t *cnt); /**< Called for every single received samples. */
int (*write)(struct hook *h, struct sample *smps[], size_t *cnt); /**< Called for every single sample which will be sent. */
};

View file

@ -1,4 +1,4 @@
/** JSON serializtion of various objects.
/** JSON serializtion sample data.
*
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @copyright 2017, Institute for Automation of Complex Power Systems, EONERC
@ -23,15 +23,9 @@
#pragma once
#include <jansson.h>
#include <libconfig.h>
#include "sample.h"
/* Convert a libconfig object to a libjansson object */
json_t * config_to_json(config_setting_t *cfg);
int json_to_config(json_t *json, config_setting_t *parent);
int sample_io_json_pack(json_t **j, struct sample *s, int flags);
int sample_io_json_unpack(json_t *j, struct sample *s, int *flags);

View file

@ -10,12 +10,12 @@
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# 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 General Public License for more details.
#
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
###################################################################################
@ -31,7 +31,8 @@ LIB_SRCS += $(addprefix lib/nodes/, file.c cbuilder.c shmem.c signal.c) \
log.c log_config.c utils.c super_node.c hist.c timing.c pool.c \
list.c queue.c queue_signalled.c memory.c advio.c web.c api.c \
plugin.c node_type.c stats.c mapping.c sample_io.c shmem.c \
json.c crypt.c compat.c log_table.c log_helper.c \
config_helper.c sample_io_json.c crypt.c compat.c log_table.c \
log_helper.c \
)
LIB_LDFLAGS = -shared

View file

@ -25,7 +25,8 @@
#include "api.h"
#include "utils.h"
#include "plugin.h"
#include "json.h"
#include "config_helper.h"
#include "super_node.h"
static int api_config(struct api_action *h, json_t *args, json_t **resp, struct api_session *s)
{
@ -43,4 +44,4 @@ static struct plugin p = {
.api.cb = api_config
};
REGISTER_PLUGIN(&p)
REGISTER_PLUGIN(&p)

View file

@ -24,8 +24,9 @@
#include "plugin.h"
#include "node.h"
#include "super_node.h"
#include "utils.h"
#include "json.h"
#include "config_helper.h"
#include "api.h"

View file

@ -25,8 +25,9 @@
#include "plugin.h"
#include "path.h"
#include "utils.h"
#include "json.h"
#include "config_helper.h"
#include "stats.h"
#include "super_node.h"
#include "api.h"
@ -40,7 +41,7 @@ static int api_paths(struct api_action *r, json_t *args, json_t **resp, struct a
json_t *json_path = json_pack("{ s: i }",
"state", p->state
);
if (p->stats)
json_object_set(json_path, "stats", stats_json(p->stats));

View file

@ -1,4 +1,4 @@
/** JSON serializtion of various objects.
/** Helpers for configuration parsers.
*
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @copyright 2017, Institute for Automation of Complex Power Systems, EONERC
@ -20,7 +20,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************/
#include "json.h"
#include "config_helper.h"
#include "utils.h"
static int json_to_config_type(int type)
{
@ -138,102 +139,22 @@ int json_to_config(json_t *json, config_setting_t *parent)
return 0;
}
int sample_io_json_pack(json_t **j, struct sample *s, int flags)
{
json_error_t err;
json_t *json_data = json_array();
for (int i = 0; i < s->length; i++) {
json_t *json_value = sample_get_data_format(s, i)
? json_integer(s->data[i].i)
: json_real(s->data[i].f);
json_array_append(json_data, json_value);
}
*j = json_pack_ex(&err, 0, "{ s: { s: [ I, I ], s: [ I, I ], s: [ I, I ] }, s: I, s: o }",
"ts",
"origin", s->ts.origin.tv_sec, s->ts.origin.tv_nsec,
"received", s->ts.received.tv_sec, s->ts.received.tv_nsec,
"sent", s->ts.sent.tv_sec, s->ts.sent.tv_nsec,
"sequence", s->sequence,
"data", json_data);
if (!*j)
return -1;
return 0;
}
int sample_io_json_unpack(json_t *j, struct sample *s, int *flags)
{
int ret, i;
json_t *json_data, *json_value;
ret = json_unpack(j, "{ s: { s: [ I, I ], s: [ I, I ], s: [ I, I ] }, s: I, s: o }",
"ts",
"origin", &s->ts.origin.tv_sec, &s->ts.origin.tv_nsec,
"received", &s->ts.received.tv_sec, &s->ts.received.tv_nsec,
"sent", &s->ts.sent.tv_sec, &s->ts.sent.tv_nsec,
"sequence", &s->sequence,
"data", &json_data);
if (ret)
return ret;
s->length = 0;
json_array_foreach(json_data, i, json_value) {
switch (json_typeof(json_value)) {
case JSON_REAL:
s->data[i].f = json_real_value(json_value);
sample_set_data_format(s, i, SAMPLE_DATA_FORMAT_FLOAT);
break;
case JSON_INTEGER:
s->data[i].f = json_integer_value(json_value);
sample_set_data_format(s, i, SAMPLE_DATA_FORMAT_INT);
break;
default:
return -1;
}
s->length++;
}
return 0;
}
int sample_io_json_fprint(FILE *f, struct sample *s, int flags)
int config_parse_cli(config_t *cfg, int argc, char *argv[])
{
int ret;
json_t *json;
char *str = NULL;
ret = sample_io_json_pack(&json, s, flags);
if (ret)
return ret;
for (int i = 0; i < argc; i++)
str = strcatf(&str, "%s", argv[i]);
ret = json_dumpf(json, f, 0);
if (!str)
return 0;
json_decref(json);
config_set_auto_convert(cfg, 1);
return ret;
}
int sample_io_json_fscan(FILE *f, struct sample *s, int *flags)
{
int ret;
json_t *json;
json_error_t err;
json = json_loadf(f, JSON_DISABLE_EOF_CHECK, &err);
if (!json)
return -1;
ret = sample_io_json_unpack(json, s, flags);
json_decref(json);
return ret;
ret = config_read_string(cfg, str);
free(str);
return ret != CONFIG_TRUE;
}

View file

@ -31,6 +31,7 @@
#include "utils.h"
#include "node.h"
#include "plugin.h"
#include "config_helper.h"
int hook_init(struct hook *h, struct hook_type *vt, struct path *p)
{
@ -70,6 +71,38 @@ int hook_parse(struct hook *h, config_setting_t *cfg)
return 0;
}
int hook_parse_cli(struct hook *h, int argc, char *argv[])
{
int ret;
if (h->_vt->parse_cli) {
ret = h->_vt->parse_cli(h, argc, argv);
if (ret)
return ret;
h->state = STATE_PARSED;
}
else {
config_t cfg;
config_setting_t *cfg_root;
config_init(&cfg);
ret = config_parse_cli(&cfg, argc, argv);
if (ret)
goto out;
cfg_root = config_root_setting(&cfg);
ret = hook_parse(h, cfg_root);
out:
config_destroy(&cfg);
}
return ret;
}
int hook_destroy(struct hook *h)
{
int ret;
@ -112,14 +145,14 @@ int hook_periodic(struct hook *h)
int hook_restart(struct hook *h)
{
debug(LOG_HOOK | 10, "Running hook %s: type=restart, priority=%d", plugin_name(h->_vt), h->priority);
return h->_vt->restart ? h->_vt->restart(h) : 0;
}
int hook_read(struct hook *h, struct sample *smps[], size_t *cnt)
{
debug(LOG_HOOK | 10, "Running hook %s: type=read, priority=%d, cnt=%zu", plugin_name(h->_vt), h->priority, *cnt);
return h->_vt->read ? h->_vt->read(h, smps, cnt) : 0;
}
@ -196,7 +229,7 @@ int hook_parse_list(struct list *list, config_setting_t *cfg, struct path *o)
continue; /* We ignore all non hook settings in this libconfig object setting */
struct hook *h = alloc(sizeof(struct hook));
ret = hook_init(h, &p->hook, o);
if (ret)
cerror(cfg_hook, "Failed to initialize hook");

View file

@ -28,6 +28,7 @@
#include "plugin.h"
#include "stats.h"
#include "path.h"
#include "super_node.h"
struct stats_send {
struct node *dest;
@ -60,7 +61,7 @@ static int stats_send_parse(struct hook *h, config_setting_t *cfg)
if (config_setting_lookup_string(cfg, "destination", &dest)) {
assert(h->path);
p->dest = list_lookup(&h->path->super_node->nodes, dest);
if (!p->dest)
cerror(cfg, "Invalid destination node '%s' for hook '%s'", dest, plugin_name(h->_vt));
@ -145,4 +146,4 @@ static struct plugin p = {
REGISTER_PLUGIN(&p)
/** @} */
/** @} */

View file

@ -28,6 +28,7 @@
#include "utils.h"
#include "config.h"
#include "plugin.h"
#include "config_helper.h"
int node_init(struct node *n, struct node_type *vt)
{
@ -87,11 +88,30 @@ int node_parse_cli(struct node *n, int argc, char *argv[])
n->vectorize = 1;
n->name = "cli";
ret = n->_vt->parse_cli ? n->_vt->parse_cli(n, argc, argv) : 0;
if (ret)
error("Failed to parse node '%s'", node_name(n));
if (n->_vt->parse_cli) {
ret = n->_vt->parse_cli(n, argc, argv);
if (ret)
return ret;
n->state = STATE_PARSED;
n->state = STATE_PARSED;
}
else {
config_t cfg;
config_setting_t *cfg_root;
config_init(&cfg);
ret = config_parse_cli(&cfg, argc, argv);
if (ret)
goto out;
cfg_root = config_root_setting(&cfg);
ret = node_parse(n, cfg_root);
out:
config_destroy(&cfg);
}
return ret;
}

View file

@ -16,6 +16,7 @@
#include "utils.h"
#include "timing.h"
#include "plugin.h"
#include "super_node.h"
#include "fpga/card.h"
@ -291,4 +292,3 @@ static struct plugin p = {
REGISTER_PLUGIN(&p)
LIST_INIT_STATIC(&p.node.instances)

View file

@ -22,9 +22,9 @@
#include <ctype.h>
#include "json.h"
#include "sample.h"
#include "sample_io.h"
#include "sample_io_json.h"
#include "timing.h"
int sample_io_fprint(FILE *f, struct sample *s, enum sample_io_format fmt, int flags)
@ -195,4 +195,3 @@ skip: if (fgets(line, sizeof(line), f) == NULL)
return sample_io_villas_scan(line, s, fl);
}

123
lib/sample_io_json.c Normal file
View file

@ -0,0 +1,123 @@
/** JSON serializtion sample data.
*
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @copyright 2017, Institute for Automation of Complex Power Systems, EONERC
* @license GNU General Public License (version 3)
*
* VILLASnode
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************/
#include "sample_io_json.h"
int sample_io_json_pack(json_t **j, struct sample *s, int flags)
{
json_error_t err;
json_t *json_data = json_array();
for (int i = 0; i < s->length; i++) {
json_t *json_value = sample_get_data_format(s, i)
? json_integer(s->data[i].i)
: json_real(s->data[i].f);
json_array_append(json_data, json_value);
}
*j = json_pack_ex(&err, 0, "{ s: { s: [ I, I ], s: [ I, I ], s: [ I, I ] }, s: I, s: o }",
"ts",
"origin", s->ts.origin.tv_sec, s->ts.origin.tv_nsec,
"received", s->ts.received.tv_sec, s->ts.received.tv_nsec,
"sent", s->ts.sent.tv_sec, s->ts.sent.tv_nsec,
"sequence", s->sequence,
"data", json_data);
if (!*j)
return -1;
return 0;
}
int sample_io_json_unpack(json_t *j, struct sample *s, int *flags)
{
int ret, i;
json_t *json_data, *json_value;
ret = json_unpack(j, "{ s: { s: [ I, I ], s: [ I, I ], s: [ I, I ] }, s: I, s: o }",
"ts",
"origin", &s->ts.origin.tv_sec, &s->ts.origin.tv_nsec,
"received", &s->ts.received.tv_sec, &s->ts.received.tv_nsec,
"sent", &s->ts.sent.tv_sec, &s->ts.sent.tv_nsec,
"sequence", &s->sequence,
"data", &json_data);
if (ret)
return ret;
s->length = 0;
json_array_foreach(json_data, i, json_value) {
switch (json_typeof(json_value)) {
case JSON_REAL:
s->data[i].f = json_real_value(json_value);
sample_set_data_format(s, i, SAMPLE_DATA_FORMAT_FLOAT);
break;
case JSON_INTEGER:
s->data[i].f = json_integer_value(json_value);
sample_set_data_format(s, i, SAMPLE_DATA_FORMAT_INT);
break;
default:
return -1;
}
s->length++;
}
return 0;
}
int sample_io_json_fprint(FILE *f, struct sample *s, int flags)
{
int ret;
json_t *json;
ret = sample_io_json_pack(&json, s, flags);
if (ret)
return ret;
ret = json_dumpf(json, f, 0);
json_decref(json);
return ret;
}
int sample_io_json_fscan(FILE *f, struct sample *s, int *flags)
{
int ret;
json_t *json;
json_error_t err;
json = json_loadf(f, JSON_DISABLE_EOF_CHECK, &err);
if (!json)
return -1;
ret = sample_io_json_unpack(json, s, flags);
json_decref(json);
return ret;
}

View file

@ -20,6 +20,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************************/
#include <string.h>
#include "stats.h"
#include "hist.h"
#include "timing.h"
@ -58,7 +60,7 @@ int stats_destroy(struct stats *s)
hist_destroy(&s->histograms[i]);
free(s->delta);
return 0;
}

View file

@ -38,7 +38,7 @@
#include "plugin.h"
#include "memory.h"
#include "config.h"
#include "json.h"
#include "config_helper.h"
#include "kernel/rt.h"

View file

@ -26,7 +26,7 @@
#include <libconfig.h>
#include "utils.h"
#include "json.h"
#include "config_helper.h"
const char *cfg_example = "test : \n"
"{\n"

View file

@ -23,7 +23,7 @@
#include <jansson.h>
#include <libconfig.h>
#include <villas/json.h>
#include <villas/config_helper.h>
#include <villas/utils.h>
void usage()