/*-=-=-=-=-=-=-=-=-=-=-=- RCCL/RCI Notice of Copyright -=-=-=-=-=-=-=-=-=-=-*
 *									    *
 *	Copyright (C) 1991 by John E. Lloyd.				    *
 *									    *
 *	Information on copyright permissions, as well as a complete	    *
 *	disclaimer of warranty, is given in the file COPYRIGHT.		    *
 *									    *
 *-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/* Program to check that basic RCI is working. It creates a task, sets
   it running, and watches that we can communicate with it. */

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

#ifdef VXWORKS_CFG
#define main	rciCheck_
#endif

#ifndef vax
#include <sys/time.h>	
#endif
#include "../h/rci.h"
#include "../h/timeval.h"
#include "../rci/rciCheck.h"

#define TASK1_INTERVAL	1000
#define TASK2_INTERVAL	1000
#define TASK3_INTERVAL	 500

#define TASK1_OFFSET	0
#define TASK2_OFFSET	600
#define TASK3_OFFSET	300

#define CLOCK_TOL	20 /* msec. */
#define CLOCK_TICK	10  /* msec. */

extern doStartup();
extern doControl();
extern doRelease();

RCI_DESC *td1;
RCI_DESC *td2;
RCI_DESC *td3;

int sigIOCaught;

onSigIO()
{
	sigIOCaught++;
}

int abortCaught;

abortHandler(code, msg, td)
int code;
char *msg;
RCI_DESC *td;
{
	if (code == 1234)
	 { abortCaught = 1;
	   if (strcmp (msg, "test abort") != 0)
	    { fprintf (stderr, "Error, bad abort message\n");
	      exit (-1);
	    }
	   if (td != td1)
	    { fprintf (stderr, "Error, bad abort task descriptor\n");
	      exit (-1);
	    }
	 }
	else
	 { rciPrintAbort(code, msg, td);
	   exit (-1);
	 }
}

char **argvec;

