Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Separate functions for setting lna, mixer and vga gains (for r82xx tuner) #31

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions include/rtl-sdr.h
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,13 @@ RTLSDR_API int rtlsdr_set_freq_correction(rtlsdr_dev_t *dev, int ppm);
*/
RTLSDR_API int rtlsdr_get_freq_correction(rtlsdr_dev_t *dev);

enum gain_types {
lna,
mixer,
vga,
total
};

enum rtlsdr_tuner {
RTLSDR_TUNER_UNKNOWN = 0,
RTLSDR_TUNER_E4000,
Expand Down Expand Up @@ -214,6 +221,16 @@ RTLSDR_API int rtlsdr_get_tuner_gains(rtlsdr_dev_t *dev, int *gains);
* \return 0 on success
*/
RTLSDR_API int rtlsdr_set_tuner_gain(rtlsdr_dev_t *dev, int gain);
RTLSDR_API int rtlsdr_set_specific_gain(rtlsdr_dev_t *dev, int gain, enum gain_types gain_type);
RTLSDR_API int rtlsdr_set_lna_gain(rtlsdr_dev_t *dev, int gain);
RTLSDR_API int rtlsdr_set_mixer_gain(rtlsdr_dev_t *dev, int gain);
RTLSDR_API int rtlsdr_set_vga_gain(rtlsdr_dev_t *dev, int gain);

RTLSDR_API int rtlsdr_get_lna_gains(rtlsdr_dev_t *dev, int *gains);
RTLSDR_API int rtlsdr_get_mixer_gains(rtlsdr_dev_t *dev, int *gains);
RTLSDR_API int rtlsdr_get_vga_gains(rtlsdr_dev_t *dev, int *gains);
RTLSDR_API int rtlsdr_get_specific_gains(rtlsdr_dev_t *dev, int *gains, enum gain_types gain_type);


/*!
* Set the bandwidth for the device.
Expand Down
3 changes: 3 additions & 0 deletions include/tuner_r82xx.h
Original file line number Diff line number Diff line change
Expand Up @@ -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_mixer_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
177 changes: 160 additions & 17 deletions src/librtlsdr.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ 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_lna_gain)(void *, int gain /* tenth dB */);
int (*set_mixer_gain)(void *, int gain /* tenth dB */);
int (*set_vga_gain)(void *, int gain /* tenth dB */);
} rtlsdr_tuner_iface_t;

enum rtlsdr_async_status {
Expand Down Expand Up @@ -254,10 +257,34 @@ int r820t_set_bw(void *dev, int bw) {
return rtlsdr_set_center_freq(devt, devt->freq);
}

/*
* r820t_set_gain sets vga gain to 16 and then
* increments lna and mixer gains until the sum
* is greater than or equal to the desired gain.
*/
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);
}

/*
* The following three functions allow for setting
* the lna, mixer and vga gains independently.
*/
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_mixer_gain(void *dev, int gain) {
rtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev;
return r82xx_set_mixer_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);
Expand All @@ -266,37 +293,43 @@ 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_gain_mode
e4000_set_gain_mode,
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
},
{
_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
},
{
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
},
{
r820t_init, r820t_exit,
r820t_set_freq, r820t_set_bw, r820t_set_gain, NULL,
r820t_set_gain_mode
r820t_set_gain_mode,
r820t_set_lna_gain, r820t_set_mixer_gain, r820t_set_vga_gain
},
{
r820t_init, r820t_exit,
r820t_set_freq, r820t_set_bw, r820t_set_gain, NULL,
r820t_set_gain_mode
r820t_set_gain_mode,
r820t_set_lna_gain, r820t_set_mixer_gain, r820t_set_vga_gain
},
};

Expand Down Expand Up @@ -955,6 +988,72 @@ enum rtlsdr_tuner rtlsdr_get_tuner_type(rtlsdr_dev_t *dev)
return dev->tuner_type;
}

int rtlsdr_get_lna_gains(rtlsdr_dev_t *dev, int *gains)
{
return rtlsdr_get_specific_gains(dev,gains,lna);
}
int rtlsdr_get_mixer_gains(rtlsdr_dev_t *dev, int *gains)
{
return rtlsdr_get_specific_gains(dev,gains,mixer);
}
int rtlsdr_get_vga_gains(rtlsdr_dev_t *dev, int *gains)
{
return rtlsdr_get_specific_gains(dev,gains,vga);
}

/*
* rtlsdr_get_specific_gains is essentially a copy of
* rtlsdr_get_tuner_gains but for getting the individual
* lna, mixer and vga gains (currently hard coded below).
* I don't like the double switch, but it was quick and
* allows for expansion to support other tuners so it
* will do for now.
*/
int rtlsdr_get_specific_gains(rtlsdr_dev_t *dev, int *gains,enum gain_types gain_type)
{
const int r82xx_lna_gains[] = { 0, 9, 22, 62, 100, 113, 144, 166, 192, 223, 249, 263, 282, 287, 322, 335 };
const int r82xx_mixer_gains[] = { 0, 5, 15, 25, 44, 53, 63, 88, 105, 115, 123, 139, 152, 158, 161, 153 };
const int r82xx_vga_gains[] = { 0, 26, 52, 82, 124, 159, 183, 196, 210, 242, 278, 312, 347, 384, 419, 455 };

const int unknown_lna_gains[] = { 0 /* no gain values */ };

const int *ptr = NULL;
int len = 0;

if (!dev)
return -1;

switch (dev->tuner_type) {
case RTLSDR_TUNER_R820T:
case RTLSDR_TUNER_R828D:
switch(gain_type)
{
case lna:
ptr = r82xx_lna_gains; len = sizeof(r82xx_lna_gains);
break;
case mixer:
ptr = r82xx_mixer_gains; len = sizeof(r82xx_mixer_gains);
break;
case vga:
default:
ptr = r82xx_vga_gains; len = sizeof(r82xx_vga_gains);
}
break;
default:
ptr = unknown_lna_gains; len = sizeof(unknown_lna_gains);
break;
}

if (!gains) { /* no buffer provided, just return the count */
return len / sizeof(int);
} else {
if (len)
memcpy(gains, ptr, len);

return len / sizeof(int);
}
}

