fix memory leak when reloading the application
[dvblast.git] / dvb.c
blob31276b035bc78406931d8a9f8be32996fa44bb7a
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 #endif
57 #define MAX_DELIVERY_SYSTEMS 20
59 #include "dvblast.h"
60 #include "en50221.h"
61 #include "comm.h"
63 #include <bitstream/common.h>
65 /*****************************************************************************
66 * Local declarations
67 *****************************************************************************/
68 #define DVR_READ_TIMEOUT 30000000 /* 30 s */
69 #define MAX_READ_ONCE 50
70 #define DVR_BUFFER_SIZE 40*188*1024 /* bytes */
72 int i_dvr_buffer_size = DVR_BUFFER_SIZE;
74 static int i_frontend, i_dvr;
75 static struct ev_io frontend_watcher, dvr_watcher;
76 static struct ev_timer lock_watcher, mute_watcher, print_watcher;
77 static fe_status_t i_last_status;
78 static block_t *p_freelist = NULL;
80 /*****************************************************************************
81 * Local prototypes
82 *****************************************************************************/
83 static void DVRRead(struct ev_loop *loop, struct ev_io *w, int revents);
84 static void DVRMuteCb(struct ev_loop *loop, struct ev_timer *w, int revents);
85 static void FrontendRead(struct ev_loop *loop, struct ev_io *w, int revents);
86 static void FrontendLockCb(struct ev_loop *loop, struct ev_timer *w, int revents);
87 static void FrontendSet( bool b_reset );
89 /*****************************************************************************
90 * dvb_Open
91 *****************************************************************************/
92 void dvb_Open( void )
94 char psz_tmp[128];
96 msg_Dbg( NULL, "compiled with DVB API version %d.%d", DVB_API_VERSION, DVB_API_VERSION_MINOR );
98 if ( i_frequency )
100 sprintf( psz_tmp, "/dev/dvb/adapter%d/frontend%d", i_adapter, i_fenum );
101 if( (i_frontend = open(psz_tmp, O_RDWR | O_NONBLOCK)) < 0 )
103 msg_Err( NULL, "opening device %s failed (%s)", psz_tmp,
104 strerror(errno) );
105 exit(1);
108 FrontendSet(true);
110 else
112 i_frontend = -1;
115 sprintf( psz_tmp, "/dev/dvb/adapter%d/dvr%d", i_adapter, i_fenum );
117 if( (i_dvr = open(psz_tmp, O_RDONLY | O_NONBLOCK)) < 0 )
119 msg_Err( NULL, "opening device %s failed (%s)", psz_tmp,
120 strerror(errno) );
121 exit(1);
124 if ( ioctl( i_dvr, DMX_SET_BUFFER_SIZE, i_dvr_buffer_size ) < 0 )
126 msg_Warn( NULL, "couldn't set %s buffer size (%s)", psz_tmp,
127 strerror(errno) );
130 ev_io_init(&dvr_watcher, DVRRead, i_dvr, EV_READ);
131 ev_io_start(event_loop, &dvr_watcher);
133 if ( i_frontend != -1 )
135 ev_io_init(&frontend_watcher, FrontendRead, i_frontend, EV_READ);
136 ev_io_start(event_loop, &frontend_watcher);
139 ev_timer_init(&lock_watcher, FrontendLockCb,
140 i_frontend_timeout_duration / 1000000.,
141 i_frontend_timeout_duration / 1000000.);
142 ev_timer_init(&mute_watcher, DVRMuteCb,
143 DVR_READ_TIMEOUT / 1000000.,
144 DVR_READ_TIMEOUT / 1000000.);
146 en50221_Init();
149 /*****************************************************************************
150 * dvb_Reset
151 *****************************************************************************/
152 void dvb_Reset( void )
154 if ( i_frequency )
155 FrontendSet(true);
158 /*****************************************************************************
159 * DVR events
160 *****************************************************************************/
161 static void DVRRead(struct ev_loop *loop, struct ev_io *w, int revents)
163 int i, i_len;
164 block_t *p_ts = p_freelist, **pp_current = &p_ts;
165 struct iovec p_iov[MAX_READ_ONCE];
167 for ( i = 0; i < MAX_READ_ONCE; i++ )
169 if ( (*pp_current) == NULL ) *pp_current = block_New();
170 p_iov[i].iov_base = (*pp_current)->p_ts;
171 p_iov[i].iov_len = TS_SIZE;
172 pp_current = &(*pp_current)->p_next;
175 if ( (i_len = readv(i_dvr, p_iov, MAX_READ_ONCE)) < 0 )
177 msg_Err( NULL, "couldn't read from DVR device (%s)",
178 strerror(errno) );
179 i_len = 0;
181 i_len /= TS_SIZE;
183 if ( i_len )
184 ev_timer_again(loop, &mute_watcher);
186 pp_current = &p_ts;
187 while ( i_len && *pp_current )
189 pp_current = &(*pp_current)->p_next;
190 i_len--;
193 p_freelist = *pp_current;
194 *pp_current = NULL;
196 demux_Run( p_ts );
199 static void DVRMuteCb(struct ev_loop *loop, struct ev_timer *w, int revents)
201 msg_Warn( NULL, "no DVR output, resetting" );
202 ev_timer_stop(loop, w);
204 switch (i_print_type) {
205 case PRINT_XML:
206 fprintf(print_fh, "<EVENT type=\"reset\" cause=\"dvr\" />\n");
207 break;
208 case PRINT_TEXT:
209 fprintf(print_fh, "reset cause: dvr\n");
210 break;
211 default:
212 break;
214 if ( i_frequency )
215 FrontendSet(false);
216 en50221_Reset();
221 * Demux
224 /*****************************************************************************
225 * dvb_SetFilter : controls the demux to add a filter
226 *****************************************************************************/
227 int dvb_SetFilter( uint16_t i_pid )
229 struct dmx_pes_filter_params s_filter_params;
230 char psz_tmp[128];
231 int i_fd;
233 sprintf( psz_tmp, "/dev/dvb/adapter%d/demux%d", i_adapter, i_fenum );
234 if( (i_fd = open(psz_tmp, O_RDWR)) < 0 )
236 msg_Err( NULL, "DMXSetFilter: opening device failed (%s)",
237 strerror(errno) );
238 return -1;
241 s_filter_params.pid = i_pid;
242 s_filter_params.input = DMX_IN_FRONTEND;
243 s_filter_params.output = DMX_OUT_TS_TAP;
244 s_filter_params.flags = DMX_IMMEDIATE_START;
245 s_filter_params.pes_type = DMX_PES_OTHER;
247 if ( ioctl( i_fd, DMX_SET_PES_FILTER, &s_filter_params ) < 0 )
249 msg_Err( NULL, "failed setting filter on %d (%s)", i_pid,
250 strerror(errno) );
251 close( i_fd );
252 return -1;
255 msg_Dbg( NULL, "setting filter on PID %d", i_pid );
257 return i_fd;
260 /*****************************************************************************
261 * dvb_UnsetFilter : removes a filter
262 *****************************************************************************/
263 void dvb_UnsetFilter( int i_fd, uint16_t i_pid )
265 if ( ioctl( i_fd, DMX_STOP ) < 0 )
266 msg_Err( NULL, "DMX_STOP failed (%s)", strerror(errno) );
267 else
268 msg_Dbg( NULL, "unsetting filter on PID %d", i_pid );
270 close( i_fd );
275 * Frontend
278 /*****************************************************************************
279 * Print info
280 *****************************************************************************/
281 static void PrintCb( struct ev_loop *loop, struct ev_timer *w, int revents )
283 uint32_t i_ber = 0;
284 uint16_t i_strength = 0, i_snr = 0;
285 uint32_t i_uncorrected = 0;
287 ioctl(i_frontend, FE_READ_BER, &i_ber);
288 ioctl(i_frontend, FE_READ_SIGNAL_STRENGTH, &i_strength);
289 ioctl(i_frontend, FE_READ_SNR, &i_snr);
290 ioctl(i_frontend, FE_READ_UNCORRECTED_BLOCKS, &i_uncorrected);
292 switch (i_print_type)
294 case PRINT_XML:
295 fprintf(print_fh,
296 "<STATUS type=\"frontend\" ber=\"%"PRIu32"\" strength=\"%"PRIu16"\" snr=\"%"PRIu16"\" uncorrected=\"%"PRIu32"\" />\n",
297 i_ber, i_strength, i_snr, i_uncorrected);
298 break;
299 case PRINT_TEXT:
300 fprintf(print_fh, "frontend ber: %"PRIu32" strength: %"PRIu16" snr: %"PRIu16" uncorrected: %"PRIu32"\n",
301 i_ber, i_strength, i_snr, i_uncorrected);
302 break;
303 default:
304 break;
308 /*****************************************************************************
309 * Frontend events
310 *****************************************************************************/
311 static void FrontendRead(struct ev_loop *loop, struct ev_io *w, int revents)
313 struct dvb_frontend_event event;
314 fe_status_t i_status, i_diff;
316 for( ;; )
318 int i_ret = ioctl( i_frontend, FE_GET_EVENT, &event );
320 if( i_ret < 0 )
322 if( errno == EWOULDBLOCK )
323 return; /* no more events */
325 msg_Err( NULL, "reading frontend event failed (%d) %s",
326 i_ret, strerror(errno) );
327 return;
330 i_status = event.status;
331 i_diff = i_status ^ i_last_status;
332 i_last_status = i_status;
335 #define IF_UP( x ) \
337 if ( i_diff & (x) ) \
339 if ( i_status & (x) )
341 IF_UP( FE_HAS_SIGNAL )
342 msg_Dbg( NULL, "frontend has acquired signal" );
343 else
344 msg_Dbg( NULL, "frontend has lost signal" );
346 IF_UP( FE_HAS_CARRIER )
347 msg_Dbg( NULL, "frontend has acquired carrier" );
348 else
349 msg_Dbg( NULL, "frontend has lost carrier" );
351 IF_UP( FE_HAS_VITERBI )
352 msg_Dbg( NULL, "frontend has acquired stable FEC" );
353 else
354 msg_Dbg( NULL, "frontend has lost FEC" );
356 IF_UP( FE_HAS_SYNC )
357 msg_Dbg( NULL, "frontend has acquired sync" );
358 else
359 msg_Dbg( NULL, "frontend has lost sync" );
361 IF_UP( FE_HAS_LOCK )
363 int32_t i_value = 0;
364 msg_Info( NULL, "frontend has acquired lock" );
365 switch (i_print_type) {
366 case PRINT_XML:
367 fprintf(print_fh, "<STATUS type=\"lock\" status=\"1\" />\n");
368 break;
369 case PRINT_TEXT:
370 fprintf(print_fh, "lock status: 1\n");
371 break;
372 default:
373 break;
376 ev_timer_stop(loop, &lock_watcher);
377 ev_timer_again(loop, &mute_watcher);
379 /* Read some statistics */
380 if( ioctl( i_frontend, FE_READ_BER, &i_value ) >= 0 )
381 msg_Dbg( NULL, "- Bit error rate: %d", i_value );
382 if( ioctl( i_frontend, FE_READ_SIGNAL_STRENGTH, &i_value ) >= 0 )
383 msg_Dbg( NULL, "- Signal strength: %d", i_value );
384 if( ioctl( i_frontend, FE_READ_SNR, &i_value ) >= 0 )
385 msg_Dbg( NULL, "- SNR: %d", i_value );
387 if (i_print_period)
389 ev_timer_init( &print_watcher, PrintCb,
390 i_print_period / 1000000.,
391 i_print_period / 1000000. );
392 ev_timer_start( event_loop, &print_watcher );
395 else
397 msg_Dbg( NULL, "frontend has lost lock" );
398 switch (i_print_type) {
399 case PRINT_XML:
400 fprintf(print_fh, "<STATUS type=\"lock\" status=\"0\"/>\n");
401 break;
402 case PRINT_TEXT:
403 fprintf(print_fh, "lock status: 0\n");
404 break;
405 default:
406 break;
409 if (i_frontend_timeout_duration)
411 ev_timer_stop(event_loop, &lock_watcher);
412 ev_timer_again(loop, &mute_watcher);
415 if (i_print_period)
416 ev_timer_stop(event_loop, &print_watcher);
419 IF_UP( FE_REINIT )
421 /* The frontend was reinited. */
422 msg_Warn( NULL, "reiniting frontend");
423 if ( i_frequency )
424 FrontendSet(true);
427 #undef IF_UP
431 static void FrontendLockCb(struct ev_loop *loop, struct ev_timer *w, int revents)
433 if ( i_quit_timeout_duration )
435 msg_Err( NULL, "no lock" );
436 ev_break(loop, EVBREAK_ALL);
437 return;
440 msg_Warn( NULL, "no lock, tuning again" );
441 ev_timer_stop(loop, w);
443 switch (i_print_type) {
444 case PRINT_XML:
445 fprintf(print_fh, "<EVENT type=\"reset\" cause=\"nolock\" />\n");
446 break;
447 case PRINT_TEXT:
448 fprintf(print_fh, "reset cause: nolock\n");
449 break;
450 default:
451 break;
453 if ( i_frequency )
454 FrontendSet(false);
457 static int FrontendDoDiseqc(void)
459 fe_sec_voltage_t fe_voltage;
460 fe_sec_tone_mode_t fe_tone;
461 int bis_frequency;
463 switch ( i_voltage )
465 case 0: fe_voltage = SEC_VOLTAGE_OFF; break;
466 default:
467 case 13: fe_voltage = SEC_VOLTAGE_13; break;
468 case 18: fe_voltage = SEC_VOLTAGE_18; break;
471 fe_tone = b_tone ? SEC_TONE_ON : SEC_TONE_OFF;
473 /* Automatic mode. */
474 if ( i_frequency >= 950000 && i_frequency <= 2150000 )
476 msg_Dbg( NULL, "frequency %d is in IF-band", i_frequency );
477 bis_frequency = i_frequency;
479 else if ( i_frequency >= 2500000 && i_frequency <= 2700000 )
481 msg_Dbg( NULL, "frequency %d is in S-band", i_frequency );
482 bis_frequency = 3650000 - i_frequency;
484 else if ( i_frequency >= 3400000 && i_frequency <= 4200000 )
486 msg_Dbg( NULL, "frequency %d is in C-band (lower)", i_frequency );
487 bis_frequency = 5150000 - i_frequency;
489 else if ( i_frequency >= 4500000 && i_frequency <= 4800000 )
491 msg_Dbg( NULL, "frequency %d is in C-band (higher)", i_frequency );
492 bis_frequency = 5950000 - i_frequency;
494 else if ( i_frequency >= 10700000 && i_frequency < 11700000 )
496 msg_Dbg( NULL, "frequency %d is in Ku-band (lower)",
497 i_frequency );
498 bis_frequency = i_frequency - 9750000;
500 else if ( i_frequency >= 11700000 && i_frequency <= 13250000 )
502 msg_Dbg( NULL, "frequency %d is in Ku-band (higher)",
503 i_frequency );
504 bis_frequency = i_frequency - 10600000;
505 fe_tone = SEC_TONE_ON;
507 else
509 msg_Err( NULL, "frequency %d is out of any known band",
510 i_frequency );
511 exit(1);
514 /* Switch off continuous tone. */
515 if ( ioctl( i_frontend, FE_SET_TONE, SEC_TONE_OFF ) < 0 )
517 msg_Err( NULL, "FE_SET_TONE failed (%s)", strerror(errno) );
518 exit(1);
521 /* Configure LNB voltage. */
522 if ( ioctl( i_frontend, FE_SET_VOLTAGE, fe_voltage ) < 0 )
524 msg_Err( NULL, "FE_SET_VOLTAGE failed (%s)", strerror(errno) );
525 exit(1);
528 /* Wait for at least 15 ms. Currently 100 ms because of broken drivers. */
529 msleep(100000);
531 /* Diseqc */
532 if ( i_satnum > 0 && i_satnum < 5 )
534 /* digital satellite equipment control,
535 * specification is available from http://www.eutelsat.com/
538 /* DiSEqC 1.1 */
539 struct dvb_diseqc_master_cmd uncmd =
540 { {0xe0, 0x10, 0x39, 0xf0, 0x00, 0x00}, 4};
542 /* DiSEqC 1.0 */
543 struct dvb_diseqc_master_cmd cmd =
544 { {0xe0, 0x10, 0x38, 0xf0, 0x00, 0x00}, 4};
546 cmd.msg[3] = 0xf0 /* reset bits */
547 | ((i_satnum - 1) << 2)
548 | (fe_voltage == SEC_VOLTAGE_13 ? 0 : 2)
549 | (fe_tone == SEC_TONE_ON ? 1 : 0);
551 if ( i_uncommitted > 0 && i_uncommitted < 17 )
553 uncmd.msg[3] = 0xf0 /* reset bits */
554 | (i_uncommitted - 1);
555 if( ioctl( i_frontend, FE_DISEQC_SEND_MASTER_CMD, &uncmd ) < 0 )
557 msg_Err( NULL, "ioctl FE_SEND_MASTER_CMD failed (%s)",
558 strerror(errno) );
559 exit(1);
561 /* Repeat uncommitted command */
562 uncmd.msg[0] = 0xe1; /* framing: master, no reply, repeated TX */
563 if( ioctl( i_frontend, FE_DISEQC_SEND_MASTER_CMD, &uncmd ) < 0 )
565 msg_Err( NULL, "ioctl FE_SEND_MASTER_CMD failed (%s)",
566 strerror(errno) );
567 exit(1);
569 /* Pause 125 ms between uncommitted & committed diseqc commands. */
570 msleep(125000);
573 if( ioctl( i_frontend, FE_DISEQC_SEND_MASTER_CMD, &cmd ) < 0 )
575 msg_Err( NULL, "ioctl FE_SEND_MASTER_CMD failed (%s)",
576 strerror(errno) );
577 exit(1);
579 msleep(100000); /* Should be 15 ms. */
581 /* Do it again just to be sure. */
582 cmd.msg[0] = 0xe1; /* framing: master, no reply, repeated TX */
583 if( ioctl( i_frontend, FE_DISEQC_SEND_MASTER_CMD, &cmd ) < 0 )
585 msg_Err( NULL, "ioctl FE_SEND_MASTER_CMD failed (%s)",
586 strerror(errno) );
587 exit(1);
589 msleep(100000); /* Again, should be 15 ms */
591 else if ( i_satnum == 0xA || i_satnum == 0xB )
593 /* A or B simple diseqc ("diseqc-compatible") */
594 if( ioctl( i_frontend, FE_DISEQC_SEND_BURST,
595 i_satnum == 0xB ? SEC_MINI_B : SEC_MINI_A ) < 0 )
597 msg_Err( NULL, "ioctl FE_SEND_BURST failed (%s)", strerror(errno) );
598 exit(1);
600 msleep(100000); /* ... */
603 if ( ioctl( i_frontend, FE_SET_TONE, fe_tone ) < 0 )
605 msg_Err( NULL, "FE_SET_TONE failed (%s)", strerror(errno) );
606 exit(1);
609 msleep(100000); /* ... */
611 msg_Dbg( NULL, "configuring LNB to v=%d p=%d satnum=%x uncommitted=%x",
612 i_voltage, b_tone, i_satnum, i_uncommitted );
613 return bis_frequency;
616 #if DVB_API_VERSION >= 5
618 #if DVBAPI_VERSION < 505
619 #warning Your linux-dvb headers are old, you should consider upgrading your kernel and/or compiling against different kernel headers
620 #endif
622 /*****************************************************************************
623 * Helper functions for S2API
624 *****************************************************************************/
625 static fe_spectral_inversion_t GetInversion(void)
627 switch ( i_inversion )
629 case 0: return INVERSION_OFF;
630 case 1: return INVERSION_ON;
631 default:
632 msg_Warn( NULL, "invalid inversion %d", i_inversion );
633 case -1: return INVERSION_AUTO;
637 static fe_code_rate_t GetFEC(fe_caps_t fe_caps, int i_fec_value)
639 #define GET_FEC_INNER(fec, val) \
640 if ( (fe_caps & FE_CAN_##fec) && (i_fec_value == val) ) \
641 return fec;
643 GET_FEC_INNER(FEC_AUTO, 999);
644 GET_FEC_INNER(FEC_AUTO, -1);
645 if (i_fec_value == 0)
646 return FEC_NONE;
647 GET_FEC_INNER(FEC_1_2, 12);
648 GET_FEC_INNER(FEC_2_3, 23);
649 GET_FEC_INNER(FEC_3_4, 34);
650 if (i_fec_value == 35)
651 return FEC_3_5;
652 GET_FEC_INNER(FEC_4_5, 45);
653 GET_FEC_INNER(FEC_5_6, 56);
654 GET_FEC_INNER(FEC_6_7, 67);
655 GET_FEC_INNER(FEC_7_8, 78);
656 GET_FEC_INNER(FEC_8_9, 89);
657 if (i_fec_value == 910)
658 return FEC_9_10;
660 #undef GET_FEC_INNER
661 msg_Warn(NULL, "invalid FEC %d", i_fec_value );
662 return FEC_AUTO;
665 #define GetFECInner(caps) GetFEC(caps, i_fec)
666 #define GetFECLP(caps) GetFEC(caps, i_fec_lp)
668 static fe_modulation_t GetModulation(void)
670 #define GET_MODULATION( mod ) \
671 if ( !strcasecmp( psz_modulation, #mod ) ) \
672 return mod;
674 GET_MODULATION(QPSK);
675 GET_MODULATION(QAM_16);
676 GET_MODULATION(QAM_32);
677 GET_MODULATION(QAM_64);
678 GET_MODULATION(QAM_128);
679 GET_MODULATION(QAM_256);
680 GET_MODULATION(QAM_AUTO);
681 GET_MODULATION(VSB_8);
682 GET_MODULATION(VSB_16);
683 GET_MODULATION(PSK_8);
684 GET_MODULATION(APSK_16);
685 GET_MODULATION(APSK_32);
686 GET_MODULATION(DQPSK);
688 #undef GET_MODULATION
689 msg_Err( NULL, "invalid modulation %s", psz_modulation );
690 exit(1);
693 static fe_pilot_t GetPilot(void)
695 switch ( i_pilot )
697 case 0: return PILOT_OFF;
698 case 1: return PILOT_ON;
699 default:
700 msg_Warn( NULL, "invalid pilot %d", i_pilot );
701 case -1: return PILOT_AUTO;
705 static fe_rolloff_t GetRollOff(void)
707 switch ( i_rolloff )
709 case -1:
710 case 0: return ROLLOFF_AUTO;
711 case 20: return ROLLOFF_20;
712 case 25: return ROLLOFF_25;
713 default:
714 msg_Warn( NULL, "invalid rolloff %d", i_rolloff );
715 case 35: return ROLLOFF_35;
719 static fe_guard_interval_t GetGuard(void)
721 switch ( i_guard )
723 case 32: return GUARD_INTERVAL_1_32;
724 case 16: return GUARD_INTERVAL_1_16;
725 case 8: return GUARD_INTERVAL_1_8;
726 case 4: return GUARD_INTERVAL_1_4;
727 default:
728 msg_Warn( NULL, "invalid guard interval %d", i_guard );
729 case -1:
730 case 0: return GUARD_INTERVAL_AUTO;
734 static fe_transmit_mode_t GetTransmission(void)
736 switch ( i_transmission )
738 case 2: return TRANSMISSION_MODE_2K;
739 case 8: return TRANSMISSION_MODE_8K;
740 #ifdef TRANSMISSION_MODE_4K
741 case 4: return TRANSMISSION_MODE_4K;
742 #endif
743 default:
744 msg_Warn( NULL, "invalid tranmission mode %d", i_transmission );
745 case -1:
746 case 0: return TRANSMISSION_MODE_AUTO;
750 static fe_hierarchy_t GetHierarchy(void)
752 switch ( i_hierarchy )
754 case 0: return HIERARCHY_NONE;
755 case 1: return HIERARCHY_1;
756 case 2: return HIERARCHY_2;
757 case 4: return HIERARCHY_4;
758 default:
759 msg_Warn( NULL, "invalid intramission mode %d", i_transmission );
760 case -1: return HIERARCHY_AUTO;
764 /*****************************************************************************
765 * FrontendInfo : Print frontend info
766 *****************************************************************************/
767 static void FrontendInfo( struct dvb_frontend_info *info, uint32_t version,
768 fe_delivery_system_t *p_systems, int i_systems )
770 msg_Dbg( NULL, "using DVB API version %d.%d", version / 256, version % 256 );
771 msg_Dbg( NULL, "Frontend \"%s\" supports:", info->name );
772 msg_Dbg( NULL, " frequency min: %d, max: %d, stepsize: %d, tolerance: %d",
773 info->frequency_min, info->frequency_max,
774 info->frequency_stepsize, info->frequency_tolerance );
775 msg_Dbg( NULL, " symbolrate min: %d, max: %d, tolerance: %d",
776 info->symbol_rate_min, info->symbol_rate_max, info->symbol_rate_tolerance);
777 msg_Dbg( NULL, " capabilities:" );
779 #define FRONTEND_INFO(caps,val,msg) \
780 if ( caps & val ) \
781 msg_Dbg( NULL, " %s", msg );
783 FRONTEND_INFO( info->caps, FE_IS_STUPID, "FE_IS_STUPID" )
784 FRONTEND_INFO( info->caps, FE_CAN_INVERSION_AUTO, "INVERSION_AUTO" )
785 FRONTEND_INFO( info->caps, FE_CAN_FEC_1_2, "FEC_1_2" )
786 FRONTEND_INFO( info->caps, FE_CAN_FEC_2_3, "FEC_2_3" )
787 FRONTEND_INFO( info->caps, FE_CAN_FEC_3_4, "FEC_3_4" )
788 FRONTEND_INFO( info->caps, FE_CAN_FEC_4_5, "FEC_4_5" )
789 FRONTEND_INFO( info->caps, FE_CAN_FEC_5_6, "FEC_5_6" )
790 FRONTEND_INFO( info->caps, FE_CAN_FEC_6_7, "FEC_6_7" )
791 FRONTEND_INFO( info->caps, FE_CAN_FEC_7_8, "FEC_7_8" )
792 FRONTEND_INFO( info->caps, FE_CAN_FEC_8_9, "FEC_8_9" )
793 FRONTEND_INFO( info->caps, FE_CAN_FEC_AUTO,"FEC_AUTO")
794 FRONTEND_INFO( info->caps, FE_CAN_QPSK, "QPSK" )
795 FRONTEND_INFO( info->caps, FE_CAN_QAM_16, "QAM_16" )
796 FRONTEND_INFO( info->caps, FE_CAN_QAM_32, "QAM_32" )
797 FRONTEND_INFO( info->caps, FE_CAN_QAM_64, "QAM_64" )
798 FRONTEND_INFO( info->caps, FE_CAN_QAM_128,"QAM_128")
799 FRONTEND_INFO( info->caps, FE_CAN_QAM_256,"QAM_256")
800 FRONTEND_INFO( info->caps, FE_CAN_QAM_AUTO,"QAM_AUTO" )
801 FRONTEND_INFO( info->caps, FE_CAN_TRANSMISSION_MODE_AUTO, "TRANSMISSION_MODE_AUTO" )
802 FRONTEND_INFO( info->caps, FE_CAN_BANDWIDTH_AUTO, "BANDWIDTH_AUTO" )
803 FRONTEND_INFO( info->caps, FE_CAN_GUARD_INTERVAL_AUTO, "GUARD_INTERVAL_AUTO" )
804 FRONTEND_INFO( info->caps, FE_CAN_HIERARCHY_AUTO, "HIERARCHY_AUTO" )
805 FRONTEND_INFO( info->caps, FE_CAN_8VSB, "8VSB" )
806 FRONTEND_INFO( info->caps, FE_CAN_16VSB,"16VSB" )
807 FRONTEND_INFO( info->caps, FE_HAS_EXTENDED_CAPS, "EXTENDED_CAPS" )
808 #if DVBAPI_VERSION >= 501
809 FRONTEND_INFO( info->caps, FE_CAN_2G_MODULATION, "2G_MODULATION" )
810 #endif
811 FRONTEND_INFO( info->caps, FE_CAN_MULTISTREAM, "MULTISTREAM" )
812 FRONTEND_INFO( info->caps, FE_NEEDS_BENDING, "NEEDS_BENDING" )
813 FRONTEND_INFO( info->caps, FE_CAN_RECOVER, "FE_CAN_RECOVER" )
814 FRONTEND_INFO( info->caps, FE_CAN_MUTE_TS, "FE_CAN_MUTE_TS" )
815 #undef FRONTEND_INFO
817 msg_Dbg( NULL, " delivery systems:" );
818 int i;
819 for ( i = 0; i < i_systems; i++ )
821 switch ( p_systems[i] )
823 #define DELSYS_INFO(delsys, msg) \
824 case delsys: msg_Dbg( NULL, " %s", msg); break;
825 DELSYS_INFO( SYS_ATSC, "ATSC" )
826 DELSYS_INFO( SYS_ATSCMH, "ATSCMH" )
827 DELSYS_INFO( SYS_CMMB, "CMBB" )
828 DELSYS_INFO( SYS_DAB, "DAB" )
829 DELSYS_INFO( SYS_DSS, "DSS" )
830 DELSYS_INFO( SYS_DVBC_ANNEX_B, "DVBC_ANNEX_B" )
831 DELSYS_INFO( SYS_DVBH, "DVBH" )
832 DELSYS_INFO( SYS_DVBS, "DVBS" )
833 DELSYS_INFO( SYS_DVBS2, "DVBS2" )
834 DELSYS_INFO( SYS_DVBT, "DVBT" )
835 DELSYS_INFO( SYS_ISDBC, "ISDBC" )
836 DELSYS_INFO( SYS_ISDBS, "ISDBS" )
837 DELSYS_INFO( SYS_ISDBT, "ISDBT" )
838 DELSYS_INFO( SYS_UNDEFINED, "UNDEFINED" )
839 #if DVBAPI_VERSION >= 505
840 DELSYS_INFO( SYS_DVBC_ANNEX_A, "DVBC_ANNEX_A" )
841 DELSYS_INFO( SYS_DVBC_ANNEX_C, "DVBC_ANNEX_C" )
842 DELSYS_INFO( SYS_DVBT2, "DVBT2" )
843 DELSYS_INFO( SYS_TURBO, "TURBO" )
844 #else
845 DELSYS_INFO( SYS_DVBC_ANNEX_AC, "DVBC_ANNEX_AC" )
846 #endif
847 #if DVBAPI_VERSION >= 507
848 DELSYS_INFO( SYS_DTMB, "DTMB" )
849 #else
850 DELSYS_INFO( SYS_DMBTH, "DMBTH" )
851 #endif
852 default: msg_Dbg( NULL, " Unknown delivery system %u", p_systems[i]);
853 break;
858 /*****************************************************************************
859 * FrontendSet
860 *****************************************************************************/
861 /* S2API */
862 #if DVBAPI_VERSION >= 505
863 static struct dtv_property info_cmdargs[] = {
864 { .cmd = DTV_API_VERSION, .u.data = 0 },
866 static struct dtv_properties info_cmdseq = {
867 .num = sizeof(info_cmdargs)/sizeof(struct dtv_property),
868 .props = info_cmdargs
871 static struct dtv_property enum_cmdargs[] = {
872 { .cmd = DTV_ENUM_DELSYS, .u.data = 0 },
874 static struct dtv_properties enum_cmdseq = {
875 .num = sizeof(enum_cmdargs)/sizeof(struct dtv_property),
876 .props = enum_cmdargs
878 #endif
880 static struct dtv_property dvbs_cmdargs[] = {
881 { .cmd = DTV_DELIVERY_SYSTEM, .u.data = SYS_DVBS },
882 { .cmd = DTV_FREQUENCY, .u.data = 0 },
883 { .cmd = DTV_MODULATION, .u.data = QPSK },
884 { .cmd = DTV_INVERSION, .u.data = INVERSION_AUTO },
885 { .cmd = DTV_SYMBOL_RATE, .u.data = 27500000 },
886 { .cmd = DTV_INNER_FEC, .u.data = FEC_AUTO },
887 { .cmd = DTV_TUNE },
889 static struct dtv_properties dvbs_cmdseq = {
890 .num = sizeof(dvbs_cmdargs)/sizeof(struct dtv_property),
891 .props = dvbs_cmdargs
894 static struct dtv_property dvbs2_cmdargs[] = {
895 { .cmd = DTV_DELIVERY_SYSTEM, .u.data = SYS_DVBS2 },
896 { .cmd = DTV_FREQUENCY, .u.data = 0 },
897 { .cmd = DTV_MODULATION, .u.data = PSK_8 },
898 { .cmd = DTV_INVERSION, .u.data = INVERSION_AUTO },
899 { .cmd = DTV_SYMBOL_RATE, .u.data = 27500000 },
900 { .cmd = DTV_INNER_FEC, .u.data = FEC_AUTO },
901 { .cmd = DTV_PILOT, .u.data = PILOT_AUTO },
902 { .cmd = DTV_ROLLOFF, .u.data = ROLLOFF_AUTO },
903 { .cmd = DTV_STREAM_ID, .u.data = 0 },
904 { .cmd = DTV_TUNE },
906 static struct dtv_properties dvbs2_cmdseq = {
907 .num = sizeof(dvbs2_cmdargs)/sizeof(struct dtv_property),
908 .props = dvbs2_cmdargs
911 static struct dtv_property dvbc_cmdargs[] = {
912 #if DVBAPI_VERSION >= 505
913 { .cmd = DTV_DELIVERY_SYSTEM, .u.data = SYS_DVBC_ANNEX_A },
914 #else
915 { .cmd = DTV_DELIVERY_SYSTEM, .u.data = SYS_DVBC_ANNEX_AC },
916 #endif
917 { .cmd = DTV_FREQUENCY, .u.data = 0 },
918 { .cmd = DTV_MODULATION, .u.data = QAM_AUTO },
919 { .cmd = DTV_INVERSION, .u.data = INVERSION_AUTO },
920 { .cmd = DTV_SYMBOL_RATE, .u.data = 27500000 },
921 { .cmd = DTV_TUNE },
923 static struct dtv_properties dvbc_cmdseq = {
924 .num = sizeof(dvbc_cmdargs)/sizeof(struct dtv_property),
925 .props = dvbc_cmdargs
928 static struct dtv_property dvbt_cmdargs[] = {
929 { .cmd = DTV_DELIVERY_SYSTEM, .u.data = SYS_DVBT },
930 { .cmd = DTV_FREQUENCY, .u.data = 0 },
931 { .cmd = DTV_MODULATION, .u.data = QAM_AUTO },
932 { .cmd = DTV_INVERSION, .u.data = INVERSION_AUTO },
933 { .cmd = DTV_BANDWIDTH_HZ, .u.data = 8000000 },
934 { .cmd = DTV_CODE_RATE_HP, .u.data = FEC_AUTO },
935 { .cmd = DTV_CODE_RATE_LP, .u.data = FEC_AUTO },
936 { .cmd = DTV_GUARD_INTERVAL, .u.data = GUARD_INTERVAL_AUTO },
937 { .cmd = DTV_TRANSMISSION_MODE,.u.data = TRANSMISSION_MODE_AUTO },
938 { .cmd = DTV_HIERARCHY, .u.data = HIERARCHY_AUTO },
939 { .cmd = DTV_TUNE },
942 static struct dtv_property dvbt2_cmdargs[] = {
943 { .cmd = DTV_DELIVERY_SYSTEM, .u.data = SYS_DVBT2 },
944 { .cmd = DTV_FREQUENCY, .u.data = 0 },
945 { .cmd = DTV_MODULATION, .u.data = QAM_AUTO },
946 { .cmd = DTV_INVERSION, .u.data = INVERSION_AUTO },
947 { .cmd = DTV_BANDWIDTH_HZ, .u.data = 8000000 },
948 { .cmd = DTV_CODE_RATE_HP, .u.data = FEC_AUTO },
949 { .cmd = DTV_CODE_RATE_LP, .u.data = FEC_AUTO },
950 { .cmd = DTV_GUARD_INTERVAL, .u.data = GUARD_INTERVAL_AUTO },
951 { .cmd = DTV_TRANSMISSION_MODE,.u.data = TRANSMISSION_MODE_AUTO },
952 { .cmd = DTV_HIERARCHY, .u.data = HIERARCHY_AUTO },
953 { .cmd = DTV_STREAM_ID, .u.data = 0 },
954 { .cmd = DTV_TUNE },
957 static struct dtv_properties dvbt2_cmdseq = {
958 .num = sizeof(dvbt2_cmdargs)/sizeof(struct dtv_property),
959 .props = dvbt2_cmdargs
962 static struct dtv_properties dvbt_cmdseq = {
963 .num = sizeof(dvbt_cmdargs)/sizeof(struct dtv_property),
964 .props = dvbt_cmdargs
967 /* ATSC + DVB-C annex B */
968 static struct dtv_property atsc_cmdargs[] = {
969 { .cmd = DTV_DELIVERY_SYSTEM, .u.data = SYS_ATSC },
970 { .cmd = DTV_FREQUENCY, .u.data = 0 },
971 { .cmd = DTV_MODULATION, .u.data = QAM_AUTO },
972 { .cmd = DTV_INVERSION, .u.data = INVERSION_AUTO },
973 { .cmd = DTV_TUNE },
975 static struct dtv_properties atsc_cmdseq = {
976 .num = sizeof(atsc_cmdargs)/sizeof(struct dtv_property),
977 .props = atsc_cmdargs
980 static struct dtv_property isdbt_cmdargs[] = {
981 { .cmd = DTV_DELIVERY_SYSTEM, .u.data = SYS_ISDBT },
982 { .cmd = DTV_FREQUENCY, .u.data = 0 },
983 { .cmd = DTV_BANDWIDTH_HZ, .u.data = 6000000 },
984 { .cmd = DTV_INVERSION, .u.data = INVERSION_AUTO },
985 { .cmd = DTV_ISDBT_LAYERA_FEC, .u.data = FEC_AUTO },
986 { .cmd = DTV_ISDBT_LAYERA_MODULATION, .u.data = QAM_AUTO },
987 { .cmd = DTV_ISDBT_LAYERA_SEGMENT_COUNT, .u.data = 0 },
988 { .cmd = DTV_ISDBT_LAYERA_TIME_INTERLEAVING,.u.data = 0 },
989 { .cmd = DTV_ISDBT_LAYERB_FEC, .u.data = FEC_AUTO },
990 { .cmd = DTV_ISDBT_LAYERB_MODULATION, .u.data = QAM_AUTO },
991 { .cmd = DTV_ISDBT_LAYERB_SEGMENT_COUNT, .u.data = 0 },
992 { .cmd = DTV_ISDBT_LAYERB_TIME_INTERLEAVING,.u.data = 0 },
993 { .cmd = DTV_ISDBT_LAYERC_FEC, .u.data = FEC_AUTO },
994 { .cmd = DTV_ISDBT_LAYERC_MODULATION, .u.data = QAM_AUTO },
995 { .cmd = DTV_ISDBT_LAYERC_SEGMENT_COUNT, .u.data = 0 },
996 { .cmd = DTV_ISDBT_LAYERC_TIME_INTERLEAVING,.u.data = 0 },
997 { .cmd = DTV_TUNE },
1000 static struct dtv_properties isdbt_cmdseq = {
1001 .num = sizeof(isdbt_cmdargs)/sizeof(struct dtv_property),
1002 .props = isdbt_cmdargs
1005 #define DELSYS 0
1006 #define FREQUENCY 1
1007 #define MODULATION 2
1008 #define INVERSION 3
1009 #define SYMBOL_RATE 4
1010 #define BANDWIDTH 4
1011 #define FEC_INNER 5
1012 #define FEC_LP 6
1013 #define GUARD 7
1014 #define PILOT 7
1015 #define TRANSMISSION 8
1016 #define ROLLOFF 8
1017 #define MIS 9
1018 #define HIERARCHY 9
1019 #define PLP_ID 10
1021 //ISDBT
1022 #define ISDBT_BANDWIDTH 2
1023 #define ISDBT_LAYERA_FEC 4
1024 #define ISDBT_LAYERA_MODULATION 5
1025 #define ISDBT_LAYERA_SEGMENT_COUNT 6
1026 #define ISDBT_LAYERA_TIME_INTERLEAVING 7
1027 #define ISDBT_LAYERB_FEC 8
1028 #define ISDBT_LAYERB_MODULATION 9
1029 #define ISDBT_LAYERB_SEGMENT_COUNT 10
1030 #define ISDBT_LAYERB_TIME_INTERLEAVING 11
1031 #define ISDBT_LAYERC_FEC 12
1032 #define ISDBT_LAYERC_MODULATION 13
1033 #define ISDBT_LAYERC_SEGMENT_COUNT 14
1034 #define ISDBT_LAYERC_TIME_INTERLEAVING 15
1036 struct dtv_property pclear[] = {
1037 { .cmd = DTV_CLEAR },
1040 struct dtv_properties cmdclear = {
1041 .num = 1,
1042 .props = pclear
1045 static fe_delivery_system_t
1046 FrontendGuessSystem( fe_delivery_system_t *p_systems, int i_systems )
1048 if ( psz_delsys != NULL )
1050 if ( !strcasecmp( psz_delsys, "DVBS" ) )
1051 return SYS_DVBS;
1052 if ( !strcasecmp( psz_delsys, "DVBS2" ) )
1053 return SYS_DVBS2;
1054 if ( !strcasecmp( psz_delsys, "DVBC_ANNEX_A" ) )
1055 #if DVBAPI_VERSION >= 505
1056 return SYS_DVBC_ANNEX_A;
1057 #else
1058 return SYS_DVBC_ANNEX_AC;
1059 #endif
1060 if ( !strcasecmp( psz_delsys, "DVBC_ANNEX_B" ) )
1061 return SYS_DVBC_ANNEX_B;
1062 if ( !strcasecmp( psz_delsys, "DVBT" ) )
1063 return SYS_DVBT;
1064 if ( !strcasecmp( psz_delsys, "DVBT2" ) )
1065 return SYS_DVBT2;
1066 if ( !strcasecmp( psz_delsys, "ATSC" ) )
1067 return SYS_ATSC;
1068 if ( !strcasecmp( psz_delsys, "ISDBT" ) )
1069 return SYS_ISDBT;
1070 msg_Err( NULL, "unknown delivery system %s", psz_delsys );
1071 exit(1);
1074 if ( i_systems == 1 )
1075 return p_systems[0];
1077 int i;
1078 for ( i = 0; i < i_systems; i++ )
1080 switch ( p_systems[i] )
1082 case SYS_DVBS:
1083 if ( i_frequency < 50000000 )
1084 return SYS_DVBS;
1085 break;
1086 #if DVBAPI_VERSION >= 505
1087 case SYS_DVBC_ANNEX_A:
1088 if ( i_frequency > 50000000 || i_srate != 27500000 ||
1089 psz_modulation != NULL )
1090 return SYS_DVBC_ANNEX_A;
1091 break;
1092 #else
1093 case SYS_DVBC_ANNEX_AC:
1094 if ( i_frequency > 50000000 || i_srate != 27500000 ||
1095 psz_modulation != NULL )
1096 return SYS_DVBC_ANNEX_AC;
1097 break;
1098 #endif
1099 case SYS_DVBT:
1100 if ( i_frequency > 50000000 )
1101 return SYS_DVBT;
1102 break;
1103 case SYS_DVBT2:
1104 if ( i_frequency > 50000000 && (dvb_plp_id) )
1105 return SYS_DVBT2;
1106 break;
1107 default:
1108 break;
1112 msg_Warn( NULL, "couldn't guess delivery system, use --delsys" );
1113 return p_systems[0];
1116 static void FrontendSet( bool b_init )
1118 struct dvb_frontend_info info;
1119 struct dtv_properties *p;
1120 fe_delivery_system_t p_systems[MAX_DELIVERY_SYSTEMS] = { 0 };
1121 int i_systems = 0;
1123 if ( ioctl( i_frontend, FE_GET_INFO, &info ) < 0 )
1125 msg_Err( NULL, "FE_GET_INFO failed (%s)", strerror(errno) );
1126 exit(1);
1129 uint32_t version = 0x300;
1130 #if DVBAPI_VERSION >= 505
1131 if ( ioctl( i_frontend, FE_GET_PROPERTY, &info_cmdseq ) < 0 )
1133 #endif
1134 /* DVBv3 device */
1135 switch ( info.type )
1137 case FE_OFDM:
1138 p_systems[i_systems++] = SYS_DVBT;
1139 #if DVBAPI_VERSION >= 505
1140 if ( info.caps & FE_CAN_2G_MODULATION )
1141 p_systems[i_systems++] = SYS_DVBT2;
1142 #endif
1143 break;
1144 case FE_QAM:
1145 #if DVBAPI_VERSION >= 505
1146 p_systems[i_systems++] = SYS_DVBC_ANNEX_A;
1147 #else
1148 p_systems[i_systems++] = SYS_DVBC_ANNEX_AC;
1149 #endif
1150 break;
1151 case FE_QPSK:
1152 p_systems[i_systems++] = SYS_DVBS;
1153 if ( info.caps & FE_CAN_2G_MODULATION )
1154 p_systems[i_systems++] = SYS_DVBS2;
1155 break;
1156 case FE_ATSC:
1157 if ( info.caps & (FE_CAN_8VSB | FE_CAN_16VSB) )
1158 p_systems[i_systems++] = SYS_ATSC;
1159 if ( info.caps & (FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_QAM_AUTO) )
1160 p_systems[i_systems++] = SYS_DVBC_ANNEX_B;
1161 break;
1162 default:
1163 msg_Err( NULL, "unknown frontend type %d", info.type );
1164 exit(1);
1166 #if DVBAPI_VERSION >= 505
1168 else
1170 version = info_cmdargs[0].u.data;
1171 if ( ioctl( i_frontend, FE_GET_PROPERTY, &enum_cmdseq ) < 0 )
1173 msg_Err( NULL, "unable to query frontend" );
1174 exit(1);
1176 i_systems = enum_cmdargs[0].u.buffer.len;
1177 if ( i_systems < 1 )
1179 msg_Err( NULL, "no available delivery system" );
1180 exit(1);
1183 int i;
1184 for ( i = 0; i < i_systems; i++ )
1185 p_systems[i] = enum_cmdargs[0].u.buffer.data[i];
1187 #endif
1189 if ( b_init )
1190 FrontendInfo( &info, version, p_systems, i_systems );
1192 /* Clear frontend commands */
1193 if ( ioctl( i_frontend, FE_SET_PROPERTY, &cmdclear ) < 0 )
1195 msg_Err( NULL, "Unable to clear frontend" );
1196 exit(1);
1199 fe_delivery_system_t system = FrontendGuessSystem( p_systems, i_systems );
1200 switch ( system )
1202 case SYS_DVBT:
1203 p = &dvbt_cmdseq;
1204 p->props[DELSYS].u.data = system;
1205 p->props[FREQUENCY].u.data = i_frequency;
1206 p->props[INVERSION].u.data = GetInversion();
1207 if ( psz_modulation != NULL )
1208 p->props[MODULATION].u.data = GetModulation();
1209 p->props[BANDWIDTH].u.data = i_bandwidth * 1000000;
1210 p->props[FEC_INNER].u.data = GetFECInner(info.caps);
1211 p->props[FEC_LP].u.data = GetFECLP(info.caps);
1212 p->props[GUARD].u.data = GetGuard();
1213 p->props[TRANSMISSION].u.data = GetTransmission();
1214 p->props[HIERARCHY].u.data = GetHierarchy();
1216 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",
1217 i_frequency, i_bandwidth, i_inversion, i_fec, i_fec_lp,
1218 i_hierarchy,
1219 psz_modulation == NULL ? "qam_auto" : psz_modulation,
1220 i_guard, i_transmission );
1221 break;
1222 case SYS_DVBT2:
1223 p = &dvbt2_cmdseq;
1224 p->props[DELSYS].u.data = system;
1225 p->props[FREQUENCY].u.data = i_frequency;
1226 p->props[INVERSION].u.data = GetInversion();
1227 if ( psz_modulation != NULL )
1228 p->props[MODULATION].u.data = GetModulation();
1229 p->props[BANDWIDTH].u.data = i_bandwidth * 1000000;
1230 p->props[FEC_INNER].u.data = GetFECInner(info.caps);
1231 p->props[FEC_LP].u.data = GetFECLP(info.caps);
1232 p->props[GUARD].u.data = GetGuard();
1233 p->props[TRANSMISSION].u.data = GetTransmission();
1234 p->props[HIERARCHY].u.data = GetHierarchy();
1235 p->props[PLP_ID].u.data = dvb_plp_id;
1237 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 ",
1238 i_frequency, i_bandwidth, i_inversion, i_fec, i_fec_lp,
1239 i_hierarchy,
1240 psz_modulation == NULL ? "qam_auto" : psz_modulation,
1241 i_guard, i_transmission, p->props[PLP_ID].u.data );
1242 break;
1243 #if DVBAPI_VERSION >= 505
1244 case SYS_DVBC_ANNEX_A:
1245 #else
1246 case SYS_DVBC_ANNEX_AC:
1247 #endif
1248 p = &dvbc_cmdseq;
1249 p->props[FREQUENCY].u.data = i_frequency;
1250 p->props[INVERSION].u.data = GetInversion();
1251 if ( psz_modulation != NULL )
1252 p->props[MODULATION].u.data = GetModulation();
1253 p->props[SYMBOL_RATE].u.data = i_srate;
1255 msg_Dbg( NULL, "tuning DVB-C frontend to f=%d srate=%d inversion=%d modulation=%s",
1256 i_frequency, i_srate, i_inversion,
1257 psz_modulation == NULL ? "qam_auto" : psz_modulation );
1258 break;
1260 case SYS_DVBC_ANNEX_B:
1261 p = &atsc_cmdseq;
1262 p->props[DELSYS].u.data = system;
1263 p->props[FREQUENCY].u.data = i_frequency;
1264 p->props[INVERSION].u.data = GetInversion();
1265 if ( psz_modulation != NULL )
1266 p->props[MODULATION].u.data = GetModulation();
1268 msg_Dbg( NULL, "tuning ATSC cable frontend to f=%d inversion=%d modulation=%s",
1269 i_frequency, i_inversion,
1270 psz_modulation == NULL ? "qam_auto" : psz_modulation );
1271 break;
1273 case SYS_DVBS:
1274 case SYS_DVBS2:
1275 if ( psz_modulation != NULL )
1277 p = &dvbs2_cmdseq;
1278 p->props[MODULATION].u.data = GetModulation();
1279 p->props[PILOT].u.data = GetPilot();
1280 p->props[ROLLOFF].u.data = GetRollOff();
1281 p->props[MIS].u.data = i_mis;
1283 else
1284 p = &dvbs_cmdseq;
1286 p->props[INVERSION].u.data = GetInversion();
1287 p->props[SYMBOL_RATE].u.data = i_srate;
1288 p->props[FEC_INNER].u.data = GetFECInner(info.caps);
1289 p->props[FREQUENCY].u.data = FrontendDoDiseqc();
1291 msg_Dbg( NULL, "tuning DVB-S frontend to f=%d srate=%d inversion=%d fec=%d rolloff=%d modulation=%s pilot=%d mis=%d",
1292 i_frequency, i_srate, i_inversion, i_fec, i_rolloff,
1293 psz_modulation == NULL ? "legacy" : psz_modulation, i_pilot,
1294 i_mis );
1295 break;
1297 case SYS_ATSC:
1298 p = &atsc_cmdseq;
1299 p->props[FREQUENCY].u.data = i_frequency;
1300 p->props[INVERSION].u.data = GetInversion();
1301 if ( psz_modulation != NULL )
1302 p->props[MODULATION].u.data = GetModulation();
1304 msg_Dbg( NULL, "tuning ATSC frontend to f=%d inversion=%d modulation=%s",
1305 i_frequency, i_inversion,
1306 psz_modulation == NULL ? "qam_auto" : psz_modulation );
1307 break;
1308 case SYS_ISDBT:
1309 p = &isdbt_cmdseq;
1310 p->props[DELSYS].u.data = system;
1311 p->props[FREQUENCY].u.data = i_frequency;
1312 p->props[ISDBT_BANDWIDTH].u.data = i_bandwidth * 1000000;
1313 p->props[INVERSION].u.data = GetInversion();
1314 p->props[ISDBT_LAYERA_FEC].u.data = FEC_AUTO;
1315 p->props[ISDBT_LAYERA_MODULATION].u.data = QAM_AUTO;
1316 p->props[ISDBT_LAYERA_SEGMENT_COUNT].u.data = 0;
1317 p->props[ISDBT_LAYERA_TIME_INTERLEAVING].u.data = 0;
1318 p->props[ISDBT_LAYERB_FEC].u.data = FEC_AUTO;
1319 p->props[ISDBT_LAYERB_MODULATION].u.data = QAM_AUTO;
1320 p->props[ISDBT_LAYERB_SEGMENT_COUNT].u.data = 0;
1321 p->props[ISDBT_LAYERB_TIME_INTERLEAVING].u.data = 0;
1322 p->props[ISDBT_LAYERC_FEC].u.data = FEC_AUTO;
1323 p->props[ISDBT_LAYERC_MODULATION].u.data = QAM_AUTO;
1324 p->props[ISDBT_LAYERC_SEGMENT_COUNT].u.data = 0;
1325 p->props[ISDBT_LAYERC_TIME_INTERLEAVING].u.data = 0;
1327 msg_Dbg( NULL, "tuning ISDB-T frontend to f=%d bandwidth=%d ",
1328 i_frequency, i_bandwidth);
1329 break;
1331 default:
1332 msg_Err( NULL, "unknown frontend type %d", info.type );
1333 exit(1);
1336 /* Empty the event queue */
1337 for ( ; ; )
1339 struct dvb_frontend_event event;
1340 if ( ioctl( i_frontend, FE_GET_EVENT, &event ) < 0
1341 && errno == EWOULDBLOCK )
1342 break;
1345 /* Now send it all to the frontend device */
1346 if ( ioctl( i_frontend, FE_SET_PROPERTY, p ) < 0 )
1348 msg_Err( NULL, "setting frontend failed (%s)", strerror(errno) );
1349 exit(1);
1352 i_last_status = 0;
1354 if (i_frontend_timeout_duration)
1355 ev_timer_again(event_loop, &lock_watcher);
1358 #else /* !S2API */
1360 #warning "You are trying to compile DVBlast with an outdated linux-dvb interface."
1361 #warning "DVBlast will be very limited and some options will have no effect."
1363 static void FrontendSet( bool b_init )
1365 struct dvb_frontend_info info;
1366 struct dvb_frontend_parameters fep;
1368 if ( ioctl( i_frontend, FE_GET_INFO, &info ) < 0 )
1370 msg_Err( NULL, "FE_GET_INFO failed (%s)", strerror(errno) );
1371 exit(1);
1374 switch ( info.type )
1376 case FE_OFDM:
1377 fep.frequency = i_frequency;
1378 fep.inversion = INVERSION_AUTO;
1380 switch ( i_bandwidth )
1382 case 6: fep.u.ofdm.bandwidth = BANDWIDTH_6_MHZ; break;
1383 case 7: fep.u.ofdm.bandwidth = BANDWIDTH_7_MHZ; break;
1384 default:
1385 case 8: fep.u.ofdm.bandwidth = BANDWIDTH_8_MHZ; break;
1388 fep.u.ofdm.code_rate_HP = FEC_AUTO;
1389 fep.u.ofdm.code_rate_LP = FEC_AUTO;
1390 fep.u.ofdm.constellation = QAM_AUTO;
1391 fep.u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO;
1392 fep.u.ofdm.guard_interval = GUARD_INTERVAL_AUTO;
1393 fep.u.ofdm.hierarchy_information = HIERARCHY_AUTO;
1395 msg_Dbg( NULL, "tuning OFDM frontend to f=%d, bandwidth=%d",
1396 i_frequency, i_bandwidth );
1397 break;
1399 case FE_QAM:
1400 fep.frequency = i_frequency;
1401 fep.inversion = INVERSION_AUTO;
1402 fep.u.qam.symbol_rate = i_srate;
1403 fep.u.qam.fec_inner = FEC_AUTO;
1404 fep.u.qam.modulation = QAM_AUTO;
1406 msg_Dbg( NULL, "tuning QAM frontend to f=%d, srate=%d",
1407 i_frequency, i_srate );
1408 break;
1410 case FE_QPSK:
1411 fep.inversion = INVERSION_AUTO;
1412 fep.u.qpsk.symbol_rate = i_srate;
1413 fep.u.qpsk.fec_inner = FEC_AUTO;
1414 fep.frequency = FrontendDoDiseqc();
1416 msg_Dbg( NULL, "tuning QPSK frontend to f=%d, srate=%d",
1417 i_frequency, i_srate );
1418 break;
1420 #if DVBAPI_VERSION >= 301
1421 case FE_ATSC:
1422 fep.frequency = i_frequency;
1424 fep.u.vsb.modulation = QAM_AUTO;
1426 msg_Dbg( NULL, "tuning ATSC frontend to f=%d", i_frequency );
1427 break;
1428 #endif
1430 default:
1431 msg_Err( NULL, "unknown frontend type %d", info.type );
1432 exit(1);
1435 /* Empty the event queue */
1436 for ( ; ; )
1438 struct dvb_frontend_event event;
1439 if ( ioctl( i_frontend, FE_GET_EVENT, &event ) < 0
1440 && errno == EWOULDBLOCK )
1441 break;
1444 /* Now send it all to the frontend device */
1445 if ( ioctl( i_frontend, FE_SET_FRONTEND, &fep ) < 0 )
1447 msg_Err( NULL, "setting frontend failed (%s)", strerror(errno) );
1448 exit(1);
1451 i_last_status = 0;
1453 if (i_frontend_timeout_duration)
1454 ev_timer_again(event_loop, &lock_watcher);
1457 #endif /* S2API */
1459 /*****************************************************************************
1460 * dvb_FrontendStatus
1461 *****************************************************************************/
1462 uint8_t dvb_FrontendStatus( uint8_t *p_answer, ssize_t *pi_size )
1464 struct ret_frontend_status *p_ret = (struct ret_frontend_status *)p_answer;
1466 if ( ioctl( i_frontend, FE_GET_INFO, &p_ret->info ) < 0 )
1468 msg_Err( NULL, "ioctl FE_GET_INFO failed (%s)", strerror(errno) );
1469 return RET_ERR;
1472 if ( ioctl( i_frontend, FE_READ_STATUS, &p_ret->i_status ) < 0 )
1474 msg_Err( NULL, "ioctl FE_READ_STATUS failed (%s)", strerror(errno) );
1475 return RET_ERR;
1478 if ( p_ret->i_status & FE_HAS_LOCK )
1480 if ( ioctl( i_frontend, FE_READ_BER, &p_ret->i_ber ) < 0 )
1481 msg_Err( NULL, "ioctl FE_READ_BER failed (%s)", strerror(errno) );
1483 if ( ioctl( i_frontend, FE_READ_SIGNAL_STRENGTH, &p_ret->i_strength )
1484 < 0 )
1485 msg_Err( NULL, "ioctl FE_READ_SIGNAL_STRENGTH failed (%s)",
1486 strerror(errno) );
1488 if ( ioctl( i_frontend, FE_READ_SNR, &p_ret->i_snr ) < 0 )
1489 msg_Err( NULL, "ioctl FE_READ_SNR failed (%s)", strerror(errno) );
1492 *pi_size = sizeof(struct ret_frontend_status);
1493 return RET_FRONTEND_STATUS;
1496 #endif