* demux.c: Fix continuity counter errors for outgoing EITs. Also fix generation of...
[dvblast.git] / dvblastctl.c
blob125709bb6a52f7e56e7b031bf006d6b426545d34
1 /*****************************************************************************
2 * dvblastctl.c
3 *****************************************************************************
4 * Copyright (C) 2008 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 <stdio.h>
26 #include <unistd.h>
27 #include <stdint.h>
28 #include <stdbool.h>
29 #include <string.h>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <sys/socket.h>
33 #include <netinet/in.h>
34 #include <arpa/inet.h>
35 #include <sys/un.h>
36 #include <errno.h>
37 #include <getopt.h>
39 #include "dvblast.h"
40 #include "en50221.h"
41 #include "comm.h"
42 #include "version.h"
44 int i_verbose = 3;
45 int i_syslog = 0;
47 void usage()
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>]" );
52 exit(1);
55 int main( int i_argc, char **ppsz_argv )
57 char psz_client_socket[L_tmpnam];
58 char *psz_srv_socket = NULL;
59 int i_fd, i_mask;
60 int i = 65535;
61 ssize_t i_size;
62 struct sockaddr_un sun_client, sun_server;
63 uint8_t p_buffer[COMM_BUFFER_SIZE];
65 for ( ; ; )
67 int c;
69 static const struct option long_options[] =
71 {"remote-socket", required_argument, NULL, 'r'},
72 {"help", no_argument, NULL, 'h'},
73 {0, 0, 0, 0}
76 if ( (c = getopt_long(i_argc, ppsz_argv, "r:h", long_options, NULL)) == -1 )
77 break;
79 switch ( c )
81 case 'r':
82 psz_srv_socket = optarg;
83 break;
85 case 'h':
86 default:
87 usage();
91 if ( ppsz_argv[optind] == NULL || psz_srv_socket == NULL )
92 usage();
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") )
104 usage();
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 )
113 usage();
115 if ( !strcmp(ppsz_argv[optind], "mmi_send_choice")
116 && ppsz_argv[optind + 2] == NULL )
117 usage();
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) );
123 return -1;
126 if ( (i_fd = socket( AF_UNIX, SOCK_DGRAM, 0 )) < 0 )
128 msg_Err( NULL, "cannot create UNIX socket (%s)", strerror(errno) );
129 return -1;
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';
139 i_mask = umask(077);
141 if ( bind( i_fd, (struct sockaddr *)&sun_client,
142 SUN_LEN(&sun_client) ) < 0 )
144 msg_Err( NULL, "cannot bind (%s)", strerror(errno) );
145 umask( i_mask );
146 close( i_fd );
147 exit(255);
149 umask( i_mask );
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;
157 p_buffer[2] = 0;
158 p_buffer[3] = 0;
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;
169 else
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;
182 else
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 = "";
198 else
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" );
209 close( i_fd );
210 unlink( psz_client_socket );
211 exit(255);
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) );
230 close( i_fd );
231 unlink( psz_client_socket );
232 exit(255);
235 i_size = recv( i_fd, p_buffer, COMM_BUFFER_SIZE, 0 );
236 close( i_fd );
237 unlink( psz_client_socket );
238 if ( i_size < COMM_HEADER_SIZE )
240 msg_Err( NULL, "cannot recv comm socket (%d:%s)", i_size,
241 strerror(errno) );
242 exit(255);
245 if ( p_buffer[0] != COMM_HEADER_MAGIC )
247 msg_Err( NULL, "wrong protocol version 0x%x", p_buffer[0] );
248 exit(255);
251 switch ( p_buffer[1] )
253 case RET_OK:
254 exit(0);
255 break;
257 case RET_MMI_WAIT:
258 exit(252);
259 break;
261 case RET_ERR:
262 msg_Err( NULL, "request failed" );
263 exit(255);
264 break;
266 case RET_HUH:
267 msg_Err( NULL, "internal error" );
268 exit(255);
269 break;
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" );
278 exit(255);
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 );
299 #undef PRINT_INFO
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 );
337 #endif
338 #if DVBAPI_VERSION >= 500
339 PRINT_CAPS( HAS_EXTENDED_CAPS );
340 #endif
341 #if DVBAPI_VERSION >= 501
342 PRINT_CAPS( CAN_2G_MODULATION );
343 #endif
344 #undef PRINT_CAPS
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 );
357 #undef PRINT_STATUS
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);
364 exit(0);
367 exit(1);
368 break;
371 case RET_MMI_STATUS:
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" );
378 exit(255);
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) ) \
385 printf(s "\n");
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" );
391 #undef PRINT_CAPS
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" );
399 PRINT_DESC( ECD );
400 PRINT_DESC( NDS );
401 PRINT_DESC( DSS );
402 #undef PRINT_DESC
404 exit( p_ret->caps.slot_num );
405 break;
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" );
415 exit(255);
418 printf("CA slot #%u: ", p_ret->sinfo.num);
420 #define PRINT_TYPE( x, s ) \
421 if ( p_ret->sinfo.type & (CA_##x) ) \
422 printf(s);
424 PRINT_TYPE( CI, "high level, " );
425 PRINT_TYPE( CI_LINK, "link layer level, " );
426 PRINT_TYPE( CI_PHYS, "physical layer level, " );
427 #undef PRINT_TYPE
429 if ( p_ret->sinfo.flags & CA_CI_MODULE_READY )
431 printf("module present and ready\n");
432 exit(0);
435 if ( p_ret->sinfo.flags & CA_CI_MODULE_PRESENT )
436 printf("module present, not ready\n");
437 else
438 printf("module not present\n");
440 exit(1);
441 break;
444 case RET_MMI_RECV:
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" );
451 exit(255);
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);
463 break;
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);
474 break;
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");
483 exit(0);
484 break;
486 default:
487 printf("unknown MMI object\n");
488 exit(255);
489 break;
492 exit(255);
493 break;
496 default:
497 msg_Err( NULL, "wrong answer %u", p_buffer[1] );
498 exit(255);