diff --git a/include/rtl-sdr.h b/include/rtl-sdr.h index 2b9fff0..98c9992 100644 --- a/include/rtl-sdr.h +++ b/include/rtl-sdr.h @@ -229,6 +229,18 @@ RTLSDR_API int rtlsdr_set_testmode(rtlsdr_dev_t *dev, int on); */ RTLSDR_API int rtlsdr_set_agc_mode(rtlsdr_dev_t *dev, int on); +/*! + * Enable or disable the direct sampling mode. When enabled, the IF mode + * of the RTL2832 is activated, and rtlsdr_set_center_freq() will control + * the IF-frequency of the DDC, which can be used to tune from 0 to 28.8 MHz + * (xtal frequency of the RTL2832). + * + * \param dev the device handle given by rtlsdr_open() + * \param direct sampling mode, 1 means enabled, 0 disabled + * \return 0 on success + */ +RTLSDR_API int rtlsdr_set_direct_sampling(rtlsdr_dev_t *dev, int on); + /* streaming functions */ RTLSDR_API int rtlsdr_reset_buffer(rtlsdr_dev_t *dev); diff --git a/include/tuner_r820t.h b/include/tuner_r820t.h index 058a9f2..5d15bfe 100644 --- a/include/tuner_r820t.h +++ b/include/tuner_r820t.h @@ -5,6 +5,8 @@ #define R820T_CHECK_ADDR 0x00 #define R820T_CHECK_VAL 0x69 +#define R820T_IF_FREQ 3570000 + //*************************************************************** //* INCLUDES.H //*************************************************************** diff --git a/src/librtlsdr.c b/src/librtlsdr.c index 87f3ebf..da7191b 100644 --- a/src/librtlsdr.c +++ b/src/librtlsdr.c @@ -79,6 +79,7 @@ struct rtlsdr_dev { /* rtl demod context */ uint32_t rate; /* Hz */ uint32_t rtl_xtal; /* Hz */ + int direct_sampling; /* tuner context */ enum rtlsdr_tuner tuner_type; rtlsdr_tuner_iface_t *tuner; @@ -562,11 +563,19 @@ int rtlsdr_deinit_baseband(rtlsdr_dev_t *dev) int rtlsdr_set_if_freq(rtlsdr_dev_t *dev, uint32_t freq) { + uint32_t rtl_xtal; int32_t if_freq; uint8_t tmp; int r; - if_freq = ((freq * TWO_POW(22)) / dev->rtl_xtal) * (-1); + if (!dev) + return -1; + + /* read corrected clock value */ + if (rtlsdr_get_xtal_freq(dev, &rtl_xtal, NULL)) + return -2; + + if_freq = ((freq * TWO_POW(22)) / rtl_xtal) * (-1); tmp = (if_freq >> 16) & 0x3f; r = rtlsdr_demod_write_reg(dev, 1, 0x19, tmp, 1); @@ -679,17 +688,19 @@ int rtlsdr_set_center_freq(rtlsdr_dev_t *dev, uint32_t freq) if (!dev || !dev->tuner) return -1; - if (dev->tuner->set_freq) { + if (dev->direct_sampling) { + r = rtlsdr_set_if_freq(dev, freq); + } else if (dev->tuner && dev->tuner->set_freq) { rtlsdr_set_i2c_repeater(dev, 1); r = dev->tuner->set_freq(dev, freq); rtlsdr_set_i2c_repeater(dev, 0); - - if (!r) - dev->freq = freq; - else - dev->freq = 0; } + if (!r) + dev->freq = freq; + else + dev->freq = 0; + return r; } @@ -751,6 +762,7 @@ int rtlsdr_get_tuner_gains(rtlsdr_dev_t *dev, int *gains) const int fc0013_gains[] = { -63, 71, 191, 197 }; const int fc2580_gains[] = { 0 /* no gain values */ }; const int r820t_gains[] = { 0 /* no gain values */ }; + const int unknown_gains[] = { 0 /* no gain values */ }; int *ptr = NULL; int len = 0; @@ -775,7 +787,7 @@ int rtlsdr_get_tuner_gains(rtlsdr_dev_t *dev, int *gains) ptr = (int *)r820t_gains; len = sizeof(r820t_gains); break; default: - fprintf(stderr, "Invalid tuner type %d\n", dev->tuner_type); + ptr = (int *)unknown_gains; len = sizeof(unknown_gains); break; } @@ -923,6 +935,52 @@ int rtlsdr_set_agc_mode(rtlsdr_dev_t *dev, int on) return rtlsdr_demod_write_reg(dev, 0, 0x19, on ? 0x25 : 0x05, 1); } +int rtlsdr_set_direct_sampling(rtlsdr_dev_t *dev, int on) +{ + int r = 0; + + if (!dev) + return -1; + + if (on) { + if (dev->tuner && dev->tuner->exit) { + rtlsdr_set_i2c_repeater(dev, 1); + r = dev->tuner->exit(dev); + rtlsdr_set_i2c_repeater(dev, 0); + } + + /* disable Zero-IF mode */ + r |= rtlsdr_demod_write_reg(dev, 1, 0xb1, 0x1a, 1); + + /* disable spectrum inversion */ + r |= rtlsdr_demod_write_reg(dev, 1, 0x15, 0x00, 1); + + fprintf(stderr, "Enabled direct sampling mode\n"); + dev->direct_sampling = 1; + } else { + if (dev->tuner && dev->tuner->init) { + rtlsdr_set_i2c_repeater(dev, 1); + r |= dev->tuner->init(dev); + rtlsdr_set_i2c_repeater(dev, 0); + } + + if (dev->tuner_type == RTLSDR_TUNER_R820T) { + r |= rtlsdr_set_if_freq(dev, R820T_IF_FREQ); + + /* enable spectrum inversion */ + r |= rtlsdr_demod_write_reg(dev, 1, 0x15, 0x01, 1); + } else { + /* Enable Zero-IF mode */ + rtlsdr_demod_write_reg(dev, 1, 0xb1, 0x1b, 1); + } + + fprintf(stderr, "Disabled direct sampling mode\n"); + dev->direct_sampling = 0; + } + + return r; +} + static rtlsdr_dongle_t *find_known_device(uint16_t vid, uint16_t pid) { unsigned int i; @@ -1137,7 +1195,7 @@ int rtlsdr_open(rtlsdr_dev_t **out_dev, uint32_t index) /* the R820T uses 3.57 MHz IF for the DVB-T 6 MHz mode, and * 4.57 MHz for the 8 MHz mode */ - rtlsdr_set_if_freq(dev, 3570000); + rtlsdr_set_if_freq(dev, R820T_IF_FREQ); /* enable spectrum inversion */ rtlsdr_demod_write_reg(dev, 1, 0x15, 0x01, 1); @@ -1169,8 +1227,8 @@ int rtlsdr_open(rtlsdr_dev_t **out_dev, uint32_t index) found: if (dev->tuner_type == RTLSDR_TUNER_UNKNOWN) { - r = -1; - goto err; + fprintf(stderr, "No supported tuner found\n"); + rtlsdr_set_direct_sampling(dev, 1); } dev->tuner = &tuners[dev->tuner_type]; @@ -1204,7 +1262,7 @@ int rtlsdr_close(rtlsdr_dev_t *dev) while (RTLSDR_INACTIVE != dev->async_status) usleep(10); - rtlsdr_deinit_baseband(dev); + rtlsdr_deinit_baseband(dev); libusb_release_interface(dev->devh, 0); libusb_close(dev->devh);