[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