summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/rtl-sdr.h20
-rw-r--r--src/librtlsdr.c121
-rw-r--r--src/tuner_fc0013.c4
-rw-r--r--src/tuner_r82xx.c96
-rw-r--r--utils/convenience/convenience.c4
-rw-r--r--utils/rtl_adsb.c21
-rw-r--r--utils/rtl_biast.c101
-rw-r--r--utils/rtl_eeprom.c7
-rw-r--r--utils/rtl_fm.c41
-rw-r--r--utils/rtl_power.c21
-rw-r--r--utils/rtl_tcp.c119
-rw-r--r--utils/rtl_test.c62
12 files changed, 459 insertions, 158 deletions
diff --git a/include/rtl-sdr.h b/include/rtl-sdr.h
index fe64bea..d64701e 100644
--- a/include/rtl-sdr.h
+++ b/include/rtl-sdr.h
@@ -380,6 +380,26 @@ RTLSDR_API int rtlsdr_read_async(rtlsdr_dev_t *dev,
*/
RTLSDR_API int rtlsdr_cancel_async(rtlsdr_dev_t *dev);
+/*!
+ * Enable or disable the bias tee on GPIO PIN 0.
+ *
+ * \param dev the device handle given by rtlsdr_open()
+ * \param on 1 for Bias T on. 0 for Bias T off.
+ * \return -1 if device is not initialized. 0 otherwise.
+ */
+RTLSDR_API int rtlsdr_set_bias_tee(rtlsdr_dev_t *dev, int on);
+
+/*!
+ * Enable or disable the bias tee on the given GPIO pin.
+ *
+ * \param dev the device handle given by rtlsdr_open()
+ * \param gpio the gpio pin to configure as a Bias T control.
+ * \param on 1 for Bias T on. 0 for Bias T off.
+ * \return -1 if device is not initialized. 0 otherwise.
+ */
+RTLSDR_API int rtlsdr_set_bias_tee_gpio(rtlsdr_dev_t *dev, int gpio, int on);
+
+
#ifdef __cplusplus
}
#endif
diff --git a/src/librtlsdr.c b/src/librtlsdr.c
index cdf1ca9..096abae 100644
--- a/src/librtlsdr.c
+++ b/src/librtlsdr.c
@@ -39,12 +39,6 @@
#define LIBUSB_CALL
#endif
-/* libusb < 1.0.9 doesn't have libusb_handle_events_timeout_completed */
-#ifndef HAVE_LIBUSB_HANDLE_EVENTS_TIMEOUT_COMPLETED
-#define libusb_handle_events_timeout_completed(ctx, tv, c) \
- libusb_handle_events_timeout(ctx, tv)
-#endif
-
/* two raised to the power of n */
#define TWO_POW(n) ((double)(1ULL<<(n)))
@@ -103,6 +97,7 @@ struct rtlsdr_dev {
void *cb_ctx;
enum rtlsdr_async_status async_status;
int async_cancel;
+ int use_zerocopy;
/* rtl demod context */
uint32_t rate; /* Hz */
uint32_t rtl_xtal; /* Hz */
@@ -329,6 +324,7 @@ static rtlsdr_dongle_t known_devices[] = {
{ 0x0ccd, 0x00e0, "Terratec NOXON DAB/DAB+ USB dongle (rev 2)" },
{ 0x1554, 0x5020, "PixelView PV-DT235U(RN)" },
{ 0x15f4, 0x0131, "Astrometa DVB-T/DVB-T2" },
+ { 0x15f4, 0x0133, "HanfTek DAB+FM+DVB-T" },
{ 0x185b, 0x0620, "Compro Videomate U620F"},
{ 0x185b, 0x0650, "Compro Videomate U650F"},
{ 0x185b, 0x0680, "Compro Videomate U680F"},
@@ -569,7 +565,7 @@ void rtlsdr_set_gpio_output(rtlsdr_dev_t *dev, uint8_t gpio)
gpio = 1 << gpio;
r = rtlsdr_read_reg(dev, SYSB, GPD, 1);
- rtlsdr_write_reg(dev, SYSB, GPO, r & ~gpio, 1);
+ rtlsdr_write_reg(dev, SYSB, GPD, r & ~gpio, 1);
r = rtlsdr_read_reg(dev, SYSB, GPOE, 1);
rtlsdr_write_reg(dev, SYSB, GPOE, r | gpio, 1);
}
@@ -1564,11 +1560,11 @@ int rtlsdr_open(rtlsdr_dev_t **out_dev, uint32_t index)
}
/* initialise GPIOs */
- rtlsdr_set_gpio_output(dev, 5);
+ rtlsdr_set_gpio_output(dev, 4);
/* reset tuner before probing */
- rtlsdr_set_gpio_bit(dev, 5, 1);
- rtlsdr_set_gpio_bit(dev, 5, 0);
+ rtlsdr_set_gpio_bit(dev, 4, 1);
+ rtlsdr_set_gpio_bit(dev, 4, 0);
reg = rtlsdr_i2c_read_reg(dev, FC2580_I2C_ADDR, FC2580_CHECK_ADDR);
if ((reg & 0x7f) == FC2580_CHECK_VAL) {
@@ -1593,6 +1589,7 @@ found:
switch (dev->tuner_type) {
case RTLSDR_TUNER_R828D:
dev->tun_xtal = R828D_XTAL_FREQ;
+ /* fall-through */
case RTLSDR_TUNER_R820T:
/* disable Zero-IF mode */
rtlsdr_demod_write_reg(dev, 1, 0xb1, 0x1a, 1);
@@ -1625,6 +1622,9 @@ found:
return 0;
err:
if (dev) {
+ if (dev->devh)
+ libusb_close(dev->devh);
+
if (dev->ctx)
libusb_exit(dev->ctx);
@@ -1739,12 +1739,64 @@ static int _rtlsdr_alloc_async_buffers(rtlsdr_dev_t *dev)
dev->xfer[i] = libusb_alloc_transfer(0);
}
- if (!dev->xfer_buf) {
- dev->xfer_buf = malloc(dev->xfer_buf_num *
- sizeof(unsigned char *));
+ if (dev->xfer_buf)
+ return -2;
- for(i = 0; i < dev->xfer_buf_num; ++i)
+ dev->xfer_buf = malloc(dev->xfer_buf_num * sizeof(unsigned char *));
+ memset(dev->xfer_buf, 0, dev->xfer_buf_num * sizeof(unsigned char *));
+
+#if defined(ENABLE_ZEROCOPY) && defined (__linux__) && LIBUSB_API_VERSION >= 0x01000105
+ fprintf(stderr, "Allocating %d zero-copy buffers\n", dev->xfer_buf_num);
+
+ dev->use_zerocopy = 1;
+ for (i = 0; i < dev->xfer_buf_num; ++i) {
+ dev->xfer_buf[i] = libusb_dev_mem_alloc(dev->devh, dev->xfer_buf_len);
+
+ if (dev->xfer_buf[i]) {
+ /* Check if Kernel usbfs mmap() bug is present: if the
+ * mapping is correct, the buffers point to memory that
+ * was memset to 0 by the Kernel, otherwise, they point
+ * to random memory. We check if the buffers are zeroed
+ * and otherwise fall back to buffers in userspace.
+ */
+ if (dev->xfer_buf[i][0] || memcmp(dev->xfer_buf[i],
+ dev->xfer_buf[i] + 1,
+ dev->xfer_buf_len - 1)) {
+ fprintf(stderr, "Detected Kernel usbfs mmap() "
+ "bug, falling back to buffers "
+ "in userspace\n");
+ dev->use_zerocopy = 0;
+ break;
+ }
+ } else {
+ fprintf(stderr, "Failed to allocate zero-copy "
+ "buffer for transfer %d\nFalling "
+ "back to buffers in userspace\n", i);
+ dev->use_zerocopy = 0;
+ break;
+ }
+ }
+
+ /* zero-copy buffer allocation failed (partially or completely)
+ * we need to free the buffers again if already allocated */
+ if (!dev->use_zerocopy) {
+ for (i = 0; i < dev->xfer_buf_num; ++i) {
+ if (dev->xfer_buf[i])
+ libusb_dev_mem_free(dev->devh,
+ dev->xfer_buf[i],
+ dev->xfer_buf_len);
+ }
+ }
+#endif
+
+ /* no zero-copy available, allocate buffers in userspace */
+ if (!dev->use_zerocopy) {
+ for (i = 0; i < dev->xfer_buf_num; ++i) {
dev->xfer_buf[i] = malloc(dev->xfer_buf_len);
+
+ if (!dev->xfer_buf[i])
+ return -ENOMEM;
+ }
}
return 0;
@@ -1769,9 +1821,18 @@ static int _rtlsdr_free_async_buffers(rtlsdr_dev_t *dev)
}
if (dev->xfer_buf) {
- for(i = 0; i < dev->xfer_buf_num; ++i) {
- if (dev->xfer_buf[i])
- free(dev->xfer_buf[i]);
+ for (i = 0; i < dev->xfer_buf_num; ++i) {
+ if (dev->xfer_buf[i]) {
+ if (dev->use_zerocopy) {
+#if defined (__linux__) && LIBUSB_API_VERSION >= 0x01000105
+ libusb_dev_mem_free(dev->devh,
+ dev->xfer_buf[i],
+ dev->xfer_buf_len);
+#endif
+ } else {
+ free(dev->xfer_buf[i]);
+ }
+ }
}
free(dev->xfer_buf);
@@ -1826,7 +1887,12 @@ int rtlsdr_read_async(rtlsdr_dev_t *dev, rtlsdr_read_async_cb_t cb, void *ctx,
r = libusb_submit_transfer(dev->xfer[i]);
if (r < 0) {
- fprintf(stderr, "Failed to submit transfer %i!\n", i);
+ fprintf(stderr, "Failed to submit transfer %i\n"
+ "Please increase your allowed "
+ "usbfs buffer size with the "
+ "following command:\n"
+ "echo 0 > /sys/module/usbcore"
+ "/parameters/usbfs_memory_mb\n", i);
dev->async_status = RTLSDR_CANCELING;
break;
}
@@ -1858,6 +1924,9 @@ int rtlsdr_read_async(rtlsdr_dev_t *dev, rtlsdr_read_async_cb_t cb, void *ctx,
/* handle events after canceling
* to allow transfer status to
* propagate */
+#ifdef _WIN32
+ Sleep(1);
+#endif
libusb_handle_events_timeout_completed(dev->ctx,
&zerotv, NULL);
if (r < 0)
@@ -1936,3 +2005,19 @@ int rtlsdr_i2c_read_fn(void *dev, uint8_t addr, uint8_t *buf, int len)
return -1;
}
+
+int rtlsdr_set_bias_tee_gpio(rtlsdr_dev_t *dev, int gpio, int on)
+{
+ if (!dev)
+ return -1;
+
+ rtlsdr_set_gpio_output(dev, gpio);
+ rtlsdr_set_gpio_bit(dev, gpio, on);
+
+ return 0;
+}
+
+int rtlsdr_set_bias_tee(rtlsdr_dev_t *dev, int on)
+{
+ return rtlsdr_set_bias_tee_gpio(dev, 0, on);
+}
diff --git a/src/tuner_fc0013.c b/src/tuner_fc0013.c
index 78b696e..5984dfb 100644
--- a/src/tuner_fc0013.c
+++ b/src/tuner_fc0013.c
@@ -248,11 +248,11 @@ int fc0013_set_params(void *dev, uint32_t freq, uint32_t bandwidth)
if (ret)
goto exit;
- /* disable UHF & enable GPS */
+ /* enable UHF & disable GPS */
ret = fc0013_readreg(dev, 0x14, &tmp);
if (ret)
goto exit;
- ret = fc0013_writereg(dev, 0x14, (tmp & 0x1f) | 0x20);
+ ret = fc0013_writereg(dev, 0x14, (tmp & 0x1f) | 0x40);
if (ret)
goto exit;
}
diff --git a/src/tuner_r82xx.c b/src/tuner_r82xx.c
index f620238..997abd7 100644
--- a/src/tuner_r82xx.c
+++ b/src/tuner_r82xx.c
@@ -330,8 +330,14 @@ static int r82xx_read(struct r82xx_priv *priv, uint8_t reg, uint8_t *val, int le
priv->buf[0] = reg;
rc = rtlsdr_i2c_write_fn(priv->rtl_dev, priv->cfg->i2c_addr, priv->buf, 1);
- if (rc < 1)
- return rc;
+
+ if (rc != 1) {
+ fprintf(stderr, "%s: i2c wr failed=%d reg=%02x len=%d\n",
+ __FUNCTION__, rc, reg, 1);
+ if (rc < 0)
+ return rc;
+ return -1;
+ }
rc = rtlsdr_i2c_read_fn(priv->rtl_dev, priv->cfg->i2c_addr, p, len);
@@ -770,78 +776,18 @@ static int r82xx_set_tv_standard(struct r82xx_priv *priv,
uint8_t lt_att, flt_ext_widest, polyfil_cur;
int need_calibration;
- if (delsys == SYS_ISDBT) {
- if_khz = 4063;
- filt_cal_lo = 59000;
- filt_gain = 0x10; /* +3db, 6mhz on */
- img_r = 0x00; /* image negative */
- filt_q = 0x10; /* r10[4]:low q(1'b1) */
- hp_cor = 0x6a; /* 1.7m disable, +2cap, 1.25mhz */
- ext_enable = 0x40; /* r30[6], ext enable; r30[5]:0 ext at lna max */
- loop_through = 0x00; /* r5[7], lt on */
- lt_att = 0x00; /* r31[7], lt att enable */
- flt_ext_widest = 0x00; /* r15[7]: flt_ext_wide off */
- polyfil_cur = 0x60; /* r25[6:5]:min */
- } else {
- if (bw <= 6) {
- if_khz = 3570;
- filt_cal_lo = 56000; /* 52000->56000 */
- filt_gain = 0x10; /* +3db, 6mhz on */
- img_r = 0x00; /* image negative */
- filt_q = 0x10; /* r10[4]:low q(1'b1) */
- hp_cor = 0x6b; /* 1.7m disable, +2cap, 1.0mhz */
- ext_enable = 0x60; /* r30[6]=1 ext enable; r30[5]:1 ext at lna max-1 */
- loop_through = 0x00; /* r5[7], lt on */
- lt_att = 0x00; /* r31[7], lt att enable */
- flt_ext_widest = 0x00; /* r15[7]: flt_ext_wide off */
- polyfil_cur = 0x60; /* r25[6:5]:min */
- } else if (bw == 7) {
-#if 0
- /*
- * There are two 7 MHz tables defined on the original
- * driver, but just the second one seems to be visible
- * by rtl2832. Keep this one here commented, as it
- * might be needed in the future
- */
-
- if_khz = 4070;
- filt_cal_lo = 60000;
- filt_gain = 0x10; /* +3db, 6mhz on */
- img_r = 0x00; /* image negative */
- filt_q = 0x10; /* r10[4]:low q(1'b1) */
- hp_cor = 0x2b; /* 1.7m disable, +1cap, 1.0mhz */
- ext_enable = 0x60; /* r30[6]=1 ext enable; r30[5]:1 ext at lna max-1 */
- loop_through = 0x00; /* r5[7], lt on */
- lt_att = 0x00; /* r31[7], lt att enable */
- flt_ext_widest = 0x00; /* r15[7]: flt_ext_wide off */
- polyfil_cur = 0x60; /* r25[6:5]:min */
-#endif
- /* 7 MHz, second table */
- if_khz = 4570;
- filt_cal_lo = 63000;
- filt_gain = 0x10; /* +3db, 6mhz on */
- img_r = 0x00; /* image negative */
- filt_q = 0x10; /* r10[4]:low q(1'b1) */
- hp_cor = 0x2a; /* 1.7m disable, +1cap, 1.25mhz */
- ext_enable = 0x60; /* r30[6]=1 ext enable; r30[5]:1 ext at lna max-1 */
- loop_through = 0x00; /* r5[7], lt on */
- lt_att = 0x00; /* r31[7], lt att enable */
- flt_ext_widest = 0x00; /* r15[7]: flt_ext_wide off */
- polyfil_cur = 0x60; /* r25[6:5]:min */
- } else {
- if_khz = 4570;
- filt_cal_lo = 68500;
- filt_gain = 0x10; /* +3db, 6mhz on */
- img_r = 0x00; /* image negative */
- filt_q = 0x10; /* r10[4]:low q(1'b1) */
- hp_cor = 0x0b; /* 1.7m disable, +0cap, 1.0mhz */
- ext_enable = 0x60; /* r30[6]=1 ext enable; r30[5]:1 ext at lna max-1 */
- loop_through = 0x00; /* r5[7], lt on */
- lt_att = 0x00; /* r31[7], lt att enable */
- flt_ext_widest = 0x00; /* r15[7]: flt_ext_wide off */
- polyfil_cur = 0x60; /* r25[6:5]:min */
- }
- }
+ /* BW < 6 MHz */
+ if_khz = 3570;
+ filt_cal_lo = 56000; /* 52000->56000 */
+ filt_gain = 0x10; /* +3db, 6mhz on */
+ img_r = 0x00; /* image negative */
+ filt_q = 0x10; /* r10[4]:low q(1'b1) */
+ hp_cor = 0x6b; /* 1.7m disable, +2cap, 1.0mhz */
+ ext_enable = 0x60; /* r30[6]=1 ext enable; r30[5]:1 ext at lna max-1 */
+ loop_through = 0x01; /* r5[7], lt off */
+ lt_att = 0x00; /* r31[7], lt att enable */
+ flt_ext_widest = 0x00; /* r15[7]: flt_ext_wide off */
+ polyfil_cur = 0x60; /* r25[6:5]:min */
/* Initialize the shadow registers */
memcpy(priv->regs, r82xx_init_array, sizeof(r82xx_init_array));
@@ -1196,7 +1142,7 @@ int r82xx_standby(struct r82xx_priv *priv)
rc = r82xx_write_reg(priv, 0x06, 0xb1);
if (rc < 0)
return rc;
- rc = r82xx_write_reg(priv, 0x05, 0x03);
+ rc = r82xx_write_reg(priv, 0x05, 0xa0);
if (rc < 0)
return rc;
rc = r82xx_write_reg(priv, 0x07, 0x3a);
diff --git a/utils/convenience/convenience.c b/utils/convenience/convenience.c
index 517dc4e..00cc2cc 100644
--- a/utils/convenience/convenience.c
+++ b/utils/convenience/convenience.c
@@ -49,9 +49,11 @@ double atofs(char *s)
case 'g':
case 'G':
suff *= 1e3;
+ /* fall-through */
case 'm':
case 'M':
suff *= 1e3;
+ /* fall-through */
case 'k':
case 'K':
suff *= 1e3;
@@ -76,9 +78,11 @@ double atoft(char *s)
case 'h':
case 'H':
suff *= 60;
+ /* fall-through */
case 'm':
case 'M':
suff *= 60;
+ /* fall-through */
case 's':
case 'S':
suff *= atof(s);
diff --git a/utils/rtl_adsb.c b/utils/rtl_adsb.c
index 7de9204..7aea8dd 100644
--- a/utils/rtl_adsb.c
+++ b/utils/rtl_adsb.c
@@ -96,6 +96,7 @@ void usage(void)
"\t[-e allowed_errors (default: 5)]\n"
"\t[-g tuner_gain (default: automatic)]\n"
"\t[-p ppm_error (default: 0)]\n"
+ "\t[-T enable bias-T on GPIO PIN 0 (works for rtl-sdr.com v3 dongles)]\n"
"\tfilename (a '-' dumps samples to stdout)\n"
"\t (omitting the filename also uses stdout)\n\n"
"Streaming with netcat:\n"
@@ -182,7 +183,7 @@ int magnitute(uint8_t *buf, int len)
return len/2;
}
-uint16_t single_manchester(uint16_t a, uint16_t b, uint16_t c, uint16_t d)
+static 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;
@@ -223,17 +224,17 @@ uint16_t single_manchester(uint16_t a, uint16_t b, uint16_t c, uint16_t d)
return BADSAMPLE;
}
-inline uint16_t min16(uint16_t a, uint16_t b)
+static inline uint16_t min16(uint16_t a, uint16_t b)
{
return a<b ? a : b;
}
-inline uint16_t max16(uint16_t a, uint16_t b)
+static inline uint16_t max16(uint16_t a, uint16_t b)
{
return a>b ? a : b;
}
-int preamble(uint16_t *buf, int i)
+static inline int preamble(uint16_t *buf, int i)
/* returns 0/1 for preamble at index i */
{
int i2;
@@ -371,11 +372,12 @@ int main(int argc, char **argv)
int dev_index = 0;
int dev_given = 0;
int ppm_error = 0;
+ int enable_biastee = 0;
pthread_cond_init(&ready, NULL);
pthread_mutex_init(&ready_m, NULL);
squares_precompute();
- while ((opt = getopt(argc, argv, "d:g:p:e:Q:VS")) != -1)
+ while ((opt = getopt(argc, argv, "d:g:p:e:Q:VST")) != -1)
{
switch (opt) {
case 'd':
@@ -400,6 +402,9 @@ int main(int argc, char **argv)
case 'Q':
quality = (int)(atof(optarg) * 10);
break;
+ case 'T':
+ enable_biastee = 1;
+ break;
default:
usage();
return 0;
@@ -470,6 +475,10 @@ int main(int argc, char **argv)
/* Set the sample rate */
verbose_set_sample_rate(dev, ADSB_RATE);
+ rtlsdr_set_bias_tee(dev, enable_biastee);
+ if (enable_biastee)
+ fprintf(stderr, "activated bias-T on GPIO PIN 0\n");
+
/* Reset endpoint before we start reading from it (mandatory) */
verbose_reset_buffer(dev);
@@ -483,6 +492,8 @@ int main(int argc, char **argv)
else {
fprintf(stderr, "\nLibrary error %d, exiting...\n", r);}
rtlsdr_cancel_async(dev);
+ pthread_cancel(demod_thread);
+ pthread_join(demod_thread, NULL);
pthread_cond_destroy(&ready);
pthread_mutex_destroy(&ready_m);
diff --git a/utils/rtl_biast.c b/utils/rtl_biast.c
new file mode 100644
index 0000000..185e838
--- /dev/null
+++ b/utils/rtl_biast.c
@@ -0,0 +1,101 @@
+/*
+ * rtl-sdr, turns your Realtek RTL2832 based DVB dongle into a SDR receiver
+ * rtl_biast, tool to set bias tee gpio output
+ * Copyright (C) 2012 by Steve Markgraf <steve@steve-m.de>
+ *
+ * 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 2 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 <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifndef _WIN32
+#include <unistd.h>
+#else
+#include <windows.h>
+#include "getopt/getopt.h"
+#endif
+
+#include "rtl-sdr.h"
+#include "convenience/convenience.h"
+
+static rtlsdr_dev_t *dev = NULL;
+
+void usage(void)
+{
+ fprintf(stderr,
+ "rtl_biast, a tool for turning the RTL-SDR.com \n"
+ "bias tee or any GPIO ON and OFF. Example to turn on the \n"
+ "bias tee: rtl_biast -d 0 -b 1\n"
+ "Any GPIO: rtl_biast -d 0 -g 1 -b 1\n\n"
+ "Usage:\n"
+ "\t[-d device_index (default: 0)]\n"
+ "\t[-b bias_on (default: 0)]\n"
+ "\t[-g GPIO select (default: 0)]\n");
+ exit(1);
+}
+
+int main(int argc, char **argv)
+{
+ int i, r, opt;
+ int dev_index = 0;
+ int dev_given = 0;
+ uint32_t bias_on = 0;
+ uint32_t gpio_pin = 0;
+ int device_count;
+
+ while ((opt = getopt(argc, argv, "d:b:g:h?")) != -1) {
+ switch (opt) {
+ case 'd':
+ dev_index = verbose_device_search(optarg);
+ dev_given = 1;
+ break;
+ case 'b':
+ bias_on = atoi(optarg);
+ break;
+ case 'g':
+ gpio_pin = atoi(optarg);
+ break;
+ default:
+ usage();
+ break;
+ }
+ }
+
+ if (!dev_given) {
+ dev_index = verbose_device_search("0");
+ }
+
+ if (dev_index < 0) {
+ exit(1);
+ }
+
+ r = rtlsdr_open(&dev, dev_index);
+ rtlsdr_set_bias_tee_gpio(dev, gpio_pin, bias_on);
+
+exit:
+ /*
+ * Note - rtlsdr_close() in this tree does not clear the bias tee
+ * GPIO line, so it leaves the bias tee enabled if a client program
+ * doesn't explictly disable it.
+ *
+ * If that behaviour changes then another rtlsdr_close() will be
+ * needed that takes some extension flags, and one of them should
+ * be to either explicitly close the biast or leave it alone.
+ */
+ rtlsdr_close(dev);
+
+ return r >= 0 ? r : -r;
+}
diff --git a/utils/rtl_eeprom.c b/utils/rtl_eeprom.c
index 5259820..24be900 100644
--- a/utils/rtl_eeprom.c
+++ b/utils/rtl_eeprom.c
@@ -303,6 +303,7 @@ int main(int argc, char **argv)
case 'w':
flash_file = 1;
change = 1;
+ /* fall-through */
case 'r':
filename = optarg;
break;
@@ -369,14 +370,14 @@ int main(int argc, char **argv)
}
if (manuf_str)
- strncpy((char*)&conf.manufacturer, manuf_str, MAX_STR_SIZE);
+ strncpy((char*)&conf.manufacturer, manuf_str, MAX_STR_SIZE - 1);
if (product_str)
- strncpy((char*)&conf.product, product_str, MAX_STR_SIZE);
+ strncpy((char*)&conf.product, product_str, MAX_STR_SIZE - 1);
if (serial_str) {
conf.have_serial = 1;
- strncpy((char*)&conf.serial, serial_str, MAX_STR_SIZE);
+ strncpy((char*)&conf.serial, serial_str, MAX_STR_SIZE - 1);
}
if (ir_endpoint != 0)
diff --git a/utils/rtl_fm.c b/utils/rtl_fm.c
index e89e42d..7c84332 100644
--- a/utils/rtl_fm.c
+++ b/utils/rtl_fm.c
@@ -193,6 +193,7 @@ void usage(void)
"\t raw mode outputs 2x16 bit IQ pairs\n"
"\t[-s sample_rate (default: 24k)]\n"
"\t[-d device_index (default: 0)]\n"
+ "\t[-T enable bias-T on GPIO PIN 0 (works for rtl-sdr.com v3 dongles)]\n"
"\t[-g tuner_gain (default: automatic)]\n"
"\t[-l squelch_level (default: 0/off)]\n"
//"\t for fm squelch is inverted\n"
@@ -200,11 +201,12 @@ void usage(void)
"\t[-p ppm_error (default: 0)]\n"
"\t[-E enable_option (default: none)]\n"
"\t use multiple -E to enable multiple options\n"
- "\t edge: enable lower edge tuning\n"
- "\t dc: enable dc blocking filter\n"
- "\t deemp: enable de-emphasis filter\n"
- "\t direct: enable direct sampling\n"
- "\t offset: enable offset tuning\n"
+ "\t edge: enable lower edge tuning\n"
+ "\t dc: enable dc blocking filter\n"
+ "\t deemp: enable de-emphasis filter\n"
+ "\t direct: enable direct sampling 1 (usually I)\n"
+ "\t direct2: enable direct sampling 2 (usually Q)\n"
+ "\t offset: enable offset tuning\n"
"\tfilename ('-' means stdout)\n"
"\t omitting the filename also uses stdout\n\n"
"Experimental options:\n"
@@ -502,7 +504,7 @@ int polar_disc_lut(int ar, int aj, int br, int bj)
if (x_abs >= atan_lut_size) {
/* we can use linear range, but it is not necessary */
- return (cj > 0) ? 1<<13 : -1<<13;
+ return (cj > 0) ? 1<<13 : -(1<<13);
}
if (x > 0) {
@@ -891,7 +893,7 @@ static void *controller_thread_fn(void *arg)
/* set up primary channel */
optimal_settings(s->freqs[0], demod.rate_in);
if (dongle.direct_sampling) {
- verbose_direct_sampling(dongle.dev, 1);}
+ verbose_direct_sampling(dongle.dev, dongle.direct_sampling);}
if (dongle.offset_tuning) {
verbose_offset_tuning(dongle.dev);}
@@ -925,8 +927,21 @@ void frequency_range(struct controller_state *s, char *arg)
int i;
start = arg;
stop = strchr(start, ':') + 1;
+ if (stop == (char *)1) { // no stop or step given
+ s->freqs[s->freq_len] = (uint32_t) atofs(start);
+ s->freq_len++;
+ return;
+ }
stop[-1] = '\0';
step = strchr(stop, ':') + 1;
+ if (step == (char *)1) { // no step given
+ s->freqs[s->freq_len] = (uint32_t) atofs(start);
+ s->freq_len++;
+ s->freqs[s->freq_len] = (uint32_t) atofs(stop);
+ s->freq_len++;
+ stop[-1] = ':';
+ return;
+ }
step[-1] = '\0';
for(i=(int)atofs(start); i<=(int)atofs(stop); i+=(int)atofs(step))
{
@@ -1042,12 +1057,13 @@ int main(int argc, char **argv)
int r, opt;
int dev_given = 0;
int custom_ppm = 0;
+ int enable_biastee = 0;
dongle_init(&dongle);
demod_init(&demod);
output_init(&output);
controller_init(&controller);
- while ((opt = getopt(argc, argv, "d:f:g:s:b:l:o:t:r:p:E:F:A:M:h")) != -1) {
+ while ((opt = getopt(argc, argv, "d:f:g:s:b:l:o:t:r:p:E:F:A:M:hT")) != -1) {
switch (opt) {
case 'd':
dongle.dev_index = verbose_device_search(optarg);
@@ -1104,6 +1120,8 @@ int main(int argc, char **argv)
demod.deemph = 1;}
if (strcmp("direct", optarg) == 0) {
dongle.direct_sampling = 1;}
+ if (strcmp("direct2", optarg) == 0) {
+ dongle.direct_sampling = 2;}
if (strcmp("offset", optarg) == 0) {
dongle.offset_tuning = 1;}
break;
@@ -1142,6 +1160,9 @@ int main(int argc, char **argv)
demod.deemph = 1;
demod.squelch_level = 0;}
break;
+ case 'T':
+ enable_biastee = 1;
+ break;
case 'h':
default:
usage();
@@ -1205,6 +1226,10 @@ int main(int argc, char **argv)
verbose_gain_set(dongle.dev, dongle.gain);
}
+ rtlsdr_set_bias_tee(dongle.dev, enable_biastee);
+ if (enable_biastee)
+ fprintf(stderr, "activated bias-T on GPIO PIN 0\n");
+
verbose_ppm_set(dongle.dev, dongle.ppm_error);
if (strcmp(output.filename, "-") == 0) { /* Write samples to stdout */
diff --git a/utils/rtl_power.c b/utils/rtl_power.c
index 23b516c..6204de2 100644
--- a/utils/rtl_power.c
+++ b/utils/rtl_power.c
@@ -133,6 +133,7 @@ void usage(void)
"\t[-d device_index (default: 0)]\n"
"\t[-g tuner_gain (default: automatic)]\n"
"\t[-p ppm_error (default: 0)]\n"
+ "\t[-T enable bias-T on GPIO PIN 0 (works for rtl-sdr.com v3 dongles)]\n"
"\tfilename (a '-' dumps samples to stdout)\n"
"\t (omitting the filename also uses stdout)\n"
"\n"
@@ -249,7 +250,7 @@ void sine_table(int size)
}
}
-int16_t FIX_MPY(int16_t a, int16_t b)
+static inline int16_t FIX_MPY(int16_t a, int16_t b)
/* fixed point multiply and scale */
{
int c = ((int)a * (int)b) >> 14;
@@ -436,8 +437,16 @@ void frequency_range(char *arg, double crop)
/* hacky string parsing */
start = arg;
stop = strchr(start, ':') + 1;
+ if (stop == (char *)1) {
+ fprintf(stderr, "Bad frequency range specification: %s\n", arg);
+ exit(1);
+ }
stop[-1] = '\0';
step = strchr(stop, ':') + 1;
+ if (step == (char *)1) {
+ fprintf(stderr, "Bad frequency range specification: %s\n", arg);
+ exit(1);
+ }
step[-1] = '\0';
lower = (int)atofs(start);
upper = (int)atofs(stop);
@@ -771,6 +780,7 @@ int main(int argc, char **argv)
int single = 0;
int direct_sampling = 0;
int offset_tuning = 0;
+ int enable_biastee = 0;
double crop = 0.0;
char *freq_optarg;
time_t next_tick;
@@ -781,7 +791,7 @@ int main(int argc, char **argv)
double (*window_fn)(int, int) = rectangle;
freq_optarg = "";
- while ((opt = getopt(argc, argv, "f:i:s:t:d:g:p:e:w:c:F:1PDOh")) != -1) {
+ while ((opt = getopt(argc, argv, "f:i:s:t:d:g:p:e:w:c:F:1PDOhT")) != -1) {
switch (opt) {
case 'f': // lower:upper:bin_size
freq_optarg = strdup(optarg);
@@ -849,6 +859,9 @@ int main(int argc, char **argv)
boxcar = 0;
comp_fir_size = atoi(optarg);
break;
+ case 'T':
+ enable_biastee = 1;
+ break;
case 'h':
default:
usage();
@@ -925,6 +938,10 @@ int main(int argc, char **argv)
verbose_ppm_set(dev, ppm_error);
+ rtlsdr_set_bias_tee(dev, enable_biastee);
+ if (enable_biastee)
+ fprintf(stderr, "activated bias-T on GPIO PIN 0\n");
+
if (strcmp(filename, "-") == 0) { /* Write log to stdout */
file = stdout;
#ifdef _WIN32
diff --git a/utils/rtl_tcp.c b/utils/rtl_tcp.c
index 317e0f3..84f5591 100644
--- a/utils/rtl_tcp.c
+++ b/utils/rtl_tcp.c
@@ -30,10 +30,12 @@
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
+#include <netdb.h>
#include <netinet/in.h>
#include <fcntl.h>
#else
#include <winsock2.h>
+#include <ws2tcpip.h>
#include "getopt/getopt.h"
#endif
@@ -54,6 +56,10 @@ typedef int socklen_t;
#define SOCKET_ERROR -1
#endif
+#define DEFAULT_PORT_STR "1234"
+#define DEFAULT_SAMPLE_RATE_HZ 2048000
+#define DEFAULT_MAX_NUM_BUFFERS 500
+
static SOCKET s;
static pthread_t tcp_worker_thread;
@@ -78,24 +84,27 @@ typedef struct { /* structure size must be multiple of 2 bytes */
static rtlsdr_dev_t *dev = NULL;
+static int enable_biastee = 0;
static int global_numq = 0;
static struct llist *ll_buffers = 0;
-static int llbuf_num = 500;
+static int llbuf_num = DEFAULT_MAX_NUM_BUFFERS;
static volatile int do_exit = 0;
+
void usage(void)
{
- printf("rtl_tcp, an I/Q spectrum server for RTL2832 based DVB-T receivers\n\n"
- "Usage:\t[-a listen address]\n"
- "\t[-p listen port (default: 1234)]\n"
- "\t[-f frequency to tune to [Hz]]\n"
- "\t[-g gain (default: 0 for auto)]\n"
- "\t[-s samplerate in Hz (default: 2048000 Hz)]\n"
- "\t[-b number of buffers (default: 15, set by library)]\n"
- "\t[-n max number of linked list buffers to keep (default: 500)]\n"
- "\t[-d device index (default: 0)]\n"
- "\t[-P ppm_error (default: 0)]\n");
+ printf("rtl_tcp, an I/Q spectrum server for RTL2832 based DVB-T receivers\n\n");
+ printf("Usage:\t[-a listen address]\n");
+ printf("\t[-p listen port (default: %s)]\n", DEFAULT_PORT_STR);
+ printf("\t[-f frequency to tune to [Hz]]\n");
+ printf("\t[-g gain (default: 0 for auto)]\n");
+ printf("\t[-s samplerate in Hz (default: %d Hz)]\n", DEFAULT_SAMPLE_RATE_HZ);
+ printf("\t[-b number of buffers (default: 15, set by library)]\n");
+ printf("\t[-n max number of linked list buffers to keep (default: %d)]\n", DEFAULT_MAX_NUM_BUFFERS);
+ printf("\t[-d device index (default: 0)]\n");
+ printf("\t[-P ppm_error (default: 0)]\n");
+ printf("\t[-T enable bias-T on GPIO PIN 0 (works for rtl-sdr.com v3 dongles)]\n");
exit(1);
}
@@ -355,6 +364,10 @@ static void *command_worker(void *arg)
printf("set tuner gain by index %d\n", ntohl(cmd.param));
set_gain_by_index(dev, ntohl(cmd.param));
break;
+ case 0x0e:
+ printf("set bias tee %d\n", ntohl(cmd.param));
+ rtlsdr_set_bias_tee(dev, (int)ntohl(cmd.param));
+ break;
default:
break;
}
@@ -365,10 +378,18 @@ static void *command_worker(void *arg)
int main(int argc, char **argv)
{
int r, opt, i;
- char* addr = "127.0.0.1";
- int port = 1234;
- uint32_t frequency = 100000000, samp_rate = 2048000;
- struct sockaddr_in local, remote;
+ char *addr = "127.0.0.1";
+ const char *port = DEFAULT_PORT_STR;
+ uint32_t frequency = 100000000, samp_rate = DEFAULT_SAMPLE_RATE_HZ;
+ struct sockaddr_storage local, remote;
+ struct addrinfo *ai;
+ struct addrinfo *aiHead;
+ struct addrinfo hints;
+ char hostinfo[NI_MAXHOST];
+ char portinfo[NI_MAXSERV];
+ char remhostinfo[NI_MAXHOST];
+ char remportinfo[NI_MAXSERV];
+ int aiErr;
uint32_t buf_num = 0;
int dev_index = 0;
int dev_given = 0;
@@ -379,7 +400,7 @@ int main(int argc, char **argv)
void *status;
struct timeval tv = {1,0};
struct linger ling = {1,0};
- SOCKET listensocket;
+ SOCKET listensocket = 0;
socklen_t rlen;
fd_set readfds;
u_long blockmode = 1;
@@ -391,7 +412,7 @@ int main(int argc, char **argv)
struct sigaction sigact, sigign;
#endif
- while ((opt = getopt(argc, argv, "a:p:f:g:s:b:n:d:P:")) != -1) {
+ while ((opt = getopt(argc, argv, "a:p:f:g:s:b:n:d:P:T")) != -1) {
switch (opt) {
case 'd':
dev_index = verbose_device_search(optarg);
@@ -407,10 +428,10 @@ int main(int argc, char **argv)
samp_rate = (uint32_t)atofs(optarg);
break;
case 'a':
- addr = optarg;
+ addr = strdup(optarg);
break;
case 'p':
- port = atoi(optarg);
+ port = strdup(optarg);
break;
case 'b':
buf_num = atoi(optarg);
@@ -421,6 +442,9 @@ int main(int argc, char **argv)
case 'P':
ppm_error = atoi(optarg);
break;
+ case 'T':
+ enable_biastee = 1;
+ break;
default:
usage();
break;
@@ -491,6 +515,10 @@ int main(int argc, char **argv)
fprintf(stderr, "Tuner gain set to %f dB.\n", gain/10.0);
}
+ rtlsdr_set_bias_tee(dev, enable_biastee);
+ if (enable_biastee)
+ fprintf(stderr, "activated bias-T on GPIO PIN 0\n");
+
/* Reset endpoint before we start reading from it (mandatory) */
r = rtlsdr_reset_buffer(dev);
if (r < 0)
@@ -502,16 +530,42 @@ int main(int argc, char **argv)
pthread_cond_init(&cond, NULL);
pthread_cond_init(&exit_cond, NULL);
- memset(&local,0,sizeof(local));
- local.sin_family = AF_INET;
- local.sin_port = htons(port);
- local.sin_addr.s_addr = inet_addr(addr);
+ hints.ai_flags = AI_PASSIVE; /* Server mode. */
+ hints.ai_family = PF_UNSPEC; /* IPv4 or IPv6. */
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = IPPROTO_TCP;
+
+ if ((aiErr = getaddrinfo(addr,
+ port,
+ &hints,
+ &aiHead )) != 0)
+ {
+ fprintf(stderr, "local address %s ERROR - %s.\n",
+ addr, gai_strerror(aiErr));
+ return(-1);
+ }
+ memcpy(&local, aiHead->ai_addr, aiHead->ai_addrlen);
+
+ for (ai = aiHead; ai != NULL; ai = ai->ai_next) {
+ aiErr = getnameinfo((struct sockaddr *)ai->ai_addr, ai->ai_addrlen,
+ hostinfo, NI_MAXHOST,
+ portinfo, NI_MAXSERV, NI_NUMERICSERV | NI_NUMERICHOST);
+ if (aiErr)
+ fprintf( stderr, "getnameinfo ERROR - %s.\n",hostinfo);
+
+ listensocket = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
+ if (listensocket < 0)
+ continue;
+
+ r = 1;
+ setsockopt(listensocket, SOL_SOCKET, SO_REUSEADDR, (char *)&r, sizeof(int));
+ setsockopt(listensocket, SOL_SOCKET, SO_LINGER, (char *)&ling, sizeof(ling));
- listensocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
- r = 1;
- setsockopt(listensocket, SOL_SOCKET, SO_REUSEADDR, (char *)&r, sizeof(int));
- setsockopt(listensocket, SOL_SOCKET, SO_LINGER, (char *)&ling, sizeof(ling));
- bind(listensocket,(struct sockaddr *)&local,sizeof(local));
+ if (bind(listensocket, (struct sockaddr *)&local, sizeof(local)))
+ fprintf(stderr, "rtl_tcp bind error: %s", strerror(errno));
+ else
+ break;
+ }
#ifdef _WIN32
ioctlsocket(listensocket, FIONBIO, &blockmode);
@@ -522,11 +576,11 @@ int main(int argc, char **argv)
while(1) {
printf("listening...\n");
- printf("Use the device argument 'rtl_tcp=%s:%d' in OsmoSDR "
+ printf("Use the device argument 'rtl_tcp=%s:%s' in OsmoSDR "
"(gr-osmosdr) source\n"
"to receive samples in GRC and control "
"rtl_tcp parameters (frequency, gain, ...).\n",
- addr, port);
+ hostinfo, portinfo);
listen(listensocket,1);
while(1) {
@@ -546,7 +600,10 @@ int main(int argc, char **argv)
setsockopt(s, SOL_SOCKET, SO_LINGER, (char *)&ling, sizeof(ling));
- printf("client accepted!\n");
+ getnameinfo((struct sockaddr *)&remote, rlen,
+ remhostinfo, NI_MAXHOST,
+ remportinfo, NI_MAXSERV, NI_NUMERICSERV);
+ printf("client accepted! %s %s\n", remhostinfo, remportinfo);
memset(&dongle_info, 0, sizeof(dongle_info));
memcpy(&dongle_info.magic, "RTL0", 4);
diff --git a/utils/rtl_test.c b/utils/rtl_test.c
index 9a6cfda..9b44097 100644
--- a/utils/rtl_test.c
+++ b/utils/rtl_test.c
@@ -53,6 +53,21 @@
#define PPM_DURATION 10
#define PPM_DUMP_TIME 5
+struct time_generic
+/* holds all the platform specific values */
+{
+#ifndef _WIN32
+ time_t tv_sec;
+ long tv_nsec;
+#else
+ long tv_sec;
+ long tv_nsec;
+ int init;
+ LARGE_INTEGER frequency;
+ LARGE_INTEGER ticks;
+#endif
+};
+
static enum {
NO_BENCHMARK,
TUNER_BENCHMARK,
@@ -134,21 +149,42 @@ static void underrun_test(unsigned char *buf, uint32_t len, int mute)
}
#ifndef _WIN32
-static int ppm_gettime(struct timespec *ts)
+static int ppm_gettime(struct time_generic *tg)
{
int rv = ENOSYS;
+ struct timespec ts;
#ifdef __unix__
- rv = clock_gettime(CLOCK_MONOTONIC, ts);
+ rv = clock_gettime(CLOCK_MONOTONIC, &ts);
+ tg->tv_sec = ts.tv_sec;
+ tg->tv_nsec = ts.tv_nsec;
#elif __APPLE__
struct timeval tv;
rv = gettimeofday(&tv, NULL);
- ts->tv_sec = tv.tv_sec;
- ts->tv_nsec = tv.tv_usec * 1000;
+ tg->tv_sec = tv.tv_sec;
+ tg->tv_nsec = tv.tv_usec * 1000;
#endif
return rv;
}
+#endif
+
+#ifdef _WIN32
+static int ppm_gettime(struct time_generic *tg)
+{
+ int rv;
+ int64_t frac;
+ if (!tg->init) {
+ QueryPerformanceFrequency(&tg->frequency);
+ tg->init = 1;
+ }
+ rv = QueryPerformanceCounter(&tg->ticks);
+ tg->tv_sec = tg->ticks.QuadPart / tg->frequency.QuadPart;
+ frac = (int64_t)(tg->ticks.QuadPart - (tg->tv_sec * tg->frequency.QuadPart));
+ tg->tv_nsec = (long)(frac * 1000000000L / (int64_t)tg->frequency.QuadPart);
+ return !rv;
+}
+#endif
static int ppm_report(uint64_t nsamples, uint64_t interval)
{
@@ -165,8 +201,8 @@ static void ppm_test(uint32_t len)
static uint64_t interval = 0;
static uint64_t nsamples_total = 0;
static uint64_t interval_total = 0;
- struct timespec ppm_now;
- static struct timespec ppm_recent;
+ struct time_generic ppm_now;
+ static struct time_generic ppm_recent;
static enum {
PPM_INIT_NO,
PPM_INIT_DUMP,
@@ -174,6 +210,7 @@ static void ppm_test(uint32_t len)
} ppm_init = PPM_INIT_NO;
ppm_gettime(&ppm_now);
+
if (ppm_init != PPM_INIT_RUN) {
/*
* Kyle Keen wrote:
@@ -189,11 +226,11 @@ static void ppm_test(uint32_t len)
}
if (ppm_init == PPM_INIT_DUMP && ppm_recent.tv_sec < ppm_now.tv_sec)
return;
- ppm_recent.tv_sec = ppm_now.tv_sec;
- ppm_recent.tv_nsec = ppm_now.tv_nsec;
+ ppm_recent = ppm_now;
ppm_init = PPM_INIT_RUN;
return;
}
+
nsamples += (uint64_t)(len / 2UL);
interval = (uint64_t)(ppm_now.tv_sec - ppm_recent.tv_sec);
if (interval < ppm_duration)
@@ -206,19 +243,16 @@ static void ppm_test(uint32_t len)
(int)((1000000000UL * nsamples) / interval),
ppm_report(nsamples, interval),
ppm_report(nsamples_total, interval_total));
- ppm_recent.tv_sec = ppm_now.tv_sec;
- ppm_recent.tv_nsec = ppm_now.tv_nsec;
+ ppm_recent = ppm_now;
nsamples = 0;
}
-#endif
static void rtlsdr_callback(unsigned char *buf, uint32_t len, void *ctx)
{
underrun_test(buf, len, 0);
-#ifndef _WIN32
+
if (test_mode == PPM_BENCHMARK)
ppm_test(len);
-#endif
}
void e4k_benchmark(void)
@@ -375,7 +409,7 @@ int main(int argc, char **argv)
verbose_reset_buffer(dev);
if ((test_mode == PPM_BENCHMARK) && !sync_mode) {
- fprintf(stderr, "Reporting PPM error measurement every %i seconds...\n", ppm_duration);
+ fprintf(stderr, "Reporting PPM error measurement every %u seconds...\n", ppm_duration);
fprintf(stderr, "Press ^C after a few minutes.\n");
}