From 0e2268be54dfe0f254b5a7470e4e71b506eb4c09 Mon Sep 17 00:00:00 2001 From: Andrew Bates Date: Sat, 21 May 2016 12:29:20 +0000 Subject: [PATCH 1/2] Added separate functions fro getting available gains for lna, mixer and vga for r82xx as well as setting those gains individually. working well so far. Only works for r82xx tuner but doesn't break anything for others (only tried with rt820 and e4000 tuners). Shouldn't break any existing code that uses the library. --- include/rtl-sdr.h | 16 ++++ include/tuner_r82xx.h | 3 + src/librtlsdr.c | 170 ++++++++++++++++++++++++++++++++++++++++-- src/tuner_r82xx.c | 87 +++++++++++++++++++++ 4 files changed, 269 insertions(+), 7 deletions(-) diff --git a/include/rtl-sdr.h b/include/rtl-sdr.h index fe64bea5..e05eb27b 100644 --- a/include/rtl-sdr.h +++ b/include/rtl-sdr.h @@ -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, @@ -214,6 +221,15 @@ 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_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. diff --git a/include/tuner_r82xx.h b/include/tuner_r82xx.h index f6c206aa..b5371d07 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_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 diff --git a/src/librtlsdr.c b/src/librtlsdr.c index 06506062..146734df 100644 --- a/src/librtlsdr.c +++ b/src/librtlsdr.c @@ -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 { @@ -258,6 +261,33 @@ 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_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); +} +/* +//REMOVETHIS +int * r820t_get_lna_gains(void *dev) { + rtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev; + return r82xx_get_lna_gains(&devt->r82xx_p); +} +int * r820t_get_mixer_gains(void *dev) { + rtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev; + return r82xx_get_mixer_gains(&devt->r82xx_p); +} +int * r820t_get_vga_gains(void *dev) { + rtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev; + return r82xx_get_vga_gains(&devt->r82xx_p); +} +*/ 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,37 +296,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 }, }; @@ -955,6 +991,62 @@ 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); +} +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 */ @@ -1056,6 +1148,70 @@ int rtlsdr_get_tuner_gain(rtlsdr_dev_t *dev) return dev->gain; } +int rtlsdr_set_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->gain = gain; + else + dev->gain = 0; + + return r; +} + +int rtlsdr_set_mixer_gain(rtlsdr_dev_t *dev, int gain) +{ + int r = 0; + + if (!dev || !dev->tuner) + return -1; + + if (dev->tuner->set_mixer_gain) { + rtlsdr_set_i2c_repeater(dev, 1); + r = dev->tuner->set_mixer_gain((void *)dev, gain); + rtlsdr_set_i2c_repeater(dev, 0); + } + + if (!r) + dev->gain = gain; + else + dev->gain = 0; + + return r; +} + +int rtlsdr_set_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->gain = gain; + else + dev->gain = 0; + + return r; +} + + 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 f6202384..7cce20df 100644 --- a/src/tuner_r82xx.c +++ b/src/tuner_r82xx.c @@ -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; @@ -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 From 92a676f5350cc6338a172fe7cdb68ec5087ef35b Mon Sep 17 00:00:00 2001 From: Andrew Bates Date: Sun, 22 May 2016 10:20:39 +0000 Subject: [PATCH 2/2] Removes some commented out code, rolled up 4 functions that were using nearly identical code and added some comments --- include/rtl-sdr.h | 1 + src/librtlsdr.c | 129 +++++++++++++++++++++------------------------- 2 files changed, 59 insertions(+), 71 deletions(-) diff --git a/include/rtl-sdr.h b/include/rtl-sdr.h index e05eb27b..f8c36046 100644 --- a/include/rtl-sdr.h +++ b/include/rtl-sdr.h @@ -221,6 +221,7 @@ 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); diff --git a/src/librtlsdr.c b/src/librtlsdr.c index 146734df..8cf39a92 100644 --- a/src/librtlsdr.c +++ b/src/librtlsdr.c @@ -257,10 +257,20 @@ 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); @@ -273,21 +283,8 @@ 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); } -/* -//REMOVETHIS -int * r820t_get_lna_gains(void *dev) { - rtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev; - return r82xx_get_lna_gains(&devt->r82xx_p); -} -int * r820t_get_mixer_gains(void *dev) { - rtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev; - return r82xx_get_mixer_gains(&devt->r82xx_p); -} -int * r820t_get_vga_gains(void *dev) { - rtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev; - return r82xx_get_vga_gains(&devt->r82xx_p); -} -*/ + + 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); @@ -1003,6 +1000,15 @@ 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 }; @@ -1047,6 +1053,7 @@ int rtlsdr_get_specific_gains(rtlsdr_dev_t *dev, int *gains,enum gain_types gain 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 */ @@ -1121,23 +1128,7 @@ int rtlsdr_set_tuner_bandwidth(rtlsdr_dev_t *dev, uint32_t bw) int rtlsdr_set_tuner_gain(rtlsdr_dev_t *dev, int gain) { - int r = 0; - - if (!dev || !dev->tuner) - return -1; - - if (dev->tuner->set_gain) { - rtlsdr_set_i2c_repeater(dev, 1); - r = dev->tuner->set_gain((void *)dev, gain); - rtlsdr_set_i2c_repeater(dev, 0); - } - - if (!r) - dev->gain = gain; - else - dev->gain = 0; - - return r; + return rtlsdr_set_specific_gain(dev,gain,total); } int rtlsdr_get_tuner_gain(rtlsdr_dev_t *dev) @@ -1148,58 +1139,55 @@ int rtlsdr_get_tuner_gain(rtlsdr_dev_t *dev) 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) { - 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->gain = gain; - else - dev->gain = 0; - - return r; + return rtlsdr_set_specific_gain(dev,gain,lna); } - int rtlsdr_set_mixer_gain(rtlsdr_dev_t *dev, int gain) { - int r = 0; - - if (!dev || !dev->tuner) - return -1; - - if (dev->tuner->set_mixer_gain) { - rtlsdr_set_i2c_repeater(dev, 1); - r = dev->tuner->set_mixer_gain((void *)dev, gain); - rtlsdr_set_i2c_repeater(dev, 0); - } - - if (!r) - dev->gain = gain; - else - dev->gain = 0; - - return r; + 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_vga_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_vga_gain((void *)dev, gain); + r = ptr_set_gain((void *)dev, gain); rtlsdr_set_i2c_repeater(dev, 0); } @@ -1211,7 +1199,6 @@ int rtlsdr_set_vga_gain(rtlsdr_dev_t *dev, int gain) return r; } - int rtlsdr_set_tuner_if_gain(rtlsdr_dev_t *dev, int stage, int gain) { int r = 0;