/*-=-=-=-=-=-=-=-=-=-=-=- 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.		    *
 *									    *
 *-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/*---------------------------------------------------------------------------
 *		
 * MODULE NAME:	robotDefs
 *
 * DESCRIPTION:	Routines to supply configuration information about a 
 *		particular robot available to the RCI system. In particular,
 *		these routines tell us two things:
 *
 *		(1) What RCI I/O device should be used for communicating with
 *		    the robot, and what is the address of that device?
 *
 *		(2) If we wish to drive the robot's controlling task off
 *		    of an interrupt coming from the robot controller, what
 *		    UNIX device should be used to supply the interrupt to
 *		    RCI?
 * 
 *		The actual information that these routines provide is
 *		contained in the configuration file conf/robots, and is read
 *		in using procedures in 'robotFile.c'.
 *		
 * CAVEATS:	These routines will probably be replaced by a more general
 *		database package that is currently in the works.
 *
 * AUTHOR/DATE:	John Lloyd, Fall 1987
 *
 * MODIFICATION HISTORY:
 *
 *--------------------------------------------------------------------------*/

#if TEST
#include <stdio.h>
#endif

#include "../h/cdefs.h"
#include "../h/errorCodes.h"
#include "../h/IOdevice.h"

#include "../rci/robotDefs.h"
#include "../rci/link.h"

/* ----- Error Messages. Defined externally to save space ----- */

static char *outOfMemoryMsg	= "%s -- out of memory\n";
static char *parseErrMsg	= "%s %s, line %d\n";
static char *cantOpenFileMsg	= "%s -- can't open file %s\n";
static char *fileReadErrMsg	= "%s -- error reading file %d\n";
static char *noRCCLEnvMsg	= "%s -- environment variable RCCL not set\n";
static char *cantDoInitMsg	= "%s -- can't initialize\n";
static char *rbtNotDefMsg	= "%s -- rbt %s: not defined in RCI tables\n";

static ROBOT_DEFS *robotDefList = NULL;

static readRobotDefs();
static ROBOT_DEFS *locateRobot();

static initDone = 0;
#define INIT_CHECK()	if (!initDone) doInit();
static doInit()
{
	initDone = 1;
	if (robotDefList)
	 { freeRobotDefs(robotDefList);
	   robotDefList = NULL;
	 }
	requestFlagInit(&initDone);
}

static readRobotDefs(fxnName)
char *fxnName;
{
	/* Called the first time rciAttachRobot() is called.
	   Reads in definitions from the config file and sets up
	   the robot list.
	 */

	char fileName[256];
	char *rcclDir;

	if ((rcclDir = (char*)getenvRCCL()) == NULL)
	 { errorMsg (EEnviron, noRCCLEnvMsg, fxnName);
	   return (-1);
	 }
	if ((robotDefList = ALLOC(ROBOT_DEFS)) == NULL)
	 { errorMsg (EMemory, outOfMemoryMsg, fxnName);
	   return (-1);
	 }
#ifdef VXWORKS_CFG
	sprintf (fileName, "%s/conf/robots.vxw", rcclDir);
#else
	sprintf (fileName, "%s/conf/robots", rcclDir);
#endif
	if (readRobotFile (fileName, robotDefList) < 0)
	 { errorMsg (getErrorCode(0), fileReadErrMsg, fxnName, fileName);
	   free(robotDefList);
	   robotDefList = NULL;
	   return (-1);
	 }
	return (1);
}

freeRobotDefs(list)
ROBOT_DEFS *list;
{
	ROBOT_DEFS *rdef, *rdef_next;

	for (rdef=list->next; rdef!=list; rdef=rdef_next)
	 { rdef_next = rdef->next;
	   if (rdef->name)
	    { FREE(rdef->name);
	    }
	   if (rdef->device)
	    { FREE(rdef->device);
	    }
	   if (rdef->interrupt)
	    { FREE(rdef->interrupt);
	    }
	   FREE(rdef);
	 }
	FREE(list);
}

static ROBOT_DEFS *locateRobot (name, fxnName)
char *name;
char *fxnName;
{
	ROBOT_DEFS *rd;

	INIT_CHECK();

	if (!robotDefList)
	 { if (readRobotDefs(fxnName) < 0)
	    { errorMsg (getErrorCode(0), cantDoInitMsg, fxnName);
	      return (NULL);
	    }
	 }
	for (rd = robotDefList->next; rd != robotDefList; rd = rd->next)
	 { if (strcmp (rd->name, name) == 0)
	    { return (rd);
	    }
	 }
	errorMsg (ENotDefined, rbtNotDefMsg, fxnName, name);
	return (NULL);
}

getRobotIdev (idev, name)
char **idev;
char *name;
{
	/* Get information about what UNIX device can supply an interrupt from
	   the robot controller to RCI.
	 */

	char *fxnName = "getRobotIdev()";

	register ROBOT_DEFS *rd;

	if ((rd = locateRobot (name, fxnName)) == NULL)
	 { return (-1);
	 }
	if (rd->interrupt)
	 { *idev = rd->interrupt;
	   return (1);
	 }
	else
	 { *idev = NULL;
	   return (0);
	 }
}

