aboutsummaryrefslogtreecommitdiffstats
path: root/src/common/display_measurements.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/common/display_measurements.c')
-rw-r--r--src/common/display_measurements.c359
1 files changed, 359 insertions, 0 deletions
diff --git a/src/common/display_measurements.c b/src/common/display_measurements.c
new file mode 100644
index 0000000..103384d
--- /dev/null
+++ b/src/common/display_measurements.c
@@ -0,0 +1,359 @@
+/* display measurements functions
+ *
+ * (C) 2017 by Andreas Eversberg <jolly@eversberg.eu>
+ * All Rights Reserved
+ *
+ * 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
+ * (at your option) 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 <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <sys/ioctl.h>
+#include <math.h>
+#include "sample.h"
+#include "sender.h"
+
+#define MAX_NAME_LEN 16
+#define MAX_UNIT_LEN 16
+
+static int has_init = 0;
+static int measurements_on = 0;
+double time_elapsed = 0.0;
+static int lines_total = 0;
+static char line[MAX_DISPLAY_WIDTH];
+static char line_color[MAX_DISPLAY_WIDTH];
+
+void display_measurements_init(sender_t *sender, int __attribute__((unused)) samplerate)
+{
+ dispmeas_t *disp = &sender->dispmeas;
+
+ memset(disp, 0, sizeof(*disp));
+ has_init = 1;
+ lines_total = 0;
+ time_elapsed = 0.0;
+}
+
+void display_measurements_exit(sender_t *sender)
+{
+ dispmeas_t *disp = &sender->dispmeas;
+ dispmeasparam_t *param = disp->head, *temp;
+
+ while (param) {
+ temp = param;
+ param = param->next;
+ free(temp);
+ }
+ disp->head = NULL;
+ has_init = 0;
+}
+
+static int color;
+
+static void display_line(int on, int w)
+{
+ int j;
+
+ if (on) {
+ for (j = 0; j < w; j++) {
+ if (line_color[j] != color && line[j] != ' ') {
+ color = line_color[j];
+ printf("\033[%d;3%dm", color / 10, color % 10);
+ }
+ putchar(line[j]);
+ }
+ } else {
+ for (j = 0; j < w; j++)
+ putchar(' ');
+ }
+ putchar('\n');
+ lines_total++;
+}
+
+static void print_measurements(int on)
+{
+ sender_t *sender;
+ dispmeasparam_t *param;
+ int i, j;
+ int width, h;
+ char text[128];
+ double value = 0.0, value2 = 0.0, hold, hold2;
+ int bar_width, bar_left, bar_right, bar_hold, bar_mark;
+
+ get_win_size(&width, &h);
+
+ /* no display, if bar graph is less than one character */
+ bar_width = width - MAX_NAME_LEN - MAX_UNIT_LEN;
+ if (bar_width < 1)
+ return;
+
+ lines_total = 0;
+ color = -1;
+ printf("\0337\033[H");
+ for (sender = sender_head; sender; sender = sender->next) {
+ memset(line, ' ', width);
+ memset(line_color, 7, width);
+ sprintf(line, "(chan %d", sender->kanal);
+ *strchr(line, '\0') = ')';
+ display_line(on, width);
+ for (param = sender->dispmeas.head; param; param = param->next) {
+ memset(line, ' ', width);
+ memset(line_color, 7, width);
+ memset(line_color, 3, MAX_NAME_LEN); /* yellow */
+ switch (param->type) {
+ case DISPLAY_MEAS_LAST:
+ value = param->value;
+ param->value = -NAN;
+ break;
+ case DISPLAY_MEAS_PEAK:
+ /* peak value */
+ value = param->value;
+ param->value = -NAN;
+ param->value_count = 0;
+ break;
+ case DISPLAY_MEAS_PEAK2PEAK:
+ /* peak to peak value */
+ value = param->value;
+ value2 = param->value2;
+ param->value = -NAN;
+ param->value2 = -NAN;
+ param->value_count = 0;
+ break;
+ case DISPLAY_MEAS_AVG:
+ /* average value */
+ if (param->value_count)
+ value = param->value / (double)param->value_count;
+ else
+ value = -NAN;
+ param->value = 0.0;
+ param->value_count = 0;
+ break;
+ }
+ /* add current value to history */
+ param->value_history[param->value_history_pos++] = value;
+ param->value2_history[param->value_history_pos++] = value2;
+ param->value_history_pos %= DISPLAY_PARAM_HISTORIES;
+ /* calculate hold values */
+ hold = -NAN;
+ hold2 = -NAN;
+ switch (param->type) {
+ case DISPLAY_MEAS_LAST:
+ /* if we have valid value, we update 'last' */
+ if (!isnan(value)) {
+ param->last = value;
+ hold = value;
+ } else
+ hold = param->last;
+ break;
+ case DISPLAY_MEAS_PEAK:
+ for (i = 0; i < DISPLAY_PARAM_HISTORIES; i++) {
+ if (isnan(param->value_history[i]))
+ continue;
+ if (isnan(hold) || param->value_history[i] > hold)
+ hold = param->value_history[i];
+ }
+ break;
+ case DISPLAY_MEAS_PEAK2PEAK:
+ for (i = 0; i < DISPLAY_PARAM_HISTORIES; i++) {
+ if (isnan(param->value_history[i]))
+ continue;
+ if (isnan(hold) || param->value_history[i] < hold)
+ hold = param->value_history[i];
+ if (isnan(hold2) || param->value2_history[i] > hold2)
+ hold2 = param->value2_history[i];
+ }
+ if (!isnan(hold))
+ hold = hold2 - hold;
+ if (!isnan(value))
+ value = value2 - value;
+ break;
+ case DISPLAY_MEAS_AVG:
+ for (i = 0, j = 0; i < DISPLAY_PARAM_HISTORIES; i++) {
+ if (isnan(param->value_history[i]))
+ continue;
+ if (j == 0)
+ hold = 0.0;
+ hold += param->value_history[i];
+ j++;
+ }
+ if (j)
+ hold /= j;
+ break;
+ }
+ /* "Deviation ::::::::::............ 4.5 KHz" */
+ strncpy(line, param->name, (strlen(param->name) < MAX_NAME_LEN) ? strlen(param->name) : MAX_NAME_LEN);
+ if (isinf(value) || isnan(value)) {
+ bar_left = -1;
+ bar_right = -1;
+ } else if (param->bar == DISPLAY_MEAS_CENTER) {
+ if (value >= 0.0) {
+ bar_left = (-param->min) / (param->max - param->min) * ((double)bar_width - 1.0);
+ bar_right = (value - param->min) / (param->max - param->min) * ((double)bar_width - 1.0);
+ } else {
+ bar_left = (value - param->min) / (param->max - param->min) * ((double)bar_width - 1.0);
+ bar_right = (-param->min) / (param->max - param->min) * ((double)bar_width - 1.0);
+ }
+ } else {
+ bar_left = -1;
+ bar_right = (value - param->min) / (param->max - param->min) * ((double)bar_width - 1.0);
+ }
+ if (isinf(hold) || isnan(hold))
+ bar_hold = -1;
+ else
+ bar_hold = (hold - param->min) / (param->max - param->min) * ((double)bar_width - 1.0);
+ if (isinf(param->mark))
+ bar_mark = -1;
+ else
+ bar_mark = (param->mark - param->min) / (param->max - param->min) * ((double)bar_width - 1.0);
+ for (i = 0; i < bar_width; i++) {
+ line[i + MAX_NAME_LEN] = ':';
+ if (i == bar_hold)
+ line_color[i + MAX_NAME_LEN] = 13;
+ else if (i == bar_mark)
+ line_color[i + MAX_NAME_LEN] = 14;
+ else if (i >= bar_left && i <= bar_right)
+ line_color[i + MAX_NAME_LEN] = 2;
+ else
+ line_color[i + MAX_NAME_LEN] = 4;
+ }
+ sprintf(text, param->format, hold);
+ if (isnan(hold))
+ memset(line_color + width - MAX_UNIT_LEN, 4, MAX_UNIT_LEN); /* blue */
+ else
+ memset(line_color + width - MAX_UNIT_LEN, 3, MAX_UNIT_LEN); /* yellow */
+ strncpy(line + width - MAX_UNIT_LEN + 1, text, (strlen(text) < MAX_UNIT_LEN) ? strlen(text) : MAX_UNIT_LEN);
+ display_line(on, width);
+ }
+ }
+ /* reset color and position */
+ printf("\033[0;39m\0338"); fflush(stdout);
+}
+
+void display_measurements_on(int on)
+{
+ if (measurements_on)
+ print_measurements(0);
+
+ if (on < 0)
+ measurements_on = 1 - measurements_on;
+ else
+ measurements_on = on;
+}
+
+void display_measurements_limit_scroll(int on)
+{
+ int w, h;
+
+ if (!measurements_on)
+ return;
+
+ get_win_size(&w, &h);
+
+ printf("\0337");
+ printf("\033[%d;%dr", (on) ? lines_total + 1 : 1, h);
+ printf("\0338");
+}
+
+/* add new parameter on startup to the list of measurements */
+dispmeasparam_t *display_measurements_add(sender_t *sender, char *name, char *format, enum display_measurements_type type, enum display_measurements_bar bar, double min, double max, double mark)
+{
+ dispmeas_t *disp = &sender->dispmeas;
+ dispmeasparam_t *param, **param_p = &disp->head;
+ int i;
+
+ if (!has_init) {
+ fprintf(stderr, "Not initialized prior adding measurement, please fix!\n");
+ abort();
+ }
+
+ while (*param_p)
+ param_p = &((*param_p)->next);
+ *param_p = calloc(sizeof(dispmeasparam_t), 1);
+ if (!*param_p)
+ return NULL;
+ param = *param_p;
+ strncpy(param->name, name, sizeof(param->name) - 1);
+ strncpy(param->format, format, sizeof(param->format) - 1);
+ param->type = type;
+ param->bar = bar;
+ param->min = min;
+ param->max = max;
+ param->mark = mark;
+ param->value = -NAN;
+ param->value2 = -NAN;
+ param->last = -NAN;
+ for (i = 0; i < DISPLAY_PARAM_HISTORIES; i++)
+ param->value_history[i] = -NAN;
+ param->value_count = 0;
+
+ return param;
+}
+
+void display_measurements_update(dispmeasparam_t *param, double value, double value2)
+{
+ /* special case where we do not have an instance of the parameter */
+ if (!param)
+ return;
+
+ if (!has_init) {
+ fprintf(stderr, "Not initialized prior updating measurement value, please fix!\n");
+ abort();
+ }
+
+ switch (param->type) {
+ case DISPLAY_MEAS_LAST:
+ param->value = value;
+ break;
+ case DISPLAY_MEAS_PEAK:
+ if (isnan(param->value) || value > param->value)
+ param->value = value;
+ break;
+ case DISPLAY_MEAS_PEAK2PEAK:
+ if (param->value_count == 0 || value < param->value)
+ param->value = value;
+ if (param->value_count == 0 || value2 > param->value2)
+ param->value2 = value2;
+ param->value_count++;
+ break;
+ case DISPLAY_MEAS_AVG:
+ param->value += value;
+ param->value_count++;
+ break;
+ default:
+ fprintf(stderr, "Paramer '%s' has unknown type %d, please fix!\n", param->name, param->type);
+ abort();
+ }
+}
+
+void display_measurements(double elapsed)
+{
+ if (!measurements_on)
+ return;
+
+ if (!has_init) {
+ fprintf(stderr, "Not initialized prior display measurement values, please fix!\n");
+ abort();
+ }
+
+ /* count and check if we need to display this time */
+ time_elapsed += elapsed;
+ if (time_elapsed < DISPLAY_INTERVAL)
+ return;
+ time_elapsed = fmod(time_elapsed, DISPLAY_INTERVAL);
+
+ print_measurements(1);
+}
+