Commit 906d79c5 authored by Georgi Chorbadzhiyski's avatar Georgi Chorbadzhiyski

dvblastctl: Add get_pat, get_cat, get_nit and get_sdt commands.

parent 682a2bf2
...@@ -18,6 +18,7 @@ Changes between 1.2 and 2.0: ...@@ -18,6 +18,7 @@ Changes between 1.2 and 2.0:
* Add basic support for ATSC * Add basic support for ATSC
* Add support for MRTG statistics * Add support for MRTG statistics
* Add detailed information for TS errors * Add detailed information for TS errors
* Add support for getting PAT/CAT/NIT/SDT tables in dvblastctl
Changes between 1.1 and 1.2: Changes between 1.1 and 1.2:
---------------------------- ----------------------------
......
...@@ -77,6 +77,8 @@ void comm_Read( void ) ...@@ -77,6 +77,8 @@ void comm_Read( void )
ssize_t i_size, i_answer_size = 0; ssize_t i_size, i_answer_size = 0;
uint8_t p_buffer[COMM_BUFFER_SIZE], p_answer[COMM_BUFFER_SIZE]; uint8_t p_buffer[COMM_BUFFER_SIZE], p_answer[COMM_BUFFER_SIZE];
uint8_t i_command, i_answer; uint8_t i_command, i_answer;
uint8_t *p_packed_section;
unsigned int i_packed_section_size;
i_size = recvfrom( i_comm_fd, p_buffer, COMM_BUFFER_SIZE, 0, i_size = recvfrom( i_comm_fd, p_buffer, COMM_BUFFER_SIZE, 0,
(struct sockaddr *)&sun_client, &sun_length ); (struct sockaddr *)&sun_client, &sun_length );
...@@ -153,6 +155,44 @@ void comm_Read( void ) ...@@ -153,6 +155,44 @@ void comm_Read( void )
i_answer_size = 0; i_answer_size = 0;
break; break;
case CMD_GET_PAT:
case CMD_GET_CAT:
case CMD_GET_NIT:
case CMD_GET_SDT:
{
#define CASE_TABLE(x) \
case CMD_GET_##x: \
{ \
i_answer = RET_##x; \
p_packed_section = demux_get_current_packed_##x(&i_packed_section_size); \
break; \
}
switch ( i_command )
{
CASE_TABLE(PAT)
CASE_TABLE(CAT)
CASE_TABLE(NIT)
CASE_TABLE(SDT)
}
#undef CASE_TABLE
if ( p_packed_section && i_packed_section_size )
{
if ( i_packed_section_size <= COMM_BUFFER_SIZE - COMM_HEADER_SIZE )
{
i_answer_size = i_packed_section_size;
memcpy( p_answer + COMM_HEADER_SIZE, p_packed_section, i_packed_section_size );
} else {
msg_Err( NULL, "section size is too big (%u)\n", i_packed_section_size );
i_answer = RET_NODATA;
}
free( p_packed_section );
} else {
i_answer = RET_NODATA;
}
break;
}
default: default:
msg_Err( NULL, "wrong command %u", i_command ); msg_Err( NULL, "wrong command %u", i_command );
i_answer = RET_HUH; i_answer = RET_HUH;
......
...@@ -19,6 +19,8 @@ ...@@ -19,6 +19,8 @@
#include <linux/dvb/frontend.h> #include <linux/dvb/frontend.h>
#include <linux/dvb/ca.h> #include <linux/dvb/ca.h>
#include <bitstream/mpeg/psi.h>
#define COMM_HEADER_SIZE 8 #define COMM_HEADER_SIZE 8
#define COMM_BUFFER_SIZE (COMM_HEADER_SIZE + ((PSI_PRIVATE_MAX_SIZE + PSI_HEADER_SIZE) * (PSI_TABLE_MAX_SECTIONS / 2))) #define COMM_BUFFER_SIZE (COMM_HEADER_SIZE + ((PSI_PRIVATE_MAX_SIZE + PSI_HEADER_SIZE) * (PSI_TABLE_MAX_SECTIONS / 2)))
#define COMM_HEADER_MAGIC 0x48 #define COMM_HEADER_MAGIC 0x48
...@@ -34,6 +36,10 @@ ...@@ -34,6 +36,10 @@
#define CMD_MMI_CLOSE 7 /* arg: slot */ #define CMD_MMI_CLOSE 7 /* arg: slot */
#define CMD_MMI_RECV 8 /* arg: slot */ #define CMD_MMI_RECV 8 /* arg: slot */
#define CMD_MMI_SEND 9 /* arg: slot, en50221_mmi_object_t */ #define CMD_MMI_SEND 9 /* arg: slot, en50221_mmi_object_t */
#define CMD_GET_PAT 10
#define CMD_GET_CAT 11
#define CMD_GET_NIT 12
#define CMD_GET_SDT 13
#define RET_OK 0 #define RET_OK 0
#define RET_ERR 1 #define RET_ERR 1
...@@ -42,6 +48,11 @@ ...@@ -42,6 +48,11 @@
#define RET_MMI_SLOT_STATUS 4 #define RET_MMI_SLOT_STATUS 4
#define RET_MMI_RECV 5 #define RET_MMI_RECV 5
#define RET_MMI_WAIT 6 #define RET_MMI_WAIT 6
#define RET_NODATA 7
#define RET_PAT 8
#define RET_CAT 9
#define RET_NIT 10
#define RET_SDT 11
#define RET_HUH 255 #define RET_HUH 255
struct ret_frontend_status struct ret_frontend_status
......
...@@ -2772,3 +2772,22 @@ static const char *get_pid_desc(uint16_t i_pid, uint16_t *i_sid) { ...@@ -2772,3 +2772,22 @@ static const char *get_pid_desc(uint16_t i_pid, uint16_t *i_sid) {
return "..."; return "...";
} }
/*****************************************************************************
* Functions that return packed sections
*****************************************************************************/
uint8_t *demux_get_current_packed_PAT( unsigned int *pi_pack_size ) {
return psi_pack_sections( pp_current_pat_sections, pi_pack_size );
}
uint8_t *demux_get_current_packed_CAT( unsigned int *pi_pack_size ) {
return psi_pack_sections( pp_current_cat_sections, pi_pack_size );
}
uint8_t *demux_get_current_packed_NIT( unsigned int *pi_pack_size ) {
return psi_pack_sections( pp_current_nit_sections, pi_pack_size );
}
uint8_t *demux_get_current_packed_SDT( unsigned int *pi_pack_size ) {
return psi_pack_sections( pp_current_sdt_sections, pi_pack_size );
}
...@@ -206,6 +206,9 @@ void hexDump( uint8_t *p_data, uint32_t i_len ); ...@@ -206,6 +206,9 @@ void hexDump( uint8_t *p_data, uint32_t i_len );
struct addrinfo *ParseNodeService( char *_psz_string, char **ppsz_end, struct addrinfo *ParseNodeService( char *_psz_string, char **ppsz_end,
uint16_t i_default_port ); uint16_t i_default_port );
uint8_t *psi_pack_sections( uint8_t **pp_sections, unsigned int *pi_size );
uint8_t **psi_unpack_sections( uint8_t *p_flat_sections, unsigned int i_size );
void dvb_Open( void ); void dvb_Open( void );
void dvb_Reset( void ); void dvb_Reset( void );
block_t * dvb_Read( mtime_t i_poll_timeout ); block_t * dvb_Read( mtime_t i_poll_timeout );
...@@ -234,6 +237,10 @@ char *demux_Iconv(void *_unused, const char *psz_encoding, ...@@ -234,6 +237,10 @@ char *demux_Iconv(void *_unused, const char *psz_encoding,
char *p_string, size_t i_length); char *p_string, size_t i_length);
void demux_Close( void ); void demux_Close( void );
uint8_t *demux_get_current_packed_PAT( unsigned int *pi_pack_size );
uint8_t *demux_get_current_packed_CAT( unsigned int *pi_pack_size );
uint8_t *demux_get_current_packed_NIT( unsigned int *pi_pack_size );
uint8_t *demux_get_current_packed_SDT( unsigned int *pi_pack_size );
output_t *output_Create( const output_config_t *p_config ); output_t *output_Create( const output_config_t *p_config );
int output_Init( output_t *p_output, const output_config_t *p_config ); int output_Init( output_t *p_output, const output_config_t *p_config );
......
...@@ -22,11 +22,13 @@ ...@@ -22,11 +22,13 @@
*****************************************************************************/ *****************************************************************************/
#include <stdlib.h> #include <stdlib.h>
#include <stdarg.h>
#include <stdio.h> #include <stdio.h>
#include <unistd.h> #include <unistd.h>
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#include <string.h> #include <string.h>
#include <inttypes.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/param.h> #include <sys/param.h>
...@@ -37,6 +39,11 @@ ...@@ -37,6 +39,11 @@
#include <errno.h> #include <errno.h>
#include <getopt.h> #include <getopt.h>
#include <bitstream/mpeg/psi.h>
#include <bitstream/dvb/si.h>
#include <bitstream/dvb/si_print.h>
#include <bitstream/mpeg/psi_print.h>
#include "dvblast.h" #include "dvblast.h"
#include "en50221.h" #include "en50221.h"
#include "comm.h" #include "comm.h"
...@@ -45,11 +52,42 @@ ...@@ -45,11 +52,42 @@
int i_verbose = 3; int i_verbose = 3;
int i_syslog = 0; int i_syslog = 0;
print_type_t i_print_type = PRINT_TEXT;
/*****************************************************************************
* The following two functinos are from biTStream's examples and are under the
* WTFPL (see LICENSE.WTFPL).
****************************************************************************/
__attribute__ ((format(printf, 2, 3)))
static void psi_print(void *_unused, const char *psz_format, ...)
{
char psz_fmt[strlen(psz_format) + 2];
va_list args;
va_start(args, psz_format);
strcpy(psz_fmt, psz_format);
strcat(psz_fmt, "\n");
vprintf(psz_fmt, args);
}
static char *iconv_append_null(const char *p_string, size_t i_length)
{
char *psz_string = malloc(i_length + 1);
memcpy(psz_string, p_string, i_length);
psz_string[i_length] = '\0';
return psz_string;
}
char *psi_iconv(void *_unused, const char *psz_encoding,
char *p_string, size_t i_length)
{
return iconv_append_null(p_string, i_length);
}
void usage() void usage()
{ {
msg_Raw( NULL, "DVBlastctl %d.%d.%d (%s)", VERSION_MAJOR, VERSION_MINOR, msg_Raw( NULL, "DVBlastctl %d.%d.%d (%s)", VERSION_MAJOR, VERSION_MINOR,
VERSION_REVISION, VERSION_EXTRA ); VERSION_REVISION, VERSION_EXTRA );
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>]" ); 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|get_pat|get_cat|get_nit|get_sdt [<CAM slot>] [-x <text|xml>] [<text/choice>]" );
exit(1); exit(1);
} }
...@@ -71,11 +109,12 @@ int main( int i_argc, char **ppsz_argv ) ...@@ -71,11 +109,12 @@ int main( int i_argc, char **ppsz_argv )
static const struct option long_options[] = static const struct option long_options[] =
{ {
{"remote-socket", required_argument, NULL, 'r'}, {"remote-socket", required_argument, NULL, 'r'},
{"print", required_argument, NULL, 'x'},
{"help", no_argument, NULL, 'h'}, {"help", no_argument, NULL, 'h'},
{0, 0, 0, 0} {0, 0, 0, 0}
}; };
if ( (c = getopt_long(i_argc, ppsz_argv, "r:h", long_options, NULL)) == -1 ) if ( (c = getopt_long(i_argc, ppsz_argv, "r:x:h", long_options, NULL)) == -1 )
break; break;
switch ( c ) switch ( c )
...@@ -84,6 +123,17 @@ int main( int i_argc, char **ppsz_argv ) ...@@ -84,6 +123,17 @@ int main( int i_argc, char **ppsz_argv )
psz_srv_socket = optarg; psz_srv_socket = optarg;
break; break;
case 'x':
if ( !strcmp(optarg, "text") )
i_print_type = PRINT_TEXT;
else if ( !strcmp(optarg, "xml") )
i_print_type = PRINT_XML;
else
msg_Warn( NULL, "unrecognized print type %s", optarg );
/* Make stdout line-buffered */
setvbuf(stdout, NULL, _IOLBF, 0);
break;
case 'h': case 'h':
default: default:
usage(); usage();
...@@ -96,6 +146,10 @@ int main( int i_argc, char **ppsz_argv ) ...@@ -96,6 +146,10 @@ int main( int i_argc, char **ppsz_argv )
if ( strcmp(ppsz_argv[optind], "reload") if ( strcmp(ppsz_argv[optind], "reload")
&& strcmp(ppsz_argv[optind], "shutdown") && strcmp(ppsz_argv[optind], "shutdown")
&& strcmp(ppsz_argv[optind], "fe_status") && strcmp(ppsz_argv[optind], "fe_status")
&& strcmp(ppsz_argv[optind], "get_pat")
&& strcmp(ppsz_argv[optind], "get_cat")
&& strcmp(ppsz_argv[optind], "get_nit")
&& strcmp(ppsz_argv[optind], "get_sdt")
&& strcmp(ppsz_argv[optind], "mmi_status") && strcmp(ppsz_argv[optind], "mmi_status")
&& strcmp(ppsz_argv[optind], "mmi_slot_status") && strcmp(ppsz_argv[optind], "mmi_slot_status")
&& strcmp(ppsz_argv[optind], "mmi_open") && strcmp(ppsz_argv[optind], "mmi_open")
...@@ -171,6 +225,14 @@ int main( int i_argc, char **ppsz_argv ) ...@@ -171,6 +225,14 @@ int main( int i_argc, char **ppsz_argv )
p_buffer[1] = CMD_SHUTDOWN; p_buffer[1] = CMD_SHUTDOWN;
else if ( !strcmp(ppsz_argv[optind], "fe_status") ) else if ( !strcmp(ppsz_argv[optind], "fe_status") )
p_buffer[1] = CMD_FRONTEND_STATUS; p_buffer[1] = CMD_FRONTEND_STATUS;
else if ( !strcmp(ppsz_argv[optind], "get_pat") )
p_buffer[1] = CMD_GET_PAT;
else if ( !strcmp(ppsz_argv[optind], "get_cat") )
p_buffer[1] = CMD_GET_CAT;
else if ( !strcmp(ppsz_argv[optind], "get_nit") )
p_buffer[1] = CMD_GET_NIT;
else if ( !strcmp(ppsz_argv[optind], "get_sdt") )
p_buffer[1] = CMD_GET_SDT;
else if ( !strcmp(ppsz_argv[optind], "mmi_status") ) else if ( !strcmp(ppsz_argv[optind], "mmi_status") )
p_buffer[1] = CMD_MMI_STATUS; p_buffer[1] = CMD_MMI_STATUS;
else else
...@@ -289,6 +351,34 @@ int main( int i_argc, char **ppsz_argv ) ...@@ -289,6 +351,34 @@ int main( int i_argc, char **ppsz_argv )
exit(255); exit(255);
break; break;
case RET_NODATA:
msg_Err( NULL, "no data" );
exit(255);
break;
case RET_PAT:
case RET_CAT:
case RET_NIT:
case RET_SDT:
{
uint8_t *p_flat_data = p_buffer + COMM_HEADER_SIZE;
unsigned int i_flat_data_size = i_size - COMM_HEADER_SIZE;
uint8_t **pp_sections = psi_unpack_sections( p_flat_data, i_flat_data_size );
switch( p_buffer[1] )
{
case RET_PAT: pat_table_print( pp_sections, psi_print, NULL, i_print_type ); break;
case RET_CAT: cat_table_print( pp_sections, psi_print, NULL, i_print_type ); break;
case RET_NIT: nit_table_print( pp_sections, psi_print, NULL, psi_iconv, NULL, i_print_type ); break;
case RET_SDT: sdt_table_print( pp_sections, psi_print, NULL, psi_iconv, NULL, i_print_type ); break;
}
psi_table_free( pp_sections );
free( pp_sections );
exit(0);
break;
}
case RET_FRONTEND_STATUS: case RET_FRONTEND_STATUS:
{ {
struct ret_frontend_status *p_ret = struct ret_frontend_status *p_ret =
......
...@@ -37,6 +37,8 @@ ...@@ -37,6 +37,8 @@
#include <errno.h> #include <errno.h>
#include <syslog.h> #include <syslog.h>
#include <bitstream/mpeg/psi.h>
#include "dvblast.h" #include "dvblast.h"
/***************************************************************************** /*****************************************************************************
...@@ -333,3 +335,69 @@ struct addrinfo *ParseNodeService( char *_psz_string, char **ppsz_end, ...@@ -333,3 +335,69 @@ struct addrinfo *ParseNodeService( char *_psz_string, char **ppsz_end,
return p_res; return p_res;
} }
/*****************************************************************************
* psi_pack_sections: return psi sections as array
* Note: Allocates the return value. The caller must free it.
*****************************************************************************/
uint8_t *psi_pack_sections( uint8_t **pp_sections, unsigned int *pi_size ) {
uint8_t i_last_section;
uint8_t *p_flat_section;
unsigned int i, i_pos = 0;
if ( !psi_table_validate( pp_sections ) )
return NULL;
i_last_section = psi_table_get_lastsection( pp_sections );
/* Calculate total size */
*pi_size = 0;
for ( i = 0; i <= i_last_section; i++ )
{
uint8_t *p_section = psi_table_get_section( pp_sections, i );
*pi_size += psi_get_length( p_section ) + PSI_HEADER_SIZE;
}
p_flat_section = malloc( *pi_size );
if ( !p_flat_section )
return NULL;
for ( i = 0; i <= i_last_section; i++ )
{
uint8_t *p_section = psi_table_get_section( pp_sections, i );
uint16_t psi_length = psi_get_length( p_section ) + PSI_HEADER_SIZE;
memcpy( p_flat_section + i_pos, p_section, psi_length );
i_pos += psi_length;
}
return p_flat_section;
}
/*****************************************************************************
* psi_unpack_sections: return psi sections
* Note: Allocates psi_table, the result must be psi_table_free()'ed
*****************************************************************************/
uint8_t **psi_unpack_sections( uint8_t *p_flat_sections, unsigned int i_size ) {
uint8_t **pp_sections;
unsigned int i, i_offset = 0;
pp_sections = psi_table_allocate();
psi_table_init( pp_sections );
for ( i = 0; i < PSI_TABLE_MAX_SECTIONS; i++ ) {
uint8_t *p_section = p_flat_sections + i_offset;
uint16_t i_section_len = psi_get_length( p_section ) + PSI_HEADER_SIZE;
/* Must use allocated section not p_flat_section + offset directly! */
uint8_t *p_section_local = psi_private_allocate();
memcpy( p_section_local, p_section, i_section_len );
psi_table_section( pp_sections, p_section_local );
i_offset += i_section_len;
if ( i_offset >= i_size - 1 )
break;
}
return pp_sections;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment