/*-=-=-=-=-=-=-=-=-=-=-=- RCCL/RCI Notice of Copyright -=-=-=-=-=-=-=-=-=-=-*
 *									    *
 *	Copyright (C) 1987, 1991 by John E. Lloyd.			    *
 *									    *
 *	Information on copyright permissions, as well as a complete	    *
 *	disclaimer of warranty, is given in the file COPYRIGHT.		    *
 *									    *
 *-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/

/* general purpose driver testbed */

#ifdef VXWORKS_CFG
#define main	driverTest_
#endif

#include <setjmp.h>

#include "../h/cdefs.h"
#include "../h/IOdevice.h"
#include "../h/rciTask.h"
#include "../h/rciMacros.h"

#include "driverTest.h"

extern int errno;

#define	COMMAND(s)	(strcmp (key_buf, s) == 0)
#define	COMMANDS(s)	(strncmp (key_buf, s, strlen(s)) == 0)
char key_buf [256];

extern doread();
extern dotestRead();
extern dowrite();
extern dotestWrite();
extern doprobe();
extern doattach();
extern dodetach();
extern dosignal();
extern doioctl();
extern dopoke();
extern dopulse();
extern dopeek();
extern doexamine();

extern cycleReadWrite();

int deviceSet = 0;

union _pack {
	unsigned char b[2];
	unsigned short s;
  } pack;

RCI_DESC *td;
int retval;

TEST_BLOCK *tblk;

jmp_buf env;

onAbort(code, msg, td)
int code;
char *msg;
RCI_DESC *td;
{
	printf ("\nABORT code %d on task %s, cycle %d\n%s\n",
		 code, rciTaskName(td), td->tcb->cycleCount, msg);
	longjmp (env, 1);
}

