Restructure: Move display from common code to 'libdisplay'
This commit is contained in:
parent
736a87873f
commit
b26642ad26
|
@ -0,0 +1,19 @@
|
|||
AM_CPPFLAGS = -Wall -Wextra -g $(all_includes)
|
||||
|
||||
noinst_LIBRARIES = libdisplay.a
|
||||
|
||||
libdisplay_a_SOURCES = \
|
||||
display_status.c \
|
||||
display_wave.c \
|
||||
display_measurements.c
|
||||
|
||||
if HAVE_SDR
|
||||
libdisplay_a_SOURCES += \
|
||||
display_iq.c \
|
||||
display_spectrum.c
|
||||
endif
|
||||
|
||||
if HAVE_SDR
|
||||
AM_CPPFLAGS += -DHAVE_SDR
|
||||
endif
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
#define DISPLAY_INTERVAL 0.04 /* time (in seconds) for each interval */
|
||||
#define DISPLAY_PARAM_HISTORIES 25 /* number of intervals (should result in one seconds) */
|
||||
|
||||
#define MAX_DISPLAY_WIDTH 1024
|
||||
|
||||
typedef struct sender sender_t;
|
||||
|
||||
typedef struct display_wave {
|
||||
int interval_pos;
|
||||
int interval_max;
|
||||
int offset;
|
||||
sample_t buffer[MAX_DISPLAY_WIDTH];
|
||||
} dispwav_t;
|
||||
|
||||
enum display_measurements_type {
|
||||
DISPLAY_MEAS_LAST, /* display last value */
|
||||
DISPLAY_MEAS_PEAK, /* display peak value */
|
||||
DISPLAY_MEAS_PEAK2PEAK, /* display peak value of min..max range */
|
||||
DISPLAY_MEAS_AVG, /* display average value */
|
||||
};
|
||||
|
||||
enum display_measurements_bar {
|
||||
DISPLAY_MEAS_LEFT, /* bar graph from left */
|
||||
DISPLAY_MEAS_CENTER, /* bar graph from center */
|
||||
};
|
||||
|
||||
typedef struct display_measurements_param {
|
||||
struct display_measurements_param *next;
|
||||
char name[32]; /* parameter name (e.g. 'Deviation') */
|
||||
char format[32]; /* unit name (e.g. "%.2f KHz") */
|
||||
enum display_measurements_type type;
|
||||
enum display_measurements_bar bar;
|
||||
double min; /* minimum value */
|
||||
double max; /* maximum value */
|
||||
double mark; /* mark (target) value */
|
||||
double value; /* current value (peak, sum...) */
|
||||
double value2; /* max value for min..max range */
|
||||
double last; /* last valid value (used for DISPLAY_MEAS_LAST) */
|
||||
int value_count; /* count number of values of one interval */
|
||||
double value_history[DISPLAY_PARAM_HISTORIES]; /* history of values of last second */
|
||||
double value2_history[DISPLAY_PARAM_HISTORIES]; /* stores max for min..max range */
|
||||
int value_history_pos; /* next history value to write */
|
||||
} dispmeasparam_t;
|
||||
|
||||
typedef struct display_measurements {
|
||||
dispmeasparam_t *head;
|
||||
} dispmeas_t;
|
||||
|
||||
#define MAX_DISPLAY_IQ 1024
|
||||
|
||||
typedef struct display_iq {
|
||||
int interval_pos;
|
||||
int interval_max;
|
||||
float buffer[MAX_DISPLAY_IQ * 2];
|
||||
} dispiq_t;
|
||||
|
||||
#define MAX_DISPLAY_SPECTRUM 1024
|
||||
|
||||
typedef struct display_spectrum {
|
||||
int interval_pos;
|
||||
int interval_max;
|
||||
double buffer_I[MAX_DISPLAY_SPECTRUM];
|
||||
double buffer_Q[MAX_DISPLAY_SPECTRUM];
|
||||
} dispspectrum_t;
|
||||
|
||||
#define MAX_HEIGHT_STATUS 32
|
||||
|
||||
void get_win_size(int *w, int *h);
|
||||
|
||||
void display_wave_init(sender_t *sender, int samplerate);
|
||||
void display_wave_on(int on);
|
||||
void display_wave_limit_scroll(int on);
|
||||
void display_wave(sender_t *sender, sample_t *samples, int length, double range);
|
||||
|
||||
void display_status_on(int on);
|
||||
void display_status_limit_scroll(int on);
|
||||
void display_status_start(void);
|
||||
void display_status_channel(int channel, const char *type, const char *state);
|
||||
void display_status_subscriber(const char *number, const char *state);
|
||||
void display_status_end(void);
|
||||
|
||||
void display_measurements_init(sender_t *sender, int samplerate);
|
||||
void display_measurements_exit(sender_t *sender);
|
||||
void display_measurements_on(int on);
|
||||
void display_measurements_limit_scroll(int on);
|
||||
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);
|
||||
void display_measurements_update(dispmeasparam_t *param, double value, double value2);
|
||||
void display_measurements(double elapsed);
|
||||
|
||||
void display_iq_init(int samplerate);
|
||||
void display_iq_on(int on);
|
||||
void display_iq_limit_scroll(int on);
|
||||
void display_iq(float *samples, int length);
|
||||
|
||||
void display_spectrum_init(int samplerate, double center_frequency);
|
||||
void display_spectrum_on(int on);
|
||||
void display_spectrum_limit_scroll(int on);
|
||||
void display_spectrum(float *samples, int length);
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -23,7 +23,7 @@
|
|||
#include <pthread.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include "../libsample/sample.h"
|
||||
#include "sender.h"
|
||||
#include "../libmobile/sender.h"
|
||||
|
||||
static int status_on = 0;
|
||||
static int line_count = 0;
|
|
@ -0,0 +1,270 @@
|
|||
/* display wave form functions
|
||||
*
|
||||
* (C) 2016 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 <pthread.h>
|
||||
#include <math.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include "../libsample/sample.h"
|
||||
#include "../libmobile/sender.h"
|
||||
|
||||
#define HEIGHT 11
|
||||
|
||||
static int num_sender = 0;
|
||||
static char screen[HEIGHT][MAX_DISPLAY_WIDTH];
|
||||
static int wave_on = 0;
|
||||
|
||||
void get_win_size(int *w, int *h)
|
||||
{
|
||||
struct winsize win;
|
||||
int rc;
|
||||
|
||||
rc = ioctl(0, TIOCGWINSZ, &win);
|
||||
if (rc) {
|
||||
*w = 80;
|
||||
*h = 25;
|
||||
return;
|
||||
}
|
||||
|
||||
*h = win.ws_row;
|
||||
*w = win.ws_col;
|
||||
if (*w > MAX_DISPLAY_WIDTH - 1)
|
||||
*w = MAX_DISPLAY_WIDTH - 1;
|
||||
}
|
||||
|
||||
void display_wave_init(sender_t *sender, int samplerate)
|
||||
{
|
||||
dispwav_t *disp = &sender->dispwav;
|
||||
|
||||
memset(disp, 0, sizeof(*disp));
|
||||
disp->offset = (num_sender++) * HEIGHT;
|
||||
disp->interval_max = (double)samplerate * DISPLAY_INTERVAL + 0.5;
|
||||
}
|
||||
|
||||
void display_wave_on(int on)
|
||||
{
|
||||
int i, j;
|
||||
int w, h;
|
||||
|
||||
get_win_size(&w, &h);
|
||||
|
||||
if (wave_on) {
|
||||
memset(&screen, ' ', sizeof(screen));
|
||||
printf("\0337\033[H");
|
||||
for (i = 0; i < num_sender; i++) {
|
||||
for (j = 0; j < HEIGHT; j++) {
|
||||
screen[j][w] = '\0';
|
||||
puts(screen[j]);
|
||||
}
|
||||
}
|
||||
printf("\0338"); fflush(stdout);
|
||||
}
|
||||
|
||||
if (on < 0)
|
||||
wave_on = 1 - wave_on;
|
||||
else
|
||||
wave_on = on;
|
||||
}
|
||||
|
||||
void display_wave_limit_scroll(int on)
|
||||
{
|
||||
int w, h;
|
||||
|
||||
if (!wave_on)
|
||||
return;
|
||||
|
||||
get_win_size(&w, &h);
|
||||
|
||||
printf("\0337");
|
||||
printf("\033[%d;%dr", (on) ? num_sender * HEIGHT + 1 : 1, h);
|
||||
printf("\0338");
|
||||
}
|
||||
|
||||
/*
|
||||
* draw wave form:
|
||||
*
|
||||
* theoretical example: HEIGHT = 3 allows 5 steps
|
||||
*
|
||||
* Line 0: '.
|
||||
* Line 1: '.
|
||||
* Line 2: '
|
||||
*
|
||||
* HEIGHT is odd, so the center line's char is ''' (otherwise '.')
|
||||
* (HEIGHT - 1) / 2 = 1, so the center line is drawn in line 1
|
||||
*
|
||||
* y is in range of 0..4, so these are 5 steps, where 2 is the
|
||||
* center line. this is calculated by (HEIGHT * 2 - 1)
|
||||
*/
|
||||
void display_wave(sender_t *sender, sample_t *samples, int length, double range)
|
||||
{
|
||||
dispwav_t *disp = &sender->dispwav;
|
||||
int pos, max;
|
||||
sample_t *buffer;
|
||||
int i, j, k, s, e;
|
||||
double last, current, next;
|
||||
int color = 9; /* default color */
|
||||
int center_line;
|
||||
char center_char;
|
||||
int width, h;
|
||||
|
||||
if (!wave_on)
|
||||
return;
|
||||
|
||||
get_win_size(&width, &h);
|
||||
|
||||
/* at what line we draw our zero-line and what character we use */
|
||||
center_line = (HEIGHT - 1) >> 1;
|
||||
center_char = (HEIGHT & 1) ? '\'' : '.';
|
||||
|
||||
pos = disp->interval_pos;
|
||||
max = disp->interval_max;
|
||||
buffer = disp->buffer;
|
||||
|
||||
for (i = 0; i < length; i++) {
|
||||
if (pos >= width + 2) {
|
||||
if (++pos == max)
|
||||
pos = 0;
|
||||
continue;
|
||||
}
|
||||
buffer[pos++] = samples[i];
|
||||
if (pos == width + 2) {
|
||||
memset(&screen, ' ', sizeof(screen));
|
||||
for (j = 0; j < width; j++) {
|
||||
/* Input value is scaled to range -1 .. 1 and then substracted from 1,
|
||||
* so the result ranges from 0 .. 2.
|
||||
* HEIGHT-1 is multiplied with the range, so a HEIGHT of 3 would allow
|
||||
* 0..4 (5 steps) and a HEIGHT of 11 would allow 0..20 (21 steps).
|
||||
* We always use odd number of steps, so there will be a center between
|
||||
* values.
|
||||
*/
|
||||
last = (1.0 - buffer[j] / range) * (double)(HEIGHT - 1);
|
||||
current = (1.0 - buffer[j + 1] / range) * (double)(HEIGHT - 1);
|
||||
next = (1.0 - buffer[j + 2] / range) * (double)(HEIGHT - 1);
|
||||
/* calculate start and end for vertical line
|
||||
* if the current value is a peak (above or below last AND next point),
|
||||
* round this peak point to become one end of the vertical line.
|
||||
* the other end is rounded up or down, so the end of the line will
|
||||
* not overlap with the ends of the surrounding lines.
|
||||
*/
|
||||
if (last > current) {
|
||||
if (next > current) {
|
||||
/* current point is a peak up */
|
||||
s = round(current);
|
||||
/* use lowest neighbor point and end is half way */
|
||||
if (last > next)
|
||||
e = floor((last + current) / 2.0);
|
||||
else
|
||||
e = floor((next + current) / 2.0);
|
||||
/* end point must not be above start point */
|
||||
if (e < s)
|
||||
e = s;
|
||||
} else {
|
||||
/* current point is a transition upwards */
|
||||
s = ceil((next + current) / 2.0);
|
||||
e = floor((last + current) / 2.0);
|
||||
/* end point must not be above start point */
|
||||
if (e < s)
|
||||
s = e = round(current);
|
||||
}
|
||||
} else {
|
||||
if (next <= current) {
|
||||
/* current point is a peak down */
|
||||
e = round(current);
|
||||
/* use heighes neighbor point and start is half way */
|
||||
if (last <= next)
|
||||
s = ceil((last + current) / 2.0);
|
||||
else
|
||||
s = ceil((next + current) / 2.0);
|
||||
/* start point must not be below end point */
|
||||
if (s > e)
|
||||
s = e;
|
||||
} else {
|
||||
/* current point is a transition downwards */
|
||||
s = ceil((last + current) / 2.0);
|
||||
e = floor((next + current) / 2.0);
|
||||
/* start point must not be below end point */
|
||||
if (s > e)
|
||||
s = e = round(current);
|
||||
}
|
||||
}
|
||||
/* only draw line, if it is in range */
|
||||
if (e >= 0 && s < HEIGHT * 2 - 1) {
|
||||
/* clip */
|
||||
if (s < 0)
|
||||
s = 0;
|
||||
if (e >= HEIGHT * 2 - 1)
|
||||
e = HEIGHT * 2 - 1;
|
||||
/* plot start and end point */
|
||||
if ((s & 1))
|
||||
screen[s >> 1][j] = '.';
|
||||
else if (e != s)
|
||||
screen[s >> 1][j] = '|';
|
||||
if (!(e & 1))
|
||||
screen[e >> 1][j] = '\'';
|
||||
else if (e != s)
|
||||
screen[e >> 1][j] = '|';
|
||||
/* plot line between start and end point */
|
||||
for (k = (s >> 1) + 1; k < (e >> 1); k++)
|
||||
screen[k][j] = '|';
|
||||
}
|
||||
}
|
||||
sprintf(screen[0], "(chan %d", sender->kanal);
|
||||
*strchr(screen[0], '\0') = ')';
|
||||
printf("\0337\033[H");
|
||||
for (j = 0; j < disp->offset; j++)
|
||||
puts("");
|
||||
for (j = 0; j < HEIGHT; j++) {
|
||||
for (k = 0; k < width; k++) {
|
||||
if (j == center_line && screen[j][k] == ' ') {
|
||||
/* blue 0-line */
|
||||
if (color != 4) {
|
||||
color = 4;
|
||||
printf("\033[0;34m");
|
||||
}
|
||||
putchar(center_char);
|
||||
} else if (screen[j][k] == '\'' || screen[j][k] == '.' || screen[j][k] == '|') {
|
||||
/* green scope curve */
|
||||
if (color != 2) {
|
||||
color = 2;
|
||||
printf("\033[1;32m");
|
||||
}
|
||||
putchar(screen[j][k]);
|
||||
} else if (screen[j][k] != ' ') {
|
||||
/* white other characters */
|
||||
if (color != 7) {
|
||||
color = 7;
|
||||
printf("\033[1;37m");
|
||||
}
|
||||
putchar(screen[j][k]);
|
||||
} else
|
||||
putchar(screen[j][k]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
/* reset color and position */
|
||||
printf("\033[0;39m\0338"); fflush(stdout);
|
||||
}
|
||||
}
|
||||
|
||||
disp->interval_pos = pos;
|
||||
}
|
||||
|
||||
|
|
@ -5,7 +5,6 @@ noinst_LIBRARIES = libmobile.a
|
|||
libmobile_a_SOURCES = \
|
||||
sender.c \
|
||||
call.c \
|
||||
display_status.c \
|
||||
main_mobile.c
|
||||
|
||||
if HAVE_SDR
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
#include "../libsamplerate/samplerate.h"
|
||||
#include "../libjitter/jitter.h"
|
||||
#include "../libemphasis/emphasis.h"
|
||||
#include "../common/display.h"
|
||||
#include "../libdisplay/display.h"
|
||||
|
||||
#define MAX_SENDER 16
|
||||
|
||||
|
|
|
@ -3,10 +3,8 @@ AM_CPPFLAGS = -Wall -Wextra -g $(all_includes)
|
|||
noinst_LIBRARIES = libsdr.a
|
||||
|
||||
libsdr_a_SOURCES = \
|
||||
dd sdr_config.c \
|
||||
sdr.c \
|
||||
display_iq.c \
|
||||
display_spectrum.c
|
||||
sdr_config.c \
|
||||
sdr.c
|
||||
|
||||
AM_CPPFLAGS += -DHAVE_SDR
|
||||
|
||||
|
|
Loading…
Reference in New Issue