diff --git a/include/rtl-sdr.h b/include/rtl-sdr.h index 804334d..1b0d82f 100644 --- a/include/rtl-sdr.h +++ b/include/rtl-sdr.h @@ -113,6 +113,34 @@ RTLSDR_API int rtlsdr_set_freq_correction(rtlsdr_dev_t *dev, int ppm); RTLSDR_API int rtlsdr_get_freq_correction(rtlsdr_dev_t *dev); +enum rtlsdr_tuner { + RTLSDR_TUNER_UNKNOWN = 0, + RTLSDR_TUNER_E4000, + RTLSDR_TUNER_FC0012, + RTLSDR_TUNER_FC0013, + RTLSDR_TUNER_FC2580 +}; + +/*! + * Get the tuner type. + * + * \param dev the device handle given by rtlsdr_open() + * \return <= 0 on error, tuner type otherwise + */ +RTLSDR_API enum rtlsdr_tuner rtlsdr_get_tuner_type(rtlsdr_dev_t *dev); + +/*! + * Get a list of gains supported by the tuner. + * + * NOTE: The gains argument must be preallocated by the caller. If NULL is + * being given instead, the number of available gain values will be returned. + * + * \param dev the device handle given by rtlsdr_open() + * \param gains array of gain values. In tenths of a dB, 115 means 11.5 dB. + * \return <= 0 on error, number of available (returned) gain values otherwise + */ +RTLSDR_API int rtlsdr_get_tuner_gains(rtlsdr_dev_t *dev, int *gains); + /*! * Set the gain for the device. * Manual gain mode must be enabled for this to work. @@ -121,6 +149,8 @@ RTLSDR_API int rtlsdr_get_freq_correction(rtlsdr_dev_t *dev); * -10, 15, 40, 65, 90, 115, 140, 165, 190, * 215, 240, 290, 340, 420, 430, 450, 470, 490 * + * Valid gain values may be queried with \ref rtlsdr_get_tuner_gains function. + * * \param dev the device handle given by rtlsdr_open() * \param gain in tenths of a dB, 115 means 11.5 dB. * \return 0 on success diff --git a/src/librtlsdr.c b/src/librtlsdr.c index d2a8713..c138438 100644 --- a/src/librtlsdr.c +++ b/src/librtlsdr.c @@ -45,7 +45,7 @@ #include "tuner_fc0013.h" #include "tuner_fc2580.h" -typedef struct rtlsdr_tuner { +typedef struct rtlsdr_tuner_iface { /* tuner interface */ int (*init)(void *); int (*exit)(void *); @@ -53,7 +53,7 @@ typedef struct rtlsdr_tuner { int (*set_bw)(void *, int bw /* Hz */); int (*set_gain)(void *, int gain /* dB */); int (*set_gain_mode)(void *, int manual); -} rtlsdr_tuner_t; +} rtlsdr_tuner_iface_t; enum rtlsdr_async_status { RTLSDR_INACTIVE = 0, @@ -75,7 +75,8 @@ struct rtlsdr_dev { uint32_t rate; /* Hz */ uint32_t rtl_xtal; /* Hz */ /* tuner context */ - rtlsdr_tuner_t *tuner; + enum rtlsdr_tuner tuner_type; + rtlsdr_tuner_iface_t *tuner; uint32_t tun_xtal; /* Hz */ uint32_t freq; /* Hz */ int corr; /* ppm */ @@ -130,9 +131,7 @@ int fc0012_set_freq(void *dev, uint32_t freq) { return fc0012_set_params(dev, freq, 6000000); } int fc0012_set_bw(void *dev, int bw) { return 0; } -int _fc0012_set_gain(void *dev, int gain) { - return fc0012_set_gain(dev, gain); -} +int _fc0012_set_gain(void *dev, int gain) { return fc0012_set_gain(dev, gain); } int fc0012_set_gain_mode(void *dev, int manual) { return 0; } int _fc0013_init(void *dev) { return fc0013_init(dev); } @@ -143,9 +142,7 @@ int fc0013_set_freq(void *dev, uint32_t freq) { return fc0013_set_params(dev, freq, 6000000); } int fc0013_set_bw(void *dev, int bw) { return 0; } -int _fc0013_set_gain(void *dev, int gain) { - return fc0013_set_gain(dev, gain); -} +int _fc0013_set_gain(void *dev, int gain) { return fc0013_set_gain(dev, gain); } int fc0013_set_gain_mode(void *dev, int manual) { return 0; } int fc2580_init(void *dev) { return fc2580_Initialize(dev); } @@ -153,20 +150,15 @@ int fc2580_exit(void *dev) { return 0; } int _fc2580_set_freq(void *dev, uint32_t freq) { return fc2580_SetRfFreqHz(dev, freq); } -int fc2580_set_bw(void *dev, int bw) { - return fc2580_SetBandwidthMode(dev, 1); -} +int fc2580_set_bw(void *dev, int bw) { return fc2580_SetBandwidthMode(dev, 1); } int fc2580_set_gain(void *dev, int gain) { return 0; } int fc2580_set_gain_mode(void *dev, int manual) { return 0; } -enum rtlsdr_tuners { - RTLSDR_TUNER_E4000, - RTLSDR_TUNER_FC0012, - RTLSDR_TUNER_FC0013, - RTLSDR_TUNER_FC2580 -}; - -static rtlsdr_tuner_t tuners[] = { +/* definition order must match enum rtlsdr_tuner */ +static rtlsdr_tuner_iface_t tuners[] = { + { + NULL, NULL, NULL, NULL, NULL, NULL /* dummy for unknown tuners */ + }, { e4000_init, e4000_exit, e4000_set_freq, e4000_set_bw, e4000_set_gain, @@ -673,6 +665,56 @@ int rtlsdr_get_freq_correction(rtlsdr_dev_t *dev) return dev->corr; } +enum rtlsdr_tuner rtlsdr_get_tuner_type(rtlsdr_dev_t *dev) +{ + if (!dev) + return -1; + + return dev->tuner_type; +} + +int rtlsdr_get_tuner_gains(rtlsdr_dev_t *dev, int *gains) +{ + const int e4k_gains[] = { -10, 15, 40, 65, 90, 115, 140, 165, 190, 215, + 240, 290, 340, 420, 430, 450, 470, 490 }; + const int fc0012_gains[] = { 0 /* no gain values */ }; + const int fc0013_gains[] = { -63, 71, 191, 197 }; + const int fc2580_gains[] = { 0 /* no gain values */ }; + + int *ptr = NULL; + int len = 0; + + if (!dev) + return -1; + + switch (dev->tuner_type) { + case RTLSDR_TUNER_E4000: + ptr = (int *)e4k_gains; len = sizeof(e4k_gains); + break; + case RTLSDR_TUNER_FC0012: + ptr = (int *)fc0012_gains; len = sizeof(fc0012_gains); + break; + case RTLSDR_TUNER_FC0013: + ptr = (int *)fc0013_gains; len = sizeof(fc0013_gains); + break; + case RTLSDR_TUNER_FC2580: + ptr = (int *)fc2580_gains; len = sizeof(fc2580_gains); + break; + default: + fprintf(stderr, "Invalid tuner type %d\n", dev->tuner_type); + break; + } + + if (!gains) { /* no buffer provided, just return the count */ + return len / sizeof(int); + } else { + if (len) + memcpy(gains, ptr, len); + + return len / sizeof(int); + } +} + int rtlsdr_set_tuner_gain(rtlsdr_dev_t *dev, int gain) { int r = 0; @@ -972,7 +1014,7 @@ int rtlsdr_open(rtlsdr_dev_t **out_dev, uint32_t index) reg = rtlsdr_i2c_read_reg(dev, E4K_I2C_ADDR, E4K_CHECK_ADDR); if (reg == E4K_CHECK_VAL) { fprintf(stderr, "Found Elonics E4000 tuner\n"); - dev->tuner = &tuners[RTLSDR_TUNER_E4000]; + dev->tuner_type = RTLSDR_TUNER_E4000; goto found; } @@ -980,7 +1022,7 @@ int rtlsdr_open(rtlsdr_dev_t **out_dev, uint32_t index) if (reg == FC0013_CHECK_VAL) { fprintf(stderr, "Found Fitipower FC0013 tuner\n"); rtlsdr_set_gpio_output(dev, 6); - dev->tuner = &tuners[RTLSDR_TUNER_FC0013]; + dev->tuner_type = RTLSDR_TUNER_FC0013; goto found; } @@ -994,7 +1036,7 @@ int rtlsdr_open(rtlsdr_dev_t **out_dev, uint32_t index) reg = rtlsdr_i2c_read_reg(dev, FC2580_I2C_ADDR, FC2580_CHECK_ADDR); if ((reg & 0x7f) == FC2580_CHECK_VAL) { fprintf(stderr, "Found FCI 2580 tuner\n"); - dev->tuner = &tuners[RTLSDR_TUNER_FC2580]; + dev->tuner_type = RTLSDR_TUNER_FC2580; goto found; } @@ -1002,18 +1044,22 @@ int rtlsdr_open(rtlsdr_dev_t **out_dev, uint32_t index) if (reg == FC0012_CHECK_VAL) { fprintf(stderr, "Found Fitipower FC0012 tuner\n"); rtlsdr_set_gpio_output(dev, 6); - dev->tuner = &tuners[RTLSDR_TUNER_FC0012]; + dev->tuner_type = RTLSDR_TUNER_FC0012; goto found; } found: - if (dev->tuner) { - dev->tun_xtal = dev->rtl_xtal; - - if (dev->tuner->init) - r = dev->tuner->init(dev); + if (dev->tuner_type == RTLSDR_TUNER_UNKNOWN) { + r = -1; + goto err; } + dev->tuner = &tuners[dev->tuner_type]; + dev->tun_xtal = dev->rtl_xtal; + + if (dev->tuner->init) + r = dev->tuner->init(dev); + rtlsdr_set_i2c_repeater(dev, 0); *out_dev = dev; diff --git a/src/rtl_test.c b/src/rtl_test.c index fffe089..e50fc47 100644 --- a/src/rtl_test.c +++ b/src/rtl_test.c @@ -160,6 +160,8 @@ int main(int argc, char **argv) uint32_t samp_rate = DEFAULT_SAMPLE_RATE; uint32_t out_block_size = DEFAULT_BUF_LENGTH; int device_count; + int count; + int gains[100]; while ((opt = getopt(argc, argv, "d:s:b:tS::")) != -1) { switch (opt) { @@ -228,6 +230,14 @@ int main(int argc, char **argv) #else SetConsoleCtrlHandler( (PHANDLER_ROUTINE) sighandler, TRUE ); #endif + count = rtlsdr_get_tuner_gains(dev, NULL); + fprintf(stderr, "Supported gain values (%d): ", count); + + count = rtlsdr_get_tuner_gains(dev, gains); + for (i = 0; i < count; i++) + fprintf(stderr, "%.1f ", gains[i] / 10.0); + fprintf(stderr, "\n"); + /* Set the sample rate */ r = rtlsdr_set_sample_rate(dev, samp_rate); if (r < 0)