
/* Generated by Interface Builder */

#import "ViscaController.h"
#import "Controller.h"
#import <appkit/Application.h>
#import <appkit/Form.h>
#import <appkit/TextField.h>
#import <appkit/Button.h>
#import <libc.h>

@implementation ViscaController
void checkSelf(teNum, now, moi) 
DPSTimedEntry teNum;
double now;
id moi;
{
	[moi updateSelf];
	return;
}


void checkClock(teNum, now, moi) 
DPSTimedEntry teNum;
double now;
id moi;
{
	[moi clockInquiry: moi];
	return;
}

void checkPosition(teNum, now, moi) 
DPSTimedEntry teNum;
double now;
id moi;
{
	[moi positionInquiry: moi];
	return;
}

void checkMode(teNum, now, moi) 
DPSTimedEntry teNum;
double now;
id moi;
{
	[moi modeInquiry: moi];
	return;
}


unsigned char bcd( int val )
{	
	unsigned char tmp;
	
	tmp = (val / 10) * 0x10 +  (val % 10);
	
	fprintf(stderr," BCDing %d == %02X\n", val, tmp);
	return tmp;
}
	

- appDidInit: sender
{
	warnUser = YES;
	strcpy(errorMessage, ERRMSG_NOERROR );

	fprintf(stderr,"ViscaController.m: appDidInit\n");
	
	visca = [[VISCA alloc] init];
	
	[NXApp initVars];
	
	[visca setPort: (char *) "/dev/ttyb"];
	[visca open];
	[visca setAddressBroadcastFrom: 0];
	[visca setWhenNow];
	[visca v_address];
	
	checkTE =    DPSAddTimedEntry(0.25, &checkSelf, self, 
		NX_MODALRESPTHRESHOLD);

	clockAuto  = YES;
	clockTE =    DPSAddTimedEntry( 0.5, &checkClock, 
			self, NX_MODALRESPTHRESHOLD);

	positionTE =    DPSAddTimedEntry(0.1, &checkPosition, 	
			self, NX_MODALRESPTHRESHOLD);
	positionAuto = YES;

	modeTE =    DPSAddTimedEntry( 0.1, &checkMode, 
		self, NX_MODALRESPTHRESHOLD);
	modeAuto = YES;

	return self;
	
}

- free
{
	fprintf(stderr, "Freeing!!!\n");
	[visca close];
	[visca free];
	DPSRemoveTimedEntry(checkTE);
	if( clockAuto )
		DPSRemoveTimedEntry(clockTE);
	return [super free];
}	

- updateSelf
{
//	[visca readStatus];
	return self;
}
	
	
- clockInquiry: sender
{
	int reply;
	unsigned char completionMessage[128];
	static char time[20];
	
	reply = [visca md_interfaceInquiry: INQ_CLOCK];
	
	if( reply == CMD_COMPLETION)
		{
		if(  [visca copyCompletionMessage: completionMessage] >= 6 )
			{
			sprintf(time, "%02X:%02X:%02X",
				completionMessage[0],
				completionMessage[1],
				completionMessage[2],
				completionMessage[3]);
			[timeField setStringValue:time];
			}
				
		}
	
	return self;
}

	

- positionInquiry: sender
{
	int reply, len;
	unsigned char completionMessage[128];
	static char counter[15];
	static char clock[15];
	
	reply = [visca md_positionInquiry];
	
	if( reply == CMD_COMPLETION)
		{
		len = [visca copyCompletionMessage: completionMessage];
		
		if(  [visca copyCompletionMessage: completionMessage] >= 10 )
			{
			sprintf(counter, "%02X:%02X:%02X:%02X",
				completionMessage[1],
				completionMessage[2],
				completionMessage[3],
				completionMessage[4]);
			[positionCounterText setStringValue:counter];
			
			sprintf(clock, "%02X:%02X:%02X:%02X%01X",
				completionMessage[5],
				completionMessage[6],
				completionMessage[7],
				completionMessage[8],
				completionMessage[9]);
			[positionClockText setStringValue:clock];
			
			}
		}

	return self;
}

- waitUntil:(struct ct_hmsf *) endFrame
{
	int reply, len;
	unsigned char cm[128];
	static char counter[15];
	double a, b;

	b = 	endFrame->hh * 60 * 60 * 100.0 +
		endFrame->mm * 60 * 100.0 +
		endFrame->ss * 100.0 +
		endFrame->ff;
	
	a = -1.0;			

	do
		{
		reply = [visca md_positionInquiry];
	
		if( reply == CMD_COMPLETION)
			{
			len = [visca copyCompletionMessage: cm];
		
			if(  [visca copyCompletionMessage: cm] 
				>= 10 )
				{
				fprintf(stderr, "Counter:=%02X:%02X:%02X:%02X",
					cm[1], cm[2], cm[3], cm[4]);
				[positionCounterText setStringValue:counter];
				a = 	cm[1] * 60 * 60 *100 + 
					cm[2] * 60 * 100 +
					cm[3] * 100 +
					cm[4];
				}
						
			}
		usleep(500);
		} while( a !=  b);


	return self;
}





- deviceInquiry: sender
{
	int reply, len;
	unsigned char completionMessage[128];
	static char dev[20];
	
	reply = [visca md_interfaceInquiry: INQ_DEVICETYPE];
	
	if( reply == CMD_COMPLETION)
		{
		len = [visca copyCompletionMessage: completionMessage];

		sprintf(dev, "%02X %02X, %02X %02X, %02X %02X",
				completionMessage[0],
				completionMessage[1],
				completionMessage[2],
				completionMessage[3],
				completionMessage[4],
				completionMessage[5]);
		[deviceField setStringValue:dev];
		}

	return self;
}




- (int) modeInquiry: sender
{
	int reply;
	unsigned char completionMessage[128];
	static char mode[20];
	BOOL	stop, rewind, ff, eject, pause, play, record;
	
	reply = [visca md_modeInquiry];

	fprintf(stderr," -- reply in modeInq is %02Xh\n", reply);
	
	if( reply == CMD_COMPLETION)
		{
		[visca copyCompletionMessage: completionMessage];

		if( completionMessage[1] != (unsigned char) 0xFF )
			{
			fprintf(stderr,"incomplete message %02Xh\n",	
				completionMessage[1]);
			return -1;
			}
		
		stop = rewind = ff = eject = pause = play = record = NO;
		
		switch( completionMessage[0] )
			{
			case MC1_STOP:
				sprintf(mode, "Stop");
				stop = YES;
				break;
			case MC1_FAST_FORWARD:
				sprintf(mode, "Fast Forward");
				ff = YES;
				break;
			case MC1_REWIND:
				sprintf(mode, "Rewind");
				rewind = YES;
				break;
			case MC1_EJECT:
				sprintf(mode, "Eject");
				eject = YES;
				break;
			case MC1_PAUSE:
				sprintf(mode, "Pause");
				play = pause = YES;
				break;
			case MC1_SLOW2:
				sprintf(mode, "Slow2");
				play = pause = YES;
				break;
			case MC1_SLOW1:
				sprintf(mode, "Slow1");
				play = pause = YES;
				break;
			case MC1_PLAY:
				sprintf(mode, "Play");
				play = YES;
				break;
			case MC1_FAST1:
				sprintf(mode, "Fast1");
				play = pause = YES;
				break;
			case MC1_FAST2:
				sprintf(mode, "Fast2");
				play = pause = YES;
				break;
			case MC1_SCAN:
				sprintf(mode, "Cue");
				play = ff = YES;
				break;

			case MC1_REVERSE_SLOW2:
				sprintf(mode, "RevSlow2");
				rewind = play = pause = YES;
				break;
			case MC1_REVERSE_SLOW1:
				sprintf(mode, "RevSlow1");
				rewind = play = pause = YES;
				break;
			case MC1_REVERSE_PLAY:
				sprintf(mode, "ReversePlay");
				rewind = play = YES;
				break;
			case MC1_REVERSE_FAST1:
				sprintf(mode, "RevFast1");
				rewind = play = pause = YES;
				break;
			case MC1_REVERSE_FAST2:
				sprintf(mode, "RevFast2");
				rewind = play = pause = YES;
				break;
			case MC1_REVERSE_SCAN:
				sprintf(mode, "Review");
				play = rewind = YES;
				break;
			case MC1_RECORD_PAUSE:
				sprintf(mode, "RecordPause");
				record = play = pause = YES;
				break;

			case MC1_RECORD:
				sprintf(mode, "Record");
				record = play = YES;
				break;
			default:
				sprintf(mode, "Unrecognized: %02X",
					 completionMessage[0]);
				break;
			}
		
		currentTransportMode = completionMessage[0];

		[self disableFlushWindow];
		[modeText 		setStringValue: mode];
		[fastForwardButton 	setState: ff];
		[stopButton 		setState: stop];
		[recordButton 		setState: record];
		[ejectButton 		setState: eject];
		[rewindButton 		setState: rewind];
		[pauseButton 		setState: pause];
		[playButton 		setState: play];

		[self reenableFlushWindow];
		[self flushWindowIfNeeded];

		}	
	else
		sprintf(mode,"Command not completed, %02Xh\n",
			reply);

	fprintf(stderr,"Mode == %s \n", mode);
	
	return reply;
}


- deviceChanged: sender
{
	return self;
}


- pause:sender
{
	currentTransportMode = MC1_PAUSE;
	[visca md_modeControl_1: currentTransportMode];
	return self;
}


- eject:sender
{
	currentTransportMode = MC1_EJECT;
	[visca md_modeControl_1: currentTransportMode];
    	return self;
}

- play:sender
{
	currentTransportMode = MC1_PLAY;
	[visca md_modeControl_1: currentTransportMode];
    	return self;
}

- stop:sender
{
	currentTransportMode = MC1_STOP;
	[visca md_modeControl_1: currentTransportMode];
	return self;
}

- record:sender
{
	currentTransportMode = MC1_RECORD;
	[visca md_modeControl_1: currentTransportMode];
	return self;
}

- fast_forward:sender
{
	int desiredMode;
	
	switch( currentTransportMode)
		{
		case MC1_REVERSE_PLAY:
			desiredMode = MC1_PLAY;
			break;
		case MC1_PLAY:
			desiredMode = MC1_FAST1;
			break;
		case MC1_FAST1:
			desiredMode = MC1_FAST2;
			break;
		default:
 			desiredMode = MC1_FAST_FORWARD;
			break;
		}
	fprintf(stderr,"Current ts = %02Xh, Desired ts = %02Xh\n",
		currentTransportMode, desiredMode);
	
	fprintf(stderr,"Executing: ret code = %02Xh\n",
		[visca md_modeControl_1: desiredMode]);
	usleep(10000000);
	[self modeInquiry: self];
	fprintf(stderr,"-- Current ts = %02Xh, Desired ts = %02Xh\n",
		currentTransportMode, desiredMode);
	if( desiredMode != currentTransportMode)
		{
		currentTransportMode = desiredMode;
		[self fast_forward: sender];
		}
	return self;
}

- rewind:sender
{
	int desiredMode;

	switch( currentTransportMode)
		{
		case MC1_PLAY:
			desiredMode = MC1_REVERSE_PLAY;
			break;
		case MC1_REVERSE_PLAY:
			desiredMode = MC1_REVERSE_FAST1;
			break;
		case MC1_FAST1:
			desiredMode = MC1_REVERSE_FAST2;
			break;
		default:
 			desiredMode = MC1_REWIND;
			break;
		}

	[visca md_modeControl_1: desiredMode];
	usleep(500);
	[self modeInquiry: self];
	if( desiredMode != currentTransportMode)
		{
		currentTransportMode = desiredMode;
		[self rewind: sender];
		}
	return self;
}

- (int) search: (struct ct_hmsf *)  search;
{
	fprintf(stderr,"Searching %02x:%02x:%02x:%02x\n",
		search->hh, search->mm, search->ss, search->ff);
			
	status = [visca md_search:CT_HMS counter: 
		(union counterType *) search];

	fprintf(stderr,"Search ended\n"  );

	return status;
}



- zoomIn: sender
{
	status = [visca md_cameraZoom: (int) ZOOM_TELE];
	if( status == CMD_ERROR )
		return [self handleError];
	else
		return self;
}



- zoomOut: sender
{
	status = [visca md_cameraZoom: (int) ZOOM_WIDE];
	if( status == CMD_ERROR )
		return [self handleError];
	else
		return self;
	return self;
}

- focusNear: sender
{
	status = [visca md_cameraFocus: (int) FOCUS_NEAR];
	if( status == CMD_ERROR )
		return [self handleError];
	else
		return self;
	return self;
}

- focusFar: sender
{
	status = [visca md_cameraFocus: (int) FOCUS_FAR];
	if( status == CMD_ERROR )
		return [self handleError];
	else
		return self;
}

- zoomFocusStop: sender
{

	status = [visca md_cameraFocus: (int) FOCUS_STOP];
	if( status == CMD_ERROR )
		return [self handleError];
	status = [visca md_cameraZoom: (int) ZOOM_STOP];
	if( status == CMD_ERROR )
		return [self handleError];
	else
		return self;
}

- frameForward: sender
{
	status = [visca md_modeControl_2:  MC2_FRAME_FORWARD];
	if( status == CMD_ERROR )
		return [self handleError];
	else
		return self;
}
	
- frameReverse: sender
{
	status = [visca md_modeControl_2:  MC2_FRAME_REVERSE];
	if( status == CMD_ERROR )
		return [self handleError];
	else
		return self;
}


- resetCounter: sender
{
	status = [visca md_subControl:  SC_COUNTER_RESET];
	if( status == CMD_ERROR )
		return [self handleError];
	else
		return self;
}
	
- realCounterMode: sender
{
	status = [visca md_subControl:  SC_REAL_COUNTER];
	if( status == CMD_ERROR )
		return [self handleError];
	else
		return self;
}

- relativeCounterMode: sender
{
	status = [visca md_subControl:  SC_RELATIVE_COUNTER];
	if( status == CMD_ERROR )
		return [self handleError];
	else
		return self;
}

- toggleAudio: sender
{
	status = [visca md_subControl:  SC_TOGGLE_AUDIO];
	if( status == CMD_ERROR )
		return [self handleError];
	else
		return self;
}

- toggleSpeed: sender
{
	status = [visca md_subControl:  SC_TOGGLE_SPEED];
	if( status == CMD_ERROR )
		return [self handleError];
	else
		return self;
}

- toggleDisplay: sender
{
	status = [visca md_subControl:  SC_TOGGLE_DISPLAY];
	if( status == CMD_ERROR )
		return [self handleError];
	else
		return self;
}


- cycleVideo: sender
{
	status = [visca md_subControl:  SC_CYCLE_VIDEO_IN];
	if( status == CMD_ERROR )
		return [self handleError];
	else
		return self;
}

- (BOOL) canBecomeMainWindow   { return NO; }

- handleError
{
	static char warnMessage[256];
	
	if( status != CMD_ERROR  )
		return self;
	
	errorCode = [visca errorCode];
	
	fprintf(stderr,"handleError: Error code = %02Xh.\n",
		errorCode);

	switch( errorCode )
		{	
		case 0x01:
			strcpy(errorMessage,"Message len error");
			break;
		case 0x02:
			strcpy(errorMessage,"Syntax error");
			break;
		case 0x03:
			strcpy(errorMessage,"Command buffer full");
			break;
		case 0x04:
			strcpy(errorMessage,"Command Cancelled");
			break;
		case 0x05:
			strcpy(errorMessage,"No socket");
			break;
		case ERROR_POWER:
			strcpy(errorMessage, ERRMSG_POWER);
			break;
		case ERROR_TIMEOUT:
			strcpy(errorMessage, ERRMSG_TIMEOUT);
			break;
		case ERROR_SEARCH:
			strcpy(errorMessage, ERRMSG_SEARCH);
			break;
		case ERROR_CONDITION:
			strcpy(errorMessage, ERRMSG_CONDITION);
			break;
		case ERROR_CAMERAMODE:
			strcpy(errorMessage, ERRMSG_CAMERAMODE);
			break;
		case ERROR_VCRMODE:
			strcpy(errorMessage, ERRMSG_VCRMODE);
			break;
		case ERROR_COUNTERTYPE:
			strcpy(errorMessage, ERRMSG_COUNTERTYPE);
			break;
		case ERROR_TUNER:
			strcpy(errorMessage, ERRMSG_TUNER);
			break;
		case ERROR_EMERGENCYSTOP:
			strcpy(errorMessage, ERRMSG_EMERGENCYSTOP);
			break;
		case ERROR_NOMEDIA:
			strcpy(errorMessage, ERRMSG_NOMEDIA);
			break;
		}			
	fprintf(stderr,"Error %02Xh in socket %d ==> %s\n",
		errorCode, socket, errorMessage);
	 	
	sprintf(warnMessage,"Error %02Xh in socket %d ==> %s\n",
		errorCode, socket, errorMessage);
	
	NXRunAlertPanel( "Error occured", warnMessage, "OK", NULL, NULL);

	return self;
		
}

- (unsigned short int) status 		{ return status; };
- (unsigned short int) errorCode 	{ return errorCode; };
- (char *) errorMessage 		{ return errorMessage; };

@end
