2014-07-14 11:49:44 +00:00
|
|
|
/** Nodes.
|
2014-06-05 09:34:29 +00:00
|
|
|
*
|
|
|
|
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
|
2017-03-03 20:20:13 -04:00
|
|
|
* @copyright 2017, Institute for Automation of Complex Power Systems, EONERC
|
2017-04-27 12:56:43 +02:00
|
|
|
* @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.
|
2017-05-05 19:24:16 +00:00
|
|
|
*
|
2017-04-27 12:56:43 +02:00
|
|
|
* 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.
|
2017-05-05 19:24:16 +00:00
|
|
|
*
|
2017-04-27 12:56:43 +02:00
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
2015-06-02 21:53:04 +02:00
|
|
|
*********************************************************************************/
|
2014-06-05 09:34:29 +00:00
|
|
|
|
|
|
|
#include <string.h>
|
2016-11-20 12:59:37 -05:00
|
|
|
|
2016-06-08 22:38:21 +02:00
|
|
|
#include "sample.h"
|
2014-12-05 12:39:52 +01:00
|
|
|
#include "node.h"
|
2014-06-05 09:34:29 +00:00
|
|
|
#include "utils.h"
|
2016-11-20 12:59:37 -05:00
|
|
|
#include "config.h"
|
2017-03-06 08:57:43 -04:00
|
|
|
#include "plugin.h"
|
2017-07-13 22:13:40 +02:00
|
|
|
#include "config_helper.h"
|
2014-06-05 09:34:29 +00:00
|
|
|
|
2017-03-12 17:13:37 -03:00
|
|
|
int node_init(struct node *n, struct node_type *vt)
|
2015-11-23 16:42:43 +01:00
|
|
|
{
|
2017-04-02 12:59:56 +02:00
|
|
|
static int max_id;
|
2015-11-23 16:42:43 +01:00
|
|
|
|
2017-03-12 17:04:43 -03:00
|
|
|
assert(n->state == STATE_DESTROYED);
|
2016-01-14 22:59:57 +01:00
|
|
|
|
2017-03-12 17:13:37 -03:00
|
|
|
n->_vt = vt;
|
|
|
|
n->_vd = alloc(vt->size);
|
2017-05-05 19:24:16 +00:00
|
|
|
|
2017-08-01 11:56:47 +02:00
|
|
|
n->name = NULL;
|
2017-04-02 12:59:56 +02:00
|
|
|
n->id = max_id++;
|
2017-05-05 19:24:16 +00:00
|
|
|
|
2017-03-27 12:54:24 +02:00
|
|
|
/* Default values */
|
|
|
|
n->vectorize = 1;
|
2017-05-05 19:24:16 +00:00
|
|
|
|
2017-03-12 17:13:37 -03:00
|
|
|
list_push(&vt->instances, n);
|
2016-06-08 22:38:21 +02:00
|
|
|
|
2017-03-11 23:50:30 -03:00
|
|
|
n->state = STATE_INITIALIZED;
|
2016-06-08 22:38:21 +02:00
|
|
|
|
2017-03-11 23:50:30 -03:00
|
|
|
return 0;
|
2016-01-14 22:59:57 +01:00
|
|
|
}
|
2015-11-23 16:42:43 +01:00
|
|
|
|
2017-08-03 00:19:27 +02:00
|
|
|
int node_parse(struct node *n, json_t *cfg, const char *name)
|
2015-12-11 17:56:14 +01:00
|
|
|
{
|
2017-03-11 23:50:30 -03:00
|
|
|
struct plugin *p;
|
2016-06-08 22:38:21 +02:00
|
|
|
int ret;
|
2017-03-11 23:50:30 -03:00
|
|
|
|
2017-08-03 00:19:27 +02:00
|
|
|
json_error_t err;
|
2017-05-05 19:24:16 +00:00
|
|
|
|
2017-08-03 00:19:27 +02:00
|
|
|
const char *type;
|
2017-05-05 19:24:16 +00:00
|
|
|
|
2017-08-03 00:19:27 +02:00
|
|
|
n->name = strdup(name);
|
2017-05-05 19:24:16 +00:00
|
|
|
|
2017-08-03 00:19:27 +02:00
|
|
|
ret = json_unpack_ex(cfg, &err, 0, "{ s: s, s?: i }",
|
|
|
|
"type", &type,
|
|
|
|
"vectorize", &n->vectorize
|
|
|
|
);
|
|
|
|
if (ret)
|
|
|
|
jerror(&err, "Failed to parse node '%s'", node_name(n));
|
2016-06-08 22:38:21 +02:00
|
|
|
|
2017-08-03 00:19:27 +02:00
|
|
|
p = plugin_lookup(PLUGIN_TYPE_NODE, type);
|
|
|
|
assert(&p->node == n->_vt);
|
2015-08-07 01:11:43 +02:00
|
|
|
|
2017-03-11 23:50:30 -03:00
|
|
|
ret = n->_vt->parse ? n->_vt->parse(n, cfg) : 0;
|
|
|
|
if (ret)
|
2017-08-03 00:19:27 +02:00
|
|
|
error("Failed to parse node '%s'", node_name(n));
|
2017-05-05 19:24:16 +00:00
|
|
|
|
2017-08-03 00:19:27 +02:00
|
|
|
n->cfg = cfg;
|
2017-03-11 23:50:30 -03:00
|
|
|
n->state = STATE_PARSED;
|
2016-06-08 22:38:21 +02:00
|
|
|
|
|
|
|
return ret;
|
2015-03-31 13:54:04 +02:00
|
|
|
}
|
|
|
|
|
2017-07-13 01:55:06 +02:00
|
|
|
int node_parse_cli(struct node *n, int argc, char *argv[])
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
assert(n->_vt);
|
|
|
|
|
2017-07-13 22:13:40 +02:00
|
|
|
if (n->_vt->parse_cli) {
|
2017-08-03 00:19:27 +02:00
|
|
|
n->name = strdup("cli");
|
|
|
|
|
2017-07-13 22:13:40 +02:00
|
|
|
ret = n->_vt->parse_cli(n, argc, argv);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
2017-07-13 01:55:06 +02:00
|
|
|
|
2017-07-13 22:13:40 +02:00
|
|
|
n->state = STATE_PARSED;
|
|
|
|
}
|
|
|
|
else {
|
2017-08-03 00:19:27 +02:00
|
|
|
n->cfg = json_load_cli(argc, argv);
|
|
|
|
if (!n->cfg)
|
|
|
|
return -1;
|
2017-07-13 22:13:40 +02:00
|
|
|
|
2017-08-03 00:19:27 +02:00
|
|
|
ret = node_parse(n, n->cfg, "cli");
|
2017-07-13 22:13:40 +02:00
|
|
|
}
|
2017-07-13 01:55:06 +02:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-03-11 23:50:30 -03:00
|
|
|
int node_check(struct node *n)
|
2015-12-11 17:56:14 +01:00
|
|
|
{
|
2017-03-12 17:04:43 -03:00
|
|
|
assert(n->state != STATE_DESTROYED);
|
2015-12-13 00:45:20 +01:00
|
|
|
|
2017-03-11 23:50:30 -03:00
|
|
|
if (n->vectorize <= 0)
|
|
|
|
error("Invalid `vectorize` value %d for node %s. Must be natural number!", n->vectorize, node_name(n));
|
2015-10-09 13:04:52 +02:00
|
|
|
|
2017-03-11 23:50:30 -03:00
|
|
|
if (n->_vt->vectorize && n->_vt->vectorize < n->vectorize)
|
|
|
|
error("Invalid value for `vectorize`. Node type requires a number smaller than %d!",
|
|
|
|
n->_vt->vectorize);
|
|
|
|
|
|
|
|
n->state = STATE_CHECKED;
|
|
|
|
|
|
|
|
return 0;
|
2015-03-31 13:54:04 +02:00
|
|
|
}
|
|
|
|
|
2014-12-05 12:39:52 +01:00
|
|
|
int node_start(struct node *n)
|
2015-12-11 17:56:14 +01:00
|
|
|
{
|
2015-11-16 10:51:00 +01:00
|
|
|
int ret;
|
2017-05-05 19:24:16 +00:00
|
|
|
|
2017-03-12 17:04:43 -03:00
|
|
|
assert(n->state == STATE_CHECKED);
|
2014-12-05 12:39:52 +01:00
|
|
|
|
2015-11-29 22:45:46 +01:00
|
|
|
info("Starting node %s", node_name_long(n));
|
2014-12-05 12:39:52 +01:00
|
|
|
{ INDENT
|
2017-04-07 17:44:20 +02:00
|
|
|
ret = n->_vt->start ? n->_vt->start(n) : 0;
|
2017-03-13 23:51:38 -03:00
|
|
|
if (ret)
|
|
|
|
return ret;
|
2014-06-05 09:34:56 +00:00
|
|
|
}
|
2017-03-13 23:51:38 -03:00
|
|
|
|
|
|
|
n->state = STATE_STARTED;
|
2017-05-05 19:24:16 +00:00
|
|
|
|
2016-10-19 01:56:00 -04:00
|
|
|
n->sequence = 0;
|
2017-05-05 19:24:16 +00:00
|
|
|
|
2015-11-16 10:51:00 +01:00
|
|
|
return ret;
|
2014-12-05 12:39:52 +01:00
|
|
|
}
|
2014-06-05 09:34:29 +00:00
|
|
|
|
2014-12-05 12:39:52 +01:00
|
|
|
int node_stop(struct node *n)
|
2015-12-11 17:56:14 +01:00
|
|
|
{
|
2015-11-16 10:51:00 +01:00
|
|
|
int ret;
|
|
|
|
|
2017-03-29 04:25:30 +02:00
|
|
|
if (n->state != STATE_STARTED)
|
|
|
|
return 0;
|
2015-11-29 22:45:46 +01:00
|
|
|
|
|
|
|
info("Stopping node %s", node_name(n));
|
2014-12-05 12:39:52 +01:00
|
|
|
{ INDENT
|
2017-04-07 17:44:20 +02:00
|
|
|
ret = n->_vt->stop ? n->_vt->stop(n) : 0;
|
2014-12-05 12:39:52 +01:00
|
|
|
}
|
2017-05-05 19:24:16 +00:00
|
|
|
|
2015-11-16 10:51:00 +01:00
|
|
|
if (ret == 0)
|
2017-03-11 23:50:30 -03:00
|
|
|
n->state = STATE_STOPPED;
|
2015-11-16 10:51:00 +01:00
|
|
|
|
|
|
|
return ret;
|
2014-06-05 09:34:29 +00:00
|
|
|
}
|
2015-03-18 16:18:10 +01:00
|
|
|
|
2017-03-11 23:50:30 -03:00
|
|
|
int node_destroy(struct node *n)
|
|
|
|
{
|
2017-03-12 17:04:43 -03:00
|
|
|
assert(n->state != STATE_DESTROYED && n->state != STATE_STARTED);
|
2017-03-11 23:50:30 -03:00
|
|
|
|
|
|
|
if (n->_vt->destroy)
|
|
|
|
n->_vt->destroy(n);
|
2017-05-05 19:24:16 +00:00
|
|
|
|
2017-03-11 23:50:30 -03:00
|
|
|
list_remove(&n->_vt->instances, n);
|
|
|
|
|
|
|
|
if (n->_vd)
|
|
|
|
free(n->_vd);
|
2017-05-05 19:24:16 +00:00
|
|
|
|
2017-03-11 23:50:30 -03:00
|
|
|
if (n->_name)
|
|
|
|
free(n->_name);
|
2017-05-05 19:24:16 +00:00
|
|
|
|
2017-04-24 18:59:45 +02:00
|
|
|
if (n->_name_long)
|
|
|
|
free(n->_name_long);
|
2017-05-05 19:24:16 +00:00
|
|
|
|
2017-08-01 11:56:47 +02:00
|
|
|
if (n->name)
|
|
|
|
free(n->name);
|
|
|
|
|
2017-03-11 23:50:30 -03:00
|
|
|
n->state = STATE_DESTROYED;
|
2017-05-05 19:24:16 +00:00
|
|
|
|
2017-03-11 23:50:30 -03:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int node_read(struct node *n, struct sample *smps[], unsigned cnt)
|
|
|
|
{
|
2017-07-02 18:58:58 +02:00
|
|
|
int readd, nread = 0;
|
2017-03-11 23:50:30 -03:00
|
|
|
|
|
|
|
if (!n->_vt->read)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
/* Send in parts if vector not supported */
|
|
|
|
if (n->_vt->vectorize > 0 && n->_vt->vectorize < cnt) {
|
|
|
|
while (cnt - nread > 0) {
|
2017-07-02 18:58:58 +02:00
|
|
|
readd = n->_vt->read(n, &smps[nread], MIN(cnt - nread, n->_vt->vectorize));
|
|
|
|
nread += readd;
|
|
|
|
debug(LOG_NODES | 5, "Received %u samples from node %s", readd, node_name(n));
|
2017-03-11 23:50:30 -03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
nread = n->_vt->read(n, smps, cnt);
|
2017-07-02 18:58:58 +02:00
|
|
|
debug(LOG_NODES | 5, "Received %u samples from node %s", nread, node_name(n));
|
2017-03-11 23:50:30 -03:00
|
|
|
}
|
2017-05-05 19:24:16 +00:00
|
|
|
|
2017-03-11 23:50:30 -03:00
|
|
|
for (int i = 0; i < nread; i++)
|
|
|
|
smps[i]->source = n;
|
2017-05-05 19:24:16 +00:00
|
|
|
|
2017-03-11 23:50:30 -03:00
|
|
|
return nread;
|
|
|
|
}
|
|
|
|
|
|
|
|
int node_write(struct node *n, struct sample *smps[], unsigned cnt)
|
|
|
|
{
|
2017-07-02 18:58:58 +02:00
|
|
|
int sent, nsent = 0;
|
2017-03-11 23:50:30 -03:00
|
|
|
|
|
|
|
if (!n->_vt->write)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
/* Send in parts if vector not supported */
|
|
|
|
if (n->_vt->vectorize > 0 && n->_vt->vectorize < cnt) {
|
2017-07-02 18:58:58 +02:00
|
|
|
while (cnt - nsent > 0) {
|
|
|
|
sent = n->_vt->write(n, &smps[nsent], MIN(cnt - nsent, n->_vt->vectorize));
|
|
|
|
nsent += sent;
|
|
|
|
debug(LOG_NODES | 5, "Sent %u samples to node %s", sent, node_name(n));
|
|
|
|
}
|
2017-03-11 23:50:30 -03:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
nsent = n->_vt->write(n, smps, cnt);
|
2017-07-02 18:58:58 +02:00
|
|
|
debug(LOG_NODES | 5, "Sent %u samples to node %s", nsent, node_name(n));
|
2017-03-11 23:50:30 -03:00
|
|
|
}
|
2017-05-05 19:24:16 +00:00
|
|
|
|
2017-03-11 23:50:30 -03:00
|
|
|
return nsent;
|
|
|
|
}
|
|
|
|
|
2015-12-12 12:40:55 +01:00
|
|
|
char * node_name(struct node *n)
|
2015-10-17 19:05:15 +02:00
|
|
|
{
|
2015-11-29 22:45:46 +01:00
|
|
|
if (!n->_name)
|
2017-07-12 00:50:29 +02:00
|
|
|
strcatf(&n->_name, CLR_RED("%s") "(" CLR_YEL("%s") ")", n->name, plugin_name(n->_vt));
|
2017-05-05 19:24:16 +00:00
|
|
|
|
2015-11-29 22:45:46 +01:00
|
|
|
return n->_name;
|
|
|
|
}
|
2015-10-17 19:05:15 +02:00
|
|
|
|
2015-12-12 12:40:55 +01:00
|
|
|
char * node_name_long(struct node *n)
|
2015-11-29 22:45:46 +01:00
|
|
|
{
|
2015-12-11 18:19:35 +01:00
|
|
|
if (!n->_name_long) {
|
|
|
|
if (n->_vt->print) {
|
2017-04-06 12:12:56 +02:00
|
|
|
struct node_type *vt = n->_vt;
|
|
|
|
char *name_long = vt->print(n);
|
2017-04-15 22:45:09 +02:00
|
|
|
strcatf(&n->_name_long, "%s: vectorize=%d, %s", node_name(n), n->vectorize, name_long);
|
2015-12-11 18:19:35 +01:00
|
|
|
free(name_long);
|
|
|
|
}
|
|
|
|
else
|
2017-05-05 19:24:16 +00:00
|
|
|
n->_name_long = node_name(n);
|
2015-12-11 18:19:35 +01:00
|
|
|
}
|
2017-05-05 19:24:16 +00:00
|
|
|
|
2015-11-29 22:45:46 +01:00
|
|
|
return n->_name_long;
|
2015-10-17 19:05:15 +02:00
|
|
|
}
|
|
|
|
|
2015-12-13 02:02:29 +01:00
|
|
|
const char * node_name_short(struct node *n)
|
|
|
|
{
|
|
|
|
return n->name;
|
|
|
|
}
|
|
|
|
|
2015-11-23 16:42:43 +01:00
|
|
|
int node_reverse(struct node *n)
|
2015-03-18 16:18:10 +01:00
|
|
|
{
|
2015-11-23 16:42:43 +01:00
|
|
|
return n->_vt->reverse ? n->_vt->reverse(n) : -1;
|
2015-03-21 15:29:00 +01:00
|
|
|
}
|
2015-03-21 15:23:57 +01:00
|
|
|
|
2017-08-03 00:19:27 +02:00
|
|
|
int node_parse_list(struct list *list, json_t *cfg, struct list *all)
|
2015-03-21 15:23:57 +01:00
|
|
|
{
|
2016-11-20 12:59:37 -05:00
|
|
|
struct node *node;
|
2017-08-03 00:19:27 +02:00
|
|
|
const char *str;
|
|
|
|
char *allstr = NULL;
|
2016-11-20 12:59:37 -05:00
|
|
|
|
2017-08-03 00:19:27 +02:00
|
|
|
size_t index;
|
|
|
|
json_t *elm;
|
|
|
|
|
|
|
|
switch (json_typeof(cfg)) {
|
|
|
|
case JSON_STRING:
|
|
|
|
str = json_string_value(cfg);
|
|
|
|
node = list_lookup(all, str);
|
|
|
|
if (!node)
|
|
|
|
goto invalid2;
|
|
|
|
|
|
|
|
list_push(list, node);
|
2016-11-20 12:59:37 -05:00
|
|
|
break;
|
|
|
|
|
2017-08-03 00:19:27 +02:00
|
|
|
case JSON_ARRAY:
|
|
|
|
json_array_foreach(cfg, index, elm) {
|
|
|
|
if (!json_is_string(elm))
|
|
|
|
goto invalid;
|
|
|
|
|
|
|
|
node = list_lookup(all, json_string_value(elm));
|
|
|
|
if (!node)
|
|
|
|
|
|
|
|
|
|
|
|
list_push(list, node);
|
2016-11-20 12:59:37 -05:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2017-08-03 00:19:27 +02:00
|
|
|
goto invalid;
|
2016-11-20 12:59:37 -05:00
|
|
|
}
|
|
|
|
|
2017-08-03 00:19:27 +02:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
invalid:
|
|
|
|
error("The node list must be an a single or an array of strings referring to the keys of the 'nodes' section");
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
invalid2:
|
|
|
|
for (size_t i = 0; i < list_length(all); i++) {
|
|
|
|
struct node *n = list_at(all, i);
|
|
|
|
|
|
|
|
strcatf(&allstr, " %s", node_name_short(n));
|
|
|
|
}
|
|
|
|
|
|
|
|
error("Unknown node '%s'. Choose of one of: %s", str, allstr);
|
|
|
|
|
2017-03-29 04:25:30 +02:00
|
|
|
return 0;
|
2016-11-20 12:59:37 -05:00
|
|
|
}
|