diff options
Diffstat (limited to 'src/libdisplay/display_measurements.c')
-rw-r--r-- | src/libdisplay/display_measurements.c | 359 |
1 files changed, 359 insertions, 0 deletions
diff --git a/src/libdisplay/display_measurements.c b/src/libdisplay/display_measurements.c new file mode 100644 index 0000000..eb8618e --- /dev/null +++ b/src/libdisplay/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 "../libsample/sample.h" +#include "../libmobile/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 = 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); +} + |