/*-=-=-=-=-=-=-=-=-=-=-=- 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.		    *
 *									    *
 *-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/

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

	RCI testing program which allows a user to interactively
	call most of the basic RCI primitives. Typically, I run this
	program with the script rcitest2CPU.cts (if I have 
	at least one slave CPU on the system) or rcitest1CPU.cts (if
	I only have an auxiliary CPU on the system).

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

#include <stdio.h>
#include <signal.h>

#ifndef VXWORKS_CFG
#include <setjmp.h>
#include <sys/file.h>
#else
#include <vxWorks.h>
#include <setjmp.h>
#define main()		rcitest_()
#endif

#ifdef sparc
#include <floatingpoint.h>
#endif

#include "messageDefs.h"
#include "rcitest.h"
#include "../h/rciTask.h"
#include "../h/rciMacros.h"
#include "../h/IOdevice.h"

extern int auxDebug;

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

extern cfstart();
extern cfrelse();
extern cfxn1();
extern cfxn2();
extern cfxn3();
extern executeFxn();

TASKCOM *taskcom[MAX_RCI_TASKS];
int idev = -1;
static int ignore = 0;
int abortCode = 0;
jmp_buf env;

void
defaultHandler(n)
{
	char *str;

	if (n == SIGUSR1)
	 { str = "SIGUSR1";
	 }
	else if (n == SIGUSR2)
	 { str = "SIGUSR2";
	 }
	else
	 { str = "???";
	 }
	fprintf (stderr, "Default handler for %s\n", str);
}

abortHandler(code, msg, td)
int code;
char *msg;
RCI_DESC *td;
{
	abortCode = code;
	fprintf (stderr, "\nRCI abort, code %d, task %s\n", code, 
		 rciTaskName(td));
	fprintf (stderr, "%s\n", msg);
	longjmp (env, 1);
}


main()
{
	char *keytree, *tree_match_parse(), *tree_match_err_at();
	char taskname[256];
	char robotname[256];
	char ibuf[256];
	int interval, offset;
	int blkCount;
	int lagCount;
	int lagWindow;
	int count;
	int signo;
	unsigned long taskmask;
	int cpu;
	int arg;
	int code;
	float naptime;
	int setting;

	ignore = 0;
	abortCode = 0;
	idev = -1;

#ifdef sparc
	ieee_handler("set","common",SIGFPE_ABORT);
#endif

	keytree = tree_match_parse("					\
(	quit								\
	create								\
	 (%s", taskname, "						\
	   (%d", &cpu, ",0,3,	\"cpu (0 to 3)\"))			\
	abort								\
	 (%d", &code, ",,,	\"abort code\"				\
	    (%s", ibuf, ",	\"abort message\"))			\
	show 								\
	 ([td tcb com]							\
	   (%s", taskname, ")						\
	  time								\
	  tasks								\
	  auxDebug							\
	  rbt								\
	   (%s", taskname, "		\"task name\"			\
	     (%d", &code, ",,,		\"robot code\"))		\
	  bus								\
	 )								\
	control								\
	 ([cfxn1 cfxn2 cfxn3 null]					\
	  (%s", taskname, "	\" task name \"				\
	    (%d", &arg, ",,,	\" argument \")))			\
	rate								\
	 (%d", &interval, ",,,		\"interval\"			\
	   (%d", &offset, ",,,		\"offset\"			\
	     (%s", taskname, ")))					\
	scheduling 							\
	 (%s", taskname, "						\
	   ([ON_FUNCTION ON_CLOCK ON_TRIGGER]				\
	    ON_SIGNAL							\
	     (SIGUSR1 SIGUSR2)))					\
	astRate								\
	 (%s", taskname, ",		\"task name\"			\
	    (%d", &interval, ",,,	\"AST interval (msec.)\"))	\
	wakeupFxn							\
	 (%s", taskname, ",		\"task name\"			\
	    (null timeReady onInterrupt))				\
	abortCount							\
	 (%s", taskname, ",		\"task name\"			\
	    (%d", &count, ",,,		\"abort count limit\"))		\
	testCrash							\
	 (%s", taskname, ",		\"task name\"			\
	   (divide0 segmentation (text data) syscall off))		\
	testRciAbortErrors						\
	 (%s", taskname, ",		\"task name\")			\
	timeout								\
	 (%s", taskname, ",		\"task name\"			\
	    (%d", &blkCount, ",,,	\"block count\"			\
		(%d", &lagCount, ",,,	\"lag count\"			\
		    (%d", &lagWindow, ",,, \"lag window\"))))		\
	attachRobot							\
	 (%s", taskname, ",		\"task name\"			\
	    (%s", robotname, ",		\"robot name\"))		\
	detachRobot							\
	 (%s", taskname, ",		\"task name\"			\
	    (%d", &code, ",,,		\"robot code\"))		\
	[start release]							\
	 (%x", &taskmask, ",,,		\"taskmask (hex)\")		\
	checkpoint							\
	signal								\
	 (SIGUSR1 SIGUSR2)						\
	interrupt 							\
	 (device							\
	   (%s", ibuf, "))						\
	delayCount							\
	 (%s", taskname, ",		\"task name\"			\
	   (%d", &count, ",0,,		\"delay count\"))		\
	printing							\
	 (%s", taskname, ",		\"task name\"			\
	   (on off))							\
	hook								\
	execute								\
	 (%s", taskname, ",		\"task name\")			\
	confirm								\
	nap								\
	 (%f", &naptime, ",		\"nap time (sec)\")		\
	printToTerminal							\
	 (%d", &setting, ",		\"setting (on or off)\")	\
	printErrors							\
)", 0);

	if (keytree == 0)
	 { printf ("ERROR/Parse error at %.30s\n", tree_match_err_at());
	   exit (-1);
	 }

	signal (SIGUSR1, defaultHandler);
	signal (SIGUSR2, defaultHandler);
	rciAbortHandler (abortHandler);

	setjmp (env);

	do
 	 { RCI_DESC *td;

	   tree_match (keytree, "RCI> ", key_buf);

	   /* get the task descriptor for those commands that need it */

	   if (COMMAND ("show td")  || COMMAND ("show com") ||
	       COMMAND ("show tcb") || COMMANDS ("control") ||
	       COMMAND ("timeout")  || COMMAND ("rate") ||
	       COMMAND ("astRate")  || COMMAND ("abortCount") ||
	       COMMANDS ("scheduling") || COMMANDS ("wakeupFxn") ||
	       COMMAND ("attachRobot") || COMMAND ("detachRobot") ||
	       COMMANDS ("testCrash") || COMMAND("show rbt") ||
	       COMMAND ("delayCount") || COMMANDS("printing") ||
	       COMMAND ("execute") || COMMANDS("testRciAbortErrors") )
	    { 
	      if ((td = (RCI_DESC*)rciDescriptor(taskname)) == NULL)
	       { printf ("no task with name \"%s\"\n", taskname);
		 continue;
	       }
	    }

	   if (COMMAND("create"))
	    { RCI_DESC *td;
	      
	      if ((td = rciCreate (taskname, (1<<cpu))) == NULL)
	       { printErrors();
		 clearErrors();
		 continue;
	       }
	      if ((taskcom[TASKNUM(td)] = (TASKCOM*)rciSharedMemory (
		     "TASKCOM", sizeof(TASKCOM), td)) == NULL)
	       { printErrors();
		 clearErrors();
	       }
	      bzero (taskcom[TASKNUM(td)], sizeof(TASKCOM));
	      taskcom[TASKNUM(td)]->printing = 1;
	      if (rciControlFxns (td, cfstart, NULLF, cfrelse, arg) < 0)
	       { printErrors();
		 clearErrors();
	       }
	    }
	   else if (COMMAND("show td"))
	    { printTd (td);
	    }
	   else if (COMMAND("show com"))
	    { printCom (td);
	    }
	   else if (COMMAND("show tcb"))
	    { printTcb (td);
	    }
	   else if (COMMAND("show rbt"))
	    { if (code >= TASKNUMROBOTS(td) ||
		  TASKROBOT(td, code) == NULL)
	       { printf ("robot with code %d is not defined\n", code);
	       }
	      else
	       { printRbt (td, code);
	       }
	    }
	   else if (COMMAND("show time"))
	    { printf ("%d\n", rciTime());
	    }
	   else if (COMMAND("show auxDebug"))
	    { printf ("%d\n", auxDebug);
	    }
	   else if (COMMAND("show tasks"))
	    { int id;
	      extern int rciNumTasks;
	      extern RCI_DESC rciTaskTable[];

	      for (id = 0; id < rciNumTasks; id++)
	       { printf ("%2d  %04x  %s\n", id, (1<<id),
			 rciTaskName(&rciTaskTable[id]));
	       }
	    }
	   else if (COMMAND("show bus"))
	    { printf ("rciBus    0x%x\n", rciBus);
	      printf ("rciIOpage 0x%x\n", rciIOpage);
	    }
	   else if (COMMAND("abort"))
	    { rciAbort (code, "abort test: %s\n", ibuf);
	    }
	   else if (COMMANDS("control"))
	    { 
	      char *str;
	      int (*f1)();

	      str = &key_buf[strlen("control")+1];
	      if (MATCH (str, "null"))
	       { f1 = 0;
	       }
	      else if (MATCH (str, "cfxn1"))
	       { f1 = cfxn1;
	       }
	      else if (MATCH (str, "cfxn2"))
	       { f1 = cfxn2;
	       }
	      else if (MATCH (str, "cfxn3"))
	       { f1 = cfxn3;
	       }
	      if (rciControlFxns (td, cfstart, f1, cfrelse, arg) < 0)
	       { printErrors();
		 clearErrors();
	       }
	    }
	   else if (COMMAND("timeout"))
	    { if (rciTimeout(td, blkCount, lagCount, lagWindow) < 0)
	       { printErrors();
		 clearErrors();
	       }
	    }
	   else if (COMMAND("rate"))
	    { if (rciRate(td, interval, offset) < 0)
	       { printErrors();
		 clearErrors();
	       }
	    }
	   else if (COMMANDS("testCrash"))
	    { if (COMMAND ("testCrash divide0"))
	       { taskcom[TASKNUM(td)]->testCrash = DIVIDE0;
	       }
	      else if (COMMAND ("testCrash segmentation text"))
	       { taskcom[TASKNUM(td)]->testCrash = SEGMENTATION_T;
	       }
	      else if (COMMAND ("testCrash segmentation data"))
	       { taskcom[TASKNUM(td)]->testCrash = SEGMENTATION_D;
	       }
	      else if (COMMAND ("testCrash syscall"))
	       {
#ifdef vax
		 printf ("kernel mode syscalls can't be caught on uVAXen\n");
#else
#ifdef VXWORKS_CFG
		 printf ("system call traps not implemented on vxWorks\n");
#else
		 taskcom[TASKNUM(td)]->testCrash = SYSCALL;
#endif
#endif
	       }
	      else if (COMMAND ("testCrash off"))
	       { taskcom[TASKNUM(td)]->testCrash = 0;
	       }
	    }
	   else if (COMMANDS("testRciAbortErrors"))
	    { taskcom[TASKNUM(td)]->testRciAbortErrors = YES;
	    }
	   else if (COMMAND("attachRobot"))
	    { int code;
	      if ((code = rciAttachRobot (td, robotname, 0)) < 0)
	       { printErrors();
		 clearErrors();
	       }
	      printf ("robot code = %d\n", code);
	    }
	   else if (COMMAND("detachRobot"))
	    { 
	      if (rciDetachRobot (td, code) < 0)
	       { printErrors();
		 clearErrors();
	       }
	    }
	   else if (COMMAND("astRate"))
	    { taskcom[TASKNUM(td)]->astRate = interval;
	    }
	   else if (COMMAND("abortCount"))
	    { taskcom[TASKNUM(td)]->abortCount = count;
	    }
	   else if (COMMAND("delayCount"))
	    { taskcom[TASKNUM(td)]->delayCount = count;
	    }
	   else if (COMMAND("printing on"))
	    { taskcom[TASKNUM(td)]->printing = 1;
	    }
	   else if (COMMAND("printing off"))
	    { taskcom[TASKNUM(td)]->printing = 0;
	    }
	   else if (COMMANDS("wakeupFxn"))
	    { if (COMMAND ("wakeupFxn onInterrupt"))
	       { taskcom[TASKNUM(td)]->wakeupFxn = rciOnInterrupt;
	       }
	      else if (COMMAND ("wakeupFxn timeReady"))
	       { taskcom[TASKNUM(td)]->wakeupFxn = rciTimeReady;
	       }
	      else if (COMMAND ("wakeupFxn null"))
	       { taskcom[TASKNUM(td)]->wakeupFxn = NULLF;
	       }
	    }
	   else if (COMMAND("start"))
	    { if (rciStart(taskmask) < 0)
	       { printErrors();
		 clearErrors();
	       }
	    }
	   else if (COMMAND("release"))
	    { if (rciRelease(taskmask) < 0)
	       { printErrors();
		 clearErrors();
	       }
	    }
	   else if (COMMAND("scheduling ON_CLOCK"))
	    { if (rciScheduling (td, ON_CLOCK, 0) < 0)
	       { printErrors();
		 clearErrors();
	       }
	    }
	   else if (COMMAND("scheduling ON_FUNCTION"))
	    { 
	      if (rciScheduling (td, ON_FUNCTION, idev) < 0)
	       { printErrors();
		 clearErrors();
	       }
	    }
	   else if (COMMAND("scheduling ON_TRIGGER"))
	    { if (rciScheduling (td, ON_TRIGGER, idev) < 0)
	       { printErrors();
		 clearErrors();
	       }
	    }
	   else if (COMMANDS("scheduling ON_SIGNAL"))
	    { 
	      if (COMMAND ("scheduling ON_SIGNAL SIGUSR1"))
	       { signo = SIGUSR1;
	       }
	      else if (COMMAND ("scheduling ON_SIGNAL SIGUSR2"))
	       { signo = SIGUSR2;
	       }
	      if (rciScheduling (td, ON_SIGNAL, signo) < 0)
	       { printErrors();
		 clearErrors();
	       }
	    }
	   else if (COMMANDS ("execute"))
	    { int retval;
	      if (rciExecute (td, executeFxn, 321, &retval) < 0)
	       { printErrors();
		 clearErrors();
	       }
	      else
	       { printf ("return value %d\n", retval);
	       }
	    }
	   else if (COMMANDS ("interrupt device"))
	    { 
#ifndef VXWORKS_CFG
	      if (idev > 0)
	       { close (idev);
	       }
	      if ((idev = open (ibuf, O_RDWR)) < 0)
	       { perror ("error opening idev");
	       }
#else
	      idev = atoi(ibuf);
#endif
	    }
	   else if (COMMANDS ("signal"))
	    { if (COMMAND ("signal SIGUSR1"))
	       { kill (getpid(), SIGUSR1);
	       }
	      else if (COMMAND ("signal SIGUSR2"))
	       { kill (getpid(), SIGUSR2);
	       }
	    }
	   else if (COMMANDS ("hook"))
	    { hook();
	    }
	   else if (COMMAND("confirm"))
	    { int c;

	      if (!ignore)
	       { printf ("<CR> to continue, 'q' to quit:");
		 switch (c = getchar())
		  { case 'q':
		     { rciRelease(~0);
		       return (0);
		       break;
		     }
		    case '!':
		     { ignore = 1;
		       break;
		     }
		  }
		 while (c != '\n')
		  { c = getchar();
		  }
	       }
	    }
	   else if (COMMAND ("nap"))
	    { nap (naptime);
	    }
	   else if (COMMAND ("printErrors"))
	    { printErrors();
	    }
	   else if (COMMAND ("printToTerminal"))
	    { rciPrintToTerminal (setting);
	    }
	 }
	while (!(COMMAND("quit")));
	rciRelease (~0);
}

