>From 46c9e44067a26c7aed60e23661b7260c9cbc72c6 Mon Sep 17 00:00:00 2001
From: Alexander Kurpiers <[email protected]>
Date: Thu, 9 Jan 2014 19:17:42 +0100
Subject: [PATCH 3/7] Introduce two gain modes optimized for linearity or
sensitivity
To enable, rtlsdr_set_tuner_gain_mode() needs to be called with
mode=2 (GAIN_MODE_LINEARITY) or mode=3 (GAIN_MODE_SENSITIVITY)
Oct. 2012 SM5BSZ
Dec. 2013 DL8AAU
---
include/rtl-sdr.h | 7 +++++
include/tuner_e4k.h | 2 ++
src/librtlsdr.c | 32 +++++++++++++++------
src/tuner_e4k.c | 78 +++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 111 insertions(+), 8 deletions(-)
diff --git a/include/rtl-sdr.h b/include/rtl-sdr.h
index 489e117..8db3a66 100644
--- a/include/rtl-sdr.h
+++ b/include/rtl-sdr.h
@@ -233,6 +233,13 @@ RTLSDR_API int rtlsdr_get_tuner_gain(rtlsdr_dev_t *dev);
*/
RTLSDR_API int rtlsdr_set_tuner_if_gain(rtlsdr_dev_t *dev, int stage, int gain);
+enum rtl_sdr_gain_mode {
+ GAIN_MODE_AGC=0,
+ GAIN_MODE_MANUAL=1,
+ GAIN_MODE_LINEARITY=2,
+ GAIN_MODE_SENSITIVITY=3
+};
+
/*!
* Set the gain mode (automatic/manual) for the device.
* Manual gain mode must be enabled for the gain setter function to work.
diff --git a/include/tuner_e4k.h b/include/tuner_e4k.h
index 79591ce..eb3ce6c 100644
--- a/include/tuner_e4k.h
+++ b/include/tuner_e4k.h
@@ -195,6 +195,7 @@ struct e4k_state {
uint8_t i2c_addr;
enum e4k_band band;
struct e4k_pll_params vco;
+ int gain_mode;
void *rtl_dev;
};
@@ -217,6 +218,7 @@ int e4k_dc_offset_calibrate(struct e4k_state *e4k);
int e4k_dc_offset_gen_table(struct e4k_state *e4k);
int e4k_set_lna_gain(struct e4k_state *e4k, int32_t gain);
+int e4k_set_lna_mixer_if_gain(struct e4k_state *e4k, int32_t gain);
int e4k_enable_manual_gain(struct e4k_state *e4k, uint8_t manual);
int e4k_set_enh_gain(struct e4k_state *e4k, int32_t gain);
#endif /* _E4K_TUNER_H */
diff --git a/src/librtlsdr.c b/src/librtlsdr.c
index 65b77fb..a889330 100644
--- a/src/librtlsdr.c
+++ b/src/librtlsdr.c
@@ -161,17 +161,25 @@ int e4000_set_gain(void *dev, int gain) {
#if 0
int enhgain = (gain - 420);
#endif
- if(e4k_set_lna_gain(&devt->e4k_s, min(300, gain - mixgain * 10)) == -EINVAL)
- return -1;
- if(e4k_mixer_gain_set(&devt->e4k_s, mixgain) == -EINVAL)
- return -1;
-#if 0 /* enhanced mixer gain seems to have no effect */
- if(enhgain >= 0)
- if(e4k_set_enh_gain(&devt->e4k_s, enhgain) == -EINVAL)
+ /* Use only (the modified) set_lna_gain if the user
+ asked for linearity or sensitivity. */
+ if (devt->e4k_s.gain_mode <= GAIN_MODE_MANUAL) {
+ if (e4k_set_lna_gain(&devt->e4k_s, min(300, gain - mixgain * 10)) == -EINVAL)
return -1;
+ if (e4k_mixer_gain_set(&devt->e4k_s, mixgain) == -EINVAL)
+ return -1;
+#if 0 /* enhanced mixer gain seems to have no effect */
+ /* SM5BSZ: enhanced gain should affect how the AGC turns down the gain */
+ if (enhgain >= 0)
+ if (e4k_set_enh_gain(&devt->e4k_s, enhgain) == -EINVAL)
+ return -1;
#endif
+ return 0;
+ }
+ e4k_set_lna_mixer_if_gain(&devt->e4k_s, gain);
return 0;
}
+
int e4000_set_if_gain(void *dev, int stage, int gain) {
rtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev;
return e4k_if_gain_set(&devt->e4k_s, (uint8_t)stage, (int8_t)(gain / 10));
@@ -945,6 +953,9 @@ int rtlsdr_get_tuner_gains(rtlsdr_dev_t *dev, int *gains)
/* all gain values are expressed in tenths of a dB */
const int e4k_gains[] = { -10, 15, 40, 65, 90, 115, 140, 165, 190, 215,
240, 290, 340, 420 };
+ /* Add standard gains */
+ const int e4k_std_gains[] = { -250, -200, -150, -100, -50, 0, 50,
+ 100, 150, 200, 250};
const int fc0012_gains[] = { -99, -40, 71, 179, 192 };
const int fc0013_gains[] = { -99, -73, -65, -63, -60, -58, -54, 58, 61,
63, 65, 67, 68, 70, 71, 179, 181, 182,
@@ -964,7 +975,12 @@ int rtlsdr_get_tuner_gains(rtlsdr_dev_t *dev, int *gains)
switch (dev->tuner_type) {
case RTLSDR_TUNER_E4000:
- ptr = e4k_gains; len = sizeof(e4k_gains);
+ /* Use standard gains (5 dB step) if gain is mode above 1. */
+ if(dev->e4k_s.gain_mode <= GAIN_MODE_MANUAL) {
+ ptr = e4k_gains; len = sizeof(e4k_gains);
+ } else {
+ ptr = e4k_std_gains; len = sizeof(e4k_std_gains);
+ }
break;
case RTLSDR_TUNER_FC0012:
ptr = fc0012_gains; len = sizeof(fc0012_gains);
diff --git a/src/tuner_e4k.c b/src/tuner_e4k.c
index c2ec044..f19f994 100644
--- a/src/tuner_e4k.c
+++ b/src/tuner_e4k.c
@@ -40,6 +40,15 @@
#define MHZ(x) ((x)*1000*1000)
#define KHZ(x) ((x)*1000)
+enum rtl_sdr_gain_mode {
+ GAIN_MODE_AGC=0,
+ GAIN_MODE_MANUAL=1,
+ GAIN_MODE_LINEARITY=2,
+ GAIN_MODE_SENSITIVITY=3
+};
+
+#define MAX_E4K_GAIN_MODES 3
+
uint32_t unsigned_delta(uint32_t a, uint32_t b)
{
if (a > b)
@@ -673,6 +682,68 @@ int e4k_set_lna_gain(struct e4k_state *e4k, int32_t gain)
return -EINVAL;
}
+static const struct gain_table_mode_struct {
+ int32_t gain;
+ int32_t LNA_gain;
+ int32_t mixer_gain;
+ int32_t IF_gain[6];
+} gain_table_mode_linearity[] = { /* LNA Mixer IF Total */
+ -250, -5, 4, { -3, 0, 0, 0, 9, 6}, /* -5 4 12 9 */
+ -200, -5, 4, { -3, 0, 0, 1, 12, 9}, /* -5 4 19 18 */
+ -150, -5, 4, { -3, 6, 0, 0, 12, 9}, /* -5 4 24 23 */
+ -100, -5, 12, { -3, 3, 0, 1, 12, 9}, /* -5 12 22 29 */
+ -50, -5, 12, { -3, 6, 0, 0, 12, 12}, /* -5 12 27 34 */
+ 0, 0, 12, { -3, 6, 0, 0, 12, 12}, /* 0 12 27 39 */
+ 50, 5, 12, { -3, 6, 0, 0, 12, 12}, /* 5 12 27 44 */
+ 100, 10, 12, { -3, 6, 0, 0, 12, 12}, /* 10 12 27 49 */
+ 150, 15, 12, { -3, 6, 0, 0, 12, 12}, /* 15 12 27 54 */
+ 200, 20, 12, { -3, 6, 0, 0, 12, 12}, /* 20 12 27 59 */
+ 250, 30, 12, { -3, 6, 0, 0, 12, 12}, /* 30 12 27 69 */
+},
+gain_table_mode_sensitivity[] = { /* LNA Mixer IF Total */
+ -250, 5, 4, { -3, 0, 0, 1, 6, 3}, /* 5 4 7 16 */
+ -200, 10, 4, { -3, 0, 0, 1, 6, 3}, /* 10 4 7 21 */
+ -150, 15, 4, { -3, 0, 0, 1, 6, 3}, /* 15 4 7 26 */
+ -100, 20, 4, { -3, 0, 0, 1, 6, 3}, /* 20 4 7 31 */
+ -50, 30, 4, { -3, 0, 0, 1, 6, 3}, /* 30 4 7 41 */
+ 0, 30, 12, { -3, 0, 0, 2, 3, 3}, /* 30 12 5 47 */
+ 50, 30, 12, { -3, 3, 0, 1, 6, 3}, /* 30 12 10 52 */
+ 100, 30, 12, { 6, 0, 0, 0, 6, 3}, /* 30 12 15 57 */
+ 150, 30, 12, { 6, 0, 0, 2, 9, 3}, /* 30 12 20 62 */
+ 200, 30, 12, { 6, 3, 0, 1, 9, 6}, /* 30 12 25 67 */
+ 250, 30, 12, { 6, 6, 0, 0, 9, 9}, /* 30 12 30 72 */
+};
+
+int e4k_set_lna_mixer_if_gain(struct e4k_state *e4k, int32_t gain)
+{
+ uint32_t i;
+ const struct gain_table_mode_struct * gain_table;
+ int gain_table_len;
+
+ if (e4k->gain_mode == GAIN_MODE_LINEARITY ) {
+ gain_table = gain_table_mode_linearity;
+ gain_table_len = ARRAY_SIZE(gain_table_mode_linearity);
+ } else if (e4k->gain_mode == GAIN_MODE_SENSITIVITY) {
+ gain_table = gain_table_mode_sensitivity;
+ gain_table_len = ARRAY_SIZE(gain_table_mode_sensitivity);
+ } else
+ return -EINVAL;
+
+ for(i = 0; i < gain_table_len; ++i) {
+ if (gain_table->gain == gain) {
+ int l;
+ e4k_set_lna_gain(e4k, gain_table->LNA_gain*10);
+ e4k_mixer_gain_set(e4k, gain_table->mixer_gain);
+ for (l=0; l<6; l++)
+ e4k_if_gain_set(e4k, l+1, gain_table->IF_gain[l]);
+
+ return gain;
+ }
+ gain_table++;
+ }
+ return -EINVAL;
+}
+
int e4k_set_enh_gain(struct e4k_state *e4k, int32_t gain)
{
uint32_t i;
@@ -699,7 +770,14 @@ int e4k_enable_manual_gain(struct e4k_state *e4k, uint8_t manual)
/* Set Mixer Gain Control to manual */
e4k_reg_set_mask(e4k, E4K_REG_AGC7, E4K_AGC7_MIX_GAIN_AUTO, 0);
+ /* Add a flag for more gain modes and return it
+ so we know the library has this feature. */
+ e4k->gain_mode = manual;
+ if (e4k->gain_mode > MAX_E4K_GAIN_MODES)
+ e4k->gain_mode = MAX_E4K_GAIN_MODES;
+ return e4k->gain_mode;
} else {
+ e4k->gain_mode=GAIN_MODE_AGC;
/* Set LNA mode to auto */
e4k_reg_set_mask(e4k, E4K_REG_AGC1, E4K_AGC1_MOD_MASK, E4K_AGC_MOD_IF_SERIAL_LNA_AUTON);
/* Set Mixer Gain Control to auto */
--
1.7.9.5