#include<dos.h>
#include<stdlib.h>

/*................Para interrupciones ..........*/

void interrupt COMX_IRQ4();
void interrupt (*com_original)(void);
int vector;
unsigned char pic_int,eoi;	/* Para manejo del PIC 8259 */

/* ....... definiciones para el puerto de comunicaci¢n serial COM1/2 */

#define DSR 0x20
#define CTS 0x10

#define LCR1 0xb	// odd,1 stops,8 bits
#define LCR2 0x7	// none,2 stops,8 bits

//#define LCR2 0x6	// none,2 stops,7 bits

int comx;

unsigned int addr = 0x3F8;
unsigned char baud = 12;	/*12 => 9600,24=>4800, 96=>1200 */
unsigned int irq = 4;

unsigned char lcr = LCR2;
int par,stop,bits;

/*..............Bytes de comunicaci¢n..............*/

int max_bytes=2400;
char rx_buffer[2400];	/* recibido via ACE 8250 */
int puntero=0;
char *p1;
int txch=0;

//......................................................................

comx_open(char *k)
{
int kp;
	kp=k[3]& 0xF;
	p1=&rx_buffer;		/* Buffer de recepcion */

	switch( kp )
	{
	case 1: {
		addr= 0x03F8;	  /* para 8250 UART o ACE */
		irq  = 4;
		vector = 0xc;     /*para definir el Vector de Int */
		pic_int= 0x10;	  /*para pic 8259 */
		eoi = 0x64;
		printf("COM1 ");
		break;
		}
	case 2: {
		addr = 0x02F8;
		irq  = 3;
		vector = 0xb;     /* para definir el vector de Int */
		pic_int= 0x08;	  /* para pic 8259 */
		eoi = 0x63;
		printf("COM2 ");
		break;
		}
/*	case 3: {
		addr= 0x03e8;
		irq  = 4;
		break;
		}
	case 4: {
		addr = 0x02e8;
		irq  = 3;
		break;
		}
*/
	default: {
		puts( "\nInvalid command line parameter." );
		com_format();return 0;
		}
	}

	kp = atoi(&k[5]);
	printf("%d ",kp);

	switch (kp)
	{ 	case 1200:baud=96   ;break;
		case 2400:baud=48   ;break;
		case 4800:baud=24   ;break;
		case 9600:baud=12   ;break;
		default:{puts(" invalid baud rate.");
				com_format();return 0;
				}
	}
	printf("%c ",k[10]);
	switch (k[10])
	{	case 'N':par=0x00;break;
		case 'O':par=0x08;break;
		case 'E':par=0x18;break;
		default:puts(" invalid parity.");com_format();return 0;
	}
	kp = k[12] & 0xF;
	printf("%d ",kp);
	switch (kp)
	{	case 1: stop=0x00;break;
		case 2: stop=0x04;break;
		default: puts(" invalid stops.");com_format();return 0;
	}
	kp = k[14] & 0xF;
	printf("%d ",kp);
	switch (kp)
	{	case 7: bits=0x02;break;
		case 8: bits=0x03;break;
		default: puts(" invalid bits."); com_format();return 0;
	}
	lcr = par | stop | bits;

	if(comx_test()==0)return 0;
	else	comx_init();	     // inicializa el puerto COM1/2
	return 1;
}
com_format(void)
{	printf("\n Formato: comx_open\(Port Bauds Parity Stops Bits\)");
	printf("\n Ejemplo: comx_open\(COM1 9600 N 1 8\)");
	printf("\n Port =  COM1, COM2, COM3, COM4");
	printf("\n Bauds=  1200, 2400, 4800, 9600");
	printf("\n Parity= N, E, O" );
	printf("\n Stop =  1, 2 ");
	printf("\n Bits =  7, 8 ");
}

int comx_test(void)
{       int ch;
	ch=inportb(addr+3);
	outportb(addr+3,0x55);
	if(inportb(addr+3) != 0x55)return 0;
	outportb(addr+3,ch);
	return 1;
}

comx_close()	     /* Para finalizar restituye los vectores */
{
	window(1,1,80,25);
	clrscr();
	setvect(vector,com_original);	/* restituye vector */
	outportb(0x21,inportb(0x21) | pic_int); /*Off IRQ3/4 en PIC 8259 */
	exit(0);   	/* Termina programa */
}

/*..........................programacion del 8250.....................
		LCR = Line Control Reg.
			bit 4,3 => X0 =none, 01= odd ,11=even
			bit 2   => 0 = 1 stop bits, 1= 2 stop bits
			bit 1,0 => 10 = 7 bits,11= 8 bits data
 Ejemplo    al=07h >none par,1 stops,8 bits
......................................................................*/

comx_init()		/* inicializa el puerto COM1 */
{
	com_original=getvect(vector);
	setvect(vector, COMX_IRQ4);
	outportb(addr+3,0x80);	/*DLAB=1 set baud rate to */
	outportb(addr+1,0x0);	/*MSB	*/
	outportb(addr,baud);	/*LSB 	baud rate */
	outportb(addr+3,lcr);	/*LCR 	parity+stop bits+word leght*/
	outportb(addr+1,0xf);	/*Prg. Int.enable: bit 3,2,1,0=Modem status,
					Line status,Tx Hold Reg.Empty, Rx data available */
	outportb(addr+4,0xb);	/*Out2=1 y habilita RTS,DTR */
/*.......................Lecturas tontas ....................*/
	inportb(addr+5); 	/*LSR   (1RA LECTURA) */
//	inportb(addr+5);	/*I/O   (2DA LEC.),(rst. Tx hold. reg. empty)*/
//	inportb(addr+2);	/*IIR   (3DA LEC.),(rst. Rx Data available)  */
	inportb(addr+6);	/*modem (4RA LEC.),(rst. ints. por Modem S.R.)*/
	outportb(0x21,inportb(0x21)&~pic_int);	/*Habilita IRQ3/4 en PIC 8259 */
}

void interrupt COMX_IRQ4()  /*Rutina Comunicaci¢n Manejo de INT 0CH  COM1 */
{
int ch;
	switch(ch=inportb(addr+2))	/* lee el reg. ident. interrup.*/
	{
	case 4:comrx(); break;		/* lee el dato */
	case 6:inportb(addr+5);		/* errores */
		inportb(addr); 		/* Elimina Dato Leido */
		break ;
	case 2:if(txch)comx_tx();      	/* Transmite dato */
			break;
	case 0:if(inportb(addr+6) & 0x20)   /* Int. (modem; CTS o DSR */
		  outportb(addr+4,0xb);     /* DTR=1,RTS=1,Habilita int.*/
		  break;
	}
	outportb(0x20,eoi);				/* EOI especifico al 8259 para COMx*/
}

/*-------transmite byte ---------------------------------------------*/

int comx_tx(char ch1)
{   if(inportb(addr+5) & 0x20)	/* LSR  read*/
    {	outportb(addr,ch1);
	txch=0;
    }
}

/*-------- Manejo de datos RECIBIDOs ---------------------------------*/
comrx( void)
{
char al;
	al=inportb(addr);      /*Lee dato*/
	p1[puntero++]=al;
	if (puntero > max_bytes)puntero=max_bytes;
}

int comx_buffer(void)
{  return(puntero);
}

int comx_rd(char *p2)		//vacia el buffer
{       int l;
	for(l=0;l<puntero;l++)p2[l]=p1[l];
	puntero=0;
	return l;
}
