aboutsummaryrefslogtreecommitdiffstats
path: root/util/scan/scan.c
diff options
context:
space:
mode:
Diffstat (limited to 'util/scan/scan.c')
-rw-r--r--util/scan/scan.c467
1 files changed, 416 insertions, 51 deletions
diff --git a/util/scan/scan.c b/util/scan/scan.c
index 30d77a5..350d9c9 100644
--- a/util/scan/scan.c
+++ b/util/scan/scan.c
@@ -1,4 +1,4 @@
-/**
+/*
* Simple MPEG parser to achieve network/service information.
*
* refered standards:
@@ -7,6 +7,15 @@
* ETSI TR 101 211
* ETSI ETR 211
* ITU-T H.222.0
+ *
+ * 2005-05-10 - Basic ATSC PSIP parsing support added
+ * ATSC Standard Revision B (A65/B)
+ *
+ * Thanks to Sean Device from Triveni for providing access to ATSC signals
+ * and to Kevin Fowlks for his independent ATSC scanning tool.
+ *
+ * Please contribute: It is possible that some descriptors for ATSC are
+ * not parsed yet and thus the result won't be complete.
*/
#include <stdlib.h>
@@ -22,6 +31,8 @@
#include <errno.h>
#include <signal.h>
#include <assert.h>
+#include <glob.h>
+#include <ctype.h>
#include <linux/dvb/frontend.h>
#include <linux/dvb/dmx.h>
@@ -33,6 +44,7 @@
#include "scan.h"
#include "lnb.h"
+#include "atsc_psip_section.h"
static char demux_devname[80];
@@ -47,10 +59,13 @@ static int current_tp_only;
static int get_other_nits;
static int vdr_dump_provider;
static int vdr_dump_channum;
+static int no_ATSC_PSIP;
+static int ATSC_type=1;
static int ca_select = 1;
static int serv_select = 7;
static int vdr_version = 2;
static struct lnb_types_st lnb_type;
+static int unique_anon_services;
static enum fe_spectral_inversion spectral_inversion = INVERSION_AUTO;
@@ -67,6 +82,7 @@ enum format {
OUTPUT_PIDS
};
static enum format output_format = OUTPUT_ZAP;
+static int output_format_set = 0;
enum polarisation {
@@ -123,6 +139,7 @@ struct transponder {
unsigned int scan_done : 1;
unsigned int last_tuning_failed : 1;
unsigned int other_frequency_flag : 1; /* DVB-T */
+ unsigned int wrong_frequency : 1; /* DVB-T with other_frequency_flag */
int n_other_f;
uint32_t *other_f; /* DVB-T freqeuency-list descriptor */
};
@@ -157,14 +174,16 @@ static struct transponder *current_tp;
static void dump_dvb_parameters (FILE *f, struct transponder *p);
static void setup_filter (struct section_buf* s, const char *dmx_devname,
- int pid, int tid, int run_once, int segmented, int timeout);
+ int pid, int tid, int tid_ext,
+ int run_once, int segmented, int timeout);
static void add_filter (struct section_buf *s);
+static const char * fe_type2str(fe_type_t t);
/* According to the DVB standards, the combination of network_id and
* transport_stream_id should be unique, but in real life the satellite
* operators and broadcasters don't care enough to coordinate
- * the numbering. Thus we identify TPs by frequency (scan handles only
+ * the numbering. Thus we identify TPs by frequency (dvbscan handles only
* one satellite at a time). Further complication: Different NITs on
* one satellite sometimes list the same TP with slightly different
* frequencies, so we have to search within some bandwidth.
@@ -201,6 +220,8 @@ static struct transponder *find_transponder(uint32_t frequency)
list_for_each(pos, &scanned_transponders) {
tp = list_entry(pos, struct transponder, list);
+ if (current_tp_only)
+ return tp;
if (is_same_transponder(tp->param.frequency, frequency))
return tp;
}
@@ -242,6 +263,7 @@ static struct service *alloc_service(struct transponder *tp, int service_id)
struct service *s = calloc(1, sizeof(*s));
INIT_LIST_HEAD(&s->list);
s->service_id = service_id;
+ s->transport_stream_id = tp->transport_stream_id;
list_add_tail(&s->list, &tp->services);
return s;
}
@@ -264,7 +286,7 @@ static void parse_ca_identifier_descriptor (const unsigned char *buf,
struct service *s)
{
unsigned char len = buf [1];
- int i;
+ unsigned int i;
buf += 2;
@@ -302,6 +324,8 @@ static void parse_iso639_language_descriptor (const unsigned char *buf, struct s
static void parse_network_name_descriptor (const unsigned char *buf, void *dummy)
{
+ (void)dummy;
+
unsigned char len = buf [1];
info("Network Name '%.*s'\n", len, buf + 2);
@@ -309,6 +333,8 @@ static void parse_network_name_descriptor (const unsigned char *buf, void *dummy
static void parse_terrestrial_uk_channel_number (const unsigned char *buf, void *dummy)
{
+ (void)dummy;
+
int i, n, channel_num, service_id;
struct list_head *p1, *p2;
struct transponder *t;
@@ -323,7 +349,7 @@ static void parse_terrestrial_uk_channel_number (const unsigned char *buf, void
buf += 2;
for (i = 0; i < n; i++) {
service_id = (buf[0]<<8)|(buf[1]&0xff);
- channel_num = (buf[2]&0x03<<8)|(buf[3]&0xff);
+ channel_num = ((buf[2]&0x03)<<8)|(buf[3]&0xff);
debug("Service ID 0x%x has channel number %d ", service_id, channel_num);
list_for_each(p1, &scanned_transponders) {
t = list_entry(p1, struct transponder, list);
@@ -381,7 +407,7 @@ static void parse_cable_delivery_system_descriptor (const unsigned char *buf,
t->param.inversion = spectral_inversion;
if (verbosity >= 5) {
- debug("0x%#04x/0x%#04x ", t->network_id, t->transport_stream_id);
+ debug("%#04x/%#04x ", t->network_id, t->transport_stream_id);
dump_dvb_parameters (stderr, t);
if (t->scan_done)
dprintf(5, " (done)");
@@ -413,7 +439,7 @@ static void parse_satellite_delivery_system_descriptor (const unsigned char *buf
t->we_flag = buf[8] >> 7;
if (verbosity >= 5) {
- debug("0x%#04x/0x%#04x ", t->network_id, t->transport_stream_id);
+ debug("%#04x/%#04x ", t->network_id, t->transport_stream_id);
dump_dvb_parameters (stderr, t);
if (t->scan_done)
dprintf(5, " (done)");
@@ -467,7 +493,7 @@ static void parse_terrestrial_delivery_system_descriptor (const unsigned char *b
t->other_frequency_flag = (buf[8] & 0x01);
if (verbosity >= 5) {
- debug("0x%#04x/0x%#04x ", t->network_id, t->transport_stream_id);
+ debug("%#04x/%#04x ", t->network_id, t->transport_stream_id);
dump_dvb_parameters (stderr, t);
if (t->scan_done)
dprintf(5, " (done)");
@@ -525,7 +551,7 @@ static void parse_service_descriptor (const unsigned char *buf, struct service *
/* remove control characters (FIXME: handle short/long name) */
/* FIXME: handle character set correctly (e.g. via iconv)
* c.f. EN 300 468 annex A */
- for (src = dest = s->provider_name; *src; src++)
+ for (src = dest = (unsigned char *) s->provider_name; *src; src++)
if (*src >= 0x20 && (*src < 0x80 || *src > 0x9f))
*dest++ = *src;
*dest = '\0';
@@ -549,7 +575,7 @@ static void parse_service_descriptor (const unsigned char *buf, struct service *
/* remove control characters (FIXME: handle short/long name) */
/* FIXME: handle character set correctly (e.g. via iconv)
* c.f. EN 300 468 annex A */
- for (src = dest = s->service_name; *src; src++)
+ for (src = dest = (unsigned char *) s->service_name; *src; src++)
if (*src >= 0x20 && (*src < 0x80 || *src > 0x9f))
*dest++ = *src;
*dest = '\0';
@@ -672,15 +698,15 @@ static void parse_descriptors(enum table_type t, const unsigned char *buf,
static void parse_pat(const unsigned char *buf, int section_length,
int transport_stream_id)
{
+ (void)transport_stream_id;
+
while (section_length > 0) {
struct service *s;
int service_id = (buf[0] << 8) | buf[1];
- if (service_id == 0) {
- buf += 4; /* skip nit pid entry... */
- section_length -= 4;
- continue;
- }
+ if (service_id == 0)
+ goto skip; /* nit pid entry */
+
/* SDT might have been parsed first... */
s = find_service(current_tp, service_id);
if (!s)
@@ -689,11 +715,12 @@ static void parse_pat(const unsigned char *buf, int section_length,
if (!s->priv && s->pmt_pid) {
s->priv = malloc(sizeof(struct section_buf));
setup_filter(s->priv, demux_devname,
- s->pmt_pid, 0x02, 1, 0, 5);
+ s->pmt_pid, 0x02, s->service_id, 1, 0, 5);
add_filter (s->priv);
}
+skip:
buf += 4;
section_length -= 4;
};
@@ -721,7 +748,7 @@ static void parse_pmt (const unsigned char *buf, int section_length, int service
buf += program_info_len + 4;
section_length -= program_info_len + 4;
- while (section_length > 0) {
+ while (section_length >= 5) {
int ES_info_len = ((buf[3] & 0x0f) << 8) | buf[4];
int elementary_pid = ((buf[1] & 0x1f) << 8) | buf[2];
@@ -733,6 +760,7 @@ static void parse_pmt (const unsigned char *buf, int section_length, int service
s->video_pid = elementary_pid;
break;
case 0x03:
+ case 0x81: /* Audio per ATSC A/53B [2] Annex B */
case 0x04:
moreverbose(" AUDIO : PID 0x%04x\n", elementary_pid);
if (s->audio_num < AUDIO_CHAN_MAX) {
@@ -775,8 +803,8 @@ static void parse_pmt (const unsigned char *buf, int section_length, int service
};
- tmp = msg_buf;
- tmp += sprintf(tmp, "0x%04x (%.4s)", s->audio_pid[0], s->audio_lang[0]);
+ tmp = msg_buf;
+ tmp += sprintf(tmp, "0x%04x (%.4s)", s->audio_pid[0], s->audio_lang[0]);
if (s->audio_num > AUDIO_CHAN_MAX) {
warning("more than %i audio channels: %i, truncating to %i\n",
@@ -846,16 +874,18 @@ static void parse_nit (const unsigned char *buf, int section_length, int network
section_length -= descriptors_loop_len + 6;
buf += descriptors_loop_len + 6;
- };
+ }
}
static void parse_sdt (const unsigned char *buf, int section_length,
int transport_stream_id)
{
+ (void)transport_stream_id;
+
buf += 3; /* skip original network id + reserved field */
- while (section_length > 4) {
+ while (section_length >= 5) {
int service_id = (buf[0] << 8) | buf[1];
int descriptors_loop_len = ((buf[3] & 0x0f) << 8) | buf[4];
struct service *s;
@@ -884,6 +914,159 @@ static void parse_sdt (const unsigned char *buf, int section_length,
};
}
+/* ATSC PSIP VCT */
+static void parse_atsc_service_loc_desc(struct service *s,const unsigned char *buf)
+{
+ struct ATSC_service_location_descriptor d = read_ATSC_service_location_descriptor(buf);
+ int i;
+ unsigned char *b = (unsigned char *) buf+5;
+
+ s->pcr_pid = d.PCR_PID;
+ for (i=0; i < d.number_elements; i++) {
+ struct ATSC_service_location_element e = read_ATSC_service_location_element(b);
+ switch (e.stream_type) {
+ case 0x02: /* video */
+ s->video_pid = e.elementary_PID;
+ moreverbose(" VIDEO : PID 0x%04x\n", e.elementary_PID);
+ break;
+ case 0x81: /* ATSC audio */
+ if (s->audio_num < AUDIO_CHAN_MAX) {
+ s->audio_pid[s->audio_num] = e.elementary_PID;
+ s->audio_lang[s->audio_num][0] = (e.ISO_639_language_code >> 16) & 0xff;
+ s->audio_lang[s->audio_num][1] = (e.ISO_639_language_code >> 8) & 0xff;
+ s->audio_lang[s->audio_num][2] = e.ISO_639_language_code & 0xff;
+ s->audio_num++;
+ }
+ moreverbose(" AUDIO : PID 0x%04x lang: %s\n",e.elementary_PID,s->audio_lang[s->audio_num-1]);
+
+ break;
+ default:
+ warning("unhandled stream_type: %x\n",e.stream_type);
+ break;
+ };
+ b += 6;
+ }
+}
+
+static void parse_atsc_ext_chan_name_desc(struct service *s,const unsigned char *buf)
+{
+ unsigned char *b = (unsigned char *) buf+2;
+ int i,j;
+ int num_str = b[0];
+
+ b++;
+ for (i = 0; i < num_str; i++) {
+ int num_seg = b[3];
+ b += 4; /* skip lang code */
+ for (j = 0; j < num_seg; j++) {
+ int comp_type = b[0],/* mode = b[1],*/ num_bytes = b[2];
+
+ switch (comp_type) {
+ case 0x00:
+ if (s->service_name)
+ free(s->service_name);
+ s->service_name = malloc(num_bytes * sizeof(char) + 1);
+ memcpy(s->service_name,&b[3],num_bytes);
+ s->service_name[num_bytes] = '\0';
+ break;
+ default:
+ warning("compressed strings are not supported yet\n");
+ break;
+ }
+ b += 3 + num_bytes;
+ }
+ }
+}
+
+static void parse_psip_descriptors(struct service *s,const unsigned char *buf,int len)
+{
+ unsigned char *b = (unsigned char *) buf;
+ int desc_len;
+ while (len > 0) {
+ desc_len = b[1];
+ switch (b[0]) {
+ case ATSC_SERVICE_LOCATION_DESCRIPTOR_ID:
+ parse_atsc_service_loc_desc(s,b);
+ break;
+ case ATSC_EXTENDED_CHANNEL_NAME_DESCRIPTOR_ID:
+ parse_atsc_ext_chan_name_desc(s,b);
+ break;
+ default:
+ warning("unhandled psip descriptor: %02x\n",b[0]);
+ break;
+ }
+ b += 2 + desc_len;
+ len -= 2 + desc_len;
+ }
+}
+
+static void parse_psip_vct (const unsigned char *buf, int section_length,
+ int table_id, int transport_stream_id)
+{
+ (void)section_length;
+ (void)table_id;
+ (void)transport_stream_id;
+
+/* int protocol_version = buf[0];*/
+ int num_channels_in_section = buf[1];
+ int i;
+ int pseudo_id = 0xffff;
+ unsigned char *b = (unsigned char *) buf + 2;
+
+ for (i = 0; i < num_channels_in_section; i++) {
+ struct service *s;
+ struct tvct_channel ch = read_tvct_channel(b);
+
+ switch (ch.service_type) {
+ case 0x01:
+ info("analog channels won't be put info channels.conf\n");
+ break;
+ case 0x02: /* ATSC TV */
+ case 0x03: /* ATSC Radio */
+ break;
+ case 0x04: /* ATSC Data */
+ default:
+ continue;
+ }
+
+ if (ch.program_number == 0)
+ ch.program_number = --pseudo_id;
+
+ s = find_service(current_tp, ch.program_number);
+ if (!s)
+ s = alloc_service(current_tp, ch.program_number);
+
+ if (s->service_name)
+ free(s->service_name);
+
+ s->service_name = malloc(7*sizeof(unsigned char));
+ /* TODO find a better solution to convert UTF-16 */
+ s->service_name[0] = ch.short_name0;
+ s->service_name[1] = ch.short_name1;
+ s->service_name[2] = ch.short_name2;
+ s->service_name[3] = ch.short_name3;
+ s->service_name[4] = ch.short_name4;
+ s->service_name[5] = ch.short_name5;
+ s->service_name[6] = ch.short_name6;
+
+ parse_psip_descriptors(s,&b[32],ch.descriptors_length);
+
+ s->channel_num = ch.major_channel_number << 10 | ch.minor_channel_number;
+
+ if (ch.hidden) {
+ s->running = RM_NOT_RUNNING;
+ info("service is not running, pseudo program_number.");
+ } else {
+ s->running = RM_RUNNING;
+ info("service is running.");
+ }
+
+ info(" Channel number: %d:%d. Name: '%s'\n",
+ ch.major_channel_number, ch.minor_channel_number,s->service_name);
+
+ b += 32 + ch.descriptors_length;
+ }
+}
static int get_bit (uint8_t *bitfield, int bit)
{
@@ -917,7 +1100,7 @@ static int parse_section (struct section_buf *s)
if (s->table_id != table_id)
return -1;
- section_length = (((buf[1] & 0x0f) << 8) | buf[2]) - 11;
+ section_length = ((buf[1] & 0x0f) << 8) | buf[2];
table_id_ext = (buf[3] << 8) | buf[4];
section_version_number = (buf[5] >> 1) & 0x1f;
@@ -960,7 +1143,13 @@ static int parse_section (struct section_buf *s)
s->next_seg = next_seg;
}
- buf += 8;
+ buf += 8; /* past generic table header */
+ section_length -= 5 + 4; /* header + crc */
+ if (section_length < 0) {
+ warning("truncated section (PID 0x%04x, lenght %d)",
+ s->pid, section_length + 9);
+ return 0;
+ }
if (!get_bit(s->section_done, section_number)) {
set_bit (s->section_done, section_number);
@@ -994,6 +1183,11 @@ static int parse_section (struct section_buf *s)
parse_sdt (buf, section_length, table_id_ext);
break;
+ case 0xc8:
+ case 0xc9:
+ verbose("ATSC VCT\n");
+ parse_psip_vct(buf, section_length, table_id, table_id_ext);
+ break;
default:
;
};
@@ -1054,13 +1248,14 @@ static int read_sections (struct section_buf *s)
static LIST_HEAD(running_filters);
static LIST_HEAD(waiting_filters);
static int n_running;
-#define MAX_RUNNING 32
+#define MAX_RUNNING 27
static struct pollfd poll_fds[MAX_RUNNING];
static struct section_buf* poll_section_bufs[MAX_RUNNING];
static void setup_filter (struct section_buf* s, const char *dmx_devname,
- int pid, int tid, int run_once, int segmented, int timeout)
+ int pid, int tid, int tid_ext,
+ int run_once, int segmented, int timeout)
{
memset (s, 0, sizeof(struct section_buf));
@@ -1077,7 +1272,7 @@ static void setup_filter (struct section_buf* s, const char *dmx_devname,
else
s->timeout = timeout;
- s->table_id_ext = -1;
+ s->table_id_ext = tid_ext;
s->section_version_number = -1;
INIT_LIST_HEAD (&s->list);
@@ -1129,6 +1324,12 @@ static int start_filter (struct section_buf* s)
f.filter.filter[0] = (uint8_t) s->table_id;
f.filter.mask[0] = 0xff;
}
+ if (s->table_id_ext < 0x10000 && s->table_id_ext > 0) {
+ f.filter.filter[1] = (uint8_t) ((s->table_id_ext >> 8) & 0xff);
+ f.filter.filter[2] = (uint8_t) (s->table_id_ext & 0xff);
+ f.filter.mask[1] = 0xff;
+ f.filter.mask[2] = 0xff;
+ }
f.timeout = 0;
f.flags = DMX_IMMEDIATE_START | DMX_CHECK_CRC;
@@ -1226,7 +1427,7 @@ static void read_filters (void)
static int mem_is_zero (const void *mem, int size)
{
const char *p = mem;
- unsigned long i;
+ int i;
for (i=0; i<size; i++) {
if (p[i] != 0x00)
@@ -1314,6 +1515,8 @@ static int tune_to_transponder (int frontend_fd, struct transponder *t)
t->scan_done = 1;
if (t->type != fe_info.type) {
+ warning("frontend type (%s) is not compatible with requested tuning type (%s)\n",
+ fe_type2str(fe_info.type),fe_type2str(t->type));
/* ignore cable descriptors in sat NIT and vice versa */
t->last_tuning_failed = 1;
return -1;
@@ -1329,18 +1532,32 @@ static int tune_to_transponder (int frontend_fd, struct transponder *t)
static int tune_to_next_transponder (int frontend_fd)
{
struct list_head *pos, *tmp;
- struct transponder *t;
+ struct transponder *t, *to;
+ uint32_t freq;
list_for_each_safe(pos, tmp, &new_transponders) {
t = list_entry (pos, struct transponder, list);
retry:
if (tune_to_transponder (frontend_fd, t) == 0)
return 0;
- if (t->other_frequency_flag &&
- t->other_f &&
- t->n_other_f) {
- t->param.frequency = t->other_f[t->n_other_f - 1];
+next:
+ if (t->other_frequency_flag && t->other_f && t->n_other_f) {
+ /* check if the alternate freqeuncy is really new to us */
+ freq = t->other_f[t->n_other_f - 1];
t->n_other_f--;
+ if (find_transponder(freq))
+ goto next;
+
+ /* remember tuning to the old frequency failed */
+ to = calloc(1, sizeof(*to));
+ to->param.frequency = t->param.frequency;
+ to->wrong_frequency = 1;
+ INIT_LIST_HEAD(&to->list);
+ INIT_LIST_HEAD(&to->services);
+ list_add_tail(&to->list, &scanned_transponders);
+ copy_transponder(to, t);
+
+ t->param.frequency = freq;
info("retrying with f=%d\n", t->param.frequency);
goto retry;
}
@@ -1363,6 +1580,17 @@ static int str2enum(const char *str, const struct strtab *tab, int deflt)
return deflt;
}
+static const char * enum2str(int v, const struct strtab *tab, const char *deflt)
+{
+ while (tab->str) {
+ if (v == tab->val)
+ return tab->str;
+ tab++;
+ }
+ error("invalid enum value '%d'\n", v);
+ return deflt;
+}
+
static enum fe_code_rate str2fec(const char *fec)
{
struct strtab fectab[] = {
@@ -1391,6 +1619,8 @@ static enum fe_modulation str2qam(const char *qam)
{ "QAM128", QAM_128 },
{ "QAM256", QAM_256 },
{ "AUTO", QAM_AUTO },
+ { "8VSB", VSB_8 },
+ { "16VSB", VSB_16 },
{ NULL, 0 }
};
return str2enum(qam, qamtab, QAM_AUTO);
@@ -1445,6 +1675,19 @@ static enum fe_hierarchy str2hier(const char *hier)
return str2enum(hier, hiertab, HIERARCHY_AUTO);
}
+static const char * fe_type2str(fe_type_t t)
+{
+ struct strtab typetab[] = {
+ { "QPSK", FE_QPSK,},
+ { "QAM", FE_QAM, },
+ { "OFDM", FE_OFDM,},
+ { "ATSC", FE_ATSC,},
+ { NULL, 0 }
+ };
+
+ return enum2str(t, typetab, "UNK");
+}
+
static int tune_initial (int frontend_fd, const char *initial)
{
FILE *inif;
@@ -1501,7 +1744,11 @@ static int tune_initial (int frontend_fd, const char *initial)
t->param.inversion = spectral_inversion;
t->param.u.ofdm.bandwidth = str2bandwidth(bw);
t->param.u.ofdm.code_rate_HP = str2fec(fec);
+ if (t->param.u.ofdm.code_rate_HP == FEC_NONE)
+ t->param.u.ofdm.code_rate_HP = FEC_AUTO;
t->param.u.ofdm.code_rate_LP = str2fec(fec2);
+ if (t->param.u.ofdm.code_rate_LP == FEC_NONE)
+ t->param.u.ofdm.code_rate_LP = FEC_AUTO;
t->param.u.ofdm.constellation = str2qam(qam);
t->param.u.ofdm.transmission_mode = str2mode(mode);
t->param.u.ofdm.guard_interval = str2guard(guard);
@@ -1516,7 +1763,12 @@ static int tune_initial (int frontend_fd, const char *initial)
t->param.u.ofdm.guard_interval,
t->param.u.ofdm.hierarchy_information);
}
- else
+ else if (sscanf(buf, "A %u %7s\n",
+ &f,qam) == 2) {
+ t = alloc_transponder(f);
+ t->type = FE_ATSC;
+ t->param.u.vsb.modulation = str2qam(qam);
+ } else
error("cannot parse'%s'\n", buf);
}
@@ -1526,7 +1778,33 @@ static int tune_initial (int frontend_fd, const char *initial)
}
-static void scan_tp (void)
+static void scan_tp_atsc(void)
+{
+ struct section_buf s0,s1,s2;
+
+ if (no_ATSC_PSIP) {
+ setup_filter(&s0, demux_devname, 0x00, 0x00, -1, 1, 0, 5); /* PAT */
+ add_filter(&s0);
+ } else {
+ if (ATSC_type & 0x1) {
+ setup_filter(&s0, demux_devname, 0x1ffb, 0xc8, -1, 1, 0, 5); /* terrestrial VCT */
+ add_filter(&s0);
+ }
+ if (ATSC_type & 0x2) {
+ setup_filter(&s1, demux_devname, 0x1ffb, 0xc9, -1, 1, 0, 5); /* cable VCT */
+ add_filter(&s1);
+ }
+ setup_filter(&s2, demux_devname, 0x00, 0x00, -1, 1, 0, 5); /* PAT */
+ add_filter(&s2);
+ }
+
+ do {
+ read_filters ();
+ } while (!(list_empty(&running_filters) &&
+ list_empty(&waiting_filters)));
+}
+
+static void scan_tp_dvb (void)
{
struct section_buf s0;
struct section_buf s1;
@@ -1536,21 +1814,21 @@ static void scan_tp (void)
/**
* filter timeouts > min repetition rates specified in ETR211
*/
- setup_filter (&s0, demux_devname, 0x00, 0x00, 1, 0, 5); /* PAT */
- setup_filter (&s1, demux_devname, 0x11, 0x42, 1, 0, 5); /* SDT */
+ setup_filter (&s0, demux_devname, 0x00, 0x00, -1, 1, 0, 5); /* PAT */
+ setup_filter (&s1, demux_devname, 0x11, 0x42, -1, 1, 0, 5); /* SDT */
add_filter (&s0);
add_filter (&s1);
if (!current_tp_only || output_format != OUTPUT_PIDS) {
- setup_filter (&s2, demux_devname, 0x10, 0x40, 1, 0, 15); /* NIT */
+ setup_filter (&s2, demux_devname, 0x10, 0x40, -1, 1, 0, 15); /* NIT */
add_filter (&s2);
if (get_other_nits) {
/* get NIT-others
* Note: There is more than one NIT-other: one per
* network, separated by the network_id.
*/
- setup_filter (&s3, demux_devname, 0x10, 0x41, 1, 1, 15);
+ setup_filter (&s3, demux_devname, 0x10, 0x41, -1, 1, 1, 15);
add_filter (&s3);
}
}
@@ -1561,6 +1839,22 @@ static void scan_tp (void)
list_empty(&waiting_filters)));
}
+static void scan_tp(void)
+{
+ switch(fe_info.type) {
+ case FE_QPSK:
+ case FE_QAM:
+ case FE_OFDM:
+ scan_tp_dvb();
+ break;
+ case FE_ATSC:
+ scan_tp_atsc();
+ break;
+ default:
+ break;
+ }
+}
+
static void scan_network (int frontend_fd, const char *initial)
{
if (tune_initial (frontend_fd, initial) < 0) {
@@ -1616,6 +1910,8 @@ static char sat_polarisation (struct transponder *t)
static int sat_number (struct transponder *t)
{
+ (void) t;
+
return switch_pos;
}
@@ -1626,9 +1922,12 @@ static void dump_lists (void)
struct service *s;
int n = 0, i;
char sn[20];
+ int anon_services = 0;
list_for_each(p1, &scanned_transponders) {
t = list_entry(p1, struct transponder, list);
+ if (t->wrong_frequency)
+ continue;
list_for_each(p2, &t->services) {
n++;
}
@@ -1637,13 +1936,21 @@ static void dump_lists (void)
list_for_each(p1, &scanned_transponders) {
t = list_entry(p1, struct transponder, list);
+ if (t->wrong_frequency)
+ continue;
list_for_each(p2, &t->services) {
s = list_entry(p2, struct service, list);
if (!s->service_name) {
/* not in SDT */
- snprintf(sn, sizeof(sn), "[%04x]", s->service_id);
+ if (unique_anon_services)
+ snprintf(sn, sizeof(sn), "[%03x-%04x]",
+ anon_services, s->service_id);
+ else
+ snprintf(sn, sizeof(sn), "[%04x]",
+ s->service_id);
s->service_name = strdup(sn);
+ anon_services++;
}
/* ':' is field separator in szap and vdr service lists */
for (i = 0; s->service_name[i]; i++) {
@@ -1677,7 +1984,7 @@ static void dump_lists (void)
s->video_pid,
s->pcr_pid,
s->audio_pid,
- //FIXME: s->audio_lang
+ s->audio_lang,
s->audio_num,
s->teletext_pid,
s->scrambled,
@@ -1712,8 +2019,32 @@ static void dump_lists (void)
info("Done.\n");
}
+static void show_existing_tuning_data_files(void)
+{
+#ifndef DATADIR
+#define DATADIR "/usr/local/share"
+#endif
+ static const char* prefixlist[] = { DATADIR "/dvb", "/etc/dvb",
+ DATADIR "/doc/packages/dvb", 0 };
+ unsigned int i;
+ const char **prefix;
+ fprintf(stderr, "initial tuning data files:\n");
+ for (prefix = prefixlist; *prefix; prefix++) {
+ glob_t globbuf;
+ char* globspec = malloc (strlen(*prefix)+9);
+ strcpy (globspec, *prefix); strcat (globspec, "/dvb-?/*");
+ if (! glob (globspec, 0, 0, &globbuf)) {
+ for (i=0; i < globbuf.gl_pathc; i++)
+ fprintf(stderr, " file: %s\n", globbuf.gl_pathv[i]);
+ }
+ free (globspec);
+ globfree (&globbuf);
+ }
+}
+
static void handle_sigint(int sig)
{
+ (void)sig;
error("interrupted by SIGINT, dumping partial result...\n");
dump_lists();
exit(2);
@@ -1721,7 +2052,7 @@ static void handle_sigint(int sig)
static const char *usage = "\n"
"usage: %s [options...] [-c | initial-tuning-data-file]\n"
- " scan doesn't do frequency scans, hence it needs initial\n"
+ " atsc/dvbscan doesn't do frequency scans, hence it needs initial\n"
" tuning data for at least one transponder/channel.\n"
" -c scan on currently tuned transponder only\n"
" -v verbose (repeat for more)\n"
@@ -1743,22 +2074,31 @@ static const char *usage = "\n"
" -p for vdr output format: dump provider name\n"
" -e N VDR version, default 2 for VDR-1.2.x\n"
" ANYTHING ELSE GIVES NONZERO NIT and TID\n"
+ " Vdr version 1.3.x and up implies -p.\n"
" -l lnb-type (DVB-S Only) (use -l help to print types) or \n"
" -l low[,high[,switch]] in Mhz\n"
- " -u UK DVB-T Freeview channel numbering for VDR\n";
+ " -u UK DVB-T Freeview channel numbering for VDR\n\n"
+ " -P do not use ATSC PSIP tables for scanning\n"
+ " (but only PAT and PMT) (applies for ATSC only)\n"
+ " -A N check for ATSC 1=Terrestrial [default], 2=Cable or 3=both\n"
+ " -U Uniquely name unknown services\n";
void
-bad_usage(char *pname, int prlnb)
+bad_usage(char *pname, int problem)
{
-int i;
-struct lnb_types_st *lnbp;
-char **cp;
+ int i;
+ struct lnb_types_st *lnbp;
+ char **cp;
- if (!prlnb) {
+ switch (problem) {
+ default:
+ case 0:
fprintf (stderr, usage, pname);
- } else {
+ break;
+ case 1:
i = 0;
- fprintf(stderr, "-l <lnb-type> or -l low[,high[,switch]] in Mhz\nwhere <lnb-type> is:\n");
+ fprintf(stderr, "-l <lnb-type> or -l low[,high[,switch]] in Mhz\n"
+ "where <lnb-type> is:\n");
while(NULL != (lnbp = lnb_enum(i))) {
fprintf (stderr, "%s\n", lnbp->name);
for (cp = lnbp->desc; *cp ; cp++) {
@@ -1766,6 +2106,10 @@ char **cp;
}
i++;
}
+ break;
+ case 2:
+ show_existing_tuning_data_files();
+ fprintf (stderr, usage, pname);
}
}
@@ -1778,16 +2122,22 @@ int main (int argc, char **argv)
int fe_open_mode;
const char *initial = NULL;
+ if (argc <= 1) {
+ bad_usage(argv[0], 2);
+ return -1;
+ }
+
/* start with default lnb type */
lnb_type = *lnb_enum(0);
- while ((opt = getopt(argc, argv, "5cnpa:f:d:s:o:x:e:t:i:l:vq:u")) != -1) {
+ while ((opt = getopt(argc, argv, "5cnpa:f:d:s:o:x:e:t:i:l:vquPA:U")) != -1) {
switch (opt) {
case 'a':
adapter = strtoul(optarg, NULL, 0);
break;
case 'c':
current_tp_only = 1;
- output_format = OUTPUT_PIDS;
+ if (!output_format_set)
+ output_format = OUTPUT_PIDS;
break;
case 'n':
get_other_nits = 1;
@@ -1812,6 +2162,7 @@ int main (int argc, char **argv)
bad_usage(argv[0], 0);
return -1;
}
+ output_format_set = 1;
break;
case '5':
long_timeout = 1;
@@ -1844,6 +2195,20 @@ int main (int argc, char **argv)
case 'u':
vdr_dump_channum = 1;
break;
+ case 'P':
+ no_ATSC_PSIP = 1;
+ break;
+ case 'A':
+ ATSC_type = strtoul(optarg,NULL,0);
+ if (ATSC_type == 0 || ATSC_type > 3) {
+ bad_usage(argv[0], 1);
+ return -1;
+ }
+
+ break;
+ case 'U':
+ unique_anon_services = 1;
+ break;
default:
bad_usage(argv[0], 0);
return -1;