printTd (td)
RCI_DESC *td;
{	
	printf ("RCI_DESC:\n");

	printc (-20, "taskID %d", td->taskID);
	printc (-20, "interruptNum %d", td->interruptNumber);
	printc (-20, "rbt 0x%x", td->rbt);
	printc (-19, "dev 0x%x", td->dev);

	putchar ('\n');

	printc (-20, "taskCode 0x%x", td->taskCode);
	printc (-20, "signalNum %d", td->signalNumber);

	putchar ('\n');

	printc (-20, "cpu %d", td->cpu);
	printc (-20, "tcb 0x%x", td->tcb);
	printc (-20, "msg 0x%x", td->msg);

	putchar ('\n');
}

printRbt (td, num)
RCI_DESC *td;
int num;
{
	RCI_RBT *rbt = TASKROBOT(td,num);

	printc (-26, "id %d", rbt->id);
	printc (-26, "class %d", rbt->class);
	printc (-26, "name %s", rbt->name);

	putchar ('\n');

	printc (-26, "how 0x%x", rbt->how);
	printc (-26, "chg 0x%x", rbt->chg);
	printc (-26, "dev 0x%x", rbt->dev);

	putchar ('\n');

	printc (-26, "jls 0x%x", rbt->jls);
	printc (-26, "kyn 0x%x", rbt->kyn);
	printc (-26, "var 0x%x", rbt->var);

	putchar ('\n');

	printc (-26, "kynSize %d", rbt->kynSize);
	printc (-26, "varSize %d", rbt->varSize);

	putchar ('\n');

	printc (-26, " ");
	printc (-26, "startup 0x%x", rbt->startup);
	printc (-26, "release 0x%x", rbt->release);

	putchar ('\n');

	printc (-26, "input 0x%x", rbt->input);
	printc (-26, "output 0x%x", rbt->output);
	printc (-26, "idev %d", rbt->idev);

	putchar ('\n');
}

printTcb (td)
RCI_DESC *td;
{
	RCI_TCB *tcb = td->tcb;

	printf ("RCI_TCB:\n");

	printc (-20, "controlMode %s", 
		     tcb->controlMode == ACTIVE ? "ACTIVE" :
		     tcb->controlMode == IDLE ? "IDLE" : "???" );
	printc (-20, "cycleCount %d", tcb->cycleCount);
	printc (-20, "schDisp %s", 
		     tcb->scheduleDisp == ON_FUNCTION ? "ON_FUNCTION" :
		     tcb->scheduleDisp == ON_CLOCK ? "ON_CLOCK" :
		     tcb->scheduleDisp == ON_TRIGGER ? "ON_TRIGGER" : 
		     tcb->scheduleDisp == ON_TRIGGER ? "ON_TRIGGER" : "???" );
	printc (-19, "maxBlkCount %d", tcb->maxBlkCount);

	putchar ('\n');

	printc (-20, "maxLagCount %d", tcb->maxLagCount);
	printc (-20, "lagWindow %d", tcb->lagWindow);
	printc (-20, "interval %d", tcb->interval);
	printc (-20, "offset %d", tcb->offset);

	putchar ('\n');

	printc (-20, "triggerFxn 0x%x", tcb->triggerFxn);
	printc (-20, "triggerArg %d", tcb->triggerArg);
	printc (-20, "wakeupFxn 0x%x", tcb->wakeupFxn);
	printc (-19, "wakeupArg %d", tcb->wakeupArg);

	putchar ('\n');

	printc (-20, "controlFxn 0x%x", tcb->controlFxn);
	printc (-20, "startupFxn 0x%x", tcb->startupFxn);
	printc (-20, "releaseFxn 0x%x", tcb->releaseFxn);
	printc (-19, "controlArg %d", tcb->controlArg);

	putchar ('\n');
	
	printc (-20, "triggerAst %d", tcb->triggerAst);
	printc (-20, "timerAst %d", tcb->timerAst);
	printc (-20, "interruptSet %d", tcb->interruptSet);
	printc (-19, "startTime %d", tcb->startTime);

	putchar ('\n');

	printc (-20, "runTime %d", tcb->runTime);
	printc (-20, "lastTime %d", tcb->lastTime);
	printc (-20, "blkTimout %d", tcb->blkTimeout);
	printc (-19, "lagAvrge %g", tcb->lagAverage);

	putchar ('\n');

	printc (-20, "newInterval %d", tcb->newInterval);
	printc (-20, "newOffset %d", tcb->newOffset);
	printc (-20, "newRate %d", tcb->newRate);

	putchar ('\n');

	printc (-20, "executeFxn 0x%x", tcb->executeFxn);
	printc (-20, "executeArg %d", tcb->executeArg);
	printc (-20, "executeRet %d", tcb->executeRet);

	putchar ('\n');

	printc (-20, "cmodeReq %d", tcb->cmodeReq);
	printc (-20, "abortReq %d", tcb->abortReq);
	printc (-20, "nrateReq %d", tcb->nrateReq);
	printc (-19, "blockReq %d", tcb->blockReq);

	putchar ('\n');

	printc (-20, " ");
	printc (-20, "fxnNotice %d", tcb->fxnNotice);
	printc (-20, " ");

	putchar ('\n');

	printc (-20, "sharedMem 0x%x", tcb->sharedMem);
	printc (-20, "globalMem 0x%x", tcb->globalMem);
	printc (-20, "privateMem 0x%x", tcb->privateMem);

	putchar ('\n');
}

printCom (td)
RCI_DESC *td;
{
	TASKCOM *com = taskcom[TASKNUM(td)];
	
	printf ("astRate = %d\n", com->astRate);
	printf ("abortCount = %d\n", com->abortCount);
	printf ("wakeupFxn = %s\n",
		com->wakeupFxn == rciTimeReady ? "timeReady" :
		com->wakeupFxn == rciOnInterrupt ? "onInterrupt" :
		com->wakeupFxn == NULLF ? "null" : "???" );
}

hook()
{
}
