Hello,
it's my first mail on this list, so please forgive me if I do something
wrong.
I'm about to post a couple of patches for RTL drivers:
1. RTL-SDR: convert _lut to float[] to reduce size by a factor of 256.
The _lut is being indexed by I + Q (16 bits = 65536 entries), however
both samples can be processed independently, resulting in 8-bit LUT.
Saves a bit of RAM and CPU cache.
lib/rtl/rtl_source_c.cc | 19 ++++++-------------
lib/rtl/rtl_source_c.h | 4 ++--
2 files changed, 8 insertions(+), 15 deletions(-)
2. RTL-TCP: Convert to single class model
The existing RTL TCP driver is quite different from its brother RTL_SDR.
It's much more complicated, uses gr::blocks::deinterleave and
gr::blocks::float_to_complex, and generally doesn't work correctly
(e.g. https://github.com/csete/gqrx/issues/99
Spectrum is mirrored when filter or demodulator changes (rtl_tcp) #99)
I've converted the RTL TCP driver to the model used by RTL_SDR,
simplifying it in the process, and fixing the GQRX issue.
lib/rtl_tcp/CMakeLists.txt | 1 -
lib/rtl_tcp/rtl_tcp_source_c.cc | 352 ++++++++++++++++++++++++++++++++--------
lib/rtl_tcp/rtl_tcp_source_c.h | 32 +++-
lib/rtl_tcp/rtl_tcp_source_f.cc | 327 -------------------------------------
lib/rtl_tcp/rtl_tcp_source_f.h | 125 --------------
5 files changed, 309 insertions(+), 528 deletions(-)
I'm also thinking about merging the code common to RTL-SDR and RTL-TCP,
but this it's done yet.
Comments?
--
Krzysztof Halasa
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
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
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 <luigi.tarenga(a)gmail.com>
---
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
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 <luigi.tarenga(a)gmail.com>
---
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
Here are some real beginner questions that I would like
to have a better understanding of concerning SDR in general and
the rtl dongles:
I understand that the I and Q signals are both 8-bit
numbers so each one can have 2^8 possible levels. 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?
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?
I could imagine that if the Q value responds to changes
in frequency that one could get the effect of a discriminator
circuit.
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.
Other than the fact that I am at the low end of the
learning curve, I see all kinds of possibilities.
Martin McCormick WB5AGZ