2 * dvlocal.c -- Local dv1394d Parser
3 * Copyright (C) 2002-2003 Ushodaya Enterprises Limited
4 * Author: Charles Yates <charles.yates@pandora.be>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25 /* System header files */
30 /* Library header files */
33 /* Application header files */
34 #include <dvclipfactory.h>
35 #include <dvframepool.h>
37 #include "dvconnection.h"
38 #include "global_commands.h"
39 #include "unit_commands.h"
41 #include "raw1394util.h"
43 /** Private dv_local structure.
51 *dv_local
, dv_local_t
;
53 /** Forward declarations.
56 static dv_response
dv_local_connect( dv_local
);
57 static dv_response
dv_local_execute( dv_local
, char * );
58 static void dv_local_close( dv_local
);
59 response_codes
print_help( command_argument arg
);
60 response_codes
dv1394d_run( command_argument arg
);
61 response_codes
dv1394d_shutdown( command_argument arg
);
63 /** DV Parser constructor.
66 dv_parser
dv_parser_init_local( )
68 dv_parser parser
= malloc( sizeof( dv_parser_t
) );
69 dv_local local
= malloc( sizeof( dv_local_t
) );
73 memset( parser
, 0, sizeof( dv_parser_t
) );
75 parser
->connect
= (parser_connect
)dv_local_connect
;
76 parser
->execute
= (parser_execute
)dv_local_execute
;
77 parser
->close
= (parser_close
)dv_local_close
;
82 memset( local
, 0, sizeof( dv_local_t
) );
83 local
->parser
= parser
;
84 local
->root_dir
[0] = '/';
90 /** response status code/message pair
100 /** response messages
103 static responses_t responses
[] =
105 {RESPONSE_SUCCESS
, "OK"},
106 {RESPONSE_SUCCESS_N
, "OK"},
107 {RESPONSE_SUCCESS_1
, "OK"},
108 {RESPONSE_UNKNOWN_COMMAND
, "Unknown command"},
109 {RESPONSE_TIMEOUT
, "Operation timed out"},
110 {RESPONSE_MISSING_ARG
, "Argument missing"},
111 {RESPONSE_INVALID_UNIT
, "Unit not found"},
112 {RESPONSE_BAD_FILE
, "Failed to locate or open clip"},
113 {RESPONSE_OUT_OF_RANGE
, "Argument value out of range"},
114 {RESPONSE_TOO_MANY_FILES
, "Too many files open"},
115 {RESPONSE_ERROR
, "Server Error"}
130 /** A command definition.
135 /* The command string corresponding to this operation (e.g. "play") */
137 /* The function associated with it */
138 response_codes (*operation
) ( command_argument
);
139 /* a boolean to indicate if this is a unit or global command
140 unit commands require a unit identifier as first argument */
142 /* What type is the argument (RTTI :-) ATYPE_whatever */
144 /* online help information */
149 /* The following define the queue of commands available to the user. The
150 first entry is the name of the command (the string which must be typed),
151 the second command is the function associated with it, the third argument
152 is for the type of the argument, and the last argument specifies whether
153 this is something which should be handled immediately or whether it
154 should be queued (only robot motion commands need to be queued). */
156 static command_t vocabulary
[] =
158 {"BYE", NULL
, 0, ATYPE_NONE
, "Terminates the session. Units are not removed and task queue is not flushed."},
159 {"HELP", print_help
, 0, ATYPE_NONE
, "Display this information!"},
160 {"NLS", dv1394d_list_nodes
, 0, ATYPE_NONE
, "List the AV/C nodes on the 1394 bus."},
161 {"UADD", dv1394d_add_unit
, 0, ATYPE_STRING
, "Create a new DV unit (virtual VTR) to transmit to receiver specified in GUID argument."},
162 {"ULS", dv1394d_list_units
, 0, ATYPE_NONE
, "Lists the units that have already been added to the server."},
163 {"CLS", dv1394d_list_clips
, 0, ATYPE_STRING
, "Lists the clips at directory name argument."},
164 {"SET", dv1394d_set_global_property
, 0, ATYPE_STRING
, "Set a server configuration property."},
165 {"GET", dv1394d_get_global_property
, 0, ATYPE_STRING
, "Get a server configuration property."},
166 {"RUN", dv1394d_run
, 0, ATYPE_STRING
, "Run a batch file." },
167 {"LIST", dv1394d_list
, 1, ATYPE_NONE
, "List the playlist associated to a unit."},
168 {"LOAD", dv1394d_load
, 1, ATYPE_STRING
, "Load clip specified in absolute filename argument."},
169 {"INSERT", dv1394d_insert
, 1, ATYPE_STRING
, "Insert a clip at the given clip index."},
170 {"REMOVE", dv1394d_remove
, 1, ATYPE_NONE
, "Remove a clip at the given clip index."},
171 {"CLEAN", dv1394d_clean
, 1, ATYPE_NONE
, "Clean a unit by removing all but the currently playing clip."},
172 {"MOVE", dv1394d_move
, 1, ATYPE_INT
, "Move a clip to another clip index."},
173 {"APND", dv1394d_append
, 1, ATYPE_STRING
, "Append a clip specified in absolute filename argument."},
174 {"PLAY", dv1394d_play
, 1, ATYPE_NONE
, "Play a loaded clip at speed -2000 to 2000 where 1000 = normal forward speed."},
175 {"STOP", dv1394d_stop
, 1, ATYPE_NONE
, "Stop a loaded and playing clip."},
176 {"PAUSE", dv1394d_pause
, 1, ATYPE_NONE
, "Pause a playing clip."},
177 {"REW", dv1394d_rewind
, 1, ATYPE_NONE
, "Rewind a unit. If stopped, seek to beginning of clip. If playing, play fast backwards."},
178 {"FF", dv1394d_ff
, 1, ATYPE_NONE
, "Fast forward a unit. If stopped, seek to beginning of clip. If playing, play fast forwards."},
179 {"STEP", dv1394d_step
, 1, ATYPE_INT
, "Step argument number of frames forward or backward."},
180 {"GOTO", dv1394d_goto
, 1, ATYPE_INT
, "Jump to frame number supplied as argument."},
181 {"SIN", dv1394d_set_in_point
, 1, ATYPE_INT
, "Set the IN point of the loaded clip to frame number argument. -1 = reset in point to 0"},
182 {"SOUT", dv1394d_set_out_point
, 1, ATYPE_INT
, "Set the OUT point of the loaded clip to frame number argument. -1 = reset out point to maximum."},
183 {"USTA", dv1394d_get_unit_status
, 1, ATYPE_NONE
, "Report information about the unit."},
184 {"USET", dv1394d_set_unit_property
, 1, ATYPE_STRING
, "Set a unit configuration property."},
185 {"UGET", dv1394d_get_unit_property
, 1, ATYPE_STRING
, "Get a unit configuration property."},
186 {"XFER", dv1394d_transfer
, 1, ATYPE_STRING
, "Transfer the unit's clip to another unit specified as argument."},
187 {"SHUTDOWN", dv1394d_shutdown
, 0, ATYPE_NONE
, "Shutdown the server."},
188 {NULL
, NULL
, 0, ATYPE_NONE
, NULL
}
194 static char helpstr
[] =
195 "dv1394d -- A DV over IEEE 1394 TCP Server\n"
196 " Copyright (C) 2002-2003 Ushodaya Enterprises Limited\n"
198 " Dan Dennedy <dan@dennedy.org>\n"
199 " Charles Yates <charles.yates@pandora.be>\n"
200 "Available commands:\n";
202 /** Lookup the response message for a status code.
205 inline char *get_response_msg( int code
)
208 for ( i
= 0; responses
[ i
].message
!= NULL
&& code
!= responses
[ i
].code
; i
++ ) ;
209 return responses
[ i
].message
;
212 /** Tell the user the dv1394d command set
215 response_codes
print_help( command_argument cmd_arg
)
219 dv_response_printf( cmd_arg
->response
, 10240, "%s", helpstr
);
221 for ( i
= 0; vocabulary
[ i
].command
!= NULL
; i
++ )
222 dv_response_printf( cmd_arg
->response
, 1024,
224 vocabulary
[ i
].command
,
225 vocabulary
[ i
].help
);
227 dv_response_printf( cmd_arg
->response
, 2, "\n" );
229 return RESPONSE_SUCCESS_N
;
232 /** Execute a batch file.
235 response_codes
dv1394d_run( command_argument cmd_arg
)
237 dv_response temp
= dv_parser_run( cmd_arg
->parser
, (char *)cmd_arg
->argument
);
243 dv_response_set_error( cmd_arg
->response
,
244 dv_response_get_error_code( temp
),
245 dv_response_get_error_string( temp
) );
247 for ( index
= 1; index
< dv_response_count( temp
); index
++ )
248 dv_response_printf( cmd_arg
->response
, 10240, "%s\n", dv_response_get_line( temp
, index
) );
250 dv_response_close( temp
);
253 return dv_response_get_error_code( cmd_arg
->response
);
256 response_codes
dv1394d_shutdown( command_argument cmd_arg
)
259 return RESPONSE_SUCCESS
;
262 /** Processes 'thread' id
265 static pthread_t self
;
267 /* Signal handler to deal with various shutdown signals. Basically this
268 should clean up and power down the motor. Note that the death of any
269 child thread will kill all thrads. */
271 void signal_handler( int sig
)
273 if ( pthread_equal( self
, pthread_self( ) ) )
277 dv1394d_log( LOG_DEBUG
, "Received %s - shutting down.", strsignal(sig
) );
279 dv1394d_log( LOG_DEBUG
, "Received signal %i - shutting down.", sig
);
286 /** Local 'connect' function.
289 static dv_response
dv_local_connect( dv_local local
)
291 dv_response response
= dv_response_init( );
293 self
= pthread_self( );
295 dv_response_set_error( response
, 100, "VTR Ready" );
297 signal( SIGHUP
, signal_handler
);
298 signal( SIGINT
, signal_handler
);
299 signal( SIGTERM
, signal_handler
);
300 signal( SIGSTOP
, signal_handler
);
301 signal( SIGCHLD
, SIG_IGN
);
303 raw1394_reconcile_bus();
304 /* Start the raw1394 service threads for handling bus resets */
305 raw1394_start_service_threads();
310 /** Set the error and determine the message associated to this command.
313 void dv_command_set_error( command_argument cmd
, response_codes code
)
315 dv_response_set_error( cmd
->response
, code
, get_response_msg( code
) );
318 /** Parse the unit argument.
321 int dv_command_parse_unit( command_argument cmd
, int argument
)
324 char *string
= dv_tokeniser_get_string( cmd
->tokeniser
, argument
);
325 if ( string
!= NULL
&& ( string
[ 0 ] == 'U' || string
[ 0 ] == 'u' ) && strlen( string
) > 1 )
326 unit
= atoi( string
+ 1 );
330 /** Parse a normal argument.
333 void *dv_command_parse_argument( command_argument cmd
, int argument
, arguments_types type
)
336 char *value
= dv_tokeniser_get_string( cmd
->tokeniser
, argument
);
346 ret
= malloc( sizeof( float ) );
348 *( float * )ret
= atof( value
);
352 ret
= strdup( value
);
356 ret
= malloc( sizeof( int ) );
358 *( int * )ret
= atoi( value
);
366 /** Get the error code - note that we simply the success return.
369 response_codes
dv_command_get_error( command_argument cmd
)
371 response_codes ret
= dv_response_get_error_code( cmd
->response
);
372 if ( ret
== RESPONSE_SUCCESS_N
|| ret
== RESPONSE_SUCCESS_1
)
373 ret
= RESPONSE_SUCCESS
;
377 /** Execute the command.
380 static dv_response
dv_local_execute( dv_local local
, char *command
)
382 command_argument_t cmd
;
383 cmd
.parser
= local
->parser
;
384 cmd
.response
= dv_response_init( );
385 cmd
.tokeniser
= dv_tokeniser_init( );
386 cmd
.command
= command
;
389 cmd
.root_dir
= local
->root_dir
;
391 /* Set the default error */
392 dv_command_set_error( &cmd
, RESPONSE_UNKNOWN_COMMAND
);
394 /* Parse the command */
395 if ( dv_tokeniser_parse_new( cmd
.tokeniser
, command
, " " ) > 0 )
398 char *value
= dv_tokeniser_get_string( cmd
.tokeniser
, 0 );
401 /* Strip quotes from all tokens */
402 for ( index
= 0; index
< dv_tokeniser_count( cmd
.tokeniser
); index
++ )
403 dv_util_strip( dv_tokeniser_get_string( cmd
.tokeniser
, index
), '\"' );
405 /* Search the vocabulary array for value */
406 for ( index
= 1; !found
&& vocabulary
[ index
].command
!= NULL
; index
++ )
407 if ( ( found
= !strcasecmp( vocabulary
[ index
].command
, value
) ) )
410 /* If we found something, the handle the args and call the handler. */
415 dv_command_set_error( &cmd
, RESPONSE_SUCCESS
);
417 if ( vocabulary
[ index
].is_unit
)
419 cmd
.unit
= dv_command_parse_unit( &cmd
, position
);
420 if ( cmd
.unit
== -1 )
421 dv_command_set_error( &cmd
, RESPONSE_MISSING_ARG
);
425 if ( dv_command_get_error( &cmd
) == RESPONSE_SUCCESS
)
427 cmd
.argument
= dv_command_parse_argument( &cmd
, position
, vocabulary
[ index
].type
);
428 if ( cmd
.argument
== NULL
&& vocabulary
[ index
].type
!= ATYPE_NONE
)
429 dv_command_set_error( &cmd
, RESPONSE_MISSING_ARG
);
433 if ( dv_command_get_error( &cmd
) == RESPONSE_SUCCESS
)
435 response_codes error
= vocabulary
[ index
].operation( &cmd
);
436 dv_command_set_error( &cmd
, error
);
439 free( cmd
.argument
);
443 dv_tokeniser_close( cmd
.tokeniser
);
448 /** Close the parser.
451 static void dv_local_close( dv_local local
)
453 raw1394_stop_service_threads();
454 dv1394d_delete_all_units();
455 pthread_kill_other_threads_np();
456 dv1394d_log( LOG_DEBUG
, "Clean shutdown." );
458 dv_clip_factory_close( );
459 dv_frame_pool_close( );