#include <dos.h>
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include <io.h>
#include <fcntl.h>
#include <time.h>

#define PROVA_LPT

#define FALSE   0
#define TRUE    1
#define TIMEOUT 2

#define LPT1ADDRESS	( *( (unsigned int *) MK_FP(0,0x408) ) )
#define BYTE unsigned char
#define BOOL unsigned char

#define CLK_TIMEOUT      5    /* numero tick (55ms) per timeout */

/*----------- INDIRIZZI DI PORTE VARIE ---------------------------------*/
#define PORTA_TX LPT1ADDRESS     /* porta di scrittura */
#define PORTA_RX 1+PORTA_TX      /* porta di lettura */

/*----------- MASCHERE -------------------------------------------------*/
/*  maschere per isolare i bit di dati e di controllo di TX e RX */
#define TX_DATI 0x0F    /* 0000 1111 pin 2..6 */
#define TX_CTR  0x10    /* 0001 0000 bit 4 porta TX pin 6*/
#define RX_DATI 0x78    /* 0111 1000 pin 15,13,12,10 */
#define RX_CTR  0x80    /* 1000 0000 bit 7 porta RX pin 11*/
#define LSN     0x0F    /* 0000 1111 low significative nibble */
#define MSN     0xF0    /* 1111 0000 most significative nibble */
#define BYTE_CTR 0xAF   /* 1010 1111 carattere di controllo */


/*----------- PROTOTIPI DI FUNZIONI ------------------------------------*/
BOOL Ricevi(BYTE *c);
BOOL Trasmetti(BYTE c);
/*************************************************************************
	OpenComunication                    PinoContini            03-07-95
--------------------------------------------------------------------------
DESCRIZIONE: viene impostata la configurazione che indica la presenza
	del terminale. Tale configurazione Š contraria di quella che si
	legge in condizioni di cavo scollegato e cioe':
	PORTA_RX = 0xFF
	quindi questa funzione imposta sulle porte di trasmisione i seguenti valori:
	PORTA_TX <- 0
	se dall'atro capo viene fatto lo stesso questa funzione porta' leggere sulle
	porte di ricezione i seguenti valori:
	PORTA_RX =0xF0                   xxxx 0000

	ad operazione terminata questa funzione imposta a zero tutti i segnali:
	PORTA_TX <- 0x0
	TX_CTR   <- 0x0
	la seconda fase Š quella di verificare la presenza del sw di trs sul
	pc remoto. Tale verifica consiste nel tentativo di trasmissione di e
	ricezione del byte di controllo

RITORNA:
	-TRUE     se la comunicazione Š presente
	-TIMEOUT  se manca la comunicazione

------------------------------------------------------------------------*/
BOOL OpenComunication(void)
{
	BYTE c,port,rx,tx;
	clock_t start = clock();

	/* imposto la mia presenza sul canale */
	outp(PORTA_TX,0);
	outp(TX_CTR,0);

	do
	{
		port = inp(PORTA_RX);                /* legge il nibble    */
																				 /* x4321x xx */
		c = (port >> 3);                     /* xxxx 4321 */
		c = c & 0xF;                         /* 0000 4321 */
		if(clock() > start + CLK_TIMEOUT*20) return TIMEOUT;
	} while (c != 0);     /* verifico che il nibble 4321 sia 0000 */

	rx = FALSE;
	tx = FALSE;
	start = clock();
	do
	{
		if((rx == FALSE) && (Ricevi(&c)==TRUE) && (c == BYTE_CTR))
			rx = TRUE;
		if((tx == FALSE) && (Trasmetti(BYTE_CTR) == TRUE))
			tx = TRUE;
		if(clock() > start + CLK_TIMEOUT*20) return TIMEOUT;
	} while(tx==FALSE || rx==FALSE);
	return TRUE;
}

/*************************************************************************
	RTS                   PinoContini            26-04-95
--------------------------------------------------------------------------
DESCRIZIONE: Request To Send. Invia una richiesta di trasmissione
RITORNA: nulla
------------------------------------------------------------------------*/
void RTS(void)
{
	BYTE port;

	port = inp(PORTA_TX);
	port = port | TX_CTR;
	outp(PORTA_TX,port);
}

/*************************************************************************
	OTS                   PinoContini            26-04-95
--------------------------------------------------------------------------
DESCRIZIONE: Ok To Send. Accetta una richiesta di trasmissione
RITORNA: nulla
------------------------------------------------------------------------*/
void OTS(void)
{
	BYTE port;

	port = inp(PORTA_TX);
	port = port | TX_CTR;
	outp(PORTA_TX,port);
}

