Signal Strength for lgdt330x

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



(I guess it would help if I actually attached the patch before sending...)

Here it is...

I have attached a patch for the LGDT330X frontend, to allow for signal strength
reporting.  It also reports snr in dB using the dvb_math functions.  This
change to SNR reporting still fits within the current interpretation of the
return value, it just gives more meaning to the numbers for those of us who
want it.  The change is applied to both 3302 and 3303 frontends.  I have passed
it around for limited testing, and it is reported to work, so I'm posting it
here for consideration.

Thanks,

Rusty
# HG changeset patch
# User Rusty Scott <rustys@xxxxxxxx>
# Node ID f4de0afd4a56499607adf29bb5f7859cbeafe118
# Parent  fae890aee0c365fe8741b166690c9f0a81c495a1
lgdt330x signal strength reporting

From: Rusty Scott <rustys@xxxxxxxx>

Change read_snr to report in dB using dvb_math functions
Add signal strength reporting as 0 to 100% of 35 dB SNR signal

Signed-off-by: Rusty Scott <rustys@xxxxxxxx>

diff -r fae890aee0c3 -r f4de0afd4a56 linux/drivers/media/dvb/frontends/lgdt330x.c
--- a/linux/drivers/media/dvb/frontends/lgdt330x.c	Tue Sep 19 12:51:56 2006 -0300
+++ b/linux/drivers/media/dvb/frontends/lgdt330x.c	Tue Sep 19 21:18:20 2006 -0600
@@ -46,6 +46,7 @@
 #include <asm/byteorder.h>
 
 #include "dvb_frontend.h"
+#include "dvb_math.h"
 #include "lgdt330x_priv.h"
 #include "lgdt330x.h"
 
@@ -549,130 +550,135 @@ static int lgdt3303_read_status(struct d
 	return 0;
 }
 
