diff options
Diffstat (limited to 'util/dib3000-watch')
| -rw-r--r-- | util/dib3000-watch/Makefile | 13 | ||||
| -rw-r--r-- | util/dib3000-watch/README.dib3000-watch | 29 | ||||
| -rw-r--r-- | util/dib3000-watch/dib-i2c.h | 43 | ||||
| -rw-r--r-- | util/dib3000-watch/dib3000-watch.c | 296 | ||||
| -rw-r--r-- | util/dib3000-watch/dib3000-watch.h | 46 | ||||
| -rw-r--r-- | util/dib3000-watch/dib3000.h | 56 | ||||
| -rw-r--r-- | util/dib3000-watch/make-i2c-dev | 6 | 
7 files changed, 489 insertions, 0 deletions
| diff --git a/util/dib3000-watch/Makefile b/util/dib3000-watch/Makefile new file mode 100644 index 0000000..2961905 --- /dev/null +++ b/util/dib3000-watch/Makefile @@ -0,0 +1,13 @@ +# Makefile for linuxtv.org dvb-apps/util/dib3000-watch + +binaries = dib3000-watch + +inst_bin = $(binaries) + +LDLIBS += -lm + +.PHONY: all + +all: $(binaries) + +include ../../Make.rules diff --git a/util/dib3000-watch/README.dib3000-watch b/util/dib3000-watch/README.dib3000-watch new file mode 100644 index 0000000..a9499d5 --- /dev/null +++ b/util/dib3000-watch/README.dib3000-watch @@ -0,0 +1,29 @@ +This is a small tool for gathering and evaluating more reception-related data +from the dib3000-demodulators, than the DVB-API currently makes use of. + +It uses the i2c-dev-interface. In order to use it, you have to enable i2c-dev +in your kernel.  The module i2c-dev is loaded automatically, when you want to +access the /dev/i2c-*-node. + +If your distribution hasn't create the /dev/i2c-*-nodes you can use the +make-i2c-dev-script located its source directory. + +It is not yet completed, but works fine for all dib3000mb-demods (all of the +USB1.1 dibusb-devices are equipped with it). +Having a CSV output would certainly be useful, when you want to make range +tests by driving around with your car and check the signal. Nevertheless, +this isn't written yet, but should be easy-going. Each line then should +have an timestamp. + +I cannot guarantee for the values this program calculates, I'm not a signal +expert, thus I don't know if they are correct. + +Thanks to Amaury Demol from DiBcom, who provides source for showing me how to +calculate frequencies from the demod values. + +Patrick Boettcher <patrick.boettcher@desy.de> + +PS: Please feel free to modify the source to fullfil your wishes. But please +remember, it is released under the GPL, thus please send back patches to the +author or to the linux-dvb mailing list, so other users can have benefit from +it. diff --git a/util/dib3000-watch/dib-i2c.h b/util/dib3000-watch/dib-i2c.h new file mode 100644 index 0000000..2e9c661 --- /dev/null +++ b/util/dib3000-watch/dib-i2c.h @@ -0,0 +1,43 @@ +/* + * adapted from different kernel headers + * "this is the current way of doing things."-Greg K-H + * + * everything copied from linux kernel 2.6.10 source + */ + +#ifndef _DIB_I2C_H +#define _DIB_I2C_H + + +/* from <linux/i2c.h> */ +#define I2C_SLAVE       0x0703 +#define I2C_SLAVE_FORCE 0x0706 +#define I2C_TENBIT      0x0704 +#define I2C_PEC         0x0708 +#define I2C_RETRIES     0x0701 +#define I2C_TIMEOUT     0x0702 + +#define I2C_FUNCS       0x0705 +#define I2C_RDWR        0x0707 +#define I2C_SMBUS       0x0720 + +struct i2c_msg { +	__u16 addr; +	__u16 flags; +#define I2C_M_RD            0x0001 +#define I2C_M_TEN           0x0010 +#define I2C_M_NOSTART       0x4000 +#define I2C_M_REV_DIR_ADDR  0x2000 +#define I2C_M_IGNORE_NAK    0x1000 +#define I2C_M_NO_RD_ACK     0x0800 +	__u16 len; +	__u8 *buf; +}; + +/* from <linux/i2c-dev.h> */ +struct i2c_rdwr_ioctl_data { +	struct i2c_msg *msgs; +	__u32 nmsgs; +}; + +#endif diff --git a/util/dib3000-watch/dib3000-watch.c b/util/dib3000-watch/dib3000-watch.c new file mode 100644 index 0000000..16bccb7 --- /dev/null +++ b/util/dib3000-watch/dib3000-watch.c @@ -0,0 +1,296 @@ +/* + * Tool for watching the dib3000*-demodulators, + * with an extended output. + * + * Copyright (C) 2005 by Patrick Boettcher <patrick.boettcher@desy.de> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + */ +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <stdlib.h> +#include <unistd.h> +#include <ctype.h> + +#include <getopt.h> + +#include <signal.h> + +#include <math.h> + +#include <fcntl.h> + +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/ioctl.h> + +#include <linux/types.h> + +#include "dib-i2c.h" +#include "dib3000-watch.h" +#include "dib3000.h" + +void usage (void) +{ +	verb("usage: dib3000-watch -d <i2c-device> -a <i2c-address> [-o <type>] [-i <seconds>]\n" +		 "   -d    normally one of /dev/i2c-[0-255]\n" +		 "   -a    is 8 for DiB3000M-B and 9, 10, 11 or 12 for DiB3000M-C or DiB3000-P\n" +		 "   -o    output type (print|csv) (default: print)\n" +		 "   -i    query interval in seconds (default: 0.1)\n" +		 "\n" +		 "Don't forget to run tzap or any other dvb-tune program (vdr, kaxtv) in order to tune a channel,\n" +		 "tuning isn't done by this tool.\n" +		 "\n" +		 "A lot of thing have been taken for the dibusb, dib3000m[bc] driver from kernel and\n" +		 "from t_demod-test software created by DiBcom. Both is GPL, so is dib-demod-watch.\n" +		 "\n" +		 "Copyright (C) 2005 by Patrick Boettcher <patrick.boettcher@desy.de>\n" +		 "\n" +		 "The source of this tool is released under the GPL.\n" +	); +	exit(1); +} + +__u16 dib_read_reg(struct dib_demod *dib,__u16 reg) +{ +	int ret; +	__u8 wb[] = { ((reg >> 8) | 0x80) & 0xff, reg & 0xff }; +	__u8 rb[2]; +	struct i2c_msg msg[] = { +		{ .addr = dib->i2c_addr, .flags = 0,        .buf = wb, .len = 2 }, +		{ .addr = dib->i2c_addr, .flags = I2C_M_RD, .buf = rb, .len = 2 }, +	}; +	struct i2c_rdwr_ioctl_data i2c_data = { +		.msgs  = msg, +		.nmsgs = 2, +	}; + +	if ((ret = ioctl(dib->fd,I2C_RDWR,&i2c_data)) != 2) { +		err("i2c_rdwr read failed. (%d)\n",ret); +		return 0; +	} +	return (rb[0] << 8)| rb[1]; +}; + +int dib_write_reg(struct dib_demod *dib, __u16 reg, __u16 val) +{ +	int ret; +	__u8 b[] = { +		(reg >> 8) & 0xff, reg & 0xff, +		(val >> 8) & 0xff, val & 0xff, +	}; +	struct i2c_msg msg[] = { +		{ .addr = dib->i2c_addr, .flags = 0, .buf = b, .len = 4 } +	}; +	struct i2c_rdwr_ioctl_data i2c_data = { +		.msgs  = msg, +		.nmsgs = 1, +	}; + +	if ((ret = ioctl(dib->fd,I2C_RDWR,&i2c_data)) != 1) { +		err("i2c_rdwr write failed. (%d)\n",ret); +		return -1; +	} +	return 0; +} + +int dib3000mb_monitoring(struct dib_demod *dib,struct dib3000mb_monitoring *m) +{ +	int dds_freq, p_dds_freq, +		n_agc_power = dib_read_reg(dib,DIB3000MB_REG_AGC_POWER), +		rf_power = dib_read_reg(dib,DIB3000MB_REG_RF_POWER), +		timing_offset; +	double ad_power_dB, minor_power; + +	m->invspec = dib_read_reg(dib,DIB3000MB_REG_DDS_INV); +	m->nfft = dib_read_reg(dib,DIB3000MB_REG_TPS_FFT); + +	m->agc_lock = dib_read_reg(dib,DIB3000MB_REG_AGC_LOCK); +	m->carrier_lock = dib_read_reg(dib,DIB3000MB_REG_CARRIER_LOCK); +	m->tps_lock = dib_read_reg(dib,DIB3000MB_REG_TPS_LOCK); +	m->vit_lock = dib_read_reg(dib,DIB3000MB_REG_VIT_LCK); +	m->ts_sync_lock = dib_read_reg(dib,DIB3000MB_REG_TS_SYNC_LOCK); +	m->ts_data_lock = dib_read_reg(dib,DIB3000MB_REG_TS_RS_LOCK); + +	p_dds_freq = ((dib_read_reg(dib,DIB3000MB_REG_DDS_FREQ_MSB) & 0xff) << 8) | +				 ((dib_read_reg(dib,DIB3000MB_REG_DDS_FREQ_LSB) & 0xff00) >> 8); +	dds_freq =   ((dib_read_reg(dib,DIB3000MB_REG_DDS_VALUE_MSB) & 0xff) << 8) | +				 ((dib_read_reg(dib,DIB3000MB_REG_DDS_VALUE_LSB) & 0xff00) >> 8); +	if (m->invspec) +		dds_freq = (1 << 16) - dds_freq; +	m->carrier_offset = (double)(dds_freq - p_dds_freq) / (double)(1 << 16) * DEF_SampFreq_KHz; + +	m->ber = (double)((dib_read_reg(dib,DIB3000MB_REG_BER_MSB) << 16) | dib_read_reg(dib,DIB3000MB_REG_BER_LSB)) / (double) 1e8; +	m->per = dib_read_reg(dib,DIB3000MB_REG_PACKET_ERROR_RATE); +	m->unc = dib_read_reg(dib,DIB3000MB_REG_UNC); +	m->fft_pos = dib_read_reg(dib,DIB3000MB_REG_FFT_WINDOW_POS); +	m->snr = 10.0 * log10( (double)(dib_read_reg(dib,DIB3000MB_REG_SIGNAL_POWER) << 8) / +		(double)((dib_read_reg(dib,DIB3000MB_REG_NOISE_POWER_MSB) << 16) + dib_read_reg(dib,DIB3000MB_REG_NOISE_POWER_LSB))); + +	m->mer = (double) ((dib_read_reg(dib,DIB3000MB_REG_MER_MSB) << 16) + dib_read_reg(dib,DIB3000MB_REG_MER_LSB)) +		/ (double) (1<<9) / (m->nfft ? 767.0 : 191.0); + +	if (n_agc_power == 0) +		n_agc_power = 1; +	ad_power_dB = 10 * log10( (double)(n_agc_power) / (double)(1<<16)); +	minor_power = ad_power_dB - DEF_agc_ref_dB ; +	m->rf_power = -DEF_gain_slope_dB * (double)rf_power/(double)(1<<16) + DEF_gain_delta_dB + minor_power; + +	timing_offset = +		(dib_read_reg(dib,DIB3000MB_REG_TIMING_OFFSET_MSB) << 16) + dib_read_reg(dib,DIB3000MB_REG_TIMING_OFFSET_LSB); +	if (timing_offset >= 0x800000) +		timing_offset |= 0xff000000; +	m->timing_offset_ppm = -(double)timing_offset / (double)(m->nfft ? 8192 : 2048) * 1e6 / (double)(1<<20); + +	return 0; +} + +int dib3000mb_print_monitoring(struct dib3000mb_monitoring *m) +{ +	printf("DiB3000M-B status\n\n"); +	printf(" AGC lock:                 %10d\n",m->agc_lock); +	printf(" carrier lock:             %10d\n",m->carrier_lock); +	printf(" TPS synchronize lock:     %10d\n",m->tps_lock); +	printf(" Viterbi lock:             %10d\n",m->vit_lock); +	printf(" MPEG TS synchronize lock: %10d\n",m->ts_sync_lock); +	printf(" MPEG TS data lock:        %10d\n",m->ts_data_lock); +	printf("\n\n"); +	printf(" spectrum inversion:       %10d\n",m->invspec); +	printf(" carrier offset:           %3.7g\n",m->carrier_offset); +	printf("\n\n"); +	printf(" bit error rate:           %3.7g\n",m->ber); +	printf(" packet error rate:        %10d\n",m->per); +	printf(" packet error count:       %10d\n",m->unc); +	printf("\n\n"); +	printf(" fft position:             %10d\n",m->fft_pos); +	printf(" transmission mode:        %10s\n",m->nfft ? "8k" : "2k"); +	printf("\n\n"); +	printf(" C / (N + I) =             %3.7g\n",m->snr); +	printf(" MER  =                    %3.7g dB\n",m->mer); +	printf(" RF power =                %3.7g dBm\n",m->rf_power); +	printf(" timing offset =           %3.7g ppm\n",m->timing_offset_ppm); +	return 0; +} + +int interrupted; + +void sighandler (int sig) +{ +	(void)sig; +	interrupted = 1; +} + +typedef enum { +	OUT_PRINT = 0, +	OUT_CSV, +} dib3000m_output_t; + +int main (int argc, char * const argv[]) +{ +	struct dib_demod dib; +	struct dib3000mb_monitoring mon; +	const char *dev = NULL; +	float intervall = 0.1; +	dib3000m_output_t out = OUT_PRINT; +	int c; + +	while ((c = getopt(argc,argv,"d:a:o:i:")) != -1) { +		switch (c) { +			case 'd': +				dev = optarg; +				break; +			case 'a': +				dib.i2c_addr = atoi(optarg); /* The I2C address */ +				break; +			case 'o': +				     if (strcasecmp(optarg,"print") == 0) out = OUT_PRINT; +				else if (strcasecmp(optarg,"csv") == 0)   out = OUT_CSV; +				else usage(); +				break; +			case 'i': +				intervall = atof(optarg); +				break; +			default: +				usage(); +		} +	} + +	if (dev == NULL) +		usage(); + +	interrupted = 0; +	signal(SIGINT, sighandler); +	signal(SIGKILL, sighandler); +	signal(SIGHUP, sighandler); + +	verb("will use '%s' as i2c-device and %d as i2c address.\n",dev,dib.i2c_addr); + +	if ((dib.fd = open(dev,O_RDWR)) < 0) { +		err("could not open %s\n",dev); +		exit(1); +	} + +    if (ioctl(dib.fd,I2C_SLAVE,dib.i2c_addr) < 0) { +		err("could not set i2c address\n"); +		exit(1); +	} + +	if (dib_read_reg(&dib,DIB3000_REG_MANUFACTOR_ID) != DIB3000_I2C_ID_DIBCOM) { +		err("could not find a dib3000 demodulator at i2c-address %d\n",dib.i2c_addr); +		exit(1); +	} + +	switch (dib_read_reg(&dib,DIB3000_REG_DEVICE_ID)) { +		case DIB3000MB_DEVICE_ID: +			verb("found a DiB3000M-B demodulator.\n"); +			dib.rev = DIB3000MB; +			break; +		case DIB3000MC_DEVICE_ID: +			verb("found a DiB3000M-C demodulator.\n"); +			dib.rev = DIB3000MC; +			break; +		case DIB3000P_DEVICE_ID: +			verb("found a DiB3000-P demodulator.\n"); +			dib.rev = DIB3000P; +			break; +		default: +			err("unsupported demodulator found.\n"); +	} + +	while (!interrupted) { +		switch (dib.rev) { +			case DIB3000MB: +				dib3000mb_monitoring(&dib,&mon); +				if (out == OUT_PRINT) { +					printf("\E[H\E[2J"); +					dib3000mb_print_monitoring(&mon); +				} else if (out == OUT_CSV) { +					printf("no csv output implemented yet.\n"); +				} +				break; +			default: +				interrupted=1; +				err("no monitoring writting for this demod, yet.\n"); +		} +		usleep((int) (intervall * 1000000)); +	} + +	close(dib.fd); + +	return 0; +} diff --git a/util/dib3000-watch/dib3000-watch.h b/util/dib3000-watch/dib3000-watch.h new file mode 100644 index 0000000..6d50521 --- /dev/null +++ b/util/dib3000-watch/dib3000-watch.h @@ -0,0 +1,46 @@ +#ifndef __DIB_DEMOD_WATCH__ +#define __DIB_DEMOD_WATCH__ + +#define err(args...)  fprintf(stderr,"error '%s': ",strerror(errno)); fprintf(stderr,args) +#define verb(args...) fprintf(stderr,args) + +typedef enum { +	DIB3000MB = 0, +	DIB3000MC, +	DIB3000P, +} dib_demod_t; + + +struct dib_demod { +	int fd; +	__u8 i2c_addr; + +	dib_demod_t rev; +}; + +struct dib3000mb_monitoring { +	int agc_lock; +	int carrier_lock; +	int tps_lock; +	int vit_lock; +	int ts_sync_lock; +	int ts_data_lock; + +	int invspec; + +	int per; +	int unc; + +	int fft_pos; + +	int nfft; + +	double carrier_offset; +	double ber; +	double snr; +	double mer; +	double rf_power; +	double timing_offset_ppm; +}; + +#endif diff --git a/util/dib3000-watch/dib3000.h b/util/dib3000-watch/dib3000.h new file mode 100644 index 0000000..7c3b8bd --- /dev/null +++ b/util/dib3000-watch/dib3000.h @@ -0,0 +1,56 @@ +#ifndef __DIB3000_H__ +#define __DIB3000_H__ + +/* most of this is taken from dib3000-common.h, dib3000mc_priv.h and dib3000mb_priv.h */ + +#define DIB3000_REG_MANUFACTOR_ID       (  1025) +#define DIB3000_I2C_ID_DIBCOM           (0x01b3) + +#define DIB3000_REG_DEVICE_ID           (  1026) +#define DIB3000MB_DEVICE_ID             (0x3000) +#define DIB3000MC_DEVICE_ID             (0x3001) +#define DIB3000P_DEVICE_ID              (0x3002) + +/* dib3000mb_priv.h */ + +#define DIB3000MB_REG_DDS_INV           (     5) +#define DIB3000MB_REG_AGC_LOCK          (   324) +#define DIB3000MB_REG_CARRIER_LOCK      (   355) +#define DIB3000MB_REG_TPS_LOCK          (   394) +#define DIB3000MB_REG_VIT_LCK           (   421) +#define DIB3000MB_REG_TS_SYNC_LOCK      (   423) +#define DIB3000MB_REG_TS_RS_LOCK        (   424) + +#define DIB3000MB_REG_DDS_FREQ_MSB      (     6) +#define DIB3000MB_REG_DDS_FREQ_LSB      (     7) +#define DIB3000MB_REG_DDS_VALUE_MSB     (   339) +#define DIB3000MB_REG_DDS_VALUE_LSB     (   340) + +#define DIB3000MB_REG_BER_MSB           (   414) +#define DIB3000MB_REG_BER_LSB           (   415) +#define DIB3000MB_REG_PACKET_ERROR_RATE (   417) +#define DIB3000MB_REG_UNC               (   420) + +#define DIB3000MB_REG_FFT_WINDOW_POS    (   353) +#define DIB3000MB_REG_TPS_FFT			(   404) + +#define DIB3000MB_REG_NOISE_POWER_MSB	(   372) +#define DIB3000MB_REG_NOISE_POWER_LSB	(   373) + +#define DIB3000MB_REG_SIGNAL_POWER		(   380) + +#define DIB3000MB_REG_MER_MSB			(   381) +#define DIB3000MB_REG_MER_LSB			(   382) + +#define DIB3000MB_REG_AGC_POWER			(   325) +#define DIB3000MB_REG_RF_POWER			(   328) + +#define DIB3000MB_REG_TIMING_OFFSET_MSB (   341) +#define DIB3000MB_REG_TIMING_OFFSET_LSB (   342) + +#define DEF_agc_ref_dB     -14 +#define DEF_gain_slope_dB  100 +#define DEF_gain_delta_dB  -2 +#define DEF_SampFreq_KHz     27700 + +#endif diff --git a/util/dib3000-watch/make-i2c-dev b/util/dib3000-watch/make-i2c-dev new file mode 100644 index 0000000..8f02bbd --- /dev/null +++ b/util/dib3000-watch/make-i2c-dev @@ -0,0 +1,6 @@ +for i in `seq 0 10`; +do +	mknod /dev/i2c-$i c 89 $i +	chown root.video /dev/i2c-$i +	chmod 664 /dev/i2c-$i +done | 
