Uwe Bugla wrote:
Am Donnerstag, 19. Juli 2007 02:29:34 schrieben Sie:
Uwe Bugla wrote:
Am Mittwoch, 18. Juli 2007 06:03:41 schrieb P. van Gaans:
I don't call myself a programmer (I've never seen any C guide), but
somehow I figured out how to add an extra switch to tzap to make it
print the status in (human-readable) decimal instead of hex. It is
attached. It would be really nice if this would make it into the
dvb-apps on linuxtv..

Talking about that, could anybody tell me the minimal and maximal and/or
possible values for status, signal, snr, ber and uncorrected? If I would
know them I could try to make the numbers more human-readable (eg signal
ranging from 0 to 99 or so).
Could you please redo that:
- in patch format (=only the additions)
- equally for tzap, czap, szap and femon?

Thus everybody could take advantage from that idea.
Would be a pleasure for us all if you did!

My idea for further enlargement (a quite old idea of mine):
route the human readable numbers into a speech recognition engine
(festival) to make them auditable and thus real usable for DVB-S dish
tuning f. ex.

Note: If the DVB-S dish is far away from the machine (card), auditable
signals are necessary.

_______________________________________________
linux-dvb mailing list
linux-dvb@linuxtv.org
http://www.linuxtv.org/cgi-bin/mailman/listinfo/linux-dvb
In patch format.. Oh please.. I have no idea how to produce that! I
installed xxdiff, it perfectly shows what I've changed but I don't see
an option to save it to a patch file!

You're lucky I've got a satellite dish so I should also be able to patch
szap and femon. I'll also produce a patched version of czap but my cable
card is not installed ATM and I don't feel like doing so (cable provider
is crap) but I'll probably get someone else on this list to test it.

Please do not try to add the switch yourself without asking me if I'm
still working on it. Nobody needs double work.

If somebody can tell me how to produce the so much wanted .diff files
I'll start working on it.

A. Take the latest kernel patch (i. e. 2.6.21.1) as an example.
B. format is as follows:
--- a/(file to be changed)
+++ b/(file to be changed)
@@ -(starting line number),(total number of lines starting from the beginning line before the change) +(starting line number),(total number of lines starting from the beginning line after the change)
(3 context lines starting with a space)
(additions start with plus)
(deletions start with minus)
(3 context lines starting with a space)

If this explanation still is too abstract, have a look at the example again.
Don't forget to test the patch!
No fuzz factors, no rejections please.
For testing purposes keep the original file to be patched in a separate directory please.
Now please give it a try - for sure you gonna make it!


I've got an idea of how the .diff is constructed, but I simply refuse to write them by hand. I've bought a computer NOT to do any more boring repetitive work ;-).

diff -urN oldfile.c newfile.c > lolwat.diff appears to work luckily.

Tzap was patched already.
Szap patched, compiles, tested and OK.
Czap patched, compiles without errors, untested because I hate my cable provider and the box I would have to install the cable card in is really noisy and unstable. Whoever wants to test: please report results, czap looks a little different from szap and tzap but I'm pretty certain it'll work straightaway. I assume this is OK, you couldn't expect all linuxtv developers to own cards for all DVB-systems anyway.. Femon patched in a different way: Femon already has a "human readable" switch, I just made BER and uncorrected show up as decimal instead of hex in human readable mode. Adding another switch sounds pointless to me.

The numbers/output seem to differ between devices and between szap and tzap greatly so for now I'm not going to try to make them more human-readable because of the possibility of breaking something.

Everything attached.
--- czap-hg.c	2007-07-18 05:18:38.000000000 +0200
+++ czap.c	2007-07-20 11:58:35.000000000 +0200
@@ -16,6 +16,7 @@
 
 static char FRONTEND_DEV [80];
 static char DEMUX_DEV [80];
+static int decread=0;
 static int exit_after_tuning;
 
 #define CHANNEL_FILE "channels.conf"
@@ -241,9 +242,18 @@
 		ioctl(fe_fd, FE_READ_BER, &ber);
 		ioctl(fe_fd, FE_READ_UNCORRECTED_BLOCKS, &uncorrected_blocks);
 
