[RFC PATCH] rtl-sdr: add support for independent gain settings

Luigi Tarenga luigi.tarenga at gmail.com
Thu Dec 29 12:27:29 UTC 2016


hello list,
with this patch I try to start adding support for independent gain 
setting to rtl-sdr.
If this will go on (after review of course) I will be able to send a 
patch for gr-osmosdr
to expose those controls to end user applications like gqrx.
I see some users wish to experiment with manual tuning like it's 
possible to do on SDR#
with airspy dongle that use R820T tuner. I see some users started their 
own tree to add this.
There will be some complexity added but I think this can be masked with 
a proper
patching of gr-osmosdr to no break compatibility with existing software 
and let users
get the old control layout.

In a future patch I wish to add:
   - single automatic gain control. I ask if it's ok to expose a 
function like
     rtlsdr_set_tuner_gain_mode() and internally recycle the function 
added by
this patch but with a new *mode* parameter.
  - optimized gain for *max sensitivity* and *max linearity* like those 
found in airspy code.
    here I ask if is fine to expose gains as just integers instead of 
tenth of dB.

best regards
Luigi

Signed-off-by: Luigi Tarenga <luigi.tarenga at gmail.com>
---
  include/rtl-sdr.h     |  62 ++++++++++++++++++++++++++
  include/tuner_r82xx.h |   3 ++
  src/librtlsdr.c       | 120 
+++++++++++++++++++++++++++++++++++++++++++++++---
  src/tuner_r82xx.c     |  53 +++++++++++++++++++++-
  4 files changed, 230 insertions(+), 8 deletions(-)

diff --git a/include/rtl-sdr.h b/include/rtl-sdr.h
index fe64bea..2eec99c 100644
--- a/include/rtl-sdr.h
+++ b/include/rtl-sdr.h
@@ -216,6 +216,41 @@ RTLSDR_API int rtlsdr_get_tuner_gains(rtlsdr_dev_t 
*dev, int *gains);
  RTLSDR_API int rtlsdr_set_tuner_gain(rtlsdr_dev_t *dev, int gain);

  /*!
+ * Set the LNA gain for the device.
+ *
+ * Valid gain values for the R820T tuner are from 0 to 15.
+ *
+ * \param dev the device handle given by rtlsdr_open()
+ * \param gain between 0 and 15.
+ * \return 0 on success
+ */
+RTLSDR_API int rtlsdr_set_tuner_lna_gain(rtlsdr_dev_t *dev, int gain);
+
+/*!
+ * Set the Mixer gain for the device.
+ * Manual gain mode must be enabled for this to work.
+ *
+ * Valid gain values for the R820T tuner are from 0 to 15.
+ *
+ * \param dev the device handle given by rtlsdr_open()
+ * \param gain between 0 and 15.
+ * \return 0 on success
+ */
+RTLSDR_API int rtlsdr_set_tuner_mix_gain(rtlsdr_dev_t *dev, int gain);
+
+/*!
+ * Set the VGA gain for the device.
+ * Manual gain mode must be enabled for this to work.
+ *
+ * Valid gain values for the R820T tuner are from 0 to 15.
+ *
+ * \param dev the device handle given by rtlsdr_open()
+ * \param gain between 0 and 15.
+ * \return 0 on success
+ */
+RTLSDR_API int rtlsdr_set_tuner_vga_gain(rtlsdr_dev_t *dev, int gain);
+
+/*!
   * Set the bandwidth for the device.
   *
   * \param dev the device handle given by rtlsdr_open()
@@ -233,6 +268,33 @@ RTLSDR_API int 
rtlsdr_set_tuner_bandwidth(rtlsdr_dev_t *dev, uint32_t bw);
  RTLSDR_API int rtlsdr_get_tuner_gain(rtlsdr_dev_t *dev);

  /*!
+ * Get actual LNA gain the device is configured to.
+ * The LNA gain must have been set with \ref rtlsdr_set_tuner_lna_gain 
function.
+ *
+ * \param dev the device handle given by rtlsdr_open()
+ * \return -1 on error, LNA gain register value (0 to 15 for R820T).
+ */
+RTLSDR_API int rtlsdr_get_tuner_lna_gain(rtlsdr_dev_t *dev);
+
+/*!
+ * Get actual Mixer gain the device is configured to.
+ * The Mixer gain must have been set with \ref 
rtlsdr_set_tuner_mix_gain function.
+ *
+ * \param dev the device handle given by rtlsdr_open()
+ * \return -1 on error, Mixer gain register value (0 to 15 for R820T).
+ */
+RTLSDR_API int rtlsdr_get_tuner_mix_gain(rtlsdr_dev_t *dev);
+
+/*!
+ * Get actual VGA gain the device is configured to.
+ * The VGA gain must have been set with \ref rtlsdr_set_tuner_vga_gain 
function.
+ *
+ * \param dev the device handle given by rtlsdr_open()
+ * \return -1 on error, VGA gain register value (0 to 15 for R820T).
+ */
+RTLSDR_API int rtlsdr_get_tuner_vga_gain(rtlsdr_dev_t *dev);
+
+/*!
   * Set the intermediate frequency gain for the device.
   *
   * \param dev the device handle given by rtlsdr_open()
diff --git a/include/tuner_r82xx.h b/include/tuner_r82xx.h
index f6c206a..3ddb9c6 100644
--- a/include/tuner_r82xx.h
+++ b/include/tuner_r82xx.h
@@ -115,6 +115,9 @@ 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_lna_gain(struct r82xx_priv *priv, int gain);
+int r82xx_set_mix_gain(struct r82xx_priv *priv, int gain);
+int r82xx_set_vga_gain(struct r82xx_priv *priv, int gain);
  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..10556a8 100644
--- a/src/librtlsdr.c
+++ b/src/librtlsdr.c
@@ -62,6 +62,9 @@ typedef struct rtlsdr_tuner_iface {
      int (*set_freq)(void *, uint32_t freq /* Hz */);
      int (*set_bw)(void *, int bw /* Hz */);
      int (*set_gain)(void *, int gain /* tenth dB */);
