diff options
author | Andreas Eversberg <jolly@eversberg.eu> | 2017-11-17 22:51:18 +0100 |
---|---|---|
committer | Andreas Eversberg <jolly@eversberg.eu> | 2017-12-03 08:45:45 +0100 |
commit | 1650cc5ad2eba4fb8857ffc920170ae0f9f1a18d (patch) | |
tree | 8af7057e2205de7548c70998c46e5ede8eabbad4 /src/common | |
parent | 45a5568f7032b11953d6ac4321970d5780eaf613 (diff) |
Restructure: Move sdr from common code to 'libsdr'
Diffstat (limited to 'src/common')
-rw-r--r-- | src/common/Makefile.am | 22 | ||||
-rw-r--r-- | src/common/display_iq.c | 280 | ||||
-rw-r--r-- | src/common/display_spectrum.c | 292 | ||||
-rw-r--r-- | src/common/main_mobile.c | 4 | ||||
-rw-r--r-- | src/common/sdr.c | 851 | ||||
-rw-r--r-- | src/common/sdr.h | 8 | ||||
-rw-r--r-- | src/common/sdr_config.c | 262 | ||||
-rw-r--r-- | src/common/sdr_config.h | 32 | ||||
-rw-r--r-- | src/common/sender.h | 2 | ||||
-rw-r--r-- | src/common/soapy.c | 466 | ||||
-rw-r--r-- | src/common/soapy.h | 8 | ||||
-rw-r--r-- | src/common/uhd.c | 583 | ||||
-rw-r--r-- | src/common/uhd.h | 8 |
13 files changed, 4 insertions, 2814 deletions
diff --git a/src/common/Makefile.am b/src/common/Makefile.am index 6d1e07b..9abad04 100644 --- a/src/common/Makefile.am +++ b/src/common/Makefile.am @@ -1,4 +1,4 @@ -AM_CPPFLAGS = -Wall -Wextra -g $(all_includes) $(GRAPHICSMAGICK_CFLAGS) $(IMAGEMAGICK_CFLAGS) $(UHD_CFLAGS) $(SOAPY_CFLAGS) +AM_CPPFLAGS = -Wall -Wextra -g $(all_includes) noinst_LIBRARIES = libcommon.a libmobile.a @@ -16,25 +16,5 @@ libmobile_a_SOURCES = \ if HAVE_SDR AM_CPPFLAGS += -DHAVE_SDR - -libcommon_a_SOURCES += \ - sdr_config.c \ - sdr.c \ - display_iq.c \ - display_spectrum.c -endif - -if HAVE_UHD -AM_CPPFLAGS += -DHAVE_UHD - -libcommon_a_SOURCES += \ - uhd.c -endif - -if HAVE_SOAPY -AM_CPPFLAGS += -DHAVE_SOAPY - -libcommon_a_SOURCES += \ - soapy.c endif diff --git a/src/common/display_iq.c b/src/common/display_iq.c deleted file mode 100644 index c63a455..0000000 --- a/src/common/display_iq.c +++ /dev/null @@ -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 "sample.h" -#include "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; -} - - diff --git a/src/common/display_spectrum.c b/src/common/display_spectrum.c deleted file mode 100644 index 80af735..0000000 --- a/src/common/display_spectrum.c +++ /dev/null @@ -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 "sample.h" -#include "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; -} - - diff --git a/src/common/main_mobile.c b/src/common/main_mobile.c index 7516bba..b4f9343 100644 --- a/src/common/main_mobile.c +++ b/src/common/main_mobile.c @@ -39,8 +39,8 @@ #include "../libmncc/mncc_sock.h" #include "../libmncc/mncc_cross.h" #ifdef HAVE_SDR -#include "sdr.h" -#include "sdr_config.h" +#include "../libsdr/sdr.h" +#include "../libsdr/sdr_config.h" #endif static int got_init = 0; diff --git a/src/common/sdr.c b/src/common/sdr.c deleted file mode 100644 index d7a445b..0000000 --- a/src/common/sdr.c +++ /dev/null @@ -1,851 +0,0 @@ -/* SDR processing - * - * (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/>. - */ - -enum paging_signal; - -#include <stdio.h> -#include <stdlib.h> -#include <stdint.h> -#include <string.h> -#include <errno.h> -#include <math.h> -#include <getopt.h> -#define __USE_GNU -#include <pthread.h> -#include <unistd.h> -#include "sample.h" -#include "../libfm/fm.h" -#include "../libtimer/timer.h" -#include "sender.h" -#include "sdr_config.h" -#include "sdr.h" -#ifdef HAVE_UHD -#include "uhd.h" -#endif -#ifdef HAVE_SOAPY -#include "soapy.h" -#endif -#include "debug.h" - -/* enable to debug buffer handling */ -//#define DEBUG_BUFFER - -/* enable to test without oversampling filter */ -//#define DISABLE_FILTER - -/* usable bandwidth of IQ rate, because no filter is perfect */ -#define USABLE_BANDWIDTH 0.75 - -typedef struct sdr_thread { - int use; - volatile int running, exit; /* flags to control exit of threads */ - int buffer_size; - volatile float *buffer; - float *buffer2; - volatile int in, out; /* in and out pointers (atomic, so no locking required) */ - int max_fill; /* measure maximum buffer fill */ - double max_fill_timer; /* timer to display/reset maximum fill */ - iir_filter_t lp[2]; /* filter for upsample/downsample IQ data */ -} sdr_thread_t; - -typedef struct sdr_chan { - double tx_frequency; /* frequency used */ - double rx_frequency; /* frequency used */ - fm_mod_t mod; /* modulator instance */ - fm_demod_t demod; /* demodulator instance */ - dispmeasparam_t *dmp_rf_level; - dispmeasparam_t *dmp_freq_offset; - dispmeasparam_t *dmp_deviation; -} sdr_chan_t; - -typedef struct sdr { - int threads; /* use threads */ - int oversample; /* oversample IQ rate */ - sdr_thread_t thread_read, - thread_write; - sdr_chan_t *chan; /* settings for all channels */ - int paging_channel; /* if set, points to paging channel */ - sdr_chan_t paging_chan; /* settings for extra paging channel */ - int channels; /* number of frequencies */ - double amplitude; /* amplitude of each carrier */ - int samplerate; /* sample rate of audio data */ - int latspl; /* latency in audio samples */ - wave_rec_t wave_rx_rec; - wave_rec_t wave_tx_rec; - wave_play_t wave_rx_play; - wave_play_t wave_tx_play; - float *modbuff; /* buffer for FM transmodulation */ - sample_t *modbuff_I; - sample_t *modbuff_Q; - sample_t *wavespl0; /* sample buffer for wave generation */ - sample_t *wavespl1; -} sdr_t; - -void *sdr_open(const char __attribute__((__unused__)) *audiodev, double *tx_frequency, double *rx_frequency, int channels, double paging_frequency, int samplerate, int latspl, double max_deviation, double max_modulation) -{ - sdr_t *sdr; - int threads = 1, oversample = 1; /* always use threads */ - double bandwidth; - double tx_center_frequency = 0.0, rx_center_frequency = 0.0; - int rc; - int c; - - PDEBUG(DSDR, DEBUG_DEBUG, "Open SDR device\n"); - - if (sdr_config->samplerate != samplerate) { - if (samplerate > sdr_config->samplerate) { - PDEBUG(DSDR, DEBUG_ERROR, "SDR sample rate must be greater than audio sample rate!\n"); - PDEBUG(DSDR, DEBUG_ERROR, "You selected an SDR rate of %d and an audio rate of %d.\n", sdr_config->samplerate, samplerate); - return NULL; - } - if ((sdr_config->samplerate % samplerate)) { - PDEBUG(DSDR, DEBUG_ERROR, "SDR sample rate must be a multiple of audio sample rate!\n"); - PDEBUG(DSDR, DEBUG_ERROR, "You selected an SDR rate of %d and an audio rate of %d.\n", sdr_config->samplerate, samplerate); - return NULL; - } - oversample = sdr_config->samplerate / samplerate; - threads = 1; - } - - bandwidth = 2.0 * (max_deviation + max_modulation); - PDEBUG(DSDR, DEBUG_INFO, "Require bandwidth of each channel is 2 * (%.1f deviation + %.1f modulation) = %.1f KHz\n", max_deviation / 1e3, max_modulation / 1e3, bandwidth / 1e3); - - if (channels < 1) { - PDEBUG(DSDR, DEBUG_ERROR, "No channel given, please fix!\n"); - abort(); - } - - sdr = calloc(sizeof(*sdr), 1); - if (!sdr) { - PDEBUG(DSDR, DEBUG_ERROR, "NO MEM!\n"); - goto error; - } - sdr->channels = channels; - sdr->amplitude = 1.0 / (double)channels; - sdr->samplerate = samplerate; - sdr->latspl = latspl; - sdr->threads = threads; /* always requried, because write may block */ - sdr->oversample = oversample; - - if (threads) { - memset(&sdr->thread_read, 0, sizeof(sdr->thread_read)); - sdr->thread_read.buffer_size = sdr->latspl * 2 * sdr->oversample + 2; - sdr->thread_read.buffer = calloc(sdr->thread_read.buffer_size, sizeof(*sdr->thread_read.buffer)); - if (!sdr->thread_read.buffer) { - PDEBUG(DSDR, DEBUG_ERROR, "No mem!\n"); - goto error; - } - sdr->thread_read.buffer2 = calloc(sdr->thread_read.buffer_size, sizeof(*sdr->thread_read.buffer2)); - if (!sdr->thread_read.buffer2) { - PDEBUG(DSDR, DEBUG_ERROR, "No mem!\n"); - goto error; - } - sdr->thread_read.in = sdr->thread_read.out = 0; - if (oversample > 1) { - iir_lowpass_init(&sdr->thread_read.lp[0], samplerate / 2.0, sdr_config->samplerate, 2); - iir_lowpass_init(&sdr->thread_read.lp[1], samplerate / 2.0, sdr_config->samplerate, 2); - } - memset(&sdr->thread_write, 0, sizeof(sdr->thread_write)); - sdr->thread_write.buffer_size = sdr->latspl * 2 + 2; - sdr->thread_write.buffer = calloc(sdr->thread_write.buffer_size, sizeof(*sdr->thread_write.buffer)); - if (!sdr->thread_write.buffer) { - PDEBUG(DSDR, DEBUG_ERROR, "No mem!\n"); - goto error; - } - sdr->thread_write.buffer2 = calloc(sdr->thread_write.buffer_size * sdr->oversample, sizeof(*sdr->thread_write.buffer2)); - if (!sdr->thread_write.buffer2) { - PDEBUG(DSDR, DEBUG_ERROR, "No mem!\n"); - goto error; - } - sdr->thread_write.in = sdr->thread_write.out = 0; - if (oversample > 1) { - iir_lowpass_init(&sdr->thread_write.lp[0], samplerate / 2.0, sdr_config->samplerate, 2); - iir_lowpass_init(&sdr->thread_write.lp[1], samplerate / 2.0, sdr_config->samplerate, 2); - } - } - - /* alloc fm modulation buffers */ - sdr->modbuff = calloc(sdr->latspl * 2, sizeof(*sdr->modbuff)); - if (!sdr->modbuff) { - PDEBUG(DSDR, DEBUG_ERROR, "NO MEM!\n"); - goto error; - } - sdr->modbuff_I = calloc(sdr->latspl, sizeof(*sdr->modbuff_I)); - if (!sdr->modbuff_I) { - PDEBUG(DSDR, DEBUG_ERROR, "NO MEM!\n"); - goto error; - } - sdr->modbuff_Q = calloc(sdr->latspl, sizeof(*sdr->modbuff_Q)); - if (!sdr->modbuff_Q) { - PDEBUG(DSDR, DEBUG_ERROR, "NO MEM!\n"); - goto error; - } - sdr->wavespl0 = calloc(sdr->latspl, sizeof(*sdr->wavespl0)); - if (!sdr->wavespl0) { - PDEBUG(DSDR, DEBUG_ERROR, "NO MEM!\n"); - goto error; - } - sdr->wavespl1 = calloc(sdr->latspl, sizeof(*sdr->wavespl1)); - if (!sdr->wavespl1) { - PDEBUG(DSDR, DEBUG_ERROR, "NO MEM!\n"); - goto error; - } - - /* special case where we use a paging frequency */ - if (paging_frequency) { - /* add extra paging channel */ - sdr->paging_channel = channels; - } - - /* create list of channel states */ - sdr->chan = calloc(sizeof(*sdr->chan), channels + (sdr->paging_channel != 0)); - if (!sdr->chan) { - PDEBUG(DSDR, DEBUG_ERROR, "NO MEM!\n"); - goto error; - } - - if (tx_frequency) { - /* calculate required bandwidth (IQ rate) */ - for (c = 0; c < channels; c++) { - PDEBUG(DSDR, DEBUG_INFO, "Frequency #%d: TX = %.6f MHz\n", c, tx_frequency[c] / 1e6); - sdr->chan[c].tx_frequency = tx_frequency[c]; - } - if (sdr->paging_channel) { - PDEBUG(DSDR, DEBUG_INFO, "Paging Frequency: TX = %.6f MHz\n", paging_frequency / 1e6); - sdr->chan[sdr->paging_channel].tx_frequency = paging_frequency; - } - - double tx_low_frequency = sdr->chan[0].tx_frequency, tx_high_frequency = sdr->chan[0].tx_frequency; - for (c = 1; c < channels; c++) { - if (sdr->chan[c].tx_frequency < tx_low_frequency) - tx_low_frequency = sdr->chan[c].tx_frequency; - if (sdr->chan[c].tx_frequency > tx_high_frequency) - tx_high_frequency = sdr->chan[c].tx_frequency; - } - if (sdr->paging_channel) { - if (sdr->chan[sdr->paging_channel].tx_frequency < tx_low_frequency) - tx_low_frequency = sdr->chan[sdr->paging_channel].tx_frequency; - if (sdr->chan[sdr->paging_channel].tx_frequency > tx_high_frequency) - tx_high_frequency = sdr->chan[sdr->paging_channel].tx_frequency; - } - /* range of TX */ - double range = tx_high_frequency - tx_low_frequency + bandwidth; - PDEBUG(DSDR, DEBUG_INFO, "Total bandwidth for all TX Frequencies: %.0f Hz\n", range); - if (range > samplerate * USABLE_BANDWIDTH) { - PDEBUG(DSDR, DEBUG_NOTICE, "*******************************************************************************\n"); - PDEBUG(DSDR, DEBUG_NOTICE, "The required bandwidth of %.0f Hz exceeds %.0f%% of the sample rate.\n", range, USABLE_BANDWIDTH * 100.0); - PDEBUG(DSDR, DEBUG_NOTICE, "Please increase samplerate!\n"); - PDEBUG(DSDR, DEBUG_NOTICE, "*******************************************************************************\n"); - goto error; - } - tx_center_frequency = (tx_high_frequency + tx_low_frequency) / 2.0; - PDEBUG(DSDR, DEBUG_INFO, "Using center frequency: TX %.6f MHz\n", tx_center_frequency / 1e6); - /* set offsets to center frequency */ - for (c = 0; c < channels; c++) { - double tx_offset; - tx_offset = sdr->chan[c].tx_frequency - tx_center_frequency; - PDEBUG(DSDR, DEBUG_DEBUG, "Frequency #%d: TX offset: %.6f MHz\n", c, tx_offset / 1e6); - rc = fm_mod_init(&sdr->chan[c].mod, samplerate, tx_offset, sdr->amplitude); - if (rc < 0) - goto error; - } - if (sdr->paging_channel) { - double tx_offset; - tx_offset = sdr->chan[sdr->paging_channel].tx_frequency - tx_center_frequency; - PDEBUG(DSDR, DEBUG_DEBUG, "Paging Frequency: TX offset: %.6f MHz\n", tx_offset / 1e6); - rc = fm_mod_init(&sdr->chan[sdr->paging_channel].mod, samplerate, tx_offset, sdr->amplitude); - if (rc < 0) - goto error; - } - /* show gain */ - PDEBUG(DSDR, DEBUG_INFO, "Using gain: TX %.1f dB\n", sdr_config->tx_gain); - /* open wave */ - if (sdr_config->write_iq_tx_wave) { - rc = wave_create_record(&sdr->wave_tx_rec, sdr_config->write_iq_tx_wave, samplerate, 2, 1.0); - if (rc < 0) { - PDEBUG(DSDR, DEBUG_ERROR, "Failed to create WAVE recoding instance!\n"); - goto error; - } - } - if (sdr_config->read_iq_tx_wave) { - rc = wave_create_playback(&sdr->wave_tx_play, sdr_config->read_iq_tx_wave, samplerate, 2, 1.0); - if (rc < 0) { - PDEBUG(DSDR, DEBUG_ERROR, "Failed to create WAVE playback instance!\n"); - goto error; - } - } - } - - if (rx_frequency) { - for (c = 0; c < channels; c++) { - PDEBUG(DSDR, DEBUG_INFO, "Frequency #%d: RX = %.6f MHz\n", c, rx_frequency[c] / 1e6); - sdr->chan[c].rx_frequency = rx_frequency[c]; - } - - /* calculate required bandwidth (IQ rate) */ - double rx_low_frequency = sdr->chan[0].rx_frequency, rx_high_frequency = sdr->chan[0].rx_frequency; - for (c = 1; c < channels; c++) { - if (sdr->chan[c].rx_frequency < rx_low_frequency) - rx_low_frequency = sdr->chan[c].rx_frequency; - if (sdr->chan[c].rx_frequency > rx_high_frequency) - rx_high_frequency = sdr->chan[c].rx_frequency; - } - /* range of RX */ - double range = rx_high_frequency - rx_low_frequency + bandwidth; - PDEBUG(DSDR, DEBUG_INFO, "Total bandwidth for all RX Frequencies: %.0f Hz\n", range); - if (range > samplerate * USABLE_BANDWIDTH) { - PDEBUG(DSDR, DEBUG_NOTICE, "*******************************************************************************\n"); - PDEBUG(DSDR, DEBUG_NOTICE, "The required bandwidth of %.0f Hz exceeds %.0f%% of the sample rate.\n", range, USABLE_BANDWIDTH * 100.0); - PDEBUG(DSDR, DEBUG_NOTICE, "Please increase samplerate!\n"); - PDEBUG(DSDR, DEBUG_NOTICE, "*******************************************************************************\n"); - goto error; - } - rx_center_frequency = (rx_high_frequency + rx_low_frequency) / 2.0; - PDEBUG(DSDR, DEBUG_INFO, "Using center frequency: RX %.6f MHz\n", rx_center_frequency / 1e6); - /* set offsets to center frequency */ - for (c = 0; c < channels; c++) { - double rx_offset; - rx_offset = sdr->chan[c].rx_frequency - rx_center_frequency; - PDEBUG(DSDR, DEBUG_DEBUG, "Frequency #%d: RX offset: %.6f MHz\n", c, rx_offset / 1e6); - rc = fm_demod_init(&sdr->chan[c].demod, samplerate, rx_offset, bandwidth); - if (rc < 0) - goto error; - } - /* show gain */ - PDEBUG(DSDR, DEBUG_INFO, "Using gain: RX %.1f dB\n", sdr_config->rx_gain); - /* open wave */ - if (sdr_config->write_iq_rx_wave) { - rc = wave_create_record(&sdr->wave_rx_rec, sdr_config->write_iq_rx_wave, samplerate, 2, 1.0); - if (rc < 0) { - PDEBUG(DSDR, DEBUG_ERROR, "Failed to create WAVE recoding instance!\n"); - goto error; - } - } - if (sdr_config->read_iq_rx_wave) { - rc = wave_create_playback(&sdr->wave_rx_play, sdr_config->read_iq_rx_wave, samplerate, 2, 1.0); - if (rc < 0) { - PDEBUG(DSDR, DEBUG_ERROR, "Failed to create WAVE playback instance!\n"); - goto error; - } - } - /* init measurements display */ - for (c = 0; c < channels; c++) { - sender_t *sender = get_sender_by_empfangsfrequenz(sdr->chan[c].rx_frequency); - if (!sender) - continue; - sdr->chan[c].dmp_rf_level = display_measurements_add(sender, "RF Level", "%.1f dB", DISPLAY_MEAS_AVG, DISPLAY_MEAS_LEFT, -96.0, 0.0, -INFINITY); - sdr->chan[c].dmp_freq_offset = display_measurements_add(sender, "Freq. Offset", "%+.2f KHz", DISPLAY_MEAS_AVG, DISPLAY_MEAS_CENTER, -max_deviation / 1000.0 * 2.0, max_deviation / 1000.0 * 2.0, 0.0); - sdr->chan[c].dmp_deviation = display_measurements_add(sender, "Deviation", "%.2f KHz", DISPLAY_MEAS_PEAK2PEAK, DISPLAY_MEAS_LEFT, 0.0, max_deviation / 1000.0 * 1.5, max_deviation / 1000.0); - } - } - - if (sdr_config->swap_links) { - double temp; - PDEBUG(DSDR, DEBUG_NOTICE, "Sapping RX and TX frequencies!\n"); - temp = rx_center_frequency; - rx_center_frequency = tx_center_frequency; - tx_center_frequency = temp; - } - - display_iq_init(samplerate); - display_spectrum_init(samplerate, rx_center_frequency); - -#ifdef HAVE_UHD - if (sdr_config->uhd) { - rc = uhd_open(sdr_config->channel, sdr_config->device_args, sdr_config->stream_args, sdr_config->tune_args, sdr_config->tx_antenna, sdr_config->rx_antenna, tx_center_frequency, rx_center_frequency, sdr_config->samplerate, sdr_config->tx_gain, sdr_config->rx_gain, sdr_config->bandwidth, sdr_config->uhd_tx_timestamps); - if (rc) - goto error; - } -#endif - -#ifdef HAVE_SOAPY - if (sdr_config->soapy) { - rc = soapy_open(sdr_config->channel, sdr_config->device_args, sdr_config->stream_args, sdr_config->tune_args, sdr_config->tx_antenna, sdr_config->rx_antenna, tx_center_frequency, rx_center_frequency, sdr_config->samplerate, sdr_config->tx_gain, sdr_config->rx_gain, sdr_config->bandwidth); - if (rc) - goto error; - } -#endif - - return sdr; - -error: - sdr_close(sdr); - return NULL; -} - -static void *sdr_write_child(void *arg) -{ - sdr_t *sdr = (sdr_t *)arg; - int num; - int fill, out; - int s, ss, o; - - while (sdr->thread_write.running) { - /* write to SDR */ - fill = (sdr->thread_write.in - sdr->thread_write.out + sdr->thread_write.buffer_size) % sdr->thread_write.buffer_size; - if (fill > sdr->thread_write.max_fill) - sdr->thread_write.max_fill = fill; - if (sdr->thread_write.max_fill_timer == 0.0) - sdr->thread_write.max_fill_timer = get_time(); - if (get_time() - sdr->thread_write.max_fill_timer > 1.0) { - double delay; - delay = (double)sdr->thread_write.max_fill / 2.0 / (double)sdr->samplerate; - sdr->thread_write.max_fill = 0; - sdr->thread_write.max_fill_timer += 1.0; - PDEBUG(DSDR, DEBUG_DEBUG, "write delay = %.3f ms\n", delay * 1000.0); - } - num = fill / 2; - if (num) { -#ifdef DEBUG_BUFFER - printf("Thread found %d samples in write buffer and forwards them to SDR.\n", num); -#endif - out = sdr->thread_write.out; - for (s = 0, ss = 0; s < num; s++) { - for (o = 0; o < sdr->oversample; o++) { - sdr->thread_write.buffer2[ss++] = sdr->thread_write.buffer[out]; - sdr->thread_write.buffer2[ss++] = sdr->thread_write.buffer[out + 1]; - } - out = (out + 2) % sdr->thread_write.buffer_size; - } - sdr->thread_write.out = out; -#ifndef DISABLE_FILTER - /* filter spectrum */ - if (sdr->oversample > 1) { - iir_process_baseband(&sdr->thread_write.lp[0], sdr->thread_write.buffer2, num * sdr->oversample); - iir_process_baseband(&sdr->thread_write.lp[1], sdr->thread_write.buffer2 + 1, num * sdr->oversample); - } -#endif -#ifdef HAVE_UHD - if (sdr_config->uhd) - uhd_send(sdr->thread_write.buffer2, num * sdr->oversample); -#endif -#ifdef HAVE_SOAPY - if (sdr_config->soapy) - soapy_send(sdr->thread_write.buffer2, num * sdr->oversample); -#endif - } - - /* delay some time */ - usleep(1000); - } - - PDEBUG(DSDR, DEBUG_DEBUG, "Thread received exit!\n"); - sdr->thread_write.exit = 1; - return NULL; -} - -static void *sdr_read_child(void *arg) -{ - sdr_t *sdr = (sdr_t *)arg; - int num, count = 0; - int space, in; - int s, ss; - - while (sdr->thread_read.running) { - /* read from SDR */ - space = (sdr->thread_read.out - sdr->thread_read.in - 2 + sdr->thread_read.buffer_size) % sdr->thread_read.buffer_size; - num = space / 2; - if (num) { -#ifdef HAVE_UHD - if (sdr_config->uhd) - count = uhd_receive(sdr->thread_read.buffer2, num); -#endif -#ifdef HAVE_SOAPY - if (sdr_config->soapy) - count = soapy_receive(sdr->thread_read.buffer2, num); -#endif - if (count > 0) { -#ifdef DEBUG_BUFFER - printf("Thread read %d samples from SDR and writes them to read buffer.\n", count); -#endif -#ifndef DISABLE_FILTER - /* filter spectrum */ - if (sdr->oversample > 1) { - iir_process_baseband(&sdr->thread_read.lp[0], sdr->thread_read.buffer2, count); - iir_process_baseband(&sdr->thread_read.lp[1], sdr->thread_read.buffer2 + 1, count); - } -#endif - in = sdr->thread_read.in; - for (s = 0, ss = 0; s < count; s++) { - sdr->thread_read.buffer[in++] = sdr->thread_read.buffer2[ss++]; - sdr->thread_read.buffer[in++] = sdr->thread_read.buffer2[ss++]; - in %= sdr->thread_read.buffer_size; - } - sdr->thread_read.in = in; - } - } - - /* delay some time */ - usleep(1000); - } - - PDEBUG(DSDR, DEBUG_DEBUG, "Thread received exit!\n"); - sdr->thread_read.exit = 1; - return NULL; -} - -/* start streaming */ -int sdr_start(void *inst) -{ - sdr_t *sdr = (sdr_t *)inst; - int rc = -EINVAL; - -#ifdef HAVE_UHD - if (sdr_config->uhd) - rc = uhd_start(); -#endif -#ifdef HAVE_SOAPY - if (sdr_config->soapy) - rc = soapy_start(); -#endif - if (rc < 0) - return rc; - - if (sdr->threads) { - int rc; - pthread_t tid; - char tname[64]; - - PDEBUG(DSDR, DEBUG_DEBUG, "Create threads!\n"); - sdr->thread_write.running = 1; - sdr->thread_write.exit = 0; - rc = pthread_create(&tid, NULL, sdr_write_child, inst); - if (rc < 0) { - sdr->thread_write.running = 0; - PDEBUG(DSDR, DEBUG_ERROR, "Failed to create thread!\n"); - return rc; - } - pthread_getname_np(tid, tname, sizeof(tname)); - strncat(tname, "-sdr_tx", sizeof(tname)); - tname[sizeof(tname) - 1] = '\0'; - pthread_setname_np(tid, tname); - sdr->thread_read.running = 1; - sdr->thread_read.exit = 0; - rc = pthread_create(&tid, NULL, sdr_read_child, inst); - if (rc < 0) { - sdr->thread_read.running = 0; - PDEBUG(DSDR, DEBUG_ERROR, "Failed to create thread!\n"); - return rc; - } - pthread_getname_np(tid, tname, sizeof(tname)); - strncat(tname, "-sdr_rx", sizeof(tname)); - tname[sizeof(tname) - 1] = '\0'; - pthread_setname_np(tid, tname); - } - - return 0; -} - -void sdr_close(void *inst) -{ - sdr_t *sdr = (sdr_t *)inst; - - PDEBUG(DSDR, DEBUG_DEBUG, "Close SDR device\n"); - - if (sdr->threads) { - if (sdr->thread_write.running) { - PDEBUG(DSDR, DEBUG_DEBUG, "Thread sending exit!\n"); - sdr->thread_write.running = 0; - while (sdr->thread_write.exit == 0) - usleep(1000); - } - if (sdr->thread_read.running) { - PDEBUG(DSDR, DEBUG_DEBUG, "Thread sending exit!\n"); - sdr->thread_read.running = 0; - while (sdr->thread_read.exit == 0) - usleep(1000); - } - } - - if (sdr->thread_read.buffer) - free((void *)sdr->thread_read.buffer); - if (sdr->thread_read.buffer2) - free((void *)sdr->thread_read.buffer2); - if (sdr->thread_write.buffer) - free((void *)sdr->thread_write.buffer); - if (sdr->thread_write.buffer2) - free((void *)sdr->thread_write.buffer2); - -#ifdef HAVE_UHD - if (sdr_config->uhd) - uhd_close(); -#endif - -#ifdef HAVE_SOAPY - if (sdr_config->soapy) - soapy_close(); -#endif - - if (sdr) { - free(sdr->modbuff); - free(sdr->modbuff_I); - free(sdr->modbuff_Q); - free(sdr->wavespl0); - free(sdr->wavespl1); - wave_destroy_record(&sdr->wave_rx_rec); - wave_destroy_record(&sdr->wave_tx_rec); - wave_destroy_playback(&sdr->wave_rx_play); - wave_destroy_playback(&sdr->wave_tx_play); - if (sdr->chan) { - int c; - - for (c = 0; c < sdr->channels; c++) { - fm_mod_exit(&sdr->chan[c].mod); - fm_demod_exit(&sdr->chan[c].demod); - } - if (sdr->paging_channel) - fm_mod_exit(&sdr->chan[sdr->paging_channel].mod); - free(sdr->chan); - } - free(sdr); - sdr = NULL; - } -} - -int sdr_write(void *inst, sample_t **samples, uint8_t **power, int num, enum paging_signal __attribute__((unused)) *paging_signal, int *on, int channels) -{ - sdr_t *sdr = (sdr_t *)inst; - float *buff = NULL; - int c, s, ss; - int sent = 0; - - if (num > sdr->latspl) { - fprintf(stderr, "exceeding maximum size given by sdr_latspl, please fix!\n"); - abort(); - } - if (channels != sdr->channels && channels != 0) { - PDEBUG(DSDR, DEBUG_ERROR, "Invalid number of channels, please fix!\n"); - abort(); - } - - /* process all channels */ - if (channels) { - buff = sdr->modbuff; - memset(buff, 0, sizeof(*buff) * num * 2); - for (c = 0; c < channels; c++) { - /* switch to paging channel, if requested */ - if (on[c] && sdr->paging_channel) - fm_modulate_complex(&sdr->chan[sdr->paging_channel].mod, samples[c], power[c], num, buff); - else - fm_modulate_complex(&sdr->chan[c].mod, samples[c], power[c], num, buff); - } - } else { - buff = (float *)samples; - } - - if (sdr->wave_tx_rec.fp) { - sample_t *spl_list[2] = { sdr->wavespl0, sdr->wavespl1 }; - for (s = 0, ss = 0; s < num; s++) { - spl_list[0][s] = buff[ss++]; - spl_list[1][s] = buff[ss++]; - } - wave_write(&sdr->wave_tx_rec, spl_list, num); - } - if (sdr->wave_tx_play.fp) { - sample_t *spl_list[2] = { sdr->wavespl0, sdr->wavespl1 }; - wave_read(&sdr->wave_tx_play, spl_list, num); - for (s = 0, ss = 0; s < num; s++) { - buff[ss++] = spl_list[0][s]; - buff[ss++] = spl_list[1][s]; - } - } - - if (sdr->threads) { - /* store data towards SDR in ring buffer */ - int space, in; - - space = (sdr->thread_write.out - sdr->thread_write.in - 2 + sdr->thread_write.buffer_size) % sdr->thread_write.buffer_size; - if (space < num * 2) { - PDEBUG(DSDR, DEBUG_ERROR, "Write SDR buffer overflow!\n"); - num = space / 2; - } -#ifdef DEBUG_BUFFER - printf("Writing %d samples to write buffer.\n", num); -#endif - in = sdr->thread_write.in; - for (s = 0, ss = 0; s < num; s++) { - sdr->thread_write.buffer[in++] = buff[ss++]; - sdr->thread_write.buffer[in++] = buff[ss++]; - in %= sdr->thread_write.buffer_size; - } - sdr->thread_write.in = in; - sent = num; - } else { -#ifdef HAVE_UHD - if (sdr_config->uhd) - sent = uhd_send(buff, num); -#endif -#ifdef HAVE_SOAPY - if (sdr_config->soapy) - sent = soapy_send(buff, num); -#endif - if (sent < 0) - return sent; - } - - return sent; -} - -int sdr_read(void *inst, sample_t **samples, int num, int channels, double *rf_level_db) -{ - sdr_t *sdr = (sdr_t *)inst; - float *buff = NULL; - int count = 0; - int c, s, ss; - - if (num > sdr->latspl) { - fprintf(stderr, "exceeding maximum size given by sdr_latspl, please fix!\n"); - abort(); - } - - if (channels) { - buff = sdr->modbuff; - } else { - buff = (float *)samples; - } - - if (sdr->threads) { - /* load data from SDR out of ring buffer */ - int fill, out; - - fill = (sdr->thread_read.in - sdr->thread_read.out + sdr->thread_read.buffer_size) % sdr->thread_read.buffer_size; - if (fill > sdr->thread_read.max_fill) - sdr->thread_read.max_fill = fill; - if (sdr->thread_read.max_fill_timer == 0.0) - sdr->thread_read.max_fill_timer = get_time(); - if (get_time() - sdr->thread_read.max_fill_timer > 1.0) { - double delay; - delay = (double)sdr->thread_read.max_fill / 2.0 / (double)sdr_config->samplerate; - sdr->thread_read.max_fill = 0; - sdr->thread_read.max_fill_timer += 1.0; - PDEBUG(DSDR, DEBUG_DEBUG, "read delay = %.3f ms\n", delay * 1000.0); - } - if (fill / 2 / sdr->oversample < num) - num = fill / 2 / sdr->oversample; -#ifdef DEBUG_BUFFER - printf("Reading %d samples from read buffer.\n", num); -#endif - out = sdr->thread_read.out; - for (s = 0, ss = 0; s < num; s++) { - buff[ss++] = sdr->thread_read.buffer[out]; - buff[ss++] = sdr->thread_read.buffer[out + 1]; - out = (out + 2 * sdr->oversample) % sdr->thread_read.buffer_size; - } - sdr->thread_read.out = out; - count = num; - } else { -#ifdef HAVE_UHD - if (sdr_config->uhd) - count = uhd_receive(buff, num); -#endif -#ifdef HAVE_SOAPY - if (sdr_config->soapy) - count = soapy_receive(buff, num); -#endif - if (count <= 0) - return count; - } - - if (sdr->wave_rx_rec.fp) { - sample_t *spl_list[2] = { sdr->wavespl0, sdr->wavespl1 }; - for (s = 0, ss = 0; s < count; s++) { - spl_list[0][s] = buff[ss++]; - spl_list[1][s] = buff[ss++]; - } - wave_write(&sdr->wave_rx_rec, spl_list, count); - } - if (sdr->wave_rx_play.fp) { - sample_t *spl_list[2] = { sdr->wavespl0, sdr->wavespl1 }; - wave_read(&sdr->wave_rx_play, spl_list, count); - for (s = 0, ss = 0; s < count; s++) { - buff[ss++] = spl_list[0][s]; - buff[ss++] = spl_list[1][s]; - } - } - display_iq(buff, count); - display_spectrum(buff, count); - - if (channels) { - for (c = 0; c < channels; c++) { - fm_demodulate_complex(&sdr->chan[c].demod, samples[c], count, buff, sdr->modbuff_I, sdr->modbuff_Q); - sender_t *sender = get_sender_by_empfangsfrequenz(sdr->chan[c].rx_frequency); - if (!sender || !count) - continue; - double min, max, avg; - avg = 0.0; - for (s = 0; s < count; s++) { - /* average the square length of vector */ - avg += sdr->modbuff_I[s] * sdr->modbuff_I[s] + sdr->modbuff_Q[s] * sdr->modbuff_Q[s]; - } - avg = sqrt(avg /(double)count); /* RMS */ - avg = log10(avg) * 20; - display_measurements_update(sdr->chan[c].dmp_rf_level, avg, 0.0); - rf_level_db[c] = avg; - min = 0.0; - max = 0.0; - avg = 0.0; - for (s = 0; s < count; s++) { - avg += samples[c][s]; - if (s == 0 || samples[c][s] > max) - max = samples[c][s]; - if (s == 0 || samples[c][s] < min) - min = samples[c][s]; - } - avg /= (double)count; - display_measurements_update(sdr->chan[c].dmp_freq_offset, avg / 1000.0, 0.0); - /* use half min and max, because we want the deviation above/below (+-) center frequency. */ - display_measurements_update(sdr->chan[c].dmp_deviation, min / 2.0 / 1000.0, max / 2.0 / 1000.0); - } - } - - return count; -} - -/* how much do we need to send (in audio sample duration) to get the target delay (latspl) */ -int sdr_get_tosend(void *inst, int latspl) -{ - sdr_t *sdr = (sdr_t *)inst; - int count = 0; - -#ifdef HAVE_UHD - if (sdr_config->uhd) - count = uhd_get_tosend(latspl * sdr->oversample); -#endif -#ifdef HAVE_SOAPY - if (sdr_config->soapy) - count = soapy_get_tosend(latspl * sdr->oversample); -#endif - if (count < 0) - return count; - count /= sdr->oversample; - - if (sdr->threads) { - /* substract what we have in write buffer, because this is not jent sent to the SDR */ - int fill; - - fill = (sdr->thread_write.in - sdr->thread_write.out + sdr->thread_write.buffer_size) % sdr->thread_write.buffer_size; - count -= fill / 2; - if (count < 0) - count = 0; - } - - return count; -} - - diff --git a/src/common/sdr.h b/src/common/sdr.h deleted file mode 100644 index 360f424..0000000 --- a/src/common/sdr.h +++ /dev/null @@ -1,8 +0,0 @@ - -int sdr_start(void *inst); -void *sdr_open(const char *audiodev, double *tx_frequency, double *rx_frequency, int channels, double paging_frequency, int samplerate, int latspl, double bandwidth, double sample_deviation); -void sdr_close(void *inst); -int sdr_write(void *inst, sample_t **samples, uint8_t **power, int num, enum paging_signal *paging_signal, int *on, int channels); -int sdr_read(void *inst, sample_t **samples, int num, int channels, double *rf_level_db); -int sdr_get_tosend(void *inst, int latspl); - diff --git a/src/common/sdr_config.c b/src/common/sdr_config.c deleted file mode 100644 index 4a49bae..0000000 --- a/src/common/sdr_config.c +++ /dev/null @@ -1,262 +0,0 @@ -/* Config for SDR - * - * (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/>. - */ - -enum paging_signal; - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <stdint.h> -#include <getopt.h> -#include "sample.h" -#include "sdr.h" -#include "sdr_config.h" - -static int got_init = 0; -extern int use_sdr; -sdr_config_t *sdr_config = NULL; - -void sdr_config_init(void) -{ - sdr_config = calloc(1, sizeof(*sdr_config)); - memset(sdr_config, 0, sizeof(*sdr_config)); - sdr_config->device_args = ""; - sdr_config->stream_args = ""; - sdr_config->tune_args = ""; - - got_init = 1; -} - -void sdr_config_print_help(void) -{ - printf("\nSDR options:\n"); - /* - - */ -#ifdef HAVE_UHD - printf(" --sdr-uhd\n"); - printf(" Force UHD driver\n"); -#endif -#ifdef HAVE_SOAPY - printf(" --sdr-soapy\n"); - printf(" Force SoapySDR driver\n"); -#endif - printf(" --sdr-channel <channel #>\n"); - printf(" Give channel number for multi channel SDR device (default = %d)\n", sdr_config->channel); - printf(" --sdr-device-args <args>\n"); - printf(" --sdr-stream-args <args>\n"); - printf(" --sdr-tune-args <args>\n"); - printf(" Optional SDR device arguments, seperated by comma\n"); - printf(" e.g. --sdr-device-args <key>=<value>[,<key>=<value>[,...]]\n"); - printf(" --sdr-samplerate <samplerate>\n"); - printf(" Sample rate to use with SDR. By default it equals the regular sample\n"); - printf(" rate.\n"); - printf(" --sdr-bandwidth <bandwidth>\n"); - printf(" Give IF filter bandwidth to use. If not, sample rate is used.\n"); - printf(" --sdr-rx-antenna <name>\n"); - printf(" SDR device's RX antenna name, use 'list' to get a list\n"); - printf(" --sdr-tx-antenna <name>\n"); - printf(" SDR device's TX antenna name, use 'list' to get a list\n"); - printf(" --sdr-rx-gain <gain>\n"); - printf(" SDR device's RX gain in dB (default = %.1f)\n", sdr_config->rx_gain); - printf(" --sdr-tx-gain <gain>\n"); - printf(" SDR device's TX gain in dB (default = %.1f)\n", sdr_config->tx_gain); - printf(" --write-iq-rx-wave <file>\n"); - printf(" Write received IQ data to given wave file.\n"); - printf(" --write-iq-tx-wave <file>\n"); - printf(" Write transmitted IQ data to given wave file.\n"); - printf(" --read-iq-rx-wave <file>\n"); - printf(" Replace received IQ data by given wave file.\n"); - printf(" --read-iq-tx-wave <file>\n"); - printf(" Replace transmitted IQ data by given wave file.\n"); - printf(" --sdr-swap-links\n"); - printf(" Swap RX and TX frequencies for loopback tests over the air.\n"); -#ifdef HAVE_UHD - printf(" --sdr-uhd-tx-timestamps\n"); - printf(" Use TX timestamps on UHD device. (May not work with some devices!)\n"); -#endif -} - -void sdr_config_print_hotkeys(void) -{ - printf("Press 'q' key to toggle display of RX I/Q vector.\n"); - printf("Press 's' key to toggle display of RX spectrum.\n"); -} - -#define OPT_SDR_UHD 1500 -#define OPT_SDR_SOAPY 1501 -#define OPT_SDR_CHANNEL 1502 -#define OPT_SDR_DEVICE_ARGS 1503 -#define OPT_SDR_STREAM_ARGS 1504 -#define OPT_SDR_TUNE_ARGS 1505 -#define OPT_SDR_RX_ANTENNA 1506 -#define OPT_SDR_TX_ANTENNA 1507 -#define OPT_SDR_RX_GAIN 1508 -#define OPT_SDR_TX_GAIN 1509 -#define OPT_SDR_SAMPLERATE 1510 -#define OPT_SDR_BANDWIDTH 1511 -#define OPT_WRITE_IQ_RX_WAVE 1512 -#define OPT_WRITE_IQ_TX_WAVE 1513 -#define OPT_READ_IQ_RX_WAVE 1514 -#define OPT_READ_IQ_TX_WAVE 1515 -#define OPT_SDR_SWAP_LINKS 1516 -#define OPT_SDR_UHD_TX_TS 1517 - -struct option sdr_config_long_options[] = { - {"sdr-uhd", 0, 0, OPT_SDR_UHD}, - {"sdr-soapy", 0, 0, OPT_SDR_SOAPY}, - {"sdr-channel", 1, 0, OPT_SDR_CHANNEL}, - {"sdr-device-args", 1, 0, OPT_SDR_DEVICE_ARGS}, - {"sdr-stream-args", 1, 0, OPT_SDR_STREAM_ARGS}, - {"sdr-tune-args", 1, 0, OPT_SDR_TUNE_ARGS}, - {"sdr-samplerate", 1, 0, OPT_SDR_SAMPLERATE}, - {"sdr-bandwidth", 1, 0, OPT_SDR_BANDWIDTH}, - {"sdr-rx-antenna", 1, 0, OPT_SDR_RX_ANTENNA}, - {"sdr-tx-antenna", 1, 0, OPT_SDR_TX_ANTENNA}, - {"sdr-rx-gain", 1, 0, OPT_SDR_RX_GAIN}, - {"sdr-tx-gain", 1, 0, OPT_SDR_TX_GAIN}, - {"write-iq-rx-wave", 1, 0, OPT_WRITE_IQ_RX_WAVE}, - {"write-iq-tx-wave", 1, 0, OPT_WRITE_IQ_TX_WAVE}, - {"read-iq-rx-wave", 1, 0, OPT_READ_IQ_RX_WAVE}, - {"read-iq-tx-wave", 1, 0, OPT_READ_IQ_TX_WAVE}, - {"sdr-swap-links", 0, 0, OPT_SDR_SWAP_LINKS}, - {"sdr-uhd-tx-timestamps", 0, 0, OPT_SDR_UHD_TX_TS}, - {0, 0, 0, 0} -}; - -const char *sdr_config_optstring = ""; - -int sdr_config_opt_switch(int c, int *skip_args) -{ - switch (c) { - case OPT_SDR_UHD: -#ifdef HAVE_UHD - sdr_config->uhd = 1; - use_sdr = 1; -#else - fprintf(stderr, "UHD SDR support not compiled in!\n"); - exit(0); -#endif - *skip_args += 1; - break; - case OPT_SDR_SOAPY: -#ifdef HAVE_SOAPY - sdr_config->soapy = 1; - use_sdr = 1; -#else - fprintf(stderr, "SoapySDR support not compiled in!\n"); - exit(0); -#endif - *skip_args += 1; - break; - case OPT_SDR_CHANNEL: - sdr_config->channel = atoi(optarg); - *skip_args += 2; - break; - case OPT_SDR_DEVICE_ARGS: - sdr_config->device_args = strdup(optarg); - *skip_args += 2; - break; - case OPT_SDR_STREAM_ARGS: - sdr_config->stream_args = strdup(optarg); - *skip_args += 2; - break; - case OPT_SDR_TUNE_ARGS: - sdr_config->tune_args = strdup(optarg); - *skip_args += 2; - break; - case OPT_SDR_SAMPLERATE: - sdr_config->samplerate = atoi(optarg); - *skip_args += 2; - break; - case OPT_SDR_BANDWIDTH: - sdr_config->bandwidth = atof(optarg); - *skip_args += 2; - break; - case OPT_SDR_RX_ANTENNA: - sdr_config->rx_antenna = strdup(optarg); - *skip_args += 2; - break; - case OPT_SDR_TX_ANTENNA: - sdr_config->tx_antenna = strdup(optarg); - *skip_args += 2; - break; - case OPT_SDR_RX_GAIN: - sdr_config->rx_gain = atof(optarg); - *skip_args += 2; - break; - case OPT_SDR_TX_GAIN: - sdr_config->tx_gain = atof(optarg); - *skip_args += 2; - break; - case OPT_WRITE_IQ_RX_WAVE: - sdr_config->write_iq_rx_wave = strdup(optarg); - *skip_args += 2; - break; - case OPT_WRITE_IQ_TX_WAVE: - sdr_config->write_iq_tx_wave = strdup(optarg); - *skip_args += 2; - break; - case OPT_READ_IQ_RX_WAVE: - sdr_config->read_iq_rx_wave = strdup(optarg); - *skip_args += 2; - break; - case OPT_READ_IQ_TX_WAVE: - sdr_config->read_iq_tx_wave = strdup(optarg); - *skip_args += 2; - break; - case OPT_SDR_SWAP_LINKS: - sdr_config->swap_links = 1; - *skip_args += 1; - break; - case OPT_SDR_UHD_TX_TS: - sdr_config->uhd_tx_timestamps = 1; - *skip_args += 1; - break; - default: - return -1; - } - - return 0; -} - -int sdr_configure(int samplerate) -{ - if (!got_init) { - fprintf(stderr, "sdr_config_init was not called, please fix!\n"); - abort(); - } - - /* no sdr selected -> return 0 */ - if (!sdr_config->uhd && !sdr_config->soapy) - return 0; - - if ((sdr_config->uhd == 1 && sdr_config->soapy == 1)) { - fprintf(stderr, "You must choose which one you want: --sdr-uhd or --sdr-soapy\n"); - exit(0); - } - - if (sdr_config->samplerate == 0) - sdr_config->samplerate = samplerate; - if (sdr_config->bandwidth == 0.0) - sdr_config->bandwidth = (double)sdr_config->samplerate; - - /* sdr selected -> return 1 */ - return 1; -} - - diff --git a/src/common/sdr_config.h b/src/common/sdr_config.h deleted file mode 100644 index b64424d..0000000 --- a/src/common/sdr_config.h +++ /dev/null @@ -1,32 +0,0 @@ - -typedef struct sdr_config { - int uhd, /* select UHD API */ - soapy; /* select Soapy SDR API */ - int channel; /* channel number */ - const char *device_args, /* arguments */ - *stream_args, - *tune_args; - int samplerate; /* ADC/DAC sample rate */ - double bandwidth; /* IF bandwidth */ - double tx_gain, /* gain */ - rx_gain; - const char *tx_antenna, /* list/override antennas */ - *rx_antenna; - const char *write_iq_tx_wave; /* wave recording and playback */ - const char *write_iq_rx_wave; - const char *read_iq_tx_wave; - const char *read_iq_rx_wave; - int swap_links; /* swap DL and UL frequency */ - int uhd_tx_timestamps; /* use UHD time stamps */ -} sdr_config_t; - -extern sdr_config_t *sdr_config; - -void sdr_config_init(void); -void sdr_config_print_help(void); -void sdr_config_print_hotkeys(void); -extern struct option sdr_config_long_options[]; -extern const char *sdr_config_optstring; -int sdr_config_opt_switch(int c, int *skip_args); -int sdr_configure(int samplerate); - diff --git a/src/common/sender.h b/src/common/sender.h index 22a23a1..12a17c9 100644 --- a/src/common/sender.h +++ b/src/common/sender.h @@ -1,6 +1,6 @@ #include "../libsound/sound.h" #ifdef HAVE_SDR -#include "sdr.h" +#include "../libsdr/sdr.h" #endif #include "../libwave/wave.h" #include "../libsamplerate/samplerate.h" diff --git a/src/common/soapy.c b/src/common/soapy.c deleted file mode 100644 index e5d10de..0000000 --- a/src/common/soapy.c +++ /dev/null @@ -1,466 +0,0 @@ -/* SoapySDR device access - * - * (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 <stdlib.h> -#include <stdint.h> -#include <string.h> -#include <errno.h> -#include <math.h> -#include <SoapySDR/Device.h> -#include <SoapySDR/Formats.h> -#include "soapy.h" -#include "debug.h" - -static SoapySDRDevice *sdr = NULL; -SoapySDRStream *rxStream = NULL; -SoapySDRStream *txStream = NULL; -static int tx_samps_per_buff, rx_samps_per_buff; -static double samplerate; -static uint64_t rx_count = 0; -static uint64_t tx_count = 0; - -static int parse_args(SoapySDRKwargs *args, const char *_args_string) -{ - char *args_string = strdup(_args_string), *key, *val; - - memset(args, 0, sizeof(*args)); - while (args_string && *args_string) { - key = args_string; - val = strchr(key, '='); - if (!val) { - PDEBUG(DSOAPY, DEBUG_ERROR, "Error parsing SDR args: No '=' after key\n"); - soapy_close(); - return -EIO; - } - *val++ = '\0'; - args_string = strchr(val, ','); - if (args_string) - *args_string++ = '\0'; - PDEBUG(DSOAPY, DEBUG_DEBUG, "SDR device args: key='%s' value='%s'\n", key, val); - SoapySDRKwargs_set(args, key, val); - } - - return 0; -} - -int soapy_open(size_t channel, const char *_device_args, const char *_stream_args, const char *_tune_args, const char *tx_antenna, const char *rx_antenna, double tx_frequency, double rx_frequency, double rate, double tx_gain, double rx_gain, double bandwidth) -{ - double got_frequency, got_rate, got_gain, got_bandwidth; - const char *got_antenna; - size_t num_channels; - SoapySDRKwargs device_args; - SoapySDRKwargs stream_args; - SoapySDRKwargs tune_args; - int rc; - - samplerate = rate; - - /* parsing ARGS */ - PDEBUG(DSOAPY, DEBUG_INFO, "Using device args \"%s\"\n", _device_args); - rc = parse_args(&device_args, _device_args); - if (rc < 0) - return rc; - PDEBUG(DSOAPY, DEBUG_INFO, "Using stream args \"%s\"\n", _stream_args); - rc = parse_args(&stream_args, _stream_args); - if (rc < 0) - return rc; - PDEBUG(DSOAPY, DEBUG_INFO, "Using tune args \"%s\"\n", _tune_args); - rc = parse_args(&tune_args, _tune_args); - if (rc < 0) - return rc; - - /* create SoapySDR device */ - sdr = SoapySDRDevice_make(&device_args); - if (!sdr) { - PDEBUG(DSOAPY, DEBUG_ERROR, "Failed to create SoapySDR\n"); - soapy_close(); - return -EIO; - } - - if (tx_frequency) { - /* get number of channels and check if requested channel is in range */ - num_channels = SoapySDRDevice_getNumChannels(sdr, SOAPY_SDR_TX); - PDEBUG(DSOAPY, DEBUG_DEBUG, "We have %d TX channel, selecting channel #%d\n", (int)num_channels, (int)channel); - if (channel >= num_channels) { - PDEBUG(DSOAPY, DEBUG_ERROR, "Requested channel #%d (capable of TX) does not exist. Please select channel %d..%d!\n", (int)channel, 0, (int)num_channels - 1); - soapy_close(); - return -EIO; - } - - /* antenna */ - if (tx_antenna && tx_antenna[0]) { - if (!strcasecmp(tx_antenna, "list")) { - char **antennas; - size_t antennas_length; - int i; - antennas = SoapySDRDevice_listAntennas(sdr, SOAPY_SDR_TX, channel, &antennas_length); - if (!antennas) { - PDEBUG(DSOAPY, DEBUG_ERROR, "Failed to request list of TX antennas!\n"); - soapy_close(); - return -EIO; - } - for (i = 0; i < (int)antennas_length; i++) - PDEBUG(DSOAPY, DEBUG_NOTICE, "TX Antenna: '%s'\n", antennas[i]); - got_antenna = SoapySDRDevice_getAntenna(sdr, SOAPY_SDR_TX, channel); - PDEBUG(DSOAPY, DEBUG_NOTICE, "Default TX Antenna: '%s'\n", got_antenna); - soapy_close(); - return 1; - } - - if (SoapySDRDevice_setAntenna(sdr, SOAPY_SDR_TX, channel, tx_antenna) != 0) { - PDEBUG(DSOAPY, DEBUG_ERROR, "Failed to set TX antenna to '%s'\n", tx_antenna); - soapy_close(); - return -EIO; - } - got_antenna = SoapySDRDevice_getAntenna(sdr, SOAPY_SDR_TX, channel); - if (!!strcasecmp(tx_antenna, got_antenna)) { - PDEBUG(DSOAPY, DEBUG_NOTICE, "Given TX antenna '%s' was accepted, but driver claims to use '%s'\n", tx_antenna, got_antenna); - soapy_close(); - return -EINVAL; - } - } - - /* set rate */ - if (SoapySDRDevice_setSampleRate(sdr, SOAPY_SDR_TX, channel, rate) != 0) { - PDEBUG(DSOAPY, DEBUG_ERROR, "Failed to set TX rate to %.0f Hz\n", rate); - soapy_close(); - return -EIO; - } - - /* see what rate actually is */ - got_rate = SoapySDRDevice_getSampleRate(sdr, SOAPY_SDR_TX, channel); - if (fabs(got_rate - rate) > 1.0) { - PDEBUG(DSOAPY, DEBUG_ERROR, "Given TX rate %.3f Hz is not supported, try %.3f Hz\n", rate, got_rate); - soapy_close(); - return -EINVAL; - } - - if (tx_gain) { - /* set gain */ - if (SoapySDRDevice_setGain(sdr, SOAPY_SDR_TX, channel, tx_gain) != 0) { - PDEBUG(DSOAPY, DEBUG_ERROR, "Failed to set TX gain to %.0f\n", tx_gain); - soapy_close(); - return -EIO; - } - - /* see what gain actually is */ - got_gain = SoapySDRDevice_getGain(sdr, SOAPY_SDR_TX, channel); - if (fabs(got_gain - tx_gain) > 0.001) { - PDEBUG(DSOAPY, DEBUG_NOTICE, "Given TX gain %.3f is not supported, we use %.3f\n", tx_gain, got_gain); - tx_gain = got_gain; - } - } - - /* set frequency */ - if (SoapySDRDevice_setFrequency(sdr, SOAPY_SDR_TX, channel, tx_frequency, &tune_args) != 0) { - PDEBUG(DSOAPY, DEBUG_ERROR, "Failed to set TX frequency to %.0f Hz\n", tx_frequency); - soapy_close(); - return -EIO; - } - - /* see what frequency actually is */ - got_frequency = SoapySDRDevice_getFrequency(sdr, SOAPY_SDR_TX, channel); - if (fabs(got_frequency - tx_frequency) > 100.0) { - PDEBUG(DSOAPY, DEBUG_ERROR, "Given TX frequency %.0f Hz is not supported, try %.0f Hz\n", tx_frequency, got_frequency); - soapy_close(); - return -EINVAL; - } - - /* set bandwidth */ - if (SoapySDRDevice_setBandwidth(sdr, SOAPY_SDR_TX, channel, bandwidth) != 0) { - PDEBUG(DSOAPY, DEBUG_ERROR, "Failed to set TX bandwidth to %.0f Hz\n", bandwidth); - soapy_close(); - return -EIO; - } - - /* see what bandwidth actually is */ - got_bandwidth = SoapySDRDevice_getBandwidth(sdr, SOAPY_SDR_TX, channel); - if (fabs(got_bandwidth - bandwidth) > 100.0) { - PDEBUG(DSOAPY, DEBUG_ERROR, "Given TX bandwidth %.0f Hz is not supported, try %.0f Hz\n", bandwidth, got_bandwidth); - soapy_close(); - return -EINVAL; - } - - /* set up streamer */ - if (SoapySDRDevice_setupStream(sdr, &txStream, SOAPY_SDR_TX, SOAPY_SDR_CF32, &channel, 1, &stream_args) != 0) { - PDEBUG(DSOAPY, DEBUG_ERROR, "Failed to set TX streamer args\n"); - soapy_close(); - return -EIO; - } - - /* get buffer sizes */ - tx_samps_per_buff = SoapySDRDevice_getStreamMTU(sdr, txStream); - if (tx_samps_per_buff == 0) { - PDEBUG(DSOAPY, DEBUG_ERROR, "Failed to get TX streamer sample buffer\n"); - soapy_close(); - return -EIO; - } - } - - if (rx_frequency) { - /* get number of channels and check if requested channel is in range */ - num_channels = SoapySDRDevice_getNumChannels(sdr, SOAPY_SDR_RX); - PDEBUG(DSOAPY, DEBUG_DEBUG, "We have %d RX channel, selecting channel #%d\n", (int)num_channels, (int)channel); - if (channel >= num_channels) { - PDEBUG(DSOAPY, DEBUG_ERROR, "Requested channel #%d (capable of RX) does not exist. Please select channel %d..%d!\n", (int)channel, 0, (int)num_channels - 1); - soapy_close(); - return -EIO; - } - - /* antenna */ - if (rx_antenna && rx_antenna[0]) { - if (!strcasecmp(rx_antenna, "list")) { - char **antennas; - size_t antennas_length; - int i; - antennas = SoapySDRDevice_listAntennas(sdr, SOAPY_SDR_RX, channel, &antennas_length); - if (!antennas) { - PDEBUG(DSOAPY, DEBUG_ERROR, "Failed to request list of RX antennas!\n"); - soapy_close(); - return -EIO; - } - for (i = 0; i < (int)antennas_length; i++) - PDEBUG(DSOAPY, DEBUG_NOTICE, "RX Antenna: '%s'\n", antennas[i]); - got_antenna = SoapySDRDevice_getAntenna(sdr, SOAPY_SDR_RX, channel); - PDEBUG(DSOAPY, DEBUG_NOTICE, "Default RX Antenna: '%s'\n", got_antenna); - soapy_close(); - return 1; - } - - if (SoapySDRDevice_setAntenna(sdr, SOAPY_SDR_RX, channel, rx_antenna) != 0) { - PDEBUG(DSOAPY, DEBUG_ERROR, "Failed to set RX antenna to '%s'\n", rx_antenna); - soapy_close(); - return -EIO; - } - got_antenna = SoapySDRDevice_getAntenna(sdr, SOAPY_SDR_RX, channel); - if (!!strcasecmp(rx_antenna, got_antenna)) { - PDEBUG(DSOAPY, DEBUG_NOTICE, "Given RX antenna '%s' was accepted, but driver claims to use '%s'\n", rx_antenna, got_antenna); - soapy_close(); - return -EINVAL; - } - } - - /* set rate */ - if (SoapySDRDevice_setSampleRate(sdr, SOAPY_SDR_RX, channel, rate) != 0) { - PDEBUG(DSOAPY, DEBUG_ERROR, "Failed to set RX rate to %.0f Hz\n", rate); - soapy_close(); - return -EIO; - } - - /* see what rate actually is */ - got_rate = SoapySDRDevice_getSampleRate(sdr, SOAPY_SDR_RX, channel); - if (fabs(got_rate - rate) > 1.0) { - PDEBUG(DSOAPY, DEBUG_ERROR, "Given RX rate %.3f Hz is not supported, try %.3f Hz\n", rate, got_rate); - soapy_close(); - return -EINVAL; - } - - if (rx_gain) { - /* set gain */ - if (SoapySDRDevice_setGain(sdr, SOAPY_SDR_RX, channel, rx_gain) != 0) { - PDEBUG(DSOAPY, DEBUG_ERROR, "Failed to set RX gain to %.0f\n", rx_gain); - soapy_close(); - return -EIO; - } - - /* see what gain actually is */ - got_gain = SoapySDRDevice_getGain(sdr, SOAPY_SDR_RX, channel); - if (fabs(got_gain - rx_gain) > 0.001) { - PDEBUG(DSOAPY, DEBUG_NOTICE, "Given RX gain %.3f is not supported, we use %.3f\n", rx_gain, got_gain); - rx_gain = got_gain; - } - } - - /* set frequency */ - if (SoapySDRDevice_setFrequency(sdr, SOAPY_SDR_RX, channel, rx_frequency, &tune_args) != 0) { - PDEBUG(DSOAPY, DEBUG_ERROR, "Failed to set RX frequency to %.0f Hz\n", rx_frequency); - soapy_close(); - return -EIO; - } - - /* see what frequency actually is */ - got_frequency = SoapySDRDevice_getFrequency(sdr, SOAPY_SDR_RX, channel); - if (fabs(got_frequency - rx_frequency) > 100.0) { - PDEBUG(DSOAPY, DEBUG_ERROR, "Given RX frequency %.0f Hz is not supported, try %.0f Hz\n", rx_frequency, got_frequency); - soapy_close(); - return -EINVAL; - } - - /* set bandwidth */ - if (SoapySDRDevice_setBandwidth(sdr, SOAPY_SDR_RX, channel, bandwidth) != 0) { - PDEBUG(DSOAPY, DEBUG_ERROR, "Failed to set RX bandwidth to %.0f Hz\n", bandwidth); - soapy_close(); - return -EIO; - } - - /* see what bandwidth actually is */ - got_bandwidth = SoapySDRDevice_getBandwidth(sdr, SOAPY_SDR_RX, channel); - if (fabs(got_bandwidth - bandwidth) > 100.0) { - PDEBUG(DSOAPY, DEBUG_ERROR, "Given RX bandwidth %.0f Hz is not supported, try %.0f Hz\n", bandwidth, got_bandwidth); - soapy_close(); - return -EINVAL; - } - - /* set up streamer */ - if (SoapySDRDevice_setupStream(sdr, &rxStream, SOAPY_SDR_RX, SOAPY_SDR_CF32, &channel, 1, &stream_args) != 0) { - PDEBUG(DSOAPY, DEBUG_ERROR, "Failed to set RX streamer args\n"); - soapy_close(); - return -EIO; - } - - /* get buffer sizes */ - rx_samps_per_buff = SoapySDRDevice_getStreamMTU(sdr, rxStream); - if (rx_samps_per_buff == 0) { - PDEBUG(DSOAPY, DEBUG_ERROR, "Failed to get RX streamer sample buffer\n"); - soapy_close(); - return -EIO; - } - } - - return 0; -} - -/* start streaming */ -int soapy_start(void) -{ - /* enable rx stream */ - if (SoapySDRDevice_activateStream(sdr, rxStream, 0, 0, 0) != 0) { - PDEBUG(DSOAPY, DEBUG_ERROR, "Failed to issue RX stream command\n"); - return -EIO; - } - - /* enable tx stream */ - if (SoapySDRDevice_activateStream(sdr, txStream, 0, 0, 0) != 0) { - PDEBUG(DSOAPY, DEBUG_ERROR, "Failed to issue TX stream command\n"); - return -EIO; - } - return 0; -} - -void soapy_close(void) -{ - PDEBUG(DSOAPY, DEBUG_DEBUG, "Clean up SoapySDR\n"); - if (txStream) { - SoapySDRDevice_deactivateStream(sdr, txStream, 0, 0); - SoapySDRDevice_closeStream(sdr, txStream); - txStream = NULL; - } - if (rxStream) { - SoapySDRDevice_deactivateStream(sdr, rxStream, 0, 0); - SoapySDRDevice_closeStream(sdr, rxStream); - rxStream = NULL; - } - if (sdr) { - SoapySDRDevice_unmake(sdr); - sdr = NULL; - } -} - -int soapy_send(float *buff, int num) -{ - const void *buffs_ptr[1]; - int chunk; - int sent = 0, count; - int flags = 0; - - while (num) { - chunk = num; - if (chunk > tx_samps_per_buff) - chunk = tx_samps_per_buff; - /* create tx metadata */ - buffs_ptr[0] = buff; - count = SoapySDRDevice_writeStream(sdr, txStream, buffs_ptr, chunk, &flags, 0, 1000000); - if (count <= 0) { - PDEBUG(DUHD, DEBUG_ERROR, "Failed to write to TX streamer (error=%d)\n", count); - break; - } - - sent += count; - buff += count * 2; - num -= count; - } - /* increment tx counter */ - tx_count += sent; - - return sent; -} - -/* read what we got, return 0, if buffer is empty, otherwise return the number of samples */ -int soapy_receive(float *buff, int max) -{ - void *buffs_ptr[1]; - int got = 0, count; - long long timeNs; - int flags = 0; - - while (1) { - if (max < rx_samps_per_buff) { - /* no more space this time */ - PDEBUG(DSOAPY, DEBUG_ERROR, "SDR RX overflow!\n"); - break; - } - /* read RX stream */ - buffs_ptr[0] = buff; - count = SoapySDRDevice_readStream(sdr, rxStream, buffs_ptr, rx_samps_per_buff, &flags, &timeNs, 0); - if (count > 0) { - /* commit received data to buffer */ - got += count; - buff += count * 2; - max -= count; - } else { - /* got nothing this time */ - break; - } - } - /* update current rx time */ - rx_count += got; - - return got; -} - -/* estimate number of samples that can be sent */ -int soapy_get_tosend(int latspl) -{ - int tosend; - - /* we need the rx time stamp to determine how much data is already sent in advance */ - if (rx_count == 0) - return 0; - - /* if we have not yet sent any data, we set initial tx time stamp */ - if (tx_count == 0) - tx_count = rx_count; - - /* we check how advance our transmitted time stamp is */ - tosend = latspl - (tx_count - rx_count); - /* in case of underrun: */ - if (tosend > latspl) { -// It is normal that we have underruns, prior inital filling of buffer. -// FIXME: better solution to detect underrun -// PDEBUG(DSOAPY, DEBUG_ERROR, "SDR TX underrun!\n"); - tosend = 0; - tx_count = rx_count; - } - if (tosend < 0) - tosend = 0; - - return tosend; -} - diff --git a/src/common/soapy.h b/src/common/soapy.h deleted file mode 100644 index 702890b..0000000 --- a/src/common/soapy.h +++ /dev/null @@ -1,8 +0,0 @@ - -int soapy_open(size_t channel, const char *_device_args, const char *_stream_args, const char *_tune_args, const char *tx_antenna, const char *rx_antenna, double tx_frequency, double rx_frequency, double rate, double tx_gain, double rx_gain, double bandwidth); -int soapy_start(void); -void soapy_close(void); -int soapy_send(float *buff, int num); -int soapy_receive(float *buff, int max); -int soapy_get_tosend(int latspl); - diff --git a/src/common/uhd.c b/src/common/uhd.c deleted file mode 100644 index e79b1f7..0000000 --- a/src/common/uhd.c +++ /dev/null @@ -1,583 +0,0 @@ -/* UHD device access - * - * (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 <stdlib.h> -#include <stdint.h> -#include <string.h> -#include <errno.h> -#include <math.h> -#include <uhd.h> -#include <uhd/usrp/usrp.h> -#include "uhd.h" -#include "debug.h" - -/* use to TX time stamp */ -//#define TX_TIMESTAMP - -static uhd_usrp_handle usrp = NULL; -static uhd_tx_streamer_handle tx_streamer = NULL; -static uhd_rx_streamer_handle rx_streamer = NULL; -static uhd_tx_metadata_handle tx_metadata = NULL; -static uhd_rx_metadata_handle rx_metadata = NULL; -static uhd_tune_request_t tune_request; -static uhd_tune_result_t tune_result; -static uhd_stream_args_t stream_args; -static uhd_stream_cmd_t stream_cmd; -static size_t tx_samps_per_buff, rx_samps_per_buff; -static double samplerate; -static time_t rx_time_secs = 0; -static double rx_time_fract_sec = 0.0; -static time_t tx_time_secs = 0; -static double tx_time_fract_sec = 0.0; -static int tx_timestamps; - -int uhd_open(size_t channel, const char *_device_args, const char *_stream_args, const char *_tune_args, const char *tx_antenna, const char *rx_antenna, double tx_frequency, double rx_frequency, double rate, double tx_gain, double rx_gain, double bandwidth, int _tx_timestamps) -{ - uhd_error error; - double got_frequency, got_rate, got_gain, got_bandwidth; - char got_antenna[64]; - - samplerate = rate; - tx_timestamps = _tx_timestamps; - - PDEBUG(DUHD, DEBUG_INFO, "Using device args \"%s\"\n", _device_args); - PDEBUG(DUHD, DEBUG_INFO, "Using stream args \"%s\"\n", _stream_args); - PDEBUG(DUHD, DEBUG_INFO, "Using tune args \"%s\"\n", _tune_args); - - /* create USRP */ - PDEBUG(DUHD, DEBUG_INFO, "Creating USRP with args \"%s\"...\n", _device_args); - error = uhd_usrp_make(&usrp, _device_args); - if (error) { - PDEBUG(DUHD, DEBUG_ERROR, "Failed to create USRP\n"); - uhd_close(); - return -EIO; - } - - if (tx_frequency) { - /* antenna */ - if (tx_antenna && tx_antenna[0]) { - if (!strcasecmp(tx_antenna, "list")) { - uhd_string_vector_handle antennas; - size_t antennas_length; - int i; - error = uhd_string_vector_make(&antennas); - if (error) { - tx_vector_error: - PDEBUG(DUHD, DEBUG_ERROR, "Failed to hande UHD vector, please fix!\n"); - uhd_close(); - return -EIO; - } - error = uhd_usrp_get_tx_antennas(usrp, channel, &antennas); - if (error) { - PDEBUG(DUHD, DEBUG_ERROR, "Failed to request list of TX antennas!\n"); - uhd_close(); - return -EIO; - } - error = uhd_string_vector_size(antennas, &antennas_length); - if (error) - goto tx_vector_error; - for (i = 0; i < (int)antennas_length; i++) { - error = uhd_string_vector_at(antennas, i, got_antenna, sizeof(got_antenna)); - if (error) - goto tx_vector_error; - PDEBUG(DUHD, DEBUG_NOTICE, "TX Antenna: '%s'\n", got_antenna); - } - uhd_string_vector_free(&antennas); - error = uhd_usrp_get_tx_antenna(usrp, channel, got_antenna, sizeof(got_antenna)); - if (error) { - PDEBUG(DUHD, DEBUG_ERROR, "Failed to get TX antenna\n"); - uhd_close(); - return -EINVAL; - } - PDEBUG(DUHD, DEBUG_NOTICE, "Default TX Antenna: '%s'\n", got_antenna); - uhd_close(); - return 1; - } - error = uhd_usrp_set_tx_antenna(usrp, tx_antenna, channel); - if (error) { - PDEBUG(DUHD, DEBUG_ERROR, "Failed to set TX antenna to '%s'\n", tx_antenna); - uhd_close(); - return -EIO; - } - error = uhd_usrp_get_tx_antenna(usrp, channel, got_antenna, sizeof(got_antenna)); - if (error) { - PDEBUG(DUHD, DEBUG_ERROR, "Failed to get TX antenna\n"); - uhd_close(); - return -EINVAL; - } - if (!!strcasecmp(tx_antenna, got_antenna)) { - PDEBUG(DUHD, DEBUG_NOTICE, "Given TX antenna '%s' was accepted, but driver claims to use '%s'\n", tx_antenna, got_antenna); - uhd_close(); - return -EINVAL; - } - } - - /* create streamers */ - error = uhd_tx_streamer_make(&tx_streamer); - if (error) { - PDEBUG(DUHD, DEBUG_ERROR, "Failed to create TX streamer\n"); - uhd_close(); - return -EIO; - } - - /* set rate */ - error = uhd_usrp_set_tx_rate(usrp, rate, channel); - if (error) { - PDEBUG(DUHD, DEBUG_ERROR, "Failed to set TX rate to %.0f Hz\n", rate); - uhd_close(); - return -EIO; - } - - /* see what rate actually is */ - error = uhd_usrp_get_tx_rate(usrp, channel, &got_rate); - if (error) { - PDEBUG(DUHD, DEBUG_ERROR, "Failed to get TX rate\n"); - uhd_close(); - return -EIO; - } - if (fabs(got_rate - rate) > 0.001) { - PDEBUG(DUHD, DEBUG_ERROR, "Given TX rate %.0f Hz is not supported, try %.0f Hz\n", rate, got_rate); - uhd_close(); - return -EINVAL; - } - - /* set gain */ - error = uhd_usrp_set_tx_gain(usrp, tx_gain, channel, ""); - if (error) { - PDEBUG(DUHD, DEBUG_ERROR, "Failed to set TX gain to %.0f\n", tx_gain); - uhd_close(); - return -EIO; - } - - /* see what gain actually is */ - error = uhd_usrp_get_tx_gain(usrp, channel, "", &got_gain); - if (error) { - PDEBUG(DUHD, DEBUG_ERROR, "Failed to get TX gain\n"); - uhd_close(); - return -EIO; - } - if (fabs(got_gain - tx_gain) > 0.001) { - PDEBUG(DUHD, DEBUG_NOTICE, "Given TX gain %.0f is not supported, we use %.0f\n", tx_gain, got_gain); - tx_gain = got_gain; - } - - /* set frequency */ - memset(&tune_request, 0, sizeof(tune_request)); - tune_request.target_freq = tx_frequency; - tune_request.rf_freq_policy = UHD_TUNE_REQUEST_POLICY_AUTO; - tune_request.dsp_freq_policy = UHD_TUNE_REQUEST_POLICY_AUTO; - tune_request.args = strdup(_tune_args); - error = uhd_usrp_set_tx_freq(usrp, &tune_request, channel, &tune_result); - if (error) { - PDEBUG(DUHD, DEBUG_ERROR, "Failed to set TX frequeny to %.0f Hz\n", tx_frequency); - uhd_close(); - return -EIO; - } - - /* see what frequency actually is */ - error = uhd_usrp_get_tx_freq(usrp, channel, &got_frequency); - if (error) { - PDEBUG(DUHD, DEBUG_ERROR, "Failed to get TX frequency\n"); - uhd_close(); - return -EIO; - } - if (fabs(got_frequency - tx_frequency) > 100.0) { - PDEBUG(DUHD, DEBUG_ERROR, "Given TX frequency %.0f Hz is not supported, try %.0f Hz\n", tx_frequency, got_frequency); - uhd_close(); - return -EINVAL; - } - - /* set bandwidth */ - if (uhd_usrp_set_tx_bandwidth(usrp, bandwidth, channel) != 0) { - PDEBUG(DUHD, DEBUG_ERROR, "Failed to set TX bandwidth to %.0f Hz\n", bandwidth); - uhd_close(); - return -EIO; - } - - /* see what bandwidth actually is */ - error = uhd_usrp_get_tx_bandwidth(usrp, channel, &got_bandwidth); - if (error) { - PDEBUG(DUHD, DEBUG_ERROR, "Failed to get TX bandwidth\n"); - uhd_close(); - return -EIO; - } - if (fabs(got_bandwidth - bandwidth) > 0.001) { - PDEBUG(DUHD, DEBUG_ERROR, "Given TX bandwidth %.0f Hz is not supported, try %.0f Hz\n", bandwidth, got_bandwidth); - uhd_close(); - return -EINVAL; - } - - /* set up streamer */ - memset(&stream_args, 0, sizeof(stream_args)); - stream_args.cpu_format = "fc32"; - stream_args.otw_format = "sc16"; - stream_args.args = strdup(_stream_args); - stream_args.channel_list = &channel; - stream_args.n_channels = 1; - error = uhd_usrp_get_tx_stream(usrp, &stream_args, tx_streamer); - if (error) { - PDEBUG(DUHD, DEBUG_ERROR, "Failed to set TX streamer args\n"); - uhd_close(); - return -EIO; - } - - /* get buffer sizes */ - error = uhd_tx_streamer_max_num_samps(tx_streamer, &tx_samps_per_buff); - if (error) { - PDEBUG(DUHD, DEBUG_ERROR, "Failed to get TX streamer sample buffer\n"); - uhd_close(); - return -EIO; - } - } - - if (rx_frequency) { - /* antenna */ - if (rx_antenna && rx_antenna[0]) { - if (!strcasecmp(rx_antenna, "list")) { - uhd_string_vector_handle antennas; - size_t antennas_length; - int i; - error = uhd_string_vector_make(&antennas); - if (error) { - rx_vector_error: - PDEBUG(DUHD, DEBUG_ERROR, "Failed to hande UHD vector, please fix!\n"); - uhd_close(); - return -EIO; - } - error = uhd_usrp_get_rx_antennas(usrp, channel, &antennas); - if (error) { - PDEBUG(DUHD, DEBUG_ERROR, "Failed to request list of RX antennas!\n"); - uhd_close(); - return -EIO; - } - error = uhd_string_vector_size(antennas, &antennas_length); - if (error) - goto rx_vector_error; - for (i = 0; i < (int)antennas_length; i++) { - error = uhd_string_vector_at(antennas, i, got_antenna, sizeof(got_antenna)); - if (error) - goto rx_vector_error; - PDEBUG(DUHD, DEBUG_NOTICE, "RX Antenna: '%s'\n", got_antenna); - } - uhd_string_vector_free(&antennas); - error = uhd_usrp_get_rx_antenna(usrp, channel, got_antenna, sizeof(got_antenna)); - if (error) { - PDEBUG(DUHD, DEBUG_ERROR, "Failed to get RX antenna\n"); - uhd_close(); - return -EINVAL; - } - PDEBUG(DUHD, DEBUG_NOTICE, "Default RX Antenna: '%s'\n", got_antenna); - uhd_close(); - return 1; - } - error = uhd_usrp_set_rx_antenna(usrp, rx_antenna, channel); - if (error) { - PDEBUG(DUHD, DEBUG_ERROR, "Failed to set RX antenna to '%s'\n", rx_antenna); - uhd_close(); - return -EIO; - } - error = uhd_usrp_get_rx_antenna(usrp, channel, got_antenna, sizeof(got_antenna)); - if (error) { - PDEBUG(DUHD, DEBUG_ERROR, "Failed to get RX antenna\n"); - uhd_close(); - return -EINVAL; - } - if (!!strcasecmp(rx_antenna, got_antenna)) { - PDEBUG(DUHD, DEBUG_NOTICE, "Given RX antenna '%s' was accepted, but driver claims to use '%s'\n", rx_antenna, got_antenna); - uhd_close(); - return -EINVAL; - } - } - /* create streamers */ - error = uhd_rx_streamer_make(&rx_streamer); - if (error) { - PDEBUG(DUHD, DEBUG_ERROR, "Failed to create RX streamer\n"); - uhd_close(); - return -EIO; - } - - /* create metadata */ - error = uhd_rx_metadata_make(&rx_metadata); - if (error) { - PDEBUG(DUHD, DEBUG_ERROR, "Failed to create RX metadata\n"); - uhd_close(); - return -EIO; - } - - /* set rate */ - error = uhd_usrp_set_rx_rate(usrp, rate, channel); - if (error) { - PDEBUG(DUHD, DEBUG_ERROR, "Failed to set RX rate to %.0f Hz\n", rate); - uhd_close(); - return -EIO; - } - - /* see what rate actually is */ - error = uhd_usrp_get_rx_rate(usrp, channel, &got_rate); - if (error) { - PDEBUG(DUHD, DEBUG_ERROR, "Failed to get RX rate\n"); - uhd_close(); - return -EIO; - } - if (fabs(got_rate - rate) > 0.001) { - PDEBUG(DUHD, DEBUG_ERROR, "Given RX rate %.0f Hz is not supported, try %.0f Hz\n", rate, got_rate); - uhd_close(); - return -EINVAL; - } - - /* set gain */ - error = uhd_usrp_set_rx_gain(usrp, rx_gain, channel, ""); - if (error) { - PDEBUG(DUHD, DEBUG_ERROR, "Failed to set RX gain to %.0f\n", rx_gain); - uhd_close(); - return -EIO; - } - - /* see what gain actually is */ - error = uhd_usrp_get_rx_gain(usrp, channel, "", &got_gain); - if (error) { - PDEBUG(DUHD, DEBUG_ERROR, "Failed to get RX gain\n"); - uhd_close(); - return -EIO; - } - if (fabs(got_gain - rx_gain) > 0.001) { - PDEBUG(DUHD, DEBUG_NOTICE, "Given RX gain %.3f is not supported, we use %.3f\n", rx_gain, got_gain); - rx_gain = got_gain; - } - - /* set frequency */ - memset(&tune_request, 0, sizeof(tune_request)); - tune_request.target_freq = rx_frequency; - tune_request.rf_freq_policy = UHD_TUNE_REQUEST_POLICY_AUTO; - tune_request.dsp_freq_policy = UHD_TUNE_REQUEST_POLICY_AUTO; - tune_request.args = strdup(_tune_args); - error = uhd_usrp_set_rx_freq(usrp, &tune_request, channel, &tune_result); - if (error) { - PDEBUG(DUHD, DEBUG_ERROR, "Failed to set RX frequeny to %.0f Hz\n", rx_frequency); - uhd_close(); - return -EIO; - } - - /* see what frequency actually is */ - error = uhd_usrp_get_rx_freq(usrp, channel, &got_frequency); - if (error) { - PDEBUG(DUHD, DEBUG_ERROR, "Failed to get RX frequency\n"); - uhd_close(); - return -EIO; - } - if (fabs(got_frequency - rx_frequency) > 100.0) { - PDEBUG(DUHD, DEBUG_ERROR, "Given RX frequency %.0f Hz is not supported, try %.0f Hz\n", rx_frequency, got_frequency); - uhd_close(); - return -EINVAL; - } - - /* set bandwidth */ - if (uhd_usrp_set_rx_bandwidth(usrp, bandwidth, channel) != 0) { - PDEBUG(DUHD, DEBUG_ERROR, "Failed to set RX bandwidth to %.0f Hz\n", bandwidth); - uhd_close(); - return -EIO; - } - - /* see what bandwidth actually is */ - error = uhd_usrp_get_rx_bandwidth(usrp, channel, &got_bandwidth); - if (error) { - PDEBUG(DUHD, DEBUG_ERROR, "Failed to get RX bandwidth\n"); - uhd_close(); - return -EIO; - } - if (fabs(got_bandwidth - bandwidth) > 0.001) { - PDEBUG(DUHD, DEBUG_ERROR, "Given RX bandwidth %.0f Hz is not supported, try %.0f Hz\n", bandwidth, got_bandwidth); - uhd_close(); - return -EINVAL; - } - - /* set up streamer */ - memset(&stream_args, 0, sizeof(stream_args)); - stream_args.cpu_format = "fc32"; - stream_args.otw_format = "sc16"; - stream_args.args = strdup(_stream_args); - stream_args.channel_list = &channel; - stream_args.n_channels = 1; - error = uhd_usrp_get_rx_stream(usrp, &stream_args, rx_streamer); - if (error) { - PDEBUG(DUHD, DEBUG_ERROR, "Failed to set RX streamer args\n"); - uhd_close(); - return -EIO; - } - - /* get buffer sizes */ - error = uhd_rx_streamer_max_num_samps(rx_streamer, &rx_samps_per_buff); - if (error) { - PDEBUG(DUHD, DEBUG_ERROR, "Failed to get RX streamer sample buffer\n"); - uhd_close(); - return -EIO; - } - } - - return 0; -} - -/* start streaming */ -int uhd_start(void) -{ - uhd_error error; - - /* enable rx stream */ - memset(&stream_cmd, 0, sizeof(stream_cmd)); - stream_cmd.stream_mode = UHD_STREAM_MODE_START_CONTINUOUS; - stream_cmd.stream_now = true; - error = uhd_rx_streamer_issue_stream_cmd(rx_streamer, &stream_cmd); - if (error) { - PDEBUG(DUHD, DEBUG_ERROR, "Failed to issue RX stream command\n"); - return -EIO; - } - return 0; -} - -void uhd_close(void) -{ - PDEBUG(DUHD, DEBUG_DEBUG, "Clean up UHD\n"); - if (tx_metadata) - uhd_tx_metadata_free(&tx_metadata); - if (rx_metadata) - uhd_rx_metadata_free(&rx_metadata); - if (tx_streamer) - uhd_tx_streamer_free(&tx_streamer); - if (rx_streamer) - uhd_rx_streamer_free(&rx_streamer); - if (usrp) - uhd_usrp_free(&usrp); -} - -int uhd_send(float *buff, int num) -{ - const void *buffs_ptr[1]; - int chunk; - size_t sent = 0, count; - uhd_error error; - - while (num) { - chunk = num; - if (chunk > (int)tx_samps_per_buff) - chunk = (int)tx_samps_per_buff; - /* create tx metadata */ - if (tx_timestamps) - error = uhd_tx_metadata_make(&tx_metadata, true, tx_time_secs, tx_time_fract_sec, false, false); - else - error = uhd_tx_metadata_make(&tx_metadata, false, 0, 0.0, false, false); - if (error) - PDEBUG(DUHD, DEBUG_ERROR, "Failed to create TX metadata\n"); - buffs_ptr[0] = buff; - count = 0; - error = uhd_tx_streamer_send(tx_streamer, buffs_ptr, chunk, &tx_metadata, 1.0, &count); - if (error) { - PDEBUG(DUHD, DEBUG_ERROR, "Failed to write to TX streamer\n"); - break; - } - if (count == 0) - break; - - /* increment time stamp */ - tx_time_fract_sec += (double)count / samplerate; - while (tx_time_fract_sec >= 1.0) { - tx_time_secs++; - tx_time_fract_sec -= 1.0; - } -//printf("adv=%.3f\n", ((double)tx_time_secs + tx_time_fract_sec) - ((double)rx_time_secs + rx_time_fract_sec)); - - sent += count; - buff += count * 2; - num -= count; - } - - return sent; -} - -/* read what we got, return 0, if buffer is empty, otherwise return the number of samples */ -int uhd_receive(float *buff, int max) -{ - void *buffs_ptr[1]; - size_t got = 0, count; - uhd_error error; - - while (1) { - if (max < (int)rx_samps_per_buff) { - /* no more space this time */ - PDEBUG(DUHD, DEBUG_ERROR, "SDR RX overflow!\n"); - break; - } - /* read RX stream */ - buffs_ptr[0] = buff; - count = 0; - error = uhd_rx_streamer_recv(rx_streamer, buffs_ptr, rx_samps_per_buff, &rx_metadata, 0.0, false, &count); - if (error) { - PDEBUG(DUHD, DEBUG_ERROR, "Failed to read from UHD device.\n"); - break; - } - if (count) { - /* get time stamp of received RX packet */ - uhd_rx_metadata_time_spec(rx_metadata, &rx_time_secs, &rx_time_fract_sec); - /* commit received data to buffer */ - got += count; - buff += count * 2; - max -= count; - } else { - /* got nothing this time */ - break; - } - } - - return got; -} - -/* estimate number of samples that can be sent */ -int uhd_get_tosend(int latspl) -{ - double advance; - int tosend; - - /* we need the rx time stamp to determine how much data is already sent in advance */ - if (rx_time_secs == 0 && rx_time_fract_sec == 0.0) - return 0; - - /* if we have not yet sent any data, we set initial tx time stamp */ - if (tx_time_secs == 0 && tx_time_fract_sec == 0.0) { - tx_time_secs = rx_time_secs; - tx_time_fract_sec = rx_time_fract_sec; - if (tx_timestamps) { - tx_time_fract_sec += (double)latspl / samplerate; - if (tx_time_fract_sec >= 1.0) { - tx_time_fract_sec -= 1.0; - tx_time_secs++; - } - } - } - - /* we check how advance our transmitted time stamp is */ - advance = ((double)tx_time_secs + tx_time_fract_sec) - ((double)rx_time_secs + rx_time_fract_sec); - /* in case of underrun: */ - if (advance < 0) - advance = 0; - tosend = latspl - (int)(advance * samplerate); - if (tosend < 0) - tosend = 0; - - return tosend; -} - diff --git a/src/common/uhd.h b/src/common/uhd.h deleted file mode 100644 index 60eb94f..0000000 --- a/src/common/uhd.h +++ /dev/null @@ -1,8 +0,0 @@ - -int uhd_open(size_t channel, const char *_device_args, const char *_stream_args, const char *_tune_args, const char *tx_antenna, const char *rx_antenna, double tx_frequency, double rx_frequency, double rate, double tx_gain, double rx_gain, double bandwidth, int _tx_timestamps); -int uhd_start(void); -void uhd_close(void); -int uhd_send(float *buff, int num); -int uhd_receive(float *buff, int max); -int uhd_get_tosend(int latspl); - |