From 542631ed5bbe7c881edf306c75a4b2dbafe9ded7 Mon Sep 17 00:00:00 2001
From: Steffen Vogel <post@steffenvogel.de>
Date: Thu, 6 Jul 2017 23:14:38 +0200
Subject: [PATCH] reuse code between villas-signal and signal node-type

---
 include/villas/nodes/signal.h |  23 +++--
 lib/nodes/signal.c            | 138 ++++++++++++++++-----------
 src/signal.c                  | 169 +++++++++++-----------------------
 3 files changed, 155 insertions(+), 175 deletions(-)

diff --git a/include/villas/nodes/signal.h b/include/villas/nodes/signal.h
index d3d262c1f..6b44d7a18 100644
--- a/include/villas/nodes/signal.h
+++ b/include/villas/nodes/signal.h
@@ -37,20 +37,23 @@
 struct node;
 struct sample;
 
+enum signal_type {
+	SIGNAL_TYPE_RANDOM,
+	SIGNAL_TYPE_SINE,
+	SIGNAL_TYPE_SQUARE,
+	SIGNAL_TYPE_TRIANGLE,
+	SIGNAL_TYPE_RAMP,
+	SIGNAL_TYPE_MIXED
+};
+
 /** Node-type for signal generation.
  * @see node_type
  */
 struct signal {
 	int tfd;			/**< timerfd file descriptor. */
+	int rt;				/**< Real-time mode? */
 	
-	enum {
-		TYPE_RANDOM,
-		TYPE_SINE,
-		TYPE_SQUARE,
-		TYPE_TRIANGLE,
-		TYPE_RAMP,
-		TYPE_MIXED
-	} type;				/**< Signal type */
+	enum signal_type type;		/**< Signal type */
 	
 	double rate;			/**< Sampling rate. */
 	double frequency;		/**< Frequency of the generated signals. */
@@ -79,4 +82,8 @@ int signal_close(struct node *n);
 /** @see node_type::read */
 int signal_read(struct node *n, struct sample *smps[], unsigned cnt);
 
+enum signal_type signal_lookup_type(const char *type);
+
+void signal_get(struct signal *s, struct sample *t, struct timespec *now);
+
 /** @} */
diff --git a/lib/nodes/signal.c b/lib/nodes/signal.c
index 45b4a2290..ab1353c9f 100644
--- a/lib/nodes/signal.c
+++ b/lib/nodes/signal.c
@@ -22,55 +22,63 @@
  *********************************************************************************/
 
 #include <math.h>
-#include <inttypes.h>
 
 #include "node.h"
 #include "plugin.h"
 #include "nodes/signal.h"
 
+enum signal_type signal_lookup_type(const char *type)
+{
+	if      (!strcmp(type, "random"))
+		return SIGNAL_TYPE_RANDOM;
+	else if (!strcmp(type, "sine"))
+		return SIGNAL_TYPE_SINE;
+	else if (!strcmp(type, "square"))
+		return SIGNAL_TYPE_SQUARE;
+	else if (!strcmp(type, "triangle"))
+		return SIGNAL_TYPE_TRIANGLE;
+	else if (!strcmp(type, "ramp"))
+		return SIGNAL_TYPE_RAMP;
+	else if (!strcmp(type, "mixed"))
+		return SIGNAL_TYPE_MIXED;
+	else
+		return -1;
+}
+
 int signal_parse(struct node *n, config_setting_t *cfg)
 {
 	struct signal *s = n->_vd;
 
 	const char *type;
-	
+
 	if (!config_setting_lookup_string(cfg, "signal", &type))
-		s->type = TYPE_MIXED;
+		s->type = SIGNAL_TYPE_MIXED;
 	else {
-		if      (!strcmp(type, "random"))
-			s->type = TYPE_RANDOM;
-		else if (!strcmp(type, "sine"))
-			s->type = TYPE_SINE;
-		else if (!strcmp(type, "square"))
-			s->type = TYPE_SQUARE;
-		else if (!strcmp(type, "triangle"))
-			s->type = TYPE_TRIANGLE;
-		else if (!strcmp(type, "ramp"))
-			s->type = TYPE_RAMP;
-		else if (!strcmp(type, "mixed"))
-			s->type = TYPE_MIXED;
-		else
-			cerror(cfg, "Invalid signal type: %s", type);
+		s->type = signal_lookup_type(type);
+		if (s->type == -1)
+			cerror(cfg, "Unknown signal type '%s'", type);
 	}
 	
+	if (!config_setting_lookup_bool(cfg, "realtime", &s->rt))
+		s->rt = 1;
+
 	if (!config_setting_lookup_int(cfg, "limit", &s->limit))
 		s->limit = -1;
-	
+
 	if (!config_setting_lookup_int(cfg, "values", &s->values))
 		s->values = 1;
-	
+
 	if (!config_setting_lookup_float(cfg, "rate", &s->rate))
 		s->rate = 10;
-	
+
 	if (!config_setting_lookup_float(cfg, "frequency", &s->frequency))
 		s->frequency = 1;
-	
+
 	if (!config_setting_lookup_float(cfg, "amplitude", &s->amplitude))
 		s->amplitude = 1;
-	
+
 	if (!config_setting_lookup_float(cfg, "stddev", &s->stddev))
 		s->stddev = 0.02;
-	
 
 	return 0;
 }
@@ -81,8 +89,15 @@ int signal_open(struct node *n)
 	
 	s->counter = 0;
 	s->started = time_now();
-	
-	s->tfd = timerfd_create_rate(s->rate);
+
+	/* Setup timer */
+	if (s->rt) {
+		s->tfd = timerfd_create_rate(s->rate);
+		if (s->tfd < 0)
+			return -1;
+	}
+	else
+		s->tfd = -1;
 
 	return 0;
 }
