[PATCH] Frontend or51211 - fixes SNR and signal strength

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

 



The attached patch makes changes to the or51211 frontend to match the SNR and
signal strength methods in the lgdt330x frontend.  It removes an embedded log
function in favor of using the functions in dvb_math.  Do not confuse this patch
with the patch just posted for the or51132 frontend.  I'm not sure why 'make
commit' caused changes to CARDLIST.cx88 as this is a bttv based frontend and I
added the changes to a fresh clone of v4l-dvb.

Rusty
# HG changeset patch
# User rscott@xxxxxxxxxxxxxxxxxxxxx
# Node ID 82045881f12f81e4645ae33a674b6312db2b9d48
# Parent  6dce18b2a3b893c06c55e34c4e9356d8eacb374b
or51211: Changed SNR and signal strength calculations

From: Rusty Scott <rustys@xxxxxxxx>

Removes embedded log functions and makes use of the DVB math functions
to provide SNR in dB.  The changes are modeled after recent changes made
to the LGDT330x frontend in lgdt330x.c

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

diff -r 6dce18b2a3b8 -r 82045881f12f linux/Documentation/video4linux/CARDLIST.cx88
--- a/linux/Documentation/video4linux/CARDLIST.cx88	Sat Nov 18 16:47:15 2006 -0200
+++ b/linux/Documentation/video4linux/CARDLIST.cx88	Sat Nov 18 16:03:06 2006 -0700
@@ -43,7 +43,7 @@
  42 -> digitalnow DNTV Live! DVB-T Pro                     [1822:0025,1822:0019]
  43 -> KWorld/VStream XPert DVB-T with cx22702             [17de:08a1,12ab:2300]
  44 -> DViCO FusionHDTV DVB-T Dual Digital                 [18ac:db50,18ac:db54]
- 45 -> KWorld HardwareMpegTV XPert                         [17de:0840]
+ 45 -> KWorld HardwareMpegTV XPert                         [17de:0840,1421:0305]
  46 -> DViCO FusionHDTV DVB-T Hybrid                       [18ac:db40,18ac:db44]
  47 -> pcHDTV HD5500 HDTV                                  [7063:5500]
  48 -> Kworld MCE 200 Deluxe                               [17de:0841]
