summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/librtlsdr.c2
-rw-r--r--src/rtl_adsb.c106
-rw-r--r--src/rtl_fm.c182
3 files changed, 199 insertions, 91 deletions
diff --git a/src/librtlsdr.c b/src/librtlsdr.c
index 4224163..b0185d2 100644
--- a/src/librtlsdr.c
+++ b/src/librtlsdr.c
@@ -229,7 +229,7 @@ typedef struct rtlsdr_dongle {
* Please add your device here and send a patch to osmocom-sdr@lists.osmocom.org
*/
static rtlsdr_dongle_t known_devices[] = {
- { 0x0bda, 0x2832, "Generic RTL2832U (e.g. hama nano)" },
+ { 0x0bda, 0x2832, "Generic RTL2832U" },
{ 0x0bda, 0x2838, "ezcap USB 2.0 DVB-T/DAB/FM dongle" },
{ 0x0ccd, 0x00a9, "Terratec Cinergy T Stick Black (rev 1)" },
{ 0x0ccd, 0x00b3, "Terratec NOXON DAB/DAB+ USB dongle (rev 1)" },
diff --git a/src/rtl_adsb.c b/src/rtl_adsb.c
index 2fb7418..44b62e2 100644
--- a/src/rtl_adsb.c
+++ b/src/rtl_adsb.c
@@ -37,7 +37,6 @@
#include "getopt/getopt.h"
#endif
-#include <semaphore.h>
#include <pthread.h>
#include <libusb.h>
@@ -54,16 +53,19 @@
#define DEFAULT_BUF_LENGTH (16 * 16384)
#define AUTO_GAIN -100
+#define MESSAGEGO 253
+#define OVERWRITE 254
+#define BADSAMPLE 255
+
static pthread_t demod_thread;
-static sem_t data_ready;
+static pthread_mutex_t data_ready; /* locked when no data available */
static volatile int do_exit = 0;
static rtlsdr_dev_t *dev = NULL;
-/* look up table, could be made smaller */
-uint8_t pyth[129][129];
+uint16_t squares[256];
/* todo, bundle these up in a struct */
-uint8_t *buffer;
+uint8_t *buffer; /* also abused for uint16_t */
int verbose_output = 0;
int short_output = 0;
double quality = 1.0;
@@ -141,17 +143,7 @@ void display(int *frame, int len)
fprintf(file, "--------------\n");
}
-void pyth_precompute(void)
-{
- int x, y;
- double scale = 1.408 ; /* use the full 8 bits */
- for (x=0; x<129; x++) {
- for (y=0; y<129; y++) {
- pyth[x][y] = (uint8_t)round(scale * sqrt(x*x + y*y));
- }}
-}
-
-inline uint8_t abs8(uint8_t x)
+int abs8(int x)
/* do not subtract 128 from the raw iq, this handles it */
{
if (x >= 128) {
@@ -159,18 +151,31 @@ inline uint8_t abs8(uint8_t x)
return 128 - x;
}
+void squares_precompute(void)
+/* equiv to abs(x-128) ^ 2 */
+{
+ int i, j;
+ // todo, check if this LUT is actually any faster
+ for (i=0; i<256; i++) {
+ j = abs8(i);
+ squares[i] = (uint16_t)(j*j);
+ }
+}
+
int magnitute(uint8_t *buf, int len)
-/* takes i/q, changes buf in place, returns new len */
+/* takes i/q, changes buf in place (16 bit), returns new len (16 bit) */
{
int i;
+ uint16_t *m;
for (i=0; i<len; i+=2) {
- buf[i/2] = pyth[abs8(buf[i])][abs8(buf[i+1])];
+ m = (uint16_t*)(&buf[i]);
+ *m = squares[buf[i]] + squares[buf[i+1]];
}
return len/2;
}
-inline uint8_t single_manchester(uint8_t a, uint8_t b, uint8_t c, uint8_t d)
-/* takes 4 consecutive real samples, return 0 or 1, 255 on error */
+inline uint16_t single_manchester(uint16_t a, uint16_t b, uint16_t c, uint16_t d)
+/* takes 4 consecutive real samples, return 0 or 1, BADSAMPLE on error */
{
int bit, bit_p;
bit_p = a > b;
@@ -181,9 +186,9 @@ inline uint8_t single_manchester(uint8_t a, uint8_t b, uint8_t c, uint8_t d)
if (quality == 0.5) {
if ( bit && bit_p && b > c) {
- return 255;}
+ return BADSAMPLE;}
if (!bit && !bit_p && b < c) {
- return 255;}
+ return BADSAMPLE;}
return bit;
}
@@ -196,7 +201,7 @@ inline uint8_t single_manchester(uint8_t a, uint8_t b, uint8_t c, uint8_t d)
return 0;}
if (!bit && !bit_p && c < b) {
return 0;}
- return 255;
+ return BADSAMPLE;
}
if ( bit && bit_p && c > b && d < a) {
@@ -207,36 +212,36 @@ inline uint8_t single_manchester(uint8_t a, uint8_t b, uint8_t c, uint8_t d)
return 0;}
if (!bit && !bit_p && c < b && d > a) {
return 0;}
- return 255;
+ return BADSAMPLE;
}
-inline uint8_t min8(uint8_t a, uint8_t b)
+inline uint16_t min16(uint16_t a, uint16_t b)
{
return a<b ? a : b;
}
-inline uint8_t max8(uint8_t a, uint8_t b)
+inline uint16_t max16(uint16_t a, uint16_t b)
{
return a>b ? a : b;
}
-inline int preamble(uint8_t *buf, int len, int i)
+inline int preamble(uint16_t *buf, int i)
/* returns 0/1 for preamble at index i */
{
int i2;
- uint8_t low = 0;
- uint8_t high = 255;
+ uint16_t low = 0;
+ uint16_t high = 65535;
for (i2=0; i2<preamble_len; i2++) {
switch (i2) {
case 0:
case 2:
case 7:
case 9:
- //high = min8(high, buf[i+i2]);
+ //high = min16(high, buf[i+i2]);
high = buf[i+i2];
break;
default:
- //low = max8(low, buf[i+i2]);
+ //low = max16(low, buf[i+i2]);
low = buf[i+i2];
break;
}
@@ -246,24 +251,24 @@ inline int preamble(uint8_t *buf, int len, int i)
return 1;
}
-void manchester(uint8_t *buf, int len)
-/* overwrites magnitude buffer with valid bits (255 on errors) */
+void manchester(uint16_t *buf, int len)
+/* overwrites magnitude buffer with valid bits (BADSAMPLE on errors) */
{
/* a and b hold old values to verify local manchester */
- uint8_t a=0, b=0;
- uint8_t bit;
+ uint16_t a=0, b=0;
+ uint16_t bit;
int i, i2, start, errors;
// todo, allow wrap across buffers
i = 0;
while (i < len) {
/* find preamble */
for ( ; i < (len - preamble_len); i++) {
- if (!preamble(buf, len, i)) {
+ if (!preamble(buf, i)) {
continue;}
a = buf[i];
b = buf[i+1];
for (i2=0; i2<preamble_len; i2++) {
- buf[i+i2] = 253;}
+ buf[i+i2] = MESSAGEGO;}
i += preamble_len;
break;
}
@@ -274,25 +279,25 @@ void manchester(uint8_t *buf, int len)
bit = single_manchester(a, b, buf[i], buf[i+1]);
a = buf[i];
b = buf[i+1];
- if (bit == 255) {
+ if (bit == BADSAMPLE) {
errors += 1;
if (errors > allowed_errors) {
- buf[i2] = 255;
+ buf[i2] = BADSAMPLE;
break;
} else {
bit = a > b;
/* these don't have to match the bit */
a = 0;
- b = 255;
+ b = 65535;
}
}
- buf[i] = buf[i+1] = 254; /* to be overwritten */
+ buf[i] = buf[i+1] = OVERWRITE;
buf[i2] = bit;
}
}
}
-void messages(uint8_t *buf, int len)
+void messages(uint16_t *buf, int len)
{
int i, i2, start, preamble_found;
int data_i, index, shift, frame_len;
@@ -328,23 +333,21 @@ void messages(uint8_t *buf, int len)
static void rtlsdr_callback(unsigned char *buf, uint32_t len, void *ctx)
{
- int dr_val;
if (do_exit) {
return;}
memcpy(buffer, buf, len);
- sem_getvalue(&data_ready, &dr_val);
- if (dr_val <= 0) {
- sem_post(&data_ready);}
+ pthread_mutex_trylock(&data_ready);
+ pthread_mutex_unlock(&data_ready);
}
static void *demod_thread_fn(void *arg)
{
int len;
while (!do_exit) {
- sem_wait(&data_ready);
+ pthread_mutex_lock(&data_ready);
len = magnitute(buffer, DEFAULT_BUF_LENGTH);
- manchester(buffer, len);
- messages(buffer, len);
+ manchester((uint16_t*)buffer, len);
+ messages((uint16_t*)buffer, len);
}
rtlsdr_cancel_async(dev);
return 0;
@@ -362,8 +365,8 @@ int main(int argc, char **argv)
int device_count;
int ppm_error = 0;
char vendor[256], product[256], serial[256];
- sem_init(&data_ready, 0, 0);
- pyth_precompute();
+ pthread_mutex_init(&data_ready, NULL);
+ squares_precompute();
while ((opt = getopt(argc, argv, "d:g:p:e:Q:VS")) != -1)
{
@@ -501,6 +504,7 @@ int main(int argc, char **argv)
else {
fprintf(stderr, "\nLibrary error %d, exiting...\n", r);}
rtlsdr_cancel_async(dev);
+ pthread_mutex_destroy(&data_ready);
if (file != stdout) {
fclose(file);}
diff --git a/src/rtl_fm.c b/src/rtl_fm.c
index 45f8e06..e8ebb77 100644
--- a/src/rtl_fm.c
+++ b/src/rtl_fm.c
@@ -3,6 +3,7 @@
* Copyright (C) 2012 by Steve Markgraf <steve@steve-m.de>
* Copyright (C) 2012 by Hoernchen <la@tfc-server.de>
* Copyright (C) 2012 by Kyle Keen <keenerd@gmail.com>
+ * Copyright (C) 2013 by Elias Oenal <EliasOenal@gmail.com>
*
* 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
@@ -53,7 +54,6 @@
#define round(x) (x > 0.0 ? floor(x + 0.5): ceil(x - 0.5))
#endif
-#include <semaphore.h>
#include <pthread.h>
#include <libusb.h>
@@ -67,25 +67,25 @@
#define AUTO_GAIN -100
static pthread_t demod_thread;
-static sem_t data_ready;
+static pthread_mutex_t data_ready; /* locked when no fresh data available */
+static pthread_mutex_t data_write; /* locked when r/w buffer */
static int do_exit = 0;
static rtlsdr_dev_t *dev = NULL;
static int lcm_post[17] = {1,1,1,3,1,5,3,7,1,9,5,11,3,13,7,15,1};
+static int *atan_lut = NULL;
+static int atan_lut_size = 131072; /* 512 KB */
+static int atan_lut_coef = 8;
+
struct fm_state
{
- int now_r;
- int now_j;
- int pre_r;
- int pre_j;
+ int now_r, now_j;
+ int pre_r, pre_j;
int prev_index;
int downsample; /* min 1, max 256 */
int post_downsample;
int output_scale;
- int squelch_level;
- int conseq_squelch;
- int squelch_hits;
- int terminate_on_squelch;
+ int squelch_level, conseq_squelch, squelch_hits, terminate_on_squelch;
int exit_flag;
uint8_t buf[MAXIMUM_BUF_LENGTH];
uint32_t buf_len;
@@ -104,10 +104,10 @@ struct fm_state
int fir[256]; /* fir_len == downsample */
int fir_sum;
int custom_atan;
- int deemph;
- int deemph_a;
+ int deemph, deemph_a;
int now_lpr;
int prev_lpr_index;
+ int dc_block, dc_avg;
void (*mode_demod)(struct fm_state*);
};
@@ -128,7 +128,7 @@ void usage(void)
"\t[-E sets lower edge tuning (default: center)]\n"
"\t[-N enables NBFM mode (default: on)]\n"
"\t[-W enables WBFM mode (default: off)]\n"
- "\t (-N -s 170k -o 4 -A -r 32k -l 0 -D)\n"
+ "\t (-N -s 170k -o 4 -A fast -r 32k -l 0 -D)\n"
"\tfilename (a '-' dumps samples to stdout)\n"
"\t (omitting the filename also uses stdout)\n\n"
"Experimental options:\n"
@@ -142,7 +142,8 @@ void usage(void)
"\t[-R enables raw mode (default: off, 2x16 bit output)]\n"
"\t[-F enables high quality FIR (default: off/square)]\n"
"\t[-D enables de-emphasis (default: off)]\n"
- "\t[-A enables high speed arctan (default: off)]\n\n"
+ "\t[-C enables DC blocking of output (default: off)]\n"
+ "\t[-A std/fast/lut choose atan math (default: std)]\n\n"
"Produces signed 16 bit ints, use Sox or aplay to hear them.\n"
"\trtl_fm ... - | play -t raw -r 24k -e signed-integer -b 16 -c 1 -V1 -\n"
"\t | aplay -r 24k -f S16_LE -t raw -c 1\n"
@@ -343,6 +344,57 @@ int polar_disc_fast(int ar, int aj, int br, int bj)
return fast_atan2(cj, cr);
}
+int atan_lut_init()
+{
+ int i = 0;
+
+ atan_lut = malloc(atan_lut_size * sizeof(int));
+
+ for (i = 0; i < atan_lut_size; i++) {
+ atan_lut[i] = (int) (atan((double) i / (1<<atan_lut_coef)) / 3.14159 * (1<<14));
+ }
+
+ return 0;
+}
+
+int polar_disc_lut(int ar, int aj, int br, int bj)
+{
+ int cr, cj, x, x_abs;
+
+ multiply(ar, aj, br, -bj, &cr, &cj);
+
+ /* special cases */
+ if (cr == 0 || cj == 0) {
+ if (cr == 0 && cj == 0)
+ {return 0;}
+ if (cr == 0 && cj > 0)
+ {return 1 << 13;}
+ if (cr == 0 && cj < 0)
+ {return -(1 << 13);}
+ if (cj == 0 && cr > 0)
+ {return 0;}
+ if (cj == 0 && cr < 0)
+ {return 1 << 14;}
+ }
+
+ /* real range -32768 - 32768 use 64x range -> absolute maximum: 2097152 */
+ x = (cj << atan_lut_coef) / cr;
+ x_abs = abs(x);
+
+ if (x_abs >= atan_lut_size) {
+ /* we can use linear range, but it is not necessary */
+ return (cj > 0) ? 1<<13 : -1<<13;
+ }
+
+ if (x > 0) {
+ return (cj > 0) ? atan_lut[x] : atan_lut[x] - (1<<14);
+ } else {
+ return (cj > 0) ? (1<<14) - atan_lut[-x] : -atan_lut[-x];
+ }
+
+ return 0;
+}
+
void fm_demod(struct fm_state *fm)
{
int i, pcm;
@@ -350,12 +402,19 @@ void fm_demod(struct fm_state *fm)
fm->pre_r, fm->pre_j);
fm->signal2[0] = (int16_t)pcm;
for (i = 2; i < (fm->signal_len); i += 2) {
- if (fm->custom_atan) {
+ switch (fm->custom_atan) {
+ case 0:
+ pcm = polar_discriminant(fm->signal[i], fm->signal[i+1],
+ fm->signal[i-2], fm->signal[i-1]);
+ break;
+ case 1:
pcm = polar_disc_fast(fm->signal[i], fm->signal[i+1],
fm->signal[i-2], fm->signal[i-1]);
- } else {
- pcm = polar_discriminant(fm->signal[i], fm->signal[i+1],
+ break;
+ case 2:
+ pcm = polar_disc_lut(fm->signal[i], fm->signal[i+1],
fm->signal[i-2], fm->signal[i-1]);
+ break;
}
fm->signal2[i/2] = (int16_t)pcm;
}
@@ -426,6 +485,21 @@ void deemph_filter(struct fm_state *fm)
}
}
+void dc_block_filter(struct fm_state *fm)
+{
+ int i, avg;
+ int64_t sum = 0;
+ for (i=0; i < fm->signal2_len; i++) {
+ sum += fm->signal2[i];
+ }
+ avg = sum / fm->signal2_len;
+ avg = (avg + fm->dc_avg * 9) / 10;
+ for (i=0; i < fm->signal2_len; i++) {
+ fm->signal2[i] -= avg;
+ }
+ fm->dc_avg = avg;
+}
+
int mad(int *samples, int len, int step)
/* mean average deviation */
{
@@ -506,6 +580,7 @@ void full_demod(struct fm_state *fm)
} else {
low_pass(fm, fm->buf, fm->buf_len);
}
+ pthread_mutex_unlock(&data_write);
fm->mode_demod(fm);
if (fm->mode_demod == &raw_demod) {
fwrite(fm->signal2, 2, fm->signal2_len, fm->file);
@@ -529,6 +604,8 @@ void full_demod(struct fm_state *fm)
}
if (fm->deemph) {
deemph_filter(fm);}
+ if (fm->dc_block) {
+ dc_block_filter(fm);}
/* ignore under runs for now */
fwrite(fm->signal2, 2, fm->signal2_len, fm->file);
if (hop) {
@@ -544,25 +621,23 @@ void full_demod(struct fm_state *fm)
static void rtlsdr_callback(unsigned char *buf, uint32_t len, void *ctx)
{
struct fm_state *fm2 = ctx;
- int dr_val;
if (do_exit) {
return;}
if (!ctx) {
return;}
+ pthread_mutex_lock(&data_write);
memcpy(fm2->buf, buf, len);
fm2->buf_len = len;
+ pthread_mutex_unlock(&data_ready);
/* single threaded uses 25% less CPU? */
/* full_demod(fm2); */
- sem_getvalue(&data_ready, &dr_val);
- if (dr_val <= 0) {
- sem_post(&data_ready);}
}
static void *demod_thread_fn(void *arg)
{
struct fm_state *fm2 = arg;
while (!do_exit) {
- sem_wait(&data_ready);
+ pthread_mutex_lock(&data_ready);
full_demod(fm2);
if (fm2->exit_flag) {
do_exit = 1;
@@ -610,6 +685,31 @@ void frequency_range(struct fm_state *fm, char *arg)
step[-1] = ':';
}
+void fm_init(struct fm_state *fm)
+{
+ fm->freqs[0] = 100000000;
+ fm->sample_rate = DEFAULT_SAMPLE_RATE;
+ fm->squelch_level = 0;
+ fm->conseq_squelch = 20;
+ fm->terminate_on_squelch = 0;
+ fm->squelch_hits = 0;
+ fm->freq_len = 0;
+ fm->edge = 0;
+ fm->fir_enable = 0;
+ fm->prev_index = 0;
+ fm->post_downsample = 1; // once this works, default = 4
+ fm->custom_atan = 0;
+ fm->deemph = 0;
+ fm->output_rate = -1; // flag for disabled
+ fm->mode_demod = &fm_demod;
+ fm->pre_j = fm->pre_r = fm->now_r = fm->now_j = 0;
+ fm->prev_lpr_index = 0;
+ fm->deemph_a = 0;
+ fm->now_lpr = 0;
+ fm->dc_block = 0;
+ fm->dc_avg = 0;
+}
+
int main(int argc, char **argv)
{
#ifndef _WIN32
@@ -624,23 +724,11 @@ int main(int argc, char **argv)
int device_count;
int ppm_error = 0;
char vendor[256], product[256], serial[256];
- fm.freqs[0] = 100000000;
- fm.sample_rate = DEFAULT_SAMPLE_RATE;
- fm.squelch_level = 0;
- fm.conseq_squelch = 20;
- fm.terminate_on_squelch = 0;
- fm.freq_len = 0;
- fm.edge = 0;
- fm.fir_enable = 0;
- fm.prev_index = 0;
- fm.post_downsample = 1; // once this works, default = 4
- fm.custom_atan = 0;
- fm.deemph = 0;
- fm.output_rate = -1; // flag for disabled
- fm.mode_demod = &fm_demod;
- sem_init(&data_ready, 0, 0);
+ fm_init(&fm);
+ pthread_mutex_init(&data_ready, NULL);
+ pthread_mutex_init(&data_write, NULL);
- while ((opt = getopt(argc, argv, "d:f:g:s:b:l:o:t:r:p:EFANWMULRD")) != -1) {
+ while ((opt = getopt(argc, argv, "d:f:g:s:b:l:o:t:r:p:EFA:NWMULRDC")) != -1) {
switch (opt) {
case 'd':
dev_index = atoi(optarg);
@@ -688,11 +776,20 @@ int main(int argc, char **argv)
fm.fir_enable = 1;
break;
case 'A':
- fm.custom_atan = 1;
+ if (strcmp("std", optarg) == 0) {
+ fm.custom_atan = 0;}
+ if (strcmp("fast", optarg) == 0) {
+ fm.custom_atan = 1;}
+ if (strcmp("lut", optarg) == 0) {
+ atan_lut_init();
+ fm.custom_atan = 2;}
break;
case 'D':
fm.deemph = 1;
break;
+ case 'C':
+ fm.dc_block = 1;
+ break;
case 'N':
fm.mode_demod = &fm_demod;
break;
@@ -726,6 +823,11 @@ int main(int argc, char **argv)
/* quadruple sample_rate to limit to Δθ to ±π/2 */
fm.sample_rate *= fm.post_downsample;
+ if (fm.freq_len == 0) {
+ fprintf(stderr, "Please specify a frequency.\n");
+ exit(1);
+ }
+
if (fm.freq_len > 1) {
fm.terminate_on_squelch = 0;
}
@@ -828,6 +930,8 @@ int main(int argc, char **argv)
else {
fprintf(stderr, "\nLibrary error %d, exiting...\n", r);}
rtlsdr_cancel_async(dev);
+ pthread_mutex_destroy(&data_ready);
+ pthread_mutex_destroy(&data_write);
if (fm.file != stdout) {
fclose(fm.file);}