[RFC PATCH v3] rtl-sdr: add support for single gain stage tuning

Luigi Tarenga luigi.tarenga at gmail.com
Mon Jan 23 10:27:19 UTC 2017


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


More information about the osmocom-sdr mailing list