int rtlsdr_get_tuner_gains(rtlsdr_dev_t *dev, int *gains)
{
/* all gain values are expressed in tenths of a dB */
Expand Down Expand Up @@ -1028,15 +1127,67 @@ int rtlsdr_set_tuner_bandwidth(rtlsdr_dev_t *dev, uint32_t bw)
}

int rtlsdr_set_tuner_gain(rtlsdr_dev_t *dev, int gain)
{
return rtlsdr_set_specific_gain(dev,gain,total);
}

int rtlsdr_get_tuner_gain(rtlsdr_dev_t *dev)
{
if (!dev)
return 0;

return dev->gain;
}

/*
* rtlsdr_set_lna_gain, rtlsdr_set_mixer_gain and rtlsdr_set_vga_gain
* all call rtlsdr_set_specific_gain. I've also rolled
* rtlsdr_set_tuner_gain (above) into this as it's using the same code.
*/
int rtlsdr_set_lna_gain(rtlsdr_dev_t *dev, int gain)
{
return rtlsdr_set_specific_gain(dev,gain,lna);
}
int rtlsdr_set_mixer_gain(rtlsdr_dev_t *dev, int gain)
{
return rtlsdr_set_specific_gain(dev,gain,mixer);
}
int rtlsdr_set_vga_gain(rtlsdr_dev_t *dev, int gain)
{
return rtlsdr_set_specific_gain(dev,gain,vga);
}

int rtlsdr_set_specific_gain(rtlsdr_dev_t *dev, int gain, enum gain_types gain_type)
{
int r = 0;

int (*ptr_set_gain)(void *, int gain /* tenth dB */) = NULL;

if (!dev || !dev->tuner)
return -1;

if (dev->tuner->set_gain) {
switch(gain_type)
{
case lna:
if (dev->tuner->set_lna_gain)
ptr_set_gain = (dev->tuner->set_lna_gain);
break;
case mixer:
if (dev->tuner->set_mixer_gain)
ptr_set_gain = (dev->tuner->set_mixer_gain);
break;
case vga:
if (dev->tuner->set_vga_gain)
ptr_set_gain = (dev->tuner->set_vga_gain);
break;
default:
if(dev->tuner->set_gain)
ptr_set_gain = (dev->tuner->set_gain);
}

if (ptr_set_gain) {
rtlsdr_set_i2c_repeater(dev, 1);
r = dev->tuner->set_gain((void *)dev, gain);
r = ptr_set_gain((void *)dev, gain);
rtlsdr_set_i2c_repeater(dev, 0);
}

Expand All @@ -1048,14 +1199,6 @@ int rtlsdr_set_tuner_gain(rtlsdr_dev_t *dev, int gain)
return r;
}

int rtlsdr_get_tuner_gain(rtlsdr_dev_t *dev)
{
if (!dev)
return 0;

return dev->gain;
}

int rtlsdr_set_tuner_if_gain(rtlsdr_dev_t *dev, int stage, int gain)
{
int r = 0;
Expand Down
87 changes: 87 additions & 0 deletions src/tuner_r82xx.c
Original file line number Diff line number Diff line change
Expand Up @@ -1004,6 +1004,7 @@ static const int r82xx_mixer_gain_steps[] = {
0, 5, 10, 10, 19, 9, 10, 25, 17, 10, 8, 16, 13, 6, 3, -8
};


int r82xx_set_gain(struct r82xx_priv *priv, int set_manual_gain, int gain)
{
int rc;
Expand Down Expand Up @@ -1073,6 +1074,92 @@ 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;

int i, total_gain = 0;
uint8_t lna_index = 0;
uint8_t data[4];

/* LNA auto off */
rc = r82xx_write_reg_mask(priv, 0x05, 0x10, 0x10);
if (rc < 0)
return rc;

for (i = 0; i < 15; i++) {
if (total_gain >= gain)
break;

total_gain += r82xx_lna_gain_steps[++lna_index];

}

/* set LNA gain */
rc = r82xx_write_reg_mask(priv, 0x05, lna_index, 0x0f);
if (rc < 0)
return rc;

return 0;
}

int r82xx_set_mixer_gain(struct r82xx_priv *priv, int gain)
{
int rc;

int i, total_gain = 0;
uint8_t mix_index = 0;
uint8_t data[4];

/* Mixer auto off */
rc = r82xx_write_reg_mask(priv, 0x07, 0, 0x10);
if (rc < 0)
return rc;

rc = r82xx_read(priv, 0x00, data, sizeof(data));
if (rc < 0)
return rc;

for (i = 0; i < 15; i++) {
if (total_gain >= gain)
break;

total_gain += r82xx_mixer_gain_steps[++mix_index];
}

/* set Mixer gain */
rc = r82xx_write_reg_mask(priv, 0x07, mix_index, 0x0f);
if (rc < 0)
return rc;

return 0;
}


int r82xx_set_vga_gain(struct r82xx_priv *priv, int gain)
{
int rc;

int i, total_gain = 0;
uint8_t vga_index = 0;
uint8_t data[4];

for (i = 0; i < 15; i++) {
if (total_gain >= gain)
break;

total_gain += r82xx_vga_gain_steps[++vga_index];
}

/* set VGA gain */
rc = r82xx_write_reg_mask(priv, 0x0c, vga_index, 0x9f);
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
Expand Down