[linux-dvb] [RFC] [PATCH] Make S/N values to appear at cx24123 frontend

Mauro Carvalho Chehab mchehab at infradead.org
Fri Apr 14 05:04:02 CEST 2006


This is an updated version. Now, it detects if lock, otherwise SNR=0.
The SNR values seem to be excessive, since BER like 4000 produce a real 
bad stream. Somebody have a rational for the previous values?

Cheers,
Mauro.

On Thu, 13 Apr 2006, Mauro Carvalho Chehab wrote:

> From: Mauro Carvalho Chehab  <mchehab at infradead.org>
> Make S/N values to appear at cx24123 frontend with higher range
> 
> SNR is estimated based on BER. The problem is that BER estimation were not
> called when reading SNR, so calls to read_snr without previously calling
> read_ber produces bad results.
> This patch makes it fill SNR value based at the estimative value calculated by BER.
> Also, it improves SNR estimation by interpolating from the closest exponential curve
> that plots the previous values.
> 
> Signed-off-by: Mauro Carvalho Chehab <mchehab at infradead.org>
> 
diff -r 436e56df57d3 linux/drivers/media/dvb/frontends/cx24123.c
--- a/linux/drivers/media/dvb/frontends/cx24123.c	Thu Apr 13 18:50:22 2006 -0300
+++ b/linux/drivers/media/dvb/frontends/cx24123.c	Fri Apr 14 00:12:36 2006 -0300
@@ -47,7 +47,6 @@ struct cx24123_state
 	struct dvb_frontend frontend;
 
 	u32 lastber;
-	u16 snr;
 	u8  lnbreg;
 
 	/* Some PLL specifics for tuning */
@@ -885,25 +884,10 @@ static int cx24123_read_ber(struct dvb_f
 		(cx24123_readreg(state, 0x1d) << 8 |
 		cx24123_readreg(state, 0x1e));
 
-	/* Do the signal quality processing here, it's derived from the BER. */
-	/* Scale the BER from a 24bit to a SNR 16 bit where higher = better */
-	if (state->lastber < 5000)
-		state->snr = 655*100;
-	else if ( (state->lastber >=   5000) && (state->lastber <  55000) )
-		state->snr = 655*90;
-	else if ( (state->lastber >=  55000) && (state->lastber < 150000) )
-		state->snr = 655*80;
-	else if ( (state->lastber >= 150000) && (state->lastber < 250000) )
-		state->snr = 655*70;
-	else if ( (state->lastber >= 250000) && (state->lastber < 450000) )
-		state->snr = 655*65;
-	else
-		state->snr = 0;
-
-	dprintk("%s:  BER = %d, S/N index = %d\n",__FUNCTION__,state->lastber, state->snr);
-
 	*ber = state->lastber;
 
+	dprintk("%s:  BER = %d\n",__FUNCTION__,*ber);
+
 	return 0;
 }
 
@@ -917,10 +901,59 @@ static int cx24123_read_signal_strength(
 	return 0;
 }
 
+static int ber_table[][2] = {	{ 100, 4798 },
+				{  99, 5380 },
+				{  98, 6032 },
+				{  95, 8502 },
+				{  90, 15066 },
+				{  85, 26696 },
+				{  80, 47306 },
+				{  75, 83826 },
+				{  70, 148539 },
+				{  65, 263210 },
+				{  60, 466406 },
+				{  40, 4598482 },
+				{  30, 14439082} };
+
 static int cx24123_read_snr(struct dvb_frontend* fe, u16* snr)
 {
 	struct cx24123_state *state = fe->demodulator_priv;
-	*snr = state->snr;
+
+	int ber, i=0;
+	int sync = cx24123_readreg(state, 0x14) & 0x80;
+
+	/* If no sync, SNR makes no sense at all */
+	if (!sync) {
+		*snr=0;
+		return 0;
+	}		
+
+	cx24123_read_ber(fe,&ber);
+
+	/* Do the signal quality processing here, it's derived from the BER.
+	 * Scale the BER from a 24bit to a SNR 16 bit where higher = better
+	 * It uses linear interpolation between each segment of an exponencial
+	 * curve given by ber_table aproximated values.
+	 */
+
+	if (ber<ber_table[0][1]) {
+		*snr=65535*ber_table[0][0]/100;
+	} else {
+		*snr=0;
+		i++;
+		while (i< ARRAY_SIZE(ber_table)) {
+			if (ber>=ber_table[i-1][1] &&
+			    ber<ber_table[i][1]) {
+				int slope1=(ber_table[i-1][0]-ber_table[i][0]);
+				int slope2=(ber_table[i-1][1]-ber_table[i][1]);
+				int origin=ber_table[i-1][0]
+					  -slope1*ber_table[i-1][1]/slope2;
+				*snr=65535*(origin+((slope1*ber)/slope2))/100;
+				break;
+			}
+			i++;
+		}
+	}
 
 	dprintk("%s:  read S/N index = %d\n",__FUNCTION__,*snr);
 
@@ -1053,7 +1086,6 @@ struct dvb_frontend* cx24123_attach(cons
 	state->i2c = i2c;
 	memcpy(&state->ops, &cx24123_ops, sizeof(struct dvb_frontend_ops));
 	state->lastber = 0;
-	state->snr = 0;
 	state->lnbreg = 0;
 	state->VCAarg = 0;
 	state->VGAarg = 0;



More information about the linux-dvb mailing list