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 <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