Remove ecm and emm non-working output options
[dvblast.git] / dvb.c
blobb0a86ce8dcd07b82efa026e36ccf5fd326a52bf9
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 *****************************************************************************/
23 #include <stdlib.h>
24 #include <stdint.h>
25 #include <stdbool.h>
26 #include <stdio.h>
27 #include <unistd.h>
28 #include <string.h>
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <fcntl.h>
32 #include <unistd.h>
33 #include <sys/ioctl.h>
34 #include <sys/socket.h>
35 #include <sys/uio.h>
36 #include <netinet/in.h>
37 #include <arpa/inet.h>
38 #include <poll.h>
39 #include <errno.h>
41 /* DVB Card Drivers */
42 #include <linux/dvb/version.h>
43 #include <linux/dvb/dmx.h>
44 #include <linux/dvb/frontend.h>
45 #include <linux/dvb/ca.h>
47 #include "dvblast.h"
48 #include "en50221.h"
49 #include "comm.h"
51 #include <bitstream/common.h>
53 /*****************************************************************************
54 * Local declarations
55 *****************************************************************************/
56 #define DVR_READ_TIMEOUT 30000000 /* 30 s */
57 #define CA_POLL_PERIOD 100000 /* 100 ms */
58 #define MAX_READ_ONCE 50
59 #define DVR_BUFFER_SIZE 40*188*1024 /* bytes */
61 static int i_frontend, i_dvr;
62 static fe_status_t i_last_status;
63 static mtime_t i_frontend_timeout;
64 static mtime_t i_last_packet = 0;
65 static mtime_t i_ca_next_event = 0;
66 static block_t *p_freelist = NULL;
68 /*****************************************************************************
69 * Local prototypes
70 *****************************************************************************/
71 static block_t *DVRRead( void );
72 static void FrontendPoll( void );
73 static void FrontendSet( bool b_reset );
75 /*****************************************************************************
76 * dvb_Open
77 *****************************************************************************/
78 void dvb_Open( void )
80 char psz_tmp[128];
82 msg_Dbg( NULL, "using linux-dvb API version %d", DVB_API_VERSION );
84 i_wallclock = mdate();
86 sprintf( psz_tmp, "/dev/dvb/adapter%d/frontend%d", i_adapter, i_fenum );
87 if( (i_frontend = open(psz_tmp, O_RDWR | O_NONBLOCK)) < 0 )
89 msg_Err( NULL, "opening device %s failed (%s)", psz_tmp,
90 strerror(errno) );
91 exit(1);
94 FrontendSet(true);
96 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_Err( NULL, "opening device %s failed (%s)", psz_tmp,
101 strerror(errno) );
102 exit(1);
105 if ( ioctl( i_dvr, DMX_SET_BUFFER_SIZE, DVR_BUFFER_SIZE ) < 0 )
107 msg_Warn( NULL, "couldn't set %s buffer size (%s)", psz_tmp,
108 strerror(errno) );
111 en50221_Init();
112 i_ca_next_event = mdate() + CA_POLL_PERIOD;
115 /*****************************************************************************
116 * dvb_Reset
117 *****************************************************************************/
118 void dvb_Reset( void )
120 FrontendSet(true);
123 /*****************************************************************************
124 * dvb_Read
125 *****************************************************************************/
126 block_t *dvb_Read( mtime_t i_poll_timeout )
128 struct pollfd ufds[4];
129 int i_ret, i_nb_fd = 2;
130 block_t *p_blocks = NULL;
132 memset( ufds, 0, sizeof(ufds) );
133 ufds[0].fd = i_dvr;
134 ufds[0].events = POLLIN;
135 ufds[1].fd = i_frontend;
136 ufds[1].events = POLLERR | POLLPRI;
137 if ( i_comm_fd != -1 )
139 ufds[i_nb_fd].fd = i_comm_fd;
140 ufds[i_nb_fd].events = POLLIN;
141 i_nb_fd++;
143 if ( i_ca_handle && i_ca_type == CA_CI_LINK )
145 ufds[i_nb_fd].fd = i_ca_handle;
146 ufds[i_nb_fd].events = POLLIN;
147 i_nb_fd++;
150 i_ret = poll( ufds, i_nb_fd, (i_poll_timeout + 999) / 1000 );
152 i_wallclock = mdate();
154 if ( i_ret < 0 )
156 if( errno != EINTR )
157 msg_Err( NULL, "poll error: %s", strerror(errno) );
158 return NULL;
161 if ( ufds[1].revents )
162 FrontendPoll();
164 if ( ufds[0].revents )
166 p_blocks = DVRRead();
167 i_wallclock = mdate();
170 if ( p_blocks != NULL )
171 i_last_packet = i_wallclock;
172 else if ( !i_frontend_timeout
173 && i_wallclock > i_last_packet + DVR_READ_TIMEOUT )
175 msg_Warn( NULL, "no DVR output, resetting" );
176 FrontendSet(false);
177 en50221_Reset();
180 if ( i_ca_handle && i_ca_type == CA_CI_LINK )
182 if ( ufds[i_nb_fd - 1].revents )
184 en50221_Read();
185 i_ca_next_event = i_wallclock + CA_POLL_PERIOD;
187 else if ( i_wallclock > i_ca_next_event )
189 en50221_Poll();
190 i_ca_next_event = i_wallclock + CA_POLL_PERIOD;
194 if ( i_frontend_timeout && i_wallclock > i_frontend_timeout )
196 if ( i_quit_timeout_duration )
198 msg_Err( NULL, "no lock" );
199 switch (i_print_type) {
200 case PRINT_XML:
201 printf("</TS>\n");
202 break;
203 default:
204 break;
206 exit(EXIT_STATUS_FRONTEND_TIMEOUT);
208 msg_Warn( NULL, "no lock, tuning again" );
209 FrontendSet(false);
212 if ( i_comm_fd != -1 && ufds[2].revents )
213 comm_Read();
215 return p_blocks;
218 /*****************************************************************************
219 * DVRRead
220 *****************************************************************************/
221 static block_t *DVRRead( void )
223 int i, i_len;
224 block_t *p_ts = p_freelist, **pp_current = &p_ts;
225 struct iovec p_iov[MAX_READ_ONCE];
227 for ( i = 0; i < MAX_READ_ONCE; i++ )
229 if ( (*pp_current) == NULL ) *pp_current = block_New();
230 p_iov[i].iov_base = (*pp_current)->p_ts;
231 p_iov[i].iov_len = TS_SIZE;
232 pp_current = &(*pp_current)->p_next;
235 if ( (i_len = readv(i_dvr, p_iov, MAX_READ_ONCE)) < 0 )
237 msg_Err( NULL, "couldn't read from DVR device (%s)",
238 strerror(errno) );
239 i_len = 0;
241 i_len /= TS_SIZE;
243 pp_current = &p_ts;
244 while ( i_len && *pp_current )
246 pp_current = &(*pp_current)->p_next;
247 i_len--;
250 p_freelist = *pp_current;
251 *pp_current = NULL;
253 return p_ts;
258 * Demux
261 /*****************************************************************************
262 * dvb_SetFilter : controls the demux to add a filter
263 *****************************************************************************/
264 int dvb_SetFilter( uint16_t i_pid )
266 struct dmx_pes_filter_params s_filter_params;
267 char psz_tmp[128];
268 int i_fd;
270 sprintf( psz_tmp, "/dev/dvb/adapter%d/demux%d", i_adapter, i_fenum );
271 if( (i_fd = open(psz_tmp, O_RDWR)) < 0 )
273 msg_Err( NULL, "DMXSetFilter: opening device failed (%s)",
274 strerror(errno) );
275 return -1;
278 s_filter_params.pid = i_pid;
279 s_filter_params.input = DMX_IN_FRONTEND;
280 s_filter_params.output = DMX_OUT_TS_TAP;
281 s_filter_params.flags = DMX_IMMEDIATE_START;
282 s_filter_params.pes_type = DMX_PES_OTHER;
284 if ( ioctl( i_fd, DMX_SET_PES_FILTER, &s_filter_params ) < 0 )
286 msg_Err( NULL, "failed setting filter on %d (%s)", i_pid,
287 strerror(errno) );
288 close( i_fd );
289 return -1;
292 msg_Dbg( NULL, "setting filter on PID %d", i_pid );
294 return i_fd;
297 /*****************************************************************************
298 * dvb_UnsetFilter : removes a filter
299 *****************************************************************************/
300 void dvb_UnsetFilter( int i_fd, uint16_t i_pid )
302 if ( ioctl( i_fd, DMX_STOP ) < 0 )
303 msg_Err( NULL, "DMX_STOP failed (%s)", strerror(errno) );
304 else
305 msg_Dbg( NULL, "unsetting filter on PID %d", i_pid );
307 close( i_fd );
312 * Frontend
315 /*****************************************************************************
316 * FrontendPoll : Poll for frontend events
317 *****************************************************************************/
318 static void FrontendPoll( void )
320 struct dvb_frontend_event event;
321 fe_status_t i_status, i_diff;
323 for( ;; )
325 int i_ret = ioctl( i_frontend, FE_GET_EVENT, &event );
327 if( i_ret < 0 )
329 if( errno == EWOULDBLOCK )
330 return; /* no more events */
332 msg_Err( NULL, "reading frontend event failed (%d) %s",
333 i_ret, strerror(errno) );
334 return;
337 i_status = event.status;
338 i_diff = i_status ^ i_last_status;
339 i_last_status = i_status;
342 #define IF_UP( x ) \
344 if ( i_diff & (x) ) \
346 if ( i_status & (x) )
348 IF_UP( FE_HAS_SIGNAL )
349 msg_Dbg( NULL, "frontend has acquired signal" );
350 else
351 msg_Dbg( NULL, "frontend has lost signal" );
353 IF_UP( FE_HAS_CARRIER )
354 msg_Dbg( NULL, "frontend has acquired carrier" );
355 else
356 msg_Dbg( NULL, "frontend has lost carrier" );
358 IF_UP( FE_HAS_VITERBI )
359 msg_Dbg( NULL, "frontend has acquired stable FEC" );
360 else
361 msg_Dbg( NULL, "frontend has lost FEC" );
363 IF_UP( FE_HAS_SYNC )
364 msg_Dbg( NULL, "frontend has acquired sync" );
365 else
366 msg_Dbg( NULL, "frontend has lost sync" );
368 IF_UP( FE_HAS_LOCK )
370 int32_t i_value = 0;
371 msg_Info( NULL, "frontend has acquired lock" );
372 switch (i_print_type) {
373 case PRINT_XML:
374 printf("<STATUS type=\"lock\" status=\"1\" />\n");
375 break;
376 default:
377 printf("frontend has acquired lock\n" );
379 i_frontend_timeout = 0;
380 i_last_packet = i_wallclock;
382 if ( i_quit_timeout_duration && !i_quit_timeout )
383 i_quit_timeout = i_wallclock + i_quit_timeout_duration;
385 /* Read some statistics */
386 if( ioctl( i_frontend, FE_READ_BER, &i_value ) >= 0 )
387 msg_Dbg( NULL, "- Bit error rate: %d", i_value );
388 if( ioctl( i_frontend, FE_READ_SIGNAL_STRENGTH, &i_value ) >= 0 )
389 msg_Dbg( NULL, "- Signal strength: %d", i_value );
390 if( ioctl( i_frontend, FE_READ_SNR, &i_value ) >= 0 )
391 msg_Dbg( NULL, "- SNR: %d", i_value );
393 else
395 msg_Dbg( NULL, "frontend has lost lock" );
396 switch (i_print_type) {
397 case PRINT_XML:
398 printf("<STATUS type=\"lock\" status=\"0\"/>\n");
399 break;
400 default:
401 printf("frontend has lost lock\n" );
403 i_frontend_timeout = i_wallclock + i_frontend_timeout_duration;
406 IF_UP( FE_REINIT )
408 /* The frontend was reinited. */
409 msg_Warn( NULL, "reiniting frontend");
410 FrontendSet(true);
413 #undef IF_UP
417 static int FrontendDoDiseqc(void)
419 fe_sec_voltage_t fe_voltage;
420 fe_sec_tone_mode_t fe_tone;
421 int bis_frequency;
423 switch ( i_voltage )
425 case 0: fe_voltage = SEC_VOLTAGE_OFF; break;
426 default:
427 case 13: fe_voltage = SEC_VOLTAGE_13; break;
428 case 18: fe_voltage = SEC_VOLTAGE_18; break;
431 fe_tone = b_tone ? SEC_TONE_ON : SEC_TONE_OFF;
433 /* Automatic mode. */
434 if ( i_frequency >= 950000 && i_frequency <= 2150000 )
436 msg_Dbg( NULL, "frequency %d is in IF-band", i_frequency );
437 bis_frequency = i_frequency;
439 else if ( i_frequency >= 2500000 && i_frequency <= 2700000 )
441 msg_Dbg( NULL, "frequency %d is in S-band", i_frequency );
442 bis_frequency = 3650000 - i_frequency;
444 else if ( i_frequency >= 3400000 && i_frequency <= 4200000 )
446 msg_Dbg( NULL, "frequency %d is in C-band (lower)", i_frequency );
447 bis_frequency = 5150000 - i_frequency;
449 else if ( i_frequency >= 4500000 && i_frequency <= 4800000 )
451 msg_Dbg( NULL, "frequency %d is in C-band (higher)", i_frequency );
452 bis_frequency = 5950000 - i_frequency;
454 else if ( i_frequency >= 10700000 && i_frequency < 11700000 )
456 msg_Dbg( NULL, "frequency %d is in Ku-band (lower)",
457 i_frequency );
458 bis_frequency = i_frequency - 9750000;
460 else if ( i_frequency >= 11700000 && i_frequency <= 13250000 )
462 msg_Dbg( NULL, "frequency %d is in Ku-band (higher)",
463 i_frequency );
464 bis_frequency = i_frequency - 10600000;
465 fe_tone = SEC_TONE_ON;
467 else
469 msg_Err( NULL, "frequency %d is out of any known band",
470 i_frequency );
471 exit(1);
474 /* Switch off continuous tone. */
475 if ( ioctl( i_frontend, FE_SET_TONE, SEC_TONE_OFF ) < 0 )
477 msg_Err( NULL, "FE_SET_TONE failed (%s)", strerror(errno) );
478 exit(1);
481 /* Configure LNB voltage. */
482 if ( ioctl( i_frontend, FE_SET_VOLTAGE, fe_voltage ) < 0 )
484 msg_Err( NULL, "FE_SET_VOLTAGE failed (%s)", strerror(errno) );
485 exit(1);
488 /* Wait for at least 15 ms. Currently 100 ms because of broken drivers. */
489 msleep(100000);
491 /* Diseqc */
492 if ( i_satnum > 0 && i_satnum < 5 )
494 /* digital satellite equipment control,
495 * specification is available from http://www.eutelsat.com/
498 struct dvb_diseqc_master_cmd cmd =
499 { {0xe0, 0x10, 0x38, 0xf0, 0x00, 0x00}, 4};
500 cmd.msg[3] = 0xf0 /* reset bits */
501 | ((i_satnum - 1) << 2)
502 | (fe_voltage == SEC_VOLTAGE_13 ? 0 : 2)
503 | (fe_tone == SEC_TONE_ON ? 1 : 0);
505 if( ioctl( i_frontend, FE_DISEQC_SEND_MASTER_CMD, &cmd ) < 0 )
507 msg_Err( NULL, "ioctl FE_SEND_MASTER_CMD failed (%s)",
508 strerror(errno) );
509 exit(1);
511 msleep(100000); /* Should be 15 ms. */
513 /* Do it again just to be sure. */
514 if( ioctl( i_frontend, FE_DISEQC_SEND_MASTER_CMD, &cmd ) < 0 )
516 msg_Err( NULL, "ioctl FE_SEND_MASTER_CMD failed (%s)",
517 strerror(errno) );
518 exit(1);
520 msleep(100000); /* Again, should be 15 ms */
522 else if ( i_satnum == 0xA || i_satnum == 0xB )
524 /* A or B simple diseqc ("diseqc-compatible") */
525 if( ioctl( i_frontend, FE_DISEQC_SEND_BURST,
526 i_satnum == 0xB ? SEC_MINI_B : SEC_MINI_A ) < 0 )
528 msg_Err( NULL, "ioctl FE_SEND_BURST failed (%s)", strerror(errno) );
529 exit(1);
531 msleep(100000); /* ... */
534 if ( ioctl( i_frontend, FE_SET_TONE, fe_tone ) < 0 )
536 msg_Err( NULL, "FE_SET_TONE failed (%s)", strerror(errno) );
537 exit(1);
540 msleep(100000); /* ... */
542 msg_Dbg( NULL, "configuring LNB to v=%d p=%d satnum=%x",
543 i_voltage, b_tone, i_satnum );
544 return bis_frequency;
547 #define DVBAPI_VERSION ((DVB_API_VERSION)*100+(DVB_API_VERSION_MINOR))
549 #if DVB_API_VERSION >= 5
551 /*****************************************************************************
552 * Helper functions for S2API
553 *****************************************************************************/
554 static fe_spectral_inversion_t GetInversion(void)
556 switch ( i_inversion )
558 case 0: return INVERSION_OFF;
559 case 1: return INVERSION_ON;
560 default:
561 msg_Warn( NULL, "invalid inversion %d", i_inversion );
562 case -1: return INVERSION_AUTO;
566 static fe_code_rate_t GetFEC(fe_caps_t fe_caps, int i_fec_value)
568 #define GET_FEC_INNER(fec, val) \
569 if ( (fe_caps & FE_CAN_##fec) && (i_fec_value == val) ) \
570 return fec;
572 GET_FEC_INNER(FEC_AUTO, 999);
573 GET_FEC_INNER(FEC_AUTO, -1);
574 if (i_fec_value == 0)
575 return FEC_NONE;
576 GET_FEC_INNER(FEC_1_2, 12);
577 GET_FEC_INNER(FEC_2_3, 23);
578 GET_FEC_INNER(FEC_3_4, 34);
579 if (i_fec_value == 35)
580 return FEC_3_5;
581 GET_FEC_INNER(FEC_4_5, 45);
582 GET_FEC_INNER(FEC_5_6, 56);
583 GET_FEC_INNER(FEC_6_7, 67);
584 GET_FEC_INNER(FEC_7_8, 78);
585 GET_FEC_INNER(FEC_8_9, 89);
586 if (i_fec_value == 910)
587 return FEC_9_10;
589 #undef GET_FEC_INNER
590 msg_Warn(NULL, "invalid FEC %d", i_fec_value );
591 return FEC_AUTO;
594 #define GetFECInner(caps) GetFEC(caps, i_fec)
595 #define GetFECLP(caps) GetFEC(caps, i_fec_lp)
597 static fe_modulation_t GetModulation(void)
599 #define GET_MODULATION( mod ) \
600 if ( !strcasecmp( psz_modulation, #mod ) ) \
601 return mod;
603 GET_MODULATION(QPSK);
604 GET_MODULATION(QAM_16);
605 GET_MODULATION(QAM_32);
606 GET_MODULATION(QAM_64);
607 GET_MODULATION(QAM_128);
608 GET_MODULATION(QAM_256);
609 GET_MODULATION(QAM_AUTO);
610 GET_MODULATION(VSB_8);
611 GET_MODULATION(VSB_16);
612 GET_MODULATION(PSK_8);
613 GET_MODULATION(APSK_16);
614 GET_MODULATION(APSK_32);
615 GET_MODULATION(DQPSK);
617 #undef GET_MODULATION
618 msg_Err( NULL, "invalid modulation %s", psz_modulation );
619 exit(1);
622 static fe_pilot_t GetPilot(void)
624 switch ( i_pilot )
626 case 0: return PILOT_OFF;
627 case 1: return PILOT_ON;
628 default:
629 msg_Warn( NULL, "invalid pilot %d", i_pilot );
630 case -1: return PILOT_AUTO;
634 static fe_rolloff_t GetRollOff(void)
636 switch ( i_rolloff )
638 case -1:
639 case 0: return ROLLOFF_AUTO;
640 case 20: return ROLLOFF_20;
641 case 25: return ROLLOFF_25;
642 default:
643 msg_Warn( NULL, "invalid rolloff %d", i_rolloff );
644 case 35: return ROLLOFF_35;
648 static fe_guard_interval_t GetGuard(void)
650 switch ( i_guard )
652 case 32: return GUARD_INTERVAL_1_32;
653 case 16: return GUARD_INTERVAL_1_16;
654 case 8: return GUARD_INTERVAL_1_8;
655 case 4: return GUARD_INTERVAL_1_4;
656 default:
657 msg_Warn( NULL, "invalid guard interval %d", i_guard );
658 case -1:
659 case 0: return GUARD_INTERVAL_AUTO;
663 static fe_transmit_mode_t GetTransmission(void)
665 switch ( i_transmission )
667 case 2: return TRANSMISSION_MODE_2K;
668 case 8: return TRANSMISSION_MODE_8K;
669 #ifdef TRANSMISSION_MODE_4K
670 case 4: return TRANSMISSION_MODE_4K;
671 #endif
672 default:
673 msg_Warn( NULL, "invalid tranmission mode %d", i_transmission );
674 case -1:
675 case 0: return TRANSMISSION_MODE_AUTO;
679 static fe_hierarchy_t GetHierarchy(void)
681 switch ( i_hierarchy )
683 case 0: return HIERARCHY_NONE;
684 case 1: return HIERARCHY_1;
685 case 2: return HIERARCHY_2;
686 case 4: return HIERARCHY_4;
687 default:
688 msg_Warn( NULL, "invalid intramission mode %d", i_transmission );
689 case -1: return HIERARCHY_AUTO;
693 /*****************************************************************************
694 * FrontendInfo : Print frontend info
695 *****************************************************************************/
696 static const char *GetFrontendTypeName( fe_type_t type )
698 switch(type)
700 case FE_QPSK: return "QPSK (DVB-S/S2)";
701 case FE_QAM: return "QAM (DVB-C)";
702 case FE_OFDM: return "OFDM (DVB-T)";
703 case FE_ATSC: return "ATSC";
704 default: return "unknown";
708 static void FrontendInfo( struct dvb_frontend_info info )
710 msg_Dbg( NULL, "Frontend \"%s\" type \"%s\" supports:",
711 info.name, GetFrontendTypeName(info.type) );
712 msg_Dbg( NULL, " frequency min: %d, max: %d, stepsize: %d, tolerance: %d",
713 info.frequency_min, info.frequency_max,
714 info.frequency_stepsize, info.frequency_tolerance );
715 msg_Dbg( NULL, " symbolrate min: %d, max: %d, tolerance: %d",
716 info.symbol_rate_min, info.symbol_rate_max, info.symbol_rate_tolerance);
717 msg_Dbg( NULL, " capabilities:" );
719 #define FRONTEND_INFO(caps,val,msg) \
720 if ( caps & val ) \
721 msg_Dbg( NULL, " %s", msg );
723 FRONTEND_INFO( info.caps, FE_IS_STUPID, "FE_IS_STUPID" )
724 FRONTEND_INFO( info.caps, FE_CAN_INVERSION_AUTO, "INVERSION_AUTO" )
725 FRONTEND_INFO( info.caps, FE_CAN_FEC_1_2, "FEC_1_2" )
726 FRONTEND_INFO( info.caps, FE_CAN_FEC_2_3, "FEC_2_3" )
727 FRONTEND_INFO( info.caps, FE_CAN_FEC_3_4, "FEC_3_4" )
728 FRONTEND_INFO( info.caps, FE_CAN_FEC_4_5, "FEC_4_5" )
729 FRONTEND_INFO( info.caps, FE_CAN_FEC_5_6, "FEC_5_6" )
730 FRONTEND_INFO( info.caps, FE_CAN_FEC_6_7, "FEC_6_7" )
731 FRONTEND_INFO( info.caps, FE_CAN_FEC_7_8, "FEC_7_8" )
732 FRONTEND_INFO( info.caps, FE_CAN_FEC_8_9, "FEC_8_9" )
733 FRONTEND_INFO( info.caps, FE_CAN_FEC_AUTO,"FEC_AUTO")
734 FRONTEND_INFO( info.caps, FE_CAN_QPSK, "QPSK" )
735 FRONTEND_INFO( info.caps, FE_CAN_QAM_16, "QAM_16" )
736 FRONTEND_INFO( info.caps, FE_CAN_QAM_32, "QAM_32" )
737 FRONTEND_INFO( info.caps, FE_CAN_QAM_64, "QAM_64" )
738 FRONTEND_INFO( info.caps, FE_CAN_QAM_128,"QAM_128")
739 FRONTEND_INFO( info.caps, FE_CAN_QAM_256,"QAM_256")
740 FRONTEND_INFO( info.caps, FE_CAN_QAM_AUTO,"QAM_AUTO" )
741 FRONTEND_INFO( info.caps, FE_CAN_TRANSMISSION_MODE_AUTO, "TRANSMISSION_MODE_AUTO" )
742 FRONTEND_INFO( info.caps, FE_CAN_BANDWIDTH_AUTO, "BANDWIDTH_AUTO" )
743 FRONTEND_INFO( info.caps, FE_CAN_GUARD_INTERVAL_AUTO, "GUARD_INTERVAL_AUTO" )
744 FRONTEND_INFO( info.caps, FE_CAN_HIERARCHY_AUTO, "HIERARCHY_AUTO" )
745 FRONTEND_INFO( info.caps, FE_CAN_8VSB, "8VSB" )
746 FRONTEND_INFO( info.caps, FE_CAN_16VSB,"16VSB" )
747 FRONTEND_INFO( info.caps, FE_HAS_EXTENDED_CAPS, "EXTENDED_CAPS" )
748 #if DVBAPI_VERSION >= 501
749 FRONTEND_INFO( info.caps, FE_CAN_2G_MODULATION, "2G_MODULATION" )
750 #endif
751 FRONTEND_INFO( info.caps, FE_NEEDS_BENDING, "NEEDS_BENDING" )
752 FRONTEND_INFO( info.caps, FE_CAN_RECOVER, "FE_CAN_RECOVER" )
753 FRONTEND_INFO( info.caps, FE_CAN_MUTE_TS, "FE_CAN_MUTE_TS" )
754 #undef FRONTEND_INFO
757 /*****************************************************************************
758 * FrontendSet
759 *****************************************************************************/
760 /* S2API */
761 static struct dtv_property dvbs_cmdargs[] = {
762 { .cmd = DTV_FREQUENCY, .u.data = 0 },
763 { .cmd = DTV_MODULATION, .u.data = QPSK },
764 { .cmd = DTV_INVERSION, .u.data = INVERSION_AUTO },
765 { .cmd = DTV_SYMBOL_RATE, .u.data = 27500000 },
766 { .cmd = DTV_INNER_FEC, .u.data = FEC_AUTO },
767 { .cmd = DTV_DELIVERY_SYSTEM, .u.data = SYS_DVBS },
768 { .cmd = DTV_TUNE },
770 static struct dtv_properties dvbs_cmdseq = {
771 .num = sizeof(dvbs_cmdargs)/sizeof(struct dtv_property),
772 .props = dvbs_cmdargs
775 static struct dtv_property dvbs2_cmdargs[] = {
776 { .cmd = DTV_FREQUENCY, .u.data = 0 },
777 { .cmd = DTV_MODULATION, .u.data = PSK_8 },
778 { .cmd = DTV_INVERSION, .u.data = INVERSION_AUTO },
779 { .cmd = DTV_SYMBOL_RATE, .u.data = 27500000 },
780 { .cmd = DTV_INNER_FEC, .u.data = FEC_AUTO },
781 { .cmd = DTV_DELIVERY_SYSTEM, .u.data = SYS_DVBS2 },
782 { .cmd = DTV_PILOT, .u.data = PILOT_AUTO },
783 { .cmd = DTV_ROLLOFF, .u.data = ROLLOFF_AUTO },
784 { .cmd = DTV_TUNE },
786 static struct dtv_properties dvbs2_cmdseq = {
787 .num = sizeof(dvbs2_cmdargs)/sizeof(struct dtv_property),
788 .props = dvbs2_cmdargs
791 static struct dtv_property dvbc_cmdargs[] = {
792 { .cmd = DTV_FREQUENCY, .u.data = 0 },
793 { .cmd = DTV_MODULATION, .u.data = QAM_AUTO },
794 { .cmd = DTV_INVERSION, .u.data = INVERSION_AUTO },
795 { .cmd = DTV_SYMBOL_RATE, .u.data = 27500000 },
796 { .cmd = DTV_DELIVERY_SYSTEM, .u.data = SYS_DVBC_ANNEX_AC },
797 { .cmd = DTV_TUNE },
799 static struct dtv_properties dvbc_cmdseq = {
800 .num = sizeof(dvbc_cmdargs)/sizeof(struct dtv_property),
801 .props = dvbc_cmdargs
804 static struct dtv_property dvbt_cmdargs[] = {
805 { .cmd = DTV_FREQUENCY, .u.data = 0 },
806 { .cmd = DTV_MODULATION, .u.data = QAM_AUTO },
807 { .cmd = DTV_INVERSION, .u.data = INVERSION_AUTO },
808 { .cmd = DTV_BANDWIDTH_HZ, .u.data = 8000000 },
809 { .cmd = DTV_CODE_RATE_HP, .u.data = FEC_AUTO },
810 { .cmd = DTV_CODE_RATE_LP, .u.data = FEC_AUTO },
811 { .cmd = DTV_GUARD_INTERVAL, .u.data = GUARD_INTERVAL_AUTO },
812 { .cmd = DTV_TRANSMISSION_MODE,.u.data = TRANSMISSION_MODE_AUTO },
813 { .cmd = DTV_HIERARCHY, .u.data = HIERARCHY_AUTO },
814 { .cmd = DTV_DELIVERY_SYSTEM, .u.data = SYS_DVBT },
815 { .cmd = DTV_TUNE },
817 static struct dtv_properties dvbt_cmdseq = {
818 .num = sizeof(dvbt_cmdargs)/sizeof(struct dtv_property),
819 .props = dvbt_cmdargs
822 static struct dtv_property atsc_cmdargs[] = {
823 { .cmd = DTV_FREQUENCY, .u.data = 0 },
824 { .cmd = DTV_MODULATION, .u.data = QAM_AUTO },
825 { .cmd = DTV_INVERSION, .u.data = INVERSION_AUTO },
826 { .cmd = DTV_DELIVERY_SYSTEM, .u.data = SYS_ATSC },
827 { .cmd = DTV_TUNE },
829 static struct dtv_properties atsc_cmdseq = {
830 .num = sizeof(atsc_cmdargs)/sizeof(struct dtv_property),
831 .props = atsc_cmdargs
834 #define FREQUENCY 0
835 #define MODULATION 1
836 #define INVERSION 2
837 #define SYMBOL_RATE 3
838 #define BANDWIDTH 3
839 #define FEC_INNER 4
840 #define FEC_LP 5
841 #define GUARD 6
842 #define PILOT 6
843 #define TRANSMISSION 7
844 #define ROLLOFF 7
845 #define HIERARCHY 8
847 struct dtv_property pclear[] = {
848 { .cmd = DTV_CLEAR },
851 struct dtv_properties cmdclear = {
852 .num = 1,
853 .props = pclear
856 static void FrontendSet( bool b_init )
858 struct dvb_frontend_info info;
859 struct dtv_properties *p;
861 if ( ioctl( i_frontend, FE_GET_INFO, &info ) < 0 )
863 msg_Err( NULL, "FE_GET_INFO failed (%s)", strerror(errno) );
864 exit(1);
867 if ( b_init )
868 FrontendInfo( info );
870 /* Clear frontend commands */
871 if ( ioctl( i_frontend, FE_SET_PROPERTY, &cmdclear ) < 0 )
873 msg_Err( NULL, "Unable to clear frontend" );
874 exit(1);
877 switch ( info.type )
879 case FE_OFDM:
880 p = &dvbt_cmdseq;
881 p->props[FREQUENCY].u.data = i_frequency;
882 p->props[INVERSION].u.data = GetInversion();
883 if ( psz_modulation != NULL )
884 p->props[MODULATION].u.data = GetModulation();
885 p->props[BANDWIDTH].u.data = i_bandwidth * 1000000;
886 p->props[FEC_INNER].u.data = GetFECInner(info.caps);
887 p->props[FEC_LP].u.data = GetFECLP(info.caps);
888 p->props[GUARD].u.data = GetGuard();
889 p->props[TRANSMISSION].u.data = GetTransmission();
890 p->props[HIERARCHY].u.data = GetHierarchy();
892 msg_Dbg( NULL, "tuning OFDM frontend to f=%d bandwidth=%d inversion=%d fec_hp=%d fec_lp=%d hierarchy=%d modulation=%s guard=%d transmission=%d",
893 i_frequency, i_bandwidth, i_inversion, i_fec, i_fec_lp,
894 i_hierarchy,
895 psz_modulation == NULL ? "qam_auto" : psz_modulation,
896 i_guard, i_transmission );
897 break;
899 case FE_QAM:
900 p = &dvbc_cmdseq;
901 p->props[FREQUENCY].u.data = i_frequency;
902 p->props[INVERSION].u.data = GetInversion();
903 if ( psz_modulation != NULL )
904 p->props[MODULATION].u.data = GetModulation();
905 p->props[SYMBOL_RATE].u.data = i_srate;
907 msg_Dbg( NULL, "tuning QAM frontend to f=%d srate=%d inversion=%d modulation=%s",
908 i_frequency, i_srate, i_inversion,
909 psz_modulation == NULL ? "qam_auto" : psz_modulation );
910 break;
912 case FE_QPSK:
913 if ( psz_modulation != NULL )
915 p = &dvbs2_cmdseq;
916 p->props[MODULATION].u.data = GetModulation();
917 p->props[PILOT].u.data = GetPilot();
918 p->props[ROLLOFF].u.data = GetRollOff();
920 else
921 p = &dvbs_cmdseq;
923 p->props[INVERSION].u.data = GetInversion();
924 p->props[SYMBOL_RATE].u.data = i_srate;
925 p->props[FEC_INNER].u.data = GetFECInner(info.caps);
926 p->props[FREQUENCY].u.data = FrontendDoDiseqc();
928 msg_Dbg( NULL, "tuning QPSK frontend to f=%d srate=%d inversion=%d fec=%d rolloff=%d modulation=%s pilot=%d",
929 i_frequency, i_srate, i_inversion, i_fec, i_rolloff,
930 psz_modulation == NULL ? "legacy" : psz_modulation, i_pilot );
931 break;
933 case FE_ATSC:
934 p = &atsc_cmdseq;
935 p->props[FREQUENCY].u.data = i_frequency;
936 p->props[INVERSION].u.data = GetInversion();
937 if ( psz_modulation != NULL )
938 p->props[MODULATION].u.data = GetModulation();
940 msg_Dbg( NULL, "tuning ATSC frontend to f=%d inversion=%d modulation=%s",
941 i_frequency, i_inversion,
942 psz_modulation == NULL ? "qam_auto" : psz_modulation );
943 break;
945 default:
946 msg_Err( NULL, "unknown frontend type %d", info.type );
947 exit(1);
950 /* Empty the event queue */
951 for ( ; ; )
953 struct dvb_frontend_event event;
954 if ( ioctl( i_frontend, FE_GET_EVENT, &event ) < 0
955 && errno == EWOULDBLOCK )
956 break;
959 /* Now send it all to the frontend device */
960 if ( ioctl( i_frontend, FE_SET_PROPERTY, p ) < 0 )
962 msg_Err( NULL, "setting frontend failed (%s)", strerror(errno) );
963 exit(1);
966 i_last_status = 0;
967 i_frontend_timeout = i_wallclock + i_frontend_timeout_duration;
970 #else /* !S2API */
972 #warning "You are trying to compile DVBlast with an outdated linux-dvb interface."
973 #warning "DVBlast will be very limited and some options will have no effect."
975 static void FrontendSet( bool b_init )
977 struct dvb_frontend_info info;
978 struct dvb_frontend_parameters fep;
980 if ( ioctl( i_frontend, FE_GET_INFO, &info ) < 0 )
982 msg_Err( NULL, "FE_GET_INFO failed (%s)", strerror(errno) );
983 exit(1);
986 switch ( info.type )
988 case FE_OFDM:
989 fep.frequency = i_frequency;
990 fep.inversion = INVERSION_AUTO;
992 switch ( i_bandwidth )
994 case 6: fep.u.ofdm.bandwidth = BANDWIDTH_6_MHZ; break;
995 case 7: fep.u.ofdm.bandwidth = BANDWIDTH_7_MHZ; break;
996 default:
997 case 8: fep.u.ofdm.bandwidth = BANDWIDTH_8_MHZ; break;
1000 fep.u.ofdm.code_rate_HP = FEC_AUTO;
1001 fep.u.ofdm.code_rate_LP = FEC_AUTO;
1002 fep.u.ofdm.constellation = QAM_AUTO;
1003 fep.u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO;
1004 fep.u.ofdm.guard_interval = GUARD_INTERVAL_AUTO;
1005 fep.u.ofdm.hierarchy_information = HIERARCHY_AUTO;
1007 msg_Dbg( NULL, "tuning OFDM frontend to f=%d, bandwidth=%d",
1008 i_frequency, i_bandwidth );
1009 break;
1011 case FE_QAM:
1012 fep.frequency = i_frequency;
1013 fep.inversion = INVERSION_AUTO;
1014 fep.u.qam.symbol_rate = i_srate;
1015 fep.u.qam.fec_inner = FEC_AUTO;
1016 fep.u.qam.modulation = QAM_AUTO;
1018 msg_Dbg( NULL, "tuning QAM frontend to f=%d, srate=%d",
1019 i_frequency, i_srate );
1020 break;
1022 case FE_QPSK:
1023 fep.inversion = INVERSION_AUTO;
1024 fep.u.qpsk.symbol_rate = i_srate;
1025 fep.u.qpsk.fec_inner = FEC_AUTO;
1026 fep.frequency = FrontendDoDiseqc();
1028 msg_Dbg( NULL, "tuning QPSK frontend to f=%d, srate=%d",
1029 i_frequency, i_srate );
1030 break;
1032 #if DVBAPI_VERSION >= 301
1033 case FE_ATSC:
1034 fep.frequency = i_frequency;
1036 fep.u.vsb.modulation = QAM_AUTO;
1038 msg_Dbg( NULL, "tuning ATSC frontend to f=%d", i_frequency );
1039 break;
1040 #endif
1042 default:
1043 msg_Err( NULL, "unknown frontend type %d", info.type );
1044 exit(1);
1047 /* Empty the event queue */
1048 for ( ; ; )
1050 struct dvb_frontend_event event;
1051 if ( ioctl( i_frontend, FE_GET_EVENT, &event ) < 0
1052 && errno == EWOULDBLOCK )
1053 break;
1056 /* Now send it all to the frontend device */
1057 if ( ioctl( i_frontend, FE_SET_FRONTEND, &fep ) < 0 )
1059 msg_Err( NULL, "setting frontend failed (%s)", strerror(errno) );
1060 exit(1);
1063 i_last_status = 0;
1064 i_frontend_timeout = i_wallclock + i_frontend_timeout_duration;
1067 #endif /* S2API */
1069 /*****************************************************************************
1070 * dvb_FrontendStatus
1071 *****************************************************************************/
1072 uint8_t dvb_FrontendStatus( uint8_t *p_answer, ssize_t *pi_size )
1074 struct ret_frontend_status *p_ret = (struct ret_frontend_status *)p_answer;
1076 if ( ioctl( i_frontend, FE_GET_INFO, &p_ret->info ) < 0 )
1078 msg_Err( NULL, "ioctl FE_GET_INFO failed (%s)", strerror(errno) );
1079 return RET_ERR;
1082 if ( ioctl( i_frontend, FE_READ_STATUS, &p_ret->i_status ) < 0 )
1084 msg_Err( NULL, "ioctl FE_READ_STATUS failed (%s)", strerror(errno) );
1085 return RET_ERR;
1088 if ( p_ret->i_status & FE_HAS_LOCK )
1090 if ( ioctl( i_frontend, FE_READ_BER, &p_ret->i_ber ) < 0 )
1091 msg_Err( NULL, "ioctl FE_READ_BER failed (%s)", strerror(errno) );
1093 if ( ioctl( i_frontend, FE_READ_SIGNAL_STRENGTH, &p_ret->i_strength )
1094 < 0 )
1095 msg_Err( NULL, "ioctl FE_READ_SIGNAL_STRENGTH failed (%s)",
1096 strerror(errno) );
1098 if ( ioctl( i_frontend, FE_READ_SNR, &p_ret->i_snr ) < 0 )
1099 msg_Err( NULL, "ioctl FE_READ_SNR failed (%s)", strerror(errno) );
1102 *pi_size = sizeof(struct ret_frontend_status);
1103 return RET_FRONTEND_STATUS;