Restructure: Move display from common code to 'libdisplay'
This commit is contained in:
@@ -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
|
||||
|
||||
|
@@ -1,280 +0,0 @@
|
||||
/* display IQ data 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 <math.h>
|
||||
#include <pthread.h>
|
||||
#include <stdlib.h>
|
||||
#include "../libsample/sample.h"
|
||||
#include "../libmobile/sender.h"
|
||||
|
||||
/* must be odd value! */
|
||||
#define SIZE 23
|
||||
|
||||
static char screen[SIZE][MAX_DISPLAY_WIDTH];
|
||||
static uint8_t screen_color[SIZE][MAX_DISPLAY_WIDTH];
|
||||
static uint8_t screen_history[SIZE * 2][MAX_DISPLAY_WIDTH];
|
||||
static int iq_on = 0;
|
||||
static double db = 80;
|
||||
|
||||
static dispiq_t disp;
|
||||
|
||||
void display_iq_init(int samplerate)
|
||||
{
|
||||
memset(&disp, 0, sizeof(disp));
|
||||
memset(&screen_history, 0, sizeof(screen_history));
|
||||
disp.interval_max = (double)samplerate * DISPLAY_INTERVAL + 0.5;
|
||||
/* should not happen due to low interval */
|
||||
if (disp.interval_max < MAX_DISPLAY_IQ - 1)
|
||||
disp.interval_max = MAX_DISPLAY_IQ - 1;
|
||||
}
|
||||
|
||||
void display_iq_on(int on)
|
||||
{
|
||||
int j;
|
||||
int w, h;
|
||||
|
||||
get_win_size(&w, &h);
|
||||
|
||||
if (iq_on) {
|
||||
memset(&screen, ' ', sizeof(screen));
|
||||
memset(&screen_history, 0, sizeof(screen_history));
|
||||
printf("\0337\033[H");
|
||||
for (j = 0; j < SIZE; j++) {
|
||||
screen[j][w] = '\0';
|
||||
puts(screen[j]);
|
||||
}
|
||||
printf("\0338"); fflush(stdout);
|
||||
}
|
||||
|
||||
if (on < 0) {
|
||||
if (++iq_on == 3)
|
||||
iq_on = 0;
|
||||
} else
|
||||
iq_on = on;
|
||||
}
|
||||
|
||||
void display_iq_limit_scroll(int on)
|
||||
{
|
||||
int w, h;
|
||||
|
||||
if (!iq_on)
|
||||
return;
|
||||
|
||||
get_win_size(&w, &h);
|
||||
|
||||
printf("\0337");
|
||||
printf("\033[%d;%dr", (on) ? SIZE + 1 : 1, h);
|
||||
printf("\0338");
|
||||
}
|
||||
|
||||
/*
|
||||
* plot IQ data:
|
||||
*
|
||||
* theoretical example: SIZE = 3 allows 6 steps plotted as dots
|
||||
*
|
||||
* Line 0: :
|
||||
* Line 1: :
|
||||
* Line 2: :
|
||||
*
|
||||
* The level of -1.0 .. 1.0 is scaled to -3 and 3.
|
||||
*
|
||||
* The lowest of the upper 3 dots ranges from 0.0 .. <1.5.
|
||||
* The upper most dot ranges from 2.5 .. <3.5.
|
||||
* The highest of the lower 3 dots ranges from <0.0 .. >-1.5;
|
||||
* The lower most dot ranges from -2.5 .. >-3.5.
|
||||
*
|
||||
* The center column ranges from -0.5 .. <0.5.
|
||||
* The columns about the center from -1.5 .. <1.5.
|
||||
*/
|
||||
void display_iq(float *samples, int length)
|
||||
{
|
||||
int pos, max;
|
||||
float *buffer;
|
||||
int i, j, k;
|
||||
int color = 9; /* default color */
|
||||
int x_center, y_center;
|
||||
double I, Q, L, l, s;
|
||||
int x, y;
|
||||
int v, r;
|
||||
int width, h;
|
||||
|
||||
if (!iq_on)
|
||||
return;
|
||||
|
||||
get_win_size(&width, &h);
|
||||
|
||||
/* at what line we draw our zero-line and what character we use */
|
||||
x_center = width >> 1;
|
||||
y_center = (SIZE - 1) >> 1;
|
||||
|
||||
pos = disp.interval_pos;
|
||||
max = disp.interval_max;
|
||||
buffer = disp.buffer;
|
||||
|
||||
for (i = 0; i < length; i++) {
|
||||
if (pos >= MAX_DISPLAY_IQ) {
|
||||
if (++pos == max)
|
||||
pos = 0;
|
||||
continue;
|
||||
}
|
||||
buffer[pos * 2] = samples[i * 2];
|
||||
buffer[pos * 2 + 1] = samples[i * 2 + 1];
|
||||
pos++;
|
||||
if (pos == MAX_DISPLAY_IQ) {
|
||||
memset(&screen, ' ', sizeof(screen));
|
||||
memset(&screen_color, 7, sizeof(screen_color));
|
||||
/* render screen history to screen */
|
||||
for (y = 0; y < SIZE * 2; y++) {
|
||||
for (x = 0; x < width; x++) {
|
||||
v = screen_history[y][x];
|
||||
v -= 8;
|
||||
if (v < 0)
|
||||
v = 0;
|
||||
screen_history[y][x] = v;
|
||||
r = random() & 0x3f;
|
||||
if (r >= v)
|
||||
continue;
|
||||
if (screen[y/2][x] == ':')
|
||||
continue;
|
||||
if (screen[y/2][x] == '.') {
|
||||
if ((y & 1) == 0)
|
||||
screen[y/2][x] = ':';
|
||||
continue;
|
||||
}
|
||||
if (screen[y/2][x] == '\'') {
|
||||
if ((y & 1))
|
||||
screen[y/2][x] = ':';
|
||||
continue;
|
||||
}
|
||||
if ((y & 1) == 0)
|
||||
screen[y/2][x] = '\'';
|
||||
else
|
||||
screen[y/2][x] = '.';
|
||||
screen_color[y/2][x] = 4;
|
||||
}
|
||||
}
|
||||
/* plot current IQ date */
|
||||
for (j = 0; j < MAX_DISPLAY_IQ; j++) {
|
||||
I = buffer[j * 2];
|
||||
Q = buffer[j * 2 + 1];
|
||||
L = I*I + Q*Q;
|
||||
if (iq_on > 1) {
|
||||
/* logarithmic scale */
|
||||
l = sqrt(L);
|
||||
s = log10(l) * 20 + db;
|
||||
if (s < 0)
|
||||
s = 0;
|
||||
I = (I / l) * (s / db);
|
||||
Q = (Q / l) * (s / db);
|
||||
}
|
||||
x = x_center + (int)(I * (double)SIZE + (double)width + 0.5) - width;
|
||||
if (x < 0)
|
||||
continue;
|
||||
if (x > width - 1)
|
||||
continue;
|
||||
if (Q >= 0)
|
||||
y = SIZE - 1 - (int)(Q * (double)SIZE - 0.5);
|
||||
else
|
||||
y = SIZE - (int)(Q * (double)SIZE + 0.5);
|
||||
if (y < 0)
|
||||
continue;
|
||||
if (y > SIZE * 2 - 1)
|
||||
continue;
|
||||
if (screen[y/2][x] == ':' && screen_color[y/2][x] >= 10)
|
||||
goto cont;
|
||||
if (screen[y/2][x] == '.' && screen_color[y/2][x] >= 10) {
|
||||
if ((y & 1) == 0)
|
||||
screen[y/2][x] = ':';
|
||||
goto cont;
|
||||
}
|
||||
if (screen[y/2][x] == '\'' && screen_color[y/2][x] >= 10) {
|
||||
if ((y & 1))
|
||||
screen[y/2][x] = ':';
|
||||
goto cont;
|
||||
}
|
||||
if ((y & 1) == 0)
|
||||
screen[y/2][x] = '\'';
|
||||
else
|
||||
screen[y/2][x] = '.';
|
||||
cont:
|
||||
screen_history[y][x] = 255;
|
||||
/* overdrive:
|
||||
* red = close to -1..1 or above
|
||||
* yellow = close to -0.5..0.5 or above
|
||||
* Note: L is square of vector length,
|
||||
* so we compare with square values.
|
||||
*/
|
||||
if (L > 0.9 * 0.9)
|
||||
screen_color[y/2][x] = 11;
|
||||
else if (L > 0.45 * 0.45 && screen_color[y/2][x] != 11)
|
||||
screen_color[y/2][x] = 13;
|
||||
else if (screen_color[y/2][x] < 10)
|
||||
screen_color[y/2][x] = 12;
|
||||
}
|
||||
if (iq_on == 1)
|
||||
sprintf(screen[0], "(IQ linear");
|
||||
else
|
||||
sprintf(screen[0], "(IQ log %.0f dB", db);
|
||||
*strchr(screen[0], '\0') = ')';
|
||||
printf("\0337\033[H");
|
||||
for (j = 0; j < SIZE; j++) {
|
||||
for (k = 0; k < width; k++) {
|
||||
if ((j == y_center || k == x_center) && screen[j][k] == ' ') {
|
||||
/* cross */
|
||||
if (color != 4) {
|
||||
color = 4;
|
||||
printf("\033[0;34m");
|
||||
}
|
||||
if (j == y_center) {
|
||||
if (k == x_center)
|
||||
putchar('o');
|
||||
else if (k == x_center - SIZE)
|
||||
putchar('+');
|
||||
else if (k == x_center + SIZE)
|
||||
putchar('+');
|
||||
else
|
||||
putchar('-');
|
||||
} else {
|
||||
if (j == 0 || j == SIZE - 1)
|
||||
putchar('+');
|
||||
else
|
||||
putchar('|');
|
||||
}
|
||||
} else {
|
||||
if (screen_color[j][k] != color) {
|
||||
color = screen_color[j][k];
|
||||
printf("\033[%d;3%dm", color / 10, color % 10);
|
||||
}
|
||||
putchar(screen[j][k]);
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
/* reset color and position */
|
||||
printf("\033[0;39m\0338"); fflush(stdout);
|
||||
}
|
||||
}
|
||||
|
||||
disp.interval_pos = pos;
|
||||
}
|
||||
|
||||
|
@@ -1,292 +0,0 @@
|
||||
/* display spectrum of IQ data
|
||||
*
|
||||
* (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 <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include "../libsample/sample.h"
|
||||
#include "../libmobile/sender.h"
|
||||
#include "../libfft/fft.h"
|
||||
|
||||
#define HEIGHT 20
|
||||
|
||||
static double buffer_max[MAX_DISPLAY_SPECTRUM];
|
||||
static char screen[HEIGHT][MAX_DISPLAY_WIDTH];
|
||||
static uint8_t screen_color[HEIGHT][MAX_DISPLAY_WIDTH];
|
||||
static int spectrum_on = 0;
|
||||
static double db = 120;
|
||||
static double center_frequency, frequency_range;
|
||||
|
||||
static dispspectrum_t disp;
|
||||
|
||||
void display_spectrum_init(int samplerate, double _center_frequency)
|
||||
{
|
||||
memset(&disp, 0, sizeof(disp));
|
||||
disp.interval_max = (double)samplerate * DISPLAY_INTERVAL + 0.5;
|
||||
/* should not happen due to low interval */
|
||||
if (disp.interval_max < MAX_DISPLAY_SPECTRUM - 1)
|
||||
disp.interval_max = MAX_DISPLAY_SPECTRUM - 1;
|
||||
memset(buffer_max, 0, sizeof(buffer_max));
|
||||
|
||||
center_frequency = _center_frequency;
|
||||
frequency_range = (double)samplerate;
|
||||
}
|
||||
|
||||
void display_spectrum_on(int on)
|
||||
{
|
||||
int j;
|
||||
int w, h;
|
||||
|
||||
get_win_size(&w, &h);
|
||||
|
||||
if (spectrum_on) {
|
||||
memset(&screen, ' ', sizeof(screen));
|
||||
printf("\0337\033[H");
|
||||
for (j = 0; j < HEIGHT; j++) {
|
||||
screen[j][w] = '\0';
|
||||
puts(screen[j]);
|
||||
}
|
||||
printf("\0338"); fflush(stdout);
|
||||
}
|
||||
|
||||
if (on < 0) {
|
||||
if (++spectrum_on == 2)
|
||||
spectrum_on = 0;
|
||||
} else
|
||||
spectrum_on = on;
|
||||
}
|
||||
|
||||
void display_spectrum_limit_scroll(int on)
|
||||
{
|
||||
int w, h;
|
||||
|
||||
if (!spectrum_on)
|
||||
return;
|
||||
|
||||
get_win_size(&w, &h);
|
||||
|
||||
printf("\0337");
|
||||
printf("\033[%d;%dr", (on) ? HEIGHT + 1 : 1, h);
|
||||
printf("\0338");
|
||||
}
|
||||
|
||||
/*
|
||||
* plot spectrum data:
|
||||
*
|
||||
*/
|
||||
void display_spectrum(float *samples, int length)
|
||||
{
|
||||
sender_t *sender;
|
||||
char print_channel[32], print_frequency[32];
|
||||
int width, h;
|
||||
int pos, max;
|
||||
double *buffer_I, *buffer_Q;
|
||||
int color = 9; /* default color */
|
||||
int i, j, k, o;
|
||||
double I, Q, v;
|
||||
int s, e, l, n;
|
||||
|
||||
if (!spectrum_on)
|
||||
return;
|
||||
|
||||
get_win_size(&width, &h);
|
||||
if (width > MAX_DISPLAY_WIDTH)
|
||||
width = MAX_DISPLAY_WIDTH;
|
||||
|
||||
/* calculate size of FFT */
|
||||
int m, fft_size = 0, fft_taps = 0;
|
||||
for (m = 0; m < 16; m++) {
|
||||
if ((1 << m) > MAX_DISPLAY_SPECTRUM)
|
||||
break;
|
||||
if ((1 << m) <= width) {
|
||||
fft_taps = m;
|
||||
fft_size = 1 << m;
|
||||
}
|
||||
}
|
||||
if (m == 16) {
|
||||
fprintf(stderr, "Size of spectrum is not a power of 2, please fix!\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
int heigh[fft_size], low[fft_size];
|
||||
|
||||
pos = disp.interval_pos;
|
||||
max = disp.interval_max;
|
||||
buffer_I = disp.buffer_I;
|
||||
buffer_Q = disp.buffer_Q;
|
||||
|
||||
for (i = 0; i < length; i++) {
|
||||
if (pos >= fft_size) {
|
||||
if (++pos == max)
|
||||
pos = 0;
|
||||
continue;
|
||||
}
|
||||
buffer_I[pos] = samples[i * 2];
|
||||
buffer_Q[pos] = samples[i * 2 + 1];
|
||||
pos++;
|
||||
if (pos == fft_size) {
|
||||
fft_process(1, fft_taps, buffer_I, buffer_Q);
|
||||
k = 0;
|
||||
for (j = 0; j < fft_size; j++) {
|
||||
/* scale result vertically */
|
||||
I = buffer_I[(j + fft_size / 2) % fft_size];
|
||||
Q = buffer_Q[(j + fft_size / 2) % fft_size];
|
||||
v = sqrt(I*I + Q*Q);
|
||||
v = log10(v) * 20 + db;
|
||||
if (v < 0)
|
||||
v = 0;
|
||||
v /= db;
|
||||
buffer_max[j] -= DISPLAY_INTERVAL / 10.0;
|
||||
if (v > buffer_max[j])
|
||||
buffer_max[j] = v;
|
||||
|
||||
/* heigh is the maximum value */
|
||||
heigh[j] = (double)(HEIGHT * 2 - 1) * (1.0 - buffer_max[j]);
|
||||
if (heigh[j] < 0)
|
||||
heigh[j] = 0;
|
||||
if (heigh[j] >= (HEIGHT * 2))
|
||||
heigh[j] = (HEIGHT * 2) - 1;
|
||||
/* low is the current value */
|
||||
low[j] = (double)(HEIGHT * 2 - 1) * (1.0 - v);
|
||||
if (low[j] < 0)
|
||||
low[j] = 0;
|
||||
if (low[j] >= (HEIGHT * 2))
|
||||
low[j] = (HEIGHT * 2) - 1;
|
||||
}
|
||||
/* plot scaled buffer */
|
||||
memset(&screen, ' ', sizeof(screen));
|
||||
memset(&screen_color, 7, sizeof(screen_color)); /* all white */
|
||||
sprintf(screen[0], "(spectrum log %.0f dB", db);
|
||||
*strchr(screen[0], '\0') = ')';
|
||||
o = (width - fft_size) / 2; /* offset from left border */
|
||||
for (j = 0; j < fft_size; j++) {
|
||||
s = l = n = low[j];
|
||||
/* get last and next value */
|
||||
if (j > 0)
|
||||
l = (low[j - 1] + s) / 2;
|
||||
if (j < fft_size - 1)
|
||||
n = (low[j + 1] + s) / 2;
|
||||
if (s > l && s > n) {
|
||||
/* current value is a minimum */
|
||||
e = s;
|
||||
s = (l < n) ? (l + 1) : (n + 1);
|
||||
} else if (s < l && s < n) {
|
||||
/* current value is a maximum */
|
||||
e = (l > n) ? l : n;
|
||||
} else if (l < n) {
|
||||
/* last value is higher, next value is lower */
|
||||
s = l + 1;
|
||||
e = n;
|
||||
} else if (l > n) {
|
||||
/* last value is lower, next value is higher */
|
||||
s = n + 1;
|
||||
e = l;
|
||||
} else {
|
||||
/* current, last and next values are equal */
|
||||
e = s;
|
||||
}
|
||||
if (s == e) {
|
||||
if ((s & 1) == 0)
|
||||
screen[s >> 1][j + o] = '\'';
|
||||
else
|
||||
screen[s >> 1][j + o] = '.';
|
||||
screen_color[s >> 1][j + o] = 13;
|
||||
} else {
|
||||
if ((s & 1) == 0)
|
||||
screen[s >> 1][j + o] = '|';
|
||||
else
|
||||
screen[s >> 1][j + o] = '.';
|
||||
screen_color[s >> 1][j + o] = 13;
|
||||
if ((e & 1) == 0)
|
||||
screen[e >> 1][j + o] = '\'';
|
||||
else
|
||||
screen[e >> 1][j + o] = '|';
|
||||
screen_color[e >> 1][j + o] = 13;
|
||||
for (k = (s >> 1) + 1; k < (e >> 1); k++) {
|
||||
screen[k][j + o] = '|';
|
||||
screen_color[k][j + o] = 13;
|
||||
}
|
||||
}
|
||||
e = s;
|
||||
s = heigh[j];
|
||||
if ((s >> 1) < (e >> 1)) {
|
||||
if ((s & 1) == 0)
|
||||
screen[s >> 1][j + o] = '|';
|
||||
else
|
||||
screen[s >> 1][j + o] = '.';
|
||||
screen_color[s >> 1][j + o] = 4;
|
||||
for (k = (s >> 1) + 1; k < (e >> 1); k++) {
|
||||
screen[k][j + o] = '|';
|
||||
screen_color[k][j + o] = 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (sender = sender_head; sender; sender = sender->next) {
|
||||
j = (int)((sender->empfangsfrequenz - center_frequency) / frequency_range * (double) fft_size + width / 2 + 0.5);
|
||||
if (j < 0 || j >= width) /* check out-of-range, should not happen */
|
||||
continue;
|
||||
for (k = 0; k < HEIGHT; k++) {
|
||||
/* skip yellow graph */
|
||||
if (screen_color[k][j] == 13)
|
||||
continue;
|
||||
screen[k][j] = ':';
|
||||
screen_color[k][j] = 12;
|
||||
}
|
||||
sprintf(print_channel, "Ch%d", sender->kanal);
|
||||
for (o = 0; o < (int)strlen(print_channel); o++) {
|
||||
s = j - strlen(print_channel) + o;
|
||||
if (s >= 0 && s < width) {
|
||||
screen[HEIGHT - 1][s] = print_channel[o];
|
||||
screen_color[HEIGHT - 1][s] = 7;
|
||||
}
|
||||
}
|
||||
if (fmod(sender->empfangsfrequenz, 1000.0))
|
||||
sprintf(print_frequency, "%.4f", sender->empfangsfrequenz / 1e6);
|
||||
else
|
||||
sprintf(print_frequency, "%.3f", sender->empfangsfrequenz / 1e6);
|
||||
for (o = 0; o < (int)strlen(print_frequency); o++) {
|
||||
s = j + o + 1;
|
||||
if (s >= 0 && s < width) {
|
||||
screen[HEIGHT - 1][s] = print_frequency[o];
|
||||
screen_color[HEIGHT - 1][s] = 7;
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("\0337\033[H");
|
||||
for (j = 0; j < HEIGHT; j++) {
|
||||
for (k = 0; k < width; k++) {
|
||||
if (screen_color[j][k] != color) {
|
||||
color = screen_color[j][k];
|
||||
printf("\033[%d;3%dm", color / 10, color % 10);
|
||||
}
|
||||
putchar(screen[j][k]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
/* reset color and position */
|
||||
printf("\033[0;39m\0338"); fflush(stdout);
|
||||
}
|
||||
}
|
||||
|
||||
disp.interval_pos = pos;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user