]> git.gir.st - ttxd.git/blob - src/szap-s2/tzap-t2.c
update to dvb-t2 (new hardware, software)
[ttxd.git] / src / szap-s2 / tzap-t2.c
1 /* tzap-t2 -- simple zapping tool for the Linux DVB S2 API
2 *
3 * Copyright (C) 2008 Igor M. Liplianin (liplianin@me.by)
4 * Copyright (C) 2013 CrazyCat (crazycat69@narod.ru)
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <limits.h>
25 #include <string.h>
26 #include <errno.h>
27 #include <signal.h>
28 #include <sys/ioctl.h>
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <sys/poll.h>
32 #include <sys/param.h>
33 #include <fcntl.h>
34 #include <time.h>
35 #include <unistd.h>
36
37 #include <stdint.h>
38 #include <sys/time.h>
39
40 #include <linux/dvb/frontend.h>
41 #include <linux/dvb/dmx.h>
42 #include <linux/dvb/audio.h>
43 #include <linux/dvb/version.h>
44 #include "lnb.h"
45
46 #if DVB_API_VERSION < 5 || DVB_API_VERSION_MINOR < 2
47 #error szap-s2 requires Linux DVB driver API version 5.2 and newer!
48 #endif
49
50 #ifndef DTV_STREAM_ID
51 #define DTV_STREAM_ID DTV_ISDBS_TS_ID
52 #endif
53
54 #ifndef NO_STREAM_ID_FILTER
55 #define NO_STREAM_ID_FILTER (~0U)
56 #endif
57
58 #ifndef TRUE
59 #define TRUE (1==1)
60 #endif
61 #ifndef FALSE
62 #define FALSE (1==0)
63 #endif
64
65 /* location of channel list file */
66 #define CHANNEL_FILE "channels.conf"
67
68 /* one line of the szap channel file has the following format:
69 * ^name:frequency_KHz:inversion:bandwidth:coderate_hp:coderate_lp:modulation:transmission_mode:guard_interval:hierarchy:vpid:apid:service_id$
70 * one line of the VDR channel file has the following format:
71 * ^name:frequency_KHz:[bandwidth][delivery][modulation][coderate_hp][coderate_lp][transmission_mode][guard_interval][hierarchy]]plp_id]:vpid:apid:?:?:service_id:?:?:?$
72 */
73
74
75 #define FRONTENDDEVICE "/dev/dvb/adapter%d/frontend%d"
76 #define DEMUXDEVICE "/dev/dvb/adapter%d/demux%d"
77 #define AUDIODEVICE "/dev/dvb/adapter%d/audio%d"
78
79 struct t_channel_parameter_map {
80 int user_value;
81 int driver_value;
82 const char *user_string;
83 };
84 /* --- Channel Parameter Maps From VDR---*/
85
86 static struct t_channel_parameter_map inversion_values[] = {
87 { 0, INVERSION_OFF, "off" },
88 { 1, INVERSION_ON, "on" },
89 { 999, INVERSION_AUTO },
90 { -1 }
91 };
92
93 static struct t_channel_parameter_map bw_values [] = {
94 { 6, BANDWIDTH_6_MHZ, "6MHz" },
95 { 7, BANDWIDTH_7_MHZ, "7MHz" },
96 { 8, BANDWIDTH_8_MHZ, "8MHz" },
97 { 5, BANDWIDTH_6_MHZ, "5MHz" },
98 { 10, BANDWIDTH_10_MHZ, "10MHz" },
99 { 999, BANDWIDTH_AUTO, "auto" },
100 { -1 }
101 };
102
103 static struct t_channel_parameter_map coderate_values[] = {
104 { 0, FEC_NONE, "none" },
105 { 12, FEC_1_2, "1/2" },
106 { 23, FEC_2_3, "2/3" },
107 { 34, FEC_3_4, "3/4" },
108 { 35, FEC_3_5, "3/5" },
109 { 45, FEC_4_5, "4/5" },
110 { 56, FEC_5_6, "5/6" },
111 { 67, FEC_6_7, "6/7" },
112 { 78, FEC_7_8, "7/8" },
113 { 89, FEC_8_9, "8/9" },
114 { 910, FEC_9_10, "9/10" },
115 { 999, FEC_AUTO, "auto" },
116 { -1 }
117 };
118
119 static struct t_channel_parameter_map modulation_values[] = {
120 // { 0, NONE, "none" },
121 { 2, QPSK, "QPSK" },
122 { 10, VSB_8, "VSB8" },
123 { 11, VSB_16, "VSB16" },
124 { 16, QAM_16, "QAM16" },
125 { 64, QAM_64, "QAM64" },
126 { 128, QAM_128, "QAM128" },
127 { 256, QAM_256, "QAM256" },
128 { 999, QAM_16 },
129 { -1 }
130 };
131
132 static struct t_channel_parameter_map mode_values [] = {
133 { 2, TRANSMISSION_MODE_2K, "2k" },
134 { 8, TRANSMISSION_MODE_2K, "8k" },
135 { 999, TRANSMISSION_MODE_AUTO, "auto" },
136 { 4, TRANSMISSION_MODE_4K, "4k" },
137 { 1, TRANSMISSION_MODE_1K, "1k" },
138 { 16, TRANSMISSION_MODE_16K, "16k" },
139 { 32, TRANSMISSION_MODE_32K, "32k" },
140 { -1 }
141 };
142
143 static struct t_channel_parameter_map guard_values [] = {
144 { 32, GUARD_INTERVAL_1_32, "1/32" },
145 { 16, GUARD_INTERVAL_1_16, "1/16" },
146 { 8, GUARD_INTERVAL_1_8, "1/8" },
147 { 4, GUARD_INTERVAL_1_4, "1/4" },
148 { 999, GUARD_INTERVAL_AUTO, "auto" },
149 { 1128, GUARD_INTERVAL_1_128, "1/128" },
150 { 19128, GUARD_INTERVAL_19_128, "19/128" },
151 { 19256, GUARD_INTERVAL_19_256, "19/256" },
152 { -1 }
153 };
154
155 static struct t_channel_parameter_map hierarchy_values [] = {
156 { 0, HIERARCHY_NONE, "none" },
157 { 1, HIERARCHY_NONE, "1" },
158 { 2, HIERARCHY_NONE, "2" },
159 { 4, HIERARCHY_NONE, "4" },
160 { 999, HIERARCHY_NONE, "auto" },
161 { -1 }
162 };
163
164 static struct t_channel_parameter_map system_values[] = {
165 { 0, SYS_DVBT, "DVB-T" },
166 { 1, SYS_DVBT2, "DVB-T2" },
167 { -1 }
168 };
169
170 static int user_index(int value, const struct t_channel_parameter_map * map)
171 {
172 const struct t_channel_parameter_map *umap = map;
173 while (umap && umap->user_value != -1) {
174 if (umap->user_value == value)
175 return umap - map;
176 umap++;
177 }
178 return -1;
179 };
180
181 static int driver_index(int value, const struct t_channel_parameter_map *map)
182 {
183 const struct t_channel_parameter_map *umap = map;
184 while (umap && umap->user_value != -1) {
185 if (umap->driver_value == value)
186 return umap - map;
187 umap++;
188 }
189 return -1;
190 };
191
192 static int map_to_user(int value, const struct t_channel_parameter_map *map, char **string)
193 {
194 int n = driver_index(value, map);
195 if (n >= 0) {
196 if (string)
197 *string = (char *)map[n].user_string;
198 return map[n].user_value;
199 }
200 return -1;
201 }
202
203 static int map_to_driver(int value, const struct t_channel_parameter_map *map)
204 {
205 int n = user_index(value, map);
206 if (n >= 0)
207 return map[n].driver_value;
208 return -1;
209 }
210
211 static struct lnb_types_st lnb_type;
212
213 static int exit_after_tuning;
214 static int interactive;
215
216 static char *usage_str =
217 "\nusage: tzap-t2 -q\n"
218 " list known channels\n"
219 " tzap-t2 [options] {-n channel-number|channel_name}\n"
220 " zap to channel via number or full name (case insensitive)\n"
221 " -a number : use given adapter (default 0)\n"
222 " -f number : use given frontend (default 0)\n"
223 " -d number : use given demux (default 0)\n"
224 " -c file : read channels list from 'file'\n"
225 " -V : use VDR channels list file format (default zap)\n"
226 " -b : enable Audio Bypass (default no)\n"
227 " -x : exit after tuning\n"
228 " -H : human readable output\n"
229 " -D : params debug\n"
230 " -r : set up /dev/dvb/adapterX/dvr0 for TS recording\n"
231 " -i : run interactively, allowing you to type in channel names\n"
232 " -p : add pat and pmt to TS recording (implies -r)\n"
233 " or -n numbers for zapping\n"
234 " -t : add teletext to TS recording (needs -V)\n"
235 " -S : delivery system type DVB-T=0, DVB-T2=1\n"
236 " -M : modulation 2=QPSK 16=16QAM 64=64QAM 256=256QAM\n"
237 " -C : fec 0=NONE 12=1/2 23=2/3 34=3/4 35=3/5 45=4/5 56=5/6 67=6/7 89=8/9 910=9/10 999=AUTO\n"
238 " -m : physical layer pipe 0-255\n";
239
240 static int set_demux(int dmxfd, int pid, int pes_type, int dvr)
241 {
242 struct dmx_pes_filter_params pesfilter;
243
244 if (pid < 0 || pid >= 0x1fff) /* ignore this pid to allow radio services */
245 return TRUE;
246
247 if (dvr) {
248 int buffersize = 64 * 1024;
249 if (ioctl(dmxfd, DMX_SET_BUFFER_SIZE, buffersize) == -1)
250 perror("DMX_SET_BUFFER_SIZE failed");
251 }
252
253 pesfilter.pid = pid;
254 pesfilter.input = DMX_IN_FRONTEND;
255 pesfilter.output = dvr ? DMX_OUT_TS_TAP : DMX_OUT_DECODER;
256 pesfilter.pes_type = pes_type;
257 pesfilter.flags = DMX_IMMEDIATE_START;
258
259 if (ioctl(dmxfd, DMX_SET_PES_FILTER, &pesfilter) == -1) {
260 fprintf(stderr, "DMX_SET_PES_FILTER failed "
261 "(PID = 0x%04x): %d %m\n", pid, errno);
262
263 return FALSE;
264 }
265
266 return TRUE;
267 }
268
269 int get_pmt_pid(char *dmxdev, int sid)
270 {
271 int patfd, count;
272 int pmt_pid = 0;
273 int patread = 0;
274 int section_length;
275 unsigned char buft[4096];
276 unsigned char *buf = buft;
277 struct dmx_sct_filter_params f;
278
279 memset(&f, 0, sizeof(f));
280 f.pid = 0;
281 f.filter.filter[0] = 0x00;
282 f.filter.mask[0] = 0xff;
283 f.timeout = 0;
284 f.flags = DMX_IMMEDIATE_START | DMX_CHECK_CRC;
285
286 if ((patfd = open(dmxdev, O_RDWR)) < 0) {
287 perror("openening pat demux failed");
288 return -1;
289 }
290
291 if (ioctl(patfd, DMX_SET_FILTER, &f) == -1) {
292 perror("ioctl DMX_SET_FILTER failed");
293 close(patfd);
294 return -1;
295 }
296
297 while (!patread) {
298 if (((count = read(patfd, buf, sizeof(buft))) < 0) && errno == EOVERFLOW)
299 count = read(patfd, buf, sizeof(buft));
300 if (count < 0) {
301 perror("read_sections: read error");
302 close(patfd);
303 return -1;
304 }
305
306 section_length = ((buf[1] & 0x0f) << 8) | buf[2];
307 if (count != section_length + 3)
308 continue;
309
310 buf += 8;
311 section_length -= 8;
312
313 patread = 1; /* assumes one section contains the whole pat */
314 while (section_length > 0) {
315 int service_id = (buf[0] << 8) | buf[1];
316 if (service_id == sid) {
317 pmt_pid = ((buf[2] & 0x1f) << 8) | buf[3];
318 section_length = 0;
319 }
320 buf += 4;
321 section_length -= 4;
322 }
323 }
324 close(patfd);
325 return pmt_pid;
326 }
327
328 static int do_tune(int fefd, unsigned int freq, unsigned int bw, enum fe_delivery_system delsys,
329 int modulation, int fec_hp, int fec_lp, int mode, int guard, int hierarchy, int stream_id)
330 {
331 struct dvb_frontend_event ev;
332 struct dtv_property p[] = {
333 { .cmd = DTV_DELIVERY_SYSTEM, .u.data = delsys },
334 { .cmd = DTV_FREQUENCY, .u.data = freq },
335 { .cmd = DTV_BANDWIDTH_HZ, .u.data = bw },
336 { .cmd = DTV_MODULATION, .u.data = modulation },
337 { .cmd = DTV_CODE_RATE_HP, .u.data = fec_hp },
338 { .cmd = DTV_CODE_RATE_LP, .u.data = fec_lp },
339 { .cmd = DTV_INVERSION, .u.data = INVERSION_AUTO },
340 { .cmd = DTV_TRANSMISSION_MODE, .u.data = mode },
341 { .cmd = DTV_GUARD_INTERVAL, .u.data = guard },
342 { .cmd = DTV_HIERARCHY, .u.data = hierarchy },
343 { .cmd = DTV_STREAM_ID, .u.data = stream_id },
344 { .cmd = DTV_TUNE },
345 };
346 struct dtv_properties cmdseq = {
347 .num = sizeof(p)/sizeof(p[0]),
348 .props = p
349 };
350
351 /* discard stale QPSK events */
352 while (1) {
353 if (ioctl(fefd, FE_GET_EVENT, &ev) == -1)
354 break;
355 }
356
357 if ((delsys != SYS_DVBT) && (delsys != SYS_DVBT2))
358 return -EINVAL;
359
360 if ((ioctl(fefd, FE_SET_PROPERTY, &cmdseq)) == -1) {
361 perror("FE_SET_PROPERTY failed");
362 return FALSE;
363 }
364
365 return TRUE;
366 }
367
368
369 static
370 int check_frontend (int fe_fd, int dvr, int human_readable, int params_debug)
371 {
372 (void)dvr;
373 fe_status_t status;
374 uint16_t snr, signal;
375 uint32_t ber, uncorrected_blocks;
376 int timeout = 0;
377 char *field;
378 struct dtv_property p[] = {
379 { .cmd = DTV_FREQUENCY },
380 { .cmd = DTV_BANDWIDTH_HZ },
381 { .cmd = DTV_DELIVERY_SYSTEM },
382 { .cmd = DTV_MODULATION },
383 { .cmd = DTV_CODE_RATE_HP },
384 { .cmd = DTV_CODE_RATE_LP },
385 { .cmd = DTV_TRANSMISSION_MODE },
386 { .cmd = DTV_GUARD_INTERVAL },
387 { .cmd = DTV_HIERARCHY },
388 };
389 struct dtv_properties cmdseq = {
390 .num = sizeof(p)/sizeof(p[0]),
391 .props = p
392 };
393
394 do {
395 if (ioctl(fe_fd, FE_READ_STATUS, &status) == -1)
396 perror("FE_READ_STATUS failed");
397 /* some frontends might not support all these ioctls, thus we
398 * avoid printing errors
399 */
400 if (ioctl(fe_fd, FE_READ_SIGNAL_STRENGTH, &signal) == -1)
401 signal = -2;
402 if (ioctl(fe_fd, FE_READ_SNR, &snr) == -1)
403 snr = -2;
404 if (ioctl(fe_fd, FE_READ_BER, &ber) == -1)
405 ber = -2;
406 if (ioctl(fe_fd, FE_READ_UNCORRECTED_BLOCKS, &uncorrected_blocks) == -1)
407 uncorrected_blocks = -2;
408
409 if (human_readable) {
410 printf ("status %02x | signal %3u%% | snr %3u%% | ber %d | unc %d | ",
411 status, (signal * 100) / 0xffff, (snr * 100) / 0xffff, ber, uncorrected_blocks);
412 } else {
413 printf ("status %02x | signal %04x | snr %04x | ber %08x | unc %08x | ",
414 status, signal, snr, ber, uncorrected_blocks);
415 }
416 if (status & FE_HAS_LOCK)
417 printf("FE_HAS_LOCK");
418 printf("\n");
419
420 if (exit_after_tuning && ((status & FE_HAS_LOCK) || (++timeout >= 10)))
421 break;
422
423 usleep(1000000);
424 } while (1);
425
426 if ((status & FE_HAS_LOCK) == 0)
427 return 0;
428
429 if ((ioctl(fe_fd, FE_GET_PROPERTY, &cmdseq)) == -1) {
430 perror("FE_GET_PROPERTY failed");
431 return 0;
432 }
433 /* printout found parameters here */
434 if (params_debug){
435 printf("frequency %d, ", p[0].u.data);
436 printf("bandwidth %d, ", p[1].u.data);
437 printf("delivery %d, ", p[2].u.data);
438 printf("modulation %d, ", p[3].u.data);
439 printf("coderate hp %d, ", p[4].u.data);
440 printf("coderate lp %d, ", p[5].u.data);
441 printf("mode %d, ", p[6].u.data);
442 printf("guard %d, ", p[7].u.data);
443 printf("hierarchy %d", p[8].u.data);
444 } else {
445 printf("frequency %d, ",p[0].u.data);
446 field = NULL;
447 map_to_user(p[1].u.data, bw_values, &field);
448 printf("bandwidth %s, ", field);
449 field = NULL;
450 map_to_user(p[2].u.data, system_values, &field);
451 printf("delivery %s, ", field);
452 field = NULL;
453 map_to_user(p[3].u.data, modulation_values, &field);
454 printf("modulation %s, ", field);
455 field = NULL;
456 map_to_user(p[4].u.data, coderate_values, &field);
457 printf("coderate-hp %s, ", field);
458 field = NULL;
459 map_to_user(p[5].u.data, coderate_values, &field);
460 printf("coderate-lp %s, ", field);
461 field = NULL;
462 map_to_user(p[6].u.data, mode_values, &field);
463 printf("mode %s, ", field);
464 field = NULL;
465 map_to_user(p[7].u.data, guard_values, &field);
466 printf("guard %s, ", field);
467 field = NULL;
468 map_to_user(p[8].u.data, hierarchy_values, &field);
469 printf("hierarchy %s", field);
470 }
471
472 printf("\n");
473
474 return 0;
475 }
476
477 static
478 int zap_to(unsigned int adapter, unsigned int frontend, unsigned int demux,
479 unsigned int freq, unsigned int bw,
480 unsigned int vpid, unsigned int apid,
481 unsigned int tpid, int sid,
482 int dvr, int rec_psi, int bypass, unsigned int delivery,
483 int modulation, int fec_hp, int fec_lp, int mode, int guard, int hierarchy, int stream_id, int human_readable,
484 int params_debug)
485 {
486 struct dtv_property p[] = {
487 { .cmd = DTV_CLEAR },
488 };
489
490 struct dtv_properties cmdseq = {
491 .num = sizeof(p)/sizeof(p[0]),
492 .props = p
493 };
494
495 char fedev[128], dmxdev[128], auddev[128];
496 static int fefd, dmxfda, dmxfdv, dmxfdt = -1, audiofd = -1, patfd, pmtfd;
497 int pmtpid;
498 int result;
499
500 if (!fefd) {
501 snprintf(fedev, sizeof(fedev), FRONTENDDEVICE, adapter, frontend);
502 snprintf(dmxdev, sizeof(dmxdev), DEMUXDEVICE, adapter, demux);
503 snprintf(auddev, sizeof(auddev), AUDIODEVICE, adapter, demux);
504 printf("using '%s' and '%s'\n", fedev, dmxdev);
505
506 if ((fefd = open(fedev, O_RDWR | O_NONBLOCK)) < 0) {
507 perror("opening frontend failed");
508 return FALSE;
509 }
510
511 if ((dmxfdv = open(dmxdev, O_RDWR)) < 0) {
512 perror("opening video demux failed");
513 close(fefd);
514 return FALSE;
515 }
516
517 if ((dmxfda = open(dmxdev, O_RDWR)) < 0) {
518 perror("opening audio demux failed");
519 close(fefd);
520 return FALSE;
521 }
522
523 if ((dmxfdt = open(dmxdev, O_RDWR)) < 0) {
524 perror("opening teletext demux failed");
525 close(fefd);
526 return FALSE;
527 }
528
529 if (dvr == 0) /* DMX_OUT_DECODER */
530 audiofd = open(auddev, O_RDWR);
531
532 if (rec_psi){
533 if ((patfd = open(dmxdev, O_RDWR)) < 0) {
534 perror("opening pat demux failed");
535 close(audiofd);
536 close(dmxfda);
537 close(dmxfdv);
538 close(dmxfdt);
539 close(fefd);
540 return FALSE;
541 }
542
543 if ((pmtfd = open(dmxdev, O_RDWR)) < 0) {
544 perror("opening pmt demux failed");
545 close(patfd);
546 close(audiofd);
547 close(dmxfda);
548 close(dmxfdv);
549 close(dmxfdt);
550 close(fefd);
551 return FALSE;
552 }
553 }
554 }
555
556
557 result = FALSE;
558
559 if ((ioctl(fefd, FE_SET_PROPERTY, &cmdseq)) == -1) {
560 perror("FE_SET_PROPERTY DTV_CLEAR failed");
561 return FALSE;
562 }
563
564 switch(bw)
565 {
566 case BANDWIDTH_5_MHZ: bw = 5000000; break;
567 case BANDWIDTH_6_MHZ: bw = 6000000; break;
568 case BANDWIDTH_7_MHZ: bw = 7000000; break;
569 case BANDWIDTH_8_MHZ: bw = 8000000; break;
570 case BANDWIDTH_10_MHZ: bw = 10000000; break;
571 case BANDWIDTH_AUTO:
572 default: bw = 0;
573 }
574
575 if (do_tune(fefd, freq, bw, delivery, modulation, fec_hp, fec_lp, mode, guard, hierarchy, stream_id))
576 if (set_demux(dmxfdv, vpid, DMX_PES_VIDEO, dvr))
577 if (audiofd >= 0)
578 (void)ioctl(audiofd, AUDIO_SET_BYPASS_MODE, bypass);
579 if (set_demux(dmxfda, apid, DMX_PES_AUDIO, dvr)) {
580 if (rec_psi) {
581 pmtpid = get_pmt_pid(dmxdev, sid);
582 if (pmtpid < 0) {
583 result = FALSE;
584 }
585 if (pmtpid == 0) {
586 fprintf(stderr,"couldn't find pmt-pid for sid %04x\n",sid);
587 result = FALSE;
588 }
589 if (set_demux(patfd, 0, DMX_PES_OTHER, dvr))
590 if (set_demux(pmtfd, pmtpid, DMX_PES_OTHER, dvr))
591 result = TRUE;
592 } else {
593 result = TRUE;
594 }
595 }
596
597 if (tpid != -1 && !set_demux(dmxfdt, tpid, DMX_PES_TELETEXT, dvr)) {
598 fprintf(stderr, "set_demux DMX_PES_TELETEXT failed\n");
599 }
600
601 check_frontend (fefd, dvr, human_readable, params_debug);
602
603 if (!interactive) {
604 close(patfd);
605 close(pmtfd);
606 if (audiofd >= 0)
607 close(audiofd);
608 close(dmxfda);
609 close(dmxfdv);
610 close(dmxfdt);
611 close(fefd);
612 }
613
614 return result;
615 }
616 static char *parse_parameter(const char *s, int *value, const struct t_channel_parameter_map *map)
617 {
618 if (*++s) {
619 char *p = NULL;
620 errno = 0;
621 int n = strtol(s, &p, 10);
622 if (!errno && p != s) {
623 value[0] = map_to_driver(n, map);
624 if (value[0] >= 0)
625 return p;
626 }
627 }
628 fprintf(stderr, "ERROR: invalid value for parameter '%C'\n", *(s - 1));
629 return NULL;
630 }
631
632 static int read_channels(const char *filename, int list_channels,
633 uint32_t chan_no, const char *chan_name,
634 unsigned int adapter, unsigned int frontend,
635 unsigned int demux, int dvr, int rec_psi,
636 int bypass, unsigned int delsys,
637 int modulation, int fec_hp, int fec_lp, int mode, int guard, int hierarchy, int stream_id, int human_readable,
638 int params_debug, int use_vdr_format, int use_tpid)
639 {
640 FILE *cfp;
641 char buf[4096];
642 char inp[256];
643 char *field, *tmp, *p;
644 unsigned int line;
645 unsigned int freq = 0, bw = 0, vpid, apid, tpid, sid;
646 int ret;
647 int trash;
648 again:
649 line = 0;
650 if (!(cfp = fopen(filename, "r"))) {
651 fprintf(stderr, "error opening channel list '%s': %d %m\n",
652 filename, errno);
653 return FALSE;
654 }
655
656 if (interactive) {
657 fprintf(stderr, "\n>>> ");
658 if (!fgets(inp, sizeof(inp), stdin)) {
659 printf("\n");
660 return -1;
661 }
662 if (inp[0] == '-' && inp[1] == 'n') {
663 chan_no = strtoul(inp+2, NULL, 0);
664 chan_name = NULL;
665 if (!chan_no) {
666 fprintf(stderr, "bad channel number\n");
667 goto again;
668 }
669 } else {
670 p = strchr(inp, '\n');
671 if (p)
672 *p = '\0';
673 chan_name = inp;
674 chan_no = 0;
675 }
676 }
677
678 while (!feof(cfp)) {
679 if (fgets(buf, sizeof(buf), cfp)) {
680 line++;
681
682 if (chan_no && chan_no != line)
683 continue;
684
685 tmp = buf;
686 field = strsep(&tmp, ":");
687
688 if (!field)
689 goto syntax_err;
690
691 if (list_channels) {
692 printf("%03u %s\n", line, field);
693 continue;
694 }
695
696 if (chan_name && strcasecmp(chan_name, field) != 0)
697 continue;
698
699 printf("zapping to %d '%s':\n", line, field);
700
701 if (!(field = strsep(&tmp, ":")))
702 goto syntax_err;
703
704 freq = strtoul(field, NULL, 0);
705
706 if (!(field = strsep(&tmp, ":")))
707 goto syntax_err;
708
709 while (field && *field) {
710 switch (toupper(*field)) {
711 case 'B':
712 field = parse_parameter(field, &bw, bw_values);
713 break;
714 case 'M':
715 if (modulation == -1)
716 field = parse_parameter(field, &modulation, modulation_values);
717 else
718 field = parse_parameter(field, &trash, modulation_values);
719 break;
720 case 'I':/* ignore */
721 field = parse_parameter(field, &ret, inversion_values);
722 break;
723 case 'C':
724 if (fec_hp == -1)
725 field = parse_parameter(field, &fec_hp, coderate_values);
726 else
727 field = parse_parameter(field, &trash, coderate_values);
728 break;
729 case 'D':
730 if (fec_lp == -1)
731 field = parse_parameter(field, &fec_lp, coderate_values);
732 else
733 field = parse_parameter(field, &trash, coderate_values);
734 break;
735 case 'T':
736 if (mode == -1)
737 field = parse_parameter(field, &mode, mode_values);
738 else
739 field = parse_parameter(field, &trash, mode_values);
740 break;
741 case 'G':
742 if (guard == -1)
743 field = parse_parameter(field, &guard, guard_values);
744 else
745 field = parse_parameter(field, &trash, guard_values);
746 break;
747 case 'Y':
748 if (hierarchy == -1)
749 field = parse_parameter(field, &hierarchy, hierarchy_values);
750 else
751 field = parse_parameter(field, &trash, hierarchy_values);
752 break;
753 case 'P':
754 stream_id = strtol(++field, &field, 10);
755 break;
756 case 'S':
757 if (delsys == -1)
758 field = parse_parameter(field, &delsys, system_values);
759 else
760 field = parse_parameter(field, &trash, system_values);
761 break;
762 default:
763 goto syntax_err;
764 }
765 }
766 /* default values for empty parameters */
767 if (modulation == -1)
768 modulation = QAM_16;
769
770 if (delsys == -1)
771 delsys = SYS_DVBT;
772
773 if (fec_hp == -1)
774 fec_hp = FEC_AUTO;
775
776 if (fec_lp == -1)
777 fec_lp = FEC_AUTO;
778
779 if (mode == -1)
780 mode = TRANSMISSION_MODE_AUTO;
781
782 if (guard == -1)
783 guard = GUARD_INTERVAL_AUTO;
784
785 if (hierarchy == -1)
786 hierarchy = HIERARCHY_NONE;
787
788 if (stream_id<0 || stream_id>255)
789 stream_id = NO_STREAM_ID_FILTER;
790
791 if (!(field = strsep(&tmp, ":")))
792 goto syntax_err;
793
794 if (!(field = strsep(&tmp, ":")))
795 goto syntax_err;
796
797 if (!(field = strsep(&tmp, ":")))
798 goto syntax_err;
799
800 vpid = strtoul(field, NULL, 0);
801 if (!vpid)
802 vpid = 0x1fff;
803
804 if (!(field = strsep(&tmp, ":")))
805 goto syntax_err;
806
807 p = strchr(field, ';');
808
809 if (p) {
810 *p = '\0';
811 p++;
812 if (bypass) {
813 if (!p || !*p)
814 goto syntax_err;
815 field = p;
816 }
817 }
818
819 apid = strtoul(field, NULL, 0);
820 if (!apid)
821 apid = 0x1fff;
822
823 tpid = -1;
824 if (use_vdr_format) {
825 if (!(field = strsep(&tmp, ":")))
826 goto syntax_err;
827
828 if (use_tpid)
829 tpid = strtoul(field, NULL, 0);
830
831 if (!(field = strsep(&tmp, ":")))
832 goto syntax_err;
833
834 strtoul(field, NULL, 0);
835 }
836
837 if (!(field = strsep(&tmp, ":")))
838 goto syntax_err;
839
840 sid = strtoul(field, NULL, 0);
841
842 fclose(cfp);
843
844 field = NULL;
845 map_to_user(bw, bw_values, &field);
846 printf("frequency %u KHz, bandwidth %s, ",
847 freq, field);
848
849 if (params_debug){
850 printf("delivery %d, ", delsys);
851 } else {
852 field = NULL;
853 map_to_user(delsys, system_values, &field);
854 printf("delivery %s, ", field);
855 }
856
857 if (params_debug){
858 printf("modulation %d\n", modulation);
859 } else {
860 field = NULL;
861 map_to_user(modulation, modulation_values, &field);
862 printf("modulation %s\n", field);
863 }
864
865 if (params_debug){
866 printf("coderate-hp %d, ", fec_hp);
867 } else {
868 field = NULL;
869 map_to_user(fec_hp, coderate_values, &field);
870 printf("coderate-hp %s, ", field);
871 }
872
873 if (params_debug){
874 printf("coderate-lp %d, ", fec_hp);
875 } else {
876 field = NULL;
877 map_to_user(fec_lp, coderate_values, &field);
878 printf("coderate-lp %s, ", field);
879 }
880
881 if (params_debug){
882 printf("mode %d, ", mode);
883 } else {
884 field = NULL;
885 map_to_user(mode, mode_values, &field);
886 printf("mode %s, ", field);
887 }
888
889 if (params_debug){
890 printf("guard %d, ", mode);
891 } else {
892 field = NULL;
893 map_to_user(guard, guard_values, &field);
894 printf("guard %s, ", field);
895 }
896
897 if (params_debug){
898 printf("hierarchy %d, ", mode);
899 } else {
900 field = NULL;
901 map_to_user(hierarchy, hierarchy_values, &field);
902 printf("hierarchy %s, ", field);
903 }
904
905 printf("plp_id %d\n", stream_id);
906
907 printf("vpid 0x%04x, apid 0x%04x, sid 0x%04x\n", vpid, apid, sid);
908
909 ret = zap_to(adapter, frontend, demux, freq * 1000, bw,
910 vpid, apid, tpid, sid, dvr, rec_psi, bypass,
911 delsys, modulation, fec_hp, fec_lp, mode, guard, hierarchy, stream_id, human_readable,
912 params_debug);
913
914 if (interactive)
915 goto again;
916
917 if (ret)
918 return TRUE;
919
920 return FALSE;
921
922 syntax_err:
923 fprintf(stderr, "syntax error in line %u: '%s'\n", line, buf);
924 } else if (ferror(cfp)) {
925 fprintf(stderr, "error reading channel list '%s': %d %m\n",
926 filename, errno);
927 fclose(cfp);
928 return FALSE;
929 } else
930 break;
931 }
932
933 fclose(cfp);
934
935 if (!list_channels) {
936 fprintf(stderr, "channel not found\n");
937
938 if (!interactive)
939 return FALSE;
940 }
941 if (interactive)
942 goto again;
943
944 return TRUE;
945 }
946
947 static void handle_sigint(int sig)
948 {
949 fprintf(stderr, "Interrupted by SIGINT!\n");
950 exit(2);
951 }
952
953 void
954 bad_usage(char *pname)
955 {
956 fprintf (stderr, usage_str, pname);
957 }
958
959 int main(int argc, char *argv[])
960 {
961 const char *home;
962 char chanfile[2 * PATH_MAX];
963 int list_channels = 0;
964 unsigned int chan_no = 0;
965 const char *chan_name = NULL;
966 unsigned int adapter = 0, frontend = 0, demux = 0, dvr = 0, rec_psi = 0;
967 int bypass = 0;
968 int opt, copt = 0;
969 int human_readable = 0;
970 int params_debug = 0;
971 int use_vdr_format = 0;
972 int use_tpid = 0;
973
974
975 int delsys = -1;
976 int modulation = -1;
977 int fec = -1;
978 int stream_id = NO_STREAM_ID_FILTER;
979
980 while ((opt = getopt(argc, argv, "M:m:C:O:HDVhqrpn:a:f:d:S:c:l:xib")) != -1) {
981 switch (opt) {
982 case '?':
983 case 'h':
984 default:
985 bad_usage(argv[0]);
986 break;
987 case 'C':
988 parse_parameter(--optarg, &fec, coderate_values);
989 break;
990 case 'M':
991 parse_parameter(--optarg, &modulation, modulation_values);
992 break;
993 case 'm':
994 stream_id = strtol(optarg, NULL, 0);
995 break;
996 case 'S':
997 parse_parameter(--optarg, &delsys, system_values);
998 break;
999 case 'b':
1000 bypass = 1;
1001 break;
1002 case 'q':
1003 list_channels = 1;
1004 break;
1005 case 'r':
1006 dvr = 1;
1007 break;
1008 case 'n':
1009 chan_no = strtoul(optarg, NULL, 0);
1010 break;
1011 case 'a':
1012 adapter = strtoul(optarg, NULL, 0);
1013 break;
1014 case 'f':
1015 frontend = strtoul(optarg, NULL, 0);
1016 break;
1017 case 'p':
1018 rec_psi = 1;
1019 break;
1020 case 'd':
1021 demux = strtoul(optarg, NULL, 0);
1022 break;
1023 case 'c':
1024 copt = 1;
1025 strncpy(chanfile, optarg, sizeof(chanfile));
1026 break;
1027 case 'x':
1028 exit_after_tuning = 1;
1029 break;
1030 case 'H':
1031 human_readable = 1;
1032 break;
1033 case 'D':
1034 params_debug = 1;
1035 break;
1036 case 'V':
1037 use_vdr_format = 1;
1038 break;
1039 case 't':
1040 use_tpid = 1;
1041 break;
1042 case 'i':
1043 interactive = 1;
1044 exit_after_tuning = 1;
1045 }
1046 }
1047 if (optind < argc)
1048 chan_name = argv[optind];
1049 if (chan_name && chan_no) {
1050 bad_usage(argv[0]);
1051 return -1;
1052 }
1053 if (list_channels && (chan_name || chan_no)) {
1054 bad_usage(argv[0]);
1055 return -1;
1056 }
1057 if (!list_channels && !chan_name && !chan_no && !interactive) {
1058 bad_usage(argv[0]);
1059 return -1;
1060 }
1061
1062 if (!copt) {
1063 if (!(home = getenv("HOME"))) {
1064 fprintf(stderr, "error: $HOME not set\n");
1065 return TRUE;
1066 }
1067 snprintf(chanfile, sizeof(chanfile),
1068 "%s/.tzap/%i/%s", home, adapter, CHANNEL_FILE);
1069 if (access(chanfile, R_OK))
1070 snprintf(chanfile, sizeof(chanfile),
1071 "%s/.tzap/%s", home, CHANNEL_FILE);
1072 }
1073
1074 printf("reading channels from file '%s'\n", chanfile);
1075
1076 if (rec_psi)
1077 dvr=1;
1078
1079 signal(SIGINT, handle_sigint);
1080
1081 if (!read_channels(chanfile, list_channels, chan_no, chan_name,
1082 adapter, frontend, demux, dvr, rec_psi, bypass, delsys,
1083 modulation, fec, -1, -1, -1, -1, stream_id, human_readable, params_debug,
1084 use_vdr_format, use_tpid))
1085
1086 return TRUE;
1087
1088 return FALSE;
1089 }
Imprint / Impressum