/* display measurements functions * * (C) 2017 by Andreas Eversberg * 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 . */ #include #include #include #include #include #include #include #include "../libsample/sample.h" #include "../libdebug/debug.h" #include "../libdisplay/display.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]; dispmeas_t *meas_head = NULL; void display_measurements_init(dispmeas_t *disp, int __attribute__((unused)) samplerate, int kanal) { dispmeas_t **disp_p; memset(disp, 0, sizeof(*disp)); disp->kanal = kanal; has_init = 1; lines_total = 0; time_elapsed = 0.0; disp_p = &meas_head; while (*disp_p) disp_p = &((*disp_p)->next); *disp_p = disp; } void display_measurements_exit(dispmeas_t *disp) { dispmeasparam_t *param = disp->param, *temp; while (param) { temp = param; param = param->next; free(temp); } disp->param = 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) { dispmeas_t *disp; 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 (disp = meas_head; disp; disp = disp->next) { memset(line, ' ', width); memset(line_color, 7, width); sprintf(line, "(chan %d", disp->kanal); *strchr(line, '\0') = ')'; display_line(on, width); for (param = disp->param; 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" */ memcpy(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); debug_limit_scroll = lines_total; } void display_measurements_on(int on) { if (measurements_on) print_measurements(0); if (on < 0) measurements_on = 1 - measurements_on; else measurements_on = on; debug_limit_scroll = 0; } /* add new parameter on startup to the list of measurements */ dispmeasparam_t *display_measurements_add(dispmeas_t *disp, char *name, char *format, enum display_measurements_type type, enum display_measurements_bar bar, double min, double max, double mark) { dispmeasparam_t *param, **param_p = &disp->param; 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_MEAS_INTERVAL) return; time_elapsed = fmod(time_elapsed, DISPLAY_MEAS_INTERVAL); print_measurements(1); }