diff --git a/include/villas/io.h b/include/villas/io.h index 275fc7d59..e0d18c700 100644 --- a/include/villas/io.h +++ b/include/villas/io.h @@ -82,7 +82,7 @@ struct io { int io_init(struct io *io, const struct format_type *fmt, struct vlist *signals, int flags); -int io_init2(struct io *io, const struct format_type *fmt, enum signal_type type, int len, int flags); +int io_init2(struct io *io, const struct format_type *fmt, const char *dt, int flags); int io_destroy(struct io *io); diff --git a/include/villas/signal.h b/include/villas/signal.h index de19f1cff..2dba077f6 100644 --- a/include/villas/signal.h +++ b/include/villas/signal.h @@ -109,11 +109,14 @@ 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 signal_type fmt); +int signal_list_generate2(struct vlist *list, const char *dt); void signal_list_dump(const struct vlist *list, const union signal_data *data, int len); int signal_list_copy(struct vlist *dst, const struct vlist *src); enum signal_type signal_type_from_str(const char *str); +enum signal_type signal_type_from_fmtstr(char c); + const char * signal_type_to_str(enum signal_type fmt); enum signal_type signal_type_detect(const char *val); diff --git a/lib/io.c b/lib/io.c index dd16195f8..50426d556 100644 --- a/lib/io.c +++ b/lib/io.c @@ -109,7 +109,7 @@ int io_init(struct io *io, const struct format_type *fmt, struct vlist *signals, return 0; } -int io_init2(struct io *io, const struct format_type *fmt, enum signal_type type, int len, int flags) +int io_init2(struct io *io, const struct format_type *fmt, const char *dt, int flags) { int ret; struct vlist *signals; @@ -121,7 +121,7 @@ int io_init2(struct io *io, const struct format_type *fmt, enum signal_type type if (ret) return ret; - ret = signal_list_generate(signals, len, type); + ret = signal_list_generate2(signals, dt); if (ret) return ret; diff --git a/lib/node_direction.c b/lib/node_direction.c index 6d9361021..535988e8f 100644 --- a/lib/node_direction.c +++ b/lib/node_direction.c @@ -126,8 +126,15 @@ int node_direction_parse(struct node_direction *nd, struct node *n, json_t *cfg) if (ret) error("Failed to parse signal definition of node %s", node_name(n)); } + else if (json_is_string(json_signals)) { + const char *dt = json_string_value(json_signals); + + ret = signal_list_generate2(&nd->signals, dt); + if (ret) + return ret; + } else { - int count = DEFAULT_SAMPLE_LENGTH; + int count = 64; const char *type_str = "float"; if (json_is_object(json_signals)) { @@ -137,13 +144,15 @@ int node_direction_parse(struct node_direction *nd, struct node *n, json_t *cfg) ); } else - warning("No signal definition found for node %s. Using the default config of %d floating point signals.", node_name(n), DEFAULT_SAMPLE_LENGTH); + warning("No signal definition found for node %s. Using the default config of 64 floating point signals.", node_name(n)); int type = signal_type_from_str(type_str); if (type < 0) error("Invalid signal type %s", type_str); - signal_list_generate(&nd->signals, count, type); + ret = signal_list_generate(&nd->signals, count, type); + if (ret) + return ret; } #ifdef WITH_HOOKS diff --git a/lib/signal.c b/lib/signal.c index d3294d875..07ced6d09 100644 --- a/lib/signal.c +++ b/lib/signal.c @@ -261,13 +261,14 @@ int signal_list_parse(struct vlist *list, json_t *cfg) return 0; } -int signal_list_generate(struct vlist *list, unsigned len, enum signal_type fmt) +int signal_list_generate(struct vlist *list, unsigned len, enum signal_type typ) { + char name[32]; + for (int i = 0; i < len; i++) { - char name[32]; snprintf(name, sizeof(name), "signal%d", i); - struct signal *sig = signal_create(name, NULL, fmt); + struct signal *sig = signal_create(name, NULL, typ); if (!sig) return -1; @@ -277,6 +278,35 @@ int signal_list_generate(struct vlist *list, unsigned len, enum signal_type fmt) return 0; } +int signal_list_generate2(struct vlist *list, const char *dt) +{ + int len, i = 0; + char name[32], *e; + enum signal_type 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 == SIGNAL_TYPE_INVALID) + return -1; + + for (int j = 0; j < len; j++) { + snprintf(name, sizeof(name), "signal%d", i++); + + struct signal *sig = signal_create(name, NULL, typ); + if (!sig) + return -1; + + vlist_push(list, sig); + } + } + + return 0; +} + void signal_list_dump(const struct vlist *list, const union signal_data *data, int len) { debug(5, " Signals:"); @@ -339,6 +369,26 @@ enum signal_type signal_type_from_str(const char *str) return SIGNAL_TYPE_INVALID; } +enum signal_type signal_type_from_fmtstr(char c) +{ + switch (c) { + case 'f': + return SIGNAL_TYPE_FLOAT; + + case 'i': + return SIGNAL_TYPE_INTEGER; + + case 'c': + return SIGNAL_TYPE_COMPLEX; + + case 'b': + return SIGNAL_TYPE_BOOLEAN; + + default: + return SIGNAL_TYPE_INVALID; + } +} + const char * signal_type_to_str(enum signal_type fmt) { switch (fmt) { diff --git a/src/villas-convert.cpp b/src/villas-convert.cpp index da1f9bfb3..eb771ea09 100644 --- a/src/villas-convert.cpp +++ b/src/villas-convert.cpp @@ -42,6 +42,7 @@ static void usage() << " OPTIONS are:" << std::endl << " -i FMT set the input format" << std::endl << " -o FMT set the output format" << std::endl + << " -t DT the data-type format string" << std::endl << " -d LVL set debug log level to LVL" << std::endl << " -h show this usage information" << std::endl << " -V show the version of the tool" << std::endl << std::endl; @@ -54,10 +55,11 @@ int main(int argc, char *argv[]) int ret; const char *input_format = "villas.human"; const char *output_format = "villas.human"; + const char *dtypes = "64f"; /* Parse optional command line arguments */ int c; - while ((c = getopt(argc, argv, "Vhd:i:o:")) != -1) { + while ((c = getopt(argc, argv, "Vhd:i:o:t:")) != -1) { switch (c) { case 'V': print_version(); @@ -71,6 +73,10 @@ int main(int argc, char *argv[]) output_format = optarg; break; + case 't': + dtypes = optarg; + break; + case 'd': logging.setLevel(optarg); break; @@ -87,7 +93,7 @@ int main(int argc, char *argv[]) exit(EXIT_FAILURE); } - struct format_type *fmt; + struct format_type *ft; struct io input = { .state = STATE_DESTROYED }; struct io output = { .state = STATE_DESTROYED }; @@ -100,11 +106,11 @@ int main(int argc, char *argv[]) }; for (unsigned i = 0; i < ARRAY_LEN(dirs); i++) { - fmt = format_type_lookup(dirs[i].name); - if (!fmt) + ft = format_type_lookup(dirs[i].name); + if (!ft) throw RuntimeError("Invalid format: {}", dirs[i].name); - ret = io_init2(dirs[i].io, fmt, SIGNAL_TYPE_FLOAT, DEFAULT_SAMPLE_LENGTH, SAMPLE_HAS_ALL); + ret = io_init2(dirs[i].io, ft, dtypes, SAMPLE_HAS_ALL); if (ret) throw RuntimeError("Failed to initialize IO: {}", dirs[i].name); diff --git a/src/villas-hook.cpp b/src/villas-hook.cpp index 9f1195ec0..3b8f87157 100644 --- a/src/villas-hook.cpp +++ b/src/villas-hook.cpp @@ -60,6 +60,7 @@ static void usage() << " PARAM* a string of configuration settings for the hook" << std::endl << " OPTIONS is one or more of the following options:" << std::endl << " -f FMT the data format" << std::endl + << " -t DT the data-type format string" << std::endl << " -d LVL set debug level to LVL" << std::endl << " -v CNT process CNT smps at once" << std::endl << " -h show this help" << std::endl @@ -84,6 +85,7 @@ int main(int argc, char *argv[]) { int ret, recv, sent, cnt; const char *format = "villas.human"; + const char *dtypes = "64f"; struct format_type *ft; struct hook_type *ht; @@ -103,7 +105,7 @@ int main(int argc, char *argv[]) /* Parse optional command line arguments */ int c; char *endptr; - while ((c = getopt(argc, argv, "Vhv:d:f:o:")) != -1) { + while ((c = getopt(argc, argv, "Vhv:d:f:t:o:")) != -1) { switch (c) { case 'V': print_version(); @@ -113,6 +115,10 @@ int main(int argc, char *argv[]) format = optarg; break; + case 't': + dtypes = optarg; + break; + case 'v': cnt = strtoul(optarg, &endptr, 0); goto check; @@ -169,7 +175,7 @@ check: if (optarg == endptr) if (!ft) throw RuntimeError("Unknown IO format '{}'", format); - ret = io_init2(&io, ft, SIGNAL_TYPE_FLOAT, DEFAULT_SAMPLE_LENGTH, SAMPLE_HAS_ALL); + ret = io_init2(&io, ft, dtypes, SAMPLE_HAS_ALL); if (ret) throw RuntimeError("Failed to initialize IO"); diff --git a/src/villas-pipe.cpp b/src/villas-pipe.cpp index cb210d234..8adc41318 100644 --- a/src/villas-pipe.cpp +++ b/src/villas-pipe.cpp @@ -127,11 +127,12 @@ static void usage() << " NODE the name of the node to which samples are sent and received from" << std::endl << " OPTIONS are:" << std::endl << " -f FMT set the format" << std::endl + << " -t DT the data-type format string" << std::endl << " -o OPTION=VALUE overwrite options in config file" << std::endl << " -x swap read / write endpoints" << std::endl << " -s only read data from stdin and send it to node" << std::endl << " -r only read data from node and write it to stdout" << std::endl - << " -t NUM terminate after NUM seconds" << std::endl + << " -T NUM terminate after NUM seconds" << std::endl << " -L NUM terminate after NUM samples sent" << std::endl << " -l NUM terminate after NUM samples received" << std::endl << " -h show this usage information" << std::endl @@ -253,6 +254,7 @@ int main(int argc, char *argv[]) int ret, timeout = 0; bool reverse = false; const char *format = "villas.human"; + const char *dtypes = "64f"; struct node *node; static struct io io = { .state = STATE_DESTROYED }; @@ -268,7 +270,7 @@ int main(int argc, char *argv[]) /* Parse optional command line arguments */ int c; char *endptr; - while ((c = getopt(argc, argv, "Vhxrsd:l:L:t:f:o:")) != -1) { + while ((c = getopt(argc, argv, "Vhxrsd:l:L:T:f:t:o:")) != -1) { switch (c) { case 'V': print_version(); @@ -278,6 +280,10 @@ int main(int argc, char *argv[]) format = optarg; break; + case 't': + dtypes = optarg; + break; + case 'x': reverse = true; break; @@ -298,7 +304,7 @@ int main(int argc, char *argv[]) limit_send = strtoul(optarg, &endptr, 10); goto check; - case 't': + case 'T': timeout = strtoul(optarg, &endptr, 10); goto check; @@ -333,7 +339,7 @@ check: if (optarg == endptr) char *uri = argv[optind]; char *nodestr = argv[optind+1]; - struct format_type *fmt; + struct format_type *ft; ret = memory_init(0); if (ret) @@ -351,11 +357,11 @@ check: if (optarg == endptr) else logger->warn("No configuration file specified. Starting unconfigured. Use the API to configure this instance."); - fmt = format_type_lookup(format); - if (!fmt) + ft = format_type_lookup(format); + if (!ft) throw RuntimeError("Invalid format: {}", format); - ret = io_init2(&io, fmt, SIGNAL_TYPE_FLOAT, DEFAULT_SAMPLE_LENGTH, SAMPLE_HAS_ALL); + ret = io_init2(&io, ft, dtypes, SAMPLE_HAS_ALL); if (ret) throw RuntimeError("Failed to initialize IO"); diff --git a/src/villas-test-cmp.cpp b/src/villas-test-cmp.cpp index d0d20ce7b..ab9ca1314 100644 --- a/src/villas-test-cmp.cpp +++ b/src/villas-test-cmp.cpp @@ -47,15 +47,17 @@ public: struct io io; struct format_type *format; + const char *dtypes; - Side(const std::string &pth, struct format_type *fmt, struct pool *p) : + Side(const std::string &pth, struct format_type *fmt, const char *dt, struct pool *p) : path(pth), - format(fmt) + format(fmt), + dtypes(dt) { int ret; io.state = STATE_DESTROYED; - ret = io_init2(&io, format, SIGNAL_TYPE_FLOAT, DEFAULT_SAMPLE_LENGTH, 0); + ret = io_init2(&io, format, dtypes, 0); if (ret) throw RuntimeError("Failed to initialize IO"); @@ -96,9 +98,10 @@ void usage() << " -d LVL adjust the debug level" << std::endl << " -e EPS set epsilon for floating point comparisons to EPS" << std::endl << " -v ignore data values" << std::endl - << " -t ignore timestamp" << std::endl + << " -T ignore timestamp" << std::endl << " -s ignore sequence no" << std::endl << " -f FMT file format for all files" << std::endl + << " -t DT the data-type format string" << std::endl << " -h show this usage information" << std::endl << " -V show the version of the tool" << std::endl << std::endl << "Return codes:" << std::endl @@ -119,6 +122,7 @@ int main(int argc, char *argv[]) /* Default values */ double epsilon = 1e-9; const char *format = "villas.human"; + const char *dtypes = "64f"; int flags = SAMPLE_HAS_SEQUENCE | SAMPLE_HAS_DATA | SAMPLE_HAS_TS_ORIGIN; struct pool pool = { .state = STATE_DESTROYED }; @@ -126,7 +130,7 @@ int main(int argc, char *argv[]) /* Parse Arguments */ int c; char *endptr; - while ((c = getopt (argc, argv, "he:vtsf:Vd:")) != -1) { + while ((c = getopt (argc, argv, "he:vTsf:t:Vd:")) != -1) { switch (c) { case 'e': epsilon = strtod(optarg, &endptr); @@ -136,7 +140,7 @@ int main(int argc, char *argv[]) flags &= ~SAMPLE_HAS_DATA; break; - case 't': + case 'T': flags &= ~SAMPLE_HAS_TS_ORIGIN; break; @@ -148,6 +152,10 @@ int main(int argc, char *argv[]) format = optarg; break; + case 't': + dtypes = optarg; + break; + case 'V': print_version(); exit(EXIT_SUCCESS); @@ -191,7 +199,7 @@ check: if (optarg == endptr) /* Open files */ for (int i = 0; i < n; i++) - s[i] = new Side(argv[optind + i], fmt, &pool); + s[i] = new Side(argv[optind + i], fmt, dtypes, &pool); line = 0; for (;;) {