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>
41 #include <bitstream/mpeg/psi.h>
42 #include <bitstream/dvb/si.h>
43 #include <bitstream/dvb/si_print.h>
44 #include <bitstream/mpeg/psi_print.h>
54 print_type_t i_print_type
= PRINT_TEXT
;
58 char psz_client_socket
[PATH_MAX
] = {0};
60 static void clean_client_socket() {
66 if ( psz_client_socket
[0] )
68 unlink( psz_client_socket
);
69 psz_client_socket
[0] = '\0';
73 /*****************************************************************************
74 * The following two functions are from biTStream's examples and are under the
75 * WTFPL (see LICENSE.WTFPL).
76 ****************************************************************************/
77 __attribute__ ((format(printf
, 2, 3)))
78 static void psi_print(void *_unused
, const char *psz_format
, ...)
80 char psz_fmt
[strlen(psz_format
) + 2];
82 va_start(args
, psz_format
);
83 strcpy(psz_fmt
, psz_format
);
84 strcat(psz_fmt
, "\n");
85 vprintf(psz_fmt
, args
);
88 __attribute__ ((format(printf
, 1, 2)))
89 void return_error( const char *psz_format
, ... )
94 clean_client_socket();
96 va_start( args
, psz_format
);
97 if ( i_print_type
== PRINT_XML
)
98 snprintf( psz_fmt
, sizeof(psz_fmt
) - 1, "<ERROR msg=\"%s\"/>\n", psz_format
);
100 snprintf( psz_fmt
, sizeof(psz_fmt
) - 1, "ERROR: %s\n", psz_format
);
101 psz_fmt
[sizeof(psz_fmt
) - 1] = '\0';
102 vfprintf( stderr
, psz_fmt
, args
);
106 static char *iconv_append_null(const char *p_string
, size_t i_length
)
108 char *psz_string
= malloc(i_length
+ 1);
109 memcpy(psz_string
, p_string
, i_length
);
110 psz_string
[i_length
] = '\0';
114 char *psi_iconv(void *_unused
, const char *psz_encoding
,
115 char *p_string
, size_t i_length
)
117 return iconv_append_null(p_string
, i_length
);
120 void print_pids_header( void )
122 if ( i_print_type
== PRINT_XML
)
126 void print_pids_footer( void )
128 if ( i_print_type
== PRINT_XML
)
132 void print_pid(uint16_t i_pid
, ts_pid_info_t
*p_info
)
134 if ( p_info
->i_packets
== 0 )
136 if ( i_print_type
== PRINT_TEXT
)
137 printf("pid %d packn %lu ccerr %lu tserr %lu scramble %d Bps %lu seen %"PRId64
"\n",
141 p_info
->i_transport_errors
,
142 p_info
->i_scrambling
,
143 p_info
->i_bytes_per_sec
,
144 now
- p_info
->i_last_packet_ts
147 printf("<PID pid=\"%d\" packn=\"%lu\" ccerr=\"%lu\" tserr=\"%lu\" scramble=\"%d\" Bps=\"%lu\" seen=\"%"PRId64
"\" />\n",
151 p_info
->i_transport_errors
,
152 p_info
->i_scrambling
,
153 p_info
->i_bytes_per_sec
,
154 now
- p_info
->i_last_packet_ts
158 void print_pids( uint8_t *p_data
)
162 for ( i_pid
= 0; i_pid
< MAX_PIDS
; i_pid
++ ) {
163 ts_pid_info_t
*p_info
= (ts_pid_info_t
*)(p_data
+ i_pid
* sizeof(ts_pid_info_t
));
164 print_pid( i_pid
, p_info
);
169 struct dvblastctl_option
{
175 static const struct dvblastctl_option options
[] =
177 { "reload", 0, CMD_RELOAD
},
178 { "shutdown", 0, CMD_SHUTDOWN
},
180 { "fe_status", 0, CMD_FRONTEND_STATUS
},
181 { "mmi_status", 0, CMD_MMI_STATUS
},
183 { "mmi_slot_status", 1, CMD_MMI_SLOT_STATUS
}, /* arg: slot */
184 { "mmi_open", 1, CMD_MMI_OPEN
}, /* arg: slot */
185 { "mmi_close", 1, CMD_MMI_CLOSE
}, /* arg: slot */
186 { "mmi_get", 1, CMD_MMI_RECV
}, /* arg: slot */
187 { "mmi_send_text", 1, CMD_MMI_SEND_TEXT
}, /* arg: slot, en50221_mmi_object_t */
188 { "mmi_send_choice", 2, CMD_MMI_SEND_CHOICE
}, /* arg: slot, en50221_mmi_object_t */
190 { "get_pat", 0, CMD_GET_PAT
},
191 { "get_cat", 0, CMD_GET_CAT
},
192 { "get_nit", 0, CMD_GET_NIT
},
193 { "get_sdt", 0, CMD_GET_SDT
},
194 { "get_pmt", 1, CMD_GET_PMT
}, /* arg: service_id (uint16_t) */
195 { "get_pids", 0, CMD_GET_PIDS
},
196 { "get_pid", 1, CMD_GET_PID
}, /* arg: pid (uint16_t) */
203 printf("DVBlastctl %d.%d.%d (%s)\n", VERSION_MAJOR
, VERSION_MINOR
,
204 VERSION_REVISION
, VERSION_EXTRA
);
205 printf("Usage: dvblastctl -r <remote socket> [-x <text|xml>] [cmd]\n");
206 printf("Options:\n");
207 printf(" -r --remote-socket <name> Set socket name to <name>.\n" );
208 printf(" -x --print <text|xml> Choose output format for info commands.\n" );
209 printf("Control commands:\n");
210 printf(" reload Reload configuration.\n");
211 printf(" shutdown Shutdown DVBlast.\n");
212 printf("Status commands:\n");
213 printf(" fe_status Read frontend status information.\n");
214 printf(" mmi_status Read CAM status.\n");
215 printf("MMI commands:\n");
216 printf(" mmi_slot_status <slot> Read MMI slot status.\n");
217 printf(" mmi_open <slot> Open MMI slot.\n");
218 printf(" mmi_close <slot> Close MMI slot.\n");
219 printf(" mmi_get <slot> Read MMI slot.\n");
220 printf(" mmi_send_text <slot> <text> Send text to MMI slot.\n");
221 printf(" mmi_send_choice <slot> <choice> Send choice to MMI slot.\n");
222 printf("Demux info commands:\n");
223 printf(" get_pat Return last PAT table.\n");
224 printf(" get_cat Return last CAT table.\n");
225 printf(" get_nit Return last NIT table.\n");
226 printf(" get_sdt Return last SDT table.\n");
227 printf(" get_pmt <service_id> Return last PMT table.\n");
228 printf(" get_pids Return info about all pids.\n");
229 printf(" get_pid <pid> Return info for chosen pid only.\n");
234 int main( int i_argc
, char **ppsz_argv
)
236 char *client_socket_tmpl
= "dvblastctl.clientsock.XXXXXX";
237 char *psz_srv_socket
= NULL
;
239 char *p_cmd
, *p_arg1
= NULL
, *p_arg2
= NULL
;
241 struct sockaddr_un sun_client
, sun_server
;
242 uint8_t p_buffer
[COMM_BUFFER_SIZE
];
243 uint8_t *p_data
= p_buffer
+ COMM_HEADER_SIZE
;
245 struct dvblastctl_option opt
= { 0, 0, 0 };
251 static const struct option long_options
[] =
253 {"remote-socket", required_argument
, NULL
, 'r'},
254 {"print", required_argument
, NULL
, 'x'},
255 {"help", no_argument
, NULL
, 'h'},
259 if ( (c
= getopt_long(i_argc
, ppsz_argv
, "r:x:h", long_options
, NULL
)) == -1 )
265 psz_srv_socket
= optarg
;
269 if ( !strcmp(optarg
, "text") )
270 i_print_type
= PRINT_TEXT
;
271 else if ( !strcmp(optarg
, "xml") )
272 i_print_type
= PRINT_XML
;
274 msg_Warn( NULL
, "unrecognized print type %s", optarg
);
275 /* Make stdout line-buffered */
276 setvbuf(stdout
, NULL
, _IOLBF
, 0);
285 /* Validate commands */
286 #define usage_error(msg, ...) \
288 msg_Err( NULL, msg, ##__VA_ARGS__ ); \
291 p_cmd
= ppsz_argv
[optind
];
292 p_arg1
= ppsz_argv
[optind
+ 1];
293 p_arg2
= ppsz_argv
[optind
+ 2];
295 if ( !psz_srv_socket
)
296 usage_error( "Remote socket is not set.\n" );
299 usage_error( "Command is not set.\n" );
303 if ( streq(ppsz_argv
[optind
], options
[i
].opt
) )
308 } while ( options
[++i
].opt
);
311 usage_error( "Unknown command: %s\n", p_cmd
);
313 if ( opt
.nparams
== 1 && !p_arg1
)
314 usage_error( "%s option needs parameter.\n", opt
.opt
);
316 if ( opt
.nparams
== 2 && (!p_arg1
|| !p_arg2
) )
317 usage_error( "%s option needs two parameters.\n", opt
.opt
);
320 /* Create client socket name */
321 char *tmpdir
= getenv("TMPDIR");
322 snprintf( psz_client_socket
, PATH_MAX
- 1, "%s/%s",
323 tmpdir
? tmpdir
: "/tmp", client_socket_tmpl
);
324 psz_client_socket
[PATH_MAX
- 1] = '\0';
326 int tmp_fd
= mkstemp(psz_client_socket
);
329 unlink(psz_client_socket
);
331 return_error( "Cannot build UNIX socket %s (%s)", psz_client_socket
, strerror(errno
) );
334 if ( (i_fd
= socket( AF_UNIX
, SOCK_DGRAM
, 0 )) < 0 )
335 return_error( "Cannot create UNIX socket (%s)", strerror(errno
) );
337 i
= COMM_MAX_MSG_CHUNK
;
338 setsockopt( i_fd
, SOL_SOCKET
, SO_RCVBUF
, &i
, sizeof(i
) );
340 memset( &sun_client
, 0, sizeof(sun_client
) );
341 sun_client
.sun_family
= AF_UNIX
;
342 strncpy( sun_client
.sun_path
, psz_client_socket
,
343 sizeof(sun_client
.sun_path
) );
344 sun_client
.sun_path
[sizeof(sun_client
.sun_path
) - 1] = '\0';
346 if ( bind( i_fd
, (struct sockaddr
*)&sun_client
,
347 SUN_LEN(&sun_client
) ) < 0 )
348 return_error( "Cannot bind (%s)", strerror(errno
) );
350 memset( &sun_server
, 0, sizeof(sun_server
) );
351 sun_server
.sun_family
= AF_UNIX
;
352 strncpy( sun_server
.sun_path
, psz_srv_socket
, sizeof(sun_server
.sun_path
) );
353 sun_server
.sun_path
[sizeof(sun_server
.sun_path
) - 1] = '\0';
355 p_buffer
[0] = COMM_HEADER_MAGIC
;
356 p_buffer
[1] = opt
.cmd
;
357 memset( p_buffer
+ 2, 0, COMM_HEADER_SIZE
- 2 );
358 i_size
= COMM_HEADER_SIZE
;
360 /* Handle commands that send parameters */
366 case CMD_FRONTEND_STATUS
:
373 /* These commands need no special handling because they have no parameters */
377 uint16_t i_sid
= atoi(p_arg1
);
378 i_size
= COMM_HEADER_SIZE
+ 2;
379 p_data
[0] = (uint8_t)((i_sid
>> 8) & 0xff);
380 p_data
[1] = (uint8_t)(i_sid
& 0xff);
385 i_pid
= (uint16_t)atoi(p_arg1
);
386 i_size
= COMM_HEADER_SIZE
+ 2;
387 p_data
[0] = (uint8_t)((i_pid
>> 8) & 0xff);
388 p_data
[1] = (uint8_t)(i_pid
& 0xff);
391 case CMD_MMI_SEND_TEXT
:
393 struct cmd_mmi_send
*p_cmd
= (struct cmd_mmi_send
*)p_data
;
394 p_cmd
->i_slot
= atoi(p_arg1
);
396 en50221_mmi_object_t object
;
397 object
.i_object_type
= EN50221_MMI_ANSW
;
398 if ( !p_arg2
|| p_arg2
[0] == '\0' )
400 object
.u
.answ
.b_ok
= 0;
401 object
.u
.answ
.psz_answ
= "";
405 object
.u
.answ
.b_ok
= 1;
406 object
.u
.answ
.psz_answ
= p_arg2
;
408 i_size
= COMM_BUFFER_SIZE
- COMM_HEADER_SIZE
409 - ((void *)&p_cmd
->object
- (void *)p_cmd
);
410 if ( en50221_SerializeMMIObject( (uint8_t *)&p_cmd
->object
,
411 &i_size
, &object
) == -1 )
412 return_error( "Comm buffer is too small" );
414 i_size
+= COMM_HEADER_SIZE
415 + ((void *)&p_cmd
->object
- (void *)p_cmd
);
418 case CMD_MMI_SEND_CHOICE
:
420 struct cmd_mmi_send
*p_cmd
= (struct cmd_mmi_send
*)p_data
;
421 p_cmd
->i_slot
= atoi(p_arg1
);
423 i_size
= COMM_HEADER_SIZE
+ sizeof(struct cmd_mmi_send
);
424 p_cmd
->object
.i_object_type
= EN50221_MMI_MENU_ANSW
;
425 p_cmd
->object
.u
.menu_answ
.i_choice
= atoi(p_arg2
);
428 case CMD_MMI_SLOT_STATUS
:
433 p_data
[0] = atoi(p_arg1
);
434 i_size
= COMM_HEADER_SIZE
+ 1;
438 /* This should not happen */
439 return_error( "Unhandled option (%d)", opt
.cmd
);
442 /* Send command and receive answer */
443 if ( sendto( i_fd
, p_buffer
, i_size
, 0, (struct sockaddr
*)&sun_server
,
444 SUN_LEN(&sun_server
) ) < 0 )
445 return_error( "Cannot send comm socket (%s)", strerror(errno
) );
447 uint32_t i_packet_size
= 0, i_received
= 0;
449 i_size
= recv( i_fd
, p_buffer
+ i_received
, COMM_MAX_MSG_CHUNK
, 0 );
452 if ( !i_packet_size
) {
453 i_packet_size
= *((uint32_t *)&p_buffer
[4]);
454 if ( i_packet_size
> COMM_BUFFER_SIZE
) {
459 i_received
+= i_size
;
460 } while ( i_received
< i_packet_size
);
462 clean_client_socket();
463 if ( i_size
< COMM_HEADER_SIZE
)
464 return_error( "Cannot recv from comm socket, size:%zd (%s)", i_size
, strerror(errno
) );
467 if ( p_buffer
[0] != COMM_HEADER_MAGIC
)
468 return_error( "Wrong protocol version 0x%x", p_buffer
[0] );
472 ctl_cmd_answer_t c_answer
= p_buffer
[1];
483 return_error( "Request failed" );
487 return_error( "Internal error" );
491 return_error( "No data" );
499 uint8_t *p_flat_data
= p_buffer
+ COMM_HEADER_SIZE
;
500 unsigned int i_flat_data_size
= i_size
- COMM_HEADER_SIZE
;
501 uint8_t **pp_sections
= psi_unpack_sections( p_flat_data
, i_flat_data_size
);
505 case RET_PAT
: pat_table_print( pp_sections
, psi_print
, NULL
, i_print_type
); break;
506 case RET_CAT
: cat_table_print( pp_sections
, psi_print
, NULL
, i_print_type
); break;
507 case RET_NIT
: nit_table_print( pp_sections
, psi_print
, NULL
, psi_iconv
, NULL
, i_print_type
); break;
508 case RET_SDT
: sdt_table_print( pp_sections
, psi_print
, NULL
, psi_iconv
, NULL
, i_print_type
); break;
509 default: break; /* Can't happen */
512 psi_table_free( pp_sections
);
519 pmt_print( p_data
, psi_print
, NULL
, psi_iconv
, NULL
, i_print_type
);
526 print_pid( i_pid
, (ts_pid_info_t
*)p_data
);
533 print_pids( p_data
);
537 case RET_FRONTEND_STATUS
:
540 struct ret_frontend_status
*p_ret
=
541 (struct ret_frontend_status
*)&p_buffer
[COMM_HEADER_SIZE
];
542 if ( i_size
!= COMM_HEADER_SIZE
+ sizeof(struct ret_frontend_status
) )
543 return_error( "Bad frontend status" );
545 if ( i_print_type
== PRINT_XML
)
546 printf("<FRONTEND>\n");
548 #define PRINT_TYPE( x ) \
550 if ( i_print_type == PRINT_XML ) \
551 printf( " <TYPE type=\"%s\"/>\n", STRINGIFY(x) ); \
553 printf( "type: %s\n", STRINGIFY(x) ); \
555 switch ( p_ret
->info
.type
)
557 case FE_QPSK
: PRINT_TYPE(QPSK
); break;
558 case FE_QAM
: PRINT_TYPE(QAM
); break;
559 case FE_OFDM
: PRINT_TYPE(OFDM
); break;
560 case FE_ATSC
: PRINT_TYPE(ATSC
); break;
561 default : PRINT_TYPE(UNKNOWN
); break;
565 #define PRINT_INFO( x ) \
567 if ( i_print_type == PRINT_XML ) \
568 printf( " <SETTING %s=\"%u\"/>\n", STRINGIFY(x), p_ret->info.x ); \
570 printf( "%s: %u\n", STRINGIFY(x), p_ret->info.x ); \
572 PRINT_INFO( frequency_min
);
573 PRINT_INFO( frequency_max
);
574 PRINT_INFO( frequency_stepsize
);
575 PRINT_INFO( frequency_tolerance
);
576 PRINT_INFO( symbol_rate_min
);
577 PRINT_INFO( symbol_rate_max
);
578 PRINT_INFO( symbol_rate_tolerance
);
579 PRINT_INFO( notifier_delay
);
582 if ( i_print_type
== PRINT_TEXT
)
583 printf("\ncapability list:\n");
585 #define PRINT_CAPS( x ) \
587 if ( p_ret->info.caps & (FE_##x) ) { \
588 if ( i_print_type == PRINT_XML ) { \
589 printf( " <CAPABILITY %s=\"1\"/>\n", STRINGIFY(x) ); \
591 printf( "%s\n", STRINGIFY(x) ); \
595 PRINT_CAPS( IS_STUPID
);
596 PRINT_CAPS( CAN_INVERSION_AUTO
);
597 PRINT_CAPS( CAN_FEC_1_2
);
598 PRINT_CAPS( CAN_FEC_2_3
);
599 PRINT_CAPS( CAN_FEC_3_4
);
600 PRINT_CAPS( CAN_FEC_4_5
);
601 PRINT_CAPS( CAN_FEC_5_6
);
602 PRINT_CAPS( CAN_FEC_6_7
);
603 PRINT_CAPS( CAN_FEC_7_8
);
604 PRINT_CAPS( CAN_FEC_8_9
);
605 PRINT_CAPS( CAN_FEC_AUTO
);
606 PRINT_CAPS( CAN_QPSK
);
607 PRINT_CAPS( CAN_QAM_16
);
608 PRINT_CAPS( CAN_QAM_32
);
609 PRINT_CAPS( CAN_QAM_64
);
610 PRINT_CAPS( CAN_QAM_128
);
611 PRINT_CAPS( CAN_QAM_256
);
612 PRINT_CAPS( CAN_QAM_AUTO
);
613 PRINT_CAPS( CAN_TRANSMISSION_MODE_AUTO
);
614 PRINT_CAPS( CAN_BANDWIDTH_AUTO
);
615 PRINT_CAPS( CAN_GUARD_INTERVAL_AUTO
);
616 PRINT_CAPS( CAN_HIERARCHY_AUTO
);
617 PRINT_CAPS( CAN_MUTE_TS
);
619 #define DVBAPI_VERSION ((DVB_API_VERSION)*100+(DVB_API_VERSION_MINOR))
621 #if DVBAPI_VERSION >= 301
622 PRINT_CAPS( CAN_8VSB
);
623 PRINT_CAPS( CAN_16VSB
);
624 PRINT_CAPS( NEEDS_BENDING
);
625 PRINT_CAPS( CAN_RECOVER
);
627 #if DVBAPI_VERSION >= 500
628 PRINT_CAPS( HAS_EXTENDED_CAPS
);
630 #if DVBAPI_VERSION >= 501
631 PRINT_CAPS( CAN_2G_MODULATION
);
635 if ( i_print_type
== PRINT_TEXT
)
636 printf("\nstatus:\n");
638 #define PRINT_STATUS( x ) \
640 if ( p_ret->i_status & (FE_##x) ) { \
641 if ( i_print_type == PRINT_XML ) { \
642 printf( " <STATUS status=\"%s\"/>\n", STRINGIFY(x) ); \
644 printf( "%s\n", STRINGIFY(x) ); \
648 PRINT_STATUS( HAS_SIGNAL
);
649 PRINT_STATUS( HAS_CARRIER
);
650 PRINT_STATUS( HAS_VITERBI
);
651 PRINT_STATUS( HAS_SYNC
);
652 PRINT_STATUS( HAS_LOCK
);
653 PRINT_STATUS( REINIT
);
656 if ( p_ret
->i_status
& FE_HAS_LOCK
)
658 if ( i_print_type
== PRINT_XML
)
660 printf(" <VALUE bit_error_rate=\"%d\"/>\n", p_ret
->i_ber
);
661 printf(" <VALUE signal_strength=\"%d\"/>\n", p_ret
->i_strength
);
662 printf(" <VALUE SNR=\"%d\"/>\n", p_ret
->i_snr
);
664 printf("\nBit error rate: %d\n", p_ret
->i_ber
);
665 printf("Signal strength: %d\n", p_ret
->i_strength
);
666 printf("SNR: %d\n", p_ret
->i_snr
);
671 if ( i_print_type
== PRINT_XML
)
672 printf("</FRONTEND>\n" );
680 struct ret_mmi_status
*p_ret
=
681 (struct ret_mmi_status
*)&p_buffer
[COMM_HEADER_SIZE
];
682 if ( i_size
!= COMM_HEADER_SIZE
+ sizeof(struct ret_mmi_status
) )
683 return_error( "Bad MMI status" );
685 printf("CA interface with %d %s, type:\n", p_ret
->caps
.slot_num
,
686 p_ret
->caps
.slot_num
== 1 ? "slot" : "slots");
687 #define PRINT_CAPS( x, s ) \
688 if ( p_ret->caps.slot_type & (CA_##x) ) \
690 PRINT_CAPS( CI
, "CI high level interface" );
691 PRINT_CAPS( CI_LINK
, "CI link layer level interface" );
692 PRINT_CAPS( CI_PHYS
, "CI physical layer level interface (not supported)" );
693 PRINT_CAPS( DESCR
, "built-in descrambler" );
694 PRINT_CAPS( SC
, "simple smartcard interface" );
697 printf("\n%d available %s\n", p_ret
->caps
.descr_num
,
698 p_ret
->caps
.descr_num
== 1 ? "descrambler (key)" :
699 "descramblers (keys)");
700 #define PRINT_DESC( x ) \
701 if ( p_ret->caps.descr_type & (CA_##x) ) \
702 printf( STRINGIFY(x) "\n" );
708 exit( p_ret
->caps
.slot_num
);
712 case RET_MMI_SLOT_STATUS
:
714 struct ret_mmi_slot_status
*p_ret
=
715 (struct ret_mmi_slot_status
*)&p_buffer
[COMM_HEADER_SIZE
];
716 if ( i_size
< COMM_HEADER_SIZE
+ sizeof(struct ret_mmi_slot_status
) )
717 return_error( "Bad MMI slot status" );
719 printf("CA slot #%u: ", p_ret
->sinfo
.num
);
721 #define PRINT_TYPE( x, s ) \
722 if ( p_ret->sinfo.type & (CA_##x) ) \
725 PRINT_TYPE( CI
, "high level, " );
726 PRINT_TYPE( CI_LINK
, "link layer level, " );
727 PRINT_TYPE( CI_PHYS
, "physical layer level, " );
730 if ( p_ret
->sinfo
.flags
& CA_CI_MODULE_READY
)
732 printf("module present and ready\n");
736 if ( p_ret
->sinfo
.flags
& CA_CI_MODULE_PRESENT
)
737 printf("module present, not ready\n");
739 printf("module not present\n");
747 struct ret_mmi_recv
*p_ret
=
748 (struct ret_mmi_recv
*)&p_buffer
[COMM_HEADER_SIZE
];
749 if ( i_size
< COMM_HEADER_SIZE
+ sizeof(struct ret_mmi_recv
) )
750 return_error( "Bad MMI recv" );
752 en50221_UnserializeMMIObject( &p_ret
->object
, i_size
753 - COMM_HEADER_SIZE
- ((void *)&p_ret
->object
- (void *)p_ret
) );
755 switch ( p_ret
->object
.i_object_type
)
757 case EN50221_MMI_ENQ
:
758 printf("%s\n", p_ret
->object
.u
.enq
.psz_text
);
759 printf("(empty to cancel)\n");
760 exit(p_ret
->object
.u
.enq
.b_blind
? 253 : 254);
763 case EN50221_MMI_MENU
:
764 printf("%s\n", p_ret
->object
.u
.menu
.psz_title
);
765 printf("%s\n", p_ret
->object
.u
.menu
.psz_subtitle
);
766 printf("0 - Cancel\n");
767 for ( i
= 0; i
< p_ret
->object
.u
.menu
.i_choices
; i
++ )
768 printf("%d - %s\n", i
+ 1,
769 p_ret
->object
.u
.menu
.ppsz_choices
[i
]);
770 printf("%s\n", p_ret
->object
.u
.menu
.psz_bottom
);
771 exit(p_ret
->object
.u
.menu
.i_choices
);
774 case EN50221_MMI_LIST
:
775 printf("%s\n", p_ret
->object
.u
.menu
.psz_title
);
776 printf("%s\n", p_ret
->object
.u
.menu
.psz_subtitle
);
777 for ( i
= 0; i
< p_ret
->object
.u
.menu
.i_choices
; i
++ )
778 printf("%s\n", p_ret
->object
.u
.menu
.ppsz_choices
[i
]);
779 printf("%s\n", p_ret
->object
.u
.menu
.psz_bottom
);
780 printf("(0 to cancel)\n");
785 return_error( "Unknown MMI object" );
794 return_error( "Unknown command answer: %u", c_answer
);