#include <stdio.h>
#include <conio.h>
#include <dos.h>
#include <alloc.h>

#define SetVect(x,y) setvect(x,y)
#define GetVect(x)   getvect(x)
#define Enable()     enable()
#define Disable()    disable()


int _int_port;  /* 0 for COM1, 1 for COM2, etc...  */
int BufSize=4096;

volatile char *_icbuffer, *HeadP, *TailP, *BuffEnd, *BufBeg;

/****************************************/
/*  Serial interupt data & declarations */
/****************************************/
struct _COMPORT_ {
		int BasePort, IntMask, Intr;
		} ComPort[]={
			0x3F8, 0xEF, 0x0C,
			0x2F8, 0xF7, 0x0B
			};
	/* Input and output Ports */
#define InPort(x)    (ComPort[x].BasePort)
#define OutPort(x)   (ComPort[x].BasePort)
	/* Baud rate divisors */
#define BaudL(x)     (ComPort[x].BasePort)
#define BaudH(x)     (ComPort[x].BasePort+1)
	/* Interrupt enable, and ID ports */
#define IntEnable(x) (ComPort[x].BasePort+1)
#define IntID(x)     (ComPort[x].BasePort+2)
	/* Lince Control register, and Modem Control Register */
#define LCReg(x)     (ComPort[x].BasePort+3)
#define MCReg(x)     (ComPort[x].BasePort+4)
	/* Lines Status and Modem Status registers */
#define LStatus(x)   (ComPort[x].BasePort+5)
#define MStatus(x)   (ComPort[x].BasePort+6)
	/* Interrupt mask and number */
#define IntMask(x)   (ComPort[x].IntMask)
#define Intr(x)      (ComPort[x].Intr)

void (interrupt far *Serial)();  /* for origninal serial int. */

void interrupt far Handler(void);

/****************************************/
/*  The actual serial interface driver  */
/****************************************/
void interrupt far Handler(void)
{
	Disable();

	*TailP++=(char)inp(InPort(_int_port));
	if (TailP==BuffEnd)
		 TailP=BufBeg;
	if (TailP==HeadP) {
		 HeadP++;
		 if (HeadP==BuffEnd)
				HeadP=BufBeg;
		 }

	Enable();
	outp(0x20, 0x20);   /* send an end of interrupt signal to hardare */
}
/******END OF SERIAL INTERUPT***************/


/*****************************************/
/*     SET & RESET SERIAL INTERUPT       */
/*****************************************/
int serlSetIntr(int cport)
{
	unsigned i;
	if((_icbuffer=malloc(BufSize))==NULL)
		return(-1);
	BufBeg=_icbuffer;
	BuffEnd=_icbuffer+BufSize;
	TailP=HeadP=BufBeg;
	if (inp(InPort(cport))==0xFF && inp(LStatus(cport))==0xFF && inp(LCReg(cport))==0xFF)
		 return(-1);   /* no UART found at port address */

		 /* install the handler  */
	_int_port=cport;
	Serial=GetVect(Intr(cport));
	SetVect(Intr(cport), Handler);    /* point to our handler  */

			 /*  set up the interupt controller  */

	outp(MCReg(cport), 0x9);   /* set OUT2, DTR, & clear RTS on UART  */

	 //	outp(MCReg(cport), 0xB);   /* set OUT2, DTR, & RTS on UART  */
	outp(IntEnable(cport), 1);     /* set interupt enable reg on UART to data ready */
	i=inp(0x21);                  /* setup interupt controller chip  */
	i= (i & IntMask(cport));
	outp(0x21, i);
	return(0);
}


int serlClosePort(int cport)
{

	int i,j;

	/* first disable the interupts via interrupt mask on PIC chip */
	free(_icbuffer);
	i=~IntMask(cport);
	j=inp(0x21);
	j=j | i;
	outp(0x21, j);


	outp(MCReg(cport), 0x0);   /* clear OUT2, DTR, & RTS on UART  */

	return(0);
}

void serlResetIntr(int cport)
{
	int i,j;
	/* first disable the interupts via interrupt mask on PIC chip */

	free(_icbuffer);
	i=~IntMask(cport);
	j=inp(0x21);
	j=j | i;

	/* then restore the original serial intr pointer  */

	SetVect(Intr(cport), Serial);
}

/*******************************************/
/*         recieve to COMx functions       */
/*******************************************/
int serlRcv(void)
{
	int ch;

	ch=*HeadP++;
	if (HeadP==BuffEnd)
		 HeadP=BufBeg;
	return(ch);
}


/******************************************/
/* func to init COMx to correct settings  */
/* returns a -1 if port not there,        */
/*           -2 if invalid parameter      */
/*            0 if ok                     */
/******************************************/

int serlPortInit(int cport, int baud, int parity, int data, int stop)
{

	unsigned char attrib=0;
	char temp;
	int cbaud;


	/* these items setup the attribute bits for the byte to be sent
		 to the UART (data bits, stop bits, etc.)  */

	if (inp(InPort(cport))==0xFF && inp(LStatus(cport))==0xFF && inp(LCReg(cport))==0xFF)
		 return(-1);   /* no UART found at port address */

	if (cport > 0x0001|| parity>2 || data>8 || stop>2)
		 return(-2);
	if (parity != 0) {
		 if (parity == 1)
				attrib = 8;
		 else
				attrib = 24;
		 }
	if (stop > 1)
		 attrib = attrib+4;
	attrib += (unsigned char)(data-5);
	cbaud = 0;
	if (baud == 19200)
		cbaud = 6;
	else if (baud == 9600)
		cbaud = 0xC;
	else if (baud == 4800)
		cbaud = 0x18;
	else if (baud == 2400)
		cbaud = 0x30;
	else if (baud == 1200)
		cbaud = 0x60;
	else if (baud == 300)
		cbaud = 0x180;
	else
		return(-2);

	outp(LCReg(cport), (unsigned) 0x80);
	outp(BaudL(cport), cbaud%0x100);
	outp(BaudH(cport), cbaud/0x100);
	outp(LCReg(cport), attrib);

	return(0);
}

void serlClrBuff(void)       /* clear communications buffer */
{
	HeadP=TailP=BufBeg;
}


void serlXmit(char ch)
{
	while (((inp(LStatus(_int_port))) & 0x20 ) ==0)
		;
	outp(OutPort(_int_port), ch);
}

void serlXmitStr(char *str)
{
	while (*str)
	{
		if ((*str == '|') || (*str == '\n'))
			serlXmit(13);
		else if (*str=='~')
			delay(1000);	/* one second */
		else
			serlXmit(*str);
		str++;
	}
}

int serlAvl(void)
{
	return(HeadP-TailP);
}

