diff --git a/include/villas/signal.h b/include/villas/signal.h index 982f46536..e638afd2d 100644 --- a/include/villas/signal.h +++ b/include/villas/signal.h @@ -25,51 +25,18 @@ #include -#include #include -#include -#include +#include +#include +#include /* "I" defined by complex.h collides with a define in OpenSSL */ #undef I /* Forward declarations */ -struct vlist; -struct node; struct mapping_entry; -/** A signal value. - * - * Data is in host endianess! - */ -union signal_data { - double f; /**< Floating point values. */ - int64_t i; /**< Integer values. */ - bool b; /**< Boolean values. */ - std::complex z; /**< Complex values. */ - - signal_data() - { } - - static union signal_data nan() - { - union signal_data d; - - d.f = std::numeric_limits::quiet_NaN(); - - return d; - } -}; - -enum class SignalType { - INVALID = 0, /**< Signal type is invalid. */ - FLOAT = 1, /**< See signal_data::f */ - INTEGER = 2, /**< See signal_data::i */ - BOOLEAN = 3, /**< See signal_data::b */ - COMPLEX = 4 /**< See signal_data::z */ -}; - /** Signal descriptor. * * This data structure contains meta data about samples values in struct sample::data @@ -114,15 +81,6 @@ int signal_parse(struct signal *s, json_t *cfg); /** Initialize signal from a mapping_entry. */ int signal_init_from_mapping(struct signal *s, const struct mapping_entry *me, unsigned index); -int signal_list_init(struct vlist *list); -int signal_list_destroy(struct vlist *list); -int signal_list_parse(struct vlist *list, json_t *cfg); -int signal_list_generate(struct vlist *list, unsigned len, enum SignalType fmt); -int signal_list_generate2(struct vlist *list, const char *dt); -void signal_list_dump(const struct vlist *list, const union signal_data *data = nullptr, unsigned len = 0); -int signal_list_copy(struct vlist *dst, const struct vlist *src); -json_t * signal_list_to_json(struct vlist *list); - enum SignalType signal_type_from_str(const char *str); enum SignalType signal_type_from_fmtstr(char c); @@ -131,16 +89,3 @@ const char * signal_type_to_str(enum SignalType fmt); enum SignalType signal_type_detect(const char *val); -/** Convert signal data from one description/format to another. */ -void signal_data_cast(union signal_data *data, const struct signal *from, const struct signal *to); - -/** Print value of a signal to a character buffer. */ -int signal_data_print_str(const union signal_data *data, const struct signal *sig, char *buf, size_t len); - -int signal_data_parse_str(union signal_data *data, const struct signal *sig, const char *ptr, char **end); - -int signal_data_parse_json(union signal_data *data, const struct signal *sig, json_t *cfg); - -json_t * signal_data_to_json(union signal_data *data, const struct signal *sig); - -void signal_data_set(union signal_data *data, const struct signal *sig, double val); diff --git a/include/villas/signal_data.h b/include/villas/signal_data.h new file mode 100644 index 000000000..392f0b50a --- /dev/null +++ b/include/villas/signal_data.h @@ -0,0 +1,68 @@ +/** Signal data. + * + * @file + * @author Steffen Vogel + * @copyright 2014-2020, 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 . + *********************************************************************************/ + +#pragma once + +#include + +#include +#include + +#include + +/** A signal value. + * + * Data is in host endianess! + */ +union signal_data { + double f; /**< Floating point values. */ + int64_t i; /**< Integer values. */ + bool b; /**< Boolean values. */ + std::complex z; /**< Complex values. */ + + signal_data() + { } + + static union signal_data nan() + { + union signal_data d; + + d.f = std::numeric_limits::quiet_NaN(); + + return d; + } +}; + +/** Convert signal data from one description/format to another. */ +void signal_data_cast(union signal_data *data, const struct signal *from, const struct signal *to); + +/** Print value of a signal to a character buffer. */ +int signal_data_print_str(const union signal_data *data, const struct signal *sig, char *buf, size_t len); + +int signal_data_parse_str(union signal_data *data, const struct signal *sig, const char *ptr, char **end); + +int signal_data_parse_json(union signal_data *data, const struct signal *sig, json_t *cfg); + +json_t * signal_data_to_json(union signal_data *data, const struct signal *sig); + +void signal_data_set(union signal_data *data, const struct signal *sig, double val); diff --git a/include/villas/signal_list.h b/include/villas/signal_list.h new file mode 100644 index 000000000..b670fc978 --- /dev/null +++ b/include/villas/signal_list.h @@ -0,0 +1,47 @@ +/** Signal metadata lits. + * + * @file + * @author Steffen Vogel + * @copyright 2014-2020, 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 . + *********************************************************************************/ + +#pragma once + +#include + +#include + +/* Forward declarations */ +struct vlist; + +int signal_list_init(struct vlist *list); + +int signal_list_destroy(struct vlist *list); + +int signal_list_parse(struct vlist *list, json_t *cfg); + +int signal_list_generate(struct vlist *list, unsigned len, enum SignalType fmt); + +int signal_list_generate2(struct vlist *list, const char *dt); + +void signal_list_dump(const struct vlist *list, const union signal_data *data = nullptr, unsigned len = 0); + +int signal_list_copy(struct vlist *dst, const struct vlist *src); + +json_t * signal_list_to_json(struct vlist *list); diff --git a/include/villas/signal_type.h b/include/villas/signal_type.h new file mode 100644 index 000000000..6b7d733a4 --- /dev/null +++ b/include/villas/signal_type.h @@ -0,0 +1,32 @@ +/** Signal type. + * + * @file + * @author Steffen Vogel + * @copyright 2014-2020, 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 . + *********************************************************************************/ + +#pragma once + +enum class SignalType { + INVALID = 0, /**< Signal type is invalid. */ + FLOAT = 1, /**< See signal_data::f */ + INTEGER = 2, /**< See signal_data::i */ + BOOLEAN = 3, /**< See signal_data::b */ + COMPLEX = 4 /**< See signal_data::z */ +}; diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 4fbb87328..d59580dbd 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -66,6 +66,9 @@ set(LIB_SRC sample.cpp shmem.cpp signal.cpp + signal_data.cpp + signal_list.cpp + signal_type.cpp stats.cpp super_node.cpp socket_addr.cpp diff --git a/lib/signal.cpp b/lib/signal.cpp index 0be9e2651..335f637f8 100644 --- a/lib/signal.cpp +++ b/lib/signal.cpp @@ -20,12 +20,8 @@ * along with this program. If not, see . *********************************************************************************/ -#include -#include #include -#include #include -#include #include #include @@ -221,508 +217,3 @@ int signal_parse(struct signal *s, json_t *cfg) return 0; } - -/* Signal list */ - -int signal_list_init(struct vlist *list) -{ - int ret; - - ret = vlist_init(list); - if (ret) - return ret; - - return 0; -} - -int signal_list_destroy(struct vlist *list) -{ - int ret; - - ret = vlist_destroy(list, (dtor_cb_t) signal_decref, false); - if (ret) - return ret; - - return 0; -} - -int signal_list_parse(struct vlist *list, json_t *cfg) -{ - int ret; - struct signal *s; - - if (!json_is_array(cfg)) - return -1; - - size_t i; - json_t *json_signal; - json_array_foreach(cfg, i, json_signal) { - s = new struct signal; - if (!s) - throw MemoryAllocationError(); - - ret = signal_init(s); - if (ret) - return ret; - - ret = signal_parse(s, json_signal); - if (ret) - return ret; - - vlist_push(list, s); - } - - return 0; -} - -int signal_list_generate(struct vlist *list, unsigned len, enum SignalType typ) -{ - char name[32]; - - for (unsigned i = 0; i < len; i++) { - snprintf(name, sizeof(name), "signal%d", i); - - struct signal *sig = signal_create(name, nullptr, typ); - if (!sig) - return -1; - - vlist_push(list, sig); - } - - return 0; -} - -int signal_list_generate2(struct vlist *list, const char *dt) -{ - int len, i = 0; - char name[32], *e; - enum SignalType typ; - - for (const char *t = dt; *t; t = e + 1) { - len = strtoul(t, &e, 10); - if (t == e) - len = 1; - - typ = signal_type_from_fmtstr(*e); - if (typ == SignalType::INVALID) - return -1; - - for (int j = 0; j < len; j++) { - snprintf(name, sizeof(name), "signal%d", i++); - - struct signal *sig = signal_create(name, nullptr, typ); - if (!sig) - return -1; - - vlist_push(list, sig); - } - } - - return 0; -} - -void signal_list_dump(const struct vlist *list, const union signal_data *data, unsigned len) -{ - for (size_t i = 0; i < vlist_length(list); i++) { - struct signal *sig = (struct signal *) vlist_at(list, i); - - char *buf = strf(" %d:", i); - - if (sig->name) - strcatf(&buf, " %s", sig->name); - - if (sig->unit) - strcatf(&buf, " [%s]", sig->unit); - - strcatf(&buf, "(%s)", signal_type_to_str(sig->type)); - - if (data && i < len) { - char val[32]; - - signal_data_print_str(&data[i], sig, val, sizeof(val)); - - strcatf(&buf, " = %s", val); - } - - info("%s", buf); - free(buf); - } -} - -int signal_list_copy(struct vlist *dst, const struct vlist *src) -{ - assert(src->state == State::INITIALIZED); - assert(dst->state == State::INITIALIZED); - - for (size_t i = 0; i < vlist_length(src); i++) { - struct signal *sig = (struct signal *) vlist_at_safe(src, i); - - signal_incref(sig); - - vlist_push(dst, sig); - } - - return 0; -} - -json_t * signal_list_to_json(struct vlist *list) -{ - json_t *json_signals = json_array(); - - for (size_t i = 0; i < vlist_length(list); i++) { - struct signal *sig = (struct signal *) vlist_at_safe(list, i); - - json_t *json_signal = json_pack("{ s: s?, s: s?, s: s, s: b, s: o }", - "name", sig->name, - "unit", sig->unit, - "type", signal_type_to_str(sig->type), - "enabled", sig->enabled, - "init", signal_data_to_json(&sig->init, sig) - ); - - json_array_append_new(json_signals, json_signal); - } - - return json_signals; -} - -/* Signal type */ - -enum SignalType signal_type_from_str(const char *str) -{ - if (!strcmp(str, "boolean")) - return SignalType::BOOLEAN; - else if (!strcmp(str, "complex")) - return SignalType::COMPLEX; - else if (!strcmp(str, "float")) - return SignalType::FLOAT; - else if (!strcmp(str, "integer")) - return SignalType::INTEGER; - else - return SignalType::INVALID; -} - -enum SignalType signal_type_from_fmtstr(char c) -{ - switch (c) { - case 'f': - return SignalType::FLOAT; - - case 'i': - return SignalType::INTEGER; - - case 'c': - return SignalType::COMPLEX; - - case 'b': - return SignalType::BOOLEAN; - - default: - return SignalType::INVALID; - } -} - -const char * signal_type_to_str(enum SignalType fmt) -{ - switch (fmt) { - case SignalType::BOOLEAN: - return "boolean"; - - case SignalType::COMPLEX: - return "complex"; - - case SignalType::FLOAT: - return "float"; - - case SignalType::INTEGER: - return "integer"; - - case SignalType::INVALID: - return "invalid"; - } - - return nullptr; -} - -enum SignalType signal_type_detect(const char *val) -{ - const char *brk; - int len; - - debug(LOG_IO | 5, "Attempt to detect type of value: %s", val); - - brk = strchr(val, 'i'); - if (brk) - return SignalType::COMPLEX; - - brk = strchr(val, '.'); - if (brk) - return SignalType::FLOAT; - - len = strlen(val); - if (len == 1 && (val[0] == '1' || val[0] == '0')) - return SignalType::BOOLEAN; - - return SignalType::INTEGER; -} - -/* Signal data */ - -void signal_data_set(union signal_data *data, const struct signal *sig, double val) -{ - switch (sig->type) { - case SignalType::BOOLEAN: - data->b = val; - break; - - case SignalType::FLOAT: - data->f = val; - break; - - case SignalType::INTEGER: - data->i = val; - break; - - case SignalType::COMPLEX: - data->z = val; - break; - - case SignalType::INVALID: - *data = signal_data::nan(); - break; - } -} - -void signal_data_cast(union signal_data *data, const struct signal *from, const struct signal *to) -{ - if (from->type == to->type) /* Nothing to do */ - return; - - switch (to->type) { - case SignalType::BOOLEAN: - switch(from->type) { - case SignalType::BOOLEAN: - data->b = data->b; - break; - - case SignalType::INTEGER: - data->b = data->i; - break; - - case SignalType::FLOAT: - data->b = data->f; - break; - - case SignalType::COMPLEX: - data->b = std::real(data->z); - break; - - default: { } - } - break; - - case SignalType::INTEGER: - switch(from->type) { - case SignalType::BOOLEAN: - data->i = data->b; - break; - - case SignalType::INTEGER: - data->i = data->i; - break; - - case SignalType::FLOAT: - data->i = data->f; - break; - - case SignalType::COMPLEX: - data->i = std::real(data->z); - break; - - default: { } - } - break; - - case SignalType::FLOAT: - switch(from->type) { - case SignalType::BOOLEAN: - data->f = data->b; - break; - - case SignalType::INTEGER: - data->f = data->i; - break; - - case SignalType::FLOAT: - data->f = data->f; - break; - - case SignalType::COMPLEX: - data->f = std::real(data->z); - break; - - default: { } - } - break; - - case SignalType::COMPLEX: - switch(from->type) { - case SignalType::BOOLEAN: - data->z = data->b; - break; - - case SignalType::INTEGER: - data->z = data->i; - break; - - case SignalType::FLOAT: - data->z = data->f; - break; - - case SignalType::COMPLEX: - data->z = data->z; - break; - - default: { } - } - break; - - default: { } - } -} - -int signal_data_parse_str(union signal_data *data, const struct signal *sig, const char *ptr, char **end) -{ - switch (sig->type) { - case SignalType::FLOAT: - data->f = strtod(ptr, end); - break; - - case SignalType::INTEGER: - data->i = strtol(ptr, end, 10); - break; - - case SignalType::BOOLEAN: - data->b = strtol(ptr, end, 10); - break; - - case SignalType::COMPLEX: { - float real, imag = 0; - - real = strtod(ptr, end); - if (*end == ptr) - return -1; - - ptr = *end; - - if (*ptr == 'i' || *ptr == 'j') { - imag = real; - real = 0; - - (*end)++; - } - else if (*ptr == '-' || *ptr == '+') { - imag = strtod(ptr, end); - if (*end == ptr) - return -1; - - if (**end != 'i' && **end != 'j') - return -1; - - (*end)++; - } - - data->z = std::complex(real, imag); - break; - } - - case SignalType::INVALID: - return -1; - } - - return 0; -} - -int signal_data_parse_json(union signal_data *data, const struct signal *sig, json_t *cfg) -{ - int ret; - - switch (sig->type) { - case SignalType::FLOAT: - data->f = json_real_value(cfg); - break; - - case SignalType::INTEGER: - data->i = json_integer_value(cfg); - break; - - case SignalType::BOOLEAN: - data->b = json_boolean_value(cfg); - break; - - case SignalType::COMPLEX: { - double real, imag; - - json_error_t err; - ret = json_unpack_ex(cfg, &err, 0, "{ s: F, s: F }", - "real", &real, - "imag", &imag - ); - if (ret) - return -2; - - data->z = std::complex(real, imag); - break; - } - - case SignalType::INVALID: - return -1; - } - - return 0; -} - -json_t * signal_data_to_json(union signal_data *data, const struct signal *sig) -{ - switch (sig->type) { - case SignalType::INTEGER: - return json_integer(data->i); - - case SignalType::FLOAT: - return json_real(data->f); - - case SignalType::BOOLEAN: - return json_boolean(data->b); - - case SignalType::COMPLEX: - return json_pack("{ s: f, s: f }", - "real", std::real(data->z), - "imag", std::imag(data->z) - ); - - case SignalType::INVALID: - return nullptr; - } - - return nullptr; -} - -int signal_data_print_str(const union signal_data *data, const struct signal *sig, char *buf, size_t len) -{ - switch (sig->type) { - case SignalType::FLOAT: - return snprintf(buf, len, "%.6f", data->f); - - case SignalType::INTEGER: - return snprintf(buf, len, "%" PRIi64, data->i); - - case SignalType::BOOLEAN: - return snprintf(buf, len, "%u", data->b); - - case SignalType::COMPLEX: - return snprintf(buf, len, "%.6f%+.6fi", std::real(data->z), std::imag(data->z)); - - default: - return 0; - } -} diff --git a/lib/signal_data.cpp b/lib/signal_data.cpp new file mode 100644 index 000000000..9b617b381 --- /dev/null +++ b/lib/signal_data.cpp @@ -0,0 +1,287 @@ +/** Signal data. + * + * @author Steffen Vogel + * @copyright 2014-2020, 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 . + *********************************************************************************/ + +#include +#include + +#include +#include +#include + +void signal_data_set(union signal_data *data, const struct signal *sig, double val) +{ + switch (sig->type) { + case SignalType::BOOLEAN: + data->b = val; + break; + + case SignalType::FLOAT: + data->f = val; + break; + + case SignalType::INTEGER: + data->i = val; + break; + + case SignalType::COMPLEX: + data->z = val; + break; + + case SignalType::INVALID: + *data = signal_data::nan(); + break; + } +} + +void signal_data_cast(union signal_data *data, const struct signal *from, const struct signal *to) +{ + if (from->type == to->type) /* Nothing to do */ + return; + + switch (to->type) { + case SignalType::BOOLEAN: + switch(from->type) { + case SignalType::BOOLEAN: + data->b = data->b; + break; + + case SignalType::INTEGER: + data->b = data->i; + break; + + case SignalType::FLOAT: + data->b = data->f; + break; + + case SignalType::COMPLEX: + data->b = std::real(data->z); + break; + + default: { } + } + break; + + case SignalType::INTEGER: + switch(from->type) { + case SignalType::BOOLEAN: + data->i = data->b; + break; + + case SignalType::INTEGER: + data->i = data->i; + break; + + case SignalType::FLOAT: + data->i = data->f; + break; + + case SignalType::COMPLEX: + data->i = std::real(data->z); + break; + + default: { } + } + break; + + case SignalType::FLOAT: + switch(from->type) { + case SignalType::BOOLEAN: + data->f = data->b; + break; + + case SignalType::INTEGER: + data->f = data->i; + break; + + case SignalType::FLOAT: + data->f = data->f; + break; + + case SignalType::COMPLEX: + data->f = std::real(data->z); + break; + + default: { } + } + break; + + case SignalType::COMPLEX: + switch(from->type) { + case SignalType::BOOLEAN: + data->z = data->b; + break; + + case SignalType::INTEGER: + data->z = data->i; + break; + + case SignalType::FLOAT: + data->z = data->f; + break; + + case SignalType::COMPLEX: + data->z = data->z; + break; + + default: { } + } + break; + + default: { } + } +} + +int signal_data_parse_str(union signal_data *data, const struct signal *sig, const char *ptr, char **end) +{ + switch (sig->type) { + case SignalType::FLOAT: + data->f = strtod(ptr, end); + break; + + case SignalType::INTEGER: + data->i = strtol(ptr, end, 10); + break; + + case SignalType::BOOLEAN: + data->b = strtol(ptr, end, 10); + break; + + case SignalType::COMPLEX: { + float real, imag = 0; + + real = strtod(ptr, end); + if (*end == ptr) + return -1; + + ptr = *end; + + if (*ptr == 'i' || *ptr == 'j') { + imag = real; + real = 0; + + (*end)++; + } + else if (*ptr == '-' || *ptr == '+') { + imag = strtod(ptr, end); + if (*end == ptr) + return -1; + + if (**end != 'i' && **end != 'j') + return -1; + + (*end)++; + } + + data->z = std::complex(real, imag); + break; + } + + case SignalType::INVALID: + return -1; + } + + return 0; +} + +int signal_data_parse_json(union signal_data *data, const struct signal *sig, json_t *cfg) +{ + int ret; + + switch (sig->type) { + case SignalType::FLOAT: + data->f = json_real_value(cfg); + break; + + case SignalType::INTEGER: + data->i = json_integer_value(cfg); + break; + + case SignalType::BOOLEAN: + data->b = json_boolean_value(cfg); + break; + + case SignalType::COMPLEX: { + double real, imag; + + json_error_t err; + ret = json_unpack_ex(cfg, &err, 0, "{ s: F, s: F }", + "real", &real, + "imag", &imag + ); + if (ret) + return -2; + + data->z = std::complex(real, imag); + break; + } + + case SignalType::INVALID: + return -1; + } + + return 0; +} + +json_t * signal_data_to_json(union signal_data *data, const struct signal *sig) +{ + switch (sig->type) { + case SignalType::INTEGER: + return json_integer(data->i); + + case SignalType::FLOAT: + return json_real(data->f); + + case SignalType::BOOLEAN: + return json_boolean(data->b); + + case SignalType::COMPLEX: + return json_pack("{ s: f, s: f }", + "real", std::real(data->z), + "imag", std::imag(data->z) + ); + + case SignalType::INVALID: + return nullptr; + } + + return nullptr; +} + +int signal_data_print_str(const union signal_data *data, const struct signal *sig, char *buf, size_t len) +{ + switch (sig->type) { + case SignalType::FLOAT: + return snprintf(buf, len, "%.6f", data->f); + + case SignalType::INTEGER: + return snprintf(buf, len, "%" PRIi64, data->i); + + case SignalType::BOOLEAN: + return snprintf(buf, len, "%u", data->b); + + case SignalType::COMPLEX: + return snprintf(buf, len, "%.6f%+.6fi", std::real(data->z), std::imag(data->z)); + + default: + return 0; + } +} diff --git a/lib/signal_list.cpp b/lib/signal_list.cpp new file mode 100644 index 000000000..a14f6590e --- /dev/null +++ b/lib/signal_list.cpp @@ -0,0 +1,194 @@ +/** Signal metadata list. + * + * @author Steffen Vogel + * @copyright 2014-2020, 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 . + *********************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include + +using namespace villas; +using namespace villas::utils; + +int signal_list_init(struct vlist *list) +{ + int ret; + + ret = vlist_init(list); + if (ret) + return ret; + + return 0; +} + +int signal_list_destroy(struct vlist *list) +{ + int ret; + + ret = vlist_destroy(list, (dtor_cb_t) signal_decref, false); + if (ret) + return ret; + + return 0; +} + +int signal_list_parse(struct vlist *list, json_t *cfg) +{ + int ret; + struct signal *s; + + if (!json_is_array(cfg)) + return -1; + + size_t i; + json_t *json_signal; + json_array_foreach(cfg, i, json_signal) { + s = new struct signal; + if (!s) + throw MemoryAllocationError(); + + ret = signal_init(s); + if (ret) + return ret; + + ret = signal_parse(s, json_signal); + if (ret) + return ret; + + vlist_push(list, s); + } + + return 0; +} + +int signal_list_generate(struct vlist *list, unsigned len, enum SignalType typ) +{ + char name[32]; + + for (unsigned i = 0; i < len; i++) { + snprintf(name, sizeof(name), "signal%d", i); + + struct signal *sig = signal_create(name, nullptr, typ); + if (!sig) + return -1; + + vlist_push(list, sig); + } + + return 0; +} + +int signal_list_generate2(struct vlist *list, const char *dt) +{ + int len, i = 0; + char name[32], *e; + enum SignalType typ; + + for (const char *t = dt; *t; t = e + 1) { + len = strtoul(t, &e, 10); + if (t == e) + len = 1; + + typ = signal_type_from_fmtstr(*e); + if (typ == SignalType::INVALID) + return -1; + + for (int j = 0; j < len; j++) { + snprintf(name, sizeof(name), "signal%d", i++); + + struct signal *sig = signal_create(name, nullptr, typ); + if (!sig) + return -1; + + vlist_push(list, sig); + } + } + + return 0; +} + +void signal_list_dump(const struct vlist *list, const union signal_data *data, unsigned len) +{ + for (size_t i = 0; i < vlist_length(list); i++) { + struct signal *sig = (struct signal *) vlist_at(list, i); + + char *buf = strf(" %d:", i); + + if (sig->name) + strcatf(&buf, " %s", sig->name); + + if (sig->unit) + strcatf(&buf, " [%s]", sig->unit); + + strcatf(&buf, "(%s)", signal_type_to_str(sig->type)); + + if (data && i < len) { + char val[32]; + + signal_data_print_str(&data[i], sig, val, sizeof(val)); + + strcatf(&buf, " = %s", val); + } + + info("%s", buf); + free(buf); + } +} + +int signal_list_copy(struct vlist *dst, const struct vlist *src) +{ + assert(src->state == State::INITIALIZED); + assert(dst->state == State::INITIALIZED); + + for (size_t i = 0; i < vlist_length(src); i++) { + struct signal *sig = (struct signal *) vlist_at_safe(src, i); + + signal_incref(sig); + + vlist_push(dst, sig); + } + + return 0; +} + +json_t * signal_list_to_json(struct vlist *list) +{ + json_t *json_signals = json_array(); + + for (size_t i = 0; i < vlist_length(list); i++) { + struct signal *sig = (struct signal *) vlist_at_safe(list, i); + + json_t *json_signal = json_pack("{ s: s?, s: s?, s: s, s: b, s: o }", + "name", sig->name, + "unit", sig->unit, + "type", signal_type_to_str(sig->type), + "enabled", sig->enabled, + "init", signal_data_to_json(&sig->init, sig) + ); + + json_array_append_new(json_signals, json_signal); + } + + return json_signals; +} diff --git a/lib/signal_type.cpp b/lib/signal_type.cpp new file mode 100644 index 000000000..a39a9fa35 --- /dev/null +++ b/lib/signal_type.cpp @@ -0,0 +1,104 @@ +/** Signal types. + * + * @author Steffen Vogel + * @copyright 2014-2020, 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 . + *********************************************************************************/ + +#include + +#include +#include + +enum SignalType signal_type_from_str(const char *str) +{ + if (!strcmp(str, "boolean")) + return SignalType::BOOLEAN; + else if (!strcmp(str, "complex")) + return SignalType::COMPLEX; + else if (!strcmp(str, "float")) + return SignalType::FLOAT; + else if (!strcmp(str, "integer")) + return SignalType::INTEGER; + else + return SignalType::INVALID; +} + +enum SignalType signal_type_from_fmtstr(char c) +{ + switch (c) { + case 'f': + return SignalType::FLOAT; + + case 'i': + return SignalType::INTEGER; + + case 'c': + return SignalType::COMPLEX; + + case 'b': + return SignalType::BOOLEAN; + + default: + return SignalType::INVALID; + } +} + +const char * signal_type_to_str(enum SignalType fmt) +{ + switch (fmt) { + case SignalType::BOOLEAN: + return "boolean"; + + case SignalType::COMPLEX: + return "complex"; + + case SignalType::FLOAT: + return "float"; + + case SignalType::INTEGER: + return "integer"; + + case SignalType::INVALID: + return "invalid"; + } + + return nullptr; +} + +enum SignalType signal_type_detect(const char *val) +{ + const char *brk; + int len; + + debug(LOG_IO | 5, "Attempt to detect type of value: %s", val); + + brk = strchr(val, 'i'); + if (brk) + return SignalType::COMPLEX; + + brk = strchr(val, '.'); + if (brk) + return SignalType::FLOAT; + + len = strlen(val); + if (len == 1 && (val[0] == '1' || val[0] == '0')) + return SignalType::BOOLEAN; + + return SignalType::INTEGER; +}