@@ -99,36 +114,51 @@ int signal_close(struct node *n)
 int signal_read(struct node *n, struct sample *smps[], unsigned cnt)
 {
 	struct signal *s = n->_vd;
+	struct sample *t = smps[0];
+	
+	struct timespec now;
 	
 	assert(cnt == 1);
 	
-	uint64_t steps = timerfd_wait(s->tfd);
-	if (steps > 1)
-		warn("Missed steps: %" PRIu64, steps);
-	
-	struct timespec now = time_now();
-	
+	/* Throttle output if desired */
+	if (s->rt) {
+		/* Block until 1/p->rate seconds elapsed */
+		int steps = timerfd_wait(s->tfd);
+		if (steps > 1)
+			warn("Missed steps: %u", steps);
+
+		s->counter += steps;
+		
+		now = time_now();
+	}
+	else {
+		struct timespec offset = time_from_double(s->counter * 1.0 / s->rate);
+
+		now = time_add(&s->started, &offset);
+		
+		s->counter += 1;
+	}
+
 	double running = time_delta(&s->started, &now);
 
-	smps[0]->ts.origin = 
-	smps[0]->ts.received = now;
-	smps[0]->sequence = s->counter;
-	smps[0]->length = s->values;
+	t->ts.origin = 
+	t->ts.received = now;
+	t->sequence = s->counter;
+	t->length = s->values;
 
-	for (int i = 0; i < MIN(s->values, smps[0]->capacity); i++) {
-		int rtype = (s->type != TYPE_MIXED) ? s->type : i % 4;
+	for (int i = 0; i < MIN(s->values, t->capacity); i++) {
+		int rtype = (s->type != SIGNAL_TYPE_MIXED) ? s->type : i % 4;
 		switch (rtype) {
-			case TYPE_RANDOM:   smps[0]->data[i].f += box_muller(0, s->stddev);                                              break;
-			case TYPE_SINE:	    smps[0]->data[i].f = s->amplitude *        sin(running * s->frequency * 2 * M_PI);           break;
-			case TYPE_TRIANGLE: smps[0]->data[i].f = s->amplitude * (fabs(fmod(running * s->frequency, 1) - .5) - 0.25) * 4; break;
-			case TYPE_SQUARE:   smps[0]->data[i].f = s->amplitude * (    (fmod(running * s->frequency, 1) < .5) ? -1 : 1);   break;
-			case TYPE_RAMP:     smps[0]->data[i].f = fmod(s->counter, s->rate / s->frequency); /** @todo send as integer? */ break;
+			case SIGNAL_TYPE_RANDOM:   t->data[i].f += box_muller(0, s->stddev);                                              break;
+			case SIGNAL_TYPE_SINE:	   t->data[i].f = s->amplitude *        sin(running * s->frequency * 2 * M_PI);           break;
+			case SIGNAL_TYPE_TRIANGLE: t->data[i].f = s->amplitude * (fabs(fmod(running * s->frequency, 1) - .5) - 0.25) * 4; break;
+			case SIGNAL_TYPE_SQUARE:   t->data[i].f = s->amplitude * (    (fmod(running * s->frequency, 1) < .5) ? -1 : 1);   break;
+			case SIGNAL_TYPE_RAMP:     t->data[i].f = fmod(s->counter, s->rate / s->frequency); /** @todo send as integer? */ break;
 		}
 	}
-	
-	s->counter++;
+
 	if (s->limit > 0 && s->counter >= s->limit) {
-		info("Reached limit of node %s", node_name(n));
+		info("Reached limit");
 		killme(SIGTERM);
 	}
 
@@ -141,12 +171,12 @@ char * signal_print(struct node *n)
 	char *type, *buf = NULL;
 	
 	switch (s->type) {
-		case TYPE_MIXED:    type = "mixed";    break;
-		case TYPE_RAMP:     type = "ramp";     break;
-		case TYPE_TRIANGLE: type = "triangle"; break;
-		case TYPE_SQUARE:   type = "square";   break;
-		case TYPE_SINE:     type = "sine";     break;
-		case TYPE_RANDOM:   type = "random";   break;
+		case SIGNAL_TYPE_MIXED:    type = "mixed";    break;
+		case SIGNAL_TYPE_RAMP:     type = "ramp";     break;
+		case SIGNAL_TYPE_TRIANGLE: type = "triangle"; break;
+		case SIGNAL_TYPE_SQUARE:   type = "square";   break;
+		case SIGNAL_TYPE_SINE:     type = "sine";     break;
+		case SIGNAL_TYPE_RANDOM:   type = "random";   break;
 		default: return NULL;
 	}
 	
@@ -165,12 +195,12 @@ static struct plugin p = {
 	.type = PLUGIN_TYPE_NODE,
 	.node = {
 		.vectorize = 1,
-		.size = sizeof(struct signal),
+		.size  = sizeof(struct signal),
 		.parse = signal_parse,
 		.print = signal_print,
 		.start = signal_open,
-		.stop = signal_close,
-		.read = signal_read,
+		.stop  = signal_close,
+		.read  = signal_read,
 	}
 };
 
diff --git a/src/signal.c b/src/signal.c
index fa4a78d6a..739c75e1e 100644
--- a/src/signal.c
+++ b/src/signal.c
@@ -32,18 +32,27 @@
 #include <villas/sample.h>
 #include <villas/sample_io.h>
 #include <villas/timing.h>
+#include <villas/node.h>
+#include <villas/nodes/signal.h>
 
-#define CLOCKID	CLOCK_REALTIME
-
-enum SIGNAL_TYPE {
-	TYPE_RANDOM,
-	TYPE_SINE,
-	TYPE_SQUARE,
-	TYPE_TRIANGLE,
-	TYPE_RAMP,
-	TYPE_MIXED
+/* Some default values */
+struct signal s = {
+	.rate = 10,
+	.frequency = 1,
+	.amplitude = 1,
+	.stddev = 0.02,
+	.type = SIGNAL_TYPE_MIXED,
+	.rt = 1,
+	.values = 1,
+	.limit = -1
 };
 
+struct node n = {
+	._vd = &s
+};
+
+struct log l;
+
 void usage()
 {
 	printf("Usage: villas-signal [OPTIONS] SIGNAL\n");
@@ -68,26 +77,18 @@ void usage()
 	print_copyright();
 }
 
+static void quit(int signal, siginfo_t *sinfo, void *ctx)
+{
+	signal_close(&n);
+
+	info(GRN("Goodbye!"));
+	exit(EXIT_SUCCESS);
+}
+
 int main(int argc, char *argv[])
 {
-	struct log log;
-	struct timespec start, now;
-
-	enum {
-		MODE_RT,
-		MODE_NON_RT
-	} mode = MODE_RT;
-
-	/* Some default values */
-	double rate = 10;
-	double freq = 1;
-	double ampl = 1;
-	double stddev = 0.02;
-	double running;
-	int type = TYPE_MIXED;
-	int values = 1;
-	int limit = -1;
-	int counter, tfd, steps, level = V;
+	char *type;
+	int ret, level = V;
 
 	/* Parse optional command line arguments */
 	char c, *endptr;
@@ -96,27 +97,27 @@ int main(int argc, char *argv[])
 			case 'd':
 				level = strtoul(optarg, &endptr, 10);
 				goto check;
+			case 'n':
+				s.rt = 0;
+				break;
 			case 'l':
-				limit = strtoul(optarg, &endptr, 10);
+				s.limit = strtoul(optarg, &endptr, 10);
 				goto check;
 			case 'v':
-				values = strtoul(optarg, &endptr, 10);
+				s.values = strtoul(optarg, &endptr, 10);
 				goto check;
 			case 'r':
-				rate   = strtof(optarg, &endptr);
+				s.rate = strtof(optarg, &endptr);
 				goto check;
 			case 'f':
-				freq   = strtof(optarg, &endptr);
+				s.frequency = strtof(optarg, &endptr);
 				goto check;
 			case 'a':
-				ampl   = strtof(optarg, &endptr);
+				s.amplitude = strtof(optarg, &endptr);
 				goto check;
 			case 'D':
-				stddev = strtof(optarg, &endptr);
+				s.stddev = strtof(optarg, &endptr);
 				goto check;
-			case 'n':
-				mode = MODE_NON_RT;
-				break;
 			case 'h':
 			case '?':
 				usage();
@@ -133,97 +134,39 @@ check:		if (optarg == endptr)
 		usage();
 		exit(EXIT_FAILURE);
 	}
+	
+	type = argv[optind];
 
-	char *typestr = argv[optind];
+	s.type = signal_lookup_type(type);
+	if (s.type == -1)
+		error("Invalid signal type: %s", type);
 
-	/* Parse signal type */
-	if      (!strcmp(typestr, "random"))
-		type = TYPE_RANDOM;
-	else if (!strcmp(typestr, "sine"))
-		type = TYPE_SINE;
-	else if (!strcmp(typestr, "square"))
-		type = TYPE_SQUARE;
-	else if (!strcmp(typestr, "triangle"))
-		type = TYPE_TRIANGLE;
-	else if (!strcmp(typestr, "ramp"))
-		type = TYPE_RAMP;
-	else if (!strcmp(typestr, "mixed"))
-		type = TYPE_MIXED;
-	else
-		error("Invalid signal type: %s", typestr);
-
-	log_init(&log, level, LOG_ALL);
+	log_init(&l, level, LOG_ALL);
+	signals_init(quit);
+	
+	info("Starting signal generation: %s", signal_print(&n));
 
 	/* Allocate memory for message buffer */
-	struct sample *s = alloc(SAMPLE_LEN(values));
+	struct sample *t = alloc(SAMPLE_LEN(s.values));
+
+	t->capacity = s.values;
 
 	/* Print header */
 	printf("# VILLASnode signal params: type=%s, values=%u, rate=%f, limit=%d, amplitude=%f, freq=%f\n",
-		typestr, values, rate, limit, ampl, freq);
+		argv[optind], s.values, s.rate, s.limit, s.amplitude, s.frequency);
 	printf("# %-20s\t\t%s\n", "sec.nsec(seq)", "data[]");
 
-	/* Setup timer */
-	if (mode == MODE_RT) {
-		tfd = timerfd_create_rate(rate);
-		if (tfd < 0)
-			serror("Failed to create timer");
-	}
-	else
-		tfd = -1;
+	ret = signal_open(&n);
+	if (ret)
+		serror("Failed to start node");
 
-	start = time_now();
+	for (;;) {
+		signal_read(&n, &t, 1);
 
-	counter = 0;
-	while (limit < 0 || counter < limit) {
-		if (mode == MODE_RT) {
-			now = time_now();
-			running = time_delta(&start, &now);
-		}
-		else {
-			struct timespec offset;
-
-			running = counter * 1.0 / rate;
-			offset = time_from_double(running);
-
-			now = time_add(&start, &offset);
-		}
-
-		s->ts.origin = now;
-		s->sequence  = counter;
-		s->length    = values;
-
-		for (int i = 0; i < values; i++) {
-			int rtype = (type != TYPE_MIXED) ? type : i % 4;
-			switch (rtype) {
-				case TYPE_RANDOM:   s->data[i].f += box_muller(0, stddev); 					break;
-				case TYPE_SINE:	    s->data[i].f = ampl *        sin(running * freq * 2 * M_PI);		break;
-				case TYPE_TRIANGLE: s->data[i].f = ampl * (fabs(fmod(running * freq, 1) - .5) - 0.25) * 4;	break;
-				case TYPE_SQUARE:   s->data[i].f = ampl * (    (fmod(running * freq, 1) < .5) ? -1 : 1);	break;
-				case TYPE_RAMP:     s->data[i].f = fmod(counter, rate / freq); /** @todo send as integer? */	break;
-			}
-		}
-
-		sample_io_villas_fprint(stdout, s, SAMPLE_IO_ALL & ~SAMPLE_IO_OFFSET);
+		sample_io_villas_fprint(stdout, t, SAMPLE_IO_ALL & ~SAMPLE_IO_OFFSET);
 		fflush(stdout);
-
-		/* Throttle output if desired */
-		if (mode == MODE_RT) {
-			/* Block until 1/p->rate seconds elapsed */
-			steps = timerfd_wait(tfd);
-			if (steps > 1)
-				warn("Missed steps: %u", steps);
-
-			counter += steps;
-		}
-		else
-			counter += 1;
 	}
 
-	if (mode == MODE_RT)
-		close(tfd);
-
-	free(s);
-
 	return 0;
 }