Merge branch 'quarium-dvb-ci'
[dvblast.git] / dvb.c
blobb6f479036d1bce94cd19943c067368937a950580
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, i_sec;
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_OpenDvr
92 *****************************************************************************/
93 void dvb_OpenDvr( void )
95 char psz_tmp[128];
97 sprintf( psz_tmp, "/dev/dvb/adapter%d/dvr%d", i_adapter, i_fenum );
98 if( (i_dvr = open(psz_tmp, O_RDONLY | O_NONBLOCK)) < 0 )
100 msg_Info(NULL, "opening device %s failed (%s), fallback on sec device",
101 psz_tmp, strerror(errno));
103 /* try to read from sec device */
104 sprintf(psz_tmp, "/dev/dvb/adapter%d/sec%d", i_adapter, i_fenum);
105 if ( (i_dvr = open(psz_tmp, O_RDONLY | O_NONBLOCK)) < 0 )
107 msg_Err(NULL, "opening device %s failed (%s)", psz_tmp,
108 strerror(errno));
109 exit(1);
113 if ( ioctl( i_dvr, DMX_SET_BUFFER_SIZE, i_dvr_buffer_size ) < 0 )
115 msg_Warn( NULL, "couldn't set %s buffer size (%s)", psz_tmp,
116 strerror(errno) );
119 ev_io_init(&dvr_watcher, DVRRead, i_dvr, EV_READ);
120 ev_io_start(event_loop, &dvr_watcher);
123 /*****************************************************************************
124 * dvb_OpenSec
125 *****************************************************************************/
126 void dvb_OpenSec( void )
128 char psz_tmp[128];
130 msg_Dbg( NULL, "compiled with DVB API version %d.%d", DVB_API_VERSION, DVB_API_VERSION_MINOR );
132 i_frontend = -1;
134 sprintf( psz_tmp, "/dev/dvb/adapter%d/sec%d", i_adapter, i_secnum );
135 if( (i_sec = open(psz_tmp, O_WRONLY)) < 0 )
137 msg_Err(NULL, "opening device %s failed (%s)", psz_tmp,
138 strerror(errno));
139 exit(1);
143 /*****************************************************************************
144 * dvb_Open
145 *****************************************************************************/
146 void dvb_Open( void )
148 char psz_tmp[128];
150 msg_Dbg( NULL, "compiled with DVB API version %d.%d", DVB_API_VERSION, DVB_API_VERSION_MINOR );
152 if ( i_frequency )
154 sprintf( psz_tmp, "/dev/dvb/adapter%d/frontend%d", i_adapter, i_fenum );
155 if( (i_frontend = open(psz_tmp, O_RDWR | O_NONBLOCK)) < 0 )
157 msg_Err( NULL, "opening device %s failed (%s)", psz_tmp,
158 strerror(errno) );
159 exit(1);
162 FrontendSet(true);
164 else
166 i_frontend = -1;
169 dvb_OpenDvr();
171 if ( i_frontend != -1 )
173 ev_io_init(&frontend_watcher, FrontendRead, i_frontend, EV_READ);
174 ev_io_start(event_loop, &frontend_watcher);
177 ev_timer_init(&lock_watcher, FrontendLockCb,
178 i_frontend_timeout_duration / 1000000.,
179 i_frontend_timeout_duration / 1000000.);
180 ev_timer_init(&mute_watcher, DVRMuteCb,
181 DVR_READ_TIMEOUT / 1000000.,
182 DVR_READ_TIMEOUT / 1000000.);
184 en50221_Init();
187 /*****************************************************************************
188 * dvb_Reset
189 *****************************************************************************/
190 void dvb_Reset( void )
192 if ( i_frequency )
193 FrontendSet(true);
196 /*****************************************************************************
197 * DVR events
198 *****************************************************************************/
199 static void DVRRead(struct ev_loop *loop, struct ev_io *w, int revents)
201 int i, i_len;
202 block_t *p_ts = p_freelist, **pp_current = &p_ts;
203 struct iovec p_iov[MAX_READ_ONCE];
205 for ( i = 0; i < MAX_READ_ONCE; i++ )
207 if ( (*pp_current) == NULL ) *pp_current = block_New();
208 p_iov[i].iov_base = (*pp_current)->p_ts;
209 p_iov[i].iov_len = TS_SIZE;
210 pp_current = &(*pp_current)->p_next;
213 if ( (i_len = readv(i_dvr, p_iov, MAX_READ_ONCE)) < 0 )
215 msg_Err( NULL, "couldn't read from DVR device (%s)",
216 strerror(errno) );
217 i_len = 0;
219 i_len /= TS_SIZE;
221 if ( i_len )
222 ev_timer_again(loop, &mute_watcher);
224 pp_current = &p_ts;
225 while ( i_len && *pp_current )
227 pp_current = &(*pp_current)->p_next;
228 i_len--;
231 p_freelist = *pp_current;
232 *pp_current = NULL;
234 demux_Run( p_ts );
237 static void DVRMuteCb(struct ev_loop *loop, struct ev_timer *w, int revents)
239 msg_Warn( NULL, "no DVR output, resetting" );
240 ev_timer_stop(loop, w);
242 switch (i_print_type) {
243 case PRINT_XML:
244 fprintf(print_fh, "<EVENT type=\"reset\" cause=\"dvr\" />\n");
245 break;
246 case PRINT_TEXT:
247 fprintf(print_fh, "reset cause: dvr\n");
248 break;
249 default:
250 break;
252 if ( i_frequency )
253 FrontendSet(false);
254 en50221_Reset();
259 * Demux
262 /*****************************************************************************
263 * dvb_SetFilter : controls the demux to add a filter
264 *****************************************************************************/
265 int dvb_SetFilter( uint16_t i_pid )
267 struct dmx_pes_filter_params s_filter_params;
268 char psz_tmp[128];
269 int i_fd;
271 sprintf( psz_tmp, "/dev/dvb/adapter%d/demux%d", i_adapter, i_fenum );
272 if( (i_fd = open(psz_tmp, O_RDWR)) < 0 )
274 msg_Err( NULL, "DMXSetFilter: opening device failed (%s)",
275 strerror(errno) );
276 return -1;
279 s_filter_params.pid = i_pid;
280 s_filter_params.input = DMX_IN_FRONTEND;
281 s_filter_params.output = DMX_OUT_TS_TAP;
282 s_filter_params.flags = DMX_IMMEDIATE_START;
283 s_filter_params.pes_type = DMX_PES_OTHER;
285 if ( ioctl( i_fd, DMX_SET_PES_FILTER, &s_filter_params ) < 0 )
287 msg_Err( NULL, "failed setting filter on %d (%s)", i_pid,
288 strerror(errno) );
289 close( i_fd );
290 return -1;
293 msg_Dbg( NULL, "setting filter on PID %d", i_pid );
295 return i_fd;
298 /*****************************************************************************
299 * dvb_UnsetFilter : removes a filter
300 *****************************************************************************/
301 void dvb_UnsetFilter( int i_fd, uint16_t i_pid )
303 if ( ioctl( i_fd, DMX_STOP ) < 0 )
304 msg_Err( NULL, "DMX_STOP failed (%s)", strerror(errno) );
305 else
306 msg_Dbg( NULL, "unsetting filter on PID %d", i_pid );
308 close( i_fd );
311 /*****************************************************************************
312 * dvb_WriteSec: write data to sec device
313 *****************************************************************************/
314 void dvb_WriteSec( block_t *p_ts )
316 int i_iov = 0;
318 for (block_t *p_b = p_ts; p_b; p_b = p_b->p_next)
319 i_iov++;
321 struct iovec p_iov[i_iov];
322 struct iovec *p_current = &p_iov[0];
323 for (block_t *p_b = p_ts; p_b; p_b = p_b->p_next)
325 p_current->iov_base = p_b->p_ts;
326 p_current->iov_len = TS_SIZE;
327 p_current++;
330 int i_len;
331 if ( (i_len = writev( i_sec, p_iov, i_iov )) < 0 )
333 msg_Err( NULL, "couldn't write to DVB sec (%s)", strerror(errno) );
336 block_DeleteChain( p_ts );
340 * Frontend
343 /*****************************************************************************
344 * Print info
345 *****************************************************************************/
346 static void PrintCb( struct ev_loop *loop, struct ev_timer *w, int revents )
348 uint32_t i_ber = 0;
349 uint16_t i_strength = 0, i_snr = 0;
350 uint32_t i_uncorrected = 0;
352 ioctl(i_frontend, FE_READ_BER, &i_ber);
353 ioctl(i_frontend, FE_READ_SIGNAL_STRENGTH, &i_strength);
354 ioctl(i_frontend, FE_READ_SNR, &i_snr);
355 ioctl(i_frontend, FE_READ_UNCORRECTED_BLOCKS, &i_uncorrected);
357 int64_t i_strength_dbm = i_strength;
358 int64_t i_snr_db = i_snr;
360 #ifdef DTV_STAT_SIGNAL_STRENGTH
361 struct dtv_property prop[] = {
362 { .cmd = DTV_STAT_SIGNAL_STRENGTH },
363 { .cmd = DTV_STAT_CNR },
366 struct dtv_properties props = { .num = 2, .props = prop };
367 if (ioctl(i_frontend, FE_GET_PROPERTY, &props) != -1)
369 if (prop[0].u.st.len > 0 &&
370 prop[0].u.st.stat[0].scale == FE_SCALE_DECIBEL)
371 i_strength_dbm = prop[0].u.st.stat[0].svalue;
372 if (prop[1].u.st.len > 0 &&
373 prop[1].u.st.stat[0].scale == FE_SCALE_DECIBEL)
374 i_snr_db = prop[1].u.st.stat[0].svalue;
376 #endif
378 switch (i_print_type)
380 case PRINT_XML:
381 fprintf(print_fh,
382 "<STATUS type=\"frontend\" ber=\"%"PRIu32"\" strength=\"%"PRId64"\" snr=\"%"PRId64"\" uncorrected=\"%"PRIu32"\" />\n",
383 i_ber, i_strength_dbm, i_snr_db, i_uncorrected);
384 break;
385 case PRINT_TEXT:
386 fprintf(print_fh, "frontend ber: %"PRIu32" strength: %"PRId64" snr: %"PRId64" uncorrected: %"PRIu32"\n",
387 i_ber, i_strength_dbm, i_snr_db, i_uncorrected);
388 break;
389 default:
390 break;
394 /*****************************************************************************
395 * Frontend events
396 *****************************************************************************/
397 static void FrontendRead(struct ev_loop *loop, struct ev_io *w, int revents)
399 struct dvb_frontend_event event;
400 fe_status_t i_status, i_diff;
402 for( ;; )
404 int i_ret = ioctl( i_frontend, FE_GET_EVENT, &event );
406 if( i_ret < 0 )
408 if( errno == EWOULDBLOCK )
409 return; /* no more events */
411 msg_Err( NULL, "reading frontend event failed (%d) %s",
412 i_ret, strerror(errno) );
413 return;
416 i_status = event.status;
417 i_diff = i_status ^ i_last_status;
418 i_last_status = i_status;
421 #define IF_UP( x ) \
423 if ( i_diff & (x) ) \
425 if ( i_status & (x) )
427 IF_UP( FE_HAS_SIGNAL )
428 msg_Dbg( NULL, "frontend has acquired signal" );
429 else
430 msg_Dbg( NULL, "frontend has lost signal" );
432 IF_UP( FE_HAS_CARRIER )
433 msg_Dbg( NULL, "frontend has acquired carrier" );
434 else
435 msg_Dbg( NULL, "frontend has lost carrier" );
437 IF_UP( FE_HAS_VITERBI )
438 msg_Dbg( NULL, "frontend has acquired stable FEC" );
439 else
440 msg_Dbg( NULL, "frontend has lost FEC" );
442 IF_UP( FE_HAS_SYNC )
443 msg_Dbg( NULL, "frontend has acquired sync" );
444 else
445 msg_Dbg( NULL, "frontend has lost sync" );
447 IF_UP( FE_HAS_LOCK )
449 int32_t i_value = 0;
450 msg_Info( NULL, "frontend has acquired lock" );
451 switch (i_print_type) {
452 case PRINT_XML:
453 fprintf(print_fh, "<STATUS type=\"lock\" status=\"1\" />\n");
454 break;
455 case PRINT_TEXT:
456 fprintf(print_fh, "lock status: 1\n");
457 break;
458 default:
459 break;
462 ev_timer_stop(loop, &lock_watcher);
463 ev_timer_again(loop, &mute_watcher);
465 /* Read some statistics */
466 if( ioctl( i_frontend, FE_READ_BER, &i_value ) >= 0 )
467 msg_Dbg( NULL, "- Bit error rate: %d", i_value );
468 if( ioctl( i_frontend, FE_READ_SIGNAL_STRENGTH, &i_value ) >= 0 )
469 msg_Dbg( NULL, "- Signal strength: %d", i_value );
470 if( ioctl( i_frontend, FE_READ_SNR, &i_value ) >= 0 )
471 msg_Dbg( NULL, "- SNR: %d", i_value );
473 if (i_print_period)
475 ev_timer_init( &print_watcher, PrintCb,
476 i_print_period / 1000000.,
477 i_print_period / 1000000. );
478 ev_timer_start( event_loop, &print_watcher );
481 else
483 msg_Dbg( NULL, "frontend has lost lock" );
484 switch (i_print_type) {
485 case PRINT_XML:
486 fprintf(print_fh, "<STATUS type=\"lock\" status=\"0\"/>\n");
487 break;
488 case PRINT_TEXT:
489 fprintf(print_fh, "lock status: 0\n");
490 break;
491 default:
492 break;
495 if (i_frontend_timeout_duration)
497 ev_timer_stop(event_loop, &lock_watcher);
498 ev_timer_again(loop, &mute_watcher);
501 if (i_print_period)
502 ev_timer_stop(event_loop, &print_watcher);
505 IF_UP( FE_REINIT )
507 /* The frontend was reinited. */
508 msg_Warn( NULL, "reiniting frontend");
509 if ( i_frequency )
510 FrontendSet(true);
513 #undef IF_UP
517 static void FrontendLockCb(struct ev_loop *loop, struct ev_timer *w, int revents)
519 if ( i_quit_timeout_duration )
521 msg_Err( NULL, "no lock" );
522 ev_break(loop, EVBREAK_ALL);
523 return;
526 msg_Warn( NULL, "no lock, tuning again" );
527 ev_timer_stop(loop, w);
529 switch (i_print_type) {
530 case PRINT_XML:
531 fprintf(print_fh, "<EVENT type=\"reset\" cause=\"nolock\" />\n");
532 break;
533 case PRINT_TEXT:
534 fprintf(print_fh, "reset cause: nolock\n");
535 break;
536 default:
537 break;
539 if ( i_frequency )
540 FrontendSet(false);
543 static int FrontendDoDiseqc(void)
545 fe_sec_voltage_t fe_voltage;
546 fe_sec_tone_mode_t fe_tone;
547 int bis_frequency;
549 switch ( i_voltage )
551 case 0: fe_voltage = SEC_VOLTAGE_OFF; break;
552 default:
553 case 13: fe_voltage = SEC_VOLTAGE_13; break;
554 case 18: fe_voltage = SEC_VOLTAGE_18; break;
557 fe_tone = b_tone ? SEC_TONE_ON : SEC_TONE_OFF;
559 if ( strcmp( psz_lnb_type, "universal" ) == 0 )
561 /* Automatic mode. */
562 if ( i_frequency >= 950000 && i_frequency <= 2150000 )
564 msg_Dbg( NULL, "frequency %d is in IF-band", i_frequency );
565 bis_frequency = i_frequency;
567 else if ( i_frequency >= 2500000 && i_frequency <= 2700000 )
569 msg_Dbg( NULL, "frequency %d is in S-band", i_frequency );
570 bis_frequency = 3650000 - i_frequency;
572 else if ( i_frequency >= 3400000 && i_frequency <= 4200000 )
574 msg_Dbg( NULL, "frequency %d is in C-band (lower)", i_frequency );
575 bis_frequency = 5150000 - i_frequency;
577 else if ( i_frequency >= 4500000 && i_frequency <= 4800000 )
579 msg_Dbg( NULL, "frequency %d is in C-band (higher)", i_frequency );
580 bis_frequency = 5950000 - i_frequency;
582 else if ( i_frequency >= 10700000 && i_frequency < 11700000 )
584 msg_Dbg( NULL, "frequency %d is in Ku-band (lower)",
585 i_frequency );
586 bis_frequency = i_frequency - 9750000;
588 else if ( i_frequency >= 11700000 && i_frequency <= 13250000 )
590 msg_Dbg( NULL, "frequency %d is in Ku-band (higher)",
591 i_frequency );
592 bis_frequency = i_frequency - 10600000;
593 fe_tone = SEC_TONE_ON;
595 else
597 msg_Err( NULL, "frequency %d is out of any known band",
598 i_frequency );
599 exit(1);
602 else if ( strcmp( psz_lnb_type, "old-sky" ) == 0 )
604 if ( i_frequency >= 11700000 && i_frequency <= 13250000 )
606 msg_Dbg( NULL, "frequency %d is in Ku-band (higher)",
607 i_frequency );
608 bis_frequency = i_frequency - 11300000;
609 fe_tone = SEC_TONE_ON;
611 else
613 msg_Err( NULL, "frequency %d is out of any known band",
614 i_frequency );
615 exit(1);
618 else
620 msg_Err( NULL, "lnb-type '%s' is not known. Valid type: universal old-sky",
621 psz_lnb_type );
622 exit(1);
625 /* Switch off continuous tone. */
626 if ( ioctl( i_frontend, FE_SET_TONE, SEC_TONE_OFF ) < 0 )
628 msg_Err( NULL, "FE_SET_TONE failed (%s)", strerror(errno) );
629 exit(1);
632 /* Configure LNB voltage. */
633 if ( ioctl( i_frontend, FE_SET_VOLTAGE, fe_voltage ) < 0 )
635 msg_Err( NULL, "FE_SET_VOLTAGE failed (%s)", strerror(errno) );
636 exit(1);
639 /* Wait for at least 15 ms. Currently 100 ms because of broken drivers. */
640 msleep(100000);
642 /* Diseqc */
643 if ( i_satnum > 0 && i_satnum < 5 )
645 /* digital satellite equipment control,
646 * specification is available from http://www.eutelsat.com/
649 /* DiSEqC 1.1 */
650 struct dvb_diseqc_master_cmd uncmd =
651 { {0xe0, 0x10, 0x39, 0xf0, 0x00, 0x00}, 4};
653 /* DiSEqC 1.0 */
654 struct dvb_diseqc_master_cmd cmd =
655 { {0xe0, 0x10, 0x38, 0xf0, 0x00, 0x00}, 4};
657 cmd.msg[3] = 0xf0 /* reset bits */
658 | ((i_satnum - 1) << 2)
659 | (fe_voltage == SEC_VOLTAGE_13 ? 0 : 2)
660 | (fe_tone == SEC_TONE_ON ? 1 : 0);
662 if ( i_uncommitted > 0 && i_uncommitted < 17 )
664 uncmd.msg[3] = 0xf0 /* reset bits */
665 | (i_uncommitted - 1);
666 if( ioctl( i_frontend, FE_DISEQC_SEND_MASTER_CMD, &uncmd ) < 0 )
668 msg_Err( NULL, "ioctl FE_SEND_MASTER_CMD failed (%s)",
669 strerror(errno) );
670 exit(1);
672 /* Repeat uncommitted command */
673 uncmd.msg[0] = 0xe1; /* framing: master, no reply, repeated TX */
674 if( ioctl( i_frontend, FE_DISEQC_SEND_MASTER_CMD, &uncmd ) < 0 )
676 msg_Err( NULL, "ioctl FE_SEND_MASTER_CMD failed (%s)",
677 strerror(errno) );
678 exit(1);
680 /* Pause 125 ms between uncommitted & committed diseqc commands. */
681 msleep(125000);
684 if( ioctl( i_frontend, FE_DISEQC_SEND_MASTER_CMD, &cmd ) < 0 )
686 msg_Err( NULL, "ioctl FE_SEND_MASTER_CMD failed (%s)",
687 strerror(errno) );
688 exit(1);
690 msleep(100000); /* Should be 15 ms. */
692 /* Do it again just to be sure. */
693 cmd.msg[0] = 0xe1; /* framing: master, no reply, repeated TX */
694 if( ioctl( i_frontend, FE_DISEQC_SEND_MASTER_CMD, &cmd ) < 0 )
696 msg_Err( NULL, "ioctl FE_SEND_MASTER_CMD failed (%s)",
697 strerror(errno) );
698 exit(1);
700 msleep(100000); /* Again, should be 15 ms */
702 else if ( i_satnum == 0xA || i_satnum == 0xB )
704 /* A or B simple diseqc ("diseqc-compatible") */
705 if( ioctl( i_frontend, FE_DISEQC_SEND_BURST,
706 i_satnum == 0xB ? SEC_MINI_B : SEC_MINI_A ) < 0 )
708 msg_Err( NULL, "ioctl FE_SEND_BURST failed (%s)", strerror(errno) );
709 exit(1);
711 msleep(100000); /* ... */
714 if ( ioctl( i_frontend, FE_SET_TONE, fe_tone ) < 0 )
716 msg_Err( NULL, "FE_SET_TONE failed (%s)", strerror(errno) );
717 exit(1);
720 msleep(100000); /* ... */
722 msg_Dbg( NULL, "configuring LNB to v=%d p=%d satnum=%x uncommitted=%x lnb-type=%s bis_frequency=%d",
723 i_voltage, b_tone, i_satnum, i_uncommitted, psz_lnb_type, bis_frequency );
724 return bis_frequency;
727 #if DVB_API_VERSION >= 5
729 #if DVBAPI_VERSION < 505
730 #warning Your linux-dvb headers are old, you should consider upgrading your kernel and/or compiling against different kernel headers
731 #endif
733 /*****************************************************************************
734 * Helper functions for S2API
735 *****************************************************************************/
736 static fe_spectral_inversion_t GetInversion(void)
738 switch ( i_inversion )
740 case 0: return INVERSION_OFF;
741 case 1: return INVERSION_ON;
742 default:
743 msg_Warn( NULL, "invalid inversion %d", i_inversion );
744 case -1: return INVERSION_AUTO;
748 static fe_code_rate_t GetFEC(fe_caps_t fe_caps, int i_fec_value)
750 #define GET_FEC_INNER(fec, val) \
751 if ( (fe_caps & FE_CAN_##fec) && (i_fec_value == val) ) \
752 return fec;
754 GET_FEC_INNER(FEC_AUTO, 999);
755 GET_FEC_INNER(FEC_AUTO, -1);
756 if (i_fec_value == 0)
757 return FEC_NONE;
758 GET_FEC_INNER(FEC_1_2, 12);
759 GET_FEC_INNER(FEC_2_3, 23);
760 GET_FEC_INNER(FEC_3_4, 34);
761 if (i_fec_value == 35)
762 return FEC_3_5;
763 GET_FEC_INNER(FEC_4_5, 45);
764 GET_FEC_INNER(FEC_5_6, 56);
765 GET_FEC_INNER(FEC_6_7, 67);
766 GET_FEC_INNER(FEC_7_8, 78);
767 GET_FEC_INNER(FEC_8_9, 89);
768 if (i_fec_value == 910)
769 return FEC_9_10;
771 #undef GET_FEC_INNER
772 msg_Warn(NULL, "invalid FEC %d", i_fec_value );
773 return FEC_AUTO;
776 #define GetFECInner(caps) GetFEC(caps, i_fec)
777 #define GetFECLP(caps) GetFEC(caps, i_fec_lp)
779 static fe_modulation_t GetModulation(void)
781 #define GET_MODULATION( mod ) \
782 if ( !strcasecmp( psz_modulation, #mod ) ) \
783 return mod;
785 GET_MODULATION(QPSK);
786 GET_MODULATION(QAM_16);
787 GET_MODULATION(QAM_32);
788 GET_MODULATION(QAM_64);
789 GET_MODULATION(QAM_128);
790 GET_MODULATION(QAM_256);
791 GET_MODULATION(QAM_AUTO);
792 GET_MODULATION(VSB_8);
793 GET_MODULATION(VSB_16);
794 GET_MODULATION(PSK_8);
795 GET_MODULATION(APSK_16);
796 GET_MODULATION(APSK_32);
797 GET_MODULATION(DQPSK);
799 #undef GET_MODULATION
800 msg_Err( NULL, "invalid modulation %s", psz_modulation );
801 exit(1);
804 static fe_pilot_t GetPilot(void)
806 switch ( i_pilot )
808 case 0: return PILOT_OFF;
809 case 1: return PILOT_ON;
810 default:
811 msg_Warn( NULL, "invalid pilot %d", i_pilot );
812 case -1: return PILOT_AUTO;
816 static fe_rolloff_t GetRollOff(void)
818 switch ( i_rolloff )
820 case -1:
821 case 0: return ROLLOFF_AUTO;
822 case 20: return ROLLOFF_20;
823 case 25: return ROLLOFF_25;
824 default:
825 msg_Warn( NULL, "invalid rolloff %d", i_rolloff );
826 case 35: return ROLLOFF_35;
830 static fe_guard_interval_t GetGuard(void)
832 switch ( i_guard )
834 case 32: return GUARD_INTERVAL_1_32;
835 case 16: return GUARD_INTERVAL_1_16;
836 case 8: return GUARD_INTERVAL_1_8;
837 case 4: return GUARD_INTERVAL_1_4;
838 default:
839 msg_Warn( NULL, "invalid guard interval %d", i_guard );
840 case -1:
841 case 0: return GUARD_INTERVAL_AUTO;
845 static fe_transmit_mode_t GetTransmission(void)
847 switch ( i_transmission )
849 case 2: return TRANSMISSION_MODE_2K;
850 case 8: return TRANSMISSION_MODE_8K;
851 #ifdef TRANSMISSION_MODE_4K
852 case 4: return TRANSMISSION_MODE_4K;
853 #endif
854 default:
855 msg_Warn( NULL, "invalid tranmission mode %d", i_transmission );
856 case -1:
857 case 0: return TRANSMISSION_MODE_AUTO;
861 static fe_hierarchy_t GetHierarchy(void)
863 switch ( i_hierarchy )
865 case 0: return HIERARCHY_NONE;
866 case 1: return HIERARCHY_1;
867 case 2: return HIERARCHY_2;
868 case 4: return HIERARCHY_4;
869 default:
870 msg_Warn( NULL, "invalid intramission mode %d", i_transmission );
871 case -1: return HIERARCHY_AUTO;
875 /*****************************************************************************
876 * FrontendInfo : Print frontend info
877 *****************************************************************************/
878 static void FrontendInfo( struct dvb_frontend_info *info, uint32_t version,
879 fe_delivery_system_t *p_systems, int i_systems )
881 msg_Dbg( NULL, "using DVB API version %d.%d", version / 256, version % 256 );
882 msg_Dbg( NULL, "Frontend \"%s\" supports:", info->name );
883 msg_Dbg( NULL, " frequency min: %d, max: %d, stepsize: %d, tolerance: %d",
884 info->frequency_min, info->frequency_max,
885 info->frequency_stepsize, info->frequency_tolerance );
886 msg_Dbg( NULL, " symbolrate min: %d, max: %d, tolerance: %d",
887 info->symbol_rate_min, info->symbol_rate_max, info->symbol_rate_tolerance);
888 msg_Dbg( NULL, " capabilities:" );
890 #define FRONTEND_INFO(caps,val,msg) \
891 if ( caps & val ) \
892 msg_Dbg( NULL, " %s", msg );
894 FRONTEND_INFO( info->caps, FE_IS_STUPID, "FE_IS_STUPID" )
895 FRONTEND_INFO( info->caps, FE_CAN_INVERSION_AUTO, "INVERSION_AUTO" )
896 FRONTEND_INFO( info->caps, FE_CAN_FEC_1_2, "FEC_1_2" )
897 FRONTEND_INFO( info->caps, FE_CAN_FEC_2_3, "FEC_2_3" )
898 FRONTEND_INFO( info->caps, FE_CAN_FEC_3_4, "FEC_3_4" )
899 FRONTEND_INFO( info->caps, FE_CAN_FEC_4_5, "FEC_4_5" )
900 FRONTEND_INFO( info->caps, FE_CAN_FEC_5_6, "FEC_5_6" )
901 FRONTEND_INFO( info->caps, FE_CAN_FEC_6_7, "FEC_6_7" )
902 FRONTEND_INFO( info->caps, FE_CAN_FEC_7_8, "FEC_7_8" )
903 FRONTEND_INFO( info->caps, FE_CAN_FEC_8_9, "FEC_8_9" )
904 FRONTEND_INFO( info->caps, FE_CAN_FEC_AUTO,"FEC_AUTO")
905 FRONTEND_INFO( info->caps, FE_CAN_QPSK, "QPSK" )
906 FRONTEND_INFO( info->caps, FE_CAN_QAM_16, "QAM_16" )
907 FRONTEND_INFO( info->caps, FE_CAN_QAM_32, "QAM_32" )
908 FRONTEND_INFO( info->caps, FE_CAN_QAM_64, "QAM_64" )
909 FRONTEND_INFO( info->caps, FE_CAN_QAM_128,"QAM_128")
910 FRONTEND_INFO( info->caps, FE_CAN_QAM_256,"QAM_256")
911 FRONTEND_INFO( info->caps, FE_CAN_QAM_AUTO,"QAM_AUTO" )
912 FRONTEND_INFO( info->caps, FE_CAN_TRANSMISSION_MODE_AUTO, "TRANSMISSION_MODE_AUTO" )
913 FRONTEND_INFO( info->caps, FE_CAN_BANDWIDTH_AUTO, "BANDWIDTH_AUTO" )
914 FRONTEND_INFO( info->caps, FE_CAN_GUARD_INTERVAL_AUTO, "GUARD_INTERVAL_AUTO" )
915 FRONTEND_INFO( info->caps, FE_CAN_HIERARCHY_AUTO, "HIERARCHY_AUTO" )
916 FRONTEND_INFO( info->caps, FE_CAN_8VSB, "8VSB" )
917 FRONTEND_INFO( info->caps, FE_CAN_16VSB,"16VSB" )
918 FRONTEND_INFO( info->caps, FE_HAS_EXTENDED_CAPS, "EXTENDED_CAPS" )
919 #if DVBAPI_VERSION >= 501
920 FRONTEND_INFO( info->caps, FE_CAN_2G_MODULATION, "2G_MODULATION" )
921 #endif
922 FRONTEND_INFO( info->caps, FE_CAN_MULTISTREAM, "MULTISTREAM" )
923 FRONTEND_INFO( info->caps, FE_CAN_TURBO_FEC, "TURBO_FEC" )
924 FRONTEND_INFO( info->caps, FE_NEEDS_BENDING, "NEEDS_BENDING" )
925 FRONTEND_INFO( info->caps, FE_CAN_RECOVER, "FE_CAN_RECOVER" )
926 FRONTEND_INFO( info->caps, FE_CAN_MUTE_TS, "FE_CAN_MUTE_TS" )
927 #undef FRONTEND_INFO
929 msg_Dbg( NULL, " delivery systems:" );
930 int i;
931 for ( i = 0; i < i_systems; i++ )
933 switch ( p_systems[i] )
935 #define DELSYS_INFO(delsys, msg) \
936 case delsys: msg_Dbg( NULL, " %s", msg); break;
937 DELSYS_INFO( SYS_ATSC, "ATSC" )
938 DELSYS_INFO( SYS_ATSCMH, "ATSCMH" )
939 DELSYS_INFO( SYS_CMMB, "CMBB" )
940 DELSYS_INFO( SYS_DAB, "DAB" )
941 DELSYS_INFO( SYS_DSS, "DSS" )
942 DELSYS_INFO( SYS_DVBC_ANNEX_B, "DVBC_ANNEX_B" )
943 DELSYS_INFO( SYS_DVBH, "DVBH" )
944 DELSYS_INFO( SYS_DVBS, "DVBS" )
945 DELSYS_INFO( SYS_DVBS2, "DVBS2" )
946 DELSYS_INFO( SYS_DVBT, "DVBT" )
947 DELSYS_INFO( SYS_ISDBC, "ISDBC" )
948 DELSYS_INFO( SYS_ISDBS, "ISDBS" )
949 DELSYS_INFO( SYS_ISDBT, "ISDBT" )
950 DELSYS_INFO( SYS_UNDEFINED, "UNDEFINED" )
951 #if DVBAPI_VERSION >= 505
952 DELSYS_INFO( SYS_DVBC_ANNEX_A, "DVBC_ANNEX_A" )
953 DELSYS_INFO( SYS_DVBC_ANNEX_C, "DVBC_ANNEX_C" )
954 DELSYS_INFO( SYS_DVBT2, "DVBT2" )
955 DELSYS_INFO( SYS_TURBO, "TURBO" )
956 #else
957 DELSYS_INFO( SYS_DVBC_ANNEX_AC, "DVBC_ANNEX_AC" )
958 #endif
959 #if DVBAPI_VERSION >= 507
960 DELSYS_INFO( SYS_DTMB, "DTMB" )
961 #else
962 DELSYS_INFO( SYS_DMBTH, "DMBTH" )
963 #endif
964 default: msg_Dbg( NULL, " Unknown delivery system %u", p_systems[i]);
965 break;
970 /*****************************************************************************
971 * FrontendSet
972 *****************************************************************************/
973 /* S2API */
974 #if DVBAPI_VERSION >= 505
975 static struct dtv_property info_cmdargs[] = {
976 { .cmd = DTV_API_VERSION, .u.data = 0 },
978 static struct dtv_properties info_cmdseq = {
979 .num = sizeof(info_cmdargs)/sizeof(struct dtv_property),
980 .props = info_cmdargs
983 static struct dtv_property enum_cmdargs[] = {
984 { .cmd = DTV_ENUM_DELSYS, .u.data = 0 },
986 static struct dtv_properties enum_cmdseq = {
987 .num = sizeof(enum_cmdargs)/sizeof(struct dtv_property),
988 .props = enum_cmdargs
990 #endif
992 static struct dtv_property dvbs_cmdargs[] = {
993 { .cmd = DTV_DELIVERY_SYSTEM, .u.data = SYS_DVBS },
994 { .cmd = DTV_FREQUENCY, .u.data = 0 },
995 { .cmd = DTV_MODULATION, .u.data = QPSK },
996 { .cmd = DTV_INVERSION, .u.data = INVERSION_AUTO },
997 { .cmd = DTV_SYMBOL_RATE, .u.data = 27500000 },
998 { .cmd = DTV_INNER_FEC, .u.data = FEC_AUTO },
999 { .cmd = DTV_TUNE },
1001 static struct dtv_properties dvbs_cmdseq = {
1002 .num = sizeof(dvbs_cmdargs)/sizeof(struct dtv_property),
1003 .props = dvbs_cmdargs
1006 #define IDX_DVBS2_PILOT 6
1007 #define IDX_DVBS2_ROLLOFF 7
1008 #define IDX_DVBS2_STREAM_ID 8
1010 /* Commands 0..5 are the same as dvbs_cmdargs */
1011 /* Commands 6..8 are special for DVB-S2 */
1012 static struct dtv_property dvbs2_cmdargs[] = {
1013 { .cmd = DTV_DELIVERY_SYSTEM, .u.data = SYS_DVBS2 },
1014 { .cmd = DTV_FREQUENCY, .u.data = 0 },
1015 { .cmd = DTV_MODULATION, .u.data = PSK_8 },
1016 { .cmd = DTV_INVERSION, .u.data = INVERSION_AUTO },
1017 { .cmd = DTV_SYMBOL_RATE, .u.data = 27500000 },
1018 { .cmd = DTV_INNER_FEC, .u.data = FEC_AUTO },
1019 { .cmd = DTV_PILOT, .u.data = PILOT_AUTO }, /* idx: 6 */
1020 { .cmd = DTV_ROLLOFF, .u.data = ROLLOFF_AUTO }, /* idx: 7 */
1021 { .cmd = DTV_STREAM_ID, .u.data = 0 }, /* idx: 8 */
1022 { .cmd = DTV_TUNE },
1024 static struct dtv_properties dvbs2_cmdseq = {
1025 .num = sizeof(dvbs2_cmdargs)/sizeof(struct dtv_property),
1026 .props = dvbs2_cmdargs
1029 static struct dtv_property dvbc_cmdargs[] = {
1030 #if DVBAPI_VERSION >= 505
1031 { .cmd = DTV_DELIVERY_SYSTEM, .u.data = SYS_DVBC_ANNEX_A },
1032 #else
1033 { .cmd = DTV_DELIVERY_SYSTEM, .u.data = SYS_DVBC_ANNEX_AC },
1034 #endif
1035 { .cmd = DTV_FREQUENCY, .u.data = 0 },
1036 { .cmd = DTV_MODULATION, .u.data = QAM_AUTO },
1037 { .cmd = DTV_INVERSION, .u.data = INVERSION_AUTO },
1038 { .cmd = DTV_SYMBOL_RATE, .u.data = 27500000 },
1039 { .cmd = DTV_TUNE },
1041 static struct dtv_properties dvbc_cmdseq = {
1042 .num = sizeof(dvbc_cmdargs)/sizeof(struct dtv_property),
1043 .props = dvbc_cmdargs
1046 static struct dtv_property dvbt_cmdargs[] = {
1047 { .cmd = DTV_DELIVERY_SYSTEM, .u.data = SYS_DVBT },
1048 { .cmd = DTV_FREQUENCY, .u.data = 0 },
1049 { .cmd = DTV_MODULATION, .u.data = QAM_AUTO },
1050 { .cmd = DTV_INVERSION, .u.data = INVERSION_AUTO },
1051 { .cmd = DTV_BANDWIDTH_HZ, .u.data = 8000000 },
1052 { .cmd = DTV_CODE_RATE_HP, .u.data = FEC_AUTO },
1053 { .cmd = DTV_CODE_RATE_LP, .u.data = FEC_AUTO },
1054 { .cmd = DTV_GUARD_INTERVAL, .u.data = GUARD_INTERVAL_AUTO },
1055 { .cmd = DTV_TRANSMISSION_MODE,.u.data = TRANSMISSION_MODE_AUTO },
1056 { .cmd = DTV_HIERARCHY, .u.data = HIERARCHY_AUTO },
1057 { .cmd = DTV_TUNE },
1060 static struct dtv_property dvbt2_cmdargs[] = {
1061 { .cmd = DTV_DELIVERY_SYSTEM, .u.data = SYS_DVBT2 },
1062 { .cmd = DTV_FREQUENCY, .u.data = 0 },
1063 { .cmd = DTV_MODULATION, .u.data = QAM_AUTO },
1064 { .cmd = DTV_INVERSION, .u.data = INVERSION_AUTO },
1065 { .cmd = DTV_BANDWIDTH_HZ, .u.data = 8000000 },
1066 { .cmd = DTV_CODE_RATE_HP, .u.data = FEC_AUTO },
1067 { .cmd = DTV_CODE_RATE_LP, .u.data = FEC_AUTO },
1068 { .cmd = DTV_GUARD_INTERVAL, .u.data = GUARD_INTERVAL_AUTO },
1069 { .cmd = DTV_TRANSMISSION_MODE,.u.data = TRANSMISSION_MODE_AUTO },
1070 { .cmd = DTV_HIERARCHY, .u.data = HIERARCHY_AUTO },
1071 { .cmd = DTV_STREAM_ID, .u.data = 0 },
1072 { .cmd = DTV_TUNE },
1075 static struct dtv_properties dvbt2_cmdseq = {
1076 .num = sizeof(dvbt2_cmdargs)/sizeof(struct dtv_property),
1077 .props = dvbt2_cmdargs
1080 static struct dtv_properties dvbt_cmdseq = {
1081 .num = sizeof(dvbt_cmdargs)/sizeof(struct dtv_property),
1082 .props = dvbt_cmdargs
1085 /* ATSC + DVB-C annex B */
1086 static struct dtv_property atsc_cmdargs[] = {
1087 { .cmd = DTV_DELIVERY_SYSTEM, .u.data = SYS_ATSC },
1088 { .cmd = DTV_FREQUENCY, .u.data = 0 },
1089 { .cmd = DTV_MODULATION, .u.data = QAM_AUTO },
1090 { .cmd = DTV_INVERSION, .u.data = INVERSION_AUTO },
1091 { .cmd = DTV_TUNE },
1093 static struct dtv_properties atsc_cmdseq = {
1094 .num = sizeof(atsc_cmdargs)/sizeof(struct dtv_property),
1095 .props = atsc_cmdargs
1098 static struct dtv_property isdbt_cmdargs[] = {
1099 { .cmd = DTV_DELIVERY_SYSTEM, .u.data = SYS_ISDBT },
1100 { .cmd = DTV_FREQUENCY, .u.data = 0 },
1101 { .cmd = DTV_BANDWIDTH_HZ, .u.data = 6000000 },
1102 { .cmd = DTV_INVERSION, .u.data = INVERSION_AUTO },
1103 { .cmd = DTV_ISDBT_LAYERA_FEC, .u.data = FEC_AUTO },
1104 { .cmd = DTV_ISDBT_LAYERA_MODULATION, .u.data = QAM_AUTO },
1105 { .cmd = DTV_ISDBT_LAYERA_SEGMENT_COUNT, .u.data = 0 },
1106 { .cmd = DTV_ISDBT_LAYERA_TIME_INTERLEAVING,.u.data = 0 },
1107 { .cmd = DTV_ISDBT_LAYERB_FEC, .u.data = FEC_AUTO },
1108 { .cmd = DTV_ISDBT_LAYERB_MODULATION, .u.data = QAM_AUTO },
1109 { .cmd = DTV_ISDBT_LAYERB_SEGMENT_COUNT, .u.data = 0 },
1110 { .cmd = DTV_ISDBT_LAYERB_TIME_INTERLEAVING,.u.data = 0 },
1111 { .cmd = DTV_ISDBT_LAYERC_FEC, .u.data = FEC_AUTO },
1112 { .cmd = DTV_ISDBT_LAYERC_MODULATION, .u.data = QAM_AUTO },
1113 { .cmd = DTV_ISDBT_LAYERC_SEGMENT_COUNT, .u.data = 0 },
1114 { .cmd = DTV_ISDBT_LAYERC_TIME_INTERLEAVING,.u.data = 0 },
1115 { .cmd = DTV_TUNE },
1118 static struct dtv_properties isdbt_cmdseq = {
1119 .num = sizeof(isdbt_cmdargs)/sizeof(struct dtv_property),
1120 .props = isdbt_cmdargs
1123 #define DELSYS 0
1124 #define FREQUENCY 1
1125 #define MODULATION 2
1126 #define INVERSION 3
1127 #define SYMBOL_RATE 4
1128 #define BANDWIDTH 4
1129 #define FEC_INNER 5
1130 #define FEC_LP 6
1131 #define GUARD 7
1132 #define TRANSMISSION 8
1134 #define HIERARCHY 9
1135 #define PLP_ID 10
1137 //ISDBT
1138 #define ISDBT_BANDWIDTH 2
1139 #define ISDBT_LAYERA_FEC 4
1140 #define ISDBT_LAYERA_MODULATION 5
1141 #define ISDBT_LAYERA_SEGMENT_COUNT 6
1142 #define ISDBT_LAYERA_TIME_INTERLEAVING 7
1143 #define ISDBT_LAYERB_FEC 8
1144 #define ISDBT_LAYERB_MODULATION 9
1145 #define ISDBT_LAYERB_SEGMENT_COUNT 10
1146 #define ISDBT_LAYERB_TIME_INTERLEAVING 11
1147 #define ISDBT_LAYERC_FEC 12
1148 #define ISDBT_LAYERC_MODULATION 13
1149 #define ISDBT_LAYERC_SEGMENT_COUNT 14
1150 #define ISDBT_LAYERC_TIME_INTERLEAVING 15
1152 struct dtv_property pclear[] = {
1153 { .cmd = DTV_CLEAR },
1156 struct dtv_properties cmdclear = {
1157 .num = 1,
1158 .props = pclear
1161 static fe_delivery_system_t
1162 FrontendGuessSystem( fe_delivery_system_t *p_systems, int i_systems )
1164 if ( psz_delsys != NULL )
1166 if ( !strcasecmp( psz_delsys, "DVBS" ) )
1167 return SYS_DVBS;
1168 if ( !strcasecmp( psz_delsys, "DVBS2" ) )
1169 return SYS_DVBS2;
1170 if ( !strcasecmp( psz_delsys, "DVBC_ANNEX_A" ) )
1171 #if DVBAPI_VERSION >= 505
1172 return SYS_DVBC_ANNEX_A;
1173 #else
1174 return SYS_DVBC_ANNEX_AC;
1175 #endif
1176 if ( !strcasecmp( psz_delsys, "DVBC_ANNEX_B" ) )
1177 return SYS_DVBC_ANNEX_B;
1178 if ( !strcasecmp( psz_delsys, "DVBT" ) )
1179 return SYS_DVBT;
1180 if ( !strcasecmp( psz_delsys, "DVBT2" ) )
1181 return SYS_DVBT2;
1182 if ( !strcasecmp( psz_delsys, "ATSC" ) )
1183 return SYS_ATSC;
1184 if ( !strcasecmp( psz_delsys, "ISDBT" ) )
1185 return SYS_ISDBT;
1186 msg_Err( NULL, "unknown delivery system %s", psz_delsys );
1187 exit(1);
1190 if ( i_systems == 1 )
1191 return p_systems[0];
1193 int i;
1194 for ( i = 0; i < i_systems; i++ )
1196 switch ( p_systems[i] )
1198 case SYS_DVBS:
1199 if ( i_frequency < 50000000 )
1200 return SYS_DVBS;
1201 break;
1202 #if DVBAPI_VERSION >= 505
1203 case SYS_DVBC_ANNEX_A:
1204 if ( i_frequency > 50000000 || i_srate != 27500000 ||
1205 psz_modulation != NULL )
1206 return SYS_DVBC_ANNEX_A;
1207 break;
1208 #else
1209 case SYS_DVBC_ANNEX_AC:
1210 if ( i_frequency > 50000000 || i_srate != 27500000 ||
1211 psz_modulation != NULL )
1212 return SYS_DVBC_ANNEX_AC;
1213 break;
1214 #endif
1215 case SYS_DVBT:
1216 if ( i_frequency > 50000000 )
1217 return SYS_DVBT;
1218 break;
1219 case SYS_DVBT2:
1220 if ( i_frequency > 50000000 && (dvb_plp_id) )
1221 return SYS_DVBT2;
1222 break;
1223 default:
1224 break;
1228 msg_Warn( NULL, "couldn't guess delivery system, use --delsys" );
1229 return p_systems[0];
1232 static void FrontendSet( bool b_init )
1234 struct dvb_frontend_info info;
1235 struct dtv_properties *p;
1236 fe_delivery_system_t p_systems[MAX_DELIVERY_SYSTEMS] = { 0 };
1237 int i_systems = 0;
1239 if ( ioctl( i_frontend, FE_GET_INFO, &info ) < 0 )
1241 msg_Err( NULL, "FE_GET_INFO failed (%s)", strerror(errno) );
1242 exit(1);
1245 uint32_t version = 0x300;
1246 #if DVBAPI_VERSION >= 505
1247 if ( ioctl( i_frontend, FE_GET_PROPERTY, &info_cmdseq ) < 0 )
1249 #endif
1250 /* DVBv3 device */
1251 switch ( info.type )
1253 case FE_OFDM:
1254 p_systems[i_systems++] = SYS_DVBT;
1255 #if DVBAPI_VERSION >= 505
1256 if ( info.caps & FE_CAN_2G_MODULATION )
1257 p_systems[i_systems++] = SYS_DVBT2;
1258 #endif
1259 break;
1260 case FE_QAM:
1261 #if DVBAPI_VERSION >= 505
1262 p_systems[i_systems++] = SYS_DVBC_ANNEX_A;
1263 #else
1264 p_systems[i_systems++] = SYS_DVBC_ANNEX_AC;
1265 #endif
1266 break;
1267 case FE_QPSK:
1268 p_systems[i_systems++] = SYS_DVBS;
1269 if ( info.caps & FE_CAN_2G_MODULATION )
1270 p_systems[i_systems++] = SYS_DVBS2;
1271 break;
1272 case FE_ATSC:
1273 if ( info.caps & (FE_CAN_8VSB | FE_CAN_16VSB) )
1274 p_systems[i_systems++] = SYS_ATSC;
1275 if ( info.caps & (FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_QAM_AUTO) )
1276 p_systems[i_systems++] = SYS_DVBC_ANNEX_B;
1277 break;
1278 default:
1279 msg_Err( NULL, "unknown frontend type %d", info.type );
1280 exit(1);
1282 #if DVBAPI_VERSION >= 505
1284 else
1286 version = info_cmdargs[0].u.data;
1287 if ( ioctl( i_frontend, FE_GET_PROPERTY, &enum_cmdseq ) < 0 )
1289 msg_Err( NULL, "unable to query frontend" );
1290 exit(1);
1292 i_systems = enum_cmdargs[0].u.buffer.len;
1293 if ( i_systems < 1 )
1295 msg_Err( NULL, "no available delivery system" );
1296 exit(1);
1299 int i;
1300 for ( i = 0; i < i_systems; i++ )
1301 p_systems[i] = enum_cmdargs[0].u.buffer.data[i];
1303 #endif
1305 if ( b_init )
1306 FrontendInfo( &info, version, p_systems, i_systems );
1308 /* Clear frontend commands */
1309 if ( ioctl( i_frontend, FE_SET_PROPERTY, &cmdclear ) < 0 )
1311 msg_Err( NULL, "Unable to clear frontend" );
1312 exit(1);
1315 fe_delivery_system_t system = FrontendGuessSystem( p_systems, i_systems );
1316 switch ( system )
1318 case SYS_DVBT:
1319 p = &dvbt_cmdseq;
1320 p->props[DELSYS].u.data = system;
1321 p->props[FREQUENCY].u.data = i_frequency;
1322 p->props[INVERSION].u.data = GetInversion();
1323 if ( psz_modulation != NULL )
1324 p->props[MODULATION].u.data = GetModulation();
1325 p->props[BANDWIDTH].u.data = i_bandwidth * 1000000;
1326 p->props[FEC_INNER].u.data = GetFECInner(info.caps);
1327 p->props[FEC_LP].u.data = GetFECLP(info.caps);
1328 p->props[GUARD].u.data = GetGuard();
1329 p->props[TRANSMISSION].u.data = GetTransmission();
1330 p->props[HIERARCHY].u.data = GetHierarchy();
1332 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",
1333 i_frequency, i_bandwidth, i_inversion, i_fec, i_fec_lp,
1334 i_hierarchy,
1335 psz_modulation == NULL ? "qam_auto" : psz_modulation,
1336 i_guard, i_transmission );
1337 break;
1338 case SYS_DVBT2:
1339 p = &dvbt2_cmdseq;
1340 p->props[DELSYS].u.data = system;
1341 p->props[FREQUENCY].u.data = i_frequency;
1342 p->props[INVERSION].u.data = GetInversion();
1343 if ( psz_modulation != NULL )
1344 p->props[MODULATION].u.data = GetModulation();
1345 p->props[BANDWIDTH].u.data = i_bandwidth * 1000000;
1346 p->props[FEC_INNER].u.data = GetFECInner(info.caps);
1347 p->props[FEC_LP].u.data = GetFECLP(info.caps);
1348 p->props[GUARD].u.data = GetGuard();
1349 p->props[TRANSMISSION].u.data = GetTransmission();
1350 p->props[HIERARCHY].u.data = GetHierarchy();
1351 p->props[PLP_ID].u.data = dvb_plp_id;
1353 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 ",
1354 i_frequency, i_bandwidth, i_inversion, i_fec, i_fec_lp,
1355 i_hierarchy,
1356 psz_modulation == NULL ? "qam_auto" : psz_modulation,
1357 i_guard, i_transmission, p->props[PLP_ID].u.data );
1358 break;
1359 #if DVBAPI_VERSION >= 505
1360 case SYS_DVBC_ANNEX_A:
1361 #else
1362 case SYS_DVBC_ANNEX_AC:
1363 #endif
1364 p = &dvbc_cmdseq;
1365 p->props[FREQUENCY].u.data = i_frequency;
1366 p->props[INVERSION].u.data = GetInversion();
1367 if ( psz_modulation != NULL )
1368 p->props[MODULATION].u.data = GetModulation();
1369 p->props[SYMBOL_RATE].u.data = i_srate;
1371 msg_Dbg( NULL, "tuning DVB-C frontend to f=%d srate=%d inversion=%d modulation=%s",
1372 i_frequency, i_srate, i_inversion,
1373 psz_modulation == NULL ? "qam_auto" : psz_modulation );
1374 break;
1376 case SYS_DVBC_ANNEX_B:
1377 p = &atsc_cmdseq;
1378 p->props[DELSYS].u.data = system;
1379 p->props[FREQUENCY].u.data = i_frequency;
1380 p->props[INVERSION].u.data = GetInversion();
1381 if ( psz_modulation != NULL )
1382 p->props[MODULATION].u.data = GetModulation();
1384 msg_Dbg( NULL, "tuning ATSC cable frontend to f=%d inversion=%d modulation=%s",
1385 i_frequency, i_inversion,
1386 psz_modulation == NULL ? "qam_auto" : psz_modulation );
1387 break;
1389 case SYS_DVBS:
1390 case SYS_DVBS2:
1391 if ( psz_modulation != NULL )
1393 p = &dvbs2_cmdseq;
1394 p->props[MODULATION].u.data = GetModulation();
1395 p->props[IDX_DVBS2_PILOT].u.data = GetPilot();
1396 p->props[IDX_DVBS2_ROLLOFF].u.data = GetRollOff();
1397 p->props[IDX_DVBS2_STREAM_ID].u.data = i_mis;
1399 else
1400 p = &dvbs_cmdseq;
1402 p->props[INVERSION].u.data = GetInversion();
1403 p->props[SYMBOL_RATE].u.data = i_srate;
1404 p->props[FEC_INNER].u.data = GetFECInner(info.caps);
1405 p->props[FREQUENCY].u.data = FrontendDoDiseqc();
1407 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 /",
1408 i_frequency, i_srate, i_inversion, i_fec, i_rolloff,
1409 psz_modulation == NULL ? "legacy" : psz_modulation, i_pilot,
1410 i_mis, psz_mis_pls_mode, i_mis_pls_mode, i_mis_pls_code, i_mis_is_id );
1411 break;
1413 case SYS_ATSC:
1414 p = &atsc_cmdseq;
1415 p->props[FREQUENCY].u.data = i_frequency;
1416 p->props[INVERSION].u.data = GetInversion();
1417 if ( psz_modulation != NULL )
1418 p->props[MODULATION].u.data = GetModulation();
1420 msg_Dbg( NULL, "tuning ATSC frontend to f=%d inversion=%d modulation=%s",
1421 i_frequency, i_inversion,
1422 psz_modulation == NULL ? "qam_auto" : psz_modulation );
1423 break;
1424 case SYS_ISDBT:
1425 p = &isdbt_cmdseq;
1426 p->props[DELSYS].u.data = system;
1427 p->props[FREQUENCY].u.data = i_frequency;
1428 p->props[ISDBT_BANDWIDTH].u.data = i_bandwidth * 1000000;
1429 p->props[INVERSION].u.data = GetInversion();
1430 p->props[ISDBT_LAYERA_FEC].u.data = FEC_AUTO;
1431 p->props[ISDBT_LAYERA_MODULATION].u.data = QAM_AUTO;
1432 p->props[ISDBT_LAYERA_SEGMENT_COUNT].u.data = 0;
1433 p->props[ISDBT_LAYERA_TIME_INTERLEAVING].u.data = 0;
1434 p->props[ISDBT_LAYERB_FEC].u.data = FEC_AUTO;
1435 p->props[ISDBT_LAYERB_MODULATION].u.data = QAM_AUTO;
1436 p->props[ISDBT_LAYERB_SEGMENT_COUNT].u.data = 0;
1437 p->props[ISDBT_LAYERB_TIME_INTERLEAVING].u.data = 0;
1438 p->props[ISDBT_LAYERC_FEC].u.data = FEC_AUTO;
1439 p->props[ISDBT_LAYERC_MODULATION].u.data = QAM_AUTO;
1440 p->props[ISDBT_LAYERC_SEGMENT_COUNT].u.data = 0;
1441 p->props[ISDBT_LAYERC_TIME_INTERLEAVING].u.data = 0;
1443 msg_Dbg( NULL, "tuning ISDB-T frontend to f=%d bandwidth=%d ",
1444 i_frequency, i_bandwidth);
1445 break;
1447 default:
1448 msg_Err( NULL, "unknown frontend type %d", info.type );
1449 exit(1);
1452 /* Empty the event queue */
1453 for ( ; ; )
1455 struct dvb_frontend_event event;
1456 if ( ioctl( i_frontend, FE_GET_EVENT, &event ) < 0
1457 && errno == EWOULDBLOCK )
1458 break;
1461 /* Now send it all to the frontend device */
1462 if ( ioctl( i_frontend, FE_SET_PROPERTY, p ) < 0 )
1464 msg_Err( NULL, "setting frontend failed (%s)", strerror(errno) );
1465 exit(1);
1468 i_last_status = 0;
1470 if (i_frontend_timeout_duration)
1471 ev_timer_again(event_loop, &lock_watcher);
1474 #else /* !S2API */
1476 #warning "You are trying to compile DVBlast with an outdated linux-dvb interface."
1477 #warning "DVBlast will be very limited and some options will have no effect."
1479 static void FrontendSet( bool b_init )
1481 struct dvb_frontend_info info;
1482 struct dvb_frontend_parameters fep;
1484 if ( ioctl( i_frontend, FE_GET_INFO, &info ) < 0 )
1486 msg_Err( NULL, "FE_GET_INFO failed (%s)", strerror(errno) );
1487 exit(1);
1490 switch ( info.type )
1492 case FE_OFDM:
1493 fep.frequency = i_frequency;
1494 fep.inversion = INVERSION_AUTO;
1496 switch ( i_bandwidth )
1498 case 6: fep.u.ofdm.bandwidth = BANDWIDTH_6_MHZ; break;
1499 case 7: fep.u.ofdm.bandwidth = BANDWIDTH_7_MHZ; break;
1500 default:
1501 case 8: fep.u.ofdm.bandwidth = BANDWIDTH_8_MHZ; break;
1504 fep.u.ofdm.code_rate_HP = FEC_AUTO;
1505 fep.u.ofdm.code_rate_LP = FEC_AUTO;
1506 fep.u.ofdm.constellation = QAM_AUTO;
1507 fep.u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO;
1508 fep.u.ofdm.guard_interval = GUARD_INTERVAL_AUTO;
1509 fep.u.ofdm.hierarchy_information = HIERARCHY_AUTO;
1511 msg_Dbg( NULL, "tuning OFDM frontend to f=%d, bandwidth=%d",
1512 i_frequency, i_bandwidth );
1513 break;
1515 case FE_QAM:
1516 fep.frequency = i_frequency;
1517 fep.inversion = INVERSION_AUTO;
1518 fep.u.qam.symbol_rate = i_srate;
1519 fep.u.qam.fec_inner = FEC_AUTO;
1520 fep.u.qam.modulation = QAM_AUTO;
1522 msg_Dbg( NULL, "tuning QAM frontend to f=%d, srate=%d",
1523 i_frequency, i_srate );
1524 break;
1526 case FE_QPSK:
1527 fep.inversion = INVERSION_AUTO;
1528 fep.u.qpsk.symbol_rate = i_srate;
1529 fep.u.qpsk.fec_inner = FEC_AUTO;
1530 fep.frequency = FrontendDoDiseqc();
1532 msg_Dbg( NULL, "tuning QPSK frontend to f=%d, srate=%d",
1533 i_frequency, i_srate );
1534 break;
1536 #if DVBAPI_VERSION >= 301
1537 case FE_ATSC:
1538 fep.frequency = i_frequency;
1540 fep.u.vsb.modulation = QAM_AUTO;
1542 msg_Dbg( NULL, "tuning ATSC frontend to f=%d", i_frequency );
1543 break;
1544 #endif
1546 default:
1547 msg_Err( NULL, "unknown frontend type %d", info.type );
1548 exit(1);
1551 /* Empty the event queue */
1552 for ( ; ; )
1554 struct dvb_frontend_event event;
1555 if ( ioctl( i_frontend, FE_GET_EVENT, &event ) < 0
1556 && errno == EWOULDBLOCK )
1557 break;
1560 /* Now send it all to the frontend device */
1561 if ( ioctl( i_frontend, FE_SET_FRONTEND, &fep ) < 0 )
1563 msg_Err( NULL, "setting frontend failed (%s)", strerror(errno) );
1564 exit(1);
1567 i_last_status = 0;
1569 if (i_frontend_timeout_duration)
1570 ev_timer_again(event_loop, &lock_watcher);
1573 #endif /* S2API */
1575 /*****************************************************************************
1576 * dvb_FrontendStatus
1577 *****************************************************************************/
1578 uint8_t dvb_FrontendStatus( uint8_t *p_answer, ssize_t *pi_size )
1580 struct ret_frontend_status *p_ret = (struct ret_frontend_status *)p_answer;
1582 if ( ioctl( i_frontend, FE_GET_INFO, &p_ret->info ) < 0 )
1584 msg_Err( NULL, "ioctl FE_GET_INFO failed (%s)", strerror(errno) );
1585 return RET_ERR;
1588 if ( ioctl( i_frontend, FE_READ_STATUS, &p_ret->i_status ) < 0 )
1590 msg_Err( NULL, "ioctl FE_READ_STATUS failed (%s)", strerror(errno) );
1591 return RET_ERR;
1594 if ( p_ret->i_status & FE_HAS_LOCK )
1596 if ( ioctl( i_frontend, FE_READ_BER, &p_ret->i_ber ) < 0 )
1597 msg_Err( NULL, "ioctl FE_READ_BER failed (%s)", strerror(errno) );
1599 if ( ioctl( i_frontend, FE_READ_SIGNAL_STRENGTH, &p_ret->i_strength )
1600 < 0 )
1601 msg_Err( NULL, "ioctl FE_READ_SIGNAL_STRENGTH failed (%s)",
1602 strerror(errno) );
1604 if ( ioctl( i_frontend, FE_READ_SNR, &p_ret->i_snr ) < 0 )
1605 msg_Err( NULL, "ioctl FE_READ_SNR failed (%s)", strerror(errno) );
1608 *pi_size = sizeof(struct ret_frontend_status);
1609 return RET_FRONTEND_STATUS;
1612 #endif