>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

Reply via email to