/*
 * Copyright 1988, 1989, 1990, 1991 Massachusetts Institute of Technology
 */

/* akai16x16_driver: the driver for the DP2000 16x16 Video Patch Panel */

#include "akai16x16.h"
#include "structs.h"
#include <stdio.h>

#define min(x,y) (x<y?x:y)
#define max(x,y) (x>y?x:y)


/* --------------------------------------------------------------- */
static int swtch (swtr, output, channel, input)
     SWTR_ptr swtr;
     int output, channel, input;

{
  char out[2], in[2], query[2], ret = 0xff;
  int cc = 0, to = 0;

  out[0] = ASSIGN_OUTPUT;
  in[0] = ASSIGN_INPUT;
  query[0] = QUERY_OUTPUT;

  input -=1 ; 

  if (channel == VIDEO_CHAN) {
    query[1] = out[1] = output + 0x10;
    in[1] = input + 0x10;
  } else if (channel == LEFT_CHAN && input < 8) {
    query[1] = out[1] = 2*output;
    in[1] = 2*input;
  } else if (channel == RIGHT_CHAN && input < 8) {
    query[1] = out[1] = 2*output + 1;
    in[1] = 2*input + 1;
  } else return 0;

  do {
    cc++;
    ttyutil_write (swtr->fd, out, 2, 0);
    ttyutil_write (swtr->fd, in, 2, 0);
    ttyutil_write (swtr->fd, query, 2, 0);
    to = 0;
    while (ttyutil_read (swtr->fd, &ret, 1, AKAI_TIMEOUT) < 0 && to < 10)
      to++;
/*
    if (DEBUG) 
      printf ("Swtch: %x <-- %x (%x)\n",(int)out[1], (int)in[1], (int)ret);
*/
  } while (ret != in[1] && cc < 5);
  
  if (cc == 5) return -1;
  return 0;
}

/* --------------------------------------------------------------- */
static int akai16x16_select (swtr)
     SWTR_ptr	swtr;
{
  char cmd[10], cm[10], ret[10];
  int cc, to;

#ifdef TRAP_BUG
  bsdsyslog(LOG_INFO, "about to fill cmd");
  bsdsyslog(LOG_INFO, "cmd = %d, cm = %d, ret = %d", cmd, cm, ret);
#endif /* TRAP_BUG */

  /* ttyutil_debug = DEBUG; */
  cmd[0] = SELECT_BASE + (char)swtr->devnum;
  cmd[1] = FILLER;
  cmd[2] = EOS;
  
  /*   if (DEBUG) printf ("AKAI: selecting switcher %d\n",swtr->devnum); */
#ifdef TRAP_BUG
  bsdsyslog(LOG_INFO, "about to loop");
#endif /* TRAP_BUG */
  to = 0;
  do {
#ifdef TRAP_BUG
    bsdsyslog(LOG_INFO, "beginning of loop");
#endif /* TRAP_BUG */
    to++;
    if (ttyutil_write (swtr->fd, cmd, 2, 0) == -1) return (-1);
#ifdef TRAP_BUG
    bsdsyslog(LOG_INFO, "wrote data");
#endif /* TRAP_BUG */
    while (ttyutil_read (swtr->fd, ret, 2, AKAI_TIMEOUT) < 0 && to < 10) 
      to++;
#ifdef TRAP_BUG
    bsdsyslog(LOG_INFO, "ending of loop");
#endif /* TRAP_BUG */
  } while (to < 10 && ret[0] != cmd[0]);
#ifdef TRAP_BUG
  bsdsyslog(LOG_INFO, "finished loop");
#endif /* TRAP_BUG */
  
  if (to == 10) {
    bsdsyslog(LOG_NOTICE, "akai16x16_select: %s: %s: timeout", 
	      swtr->devname, swtr->devname);
    return (-1);
  }
#ifdef TRAP_BUG
  bsdsyslog(LOG_INFO, "about to fill cm");
#endif /* TRAP_BUG */
  cm[0] = REQ_PATTERN;
  cm[1] = 0x01;

#ifdef TRAP_BUG
  bsdsyslog(LOG_INFO, "about to fill cmd");
#endif /* TRAP_BUG */
  cmd[0] = SET_PATTERN;
  cmd[1] = 0x01;
  cmd[2] = 0x01;

#ifdef TRAP_BUG
  bsdsyslog(LOG_INFO, "about to loop");
#endif /* TRAP_BUG */
  cc = 0;
  do {
    cc++;
    ttyutil_write (swtr->fd, cmd, 3, 0);
    ttyutil_write (swtr->fd, cm, 2, 0);
    to = 0;
    while (ttyutil_read (swtr->fd, ret, 2, AKAI_TIMEOUT) < 0 && to < 10)
      to++;
/*
    if (DEBUG)
      printf ("pattern: %x,%x --> %x, %x\n",1,1,(int)ret[0],(int)ret[1]);
*/
  } while ((cmd[1] != ret[0] || cmd[2] != ret[1]) && cc < 5);
#ifdef TRAP_BUG
  bsdsyslog(LOG_INFO, "finished 2nd loop");
#endif /* TRAP_BUG */

  if (cc == 5) {
    bsdsyslog(LOG_NOTICE, "akai16x16_select: %s: %s: 2nd timeout", 
	      swtr->devname, swtr->devname);
    return (-1);
  }
  return 0;
}

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