-		printf ("status %02x | signal %04x | snr %04x | "
+		if(decread==1)
+			{
+			printf ("status %d | signal %d | snr %d | "
+			"ber %d | unc %d | ",
+			status, signal, snr, ber, uncorrected_blocks);
+			}
+		else
+			{
+			printf ("status %02x | signal %04x | snr %04x | "
 			"ber %08x | unc %08x | ",
 			status, signal, snr, ber, uncorrected_blocks);
+			}
 
 		if (status & FE_HAS_LOCK)
 			printf("FE_HAS_LOCK");
@@ -261,7 +271,8 @@
 
 
 static const char *usage = "\nusage: %s [-a adapter_num] [-f frontend_id] [-d demux_id] [-c conf_file] {<channel name>| -n channel_num} [-x]\n"
-	"   or: %s [-c conf_file]  -l\n\n";
+	"   or: %s [-c conf_file]  -l\n\n"
+	"   -D for decimal status readings\n\n";
 
 
 int main(int argc, char **argv)
@@ -275,7 +286,7 @@
 	int frontend_fd, video_fd, audio_fd;
 	int opt, list_channels = 0, chan_no = 0;
 
-	while ((opt = getopt(argc, argv, "ln:hrn:a:f:d:c:x")) != -1) {
+	while ((opt = getopt(argc, argv, "Dln:hrn:a:f:d:c:x")) != -1) {
 		switch (opt) {
 		case 'a':
 			adapter = strtoul(optarg, NULL, 0);
@@ -298,6 +309,9 @@
 		case 'x':
 			exit_after_tuning = 1;
 			break;
+		case 'D':
+			decread = 1; /* alternative status readings (decimal instead of hex) */
+			break;
 		case 'c':
 			confname = optarg;
 			break;
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include <fcntl.h>
#include <ctype.h>
#include <errno.h>

#include <linux/dvb/frontend.h>
#include <linux/dvb/dmx.h>


static char FRONTEND_DEV [80];
static char DEMUX_DEV [80];
static int decread=0;
static int exit_after_tuning;

#define CHANNEL_FILE "channels.conf"

#define ERROR(x...)							\
	do {								\
		fprintf(stderr, "ERROR: ");				\
		fprintf(stderr, x);					\
		fprintf (stderr, "\n");					\
	} while (0)

#define PERROR(x...)							\
	do {								\
		fprintf(stderr, "ERROR: ");				\
		fprintf(stderr, x);					\
		fprintf (stderr, " (%s)\n", strerror(errno));		\
	} while (0)


typedef struct {
	char *name;
	int value;
} Param;

static const Param inversion_list[] = {
	{ "INVERSION_OFF", INVERSION_OFF },
	{ "INVERSION_ON", INVERSION_ON },
	{ "INVERSION_AUTO", INVERSION_AUTO }
};

static const Param fec_list[] = {
	{ "FEC_1_2", FEC_1_2 },
	{ "FEC_2_3", FEC_2_3 },
	{ "FEC_3_4", FEC_3_4 },
	{ "FEC_4_5", FEC_4_5 },
	{ "FEC_5_6", FEC_5_6 },
	{ "FEC_6_7", FEC_6_7 },
	{ "FEC_7_8", FEC_7_8 },
	{ "FEC_8_9", FEC_8_9 },
	{ "FEC_AUTO", FEC_AUTO },
	{ "FEC_NONE", FEC_NONE }
};

static const Param modulation_list[] = {
	{ "QAM_16", QAM_16 },
	{ "QAM_32", QAM_32 },
	{ "QAM_64", QAM_64 },
	{ "QAM_128", QAM_128 },
	{ "QAM_256", QAM_256 },
	{ "QAM_AUTO", QAM_AUTO }
};

#define LIST_SIZE(x) sizeof(x)/sizeof(Param)


static
int parse_param(const char *val, const Param * plist, int list_size, int *ok)
{
	int i;

	for (i = 0; i < list_size; i++) {
		if (strcasecmp(plist[i].name, val) == 0) {
			*ok = 1;
			return plist[i].value;
		}
	}
	*ok = 0;
	return -1;
}


static char line_buf[256];
static
char *find_channel(FILE *f, int list_channels, int *chan_no, const char *channel)
{
	size_t l;
	int lno = 0;

	l = channel ? strlen(channel) : 0;
	while (!feof(f)) {
		if (!fgets(line_buf, sizeof(line_buf), f))
			return NULL;
		lno++;
		if (list_channels) {
			printf("%3d %s", lno, line_buf);
		}
		else if (*chan_no) {
			if (*chan_no == lno)
				return line_buf;
		}
		else if ((strncasecmp(channel, line_buf, l) == 0)
				&& (line_buf[l] == ':')) {
			*chan_no = lno;
			return line_buf;
		}
	};

	return NULL;
}


int parse(const char *fname, int list_channels, int chan_no, const char *channel,
	  struct dvb_frontend_parameters *frontend, int *vpid, int *apid)
{
	FILE *f;
	char *chan;
	char *name, *inv, *fec, *mod;
	int ok;

	if ((f = fopen(fname, "r")) == NULL) {
		PERROR("could not open file '%s'", fname);
		return -1;
	}

	chan = find_channel(f, list_channels, &chan_no, channel);
	fclose(f);
	if (list_channels)
		return 0;
	if (!chan) {
		ERROR("could not find channel '%s' in channel list",
		      channel);
		return -2;
	}
	printf("%3d %s", chan_no, chan);

	if ((sscanf(chan, "%a[^:]:%d:%a[^:]:%d:%a[^:]:%a[^:]:%d:%d\n",
				&name, &frontend->frequency,
				&inv, &frontend->u.qam.symbol_rate,
				&fec, &mod, vpid, apid) != 8)
			|| !name || !inv || !fec | !mod) {
		ERROR("cannot parse service data");
		return -3;
	}
	frontend->inversion = parse_param(inv, inversion_list, LIST_SIZE(inversion_list), &ok);
	if (!ok) {
		ERROR("inversion field syntax '%s'", inv);
		return -4;
	}
	frontend->u.qam.fec_inner = parse_param(fec, fec_list, LIST_SIZE(fec_list), &ok);
	if (!ok) {
		ERROR("FEC field syntax '%s'", fec);
		return -5;
	}
	frontend->u.qam.modulation = parse_param(mod, modulation_list,
			LIST_SIZE(modulation_list), &ok);
	if (!ok) {
		ERROR("modulation field syntax '%s'", mod);
		return -6;
	}
	printf("%3d %s: f %d, s %d, i %d, fec %d, qam %d, v %#x, a %#x\n",
			chan_no, name, frontend->frequency, frontend->u.qam.symbol_rate,
			frontend->inversion, frontend->u.qam.fec_inner,
			frontend->u.qam.modulation, *vpid, *apid);
	free(name);
	free(inv);
	free(fec);
	free(mod);

	return 0;
}



static
int set_pesfilter (int fd, int pid, dmx_pes_type_t type, int dvr)
{
	struct dmx_pes_filter_params pesfilter;

	if (pid <= 0 || pid >= 0x1fff)
		return 0;

	pesfilter.pid = pid;
	pesfilter.input = DMX_IN_FRONTEND;
	pesfilter.output = dvr ? DMX_OUT_TS_TAP : DMX_OUT_DECODER;
	pesfilter.pes_type = type;
	pesfilter.flags = DMX_IMMEDIATE_START;

	if (ioctl(fd, DMX_SET_PES_FILTER, &pesfilter) < 0) {
		PERROR ("ioctl(DMX_SET_PES_FILTER) for %s PID failed",
			type == DMX_PES_AUDIO ? "Audio" :
			type == DMX_PES_VIDEO ? "Video" : "??");
		return -1;
	}

	return 0;
}

static
int setup_frontend(int fe_fd, struct dvb_frontend_parameters *frontend)
{
	struct dvb_frontend_info fe_info;

	if (ioctl(fe_fd, FE_GET_INFO, &fe_info) < 0) {
		PERROR ("ioctl FE_GET_INFO failed");
		return -1;
	}

	if (fe_info.type != FE_QAM) {
		ERROR ("frontend device is not a QAM (DVB-C) device");
		return -1;
	}

	if (ioctl(fe_fd, FE_SET_FRONTEND, frontend) < 0) {
		PERROR ("ioctl FE_SET_FRONTEND failed");
		return -1;
	}

	return 0;
}


static
int check_frontend (int fe_fd)
{
	fe_status_t status;
	uint16_t snr, signal;
	uint32_t ber, uncorrected_blocks;

	do {
		ioctl(fe_fd, FE_READ_STATUS, &status);
		ioctl(fe_fd, FE_READ_SIGNAL_STRENGTH, &signal);
		ioctl(fe_fd, FE_READ_SNR, &snr);
		ioctl(fe_fd, FE_READ_BER, &ber);
		ioctl(fe_fd, FE_READ_UNCORRECTED_BLOCKS, &uncorrected_blocks);

		if(decread==1)
			{
			printf ("status %d | signal %d | snr %d | "
			"ber %d | unc %d | ",
			status, signal, snr, ber, uncorrected_blocks);
			}
		else
			{
			printf ("status %02x | signal %04x | snr %04x | "
			"ber %08x | unc %08x | ",
			status, signal, snr, ber, uncorrected_blocks);
			}

		if (status & FE_HAS_LOCK)
			printf("FE_HAS_LOCK");

		usleep(1000000);

		printf("\n");

		if (exit_after_tuning && (status & FE_HAS_LOCK))
			break;
	} while (1);

	return 0;
}


static const char *usage = "\nusage: %s [-a adapter_num] [-f frontend_id] [-d demux_id] [-c conf_file] {<channel name>| -n channel_num} [-x]\n"
	"   or: %s [-c conf_file]  -l\n\n"
	"   -D for decimal status readings\n\n";


int main(int argc, char **argv)
{
	struct dvb_frontend_parameters frontend_param;
	char *homedir = getenv("HOME");
	char *confname = NULL;
	char *channel = NULL;
	int adapter = 0, frontend = 0, demux = 0, dvr = 0;
	int vpid, apid;
	int frontend_fd, video_fd, audio_fd;
	int opt, list_channels = 0, chan_no = 0;

	while ((opt = getopt(argc, argv, "Dln:hrn:a:f:d:c:x")) != -1) {
		switch (opt) {
		case 'a':
			adapter = strtoul(optarg, NULL, 0);
			break;
		case 'f':
			frontend = strtoul(optarg, NULL, 0);
			break;
		case 'd':
			demux = strtoul(optarg, NULL, 0);
			break;
		case 'r':
			dvr = 1;
			break;
		case 'l':
			list_channels = 1;
			break;
		case 'n':
			chan_no = strtoul(optarg, NULL, 0);
			break;
		case 'x':
			exit_after_tuning = 1;
			break;
		case 'D':
			decread = 1; /* alternative status readings (decimal instead of hex) */
			break;
		case 'c':
			confname = optarg;
			break;
		case '?':
		case 'h':
		default:
			fprintf (stderr, usage, argv[0], argv[0]);
			return -1;
		};
	}

	if (optind < argc)
		channel = argv[optind];

	if (!channel && chan_no <= 0 && !list_channels) {
		fprintf (stderr, usage, argv[0], argv[0]);
		return -1;
	}

	if (!homedir)
		ERROR("$HOME not set");

	snprintf (FRONTEND_DEV, sizeof(FRONTEND_DEV),
		  "/dev/dvb/adapter%i/frontend%i", adapter, frontend);

	snprintf (DEMUX_DEV, sizeof(DEMUX_DEV),
		  "/dev/dvb/adapter%i/demux%i", adapter, demux);

	printf ("using '%s' and '%s'\n", FRONTEND_DEV, DEMUX_DEV);

	if (!confname)
	{
		int len = strlen(homedir) + strlen(CHANNEL_FILE) + 18;
		if (!homedir)
			ERROR("$HOME not set");
		confname = malloc(len);
		snprintf(confname, len, "%s/.czap/%i/%s",
			 homedir, adapter, CHANNEL_FILE);
		if (access(confname, R_OK))
			snprintf(confname, len, "%s/.czap/%s",
				 homedir, CHANNEL_FILE);
	}
	printf("reading channels from file '%s'\n", confname);

	memset(&frontend_param, 0, sizeof(struct dvb_frontend_parameters));

	if (parse(confname, list_channels, chan_no, channel, &frontend_param, &vpid, &apid))
		return -1;
	if (list_channels)
		return 0;

	if ((frontend_fd = open(FRONTEND_DEV, O_RDWR)) < 0) {
		PERROR("failed opening '%s'", FRONTEND_DEV);
		return -1;
	}

	if (setup_frontend(frontend_fd, &frontend_param) < 0)
		return -1;

	if ((video_fd = open(DEMUX_DEV, O_RDWR)) < 0) {
		PERROR("failed opening '%s'", DEMUX_DEV);
		return -1;
	}

	if (set_pesfilter (video_fd, vpid, DMX_PES_VIDEO, dvr) < 0)
		return -1;

	if ((audio_fd = open(DEMUX_DEV, O_RDWR)) < 0) {
		PERROR("failed opening '%s'", DEMUX_DEV);
		return -1;
	}

	if (set_pesfilter (audio_fd, apid, DMX_PES_AUDIO, dvr) < 0)
		return -1;

	check_frontend (frontend_fd);

	close (audio_fd);
	close (video_fd);
	close (frontend_fd);

	return 0;
}
--- femon-hg.c	2007-07-18 05:18:38.000000000 +0200
+++ femon.c	2007-07-20 12:06:00.000000000 +0200
@@ -68,7 +68,7 @@
 
 
 		if (human_readable) {
-                       printf ("status %c%c%c%c%c | signal %3u%% | snr %3u%% | ber %08x | unc %08x | ",
+                       printf ("status %c%c%c%c%c | signal %3u%% | snr %3u%% | ber %d | unc %d | ",
 				fe_info.signal ? 'S' : ' ',
 				fe_info.carrier ? 'C' : ' ',
 				fe_info.viterbi ? 'V' : ' ',
/* femon -- monitor frontend status
 *
 * Copyright (C) 2003 convergence GmbH
 * Johannes Stezenbach <[EMAIL PROTECTED]>
 *
 * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
 */


#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <string.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/poll.h>
#include <fcntl.h>
#include <time.h>
#include <unistd.h>

#include <stdint.h>
#include <sys/time.h>

#include <libdvbapi/dvbfe.h>

#define FE_STATUS_PARAMS (DVBFE_INFO_LOCKSTATUS|DVBFE_INFO_SIGNAL_STRENGTH|DVBFE_INFO_BER|DVBFE_INFO_SNR|DVBFE_INFO_UNCORRECTED_BLOCKS)

static char *usage_str =
    "\nusage: femon [options]\n"
    "     -h        : human readable output\n"
    "     -a number : use given adapter (default 0)\n"
    "     -f number : use given frontend (default 0)\n"
    "     -c number : samples to take (default 0 = infinite)\n\n";


static void usage(void)
{
	fprintf(stderr, usage_str);
	exit(1);
}


static
int check_frontend (struct dvbfe_handle *fe, int human_readable, unsigned int count)
{
	struct dvbfe_info fe_info;
	unsigned int samples = 0;

	do {
		if (dvbfe_get_info(fe, FE_STATUS_PARAMS, &fe_info, DVBFE_INFO_QUERYTYPE_IMMEDIATE, 0) != FE_STATUS_PARAMS) {
			fprintf(stderr, "Problem retrieving frontend information: %m\n");
		}



		if (human_readable) {
                       printf ("status %c%c%c%c%c | signal %3u%% | snr %3u%% | ber %d | unc %d | ",
				fe_info.signal ? 'S' : ' ',
				fe_info.carrier ? 'C' : ' ',
				fe_info.viterbi ? 'V' : ' ',
				fe_info.sync ? 'Y' : ' ',
				fe_info.lock ? 'L' : ' ',
				(fe_info.signal_strength * 100) / 0xffff,
				(fe_info.snr * 100) / 0xffff,
				fe_info.ber,
				fe_info.ucblocks);
		} else {
			printf ("status %c%c%c%c%c | signal %04x | snr %04x | ber %08x | unc %08x | ",
				fe_info.signal ? 'S' : ' ',
				fe_info.carrier ? 'C' : ' ',
				fe_info.viterbi ? 'V' : ' ',
				fe_info.sync ? 'Y' : ' ',
				fe_info.lock ? 'L' : ' ',
				fe_info.signal_strength,
				fe_info.snr,
				fe_info.ber,
				fe_info.ucblocks);
		}

		if (fe_info.lock)
			printf("FE_HAS_LOCK");

		printf("\n");
		fflush(stdout);
		usleep(1000000);
		samples++;
	} while ((!count) || (count-samples));

	return 0;
}


static
int do_mon(unsigned int adapter, unsigned int frontend, int human_readable, unsigned int count)
{
	int result;
	struct dvbfe_handle *fe;
	struct dvbfe_info fe_info;
	char *fe_type = "UNKNOWN";

	fe = dvbfe_open(adapter, frontend, 1);
	if (fe == NULL) {
		perror("opening frontend failed");
		return 0;
	}

	dvbfe_get_info(fe, 0, &fe_info, DVBFE_INFO_QUERYTYPE_IMMEDIATE, 0);
	switch(fe_info.type) {
	case DVBFE_TYPE_DVBS:
		fe_type = "DVBS";
		break;
	case DVBFE_TYPE_DVBC:
		fe_type = "DVBC";
		break;
	case DVBFE_TYPE_DVBT:
		fe_type = "DVBT";
		break;
	case DVBFE_TYPE_ATSC:
		fe_type = "ATSC";
		break;
	}
	printf("FE: %s (%s)\n", fe_info.name, fe_type);

	result = check_frontend (fe, human_readable, count);

	dvbfe_close(fe);

	return result;
}

int main(int argc, char *argv[])
{
	unsigned int adapter = 0, frontend = 0, count = 0;
	int human_readable = 0;
	int opt;

       while ((opt = getopt(argc, argv, "ha:f:c:")) != -1) {
		switch (opt)
		{
		default:
			usage();
			break;
		case 'a':
			adapter = strtoul(optarg, NULL, 0);
			break;
		case 'c':
			count = strtoul(optarg, NULL, 0);
			break;
		case 'f':
			frontend = strtoul(optarg, NULL, 0);
			break;
		case 'h':
			human_readable = 1;
			break;
		}
	}

	do_mon(adapter, frontend, human_readable, count);

	return 0;
}
--- szap-hg.c	2007-07-18 05:18:38.000000000 +0200
+++ szap.c	2007-07-20 11:53:03.000000000 +0200
@@ -72,6 +72,7 @@
 
 static int exit_after_tuning;
 static int interactive;
+static int decread=0;
 
 static char *usage_str =
     "\nusage: szap -q\n"
@@ -84,6 +85,7 @@
     "     -c file   : read channels list from 'file'\n"
     "     -b        : enable Audio Bypass (default no)\n"
     "     -x        : exit after tuning\n"
+    "     -D        : Show status with decimal numbers instead of hex\n"
     "     -r        : set up /dev/dvb/adapterX/dvr0 for TS recording\n"
     "     -l lnb-type (DVB-S Only) (use -l help to print types) or \n"
     "     -l low[,high[,switch]] in Mhz\n"
@@ -275,8 +277,16 @@
       if (ioctl(fe_fd, FE_READ_UNCORRECTED_BLOCKS, &uncorrected_blocks) == -1)
          uncorrected_blocks = -2;
 
-      printf ("status %02x | signal %04x | snr %04x | ber %08x | unc %08x | ",
-	      status, signal, snr, ber, uncorrected_blocks);
+	if(decread==1)
+		{
+		printf ("status %d | signal %d | snr %d | ber %d | unc %d | ",
+		status, signal, snr, ber, uncorrected_blocks);
+		}
+		else
+		{
+		printf ("status %02x | signal %04x | snr %04x | ber %08x | unc %08x | ",
+		status, signal, snr, ber, uncorrected_blocks);
+		}
 
       if (status & FE_HAS_LOCK)
 	 printf("FE_HAS_LOCK");
@@ -614,7 +624,7 @@
    int opt, copt = 0;
 
    lnb_type = *lnb_enum(0);
-   while ((opt = getopt(argc, argv, "hqrpn:a:f:d:c:l:xib")) != -1) {
+   while ((opt = getopt(argc, argv, "Dhqrpn:a:f:d:c:l:xib")) != -1) {
       switch (opt)
       {
 	 case '?':
@@ -658,6 +668,9 @@
 	 case 'x':
 	    exit_after_tuning = 1;
 	    break;
+	case 'D':
+	    decread = 1; /* alternative status readings (decimal instead of hex) */
+	    break;
 	 case 'i':
 	    interactive = 1;
 	    exit_after_tuning = 1;
/* szap -- simple zapping tool for the Linux DVB API
 *
 * szap operates on VDR (http://www.cadsoft.de/people/kls/vdr/index.htm)
 * satellite channel lists (e.g. from http://www.dxandy.de/cgi-bin/dvbchan.pl).
 * szap assumes you have a "Universal LNB" (i.e. with LOFs 9750/10600 MHz).
 *
 * Compilation: `gcc -Wall -I../../ost/include -O2 szap.c -o szap`
 *  or, if your DVB driver is in the kernel source tree:
 *              `gcc -Wall -DDVB_IN_KERNEL -O2 szap.c -o szap`
 *
 * Copyright (C) 2001 Johannes Stezenbach ([EMAIL PROTECTED])
 * for convergence integrated media
 *
 * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
 */


#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <string.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/poll.h>
#include <sys/param.h>
#include <fcntl.h>
#include <time.h>
#include <unistd.h>

#include <stdint.h>
#include <sys/time.h>

#include <linux/dvb/frontend.h>
#include <linux/dvb/dmx.h>
#include <linux/dvb/audio.h>
#include "lnb.h"

#ifndef TRUE
#define TRUE (1==1)
#endif
#ifndef FALSE
#define FALSE (1==0)
#endif

/* location of channel list file */
#define CHANNEL_FILE "channels.conf"

/* one line of the VDR channel file has the following format:
 * ^name:frequency_MHz:polarization:sat_no:symbolrate:vpid:apid:?:service_id$
 */


#define FRONTENDDEVICE "/dev/dvb/adapter%d/frontend%d"
#define DEMUXDEVICE "/dev/dvb/adapter%d/demux%d"
#define AUDIODEVICE "/dev/dvb/adapter%d/audio%d"

static struct lnb_types_st lnb_type;

static int exit_after_tuning;
static int interactive;
static int decread=0;

static char *usage_str =
    "\nusage: szap -q\n"
    "         list known channels\n"
    "       szap [options] {-n channel-number|channel_name}\n"
    "         zap to channel via number or full name (case insensitive)\n"
    "     -a number : use given adapter (default 0)\n"
    "     -f number : use given frontend (default 0)\n"
    "     -d number : use given demux (default 0)\n"
    "     -c file   : read channels list from 'file'\n"
    "     -b        : enable Audio Bypass (default no)\n"
    "     -x        : exit after tuning\n"
    "     -D        : Show status with decimal numbers instead of hex\n"
    "     -r        : set up /dev/dvb/adapterX/dvr0 for TS recording\n"
    "     -l lnb-type (DVB-S Only) (use -l help to print types) or \n"
    "     -l low[,high[,switch]] in Mhz\n"
    "     -i        : run interactively, allowing you to type in channel names\n"
    "     -p        : add pat and pmt to TS recording (implies -r)\n"
    "                 or -n numbers for zapping\n";

static int set_demux(int dmxfd, int pid, int pes_type, int dvr)
{
   struct dmx_pes_filter_params pesfilter;

   if (pid < 0 || pid >= 0x1fff) /* ignore this pid to allow radio services */
	   return TRUE;

   if (dvr) {
      int buffersize = 64 * 1024;
      if (ioctl(dmxfd, DMX_SET_BUFFER_SIZE, buffersize) == -1)
        perror("DMX_SET_BUFFER_SIZE failed");
   }

   pesfilter.pid = pid;
   pesfilter.input = DMX_IN_FRONTEND;
   pesfilter.output = dvr ? DMX_OUT_TS_TAP : DMX_OUT_DECODER;
   pesfilter.pes_type = pes_type;
   pesfilter.flags = DMX_IMMEDIATE_START;

   if (ioctl(dmxfd, DMX_SET_PES_FILTER, &pesfilter) == -1) {
      fprintf(stderr, "DMX_SET_PES_FILTER failed "
	      "(PID = 0x%04x): %d %m\n", pid, errno);
      return FALSE;
   }

   return TRUE;
}

int get_pmt_pid(char *dmxdev, int sid)
{
   int patfd, count;
   int pmt_pid = 0;
   int patread = 0;
   int section_length;
   unsigned char buft[4096];
   unsigned char *buf = buft;
   struct dmx_sct_filter_params f;

   memset(&f, 0, sizeof(f));
   f.pid = 0;
   f.filter.filter[0] = 0x00;
   f.filter.mask[0] = 0xff;
   f.timeout = 0;
   f.flags = DMX_IMMEDIATE_START | DMX_CHECK_CRC;

   if ((patfd = open(dmxdev, O_RDWR)) < 0) {
      perror("openening pat demux failed");
      return -1;
   }

   if (ioctl(patfd, DMX_SET_FILTER, &f) == -1) {
      perror("ioctl DMX_SET_FILTER failed");
      close(patfd);
      return -1;
   }

   while (!patread){
      if (((count = read(patfd, buf, sizeof(buft))) < 0) && errno == EOVERFLOW)
         count = read(patfd, buf, sizeof(buft));
      if (count < 0) {
         perror("read_sections: read error");
         close(patfd);
         return -1;
      }

      section_length = ((buf[1] & 0x0f) << 8) | buf[2];
      if (count != section_length + 3)
         continue;

      buf += 8;
      section_length -= 8;

      patread = 1; /* assumes one section contains the whole pat */
      while (section_length > 0) {
         int service_id = (buf[0] << 8) | buf[1];
         if (service_id == sid) {
            pmt_pid = ((buf[2] & 0x1f) << 8) | buf[3];
            section_length = 0;
         }
         buf += 4;
         section_length -= 4;
     }
   }

   close(patfd);
   return pmt_pid;
}

struct diseqc_cmd {
   struct dvb_diseqc_master_cmd cmd;
   uint32_t wait;
};

void diseqc_send_msg(int fd, fe_sec_voltage_t v, struct diseqc_cmd *cmd,
		     fe_sec_tone_mode_t t, fe_sec_mini_cmd_t b)
{
   if (ioctl(fd, FE_SET_TONE, SEC_TONE_OFF) == -1)
      perror("FE_SET_TONE failed");
   if (ioctl(fd, FE_SET_VOLTAGE, v) == -1)
      perror("FE_SET_VOLTAGE failed");
   usleep(15 * 1000);
   if (ioctl(fd, FE_DISEQC_SEND_MASTER_CMD, &cmd->cmd) == -1)
      perror("FE_DISEQC_SEND_MASTER_CMD failed");
   usleep(cmd->wait * 1000);
   usleep(15 * 1000);
   if (ioctl(fd, FE_DISEQC_SEND_BURST, b) == -1)
      perror("FE_DISEQC_SEND_BURST failed");
   usleep(15 * 1000);
   if (ioctl(fd, FE_SET_TONE, t) == -1)
      perror("FE_SET_TONE failed");
}




/* digital satellite equipment control,
 * specification is available from http://www.eutelsat.com/
 */
static int diseqc(int secfd, int sat_no, int pol_vert, int hi_band)
{
   struct diseqc_cmd cmd =
       { {{0xe0, 0x10, 0x38, 0xf0, 0x00, 0x00}, 4}, 0 };

   /* param: high nibble: reset bits, low nibble set bits,
    * bits are: option, position, polarization, band
    */
   cmd.cmd.msg[3] =
       0xf0 | (((sat_no * 4) & 0x0f) | (hi_band ? 1 : 0) | (pol_vert ? 0 : 2));

   diseqc_send_msg(secfd, pol_vert ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18,
		   &cmd, hi_band ? SEC_TONE_ON : SEC_TONE_OFF,
		   sat_no % 2 ? SEC_MINI_B : SEC_MINI_A);

   return TRUE;
}

static int do_tune(int fefd, unsigned int ifreq, unsigned int sr)
{
   struct dvb_frontend_parameters tuneto;
   struct dvb_frontend_event ev;

   /* discard stale QPSK events */
   while (1) {
      if (ioctl(fefd, FE_GET_EVENT, &ev) == -1)
	 break;
   }

   tuneto.frequency = ifreq;
   tuneto.inversion = INVERSION_AUTO;
   tuneto.u.qpsk.symbol_rate = sr;
   tuneto.u.qpsk.fec_inner = FEC_AUTO;

   if (ioctl(fefd, FE_SET_FRONTEND, &tuneto) == -1) {
      perror("FE_SET_FRONTEND failed");
      return FALSE;
   }

   return TRUE;
}


static
int check_frontend (int fe_fd, int dvr)
{
   (void)dvr;
   fe_status_t status;
   uint16_t snr, signal;
   uint32_t ber, uncorrected_blocks;
   int timeout = 0;

   do {
      if (ioctl(fe_fd, FE_READ_STATUS, &status) == -1)
         perror("FE_READ_STATUS failed");
      /* some frontends might not support all these ioctls, thus we
       * avoid printing errors */
      if (ioctl(fe_fd, FE_READ_SIGNAL_STRENGTH, &signal) == -1)
         signal = -2;
      if (ioctl(fe_fd, FE_READ_SNR, &snr) == -1)
         snr = -2;
      if (ioctl(fe_fd, FE_READ_BER, &ber) == -1)
         ber = -2;
      if (ioctl(fe_fd, FE_READ_UNCORRECTED_BLOCKS, &uncorrected_blocks) == -1)
         uncorrected_blocks = -2;

	if(decread==1)
		{
		printf ("status %d | signal %d | snr %d | ber %d | unc %d | ",
		status, signal, snr, ber, uncorrected_blocks);
		}
		else
		{
		printf ("status %02x | signal %04x | snr %04x | ber %08x | unc %08x | ",
		status, signal, snr, ber, uncorrected_blocks);
		}

      if (status & FE_HAS_LOCK)
	 printf("FE_HAS_LOCK");
      printf("\n");

      if (exit_after_tuning && ((status & FE_HAS_LOCK) || (++timeout >= 10)))
         break;

      usleep(1000000);
   } while (1);

   return 0;
}


static
int zap_to(unsigned int adapter, unsigned int frontend, unsigned int demux,
      unsigned int sat_no, unsigned int freq, unsigned int pol,
      unsigned int sr, unsigned int vpid, unsigned int apid, int sid,
      int dvr, int rec_psi, int bypass)
{
   char fedev[128], dmxdev[128], auddev[128];
   static int fefd, dmxfda, dmxfdv, audiofd = -1, patfd, pmtfd;
   int pmtpid;
   uint32_t ifreq;
   int hiband, result;
   static struct dvb_frontend_info fe_info;

   if (!fefd) {
      snprintf(fedev, sizeof(fedev), FRONTENDDEVICE, adapter, frontend);
      snprintf(dmxdev, sizeof(dmxdev), DEMUXDEVICE, adapter, demux);
      snprintf(auddev, sizeof(auddev), AUDIODEVICE, adapter, demux);
      printf("using '%s' and '%s'\n", fedev, dmxdev);

      if ((fefd = open(fedev, O_RDWR | O_NONBLOCK)) < 0) {
	 perror("opening frontend failed");
	 return FALSE;
      }

      result = ioctl(fefd, FE_GET_INFO, &fe_info);

      if (result < 0) {
	 perror("ioctl FE_GET_INFO failed");
	 close(fefd);
	 return FALSE;
      }

      if (fe_info.type != FE_QPSK) {
	 fprintf(stderr, "frontend device is not a QPSK (DVB-S) device!\n");
	 close(fefd);
	 return FALSE;
      }

      if ((dmxfdv = open(dmxdev, O_RDWR)) < 0) {
	 perror("opening video demux failed");
	 close(fefd);
	 return FALSE;
      }

      if ((dmxfda = open(dmxdev, O_RDWR)) < 0) {
	 perror("opening audio demux failed");
	 close(fefd);
	 return FALSE;
      }

      if (dvr == 0)	/* DMX_OUT_DECODER */
	 audiofd = open(auddev, O_RDWR);

      if (rec_psi){
         if ((patfd = open(dmxdev, O_RDWR)) < 0) {
	    perror("opening pat demux failed");
	    close(audiofd);
	    close(dmxfda);
	    close(dmxfdv);
	    close(fefd);
	    return FALSE;
         }

         if ((pmtfd = open(dmxdev, O_RDWR)) < 0) {
	    perror("opening pmt demux failed");
	    close(patfd);
	    close(audiofd);
	    close(dmxfda);
	    close(dmxfdv);
	    close(fefd);
	    return FALSE;
         }
      }
   }

   hiband = 0;
   if (lnb_type.switch_val && lnb_type.high_val &&
	freq >= lnb_type.switch_val)
	hiband = 1;

   if (hiband)
      ifreq = freq - lnb_type.high_val;
   else {
      if (freq < lnb_type.low_val)
          ifreq = lnb_type.low_val - freq;
      else
          ifreq = freq - lnb_type.low_val;
   }
   result = FALSE;

   if (diseqc(fefd, sat_no, pol, hiband))
      if (do_tune(fefd, ifreq, sr))
	 if (set_demux(dmxfdv, vpid, DMX_PES_VIDEO, dvr))
	    if (audiofd >= 0)
	       (void)ioctl(audiofd, AUDIO_SET_BYPASS_MODE, bypass);
	    if (set_demux(dmxfda, apid, DMX_PES_AUDIO, dvr)) {
	       if (rec_psi) {
	          pmtpid = get_pmt_pid(dmxdev, sid);
		  if (pmtpid < 0) {
		     result = FALSE;
		  }
		  if (pmtpid == 0) {
		     fprintf(stderr,"couldn't find pmt-pid for sid %04x\n",sid);
		     result = FALSE;
		  }
		  if (set_demux(patfd, 0, DMX_PES_OTHER, dvr))
	             if (set_demux(pmtfd, pmtpid, DMX_PES_OTHER, dvr))
	                result = TRUE;
	          } else {
		    result = TRUE;
		  }
	       }

   check_frontend (fefd, dvr);

   if (!interactive) {
      close(patfd);
      close(pmtfd);
      if (audiofd >= 0)
	 close(audiofd);
      close(dmxfda);
      close(dmxfdv);
      close(fefd);
   }

   return result;
}


static int read_channels(const char *filename, int list_channels,
			 uint32_t chan_no, const char *chan_name,
			 unsigned int adapter, unsigned int frontend,
			 unsigned int demux, int dvr, int rec_psi,
			 int bypass)
{
   FILE *cfp;
   char buf[4096];
   char inp[256];
   char *field, *tmp, *p;
   unsigned int line;
   unsigned int freq, pol, sat_no, sr, vpid, apid, sid;
   int ret;

again:
   line = 0;
   if (!(cfp = fopen(filename, "r"))) {
      fprintf(stderr, "error opening channel list '%s': %d %m\n",
	      filename, errno);
      return FALSE;
   }

   if (interactive) {
      fprintf(stderr, "\n>>> ");
      if (!fgets(inp, sizeof(inp), stdin)) {
	 printf("\n");
	 return -1;
      }
      if (inp[0] == '-' && inp[1] == 'n') {
	 chan_no = strtoul(inp+2, NULL, 0);
	 chan_name = NULL;
	 if (!chan_no) {
	    fprintf(stderr, "bad channel number\n");
	    goto again;
	 }
      } else {
	 p = strchr(inp, '\n');
	 if (p)
	    *p = '\0';
	 chan_name = inp;
	 chan_no = 0;
      }
   }

   while (!feof(cfp)) {
      if (fgets(buf, sizeof(buf), cfp)) {
	 line++;

	 if (chan_no && chan_no != line)
	    continue;

	 tmp = buf;
	 field = strsep(&tmp, ":");

	 if (!field)
	    goto syntax_err;

	 if (list_channels) {
	    printf("%03u %s\n", line, field);
	    continue;
	 }

	 if (chan_name && strcasecmp(chan_name, field) != 0)
	    continue;

	 printf("zapping to %d '%s':\n", line, field);

	 if (!(field = strsep(&tmp, ":")))
	    goto syntax_err;

	 freq = strtoul(field, NULL, 0);

	 if (!(field = strsep(&tmp, ":")))
	    goto syntax_err;

	 pol = (field[0] == 'h' ? 0 : 1);

	 if (!(field = strsep(&tmp, ":")))
	    goto syntax_err;

	 sat_no = strtoul(field, NULL, 0);

	 if (!(field = strsep(&tmp, ":")))
	    goto syntax_err;

	 sr = strtoul(field, NULL, 0) * 1000;

	 if (!(field = strsep(&tmp, ":")))
	    goto syntax_err;

	 vpid = strtoul(field, NULL, 0);
	 if (!vpid)
            vpid = 0x1fff;

	 if (!(field = strsep(&tmp, ":")))
	    goto syntax_err;

	 p = strchr(field, ';');

	 if (p) {
	    *p = '\0';
	    p++;
	    if (bypass) {
	       if (!p || !*p)
		  goto syntax_err;
	       field = p;
	    }
	 }

	 apid = strtoul(field, NULL, 0);
	 if (!apid)
            apid = 0x1fff;

	 if (!(field = strsep(&tmp, ":")))
	    goto syntax_err;

	 sid = strtoul(field, NULL, 0);

	 printf("sat %u, frequency = %u MHz %c, symbolrate %u, "
		"vpid = 0x%04x, apid = 0x%04x sid = 0x%04x\n",
		sat_no, freq, pol ? 'V' : 'H', sr, vpid, apid, sid);

	 fclose(cfp);

	 ret = zap_to(adapter, frontend, demux, sat_no, freq * 1000,
		      pol, sr, vpid, apid, sid, dvr, rec_psi, bypass);
	 if (interactive)
	    goto again;

	 if (ret)
	    return TRUE;

	 return FALSE;

       syntax_err:
	 fprintf(stderr, "syntax error in line %u: '%s'\n", line, buf);
      } else if (ferror(cfp)) {
	 fprintf(stderr, "error reading channel list '%s': %d %m\n",
		 filename, errno);
	 fclose(cfp);
	 return FALSE;
      } else
	 break;
   }

   fclose(cfp);

   if (!list_channels) {
      fprintf(stderr, "channel not found\n");
      if (!interactive)
	 return FALSE;
   }
   if (interactive)
      goto again;

   return TRUE;
}


void
bad_usage(char *pname, int prlnb)
{
int i;
struct lnb_types_st *lnbp;
char **cp;

	if (!prlnb) {
		fprintf (stderr, usage_str, pname);
	} else {
		i = 0;
		fprintf(stderr, "-l <lnb-type> or -l low[,high[,switch]] in Mhz\nwhere <lnb-type> is:\n");
		while(NULL != (lnbp = lnb_enum(i))) {
			fprintf (stderr, "%s\n", lnbp->name);
			for (cp = lnbp->desc; *cp ; cp++) {
				fprintf (stderr, "   %s\n", *cp);
			}
			i++;
		}
	}
}

int main(int argc, char *argv[])
{
   const char *home;
   char chanfile[2 * PATH_MAX];
   int list_channels = 0;
   unsigned int chan_no = 0;
   const char *chan_name = NULL;
   unsigned int adapter = 0, frontend = 0, demux = 0, dvr = 0, rec_psi = 0;
   int bypass = 0;
   int opt, copt = 0;

   lnb_type = *lnb_enum(0);
   while ((opt = getopt(argc, argv, "Dhqrpn:a:f:d:c:l:xib")) != -1) {
      switch (opt)
      {
	 case '?':
	 case 'h':
	 default:
	    bad_usage(argv[0], 0);
	 case 'b':
	    bypass = 1;
	    break;
	 case 'q':
	    list_channels = 1;
	    break;
	 case 'r':
	    dvr = 1;
	    break;
	 case 'n':
	    chan_no = strtoul(optarg, NULL, 0);
	    break;
	 case 'a':
	    adapter = strtoul(optarg, NULL, 0);
	    break;
	 case 'f':
	    frontend = strtoul(optarg, NULL, 0);
	    break;
	 case 'p':
	    rec_psi = 1;
	    break;
	 case 'd':
	    demux = strtoul(optarg, NULL, 0);
	    break;
	 case 'c':
	    copt = 1;
	    strncpy(chanfile, optarg, sizeof(chanfile));
	    break;
	 case 'l':
	    if (lnb_decode(optarg, &lnb_type) < 0) {
		bad_usage(argv[0], 1);
		return -1;
	    }
	    break;
	 case 'x':
	    exit_after_tuning = 1;
	    break;
	case 'D':
	    decread = 1; /* alternative status readings (decimal instead of hex) */
	    break;
	 case 'i':
	    interactive = 1;
	    exit_after_tuning = 1;
      }
   }
   lnb_type.low_val *= 1000;	/* convert to kiloherz */
   lnb_type.high_val *= 1000;	/* convert to kiloherz */
   lnb_type.switch_val *= 1000;	/* convert to kiloherz */
   if (optind < argc)
      chan_name = argv[optind];
   if (chan_name && chan_no) {
	bad_usage(argv[0], 0);
	return -1;
   }
   if (list_channels && (chan_name || chan_no)) {
	bad_usage(argv[0], 0);
	return -1;
   }
   if (!list_channels && !chan_name && !chan_no && !interactive) {
	bad_usage(argv[0], 0);
	return -1;
   }

   if (!copt) {
       if (!(home = getenv("HOME"))) {
          fprintf(stderr, "error: $HOME not set\n");
          return TRUE;
       }
       snprintf(chanfile, sizeof(chanfile),
		"%s/.szap/%i/%s", home, adapter, CHANNEL_FILE);
       if (access(chanfile, R_OK))
		snprintf(chanfile, sizeof(chanfile),
			 "%s/.szap/%s", home, CHANNEL_FILE);
   }

   printf("reading channels from file '%s'\n", chanfile);

   if (rec_psi)
      dvr=1;

   if (!read_channels(chanfile, list_channels, chan_no, chan_name,
	    adapter, frontend, demux, dvr, rec_psi, bypass))
      return TRUE;

   return FALSE;
}
--- tzap-hg.c	2007-07-19 01:55:48.000000000 +0200
+++ tzap.c	2007-07-18 05:52:29.000000000 +0200
@@ -40,6 +40,7 @@
 static char DVR_DEV [80];
 static int timeout_flag=0;
 static int silent=0,timeout=0;
+static int decread=0;
 static int exit_after_tuning;
 
 #define CHANNEL_FILE "channels.conf"
@@ -428,9 +429,18 @@
 	ioctl(fe_fd, FE_READ_BER, &ber);
 	ioctl(fe_fd, FE_READ_UNCORRECTED_BLOCKS, &uncorrected_blocks);
 
-	fprintf (stderr,"status %02x | signal %04x | snr %04x | "
+	if(decread==1)
+		{
+		fprintf (stderr,"status %d | signal %d | snr %d | "
+		"ber %d | unc %d | ",
+		status, _signal, snr, ber, uncorrected_blocks);
+		}
+	else
+		{
+		fprintf (stderr,"status %02x | signal %04x | snr %04x | "
 		"ber %08x | unc %08x | ",
 		status, _signal, snr, ber, uncorrected_blocks);
+		}
 
 	if (status & FE_HAS_LOCK)
 		fprintf(stderr,"FE_HAS_LOCK");
@@ -498,6 +508,7 @@
     "     -r        : set up /dev/dvb/adapterX/dvr0 for TS recording\n"
     "     -s        : only print summary\n"
     "     -S        : run silently (no output)\n"
+    "     -D        : Show status with decimal numbers instead of hex\n"
     "     -F        : set up frontend only, don't touch demux\n"
     "     -t number : timeout (seconds)\n"
     "     -o file   : output filename (use -o - for stdout)\n"
@@ -518,7 +529,7 @@
 	int frontend_only = 0;
 	char *filename = NULL;
 
-	while ((opt = getopt(argc, argv, "?hrxRsFSn:a:f:d:c:t:o:")) != -1) {
+	while ((opt = getopt(argc, argv, "?DhrxRsFSn:a:f:d:c:t:o:")) != -1) {
 		switch (opt) {
 		case 'a':
 			adapter = strtoul(optarg, NULL, 0);
@@ -554,6 +565,9 @@
 		case 'F':
 			frontend_only = 1;
 			break;
+		case 'D':
+			decread = 1; /* alternative status readings (decimal instead of hex) */
+			break;
 		case '?':
 		case 'h':
 		default:
/* tzap -- DVB-T zapping utility
 */

/*
 * Added recording to a file
 * arguments:
 *
 * -t	timeout (seconds)
 * -o filename		output filename (use -o - for stdout)
 * -s	only print summary
 * -S	run silently (no output)
 *
 * Bernard Hatt 24/2/04
 */



#define _FILE_OFFSET_BITS 64
#define _LARGEFILE_SOURCE 1
#define _LARGEFILE64_SOURCE 1

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include <fcntl.h>
#include <ctype.h>
#include <errno.h>
#include <signal.h>

#include <linux/dvb/frontend.h>
#include <linux/dvb/dmx.h>

static char FRONTEND_DEV [80];
static char DEMUX_DEV [80];
static char DVR_DEV [80];
static int timeout_flag=0;
static int silent=0,timeout=0;
static int decread=0;
static int exit_after_tuning;

#define CHANNEL_FILE "channels.conf"

#define ERROR(x...)                                                     \
        do {                                                            \
                fprintf(stderr, "ERROR: ");                             \
                fprintf(stderr, x);                                     \
                fprintf (stderr, "\n");                                 \
        } while (0)

#define PERROR(x...)                                                    \
        do {                                                            \
                fprintf(stderr, "ERROR: ");                             \
                fprintf(stderr, x);                                     \
                fprintf (stderr, " (%s)\n", strerror(errno));		\
        } while (0)


typedef struct {
	char *name;
	int value;
} Param;

static const Param inversion_list [] = {
	{ "INVERSION_OFF", INVERSION_OFF },
	{ "INVERSION_ON", INVERSION_ON },
	{ "INVERSION_AUTO", INVERSION_AUTO }
};

static const Param bw_list [] = {
	{ "BANDWIDTH_6_MHZ", BANDWIDTH_6_MHZ },
	{ "BANDWIDTH_7_MHZ", BANDWIDTH_7_MHZ },
	{ "BANDWIDTH_8_MHZ", BANDWIDTH_8_MHZ }
};

static const Param fec_list [] = {
	{ "FEC_1_2", FEC_1_2 },
	{ "FEC_2_3", FEC_2_3 },
	{ "FEC_3_4", FEC_3_4 },
	{ "FEC_4_5", FEC_4_5 },
	{ "FEC_5_6", FEC_5_6 },
	{ "FEC_6_7", FEC_6_7 },
	{ "FEC_7_8", FEC_7_8 },
	{ "FEC_8_9", FEC_8_9 },
	{ "FEC_AUTO", FEC_AUTO },
	{ "FEC_NONE", FEC_NONE }
};

static const Param guard_list [] = {
	{"GUARD_INTERVAL_1_16", GUARD_INTERVAL_1_16},
	{"GUARD_INTERVAL_1_32", GUARD_INTERVAL_1_32},
	{"GUARD_INTERVAL_1_4", GUARD_INTERVAL_1_4},
	{"GUARD_INTERVAL_1_8", GUARD_INTERVAL_1_8},
	{"GUARD_INTERVAL_AUTO", GUARD_INTERVAL_AUTO}
};

static const Param hierarchy_list [] = {
	{ "HIERARCHY_1", HIERARCHY_1 },
	{ "HIERARCHY_2", HIERARCHY_2 },
	{ "HIERARCHY_4", HIERARCHY_4 },
	{ "HIERARCHY_NONE", HIERARCHY_NONE },
	{ "HIERARCHY_AUTO", HIERARCHY_AUTO }
};

static const Param constellation_list [] = {
	{ "QPSK", QPSK },
	{ "QAM_128", QAM_128 },
	{ "QAM_16", QAM_16 },
	{ "QAM_256", QAM_256 },
	{ "QAM_32", QAM_32 },
	{ "QAM_64", QAM_64 },
	{ "QAM_AUTO", QAM_AUTO }
};

static const Param transmissionmode_list [] = {
	{ "TRANSMISSION_MODE_2K", TRANSMISSION_MODE_2K },
	{ "TRANSMISSION_MODE_8K", TRANSMISSION_MODE_8K },
	{ "TRANSMISSION_MODE_AUTO", TRANSMISSION_MODE_AUTO }
};

#define LIST_SIZE(x) sizeof(x)/sizeof(Param)


static
int parse_param (int fd, const Param * plist, int list_size, int *param)
{
	char c;
	int character = 0;
	int _index = 0;

	while (1) {
		if (read(fd, &c, 1) < 1)
			return -1;	/*  EOF? */

		if ((c == ':' || c == '\n')
		    && plist->name[character] == '\0')
			break;

		while (toupper(c) != plist->name[character]) {
			_index++;
			plist++;
			if (_index >= list_size)	 /*  parse error, no valid */
				return -2;	 /*  parameter name found  */
		}

		character++;
	}

	*param = plist->value;

	return 0;
}


static
int parse_int(int fd, int *val)
{
	char number[11];	/* 2^32 needs 10 digits... */
	int character = 0;

	while (1) {
		if (read(fd, &number[character], 1) < 1)
			return -1;	/*  EOF? */

		if (number[character] == ':' || number[character] == '\n') {
			number[character] = '\0';
			break;
		}

		if (!isdigit(number[character]))
			return -2;	/*  parse error, not a digit... */

		character++;

		if (character > 10)	/*  overflow, number too big */
			return -3;	/*  to fit in 32 bit */
	};

	*val = strtol(number, NULL, 10);

	return 0;
}


static
int find_channel(int fd, const char *channel)
{
	int character = 0;

	while (1) {
		char c;

		if (read(fd, &c, 1) < 1)
			return -1;	/*  EOF! */

		if ( '\n' == c ) /* start of line */
			character = 0;
		else if ( character >= 0 ) { /* we are in the namefield */

			if (c == ':' && channel[character] == '\0')
				break;

			if (toupper(c) == toupper(channel[character]))
				character++;
			else
				character = -1;
		}
	};

	return 0;
}


static
int try_parse_int(int fd, int *val, const char *pname)
{
	int err;

	err = parse_int(fd, val);

	if (err)
		ERROR("error while parsing %s (%s)", pname,
		      err == -1 ? "end of file" :
		      err == -2 ? "not a number" : "number too big");

	return err;
}


static
int try_parse_param(int fd, const Param * plist, int list_size, int *param,
		    const char *pname)
{
	int err;

	err = parse_param(fd, plist, list_size, param);

	if (err)
		ERROR("error while parsing %s (%s)", pname,
		      err == -1 ? "end of file" : "syntax error");

	return err;
}

static int check_fec(fe_code_rate_t *fec)
{
	switch (*fec)
	{
	case FEC_NONE:
		*fec = FEC_AUTO;
	case FEC_AUTO:
	case FEC_1_2:
	case FEC_2_3:
	case FEC_3_4:
	case FEC_5_6:
	case FEC_7_8:
		return 0;
	default:
		;
	}
	return 1;
}


int parse(const char *fname, const char *channel,
	  struct dvb_frontend_parameters *frontend, int *vpid, int *apid)
{
	int fd;
	int err;
	int tmp;

	if ((fd = open(fname, O_RDONLY | O_NONBLOCK)) < 0) {
		PERROR ("could not open file '%s'", fname);
		perror ("");
		return -1;
	}

	if (find_channel(fd, channel) < 0) {
		ERROR("could not find channel '%s' in channel list", channel);
		return -2;
	}

	if ((err = try_parse_int(fd, &tmp, "frequency")))
		return -3;
	frontend->frequency = tmp;

	if ((err = try_parse_param(fd,
				   inversion_list, LIST_SIZE(inversion_list),
				   &tmp, "inversion")))
		return -4;
	frontend->inversion = tmp;

	if ((err = try_parse_param(fd, bw_list, LIST_SIZE(bw_list),
				   &tmp, "bandwidth")))
		return -5;
	frontend->u.ofdm.bandwidth = tmp;

	if ((err = try_parse_param(fd, fec_list, LIST_SIZE(fec_list),
				   &tmp, "code_rate_HP")))
		return -6;
	frontend->u.ofdm.code_rate_HP = tmp;
	if (check_fec(&frontend->u.ofdm.code_rate_HP))
		return -6;

	if ((err = try_parse_param(fd, fec_list, LIST_SIZE(fec_list),
				   &tmp, "code_rate_LP")))
		return -7;
	frontend->u.ofdm.code_rate_LP = tmp;
	if (check_fec(&frontend->u.ofdm.code_rate_LP))
		return -7;

	if ((err = try_parse_param(fd, constellation_list,
				   LIST_SIZE(constellation_list),
				   &tmp, "constellation")))
		return -8;
	frontend->u.ofdm.constellation = tmp;

	if ((err = try_parse_param(fd, transmissionmode_list,
				   LIST_SIZE(transmissionmode_list),
				   &tmp, "transmission_mode")))
		return -9;
	frontend->u.ofdm.transmission_mode = tmp;

	if ((err = try_parse_param(fd, guard_list, LIST_SIZE(guard_list),
				   &tmp, "guard_interval")))
		return -10;
	frontend->u.ofdm.guard_interval = tmp;

	if ((err = try_parse_param(fd, hierarchy_list,
				   LIST_SIZE(hierarchy_list),
				   &tmp, "hierarchy_information")))
		return -11;
	frontend->u.ofdm.hierarchy_information = tmp;

	if ((err = try_parse_int(fd, vpid, "Video PID")))
		return -12;

	if ((err = try_parse_int(fd, apid, "Audio PID")))
		return -13;

	close(fd);

	return 0;
}


static
int set_pesfilter (int fd, int pid, dmx_pes_type_t type, int dvr)
{
        struct dmx_pes_filter_params pesfilter;

        if (pid <= 0 || pid >= 0x1fff)
                return 0;

        pesfilter.pid = pid;
        pesfilter.input = DMX_IN_FRONTEND;
        pesfilter.output = dvr ? DMX_OUT_TS_TAP : DMX_OUT_DECODER;
        pesfilter.pes_type = type;
        pesfilter.flags = DMX_IMMEDIATE_START;

        if (ioctl(fd, DMX_SET_PES_FILTER, &pesfilter) < 0) {
                PERROR ("ioctl(DMX_SET_PES_FILTER) for %s PID failed",
                        type == DMX_PES_AUDIO ? "Audio" :
                        type == DMX_PES_VIDEO ? "Video" : "??");
                return -1;
        }

        return 0;
}


static
int setup_frontend (int fe_fd, struct dvb_frontend_parameters *frontend)
{
	struct dvb_frontend_info fe_info;

	if (ioctl(fe_fd, FE_GET_INFO, &fe_info) < 0) {
		PERROR("ioctl FE_GET_INFO failed");
		return -1;
	}

	if (fe_info.type != FE_OFDM) {
		ERROR ("frontend device is not a OFDM (DVB-T) device");
		return -1;
	}

	if (silent<2)
		fprintf (stderr,"tuning to %i Hz\n", frontend->frequency);

	if (ioctl(fe_fd, FE_SET_FRONTEND, frontend) < 0) {
		PERROR("ioctl FE_SET_FRONTEND failed");
		return -1;
	}

	return 0;
}

static void
do_timeout(int x)
{
	(void)x;
	if (timeout_flag==0)
	{
		timeout_flag=1;
		alarm(2);
		signal(SIGALRM, do_timeout);
	}
	else
	{
		/* something has gone wrong ... exit */
		exit(1);
	}
}

static void
print_frontend_stats (int fe_fd)
{
	fe_status_t status;
	uint16_t snr, _signal;
	uint32_t ber, uncorrected_blocks;

	ioctl(fe_fd, FE_READ_STATUS, &status);
	ioctl(fe_fd, FE_READ_SIGNAL_STRENGTH, &_signal);
	ioctl(fe_fd, FE_READ_SNR, &snr);
	ioctl(fe_fd, FE_READ_BER, &ber);
	ioctl(fe_fd, FE_READ_UNCORRECTED_BLOCKS, &uncorrected_blocks);

	if(decread==1)
		{
		fprintf (stderr,"status %d | signal %d | snr %d | "
		"ber %d | unc %d | ",
		status, _signal, snr, ber, uncorrected_blocks);
		}
	else
		{
		fprintf (stderr,"status %02x | signal %04x | snr %04x | "
		"ber %08x | unc %08x | ",
		status, _signal, snr, ber, uncorrected_blocks);
		}

	if (status & FE_HAS_LOCK)
		fprintf(stderr,"FE_HAS_LOCK");

	fprintf(stderr,"\n");
}

static
int check_frontend (int fe_fd)
{
	fe_status_t status;
	do {
	        ioctl(fe_fd, FE_READ_STATUS, &status);
		if (!silent)
			print_frontend_stats(fe_fd);
		if (exit_after_tuning && (status & FE_HAS_LOCK))
			break;
		usleep(1000000);
	} while (!timeout_flag);
	if (silent < 2)
		print_frontend_stats (fe_fd);

	return 0;
}

#define BUFLEN (188*256)
static
void copy_to_file(int in_fd, int out_fd)
{
	char buf[BUFLEN];
	int r;
	long long int rc = 0LL;
	while(timeout_flag==0)
	{
		r=read(in_fd,buf,BUFLEN);
		if (r < 0) {
			if (errno == EOVERFLOW) {
				printf("buffer overrun\n");
				continue;
			}
			PERROR("Read failed");
			break;
		}
		if (write(out_fd,buf,r) < 0) {
			PERROR("Write failed");
			break;
		}
		rc+=r;
	}
	if (silent<2)
	{
		fprintf(stderr, "copied %lld bytes (%lld Kbytes/sec)\n",rc,rc/(1024*timeout));
	}
}

static char *usage =
    "usage:\n"
    "       tzap [options] <channel_name>\n"
    "         zap to channel channel_name (case insensitive)\n"
    "     -a number : use given adapter (default 0)\n"
    "     -f number : use given frontend (default 0)\n"
    "     -d number : use given demux (default 0)\n"
    "     -c file   : read channels list from 'file'\n"
    "     -x        : exit after tuning\n"
    "     -r        : set up /dev/dvb/adapterX/dvr0 for TS recording\n"
    "     -s        : only print summary\n"
    "     -S        : run silently (no output)\n"
    "     -D        : Show status with decimal numbers instead of hex\n"
    "     -F        : set up frontend only, don't touch demux\n"
    "     -t number : timeout (seconds)\n"
    "     -o file   : output filename (use -o - for stdout)\n"
    "     -h -?     : display this help and exit\n";


int main(int argc, char **argv)
{
	struct dvb_frontend_parameters frontend_param;
	char *homedir = getenv ("HOME");
	char *confname = NULL;
	char *channel = NULL;
	int adapter = 0, frontend = 0, demux = 0, dvr = 0;
	int vpid, apid;
	int frontend_fd, audio_fd = 0, video_fd = 0, dvr_fd, file_fd;
	int opt;
	int record = 0;
	int frontend_only = 0;
	char *filename = NULL;

	while ((opt = getopt(argc, argv, "?DhrxRsFSn:a:f:d:c:t:o:")) != -1) {
		switch (opt) {
		case 'a':
			adapter = strtoul(optarg, NULL, 0);
			break;
		case 'f':
			frontend = strtoul(optarg, NULL, 0);
			break;
		case 'd':
			demux = strtoul(optarg, NULL, 0);
			break;
		case 't':
			timeout = strtoul(optarg, NULL, 0);
			break;
		case 'o':
			filename = strdup(optarg);
			record=1;
			/* fall through */
		case 'r':
			dvr = 1;
			break;
		case 'x':
			exit_after_tuning = 1;
			break;
		case 'c':
			confname = optarg;
			break;
		case 's':
			silent = 1;
			break;
		case 'S':
			silent = 2;
			break;
		case 'F':
			frontend_only = 1;
			break;
		case 'D':
			decread = 1; /* alternative status readings (decimal instead of hex) */
			break;
		case '?':
		case 'h':
		default:
			fprintf (stderr, usage, argv[0]);
			return -1;
		};
	}

	if (optind < argc)
		channel = argv[optind];

	if (!channel) {
		fprintf (stderr, usage, argv[0]);
		return -1;
	}

	snprintf (FRONTEND_DEV, sizeof(FRONTEND_DEV),
		  "/dev/dvb/adapter%i/frontend%i", adapter, frontend);

	snprintf (DEMUX_DEV, sizeof(DEMUX_DEV),
		  "/dev/dvb/adapter%i/demux%i", adapter, demux);

	snprintf (DVR_DEV, sizeof(DVR_DEV),
		  "/dev/dvb/adapter%i/dvr%i", adapter, demux);

	if (silent<2)
		fprintf (stderr,"using '%s' and '%s'\n", FRONTEND_DEV, DEMUX_DEV);

	if (!confname)
	{
		int len = strlen(homedir) + strlen(CHANNEL_FILE) + 18;
		if (!homedir)
			ERROR ("$HOME not set");
		confname = malloc (len);
		snprintf (confname, len, "%s/.tzap/%i/%s",
			  homedir, adapter, CHANNEL_FILE);
		if (access (confname, R_OK))
			snprintf (confname, len, "%s/.tzap/%s",
				  homedir, CHANNEL_FILE);
	}
	printf("reading channels from file '%s'\n", confname);

	memset(&frontend_param, 0, sizeof(struct dvb_frontend_parameters));

	if (parse (confname, channel, &frontend_param, &vpid, &apid))
		return -1;

	if ((frontend_fd = open(FRONTEND_DEV, O_RDWR)) < 0) {
		PERROR ("failed opening '%s'", FRONTEND_DEV);
		return -1;
	}

	if (setup_frontend (frontend_fd, &frontend_param) < 0)
		return -1;

	if (frontend_only)
		goto just_the_frontend_dude;

        if ((video_fd = open(DEMUX_DEV, O_RDWR)) < 0) {
                PERROR("failed opening '%s'", DEMUX_DEV);
                return -1;
        }

	if (silent<2)
		fprintf (stderr,"video pid 0x%04x, audio pid 0x%04x\n", vpid, apid);

	if (set_pesfilter (video_fd, vpid, DMX_PES_VIDEO, dvr) < 0)
		return -1;

	if ((audio_fd = open(DEMUX_DEV, O_RDWR)) < 0) {
                PERROR("failed opening '%s'", DEMUX_DEV);
                return -1;
        }

	if (set_pesfilter (audio_fd, apid, DMX_PES_AUDIO, dvr) < 0)
		return -1;

	signal(SIGALRM,do_timeout);
	if (timeout>0)
		alarm(timeout);


	if (record)
	{
		if (filename!=NULL)
		{
			if (strcmp(filename,"-")!=0)
			{
				file_fd = open (filename,O_WRONLY|O_LARGEFILE|O_CREAT,0644);
				if (file_fd<0)
				{
					PERROR("open of '%s' failed",filename);
					return -1;
				}
			}
			else
			{
				file_fd=1;
			}
		}
		else
		{
			PERROR("Record mode but no filename!");
			return -1;
		}

		if ((dvr_fd = open(DVR_DEV, O_RDONLY)) < 0) {
	                PERROR("failed opening '%s'", DVR_DEV);
	                return -1;
	        }
		if (ioctl(dvr_fd, DMX_SET_BUFFER_SIZE, 1024 * 1024)<0)
		{
			PERROR("DMX_SET_BUFFER_SIZE failed");
			return -1;
		}
		if (silent<2)
			print_frontend_stats (frontend_fd);

		copy_to_file(dvr_fd,file_fd);

		if (silent<2)
			print_frontend_stats (frontend_fd);
	}
	else {
just_the_frontend_dude:
		check_frontend (frontend_fd);
	}

	close (audio_fd);
	close (video_fd);
	close (frontend_fd);

	return 0;
}
_______________________________________________
linux-dvb mailing list
linux-dvb@linuxtv.org
http://www.linuxtv.org/cgi-bin/mailman/listinfo/linux-dvb

Reply via email to