/*************************************************************************
	DR                   PinoContini            26-04-95
--------------------------------------------------------------------------
DESCRIZIONE: Data Ready
RITORNA: nulla
------------------------------------------------------------------------*/
void DR(void)
{
	BYTE port;

	port = inp(PORTA_TX);
	port = port & (~TX_CTR);
	outp(PORTA_TX,port);
}

/*************************************************************************
	ER                   PinoContini            26-04-95
--------------------------------------------------------------------------
DESCRIZIONE: End Read
RITORNA: nulla
------------------------------------------------------------------------*/
void ER(void)
{
	BYTE port;

	port = inp(PORTA_TX);
	port = port & (~TX_CTR);
	outp(PORTA_TX,port);
}

/*************************************************************************
	IsRTS                   PinoContini            26-04-95
--------------------------------------------------------------------------
DESCRIZIONE: Verifica se sulla linea e' presente un RTS
 RITORNA: TRUE o FALSE
------------------------------------------------------------------------*/
BOOL IsRTS(void)
{
	BYTE port;
	port = ~inp(PORTA_RX);       /* leggo lo stato della porta */
	port = port & RX_CTR;        /* test sul bit di controllo in lettura */
	if (port==0) return FALSE;
	else return TRUE;
}
/*************************************************************************
	WaitRTS                   PinoContini            26-04-95
--------------------------------------------------------------------------
DESCRIZIONE: Attende una richiesta di trasmissione
 l'ingresso del bit di controllo Š negato (busy)
RITORNA: TRUE se RTS TIMEOUT diversamente
------------------------------------------------------------------------*/
BOOL WaitRTS(void)
{
	BYTE port;
	clock_t start = clock();       /* istante iniziale */
	do
	{
		port = ~inp(PORTA_RX);       /* leggo lo stato della porta */
		port = port & RX_CTR;        /* test sul bit di controllo in lettura */
		if(clock() > start + CLK_TIMEOUT) return TIMEOUT;
	} while(port == 0);
	return TRUE;
}

/*************************************************************************
	WaitDR                   PinoContini            26-04-95
--------------------------------------------------------------------------
DESCRIZIONE: Attende che sia in Data Ready
RITORNA: TRUE se DR TIMEOUT diversamente
------------------------------------------------------------------------*/
BOOL WaitDR(void)
{
	BYTE port;
	clock_t start = clock();       /* istante iniziale */
	do
	{
		port = ~inp(PORTA_RX);        /* leggo lo stato della porta */
		port = port | (~RX_CTR);    /* test sul bit di controllo in lettura */
		if(clock() > start + CLK_TIMEOUT) return TIMEOUT;
	} while(port != 0x7F);         /* 0111 1111 */
	return TRUE;
}

/*************************************************************************
	WaitOTS                   PinoContini            26-04-95
--------------------------------------------------------------------------
DESCRIZIONE: Is Ok To Send. Attende che RX si dispone in OTS.
RITORNA: TRUE se OTS TIMEOUT diversamente
------------------------------------------------------------------------*/
BOOL WaitOTS(void)
{
	BYTE port;
	clock_t start = clock();       /* istante iniziale */
	do
	{
		port = ~inp(PORTA_RX);        /* leggo lo stato della porta */
		port = port & RX_CTR;        /* test sul bit di controllo in lettura */
		if(clock() > start + CLK_TIMEOUT) return TIMEOUT;
	} while(port == 0);
	return TRUE;
}

/*************************************************************************
	WaitER                   PinoContini            26-04-95
--------------------------------------------------------------------------
DESCRIZIONE: Aspetta End Read. Attende che RX si dispone in ER.
RITORNA: TRUE se OTS TIMEOUT diversamente
------------------------------------------------------------------------*/
BOOL WaitER(void)
{
	BYTE port;
	clock_t start = clock();       /* istante iniziale */
	do
	{
		port = ~inp(PORTA_RX);       /* leggo lo stato della porta */
		port = port | (~RX_CTR);    /* test sul bit di controllo in lettura */
		if(clock() > start + CLK_TIMEOUT) return TIMEOUT;
	} while(port != 0x7F);        /* 0111 1111  */
	return TRUE;
}


