[linux-dvb] Signal Strength for lgdt330x

Michael Krufky mkrufky at linuxtv.org
Thu Sep 28 00:36:29 CEST 2006


Rusty Scott wrote:
> (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

Great work, Rusty!

I have tested the patch and it seems to work as expected on cards based
on both LG DT3302 and DT3303.

Mac,

Do you have any problems with this patch being applied?  Rusty has been
trying to contact you about this as well, but emails have been bouncing
back...

If I dont hear back after a few more days, I will go ahead and merge it,
although I'd be happier if Mac would add his sign-off to Rusty's patch
before I move forward.

Please review and respond.

Thanks,

Mike Krufky



> ------------------------------------------------------------------------
> 
> # HG changeset patch
> # User Rusty Scott <rustys at ieee.org>
> # Node ID f4de0afd4a56499607adf29bb5f7859cbeafe118
> # Parent  fae890aee0c365fe8741b166690c9f0a81c495a1
> lgdt330x signal strength reporting
> 
> From: Rusty Scott <rustys at ieee.org>
> 
> 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 at ieee.org>
> 
> 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 at linuxtv.org
> http://www.linuxtv.org/cgi-bin/mailman/listinfo/linux-dvb




More information about the linux-dvb mailing list