diff options
Diffstat (limited to '')
-rw-r--r-- | util/scan/scan.c | 467 |
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; |