/* dvcont - A DV Camera Console Control Program
 * By: Jason Howard <jason@spectsoft.com>
 * http://www.spectsoft.com
 * Code Started January 1, 2001.
 * Version 0.4
 * Adapted to libavc1394 by Dan Dennedy <dan@dennedy.org>
 * Many commands since 0.04 added by Dan Dennedy
 *
 * This code is based off a GNU project called gscanbus by Andreas Micklei
 * -- Thanks Andreas for the great code! --
 * 
 * Thanks to Dan Dennedy for patching this version to get it to work
 * with his camera.  (Panasonic PV-DV910) 
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

// Load up the needed includes.
#include <config.h>

#include "../librom1394/rom1394.h"
#include "../libavc1394/avc1394.h"
#include "../libavc1394/avc1394_vcr.h"

#include <libraw1394/raw1394.h>
#include <libraw1394/csr.h>
#include <sys/types.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>

#define version "Version 0.4"

void show_help() {

printf("\n--- DVCONT HELP ---");
printf("\n\nUsage: dvcont <command>");
printf("\n\nCommands:");
printf("\nplay - Tell the camera to play (or toggle slow-mo)");
printf("\nreverse - Tell the camera to play in reverse (or toggle reverse slow-mo)");
printf("\ntrickplay - Tell the camera to play back at -14 to +14 (not supported by all cams)");
printf("\nstop - Tell the camera to stop");
printf("\nrewind - Tell the camera to rewind (stop or play mode)");
printf("\nff - Tell the camera to fast forward (stop or play mode)");
printf("\npause - Tell the camera to toggle pause play");
printf("\nnext - Tell the camera to go to the next frame (pause mode)");
printf("\nnextindex - Tell the camera to go to the next index point and pause");
printf("\nprev - Tell the camera to go to the previous frame (pause mode)");
printf("\nprevindex - Tell the camera to go to the previous index point and pause");
printf("\nrecord - Tell the camera to record (use with caution!)");
printf("\neject - Tell the camera to eject the tape (awe your friends!)");
printf("\ntimecode - Report the timecode from the tape (HH:MM:SS:FF)");
printf("\nseek - Tell the camera to go to the <timecode> (HH:MM:SS:FF)");
printf("\nstatus - Report the status of the device");
printf("\npluginfo - Report available plugs");
printf("\nverbose - Tell the program to tell you debug info.");
printf("\nversion - Tell the program to tell you the program version.");
printf("\nhelp - Tell the program to show you this screen");
printf("\ndev <number> - Select device number on chain to use.");
printf("\n               (use the dev command BEFORE any other commands)");
printf("\n\n");

}

int main (int argc, char *argv[])
{
	rom1394_directory rom_dir;
	raw1394handle_t handle;
	int device = -1;
	int verbose = 0;
    int i, j;
	int speed;
	char timecode[12];

	if (argc < 2)
	{
		show_help();
		exit(0);
	}
	
#ifdef RAW1394_V_0_8
	handle = raw1394_get_handle();
#else
    handle = raw1394_new_handle();
#endif
    if (!handle)
    {
        if (!errno)
        {
            fprintf(stderr, "Not Compatable!\n");
        } else {
            perror("Couldn't get 1394 handle");
            fprintf(stderr, "Is ieee1394, driver, and raw1394 loaded?\n");
        }
        exit(1);
    } 

	if (raw1394_set_port(handle, 0) < 0) {
		perror("couldn't set port");
        raw1394_destroy_handle(handle);
		exit(1);
	}

		
   	for (i=0; i < raw1394_get_nodecount(handle); ++i)
    {
    	if (rom1394_get_directory(handle, i, &rom_dir) < 0)
    	{
    	    fprintf(stderr,"error reading config rom directory for node %d\n", i);
    	    continue;
        }

		for (j = 1; j < argc; ++j) {
			if (strcmp("verbose", argv[j]) == 0) {
				printf ("node %d type = %d\n", i, rom1394_get_node_type(&rom_dir));
				if ( (rom1394_get_node_type(&rom_dir) == ROM1394_NODE_TYPE_AVC) ) {
					printf ("node %d AVC video recorder? %s\n", i, avc1394_check_subunit_type(handle, i, AVC1394_SUBUNIT_TYPE_TAPE_RECORDER) ? "yes":"no");
					printf ("node %d AVC disk recorder? %s\n", i, avc1394_check_subunit_type(handle, i, AVC1394_SUBUNIT_TYPE_DISC_RECORDER) ? "yes":"no");
					printf ("node %d AVC tuner? %s\n", i, avc1394_check_subunit_type(handle, i, AVC1394_SUBUNIT_TYPE_TUNER) ? "yes":"no");
					printf ("node %d AVC video camera? %s\n", i, avc1394_check_subunit_type(handle, i, AVC1394_SUBUNIT_TYPE_VIDEO_CAMERA) ? "yes":"no");
					printf ("node %d AVC video monitor? %s\n", i, avc1394_check_subunit_type(handle, i, AVC1394_SUBUNIT_TYPE_VIDEO_MONITOR) ? "yes":"no");
				}
			}
		}
		
        if ( (rom1394_get_node_type(&rom_dir) == ROM1394_NODE_TYPE_AVC) &&
            avc1394_check_subunit_type(handle, i, AVC1394_SUBUNIT_TYPE_VCR))
        {
            device = i;
            break;
        }
    }
    
    if (device == -1)
    {
        fprintf(stderr, "Could not find any AV/C devices on the 1394 bus.\n");
        raw1394_destroy_handle(handle);
        exit(1);
    }

    for (i = 1; i < argc; ++i) {
        
        if (strcmp("play", argv[i]) == 0) {
            avc1394_vcr_play(handle, device);
          
	    } else if (strcmp("reverse", argv[i]) == 0) {
            avc1394_vcr_reverse(handle, device);
	    
	    } else if (strcmp("trickplay", argv[i]) == 0) {
	        if (i+1 < argc) {
                speed = atoi(argv[(i+1)]);
                avc1394_vcr_trick_play(handle, device, speed);
            }
	    
	    } else if (strcmp("stop", argv[i]) == 0) {
            avc1394_vcr_stop(handle, device);
	    
	    } else if (strcmp("rewind", argv[i]) == 0) {
    		avc1394_vcr_rewind(handle, device);
	    
	    } else if (strcmp("ff", argv[i]) == 0) {
    		avc1394_vcr_forward(handle, device);
	    
	    } else if (strcmp("pause", argv[i]) == 0) {
		    avc1394_vcr_pause(handle, device);
	    
	    } else if (strcmp("record", argv[i]) == 0) {
    		avc1394_vcr_record(handle, device);
	    
	    } else if (strcmp("eject", argv[i]) == 0) {
    		avc1394_vcr_eject(handle, device);
	    
	    } else if (strcmp("status", argv[i]) == 0) {
    		printf( "%s\n", avc1394_vcr_decode_status(avc1394_vcr_status(handle, device)));
	    
	    } else if (strcmp("timecode", argv[i]) == 0) {
	        if (avc1394_vcr_get_timecode2(handle, device, timecode) == 0)
        		printf( "%s\n", timecode);
			else
				printf( "--:--:--:--\n");
	    
	    } else if (strcmp("seek", argv[i]) == 0) {
	        avc1394_vcr_seek_timecode(handle, device, argv[i+1]);
	    
	    } else if (strcmp("version", argv[i]) == 0) {
			printf("\nDV Camera Console Control Program\n%s\nBy: Jason Howard, Dan Dennedy, and Andreas Micklei\n", version);
	    
	    } else if (strcmp("verbose", argv[i]) == 0) {
			printf("successfully got handle\n");
			printf("current generation number: %d\n", raw1394_get_generation(handle));
			printf("using first card found: %d nodes on bus, local ID is %d\n",
			raw1394_get_nodecount(handle),
			raw1394_get_local_id(handle) & 0x3f);
			verbose = 1;

	    } else if (strcmp("next", argv[i]) == 0) {
			avc1394_vcr_next(handle, device);
	    
	    } else if (strcmp("nextindex", argv[i]) == 0) {
			avc1394_vcr_next_index(handle, device);
	    
	    } else if (strcmp("prev", argv[i]) == 0) {
			avc1394_vcr_previous(handle, device);
	    
	    } else if (strcmp("previndex", argv[i]) == 0) {
			avc1394_vcr_previous_index(handle, device);
	    
	    } else if (strcmp("help", argv[i]) == 0) {
			show_help ();
	    
	    } else if (strcmp("dev", argv[i]) == 0) {
		
			device = atoi(argv[(i+1)]);
		
    		if (verbose == 1) {
    			printf("\nUsing Device: %d\n", device);
    		}

		} else if (strcmp( "pluginfo", argv[i]) == 0) {
			quadlet_t  request[2];
			quadlet_t *response;
		
			request[0] = AVC1394_CTYPE_STATUS | AVC1394_SUBUNIT_TYPE_TAPE_RECORDER | AVC1394_SUBUNIT_ID_0
						 | AVC1394_COMMAND_PLUG_INFO | 0x00;
			request[1] = 0xFFFFFFFF;
			response = avc1394_transaction_block(handle, device, request, 2, 2);
			if (response != NULL) {
				printf("serial bus input plugs = %d\n", (unsigned char) ((response[1]>>24) & 0xff));
				printf("serial bus output plugs = %d\n", (unsigned char) ((response[1]>>16) & 0xff));
				printf("external input plugs = %d\n", (unsigned char) ((response[1]>>8) & 0xff));
				printf("external output plugs = %d\n", (unsigned char) ((response[1]) & 0xff));
#ifdef DEBUG
				fprintf(stderr, "pluginfo: 0x%08X 0x%08X\n", response[0], response[1]);
#endif
			}
			avc1394_transaction_block_close(handle);
		}
	}
		
    raw1394_destroy_handle(handle);
	return 0;
}