main(argc, argv)
int argc;
char *argv[];
{
	int i, j, k;
	int interface[10];
	int interval;

	char *keytree, *tree_match_parse(), *tree_match_err_at();
	char devName[256];
	int address;
	int size;
	int index;
	int value;
	int status;
	int num;
	int cpuNum = UNDEF;
	int numbytes;
	int argnum;
	int argval;
	int ioctlNum;

	struct devAddr devAddr;

	argc--; argv++;
	while (argc)
	 { if (ARGUMENT ("-cpu"))
	    { int x;
	      argc--; argv++;
	      if (argc < 1)
	       { argc = -1;
		 break;
	       }
	      if (!scanInteger (&x, *argv))
	       { fatalMsg ("integer expected after '-cpu' option\n");
	       }
	      cpuNum = x;
	    }
	   else
	    { argc = -1;
	      break;
	    }
	   argc--; argv++;
	 }
	if (argc < 0)
	 { usageMsg ("dt [-cpu <number>]\n");
	 }
	if (cpuNum == UNDEF)
	 { cpuNum = 0;
	 }
	keytree = tree_match_parse("					\
(	quit								\
	set								\
	 (device 							\
	   (%s", devName, "						\
	     (%x", &address, ",,,	\"device address (hex)\"))	\
	  arg								\
	   (%d", &argnum, ",0,,		\"argument number\"		\
	     (%x", &argval, ",,,	\"argument value\")))		\
	probe								\
	read								\
	write								\
	 (%d", &size, ",0,256,		\"number of bytes\")		\
	signal								\
	 (%d", &num, ",,,		\"signal number\")		\
	attach								\
	detach								\
	ioctl								\
	 (SIGINTER_ENABLE 						\
	  SIGINTER_DISABLE						\
	  TIMEOUT							\
	   (%d", &value, ",,,		\"timeout value\")		\
	  SET_BLOCKTIME							\
	   (%d", &value, ",,,		\"timeout value\")		\
	  GET_BLOCKTIME							\
	  %d", &ioctlNum, ",,,		\"ioctl number\"		\
	 )								\
	testRead							\
	testWrite							\
	examine								\
	peek								\
	    (%d", &index, ",,,		\"byte offset\")		\
	poke								\
	 (%x", &value, ",,,		\"value (hex)\"			\
	   (%d", &index, ",,,		\"byte offset\"))		\
	pulse								\
	 (%x", &value, ",,,		\"value (hex)\"			\
	   (%d", &index, ",,,		\"byte offset\"))		\
	cycle								\
	 (read-write							\
	   (%d", &interval, ",,,	\"interval (msec)\"))		\
	loop								\
	 (read-write)							\
)",0);

	if (keytree == 0)
	 { printf ("ERROR/Parse error at %.30s\n", tree_match_err_at());
	   exit (-1);
	 }
	if ((td = rciCreate ("driverTest", 1<<cpuNum)) == NULL)
	 { printErrors();
	   exit (-1);
	 }
	if ((tblk = (TEST_BLOCK*)allocMem("TESTBLOCK", 
					     sizeof(TEST_BLOCK), 0)) == NULL)
	 { printErrors();
	   exit (-1);
	 }
	tblk->bufsize = BUFSIZE;

	setjmp(env);
	rciAbortHandler (onAbort);

	for (i=0; i<MAX_DEVARGS; i++)
	 { devAddr.args[i] = 0;
	 }

	do
 	 { tree_match (keytree, "DRIVERTEST> ", key_buf);

	   if (COMMAND("set device"))
	    { int s;

	      devAddr.name = devName;
	      devAddr.address = address;
	      deviceSet = 0;

	      rciDeallocDevice (td);

	      if ((s = rciAllocDevice (td, &devAddr, 0)) < 0)
	       { printErrors();
		 clearErrors();
	       }
	      else if (s != 0)
	       { int size;

		 tblk->userMode = (strcmp(devName,"sim")==0) ? 1 : 0;

		 if ((size = execute (doprobe)) < 0)
		  { printf ("probe reports error %d\n", TASKDEV(td)->error);
		  }
		 else
		  { printf ("device size is %d\n", size);
		    deviceSet = 1;
		    tblk->deviceSize = size;
		  }
	       }
	      else
	       { printf ("device %s not found\n", devName);
	       }
	    }
	   else if (COMMAND ("set arg"))
	    { if (argnum >= MAX_DEVARGS)
	       { printf ("argument number must be between 0 and %d\n",
			  MAX_DEVARGS);
	       }
	      else
	       { devAddr.args[argnum] = argval;
	       }
	    }
	   else if (!deviceSet)
	    { printf ("no device set\n");
	    }
	   else if (COMMAND("attach"))
	    { if ((status = execute (doattach)) < 0)
	       { printf ("attach reports error %d\n", TASKDEV(td)->error);
	       }
	      else
	       { printf ("%d\n", status);
	       }
	    }
	   else if (COMMAND("detach"))
	    { if ((status = execute (dodetach)) < 0)
	       { printf ("detach reports error %d\n", TASKDEV(td)->error);
	       }
	      else
	       { printf ("%d\n", status);
	       }
	    }
	   else if (COMMAND("signal"))
	    { tblk->signalNum = num;
	      if ((status = execute (dosignal)) < 0)
	       { printf ("signal reports error %d\n", TASKDEV(td)->error);
	       }
	      else
	       { printf ("%d\n", status);
	       }
	    }
	   else if (COMMAND("testRead"))
	    { if ((status = execute (dotestRead)) < 0)
	       { printf ("testRead reports error %d\n", TASKDEV(td)->error);
	       }
	      else
	       { printf ("%d\n", status);
	       }
	    }
	   else if (COMMAND("testWrite"))
	    { if ((status = execute (dotestWrite)) < 0)
	       { printf ("testWrite reports error %d\n", TASKDEV(td)->error);
	       }
	      else
	       { printf ("%d\n", status);
	       }
	    }
	   else if (COMMAND("read"))
	    { if ((status = execute (doread)) < 0)
	       { printf ("read reports error %d\n", TASKDEV(td)->error);
	       }
	      else
	       { printf ("%d\n", status);
		 if (status <= 40)
		  { for (i=0; i<status/2; i++)
		     { pack.b[0] = tblk->readBuf[i*2];
		       pack.b[1] = tblk->readBuf[i*2+1];
		       printf ("%2d  %02x %02x\n", 
				i*2, pack.b[1], pack.b[0]);
		     }
		    if (status % 2)
		     { printf ("%2d     %02x\n", tblk->readBuf[status-1]);
		     }
		  }
		 else
		  { printf ("read buffer too big to print\n");
		  }
	       }
	    }
	   else if (COMMAND("write"))
	    { for (i=0; i<size; i++)
	       { tblk->writeBuf[i] = i;
	       }
	      tblk->writeSize = size;
	      if ((status = execute (dowrite)) < 0)
	       { printf ("write reports error %d\n", TASKDEV(td)->error);
	       }
	      else
	       { printf ("%d\n", status);
	       }
	    }
	   else if (COMMANDS("ioctl"))
	    { if (COMMAND ("ioctl SIGINTER_DISABLE"))
	       { tblk->ioctlCom = IOC_SIGINTER_DISABLE;
	       }
	      else if (COMMAND ("ioctl SIGINTER_ENABLE"))
	       { tblk->ioctlCom = IOC_SIGINTER_ENABLE;
	       }
	      else if (COMMAND ("ioctl SET_BLOCKTIME"))
	       { tblk->ioctlCom = IOC_SET_BLOCKTIME;
		 *(int *)tblk->ioctlBuf = value;
	       }
	      else if (COMMAND ("ioctl GET_BLOCKTIME"))
	       { tblk->ioctlCom = IOC_GET_BLOCKTIME;
	       }
	      else if (COMMAND ("ioctl TIMEOUT"))
	       { tblk->ioctlCom = IOC_TIMEOUT;
		 *(int *)tblk->ioctlBuf = value;
	       }
	      else
	       { tblk->ioctlCom = ioctlNum;
	       }
	      if ((status = execute (doioctl)) < 0)
	       { printf ("ioctl reports error %d\n", TASKDEV(td)->error);
	       }
	      else
	       { printf ("%d\n", status);
		 if (COMMAND ("ioctl GET_BLOCKTIME"))
		  { printf ("blocktime is %d\n", *(int*)tblk->ioctlBuf);
		  }
	       }
	    }
	   else if (COMMAND("examine"))
	    { if (tblk->deviceSize > tblk->bufsize)
	       { printf ("devsize of %d too big for peek buffer\n", 
			 tblk->deviceSize);
	       }
	      else
	       { if (execute (doexamine) >= 0)
		  { for (i=0; i<(tblk->deviceSize+1)/2; i++)
		     { printf ("%2d  0x%04x\n", 2*i, tblk->peekBuf[i]);
		     }
		  }
	       }
	    }
	   else if (COMMAND("peek"))
	    { 
	      if (index >= tblk->deviceSize-1)
	       { printf ("peek extends beyond device\n");
	       }
	      else
	       { tblk->peekIndex = index/2;
		 execute (dopeek);
		 printf ("%4d  0x%04x\n", index, tblk->peekBuf[0]);
	       }
	    }
	   else if (COMMAND ("poke"))
	    { if (index % 2)
	       { printf ("byte offset must be even (word aligned)\n");
	       }
	      else if (index > (tblk->deviceSize-2))
	       { printf ("maximum index for this device is %d\n",
			 (tblk->deviceSize-2));
	       }
	      else
	       { tblk->pokeBuf = 0xffff & value;
		 tblk->pokeIndex = index/2;
		 execute (dopoke);
	       }
	    }
	   else if (COMMAND ("pulse"))
	    { if (index % 2)
	       { printf ("byte offset must be even (word aligned)\n");
	       }
	      else if (index > (tblk->deviceSize-2))
	       { printf ("maximum index for this device is %d\n",
			 (tblk->deviceSize-2));
	       }
	      else
	       { tblk->pulseBuf = 0xffff & value;
		 tblk->pulseIndex = index/2;
		 execute (dopulse);
	       }
	    }
	   else if (COMMAND ("cycle read-write"))
	    { char buf[256];
	      int k;

	      if (rciControlFxns (td, NULLF, cycleReadWrite, NULLF, 0) < 0)
	       { printErrors();
		 clearErrors();
		 continue;
	       }
	      if (interval < 1)
	       { printf ("Error -- illegal interval (%d)\n", interval);
		 continue;
	       }
	      rciScheduling (td, ON_CLOCK, 0);
	      rciRate (td, interval, 0);
	      if (rciStart (~0) < 0)
	       { printErrors();
		 clearErrors();
		 continue;
	       }
	      printf ("Hit any key to stop\n");
	      k = 0;
	      while (!testchar())
	       { if (td->tcb->cycleCount > k + 1000)
		  { k += 1000;
		    printf ("%6d cycles\n", k);
		  }
		 nap(1.0);
	       }
	      gets (buf);
	      rciRelease (~0);
	    }
	   else if (COMMAND ("loop read-write"))
	    { char buf[256];
	      int k;

	      printf ("Hit any key to stop\n");
	      k = 0;
	      while (!testchar())
	       { if ((k++ % 1000) == 0)
		  { printf ("%6d cycles\n", k);
		  }
		 cycleReadWrite (td);		 
	       }
	      gets (buf);
	    }
	 }
	while (!(COMMAND("quit")));
}

execute (fxn)
int (*fxn)();
{
	int retval;
	
	if (tblk->userMode)
	 { retval = (*fxn)(td, 0);
	 }
	else
	 { if (rciExecute (td, fxn, 0, &retval) < 0)
	    { printErrors();
	      exit (-1);
	    }
	 }
	return (retval);
}