diff -r 6dce18b2a3b8 -r 82045881f12f linux/drivers/media/dvb/frontends/or51211.c
--- a/linux/drivers/media/dvb/frontends/or51211.c	Sat Nov 18 16:47:15 2006 -0200
+++ b/linux/drivers/media/dvb/frontends/or51211.c	Sat Nov 18 16:03:06 2006 -0700
@@ -63,9 +63,11 @@ struct or51211_state {
 
 	/* Demodulator private data */
 	u8 initialized:1;
+	u32 snr; /* Result of last SNR claculation */
 
 	/* Tuner private data */
 	u32 current_frequency;
+
 };
 
 static int i2c_writebytes (struct or51211_state* state, u8 reg, u8 *buf,
@@ -292,54 +294,39 @@ static int or51211_read_status(struct dv
 	return 0;
 }
 
-/* log10-1 table at .5 increments from 1 to 100.5 */
-static unsigned int i100x20log10[] = {
-		0,  352,  602,  795,  954, 1088, 1204, 1306, 1397, 1480,
-	 1556, 1625, 1690, 1750, 1806, 1858, 1908, 1955, 2000, 2042,
-	 2082, 2121, 2158, 2193, 2227, 2260, 2292, 2322, 2352, 2380,
-	 2408, 2434, 2460, 2486, 2510, 2534, 2557, 2580, 2602, 2623,
-	 2644, 2664, 2684, 2704, 2723, 2742, 2760, 2778, 2795, 2813,
-	 2829, 2846, 2862, 2878, 2894, 2909, 2924, 2939, 2954, 2968,
-	 2982, 2996, 3010, 3023, 3037, 3050, 3062, 3075, 3088, 3100,
-	 3112, 3124, 3136, 3148, 3159, 3170, 3182, 3193, 3204, 3214,
-	 3225, 3236, 3246, 3256, 3266, 3276, 3286, 3296, 3306, 3316,
-	 3325, 3334, 3344, 3353, 3362, 3371, 3380, 3389, 3397, 3406,
-	 3415, 3423, 3432, 3440, 3448, 3456, 3464, 3472, 3480, 3488,
-	 3496, 3504, 3511, 3519, 3526, 3534, 3541, 3549, 3556, 3563,
-	 3570, 3577, 3584, 3591, 3598, 3605, 3612, 3619, 3625, 3632,
-	 3639, 3645, 3652, 3658, 3665, 3671, 3677, 3683, 3690, 3696,
-	 3702, 3708, 3714, 3720, 3726, 3732, 3738, 3744, 3750, 3755,
-	 3761, 3767, 3772, 3778, 3784, 3789, 3795, 3800, 3806, 3811,
-	 3816, 3822, 3827, 3832, 3838, 3843, 3848, 3853, 3858, 3863,
-	 3868, 3874, 3879, 3884, 3888, 3893, 3898, 3903, 3908, 3913,
-	 3918, 3922, 3927, 3932, 3936, 3941, 3946, 3950, 3955, 3960,
-	 3964, 3969, 3973, 3978, 3982, 3986, 3991, 3995, 4000, 4004,
-};
-
-static unsigned int denom[] = {1,1,100,1000,10000,100000,1000000,10000000,100000000};
-
-static unsigned int i20Log10(unsigned short val)
-{
-	unsigned int rntval = 100;
-	unsigned int tmp = val;
-	unsigned int exp = 1;
-
-	while(tmp > 100) {tmp /= 100; exp++;}
-
-	val = (2 * val)/denom[exp];
-	if (exp > 1) rntval = 2000*exp;
-
-	rntval += i100x20log10[val];
-	return rntval;
-}
-
-static int or51211_read_signal_strength(struct dvb_frontend* fe, u16* strength)
+/* Calculate SNR estimation (scaled by 2^24)
+
+   8-VSB SNR equation from Oren datasheets
+
+   For 8-VSB:
+     SNR[dB] = 10 * log10(219037.9454 / MSE^2 )
+
+   We re-write the snr equation as:
+     SNR * 2^24 = 10*(c - 2*intlog10(MSE))
+   Where for 8-VSB, c = log10(219037.9454) * 2^24 */
+
+static u32 calculate_snr(u32 mse, u32 c)
+{
+	if (mse == 0) /* No signal */
+		return 0;
+
+	mse = 2*intlog10(mse);
+	if (mse > c) {
+		/* Negative SNR, which is possible, but realisticly the
+		demod will lose lock before the signal gets this bad.  The
+		API only allows for unsigned values, so just return 0 */
+		return 0;
+	}
+	return 10*(c - mse);
+}
+
+static int or51211_read_snr(struct dvb_frontend* fe, u16* snr)
 {
 	struct or51211_state* state = fe->demodulator_priv;
 	u8 rec_buf[2];
 	u8 snd_buf[4];
-	u8 snr_equ;
-	u32 signal_strength;
+	u32 noise;
+	u32 c;
 
 	/* SNR after Equalizer */
 	snd_buf[0] = 0x04;
@@ -348,51 +335,47 @@ static int or51211_read_signal_strength(
 	snd_buf[3] = 0x00;
 
 	if (i2c_writebytes(state,state->config->demod_address,snd_buf,3)) {
-		printk(KERN_WARNING "or51211: read_status write error\n");
-		return -1;
-	}
-	msleep(3);
+		printk(KERN_WARNING "%s: error writing snr reg\n",
+		       __FUNCTION__);
+		return -1;
+	}
 	if (i2c_readbytes(state,state->config->demod_address,rec_buf,2)) {
-		printk(KERN_WARNING "or51211: read_status read error\n");
-		return -1;
-	}
-	snr_equ = rec_buf[0] & 0xff;
-
-	/* The value reported back from the frontend will be FFFF=100% 0000=0% */
-	signal_strength = (((5334 - i20Log10(snr_equ))/3+5)*65535)/1000;
-	if (signal_strength > 0xffff)
+		printk(KERN_WARNING "%s: read_status read error\n",
+		       __FUNCTION__);
+		return -1;
+	}
+	noise = rec_buf[0] & 0xff;
+	dprintk("%s: %x (%i)\n", __FUNCTION__, rec_buf[0], noise);
+
+	c = 89599047;
+
+	state->snr = calculate_snr(noise,c);
+	*snr = (state->snr) >> 16;
+
+	dprintk("%s: noise = 0x%08x, snr = %d.%02d dB\n", __FUNCTION__, noise,
+		state->snr >> 24, (((state->snr>>8) & 0xffff) * 100) >> 16);
+
+	return 0;
+}
+
+static int or51211_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%   */
+	struct or51211_state* state = (or51211_state*)fe->demodulator_priv;
+	u16 snr;
+	int ret;
+
+	ret = fe->ops.read_snr(fe, &snr);
+	if (ret != 0)
+		return ret;
+	/* Rather than use the 8.8 value snr, use state->snr which is 8.24 */
+	/* scale the range 0 - 35*2^24 into 0 - 65535 */
+	if (state->snr >= 8960 * 0x10000)
 		*strength = 0xffff;
 	else
-		*strength = signal_strength;
-	dprintk("read_signal_strength %i\n",*strength);
-
-	return 0;
-}
-
-static int or51211_read_snr(struct dvb_frontend* fe, u16* snr)
-{
-	struct or51211_state* state = fe->demodulator_priv;
-	u8 rec_buf[2];
-	u8 snd_buf[4];
-
-	/* SNR after Equalizer */
-	snd_buf[0] = 0x04;
-	snd_buf[1] = 0x00;
-	snd_buf[2] = 0x04;
-	snd_buf[3] = 0x00;
-
-	if (i2c_writebytes(state,state->config->demod_address,snd_buf,3)) {
-		printk(KERN_WARNING "or51211: read_status write error\n");
-		return -1;
-	}
-	msleep(3);
-	if (i2c_readbytes(state,state->config->demod_address,rec_buf,2)) {
-		printk(KERN_WARNING "or51211: read_status read error\n");
-		return -1;
-	}
-	*snr = rec_buf[0] & 0xff;
-
-	dprintk("read_snr %i\n",*snr);
+		*strength = state->snr / 8960;
 
 	return 0;
 }
_______________________________________________
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