1 /*****************************************************************************
3 *****************************************************************************
4 * Copyright (C) 2008 VideoLAN
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 *****************************************************************************/
30 #include <sys/types.h>
32 #include <sys/socket.h>
33 #include <netinet/in.h>
34 #include <arpa/inet.h>
49 msg_Raw( NULL
, "DVBlastctl %d.%d.%d%s", VERSION_MAJOR
, VERSION_MINOR
,
50 VERSION_REVISION
, VERSION_EXTRA
);
51 msg_Raw( NULL
, "Usage: dvblastctl -r <remote socket> reload|shutdown|fe_status|mmi_status|mmi_open|mmi_close|mmi_get|mmi_send_text|mmi_send_choice [<CAM slot>] [<text/choice>]" );
55 int main( int i_argc
, char **ppsz_argv
)
57 char psz_client_socket
[L_tmpnam
];
58 char *psz_srv_socket
= NULL
;
62 struct sockaddr_un sun_client
, sun_server
;
63 uint8_t p_buffer
[COMM_BUFFER_SIZE
];
69 static const struct option long_options
[] =
71 {"remote-socket", required_argument
, NULL
, 'r'},
72 {"help", no_argument
, NULL
, 'h'},
76 if ( (c
= getopt_long(i_argc
, ppsz_argv
, "r:h", long_options
, NULL
)) == -1 )
82 psz_srv_socket
= optarg
;
91 if ( ppsz_argv
[optind
] == NULL
|| psz_srv_socket
== NULL
)
94 if ( strcmp(ppsz_argv
[optind
], "reload")
95 && strcmp(ppsz_argv
[optind
], "shutdown")
96 && strcmp(ppsz_argv
[optind
], "fe_status")
97 && strcmp(ppsz_argv
[optind
], "mmi_status")
98 && strcmp(ppsz_argv
[optind
], "mmi_slot_status")
99 && strcmp(ppsz_argv
[optind
], "mmi_open")
100 && strcmp(ppsz_argv
[optind
], "mmi_close")
101 && strcmp(ppsz_argv
[optind
], "mmi_get")
102 && strcmp(ppsz_argv
[optind
], "mmi_send_text")
103 && strcmp(ppsz_argv
[optind
], "mmi_send_choice") )
106 if ( (!strcmp(ppsz_argv
[optind
], "mmi_slot_status")
107 || !strcmp(ppsz_argv
[optind
], "mmi_open")
108 || !strcmp(ppsz_argv
[optind
], "mmi_close")
109 || !strcmp(ppsz_argv
[optind
], "mmi_get")
110 || !strcmp(ppsz_argv
[optind
], "mmi_send_text")
111 || !strcmp(ppsz_argv
[optind
], "mmi_send_choice"))
112 && ppsz_argv
[optind
+ 1] == NULL
)
115 if ( !strcmp(ppsz_argv
[optind
], "mmi_send_choice")
116 && ppsz_argv
[optind
+ 2] == NULL
)
119 #warning expect brain-dead gcc warning about tmpnam here
120 if ( tmpnam(psz_client_socket
) == NULL
)
122 msg_Err( NULL
, "cannot build UNIX socket (%s)", strerror(errno
) );
126 if ( (i_fd
= socket( AF_UNIX
, SOCK_DGRAM
, 0 )) < 0 )
128 msg_Err( NULL
, "cannot create UNIX socket (%s)", strerror(errno
) );
132 setsockopt( i_fd
, SOL_SOCKET
, SO_RCVBUF
, &i
, sizeof(i
) );
134 memset( &sun_client
, 0, sizeof(sun_client
) );
135 sun_client
.sun_family
= AF_UNIX
;
136 strncpy( sun_client
.sun_path
, psz_client_socket
,
137 sizeof(sun_client
.sun_path
) );
138 sun_client
.sun_path
[sizeof(sun_client
.sun_path
) - 1] = '\0';
141 if ( bind( i_fd
, (struct sockaddr
*)&sun_client
,
142 SUN_LEN(&sun_client
) ) < 0 )
144 msg_Err( NULL
, "cannot bind (%s)", strerror(errno
) );
151 memset( &sun_server
, 0, sizeof(sun_server
) );
152 sun_server
.sun_family
= AF_UNIX
;
153 strncpy( sun_server
.sun_path
, psz_srv_socket
, sizeof(sun_server
.sun_path
) );
154 sun_server
.sun_path
[sizeof(sun_server
.sun_path
) - 1] = '\0';
156 p_buffer
[0] = COMM_HEADER_MAGIC
;
159 i_size
= COMM_HEADER_SIZE
;
161 if ( !strcmp(ppsz_argv
[optind
], "reload") )
162 p_buffer
[1] = CMD_RELOAD
;
163 else if ( !strcmp(ppsz_argv
[optind
], "shutdown") )
164 p_buffer
[1] = CMD_SHUTDOWN
;
165 else if ( !strcmp(ppsz_argv
[optind
], "fe_status") )
166 p_buffer
[1] = CMD_FRONTEND_STATUS
;
167 else if ( !strcmp(ppsz_argv
[optind
], "mmi_status") )
168 p_buffer
[1] = CMD_MMI_STATUS
;
171 p_buffer
[4] = atoi(ppsz_argv
[optind
+ 1]);
172 i_size
= COMM_HEADER_SIZE
+ 1;
174 if ( !strcmp(ppsz_argv
[optind
], "mmi_slot_status") )
175 p_buffer
[1] = CMD_MMI_SLOT_STATUS
;
176 else if ( !strcmp(ppsz_argv
[optind
], "mmi_open") )
177 p_buffer
[1] = CMD_MMI_OPEN
;
178 else if ( !strcmp(ppsz_argv
[optind
], "mmi_close") )
179 p_buffer
[1] = CMD_MMI_CLOSE
;
180 else if ( !strcmp(ppsz_argv
[optind
], "mmi_get") )
181 p_buffer
[1] = CMD_MMI_RECV
;
184 struct cmd_mmi_send
*p_cmd
= (struct cmd_mmi_send
*)&p_buffer
[4];
185 p_buffer
[1] = CMD_MMI_SEND
;
186 p_cmd
->i_slot
= atoi(ppsz_argv
[optind
+ 1]);
188 if ( !strcmp(ppsz_argv
[optind
], "mmi_send_text") )
190 en50221_mmi_object_t object
;
191 object
.i_object_type
= EN50221_MMI_ANSW
;
192 if ( ppsz_argv
[optind
+ 2] == NULL
193 || ppsz_argv
[optind
+ 2][0] == '\0' )
195 object
.u
.answ
.b_ok
= 0;
196 object
.u
.answ
.psz_answ
= "";
200 object
.u
.answ
.b_ok
= 1;
201 object
.u
.answ
.psz_answ
= ppsz_argv
[optind
+ 2];
203 i_size
= COMM_BUFFER_SIZE
- COMM_HEADER_SIZE
204 - ((void *)&p_cmd
->object
- (void *)p_cmd
);
205 if ( en50221_SerializeMMIObject( (uint8_t *)&p_cmd
->object
,
206 &i_size
, &object
) == -1 )
208 msg_Err( NULL
, "buffer too small" );
210 unlink( psz_client_socket
);
213 i_size
+= COMM_HEADER_SIZE
214 + ((void *)&p_cmd
->object
- (void *)p_cmd
);
216 else /* mmi_send_choice */
218 i_size
= COMM_HEADER_SIZE
+ sizeof(struct cmd_mmi_send
);
219 p_cmd
->object
.i_object_type
= EN50221_MMI_MENU_ANSW
;
220 p_cmd
->object
.u
.menu_answ
.i_choice
221 = atoi(ppsz_argv
[optind
+ 2]);
226 if ( sendto( i_fd
, p_buffer
, i_size
, 0, (struct sockaddr
*)&sun_server
,
227 SUN_LEN(&sun_server
) ) < 0 )
229 msg_Err( NULL
, "cannot send comm socket (%s)", strerror(errno
) );
231 unlink( psz_client_socket
);
235 i_size
= recv( i_fd
, p_buffer
, COMM_BUFFER_SIZE
, 0 );
237 unlink( psz_client_socket
);
238 if ( i_size
< COMM_HEADER_SIZE
)
240 msg_Err( NULL
, "cannot recv comm socket (%d:%s)", i_size
,
245 if ( p_buffer
[0] != COMM_HEADER_MAGIC
)
247 msg_Err( NULL
, "wrong protocol version 0x%x", p_buffer
[0] );
251 switch ( p_buffer
[1] )
262 msg_Err( NULL
, "request failed" );
267 msg_Err( NULL
, "internal error" );
271 case RET_FRONTEND_STATUS
:
273 struct ret_frontend_status
*p_ret
=
274 (struct ret_frontend_status
*)&p_buffer
[COMM_HEADER_SIZE
];
275 if ( i_size
!= COMM_HEADER_SIZE
+ sizeof(struct ret_frontend_status
) )
277 msg_Err( NULL
, "bad frontend status" );
281 switch ( p_ret
->info
.type
)
283 case FE_QPSK
: printf("type: QPSK\n"); break;
284 case FE_QAM
: printf("type: QAM\n"); break;
285 case FE_OFDM
: printf("type: OFDM\n"); break;
286 default: printf("type: UNKNOWN\n"); break;
289 #define PRINT_INFO( x ) \
290 printf( STRINGIFY(x) ": %u\n", p_ret->info.x );
291 PRINT_INFO( frequency_min
);
292 PRINT_INFO( frequency_max
);
293 PRINT_INFO( frequency_stepsize
);
294 PRINT_INFO( frequency_tolerance
);
295 PRINT_INFO( symbol_rate_min
);
296 PRINT_INFO( symbol_rate_max
);
297 PRINT_INFO( symbol_rate_tolerance
);
298 PRINT_INFO( notifier_delay
);
301 printf("\ncapability list:\n");
303 #define PRINT_CAPS( x ) \
304 if ( p_ret->info.caps & (FE_##x) ) \
305 printf( STRINGIFY(x) "\n" );
306 PRINT_CAPS( IS_STUPID
);
307 PRINT_CAPS( CAN_INVERSION_AUTO
);
308 PRINT_CAPS( CAN_FEC_1_2
);
309 PRINT_CAPS( CAN_FEC_2_3
);
310 PRINT_CAPS( CAN_FEC_3_4
);
311 PRINT_CAPS( CAN_FEC_4_5
);
312 PRINT_CAPS( CAN_FEC_5_6
);
313 PRINT_CAPS( CAN_FEC_6_7
);
314 PRINT_CAPS( CAN_FEC_7_8
);
315 PRINT_CAPS( CAN_FEC_8_9
);
316 PRINT_CAPS( CAN_FEC_AUTO
);
317 PRINT_CAPS( CAN_QPSK
);
318 PRINT_CAPS( CAN_QAM_16
);
319 PRINT_CAPS( CAN_QAM_32
);
320 PRINT_CAPS( CAN_QAM_64
);
321 PRINT_CAPS( CAN_QAM_128
);
322 PRINT_CAPS( CAN_QAM_256
);
323 PRINT_CAPS( CAN_QAM_AUTO
);
324 PRINT_CAPS( CAN_TRANSMISSION_MODE_AUTO
);
325 PRINT_CAPS( CAN_BANDWIDTH_AUTO
);
326 PRINT_CAPS( CAN_GUARD_INTERVAL_AUTO
);
327 PRINT_CAPS( CAN_HIERARCHY_AUTO
);
328 PRINT_CAPS( CAN_MUTE_TS
);
330 #define DVBAPI_VERSION ((DVB_API_VERSION)*100+(DVB_API_VERSION_MINOR))
332 #if DVBAPI_VERSION >= 301
333 PRINT_CAPS( CAN_8VSB
);
334 PRINT_CAPS( CAN_16VSB
);
335 PRINT_CAPS( NEEDS_BENDING
);
336 PRINT_CAPS( CAN_RECOVER
);
338 #if DVBAPI_VERSION >= 500
339 PRINT_CAPS( HAS_EXTENDED_CAPS
);
341 #if DVBAPI_VERSION >= 501
342 PRINT_CAPS( CAN_2G_MODULATION
);
346 printf("\nstatus:\n");
348 #define PRINT_STATUS( x ) \
349 if ( p_ret->i_status & (FE_##x) ) \
350 printf( STRINGIFY(x) "\n" );
351 PRINT_STATUS( HAS_SIGNAL
);
352 PRINT_STATUS( HAS_CARRIER
);
353 PRINT_STATUS( HAS_VITERBI
);
354 PRINT_STATUS( HAS_SYNC
);
355 PRINT_STATUS( HAS_LOCK
);
356 PRINT_STATUS( REINIT
);
359 if ( p_ret
->i_status
& FE_HAS_LOCK
)
361 printf("\nBit error rate: %d\n", p_ret
->i_ber
);
362 printf("Signal strength: %d\n", p_ret
->i_strength
);
363 printf("SNR: %d\n", p_ret
->i_snr
);
373 struct ret_mmi_status
*p_ret
=
374 (struct ret_mmi_status
*)&p_buffer
[COMM_HEADER_SIZE
];
375 if ( i_size
!= COMM_HEADER_SIZE
+ sizeof(struct ret_mmi_status
) )
377 msg_Err( NULL
, "bad MMI status" );
381 printf("CA interface with %d %s, type:\n", p_ret
->caps
.slot_num
,
382 p_ret
->caps
.slot_num
== 1 ? "slot" : "slots");
383 #define PRINT_CAPS( x, s ) \
384 if ( p_ret->caps.slot_type & (CA_##x) ) \
386 PRINT_CAPS( CI
, "CI high level interface" );
387 PRINT_CAPS( CI_LINK
, "CI link layer level interface" );
388 PRINT_CAPS( CI_PHYS
, "CI physical layer level interface (not supported)" );
389 PRINT_CAPS( DESCR
, "built-in descrambler" );
390 PRINT_CAPS( SC
, "simple smartcard interface" );
393 printf("\n%d available %s\n", p_ret
->caps
.descr_num
,
394 p_ret
->caps
.descr_num
== 1 ? "descrambler (key)" :
395 "descramblers (keys)");
396 #define PRINT_DESC( x ) \
397 if ( p_ret->caps.descr_type & (CA_##x) ) \
398 printf( STRINGIFY(x) "\n" );
404 exit( p_ret
->caps
.slot_num
);
408 case RET_MMI_SLOT_STATUS
:
410 struct ret_mmi_slot_status
*p_ret
=
411 (struct ret_mmi_slot_status
*)&p_buffer
[COMM_HEADER_SIZE
];
412 if ( i_size
< COMM_HEADER_SIZE
+ sizeof(struct ret_mmi_slot_status
) )
414 msg_Err( NULL
, "bad MMI slot status" );
418 printf("CA slot #%u: ", p_ret
->sinfo
.num
);
420 #define PRINT_TYPE( x, s ) \
421 if ( p_ret->sinfo.type & (CA_##x) ) \
424 PRINT_TYPE( CI
, "high level, " );
425 PRINT_TYPE( CI_LINK
, "link layer level, " );
426 PRINT_TYPE( CI_PHYS
, "physical layer level, " );
429 if ( p_ret
->sinfo
.flags
& CA_CI_MODULE_READY
)
431 printf("module present and ready\n");
435 if ( p_ret
->sinfo
.flags
& CA_CI_MODULE_PRESENT
)
436 printf("module present, not ready\n");
438 printf("module not present\n");
446 struct ret_mmi_recv
*p_ret
=
447 (struct ret_mmi_recv
*)&p_buffer
[COMM_HEADER_SIZE
];
448 if ( i_size
< COMM_HEADER_SIZE
+ sizeof(struct ret_mmi_recv
) )
450 msg_Err( NULL
, "bad MMI recv" );
454 en50221_UnserializeMMIObject( &p_ret
->object
, i_size
455 - COMM_HEADER_SIZE
- ((void *)&p_ret
->object
- (void *)p_ret
) );
457 switch ( p_ret
->object
.i_object_type
)
459 case EN50221_MMI_ENQ
:
460 printf("%s\n", p_ret
->object
.u
.enq
.psz_text
);
461 printf("(empty to cancel)\n");
462 exit(p_ret
->object
.u
.enq
.b_blind
? 253 : 254);
465 case EN50221_MMI_MENU
:
466 printf("%s\n", p_ret
->object
.u
.menu
.psz_title
);
467 printf("%s\n", p_ret
->object
.u
.menu
.psz_subtitle
);
468 printf("0 - Cancel\n");
469 for ( i
= 0; i
< p_ret
->object
.u
.menu
.i_choices
; i
++ )
470 printf("%d - %s\n", i
+ 1,
471 p_ret
->object
.u
.menu
.ppsz_choices
[i
]);
472 printf("%s\n", p_ret
->object
.u
.menu
.psz_bottom
);
473 exit(p_ret
->object
.u
.menu
.i_choices
);
476 case EN50221_MMI_LIST
:
477 printf("%s\n", p_ret
->object
.u
.menu
.psz_title
);
478 printf("%s\n", p_ret
->object
.u
.menu
.psz_subtitle
);
479 for ( i
= 0; i
< p_ret
->object
.u
.menu
.i_choices
; i
++ )
480 printf("%s\n", p_ret
->object
.u
.menu
.ppsz_choices
[i
]);
481 printf("%s\n", p_ret
->object
.u
.menu
.psz_bottom
);
482 printf("(0 to cancel)\n");
487 printf("unknown MMI object\n");
497 msg_Err( NULL
, "wrong answer %u", p_buffer
[1] );