diff --git a/include/rtl-sdr.h b/include/rtl-sdr.h index 489e117..fe64bea 100644 --- a/include/rtl-sdr.h +++ b/include/rtl-sdr.h @@ -215,6 +215,15 @@ RTLSDR_API int rtlsdr_get_tuner_gains(rtlsdr_dev_t *dev, int *gains); */ RTLSDR_API int rtlsdr_set_tuner_gain(rtlsdr_dev_t *dev, int gain); +/*! + * Set the bandwidth for the device. + * + * \param dev the device handle given by rtlsdr_open() + * \param bw bandwidth in Hz. Zero means automatic BW selection. + * \return 0 on success + */ +RTLSDR_API int rtlsdr_set_tuner_bandwidth(rtlsdr_dev_t *dev, uint32_t bw); + /*! * Get actual gain the device is configured to. * diff --git a/include/tuner_r82xx.h b/include/tuner_r82xx.h index fd81e1d..f6c206a 100644 --- a/include/tuner_r82xx.h +++ b/include/tuner_r82xx.h @@ -115,5 +115,6 @@ int r82xx_standby(struct r82xx_priv *priv); int r82xx_init(struct r82xx_priv *priv); int r82xx_set_freq(struct r82xx_priv *priv, uint32_t freq); int r82xx_set_gain(struct r82xx_priv *priv, int set_manual_gain, int gain); +int r82xx_set_bandwidth(struct r82xx_priv *priv, int bandwidth, uint32_t rate); #endif diff --git a/rtl-sdr.rules b/rtl-sdr.rules index 4213454..b2f4054 100644 --- a/rtl-sdr.rules +++ b/rtl-sdr.rules @@ -72,6 +72,9 @@ SUBSYSTEMS=="usb", ATTRS{idVendor}=="1554", ATTRS{idProduct}=="5020", MODE:="066 # Astrometa DVB-T/DVB-T2 (R828D) SUBSYSTEMS=="usb", ATTRS{idVendor}=="15f4", ATTRS{idProduct}=="0131", MODE:="0666" +# HanfTek DAB+FM+DVB-T +SUBSYSTEMS=="usb", ATTRS{idVendor}=="15f4", ATTRS{idProduct}=="0133", MODE:="0666" + # Compro Videomate U620F (E4000) SUBSYSTEMS=="usb", ATTRS{idVendor}=="185b", ATTRS{idProduct}=="0620", MODE:="0666" diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 77e1dc4..07d64ab 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -17,10 +17,11 @@ # the Free Software Foundation, Inc., 51 Franklin Street, # Boston, MA 02110-1301, USA. -######################################################################## -# Setup library -######################################################################## -add_library(rtlsdr_shared SHARED +MACRO(RTLSDR_APPEND_SRCS) + LIST(APPEND rtlsdr_srcs ${ARGV}) +ENDMACRO(RTLSDR_APPEND_SRCS) + +RTLSDR_APPEND_SRCS( librtlsdr.c tuner_e4k.c tuner_fc0012.c @@ -29,24 +30,44 @@ add_library(rtlsdr_shared SHARED tuner_r82xx.c ) -target_link_libraries(rtlsdr_shared - ${LIBUSB_LIBRARIES} -) +######################################################################## +# Set up Windows DLL resource files +######################################################################## +IF(MSVC) + include(${CMAKE_SOURCE_DIR}/cmake/Modules/Version.cmake) + + configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/rtlsdr.rc.in + ${CMAKE_CURRENT_BINARY_DIR}/rtlsdr.rc + @ONLY) + RTLSDR_APPEND_SRCS(${CMAKE_CURRENT_BINARY_DIR}/rtlsdr.rc) +ENDIF(MSVC) + +######################################################################## +# Setup shared library variant +######################################################################## +add_library(rtlsdr_shared SHARED ${rtlsdr_srcs}) +target_link_libraries(rtlsdr_shared ${LIBUSB_LIBRARIES}) set_target_properties(rtlsdr_shared PROPERTIES DEFINE_SYMBOL "rtlsdr_EXPORTS") set_target_properties(rtlsdr_shared PROPERTIES OUTPUT_NAME rtlsdr) set_target_properties(rtlsdr_shared PROPERTIES SOVERSION ${MAJOR_VERSION}) set_target_properties(rtlsdr_shared PROPERTIES VERSION ${LIBVER}) -add_library(rtlsdr_static STATIC - librtlsdr.c - tuner_e4k.c - tuner_fc0012.c - tuner_fc0013.c - tuner_fc2580.c - tuner_r82xx.c -) +######################################################################## +# Setup static library variant +######################################################################## +add_library(rtlsdr_static STATIC ${rtlsdr_srcs}) +target_link_libraries(rtlsdr_static ${LIBUSB_LIBRARIES}) +set_property(TARGET rtlsdr_static APPEND PROPERTY COMPILE_DEFINITIONS "rtlsdr_STATIC" ) +if(NOT WIN32) +# Force same library filename for static and shared variants of the library +set_target_properties(rtlsdr_static PROPERTIES OUTPUT_NAME rtlsdr) +endif() +######################################################################## +# Setup libraries used in executables +######################################################################## add_library(convenience_static STATIC convenience/convenience.c ) @@ -60,17 +81,6 @@ target_link_libraries(convenience_static ) endif() -target_link_libraries(rtlsdr_static - ${LIBUSB_LIBRARIES} -) - -set_property(TARGET rtlsdr_static APPEND PROPERTY COMPILE_DEFINITIONS "rtlsdr_STATIC" ) - -if(NOT WIN32) -# Force same library filename for static and shared variants of the library -set_target_properties(rtlsdr_static PROPERTIES OUTPUT_NAME rtlsdr) -endif() - ######################################################################## # Build utility ######################################################################## diff --git a/src/librtlsdr.c b/src/librtlsdr.c index 9a3ebcd..0e45911 100644 --- a/src/librtlsdr.c +++ b/src/librtlsdr.c @@ -113,6 +113,7 @@ struct rtlsdr_dev { rtlsdr_tuner_iface_t *tuner; uint32_t tun_xtal; /* Hz */ uint32_t freq; /* Hz */ + uint32_t bw; uint32_t offs_freq; /* Hz */ int corr; /* ppm */ int gain; /* tenth dB */ @@ -126,6 +127,7 @@ struct rtlsdr_dev { }; void rtlsdr_set_gpio_bit(rtlsdr_dev_t *dev, uint8_t gpio, int val); +static int rtlsdr_set_if_freq(rtlsdr_dev_t *dev, uint32_t freq); /* generic tuner interface functions, shall be moved to the tuner implementations */ int e4000_init(void *dev) { @@ -238,7 +240,20 @@ int r820t_set_freq(void *dev, uint32_t freq) { rtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev; return r82xx_set_freq(&devt->r82xx_p, freq); } -int r820t_set_bw(void *dev, int bw) { return 0; } + +int r820t_set_bw(void *dev, int bw) { + int r; + rtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev; + + r = r82xx_set_bandwidth(&devt->r82xx_p, bw, devt->rate); + if(r < 0) + return r; + r = rtlsdr_set_if_freq(devt, r); + if (r) + return r; + return rtlsdr_set_center_freq(devt, devt->freq); +} + int r820t_set_gain(void *dev, int gain) { rtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev; return r82xx_set_gain(&devt->r82xx_p, 1, gain); @@ -314,6 +329,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"}, @@ -338,7 +354,7 @@ static rtlsdr_dongle_t known_devices[] = { { 0x1f4d, 0xd803, "PROlectrix DV107669" }, }; -#define DEFAULT_BUF_NUMBER 15 +#define DEFAULT_BUF_NUMBER 1 #define DEFAULT_BUF_LENGTH (16 * 32 * 512) #define DEF_RTL_XTAL_FREQ 28800000 @@ -670,7 +686,7 @@ int rtlsdr_deinit_baseband(rtlsdr_dev_t *dev) return r; } -int rtlsdr_set_if_freq(rtlsdr_dev_t *dev, uint32_t freq) +static int rtlsdr_set_if_freq(rtlsdr_dev_t *dev, uint32_t freq) { uint32_t rtl_xtal; int32_t if_freq; @@ -994,6 +1010,24 @@ int rtlsdr_get_tuner_gains(rtlsdr_dev_t *dev, int *gains) } } +int rtlsdr_set_tuner_bandwidth(rtlsdr_dev_t *dev, uint32_t bw) +{ + int r = 0; + + if (!dev || !dev->tuner) + return -1; + + if (dev->tuner->set_bw) { + rtlsdr_set_i2c_repeater(dev, 1); + r = dev->tuner->set_bw(dev, bw > 0 ? bw : dev->rate); + rtlsdr_set_i2c_repeater(dev, 0); + if (r) + return r; + dev->bw = bw; + } + return r; +} + int rtlsdr_set_tuner_gain(rtlsdr_dev_t *dev, int gain) { int r = 0; @@ -1081,14 +1115,14 @@ int rtlsdr_set_sample_rate(rtlsdr_dev_t *dev, uint32_t samp_rate) if ( ((double)samp_rate) != real_rate ) fprintf(stderr, "Exact sample rate is: %f Hz\n", real_rate); + dev->rate = (uint32_t)real_rate; + if (dev->tuner && dev->tuner->set_bw) { rtlsdr_set_i2c_repeater(dev, 1); - dev->tuner->set_bw(dev, (int)real_rate); + dev->tuner->set_bw(dev, dev->bw > 0 ? dev->bw : dev->rate); rtlsdr_set_i2c_repeater(dev, 0); } - dev->rate = (uint32_t)real_rate; - tmp = (rsamp_ratio >> 16); r |= rtlsdr_demod_write_reg(dev, 1, 0x9f, tmp, 2); tmp = rsamp_ratio & 0xffff; @@ -1205,6 +1239,7 @@ int rtlsdr_get_direct_sampling(rtlsdr_dev_t *dev) int rtlsdr_set_offset_tuning(rtlsdr_dev_t *dev, int on) { int r = 0; + int bw; if (!dev) return -1; @@ -1222,7 +1257,14 @@ int rtlsdr_set_offset_tuning(rtlsdr_dev_t *dev, int on) if (dev->tuner && dev->tuner->set_bw) { rtlsdr_set_i2c_repeater(dev, 1); - dev->tuner->set_bw(dev, on ? (2 * dev->offs_freq) : dev->rate); + if (on) { + bw = 2 * dev->offs_freq; + } else if (dev->bw > 0) { + bw = dev->bw; + } else { + bw = dev->rate; + } + dev->tuner->set_bw(dev, bw); rtlsdr_set_i2c_repeater(dev, 0); } @@ -1257,14 +1299,16 @@ static rtlsdr_dongle_t *find_known_device(uint16_t vid, uint16_t pid) uint32_t rtlsdr_get_device_count(void) { - int i; + int i,r; libusb_context *ctx; libusb_device **list; uint32_t device_count = 0; struct libusb_device_descriptor dd; ssize_t cnt; - libusb_init(&ctx); + r = libusb_init(&ctx); + if(r < 0) + return 0; cnt = libusb_get_device_list(ctx, &list); @@ -1284,7 +1328,7 @@ uint32_t rtlsdr_get_device_count(void) const char *rtlsdr_get_device_name(uint32_t index) { - int i; + int i,r; libusb_context *ctx; libusb_device **list; struct libusb_device_descriptor dd; @@ -1292,7 +1336,9 @@ const char *rtlsdr_get_device_name(uint32_t index) uint32_t device_count = 0; ssize_t cnt; - libusb_init(&ctx); + r = libusb_init(&ctx); + if(r < 0) + return ""; cnt = libusb_get_device_list(ctx, &list); @@ -1332,7 +1378,9 @@ int rtlsdr_get_device_usb_strings(uint32_t index, char *manufact, uint32_t device_count = 0; ssize_t cnt; - libusb_init(&ctx); + r = libusb_init(&ctx); + if(r < 0) + return r; cnt = libusb_get_device_list(ctx, &list); @@ -1406,7 +1454,11 @@ int rtlsdr_open(rtlsdr_dev_t **out_dev, uint32_t index) memset(dev, 0, sizeof(rtlsdr_dev_t)); memcpy(dev->fir, fir_default, sizeof(fir_default)); - libusb_init(&dev->ctx); + r = libusb_init(&dev->ctx); + if(r < 0){ + free(dev); + return -1; + } dev->dev_lost = 1; diff --git a/src/rtl_adsb.c b/src/rtl_adsb.c index 7b10306..e611e78 100644 --- a/src/rtl_adsb.c +++ b/src/rtl_adsb.c @@ -45,8 +45,10 @@ #ifdef _WIN32 #define sleep Sleep +#if defined(_MSC_VER) && (_MSC_VER < 1800) #define round(x) (x > 0.0 ? floor(x + 0.5): ceil(x - 0.5)) #endif +#endif #define ADSB_RATE 2000000 #define ADSB_FREQ 1090000000 diff --git a/src/rtl_fm.c b/src/rtl_fm.c index 0f7ac38..89ce5e6 100644 --- a/src/rtl_fm.c +++ b/src/rtl_fm.c @@ -62,7 +62,7 @@ #include #include "getopt/getopt.h" #define usleep(x) Sleep(x/1000) -#ifdef _MSC_VER +#if defined(_MSC_VER) && (_MSC_VER < 1800) #define round(x) (x > 0.0 ? floor(x + 0.5): ceil(x - 0.5)) #endif #define _USE_MATH_DEFINES @@ -92,6 +92,9 @@ static int *atan_lut = NULL; static int atan_lut_size = 131072; /* 512 KB */ static int atan_lut_coef = 8; +static uint8_t *buffer = NULL; +static int use_sync = 0; + struct dongle_state { int exit_flag; @@ -215,6 +218,7 @@ void usage(void) "\t enables low-leakage downsample filter\n" "\t size can be 0 or 9. 0 has bad roll off\n" "\t[-A std/fast/lut choose atan math (default: std)]\n" + "\t[-S force sync output (defatuls: async)]\n" //"\t[-C clip_path (default: off)\n" //"\t (create time stamped raw clips, requires squelch)\n" //"\t (path must have '\%s' and will expand to date_time_freq)\n" @@ -236,7 +240,8 @@ sighandler(int signum) if (CTRL_C_EVENT == signum) { fprintf(stderr, "Signal caught, exiting!\n"); do_exit = 1; - rtlsdr_cancel_async(dongle.dev); + if (!use_sync) + rtlsdr_cancel_async(dongle.dev); return TRUE; } return FALSE; @@ -246,7 +251,8 @@ static void sighandler(int signum) { fprintf(stderr, "Signal caught, exiting!\n"); do_exit = 1; - rtlsdr_cancel_async(dongle.dev); + if (!use_sync) + rtlsdr_cancel_async(dongle.dev); } #endif @@ -271,7 +277,7 @@ int cic_9_tables[][10] = { {9, -199, -362, 5303, -25505, 77489, -25505, 5303, -362, -199}, }; -#ifdef _MSC_VER +#if defined(_MSC_VER) && (_MSC_VER < 1800) double log2(double n) { return log(n) / log(2.0); @@ -1034,6 +1040,20 @@ void sanity_checks(void) } +void dongle_read_sync(struct dongle_state *s) +{ + int r; + int n_read; + + r = rtlsdr_read_sync(s->dev, buffer, ACTUAL_BUF_LENGTH, &n_read); + if (r < 0) { + fprintf(stderr, "WARNING: sync read failed.\n"); + return; + } + + rtlsdr_callback(buffer, n_read, s); +} + int main(int argc, char **argv) { #ifndef _WIN32 @@ -1047,7 +1067,7 @@ int main(int argc, char **argv) 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:h:S")) != -1) { switch (opt) { case 'd': dongle.dev_index = verbose_device_search(optarg); @@ -1142,6 +1162,9 @@ int main(int argc, char **argv) demod.deemph = 1; demod.squelch_level = 0;} break; + case 'S': + use_sync = 1; + break; case 'h': default: usage(); @@ -1229,18 +1252,33 @@ int main(int argc, char **argv) usleep(100000); pthread_create(&output.thread, NULL, output_thread_fn, (void *)(&output)); pthread_create(&demod.thread, NULL, demod_thread_fn, (void *)(&demod)); - pthread_create(&dongle.thread, NULL, dongle_thread_fn, (void *)(&dongle)); - while (!do_exit) { - usleep(100000); + if (!use_sync) { + pthread_create(&dongle.thread, NULL, dongle_thread_fn, (void *)(&dongle)); + while(!do_exit) { + usleep(100000); + } + } + else { + + buffer = malloc(ACTUAL_BUF_LENGTH * sizeof(uint8_t)); + + while (!do_exit) { + dongle_read_sync(&dongle); + usleep(100); + } + + free (buffer); } + if (do_exit) { fprintf(stderr, "\nUser cancel, exiting...\n");} else { fprintf(stderr, "\nLibrary error %d, exiting...\n", r);} - rtlsdr_cancel_async(dongle.dev); + if (!use_sync) + rtlsdr_cancel_async(dongle.dev); pthread_join(dongle.thread, NULL); safe_cond_signal(&demod.ready, &demod.ready_m); pthread_join(demod.thread, NULL); diff --git a/src/rtl_power.c b/src/rtl_power.c index 7eb1d06..aa7a138 100644 --- a/src/rtl_power.c +++ b/src/rtl_power.c @@ -53,7 +53,7 @@ #include #include "getopt/getopt.h" #define usleep(x) Sleep(x/1000) -#ifdef _MSC_VER +#if defined(_MSC_VER) && (_MSC_VER < 1800) #define round(x) (x > 0.0 ? floor(x + 0.5): ceil(x - 0.5)) #endif #define _USE_MATH_DEFINES @@ -220,7 +220,7 @@ int cic_9_tables[][10] = { {9, -199, -362, 5303, -25505, 77489, -25505, 5303, -362, -199}, }; -#ifdef _MSC_VER +#if defined(_MSC_VER) && (_MSC_VER < 1800) double log2(double n) { return log(n) / log(2.0); diff --git a/src/rtlsdr.rc.in b/src/rtlsdr.rc.in new file mode 100644 index 0000000..bf603c3 --- /dev/null +++ b/src/rtlsdr.rc.in @@ -0,0 +1,34 @@ + +#include + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 0,0,0,0 + PRODUCTVERSION 0,0,0,0 + FILEFLAGSMASK 0x3fL +#ifndef NDEBUG + FILEFLAGS 0x0L +#else + FILEFLAGS 0x1L +#endif + FILEOS VOS__WINDOWS32 + FILETYPE VFT_DLL + FILESUBTYPE VFT2_DRV_INSTALLABLE + BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "FileDescription", "osmocom rtl-sdr" + VALUE "FileVersion", "@VERSION@" + VALUE "InternalName", "rtl-sdr.dll" + VALUE "LegalCopyright", "Licensed under GPLv2" + VALUE "OriginalFilename", "rtl-sdr.dll" + VALUE "ProductName", "osmocom rtl-sdr" + VALUE "ProductVersion", "@VERSION@" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END + END diff --git a/src/tuner_e4k.c b/src/tuner_e4k.c index c2ec044..400e745 100644 --- a/src/tuner_e4k.c +++ b/src/tuner_e4k.c @@ -64,11 +64,13 @@ static const uint8_t width2mask[] = { */ static int e4k_reg_write(struct e4k_state *e4k, uint8_t reg, uint8_t val) { + int r; uint8_t data[2]; data[0] = reg; data[1] = val; - return rtlsdr_i2c_write_fn(e4k->rtl_dev, e4k->i2c_addr, data, 2); + r = rtlsdr_i2c_write_fn(e4k->rtl_dev, e4k->i2c_addr, data, 2); + return r == 2 ? 0 : -1; } /*! \brief Read a register of the tuner chip diff --git a/src/tuner_r82xx.c b/src/tuner_r82xx.c index e03e034..f620238 100644 --- a/src/tuner_r82xx.c +++ b/src/tuner_r82xx.c @@ -1073,6 +1073,82 @@ int r82xx_set_gain(struct r82xx_priv *priv, int set_manual_gain, int gain) return 0; } +/* Bandwidth contribution by low-pass filter. */ +static const int r82xx_if_low_pass_bw_table[] = { + 1700000, 1600000, 1550000, 1450000, 1200000, 900000, 700000, 550000, 450000, 350000 +}; + +#define FILT_HP_BW1 350000 +#define FILT_HP_BW2 380000 +int r82xx_set_bandwidth(struct r82xx_priv *priv, int bw, uint32_t rate) +{ + int rc; + unsigned int i; + int real_bw = 0; + uint8_t reg_0a; + uint8_t reg_0b; + + if (bw > 7000000) { + // BW: 8 MHz + reg_0a = 0x10; + reg_0b = 0x0b; + priv->int_freq = 4570000; + } else if (bw > 6000000) { + // BW: 7 MHz + reg_0a = 0x10; + reg_0b = 0x2a; + priv->int_freq = 4570000; + } else if (bw > r82xx_if_low_pass_bw_table[0] + FILT_HP_BW1 + FILT_HP_BW2) { + // BW: 6 MHz + reg_0a = 0x10; + reg_0b = 0x6b; + priv->int_freq = 3570000; + } else { + reg_0a = 0x00; + reg_0b = 0x80; + priv->int_freq = 2300000; + + if (bw > r82xx_if_low_pass_bw_table[0] + FILT_HP_BW1) { + bw -= FILT_HP_BW2; + priv->int_freq += FILT_HP_BW2; + real_bw += FILT_HP_BW2; + } else { + reg_0b |= 0x20; + } + + if (bw > r82xx_if_low_pass_bw_table[0]) { + bw -= FILT_HP_BW1; + priv->int_freq += FILT_HP_BW1; + real_bw += FILT_HP_BW1; + } else { + reg_0b |= 0x40; + } + + // find low-pass filter + for(i = 0; i < ARRAY_SIZE(r82xx_if_low_pass_bw_table); ++i) { + if (bw > r82xx_if_low_pass_bw_table[i]) + break; + } + --i; + reg_0b |= 15 - i; + real_bw += r82xx_if_low_pass_bw_table[i]; + + priv->int_freq -= real_bw / 2; + } + + rc = r82xx_write_reg_mask(priv, 0x0a, reg_0a, 0x10); + if (rc < 0) + return rc; + + rc = r82xx_write_reg_mask(priv, 0x0b, reg_0b, 0xef); + if (rc < 0) + return rc; + + return priv->int_freq; +} +#undef FILT_HP_BW1 +#undef FILT_HP_BW2 + int r82xx_set_freq(struct r82xx_priv *priv, uint32_t freq) { int rc = -1;