main(argc, argv)
int argc;
char **argv;
{
	COMBLK *cb1, *cb2, *cb3;
	struct timeval sysT1, sysT2;
	int t1, t2, t3;
	double x;
	int k;

	int doCrash = 0;

	argvec = argv;
	argc--; argv++;
	while (argc > 0)
	 { if (ARGUMENT ("-crash"))
	    { doCrash = 1;
	    }
	   else
	    { argc = -1;
	      break;
	    }
	   argc--; argv++;
	 }
	if (argc == -1)
	 { fprintf (stderr, "Usage: %s [-crash]\n", argvec[0]);
	   exit (-1);
	 }

	signal (SIGIO, onSigIO);

	rciSetOptions (EXIT_ON_ERROR);

	printf ("Setting up control tasks ...\n");
	
	td1 = rciCreate ("arb1", 0x1);
	td2 = rciCreate ("arb2", 0x1);
	td3 = rciCreate ("arb3", 0x1);

	rciRate (td1, TASK1_INTERVAL, TASK1_OFFSET);
	rciRate (td2, TASK2_INTERVAL, TASK2_OFFSET);
	rciRate (td3, TASK3_INTERVAL, TASK3_OFFSET);

	rciScheduling (td1, ON_CLOCK, 0);
	rciScheduling (td2, ON_CLOCK, 0);
	rciScheduling (td3, ON_CLOCK, 0);

	cb1 = ALLOC_MEM("cb1", COMBLK, UNDEF);
	cb2 = ALLOC_MEM("cb2", COMBLK, UNDEF);
	cb3 = ALLOC_MEM("cb3", COMBLK, UNDEF);

	rciControlFxns (td1, doStartup, doControl, doRelease, (int)cb1);
	rciControlFxns (td2, doStartup, doControl, doRelease, (int)cb2);
	rciControlFxns (td3, doStartup, doControl, doRelease, (int)cb3);

	printf ("Starting control tasks ... \n");

	rciStart (~0);

	if (cb1->startupCnt != 1 || cb2->startupCnt != 1)
	 { fprintf (stderr, "Error, startuo function(s) not called\n");
	   exit (-1);
	 }

	/* now check rciTime() to see if it is working OK */

	getSystemTime(&sysT1);
	t1 = rciTime();
	nap (2.0);		
	t2 = rciTime();
	getSystemTime(&sysT2);

	printf ("Checking rciTime() ... \n");

	x = 1000.0*(timevalToDouble(diffTimeval(sysT2,sysT1))) - (t2-t1);
	if (x < -CLOCK_TICK)
	 { fprintf (stderr, "Error, rciTime() not working\n");
	   exit (-1);
	 }
	
	/* now make sure that the control tasks are running */

	printf ("Making sure tasks are running.\n");
	printf ("(this should take about 5 seconds max.) ... \n");

	k = cb1->controlCnt;
	while (k == cb1->controlCnt)
	   ;
	k = cb1->controlCnt;
	t1 = rciTime();
	while (k == cb1->controlCnt)
	   ;
	k = cb2->controlCnt;
	t2 = rciTime();
	while (k == cb2->controlCnt)
	   ;
	t3 = rciTime();

	/* difference between t2 and t1 should be the sample rate */
	x = t2-t1-TASK1_INTERVAL;
	if (x < -CLOCK_TICK)
	 { fprintf (stderr,
"Error, task 1 seems to be running at %d instead of %d msec.\n", 
		    t2-t1, TASK1_INTERVAL);
	   exit(-1);
	 }
	if (x > CLOCK_TOL)
	 { fprintf (stderr,
"Hmmmm, task 1 seems to be running at %d instead of %d msec.\n\
This might just be your system being slow. Try running rciCheck again.\n\
If the system is busy, try to reduce the load.\n", t2-t1, TASK1_INTERVAL);
	 }

	/* difference between t3 and t2 should be TASK2_OFFSET */
	x = t3-t2-TASK2_OFFSET;
	if (ABS(x) > 2*CLOCK_TOL)
	 { fprintf (stderr,
"Hmmmm, task 2 seems to be skewed by %d instead of %d msec.\n\
This might just be your system being slow. Try running rciCheck again.\n\
If the system is busy, try to reduce the load.\n", t3-t2, TASK2_OFFSET);
	 }
	
	rciRelease(~0);

	printf ("Checking out the task release code ...\n");

	/* now make sure that the tasks really did stop ... */

	if (cb1->releaseCnt != 1 || cb2->releaseCnt != 1)
	 { fprintf (stderr, "Error, release function was not called\n");
	   exit (-1);
	 }
	k = cb1->controlCnt;
	nap (1.0);
	if (cb1->controlCnt != k)
	 { fprintf (stderr, "Error, control function ran after release\n");
	   exit (-1);
	 }

	printf ("Now testing rciSignal() and rciAbort() ... \n");

	rciRate (td1, 20, 0);
	rciStart(~0);

	/* test rciSignal */

	sigIOCaught = 0;
	cb1->cmd = DO_SIGNAL;
	nap (0.1);
	if (sigIOCaught != 1)
	 { fprintf (stderr, "Error, didn't get signal from control level\n");
	   exit (-1);
	 }

	/* test rciAbort */

	rciAbortHandler(abortHandler);

	abortCaught = 0;
	cb1->cmd = DO_ABORT;
	nap (0.1);
	if (abortCaught != 1)
	 { fprintf (stderr, "Error, didn't get abort from control level\n");
	   exit (-1);
	 }

	/* we have now aborted */

	rciStart(~0);

	if (doCrash)
	 { printf ("Will now crash control level with memory fault\n");
	   cb1->cmd = DO_CRASH;
	   nap (5.0);
	   fprintf (stderr, "Error, crash didn't happen!\n");
	   exit (-1);
	 }

	printf ("\nPROGRAM RUN OK\n\n");
}
