From martin.m at suddenlink.net Thu Jan 5 17:07:40 2017 From: martin.m at suddenlink.net (Martin McCormick) Date: Thu, 05 Jan 2017 11:07:40 -0600 Subject: Just Getting Started with the SDR Dongles. In-Reply-To: <9c473dbc-1966-5110-bcc8-da90f5c7cb0c@ettus.com> References: <9c473dbc-1966-5110-bcc8-da90f5c7cb0c@ettus.com> Message-ID: Thanks and sorry for my delay. I will respond to several points. =?UTF-8?Q?Marcus_M=c3=bcller?= writes: > Hi Martin, > > let me quickly address this in-text > On 12/30/2016 07:20 PM, Martin McCormick wrote: >Is the in-phase > > value related to the amplitude of the signal such that frequency > > variations within the pass band don't change it much? > Short answer: Yep. > Long answer: analog filters are never perfectly flat; in fact, the > flatter they are, the more expensive. But: if you use a bandwidth of > multiple MHz, and your signal of interest shifts within that by a > couple 100 kHz, you can basically assume flatness. Makes perfects sense to me. > > Is the Q or Quadrature value something that varies with > > whether or not the frequency is higher or lower than the center > > frequency set in to the device? > You should not consider I and Q to be independent things. I and Q are > *two* physical analog signals, but IQ **together** is the baseband > signal that represents the passband (==RF) signal that you want to > observe. > If there is a gain difference, we call that /IQ imbalance/, and it's > detrimental to any phase-sensitive modulation; therefore, receivers are > designed to minimize that effect. I and Q analog signal chains are > always designed to be as identical as possible! In fact, the only > difference is that the I signal is the RF signal mixed with a *cosine* > of the RF center frequency (and then low-pass filtered), and the Q > signal is the RF signal mixed with a *sine* of the same frequency ? the > two oscillators used for mixing are 90? out-of-phase, which is why the > first one is called *I*nphase, and the second *Q*uadrature (if you draw > a constellation diagram, the Q axis is orthogonal to the I axis). Ah! That is more or less what I expected. I knew there had to be sines and cosines in there since we are dealing with a cyclic pattern and essentially adding and subtracting vectors which produce positive, 0 and negative values depending upon the instantaneous values in the two readings. > > I could imagine that if the Q value responds to changes > > in frequency that one could get the effect of a discriminator > > circuit. > No, sorry. As explained, I and Q are exactly the same, but for a 90? > oscillator phase shift. That's how you convert a *real-valued passband* > to a *complex baseband* signal (just to give you two terms to look out > for). I am glad to read these things because it is one thing to be totally mystified by something as opposed to at least slightly understanding what is going on. > > I bought a couple of the rtl dongles and tried out the > > rtl-fm program to receive local FM signals and it worked quite > > well. > > > > Finally, what determines the pass-band? It did seem to > > get smaller if I tried a 12,000 HZ sample rate. I also was > > surprised at how accurate the frequency is. > So: The passband that you can observe is from -f_sample/2 to +f_sample/2 > around the frequency you tune to. Filtering is adjusted to give you a > perfect-as-feasible part of the spectrum that fits into that. I did try values lower than 12 KHZ but rtl_fm was reporting with floating-point issues and not running so I don't know if that was because I was trying to do something akin to dividing by 0 or trying to get the square root of a negative number. > > Other than the fact that I am at the low end of the > > learning curve, I see all kinds of possibilities. > :) Don't worry, you seem to be doing fine so far. > I don't really know from which background you're coming from, but if > you're rather curious and want to learn about *why* we use SDR, and how > that actually works, I'd recommend something like [1] (which also > explains in detail what I and Q are). Beware: It's pretty math-y ! > That's why I like SDR: It's really just doing math, but that math > actually does something to a signal that converts an intangible RF wave > to something very /practical/ (e.g. audible, if audio) and > /understandable, rather than just observable/ (as math concepts). > If you're not *that* curious (which I really couldn't blame you for), a > simple explanation for I and Q is that if you simply mix something with > a tone of its center frequency, than half of the signal (the upper > sideband) ends up on low, positive frequencies, whereas the other half > ends up on the negative frequencies, theoretically: mixing with a tone > shifts by the tone's frequency, and if you mix with the center > frequency, what was originally right and left of that center frequency > in spectrum ends up around 0Hz. Since with "normal" real signals, you > can't tell positive from negative frequencies (I can look at a cosine of > frequency f or -f for as long as I want, cos(f t) == cos (-f t)), you > need a way to tell positive from negative frequencies. The combination > of the two mixing products of sine and cosine of the same frequency does > that. Again, another light bulb moment. Briefly, my math background is best described as basic. I needed to take college algebra, trig and 6 hours of what was called Technical Calculus when I was attempting to become a vocational teacher during the 1980's. As a computer experimenter and amateur radio operator who also happens to be blind, the math started out a little rough in high school and early college but I then began to get the hang of it and ended up doing reasonably well by the end of the calculus course. A word to the wise is to learn those trig identities well. They will make your life much easier. To make a long story short, life took some other interesting turns and I worked for 25 years for Oklahoma State University's IT department in Network Operations, riding herd on unix systems and building all sorts of scripts and a few C programs for us to do our jobs better and more quickly. I retired in 2015, but it was mostly lots of fun, sort of the ultimate game. Back to the real topic at hand. You and another person in a completely unrelated discussion group just described the phasing method for transmitting and receiving single sideband signals which has always mystified me but is starting to come in to focus. The common method for sending and receiving SSB signals is to have a very expensive filter as you mentioned and then set the injection center frequency for the signal right on either the upper edge of the filter so that only lower sideband gets through or on the lower edge so that only USB signals get through. This works great but if you switch sidebands, the signal is now off frequency unless one adjusts a mixer frequency to compensate for the width of the rejection filter. Since we have digital signals in SDR, the phasing method should work really well as the old way is done with discrete components. I would imagine that a phasing modulator/demodulator probably only works right at the one frequency it was designed for and starts to be less effective at other frequencies. Anyway, many thanks for the good explanations and an apology for the rather long message. Martin WB5AGZ From luigi.tarenga at gmail.com Mon Jan 9 16:13:57 2017 From: luigi.tarenga at gmail.com (Luigi Tarenga) Date: Mon, 9 Jan 2017 17:13:57 +0100 Subject: [RFC PATCH v2] rtl-sdr: add support for single gain stage tuning Message-ID: Hello list, I repropose a patch to set independent gain for each stage with r820t tuner. The approach should be enough generalized to be extended to e4000 tuner too. I'm looking for feedback. best regards Luigi Signed-off-by: Luigi Tarenga --- include/rtl-sdr.h | 59 +++++++++++++++++++++++++ include/tuner_r82xx.h | 5 +++ src/librtlsdr.c | 118 +++++++++++++++++++++++++++++++++++++++++++++++--- src/tuner_r82xx.c | 83 +++++++++++++++++++++++++++++++++++ 4 files changed, 258 insertions(+), 7 deletions(-) diff --git a/include/rtl-sdr.h b/include/rtl-sdr.h index fe64bea..3719df4 100644 --- a/include/rtl-sdr.h +++ b/include/rtl-sdr.h @@ -200,6 +200,65 @@ RTLSDR_API enum rtlsdr_tuner rtlsdr_get_tuner_type(rtlsdr_dev_t *dev); RTLSDR_API int rtlsdr_get_tuner_gains(rtlsdr_dev_t *dev, int *gains); /*! + * Set the gain of a single gain stage for the device. + * + * Valid gain values may be queried with \ref rtlsdr_get_tuner_gain_stage_gains function. + * Usually those are from 0 to a positive integer plus -1 to set the stage in Auto gain mode. + * + * \param dev the device handle given by rtlsdr_open() + * \param stage from 0 to number of gain stages minus 1. + * \param gain from 0 to maximum supported gain for selected stage or -1 to set Auto gain mode. + * \return 0 on success + */ +RTLSDR_API int rtlsdr_set_tuner_gain_stage(rtlsdr_dev_t *dev, int stage, int gain); + + +/*! + * Get the gain of a single gain stage for the device. + * + * The value returned is a number from 0 to maximum supported gain. or -1 to indicate Auto gain mode. + * + * \param dev the device handle given by rtlsdr_open() + * \param stage from 0 to number of gain stages minus 1. + * \return the gain value in a range from 0 to maximum supported gain or -1 if Auto gain mode. + */ +RTLSDR_API int rtlsdr_get_tuner_gain_stage(rtlsdr_dev_t *dev, int stage); + + +/*! + * Get the number of gain stages supported by the device. + * + * The value returned is a number from 0 to the number of independent gain stages in the device. + * + * \param dev the device handle given by rtlsdr_open() + * \return the number of gain stages in the devices. 0 if none are supported. + */ +RTLSDR_API int rtlsdr_get_tuner_gain_stages(rtlsdr_dev_t *dev); + +/*! + * Get the supported values of gains in tenth of dB for a given stage. + * + * The value returned is the number of gain steps for the given stage and the maximum supported + * gain value plus one. The returned value -1 is the maximum value that + * can be used with \ref rtlsdr_set_tuner_gain_stage function as gain parameter. + * + * \param dev the device handle given by rtlsdr_open() + * \param stage from 0 to number of gain stages minus 1. + * \param gains a pointer to an array of integer where supported dB steps will be copied. NULL for no copy. + * \return the number of gain steps for the given stage. + */ +RTLSDR_API int rtlsdr_get_tuner_gain_stage_gains(rtlsdr_dev_t *dev, int stage, int *gains); + +/*! + * Get the name of the given gain stage. + * + * \param dev the device handle given by rtlsdr_open() + * \param stage from 0 to number of gain stages minus 1. + * \return the address of a NULL terminated char array containing a descriptive name of the give gain stage. + */ +RTLSDR_API const char* rtlsdr_get_tuner_gain_stage_name(rtlsdr_dev_t *dev, int stage); + +/*! * Set the gain for the device. * Manual gain mode must be enabled for this to work. * diff --git a/include/tuner_r82xx.h b/include/tuner_r82xx.h index f6c206a..b21988d 100644 --- a/include/tuner_r82xx.h +++ b/include/tuner_r82xx.h @@ -115,6 +115,11 @@ 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_gain_stage(struct r82xx_priv *priv, int stage, int gain); +int r82xx_get_gain_stage(struct r82xx_priv *priv, int stage); +int r82xx_get_gain_stages(struct r82xx_priv *priv); +int r82xx_get_gain_stage_gains(struct r82xx_priv *priv, int stage, int *gains); +const char *r82xx_get_gain_stage_name(struct r82xx_priv *priv, int stage); int r82xx_set_bandwidth(struct r82xx_priv *priv, int bandwidth, uint32_t rate); #endif diff --git a/src/librtlsdr.c b/src/librtlsdr.c index 9b7ba52..d0db745 100644 --- a/src/librtlsdr.c +++ b/src/librtlsdr.c @@ -64,6 +64,11 @@ typedef struct rtlsdr_tuner_iface { int (*set_gain)(void *, int gain /* tenth dB */); int (*set_if_gain)(void *, int stage, int gain /* tenth dB */); int (*set_gain_mode)(void *, int manual); + int (*set_gain_stage)(void *, int stage, int gain); + int (*get_gain_stage)(void *, int stage); + int (*get_gain_stages)(void *); + int (*get_gain_stage_gains)(void *, int stage, int *gains); + const char * (*get_gain_stage_name)(void *, int stage); } rtlsdr_tuner_iface_t; enum rtlsdr_async_status { @@ -258,45 +263,76 @@ 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); } + int r820t_set_gain_mode(void *dev, int manual) { rtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev; return r82xx_set_gain(&devt->r82xx_p, manual, 0); } +int r820t_set_gain_stage(void *dev, int stage, int gain) { + rtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev; + return r82xx_set_gain_stage(&devt->r82xx_p, stage, gain); +} + +int r820t_get_gain_stage(void *dev, int stage) { + rtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev; + return r82xx_get_gain_stage(&devt->r82xx_p, stage); +} + +int r820t_get_gain_stages(void *dev) { + rtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev; + return r82xx_get_gain_stages(&devt->r82xx_p); +} + +int r820t_get_gain_stage_gains(void *dev, int stage, int *gains) { + rtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev; + return r82xx_get_gain_stage_gains(&devt->r82xx_p, stage, gains); +} + +const char *r820t_get_gain_stage_name(void *dev, int stage) { + rtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev; + return r82xx_get_gain_stage_name(&devt->r82xx_p, stage); +} + /* definition order must match enum rtlsdr_tuner */ static rtlsdr_tuner_iface_t tuners[] = { { - NULL, NULL, NULL, NULL, NULL, NULL, NULL /* dummy for unknown tuners */ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL /* dummy for unknown tuners */ }, { e4000_init, e4000_exit, e4000_set_freq, e4000_set_bw, e4000_set_gain, e4000_set_if_gain, - e4000_set_gain_mode + e4000_set_gain_mode, NULL, NULL, NULL, NULL, NULL }, { _fc0012_init, fc0012_exit, fc0012_set_freq, fc0012_set_bw, _fc0012_set_gain, NULL, - fc0012_set_gain_mode + fc0012_set_gain_mode, NULL, NULL, NULL, NULL, NULL }, { _fc0013_init, fc0013_exit, fc0013_set_freq, fc0013_set_bw, _fc0013_set_gain, NULL, - fc0013_set_gain_mode + fc0013_set_gain_mode, NULL, NULL, NULL, NULL, NULL }, { fc2580_init, fc2580_exit, _fc2580_set_freq, fc2580_set_bw, fc2580_set_gain, NULL, - fc2580_set_gain_mode + fc2580_set_gain_mode, NULL, NULL, NULL, NULL, NULL }, { r820t_init, r820t_exit, r820t_set_freq, r820t_set_bw, r820t_set_gain, NULL, - r820t_set_gain_mode + r820t_set_gain_mode, + r820t_set_gain_stage, + r820t_get_gain_stage, + r820t_get_gain_stages, + r820t_get_gain_stage_gains, + r820t_get_gain_stage_name }, { r820t_init, r820t_exit, r820t_set_freq, r820t_set_bw, r820t_set_gain, NULL, - r820t_set_gain_mode + r820t_set_gain_mode, NULL, NULL, NULL, NULL, NULL }, }; @@ -1089,6 +1125,74 @@ int rtlsdr_set_tuner_gain_mode(rtlsdr_dev_t *dev, int mode) return r; } +int rtlsdr_set_tuner_gain_stage(rtlsdr_dev_t *dev, int stage, int gain) +{ + int r = 0; + + if (!dev || !dev->tuner) + return -1; + + if (dev->tuner->set_gain_stage) { + rtlsdr_set_i2c_repeater(dev, 1); + r = dev->tuner->set_gain_stage(dev, stage, gain); + rtlsdr_set_i2c_repeater(dev, 0); + } + + return r; +} + +int rtlsdr_get_tuner_gain_stage(rtlsdr_dev_t *dev, int stage) +{ + int r = 0; + + if (!dev || !dev->tuner) + return -1; + + if (dev->tuner->get_gain_stage) + r = dev->tuner->get_gain_stage(dev, stage); + + return r; +} + +int rtlsdr_get_tuner_gain_stages(rtlsdr_dev_t *dev) +{ + int r = 0; + + if (!dev || !dev->tuner) + return -1; + + if (dev->tuner->get_gain_stages) + r = dev->tuner->get_gain_stages(dev); + + return r; +} + +int rtlsdr_get_tuner_gain_stage_gains(rtlsdr_dev_t *dev, int stage, int *gains) +{ + int r = 0; + + if (!dev || !dev->tuner) + return -1; + + if (dev->tuner->get_gain_stage_gains) + r = dev->tuner->get_gain_stage_gains(dev, stage, gains); + + return r; +} + +const char *rtlsdr_get_tuner_gain_stage_name(rtlsdr_dev_t *dev, int stage) +{ + const char *r = ""; + + if (!dev || !dev->tuner) + return ""; + + if (dev->tuner->get_gain_stage_name) + r = dev->tuner->get_gain_stage_name(dev, stage); + + return r; +} + int rtlsdr_set_sample_rate(rtlsdr_dev_t *dev, uint32_t samp_rate) { int r = 0; diff --git a/src/tuner_r82xx.c b/src/tuner_r82xx.c index f620238..8c9b5d1 100644 --- a/src/tuner_r82xx.c +++ b/src/tuner_r82xx.c @@ -1073,6 +1073,89 @@ int r82xx_set_gain(struct r82xx_priv *priv, int set_manual_gain, int gain) return 0; } +#define STAGE_NUM 3 +typedef struct r82xx_gain_stage { + const char *name; + const int *steps; + const int num; + int gain; +} r82xx_gain_stage_t; + + +static r82xx_gain_stage_t gain_stage[STAGE_NUM] = { + { "LNA", (int []) { 0, 9, 13, 40, 38, 13, 31, 22, 26, 31, 26, 14, 19, 5, 35, 13 }, 16, 0}, + { "MIX", (int []) { 0, 5, 10, 10, 19, 9, 10, 25, 17, 10, 8, 16, 13, 6, 3, -8 }, 16, 0}, + { "VGA", (int []) { 0, 26, 26, 30, 42, 35, 24, 13, 14, 32, 36, 34, 35, 37, 35, 36 }, 16, 0} +}; + +static const int r82xx_gain_stage_register[STAGE_NUM] = { 0x05, 0x07, 0x0c }; +static const int r82xx_gain_stage_mask[STAGE_NUM] = { 0x0f, 0x0f, 0x0f }; +static const int r82xx_gain_stage_manual[STAGE_NUM] = { 0x01, 0x00, 0x00 }; +static const int r82xx_gain_stage_manual_mask[STAGE_NUM] = { 0x10, 0x10, 0x10 }; + +int r82xx_set_gain_stage(struct r82xx_priv *priv, int stage, int gain) +{ + int rc; + + if (stage < 0 || stage >= (int) ARRAY_SIZE(gain_stage)) + return -1; + + if (gain < -1 || gain >= gain_stage[stage].num) + return -1; + + if (gain >= 0) { + /* stage auto off */ + rc = r82xx_write_reg_mask(priv, r82xx_gain_stage_register[stage], r82xx_gain_stage_manual[stage], r82xx_gain_stage_manual_mask[stage]); + if (rc < 0) + return rc; + + rc = r82xx_write_reg_mask(priv, r82xx_gain_stage_register[stage], (uint8_t) gain, r82xx_gain_stage_mask[stage]); + if (rc < 0) + return rc; + + gain_stage[stage].gain = gain; + } else { + /* stage auto on */ + rc = r82xx_write_reg_mask(priv, r82xx_gain_stage_register[stage], ~(r82xx_gain_stage_manual[stage]), r82xx_gain_stage_manual_mask[stage]); + if (rc < 0) + return rc; + } + + return 0; +} + +int r82xx_get_gain_stage(struct r82xx_priv *priv, int stage) +{ + if (stage < 0 || stage >= (int) ARRAY_SIZE(gain_stage)) + return 0; + + return gain_stage[stage].gain; +} + +int r82xx_get_gain_stages(struct r82xx_priv *priv) +{ + return ARRAY_SIZE(gain_stage); +} + +int r82xx_get_gain_stage_gains(struct r82xx_priv *priv, int stage, int *gains) +{ + if (stage < 0 || stage >= (int) ARRAY_SIZE(gain_stage)) + return -1; + + if (gains) + memcpy(gains, gain_stage[stage].steps, gain_stage[stage].num * sizeof(int)); + + return gain_stage[stage].num; +} + +const char *r82xx_get_gain_stage_name(struct r82xx_priv *priv, int stage) +{ + if (stage < 0 || stage >= (int) ARRAY_SIZE(gain_stage)) + return ""; + + return gain_stage[stage].name; +} + /* 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 -- 2.11.0 From luigi.tarenga at gmail.com Tue Jan 10 10:10:59 2017 From: luigi.tarenga at gmail.com (Luigi Tarenga) Date: Tue, 10 Jan 2017 11:10:59 +0100 Subject: [RFC PATCH v3] rtl-sdr: add support for single gain stage tuning Message-ID: <4a89c7ea-918f-d64b-afb7-8a6491b5bbdc@gmail.com> Hi list, there is a bug in v2. I didn't put the gain array in the priv structure but used a global variable so multiple instance would use the same variable. v3 fix this by putting a gain[] in the priv structure so every dongle get its array allocated with a malloc. best regards Luigi Signed-off-by: Luigi Tarenga --- include/rtl-sdr.h | 59 +++++++++++++++++++++++++ include/tuner_r82xx.h | 7 +++ src/librtlsdr.c | 118 +++++++++++++++++++++++++++++++++++++++++++++++--- src/tuner_r82xx.c | 81 ++++++++++++++++++++++++++++++++++ 4 files changed, 258 insertions(+), 7 deletions(-) diff --git a/include/rtl-sdr.h b/include/rtl-sdr.h index fe64bea..3719df4 100644 --- a/include/rtl-sdr.h +++ b/include/rtl-sdr.h @@ -200,6 +200,65 @@ RTLSDR_API enum rtlsdr_tuner rtlsdr_get_tuner_type(rtlsdr_dev_t *dev); RTLSDR_API int rtlsdr_get_tuner_gains(rtlsdr_dev_t *dev, int *gains); /*! + * Set the gain of a single gain stage for the device. + * + * Valid gain values may be queried with \ref rtlsdr_get_tuner_gain_stage_gains function. + * Usually those are from 0 to a positive integer plus -1 to set the stage in Auto gain mode. + * + * \param dev the device handle given by rtlsdr_open() + * \param stage from 0 to number of gain stages minus 1. + * \param gain from 0 to maximum supported gain for selected stage or -1 to set Auto gain mode. + * \return 0 on success + */ +RTLSDR_API int rtlsdr_set_tuner_gain_stage(rtlsdr_dev_t *dev, int stage, int gain); + + +/*! + * Get the gain of a single gain stage for the device. + * + * The value returned is a number from 0 to maximum supported gain. or -1 to indicate Auto gain mode. + * + * \param dev the device handle given by rtlsdr_open() + * \param stage from 0 to number of gain stages minus 1. + * \return the gain value in a range from 0 to maximum supported gain or -1 if Auto gain mode. + */ +RTLSDR_API int rtlsdr_get_tuner_gain_stage(rtlsdr_dev_t *dev, int stage); + + +/*! + * Get the number of gain stages supported by the device. + * + * The value returned is a number from 0 to the number of independent gain stages in the device. + * + * \param dev the device handle given by rtlsdr_open() + * \return the number of gain stages in the devices. 0 if none are supported. + */ +RTLSDR_API int rtlsdr_get_tuner_gain_stages(rtlsdr_dev_t *dev); + +/*! + * Get the supported values of gains in tenth of dB for a given stage. + * + * The value returned is the number of gain steps for the given stage and the maximum supported + * gain value plus one. The returned value -1 is the maximum value that + * can be used with \ref rtlsdr_set_tuner_gain_stage function as gain parameter. + * + * \param dev the device handle given by rtlsdr_open() + * \param stage from 0 to number of gain stages minus 1. + * \param gains a pointer to an array of integer where supported dB steps will be copied. NULL for no copy. + * \return the number of gain steps for the given stage. + */ +RTLSDR_API int rtlsdr_get_tuner_gain_stage_gains(rtlsdr_dev_t *dev, int stage, int *gains); + +/*! + * Get the name of the given gain stage. + * + * \param dev the device handle given by rtlsdr_open() + * \param stage from 0 to number of gain stages minus 1. + * \return the address of a NULL terminated char array containing a descriptive name of the give gain stage. + */ +RTLSDR_API const char* rtlsdr_get_tuner_gain_stage_name(rtlsdr_dev_t *dev, int stage); + +/*! * Set the gain for the device. * Manual gain mode must be enabled for this to work. * diff --git a/include/tuner_r82xx.h b/include/tuner_r82xx.h index f6c206a..04bb113 100644 --- a/include/tuner_r82xx.h +++ b/include/tuner_r82xx.h @@ -38,6 +38,7 @@ #define NUM_REGS 30 #define NUM_IMR 5 #define IMR_TRIAL 9 +#define NUM_GAIN_STAGES 3 #define VER_NUM 49 @@ -90,6 +91,7 @@ struct r82xx_priv { enum r82xx_tuner_type type; uint32_t bw; /* in MHz */ + int gain[NUM_GAIN_STAGES]; void *rtl_dev; }; @@ -115,6 +117,11 @@ 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_gain_stage(struct r82xx_priv *priv, int stage, int gain); +int r82xx_get_gain_stage(struct r82xx_priv *priv, int stage); +int r82xx_get_gain_stages(struct r82xx_priv *priv); +int r82xx_get_gain_stage_gains(struct r82xx_priv *priv, int stage, int *gains); +const char *r82xx_get_gain_stage_name(struct r82xx_priv *priv, int stage); int r82xx_set_bandwidth(struct r82xx_priv *priv, int bandwidth, uint32_t rate); #endif diff --git a/src/librtlsdr.c b/src/librtlsdr.c index 9b7ba52..d0db745 100644 --- a/src/librtlsdr.c +++ b/src/librtlsdr.c @@ -64,6 +64,11 @@ typedef struct rtlsdr_tuner_iface { int (*set_gain)(void *, int gain /* tenth dB */); int (*set_if_gain)(void *, int stage, int gain /* tenth dB */); int (*set_gain_mode)(void *, int manual); + int (*set_gain_stage)(void *, int stage, int gain); + int (*get_gain_stage)(void *, int stage); + int (*get_gain_stages)(void *); + int (*get_gain_stage_gains)(void *, int stage, int *gains); + const char * (*get_gain_stage_name)(void *, int stage); } rtlsdr_tuner_iface_t; enum rtlsdr_async_status { @@ -258,45 +263,76 @@ 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); } + int r820t_set_gain_mode(void *dev, int manual) { rtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev; return r82xx_set_gain(&devt->r82xx_p, manual, 0); } +int r820t_set_gain_stage(void *dev, int stage, int gain) { + rtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev; + return r82xx_set_gain_stage(&devt->r82xx_p, stage, gain); +} + +int r820t_get_gain_stage(void *dev, int stage) { + rtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev; + return r82xx_get_gain_stage(&devt->r82xx_p, stage); +} + +int r820t_get_gain_stages(void *dev) { + rtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev; + return r82xx_get_gain_stages(&devt->r82xx_p); +} + +int r820t_get_gain_stage_gains(void *dev, int stage, int *gains) { + rtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev; + return r82xx_get_gain_stage_gains(&devt->r82xx_p, stage, gains); +} + +const char *r820t_get_gain_stage_name(void *dev, int stage) { + rtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev; + return r82xx_get_gain_stage_name(&devt->r82xx_p, stage); +} + /* definition order must match enum rtlsdr_tuner */ static rtlsdr_tuner_iface_t tuners[] = { { - NULL, NULL, NULL, NULL, NULL, NULL, NULL /* dummy for unknown tuners */ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL /* dummy for unknown tuners */ }, { e4000_init, e4000_exit, e4000_set_freq, e4000_set_bw, e4000_set_gain, e4000_set_if_gain, - e4000_set_gain_mode + e4000_set_gain_mode, NULL, NULL, NULL, NULL, NULL }, { _fc0012_init, fc0012_exit, fc0012_set_freq, fc0012_set_bw, _fc0012_set_gain, NULL, - fc0012_set_gain_mode + fc0012_set_gain_mode, NULL, NULL, NULL, NULL, NULL }, { _fc0013_init, fc0013_exit, fc0013_set_freq, fc0013_set_bw, _fc0013_set_gain, NULL, - fc0013_set_gain_mode + fc0013_set_gain_mode, NULL, NULL, NULL, NULL, NULL }, { fc2580_init, fc2580_exit, _fc2580_set_freq, fc2580_set_bw, fc2580_set_gain, NULL, - fc2580_set_gain_mode + fc2580_set_gain_mode, NULL, NULL, NULL, NULL, NULL }, { r820t_init, r820t_exit, r820t_set_freq, r820t_set_bw, r820t_set_gain, NULL, - r820t_set_gain_mode + r820t_set_gain_mode, + r820t_set_gain_stage, + r820t_get_gain_stage, + r820t_get_gain_stages, + r820t_get_gain_stage_gains, + r820t_get_gain_stage_name }, { r820t_init, r820t_exit, r820t_set_freq, r820t_set_bw, r820t_set_gain, NULL, - r820t_set_gain_mode + r820t_set_gain_mode, NULL, NULL, NULL, NULL, NULL }, }; @@ -1089,6 +1125,74 @@ int rtlsdr_set_tuner_gain_mode(rtlsdr_dev_t *dev, int mode) return r; } +int rtlsdr_set_tuner_gain_stage(rtlsdr_dev_t *dev, int stage, int gain) +{ + int r = 0; + + if (!dev || !dev->tuner) + return -1; + + if (dev->tuner->set_gain_stage) { + rtlsdr_set_i2c_repeater(dev, 1); + r = dev->tuner->set_gain_stage(dev, stage, gain); + rtlsdr_set_i2c_repeater(dev, 0); + } + + return r; +} + +int rtlsdr_get_tuner_gain_stage(rtlsdr_dev_t *dev, int stage) +{ + int r = 0; + + if (!dev || !dev->tuner) + return -1; + + if (dev->tuner->get_gain_stage) + r = dev->tuner->get_gain_stage(dev, stage); + + return r; +} + +int rtlsdr_get_tuner_gain_stages(rtlsdr_dev_t *dev) +{ + int r = 0; + + if (!dev || !dev->tuner) + return -1; + + if (dev->tuner->get_gain_stages) + r = dev->tuner->get_gain_stages(dev); + + return r; +} + +int rtlsdr_get_tuner_gain_stage_gains(rtlsdr_dev_t *dev, int stage, int *gains) +{ + int r = 0; + + if (!dev || !dev->tuner) + return -1; + + if (dev->tuner->get_gain_stage_gains) + r = dev->tuner->get_gain_stage_gains(dev, stage, gains); + + return r; +} + +const char *rtlsdr_get_tuner_gain_stage_name(rtlsdr_dev_t *dev, int stage) +{ + const char *r = ""; + + if (!dev || !dev->tuner) + return ""; + + if (dev->tuner->get_gain_stage_name) + r = dev->tuner->get_gain_stage_name(dev, stage); + + return r; +} + int rtlsdr_set_sample_rate(rtlsdr_dev_t *dev, uint32_t samp_rate) { int r = 0; diff --git a/src/tuner_r82xx.c b/src/tuner_r82xx.c index f620238..eeb646f 100644 --- a/src/tuner_r82xx.c +++ b/src/tuner_r82xx.c @@ -1073,6 +1073,87 @@ int r82xx_set_gain(struct r82xx_priv *priv, int set_manual_gain, int gain) return 0; } +typedef struct r82xx_gain_stage { + const char *name; + const int *steps; + const int num; +} r82xx_gain_stage_t; + + +static r82xx_gain_stage_t gain_stage[NUM_GAIN_STAGES] = { + { "LNA", (int []) { 0, 9, 13, 40, 38, 13, 31, 22, 26, 31, 26, 14, 19, 5, 35, 13 }, 16 }, + { "MIX", (int []) { 0, 5, 10, 10, 19, 9, 10, 25, 17, 10, 8, 16, 13, 6, 3, -8 }, 16 }, + { "VGA", (int []) { 0, 26, 26, 30, 42, 35, 24, 13, 14, 32, 36, 34, 35, 37, 35, 36 }, 16 } +}; + +static const int r82xx_gain_stage_register[NUM_GAIN_STAGES] = { 0x05, 0x07, 0x0c }; +static const int r82xx_gain_stage_mask[NUM_GAIN_STAGES] = { 0x0f, 0x0f, 0x0f }; +static const int r82xx_gain_stage_manual[NUM_GAIN_STAGES] = { 0x01, 0x00, 0x00 }; +static const int r82xx_gain_stage_manual_mask[NUM_GAIN_STAGES] = { 0x10, 0x10, 0x10 }; + +int r82xx_set_gain_stage(struct r82xx_priv *priv, int stage, int gain) +{ + int rc; + + if (stage < 0 || stage >= (int) ARRAY_SIZE(gain_stage)) + return -1; + + if (gain < -1 || gain >= gain_stage[stage].num) + return -1; + + if (gain >= 0) { + /* stage auto off */ + rc = r82xx_write_reg_mask(priv, r82xx_gain_stage_register[stage], r82xx_gain_stage_manual[stage], r82xx_gain_stage_manual_mask[stage]); + if (rc < 0) + return rc; + + rc = r82xx_write_reg_mask(priv, r82xx_gain_stage_register[stage], (uint8_t) gain, r82xx_gain_stage_mask[stage]); + if (rc < 0) + return rc; + + priv->gain[stage] = gain; + } else { + /* stage auto on */ + rc = r82xx_write_reg_mask(priv, r82xx_gain_stage_register[stage], ~(r82xx_gain_stage_manual[stage]), r82xx_gain_stage_manual_mask[stage]); + if (rc < 0) + return rc; + } + + return 0; +} + +int r82xx_get_gain_stage(struct r82xx_priv *priv, int stage) +{ + if (stage < 0 || stage >= (int) ARRAY_SIZE(gain_stage)) + return 0; + + return priv->gain[stage]; +} + +int r82xx_get_gain_stages(struct r82xx_priv *priv) +{ + return ARRAY_SIZE(gain_stage); +} + +int r82xx_get_gain_stage_gains(struct r82xx_priv *priv, int stage, int *gains) +{ + if (stage < 0 || stage >= (int) ARRAY_SIZE(gain_stage)) + return -1; + + if (gains) + memcpy(gains, gain_stage[stage].steps, gain_stage[stage].num * sizeof(int)); + + return gain_stage[stage].num; +} + +const char *r82xx_get_gain_stage_name(struct r82xx_priv *priv, int stage) +{ + if (stage < 0 || stage >= (int) ARRAY_SIZE(gain_stage)) + return ""; + + return gain_stage[stage].name; +} + /* 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 -- 2.11.0 From luigi.tarenga at gmail.com Mon Jan 23 10:27:19 2017 From: luigi.tarenga at gmail.com (Luigi Tarenga) Date: Mon, 23 Jan 2017 11:27:19 +0100 Subject: [RFC PATCH v3] rtl-sdr: add support for single gain stage tuning In-Reply-To: <4a89c7ea-918f-d64b-afb7-8a6491b5bbdc@gmail.com> References: <4a89c7ea-918f-d64b-afb7-8a6491b5bbdc@gmail.com> Message-ID: <4b826604-398b-c54e-9051-416956d95d45@gmail.com> Hello, I didn't received any feedback on this. Is there any chance my patch get considered to implement single gain tuning? Is this subject of any interest? thanks Luigi On 10/01/17 11:10, Luigi Tarenga wrote: > Hi list, > there is a bug in v2. I didn't put the gain array in the priv structure but used > a global variable so multiple instance would use the same variable. > > v3 fix this by putting a gain[] in the priv structure so every dongle get its > array allocated with a malloc. > > best regards > Luigi > > Signed-off-by: Luigi Tarenga > --- > include/rtl-sdr.h | 59 +++++++++++++++++++++++++ > include/tuner_r82xx.h | 7 +++ > src/librtlsdr.c | 118 +++++++++++++++++++++++++++++++++++++++++++++++--- > src/tuner_r82xx.c | 81 ++++++++++++++++++++++++++++++++++ > 4 files changed, 258 insertions(+), 7 deletions(-) > > diff --git a/include/rtl-sdr.h b/include/rtl-sdr.h > index fe64bea..3719df4 100644 > --- a/include/rtl-sdr.h > +++ b/include/rtl-sdr.h > @@ -200,6 +200,65 @@ RTLSDR_API enum rtlsdr_tuner rtlsdr_get_tuner_type(rtlsdr_dev_t *dev); > RTLSDR_API int rtlsdr_get_tuner_gains(rtlsdr_dev_t *dev, int *gains); > > /*! > + * Set the gain of a single gain stage for the device. > + * > + * Valid gain values may be queried with \ref rtlsdr_get_tuner_gain_stage_gains function. > + * Usually those are from 0 to a positive integer plus -1 to set the stage in Auto gain mode. > + * > + * \param dev the device handle given by rtlsdr_open() > + * \param stage from 0 to number of gain stages minus 1. > + * \param gain from 0 to maximum supported gain for selected stage or -1 to set Auto gain mode. > + * \return 0 on success > + */ > +RTLSDR_API int rtlsdr_set_tuner_gain_stage(rtlsdr_dev_t *dev, int stage, int gain); > + > + > +/*! > + * Get the gain of a single gain stage for the device. > + * > + * The value returned is a number from 0 to maximum supported gain. or -1 to indicate Auto gain mode. > + * > + * \param dev the device handle given by rtlsdr_open() > + * \param stage from 0 to number of gain stages minus 1. > + * \return the gain value in a range from 0 to maximum supported gain or -1 if Auto gain mode. > + */ > +RTLSDR_API int rtlsdr_get_tuner_gain_stage(rtlsdr_dev_t *dev, int stage); > + > + > +/*! > + * Get the number of gain stages supported by the device. > + * > + * The value returned is a number from 0 to the number of independent gain stages in the device. > + * > + * \param dev the device handle given by rtlsdr_open() > + * \return the number of gain stages in the devices. 0 if none are supported. > + */ > +RTLSDR_API int rtlsdr_get_tuner_gain_stages(rtlsdr_dev_t *dev); > + > +/*! > + * Get the supported values of gains in tenth of dB for a given stage. > + * > + * The value returned is the number of gain steps for the given stage and the maximum supported > + * gain value plus one. The returned value -1 is the maximum value that > + * can be used with \ref rtlsdr_set_tuner_gain_stage function as gain parameter. > + * > + * \param dev the device handle given by rtlsdr_open() > + * \param stage from 0 to number of gain stages minus 1. > + * \param gains a pointer to an array of integer where supported dB steps will be copied. NULL for no copy. > + * \return the number of gain steps for the given stage. > + */ > +RTLSDR_API int rtlsdr_get_tuner_gain_stage_gains(rtlsdr_dev_t *dev, int stage, int *gains); > + > +/*! > + * Get the name of the given gain stage. > + * > + * \param dev the device handle given by rtlsdr_open() > + * \param stage from 0 to number of gain stages minus 1. > + * \return the address of a NULL terminated char array containing a descriptive name of the give gain stage. > + */ > +RTLSDR_API const char* rtlsdr_get_tuner_gain_stage_name(rtlsdr_dev_t *dev, int stage); > + > +/*! > * Set the gain for the device. > * Manual gain mode must be enabled for this to work. > * > diff --git a/include/tuner_r82xx.h b/include/tuner_r82xx.h > index f6c206a..04bb113 100644 > --- a/include/tuner_r82xx.h > +++ b/include/tuner_r82xx.h > @@ -38,6 +38,7 @@ > #define NUM_REGS 30 > #define NUM_IMR 5 > #define IMR_TRIAL 9 > +#define NUM_GAIN_STAGES 3 > > #define VER_NUM 49 > > @@ -90,6 +91,7 @@ struct r82xx_priv { > enum r82xx_tuner_type type; > > uint32_t bw; /* in MHz */ > + int gain[NUM_GAIN_STAGES]; > > void *rtl_dev; > }; > @@ -115,6 +117,11 @@ 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_gain_stage(struct r82xx_priv *priv, int stage, int gain); > +int r82xx_get_gain_stage(struct r82xx_priv *priv, int stage); > +int r82xx_get_gain_stages(struct r82xx_priv *priv); > +int r82xx_get_gain_stage_gains(struct r82xx_priv *priv, int stage, int *gains); > +const char *r82xx_get_gain_stage_name(struct r82xx_priv *priv, int stage); > int r82xx_set_bandwidth(struct r82xx_priv *priv, int bandwidth, uint32_t rate); > > #endif > diff --git a/src/librtlsdr.c b/src/librtlsdr.c > index 9b7ba52..d0db745 100644 > --- a/src/librtlsdr.c > +++ b/src/librtlsdr.c > @@ -64,6 +64,11 @@ typedef struct rtlsdr_tuner_iface { > int (*set_gain)(void *, int gain /* tenth dB */); > int (*set_if_gain)(void *, int stage, int gain /* tenth dB */); > int (*set_gain_mode)(void *, int manual); > + int (*set_gain_stage)(void *, int stage, int gain); > + int (*get_gain_stage)(void *, int stage); > + int (*get_gain_stages)(void *); > + int (*get_gain_stage_gains)(void *, int stage, int *gains); > + const char * (*get_gain_stage_name)(void *, int stage); > } rtlsdr_tuner_iface_t; > > enum rtlsdr_async_status { > @@ -258,45 +263,76 @@ 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); > } > + > int r820t_set_gain_mode(void *dev, int manual) { > rtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev; > return r82xx_set_gain(&devt->r82xx_p, manual, 0); > } > > +int r820t_set_gain_stage(void *dev, int stage, int gain) { > + rtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev; > + return r82xx_set_gain_stage(&devt->r82xx_p, stage, gain); > +} > + > +int r820t_get_gain_stage(void *dev, int stage) { > + rtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev; > + return r82xx_get_gain_stage(&devt->r82xx_p, stage); > +} > + > +int r820t_get_gain_stages(void *dev) { > + rtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev; > + return r82xx_get_gain_stages(&devt->r82xx_p); > +} > + > +int r820t_get_gain_stage_gains(void *dev, int stage, int *gains) { > + rtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev; > + return r82xx_get_gain_stage_gains(&devt->r82xx_p, stage, gains); > +} > + > +const char *r820t_get_gain_stage_name(void *dev, int stage) { > + rtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev; > + return r82xx_get_gain_stage_name(&devt->r82xx_p, stage); > +} > + > /* definition order must match enum rtlsdr_tuner */ > static rtlsdr_tuner_iface_t tuners[] = { > { > - NULL, NULL, NULL, NULL, NULL, NULL, NULL /* dummy for unknown tuners */ > + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL /* dummy for unknown tuners */ > }, > { > e4000_init, e4000_exit, > e4000_set_freq, e4000_set_bw, e4000_set_gain, e4000_set_if_gain, > - e4000_set_gain_mode > + e4000_set_gain_mode, NULL, NULL, NULL, NULL, NULL > }, > { > _fc0012_init, fc0012_exit, > fc0012_set_freq, fc0012_set_bw, _fc0012_set_gain, NULL, > - fc0012_set_gain_mode > + fc0012_set_gain_mode, NULL, NULL, NULL, NULL, NULL > }, > { > _fc0013_init, fc0013_exit, > fc0013_set_freq, fc0013_set_bw, _fc0013_set_gain, NULL, > - fc0013_set_gain_mode > + fc0013_set_gain_mode, NULL, NULL, NULL, NULL, NULL > }, > { > fc2580_init, fc2580_exit, > _fc2580_set_freq, fc2580_set_bw, fc2580_set_gain, NULL, > - fc2580_set_gain_mode > + fc2580_set_gain_mode, NULL, NULL, NULL, NULL, NULL > }, > { > r820t_init, r820t_exit, > r820t_set_freq, r820t_set_bw, r820t_set_gain, NULL, > - r820t_set_gain_mode > + r820t_set_gain_mode, > + r820t_set_gain_stage, > + r820t_get_gain_stage, > + r820t_get_gain_stages, > + r820t_get_gain_stage_gains, > + r820t_get_gain_stage_name > }, > { > r820t_init, r820t_exit, > r820t_set_freq, r820t_set_bw, r820t_set_gain, NULL, > - r820t_set_gain_mode > + r820t_set_gain_mode, NULL, NULL, NULL, NULL, NULL > }, > }; > > @@ -1089,6 +1125,74 @@ int rtlsdr_set_tuner_gain_mode(rtlsdr_dev_t *dev, int mode) > return r; > } > > +int rtlsdr_set_tuner_gain_stage(rtlsdr_dev_t *dev, int stage, int gain) > +{ > + int r = 0; > + > + if (!dev || !dev->tuner) > + return -1; > + > + if (dev->tuner->set_gain_stage) { > + rtlsdr_set_i2c_repeater(dev, 1); > + r = dev->tuner->set_gain_stage(dev, stage, gain); > + rtlsdr_set_i2c_repeater(dev, 0); > + } > + > + return r; > +} > + > +int rtlsdr_get_tuner_gain_stage(rtlsdr_dev_t *dev, int stage) > +{ > + int r = 0; > + > + if (!dev || !dev->tuner) > + return -1; > + > + if (dev->tuner->get_gain_stage) > + r = dev->tuner->get_gain_stage(dev, stage); > + > + return r; > +} > + > +int rtlsdr_get_tuner_gain_stages(rtlsdr_dev_t *dev) > +{ > + int r = 0; > + > + if (!dev || !dev->tuner) > + return -1; > + > + if (dev->tuner->get_gain_stages) > + r = dev->tuner->get_gain_stages(dev); > + > + return r; > +} > + > +int rtlsdr_get_tuner_gain_stage_gains(rtlsdr_dev_t *dev, int stage, int *gains) > +{ > + int r = 0; > + > + if (!dev || !dev->tuner) > + return -1; > + > + if (dev->tuner->get_gain_stage_gains) > + r = dev->tuner->get_gain_stage_gains(dev, stage, gains); > + > + return r; > +} > + > +const char *rtlsdr_get_tuner_gain_stage_name(rtlsdr_dev_t *dev, int stage) > +{ > + const char *r = ""; > + > + if (!dev || !dev->tuner) > + return ""; > + > + if (dev->tuner->get_gain_stage_name) > + r = dev->tuner->get_gain_stage_name(dev, stage); > + > + return r; > +} > + > int rtlsdr_set_sample_rate(rtlsdr_dev_t *dev, uint32_t samp_rate) > { > int r = 0; > diff --git a/src/tuner_r82xx.c b/src/tuner_r82xx.c > index f620238..eeb646f 100644 > --- a/src/tuner_r82xx.c > +++ b/src/tuner_r82xx.c > @@ -1073,6 +1073,87 @@ int r82xx_set_gain(struct r82xx_priv *priv, int set_manual_gain, int gain) > return 0; > } > > +typedef struct r82xx_gain_stage { > + const char *name; > + const int *steps; > + const int num; > +} r82xx_gain_stage_t; > + > + > +static r82xx_gain_stage_t gain_stage[NUM_GAIN_STAGES] = { > + { "LNA", (int []) { 0, 9, 13, 40, 38, 13, 31, 22, 26, 31, 26, 14, 19, 5, 35, 13 }, 16 }, > + { "MIX", (int []) { 0, 5, 10, 10, 19, 9, 10, 25, 17, 10, 8, 16, 13, 6, 3, -8 }, 16 }, > + { "VGA", (int []) { 0, 26, 26, 30, 42, 35, 24, 13, 14, 32, 36, 34, 35, 37, 35, 36 }, 16 } > +}; > + > +static const int r82xx_gain_stage_register[NUM_GAIN_STAGES] = { 0x05, 0x07, 0x0c }; > +static const int r82xx_gain_stage_mask[NUM_GAIN_STAGES] = { 0x0f, 0x0f, 0x0f }; > +static const int r82xx_gain_stage_manual[NUM_GAIN_STAGES] = { 0x01, 0x00, 0x00 }; > +static const int r82xx_gain_stage_manual_mask[NUM_GAIN_STAGES] = { 0x10, 0x10, 0x10 }; > + > +int r82xx_set_gain_stage(struct r82xx_priv *priv, int stage, int gain) > +{ > + int rc; > + > + if (stage < 0 || stage >= (int) ARRAY_SIZE(gain_stage)) > + return -1; > + > + if (gain < -1 || gain >= gain_stage[stage].num) > + return -1; > + > + if (gain >= 0) { > + /* stage auto off */ > + rc = r82xx_write_reg_mask(priv, r82xx_gain_stage_register[stage], r82xx_gain_stage_manual[stage], r82xx_gain_stage_manual_mask[stage]); > + if (rc < 0) > + return rc; > + > + rc = r82xx_write_reg_mask(priv, r82xx_gain_stage_register[stage], (uint8_t) gain, r82xx_gain_stage_mask[stage]); > + if (rc < 0) > + return rc; > + > + priv->gain[stage] = gain; > + } else { > + /* stage auto on */ > + rc = r82xx_write_reg_mask(priv, r82xx_gain_stage_register[stage], ~(r82xx_gain_stage_manual[stage]), r82xx_gain_stage_manual_mask[stage]); > + if (rc < 0) > + return rc; > + } > + > + return 0; > +} > + > +int r82xx_get_gain_stage(struct r82xx_priv *priv, int stage) > +{ > + if (stage < 0 || stage >= (int) ARRAY_SIZE(gain_stage)) > + return 0; > + > + return priv->gain[stage]; > +} > + > +int r82xx_get_gain_stages(struct r82xx_priv *priv) > +{ > + return ARRAY_SIZE(gain_stage); > +} > + > +int r82xx_get_gain_stage_gains(struct r82xx_priv *priv, int stage, int *gains) > +{ > + if (stage < 0 || stage >= (int) ARRAY_SIZE(gain_stage)) > + return -1; > + > + if (gains) > + memcpy(gains, gain_stage[stage].steps, gain_stage[stage].num * sizeof(int)); > + > + return gain_stage[stage].num; > +} > + > +const char *r82xx_get_gain_stage_name(struct r82xx_priv *priv, int stage) > +{ > + if (stage < 0 || stage >= (int) ARRAY_SIZE(gain_stage)) > + return ""; > + > + return gain_stage[stage].name; > +} > + > /* 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 > From stefan.groissmeier at yahoo.com Tue Jan 10 16:37:55 2017 From: stefan.groissmeier at yahoo.com (=?UTF-8?Q?Stefan_Groi=c3=9fmeier?=) Date: Tue, 10 Jan 2017 16:37:55 -0000 Subject: Fwd: How to get out the maximum from cheap sdrs In-Reply-To: References: Message-ID: Hi All, I would like to realize an algorithm to build the best possible dvb-t sdr experience. The idea is, that no matter how many sdrs and what kind of antenna you have, the software gets the best out of your hardware. This is what I have thought: The user community of a system depends on how useful it is, how easy it is to use, build and how much money it costs. Rtl-sdrs are quite cheap, but for now a user has no benefit of having multiple sdrs in its system. That is why I'm searching a way to correlate the signals of the sdrs without hardware modification. I think everyone of you has seen the noise from the power source. Has anyone tried to build a filter to use that noise to calculate the delay between multiple dongles? I mean, they get the same noise. I don't know if it is sufficient, but it is also a good spot, to put some artificial noise in, as it can be easily accessed and does not interfere with rf circuitry when it is switched off. Is that an useful approach? Do you think this could work? Did I miss something? regards, Steve From knoeck at yahoo.com Wed Jan 11 07:06:17 2017 From: knoeck at yahoo.com (Steve Knoeck) Date: Wed, 11 Jan 2017 07:06:17 -0000 Subject: Floating point error in tuner_r82xx.c Message-ID: <3c1fc3dc-9303-504f-ca54-c36ae60379ba@yahoo.com> Hi, I get a floating point exception when I run rtl_tcp. I traced the error with GDB to line 515 of tuner_r82xx.c if (vco_fra > (2 * pll_ref_khz / n_sdm)) I found that n_sdm was 0. I don't understand how this code work and I'm very new to this software but it sure looks like a programming bug. | 513 /* sdm calculator */|| || 514 while (vco_fra > 1) {|| || 515 if (vco_fra > (2 * pll_ref_khz / n_sdm)) {|| || 516 sdm = sdm + 32768 / (n_sdm / 2);|| || 517 vco_fra = vco_fra - 2 * pll_ref_khz / n_sdm;|| || 518 if (n_sdm >= 0x8000)|| || 519 break;|| || 520 }|| || 521 n_sdm <<= 1;|| || 522 }| If the condition on line 515 ever evaluates to false then vco_fra doesn't get updated. The loop will keep repeating with the same value of vco_fra until n_sdm becomes 0. Steve -------------- next part -------------- An HTML attachment was scrubbed... URL: