//
//  rs232srv.c	rs232 command server
//
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <dos.h>
#include <string.h>
#include <conio.h>
#include "pcl4c.h"
#define FALSE 0
#define TRUE !FALSE
#define BUFSIZE			1024
#define ESC				0x1B
#define CR				0x0D
#define LF				0x0A
//
// Events
//
#define QUIT					(-1)
#define NOTHING					0
#define EXEC_LOCAL_COMMAND		1
#define RCV_REMOTE_COMMAND		2
#define SEND_KBRD_COMMAND		3
#define COMPLETE				4
#define NOT_COMPLETE			5
#define SIO_BRKKEY				6
#define SIO_BRKSIG				7
//	Global Variables
int Port = COM1;          // Port COM1
int BaudCode;             // baud rate code ( index into BaudRate[] )
char *BaudRate[10] =  {"300","600","1200","2400","4800","9600",
					   "19200","38400","57600","115200"};
char RxBuffer[BUFSIZE+16];
char TxBuffer[BUFSIZE+16];
char KbrdBuffer[BUFSIZE];
int	 KbrdBufferCnt=0;
char PortBuffer[BUFSIZE];
int	 PortBufferCnt=0;
char CommandBuffer[BUFSIZE];
//	local prototypes
int	 BaudMatch(char *);
int  ErrorCheck(int);
int  PeekIO(void);
int  ProcessKbrdBuffer(void);
int  ProcessPortBuffer(void);
void RunCommand(char *Command);
void main(int argc, char *argv[])
{
char c;
int  i, rc;
char far *Ptr;
int  Seg;
if(argc!=3)
	{
	printf("Usage: RS232SRV <port> <baud>\n");
	exit(1);
	}
//	get port number from command line
Port = atoi(argv[1]) - 1;
if((Port<COM1) || (Port>COM20))
	{
	printf("Port must be COM1 to COM20\n");
	exit(1);
	}
// get baud rate from command line
BaudCode = BaudMatch(argv[2]);
if(BaudCode<0)
	{
	printf("Cannot recognize baud rate = %s\n",argv[2]);
	exit(1);
	}
// setup receive buffer
Ptr = (char far *)RxBuffer;
Seg = FP_SEG(Ptr) + ((FP_OFF(Ptr)+15)>>4);
SioRxBuf(Port,Seg,Size128);
// setup transmit buffer
Ptr = (char far *)TxBuffer;
Seg = FP_SEG(Ptr) + ((FP_OFF(Ptr)+15)>>4);
SioTxBuf(Port,Seg,Size128);
// set port parmameters
ErrorCheck( SioParms(Port,NoParity,OneStopBit,WordLength8) );
// reset the port
ErrorCheck( SioReset(Port,BaudCode) );
// set DTR and RTS
ErrorCheck( SioDTR(Port,'S') );
ErrorCheck( SioRTS(Port,'S') );
// set RTS/CTS flow control
ErrorCheck( SioFlow(Port,18) );
// Set FIFO level
if(SioFIFO(Port,LEVEL_14)) printf("[16550]\n");
//
//	Enter "PeekIO" loop.
//
while(TRUE)
	{
	switch(PeekIO())
		{
		case SIO_BRKKEY:
			printf("Break!\n");
			SioDone(Port);
			exit(2);
			break;
		case SIO_BRKSIG:
			printf("[BREAK detected]\n");
			break;
		case EXEC_LOCAL_COMMAND:	// Run a command locally
			printf("EXEC_LOCAL_COMMAND %s\n",CommandBuffer);
			RunCommand(CommandBuffer)
			break;
		case RCV_REMOTE_COMMAND:	// Run a command received via the rs232
			printf("RCV_REMOTE_COMMAND %s\n",CommandBuffer);
			RunCommand(CommandBuffer);
			break;
		case SEND_KBRD_COMMAND:		// Send a command over the rs232
			printf("SEND_KBRD_COMMAND %s\n",CommandBuffer);
			strcat(CommandBuffer,"\n\r");
			SioPuts(Port,&CommandBuffer[1],strlen(CommandBuffer)-1);
			break;
		case QUIT:
			SioDone(Port);
			exit(1);
			break;
		}
	}
}
int PeekIO(void)
{
extern int  KbrdBufferCnt;
extern char KbrdBuffer[BUFSIZE];
extern char	PortBuffer[BUFSIZE];
//	Put strings together from the keyboard
//	up to a newline.  Provide backspace editing.
if(kbhit())
	{
	if(ProcessKbrdBuffer() == COMPLETE)
		{
		KbrdBufferCnt = 0;
		strcpy(CommandBuffer,KbrdBuffer);
		KbrdBuffer[0] = NULL;
		if(CommandBuffer[0] == '~')
			{ return(SEND_KBRD_COMMAND); }
		else
			{ return(EXEC_LOCAL_COMMAND); }
		}
	if(KbrdBuffer[0] == ESC)
			{ return(QUIT); }
	return(NOTHING);
	}
//	Put strings together from the serial line
//	up to a newline.
if(SioRxQue(Port) > 0)
	{
	if(ProcessPortBuffer() == COMPLETE)
		{
		PortBufferCnt = 0;
		strcpy(CommandBuffer,PortBuffer);
		PortBuffer[0] = NULL;
		return(RCV_REMOTE_COMMAND);
		}
	return(NOTHING);
	}
//	Check for break and quit.
return(NOTHING);
}
int ProcessKbrdBuffer(void)
{
extern int KbrdBufferCnt;
extern char KbrdBuffer[BUFSIZE];
int Complete = FALSE;
KbrdBuffer[KbrdBufferCnt] = getche();
KbrdBuffer[KbrdBufferCnt+1] = NULL;
if(KbrdBuffer[KbrdBufferCnt] == CR)
	{ KbrdBuffer[KbrdBufferCnt] = NULL; Complete = TRUE; }
if(KbrdBuffer[KbrdBufferCnt] == LF)
	{ KbrdBuffer[KbrdBufferCnt] = NULL; Complete = TRUE; }
if(Complete)
	{
	KbrdBufferCnt = strlen(KbrdBuffer);
	if(KbrdBufferCnt > 0)
		{ return(COMPLETE); }
	else
		{ return(NOT_COMPLETE); }
	}
KbrdBufferCnt = strlen(KbrdBuffer);
return(NOT_COMPLETE);
}
int ProcessPortBuffer(void)
{
extern int	Port;
extern char	PortBuffer[BUFSIZE];
extern int	PortBufferCnt;
int Complete = FALSE;
PortBuffer[PortBufferCnt] = SioGetc(Port,0);
PortBuffer[PortBufferCnt+1] = NULL;
if(PortBuffer[PortBufferCnt] == CR)
	{ PortBuffer[PortBufferCnt] = NULL; Complete = TRUE; }
if(PortBuffer[PortBufferCnt] == LF)
	{ PortBuffer[PortBufferCnt] = NULL; Complete = TRUE; }
if(Complete)
	{
	PortBufferCnt = strlen(PortBuffer);
	if(PortBufferCnt > 0)
		{ return(COMPLETE); }
	else
		{ return(NOT_COMPLETE); }
	}
PortBufferCnt = strlen(PortBuffer);
return(NOT_COMPLETE);
}
void RunCommand(char *Command)
{
extern int Port;
char buf[512], *endptr;
char function[100];
char arg[7][100];
Position Pos;
//	Parse the command into function and arguments
argc = sscanf(Command,
	"%s %s %s %s %s %s %s %s",
	function,
	arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6]);
if(argc<1) { return; }
//	Select the appropriate action
//	System command
if(stricmp(function,"system" == 0) 		// Run the command via "system()"
	{
	sprintf(buf,"%s %s %s %s %s %s %s",
		arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6]);
	system(buf);
	_fpreset();
	return;
	}
//	Secondary Beam Control
if(stricmp(function,"writebeam")	// Turn the beam on or off
	{
	if(argc == 2)
		{ WriteBeam((unsigned char)atoi(arg[0])); }
	return;
	}
if(stricmp(function,"writedetector") == 0)
	{
	if(argc == 2)
		{ WriteDetector((unsigned int)atoi(arg[0])); }
	return;
	}
if(stricmp(function,"readdetector") == 0)
	{
	sprintf(buf,"%d\n",ReadDetector());
	SioPuts(Port,buf,strlen(buf));
	return;
	}
if(stricmp(function,"readimagedfield") == 0)
	{
	sprintf(buf,"%d\n",ReadImagedField());
	SioPuts(Port,buf,strlen(buf));
	return;
	}
if(stricmp(function,"writehvoffset") == 0)
	{
	if(argc == 2)
		{ WriteHVOffset(atof(arg[0])); }
	return;
	}
//	Magnet
if(stricmp(function,"writemassdisplay") == 0)
	{
	if(argc == 2)
		{ WriteMassDisplay(atof(arg[0])); }
	return;
	}
if(stricmp(function,"readmagnetfield") == 0)
	{
	sprintf(buf,"%ul\n",ReadMagnetField());
	SioPuts(Port,buf,strlen(buf));
	return;
	}
if(stricmp(function,"writemagnetfield") == 0)
	{
	if(argc == 2)
		{ WriteMagnetField(strtoul(arg[0],&endptr,10)); }
	return;
	}
//	Measurement Chassis
if(stricmp(function,"readmetervalue")
	{
	sprintf(buf,"%ul\n",ReadMeterValue((unsigned int)atoi(arg[0]));
	SioPuts(Port,buf,strlen(buf));
	return;
	}
if(stricmp(function,"readcounter")
	{
	sprintf(buf,"%u\n",Readcounter());
	SioPuts(Port,buf,strlen(buf));
	return;
	}
if(stricmp(function,"writecounttime") == 0)
	{
	if(argc == 2)
		{ WriteCountTime((unsigned int)(atol(arg[0])); }
	return;
	}
if(stricmp(function,"writepolarity") == 0)
	{
	if(argc == 3)
		{ WritePolarity(atoi(arg[0]),atoi(arg[1])); }
	return;
	}
//	Stage Control
if(stricmp(function,"readmotors")
	{
	Pos = ReadMotors();
	sprintf(buf,"%f %f\n",Pos.X, Pos.Y);
	SioPuts(Port,buf,strlen(buf));
	return;
	}
if(stricmp(function,"writemotors") == 0)
	{
	if(argc == 3)
		{ WriteMotors(atof(arg[0]),atof(arg[1])); }
	return;
	}
if(stricmp(function,"movestageby") == 0)
	{
	if(argc == 3)
		{ MoveStageBy(atof(arg[0]),atof(arg[1])); }
	return;
	}
if(stricmp(function,"movestageto") == 0)
	{
	if(argc == 3)
		{ MoveStageTo(atof(arg[0]),atof(arg[1])); }
	return;
	}
return;
}
int ErrorCheck(int Code)
{/* trap PCL error codes */
 if(Code<0)
	 {printf("ERROR %d:",Code);
	  SioError(Code);
	  SioDone(Port);
	  exit(1);
	 }
 return(0);
} /* end ErrorCheck */
int BaudMatch(char *P)
{int i;
 /* find baud rate in table */
 for(i=0;i<10;i++) if(strcmp(BaudRate[i],P)==0) return(i);
 return(-1);
}