-static int lgdt330x_read_signal_strength(struct dvb_frontend* fe, u16* strength)
-{
-	/* not directly available. */
-	*strength = 0;
-	return 0;
-}
-
 static int lgdt3302_read_snr(struct dvb_frontend* fe, u16* snr)
 {
-#ifdef SNR_IN_DB
 	/*
 	 * Spec sheet shows formula for SNR_EQ = 10 log10(25 * 24**2 / noise)
-	 * and SNR_PH = 10 log10(25 * 32**2 / noise) for equalizer and phase tracker
-	 * respectively. The following tables are built on these formulas.
-	 * The usual definition is SNR = 20 log10(signal/noise)
-	 * If the specification is wrong the value retuned is 1/2 the actual SNR in db.
-	 *
-	 * This table is a an ordered list of noise values computed by the
-	 * formula from the spec sheet such that the index into the table
-	 * starting at 43 or 45 is the SNR value in db. There are duplicate noise
-	 * value entries at the beginning because the SNR varies more than
-	 * 1 db for a change of 1 digit in noise at very small values of noise.
-	 *
-	 * Examples from SNR_EQ table:
-	 * noise SNR
-	 *   0    43
-	 *   1    42
-	 *   2    39
-	 *   3    37
-	 *   4    36
-	 *   5    35
-	 *   6    34
-	 *   7    33
-	 *   8    33
-	 *   9    32
-	 *   10   32
-	 *   11   31
-	 *   12   31
-	 *   13   30
+	 * and SNR_PH = 10 log10(25 * 32**2 / noise) for equalizer and phase
+	 * tracker respectively.
 	 */
 
-	static const u32 SNR_EQ[] =
-		{ 1,     2,      2,      2, 3,      3,      4,     4,     5,     7,
-		  9,     11,     13,     17, 21,     26,     33,    41,    52,    65,
-		  81,    102,    129,    162, 204,    257,    323,   406,   511,   644,
-		  810,   1020,   1284,   1616, 2035,   2561,   3224,  4059,  5110,  6433,
-		  8098,  10195,  12835,  16158, 20341,  25608,  32238, 40585, 51094, 64323,
-		  80978, 101945, 128341, 161571, 203406, 256073, 0x40000
-		};
-
-	static const u32 SNR_PH[] =
-		{ 1,     2,      2,      2,      3,      3,     4,     5,     6,     8,
-		  10,    12,     15,     19,     23,     29, 37,    46,    58,    73,
-		  91,    115,    144,    182,    229,    288, 362,   456,   574,   722,
-		  909,   1144,   1440,   1813,   2282,   2873, 3617,  4553,  5732,  7216,
-		  9084,  11436,  14396,  18124,  22817,  28724,  36161, 45524, 57312, 72151,
-		  90833, 114351, 143960, 181235, 228161, 0x080000
-		};
-
-	static u8 buf[5];/* read data buffer */
-	static u32 noise;   /* noise value */
-	static u32 snr_db;  /* index into SNR_EQ[] */
-	struct lgdt330x_state* state = (struct lgdt330x_state*) fe->demodulator_priv;
-
-	/* read both equalizer and phase tracker noise data */
-	i2c_read_demod_bytes(state, EQPH_ERR0, buf, sizeof(buf));
-
-	if (state->current_modulation == VSB_8) {
-		/* Equalizer Mean-Square Error Register for VSB */
-		noise = ((buf[0] & 7) << 16) | (buf[1] << 8) | buf[2];
-
-		/*
-		 * Look up noise value in table.
-		 * A better search algorithm could be used...
-		 * watch out there are duplicate entries.
-		 */
-		for (snr_db = 0; snr_db < sizeof(SNR_EQ); snr_db++) {
-			if (noise < SNR_EQ[snr_db]) {
-				*snr = 43 - snr_db;
-				break;
-			}
-		}
-	} else {
-		/* Phase Tracker Mean-Square Error Register for QAM */
-		noise = ((buf[0] & 7<<3) << 13) | (buf[3] << 8) | buf[4];
-
-		/* Look up noise value in table. */
-		for (snr_db = 0; snr_db < sizeof(SNR_PH); snr_db++) {
-			if (noise < SNR_PH[snr_db]) {
-				*snr = 45 - snr_db;
-				break;
-			}
-		}
-	}
-#else
 	/* Return the raw noise value */
 	static u8 buf[5];/* read data buffer */
 	static u32 noise;   /* noise value */
+	static s32 value;   /* full precision converted value */
 	struct lgdt330x_state* state = (struct lgdt330x_state*) fe->demodulator_priv;
 
-	/* read both equalizer and pase tracker noise data */
-	i2c_read_demod_bytes(state, EQPH_ERR0, buf, sizeof(buf));
 
 	if (state->current_modulation == VSB_8) {
+		/* read both equalizer and pase tracker noise data */
+		i2c_read_demod_bytes(state, EQPH_ERR0, buf, sizeof(buf));
 #if 0
 		/* Equalizer Mean-Square Error Register for VSB */
 		noise = ((buf[0] & 7) << 16) | (buf[1] << 8) | buf[2];
+		/* From comment above, SNR = 10*log10(25*24^2/EQ_MSE) */
+		/* dvb_math intlog10 returns log10(x)*2^24 */
+		/* log10(25*24^2)*2^24 = 69765745 */
+		/* SNR for 8VSB ranges from -13.11 to +41.03 */
+		if (noise!=0) {
+			value = 10*(69765745 - intlog10(noise));
+		} else {
+			value = -697657450;
+		}
 #else
 		/* Phase Tracker Mean-Square Error Register for VSB */
 		noise = ((buf[0] & 7<<3) << 13) | (buf[3] << 8) | buf[4];
+		/* From comment above, SNR = 10*log10(25*32^2/PT_MSE) */
+		/* dvb_math intlog10 returns log10(x)*2^24 */
+		/* log10(25*32^2)*2^24 = 73957994 */
+		/* SNR for 8VSB ranges from -13.11 to +41.03 */
+		if (noise!=0) {
+			value = 10*(73957994 - intlog10(noise));
+		} else {
+			value = -739579940;
+		}
 #endif
 	} else {
 
 		/* Carrier Recovery Mean-Square Error for QAM */
 		i2c_read_demod_bytes(state, 0x1a, buf, 2);
 		noise = ((buf[0] & 3) << 8) | buf[1];
-	}
-
+		/* From lgdt3302 data sheet, SNR = 10*log10(Ps/MSEQAM) */
+		/* Ps varies depending on the QAM type */
+		/* dvb_math intlog10 returns log10(x)*2^24 */
+		switch (state->current_modulation) {
+		case QAM_64:
+			/* !!! FIXME - These valuse are from LGDT3303 */
+			/* datasheet, need values for LGDT3302 */
+			/* Ps = 688128 */
+			/* log10(688128)*2^24 = 97939837 */
+			if (noise != 0) {
+				value = 10*(97939837 - intlog10(noise));
+			} else {
+				value = -979398370;
+			}
+			break;
+		case QAM_256:
+			/* !!! FIXME - These valuse are from LGDT3303 */
+			/* datasheet, need values for LGDT3302 */
+			/* Ps = 696320 */
+			/* log10(696320)*2^24 = 98026066 */
+			if (noise != 0) {
+				value = 10*(98026066 - intlog10(noise));
+			} else {
+				value = -980260660;
+			}
+			break;
+		default:
+			printk("KERN_WARNING lgdt330x: %s: Modulation set to unsupported value\n", __FUNCTION__);
+		}
+	}
+
+#if 0
 	/* Small values for noise mean signal is better so invert noise */
 	*snr = ~noise;
+#else
+	/* value is in signed 8.24 format, shift to signed 8.8 format */
+	*snr = (u16)(value >> 16);
 #endif
-
-	dprintk("%s: noise = 0x%05x, snr = %idb\n",__FUNCTION__, noise, *snr);
-
+	dprintk("%s: noise=0x%08x, snr = %idb\n",__FUNCTION__, noise,
+		((value>>5)*100)>>19);
+
+	return 0;
+}
+
+static int lgdt3302_read_signal_strength(struct dvb_frontend* fe, u16* strength)
+{
+	/* Calculate Strength from SNR up to 35dB */
+	/* Even though the SNR can go higher than 35dB, there is some comfort */
+	/* factor in having a range of strong signals that can show at 100%   */
+	s16 snr;
+	struct lgdt330x_state* state = (struct lgdt330x_state*) fe->demodulator_priv;
+
+	lgdt3302_read_snr(fe, (u16*)&snr);
+	if (state->current_modulation == VSB_8) {
+		/* SNR for 8VSB ranges from -13.11 to +41.03 */
+		/* use signals from -13dB to 35dB SNR and map into 16 bits*/
+		if ((snr > -13*256) && (snr < 35*256)) {
+			*strength =((snr + 13*256)*0xffff)/(48*256);
+		} else {
+			if (snr > 0) {
+				*strength = 0xffff;
+			} else {
+				*strength = 0;
+			}
+		}
+	} else {
+		/* SNR for QAM64 ranges from 10.11 to 58.27 */
+		/* SNR for QAM256 ranges from 10.26 to 58.42 */
+		/* Use signals from 10dB to 35dB SNR and map into 16 bits*/
+		if ((snr > 10*256) && (snr < 35*256)) {
+			*strength =((snr - 10*256)*0xffff)/(25*256);
+		} else {
+			if (snr > 0) {
+				*strength = 0xffff;
+			} else {
+				*strength = 0;
+			}
+		}
+	}
+	dprintk("%s: snr = %idb, strength = 0x%05x\n",__FUNCTION__,
+		((snr >> 4)*100)>>4, *strength);
 	return 0;
 }
 
@@ -681,6 +687,7 @@ static int lgdt3303_read_snr(struct dvb_
 	/* Return the raw noise value */
 	static u8 buf[5];/* read data buffer */
 	static u32 noise;   /* noise value */
+	static s32 value; /* temp value in full signed precision */
 	struct lgdt330x_state* state = (struct lgdt330x_state*) fe->demodulator_priv;
 
 	if (state->current_modulation == VSB_8) {
@@ -688,23 +695,111 @@ static int lgdt3303_read_snr(struct dvb_
 		i2c_read_demod_bytes(state, 0x6e, buf, 5);
 #if 0
 		/* Equalizer Mean-Square Error Register for VSB */
+		/* EQ_MSE is a 20 bit value */
 		noise = ((buf[0] & 0x78) << 13) | (buf[1] << 8) | buf[2];
+		/* From lgdt3303 data sheet, SNR = 10*log10(25*32^2/EQ_MSE) */
+		/* dvb_math intlog10 returns log10(x)*2^24 */
+		/* log10(25*32^2)*2^24 = 73957994 */
+		/* SNR for 8VSB ranges from -16.12 to +41.03 */
+		if (noise != 0) {
+			value = 10*(73957994-intlog10(noise));
+		} else {
+			value = -739579940));
 #else
 		/* Phase Tracker Mean-Square Error Register for VSB */
 		noise = ((buf[0] & 7) << 16) | (buf[3] << 8) | buf[4];
+		/* From lgdt3303 data sheet, SNR = 10*log10(25*32^2/PT_MSE) */
+		/* dvb_math intlog10 returns log10(x)*2^24 */
+		/* log10(25*32^2)*2^24 = 73957994 */
+		/* SNR for 8VSB ranges from -13.11 to +41.03 */
+		if (noise != 0) {
+			value = 10*(73957994 - intlog10(noise));
+		} else {
+			value = -739579940;
+		}
 #endif
 	} else {
 
 		/* Carrier Recovery Mean-Square Error for QAM */
 		i2c_read_demod_bytes(state, 0x1a, buf, 2);
 		noise = (buf[0] << 8) | buf[1];
-	}
-
+		/* From lgdt3303 data sheet, SNR = 10*log10(Ps/MSEQAM) */
+		/* Ps varies depending on the QAM type */
+		/* dvb_math intlog10 returns log10(x)*2^24 */
+		switch (state->current_modulation) {
+		case QAM_64:
+			/* Ps = 688128 */
+			/* log10(688128)*2^24 = 97939837 */
+			if (noise != 0) {
+				value = 10*(97939837 - intlog10(noise));
+			} else {
+				value = -979398370;
+			}
+			break;
+		case QAM_256:
+			/* Ps = 696320 */
+			/* log10(696320)*2^24 = 98026066 */
+			if (noise != 0) {
+				value = 10*(98026066 - intlog10(noise));
+			} else {
+				value = -980260660;
+			}
+			break;
+		default:
+			printk("KERN_WARNING lgdt330x: %s: Modulation set to unsupported value\n", __FUNCTION__);
+		}
+	}
+
+#if 0
 	/* Small values for noise mean signal is better so invert noise */
 	*snr = ~noise;
