1 /*****************************************************************************
3 *****************************************************************************
4 * Copyright (C) 2008 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 *****************************************************************************/
31 #include <sys/types.h>
33 #include <sys/param.h>
34 #include <sys/socket.h>
35 #include <netinet/in.h>
36 #include <arpa/inet.h>
43 #include <bitstream/mpeg/psi.h>
44 #include <bitstream/dvb/si.h>
45 #include <bitstream/dvb/si_print.h>
46 #include <bitstream/mpeg/psi_print.h>
51 #define STRINGIFY( z ) UGLY_KLUDGE( z )
52 #define UGLY_KLUDGE( z ) #z
56 unsigned int i_timeout_seconds
= 15;
58 print_type_t i_print_type
= PRINT_TEXT
;
62 char psz_client_socket
[PATH_MAX
] = {0};
64 static iconv_t iconv_handle
= (iconv_t
)-1;
66 static void clean_client_socket() {
72 if ( psz_client_socket
[0] )
74 unlink( psz_client_socket
);
75 psz_client_socket
[0] = '\0';
79 /*****************************************************************************
80 * The following two functions are from biTStream's examples and are under the
81 * WTFPL (see LICENSE.WTFPL).
82 ****************************************************************************/
83 __attribute__ ((format(printf
, 2, 3)))
84 static void psi_print(void *_unused
, const char *psz_format
, ...)
86 char psz_fmt
[strlen(psz_format
) + 2];
88 va_start(args
, psz_format
);
89 strcpy(psz_fmt
, psz_format
);
90 strcat(psz_fmt
, "\n");
91 vprintf(psz_fmt
, args
);
95 __attribute__ ((format(printf
, 1, 2)))
96 void return_error( const char *psz_format
, ... )
101 clean_client_socket();
103 va_start( args
, psz_format
);
104 if ( i_print_type
== PRINT_XML
)
105 snprintf( psz_fmt
, sizeof(psz_fmt
) - 1, "<ERROR msg=\"%s\"/>\n", psz_format
);
107 snprintf( psz_fmt
, sizeof(psz_fmt
) - 1, "ERROR: %s\n", psz_format
);
108 psz_fmt
[sizeof(psz_fmt
) - 1] = '\0';
109 vfprintf( stderr
, psz_fmt
, args
);
114 static char *iconv_append_null(const char *p_string
, size_t i_length
)
116 char *psz_string
= malloc(i_length
+ 1);
117 memcpy(psz_string
, p_string
, i_length
);
118 psz_string
[i_length
] = '\0';
122 const char *psz_native_charset
= "UTF-8//IGNORE";
124 char *psi_iconv(void *_unused
, const char *psz_encoding
,
125 char *p_string
, size_t i_length
)
127 static const char *psz_current_encoding
= "";
129 char *psz_string
, *p
;
132 if (!strcmp(psz_encoding
, psz_native_charset
))
133 return iconv_append_null(p_string
, i_length
);
135 if (iconv_handle
!= (iconv_t
)-1 &&
136 strcmp(psz_encoding
, psz_current_encoding
)) {
137 iconv_close(iconv_handle
);
138 iconv_handle
= (iconv_t
)-1;
141 if (iconv_handle
== (iconv_t
)-1)
142 iconv_handle
= iconv_open(psz_native_charset
, psz_encoding
);
143 if (iconv_handle
== (iconv_t
)-1) {
144 msg_Warn(NULL
, "couldn't open converter from %s to %s (%m)", psz_encoding
,
146 return iconv_append_null(p_string
, i_length
);
148 psz_current_encoding
= psz_encoding
;
150 /* converted strings can be up to six times larger */
151 i_out_length
= i_length
* 6;
152 p
= psz_string
= malloc(i_out_length
);
153 if (iconv(iconv_handle
, &p_string
, &i_length
, &p
, &i_out_length
) == (size_t)-1) {
154 msg_Warn(NULL
, "couldn't convert from %s to %s (%m)", psz_encoding
,
157 return iconv_append_null(p_string
, i_length
);
160 msg_Warn(NULL
, "partial conversion from %s to %s", psz_encoding
,
167 void print_pids_header( void )
169 if ( i_print_type
== PRINT_XML
)
173 void print_pids_footer( void )
175 if ( i_print_type
== PRINT_XML
)
179 void print_pid(uint16_t i_pid
, ts_pid_info_t
*p_info
)
181 if ( p_info
->i_packets
== 0 )
183 if ( i_print_type
== PRINT_TEXT
)
184 printf("pid %d packn %lu ccerr %lu tserr %lu scramble %d Bps %lu seen %"PRId64
"\n",
188 p_info
->i_transport_errors
,
189 p_info
->i_scrambling
,
190 p_info
->i_bytes_per_sec
,
191 now
- p_info
->i_last_packet_ts
194 printf("<PID pid=\"%d\" packn=\"%lu\" ccerr=\"%lu\" tserr=\"%lu\" scramble=\"%d\" Bps=\"%lu\" seen=\"%"PRId64
"\" />\n",
198 p_info
->i_transport_errors
,
199 p_info
->i_scrambling
,
200 p_info
->i_bytes_per_sec
,
201 now
- p_info
->i_last_packet_ts
205 void print_pids( uint8_t *p_data
)
209 for ( i_pid
= 0; i_pid
< MAX_PIDS
; i_pid
++ ) {
210 ts_pid_info_t
*p_info
= (ts_pid_info_t
*)(p_data
+ i_pid
* sizeof(ts_pid_info_t
));
211 print_pid( i_pid
, p_info
);
216 void print_eit_events(uint8_t *p_eit
, f_print pf_print
, void *print_opaque
, f_iconv pf_iconv
, void *iconv_opaque
, print_type_t i_print_type
)
220 while ((p_event
= eit_get_event(p_eit
, j
)) != NULL
) {
222 char start_str
[25], duration_str
[20];
223 int duration
, hour
, min
, sec
;
226 start_ts
= dvb_time_format_UTC(eitn_get_start_time(p_event
), NULL
, start_str
);
228 dvb_time_decode_bcd(eitn_get_duration_bcd(p_event
), &duration
, &hour
, &min
, &sec
);
229 sprintf(duration_str
, "%02d:%02d:%02d", hour
, min
, sec
);
231 switch (i_print_type
) {
233 pf_print(print_opaque
, "<EVENT id=\"%u\" start_time=\"%ld\" start_time_dec=\"%s\""
234 " duration=\"%u\" duration_dec=\"%s\""
235 " running=\"%d\" free_CA=\"%d\">",
236 eitn_get_event_id(p_event
),
238 duration
, duration_str
,
239 eitn_get_running(p_event
),
244 pf_print(print_opaque
, " * EVENT id=%u start_time=%ld start_time_dec=\"%s\" duration=%u duration_dec=%s running=%d free_CA=%d",
245 eitn_get_event_id(p_event
),
247 duration
, duration_str
,
248 eitn_get_running(p_event
),
253 descs_print(eitn_get_descs(p_event
), pf_print
, print_opaque
,
254 pf_iconv
, iconv_opaque
, i_print_type
);
256 switch (i_print_type
) {
258 pf_print(print_opaque
, "</EVENT>");
266 void print_eit(uint8_t *p_eit
, unsigned int i_eit_size
, f_print pf_print
, void *print_opaque
, f_iconv pf_iconv
, void *iconv_opaque
, print_type_t i_print_type
)
268 uint8_t *p_eit_end
= p_eit
+ i_eit_size
;
269 uint8_t i_tid
= psi_get_tableid(p_eit
);
270 const char *psz_tid
= "unknown";
272 if (i_tid
== EIT_TABLE_ID_PF_ACTUAL
)
273 psz_tid
= "actual_pf";
274 else if (i_tid
== EIT_TABLE_ID_PF_OTHER
)
275 psz_tid
= "other_pf";
276 else if (i_tid
>= EIT_TABLE_ID_SCHED_ACTUAL_FIRST
&& i_tid
<= EIT_TABLE_ID_SCHED_ACTUAL_LAST
)
277 psz_tid
= "actual_schedule";
278 else if (i_tid
>= EIT_TABLE_ID_SCHED_OTHER_FIRST
&& i_tid
<= EIT_TABLE_ID_SCHED_OTHER_LAST
)
279 psz_tid
= "other_schedule";
281 switch (i_print_type
) {
283 pf_print(print_opaque
,
284 "<EIT tableid=\"0x%02x\" type=\"%s\" service_id=\"%u\""
286 " current_next=\"%u\""
287 " tsid=\"%u\" onid=\"%u\">",
290 psi_get_version(p_eit
),
291 !psi_get_current(p_eit
) ? 0 : 1,
297 pf_print(print_opaque
,
298 "new EIT tableid=0x%02x type=%s service_id=%u version=%u%s"
303 psi_get_version(p_eit
),
304 !psi_get_current(p_eit
) ? " (next)" : "",
310 while (p_eit
< p_eit_end
) {
311 print_eit_events(p_eit
, pf_print
, print_opaque
, pf_iconv
, iconv_opaque
, i_print_type
);
312 p_eit
+= psi_get_length( p_eit
) + PSI_HEADER_SIZE
;
315 switch (i_print_type
) {
317 pf_print(print_opaque
, "</EIT>");
320 pf_print(print_opaque
, "end EIT");
324 struct dvblastctl_option
{
330 static const struct dvblastctl_option options
[] =
332 { "reload", 0, CMD_RELOAD
},
333 { "shutdown", 0, CMD_SHUTDOWN
},
335 { "fe_status", 0, CMD_FRONTEND_STATUS
},
336 { "get_pat", 0, CMD_GET_PAT
},
337 { "get_cat", 0, CMD_GET_CAT
},
338 { "get_nit", 0, CMD_GET_NIT
},
339 { "get_sdt", 0, CMD_GET_SDT
},
340 { "get_eit_pf", 1, CMD_GET_EIT_PF
}, /* arg: service_id (uint16_t) */
341 { "get_eit_schedule", 1, CMD_GET_EIT_SCHEDULE
}, /* arg: service_id (uint16_t) */
342 { "get_pmt", 1, CMD_GET_PMT
}, /* arg: service_id (uint16_t) */
343 { "get_pids", 0, CMD_GET_PIDS
},
344 { "get_pid", 1, CMD_GET_PID
}, /* arg: pid (uint16_t) */
351 printf("DVBlastctl %s (%s)\n", VERSION
, VERSION_EXTRA
);
352 printf("Usage: dvblastctl -r <remote socket> [-x <text|xml>] [cmd]\n");
353 printf("Options:\n");
354 printf(" -r --remote-socket <name> Set socket name to <name>.\n" );
355 printf(" -t --timeout <seconds> Set socket read/write timeout in seconds (default 15).\n" );
356 printf(" -j --system-charset <name> Character set used for output (default UTF-8//IGNORE)\n" );
357 printf(" -x --print <text|xml> Choose output format for info commands.\n" );
358 printf("Control commands:\n");
359 printf(" reload Reload configuration.\n");
360 printf(" shutdown Shutdown DVBlast.\n");
361 #ifdef HAVE_DVB_SUPPORT
362 printf("Status commands:\n");
363 printf(" fe_status Read frontend status information.\n");
365 printf("Demux info commands:\n");
366 printf(" get_pat Return last PAT table.\n");
367 printf(" get_cat Return last CAT table.\n");
368 printf(" get_nit Return last NIT table.\n");
369 printf(" get_sdt Return last SDT table.\n");
370 printf(" get_eit_pf <service_id> Return last EIT present/following data.\n");
371 printf(" get_eit_schedule <service_id> Return last EIT schedule data.\n");
372 printf(" get_pmt <service_id> Return last PMT table.\n");
373 printf(" get_pids Return info about all pids.\n");
374 printf(" get_pid <pid> Return info for chosen pid only.\n");
379 int main( int i_argc
, char **ppsz_argv
)
381 char *client_socket_tmpl
= "dvblastctl.clientsock.XXXXXX";
382 char *psz_srv_socket
= NULL
;
384 char *p_cmd
, *p_arg1
= NULL
, *p_arg2
= NULL
;
386 struct sockaddr_un sun_client
, sun_server
;
387 uint8_t p_buffer
[COMM_BUFFER_SIZE
];
388 uint8_t *p_data
= p_buffer
+ COMM_HEADER_SIZE
;
390 struct dvblastctl_option opt
= { 0, 0, 0 };
396 static const struct option long_options
[] =
398 {"remote-socket", required_argument
, NULL
, 'r'},
399 {"timeout", required_argument
, NULL
, 't'},
400 {"system-charset", required_argument
, NULL
, 'j'},
401 {"print", required_argument
, NULL
, 'x'},
402 {"help", no_argument
, NULL
, 'h'},
406 if ( (c
= getopt_long(i_argc
, ppsz_argv
, "r:t:x:j:h", long_options
, NULL
)) == -1 )
412 psz_srv_socket
= optarg
;
416 i_timeout_seconds
= (unsigned int)strtoul(optarg
, NULL
, 10);
420 psz_native_charset
= optarg
;
424 if ( !strcmp(optarg
, "text") )
425 i_print_type
= PRINT_TEXT
;
426 else if ( !strcmp(optarg
, "xml") )
427 i_print_type
= PRINT_XML
;
429 msg_Warn( NULL
, "unrecognized print type %s", optarg
);
430 /* Make stdout line-buffered */
431 setvbuf(stdout
, NULL
, _IOLBF
, 0);
440 /* Validate commands */
441 #define usage_error(msg, ...) \
443 msg_Err( NULL, msg, ##__VA_ARGS__ ); \
446 p_cmd
= ppsz_argv
[optind
];
447 p_arg1
= ppsz_argv
[optind
+ 1];
448 p_arg2
= ppsz_argv
[optind
+ 2];
450 if ( !psz_srv_socket
)
451 usage_error( "Remote socket is not set.\n" );
454 usage_error( "Command is not set.\n" );
458 if ( streq(ppsz_argv
[optind
], options
[i
].opt
) )
463 } while ( options
[++i
].opt
);
466 usage_error( "Unknown command: %s\n", p_cmd
);
468 if ( opt
.nparams
== 1 && !p_arg1
)
469 usage_error( "%s option needs parameter.\n", opt
.opt
);
471 if ( opt
.nparams
== 2 && (!p_arg1
|| !p_arg2
) )
472 usage_error( "%s option needs two parameters.\n", opt
.opt
);
475 /* Create client socket name */
476 char *tmpdir
= getenv("TMPDIR");
477 snprintf( psz_client_socket
, PATH_MAX
- 1, "%s/%s",
478 tmpdir
? tmpdir
: "/tmp", client_socket_tmpl
);
479 psz_client_socket
[PATH_MAX
- 1] = '\0';
481 int tmp_fd
= mkstemp(psz_client_socket
);
484 unlink(psz_client_socket
);
486 return_error( "Cannot build UNIX socket %s (%s)", psz_client_socket
, strerror(errno
) );
489 if ( (i_fd
= socket( AF_UNIX
, SOCK_DGRAM
, 0 )) < 0 )
490 return_error( "Cannot create UNIX socket (%s)", strerror(errno
) );
492 i
= COMM_MAX_MSG_CHUNK
;
493 setsockopt( i_fd
, SOL_SOCKET
, SO_RCVBUF
, &i
, sizeof(i
) );
495 memset( &sun_client
, 0, sizeof(sun_client
) );
496 sun_client
.sun_family
= AF_UNIX
;
497 strncpy( sun_client
.sun_path
, psz_client_socket
,
498 sizeof(sun_client
.sun_path
) );
499 sun_client
.sun_path
[sizeof(sun_client
.sun_path
) - 1] = '\0';
501 if ( bind( i_fd
, (struct sockaddr
*)&sun_client
,
502 SUN_LEN(&sun_client
) ) < 0 )
503 return_error( "Cannot bind (%s)", strerror(errno
) );
505 memset( &sun_server
, 0, sizeof(sun_server
) );
506 sun_server
.sun_family
= AF_UNIX
;
507 strncpy( sun_server
.sun_path
, psz_srv_socket
, sizeof(sun_server
.sun_path
) );
508 sun_server
.sun_path
[sizeof(sun_server
.sun_path
) - 1] = '\0';
510 p_buffer
[0] = COMM_HEADER_MAGIC
;
511 p_buffer
[1] = opt
.cmd
;
512 memset( p_buffer
+ 2, 0, COMM_HEADER_SIZE
- 2 );
513 i_size
= COMM_HEADER_SIZE
;
515 /* Handle commands that send parameters */
521 case CMD_FRONTEND_STATUS
:
527 /* These commands need no special handling because they have no parameters */
530 case CMD_GET_EIT_SCHEDULE
:
533 uint16_t i_sid
= atoi(p_arg1
);
534 i_size
= COMM_HEADER_SIZE
+ 2;
535 p_data
[0] = (uint8_t)((i_sid
>> 8) & 0xff);
536 p_data
[1] = (uint8_t)(i_sid
& 0xff);
541 i_pid
= (uint16_t)atoi(p_arg1
);
542 i_size
= COMM_HEADER_SIZE
+ 2;
543 p_data
[0] = (uint8_t)((i_pid
>> 8) & 0xff);
544 p_data
[1] = (uint8_t)(i_pid
& 0xff);
548 /* This should not happen */
549 return_error( "Unhandled option (%d)", opt
.cmd
);
552 if ( i_timeout_seconds
> 0 ) {
553 struct timeval tv_timeout
= {
554 .tv_sec
= i_timeout_seconds
,
557 if ( setsockopt( i_fd
, SOL_SOCKET
, SO_SNDTIMEO
, &tv_timeout
, sizeof( tv_timeout
) ) != 0 )
558 return_error( "Cannot set SO_SNDTIMEO (%s)", strerror(errno
) );
560 if ( setsockopt( i_fd
, SOL_SOCKET
, SO_RCVTIMEO
, &tv_timeout
, sizeof( tv_timeout
) ) != 0 )
561 return_error( "Cannot set SO_RCVTIMEO (%s)", strerror(errno
) );
564 /* Send command and receive answer */
565 if ( sendto( i_fd
, p_buffer
, i_size
, 0, (struct sockaddr
*)&sun_server
,
566 SUN_LEN(&sun_server
) ) < 0 )
567 return_error( "Cannot send comm socket (%s)", strerror(errno
) );
569 uint32_t i_packet_size
= 0, i_received
= 0;
571 i_size
= recv( i_fd
, p_buffer
+ i_received
, COMM_MAX_MSG_CHUNK
, 0 );
574 if ( !i_packet_size
) {
575 uint32_t *p_packet_size
= (uint32_t *)&p_buffer
[4];
576 i_packet_size
= *p_packet_size
;
577 if ( i_packet_size
> COMM_BUFFER_SIZE
) {
582 i_received
+= i_size
;
583 } while ( i_received
< i_packet_size
);
585 clean_client_socket();
586 if ( i_packet_size
< COMM_HEADER_SIZE
)
587 return_error( "Cannot recv from comm socket, size:%"PRIu32
" (%s)", i_packet_size
, strerror(errno
) );
590 if ( p_buffer
[0] != COMM_HEADER_MAGIC
)
591 return_error( "Wrong protocol version 0x%x", p_buffer
[0] );
595 ctl_cmd_answer_t c_answer
= p_buffer
[1];
602 return_error( "Request failed" );
606 return_error( "Internal error" );
610 return_error( "No data" );
618 uint8_t *p_flat_data
= p_buffer
+ COMM_HEADER_SIZE
;
619 unsigned int i_flat_data_size
= i_packet_size
- COMM_HEADER_SIZE
;
620 uint8_t **pp_sections
= psi_unpack_sections( p_flat_data
, i_flat_data_size
);
623 return_error( "Error unpacking PSI" );
629 case RET_PAT
: pat_table_print( pp_sections
, psi_print
, NULL
, i_print_type
); break;
630 case RET_CAT
: cat_table_print( pp_sections
, psi_print
, NULL
, i_print_type
); break;
631 case RET_NIT
: nit_table_print( pp_sections
, psi_print
, NULL
, psi_iconv
, NULL
, i_print_type
); break;
632 case RET_SDT
: sdt_table_print( pp_sections
, psi_print
, NULL
, psi_iconv
, NULL
, i_print_type
); break;
633 default: break; /* Can't happen */
636 psi_table_free( pp_sections
);
642 case RET_EIT_SCHEDULE
:
644 uint8_t *p_eit_data
= p_buffer
+ COMM_HEADER_SIZE
;
645 unsigned int i_eit_data_size
= i_received
- COMM_HEADER_SIZE
;
646 print_eit( p_eit_data
, i_eit_data_size
, psi_print
, NULL
, psi_iconv
, NULL
, i_print_type
);
652 pmt_print( p_data
, psi_print
, NULL
, psi_iconv
, NULL
, i_print_type
);
659 print_pid( i_pid
, (ts_pid_info_t
*)p_data
);
666 print_pids( p_data
);
670 #ifdef HAVE_DVB_SUPPORT
671 case RET_FRONTEND_STATUS
:
674 struct ret_frontend_status
*p_ret
=
675 (struct ret_frontend_status
*)&p_buffer
[COMM_HEADER_SIZE
];
676 if ( i_packet_size
!= COMM_HEADER_SIZE
+ sizeof(struct ret_frontend_status
) )
677 return_error( "Bad frontend status" );
679 if ( i_print_type
== PRINT_XML
)
680 printf("<FRONTEND>\n");
682 #define PRINT_TYPE( x ) \
684 if ( i_print_type == PRINT_XML ) \
685 printf( " <TYPE type=\"%s\"/>\n", STRINGIFY(x) ); \
687 printf( "type: %s\n", STRINGIFY(x) ); \
689 switch ( p_ret
->info
.type
)
691 case FE_QPSK
: PRINT_TYPE(QPSK
); break;
692 case FE_QAM
: PRINT_TYPE(QAM
); break;
693 case FE_OFDM
: PRINT_TYPE(OFDM
); break;
694 case FE_ATSC
: PRINT_TYPE(ATSC
); break;
695 default : PRINT_TYPE(UNKNOWN
); break;
699 #define PRINT_INFO( x ) \
701 if ( i_print_type == PRINT_XML ) \
702 printf( " <SETTING %s=\"%u\"/>\n", STRINGIFY(x), p_ret->info.x ); \
704 printf( "%s: %u\n", STRINGIFY(x), p_ret->info.x ); \
707 if ( i_print_type
== PRINT_XML
)
708 printf( " <SETTING name=\"%s\"/>\n", p_ret
->info
.name
);
710 printf( "name: %s\n", p_ret
->info
.name
);
712 PRINT_INFO( frequency_min
);
713 PRINT_INFO( frequency_max
);
714 PRINT_INFO( frequency_stepsize
);
715 PRINT_INFO( frequency_tolerance
);
716 PRINT_INFO( symbol_rate_min
);
717 PRINT_INFO( symbol_rate_max
);
718 PRINT_INFO( symbol_rate_tolerance
);
719 PRINT_INFO( notifier_delay
);
722 if ( i_print_type
== PRINT_TEXT
)
723 printf("\ncapability list:\n");
725 #define PRINT_CAPS( x ) \
727 if ( p_ret->info.caps & (FE_##x) ) { \
728 if ( i_print_type == PRINT_XML ) { \
729 printf( " <CAPABILITY %s=\"1\"/>\n", STRINGIFY(x) ); \
731 printf( "%s\n", STRINGIFY(x) ); \
735 PRINT_CAPS( IS_STUPID
);
736 PRINT_CAPS( CAN_INVERSION_AUTO
);
737 PRINT_CAPS( CAN_FEC_1_2
);
738 PRINT_CAPS( CAN_FEC_2_3
);
739 PRINT_CAPS( CAN_FEC_3_4
);
740 PRINT_CAPS( CAN_FEC_4_5
);
741 PRINT_CAPS( CAN_FEC_5_6
);
742 PRINT_CAPS( CAN_FEC_6_7
);
743 PRINT_CAPS( CAN_FEC_7_8
);
744 PRINT_CAPS( CAN_FEC_8_9
);
745 PRINT_CAPS( CAN_FEC_AUTO
);
746 PRINT_CAPS( CAN_QPSK
);
747 PRINT_CAPS( CAN_QAM_16
);
748 PRINT_CAPS( CAN_QAM_32
);
749 PRINT_CAPS( CAN_QAM_64
);
750 PRINT_CAPS( CAN_QAM_128
);
751 PRINT_CAPS( CAN_QAM_256
);
752 PRINT_CAPS( CAN_QAM_AUTO
);
753 PRINT_CAPS( CAN_TRANSMISSION_MODE_AUTO
);
754 PRINT_CAPS( CAN_BANDWIDTH_AUTO
);
755 PRINT_CAPS( CAN_GUARD_INTERVAL_AUTO
);
756 PRINT_CAPS( CAN_HIERARCHY_AUTO
);
757 PRINT_CAPS( CAN_MUTE_TS
);
759 #if DVBAPI_VERSION >= 301
760 PRINT_CAPS( CAN_8VSB
);
761 PRINT_CAPS( CAN_16VSB
);
762 PRINT_CAPS( NEEDS_BENDING
);
763 PRINT_CAPS( CAN_RECOVER
);
765 #if DVBAPI_VERSION >= 500
766 PRINT_CAPS( HAS_EXTENDED_CAPS
);
768 #if DVBAPI_VERSION >= 501
769 PRINT_CAPS( CAN_2G_MODULATION
);
771 #if DVBAPI_VERSION >= 508
772 PRINT_CAPS( CAN_TURBO_FEC
);
773 PRINT_CAPS( CAN_MULTISTREAM
);
777 if ( i_print_type
== PRINT_TEXT
)
778 printf("\nstatus:\n");
780 #define PRINT_STATUS( x ) \
782 if ( p_ret->i_status & (FE_##x) ) { \
783 if ( i_print_type == PRINT_XML ) { \
784 printf( " <STATUS status=\"%s\"/>\n", STRINGIFY(x) ); \
786 printf( "%s\n", STRINGIFY(x) ); \
790 PRINT_STATUS( HAS_SIGNAL
);
791 PRINT_STATUS( HAS_CARRIER
);
792 PRINT_STATUS( HAS_VITERBI
);
793 PRINT_STATUS( HAS_SYNC
);
794 PRINT_STATUS( HAS_LOCK
);
795 PRINT_STATUS( REINIT
);
798 if ( p_ret
->i_status
& FE_HAS_LOCK
)
800 if ( i_print_type
== PRINT_XML
)
802 printf(" <VALUE bit_error_rate=\"%u\"/>\n", p_ret
->i_ber
);
803 printf(" <VALUE signal_strength=\"%u\"/>\n", p_ret
->i_strength
);
804 printf(" <VALUE SNR=\"%u\"/>\n", p_ret
->i_snr
);
806 printf("\nBit error rate: %u\n", p_ret
->i_ber
);
807 printf("Signal strength: %u\n", p_ret
->i_strength
);
808 printf("SNR: %u\n", p_ret
->i_snr
);
813 if ( i_print_type
== PRINT_XML
)
814 printf("</FRONTEND>\n" );
822 return_error( "Unknown command answer: %u", c_answer
);
825 if (iconv_handle
!= (iconv_t
)-1) {
826 iconv_close(iconv_handle
);
827 iconv_handle
= (iconv_t
)-1;