* dvbiscovery.sh: NIT can take longer than 15s. * dvbiscovery_dvb-s.conf: Change...
[dvblast.git] / dvb.c
blob579338107d67eea137172be5e1c3da52b106d29c
1 /*****************************************************************************
2 * dvb.c: linux-dvb input for DVBlast
3 *****************************************************************************
4 * Copyright (C) 2008-2010 VideoLAN
5 * $Id$
7 * Authors: Christophe Massiot <massiot@via.ecp.fr>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 #include <stdlib.h>
25 #include <stdint.h>
26 #include <stdbool.h>
27 #include <stdio.h>
28 #include <unistd.h>
29 #include <string.h>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <fcntl.h>
33 #include <unistd.h>
34 #include <sys/ioctl.h>
35 #include <sys/socket.h>
36 #include <sys/uio.h>
37 #include <netinet/in.h>
38 #include <arpa/inet.h>
39 #include <poll.h>
40 #include <errno.h>
42 /* DVB Card Drivers */
43 #include <linux/dvb/version.h>
44 #include <linux/dvb/dmx.h>
45 #include <linux/dvb/frontend.h>
46 #include <linux/dvb/ca.h>
48 #include "dvblast.h"
49 #include "en50221.h"
50 #include "comm.h"
52 #include <bitstream/common.h>
54 /*****************************************************************************
55 * Local declarations
56 *****************************************************************************/
57 #define DVR_READ_TIMEOUT 30000000 /* 30 s */
58 #define CA_POLL_PERIOD 100000 /* 100 ms */
59 #define MAX_READ_ONCE 50
60 #define DVR_BUFFER_SIZE 40*188*1024 /* bytes */
62 static int i_frontend, i_dvr;
63 static fe_status_t i_last_status;
64 static mtime_t i_frontend_timeout;
65 static mtime_t i_last_packet = 0;
66 static mtime_t i_ca_next_event = 0;
67 static block_t *p_freelist = NULL;
69 /*****************************************************************************
70 * Local prototypes
71 *****************************************************************************/
72 static block_t *DVRRead( void );
73 static void FrontendPoll( void );
74 static void FrontendSet( bool b_reset );
76 /*****************************************************************************
77 * dvb_Open
78 *****************************************************************************/
79 void dvb_Open( void )
81 char psz_tmp[128];
83 msg_Dbg( NULL, "using linux-dvb API version %d", DVB_API_VERSION );
85 i_wallclock = mdate();
87 sprintf( psz_tmp, "/dev/dvb/adapter%d/frontend%d", i_adapter, i_fenum );
88 if( (i_frontend = open(psz_tmp, O_RDWR | O_NONBLOCK)) < 0 )
90 msg_Err( NULL, "opening device %s failed (%s)", psz_tmp,
91 strerror(errno) );
92 exit(1);
95 FrontendSet(true);
97 sprintf( psz_tmp, "/dev/dvb/adapter%d/dvr%d", i_adapter, i_fenum );
99 if( (i_dvr = open(psz_tmp, O_RDONLY | O_NONBLOCK)) < 0 )
101 msg_Err( NULL, "opening device %s failed (%s)", psz_tmp,
102 strerror(errno) );
103 exit(1);
106 if ( ioctl( i_dvr, DMX_SET_BUFFER_SIZE, DVR_BUFFER_SIZE ) < 0 )
108 msg_Warn( NULL, "couldn't set %s buffer size (%s)", psz_tmp,
109 strerror(errno) );
112 en50221_Init();
113 i_ca_next_event = mdate() + CA_POLL_PERIOD;
116 /*****************************************************************************
117 * dvb_Reset
118 *****************************************************************************/
119 void dvb_Reset( void )
121 FrontendSet(true);
124 /*****************************************************************************
125 * dvb_Read
126 *****************************************************************************/
127 block_t *dvb_Read( mtime_t i_poll_timeout )
129 struct pollfd ufds[4];
130 int i_ret, i_nb_fd = 2;
131 block_t *p_blocks = NULL;
133 memset( ufds, 0, sizeof(ufds) );
134 ufds[0].fd = i_dvr;
135 ufds[0].events = POLLIN;
136 ufds[1].fd = i_frontend;
137 ufds[1].events = POLLERR | POLLPRI;
138 if ( i_comm_fd != -1 )
140 ufds[i_nb_fd].fd = i_comm_fd;
141 ufds[i_nb_fd].events = POLLIN;
142 i_nb_fd++;
144 if ( i_ca_handle && i_ca_type == CA_CI_LINK )
146 ufds[i_nb_fd].fd = i_ca_handle;
147 ufds[i_nb_fd].events = POLLIN;
148 i_nb_fd++;
151 i_ret = poll( ufds, i_nb_fd, (i_poll_timeout + 999) / 1000 );
153 i_wallclock = mdate();
155 if ( i_ret < 0 )
157 if( errno != EINTR )
158 msg_Err( NULL, "poll error: %s", strerror(errno) );
159 return NULL;
162 if ( ufds[0].revents )
164 p_blocks = DVRRead();
165 i_wallclock = mdate();
168 if ( p_blocks != NULL )
169 i_last_packet = i_wallclock;
170 else if ( !i_frontend_timeout
171 && i_wallclock > i_last_packet + DVR_READ_TIMEOUT )
173 msg_Warn( NULL, "no DVR output, resetting" );
174 FrontendSet(false);
175 en50221_Reset();
178 if ( i_ca_handle && i_ca_type == CA_CI_LINK )
180 if ( ufds[i_nb_fd - 1].revents )
182 en50221_Read();
183 i_ca_next_event = i_wallclock + CA_POLL_PERIOD;
185 else if ( i_wallclock > i_ca_next_event )
187 en50221_Poll();
188 i_ca_next_event = i_wallclock + CA_POLL_PERIOD;
192 if ( ufds[1].revents )
193 FrontendPoll();
195 if ( i_frontend_timeout && i_wallclock > i_frontend_timeout )
197 if ( i_quit_timeout_duration )
199 msg_Err( NULL, "no lock" );
200 exit(EXIT_STATUS_FRONTEND_TIMEOUT);
202 msg_Warn( NULL, "no lock, tuning again" );
203 FrontendSet(false);
206 if ( i_comm_fd != -1 && ufds[2].revents )
207 comm_Read();
209 return p_blocks;
212 /*****************************************************************************
213 * DVRRead
214 *****************************************************************************/
215 static block_t *DVRRead( void )
217 int i, i_len;
218 block_t *p_ts = p_freelist, **pp_current = &p_ts;
219 struct iovec p_iov[MAX_READ_ONCE];
221 for ( i = 0; i < MAX_READ_ONCE; i++ )
223 if ( (*pp_current) == NULL ) *pp_current = block_New();
224 p_iov[i].iov_base = (*pp_current)->p_ts;
225 p_iov[i].iov_len = TS_SIZE;
226 pp_current = &(*pp_current)->p_next;
229 if ( (i_len = readv(i_dvr, p_iov, MAX_READ_ONCE)) < 0 )
231 msg_Err( NULL, "couldn't read from DVR device (%s)",
232 strerror(errno) );
233 i_len = 0;
235 i_len /= TS_SIZE;
237 pp_current = &p_ts;
238 while ( i_len && *pp_current )
240 pp_current = &(*pp_current)->p_next;
241 i_len--;
244 p_freelist = *pp_current;
245 *pp_current = NULL;
247 return p_ts;
252 * Demux
255 /*****************************************************************************
256 * dvb_SetFilter : controls the demux to add a filter
257 *****************************************************************************/
258 int dvb_SetFilter( uint16_t i_pid )
260 struct dmx_pes_filter_params s_filter_params;
261 char psz_tmp[128];
262 int i_fd;
264 sprintf( psz_tmp, "/dev/dvb/adapter%d/demux%d", i_adapter, i_fenum );
265 if( (i_fd = open(psz_tmp, O_RDWR)) < 0 )
267 msg_Err( NULL, "DMXSetFilter: opening device failed (%s)",
268 strerror(errno) );
269 return -1;
272 s_filter_params.pid = i_pid;
273 s_filter_params.input = DMX_IN_FRONTEND;
274 s_filter_params.output = DMX_OUT_TS_TAP;
275 s_filter_params.flags = DMX_IMMEDIATE_START;
276 s_filter_params.pes_type = DMX_PES_OTHER;
278 if ( ioctl( i_fd, DMX_SET_PES_FILTER, &s_filter_params ) < 0 )
280 msg_Err( NULL, "failed setting filter on %d (%s)", i_pid,
281 strerror(errno) );
282 close( i_fd );
283 return -1;
286 msg_Dbg( NULL, "setting filter on PID %d", i_pid );
288 return i_fd;
291 /*****************************************************************************
292 * dvb_UnsetFilter : removes a filter
293 *****************************************************************************/
294 void dvb_UnsetFilter( int i_fd, uint16_t i_pid )
296 if ( ioctl( i_fd, DMX_STOP ) < 0 )
297 msg_Err( NULL, "DMX_STOP failed (%s)", strerror(errno) );
298 else
299 msg_Dbg( NULL, "unsetting filter on PID %d", i_pid );
301 close( i_fd );
306 * Frontend
309 /*****************************************************************************
310 * FrontendPoll : Poll for frontend events
311 *****************************************************************************/
312 static void FrontendPoll( void )
314 struct dvb_frontend_event event;
315 fe_status_t i_status, i_diff;
317 for( ;; )
319 int i_ret = ioctl( i_frontend, FE_GET_EVENT, &event );
321 if( i_ret < 0 )
323 if( errno == EWOULDBLOCK )
324 return; /* no more events */
326 msg_Err( NULL, "reading frontend event failed (%d) %s",
327 i_ret, strerror(errno) );
328 return;
331 i_status = event.status;
332 i_diff = i_status ^ i_last_status;
333 i_last_status = i_status;
336 #define IF_UP( x ) \
338 if ( i_diff & (x) ) \
340 if ( i_status & (x) )
342 IF_UP( FE_HAS_SIGNAL )
343 msg_Dbg( NULL, "frontend has acquired signal" );
344 else
345 msg_Dbg( NULL, "frontend has lost signal" );
347 IF_UP( FE_HAS_CARRIER )
348 msg_Dbg( NULL, "frontend has acquired carrier" );
349 else
350 msg_Dbg( NULL, "frontend has lost carrier" );
352 IF_UP( FE_HAS_VITERBI )
353 msg_Dbg( NULL, "frontend has acquired stable FEC" );
354 else
355 msg_Dbg( NULL, "frontend has lost FEC" );
357 IF_UP( FE_HAS_SYNC )
358 msg_Dbg( NULL, "frontend has acquired sync" );
359 else
360 msg_Dbg( NULL, "frontend has lost sync" );
362 IF_UP( FE_HAS_LOCK )
364 int32_t i_value = 0;
365 msg_Info( NULL, "frontend has acquired lock" );
366 switch (i_print_type) {
367 case PRINT_XML:
368 printf("<STATUS type=\"lock\" status=\"1\" />\n");
369 break;
370 default:
371 printf("frontend has acquired lock\n" );
373 i_frontend_timeout = 0;
374 i_last_packet = i_wallclock;
376 if ( i_quit_timeout_duration && !i_quit_timeout )
377 i_quit_timeout = i_wallclock + i_quit_timeout_duration;
379 /* Read some statistics */
380 if( ioctl( i_frontend, FE_READ_BER, &i_value ) >= 0 )
381 msg_Dbg( NULL, "- Bit error rate: %d", i_value );
382 if( ioctl( i_frontend, FE_READ_SIGNAL_STRENGTH, &i_value ) >= 0 )
383 msg_Dbg( NULL, "- Signal strength: %d", i_value );
384 if( ioctl( i_frontend, FE_READ_SNR, &i_value ) >= 0 )
385 msg_Dbg( NULL, "- SNR: %d", i_value );
387 else
389 msg_Dbg( NULL, "frontend has lost lock" );
390 switch (i_print_type) {
391 case PRINT_XML:
392 printf("<STATUS type=\"lock\" status=\"0\"/>\n");
393 break;
394 default:
395 printf("frontend has lost lock\n" );
397 i_frontend_timeout = i_wallclock + i_frontend_timeout_duration;
400 IF_UP( FE_REINIT )
402 /* The frontend was reinited. */
403 msg_Warn( NULL, "reiniting frontend");
404 FrontendSet(true);
407 #undef IF_UP
411 static int FrontendDoDiseqc(void)
413 fe_sec_voltage_t fe_voltage;
414 fe_sec_tone_mode_t fe_tone;
415 int bis_frequency;
417 switch ( i_voltage )
419 case 0: fe_voltage = SEC_VOLTAGE_OFF; break;
420 default:
421 case 13: fe_voltage = SEC_VOLTAGE_13; break;
422 case 18: fe_voltage = SEC_VOLTAGE_18; break;
425 fe_tone = b_tone ? SEC_TONE_ON : SEC_TONE_OFF;
427 /* Automatic mode. */
428 if ( i_frequency >= 950000 && i_frequency <= 2150000 )
430 msg_Dbg( NULL, "frequency %d is in IF-band", i_frequency );
431 bis_frequency = i_frequency;
433 else if ( i_frequency >= 2500000 && i_frequency <= 2700000 )
435 msg_Dbg( NULL, "frequency %d is in S-band", i_frequency );
436 bis_frequency = 3650000 - i_frequency;
438 else if ( i_frequency >= 3400000 && i_frequency <= 4200000 )
440 msg_Dbg( NULL, "frequency %d is in C-band (lower)", i_frequency );
441 bis_frequency = 5150000 - i_frequency;
443 else if ( i_frequency >= 4500000 && i_frequency <= 4800000 )
445 msg_Dbg( NULL, "frequency %d is in C-band (higher)", i_frequency );
446 bis_frequency = 5950000 - i_frequency;
448 else if ( i_frequency >= 10700000 && i_frequency < 11700000 )
450 msg_Dbg( NULL, "frequency %d is in Ku-band (lower)",
451 i_frequency );
452 bis_frequency = i_frequency - 9750000;
454 else if ( i_frequency >= 11700000 && i_frequency <= 13250000 )
456 msg_Dbg( NULL, "frequency %d is in Ku-band (higher)",
457 i_frequency );
458 bis_frequency = i_frequency - 10600000;
459 fe_tone = SEC_TONE_ON;
461 else
463 msg_Err( NULL, "frequency %d is out of any known band",
464 i_frequency );
465 exit(1);
468 /* Switch off continuous tone. */
469 if ( ioctl( i_frontend, FE_SET_TONE, SEC_TONE_OFF ) < 0 )
471 msg_Err( NULL, "FE_SET_TONE failed (%s)", strerror(errno) );
472 exit(1);
475 /* Configure LNB voltage. */
476 if ( ioctl( i_frontend, FE_SET_VOLTAGE, fe_voltage ) < 0 )
478 msg_Err( NULL, "FE_SET_VOLTAGE failed (%s)", strerror(errno) );
479 exit(1);
482 /* Wait for at least 15 ms. Currently 100 ms because of broken drivers. */
483 msleep(100000);
485 /* Diseqc */
486 if ( i_satnum > 0 && i_satnum < 5 )
488 /* digital satellite equipment control,
489 * specification is available from http://www.eutelsat.com/
492 struct dvb_diseqc_master_cmd cmd =
493 { {0xe0, 0x10, 0x38, 0xf0, 0x00, 0x00}, 4};
494 cmd.msg[3] = 0xf0 /* reset bits */
495 | ((i_satnum - 1) << 2)
496 | (fe_voltage == SEC_VOLTAGE_13 ? 0 : 2)
497 | (fe_tone == SEC_TONE_ON ? 1 : 0);
499 if( ioctl( i_frontend, FE_DISEQC_SEND_MASTER_CMD, &cmd ) < 0 )
501 msg_Err( NULL, "ioctl FE_SEND_MASTER_CMD failed (%s)",
502 strerror(errno) );
503 exit(1);
505 msleep(100000); /* Should be 15 ms. */
507 /* Do it again just to be sure. */
508 if( ioctl( i_frontend, FE_DISEQC_SEND_MASTER_CMD, &cmd ) < 0 )
510 msg_Err( NULL, "ioctl FE_SEND_MASTER_CMD failed (%s)",
511 strerror(errno) );
512 exit(1);
514 msleep(100000); /* Again, should be 15 ms */
516 else if ( i_satnum == 0xA || i_satnum == 0xB )
518 /* A or B simple diseqc ("diseqc-compatible") */
519 if( ioctl( i_frontend, FE_DISEQC_SEND_BURST,
520 i_satnum == 0xB ? SEC_MINI_B : SEC_MINI_A ) < 0 )
522 msg_Err( NULL, "ioctl FE_SEND_BURST failed (%m)", strerror(errno) );
523 exit(1);
525 msleep(100000); /* ... */
528 else if ( ioctl( i_frontend, FE_SET_TONE, fe_tone ) < 0 )
530 msg_Err( NULL, "FE_SET_TONE failed (%s)", strerror(errno) );
531 exit(1);
534 msleep(100000); /* ... */
536 msg_Dbg( NULL, "configuring LNB to v=%d p=%d satnum=%x",
537 i_voltage, b_tone, i_satnum );
538 return bis_frequency;
541 #define DVBAPI_VERSION ((DVB_API_VERSION)*100+(DVB_API_VERSION_MINOR))
543 #if DVB_API_VERSION >= 5
545 /*****************************************************************************
546 * Helper functions for S2API
547 *****************************************************************************/
548 static fe_spectral_inversion_t GetInversion(void)
550 switch ( i_inversion )
552 case 0: return INVERSION_OFF;
553 case 1: return INVERSION_ON;
554 default:
555 msg_Warn( NULL, "invalid inversion %d", i_inversion );
556 case -1: return INVERSION_AUTO;
560 static fe_code_rate_t GetFEC(fe_caps_t fe_caps, int i_fec_value)
562 #define GET_FEC_INNER(fec, val) \
563 if ( (fe_caps & FE_CAN_##fec) && (i_fec_value == val) ) \
564 return fec;
566 GET_FEC_INNER(FEC_AUTO, 999);
567 GET_FEC_INNER(FEC_AUTO, -1);
568 if (i_fec_value == 0)
569 return FEC_NONE;
570 GET_FEC_INNER(FEC_1_2, 12);
571 GET_FEC_INNER(FEC_2_3, 23);
572 GET_FEC_INNER(FEC_3_4, 34);
573 if (i_fec_value == 35)
574 return FEC_3_5;
575 GET_FEC_INNER(FEC_4_5, 45);
576 GET_FEC_INNER(FEC_5_6, 56);
577 GET_FEC_INNER(FEC_6_7, 67);
578 GET_FEC_INNER(FEC_7_8, 78);
579 GET_FEC_INNER(FEC_8_9, 89);
580 if (i_fec_value == 910)
581 return FEC_9_10;
583 #undef GET_FEC_INNER
584 msg_Warn(NULL, "invalid FEC %d", i_fec_value );
585 return FEC_AUTO;
588 #define GetFECInner(caps) GetFEC(caps, i_fec)
589 #define GetFECLP(caps) GetFEC(caps, i_fec_lp)
591 static fe_modulation_t GetModulation(void)
593 #define GET_MODULATION( mod ) \
594 if ( !strcasecmp( psz_modulation, #mod ) ) \
595 return mod;
597 GET_MODULATION(QPSK);
598 GET_MODULATION(QAM_16);
599 GET_MODULATION(QAM_32);
600 GET_MODULATION(QAM_64);
601 GET_MODULATION(QAM_128);
602 GET_MODULATION(QAM_256);
603 GET_MODULATION(QAM_AUTO);
604 GET_MODULATION(VSB_8);
605 GET_MODULATION(VSB_16);
606 GET_MODULATION(PSK_8);
607 GET_MODULATION(APSK_16);
608 GET_MODULATION(APSK_32);
609 GET_MODULATION(DQPSK);
611 #undef GET_MODULATION
612 msg_Err( NULL, "invalid modulation %s", psz_modulation );
613 exit(1);
616 static fe_pilot_t GetPilot(void)
618 switch ( i_pilot )
620 case 0: return PILOT_OFF;
621 case 1: return PILOT_ON;
622 default:
623 msg_Warn( NULL, "invalid pilot %d", i_pilot );
624 case -1: return PILOT_AUTO;
628 static fe_rolloff_t GetRollOff(void)
630 switch ( i_rolloff )
632 case -1:
633 case 0: return ROLLOFF_AUTO;
634 case 20: return ROLLOFF_20;
635 case 25: return ROLLOFF_25;
636 default:
637 msg_Warn( NULL, "invalid rolloff %d", i_rolloff );
638 case 35: return ROLLOFF_35;
642 static fe_guard_interval_t GetGuard(void)
644 switch ( i_guard )
646 case 32: return GUARD_INTERVAL_1_32;
647 case 16: return GUARD_INTERVAL_1_16;
648 case 8: return GUARD_INTERVAL_1_8;
649 case 4: return GUARD_INTERVAL_1_4;
650 default:
651 msg_Warn( NULL, "invalid guard interval %d", i_guard );
652 case -1:
653 case 0: return GUARD_INTERVAL_AUTO;
657 static fe_transmit_mode_t GetTransmission(void)
659 switch ( i_transmission )
661 case 2: return TRANSMISSION_MODE_2K;
662 case 8: return TRANSMISSION_MODE_8K;
663 #ifdef TRANSMISSION_MODE_4K
664 case 4: return TRANSMISSION_MODE_4K;
665 #endif
666 default:
667 msg_Warn( NULL, "invalid tranmission mode %d", i_transmission );
668 case -1:
669 case 0: return TRANSMISSION_MODE_AUTO;
673 static fe_hierarchy_t GetHierarchy(void)
675 switch ( i_hierarchy )
677 case 0: return HIERARCHY_NONE;
678 case 1: return HIERARCHY_1;
679 case 2: return HIERARCHY_2;
680 case 4: return HIERARCHY_4;
681 default:
682 msg_Warn( NULL, "invalid intramission mode %d", i_transmission );
683 case -1: return HIERARCHY_AUTO;
687 /*****************************************************************************
688 * FrontendInfo : Print frontend info
689 *****************************************************************************/
690 static const char *GetFrontendTypeName( fe_type_t type )
692 switch(type)
694 case FE_QPSK: return "QPSK (DVB-S/S2)";
695 case FE_QAM: return "QAM (DVB-C)";
696 case FE_OFDM: return "OFDM (DVB-T)";
697 case FE_ATSC: return "ATSC";
698 default: return "unknown";
702 static void FrontendInfo( struct dvb_frontend_info info )
704 msg_Dbg( NULL, "Frontend \"%s\" type \"%s\" supports:",
705 info.name, GetFrontendTypeName(info.type) );
706 msg_Dbg( NULL, " frequency min: %d, max: %d, stepsize: %d, tolerance: %d",
707 info.frequency_min, info.frequency_max,
708 info.frequency_stepsize, info.frequency_tolerance );
709 msg_Dbg( NULL, " symbolrate min: %d, max: %d, tolerance: %d",
710 info.symbol_rate_min, info.symbol_rate_max, info.symbol_rate_tolerance);
711 msg_Dbg( NULL, " capabilities:" );
713 #define FRONTEND_INFO(caps,val,msg) \
714 if ( caps & val ) \
715 msg_Dbg( NULL, " %s", msg );
717 FRONTEND_INFO( info.caps, FE_IS_STUPID, "FE_IS_STUPID" )
718 FRONTEND_INFO( info.caps, FE_CAN_INVERSION_AUTO, "INVERSION_AUTO" )
719 FRONTEND_INFO( info.caps, FE_CAN_FEC_1_2, "FEC_1_2" )
720 FRONTEND_INFO( info.caps, FE_CAN_FEC_2_3, "FEC_2_3" )
721 FRONTEND_INFO( info.caps, FE_CAN_FEC_3_4, "FEC_3_4" )
722 FRONTEND_INFO( info.caps, FE_CAN_FEC_4_5, "FEC_4_5" )
723 FRONTEND_INFO( info.caps, FE_CAN_FEC_5_6, "FEC_5_6" )
724 FRONTEND_INFO( info.caps, FE_CAN_FEC_6_7, "FEC_6_7" )
725 FRONTEND_INFO( info.caps, FE_CAN_FEC_7_8, "FEC_7_8" )
726 FRONTEND_INFO( info.caps, FE_CAN_FEC_8_9, "FEC_8_9" )
727 FRONTEND_INFO( info.caps, FE_CAN_FEC_AUTO,"FEC_AUTO")
728 FRONTEND_INFO( info.caps, FE_CAN_QPSK, "QPSK" )
729 FRONTEND_INFO( info.caps, FE_CAN_QAM_16, "QAM_16" )
730 FRONTEND_INFO( info.caps, FE_CAN_QAM_32, "QAM_32" )
731 FRONTEND_INFO( info.caps, FE_CAN_QAM_64, "QAM_64" )
732 FRONTEND_INFO( info.caps, FE_CAN_QAM_128,"QAM_128")
733 FRONTEND_INFO( info.caps, FE_CAN_QAM_256,"QAM_256")
734 FRONTEND_INFO( info.caps, FE_CAN_QAM_AUTO,"QAM_AUTO" )
735 FRONTEND_INFO( info.caps, FE_CAN_TRANSMISSION_MODE_AUTO, "TRANSMISSION_MODE_AUTO" )
736 FRONTEND_INFO( info.caps, FE_CAN_BANDWIDTH_AUTO, "BANDWIDTH_AUTO" )
737 FRONTEND_INFO( info.caps, FE_CAN_GUARD_INTERVAL_AUTO, "GUARD_INTERVAL_AUTO" )
738 FRONTEND_INFO( info.caps, FE_CAN_HIERARCHY_AUTO, "HIERARCHY_AUTO" )
739 FRONTEND_INFO( info.caps, FE_CAN_8VSB, "8VSB" )
740 FRONTEND_INFO( info.caps, FE_CAN_16VSB,"16VSB" )
741 FRONTEND_INFO( info.caps, FE_HAS_EXTENDED_CAPS, "EXTENDED_CAPS" )
742 #if DVBAPI_VERSION >= 501
743 FRONTEND_INFO( info.caps, FE_CAN_2G_MODULATION, "2G_MODULATION" )
744 #endif
745 FRONTEND_INFO( info.caps, FE_NEEDS_BENDING, "NEEDS_BENDING" )
746 FRONTEND_INFO( info.caps, FE_CAN_RECOVER, "FE_CAN_RECOVER" )
747 FRONTEND_INFO( info.caps, FE_CAN_MUTE_TS, "FE_CAN_MUTE_TS" )
748 #undef FRONTEND_INFO
751 /*****************************************************************************
752 * FrontendSet
753 *****************************************************************************/
754 /* S2API */
755 static struct dtv_property dvbs_cmdargs[] = {
756 { .cmd = DTV_FREQUENCY, .u.data = 0 },
757 { .cmd = DTV_MODULATION, .u.data = QPSK },
758 { .cmd = DTV_INVERSION, .u.data = INVERSION_AUTO },
759 { .cmd = DTV_SYMBOL_RATE, .u.data = 27500000 },
760 { .cmd = DTV_INNER_FEC, .u.data = FEC_AUTO },
761 { .cmd = DTV_DELIVERY_SYSTEM, .u.data = SYS_DVBS },
762 { .cmd = DTV_TUNE },
764 static struct dtv_properties dvbs_cmdseq = {
765 .num = sizeof(dvbs_cmdargs)/sizeof(struct dtv_property),
766 .props = dvbs_cmdargs
769 static struct dtv_property dvbs2_cmdargs[] = {
770 { .cmd = DTV_FREQUENCY, .u.data = 0 },
771 { .cmd = DTV_MODULATION, .u.data = PSK_8 },
772 { .cmd = DTV_INVERSION, .u.data = INVERSION_AUTO },
773 { .cmd = DTV_SYMBOL_RATE, .u.data = 27500000 },
774 { .cmd = DTV_INNER_FEC, .u.data = FEC_AUTO },
775 { .cmd = DTV_DELIVERY_SYSTEM, .u.data = SYS_DVBS2 },
776 { .cmd = DTV_PILOT, .u.data = PILOT_AUTO },
777 { .cmd = DTV_ROLLOFF, .u.data = ROLLOFF_AUTO },
778 { .cmd = DTV_TUNE },
780 static struct dtv_properties dvbs2_cmdseq = {
781 .num = sizeof(dvbs2_cmdargs)/sizeof(struct dtv_property),
782 .props = dvbs2_cmdargs
785 static struct dtv_property dvbc_cmdargs[] = {
786 { .cmd = DTV_FREQUENCY, .u.data = 0 },
787 { .cmd = DTV_MODULATION, .u.data = QAM_AUTO },
788 { .cmd = DTV_INVERSION, .u.data = INVERSION_AUTO },
789 { .cmd = DTV_SYMBOL_RATE, .u.data = 27500000 },
790 { .cmd = DTV_DELIVERY_SYSTEM, .u.data = SYS_DVBC_ANNEX_AC },
791 { .cmd = DTV_TUNE },
793 static struct dtv_properties dvbc_cmdseq = {
794 .num = sizeof(dvbc_cmdargs)/sizeof(struct dtv_property),
795 .props = dvbc_cmdargs
798 static struct dtv_property dvbt_cmdargs[] = {
799 { .cmd = DTV_FREQUENCY, .u.data = 0 },
800 { .cmd = DTV_MODULATION, .u.data = QAM_AUTO },
801 { .cmd = DTV_INVERSION, .u.data = INVERSION_AUTO },
802 { .cmd = DTV_BANDWIDTH_HZ, .u.data = 8000000 },
803 { .cmd = DTV_CODE_RATE_HP, .u.data = FEC_AUTO },
804 { .cmd = DTV_CODE_RATE_LP, .u.data = FEC_AUTO },
805 { .cmd = DTV_GUARD_INTERVAL, .u.data = GUARD_INTERVAL_AUTO },
806 { .cmd = DTV_TRANSMISSION_MODE,.u.data = TRANSMISSION_MODE_AUTO },
807 { .cmd = DTV_HIERARCHY, .u.data = HIERARCHY_AUTO },
808 { .cmd = DTV_DELIVERY_SYSTEM, .u.data = SYS_DVBT },
809 { .cmd = DTV_TUNE },
811 static struct dtv_properties dvbt_cmdseq = {
812 .num = sizeof(dvbt_cmdargs)/sizeof(struct dtv_property),
813 .props = dvbt_cmdargs
816 #define FREQUENCY 0
817 #define MODULATION 1
818 #define INVERSION 2
819 #define SYMBOL_RATE 3
820 #define BANDWIDTH 3
821 #define FEC_INNER 4
822 #define FEC_LP 5
823 #define GUARD 6
824 #define PILOT 6
825 #define TRANSMISSION 7
826 #define ROLLOFF 7
827 #define HIERARCHY 8
829 struct dtv_property pclear[] = {
830 { .cmd = DTV_CLEAR },
833 struct dtv_properties cmdclear = {
834 .num = 1,
835 .props = pclear
838 static void FrontendSet( bool b_init )
840 struct dvb_frontend_info info;
841 struct dtv_properties *p;
843 if ( ioctl( i_frontend, FE_GET_INFO, &info ) < 0 )
845 msg_Err( NULL, "FE_GET_INFO failed (%s)", strerror(errno) );
846 exit(1);
849 if ( b_init )
850 FrontendInfo( info );
852 /* Clear frontend commands */
853 if ( ioctl( i_frontend, FE_SET_PROPERTY, &cmdclear ) < 0 )
855 msg_Err( NULL, "Unable to clear frontend" );
856 exit(1);
859 switch ( info.type )
861 case FE_OFDM:
862 p = &dvbt_cmdseq;
863 p->props[FREQUENCY].u.data = i_frequency;
864 p->props[INVERSION].u.data = GetInversion();
865 if ( psz_modulation != NULL )
866 p->props[MODULATION].u.data = GetModulation();
867 p->props[BANDWIDTH].u.data = i_bandwidth * 1000000;
868 p->props[FEC_INNER].u.data = GetFECInner(info.caps);
869 p->props[FEC_LP].u.data = GetFECLP(info.caps);
870 p->props[GUARD].u.data = GetGuard();
871 p->props[TRANSMISSION].u.data = GetTransmission();
872 p->props[HIERARCHY].u.data = GetHierarchy();
874 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",
875 i_frequency, i_bandwidth, i_inversion, i_fec, i_fec_lp,
876 i_hierarchy,
877 psz_modulation == NULL ? "qam_auto" : psz_modulation,
878 i_guard, i_transmission );
879 break;
881 case FE_QAM:
882 p = &dvbc_cmdseq;
883 p->props[FREQUENCY].u.data = i_frequency;
884 p->props[INVERSION].u.data = GetInversion();
885 if ( psz_modulation != NULL )
886 p->props[MODULATION].u.data = GetModulation();
887 p->props[SYMBOL_RATE].u.data = i_srate;
889 msg_Dbg( NULL, "tuning QAM frontend to f=%d srate=%d inversion=%d modulation=%s",
890 i_frequency, i_srate, i_inversion,
891 psz_modulation == NULL ? "qam_auto" : psz_modulation );
892 break;
894 case FE_QPSK:
895 if ( psz_modulation != NULL )
897 p = &dvbs2_cmdseq;
898 p->props[MODULATION].u.data = GetModulation();
899 p->props[PILOT].u.data = GetPilot();
900 p->props[ROLLOFF].u.data = GetRollOff();
902 else
903 p = &dvbs_cmdseq;
905 p->props[INVERSION].u.data = GetInversion();
906 p->props[SYMBOL_RATE].u.data = i_srate;
907 p->props[FEC_INNER].u.data = GetFECInner(info.caps);
908 p->props[FREQUENCY].u.data = FrontendDoDiseqc();
910 msg_Dbg( NULL, "tuning QPSK frontend to f=%d srate=%d inversion=%d fec=%d rolloff=%d modulation=%s pilot=%d",
911 i_frequency, i_srate, i_inversion, i_fec, i_rolloff,
912 psz_modulation == NULL ? "legacy" : psz_modulation, i_pilot );
913 break;
915 default:
916 msg_Err( NULL, "unknown frontend type %d", info.type );
917 exit(1);
920 /* Empty the event queue */
921 for ( ; ; )
923 struct dvb_frontend_event event;
924 if ( ioctl( i_frontend, FE_GET_EVENT, &event ) < 0
925 && errno == EWOULDBLOCK )
926 break;
929 /* Now send it all to the frontend device */
930 if ( ioctl( i_frontend, FE_SET_PROPERTY, p ) < 0 )
932 msg_Err( NULL, "setting frontend failed (%s)", strerror(errno) );
933 exit(1);
936 i_last_status = 0;
937 i_frontend_timeout = i_wallclock + i_frontend_timeout_duration;
940 #else /* !S2API */
942 #warn "You are trying to compile DVBlast with an outdated linux-dvb interface."
943 #warn "DVBlast will be very limited and some options will have no effect."
945 static void FrontendSet( bool b_init )
947 struct dvb_frontend_info info;
948 struct dvb_frontend_parameters fep;
950 if ( ioctl( i_frontend, FE_GET_INFO, &info ) < 0 )
952 msg_Err( NULL, "FE_GET_INFO failed (%s)", strerror(errno) );
953 exit(1);
956 switch ( info.type )
958 case FE_OFDM:
959 fep.frequency = i_frequency;
960 fep.inversion = INVERSION_AUTO;
962 switch ( i_bandwidth )
964 case 6: fep.u.ofdm.bandwidth = BANDWIDTH_6_MHZ; break;
965 case 7: fep.u.ofdm.bandwidth = BANDWIDTH_7_MHZ; break;
966 default:
967 case 8: fep.u.ofdm.bandwidth = BANDWIDTH_8_MHZ; break;
970 fep.u.ofdm.code_rate_HP = FEC_AUTO;
971 fep.u.ofdm.code_rate_LP = FEC_AUTO;
972 fep.u.ofdm.constellation = QAM_AUTO;
973 fep.u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO;
974 fep.u.ofdm.guard_interval = GUARD_INTERVAL_AUTO;
975 fep.u.ofdm.hierarchy_information = HIERARCHY_AUTO;
977 msg_Dbg( NULL, "tuning OFDM frontend to f=%d, bandwidth=%d",
978 i_frequency, i_bandwidth );
979 break;
981 case FE_QAM:
982 fep.frequency = i_frequency;
983 fep.inversion = INVERSION_AUTO;
984 fep.u.qam.symbol_rate = i_srate;
985 fep.u.qam.fec_inner = FEC_AUTO;
986 fep.u.qam.modulation = QAM_AUTO;
988 msg_Dbg( NULL, "tuning QAM frontend to f=%d, srate=%d",
989 i_frequency, i_srate );
990 break;
992 case FE_QPSK:
993 fep.inversion = INVERSION_AUTO;
994 fep.u.qpsk.symbol_rate = i_srate;
995 fep.u.qpsk.fec_inner = FEC_AUTO;
996 fep.frequency = FrontendDoDiseqc();
998 msg_Dbg( NULL, "tuning QPSK frontend to f=%d, srate=%d",
999 i_frequency, i_srate );
1000 break;
1002 #if DVBAPI_VERSION >= 301
1003 case FE_ATSC:
1004 fep.frequency = i_frequency;
1006 fep.u.vsb.modulation = QAM_AUTO;
1008 msg_Dbg( NULL, "tuning ATSC frontend to f=%d", i_frequency );
1009 break;
1010 #endif
1012 default:
1013 msg_Err( NULL, "unknown frontend type %d", info.type );
1014 exit(1);
1017 /* Empty the event queue */
1018 for ( ; ; )
1020 struct dvb_frontend_event event;
1021 if ( ioctl( i_frontend, FE_GET_EVENT, &event ) < 0
1022 && errno == EWOULDBLOCK )
1023 break;
1026 /* Now send it all to the frontend device */
1027 if ( ioctl( i_frontend, FE_SET_FRONTEND, &fep ) < 0 )
1029 msg_Err( NULL, "setting frontend failed (%s)", strerror(errno) );
1030 exit(1);
1033 i_last_status = 0;
1034 i_frontend_timeout = i_wallclock + i_frontend_timeout_duration;
1037 #endif /* S2API */
1039 /*****************************************************************************
1040 * dvb_FrontendStatus
1041 *****************************************************************************/
1042 uint8_t dvb_FrontendStatus( uint8_t *p_answer, ssize_t *pi_size )
1044 struct ret_frontend_status *p_ret = (struct ret_frontend_status *)p_answer;
1046 if ( ioctl( i_frontend, FE_GET_INFO, &p_ret->info ) < 0 )
1048 msg_Err( NULL, "ioctl FE_GET_INFO failed (%s)", strerror(errno) );
1049 return RET_ERR;
1052 if ( ioctl( i_frontend, FE_READ_STATUS, &p_ret->i_status ) < 0 )
1054 msg_Err( NULL, "ioctl FE_READ_STATUS failed (%s)", strerror(errno) );
1055 return RET_ERR;
1058 if ( p_ret->i_status & FE_HAS_LOCK )
1060 if ( ioctl( i_frontend, FE_READ_BER, &p_ret->i_ber ) < 0 )
1061 msg_Err( NULL, "ioctl FE_READ_BER failed (%s)", strerror(errno) );
1063 if ( ioctl( i_frontend, FE_READ_SIGNAL_STRENGTH, &p_ret->i_strength )
1064 < 0 )
1065 msg_Err( NULL, "ioctl FE_READ_SIGNAL_STRENGTH failed (%s)",
1066 strerror(errno) );
1068 if ( ioctl( i_frontend, FE_READ_SNR, &p_ret->i_snr ) < 0 )
1069 msg_Err( NULL, "ioctl FE_READ_SNR failed (%s)", strerror(errno) );
1072 *pi_size = sizeof(struct ret_frontend_status);
1073 return RET_FRONTEND_STATUS;