#include   "uart.h"

int  iBase;		/* com port base address */
char cHI,cLO;
void compute_chksum(char cBuf[]);
char hex_to_ascii(int iHex);

/* ----------------------------------------------------------------------- */
/* input  : port   = 1/2/3/4
	    baud   = 1200/2400/4800/9600/19200/38400
	    chksum = 0 is DISABLE, others is ENABLE

   return : 0 --> OK
	    1 --> port value error
	    2 --> baud rate  error
*/

int OPEN_COM(int iPort, long int lBaudRate)
{
int uart,i;
char ratehi,ratelo;
long int bb;
int cc;

switch(iPort)
	{
	case 1 : iBase=Com1; break;
	case 2 : iBase=Com2; break;
	case 3 : iBase=Com3; break;
	case 4 : iBase=Com4; break;
	default: printf("(iPort=%d)",iPort); getch();
		 return 1;		/* port must 1/2/3/4 */

	}

switch(lBaudRate)
	{
	case 1200L : break;
	case 2400L : break;
	case 4800L : break;
	case 9600L : break;
	case 19200L: break;
	case 38400L: break;
	case 57600L: break;
	case 115200L: break;
	default    : return 2;		/* baud rate error */
	}

bb=115200L;
cc=bb/lBaudRate;
ratehi=(cc&0xff00)>>8;
ratelo=cc&0xff;

outportb(iBase+Lcr,0x80);	 /* set DLAB */
outportb(iBase+Dll,ratelo);
outportb(iBase+Dlh,ratehi);

outportb(iBase+Lcr,0x03);	 /* data format */
				/* 0000 0011 --> 8_bit+1_stop+no_parity */

outportb(iBase+Ier,0);		 /* disable interrupt */
outportb(iBase+Fcr,0x07);	 /* clear input/output FIFO*/

for (i=0; i<8; i++) inportb(iBase+i);	 /* clear R */
outportb(iBase+Fcr,0x01);	 /* enable FIFO */
return 0;
}

/* ----------------------------------------------------------------------- */
/* return : 0 --> OK
	    1 --> error
*/
int CLOSE_COM(int iPort)
{
/* use polling, so do nothing here */
return 0;
}

/* ----------------------------------------------------------------------- */
/* return : 0 --> OK
	    1 --> port value error
	    2 --> timeout
*/

int SEND_CMD(int iPort, char cCmd[], long int lTimeout, int iChksum)
{
int i,ret;
long t;

switch(iPort)
	{
	case 1 : iBase=Com1; break;
	case 2 : iBase=Com2; break;
	case 3 : iBase=Com3; break;
	case 4 : iBase=Com4; break;
	default: return 1;		/* port must 1/2/3/4 */
	}

compute_chksum(cCmd);			/* add chksum and 0x0d to input */

i=0; t=0;
while (cCmd[i]!=NULL)
{
while((inportb(iBase+Lsr)&0x20)==0)	/* check line ready */
	{
	t++; if (t>lTimeout) return 2;	/* time out */
	}
outportb(iBase+Txbuf,cCmd[i]);
i++;					/* next char */
t=0;					/* reset timer */
}

if (iChksum!=0)
   {
   while((inportb(iBase+Lsr)&0x20)==0)	/* check line ready */
	{
	t++; if (t>lTimeout) return 2;	/* time out */
	}
   outportb(iBase+Txbuf,cHI);		/* send out checksum HIGH byte */
   t=0; 				/* reset timer */

   while((inportb(iBase+Lsr)&0x20)==0)	/* check line ready */
	{
	t++; if (t>lTimeout) return 2;	/* time out */
	}
   outportb(iBase+Txbuf,cLO);		/* send out checksum LOW byte */
   t=0; 				/* reset timer */
   }

while((inportb(iBase+Lsr)&0x20)==0)	/* check line ready */
   {
   t++; if (t>lTimeout) return 2;	/* time out */
   }

outportb(iBase+Txbuf,0x0D);		/* send out 0x0D */
return 0;				/* send cmd OK */
}

/* ----------------------------------------------------------------------- */
/* return : 0 --> OK
	    1 --> port value error
	    2 --> timeout
	    3 --> chksum error
*/

int RECEIVE_CMD(int iPort, char cCmd[], long int lTimeout, int iChksum)
{
int i;
char c;
long t;

switch(iPort)
	{
	case 1 : iBase=Com1; break;
	case 2 : iBase=Com2; break;
	case 3 : iBase=Com3; break;
	case 4 : iBase=Com4; break;
	default: return 1;		/* port must 1/2/3/4 */
	}

i=0; t=0;
for(;;)
{
while((inportb(iBase+Lsr)&0x01) != 0x01)   /* check line ready */
	{
	t++; if (t>lTimeout) return 2;	   /* time_out */
	}
c=inportb(iBase+Rxbuf)&0xff;	/* receive next char */
if (c==0x0d) break;		/* receive 0x0d --> end of command */
else cCmd[i]=c; 		/* store the command */
i++;				/* next char */
if (i>20)
   {
   cCmd[i]=0;			   /* string must terminate with 0 */
   printf("[%s]\7\7\7",cCmd);
   break;
   }

t=0;				/* reset timer */
}
cCmd[i]=0;			/* string must terminate with 0 */

if (iChksum!=0) return chk_chksum(cCmd); else return 0;
}

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

void compute_chksum(char cBuf[])
{
unsigned int i,j,len,sum;

len=strlen(cBuf);
j=len;

sum=0;
for (i=0; i<len; i++) sum+=(cBuf[i]&0xff);	/* 0x0D not included */
sum=sum&0xff;
cHI=hex_to_ascii(sum/16); /* CHKSUM high byte */
cLO=hex_to_ascii(sum%16); /* CHKSUM low  byte */
}


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

char hex_to_ascii(int iHex)
{
if (iHex<10) return(iHex+'0');
else return('A'+iHex-10);
}

/* ----------------------------------------------------------------------- */
/* return : 3 --> chksum error
	    0 --> OK
*/

int chk_chksum(char cBuf[])
{
unsigned int i,len,sum;
char h,l;

len=strlen(cBuf); sum=0;
for (i=0; i<len-2; i++) sum+=(cBuf[i])&0xff;
sum=sum&0xff;
h=hex_to_ascii(sum/16);
l=hex_to_ascii(sum%16);

if (cBuf[len-2]!=h) return 3;	/* compare CHECKSUM high byte */
if (cBuf[len-1]!=l) return 3;	/* compare CHECKSUM low  byte */
return 0;
}