+    int (*set_lna_gain)(void *, int gain /* register value */);
+    int (*set_mix_gain)(void *, int gain /* register value */);
+    int (*set_vga_gain)(void *, int gain /* register value */);
      int (*set_if_gain)(void *, int stage, int gain /* tenth dB */);
      int (*set_gain_mode)(void *, int manual);
  } rtlsdr_tuner_iface_t;
@@ -117,6 +120,9 @@ struct rtlsdr_dev {
      uint32_t offs_freq; /* Hz */
      int corr; /* ppm */
      int gain; /* tenth dB */
+    int lna_gain; /* register value */
+    int mix_gain; /* register value */
+    int vga_gain; /* register value */
      struct e4k_state e4k_s;
      struct r82xx_config r82xx_c;
      struct r82xx_priv r82xx_p;
@@ -258,6 +264,18 @@ 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_lna_gain(void *dev, int gain) {
+    rtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev;
+    return r82xx_set_lna_gain(&devt->r82xx_p, gain);
+}
+int r820t_set_mix_gain(void *dev, int gain) {
+    rtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev;
+    return r82xx_set_mix_gain(&devt->r82xx_p, gain);
+}
+int r820t_set_vga_gain(void *dev, int gain) {
+    rtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev;
+    return r82xx_set_vga_gain(&devt->r82xx_p, 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);
@@ -266,36 +284,37 @@ int r820t_set_gain_mode(void *dev, int manual) {
  /* 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 /* 
dummy for unknown tuners */
      },
      {
          e4000_init, e4000_exit,
-        e4000_set_freq, e4000_set_bw, e4000_set_gain, e4000_set_if_gain,
+        e4000_set_freq, e4000_set_bw, e4000_set_gain, NULL, NULL, NULL, 
e4000_set_if_gain,
          e4000_set_gain_mode
      },
      {
          _fc0012_init, fc0012_exit,
-        fc0012_set_freq, fc0012_set_bw, _fc0012_set_gain, NULL,
+        fc0012_set_freq, fc0012_set_bw, _fc0012_set_gain, NULL, NULL, 
NULL, NULL,
          fc0012_set_gain_mode
      },
      {
          _fc0013_init, fc0013_exit,
-        fc0013_set_freq, fc0013_set_bw, _fc0013_set_gain, NULL,
+        fc0013_set_freq, fc0013_set_bw, _fc0013_set_gain, NULL, NULL, 
NULL, NULL,
          fc0013_set_gain_mode
      },
      {
          fc2580_init, fc2580_exit,
-        _fc2580_set_freq, fc2580_set_bw, fc2580_set_gain, NULL,
+        _fc2580_set_freq, fc2580_set_bw, fc2580_set_gain, NULL, NULL, 
NULL, NULL,
          fc2580_set_gain_mode
      },
      {
          r820t_init, r820t_exit,
-        r820t_set_freq, r820t_set_bw, r820t_set_gain, NULL,
+        r820t_set_freq, r820t_set_bw, r820t_set_gain,
+        r820t_set_lna_gain, r820t_set_mix_gain, r820t_set_vga_gain, NULL,
          r820t_set_gain_mode
      },
      {
          r820t_init, r820t_exit,
-        r820t_set_freq, r820t_set_bw, r820t_set_gain, NULL,
+        r820t_set_freq, r820t_set_bw, r820t_set_gain, NULL, NULL, NULL, 
NULL,
          r820t_set_gain_mode
      },
  };
@@ -1049,6 +1068,69 @@ int rtlsdr_set_tuner_gain(rtlsdr_dev_t *dev, int 
gain)
      return r;
  }