getRobotIntraddr (intraddr, name)
int *intraddr;
char *name;
{
	/* For non-UNIX systems: get information about the interrupt
	   address */

	char *fxnName = "getRobotIntraddr()";

	register ROBOT_DEFS *rd;

	if ((rd = locateRobot (name, fxnName)) == NULL)
	 { return (-1);
	 }
	if (rd->intraddrSet)
	 { *intraddr = rd->intraddr;
	   return (1);
	 }
	else
	 { *intraddr = UNDEF;
	   return (0);
	 }
}

getRobotVector (vector, name)
int *vector;
char *name;
{
	/* For non-UNIX systems: get information about the interrupt
	   vector */

	char *fxnName = "getRobotIvec()";

	register ROBOT_DEFS *rd;

	if ((rd = locateRobot (name, fxnName)) == NULL)
	 { return (-1);
	 }
	if (rd->vectorSet)
	 { *vector = rd->vector;
	   return (1);
	 }
	else
	 { *vector = UNDEF;
	   return (0);
	 }
}

getRobotIpl (ipl, name)
int *ipl;
char *name;
{
	/* For non-UNIX systems: get information about the interrupt
	   vector */

	char *fxnName = "getRobotIvec()";

	register ROBOT_DEFS *rd;

	if ((rd = locateRobot (name, fxnName)) == NULL)
	 { return (-1);
	 }
	if (rd->iplSet)
	 { *ipl = rd->ipl;
	   return (1);
	 }
	else
	 { *ipl = UNDEF;
	   return (0);
	 }
}

getRobotDevice (devAddr, name)
struct devAddr *devAddr;
char *name;
{
	/* Get information about what RCI I/O device/address combination 
	   should be used to communicate with the robot.
	 */
	char *fxnName = "getRobotDevice()";

	register ROBOT_DEFS *rd;
	int k;

	if ((rd = locateRobot (name, fxnName)) == NULL)
	 { return (-1);
	 }
	if (rd->addressSet && rd->device)
	 { devAddr->name = rd->device;
	   devAddr->address = rd->address;
	   for (k=0; k<MAX_DEVARGS; k++)
	    { devAddr->args[k] = rd->args[k];
	    }
	   return (1);
	 }
	else
	 { devAddr->name = NULL;
	   devAddr->address = UNDEF;
	   for (k=0; k<MAX_DEVARGS; k++)
	    { devAddr->args[k] = UNDEF;
	    }
	   return (0);
	 }
}

#if TEST

char **argvec;

main(argc, argv)
int argc;
char **argv;
{
	struct devAddr addr;
	int addrSet;
	char *idev;
	int idevSet;
	int vector, vectorSet;
	int intraddr, intraddrSet;
	int ipl, iplSet;
	int k;

	argvec = argv;
	argc--; argv++;

	if (argc != 1)
	 { fprintf (stderr, "Usage: %s <robotName>\n", argvec[0]);
	   exit (-1);
	 }

	if ((addrSet = getRobotDevice (&addr, *argv)) < 0)
	 { printErrors();
	   exit (-1);
	 }
	if ((idevSet = getRobotIdev (&idev, *argv)) < 0)
	 { printErrors();
	   exit (-1);
	 }
	if ((intraddrSet = getRobotIntraddr (&intraddr, *argv)) < 0)
	 { printErrors();
	   exit (-1);
	 }
	if ((vectorSet = getRobotVector (&vector, *argv)) < 0)
	 { printErrors();
	   exit (-1);
	 }
	if ((iplSet = getRobotIpl (&ipl, *argv)) < 0)
	 { printErrors();
	   exit (-1);
	 }

	putchar ('\n');
	if (addrSet)
	 { printf ("device    SET: %s at %d (0x%x)\n",
		    addr.name, addr.address, addr.address);
	   for (k=0; k<MAX_DEVARGS; k++)
	    { printf ("arg       %d (0x%x)\n", addr.args[k],addr.args[k]);
	    }
	 }
	else
	 { printf ("device    NOT SET\n");
	 }
	if (idevSet)
	 { printf ("idev      SET: %s\n", idev);
	 }
	else
	 { printf ("idev      NOT SET\n");
	 }
	if (intraddrSet)
	 { printf ("intraddr  SET: %d (0x%x)\n", intraddr, intraddr);
	 }
	else
	 { printf ("intraddr  NOT SET\n");
	 }
	if (vectorSet)
	 { printf ("vector    SET: %d (0x%x)\n", vector, vector);
	 }
	else
	 { printf ("vector    NOT SET\n");
	 }
	if (iplSet)
	 { printf ("ipl       SET: %d\n", ipl);
	 }
	else
	 { printf ("ipl       NOT SET\n");
	 }
	putchar ('\n');
}
#endif
