Merge branch 'nto-signal-stats'
[dvblast.git] / dvb.c
blob61863150bc30221b94b729b1b626e4cc4e383a99
1 /*****************************************************************************
2 * dvb.c: linux-dvb input for DVBlast
3 *****************************************************************************
4 * Copyright (C) 2008-2010, 2015 VideoLAN
6 * Authors: Christophe Massiot <massiot@via.ecp.fr>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21 *****************************************************************************/
22 #include "config.h"
24 #ifdef HAVE_DVB_SUPPORT
26 #include <stdlib.h>
27 #include <stdint.h>
28 #include <stdbool.h>
29 #include <stdio.h>
30 #include <unistd.h>
31 #include <string.h>
32 #include <sys/types.h>
33 #include <sys/stat.h>
34 #include <fcntl.h>
35 #include <unistd.h>
36 #include <sys/ioctl.h>
37 #include <sys/socket.h>
38 #include <sys/uio.h>
39 #include <netinet/in.h>
40 #include <arpa/inet.h>
41 #include <poll.h>
42 #include <errno.h>
44 /* DVB Card Drivers */
45 #include <linux/dvb/version.h>
46 #include <linux/dvb/dmx.h>
47 #include <linux/dvb/frontend.h>
48 #include <linux/dvb/ca.h>
50 #include <ev.h>
52 #if DVBAPI_VERSION < 508
53 #define DTV_STREAM_ID 42
54 #define FE_CAN_MULTISTREAM 0x4000000
55 #define FE_CAN_TURBO_FEC 0x8000000
56 #endif
58 #define MAX_DELIVERY_SYSTEMS 20
60 #include "dvblast.h"
61 #include "en50221.h"
62 #include "comm.h"
64 #include <bitstream/common.h>
66 /*****************************************************************************
67 * Local declarations
68 *****************************************************************************/
69 #define DVR_READ_TIMEOUT 30000000 /* 30 s */
70 #define MAX_READ_ONCE 50
71 #define DVR_BUFFER_SIZE 40*188*1024 /* bytes */
73 int i_dvr_buffer_size = DVR_BUFFER_SIZE;
75 static int i_frontend, i_dvr;
76 static struct ev_io frontend_watcher, dvr_watcher;
77 static struct ev_timer lock_watcher, mute_watcher, print_watcher;
78 static fe_status_t i_last_status;
79 static block_t *p_freelist = NULL;
81 /*****************************************************************************
82 * Local prototypes
83 *****************************************************************************/
84 static void DVRRead(struct ev_loop *loop, struct ev_io *w, int revents);
85 static void DVRMuteCb(struct ev_loop *loop, struct ev_timer *w, int revents);
86 static void FrontendRead(struct ev_loop *loop, struct ev_io *w, int revents);
87 static void FrontendLockCb(struct ev_loop *loop, struct ev_timer *w, int revents);
88 static void FrontendSet( bool b_reset );
90 /*****************************************************************************
91 * dvb_Open
92 *****************************************************************************/
93 void dvb_Open( void )
95 char psz_tmp[128];
97 msg_Dbg( NULL, "compiled with DVB API version %d.%d", DVB_API_VERSION, DVB_API_VERSION_MINOR );
99 if ( i_frequency )
101 sprintf( psz_tmp, "/dev/dvb/adapter%d/frontend%d", i_adapter, i_fenum );
102 if( (i_frontend = open(psz_tmp, O_RDWR | O_NONBLOCK)) < 0 )
104 msg_Err( NULL, "opening device %s failed (%s)", psz_tmp,
105 strerror(errno) );
106 exit(1);
109 FrontendSet(true);
111 else
113 i_frontend = -1;
116 sprintf( psz_tmp, "/dev/dvb/adapter%d/dvr%d", i_adapter, i_fenum );
118 if( (i_dvr = open(psz_tmp, O_RDONLY | O_NONBLOCK)) < 0 )
120 msg_Err( NULL, "opening device %s failed (%s)", psz_tmp,
121 strerror(errno) );
122 exit(1);
125 if ( ioctl( i_dvr, DMX_SET_BUFFER_SIZE, i_dvr_buffer_size ) < 0 )
127 msg_Warn( NULL, "couldn't set %s buffer size (%s)", psz_tmp,
128 strerror(errno) );
131 ev_io_init(&dvr_watcher, DVRRead, i_dvr, EV_READ);
132 ev_io_start(event_loop, &dvr_watcher);
134 if ( i_frontend != -1 )
136 ev_io_init(&frontend_watcher, FrontendRead, i_frontend, EV_READ);
137 ev_io_start(event_loop, &frontend_watcher);
140 ev_timer_init(&lock_watcher, FrontendLockCb,
141 i_frontend_timeout_duration / 1000000.,
142 i_frontend_timeout_duration / 1000000.);
143 ev_timer_init(&mute_watcher, DVRMuteCb,
144 DVR_READ_TIMEOUT / 1000000.,
145 DVR_READ_TIMEOUT / 1000000.);
147 en50221_Init();
150 /*****************************************************************************
151 * dvb_Reset
152 *****************************************************************************/
153 void dvb_Reset( void )
155 if ( i_frequency )
156 FrontendSet(true);
159 /*****************************************************************************
160 * DVR events
161 *****************************************************************************/
162 static void DVRRead(struct ev_loop *loop, struct ev_io *w, int revents)
164 int i, i_len;
165 block_t *p_ts = p_freelist, **pp_current = &p_ts;
166 struct iovec p_iov[MAX_READ_ONCE];
168 for ( i = 0; i < MAX_READ_ONCE; i++ )
170 if ( (*pp_current) == NULL ) *pp_current = block_New();
171 p_iov[i].iov_base = (*pp_current)->p_ts;
172 p_iov[i].iov_len = TS_SIZE;
173 pp_current = &(*pp_current)->p_next;
176 if ( (i_len = readv(i_dvr, p_iov, MAX_READ_ONCE)) < 0 )
178 msg_Err( NULL, "couldn't read from DVR device (%s)",
179 strerror(errno) );
180 i_len = 0;
182 i_len /= TS_SIZE;
184 if ( i_len )
185 ev_timer_again(loop, &mute_watcher);
187 pp_current = &p_ts;
188 while ( i_len && *pp_current )
190 pp_current = &(*pp_current)->p_next;
191 i_len--;
194 p_freelist = *pp_current;
195 *pp_current = NULL;
197 demux_Run( p_ts );
200 static void DVRMuteCb(struct ev_loop *loop, struct ev_timer *w, int revents)
202 msg_Warn( NULL, "no DVR output, resetting" );
203 ev_timer_stop(loop, w);
205 switch (i_print_type) {
206 case PRINT_XML:
207 fprintf(print_fh, "<EVENT type=\"reset\" cause=\"dvr\" />\n");
208 break;
209 case PRINT_TEXT:
210 fprintf(print_fh, "reset cause: dvr\n");
211 break;
212 default:
213 break;
215 if ( i_frequency )
216 FrontendSet(false);
217 en50221_Reset();
222 * Demux
225 /*****************************************************************************
226 * dvb_SetFilter : controls the demux to add a filter
227 *****************************************************************************/
228 int dvb_SetFilter( uint16_t i_pid )
230 struct dmx_pes_filter_params s_filter_params;
231 char psz_tmp[128];
232 int i_fd;
234 sprintf( psz_tmp, "/dev/dvb/adapter%d/demux%d", i_adapter, i_fenum );
235 if( (i_fd = open(psz_tmp, O_RDWR)) < 0 )
237 msg_Err( NULL, "DMXSetFilter: opening device failed (%s)",
238 strerror(errno) );
239 return -1;
242 s_filter_params.pid = i_pid;
243 s_filter_params.input = DMX_IN_FRONTEND;
244 s_filter_params.output = DMX_OUT_TS_TAP;
245 s_filter_params.flags = DMX_IMMEDIATE_START;
246 s_filter_params.pes_type = DMX_PES_OTHER;
248 if ( ioctl( i_fd, DMX_SET_PES_FILTER, &s_filter_params ) < 0 )
250 msg_Err( NULL, "failed setting filter on %d (%s)", i_pid,
251 strerror(errno) );
252 close( i_fd );
253 return -1;
256 msg_Dbg( NULL, "setting filter on PID %d", i_pid );
258 return i_fd;
261 /*****************************************************************************
262 * dvb_UnsetFilter : removes a filter
263 *****************************************************************************/
264 void dvb_UnsetFilter( int i_fd, uint16_t i_pid )
266 if ( ioctl( i_fd, DMX_STOP ) < 0 )
267 msg_Err( NULL, "DMX_STOP failed (%s)", strerror(errno) );
268 else
269 msg_Dbg( NULL, "unsetting filter on PID %d", i_pid );
271 close( i_fd );
276 * Frontend
279 /*****************************************************************************
280 * Print info
281 *****************************************************************************/
282 static void PrintCb( struct ev_loop *loop, struct ev_timer *w, int revents )
284 uint32_t i_ber = 0;
285 uint16_t i_strength = 0, i_snr = 0;
286 uint32_t i_uncorrected = 0;
288 ioctl(i_frontend, FE_READ_BER, &i_ber);
289 ioctl(i_frontend, FE_READ_SIGNAL_STRENGTH, &i_strength);
290 ioctl(i_frontend, FE_READ_SNR, &i_snr);
291 ioctl(i_frontend, FE_READ_UNCORRECTED_BLOCKS, &i_uncorrected);
293 int64_t i_strength_dbm = i_strength;
294 int64_t i_snr_db = i_snr;
296 #ifdef DTV_STAT_SIGNAL_STRENGTH
297 struct dtv_property prop[] = {
298 { .cmd = DTV_STAT_SIGNAL_STRENGTH },
299 { .cmd = DTV_STAT_CNR },
302 struct dtv_properties props = { .num = 2, .props = prop };
303 if (ioctl(i_frontend, FE_GET_PROPERTY, &props) != -1)
305 if (prop[0].u.st.len > 0 &&
306 prop[0].u.st.stat[0].scale == FE_SCALE_DECIBEL)
307 i_strength_dbm = prop[0].u.st.stat[0].svalue;
308 if (prop[1].u.st.len > 0 &&
309 prop[1].u.st.stat[0].scale == FE_SCALE_DECIBEL)
310 i_snr_db = prop[1].u.st.stat[0].svalue;
312 #endif
314 switch (i_print_type)
316 case PRINT_XML:
317 fprintf(print_fh,
318 "<STATUS type=\"frontend\" ber=\"%"PRIu32"\" strength=\"%"PRId64"\" snr=\"%"PRId64"\" uncorrected=\"%"PRIu32"\" />\n",
319 i_ber, i_strength_dbm, i_snr_db, i_uncorrected);
320 break;
321 case PRINT_TEXT:
322 fprintf(print_fh, "frontend ber: %"PRIu32" strength: %"PRId64" snr: %"PRId64" uncorrected: %"PRIu32"\n",
323 i_ber, i_strength_dbm, i_snr_db, i_uncorrected);
324 break;
325 default:
326 break;
330 /*****************************************************************************
331 * Frontend events
332 *****************************************************************************/
333 static void FrontendRead(struct ev_loop *loop, struct ev_io *w, int revents)
335 struct dvb_frontend_event event;
336 fe_status_t i_status, i_diff;
338 for( ;; )
340 int i_ret = ioctl( i_frontend, FE_GET_EVENT, &event );
342 if( i_ret < 0 )
344 if( errno == EWOULDBLOCK )
345 return; /* no more events */
347 msg_Err( NULL, "reading frontend event failed (%d) %s",
348 i_ret, strerror(errno) );
349 return;
352 i_status = event.status;
353 i_diff = i_status ^ i_last_status;
354 i_last_status = i_status;
357 #define IF_UP( x ) \
359 if ( i_diff & (x) ) \
361 if ( i_status & (x) )
363 IF_UP( FE_HAS_SIGNAL )
364 msg_Dbg( NULL, "frontend has acquired signal" );
365 else
366 msg_Dbg( NULL, "frontend has lost signal" );
368 IF_UP( FE_HAS_CARRIER )
369 msg_Dbg( NULL, "frontend has acquired carrier" );
370 else
371 msg_Dbg( NULL, "frontend has lost carrier" );
373 IF_UP( FE_HAS_VITERBI )
374 msg_Dbg( NULL, "frontend has acquired stable FEC" );
375 else
376 msg_Dbg( NULL, "frontend has lost FEC" );
378 IF_UP( FE_HAS_SYNC )
379 msg_Dbg( NULL, "frontend has acquired sync" );
380 else
381 msg_Dbg( NULL, "frontend has lost sync" );
383 IF_UP( FE_HAS_LOCK )
385 int32_t i_value = 0;
386 msg_Info( NULL, "frontend has acquired lock" );
387 switch (i_print_type) {
388 case PRINT_XML:
389 fprintf(print_fh, "<STATUS type=\"lock\" status=\"1\" />\n");
390 break;
391 case PRINT_TEXT:
392 fprintf(print_fh, "lock status: 1\n");
393 break;
394 default:
395 break;
398 ev_timer_stop(loop, &lock_watcher);
399 ev_timer_again(loop, &mute_watcher);
401 /* Read some statistics */
402 if( ioctl( i_frontend, FE_READ_BER, &i_value ) >= 0 )
403 msg_Dbg( NULL, "- Bit error rate: %d", i_value );
404 if( ioctl( i_frontend, FE_READ_SIGNAL_STRENGTH, &i_value ) >= 0 )
405 msg_Dbg( NULL, "- Signal strength: %d", i_value );
406 if( ioctl( i_frontend, FE_READ_SNR, &i_value ) >= 0 )
407 msg_Dbg( NULL, "- SNR: %d", i_value );
409 if (i_print_period)
411 ev_timer_init( &print_watcher, PrintCb,
412 i_print_period / 1000000.,
413 i_print_period / 1000000. );
414 ev_timer_start( event_loop, &print_watcher );
417 else
419 msg_Dbg( NULL, "frontend has lost lock" );
420 switch (i_print_type) {
421 case PRINT_XML:
422 fprintf(print_fh, "<STATUS type=\"lock\" status=\"0\"/>\n");
423 break;
424 case PRINT_TEXT:
425 fprintf(print_fh, "lock status: 0\n");
426 break;
427 default:
428 break;
431 if (i_frontend_timeout_duration)
433 ev_timer_stop(event_loop, &lock_watcher);
434 ev_timer_again(loop, &mute_watcher);
437 if (i_print_period)
438 ev_timer_stop(event_loop, &print_watcher);
441 IF_UP( FE_REINIT )
443 /* The frontend was reinited. */
444 msg_Warn( NULL, "reiniting frontend");
445 if ( i_frequency )
446 FrontendSet(true);
449 #undef IF_UP
453 static void FrontendLockCb(struct ev_loop *loop, struct ev_timer *w, int revents)
455 if ( i_quit_timeout_duration )
457 msg_Err( NULL, "no lock" );
458 ev_break(loop, EVBREAK_ALL);
459 return;
462 msg_Warn( NULL, "no lock, tuning again" );
463 ev_timer_stop(loop, w);
465 switch (i_print_type) {
466 case PRINT_XML:
467 fprintf(print_fh, "<EVENT type=\"reset\" cause=\"nolock\" />\n");
468 break;
469 case PRINT_TEXT:
470 fprintf(print_fh, "reset cause: nolock\n");
471 break;
472 default:
473 break;
475 if ( i_frequency )
476 FrontendSet(false);
479 static int FrontendDoDiseqc(void)
481 fe_sec_voltage_t fe_voltage;
482 fe_sec_tone_mode_t fe_tone;
483 int bis_frequency;
485 switch ( i_voltage )
487 case 0: fe_voltage = SEC_VOLTAGE_OFF; break;
488 default:
489 case 13: fe_voltage = SEC_VOLTAGE_13; break;
490 case 18: fe_voltage = SEC_VOLTAGE_18; break;
493 fe_tone = b_tone ? SEC_TONE_ON : SEC_TONE_OFF;
495 if ( strcmp( psz_lnb_type, "universal" ) == 0 )
497 /* Automatic mode. */
498 if ( i_frequency >= 950000 && i_frequency <= 2150000 )
500 msg_Dbg( NULL, "frequency %d is in IF-band", i_frequency );
501 bis_frequency = i_frequency;
503 else if ( i_frequency >= 2500000 && i_frequency <= 2700000 )
505 msg_Dbg( NULL, "frequency %d is in S-band", i_frequency );
506 bis_frequency = 3650000 - i_frequency;
508 else if ( i_frequency >= 3400000 && i_frequency <= 4200000 )
510 msg_Dbg( NULL, "frequency %d is in C-band (lower)", i_frequency );
511 bis_frequency = 5150000 - i_frequency;
513 else if ( i_frequency >= 4500000 && i_frequency <= 4800000 )
515 msg_Dbg( NULL, "frequency %d is in C-band (higher)", i_frequency );
516 bis_frequency = 5950000 - i_frequency;
518 else if ( i_frequency >= 10700000 && i_frequency < 11700000 )
520 msg_Dbg( NULL, "frequency %d is in Ku-band (lower)",
521 i_frequency );
522 bis_frequency = i_frequency - 9750000;
524 else if ( i_frequency >= 11700000 && i_frequency <= 13250000 )
526 msg_Dbg( NULL, "frequency %d is in Ku-band (higher)",
527 i_frequency );
528 bis_frequency = i_frequency - 10600000;
529 fe_tone = SEC_TONE_ON;
531 else
533 msg_Err( NULL, "frequency %d is out of any known band",
534 i_frequency );
535 exit(1);
538 else if ( strcmp( psz_lnb_type, "old-sky" ) == 0 )
540 if ( i_frequency >= 11700000 && i_frequency <= 13250000 )
542 msg_Dbg( NULL, "frequency %d is in Ku-band (higher)",
543 i_frequency );
544 bis_frequency = i_frequency - 11300000;
545 fe_tone = SEC_TONE_ON;
547 else
549 msg_Err( NULL, "frequency %d is out of any known band",
550 i_frequency );
551 exit(1);
554 else
556 msg_Err( NULL, "lnb-type '%s' is not known. Valid type: universal old-sky",
557 psz_lnb_type );
558 exit(1);
561 /* Switch off continuous tone. */
562 if ( ioctl( i_frontend, FE_SET_TONE, SEC_TONE_OFF ) < 0 )
564 msg_Err( NULL, "FE_SET_TONE failed (%s)", strerror(errno) );
565 exit(1);
568 /* Configure LNB voltage. */
569 if ( ioctl( i_frontend, FE_SET_VOLTAGE, fe_voltage ) < 0 )
571 msg_Err( NULL, "FE_SET_VOLTAGE failed (%s)", strerror(errno) );
572 exit(1);
575 /* Wait for at least 15 ms. Currently 100 ms because of broken drivers. */
576 msleep(100000);
578 /* Diseqc */
579 if ( i_satnum > 0 && i_satnum < 5 )
581 /* digital satellite equipment control,
582 * specification is available from http://www.eutelsat.com/
585 /* DiSEqC 1.1 */
586 struct dvb_diseqc_master_cmd uncmd =
587 { {0xe0, 0x10, 0x39, 0xf0, 0x00, 0x00}, 4};
589 /* DiSEqC 1.0 */
590 struct dvb_diseqc_master_cmd cmd =
591 { {0xe0, 0x10, 0x38, 0xf0, 0x00, 0x00}, 4};
593 cmd.msg[3] = 0xf0 /* reset bits */
594 | ((i_satnum - 1) << 2)
595 | (fe_voltage == SEC_VOLTAGE_13 ? 0 : 2)
596 | (fe_tone == SEC_TONE_ON ? 1 : 0);
598 if ( i_uncommitted > 0 && i_uncommitted < 17 )
600 uncmd.msg[3] = 0xf0 /* reset bits */
601 | (i_uncommitted - 1);
602 if( ioctl( i_frontend, FE_DISEQC_SEND_MASTER_CMD, &uncmd ) < 0 )
604 msg_Err( NULL, "ioctl FE_SEND_MASTER_CMD failed (%s)",
605 strerror(errno) );
606 exit(1);
608 /* Repeat uncommitted command */
609 uncmd.msg[0] = 0xe1; /* framing: master, no reply, repeated TX */
610 if( ioctl( i_frontend, FE_DISEQC_SEND_MASTER_CMD, &uncmd ) < 0 )
612 msg_Err( NULL, "ioctl FE_SEND_MASTER_CMD failed (%s)",
613 strerror(errno) );
614 exit(1);
616 /* Pause 125 ms between uncommitted & committed diseqc commands. */
617 msleep(125000);
620 if( ioctl( i_frontend, FE_DISEQC_SEND_MASTER_CMD, &cmd ) < 0 )
622 msg_Err( NULL, "ioctl FE_SEND_MASTER_CMD failed (%s)",
623 strerror(errno) );
624 exit(1);
626 msleep(100000); /* Should be 15 ms. */
628 /* Do it again just to be sure. */
629 cmd.msg[0] = 0xe1; /* framing: master, no reply, repeated TX */
630 if( ioctl( i_frontend, FE_DISEQC_SEND_MASTER_CMD, &cmd ) < 0 )
632 msg_Err( NULL, "ioctl FE_SEND_MASTER_CMD failed (%s)",
633 strerror(errno) );
634 exit(1);
636 msleep(100000); /* Again, should be 15 ms */
638 else if ( i_satnum == 0xA || i_satnum == 0xB )
640 /* A or B simple diseqc ("diseqc-compatible") */
641 if( ioctl( i_frontend, FE_DISEQC_SEND_BURST,
642 i_satnum == 0xB ? SEC_MINI_B : SEC_MINI_A ) < 0 )
644 msg_Err( NULL, "ioctl FE_SEND_BURST failed (%s)", strerror(errno) );
645 exit(1);
647 msleep(100000); /* ... */
650 if ( ioctl( i_frontend, FE_SET_TONE, fe_tone ) < 0 )
652 msg_Err( NULL, "FE_SET_TONE failed (%s)", strerror(errno) );
653 exit(1);
656 msleep(100000); /* ... */
658 msg_Dbg( NULL, "configuring LNB to v=%d p=%d satnum=%x uncommitted=%x lnb-type=%s bis_frequency=%d",
659 i_voltage, b_tone, i_satnum, i_uncommitted, psz_lnb_type, bis_frequency );
660 return bis_frequency;
663 #if DVB_API_VERSION >= 5
665 #if DVBAPI_VERSION < 505
666 #warning Your linux-dvb headers are old, you should consider upgrading your kernel and/or compiling against different kernel headers
667 #endif
669 /*****************************************************************************
670 * Helper functions for S2API
671 *****************************************************************************/
672 static fe_spectral_inversion_t GetInversion(void)
674 switch ( i_inversion )
676 case 0: return INVERSION_OFF;
677 case 1: return INVERSION_ON;
678 default:
679 msg_Warn( NULL, "invalid inversion %d", i_inversion );
680 case -1: return INVERSION_AUTO;
684 static fe_code_rate_t GetFEC(fe_caps_t fe_caps, int i_fec_value)
686 #define GET_FEC_INNER(fec, val) \
687 if ( (fe_caps & FE_CAN_##fec) && (i_fec_value == val) ) \
688 return fec;
690 GET_FEC_INNER(FEC_AUTO, 999);
691 GET_FEC_INNER(FEC_AUTO, -1);
692 if (i_fec_value == 0)
693 return FEC_NONE;
694 GET_FEC_INNER(FEC_1_2, 12);
695 GET_FEC_INNER(FEC_2_3, 23);
696 GET_FEC_INNER(FEC_3_4, 34);
697 if (i_fec_value == 35)
698 return FEC_3_5;
699 GET_FEC_INNER(FEC_4_5, 45);
700 GET_FEC_INNER(FEC_5_6, 56);
701 GET_FEC_INNER(FEC_6_7, 67);
702 GET_FEC_INNER(FEC_7_8, 78);
703 GET_FEC_INNER(FEC_8_9, 89);
704 if (i_fec_value == 910)
705 return FEC_9_10;
707 #undef GET_FEC_INNER
708 msg_Warn(NULL, "invalid FEC %d", i_fec_value );
709 return FEC_AUTO;
712 #define GetFECInner(caps) GetFEC(caps, i_fec)
713 #define GetFECLP(caps) GetFEC(caps, i_fec_lp)
715 static fe_modulation_t GetModulation(void)
717 #define GET_MODULATION( mod ) \
718 if ( !strcasecmp( psz_modulation, #mod ) ) \
719 return mod;
721 GET_MODULATION(QPSK);
722 GET_MODULATION(QAM_16);
723 GET_MODULATION(QAM_32);
724 GET_MODULATION(QAM_64);
725 GET_MODULATION(QAM_128);
726 GET_MODULATION(QAM_256);
727 GET_MODULATION(QAM_AUTO);
728 GET_MODULATION(VSB_8);
729 GET_MODULATION(VSB_16);
730 GET_MODULATION(PSK_8);
731 GET_MODULATION(APSK_16);
732 GET_MODULATION(APSK_32);
733 GET_MODULATION(DQPSK);
735 #undef GET_MODULATION
736 msg_Err( NULL, "invalid modulation %s", psz_modulation );
737 exit(1);
740 static fe_pilot_t GetPilot(void)
742 switch ( i_pilot )
744 case 0: return PILOT_OFF;
745 case 1: return PILOT_ON;
746 default:
747 msg_Warn( NULL, "invalid pilot %d", i_pilot );
748 case -1: return PILOT_AUTO;
752 static fe_rolloff_t GetRollOff(void)
754 switch ( i_rolloff )
756 case -1:
757 case 0: return ROLLOFF_AUTO;
758 case 20: return ROLLOFF_20;
759 case 25: return ROLLOFF_25;
760 default:
761 msg_Warn( NULL, "invalid rolloff %d", i_rolloff );
762 case 35: return ROLLOFF_35;
766 static fe_guard_interval_t GetGuard(void)
768 switch ( i_guard )
770 case 32: return GUARD_INTERVAL_1_32;
771 case 16: return GUARD_INTERVAL_1_16;
772 case 8: return GUARD_INTERVAL_1_8;
773 case 4: return GUARD_INTERVAL_1_4;
774 default:
775 msg_Warn( NULL, "invalid guard interval %d", i_guard );
776 case -1:
777 case 0: return GUARD_INTERVAL_AUTO;
781 static fe_transmit_mode_t GetTransmission(void)
783 switch ( i_transmission )
785 case 2: return TRANSMISSION_MODE_2K;
786 case 8: return TRANSMISSION_MODE_8K;
787 #ifdef TRANSMISSION_MODE_4K
788 case 4: return TRANSMISSION_MODE_4K;
789 #endif
790 default:
791 msg_Warn( NULL, "invalid tranmission mode %d", i_transmission );
792 case -1:
793 case 0: return TRANSMISSION_MODE_AUTO;
797 static fe_hierarchy_t GetHierarchy(void)
799 switch ( i_hierarchy )
801 case 0: return HIERARCHY_NONE;
802 case 1: return HIERARCHY_1;
803 case 2: return HIERARCHY_2;
804 case 4: return HIERARCHY_4;
805 default:
806 msg_Warn( NULL, "invalid intramission mode %d", i_transmission );
807 case -1: return HIERARCHY_AUTO;
811 /*****************************************************************************
812 * FrontendInfo : Print frontend info
813 *****************************************************************************/
814 static void FrontendInfo( struct dvb_frontend_info *info, uint32_t version,
815 fe_delivery_system_t *p_systems, int i_systems )
817 msg_Dbg( NULL, "using DVB API version %d.%d", version / 256, version % 256 );
818 msg_Dbg( NULL, "Frontend \"%s\" supports:", info->name );
819 msg_Dbg( NULL, " frequency min: %d, max: %d, stepsize: %d, tolerance: %d",
820 info->frequency_min, info->frequency_max,
821 info->frequency_stepsize, info->frequency_tolerance );
822 msg_Dbg( NULL, " symbolrate min: %d, max: %d, tolerance: %d",
823 info->symbol_rate_min, info->symbol_rate_max, info->symbol_rate_tolerance);
824 msg_Dbg( NULL, " capabilities:" );
826 #define FRONTEND_INFO(caps,val,msg) \
827 if ( caps & val ) \
828 msg_Dbg( NULL, " %s", msg );
830 FRONTEND_INFO( info->caps, FE_IS_STUPID, "FE_IS_STUPID" )
831 FRONTEND_INFO( info->caps, FE_CAN_INVERSION_AUTO, "INVERSION_AUTO" )
832 FRONTEND_INFO( info->caps, FE_CAN_FEC_1_2, "FEC_1_2" )
833 FRONTEND_INFO( info->caps, FE_CAN_FEC_2_3, "FEC_2_3" )
834 FRONTEND_INFO( info->caps, FE_CAN_FEC_3_4, "FEC_3_4" )
835 FRONTEND_INFO( info->caps, FE_CAN_FEC_4_5, "FEC_4_5" )
836 FRONTEND_INFO( info->caps, FE_CAN_FEC_5_6, "FEC_5_6" )
837 FRONTEND_INFO( info->caps, FE_CAN_FEC_6_7, "FEC_6_7" )
838 FRONTEND_INFO( info->caps, FE_CAN_FEC_7_8, "FEC_7_8" )
839 FRONTEND_INFO( info->caps, FE_CAN_FEC_8_9, "FEC_8_9" )
840 FRONTEND_INFO( info->caps, FE_CAN_FEC_AUTO,"FEC_AUTO")
841 FRONTEND_INFO( info->caps, FE_CAN_QPSK, "QPSK" )
842 FRONTEND_INFO( info->caps, FE_CAN_QAM_16, "QAM_16" )
843 FRONTEND_INFO( info->caps, FE_CAN_QAM_32, "QAM_32" )
844 FRONTEND_INFO( info->caps, FE_CAN_QAM_64, "QAM_64" )
845 FRONTEND_INFO( info->caps, FE_CAN_QAM_128,"QAM_128")
846 FRONTEND_INFO( info->caps, FE_CAN_QAM_256,"QAM_256")
847 FRONTEND_INFO( info->caps, FE_CAN_QAM_AUTO,"QAM_AUTO" )
848 FRONTEND_INFO( info->caps, FE_CAN_TRANSMISSION_MODE_AUTO, "TRANSMISSION_MODE_AUTO" )
849 FRONTEND_INFO( info->caps, FE_CAN_BANDWIDTH_AUTO, "BANDWIDTH_AUTO" )
850 FRONTEND_INFO( info->caps, FE_CAN_GUARD_INTERVAL_AUTO, "GUARD_INTERVAL_AUTO" )
851 FRONTEND_INFO( info->caps, FE_CAN_HIERARCHY_AUTO, "HIERARCHY_AUTO" )
852 FRONTEND_INFO( info->caps, FE_CAN_8VSB, "8VSB" )
853 FRONTEND_INFO( info->caps, FE_CAN_16VSB,"16VSB" )
854 FRONTEND_INFO( info->caps, FE_HAS_EXTENDED_CAPS, "EXTENDED_CAPS" )
855 #if DVBAPI_VERSION >= 501
856 FRONTEND_INFO( info->caps, FE_CAN_2G_MODULATION, "2G_MODULATION" )
857 #endif
858 FRONTEND_INFO( info->caps, FE_CAN_MULTISTREAM, "MULTISTREAM" )
859 FRONTEND_INFO( info->caps, FE_CAN_TURBO_FEC, "TURBO_FEC" )
860 FRONTEND_INFO( info->caps, FE_NEEDS_BENDING, "NEEDS_BENDING" )
861 FRONTEND_INFO( info->caps, FE_CAN_RECOVER, "FE_CAN_RECOVER" )
862 FRONTEND_INFO( info->caps, FE_CAN_MUTE_TS, "FE_CAN_MUTE_TS" )
863 #undef FRONTEND_INFO
865 msg_Dbg( NULL, " delivery systems:" );
866 int i;
867 for ( i = 0; i < i_systems; i++ )
869 switch ( p_systems[i] )
871 #define DELSYS_INFO(delsys, msg) \
872 case delsys: msg_Dbg( NULL, " %s", msg); break;
873 DELSYS_INFO( SYS_ATSC, "ATSC" )
874 DELSYS_INFO( SYS_ATSCMH, "ATSCMH" )
875 DELSYS_INFO( SYS_CMMB, "CMBB" )
876 DELSYS_INFO( SYS_DAB, "DAB" )
877 DELSYS_INFO( SYS_DSS, "DSS" )
878 DELSYS_INFO( SYS_DVBC_ANNEX_B, "DVBC_ANNEX_B" )
879 DELSYS_INFO( SYS_DVBH, "DVBH" )
880 DELSYS_INFO( SYS_DVBS, "DVBS" )
881 DELSYS_INFO( SYS_DVBS2, "DVBS2" )
882 DELSYS_INFO( SYS_DVBT, "DVBT" )
883 DELSYS_INFO( SYS_ISDBC, "ISDBC" )
884 DELSYS_INFO( SYS_ISDBS, "ISDBS" )
885 DELSYS_INFO( SYS_ISDBT, "ISDBT" )
886 DELSYS_INFO( SYS_UNDEFINED, "UNDEFINED" )
887 #if DVBAPI_VERSION >= 505
888 DELSYS_INFO( SYS_DVBC_ANNEX_A, "DVBC_ANNEX_A" )
889 DELSYS_INFO( SYS_DVBC_ANNEX_C, "DVBC_ANNEX_C" )
890 DELSYS_INFO( SYS_DVBT2, "DVBT2" )
891 DELSYS_INFO( SYS_TURBO, "TURBO" )
892 #else
893 DELSYS_INFO( SYS_DVBC_ANNEX_AC, "DVBC_ANNEX_AC" )
894 #endif
895 #if DVBAPI_VERSION >= 507
896 DELSYS_INFO( SYS_DTMB, "DTMB" )
897 #else
898 DELSYS_INFO( SYS_DMBTH, "DMBTH" )
899 #endif
900 default: msg_Dbg( NULL, " Unknown delivery system %u", p_systems[i]);
901 break;
906 /*****************************************************************************
907 * FrontendSet
908 *****************************************************************************/
909 /* S2API */
910 #if DVBAPI_VERSION >= 505
911 static struct dtv_property info_cmdargs[] = {
912 { .cmd = DTV_API_VERSION, .u.data = 0 },
914 static struct dtv_properties info_cmdseq = {
915 .num = sizeof(info_cmdargs)/sizeof(struct dtv_property),
916 .props = info_cmdargs
919 static struct dtv_property enum_cmdargs[] = {
920 { .cmd = DTV_ENUM_DELSYS, .u.data = 0 },
922 static struct dtv_properties enum_cmdseq = {
923 .num = sizeof(enum_cmdargs)/sizeof(struct dtv_property),
924 .props = enum_cmdargs
926 #endif
928 static struct dtv_property dvbs_cmdargs[] = {
929 { .cmd = DTV_DELIVERY_SYSTEM, .u.data = SYS_DVBS },
930 { .cmd = DTV_FREQUENCY, .u.data = 0 },
931 { .cmd = DTV_MODULATION, .u.data = QPSK },
932 { .cmd = DTV_INVERSION, .u.data = INVERSION_AUTO },
933 { .cmd = DTV_SYMBOL_RATE, .u.data = 27500000 },
934 { .cmd = DTV_INNER_FEC, .u.data = FEC_AUTO },
935 { .cmd = DTV_TUNE },
937 static struct dtv_properties dvbs_cmdseq = {
938 .num = sizeof(dvbs_cmdargs)/sizeof(struct dtv_property),
939 .props = dvbs_cmdargs
942 #define IDX_DVBS2_PILOT 6
943 #define IDX_DVBS2_ROLLOFF 7
944 #define IDX_DVBS2_STREAM_ID 8
946 /* Commands 0..5 are the same as dvbs_cmdargs */
947 /* Commands 6..8 are special for DVB-S2 */
948 static struct dtv_property dvbs2_cmdargs[] = {
949 { .cmd = DTV_DELIVERY_SYSTEM, .u.data = SYS_DVBS2 },
950 { .cmd = DTV_FREQUENCY, .u.data = 0 },
951 { .cmd = DTV_MODULATION, .u.data = PSK_8 },
952 { .cmd = DTV_INVERSION, .u.data = INVERSION_AUTO },
953 { .cmd = DTV_SYMBOL_RATE, .u.data = 27500000 },
954 { .cmd = DTV_INNER_FEC, .u.data = FEC_AUTO },
955 { .cmd = DTV_PILOT, .u.data = PILOT_AUTO }, /* idx: 6 */
956 { .cmd = DTV_ROLLOFF, .u.data = ROLLOFF_AUTO }, /* idx: 7 */
957 { .cmd = DTV_STREAM_ID, .u.data = 0 }, /* idx: 8 */
958 { .cmd = DTV_TUNE },
960 static struct dtv_properties dvbs2_cmdseq = {
961 .num = sizeof(dvbs2_cmdargs)/sizeof(struct dtv_property),
962 .props = dvbs2_cmdargs
965 static struct dtv_property dvbc_cmdargs[] = {
966 #if DVBAPI_VERSION >= 505
967 { .cmd = DTV_DELIVERY_SYSTEM, .u.data = SYS_DVBC_ANNEX_A },
968 #else
969 { .cmd = DTV_DELIVERY_SYSTEM, .u.data = SYS_DVBC_ANNEX_AC },
970 #endif
971 { .cmd = DTV_FREQUENCY, .u.data = 0 },
972 { .cmd = DTV_MODULATION, .u.data = QAM_AUTO },
973 { .cmd = DTV_INVERSION, .u.data = INVERSION_AUTO },
974 { .cmd = DTV_SYMBOL_RATE, .u.data = 27500000 },
975 { .cmd = DTV_TUNE },
977 static struct dtv_properties dvbc_cmdseq = {
978 .num = sizeof(dvbc_cmdargs)/sizeof(struct dtv_property),
979 .props = dvbc_cmdargs
982 static struct dtv_property dvbt_cmdargs[] = {
983 { .cmd = DTV_DELIVERY_SYSTEM, .u.data = SYS_DVBT },
984 { .cmd = DTV_FREQUENCY, .u.data = 0 },
985 { .cmd = DTV_MODULATION, .u.data = QAM_AUTO },
986 { .cmd = DTV_INVERSION, .u.data = INVERSION_AUTO },
987 { .cmd = DTV_BANDWIDTH_HZ, .u.data = 8000000 },
988 { .cmd = DTV_CODE_RATE_HP, .u.data = FEC_AUTO },
989 { .cmd = DTV_CODE_RATE_LP, .u.data = FEC_AUTO },
990 { .cmd = DTV_GUARD_INTERVAL, .u.data = GUARD_INTERVAL_AUTO },
991 { .cmd = DTV_TRANSMISSION_MODE,.u.data = TRANSMISSION_MODE_AUTO },
992 { .cmd = DTV_HIERARCHY, .u.data = HIERARCHY_AUTO },
993 { .cmd = DTV_TUNE },
996 static struct dtv_property dvbt2_cmdargs[] = {
997 { .cmd = DTV_DELIVERY_SYSTEM, .u.data = SYS_DVBT2 },
998 { .cmd = DTV_FREQUENCY, .u.data = 0 },
999 { .cmd = DTV_MODULATION, .u.data = QAM_AUTO },
1000 { .cmd = DTV_INVERSION, .u.data = INVERSION_AUTO },
1001 { .cmd = DTV_BANDWIDTH_HZ, .u.data = 8000000 },
1002 { .cmd = DTV_CODE_RATE_HP, .u.data = FEC_AUTO },
1003 { .cmd = DTV_CODE_RATE_LP, .u.data = FEC_AUTO },
1004 { .cmd = DTV_GUARD_INTERVAL, .u.data = GUARD_INTERVAL_AUTO },
1005 { .cmd = DTV_TRANSMISSION_MODE,.u.data = TRANSMISSION_MODE_AUTO },
1006 { .cmd = DTV_HIERARCHY, .u.data = HIERARCHY_AUTO },
1007 { .cmd = DTV_STREAM_ID, .u.data = 0 },
1008 { .cmd = DTV_TUNE },
1011 static struct dtv_properties dvbt2_cmdseq = {
1012 .num = sizeof(dvbt2_cmdargs)/sizeof(struct dtv_property),
1013 .props = dvbt2_cmdargs
1016 static struct dtv_properties dvbt_cmdseq = {
1017 .num = sizeof(dvbt_cmdargs)/sizeof(struct dtv_property),
1018 .props = dvbt_cmdargs
1021 /* ATSC + DVB-C annex B */
1022 static struct dtv_property atsc_cmdargs[] = {
1023 { .cmd = DTV_DELIVERY_SYSTEM, .u.data = SYS_ATSC },
1024 { .cmd = DTV_FREQUENCY, .u.data = 0 },
1025 { .cmd = DTV_MODULATION, .u.data = QAM_AUTO },
1026 { .cmd = DTV_INVERSION, .u.data = INVERSION_AUTO },
1027 { .cmd = DTV_TUNE },
1029 static struct dtv_properties atsc_cmdseq = {
1030 .num = sizeof(atsc_cmdargs)/sizeof(struct dtv_property),
1031 .props = atsc_cmdargs
1034 static struct dtv_property isdbt_cmdargs[] = {
1035 { .cmd = DTV_DELIVERY_SYSTEM, .u.data = SYS_ISDBT },
1036 { .cmd = DTV_FREQUENCY, .u.data = 0 },
1037 { .cmd = DTV_BANDWIDTH_HZ, .u.data = 6000000 },
1038 { .cmd = DTV_INVERSION, .u.data = INVERSION_AUTO },
1039 { .cmd = DTV_ISDBT_LAYERA_FEC, .u.data = FEC_AUTO },
1040 { .cmd = DTV_ISDBT_LAYERA_MODULATION, .u.data = QAM_AUTO },
1041 { .cmd = DTV_ISDBT_LAYERA_SEGMENT_COUNT, .u.data = 0 },
1042 { .cmd = DTV_ISDBT_LAYERA_TIME_INTERLEAVING,.u.data = 0 },
1043 { .cmd = DTV_ISDBT_LAYERB_FEC, .u.data = FEC_AUTO },
1044 { .cmd = DTV_ISDBT_LAYERB_MODULATION, .u.data = QAM_AUTO },
1045 { .cmd = DTV_ISDBT_LAYERB_SEGMENT_COUNT, .u.data = 0 },
1046 { .cmd = DTV_ISDBT_LAYERB_TIME_INTERLEAVING,.u.data = 0 },
1047 { .cmd = DTV_ISDBT_LAYERC_FEC, .u.data = FEC_AUTO },
1048 { .cmd = DTV_ISDBT_LAYERC_MODULATION, .u.data = QAM_AUTO },
1049 { .cmd = DTV_ISDBT_LAYERC_SEGMENT_COUNT, .u.data = 0 },
1050 { .cmd = DTV_ISDBT_LAYERC_TIME_INTERLEAVING,.u.data = 0 },
1051 { .cmd = DTV_TUNE },
1054 static struct dtv_properties isdbt_cmdseq = {
1055 .num = sizeof(isdbt_cmdargs)/sizeof(struct dtv_property),
1056 .props = isdbt_cmdargs
1059 #define DELSYS 0
1060 #define FREQUENCY 1
1061 #define MODULATION 2
1062 #define INVERSION 3
1063 #define SYMBOL_RATE 4
1064 #define BANDWIDTH 4
1065 #define FEC_INNER 5
1066 #define FEC_LP 6
1067 #define GUARD 7
1068 #define TRANSMISSION 8
1070 #define HIERARCHY 9
1071 #define PLP_ID 10
1073 //ISDBT
1074 #define ISDBT_BANDWIDTH 2
1075 #define ISDBT_LAYERA_FEC 4
1076 #define ISDBT_LAYERA_MODULATION 5
1077 #define ISDBT_LAYERA_SEGMENT_COUNT 6
1078 #define ISDBT_LAYERA_TIME_INTERLEAVING 7
1079 #define ISDBT_LAYERB_FEC 8
1080 #define ISDBT_LAYERB_MODULATION 9
1081 #define ISDBT_LAYERB_SEGMENT_COUNT 10
1082 #define ISDBT_LAYERB_TIME_INTERLEAVING 11
1083 #define ISDBT_LAYERC_FEC 12
1084 #define ISDBT_LAYERC_MODULATION 13
1085 #define ISDBT_LAYERC_SEGMENT_COUNT 14
1086 #define ISDBT_LAYERC_TIME_INTERLEAVING 15
1088 struct dtv_property pclear[] = {
1089 { .cmd = DTV_CLEAR },
1092 struct dtv_properties cmdclear = {
1093 .num = 1,
1094 .props = pclear
1097 static fe_delivery_system_t
1098 FrontendGuessSystem( fe_delivery_system_t *p_systems, int i_systems )
1100 if ( psz_delsys != NULL )
1102 if ( !strcasecmp( psz_delsys, "DVBS" ) )
1103 return SYS_DVBS;
1104 if ( !strcasecmp( psz_delsys, "DVBS2" ) )
1105 return SYS_DVBS2;
1106 if ( !strcasecmp( psz_delsys, "DVBC_ANNEX_A" ) )
1107 #if DVBAPI_VERSION >= 505
1108 return SYS_DVBC_ANNEX_A;
1109 #else
1110 return SYS_DVBC_ANNEX_AC;
1111 #endif
1112 if ( !strcasecmp( psz_delsys, "DVBC_ANNEX_B" ) )
1113 return SYS_DVBC_ANNEX_B;
1114 if ( !strcasecmp( psz_delsys, "DVBT" ) )
1115 return SYS_DVBT;
1116 if ( !strcasecmp( psz_delsys, "DVBT2" ) )
1117 return SYS_DVBT2;
1118 if ( !strcasecmp( psz_delsys, "ATSC" ) )
1119 return SYS_ATSC;
1120 if ( !strcasecmp( psz_delsys, "ISDBT" ) )
1121 return SYS_ISDBT;
1122 msg_Err( NULL, "unknown delivery system %s", psz_delsys );
1123 exit(1);
1126 if ( i_systems == 1 )
1127 return p_systems[0];
1129 int i;
1130 for ( i = 0; i < i_systems; i++ )
1132 switch ( p_systems[i] )
1134 case SYS_DVBS:
1135 if ( i_frequency < 50000000 )
1136 return SYS_DVBS;
1137 break;
1138 #if DVBAPI_VERSION >= 505
1139 case SYS_DVBC_ANNEX_A:
1140 if ( i_frequency > 50000000 || i_srate != 27500000 ||
1141 psz_modulation != NULL )
1142 return SYS_DVBC_ANNEX_A;
1143 break;
1144 #else
1145 case SYS_DVBC_ANNEX_AC:
1146 if ( i_frequency > 50000000 || i_srate != 27500000 ||
1147 psz_modulation != NULL )
1148 return SYS_DVBC_ANNEX_AC;
1149 break;
1150 #endif
1151 case SYS_DVBT:
1152 if ( i_frequency > 50000000 )
1153 return SYS_DVBT;
1154 break;
1155 case SYS_DVBT2:
1156 if ( i_frequency > 50000000 && (dvb_plp_id) )
1157 return SYS_DVBT2;
1158 break;
1159 default:
1160 break;
1164 msg_Warn( NULL, "couldn't guess delivery system, use --delsys" );
1165 return p_systems[0];
1168 static void FrontendSet( bool b_init )
1170 struct dvb_frontend_info info;
1171 struct dtv_properties *p;
1172 fe_delivery_system_t p_systems[MAX_DELIVERY_SYSTEMS] = { 0 };
1173 int i_systems = 0;
1175 if ( ioctl( i_frontend, FE_GET_INFO, &info ) < 0 )
1177 msg_Err( NULL, "FE_GET_INFO failed (%s)", strerror(errno) );
1178 exit(1);
1181 uint32_t version = 0x300;
1182 #if DVBAPI_VERSION >= 505
1183 if ( ioctl( i_frontend, FE_GET_PROPERTY, &info_cmdseq ) < 0 )
1185 #endif
1186 /* DVBv3 device */
1187 switch ( info.type )
1189 case FE_OFDM:
1190 p_systems[i_systems++] = SYS_DVBT;
1191 #if DVBAPI_VERSION >= 505
1192 if ( info.caps & FE_CAN_2G_MODULATION )
1193 p_systems[i_systems++] = SYS_DVBT2;
1194 #endif
1195 break;
1196 case FE_QAM:
1197 #if DVBAPI_VERSION >= 505
1198 p_systems[i_systems++] = SYS_DVBC_ANNEX_A;
1199 #else
1200 p_systems[i_systems++] = SYS_DVBC_ANNEX_AC;
1201 #endif
1202 break;
1203 case FE_QPSK:
1204 p_systems[i_systems++] = SYS_DVBS;
1205 if ( info.caps & FE_CAN_2G_MODULATION )
1206 p_systems[i_systems++] = SYS_DVBS2;
1207 break;
1208 case FE_ATSC:
1209 if ( info.caps & (FE_CAN_8VSB | FE_CAN_16VSB) )
1210 p_systems[i_systems++] = SYS_ATSC;
1211 if ( info.caps & (FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_QAM_AUTO) )
1212 p_systems[i_systems++] = SYS_DVBC_ANNEX_B;
1213 break;
1214 default:
1215 msg_Err( NULL, "unknown frontend type %d", info.type );
1216 exit(1);
1218 #if DVBAPI_VERSION >= 505
1220 else
1222 version = info_cmdargs[0].u.data;
1223 if ( ioctl( i_frontend, FE_GET_PROPERTY, &enum_cmdseq ) < 0 )
1225 msg_Err( NULL, "unable to query frontend" );
1226 exit(1);
1228 i_systems = enum_cmdargs[0].u.buffer.len;
1229 if ( i_systems < 1 )
1231 msg_Err( NULL, "no available delivery system" );
1232 exit(1);
1235 int i;
1236 for ( i = 0; i < i_systems; i++ )
1237 p_systems[i] = enum_cmdargs[0].u.buffer.data[i];
1239 #endif
1241 if ( b_init )
1242 FrontendInfo( &info, version, p_systems, i_systems );
1244 /* Clear frontend commands */
1245 if ( ioctl( i_frontend, FE_SET_PROPERTY, &cmdclear ) < 0 )
1247 msg_Err( NULL, "Unable to clear frontend" );
1248 exit(1);
1251 fe_delivery_system_t system = FrontendGuessSystem( p_systems, i_systems );
1252 switch ( system )
1254 case SYS_DVBT:
1255 p = &dvbt_cmdseq;
1256 p->props[DELSYS].u.data = system;
1257 p->props[FREQUENCY].u.data = i_frequency;
1258 p->props[INVERSION].u.data = GetInversion();
1259 if ( psz_modulation != NULL )
1260 p->props[MODULATION].u.data = GetModulation();
1261 p->props[BANDWIDTH].u.data = i_bandwidth * 1000000;
1262 p->props[FEC_INNER].u.data = GetFECInner(info.caps);
1263 p->props[FEC_LP].u.data = GetFECLP(info.caps);
1264 p->props[GUARD].u.data = GetGuard();
1265 p->props[TRANSMISSION].u.data = GetTransmission();
1266 p->props[HIERARCHY].u.data = GetHierarchy();
1268 msg_Dbg( NULL, "tuning DVB-T frontend to f=%d bandwidth=%d inversion=%d fec_hp=%d fec_lp=%d hierarchy=%d modulation=%s guard=%d transmission=%d",
1269 i_frequency, i_bandwidth, i_inversion, i_fec, i_fec_lp,
1270 i_hierarchy,
1271 psz_modulation == NULL ? "qam_auto" : psz_modulation,
1272 i_guard, i_transmission );
1273 break;
1274 case SYS_DVBT2:
1275 p = &dvbt2_cmdseq;
1276 p->props[DELSYS].u.data = system;
1277 p->props[FREQUENCY].u.data = i_frequency;
1278 p->props[INVERSION].u.data = GetInversion();
1279 if ( psz_modulation != NULL )
1280 p->props[MODULATION].u.data = GetModulation();
1281 p->props[BANDWIDTH].u.data = i_bandwidth * 1000000;
1282 p->props[FEC_INNER].u.data = GetFECInner(info.caps);
1283 p->props[FEC_LP].u.data = GetFECLP(info.caps);
1284 p->props[GUARD].u.data = GetGuard();
1285 p->props[TRANSMISSION].u.data = GetTransmission();
1286 p->props[HIERARCHY].u.data = GetHierarchy();
1287 p->props[PLP_ID].u.data = dvb_plp_id;
1289 msg_Dbg( NULL, "tuning DVB-T2 frontend to f=%d bandwidth=%d inversion=%d fec_hp=%d fec_lp=%d hierarchy=%d modulation=%s guard=%d transmission=%d PLP_ID=%d ",
1290 i_frequency, i_bandwidth, i_inversion, i_fec, i_fec_lp,
1291 i_hierarchy,
1292 psz_modulation == NULL ? "qam_auto" : psz_modulation,
1293 i_guard, i_transmission, p->props[PLP_ID].u.data );
1294 break;
1295 #if DVBAPI_VERSION >= 505
1296 case SYS_DVBC_ANNEX_A:
1297 #else
1298 case SYS_DVBC_ANNEX_AC:
1299 #endif
1300 p = &dvbc_cmdseq;
1301 p->props[FREQUENCY].u.data = i_frequency;
1302 p->props[INVERSION].u.data = GetInversion();
1303 if ( psz_modulation != NULL )
1304 p->props[MODULATION].u.data = GetModulation();
1305 p->props[SYMBOL_RATE].u.data = i_srate;
1307 msg_Dbg( NULL, "tuning DVB-C frontend to f=%d srate=%d inversion=%d modulation=%s",
1308 i_frequency, i_srate, i_inversion,
1309 psz_modulation == NULL ? "qam_auto" : psz_modulation );
1310 break;
1312 case SYS_DVBC_ANNEX_B:
1313 p = &atsc_cmdseq;
1314 p->props[DELSYS].u.data = system;
1315 p->props[FREQUENCY].u.data = i_frequency;
1316 p->props[INVERSION].u.data = GetInversion();
1317 if ( psz_modulation != NULL )
1318 p->props[MODULATION].u.data = GetModulation();
1320 msg_Dbg( NULL, "tuning ATSC cable frontend to f=%d inversion=%d modulation=%s",
1321 i_frequency, i_inversion,
1322 psz_modulation == NULL ? "qam_auto" : psz_modulation );
1323 break;
1325 case SYS_DVBS:
1326 case SYS_DVBS2:
1327 if ( psz_modulation != NULL )
1329 p = &dvbs2_cmdseq;
1330 p->props[MODULATION].u.data = GetModulation();
1331 p->props[IDX_DVBS2_PILOT].u.data = GetPilot();
1332 p->props[IDX_DVBS2_ROLLOFF].u.data = GetRollOff();
1333 p->props[IDX_DVBS2_STREAM_ID].u.data = i_mis;
1335 else
1336 p = &dvbs_cmdseq;
1338 p->props[INVERSION].u.data = GetInversion();
1339 p->props[SYMBOL_RATE].u.data = i_srate;
1340 p->props[FEC_INNER].u.data = GetFECInner(info.caps);
1341 p->props[FREQUENCY].u.data = FrontendDoDiseqc();
1343 msg_Dbg( NULL, "tuning DVB-S frontend to f=%d srate=%d inversion=%d fec=%d rolloff=%d modulation=%s pilot=%d mis=%d /pls-mode: %s (%d) pls-code: %d is-id: %d /",
1344 i_frequency, i_srate, i_inversion, i_fec, i_rolloff,
1345 psz_modulation == NULL ? "legacy" : psz_modulation, i_pilot,
1346 i_mis, psz_mis_pls_mode, i_mis_pls_mode, i_mis_pls_code, i_mis_is_id );
1347 break;
1349 case SYS_ATSC:
1350 p = &atsc_cmdseq;
1351 p->props[FREQUENCY].u.data = i_frequency;
1352 p->props[INVERSION].u.data = GetInversion();
1353 if ( psz_modulation != NULL )
1354 p->props[MODULATION].u.data = GetModulation();
1356 msg_Dbg( NULL, "tuning ATSC frontend to f=%d inversion=%d modulation=%s",
1357 i_frequency, i_inversion,
1358 psz_modulation == NULL ? "qam_auto" : psz_modulation );
1359 break;
1360 case SYS_ISDBT:
1361 p = &isdbt_cmdseq;
1362 p->props[DELSYS].u.data = system;
1363 p->props[FREQUENCY].u.data = i_frequency;
1364 p->props[ISDBT_BANDWIDTH].u.data = i_bandwidth * 1000000;
1365 p->props[INVERSION].u.data = GetInversion();
1366 p->props[ISDBT_LAYERA_FEC].u.data = FEC_AUTO;
1367 p->props[ISDBT_LAYERA_MODULATION].u.data = QAM_AUTO;
1368 p->props[ISDBT_LAYERA_SEGMENT_COUNT].u.data = 0;
1369 p->props[ISDBT_LAYERA_TIME_INTERLEAVING].u.data = 0;
1370 p->props[ISDBT_LAYERB_FEC].u.data = FEC_AUTO;
1371 p->props[ISDBT_LAYERB_MODULATION].u.data = QAM_AUTO;
1372 p->props[ISDBT_LAYERB_SEGMENT_COUNT].u.data = 0;
1373 p->props[ISDBT_LAYERB_TIME_INTERLEAVING].u.data = 0;
1374 p->props[ISDBT_LAYERC_FEC].u.data = FEC_AUTO;
1375 p->props[ISDBT_LAYERC_MODULATION].u.data = QAM_AUTO;
1376 p->props[ISDBT_LAYERC_SEGMENT_COUNT].u.data = 0;
1377 p->props[ISDBT_LAYERC_TIME_INTERLEAVING].u.data = 0;
1379 msg_Dbg( NULL, "tuning ISDB-T frontend to f=%d bandwidth=%d ",
1380 i_frequency, i_bandwidth);
1381 break;
1383 default:
1384 msg_Err( NULL, "unknown frontend type %d", info.type );
1385 exit(1);
1388 /* Empty the event queue */
1389 for ( ; ; )
1391 struct dvb_frontend_event event;
1392 if ( ioctl( i_frontend, FE_GET_EVENT, &event ) < 0
1393 && errno == EWOULDBLOCK )
1394 break;
1397 /* Now send it all to the frontend device */
1398 if ( ioctl( i_frontend, FE_SET_PROPERTY, p ) < 0 )
1400 msg_Err( NULL, "setting frontend failed (%s)", strerror(errno) );
1401 exit(1);
1404 i_last_status = 0;
1406 if (i_frontend_timeout_duration)
1407 ev_timer_again(event_loop, &lock_watcher);
1410 #else /* !S2API */
1412 #warning "You are trying to compile DVBlast with an outdated linux-dvb interface."
1413 #warning "DVBlast will be very limited and some options will have no effect."
1415 static void FrontendSet( bool b_init )
1417 struct dvb_frontend_info info;
1418 struct dvb_frontend_parameters fep;
1420 if ( ioctl( i_frontend, FE_GET_INFO, &info ) < 0 )
1422 msg_Err( NULL, "FE_GET_INFO failed (%s)", strerror(errno) );
1423 exit(1);
1426 switch ( info.type )
1428 case FE_OFDM:
1429 fep.frequency = i_frequency;
1430 fep.inversion = INVERSION_AUTO;
1432 switch ( i_bandwidth )
1434 case 6: fep.u.ofdm.bandwidth = BANDWIDTH_6_MHZ; break;
1435 case 7: fep.u.ofdm.bandwidth = BANDWIDTH_7_MHZ; break;
1436 default:
1437 case 8: fep.u.ofdm.bandwidth = BANDWIDTH_8_MHZ; break;
1440 fep.u.ofdm.code_rate_HP = FEC_AUTO;
1441 fep.u.ofdm.code_rate_LP = FEC_AUTO;
1442 fep.u.ofdm.constellation = QAM_AUTO;
1443 fep.u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO;
1444 fep.u.ofdm.guard_interval = GUARD_INTERVAL_AUTO;
1445 fep.u.ofdm.hierarchy_information = HIERARCHY_AUTO;
1447 msg_Dbg( NULL, "tuning OFDM frontend to f=%d, bandwidth=%d",
1448 i_frequency, i_bandwidth );
1449 break;
1451 case FE_QAM:
1452 fep.frequency = i_frequency;
1453 fep.inversion = INVERSION_AUTO;
1454 fep.u.qam.symbol_rate = i_srate;
1455 fep.u.qam.fec_inner = FEC_AUTO;
1456 fep.u.qam.modulation = QAM_AUTO;
1458 msg_Dbg( NULL, "tuning QAM frontend to f=%d, srate=%d",
1459 i_frequency, i_srate );
1460 break;
1462 case FE_QPSK:
1463 fep.inversion = INVERSION_AUTO;
1464 fep.u.qpsk.symbol_rate = i_srate;
1465 fep.u.qpsk.fec_inner = FEC_AUTO;
1466 fep.frequency = FrontendDoDiseqc();
1468 msg_Dbg( NULL, "tuning QPSK frontend to f=%d, srate=%d",
1469 i_frequency, i_srate );
1470 break;
1472 #if DVBAPI_VERSION >= 301
1473 case FE_ATSC:
1474 fep.frequency = i_frequency;
1476 fep.u.vsb.modulation = QAM_AUTO;
1478 msg_Dbg( NULL, "tuning ATSC frontend to f=%d", i_frequency );
1479 break;
1480 #endif
1482 default:
1483 msg_Err( NULL, "unknown frontend type %d", info.type );
1484 exit(1);
1487 /* Empty the event queue */
1488 for ( ; ; )
1490 struct dvb_frontend_event event;
1491 if ( ioctl( i_frontend, FE_GET_EVENT, &event ) < 0
1492 && errno == EWOULDBLOCK )
1493 break;
1496 /* Now send it all to the frontend device */
1497 if ( ioctl( i_frontend, FE_SET_FRONTEND, &fep ) < 0 )
1499 msg_Err( NULL, "setting frontend failed (%s)", strerror(errno) );
1500 exit(1);
1503 i_last_status = 0;
1505 if (i_frontend_timeout_duration)
1506 ev_timer_again(event_loop, &lock_watcher);
1509 #endif /* S2API */
1511 /*****************************************************************************
1512 * dvb_FrontendStatus
1513 *****************************************************************************/
1514 uint8_t dvb_FrontendStatus( uint8_t *p_answer, ssize_t *pi_size )
1516 struct ret_frontend_status *p_ret = (struct ret_frontend_status *)p_answer;
1518 if ( ioctl( i_frontend, FE_GET_INFO, &p_ret->info ) < 0 )
1520 msg_Err( NULL, "ioctl FE_GET_INFO failed (%s)", strerror(errno) );
1521 return RET_ERR;
1524 if ( ioctl( i_frontend, FE_READ_STATUS, &p_ret->i_status ) < 0 )
1526 msg_Err( NULL, "ioctl FE_READ_STATUS failed (%s)", strerror(errno) );
1527 return RET_ERR;
1530 if ( p_ret->i_status & FE_HAS_LOCK )
1532 if ( ioctl( i_frontend, FE_READ_BER, &p_ret->i_ber ) < 0 )
1533 msg_Err( NULL, "ioctl FE_READ_BER failed (%s)", strerror(errno) );
1535 if ( ioctl( i_frontend, FE_READ_SIGNAL_STRENGTH, &p_ret->i_strength )
1536 < 0 )
1537 msg_Err( NULL, "ioctl FE_READ_SIGNAL_STRENGTH failed (%s)",
1538 strerror(errno) );
1540 if ( ioctl( i_frontend, FE_READ_SNR, &p_ret->i_snr ) < 0 )
1541 msg_Err( NULL, "ioctl FE_READ_SNR failed (%s)", strerror(errno) );
1544 *pi_size = sizeof(struct ret_frontend_status);
1545 return RET_FRONTEND_STATUS;
1548 #endif