static int akai16x16_set_state( swtr, output, v, a1, a2 )
	SWTR_ptr swtr;
	int	output;	  /* the number of the output */
	int	v,a1,a2;  /* the number of the input patched to that channel */

{
  int retcode = 0;
/*
  if (DEBUG) printf ("%d switching to: %d %d %d\n",output,v,a1,a2);
*/
  if (!swtr || output<1 || output>NUM_OUTPUTS)  return -1;

  output -= 1;	/* adjust for zero-base */

  /* if anything is 0, leave it alone */

  if (v) {
    swtr->state[output].VideoSource = v = max(1,min(v,NUM_INPUTS));
    retcode += swtch (swtr, output, VIDEO_CHAN, v);
  }

  if (a1) {
    if (output < NUM_OUTPUTS/2 && a1 <= NUM_INPUTS/2) {
      swtr->state[output].LeftSource = a1 = max(1,min(a1,NUM_INPUTS));
      retcode += swtch (swtr, output, LEFT_CHAN, a1);
    } else {
      a1 = -2;
    }
  }

  if (a2) {
    if (output < NUM_OUTPUTS/2 && a2 <= NUM_INPUTS/2) {
      swtr->state[output].RightSource = a2 = max(1,min(a2,NUM_INPUTS));
      retcode += swtch (swtr, output, RIGHT_CHAN, a2);
    } else {
      a2 = -2;
    }
  }
/*
  if (DEBUG) 
    printf ("AKAI SET STATE %d: %d %d %d :%d\n",output,v-1,a1-1,a2-1,retcode);
*/
  if (retcode < 0) return -1;
  return 0;
}

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

int akai16x16_reset (swtr)
	SWTR_ptr	swtr;

{
  char	in[2], out[2], ret[2], cmd[1];
  int output, default_in;
  int i=0;


  if (!swtr) return -1;
  if (swtr->fd<0) return -1;

/*  if (DEBUG) printf("Resetting akai "); */
  
/*
  while (1) {
    cmd[0] = ACK;
    ttyutil_write (swtr->fd, cmd, 1, 0);
    i = ttyutil_read (swtr->fd, cmd, 1, AKAI_TIMEOUT);
    if (i < 1) {
      if (DEBUG) {
	printf ("!%d",i);
	fflush(stdout);
      }
    } else 
      break;
  }
*/

  if (akai16x16_select (swtr) < 0) return -1;
#ifdef TRAP_BUG
  bsdsyslog(LOG_INFO, "selected AKAI switcher");
#endif /* TRAP_BUG */
  for (i = 1; i <= NUM_OUTPUTS; i++) {
    if (swtr->default_input[i] != -1) default_in = swtr->default_input[i];
    else default_in = i;
    if (akai16x16_set_state (swtr, i, default_in, default_in, default_in) < 0)
      return -1;
  }
#ifdef TRAP_BUG
  bsdsyslog(LOG_INFO, "set AKAI switcher to defaults");
#endif /* TRAP_BUG */

  return 0;
}

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

int akai16x16_set_chan_src (swtr, chan, srcnum, output)
	SWTR_ptr swtr;
	int	output;	
	int	chan;
	int	srcnum;

{
  int	ret = -1;
  char	cmd[10];
  int curvid = 0, curch1 = 0, curch2 = 0;

  if (!swtr) return -1;
  if (swtr->fd < 0) return -1;

  srcnum = max (1, min(srcnum, NUM_INPUTS));
  output = max (1, min(output, NUM_OUTPUTS));
  
  if (chan&VIDEO_CHAN) curvid = srcnum;
  if (chan&LEFT_CHAN) curch1 = srcnum;
  if (chan&RIGHT_CHAN) curch2 = srcnum;

/*
  if (DEBUG) 
    printf("Set output %d of akai dp2000 to input %d, mask %d[%d %d %d]\n",
	   output, srcnum, chan, curvid, curch1, curch2);
*/

  if (akai16x16_select (swtr) < 0) return -1;
  if (akai16x16_set_state (swtr, output, curvid, curch1, curch2) < 0)
    return -1;
  return 0;
}

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

int akai16x16_inquire( swtr, output, vsrc, lsrc, rsrc )
	SWTR_ptr swtr;
	int	output;
	int *	vsrc;
	int *	lsrc;
	int *	rsrc;

{

  if( output < 1 || output > NUM_OUTPUTS || !swtr)
    return -1;	/* don't mess with the channel return values */
  output -= 1;		/* adjust for zero-base */

  /* This is only here so that an inquire can be used to check if
     a switcher is hooked up. */
  if (akai16x16_select (swtr) < 0) return -1;

  *vsrc = swtr->state[output].VideoSource;
  *lsrc = swtr->state[output].LeftSource;
  *rsrc = swtr->state[output].RightSource;
  /*  if (DEBUG) printf("Inquired about akai output %d\n",output); */
  return 0;
}

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

int akai16x16_setfuncs (swtr)
	SWTR_ptr	swtr;

{
  swtr->reset = akai16x16_reset;
  swtr->set_chan_src = akai16x16_set_chan_src;
  swtr->inquire = akai16x16_inquire;
  swtr->inputs = NUM_INPUTS;	/* from akai16x16.h */
  swtr->outputs = NUM_OUTPUTS;	/* from akai16x16.h */
  return 0;
}



