Restore correct behaviour for --select-pmts
[dvblast.git] / dvb.c
blob6873da44344b7bd215901f75cbcb35347c983435
1 /*****************************************************************************
2 * dvb.c: linux-dvb input for DVBlast
3 *****************************************************************************
4 * Copyright (C) 2008-2010 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 #if DVBAPI_VERSION < 508
51 #define DTV_STREAM_ID 42
52 #define FE_CAN_MULTISTREAM 0x4000000
53 #endif
55 #define MAX_DELIVERY_SYSTEMS 20
57 #include "dvblast.h"
58 #include "en50221.h"
59 #include "comm.h"
61 #include <bitstream/common.h>
63 /*****************************************************************************
64 * Local declarations
65 *****************************************************************************/
66 #define DVR_READ_TIMEOUT 30000000 /* 30 s */
67 #define CA_POLL_PERIOD 100000 /* 100 ms */
68 #define MAX_READ_ONCE 50
69 #define DVR_BUFFER_SIZE 40*188*1024 /* bytes */
71 int i_dvr_buffer_size = DVR_BUFFER_SIZE;
73 static int i_frontend, i_dvr;
74 static fe_status_t i_last_status;
75 static mtime_t i_frontend_timeout;
76 static mtime_t i_last_packet = 0;
77 static mtime_t i_ca_next_event = 0;
78 static block_t *p_freelist = NULL;
80 /*****************************************************************************
81 * Local prototypes
82 *****************************************************************************/
83 static block_t *DVRRead( void );
84 static void FrontendPoll( void );
85 static void FrontendSet( bool b_reset );
87 /*****************************************************************************
88 * dvb_Open
89 *****************************************************************************/
90 void dvb_Open( void )
92 char psz_tmp[128];
94 msg_Dbg( NULL, "compiled with DVB API version %d.%d", DVB_API_VERSION, DVB_API_VERSION_MINOR );
96 i_wallclock = mdate();
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 en50221_Init();
131 i_ca_next_event = mdate() + CA_POLL_PERIOD;
134 /*****************************************************************************
135 * dvb_Reset
136 *****************************************************************************/
137 void dvb_Reset( void )
139 if ( i_frequency )
140 FrontendSet(true);
143 /*****************************************************************************
144 * dvb_Read
145 *****************************************************************************/
146 block_t *dvb_Read( mtime_t i_poll_timeout )
148 struct pollfd ufds[4];
149 int i_ret, i_nb_fd = 1;
150 block_t *p_blocks = NULL;
152 memset( ufds, 0, sizeof(ufds) );
153 ufds[0].fd = i_dvr;
154 ufds[0].events = POLLIN;
155 if ( i_frontend != -1 )
157 ufds[1].fd = i_frontend;
158 ufds[1].events = POLLERR | POLLPRI;
159 i_nb_fd++;
161 if ( i_comm_fd != -1 )
163 ufds[i_nb_fd].fd = i_comm_fd;
164 ufds[i_nb_fd].events = POLLIN;
165 i_nb_fd++;
167 if ( i_ca_handle && i_ca_type == CA_CI_LINK )
169 ufds[i_nb_fd].fd = i_ca_handle;
170 ufds[i_nb_fd].events = POLLIN;
171 i_nb_fd++;
174 i_ret = poll( ufds, i_nb_fd, (i_poll_timeout + 999) / 1000 );
176 i_wallclock = mdate();
178 if ( i_ret < 0 )
180 if( errno != EINTR )
181 msg_Err( NULL, "poll error: %s", strerror(errno) );
182 return NULL;
185 if ( ufds[1].revents )
186 FrontendPoll();
188 if ( ufds[0].revents )
190 p_blocks = DVRRead();
191 i_wallclock = mdate();
194 if ( p_blocks != NULL )
195 i_last_packet = i_wallclock;
196 else if ( !i_frontend_timeout
197 && i_wallclock > i_last_packet + DVR_READ_TIMEOUT )
199 msg_Warn( NULL, "no DVR output, resetting" );
200 if ( i_frequency )
201 FrontendSet(false);
202 en50221_Reset();
205 if ( i_ca_handle && i_ca_type == CA_CI_LINK )
207 if ( ufds[i_nb_fd - 1].revents )
209 en50221_Read();
210 i_ca_next_event = i_wallclock + CA_POLL_PERIOD;
212 else if ( i_wallclock > i_ca_next_event )
214 en50221_Poll();
215 i_ca_next_event = i_wallclock + CA_POLL_PERIOD;
219 if ( i_frontend_timeout && i_wallclock > i_frontend_timeout )
221 if ( i_quit_timeout_duration )
223 msg_Err( NULL, "no lock" );
224 switch (i_print_type) {
225 case PRINT_XML:
226 printf("</TS>\n");
227 break;
228 default:
229 break;
231 exit(EXIT_STATUS_FRONTEND_TIMEOUT);
233 msg_Warn( NULL, "no lock, tuning again" );
234 if ( i_frequency )
235 FrontendSet(false);
238 if ( i_comm_fd != -1 && ufds[2].revents )
239 comm_Read();
241 return p_blocks;
244 /*****************************************************************************
245 * DVRRead
246 *****************************************************************************/
247 static block_t *DVRRead( void )
249 int i, i_len;
250 block_t *p_ts = p_freelist, **pp_current = &p_ts;
251 struct iovec p_iov[MAX_READ_ONCE];
253 for ( i = 0; i < MAX_READ_ONCE; i++ )
255 if ( (*pp_current) == NULL ) *pp_current = block_New();
256 p_iov[i].iov_base = (*pp_current)->p_ts;
257 p_iov[i].iov_len = TS_SIZE;
258 pp_current = &(*pp_current)->p_next;
261 if ( (i_len = readv(i_dvr, p_iov, MAX_READ_ONCE)) < 0 )
263 msg_Err( NULL, "couldn't read from DVR device (%s)",
264 strerror(errno) );
265 i_len = 0;
267 i_len /= TS_SIZE;
269 pp_current = &p_ts;
270 while ( i_len && *pp_current )
272 pp_current = &(*pp_current)->p_next;
273 i_len--;
276 p_freelist = *pp_current;
277 *pp_current = NULL;
279 return p_ts;
284 * Demux
287 /*****************************************************************************
288 * dvb_SetFilter : controls the demux to add a filter
289 *****************************************************************************/
290 int dvb_SetFilter( uint16_t i_pid )
292 struct dmx_pes_filter_params s_filter_params;
293 char psz_tmp[128];
294 int i_fd;
296 sprintf( psz_tmp, "/dev/dvb/adapter%d/demux%d", i_adapter, i_fenum );
297 if( (i_fd = open(psz_tmp, O_RDWR)) < 0 )
299 msg_Err( NULL, "DMXSetFilter: opening device failed (%s)",
300 strerror(errno) );
301 return -1;
304 s_filter_params.pid = i_pid;
305 s_filter_params.input = DMX_IN_FRONTEND;
306 s_filter_params.output = DMX_OUT_TS_TAP;
307 s_filter_params.flags = DMX_IMMEDIATE_START;
308 s_filter_params.pes_type = DMX_PES_OTHER;
310 if ( ioctl( i_fd, DMX_SET_PES_FILTER, &s_filter_params ) < 0 )
312 msg_Err( NULL, "failed setting filter on %d (%s)", i_pid,
313 strerror(errno) );
314 close( i_fd );
315 return -1;
318 msg_Dbg( NULL, "setting filter on PID %d", i_pid );
320 return i_fd;
323 /*****************************************************************************
324 * dvb_UnsetFilter : removes a filter
325 *****************************************************************************/
326 void dvb_UnsetFilter( int i_fd, uint16_t i_pid )
328 if ( ioctl( i_fd, DMX_STOP ) < 0 )
329 msg_Err( NULL, "DMX_STOP failed (%s)", strerror(errno) );
330 else
331 msg_Dbg( NULL, "unsetting filter on PID %d", i_pid );
333 close( i_fd );
338 * Frontend
341 /*****************************************************************************
342 * FrontendPoll : Poll for frontend events
343 *****************************************************************************/
344 static void FrontendPoll( void )
346 struct dvb_frontend_event event;
347 fe_status_t i_status, i_diff;
349 for( ;; )
351 int i_ret = ioctl( i_frontend, FE_GET_EVENT, &event );
353 if( i_ret < 0 )
355 if( errno == EWOULDBLOCK )
356 return; /* no more events */
358 msg_Err( NULL, "reading frontend event failed (%d) %s",
359 i_ret, strerror(errno) );
360 return;
363 i_status = event.status;
364 i_diff = i_status ^ i_last_status;
365 i_last_status = i_status;
368 #define IF_UP( x ) \
370 if ( i_diff & (x) ) \
372 if ( i_status & (x) )
374 IF_UP( FE_HAS_SIGNAL )
375 msg_Dbg( NULL, "frontend has acquired signal" );
376 else
377 msg_Dbg( NULL, "frontend has lost signal" );
379 IF_UP( FE_HAS_CARRIER )
380 msg_Dbg( NULL, "frontend has acquired carrier" );
381 else
382 msg_Dbg( NULL, "frontend has lost carrier" );
384 IF_UP( FE_HAS_VITERBI )
385 msg_Dbg( NULL, "frontend has acquired stable FEC" );
386 else
387 msg_Dbg( NULL, "frontend has lost FEC" );
389 IF_UP( FE_HAS_SYNC )
390 msg_Dbg( NULL, "frontend has acquired sync" );
391 else
392 msg_Dbg( NULL, "frontend has lost sync" );
394 IF_UP( FE_HAS_LOCK )
396 int32_t i_value = 0;
397 msg_Info( NULL, "frontend has acquired lock" );
398 switch (i_print_type) {
399 case PRINT_XML:
400 printf("<STATUS type=\"lock\" status=\"1\" />\n");
401 break;
402 default:
403 printf("frontend has acquired lock\n" );
405 i_frontend_timeout = 0;
406 i_last_packet = i_wallclock;
408 if ( i_quit_timeout_duration && !i_quit_timeout )
409 i_quit_timeout = i_wallclock + i_quit_timeout_duration;
411 /* Read some statistics */
412 if( ioctl( i_frontend, FE_READ_BER, &i_value ) >= 0 )
413 msg_Dbg( NULL, "- Bit error rate: %d", i_value );
414 if( ioctl( i_frontend, FE_READ_SIGNAL_STRENGTH, &i_value ) >= 0 )
415 msg_Dbg( NULL, "- Signal strength: %d", i_value );
416 if( ioctl( i_frontend, FE_READ_SNR, &i_value ) >= 0 )
417 msg_Dbg( NULL, "- SNR: %d", i_value );
419 else
421 msg_Dbg( NULL, "frontend has lost lock" );
422 switch (i_print_type) {
423 case PRINT_XML:
424 printf("<STATUS type=\"lock\" status=\"0\"/>\n");
425 break;
426 default:
427 printf("frontend has lost lock\n" );
429 i_frontend_timeout = i_wallclock + i_frontend_timeout_duration;
432 IF_UP( FE_REINIT )
434 /* The frontend was reinited. */
435 msg_Warn( NULL, "reiniting frontend");
436 if ( i_frequency )
437 FrontendSet(true);
440 #undef IF_UP
444 static int FrontendDoDiseqc(void)
446 fe_sec_voltage_t fe_voltage;
447 fe_sec_tone_mode_t fe_tone;
448 int bis_frequency;
450 switch ( i_voltage )
452 case 0: fe_voltage = SEC_VOLTAGE_OFF; break;
453 default:
454 case 13: fe_voltage = SEC_VOLTAGE_13; break;
455 case 18: fe_voltage = SEC_VOLTAGE_18; break;
458 fe_tone = b_tone ? SEC_TONE_ON : SEC_TONE_OFF;
460 /* Automatic mode. */
461 if ( i_frequency >= 950000 && i_frequency <= 2150000 )
463 msg_Dbg( NULL, "frequency %d is in IF-band", i_frequency );
464 bis_frequency = i_frequency;
466 else if ( i_frequency >= 2500000 && i_frequency <= 2700000 )
468 msg_Dbg( NULL, "frequency %d is in S-band", i_frequency );
469 bis_frequency = 3650000 - i_frequency;
471 else if ( i_frequency >= 3400000 && i_frequency <= 4200000 )
473 msg_Dbg( NULL, "frequency %d is in C-band (lower)", i_frequency );
474 bis_frequency = 5150000 - i_frequency;
476 else if ( i_frequency >= 4500000 && i_frequency <= 4800000 )
478 msg_Dbg( NULL, "frequency %d is in C-band (higher)", i_frequency );
479 bis_frequency = 5950000 - i_frequency;
481 else if ( i_frequency >= 10700000 && i_frequency < 11700000 )
483 msg_Dbg( NULL, "frequency %d is in Ku-band (lower)",
484 i_frequency );
485 bis_frequency = i_frequency - 9750000;
487 else if ( i_frequency >= 11700000 && i_frequency <= 13250000 )
489 msg_Dbg( NULL, "frequency %d is in Ku-band (higher)",
490 i_frequency );
491 bis_frequency = i_frequency - 10600000;
492 fe_tone = SEC_TONE_ON;
494 else
496 msg_Err( NULL, "frequency %d is out of any known band",
497 i_frequency );
498 exit(1);
501 /* Switch off continuous tone. */
502 if ( ioctl( i_frontend, FE_SET_TONE, SEC_TONE_OFF ) < 0 )
504 msg_Err( NULL, "FE_SET_TONE failed (%s)", strerror(errno) );
505 exit(1);
508 /* Configure LNB voltage. */
509 if ( ioctl( i_frontend, FE_SET_VOLTAGE, fe_voltage ) < 0 )
511 msg_Err( NULL, "FE_SET_VOLTAGE failed (%s)", strerror(errno) );
512 exit(1);
515 /* Wait for at least 15 ms. Currently 100 ms because of broken drivers. */
516 msleep(100000);
518 /* Diseqc */
519 if ( i_satnum > 0 && i_satnum < 5 )
521 /* digital satellite equipment control,
522 * specification is available from http://www.eutelsat.com/
525 /* DiSEqC 1.1 */
526 struct dvb_diseqc_master_cmd uncmd =
527 { {0xe0, 0x10, 0x39, 0xf0, 0x00, 0x00}, 4};
529 /* DiSEqC 1.0 */
530 struct dvb_diseqc_master_cmd cmd =
531 { {0xe0, 0x10, 0x38, 0xf0, 0x00, 0x00}, 4};
533 cmd.msg[3] = 0xf0 /* reset bits */
534 | ((i_satnum - 1) << 2)
535 | (fe_voltage == SEC_VOLTAGE_13 ? 0 : 2)
536 | (fe_tone == SEC_TONE_ON ? 1 : 0);
538 if ( i_uncommitted > 0 && i_uncommitted < 5 )
540 uncmd.msg[3] = 0xf0 /* reset bits */
541 | ((i_uncommitted - 1) << 2)
542 | (fe_voltage == SEC_VOLTAGE_13 ? 0 : 2)
543 | (fe_tone == SEC_TONE_ON ? 1 : 0);
544 if( ioctl( i_frontend, FE_DISEQC_SEND_MASTER_CMD, &uncmd ) < 0 )
546 msg_Err( NULL, "ioctl FE_SEND_MASTER_CMD failed (%s)",
547 strerror(errno) );
548 exit(1);
550 /* Repeat uncommitted command */
551 uncmd.msg[0] = 0xe1; /* framing: master, no reply, repeated TX */
552 if( ioctl( i_frontend, FE_DISEQC_SEND_MASTER_CMD, &uncmd ) < 0 )
554 msg_Err( NULL, "ioctl FE_SEND_MASTER_CMD failed (%s)",
555 strerror(errno) );
556 exit(1);
558 /* Pause 125 ms between uncommitted & committed diseqc commands. */
559 msleep(125000);
562 if( ioctl( i_frontend, FE_DISEQC_SEND_MASTER_CMD, &cmd ) < 0 )
564 msg_Err( NULL, "ioctl FE_SEND_MASTER_CMD failed (%s)",
565 strerror(errno) );
566 exit(1);
568 msleep(100000); /* Should be 15 ms. */
570 /* Do it again just to be sure. */
571 cmd.msg[0] = 0xe1; /* framing: master, no reply, repeated TX */
572 if( ioctl( i_frontend, FE_DISEQC_SEND_MASTER_CMD, &cmd ) < 0 )
574 msg_Err( NULL, "ioctl FE_SEND_MASTER_CMD failed (%s)",
575 strerror(errno) );
576 exit(1);
578 msleep(100000); /* Again, should be 15 ms */
580 else if ( i_satnum == 0xA || i_satnum == 0xB )
582 /* A or B simple diseqc ("diseqc-compatible") */
583 if( ioctl( i_frontend, FE_DISEQC_SEND_BURST,
584 i_satnum == 0xB ? SEC_MINI_B : SEC_MINI_A ) < 0 )
586 msg_Err( NULL, "ioctl FE_SEND_BURST failed (%s)", strerror(errno) );
587 exit(1);
589 msleep(100000); /* ... */
592 if ( ioctl( i_frontend, FE_SET_TONE, fe_tone ) < 0 )
594 msg_Err( NULL, "FE_SET_TONE failed (%s)", strerror(errno) );
595 exit(1);
598 msleep(100000); /* ... */
600 msg_Dbg( NULL, "configuring LNB to v=%d p=%d satnum=%x uncommitted=%x",
601 i_voltage, b_tone, i_satnum, i_uncommitted );
602 return bis_frequency;
605 #if DVB_API_VERSION >= 5
607 #if DVBAPI_VERSION < 505
608 #warning Your linux-dvb headers are old, you should consider upgrading your kernel and/or compiling against different kernel headers
609 #endif
611 /*****************************************************************************
612 * Helper functions for S2API
613 *****************************************************************************/
614 static fe_spectral_inversion_t GetInversion(void)
616 switch ( i_inversion )
618 case 0: return INVERSION_OFF;
619 case 1: return INVERSION_ON;
620 default:
621 msg_Warn( NULL, "invalid inversion %d", i_inversion );
622 case -1: return INVERSION_AUTO;
626 static fe_code_rate_t GetFEC(fe_caps_t fe_caps, int i_fec_value)
628 #define GET_FEC_INNER(fec, val) \
629 if ( (fe_caps & FE_CAN_##fec) && (i_fec_value == val) ) \
630 return fec;
632 GET_FEC_INNER(FEC_AUTO, 999);
633 GET_FEC_INNER(FEC_AUTO, -1);
634 if (i_fec_value == 0)
635 return FEC_NONE;
636 GET_FEC_INNER(FEC_1_2, 12);
637 GET_FEC_INNER(FEC_2_3, 23);
638 GET_FEC_INNER(FEC_3_4, 34);
639 if (i_fec_value == 35)
640 return FEC_3_5;
641 GET_FEC_INNER(FEC_4_5, 45);
642 GET_FEC_INNER(FEC_5_6, 56);
643 GET_FEC_INNER(FEC_6_7, 67);
644 GET_FEC_INNER(FEC_7_8, 78);
645 GET_FEC_INNER(FEC_8_9, 89);
646 if (i_fec_value == 910)
647 return FEC_9_10;
649 #undef GET_FEC_INNER
650 msg_Warn(NULL, "invalid FEC %d", i_fec_value );
651 return FEC_AUTO;
654 #define GetFECInner(caps) GetFEC(caps, i_fec)
655 #define GetFECLP(caps) GetFEC(caps, i_fec_lp)
657 static fe_modulation_t GetModulation(void)
659 #define GET_MODULATION( mod ) \
660 if ( !strcasecmp( psz_modulation, #mod ) ) \
661 return mod;
663 GET_MODULATION(QPSK);
664 GET_MODULATION(QAM_16);
665 GET_MODULATION(QAM_32);
666 GET_MODULATION(QAM_64);
667 GET_MODULATION(QAM_128);
668 GET_MODULATION(QAM_256);
669 GET_MODULATION(QAM_AUTO);
670 GET_MODULATION(VSB_8);
671 GET_MODULATION(VSB_16);
672 GET_MODULATION(PSK_8);
673 GET_MODULATION(APSK_16);
674 GET_MODULATION(APSK_32);
675 GET_MODULATION(DQPSK);
677 #undef GET_MODULATION
678 msg_Err( NULL, "invalid modulation %s", psz_modulation );
679 exit(1);
682 static fe_pilot_t GetPilot(void)
684 switch ( i_pilot )
686 case 0: return PILOT_OFF;
687 case 1: return PILOT_ON;
688 default:
689 msg_Warn( NULL, "invalid pilot %d", i_pilot );
690 case -1: return PILOT_AUTO;
694 static fe_rolloff_t GetRollOff(void)
696 switch ( i_rolloff )
698 case -1:
699 case 0: return ROLLOFF_AUTO;
700 case 20: return ROLLOFF_20;
701 case 25: return ROLLOFF_25;
702 default:
703 msg_Warn( NULL, "invalid rolloff %d", i_rolloff );
704 case 35: return ROLLOFF_35;
708 static fe_guard_interval_t GetGuard(void)
710 switch ( i_guard )
712 case 32: return GUARD_INTERVAL_1_32;
713 case 16: return GUARD_INTERVAL_1_16;
714 case 8: return GUARD_INTERVAL_1_8;
715 case 4: return GUARD_INTERVAL_1_4;
716 default:
717 msg_Warn( NULL, "invalid guard interval %d", i_guard );
718 case -1:
719 case 0: return GUARD_INTERVAL_AUTO;
723 static fe_transmit_mode_t GetTransmission(void)
725 switch ( i_transmission )
727 case 2: return TRANSMISSION_MODE_2K;
728 case 8: return TRANSMISSION_MODE_8K;
729 #ifdef TRANSMISSION_MODE_4K
730 case 4: return TRANSMISSION_MODE_4K;
731 #endif
732 default:
733 msg_Warn( NULL, "invalid tranmission mode %d", i_transmission );
734 case -1:
735 case 0: return TRANSMISSION_MODE_AUTO;
739 static fe_hierarchy_t GetHierarchy(void)
741 switch ( i_hierarchy )
743 case 0: return HIERARCHY_NONE;
744 case 1: return HIERARCHY_1;
745 case 2: return HIERARCHY_2;
746 case 4: return HIERARCHY_4;
747 default:
748 msg_Warn( NULL, "invalid intramission mode %d", i_transmission );
749 case -1: return HIERARCHY_AUTO;
753 /*****************************************************************************
754 * FrontendInfo : Print frontend info
755 *****************************************************************************/
756 static void FrontendInfo( struct dvb_frontend_info *info, uint32_t version,
757 fe_delivery_system_t *p_systems, int i_systems )
759 msg_Dbg( NULL, "using DVB API version %d.%d", version / 256, version % 256 );
760 msg_Dbg( NULL, "Frontend \"%s\" supports:", info->name );
761 msg_Dbg( NULL, " frequency min: %d, max: %d, stepsize: %d, tolerance: %d",
762 info->frequency_min, info->frequency_max,
763 info->frequency_stepsize, info->frequency_tolerance );
764 msg_Dbg( NULL, " symbolrate min: %d, max: %d, tolerance: %d",
765 info->symbol_rate_min, info->symbol_rate_max, info->symbol_rate_tolerance);
766 msg_Dbg( NULL, " capabilities:" );
768 #define FRONTEND_INFO(caps,val,msg) \
769 if ( caps & val ) \
770 msg_Dbg( NULL, " %s", msg );
772 FRONTEND_INFO( info->caps, FE_IS_STUPID, "FE_IS_STUPID" )
773 FRONTEND_INFO( info->caps, FE_CAN_INVERSION_AUTO, "INVERSION_AUTO" )
774 FRONTEND_INFO( info->caps, FE_CAN_FEC_1_2, "FEC_1_2" )
775 FRONTEND_INFO( info->caps, FE_CAN_FEC_2_3, "FEC_2_3" )
776 FRONTEND_INFO( info->caps, FE_CAN_FEC_3_4, "FEC_3_4" )
777 FRONTEND_INFO( info->caps, FE_CAN_FEC_4_5, "FEC_4_5" )
778 FRONTEND_INFO( info->caps, FE_CAN_FEC_5_6, "FEC_5_6" )
779 FRONTEND_INFO( info->caps, FE_CAN_FEC_6_7, "FEC_6_7" )
780 FRONTEND_INFO( info->caps, FE_CAN_FEC_7_8, "FEC_7_8" )
781 FRONTEND_INFO( info->caps, FE_CAN_FEC_8_9, "FEC_8_9" )
782 FRONTEND_INFO( info->caps, FE_CAN_FEC_AUTO,"FEC_AUTO")
783 FRONTEND_INFO( info->caps, FE_CAN_QPSK, "QPSK" )
784 FRONTEND_INFO( info->caps, FE_CAN_QAM_16, "QAM_16" )
785 FRONTEND_INFO( info->caps, FE_CAN_QAM_32, "QAM_32" )
786 FRONTEND_INFO( info->caps, FE_CAN_QAM_64, "QAM_64" )
787 FRONTEND_INFO( info->caps, FE_CAN_QAM_128,"QAM_128")
788 FRONTEND_INFO( info->caps, FE_CAN_QAM_256,"QAM_256")
789 FRONTEND_INFO( info->caps, FE_CAN_QAM_AUTO,"QAM_AUTO" )
790 FRONTEND_INFO( info->caps, FE_CAN_TRANSMISSION_MODE_AUTO, "TRANSMISSION_MODE_AUTO" )
791 FRONTEND_INFO( info->caps, FE_CAN_BANDWIDTH_AUTO, "BANDWIDTH_AUTO" )
792 FRONTEND_INFO( info->caps, FE_CAN_GUARD_INTERVAL_AUTO, "GUARD_INTERVAL_AUTO" )
793 FRONTEND_INFO( info->caps, FE_CAN_HIERARCHY_AUTO, "HIERARCHY_AUTO" )
794 FRONTEND_INFO( info->caps, FE_CAN_8VSB, "8VSB" )
795 FRONTEND_INFO( info->caps, FE_CAN_16VSB,"16VSB" )
796 FRONTEND_INFO( info->caps, FE_HAS_EXTENDED_CAPS, "EXTENDED_CAPS" )
797 #if DVBAPI_VERSION >= 501
798 FRONTEND_INFO( info->caps, FE_CAN_2G_MODULATION, "2G_MODULATION" )
799 #endif
800 FRONTEND_INFO( info->caps, FE_CAN_MULTISTREAM, "MULTISTREAM" )
801 FRONTEND_INFO( info->caps, FE_NEEDS_BENDING, "NEEDS_BENDING" )
802 FRONTEND_INFO( info->caps, FE_CAN_RECOVER, "FE_CAN_RECOVER" )
803 FRONTEND_INFO( info->caps, FE_CAN_MUTE_TS, "FE_CAN_MUTE_TS" )
804 #undef FRONTEND_INFO
806 msg_Dbg( NULL, " delivery systems:" );
807 int i;
808 for ( i = 0; i < i_systems; i++ )
810 switch ( p_systems[i] )
812 #define DELSYS_INFO(delsys, msg) \
813 case delsys: msg_Dbg( NULL, " %s", msg); break;
814 DELSYS_INFO( SYS_ATSC, "ATSC" )
815 DELSYS_INFO( SYS_ATSCMH, "ATSCMH" )
816 DELSYS_INFO( SYS_CMMB, "CMBB" )
817 DELSYS_INFO( SYS_DAB, "DAB" )
818 DELSYS_INFO( SYS_DSS, "DSS" )
819 DELSYS_INFO( SYS_DVBC_ANNEX_B, "DVBC_ANNEX_B" )
820 DELSYS_INFO( SYS_DVBH, "DVBH" )
821 DELSYS_INFO( SYS_DVBS, "DVBS" )
822 DELSYS_INFO( SYS_DVBS2, "DVBS2" )
823 DELSYS_INFO( SYS_DVBT, "DVBT" )
824 DELSYS_INFO( SYS_ISDBC, "ISDBC" )
825 DELSYS_INFO( SYS_ISDBS, "ISDBS" )
826 DELSYS_INFO( SYS_ISDBT, "ISDBT" )
827 DELSYS_INFO( SYS_UNDEFINED, "UNDEFINED" )
828 #if DVBAPI_VERSION >= 505
829 DELSYS_INFO( SYS_DVBC_ANNEX_A, "DVBC_ANNEX_A" )
830 DELSYS_INFO( SYS_DVBC_ANNEX_C, "DVBC_ANNEX_C" )
831 DELSYS_INFO( SYS_DVBT2, "DVBT2" )
832 DELSYS_INFO( SYS_TURBO, "TURBO" )
833 #else
834 DELSYS_INFO( SYS_DVBC_ANNEX_AC, "DVBC_ANNEX_AC" )
835 #endif
836 #if DVBAPI_VERSION >= 507
837 DELSYS_INFO( SYS_DTMB, "DTMB" )
838 #else
839 DELSYS_INFO( SYS_DMBTH, "DMBTH" )
840 #endif
845 /*****************************************************************************
846 * FrontendSet
847 *****************************************************************************/
848 /* S2API */
849 #if DVBAPI_VERSION >= 505
850 static struct dtv_property info_cmdargs[] = {
851 { .cmd = DTV_API_VERSION, .u.data = 0 },
853 static struct dtv_properties info_cmdseq = {
854 .num = sizeof(info_cmdargs)/sizeof(struct dtv_property),
855 .props = info_cmdargs
858 static struct dtv_property enum_cmdargs[] = {
859 { .cmd = DTV_ENUM_DELSYS, .u.data = 0 },
861 static struct dtv_properties enum_cmdseq = {
862 .num = sizeof(enum_cmdargs)/sizeof(struct dtv_property),
863 .props = enum_cmdargs
865 #endif
867 static struct dtv_property dvbs_cmdargs[] = {
868 { .cmd = DTV_DELIVERY_SYSTEM, .u.data = SYS_DVBS },
869 { .cmd = DTV_FREQUENCY, .u.data = 0 },
870 { .cmd = DTV_MODULATION, .u.data = QPSK },
871 { .cmd = DTV_INVERSION, .u.data = INVERSION_AUTO },
872 { .cmd = DTV_SYMBOL_RATE, .u.data = 27500000 },
873 { .cmd = DTV_INNER_FEC, .u.data = FEC_AUTO },
874 { .cmd = DTV_TUNE },
876 static struct dtv_properties dvbs_cmdseq = {
877 .num = sizeof(dvbs_cmdargs)/sizeof(struct dtv_property),
878 .props = dvbs_cmdargs
881 static struct dtv_property dvbs2_cmdargs[] = {
882 { .cmd = DTV_DELIVERY_SYSTEM, .u.data = SYS_DVBS2 },
883 { .cmd = DTV_FREQUENCY, .u.data = 0 },
884 { .cmd = DTV_MODULATION, .u.data = PSK_8 },
885 { .cmd = DTV_INVERSION, .u.data = INVERSION_AUTO },
886 { .cmd = DTV_SYMBOL_RATE, .u.data = 27500000 },
887 { .cmd = DTV_INNER_FEC, .u.data = FEC_AUTO },
888 { .cmd = DTV_PILOT, .u.data = PILOT_AUTO },
889 { .cmd = DTV_ROLLOFF, .u.data = ROLLOFF_AUTO },
890 { .cmd = DTV_STREAM_ID, .u.data = 0 },
891 { .cmd = DTV_TUNE },
893 static struct dtv_properties dvbs2_cmdseq = {
894 .num = sizeof(dvbs2_cmdargs)/sizeof(struct dtv_property),
895 .props = dvbs2_cmdargs
898 static struct dtv_property dvbc_cmdargs[] = {
899 #if DVBAPI_VERSION >= 505
900 { .cmd = DTV_DELIVERY_SYSTEM, .u.data = SYS_DVBC_ANNEX_A },
901 #else
902 { .cmd = DTV_DELIVERY_SYSTEM, .u.data = SYS_DVBC_ANNEX_AC },
903 #endif
904 { .cmd = DTV_FREQUENCY, .u.data = 0 },
905 { .cmd = DTV_MODULATION, .u.data = QAM_AUTO },
906 { .cmd = DTV_INVERSION, .u.data = INVERSION_AUTO },
907 { .cmd = DTV_SYMBOL_RATE, .u.data = 27500000 },
908 { .cmd = DTV_TUNE },
910 static struct dtv_properties dvbc_cmdseq = {
911 .num = sizeof(dvbc_cmdargs)/sizeof(struct dtv_property),
912 .props = dvbc_cmdargs
915 static struct dtv_property dvbt_cmdargs[] = {
916 { .cmd = DTV_DELIVERY_SYSTEM, .u.data = SYS_DVBT },
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_BANDWIDTH_HZ, .u.data = 8000000 },
921 { .cmd = DTV_CODE_RATE_HP, .u.data = FEC_AUTO },
922 { .cmd = DTV_CODE_RATE_LP, .u.data = FEC_AUTO },
923 { .cmd = DTV_GUARD_INTERVAL, .u.data = GUARD_INTERVAL_AUTO },
924 { .cmd = DTV_TRANSMISSION_MODE,.u.data = TRANSMISSION_MODE_AUTO },
925 { .cmd = DTV_HIERARCHY, .u.data = HIERARCHY_AUTO },
926 { .cmd = DTV_TUNE },
928 static struct dtv_properties dvbt_cmdseq = {
929 .num = sizeof(dvbt_cmdargs)/sizeof(struct dtv_property),
930 .props = dvbt_cmdargs
933 /* ATSC + DVB-C annex B */
934 static struct dtv_property atsc_cmdargs[] = {
935 { .cmd = DTV_DELIVERY_SYSTEM, .u.data = SYS_ATSC },
936 { .cmd = DTV_FREQUENCY, .u.data = 0 },
937 { .cmd = DTV_MODULATION, .u.data = QAM_AUTO },
938 { .cmd = DTV_INVERSION, .u.data = INVERSION_AUTO },
939 { .cmd = DTV_TUNE },
941 static struct dtv_properties atsc_cmdseq = {
942 .num = sizeof(atsc_cmdargs)/sizeof(struct dtv_property),
943 .props = atsc_cmdargs
946 #define DELSYS 0
947 #define FREQUENCY 1
948 #define MODULATION 2
949 #define INVERSION 3
950 #define SYMBOL_RATE 4
951 #define BANDWIDTH 4
952 #define FEC_INNER 5
953 #define FEC_LP 6
954 #define GUARD 7
955 #define PILOT 7
956 #define TRANSMISSION 8
957 #define ROLLOFF 8
958 #define MIS 9
959 #define HIERARCHY 9
961 struct dtv_property pclear[] = {
962 { .cmd = DTV_CLEAR },
965 struct dtv_properties cmdclear = {
966 .num = 1,
967 .props = pclear
970 static fe_delivery_system_t
971 FrontendGuessSystem( fe_delivery_system_t *p_systems, int i_systems )
973 if ( psz_delsys != NULL )
975 if ( !strcasecmp( psz_delsys, "DVBS" ) )
976 return SYS_DVBS;
977 if ( !strcasecmp( psz_delsys, "DVBS2" ) )
978 return SYS_DVBS2;
979 if ( !strcasecmp( psz_delsys, "DVBC_ANNEX_A" ) )
980 #if DVBAPI_VERSION >= 505
981 return SYS_DVBC_ANNEX_A;
982 #else
983 return SYS_DVBC_ANNEX_AC;
984 #endif
985 if ( !strcasecmp( psz_delsys, "DVBC_ANNEX_B" ) )
986 return SYS_DVBC_ANNEX_B;
987 if ( !strcasecmp( psz_delsys, "DVBT" ) )
988 return SYS_DVBT;
989 if ( !strcasecmp( psz_delsys, "ATSC" ) )
990 return SYS_ATSC;
991 msg_Err( NULL, "unknown delivery system %s", psz_delsys );
992 exit(1);
995 if ( i_systems == 1 )
996 return p_systems[0];
998 int i;
999 for ( i = 0; i < i_systems; i++ )
1001 switch ( p_systems[i] )
1003 case SYS_DVBS:
1004 if ( i_frequency < 50000000 )
1005 return SYS_DVBS;
1006 break;
1007 #if DVBAPI_VERSION >= 505
1008 case SYS_DVBC_ANNEX_A:
1009 if ( i_frequency > 50000000 || i_srate != 27500000 ||
1010 psz_modulation != NULL )
1011 return SYS_DVBC_ANNEX_A;
1012 break;
1013 #else
1014 case SYS_DVBC_ANNEX_AC:
1015 if ( i_frequency > 50000000 || i_srate != 27500000 ||
1016 psz_modulation != NULL )
1017 return SYS_DVBC_ANNEX_AC;
1018 break;
1019 #endif
1020 case SYS_DVBT:
1021 if ( i_frequency > 50000000 )
1022 return SYS_DVBT;
1023 break;
1024 default:
1025 break;
1029 msg_Warn( NULL, "couldn't guess delivery system, use --delsys" );
1030 return p_systems[0];
1033 static void FrontendSet( bool b_init )
1035 struct dvb_frontend_info info;
1036 struct dtv_properties *p;
1037 fe_delivery_system_t p_systems[MAX_DELIVERY_SYSTEMS] = { 0 };
1038 int i_systems = 0;
1040 if ( ioctl( i_frontend, FE_GET_INFO, &info ) < 0 )
1042 msg_Err( NULL, "FE_GET_INFO failed (%s)", strerror(errno) );
1043 exit(1);
1046 uint32_t version = 0x300;
1047 #if DVBAPI_VERSION >= 505
1048 if ( ioctl( i_frontend, FE_GET_PROPERTY, &info_cmdseq ) < 0 )
1050 #endif
1051 /* DVBv3 device */
1052 switch ( info.type )
1054 case FE_OFDM:
1055 p_systems[i_systems++] = SYS_DVBT;
1056 #if DVBAPI_VERSION >= 505
1057 if ( info.caps & FE_CAN_2G_MODULATION )
1058 p_systems[i_systems++] = SYS_DVBT2;
1059 #endif
1060 break;
1061 case FE_QAM:
1062 #if DVBAPI_VERSION >= 505
1063 p_systems[i_systems++] = SYS_DVBC_ANNEX_A;
1064 #else
1065 p_systems[i_systems++] = SYS_DVBC_ANNEX_AC;
1066 #endif
1067 break;
1068 case FE_QPSK:
1069 p_systems[i_systems++] = SYS_DVBS;
1070 if ( info.caps & FE_CAN_2G_MODULATION )
1071 p_systems[i_systems++] = SYS_DVBS2;
1072 break;
1073 case FE_ATSC:
1074 if ( info.caps & (FE_CAN_8VSB | FE_CAN_16VSB) )
1075 p_systems[i_systems++] = SYS_ATSC;
1076 if ( info.caps & (FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_QAM_AUTO) )
1077 p_systems[i_systems++] = SYS_DVBC_ANNEX_B;
1078 break;
1079 default:
1080 msg_Err( NULL, "unknown frontend type %d", info.type );
1081 exit(1);
1083 #if DVBAPI_VERSION >= 505
1085 else
1087 version = info_cmdargs[0].u.data;
1088 if ( ioctl( i_frontend, FE_GET_PROPERTY, &enum_cmdseq ) < 0 )
1090 msg_Err( NULL, "unable to query frontend" );
1091 exit(1);
1093 i_systems = enum_cmdargs[0].u.buffer.len;
1094 if ( i_systems < 1 )
1096 msg_Err( NULL, "no available delivery system" );
1097 exit(1);
1100 int i;
1101 for ( i = 0; i < i_systems; i++ )
1102 p_systems[i] = enum_cmdargs[0].u.buffer.data[i];
1104 #endif
1106 if ( b_init )
1107 FrontendInfo( &info, version, p_systems, i_systems );
1109 /* Clear frontend commands */
1110 if ( ioctl( i_frontend, FE_SET_PROPERTY, &cmdclear ) < 0 )
1112 msg_Err( NULL, "Unable to clear frontend" );
1113 exit(1);
1116 fe_delivery_system_t system = FrontendGuessSystem( p_systems, i_systems );
1117 switch ( system )
1119 case SYS_DVBT:
1120 p = &dvbt_cmdseq;
1121 p->props[DELSYS].u.data = system;
1122 p->props[FREQUENCY].u.data = i_frequency;
1123 p->props[INVERSION].u.data = GetInversion();
1124 if ( psz_modulation != NULL )
1125 p->props[MODULATION].u.data = GetModulation();
1126 p->props[BANDWIDTH].u.data = i_bandwidth * 1000000;
1127 p->props[FEC_INNER].u.data = GetFECInner(info.caps);
1128 p->props[FEC_LP].u.data = GetFECLP(info.caps);
1129 p->props[GUARD].u.data = GetGuard();
1130 p->props[TRANSMISSION].u.data = GetTransmission();
1131 p->props[HIERARCHY].u.data = GetHierarchy();
1133 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",
1134 i_frequency, i_bandwidth, i_inversion, i_fec, i_fec_lp,
1135 i_hierarchy,
1136 psz_modulation == NULL ? "qam_auto" : psz_modulation,
1137 i_guard, i_transmission );
1138 break;
1140 #if DVBAPI_VERSION >= 505
1141 case SYS_DVBC_ANNEX_A:
1142 #else
1143 case SYS_DVBC_ANNEX_AC:
1144 #endif
1145 p = &dvbc_cmdseq;
1146 p->props[FREQUENCY].u.data = i_frequency;
1147 p->props[INVERSION].u.data = GetInversion();
1148 if ( psz_modulation != NULL )
1149 p->props[MODULATION].u.data = GetModulation();
1150 p->props[SYMBOL_RATE].u.data = i_srate;
1152 msg_Dbg( NULL, "tuning DVB-C frontend to f=%d srate=%d inversion=%d modulation=%s",
1153 i_frequency, i_srate, i_inversion,
1154 psz_modulation == NULL ? "qam_auto" : psz_modulation );
1155 break;
1157 case SYS_DVBC_ANNEX_B:
1158 p = &atsc_cmdseq;
1159 p->props[DELSYS].u.data = system;
1160 p->props[FREQUENCY].u.data = i_frequency;
1161 p->props[INVERSION].u.data = GetInversion();
1162 if ( psz_modulation != NULL )
1163 p->props[MODULATION].u.data = GetModulation();
1165 msg_Dbg( NULL, "tuning ATSC cable frontend to f=%d inversion=%d modulation=%s",
1166 i_frequency, i_inversion,
1167 psz_modulation == NULL ? "qam_auto" : psz_modulation );
1168 break;
1170 case SYS_DVBS:
1171 case SYS_DVBS2:
1172 if ( psz_modulation != NULL )
1174 p = &dvbs2_cmdseq;
1175 p->props[MODULATION].u.data = GetModulation();
1176 p->props[PILOT].u.data = GetPilot();
1177 p->props[ROLLOFF].u.data = GetRollOff();
1178 p->props[MIS].u.data = i_mis;
1180 else
1181 p = &dvbs_cmdseq;
1183 p->props[INVERSION].u.data = GetInversion();
1184 p->props[SYMBOL_RATE].u.data = i_srate;
1185 p->props[FEC_INNER].u.data = GetFECInner(info.caps);
1186 p->props[FREQUENCY].u.data = FrontendDoDiseqc();
1188 msg_Dbg( NULL, "tuning DVB-S frontend to f=%d srate=%d inversion=%d fec=%d rolloff=%d modulation=%s pilot=%d mis=%d",
1189 i_frequency, i_srate, i_inversion, i_fec, i_rolloff,
1190 psz_modulation == NULL ? "legacy" : psz_modulation, i_pilot,
1191 i_mis );
1192 break;
1194 case SYS_ATSC:
1195 p = &atsc_cmdseq;
1196 p->props[FREQUENCY].u.data = i_frequency;
1197 p->props[INVERSION].u.data = GetInversion();
1198 if ( psz_modulation != NULL )
1199 p->props[MODULATION].u.data = GetModulation();
1201 msg_Dbg( NULL, "tuning ATSC frontend to f=%d inversion=%d modulation=%s",
1202 i_frequency, i_inversion,
1203 psz_modulation == NULL ? "qam_auto" : psz_modulation );
1204 break;
1206 default:
1207 msg_Err( NULL, "unknown frontend type %d", info.type );
1208 exit(1);
1211 /* Empty the event queue */
1212 for ( ; ; )
1214 struct dvb_frontend_event event;
1215 if ( ioctl( i_frontend, FE_GET_EVENT, &event ) < 0
1216 && errno == EWOULDBLOCK )
1217 break;
1220 /* Now send it all to the frontend device */
1221 if ( ioctl( i_frontend, FE_SET_PROPERTY, p ) < 0 )
1223 msg_Err( NULL, "setting frontend failed (%s)", strerror(errno) );
1224 exit(1);
1227 i_last_status = 0;
1228 i_frontend_timeout = i_wallclock + i_frontend_timeout_duration;
1231 #else /* !S2API */
1233 #warning "You are trying to compile DVBlast with an outdated linux-dvb interface."
1234 #warning "DVBlast will be very limited and some options will have no effect."
1236 static void FrontendSet( bool b_init )
1238 struct dvb_frontend_info info;
1239 struct dvb_frontend_parameters fep;
1241 if ( ioctl( i_frontend, FE_GET_INFO, &info ) < 0 )
1243 msg_Err( NULL, "FE_GET_INFO failed (%s)", strerror(errno) );
1244 exit(1);
1247 switch ( info.type )
1249 case FE_OFDM:
1250 fep.frequency = i_frequency;
1251 fep.inversion = INVERSION_AUTO;
1253 switch ( i_bandwidth )
1255 case 6: fep.u.ofdm.bandwidth = BANDWIDTH_6_MHZ; break;
1256 case 7: fep.u.ofdm.bandwidth = BANDWIDTH_7_MHZ; break;
1257 default:
1258 case 8: fep.u.ofdm.bandwidth = BANDWIDTH_8_MHZ; break;
1261 fep.u.ofdm.code_rate_HP = FEC_AUTO;
1262 fep.u.ofdm.code_rate_LP = FEC_AUTO;
1263 fep.u.ofdm.constellation = QAM_AUTO;
1264 fep.u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO;
1265 fep.u.ofdm.guard_interval = GUARD_INTERVAL_AUTO;
1266 fep.u.ofdm.hierarchy_information = HIERARCHY_AUTO;
1268 msg_Dbg( NULL, "tuning OFDM frontend to f=%d, bandwidth=%d",
1269 i_frequency, i_bandwidth );
1270 break;
1272 case FE_QAM:
1273 fep.frequency = i_frequency;
1274 fep.inversion = INVERSION_AUTO;
1275 fep.u.qam.symbol_rate = i_srate;
1276 fep.u.qam.fec_inner = FEC_AUTO;
1277 fep.u.qam.modulation = QAM_AUTO;
1279 msg_Dbg( NULL, "tuning QAM frontend to f=%d, srate=%d",
1280 i_frequency, i_srate );
1281 break;
1283 case FE_QPSK:
1284 fep.inversion = INVERSION_AUTO;
1285 fep.u.qpsk.symbol_rate = i_srate;
1286 fep.u.qpsk.fec_inner = FEC_AUTO;
1287 fep.frequency = FrontendDoDiseqc();
1289 msg_Dbg( NULL, "tuning QPSK frontend to f=%d, srate=%d",
1290 i_frequency, i_srate );
1291 break;
1293 #if DVBAPI_VERSION >= 301
1294 case FE_ATSC:
1295 fep.frequency = i_frequency;
1297 fep.u.vsb.modulation = QAM_AUTO;
1299 msg_Dbg( NULL, "tuning ATSC frontend to f=%d", i_frequency );
1300 break;
1301 #endif
1303 default:
1304 msg_Err( NULL, "unknown frontend type %d", info.type );
1305 exit(1);
1308 /* Empty the event queue */
1309 for ( ; ; )
1311 struct dvb_frontend_event event;
1312 if ( ioctl( i_frontend, FE_GET_EVENT, &event ) < 0
1313 && errno == EWOULDBLOCK )
1314 break;
1317 /* Now send it all to the frontend device */
1318 if ( ioctl( i_frontend, FE_SET_FRONTEND, &fep ) < 0 )
1320 msg_Err( NULL, "setting frontend failed (%s)", strerror(errno) );
1321 exit(1);
1324 i_last_status = 0;
1325 i_frontend_timeout = i_wallclock + i_frontend_timeout_duration;
1328 #endif /* S2API */
1330 /*****************************************************************************
1331 * dvb_FrontendStatus
1332 *****************************************************************************/
1333 uint8_t dvb_FrontendStatus( uint8_t *p_answer, ssize_t *pi_size )
1335 struct ret_frontend_status *p_ret = (struct ret_frontend_status *)p_answer;
1337 if ( ioctl( i_frontend, FE_GET_INFO, &p_ret->info ) < 0 )
1339 msg_Err( NULL, "ioctl FE_GET_INFO failed (%s)", strerror(errno) );
1340 return RET_ERR;
1343 if ( ioctl( i_frontend, FE_READ_STATUS, &p_ret->i_status ) < 0 )
1345 msg_Err( NULL, "ioctl FE_READ_STATUS failed (%s)", strerror(errno) );
1346 return RET_ERR;
1349 if ( p_ret->i_status & FE_HAS_LOCK )
1351 if ( ioctl( i_frontend, FE_READ_BER, &p_ret->i_ber ) < 0 )
1352 msg_Err( NULL, "ioctl FE_READ_BER failed (%s)", strerror(errno) );
1354 if ( ioctl( i_frontend, FE_READ_SIGNAL_STRENGTH, &p_ret->i_strength )
1355 < 0 )
1356 msg_Err( NULL, "ioctl FE_READ_SIGNAL_STRENGTH failed (%s)",
1357 strerror(errno) );
1359 if ( ioctl( i_frontend, FE_READ_SNR, &p_ret->i_snr ) < 0 )
1360 msg_Err( NULL, "ioctl FE_READ_SNR failed (%s)", strerror(errno) );
1363 *pi_size = sizeof(struct ret_frontend_status);
1364 return RET_FRONTEND_STATUS;
1367 #endif