/*************************************************************************
	Trasmetti                   PinoContini            26-04-95
--------------------------------------------------------------------------
DESCRIZIONE: Trasmette un byte.
RITORNA: L'esito dell'operazione (TRUE, TIMEOUT)
------------------------------------------------------------------------*/
BOOL Trasmetti(BYTE c)
{
	BYTE port;
	/*------------------------- Trasmetto il nibble MENO significativo */
	RTS();                             /* invia richiesta trasmissione */

	port = inp(PORTA_TX);             /* legge lo stato della porta   */
	port = port & (~TX_DATI);        /* azzero i bit di trasmissione */
	port = port | (c & LSN);         /* imposto i bit 0..3 con LSN   */
	if(WaitOTS()!=TRUE) return TIMEOUT;
	outp(PORTA_TX,port);              /* trasmetto il nibble          */
	DR();                              /* invio Data Ready */
	if(WaitER() !=TRUE) return TIMEOUT;

	/*------------------------- Trasmetto il nibble PIU  significativo */
	RTS();                         /* invia richiesta trasmissione */

	port = inp(PORTA_TX);             /* legge lo stato della porta   */
	port = port & (~TX_DATI);        /* azzero i bit di trasmissione */
	port = port | (c >> 4);          /* imposto i bit 0..3 con MSN   */

	if(WaitOTS()!=TRUE) return TIMEOUT;
	outp(PORTA_TX,port);              /* trasmetto il nibble          */
	DR();                              /* invio Data Ready */
	if(WaitER() !=TRUE) return TIMEOUT;

	return TRUE;
}

/*************************************************************************
	Ricevi                      PinoContini            26-04-95
--------------------------------------------------------------------------
DESCRIZIONE: Riceve un byte. Questa funzione viene chiamata da una
	funzione che ascolta TX per verificare la presenza di una RTS.
RITORNA: L'esito dell'operazione
	-TRUE     =>  carattere ricevuto
	-FALSE    =>  nessun carattere trasmesso
	-TIMEOUT  =>  tentativo di trasmissione di TX ma non ricevuto correttamente
------------------------------------------------------------------------*/
BOOL Ricevi(BYTE *c)
{
	BYTE port;

	if(IsRTS() == FALSE) return FALSE;

	OTS();                               /* emette un Ok To Send */
	if(WaitDR() != TRUE) return TIMEOUT;
	port = inp(PORTA_RX);                /* legge il nibble    */
	ER();                                /* emette un End Read */
	*c = (port >> 3);                    /* leggo LSN */

	if(WaitRTS() != TRUE) return TIMEOUT;
	OTS();
	if(WaitDR() != TRUE) return TIMEOUT;
	port = inp(PORTA_RX);                /* legge il nibble    */
	ER();                                /* emette un End Read */
	*c = (*c & ~MSN);                    /* azzero MSN di c*/
	*c = (*c | ((port >> 3) << 4));      /* leggo MSN */

	return TRUE;
}

#ifdef PROVA_LPT
void main(void)
{
	BYTE cs,cr,res;
	int rows=1,rowr=13,culs=1,culr=1;

	clrscr();
	printf("\nProva del programma LPTLINK  trasmette e riceve.\n");
	printf("\nCollegati con un altro comupter e comincia a scrivergli,");
	printf("\nPremi @ per terminare\n");
	printf("\nVerifica connessione...premi un tasto per interrompre");

	while(kbhit() != 0) getch();      //svuoto il buffere tastiera
	while(OpenComunication()!=TRUE)
	{
		if (kbhit() != 0)
		{
			printf("\nConnessione non verificata ...premi un tasto!!");
			getch();
			break;
		}
	}

	clrscr();
	gotoxy(1,12);
	printf("------------------------------------------Premi @ per terminare");

////
	while(kbhit() != 0) getch();      //svuoto il buffere tastiera
	do
	{
		if(kbhit() !=0)
		{
			cs = getch();
			if(cs == '\r')
				{cs = '\n';
				 culs = 1;}
			gotoxy(culs,rows);
			putch(cs);
			culs = wherex();
			rows = wherey();
			(rows >= 12)?rows=1:rows;
			if(TRUE != Trasmetti(cs))
				printf("ERRORE DI TRASMISSIONE !!");
		}
		if(TRUE==Ricevi(&cr))
		{
			if(cr == '\n') culr = 1;
			gotoxy(culr,rowr);
			putch(cr);
			rowr = wherey();
			culr = wherex();
			(rowr > 24)?rowr=13:rowr;
			}
	} while((cs != '@')&&(cr != '@'));
	if(cr == '@') printf("\nLa comunicazione e' stata interrotta\n");
}


#endif
