diff options
Diffstat (limited to 'util/dvbscan')
| -rw-r--r-- | util/dvbscan/Makefile | 22 | ||||
| -rw-r--r-- | util/dvbscan/dvbscan.c | 370 | ||||
| -rw-r--r-- | util/dvbscan/dvbscan.h | 136 | ||||
| -rw-r--r-- | util/dvbscan/dvbscan_atsc.c | 30 | ||||
| -rw-r--r-- | util/dvbscan/dvbscan_dvb.c | 30 | ||||
| -rw-r--r-- | util/dvbscan/dvbscan_structutils.c | 99 | 
6 files changed, 687 insertions, 0 deletions
| diff --git a/util/dvbscan/Makefile b/util/dvbscan/Makefile new file mode 100644 index 0000000..d7e5de5 --- /dev/null +++ b/util/dvbscan/Makefile @@ -0,0 +1,22 @@ +# Makefile for linuxtv.org dvb-apps/util/dvbscan + +objects  = dvbscan.o  \ +	   dvbscan_structutils.o \ +           dvbscan_dvb.o \ +           dvbscan_atsc.o + +binaries = dvbscan + +inst_bin = $(binaries) + +CPPFLAGS += -I../../lib +LDFLAGS  += -L../../lib/libdvbapi -L../../lib/libdvbcfg -L../../lib/libdvbsec -L../../lib/libucsi +LDLIBS   += -ldvbcfg -lucsi -ldvbsec -ldvbapi -lpthread + +.PHONY: all + +all: $(binaries) + +$(binaries): $(objects) + +include ../../Make.rules diff --git a/util/dvbscan/dvbscan.c b/util/dvbscan/dvbscan.c new file mode 100644 index 0000000..c6f9ea8 --- /dev/null +++ b/util/dvbscan/dvbscan.c @@ -0,0 +1,370 @@ +/* +	dvbscan utility + +	Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net) + +	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 <stdlib.h> +#include <unistd.h> +#include <stdio.h> +#include <string.h> +#include <time.h> +#include <libdvbsec/dvbsec_cfg.h> +#include <libdvbcfg/dvbcfg_scanfile.h> +#include <libdvbapi/dvbdemux.h> +#include "dvbscan.h" + + +#define OUTPUT_TYPE_RAW 		1 +#define OUTPUT_TYPE_CHANNELS 		2 +#define OUTPUT_TYPE_VDR12 		3 +#define OUTPUT_TYPE_VDR13 		4 + +#define SERVICE_FILTER_TV		1 +#define SERVICE_FILTER_RADIO		2 +#define SERVICE_FILTER_OTHER		4 +#define SERVICE_FILTER_ENCRYPTED	8 + +#define TIMEOUT_WAIT_LOCK		2 + + +// transponders we have yet to scan +static struct transponder *toscan = NULL; +static struct transponder *toscan_end = NULL; + +// transponders we have scanned +static struct transponder *scanned = NULL; +static struct transponder *scanned_end = NULL; + + +static void usage(void) +{ +	static const char *_usage = "\n" +		" dvbscan: A digital tv channel scanning utility\n" +		" Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net)\n\n" +		" usage: dvbscan <options> as follows:\n" +		" -h			help\n" +		" -adapter <id>		adapter to use (default 0)\n" +		" -frontend <id>	frontend to use (default 0)\n" +		" -demux <id>		demux to use (default 0)\n" +		" -secfile <filename>	Optional sec.conf file.\n" +		" -secid <secid>	ID of the SEC configuration to use, one of:\n" +		"			 * UNIVERSAL (default) - Europe, 10800 to 11800 MHz and 11600 to 12700 Mhz,\n" +		" 						 Dual LO, loband 9750, hiband 10600 MHz.\n" +		"			 * DBS - Expressvu, North America, 12200 to 12700 MHz, Single LO, 11250 MHz.\n" +		"			 * STANDARD - 10945 to 11450 Mhz, Single LO, 10000 Mhz.\n" +		"			 * ENHANCED - Astra, 10700 to 11700 MHz, Single LO, 9750 MHz.\n" +		"			 * C-BAND - Big Dish, 3700 to 4200 MHz, Single LO, 5150 Mhz.\n" +		"			 * C-MULTI - Big Dish - Multipoint LNBf, 3700 to 4200 MHz,\n" +		"						Dual LO, H:5150MHz, V:5750MHz.\n" +		"			 * One of the sec definitions from the secfile if supplied\n" +		" -satpos <position>	Specify DISEQC switch position for DVB-S.\n" +		" -inversion <on|off|auto> Specify inversion (default: auto).\n" +		" -uk-ordering 		Use UK DVB-T channel ordering if present.\n" +		" -timeout <secs>	Specify filter timeout to use (standard specced values will be used by default)\n" +		" -filter <filter>	Specify service filter, a comma seperated list of the following tokens:\n" +		" 			 (If no filter is supplied, all services will be output)\n" +		"			 * tv - Output TV channels\n" +		"			 * radio - Output radio channels\n" +		"			 * other - Output other channels\n" +		"			 * encrypted - Output encrypted channels\n" +		" -out raw <filename>|-	 Output in raw format to <filename> or stdout\n" +		"      channels <filename>|-  Output in channels.conf format to <filename> or stdout.\n" +		"      vdr12 <filename>|- Output in vdr 1.2.x format to <filename> or stdout.\n" +		"      vdr13 <filename>|- Output in vdr 1.3.x format to <filename> or stdout.\n" +		" <initial scan file>\n"; +	fprintf(stderr, "%s\n", _usage); + +	exit(1); +} + + +static int scan_load_callback(struct dvbcfg_scanfile *channel, void *private_data) +{ +	struct dvbfe_info *feinfo = (struct dvbfe_info *) private_data; + +	if (channel->fe_type != feinfo->type) +		return 0; + +	struct transponder *t = new_transponder(); +	append_transponder(t, &toscan, &toscan_end); +	memcpy(&t->params, &channel->fe_params, sizeof(struct dvbfe_parameters)); + +	add_frequency(t, t->params.frequency); +	t->params.frequency = 0; + +	return 0; +} + +int main(int argc, char *argv[]) +{ +	uint32_t i; +	int argpos = 1; +	int adapter_id = 0; +	int frontend_id = 0; +	int demux_id = 0; +	char *secfile = NULL; +	char *secid = NULL; +	int satpos = 0; +	enum dvbfe_spectral_inversion inversion = DVBFE_INVERSION_AUTO; +	int service_filter = -1; +	int uk_ordering = 0; +	int timeout = 5; +	int output_type = OUTPUT_TYPE_RAW; +	char *output_filename = NULL; +	char *scan_filename = NULL; +	struct dvbsec_config sec; +	int valid_sec = 0; + +	while(argpos != argc) { +		if (!strcmp(argv[argpos], "-h")) { +			usage(); +		} else if (!strcmp(argv[argpos], "-adapter")) { +			if ((argc - argpos) < 2) +				usage(); +			if (sscanf(argv[argpos+1], "%i", &adapter_id) != 1) +				usage(); +			argpos+=2; +		} else if (!strcmp(argv[argpos], "-frontend")) { +			if ((argc - argpos) < 2) +				usage(); +			if (sscanf(argv[argpos+1], "%i", &frontend_id) != 1) +				usage(); +			argpos+=2; +		} else if (!strcmp(argv[argpos], "-demux")) { +			if ((argc - argpos) < 2) +				usage(); +			if (sscanf(argv[argpos+1], "%i", &demux_id) != 1) +				usage(); +			argpos+=2; +		} else if (!strcmp(argv[argpos], "-secfile")) { +			if ((argc - argpos) < 2) +				usage(); +			secfile = argv[argpos+1]; +			argpos+=2; +		} else if (!strcmp(argv[argpos], "-secid")) { +			if ((argc - argpos) < 2) +				usage(); +			secid = argv[argpos+1]; +			argpos+=2; +		} else if (!strcmp(argv[argpos], "-satpos")) { +			if ((argc - argpos) < 2) +				usage(); +			if (sscanf(argv[argpos+1], "%i", &satpos) != 1) +				usage(); +			argpos+=2; +		} else if (!strcmp(argv[argpos], "-inversion")) { +			if ((argc - argpos) < 2) +				usage(); +			if (!strcmp(argv[argpos+1], "off")) { +				inversion = DVBFE_INVERSION_OFF; +			} else if (!strcmp(argv[argpos+1], "on")) { +				inversion = DVBFE_INVERSION_ON; +			} else if (!strcmp(argv[argpos+1], "auto")) { +				inversion = DVBFE_INVERSION_AUTO; +			} else { +				usage(); +			} +			argpos+=2; +		} else if (!strcmp(argv[argpos], "-uk-ordering")) { +			if ((argc - argpos) < 1) +				usage(); +			uk_ordering = 1; +		} else if (!strcmp(argv[argpos], "-timeout")) { +			if ((argc - argpos) < 2) +				usage(); +			if (sscanf(argv[argpos+1], "%i", &timeout) != 1) +				usage(); +			argpos+=2; +		} else if (!strcmp(argv[argpos], "-filter")) { +			if ((argc - argpos) < 2) +				usage(); +			service_filter = 0; +			if (!strstr(argv[argpos+1], "tv")) { +				service_filter |= SERVICE_FILTER_TV; +			} + 			if (!strstr(argv[argpos+1], "radio")) { +				service_filter |= SERVICE_FILTER_RADIO; + 			} +			if (!strstr(argv[argpos+1], "other")) { +				service_filter |= SERVICE_FILTER_OTHER; +			} +			if (!strstr(argv[argpos+1], "encrypted")) { +				service_filter |= SERVICE_FILTER_ENCRYPTED; +			} +			argpos+=2; +		} else if (!strcmp(argv[argpos], "-out")) { +			if ((argc - argpos) < 3) +				usage(); +			if (!strcmp(argv[argpos+1], "raw")) { +				output_type = OUTPUT_TYPE_RAW; +			} else if (!strcmp(argv[argpos+1], "channels")) { +				output_type = OUTPUT_TYPE_CHANNELS; +			} else if (!strcmp(argv[argpos+1], "vdr12")) { +				output_type = OUTPUT_TYPE_VDR12; +			} else if (!strcmp(argv[argpos+1], "vdr13")) { +				output_type = OUTPUT_TYPE_VDR13; +			} else { +				usage(); +			} +			output_filename = argv[argpos+2]; +			if (!strcmp(output_filename, "-")) +				output_filename = NULL; +		} else { +			if ((argc - argpos) != 1) +				usage(); +			scan_filename = argv[argpos]; +			argpos++; +		} +	} + +	// open the frontend & get its type +	struct dvbfe_handle *fe = dvbfe_open(adapter_id, frontend_id, 0); +	if (fe == NULL) { +		fprintf(stderr, "Failed to open frontend\n"); +		exit(1); +	} +	struct dvbfe_info feinfo; +	if (dvbfe_get_info(fe, 0, &feinfo, DVBFE_INFO_QUERYTYPE_IMMEDIATE, 0) != 0) { +		fprintf(stderr, "Failed to query frontend\n"); +		exit(1); +	} + +	// default SEC with a DVBS card +	if ((secid == NULL) && (feinfo.type == DVBFE_TYPE_DVBS)) +		secid = "UNIVERSAL"; + +	// look up SECID if one was supplied +	if (secid != NULL) { +		if (dvbsec_cfg_find(secfile, secid, &sec)) { +			fprintf(stderr, "Unable to find suitable sec/lnb configuration for channel\n"); +			exit(1); +		} +		valid_sec = 1; +	} + +	// load the initial scan file +	FILE *scan_file = fopen(scan_filename, "r"); +	if (scan_file == NULL) { +		fprintf(stderr, "Could not open scan file %s\n", scan_filename); +		exit(1); +	} +	if (dvbcfg_scanfile_parse(scan_file, scan_load_callback, &feinfo) < 0) { +		fprintf(stderr, "Could not parse scan file %s\n", scan_filename); +		exit(1); +	} +	fclose(scan_file); + +	// main scan loop +	while(toscan) { +		// get the first item on the toscan list +		struct transponder *tmp = first_transponder(&toscan, &toscan_end); + +		// have we already seen this transponder? +		if (seen_transponder(tmp, scanned)) { +			free_transponder(tmp); +			continue; +		} + +		// do we have a valid SEC configuration? +		struct dvbsec_config *psec = NULL; +		if (valid_sec) +			psec = &sec; + +		// tune it +		int tuned_ok = 0; +		for(i=0; i < tmp->frequency_count; i++) { +			tmp->params.frequency = tmp->frequencies[i]; +			if (dvbsec_set(fe, +					psec, +					tmp->polarization, +					(satpos & 0x01) ? DISEQC_SWITCH_B : DISEQC_SWITCH_A, +					(satpos & 0x02) ? DISEQC_SWITCH_B : DISEQC_SWITCH_A, +					&tmp->params, +					0)) { +				fprintf(stderr, "Failed to set frontend\n"); +				exit(1); +			} + +			// wait for lock +			time_t starttime = time(NULL); +			while((time(NULL) - starttime) < TIMEOUT_WAIT_LOCK) { +				if (dvbfe_get_info(fe, DVBFE_INFO_LOCKSTATUS, &feinfo, +				    			DVBFE_INFO_QUERYTYPE_IMMEDIATE, 0) != +					DVBFE_INFO_QUERYTYPE_IMMEDIATE) { +					fprintf(stderr, "Unable to query frontend status\n"); +					exit(1); +				} +				if (feinfo.lock) { +					tuned_ok = 1; +					break; +				} +				usleep(100000); +			} +		} +		if (!tuned_ok) { +			free_transponder(tmp); +			continue; +		} + +		// scan it +		switch(feinfo.type) { +		case DVBFE_TYPE_DVBS: +		case DVBFE_TYPE_DVBC: +		case DVBFE_TYPE_DVBT: +			dvbscan_scan_dvb(fe); +			break; + +		case DVBFE_TYPE_ATSC: +			dvbscan_scan_atsc(fe); +			break; +		} + +		// add to scanned list. +		append_transponder(tmp, &scanned, &scanned_end); +	} + +	// FIXME: output the data + +	return 0; +} + +int create_section_filter(int adapter, int demux, uint16_t pid, uint8_t table_id) +{ +	int demux_fd = -1; +	uint8_t filter[18]; +	uint8_t mask[18]; + +	// open the demuxer +	if ((demux_fd = dvbdemux_open_demux(adapter, demux, 0)) < 0) { +		return -1; +	} + +	// create a section filter +	memset(filter, 0, sizeof(filter)); +	memset(mask, 0, sizeof(mask)); +	filter[0] = table_id; +	mask[0] = 0xFF; +	if (dvbdemux_set_section_filter(demux_fd, pid, filter, mask, 1, 1)) { +		close(demux_fd); +		return -1; +	} + +	// done +	return demux_fd; +} diff --git a/util/dvbscan/dvbscan.h b/util/dvbscan/dvbscan.h new file mode 100644 index 0000000..ddf61cf --- /dev/null +++ b/util/dvbscan/dvbscan.h @@ -0,0 +1,136 @@ +/* +	dvbscan utility + +	Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net) + +	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. +*/ + +#ifndef DVBSCAN_H +#define DVBSCAN_H 1 + +#include <libdvbapi/dvbfe.h> +#include <libdvbsec/dvbsec_api.h> +#include <libucsi/types.h> + +/** + * A stream which is part of a service. + */ +struct stream +{ +	uint8_t stream_type; +	iso639lang_t language; + +	struct stream *next; +}; + +/** + * A service (programme) which is part of a transponder. + */ +struct service +{ +	/** +	 * Service identification stuff. Strings are in UTF-8. +	 */ +	uint16_t service_id; +	char *provider_name; +	char *service_name; + +	/** +	 * Pids common to the whole service. +	 */ +	uint16_t pmt_pid; +	uint16_t pcr_pid; + +	/** +	 * CA stuff. +	 */ +	uint16_t *ca_ids; +	uint32_t ca_ids_count; +	uint8_t is_scrambled; + +	/** +	 * BBC channel number (-1 if unknown). +	 */ +	int bbc_channel_number; + +	/** +	 * Streams composing this service. +	 */ +	struct stream *streams; +	struct stream *streams_end; + +	/** +	 * Next service in list. +	 */ +	struct service *next; +}; + +/** + * A collection of multiplexed services. + */ +struct transponder +{ +	/** +	 * we need to have a seperate list of frequencies since the +	 * DVB standard allows a frequency list descriptor of alternate +	 * frequencies to be supplied. +	 */ +	uint32_t *frequencies; +	uint32_t frequency_count; + +	/** +	 * The rest of the tuning parameters. +	 */ +	struct dvbfe_parameters params; + +	/** +	 * DVBS specific parameters +	 */ +	enum dvbsec_diseqc_polarization polarization; +	int oribital_position; + +	/** +	 * Numerical IDs +	 */ +	uint16_t network_id; +	uint16_t original_network_id; +	uint16_t transport_stream_id; + +	/** +	 * Services detected on this transponder. +	 */ +	struct service *services; +	struct service *services_end; + +	/** +	 * Next item in list. +	 */ +	struct transponder *next; +}; + +extern void append_transponder(struct transponder *t, struct transponder **tlist, struct transponder **tlist_end); +extern struct transponder *new_transponder(void); +extern void free_transponder(struct transponder *t); +extern int seen_transponder(struct transponder *t, struct transponder *checklist); +extern void add_frequency(struct transponder *t, uint32_t frequency); +extern struct transponder *first_transponder(struct transponder **tlist, struct transponder **tlist_end); + +extern int create_section_filter(int adapter, int demux, uint16_t pid, uint8_t table_id); +extern void dvbscan_scan_dvb(struct dvbfe_handle *fe); +extern void dvbscan_scan_atsc(struct dvbfe_handle *fe); + +#endif diff --git a/util/dvbscan/dvbscan_atsc.c b/util/dvbscan/dvbscan_atsc.c new file mode 100644 index 0000000..b346f78 --- /dev/null +++ b/util/dvbscan/dvbscan_atsc.c @@ -0,0 +1,30 @@ +/* +	dvbscan utility + +	Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net) + +	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 <stdlib.h> +#include <stdio.h> +#include <string.h> +#include "dvbscan.h" + +void dvbscan_scan_atsc(struct dvbfe_handle *fe) +{ +	// FIXME +} diff --git a/util/dvbscan/dvbscan_dvb.c b/util/dvbscan/dvbscan_dvb.c new file mode 100644 index 0000000..c76d072 --- /dev/null +++ b/util/dvbscan/dvbscan_dvb.c @@ -0,0 +1,30 @@ +/* +	dvbscan utility + +	Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net) + +	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 <stdlib.h> +#include <stdio.h> +#include <string.h> +#include "dvbscan.h" + +void dvbscan_scan_dvb(struct dvbfe_handle *fe) +{ +	// FIXME +} diff --git a/util/dvbscan/dvbscan_structutils.c b/util/dvbscan/dvbscan_structutils.c new file mode 100644 index 0000000..6fe3124 --- /dev/null +++ b/util/dvbscan/dvbscan_structutils.c @@ -0,0 +1,99 @@ +/* +	dvbscan utility + +	Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net) + +	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 <stdlib.h> +#include <stdio.h> +#include <string.h> +#include "dvbscan.h" + +void append_transponder(struct transponder *t, struct transponder **tlist, struct transponder **tlist_end) +{ +	if (*tlist_end == NULL) { +		*tlist = t; +	} else { +		(*tlist_end)->next = t; +	} +	*tlist_end = t; +	t->next = NULL; +} + +struct transponder *new_transponder(void) +{ +	struct transponder *t = (struct transponder *) malloc(sizeof(struct transponder)); +	if (t == NULL) { +		fprintf(stderr, "Out of memory\n"); +		exit(1); +	} +	memset(t, 0, sizeof(struct transponder)); + +	return t; +} + +void free_transponder(struct transponder *t) +{ +	if (t->frequencies) +		free(t->frequencies); +	// FIXME: free services +	free(t); +} + +int seen_transponder(struct transponder *t, struct transponder *checklist) +{ +	uint32_t i; + +	struct transponder *cur_check = checklist; +	while(cur_check) { +		uint32_t freq1 = cur_check->params.frequency / 2000; +		for(i=0; i < t->frequency_count; i++) { +			uint32_t freq2 = t->frequencies[i] / 2000; +			if (freq1 == freq2) { +				return 1; +			} +		} +		cur_check = cur_check->next; +	} + +	return 0; +} + +void add_frequency(struct transponder *t, uint32_t frequency) +{ +	uint32_t *tmp; + +	tmp = (uint32_t*) realloc(t->frequencies, sizeof(uint32_t) * (t->frequency_count + 1)); +	if (tmp == NULL) { +		fprintf(stderr, "Out of memory\n"); +		exit(1); +	} +	tmp[t->frequency_count++] = frequency; +	t->frequencies = tmp; +} + +struct transponder *first_transponder(struct transponder **tlist, struct transponder **tlist_end) +{ +	struct transponder *t = *tlist; + +	*tlist = t->next; +	if (*tlist == NULL) +		*tlist_end = NULL; + +	return t; +} | 