-
-	dprintk("%s: noise = 0x%05x, snr = %idb\n",__FUNCTION__, noise, *snr);
-
+#else
+	/* value is in signed 8.24 format, shift to signed 8.8 format */
+	*snr = (u16)(value >> 16);
+#endif
+	dprintk("%s: noise=0x%08x, snr = %idb\n",__FUNCTION__, noise,
+		((value>>5)*100)>>19);
+
+	return 0;
+}
+
+static int lgdt3303_read_signal_strength(struct dvb_frontend* fe, u16* strength)
+{
+	/* Calculate Strength from SNR up to 35dB */
+	/* Even though the SNR can go higher than 35dB, there is some comfort */
+	/* factor in having a range of strong signals that can show at 100%   */
+	s16 snr;
+	struct lgdt330x_state* state = (struct lgdt330x_state*) fe->demodulator_priv;
+
+	lgdt3303_read_snr(fe, (u16*)&snr);
+	if (state->current_modulation == VSB_8) {
+		/* SNR for 8VSB ranges from -13.11 to +41.03 */
+		/* use signals from -13dB to 35dB SNR and map into 16 bits*/
+		if ((snr > -13*256) && (snr < 35*256)) {
+			*strength =((snr + 13*256)*0xffff)/(48*256);
+		} else {
+			if (snr > 0) {
+				*strength = 0xffff;
+			} else {
+				*strength = 0;
+			}
+		}
+	} else {
+		/* SNR for QAM64 ranges from 10.11 to 58.27 */
+		/* SNR for QAM256 ranges from 10.26 to 58.42 */
+		/* Use signals from 10dB to 35dB SNR and map into 16 bits*/
+		if ((snr > 10*256) && (snr < 35*256)) {
+			*strength =((snr - 10*256)*0xffff)/(25*256);
+		} else {
+			if (snr > 0) {
+				*strength = 0xffff;
+			} else {
+				*strength = 0;
+			}
+		}
+	}
+	dprintk("%s: snr = %idb, strength = 0x%05x\n",__FUNCTION__,
+		((snr >> 4)*100)>>4, *strength);
 	return 0;
 }
 
@@ -786,7 +881,7 @@ static struct dvb_frontend_ops lgdt3302_
 	.get_tune_settings    = lgdt330x_get_tune_settings,
 	.read_status          = lgdt3302_read_status,
 	.read_ber             = lgdt330x_read_ber,
-	.read_signal_strength = lgdt330x_read_signal_strength,
+	.read_signal_strength = lgdt3302_read_signal_strength,
 	.read_snr             = lgdt3302_read_snr,
 	.read_ucblocks        = lgdt330x_read_ucblocks,
 	.release              = lgdt330x_release,
@@ -809,7 +904,7 @@ static struct dvb_frontend_ops lgdt3303_
 	.get_tune_settings    = lgdt330x_get_tune_settings,
 	.read_status          = lgdt3303_read_status,
 	.read_ber             = lgdt330x_read_ber,
-	.read_signal_strength = lgdt330x_read_signal_strength,
+	.read_signal_strength = lgdt3303_read_signal_strength,
 	.read_snr             = lgdt3303_read_snr,
 	.read_ucblocks        = lgdt330x_read_ucblocks,
 	.release              = lgdt330x_release,
_______________________________________________
linux-dvb mailing list
linux-dvb@xxxxxxxxxxx
http://www.linuxtv.org/cgi-bin/mailman/listinfo/linux-dvb

[Index of Archives]     [Linux Media]     [Video 4 Linux]     [Asterisk]     [Samba]     [Xorg]     [Xfree86]     [Linux USB]

  Powered by Linux