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 *****************************************************************************/
29 #include <sys/types.h>
33 #include <sys/ioctl.h>
34 #include <sys/socket.h>
36 #include <netinet/in.h>
37 #include <arpa/inet.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>
51 #include <bitstream/common.h>
53 /*****************************************************************************
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 /*****************************************************************************
70 *****************************************************************************/
71 static block_t
*DVRRead( void );
72 static void FrontendPoll( void );
73 static void FrontendSet( bool b_reset
);
75 /*****************************************************************************
77 *****************************************************************************/
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
,
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
,
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
,
112 i_ca_next_event
= mdate() + CA_POLL_PERIOD
;
115 /*****************************************************************************
117 *****************************************************************************/
118 void dvb_Reset( void )
123 /*****************************************************************************
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
) );
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
;
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
;
150 i_ret
= poll( ufds
, i_nb_fd
, (i_poll_timeout
+ 999) / 1000 );
152 i_wallclock
= mdate();
157 msg_Err( NULL
, "poll error: %s", strerror(errno
) );
161 if ( ufds
[1].revents
)
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" );
180 if ( i_ca_handle
&& i_ca_type
== CA_CI_LINK
)
182 if ( ufds
[i_nb_fd
- 1].revents
)
185 i_ca_next_event
= i_wallclock
+ CA_POLL_PERIOD
;
187 else if ( i_wallclock
> i_ca_next_event
)
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
) {
206 exit(EXIT_STATUS_FRONTEND_TIMEOUT
);
208 msg_Warn( NULL
, "no lock, tuning again" );
212 if ( i_comm_fd
!= -1 && ufds
[2].revents
)
218 /*****************************************************************************
220 *****************************************************************************/
221 static block_t
*DVRRead( void )
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)",
244 while ( i_len
&& *pp_current
)
246 pp_current
= &(*pp_current
)->p_next
;
250 p_freelist
= *pp_current
;
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
;
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)",
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
,
292 msg_Dbg( NULL
, "setting filter on PID %d", i_pid
);
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
) );
305 msg_Dbg( NULL
, "unsetting filter on PID %d", i_pid
);
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
;
325 int i_ret
= ioctl( i_frontend
, FE_GET_EVENT
, &event
);
329 if( errno
== EWOULDBLOCK
)
330 return; /* no more events */
332 msg_Err( NULL
, "reading frontend event failed (%d) %s",
333 i_ret
, strerror(errno
) );
337 i_status
= event
.status
;
338 i_diff
= i_status
^ i_last_status
;
339 i_last_status
= i_status
;
344 if ( i_diff & (x) ) \
346 if ( i_status & (x) )
348 IF_UP( FE_HAS_SIGNAL
)
349 msg_Dbg( NULL
, "frontend has acquired signal" );
351 msg_Dbg( NULL
, "frontend has lost signal" );
353 IF_UP( FE_HAS_CARRIER
)
354 msg_Dbg( NULL
, "frontend has acquired carrier" );
356 msg_Dbg( NULL
, "frontend has lost carrier" );
358 IF_UP( FE_HAS_VITERBI
)
359 msg_Dbg( NULL
, "frontend has acquired stable FEC" );
361 msg_Dbg( NULL
, "frontend has lost FEC" );
364 msg_Dbg( NULL
, "frontend has acquired sync" );
366 msg_Dbg( NULL
, "frontend has lost sync" );
371 msg_Info( NULL
, "frontend has acquired lock" );
372 switch (i_print_type
) {
374 printf("<STATUS type=\"lock\" status=\"1\" />\n");
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
);
395 msg_Dbg( NULL
, "frontend has lost lock" );
396 switch (i_print_type
) {
398 printf("<STATUS type=\"lock\" status=\"0\"/>\n");
401 printf("frontend has lost lock\n" );
403 i_frontend_timeout
= i_wallclock
+ i_frontend_timeout_duration
;
408 /* The frontend was reinited. */
409 msg_Warn( NULL
, "reiniting frontend");
417 static int FrontendDoDiseqc(void)
419 fe_sec_voltage_t fe_voltage
;
420 fe_sec_tone_mode_t fe_tone
;
425 case 0: fe_voltage
= SEC_VOLTAGE_OFF
; break;
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)",
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)",
464 bis_frequency
= i_frequency
- 10600000;
465 fe_tone
= SEC_TONE_ON
;
469 msg_Err( NULL
, "frequency %d is out of any known band",
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
) );
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
) );
488 /* Wait for at least 15 ms. Currently 100 ms because of broken drivers. */
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)",
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)",
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
) );
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
) );
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
;
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) ) \
572 GET_FEC_INNER(FEC_AUTO
, 999);
573 GET_FEC_INNER(FEC_AUTO
, -1);
574 if (i_fec_value
== 0)
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)
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)
590 msg_Warn(NULL
, "invalid FEC %d", i_fec_value
);
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 ) ) \
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
);
622 static fe_pilot_t
GetPilot(void)
626 case 0: return PILOT_OFF
;
627 case 1: return PILOT_ON
;
629 msg_Warn( NULL
, "invalid pilot %d", i_pilot
);
630 case -1: return PILOT_AUTO
;
634 static fe_rolloff_t
GetRollOff(void)
639 case 0: return ROLLOFF_AUTO
;
640 case 20: return ROLLOFF_20
;
641 case 25: return ROLLOFF_25
;
643 msg_Warn( NULL
, "invalid rolloff %d", i_rolloff
);
644 case 35: return ROLLOFF_35
;
648 static fe_guard_interval_t
GetGuard(void)
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
;
657 msg_Warn( NULL
, "invalid guard interval %d", i_guard
);
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
;
673 msg_Warn( NULL
, "invalid tranmission mode %d", i_transmission
);
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
;
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
)
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) \
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" )
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" )
757 /*****************************************************************************
759 *****************************************************************************/
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
},
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
},
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
},
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
},
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
},
829 static struct dtv_properties atsc_cmdseq
= {
830 .num
= sizeof(atsc_cmdargs
)/sizeof(struct dtv_property
),
831 .props
= atsc_cmdargs
837 #define SYMBOL_RATE 3
843 #define TRANSMISSION 7
847 struct dtv_property pclear
[] = {
848 { .cmd
= DTV_CLEAR
},
851 struct dtv_properties cmdclear
= {
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
) );
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" );
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
,
895 psz_modulation
== NULL
? "qam_auto" : psz_modulation
,
896 i_guard
, i_transmission
);
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
);
913 if ( psz_modulation
!= NULL
)
916 p
->props
[MODULATION
].u
.data
= GetModulation();
917 p
->props
[PILOT
].u
.data
= GetPilot();
918 p
->props
[ROLLOFF
].u
.data
= GetRollOff();
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
);
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
);
946 msg_Err( NULL
, "unknown frontend type %d", info
.type
);
950 /* Empty the event queue */
953 struct dvb_frontend_event event
;
954 if ( ioctl( i_frontend
, FE_GET_EVENT
, &event
) < 0
955 && errno
== EWOULDBLOCK
)
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
) );
967 i_frontend_timeout
= i_wallclock
+ i_frontend_timeout_duration
;
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
) );
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;
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
);
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
);
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
);
1032 #if DVBAPI_VERSION >= 301
1034 fep
.frequency
= i_frequency
;
1036 fep
.u
.vsb
.modulation
= QAM_AUTO
;
1038 msg_Dbg( NULL
, "tuning ATSC frontend to f=%d", i_frequency
);
1043 msg_Err( NULL
, "unknown frontend type %d", info
.type
);
1047 /* Empty the event queue */
1050 struct dvb_frontend_event event
;
1051 if ( ioctl( i_frontend
, FE_GET_EVENT
, &event
) < 0
1052 && errno
== EWOULDBLOCK
)
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
) );
1064 i_frontend_timeout
= i_wallclock
+ i_frontend_timeout_duration
;
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
) );
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
) );
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
)
1095 msg_Err( NULL
, "ioctl FE_READ_SIGNAL_STRENGTH failed (%s)",
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
;