📄 scan.c
字号:
int hiband = (p.frequency >= SWITCHFREQ); setup_switch (frontend_fd, switch_pos, t->polarisation == POLARISATION_VERTICAL ? 0 : 1, hiband); usleep(50000); if (hiband) p.frequency -= LOF_HI; else p.frequency -= LOF_LO; } if (ioctl(frontend_fd, FE_SET_FRONTEND, &p) == -1) { errorn("Setting frontend parameters failed"); return -1; } for (i = 0; i < 10; i++) { usleep (200000); if (ioctl(frontend_fd, FE_READ_STATUS, &s) == -1) { errorn("FE_READ_STATUS failed"); return -1; } verbose(">>> tuning status == 0x%02x\n", s); if (s & FE_HAS_LOCK) { t->last_tuning_failed = 0; return 0; } } warning(">>> tuning failed!!!\n"); t->last_tuning_failed = 1; return -1;}static int tune_to_transponder (int frontend_fd, struct transponder *t){ /* move TP from "new" to "scanned" list */ list_del_init(&t->list); list_add_tail(&t->list, &scanned_transponders); t->scan_done = 1; if (t->type != fe_info.type) { /* ignore cable descriptors in sat NIT and vice versa */ t->last_tuning_failed = 1; return -1; } if (__tune_to_transponder (frontend_fd, t) == 0) return 0; return __tune_to_transponder (frontend_fd, t);}static int tune_to_next_transponder (int frontend_fd){ struct list_head *pos, *tmp; struct transponder *t; 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]; t->n_other_f--; info("retrying with f=%d\n", t->param.frequency); goto retry; } } return -1;}struct strtab { const char *str; int val;};static int str2enum(const char *str, const struct strtab *tab, int deflt){ while (tab->str) { if (!strcmp(tab->str, str)) return tab->val; tab++; } error("invalid enum value '%s'\n", str); return deflt;}static enum fe_code_rate str2fec(const char *fec){ struct strtab fectab[] = { { "NONE", FEC_NONE }, { "1/2", FEC_1_2 }, { "2/3", FEC_2_3 }, { "3/4", FEC_3_4 }, { "4/5", FEC_4_5 }, { "5/6", FEC_5_6 }, { "6/7", FEC_6_7 }, { "7/8", FEC_7_8 }, { "8/9", FEC_8_9 }, { "AUTO", FEC_AUTO }, { NULL, 0 } }; return str2enum(fec, fectab, FEC_AUTO);}static enum fe_modulation str2qam(const char *qam){ struct strtab qamtab[] = { { "QPSK", QPSK }, { "QAM16", QAM_16 }, { "QAM32", QAM_32 }, { "QAM64", QAM_64 }, { "QAM128", QAM_128 }, { "QAM256", QAM_256 }, { "AUTO", QAM_AUTO }, { NULL, 0 } }; return str2enum(qam, qamtab, QAM_AUTO);}static enum fe_bandwidth str2bandwidth(const char *bw){ struct strtab bwtab[] = { { "8MHz", BANDWIDTH_8_MHZ }, { "7MHz", BANDWIDTH_7_MHZ }, { "6MHz", BANDWIDTH_6_MHZ }, { "AUTO", BANDWIDTH_AUTO }, { NULL, 0 } }; return str2enum(bw, bwtab, BANDWIDTH_AUTO);}static enum fe_transmit_mode str2mode(const char *mode){ struct strtab modetab[] = { { "2k", TRANSMISSION_MODE_2K }, { "8k", TRANSMISSION_MODE_8K }, { "AUTO", TRANSMISSION_MODE_AUTO }, { NULL, 0 } }; return str2enum(mode, modetab, TRANSMISSION_MODE_AUTO);}static enum fe_guard_interval str2guard(const char *guard){ struct strtab guardtab[] = { { "1/32", GUARD_INTERVAL_1_32 }, { "1/16", GUARD_INTERVAL_1_16 }, { "1/8", GUARD_INTERVAL_1_8 }, { "1/4", GUARD_INTERVAL_1_4 }, { "AUTO", GUARD_INTERVAL_AUTO }, { NULL, 0 } }; return str2enum(guard, guardtab, GUARD_INTERVAL_AUTO);}static enum fe_hierarchy str2hier(const char *hier){ struct strtab hiertab[] = { { "NONE", HIERARCHY_NONE }, { "1", HIERARCHY_1 }, { "2", HIERARCHY_2 }, { "4", HIERARCHY_4 }, { "AUTO", HIERARCHY_AUTO }, { NULL, 0 } }; return str2enum(hier, hiertab, HIERARCHY_AUTO);}static int tune_initial (int frontend_fd, const char *initial){ FILE *inif; unsigned int f, sr; char buf[200]; char pol[20], fec[20], qam[20], bw[20], fec2[20], mode[20], guard[20], hier[20]; struct transponder *t; inif = fopen(initial, "r"); if (!inif) { error("cannot open '%s': %d %m\n", initial, errno); return -1; } while (fgets(buf, sizeof(buf), inif)) { if (buf[0] == '#' || buf[0] == '\n') ; else if (sscanf(buf, "S %u %1[HV] %u %4s\n", &f, pol, &sr, fec) == 4) { t = alloc_transponder(f); t->type = FE_QPSK; t->polarisation = pol[0] == 'H' ? POLARISATION_HORIZONTAL : POLARISATION_VERTICAL; t->param.inversion = spectral_inversion; t->param.u.qpsk.symbol_rate = sr; t->param.u.qpsk.fec_inner = str2fec(fec); info("initial transponder %u %c %u %d\n", t->param.frequency, pol[0], sr, t->param.u.qpsk.fec_inner); } else if (sscanf(buf, "C %u %u %4s %6s\n", &f, &sr, fec, qam) == 4) { t = alloc_transponder(f); t->type = FE_QAM; t->param.inversion = spectral_inversion; t->param.u.qam.symbol_rate = sr; t->param.u.qam.fec_inner = str2fec(fec); t->param.u.qam.modulation = str2qam(qam); info("initial transponder %u %u %d %d\n", t->param.frequency, sr, t->param.u.qam.fec_inner, t->param.u.qam.modulation); } else if (sscanf(buf, "T %u %4s %4s %4s %7s %4s %4s %4s\n", &f, bw, fec, fec2, qam, mode, guard, hier) == 8) { t = alloc_transponder(f); t->type = FE_OFDM; t->param.inversion = spectral_inversion; t->param.u.ofdm.bandwidth = str2bandwidth(bw); t->param.u.ofdm.code_rate_HP = str2fec(fec); t->param.u.ofdm.code_rate_LP = str2fec(fec2); t->param.u.ofdm.constellation = str2qam(qam); t->param.u.ofdm.transmission_mode = str2mode(mode); t->param.u.ofdm.guard_interval = str2guard(guard); t->param.u.ofdm.hierarchy_information = str2hier(hier); info("initial transponder %u %d %d %d %d %d %d %d\n", t->param.frequency, t->param.u.ofdm.bandwidth, t->param.u.ofdm.code_rate_HP, t->param.u.ofdm.code_rate_LP, t->param.u.ofdm.constellation, t->param.u.ofdm.transmission_mode, t->param.u.ofdm.guard_interval, t->param.u.ofdm.hierarchy_information); } else error("cannot parse'%s'\n", buf); } fclose(inif); return tune_to_next_transponder(frontend_fd);}static void scan_tp (void){ struct section_buf s0; struct section_buf s1; struct section_buf s2; struct section_buf s3; /** * 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 */ 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 */ 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); add_filter (&s3); } } do { read_filters (); } while (!(list_empty(&running_filters) && list_empty(&waiting_filters)));}static void scan_network (int frontend_fd, const char *initial){ if (tune_initial (frontend_fd, initial) < 0) { error("initial tuning failed\n"); return; } do { scan_tp(); } while (tune_to_next_transponder(frontend_fd) == 0);}static void pids_dump_service_parameter_set(FILE *f, struct service *s){ int i; fprintf(f, "%-24.24s (0x%04x) %02x: ", s->service_name, s->service_id, s->type); if (!s->pcr_pid || (s->type > 2)) fprintf(f, " "); else if (s->pcr_pid == s->video_pid) fprintf(f, "PCR == V "); else if ((s->audio_num == 1) && (s->pcr_pid == s->audio_pid[0])) fprintf(f, "PCR == A "); else fprintf(f, "PCR 0x%04x ", s->pcr_pid); if (s->video_pid) fprintf(f, "V 0x%04x", s->video_pid); else fprintf(f, " "); if (s->audio_num) fprintf(f, " A"); for (i = 0; i < s->audio_num; i++) { fprintf(f, " 0x%04x", s->audio_pid[i]); if (s->audio_lang[i][0]) fprintf(f, " (%.3s)", s->audio_lang[i]); else if (s->audio_num == 1) fprintf(f, " "); } if (s->teletext_pid) fprintf(f, " TT 0x%04x", s->teletext_pid); if (s->ac3_pid) fprintf(f, " AC3 0x%04x", s->ac3_pid); if (s->subtitling_pid) fprintf(f, " SUB 0x%04x", s->subtitling_pid); fprintf(f, "\n");}static char sat_polarisation (struct transponder *t){ return t->polarisation == POLARISATION_VERTICAL ? 'v' : 'h';}static int sat_number (struct transponder *t){ return switch_pos;}static void dump_lists (void){ struct list_head *p1, *p2; struct transponder *t; struct service *s; int n = 0; char sn[20]; list_for_each(p1, &scanned_transponders) { t = list_entry(p1, struct transponder, list); list_for_each(p2, &t->services) { n++; } } info("dumping lists (%d services)\n", n); list_for_each(p1, &scanned_transponders) { t = list_entry(p1, struct transponder, list); 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); s->service_name = strdup(sn); } if (s->video_pid && !(serv_select & 1)) continue; /* no TV services */ if (!s->video_pid && s->audio_num && !(serv_select & 2)) continue; /* no radio services */ if (!s->video_pid && !s->audio_num && !(serv_select & 4)) continue; /* no data/other services */ if (s->scrambled && !ca_select) continue; /* FTA only */ switch (output_format) { case OUTPUT_PIDS: pids_dump_service_parameter_set (stdout, s); break; case OUTPUT_VDR: vdr_dump_service_parameter_set (stdout, s->service_name, s->provider_name, t->type, &t->param, sat_polarisation(t), s->video_pid, s->pcr_pid, s->audio_pid, //FIXME: s->audio_lang s->audio_num, s->teletext_pid, s->scrambled, //FIXME: s->subtitling_pid s->ac3_pid, s->service_id, t->network_id, s->transport_stream_id, t->orbital_pos, t->we_flag, vdr_dump_provider, ca_select, vdr_version); break; case OUTPUT_ZAP: zap_dump_service_parameter_set (stdout, s->service_name, t->type, &t->param, sat_polarisation(t), sat_number(t), s->video_pid, s->audio_pid, s->service_id); default: break; } } } info("Done.\n");}static void handle_sigint(int sig){ error("interrupted by SIGINT, dumping partial result...\n"); dump_lists(); exit(2);}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" " tuning data for at least one transponder/channel.\n" " -c scan on currently tuned transponder only\n" " -v verbose (repeat for more)\n" " -q quiet (repeat for less)\n" " -a N use DVB /dev/dvb/adapterN/\n" " -f N use DVB /dev/dvb/adapter?/frontendN\n" " -d N use DVB /dev/dvb/adapter?/demuxN\n" " -s N use DiSEqC switch position N (DVB-S only)\n" " -i N spectral inversion setting (0: off, 1: on, 2: auto [default])\n" " -n evaluate NIT-other for full network scan (slow!)\n" " -5 multiply all filter timeouts by factor 5\n" " for non-DVB-compliant section repitition rates\n" " -o fmt output format: 'zap' (default), 'vdr' or 'pids' (default with -c)\n" " -x N Conditional Axcess, (default 1)\n" " N=0 gets only FTA channels\n" " N=xxx sets ca field in vdr output to :xxx:\n" " -t N Service select, Combined bitfield parameter.\n" " 1 = TV, 2 = Radio, 4 = Other, (default 7)\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";int main (int argc, char **argv){ char frontend_devname [80]; int adapter = 0, frontend = 0, demux = 0; int opt, i; int frontend_fd; int fe_open_mode; const char *initial = NULL; while ((opt = getopt(argc, argv, "5cnpa:f:d:s:o:x:e:t:i:vq")) != -1) { switch (opt) { case 'a': adapter = strtoul(optarg, NULL, 0); break; case 'c': current_tp_only = 1; output_format = OUTPUT_PIDS; break; case 'n': get_other_nits = 1; break; case 'd': demux = strtoul(optarg, NULL, 0); break; case 'f': frontend = strtoul(optarg, NULL, 0); break; case 'p': vdr_dump_provider = 1; break; case 's': switch_pos = strtoul(optarg, NULL, 0); break; case 'o': if (strcmp(optarg, "zap") == 0) output_format = OUTPUT_ZAP; else if (strcmp(optarg, "vdr") == 0) output_format = OUTPUT_VDR; else if (strcmp(optarg, "pids") == 0) output_format = OUTPUT_PIDS; else { fprintf (stderr, usage, argv[0]); return -1; } break; case '5': long_timeout = 1; break; case 'x': ca_select = strtoul(optarg, NULL, 0); break; case 'e': vdr_version = strtoul(optarg, NULL, 0); break; case 't': serv_select = strtoul(optarg, NULL, 0); break; case 'i': spectral_inversion = strtoul(optarg, NULL, 0); break; case 'v': verbosity++; break; case 'q': if (--verbosity < 0) verbosity = 0; break; default: fprintf (stderr, usage, argv[0]); return -1; }; } if (optind < argc) initial = argv[optind]; if ((!initial && !current_tp_only) || (initial && current_tp_only) || (spectral_inversion > 2)) { fprintf (stderr, usage, argv[0]); return -1; } if (switch_pos >= 4) { fprintf (stderr, "switch position needs to be < 4!\n"); return -1; } if (initial) info("scanning %s\n", initial); snprintf (frontend_devname, sizeof(frontend_devname), "/dev/dvb/adapter%i/frontend%i", adapter, frontend); snprintf (demux_devname, sizeof(demux_devname), "/dev/dvb/adapter%i/demux%i", adapter, demux); info("using '%s' and '%s'\n", frontend_devname, demux_devname); for (i = 0; i < MAX_RUNNING; i++) poll_fds[i].fd = -1; fe_open_mode = current_tp_only ? O_RDONLY : O_RDWR; if ((frontend_fd = open (frontend_devname, fe_open_mode)) < 0) fatal("failed to open '%s': %d %m\n", frontend_devname, errno); /* determine FE type and caps */ if (ioctl(frontend_fd, FE_GET_INFO, &fe_info) == -1) fatal("FE_GET_INFO failed: %d %m\n", errno); if ((spectral_inversion == INVERSION_AUTO ) && !(fe_info.caps & FE_CAN_INVERSION_AUTO)) { info("Frontend can not do INVERSION_AUTO, trying INVERSION_OFF instead\n"); spectral_inversion = INVERSION_OFF; } signal(SIGINT, handle_sigint); if (current_tp_only) { current_tp = alloc_transponder(0); /* dummy */ /* move TP from "new" to "scanned" list */ list_del_init(¤t_tp->list); list_add_tail(¤t_tp->list, &scanned_transponders); current_tp->scan_done = 1; scan_tp (); } else scan_network (frontend_fd, initial); close (frontend_fd); dump_lists (); return 0;}static void dump_dvb_parameters (FILE *f, struct transponder *t){ switch (output_format) { case OUTPUT_PIDS: case OUTPUT_VDR: vdr_dump_dvb_parameters(f, t->type, &t->param, sat_polarisation (t), t->orbital_pos, t->we_flag); break; case OUTPUT_ZAP: zap_dump_dvb_parameters (f, t->type, &t->param, sat_polarisation (t), sat_number (t)); break; default: break; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -