
/* sony_driver.c: command routines for SONY LDP-1000A videodisc player */

#include "sony.h"
#include "rpd_driver.h"
#include <stdio.h>

typedef unsigned char byte;

#define MAXRETRYS 0		/* the number of times we try before giving up */
#define SONYDELAY 10		/* 10 millisecs between chars for sony to swallow */
#define SONY_STD_WAIT 250	/* normal time before a timeout occurs */

extern int ttyutil_debug;

int		sony_debug = 0;
static	int  	retry = 0;
static	char	inchars[16];
static int	lid_open = 0;
static int	motor_off = 0;

/* ------------------------------------------------------------------------ */

sony_cmd(rpd,num)

	RPD_ptr	rpd;
	int 	num;
{
int	cmd;
int	res;
int	loadtime = 15000;	/* 15 seconds for loading/unloading */

	/*
	 	all commands are sent twice, so that an unsolicited ACK
		is not mistaken for the normal response
	*/

	switch(num)
	{
		case INDEX_ON:
			cmd = SONY_INDEXON;
			res = sony_ttyio(rpd->fd,&cmd,1,1);
			res = sony_ttyio(rpd->fd,&cmd,1,1);
			if( res == SONY_ACK )	/* now set state */
				rpd->state.indexon = 1;
			break;
		case INDEX_OFF:
			cmd = SONY_INDEXOFF;
			res = sony_ttyio(rpd->fd,&cmd,1,1);
			res = sony_ttyio(rpd->fd,&cmd,1,1);
			if( res == SONY_ACK )	/* now set state */
				rpd->state.indexon = 0;
			break;
		case A1_ON:
			cmd = SONY_CH1ON;
			res = sony_ttyio(rpd->fd,&cmd,1,1);
			res = sony_ttyio(rpd->fd,&cmd,1,1);
			if( res == SONY_ACK )	/* now set state */
				rpd->state.audio1_on = 1;
			break;
		case A1_OFF:
			cmd = SONY_CH1OFF;
			res = sony_ttyio(rpd->fd,&cmd,1,1);
			res = sony_ttyio(rpd->fd,&cmd,1,1);
			if( res == SONY_ACK )	/* now set state */
				rpd->state.audio1_on = 0;
			break;
		case A2_ON:
			cmd = SONY_CH2ON;
			res = sony_ttyio(rpd->fd,&cmd,1,1);
			res = sony_ttyio(rpd->fd,&cmd,1,1);
			if( res == SONY_ACK )	/* now set state */
				rpd->state.audio2_on = 1;
			break;
		case A2_OFF:
			cmd = SONY_CH2OFF;
			res = sony_ttyio(rpd->fd,&cmd,1,1);
			res = sony_ttyio(rpd->fd,&cmd,1,1);
			if( res == SONY_ACK )	/* now set state */
				rpd->state.audio2_on = 0;
			break;
		case LOAD:
			cmd = SONY_MOTORON;
			sony_getstatus(rpd);
			if( !motor_off )
			{
				res = SONY_ACK;
				break;
			}
			if( lid_open )
			{
				res = -1;
				break;
			}
			/* special processing; because of long timeout, wait for byte here */
			sony_ttyio(rpd->fd,&cmd,1,0);
			res = ttyutil_read(rpd->fd,inchars,1,loadtime);
			if( res > 0 && inchars[res-1] == SONY_ACK )
			{
				rpd->state.volume_loaded = 1;
				strcpy(rpd->volume,"#ffffff");	/* it's empty */
				res = SONY_ACK;
			}
			break;
		case UNLOAD:
			cmd = SONY_MOTOROFF;
			sony_getstatus(rpd);
			if( motor_off || lid_open )
			{
				res = SONY_ACK;
				break;
			}
			/* special processing; because of long timeout, wait for byte here */
			sony_ttyio(rpd->fd,&cmd,1,0);
			res = ttyutil_read(rpd->fd,inchars,1,loadtime);
			if( res > 0 && inchars[res-1] == SONY_ACK )	/* now set state */
			{
				rpd->state.volume_loaded = 0;
				rpd->volume[0] = 0;
				res = SONY_ACK;
			}
			break;
		default:
			fprintf(stderr,"sony_cmd: illegal request %d\n",cmd);
			break;
	}

	if( res != SONY_ACK )
		return(-1);
	else
		return(0);
}

/* ------------------------------------------------------------------------ */

sony_varspeed(rpd,num)

	RPD_ptr	rpd;
	int	num;
{
int 	cmd;
int	res;

	switch(num)
	{
		case R_MAX:
			cmd = SONY_RSCAN;		
			res = sony_ttyio(rpd->fd,&cmd,1,1);
			res = sony_ttyio(rpd->fd,&cmd,1,1);
			if( res == SONY_ACK );
			break;
		case R_VERY_FAST:
			cmd = SONY_RSCAN;
			res = sony_ttyio(rpd->fd,&cmd,1,1);
			res = sony_ttyio(rpd->fd,&cmd,1,1);
			if( res == SONY_ACK );
			break;
		case R_FAST:
			cmd = SONY_RFAST;
			res = sony_ttyio(rpd->fd,&cmd,1,1);
			res = sony_ttyio(rpd->fd,&cmd,1,1);
			if( res == SONY_ACK );
			break;
		case R_PLAY:
			cmd = SONY_RPLAY;
			res = sony_ttyio(rpd->fd,&cmd,1,1);
			res = sony_ttyio(rpd->fd,&cmd,1,1);
			if( res == SONY_ACK );
			break;
		case R_SLOW:
			cmd = SONY_RSLOW;
			res = sony_ttyio(rpd->fd,&cmd,1,1);
			res = sony_ttyio(rpd->fd,&cmd,1,1);
			if( res == SONY_ACK );
			break;
		case R_VERY_SLOW:
			cmd = SONY_RSTEP;
			res = sony_ttyio(rpd->fd,&cmd,1,1);
			res = sony_ttyio(rpd->fd,&cmd,1,1);
			if( res == SONY_ACK );
			break;
		case STOP:
			cmd = SONY_STILL;
			res = sony_ttyio(rpd->fd,&cmd,1,1);
			res = sony_ttyio(rpd->fd,&cmd,1,1);
			if( res == SONY_ACK );
			break;
		case F_VERY_SLOW:
			cmd = SONY_FSTEP;
			res = sony_ttyio(rpd->fd,&cmd,1,1);
			res = sony_ttyio(rpd->fd,&cmd,1,1);
			if( res == SONY_ACK );
			break;
		case F_SLOW:
			cmd = SONY_FSLOW;
			res = sony_ttyio(rpd->fd,&cmd,1,1);
			res = sony_ttyio(rpd->fd,&cmd,1,1);
			if( res == SONY_ACK );
			break;
		case F_PLAY:
			cmd = SONY_FPLAY;
			res = sony_ttyio(rpd->fd,&cmd,1,1);
			res = sony_ttyio(rpd->fd,&cmd,1,1);
			if( res == SONY_ACK );
			break;
		case F_FAST:
			cmd = SONY_FFAST;
			res = sony_ttyio(rpd->fd,&cmd,1,1);
			res = sony_ttyio(rpd->fd,&cmd,1,1);
			if( res == SONY_ACK );
			break;
		case F_VERY_FAST:
			cmd = SONY_FSCAN;
			res = sony_ttyio(rpd->fd,&cmd,1,1);
			res = sony_ttyio(rpd->fd,&cmd,1,1);
			if( res == SONY_ACK );
			break;
		case F_MAX:
			cmd = SONY_FSCAN;
			res = sony_ttyio(rpd->fd,&cmd,1,1);
			res = sony_ttyio(rpd->fd,&cmd,1,1);
			if( res == SONY_ACK );
			break;
		default:
		fprintf(stderr,"sony_varspeed: illegal cmd %d\n",num);
			return(-1);
			break;
	}


	if( res != SONY_ACK )
		return(-1);
	else
		return(0);
}

/* ------------------------------------------------------------------------ */

sony_jog(rpd,num)

	RPD_ptr	rpd;
	int	num;
{
int	i;
int	cmd;
int	dir;

	(num > 0) ? (dir=SONY_FSTEP) : (dir=SONY_RSTEP);
	if( num<0 ) num = (-num);

	for( i=0; i<abs(num); i++ )
	{
		if( sony_ttyio(rpd->fd,&dir,1,0) )
			return (-1);
		mpause(33);	/* 33 millisecs */
		cmd = SONY_STILL;
		if( sony_ttyio(rpd->fd,&cmd,1,0) )
			return (-1);
	}
	return (0);
}

/* ------------------------------------------------------------------------ */

sony_getframe(rpd)

	RPD_ptr	rpd;
{
int	cmd;

	/* can't SONY_CL or stops playing */
	cmd = SONY_ADDRINQ;
	if( sony_ttyio(rpd->fd,&cmd,1,5) == -1 )
		return (-1);
	inchars[5] = '\0';
	return (atoi(inchars));
}

/* ------------------------------------------------------------------------ */

sony_getstatus(rpd)

	RPD_ptr	rpd;
{
int	cmd;
int	res;
int	i;
int	nopr;

	cmd = SONY_STATUSINQ;
	if( sony_ttyio(rpd->fd,&cmd,1,5) == -1 )
	{
		fprintf(stderr,"%s: unable to get status\n",rpd->devname);
		return (-1);
	}

	motor_off = ( inchars[0] & 32 );
	lid_open = ( inchars[0] & 8 );
	return 0;
			
/*	shows the raw status bytes
	for( i=0; i<5; i++ )
		printf("[%d] %02x\n",i,(int)inchars[i]);

	printf("--------------\n");

	if( inchars[0] & 64 )
		printf("\tin search/repeat mode\n");

	if( inchars[0] & 32 )
		printf("\tmotor is OFF\n");

	if( inchars[0] & 16 )
		printf("\tplayer is NOT initialized! (lid open?)\n");

	if( inchars[0] & 8 )
		printf("\tlid is open!\n");

	if( inchars[0] & 1 )
		printf("\tplayer has ERROR condition!\n");

	if( inchars[2] & 64 )
		;
	else
		printf("\tplayer is in PROGRAM mode!\n");

	if( inchars[3] & 8 )
		;
	else
		printf("\tplayer auto-stopped by code or program!\n");

	if( inchars[3] & 4 )
		printf("\tin REPEAT mode!\n");

	if( inchars[3] & 2 )
		printf("\tin SEARCH mode!\n");
	
	printf("\tMOTION: ");

	nopr = 0;

	if( inchars[4] & 32 )
	{
		printf("stop ");
		nopr = 1;
	}
	else	
	{
		if( inchars[4] & 16 )
			printf("scan ");
		else if( inchars[4] & 4 )
			printf("slow ");
		else if( inchars[4] & 8 )
			printf("step ");
		else if( inchars[4] & 2 )
			printf("fast ");
		else if( inchars[4] & 1 )
			printf("play ");
		else
		{
			printf("still ");
			nopr = 1;
		}
	}

	if( !nopr )
	{
		if( inchars[4] & 128 )
			printf("reverse ");
		else
			printf("forward ");
	}

	printf("\n");
	printf("--------------\n");
*/
}	

/* ------------------------------------------------------------------------ */

sony_search(rpd,frame,wait)

	RPD_ptr	rpd;
	int	frame;
	int	wait;		/* if true, hangs until it gets there 
					or times out */
{
byte	cmdstr[16];
byte	reply[16];
int	res;
int	len;

	sprintf(cmdstr,"%c%c%c",SONY_CL,SONY_CE,0);
	sony_ttyio(rpd->fd,cmdstr,strlen(cmdstr),1);

	sprintf(cmdstr,"%c%05d%c%c",
		SONY_SEARCH,frame,SONY_ENTER,0);
	len = strlen(cmdstr);

	ttyutil_clear(rpd->fd);
	
	if( (res = ttyutil_write(rpd->fd,cmdstr,len,10)) < 0 )
	{
		fprintf(stderr,"search: write failed; res = %d\n",res);
		return(-1);
	}

	if( !wait )		/* don't wait for reply */
	{
		return(0);
	}
	else if( (res = ttyutil_read(rpd->fd,reply,len+1,6000)) < 0 )
	{
		if( res == -1 )
			fprintf(stderr,"search: read failed; res = %d\n",res);
		if( res == -2 )
			fprintf(stderr,"search: timeout\n");
		return(-1);
	}

	if( reply[len] != SONY_COMPLETION )
	{
		fprintf(stderr,"search: return code error %d\n",reply[len]);
		return(-1);
	}
	return(0);
}

/* ------------------------------------------------------------------------ */

sony_reset(rpd)

	RPD_ptr	rpd;
{
byte cmdstr[5];
int	ret = 0;


	sprintf(cmdstr,"%c%c%c",SONY_CL,SONY_CE,0);
	if( sony_ttyio(rpd->fd,cmdstr,strlen(cmdstr),2) < 0)
	{
		rpd->state.volume_loaded = 0;
		rpd->state.not_responding = 1;
		return -1;
	}
	
	if( sony_getstatus(rpd) )	/* couldn't even get status */
	{
		rpd->state.volume_loaded = 0;
		rpd->state.not_responding = 1;
		return -1;		
	}

	if( lid_open )
	{
		fprintf(stderr,"%s: lid is open\n",rpd->devname);
		rpd->state.not_responding = 1;
		rpd->state.volume_loaded = 0;
		ret = -1;
	}

	if( motor_off && !lid_open )
	{
		if( (*rpd->cmd)(rpd,LOAD) )
			ret += -1;
	}

	ret += sony_cmd(rpd,INDEX_OFF);
	ret += sony_cmd(rpd,A1_ON);
	ret += sony_cmd(rpd,A2_ON);

	if( ret < 0 )
	{
		rpd->state.volume_loaded = 0;
		rpd->state.not_responding = 1;
		fprintf(stderr,"rpd '%s' not responding\n",rpd->devname);
		ret = -1;
	}
	else
	{
		rpd->state.not_responding = 0;
		ret = 0;
	}
	return ret;
}

/* ------------------------------------------------------------------------ */

sony_segplay(rpd,f1,f2,wait)

	RPD_ptr	rpd;
	int	f1,f2;
	int	wait;		/* if true, hangs until done */
{
byte cmdstr[16];
byte reply[16];
int  res;
int  len;

	if( f1 > f2 ) 
	{
		fprintf(stderr,"%s: segplay: can only play forward yet\n",rpd->devname);
		return(-1);
	}
	len = f2 - f1;

	sprintf(cmdstr,"%c%05d%c%c",SONY_SEARCH,f1,SONY_ENTER,0);

	sony_search( rpd, f1, 1 );	/* wait for the reply */

	sprintf(cmdstr,"%c%05d%c%c%c%c",
		SONY_REPEAT,f2,SONY_ENTER,'1',SONY_ENTER,0);
	ttyutil_clear(rpd->fd);
	if( (res = ttyutil_write(rpd->fd,cmdstr,strlen(cmdstr),10)) == -1 )
	{
		fprintf(stderr,"write error; res = %d\n",res);
		return(-1);
	}

	if( !wait )
	{
		return(0);
	}
	else if( (res = ttyutil_read(rpd->fd,reply,strlen(cmdstr)+1,
		(len*33)+1000)) < 0 )
	{
		if( res==-1 )
			fprintf(stderr,"%s: read error; res = %d\n",rpd->devname,res);
		else if (res==-2)
			fprintf(stderr,"%s: time out on play\n",rpd->devname);
		return(-1);	
	}

	return(0);
}

/* ------------------------------------------------------------------------ */

sony_ttyio( fd, cmdstr, writenum, readnum )

	int	fd;
	char 	*cmdstr;
	int	writenum;
	int	readnum;
{
int	num = 0;

	ttyutil_debug = sony_debug;
	ttyutil_clear(fd);

	if( ttyutil_write( fd,cmdstr,writenum,SONYDELAY ) == -1 )
		return (-1);

	if( readnum == 0 )
		return (0);
	
	if( (num=ttyutil_read(fd,inchars,readnum,SONY_STD_WAIT)) < 0 )
		return (-1);	/* timeout after .5 seconds */

	if( num==-2 || (readnum==1 && inchars[0] == SONY_ERROR) )
	{
		if( sony_debug )
		{
			if( num == -2 )
			fprintf(stderr,"sony_ttyio: NO RESPONSE, try %d\n",retry+1);
			else
			fprintf(stderr,"sony_ttyio: ERROR RESPONSE, try %d\n",retry+1);
		}
		if( retry++ < MAXRETRYS )
		{
		int rv;
			rv = sony_ttyio(fd,cmdstr,writenum,readnum);
			retry = 0;
			return (rv);
		}
		else
		{
			fprintf(stderr,"sony_ttyio: i/o timeout\n");
			return (-1);
		}
	}

	if( readnum==1 )	/* search - completion, nottarget, error */
		return ((int)inchars[0]);
	return(0);
}

/* ------------------------------------------------------------------------ */

sony_setfuncs( disc )

	RPD_ptr	disc;
{
	disc->reset = sony_reset;
	disc->cmd = sony_cmd;
	disc->search = sony_search;
	disc->segplay = sony_segplay;
	disc->getframe = sony_getframe;
	disc->varspeed = sony_varspeed;
	disc->jog = sony_jog;
	disc->record = NULL;
}
