]> git.gir.st - ttxd.git/blob - src/szap-s2/szap-s2.c
update to dvb-t2 (new hardware, software)
[ttxd.git] / src / szap-s2 / szap-s2.c
1 /* szap-s2 -- 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_MHz:polarization:sat_no:symbolrate:vpid:apid:service_id$
70 * one line of the VDR channel file has the following format:
71 * ^name:frequency_MHz:polarization[coderate][delivery][modulation][rolloff]:sat_no:symbolrate: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 coderate_values[] = {
94 { 0, FEC_NONE, "none" },
95 { 12, FEC_1_2, "1/2" },
96 // { 13, FEC_1_3, "1/3" },
97 // { 14, FEC_1_4, "1/4" },
98 { 23, FEC_2_3, "2/3" },
99 // { 25, FEC_2_5, "2/5" },
100 { 34, FEC_3_4, "3/4" },
101 { 35, FEC_3_5, "3/5" },
102 { 45, FEC_4_5, "4/5" },
103 { 56, FEC_5_6, "5/6" },
104 { 67, FEC_6_7, "6/7" },
105 { 78, FEC_7_8, "7/8" },
106 { 89, FEC_8_9, "8/9" },
107 { 910, FEC_9_10, "9/10" },
108 { 999, FEC_AUTO, "auto" },
109 { -1 }
110 };
111
112 static struct t_channel_parameter_map modulation_values[] = {
113 // { 0, NONE, "none" },
114 // { 4, QAM_4, "QAM4" },
115 { 16, QAM_16, "QAM16" },
116 { 32, QAM_32, "QAM32" },
117 { 64, QAM_64, "QAM64" },
118 { 128, QAM_128, "QAM128" },
119 { 256, QAM_256, "QAM256" },
120 // { 512, QAM_512, "QAM512" },
121 // {1024, QAM_1024, "QAM1024" },
122 // { 1, BPSK, "BPSK" },
123 { 2, QPSK, "QPSK" },
124 // { 3, OQPSK, "OQPSK" },
125 { 5, PSK_8, "8PSK" },
126 { 6, APSK_16, "16APSK" },
127 { 7, APSK_32, "32APSK" },
128 // { 8, OFDM, "OFDM" },
129 // { 9, COFDM, "COFDM" },
130 { 10, VSB_8, "VSB8" },
131 { 11, VSB_16, "VSB16" },
132 { 998, QAM_AUTO, "QAMAUTO" },
133 // { 999, AUTO },
134 { -1 }
135 };
136
137 static struct t_channel_parameter_map system_values[] = {
138 { 0, SYS_DVBS, "DVB-S" },
139 { 1, SYS_DVBS2, "DVB-S2" },
140 { -1 }
141 };
142
143
144 static struct t_channel_parameter_map rolloff_values[] = {
145 // { 0, ROLLOFF_AUTO, "auto"},
146 { 20, ROLLOFF_20, "0.20" },
147 { 25, ROLLOFF_25, "0.25" },
148 { 35, ROLLOFF_35, "0.35" },
149 { -1 }
150 };
151
152 static int user_index(int value, const struct t_channel_parameter_map * map)
153 {
154 const struct t_channel_parameter_map *umap = map;
155 while (umap && umap->user_value != -1) {
156 if (umap->user_value == value)
157 return umap - map;
158 umap++;
159 }
160 return -1;
161 };
162
163 static int driver_index(int value, const struct t_channel_parameter_map *map)
164 {
165 const struct t_channel_parameter_map *umap = map;
166 while (umap && umap->user_value != -1) {
167 if (umap->driver_value == value)
168 return umap - map;
169 umap++;
170 }
171 return -1;
172 };
173
174 static int map_to_user(int value, const struct t_channel_parameter_map *map, char **string)
175 {
176 int n = driver_index(value, map);
177 if (n >= 0) {
178 if (string)
179 *string = (char *)map[n].user_string;
180 return map[n].user_value;
181 }
182 return -1;
183 }
184
185 static int map_to_driver(int value, const struct t_channel_parameter_map *map)
186 {
187 int n = user_index(value, map);
188 if (n >= 0)
189 return map[n].driver_value;
190 return -1;
191 }
192
193 static struct lnb_types_st lnb_type;
194
195 static int exit_after_tuning;
196 static int interactive;
197
198 static char *usage_str =
199 "\nusage: szap-s2 -q\n"
200 " list known channels\n"
201 " szap-s2 [options] {-n channel-number|channel_name}\n"
202 " zap to channel via number or full name (case insensitive)\n"
203 " -a number : use given adapter (default 0)\n"
204 " -f number : use given frontend (default 0)\n"
205 " -d number : use given demux (default 0)\n"
206 " -c file : read channels list from 'file'\n"
207 " -V : use VDR channels list file format (default zap)\n"
208 " -b : enable Audio Bypass (default no)\n"
209 " -x : exit after tuning\n"
210 " -H : human readable output\n"
211 " -D : params debug\n"
212 " -r : set up /dev/dvb/adapterX/dvr0 for TS recording\n"
213 " -l lnb-type (DVB-S Only) (use -l help to print types) or \n"
214 " -l low[,high[,switch]] in Mhz\n"
215 " -i : run interactively, allowing you to type in channel names\n"
216 " -p : add pat and pmt to TS recording (implies -r)\n"
217 " or -n numbers for zapping\n"
218 " -t : add teletext to TS recording (needs -V)\n"
219 " -S : delivery system type DVB-S=0, DVB-S2=1\n"
220 " -M : modulation 1=BPSK 2=QPSK 5=8PSK\n"
221 " -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"
222 " -O : rolloff 35=0.35 25=0.25 20=0.20 0=UNKNOWN\n"
223 " -m : input stream 0-255\n";
224
225 static int set_demux(int dmxfd, int pid, int pes_type, int dvr)
226 {
227 struct dmx_pes_filter_params pesfilter;
228
229 if (pid < 0 || pid >= 0x1fff) /* ignore this pid to allow radio services */
230 return TRUE;
231
232 if (dvr) {
233 int buffersize = 64 * 1024;
234 if (ioctl(dmxfd, DMX_SET_BUFFER_SIZE, buffersize) == -1)
235 perror("DMX_SET_BUFFER_SIZE failed");
236 }
237
238 pesfilter.pid = pid;
239 pesfilter.input = DMX_IN_FRONTEND;
240 pesfilter.output = dvr ? DMX_OUT_TS_TAP : DMX_OUT_DECODER;
241 pesfilter.pes_type = pes_type;
242 pesfilter.flags = DMX_IMMEDIATE_START;
243
244 if (ioctl(dmxfd, DMX_SET_PES_FILTER, &pesfilter) == -1) {
245 fprintf(stderr, "DMX_SET_PES_FILTER failed "
246 "(PID = 0x%04x): %d %m\n", pid, errno);
247
248 return FALSE;
249 }
250
251 return TRUE;
252 }
253
254 int get_pmt_pid(char *dmxdev, int sid)
255 {
256 int patfd, count;
257 int pmt_pid = 0;
258 int patread = 0;
259 int section_length;
260 unsigned char buft[4096];
261 unsigned char *buf = buft;
262 struct dmx_sct_filter_params f;
263
264 memset(&f, 0, sizeof(f));
265 f.pid = 0;
266 f.filter.filter[0] = 0x00;
267 f.filter.mask[0] = 0xff;
268 f.timeout = 0;
269 f.flags = DMX_IMMEDIATE_START | DMX_CHECK_CRC;
270
271 if ((patfd = open(dmxdev, O_RDWR)) < 0) {
272 perror("openening pat demux failed");
273 return -1;
274 }
275
276 if (ioctl(patfd, DMX_SET_FILTER, &f) == -1) {
277 perror("ioctl DMX_SET_FILTER failed");
278 close(patfd);
279 return -1;
280 }
281
282 while (!patread) {
283 if (((count = read(patfd, buf, sizeof(buft))) < 0) && errno == EOVERFLOW)
284 count = read(patfd, buf, sizeof(buft));
285 if (count < 0) {
286 perror("read_sections: read error");
287 close(patfd);
288 return -1;
289 }
290
291 section_length = ((buf[1] & 0x0f) << 8) | buf[2];
292 if (count != section_length + 3)
293 continue;
294
295 buf += 8;
296 section_length -= 8;
297
298 patread = 1; /* assumes one section contains the whole pat */
299 while (section_length > 0) {
300 int service_id = (buf[0] << 8) | buf[1];
301 if (service_id == sid) {
302 pmt_pid = ((buf[2] & 0x1f) << 8) | buf[3];
303 section_length = 0;
304 }
305 buf += 4;
306 section_length -= 4;
307 }
308 }
309 close(patfd);
310 return pmt_pid;
311 }
312
313 struct diseqc_cmd {
314 struct dvb_diseqc_master_cmd cmd;
315 uint32_t wait;
316 };
317
318 void diseqc_send_msg(int fd, fe_sec_voltage_t v, struct diseqc_cmd *cmd,
319 fe_sec_tone_mode_t t, fe_sec_mini_cmd_t b)
320 {
321 if (ioctl(fd, FE_SET_TONE, SEC_TONE_OFF) == -1)
322 perror("FE_SET_TONE failed");
323 if (ioctl(fd, FE_SET_VOLTAGE, v) == -1)
324 perror("FE_SET_VOLTAGE failed");
325 usleep(15 * 1000);
326 if (ioctl(fd, FE_DISEQC_SEND_MASTER_CMD, &cmd->cmd) == -1)
327 perror("FE_DISEQC_SEND_MASTER_CMD failed");
328 usleep(cmd->wait * 1000);
329 usleep(15 * 1000);
330 if (ioctl(fd, FE_DISEQC_SEND_BURST, b) == -1)
331 perror("FE_DISEQC_SEND_BURST failed");
332 usleep(15 * 1000);
333 if (ioctl(fd, FE_SET_TONE, t) == -1)
334 perror("FE_SET_TONE failed");
335
336 }
337
338
339
340
341 /* digital satellite equipment control,
342 * specification is available from http://www.eutelsat.com/
343 */
344 static int diseqc(int secfd, int sat_no, int pol_vert, int hi_band)
345 {
346 struct diseqc_cmd cmd =
347 { {{0xe0, 0x10, 0x38, 0xf0, 0x00, 0x00}, 4}, 0 };
348
349 /**
350 * param: high nibble: reset bits, low nibble set bits,
351 * bits are: option, position, polarizaion, band
352 */
353 cmd.cmd.msg[3] =
354 0xf0 | (((sat_no * 4) & 0x0f) | (hi_band ? 1 : 0) | (pol_vert ? 0 : 2));
355
356 diseqc_send_msg(secfd, pol_vert ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18,
357 &cmd, hi_band ? SEC_TONE_ON : SEC_TONE_OFF,
358 (sat_no / 4) % 2 ? SEC_MINI_B : SEC_MINI_A);
359
360 return TRUE;
361 }
362
363 static int do_tune(int fefd, unsigned int ifreq, unsigned int sr, enum fe_delivery_system delsys,
364 int modulation, int fec, int rolloff, int stream_id)
365 {
366 struct dvb_frontend_event ev;
367 struct dtv_property p[] = {
368 { .cmd = DTV_DELIVERY_SYSTEM, .u.data = delsys },
369 { .cmd = DTV_FREQUENCY, .u.data = ifreq },
370 { .cmd = DTV_MODULATION, .u.data = modulation },
371 { .cmd = DTV_SYMBOL_RATE, .u.data = sr },
372 { .cmd = DTV_INNER_FEC, .u.data = fec },
373 { .cmd = DTV_INVERSION, .u.data = INVERSION_AUTO },
374 { .cmd = DTV_ROLLOFF, .u.data = rolloff },
375 { .cmd = DTV_PILOT, .u.data = PILOT_AUTO },
376 { .cmd = DTV_STREAM_ID, .u.data = stream_id },
377 { .cmd = DTV_TUNE },
378 };
379 struct dtv_properties cmdseq = {
380 .num = sizeof(p)/sizeof(p[0]),
381 .props = p
382 };
383
384 /* discard stale QPSK events */
385 while (1) {
386 if (ioctl(fefd, FE_GET_EVENT, &ev) == -1)
387 break;
388 }
389
390 if ((delsys != SYS_DVBS) && (delsys != SYS_DVBS2))
391 return -EINVAL;
392
393 if ((ioctl(fefd, FE_SET_PROPERTY, &cmdseq)) == -1) {
394 perror("FE_SET_PROPERTY failed");
395 return FALSE;
396 }
397
398 return TRUE;
399 }
400
401
402 static
403 int check_frontend (int fe_fd, int dvr, int human_readable, int params_debug,
404 int hiband)
405 {
406 (void)dvr;
407 fe_status_t status;
408 uint16_t snr, signal;
409 uint32_t ber, uncorrected_blocks;
410 int timeout = 0;
411 char *field;
412 struct dtv_property p[] = {
413 { .cmd = DTV_DELIVERY_SYSTEM },
414 { .cmd = DTV_MODULATION },
415 { .cmd = DTV_INNER_FEC },
416 { .cmd = DTV_ROLLOFF },
417 { .cmd = DTV_FREQUENCY },
418 { .cmd = DTV_SYMBOL_RATE },
419 };
420 struct dtv_properties cmdseq = {
421 .num = sizeof(p)/sizeof(p[0]),
422 .props = p
423 };
424
425 do {
426 if (ioctl(fe_fd, FE_READ_STATUS, &status) == -1)
427 perror("FE_READ_STATUS failed");
428 /* some frontends might not support all these ioctls, thus we
429 * avoid printing errors
430 */
431 if (ioctl(fe_fd, FE_READ_SIGNAL_STRENGTH, &signal) == -1)
432 signal = -2;
433 if (ioctl(fe_fd, FE_READ_SNR, &snr) == -1)
434 snr = -2;
435 if (ioctl(fe_fd, FE_READ_BER, &ber) == -1)
436 ber = -2;
437 if (ioctl(fe_fd, FE_READ_UNCORRECTED_BLOCKS, &uncorrected_blocks) == -1)
438 uncorrected_blocks = -2;
439
440 if (human_readable) {
441 printf ("status %02x | signal %3u%% | snr %3u%% | ber %d | unc %d | ",
442 status, (signal * 100) / 0xffff, (snr * 100) / 0xffff, ber, uncorrected_blocks);
443 } else {
444 printf ("status %02x | signal %04x | snr %04x | ber %08x | unc %08x | ",
445 status, signal, snr, ber, uncorrected_blocks);
446 }
447 if (status & FE_HAS_LOCK)
448 printf("FE_HAS_LOCK");
449 printf("\n");
450
451 if (exit_after_tuning && ((status & FE_HAS_LOCK) || (++timeout >= 10)))
452 break;
453
454 usleep(1000000);
455 } while (1);
456
457 if ((status & FE_HAS_LOCK) == 0)
458 return 0;
459
460 if ((ioctl(fe_fd, FE_GET_PROPERTY, &cmdseq)) == -1) {
461 perror("FE_GET_PROPERTY failed");
462 return 0;
463 }
464 /* printout found parameters here */
465 if (params_debug){
466 printf("delivery 0x%x, ", p[0].u.data);
467 printf("modulation 0x%x\n", p[1].u.data);
468 printf("coderate 0x%x, ", p[2].u.data);
469 printf("rolloff 0x%x\n", p[3].u.data);
470 printf("intermediate frequency %d,", p[4].u.data);
471 } else {
472 field = NULL;
473 map_to_user(p[0].u.data, system_values, &field);
474 printf("delivery %s, ", field);
475 field = NULL;
476 map_to_user(p[1].u.data, modulation_values, &field);
477 printf("modulation %s\n", field);
478 field = NULL;
479 map_to_user(p[2].u.data, coderate_values, &field);
480 printf("coderate %s, ", field);
481 field = NULL;
482 map_to_user(p[3].u.data, rolloff_values, &field);
483 printf("rolloff %s\n", field);
484 if (hiband)
485 printf("frequency %lu,",lnb_type.high_val + p[4].u.data);
486 else
487 printf("frequency %lu,",lnb_type.low_val + p[4].u.data);
488
489 }
490
491 printf("symbol_rate %d\n", p[5].u.data);
492
493 return 0;
494 }
495
496 static
497 int zap_to(unsigned int adapter, unsigned int frontend, unsigned int demux,
498 unsigned int sat_no, unsigned int freq, unsigned int pol,
499 unsigned int sr, unsigned int vpid, unsigned int apid,
500 unsigned int tpid, int sid,
501 int dvr, int rec_psi, int bypass, unsigned int delivery,
502 int modulation, int fec, int rolloff, int stream_id, int human_readable,
503 int params_debug)
504 {
505 struct dtv_property p[] = {
506 { .cmd = DTV_CLEAR },
507 };
508
509 struct dtv_properties cmdseq = {
510 .num = sizeof(p)/sizeof(p[0]),
511 .props = p
512 };
513
514 char fedev[128], dmxdev[128], auddev[128];
515 static int fefd, dmxfda, dmxfdv, dmxfdt = -1, audiofd = -1, patfd, pmtfd;
516 int pmtpid;
517 uint32_t ifreq;
518 int hiband, result;
519
520 if (!fefd) {
521 snprintf(fedev, sizeof(fedev), FRONTENDDEVICE, adapter, frontend);
522 snprintf(dmxdev, sizeof(dmxdev), DEMUXDEVICE, adapter, demux);
523 snprintf(auddev, sizeof(auddev), AUDIODEVICE, adapter, demux);
524 printf("using '%s' and '%s'\n", fedev, dmxdev);
525
526 if ((fefd = open(fedev, O_RDWR | O_NONBLOCK)) < 0) {
527 perror("opening frontend failed");
528 return FALSE;
529 }
530
531 if ((dmxfdv = open(dmxdev, O_RDWR)) < 0) {
532 perror("opening video demux failed");
533 close(fefd);
534 return FALSE;
535 }
536
537 if ((dmxfda = open(dmxdev, O_RDWR)) < 0) {
538 perror("opening audio demux failed");
539 close(fefd);
540 return FALSE;
541 }
542
543 if ((dmxfdt = open(dmxdev, O_RDWR)) < 0) {
544 perror("opening teletext demux failed");
545 close(fefd);
546 return FALSE;
547 }
548
549 if (dvr == 0) /* DMX_OUT_DECODER */
550 audiofd = open(auddev, O_RDWR);
551
552 if (rec_psi){
553 if ((patfd = open(dmxdev, O_RDWR)) < 0) {
554 perror("opening pat demux failed");
555 close(audiofd);
556 close(dmxfda);
557 close(dmxfdv);
558 close(dmxfdt);
559 close(fefd);
560 return FALSE;
561 }
562
563 if ((pmtfd = open(dmxdev, O_RDWR)) < 0) {
564 perror("opening pmt demux failed");
565 close(patfd);
566 close(audiofd);
567 close(dmxfda);
568 close(dmxfdv);
569 close(dmxfdt);
570 close(fefd);
571 return FALSE;
572 }
573 }
574 }
575
576
577 hiband = 0;
578 if (lnb_type.switch_val && lnb_type.high_val &&
579 freq >= lnb_type.switch_val)
580 hiband = 1;
581
582 if (hiband)
583 ifreq = freq - lnb_type.high_val;
584 else {
585 if (freq < lnb_type.low_val)
586 ifreq = lnb_type.low_val - freq;
587 else
588 ifreq = freq - lnb_type.low_val;
589 }
590 result = FALSE;
591
592 if ((ioctl(fefd, FE_SET_PROPERTY, &cmdseq)) == -1) {
593 perror("FE_SET_PROPERTY DTV_CLEAR failed");
594 return FALSE;
595 }
596
597 if (diseqc(fefd, sat_no, pol, hiband))
598 if (do_tune(fefd, ifreq, sr, delivery, modulation, fec, rolloff, stream_id))
599 if (set_demux(dmxfdv, vpid, DMX_PES_VIDEO, dvr))
600 if (audiofd >= 0)
601 (void)ioctl(audiofd, AUDIO_SET_BYPASS_MODE, bypass);
602 if (set_demux(dmxfda, apid, DMX_PES_AUDIO, dvr)) {
603 if (rec_psi) {
604 pmtpid = get_pmt_pid(dmxdev, sid);
605 if (pmtpid < 0) {
606 result = FALSE;
607 }
608 if (pmtpid == 0) {
609 fprintf(stderr,"couldn't find pmt-pid for sid %04x\n",sid);
610 result = FALSE;
611 }
612 if (set_demux(patfd, 0, DMX_PES_OTHER, dvr))
613 if (set_demux(pmtfd, pmtpid, DMX_PES_OTHER, dvr))
614 result = TRUE;
615 } else {
616 result = TRUE;
617 }
618 }
619
620 if (tpid != -1 && !set_demux(dmxfdt, tpid, DMX_PES_TELETEXT, dvr)) {
621 fprintf(stderr, "set_demux DMX_PES_TELETEXT failed\n");
622 }
623
624 check_frontend (fefd, dvr, human_readable, params_debug, hiband);
625
626 if (!interactive) {
627 close(patfd);
628 close(pmtfd);
629 if (audiofd >= 0)
630 close(audiofd);
631 close(dmxfda);
632 close(dmxfdv);
633 close(dmxfdt);
634 close(fefd);
635 }
636
637 return result;
638 }
639 static char *parse_parameter(const char *s, int *value, const struct t_channel_parameter_map *map)
640 {
641 if (*++s) {
642 char *p = NULL;
643 errno = 0;
644 int n = strtol(s, &p, 10);
645 if (!errno && p != s) {
646 value[0] = map_to_driver(n, map);
647 if (value[0] >= 0)
648 return p;
649 }
650 }
651 fprintf(stderr, "ERROR: invalid value for parameter '%C'\n", *(s - 1));
652 return NULL;
653 }
654
655 static int read_channels(const char *filename, int list_channels,
656 uint32_t chan_no, const char *chan_name,
657 unsigned int adapter, unsigned int frontend,
658 unsigned int demux, int dvr, int rec_psi,
659 int bypass, unsigned int delsys,
660 int modulation, int fec, int rolloff, int stream_id,
661 int human_readable, int params_debug,
662 int use_vdr_format, int use_tpid)
663 {
664 FILE *cfp;
665 char buf[4096];
666 char inp[256];
667 char *field, *tmp, *p;
668 unsigned int line;
669 unsigned int freq, pol, sat_no, sr, vpid, apid, tpid, sid;
670 int ret;
671 int trash;
672 again:
673 line = 0;
674 if (!(cfp = fopen(filename, "r"))) {
675 fprintf(stderr, "error opening channel list '%s': %d %m\n",
676 filename, errno);
677 return FALSE;
678 }
679
680 if (interactive) {
681 fprintf(stderr, "\n>>> ");
682 if (!fgets(inp, sizeof(inp), stdin)) {
683 printf("\n");
684 return -1;
685 }
686 if (inp[0] == '-' && inp[1] == 'n') {
687 chan_no = strtoul(inp+2, NULL, 0);
688 chan_name = NULL;
689 if (!chan_no) {
690 fprintf(stderr, "bad channel number\n");
691 goto again;
692 }
693 } else {
694 p = strchr(inp, '\n');
695 if (p)
696 *p = '\0';
697 chan_name = inp;
698 chan_no = 0;
699 }
700 }
701
702 while (!feof(cfp)) {
703 if (fgets(buf, sizeof(buf), cfp)) {
704 line++;
705
706 if (chan_no && chan_no != line)
707 continue;
708
709 tmp = buf;
710 field = strsep(&tmp, ":");
711
712 if (!field)
713 goto syntax_err;
714
715 if (list_channels) {
716 printf("%03u %s\n", line, field);
717 continue;
718 }
719
720 if (chan_name && strcasecmp(chan_name, field) != 0)
721 continue;
722
723 printf("zapping to %d '%s':\n", line, field);
724
725 if (!(field = strsep(&tmp, ":")))
726 goto syntax_err;
727
728 freq = strtoul(field, NULL, 0);
729
730 if (!(field = strsep(&tmp, ":")))
731 goto syntax_err;
732
733 while (field && *field) {
734 switch (toupper(*field)) {
735 case 'C':
736 if (fec == -1)
737 field = parse_parameter(field, &fec, coderate_values);
738 else
739 field = parse_parameter(field, &trash, coderate_values);
740 break;
741 case 'H':
742 pol = 0;
743 *field++;
744 break;
745 case 'I':/* ignore */
746 field = parse_parameter(field, &ret, inversion_values);
747 break;
748 case 'L':
749 pol = 0;
750 *field++;
751 break;
752 case 'M':
753 if (modulation == -1)
754 field = parse_parameter(field, &modulation, modulation_values);
755 else
756 field = parse_parameter(field, &trash, modulation_values);
757 break;
758 case 'Z':
759 case 'O':
760 if (rolloff == -1)
761 field = parse_parameter(field, &rolloff, rolloff_values);
762 else
763 field = parse_parameter(field, &trash, rolloff_values);
764 break;
765 case 'P':
766 stream_id = strtol(++field, &field, 10);
767 break;
768 case 'R':
769 pol = 1;
770 *field++;
771 break;
772 case 'S':
773 if (delsys == -1)
774 field = parse_parameter(field, &delsys, system_values);
775 else
776 field = parse_parameter(field, &trash, system_values);
777 break;
778 case 'V':
779 pol = 1;
780 *field++;
781 break;
782 default:
783 goto syntax_err;
784 }
785 }
786 /* default values for empty parameters */
787 if (fec == -1)
788 fec = FEC_AUTO;
789
790 if (modulation == -1)
791 modulation = QPSK;
792
793 if (delsys == -1)
794 delsys = SYS_DVBS;
795
796 if (rolloff == -1)
797 rolloff = ROLLOFF_35;
798
799 #if 0
800 if (stream_id<0 || stream_id>255)
801 stream_id = NO_STREAM_ID_FILTER;
802 #endif
803
804 if (!(field = strsep(&tmp, ":")))
805 goto syntax_err;
806
807 sat_no = strtoul(field, NULL, 0);
808
809 if (!(field = strsep(&tmp, ":")))
810 goto syntax_err;
811
812 sr = strtoul(field, NULL, 0) * 1000;
813
814 if (!(field = strsep(&tmp, ":")))
815 goto syntax_err;
816
817 vpid = strtoul(field, NULL, 0);
818 if (!vpid)
819 vpid = 0x1fff;
820
821 if (!(field = strsep(&tmp, ":")))
822 goto syntax_err;
823
824 p = strchr(field, ';');
825
826 if (p) {
827 *p = '\0';
828 p++;
829 if (bypass) {
830 if (!p || !*p)
831 goto syntax_err;
832 field = p;
833 }
834 }
835
836 apid = strtoul(field, NULL, 0);
837 if (!apid)
838 apid = 0x1fff;
839
840 tpid = -1;
841 if (use_vdr_format) {
842 if (!(field = strsep(&tmp, ":")))
843 goto syntax_err;
844
845 if (use_tpid)
846 tpid = strtoul(field, NULL, 0);
847
848 if (!(field = strsep(&tmp, ":")))
849 goto syntax_err;
850
851 strtoul(field, NULL, 0);
852 }
853
854 if (!(field = strsep(&tmp, ":")))
855 goto syntax_err;
856
857 sid = strtoul(field, NULL, 0);
858
859 fclose(cfp);
860 if (params_debug){
861 printf("delivery 0x%x, ", delsys);
862 } else {
863 field = NULL;
864 map_to_user(delsys, system_values, &field);
865 printf("delivery %s, ", field);
866 }
867
868 if (params_debug){
869 printf("modulation 0x%x\n", modulation);
870 } else {
871 field = NULL;
872 map_to_user(modulation, modulation_values, &field);
873 printf("modulation %s\n", field);
874 }
875
876 printf("sat %u, frequency %u MHz %c, symbolrate %u, ",
877 sat_no, freq, pol ? 'V' : 'H', sr);
878
879 if (params_debug){
880 printf("coderate 0x%x, ", fec);
881 } else {
882 field = NULL;
883 map_to_user(fec, coderate_values, &field);
884 printf("coderate %s, ", field);
885 }
886
887 if (params_debug){
888 printf("rolloff 0x%x stream_id %d\n"
889 "vpid 0x%04x, apid 0x%04x, sid 0x%04x\n", rolloff, stream_id, vpid, apid, sid);
890 } else {
891 field = NULL;
892 map_to_user(rolloff, rolloff_values, &field);
893 printf("rolloff %s stream_id %d\n"
894 "vpid 0x%04x, apid 0x%04x, sid 0x%04x\n", field, stream_id, vpid, apid, sid);
895 }
896
897 ret = zap_to(adapter, frontend, demux, sat_no, freq * 1000,
898 pol, sr, vpid, apid, tpid, sid, dvr, rec_psi, bypass,
899 delsys, modulation, fec, rolloff, stream_id, human_readable,
900 params_debug);
901
902 if (interactive)
903 goto again;
904
905 if (ret)
906 return TRUE;
907
908 return FALSE;
909
910 syntax_err:
911 fprintf(stderr, "syntax error in line %u: '%s'\n", line, buf);
912 } else if (ferror(cfp)) {
913 fprintf(stderr, "error reading channel list '%s': %d %m\n",
914 filename, errno);
915 fclose(cfp);
916 return FALSE;
917 } else
918 break;
919 }
920
921 fclose(cfp);
922
923 if (!list_channels) {
924 fprintf(stderr, "channel not found\n");
925
926 if (!interactive)
927 return FALSE;
928 }
929 if (interactive)
930 goto again;
931
932 return TRUE;
933 }
934
935 static void handle_sigint(int sig)
936 {
937 fprintf(stderr, "Interrupted by SIGINT!\n");
938 exit(2);
939 }
940
941 void
942 bad_usage(char *pname, int prlnb)
943 {
944 int i;
945 struct lnb_types_st *lnbp;
946 char **cp;
947
948 if (!prlnb) {
949 fprintf (stderr, usage_str, pname);
950 } else {
951 i = 0;
952 fprintf(stderr, "-l <lnb-type> or -l low[,high[,switch]] in Mhz\nwhere <lnb-type> is:\n");
953 while(NULL != (lnbp = lnb_enum(i))) {
954 fprintf (stderr, "%s\n", lnbp->name);
955 for (cp = lnbp->desc; *cp ; cp++) {
956 fprintf (stderr, " %s\n", *cp);
957 }
958 i++;
959 }
960 }
961 }
962
963 int main(int argc, char *argv[])
964 {
965 const char *home;
966 char chanfile[2 * PATH_MAX];
967 int list_channels = 0;
968 unsigned int chan_no = 0;
969 const char *chan_name = NULL;
970 unsigned int adapter = 0, frontend = 0, demux = 0, dvr = 0, rec_psi = 0;
971 int bypass = 0;
972 int opt, copt = 0;
973 int human_readable = 0;
974 int params_debug = 0;
975 int use_vdr_format = 0;
976 int use_tpid = 0;
977
978
979 int delsys = -1;
980 int modulation = -1;
981 int fec = -1;
982 int rolloff = -1;
983 int stream_id = NO_STREAM_ID_FILTER;
984
985 lnb_type = *lnb_enum(0);
986 while ((opt = getopt(argc, argv, "M:m:C:O:HDVhqrpn:a:f:d:S:c:l:xib")) != -1) {
987 switch (opt) {
988 case '?':
989 case 'h':
990 default:
991 bad_usage(argv[0], 0);
992 break;
993 case 'C':
994 parse_parameter(--optarg, &fec, coderate_values);
995 break;
996 case 'M':
997 parse_parameter(--optarg, &modulation, modulation_values);
998 break;
999 case 'Z':
1000 case 'O':
1001 parse_parameter(--optarg, &rolloff, rolloff_values);
1002 break;
1003 case 'm':
1004 stream_id = strtol(optarg, NULL, 0);
1005 break;
1006 case 'S':
1007 parse_parameter(--optarg, &delsys, system_values);
1008 break;
1009 case 'b':
1010 bypass = 1;
1011 break;
1012 case 'q':
1013 list_channels = 1;
1014 break;
1015 case 'r':
1016 dvr = 1;
1017 break;
1018 case 'n':
1019 chan_no = strtoul(optarg, NULL, 0);
1020 break;
1021 case 'a':
1022 adapter = strtoul(optarg, NULL, 0);
1023 break;
1024 case 'f':
1025 frontend = strtoul(optarg, NULL, 0);
1026 break;
1027 case 'p':
1028 rec_psi = 1;
1029 break;
1030 case 'd':
1031 demux = strtoul(optarg, NULL, 0);
1032 break;
1033 case 'c':
1034 copt = 1;
1035 strncpy(chanfile, optarg, sizeof(chanfile));
1036 break;
1037 case 'l':
1038 if (lnb_decode(optarg, &lnb_type) < 0) {
1039 bad_usage(argv[0], 1);
1040 return -1;
1041 }
1042 break;
1043 case 'x':
1044 exit_after_tuning = 1;
1045 break;
1046 case 'H':
1047 human_readable = 1;
1048 break;
1049 case 'D':
1050 params_debug = 1;
1051 break;
1052 case 'V':
1053 use_vdr_format = 1;
1054 break;
1055 case 't':
1056 use_tpid = 1;
1057 break;
1058 case 'i':
1059 interactive = 1;
1060 exit_after_tuning = 1;
1061 }
1062 }
1063 lnb_type.low_val *= 1000; /* convert to kiloherz */
1064 lnb_type.high_val *= 1000; /* convert to kiloherz */
1065 lnb_type.switch_val *= 1000; /* convert to kiloherz */
1066 if (optind < argc)
1067 chan_name = argv[optind];
1068 if (chan_name && chan_no) {
1069 bad_usage(argv[0], 0);
1070 return -1;
1071 }
1072 if (list_channels && (chan_name || chan_no)) {
1073 bad_usage(argv[0], 0);
1074 return -1;
1075 }
1076 if (!list_channels && !chan_name && !chan_no && !interactive) {
1077 bad_usage(argv[0], 0);
1078 return -1;
1079 }
1080
1081 if (!copt) {
1082 if (!(home = getenv("HOME"))) {
1083 fprintf(stderr, "error: $HOME not set\n");
1084 return TRUE;
1085 }
1086 snprintf(chanfile, sizeof(chanfile),
1087 "%s/.szap/%i/%s", home, adapter, CHANNEL_FILE);
1088 if (access(chanfile, R_OK))
1089 snprintf(chanfile, sizeof(chanfile),
1090 "%s/.szap/%s", home, CHANNEL_FILE);
1091 }
1092
1093 printf("reading channels from file '%s'\n", chanfile);
1094
1095 if (rec_psi)
1096 dvr=1;
1097
1098 signal(SIGINT, handle_sigint);
1099
1100 if (!read_channels(chanfile, list_channels, chan_no, chan_name,
1101 adapter, frontend, demux, dvr, rec_psi, bypass, delsys,
1102 modulation, fec, rolloff, stream_id, human_readable, params_debug,
1103 use_vdr_format, use_tpid))
1104
1105 return TRUE;
1106
1107 return FALSE;
1108 }
Imprint / Impressum