+int rtlsdr_set_tuner_lna_gain(rtlsdr_dev_t *dev, int gain)
+{
+    int r = 0;
+
+    if (!dev || !dev->tuner)
+        return -1;
+
+    if (dev->tuner->set_lna_gain) {
+        rtlsdr_set_i2c_repeater(dev, 1);
+        r = dev->tuner->set_lna_gain((void *)dev, gain);
+        rtlsdr_set_i2c_repeater(dev, 0);
+    }
+
+    if (!r)
+        dev->lna_gain = gain;
+    else
+        dev->lna_gain = 0;
+
+    return r;
+}
+
+int rtlsdr_set_tuner_mix_gain(rtlsdr_dev_t *dev, int gain)
+{
+    int r = 0;
+
+    if (!dev || !dev->tuner)
+        return -1;
+
+    if (dev->tuner->set_mix_gain) {
+        rtlsdr_set_i2c_repeater(dev, 1);
+        r = dev->tuner->set_mix_gain((void *)dev, gain);
+        rtlsdr_set_i2c_repeater(dev, 0);
+    }
+
+    if (!r)
+        dev->mix_gain = gain;
+    else
+        dev->mix_gain = 0;
+
+    return r;
+}
+
+int rtlsdr_set_tuner_vga_gain(rtlsdr_dev_t *dev, int gain)
+{
+    int r = 0;
+
+    if (!dev || !dev->tuner)
+        return -1;
+
+    if (dev->tuner->set_vga_gain) {
+        rtlsdr_set_i2c_repeater(dev, 1);
+        r = dev->tuner->set_vga_gain((void *)dev, gain);
+        rtlsdr_set_i2c_repeater(dev, 0);
+    }
+
+    if (!r)
+        dev->vga_gain = gain;
+    else
+        dev->vga_gain = 0;
+
+    return r;
+}
+
  int rtlsdr_get_tuner_gain(rtlsdr_dev_t *dev)
  {
      if (!dev)
@@ -1057,6 +1139,30 @@ int rtlsdr_get_tuner_gain(rtlsdr_dev_t *dev)
      return dev->gain;
  }

+int rtlsdr_get_tuner_lna_gain(rtlsdr_dev_t *dev)
+{
+    if (!dev)
+        return -1;
+
+    return dev->lna_gain;
+}
+
+int rtlsdr_get_tuner_mix_gain(rtlsdr_dev_t *dev)
+{
+    if (!dev)
+        return -1;
+
+    return dev->mix_gain;
+}
+
+int rtlsdr_get_tuner_vga_gain(rtlsdr_dev_t *dev)
+{
+    if (!dev)
+        return -1;
+
+    return dev->vga_gain;
+}
+
  int rtlsdr_set_tuner_if_gain(rtlsdr_dev_t *dev, int stage, int gain)
  {
      int r = 0;
diff --git a/src/tuner_r82xx.c b/src/tuner_r82xx.c
index f620238..64d412b 100644
--- a/src/tuner_r82xx.c
+++ b/src/tuner_r82xx.c
@@ -1018,7 +1018,7 @@ int r82xx_set_gain(struct r82xx_priv *priv, int 
set_manual_gain, int gain)
          if (rc < 0)
              return rc;

-         /* Mixer auto off */
+        /* Mixer auto off */
          rc = r82xx_write_reg_mask(priv, 0x07, 0, 0x10);
          if (rc < 0)
              return rc;
@@ -1073,6 +1073,57 @@ int r82xx_set_gain(struct r82xx_priv *priv, int 
set_manual_gain, int gain)
      return 0;
  }

+int r82xx_set_lna_gain(struct r82xx_priv *priv, int gain)
+{
+    int rc;
+
+    /* LNA auto off */
+    rc = r82xx_write_reg_mask(priv, 0x05, 0x10, 0x10);
+    if (rc < 0)
+        return rc;
+
+    /* set LNA gain */
+    rc = r82xx_write_reg_mask(priv, 0x05, (uint8_t) gain, 0x0f);
+    if (rc < 0)
+        return rc;
+
+    return 0;
+}
+
+int r82xx_set_mix_gain(struct r82xx_priv *priv, int gain)
+{
+    int rc;
+
+    /* Mixer auto off */
+    rc = r82xx_write_reg_mask(priv, 0x07, 0, 0x10);
+    if (rc < 0)
+        return rc;
+
+    /* set Mixer gain */
+    rc = r82xx_write_reg_mask(priv, 0x07, (uint8_t) gain, 0x0f);
+    if (rc < 0)
+        return rc;
+
+    return 0;
+}
+
+int r82xx_set_vga_gain(struct r82xx_priv *priv, int gain)
+{
+    int rc;
+
+    /* VGA auto off */
+    rc = r82xx_write_reg_mask(priv, 0x0c, 0, 0x10);
+    if (rc < 0)
+        return rc;
+
+    /* set VGA gain */
+    rc = r82xx_write_reg_mask(priv, 0x0c, (uint8_t) gain, 0x0f);
+    if (rc < 0)
+        return rc;
+
+    return 0;
+}
+
  /* 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





More information about the osmocom-sdr mailing list