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@xxxxxxxxxxxxx> > 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@xxxxxxxxxxxxx> > 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; _______________________________________________ linux-dvb@xxxxxxxxxxx http://www.linuxtv.org/cgi-bin/mailman/listinfo/linux-dvb