/*	PiWinS.c - Edit 1

	LoadICE Version 4
	Copyright (C) 1990-99 Grammar Engine, Inc.
	All rights reserved
	
	NOTICE:  This software source is a licensed copy of Grammar Engine's
	property.  It is supplied to you as part of support and maintenance
	of some Grammar Engine products that you may have purchased.  Use of
	this software is strictly limited to use with such products.  Any
	other use constitutes a violation of this license to you.
*/

/*	S Y S T E M  S P E C I F I C   D E V I C E  I/O  R O U T I N E S
	Adapted to Windows 95/NT using standard serial driver and custom
	parallel port driver called PromICE.sys from Grammar Engine Inc.
	Plus support for Ethernet with the FastPort print server
*/

#ifdef	WIN32

#define	USECOMM		// We are using Serial I/O stuff

#include	<windows.h>
#include	<commdlg.h>
#include	<string.h>
#include	<io.h>
#include	<conio.h>
#include	<stdio.h>
#include	<memory.h>
#include	<time.h>
#include	<\ddk\inc32\devioctl.h>
#include	<winsock.h>

#include "piconfig.h"
#include "pistruct.h"
#include "pierror.h"
#include "pidriver.h"
#include "pidata.h"
#include "pidev.h"
#include "piioctl.h"

long pi_raw(void);
void pi_toggle(void);
void pi_cook(void);
long pi_switch(void);
long pi_aitty(void);
void pi_beep(void);
void pi_sleep(short time);
void pi_setime(time_t time);
long pi_chktime();
long pi_rcv();
void pi_put(char data);
void pi_putp(char data);
void pi_puts(char *str);
long pi_get(char *data);
long pi_getp(char *data);
void pi_putp(char data);
long pi_chksts(short addr, char data, char bit);
void pi_ccw(void);
void pi_cccw(void);
void pi_uppp(void);
static void do_back(void);

unsigned short	pxmctl;					/* modem control value */
unsigned char	pxdllsb;				/* initial UART values to be restored */
unsigned char	pxdlmsb;				/* divisor latch */
unsigned char	pxlcreg;				/* line control register */
unsigned char	pxiereg;				/* interrupt enable register */
unsigned int	pxmstat;				/* modem status  */
unsigned int	pxlstat;				/* line status */
unsigned int	pxcomerror;				/* error number */
extern short pptwo;
extern int pclog;
static unsigned short picuct;
static long to;
static time_t pithen = 0;
static short pitimer = 0;
char *pxaicstr = "MCON 000 000";
static unsigned char ppon[4] = {0,PI_MO,1,MO_PPXN};
static unsigned char ppoff[4] = {0,PI_MO,1,MO_PPXO};
static char idon = 0;
static int pl_once;

struct sockaddr_in server;
//struct hostent FAR * PASCAL FAR hp;
struct hostent FAR * hp;

HANDLE	sid,pid;
COMMTIMEOUTS lcomt;
LPCOMMTIMEOUTS lpcomt;
DCB	pidcb;
UCHAR Pbuf[260];
DWORD wlen,rlen;
BOOL iocr;

WORD	wVersionRequested = MAKEWORD(1,1);
WSADATA	wsaData;
int	nErrorStatus;

/* `pi_raw` - set serial port to raw mode or mess with the parallel port */

long pi_raw()
	{
	long localflag;

	if (piflags&PiNE)
		{
		/* reset fastport */
		char one;

		nErrorStatus = WSAStartup(wVersionRequested, &wsaData);
		if (nErrorStatus != 0)
		{
			printf("\nCan not start WINSOCK (windows socket stuff)\n");
			exit(1);
		}
		if (piflags&PiRF)
			{
			if ((pxlink.saddr = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
				perror("SocketMonitor"), exit(1);
			server.sin_family = AF_INET;

			if (hp = gethostbyname(pxhost))
				{
				CopyMemory((char *)&server.sin_addr,(char *)hp->h_addr,hp->h_length);
				server.sin_port = htons(pxhostcs);
				}
			else
				{
				printf("HOST=%s ",pxhost);
				perror("FastPort hostname");
				exit(1);
				}

			printf("\nConnecting to the FastPort Monitor\n");
			if (connect(pxlink.saddr,(struct sockaddr *)&server,sizeof(server)) == SOCKET_ERROR)
				perror("ConnectMonitor"), exit(1);
			localflag = 0;
			for (;;)
			{
				while (pi_get(&one));
				if (one == 'V')
				{
					pi_put('!');
					pi_put('\r');
					localflag++;
					break;
				}
				else
					if (one == 'W')
						break;
			}
			pi_put('y');
			pi_put('\r');
			for (;;)
				{
				while (pi_get(&one));
				if (one == '>')
					break;
				}
			while (pi_get(&one));
			while (pi_get(&one));
			pi_put('r');
			pi_put('\r');
			closesocket(pxlink.saddr);
			if (localflag)
			{
				printf("Issuing Reset - 22 seconds wait!\n");
				pi_sleep(110);
			}
			else
			{
				printf("Issuing Reset - 11 seconds wait!\n");
				pi_sleep(55);
			}
			}

		/* serial */
		printf("\nConnecting to the Serial Port on the FastPort\n - ");
		if ((pxlink.saddr = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
			perror("SocketSerial"), exit(1);
		server.sin_family = AF_INET;

		if (!(piflags&PiRF))
			{
			if (hp = gethostbyname(pxhost))
				{
				CopyMemory((char *)&server.sin_addr,(char *)hp->h_addr,hp->h_length);
				server.sin_port = htons(pxhostss);
				}
			else
				{
				printf("HOST=%s ",pxhost);
				perror("FastPort hostname");
				exit(1);
				}
			}
		else
			server.sin_port = htons(pxhostss);
	
		printf("Got a Socket - ");
		if (connect(pxlink.saddr,(struct sockaddr *)&server,sizeof(server)) == SOCKET_ERROR)
		{
			printf(" Failed to connect. Error code = %x ",WSAGetLastError());
			exit(1);
		}
			printf(" Connected!\n");
		if (pxlink.flags&(PLPP|PLPQ))
			{
			/* parallel */
			printf("Connecting to the Parallel Port on the FastPort\n - ");
			if ((pxlink.paddr = socket(AF_INET, SOCK_STREAM, 0)) < 0)
				perror("SocketParalell"), exit(1);
			server.sin_family = AF_INET;

			server.sin_port = htons(pxhostps);

			printf("Got a Socket - ");
			if (connect(pxlink.paddr,(struct sockaddr *)&server,sizeof(server))<0)
				perror("ConnectParallel"), exit(1);
			printf("Connected!\n");
			}
		if (piflags&PiAI)
			pi_put((char)pxaibchr);
		}
	else
	{
	lpcomt = &lcomt;
	pl_once = 0;
	if (!(pxlink.flags&PLPQ) || (piflags&PiAI && !(piflags&PiXP)))
		{
		if (!strlen(pxlink.name)) return(PGE_BPN);
		pi_estr1 = pxlink.name;
		if (pxlink.brate == 0)
			pxlink.brate = PIC_BAUD;
		if (pxdisp&PXHI)
			printf("\n Opening Serial Port %s @BR-%ld",
				pxlink.name,pxlink.brate);

		if ((sid = CreateFile(pxlink.name,GENERIC_READ|GENERIC_WRITE,
					0,
					NULL,
					OPEN_EXISTING,
					FILE_ATTRIBUTE_NORMAL,
					NULL)) == INVALID_HANDLE_VALUE)
			{
			LPVOID lpMsgBuf;
 
			FormatMessage( 
				FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
				NULL,
				GetLastError(),
				MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
				(LPTSTR) &lpMsgBuf,
				0,
				NULL 
				);

			// Display the string.
			MessageBox( NULL, lpMsgBuf, "LoadICE: Open Serial Port", MB_OK|MB_ICONSTOP );

			// Free the buffer.
			LocalFree( lpMsgBuf );
			return(PGE_NOD);
			}
		pidcb.DCBlength = sizeof(DCB);
		GetCommState(sid,&pidcb);
		switch(pxlink.brate)
		{
		case 1200:
			pidcb.BaudRate = CBR_1200;
			break;
		case 2400:
			pidcb.BaudRate = CBR_2400;
			break;
		case 4800:
			pidcb.BaudRate = CBR_4800;
			break;
		case 9600:
			pidcb.BaudRate = CBR_9600;
			break;
		case 19200:
			pidcb.BaudRate = CBR_19200;
			break;
		case 57600:
			pidcb.BaudRate = CBR_57600;
			break;
		default:
			return(PGE_BAA);
		}
		pidcb.ByteSize = 8;
		pidcb.Parity = NOPARITY;
		pidcb.StopBits = TWOSTOPBITS;
		SetCommState(sid,&pidcb);
		PurgeComm(sid,PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR);
		lpcomt->ReadIntervalTimeout = MAXDWORD;
		lpcomt->ReadTotalTimeoutMultiplier = 0;
		lpcomt->ReadTotalTimeoutConstant = 0;
		lpcomt->WriteTotalTimeoutMultiplier = 0;
		lpcomt->WriteTotalTimeoutConstant = 0;
		if (!SetCommTimeouts(sid,lpcomt))
			return(PGE_IOE);
		}
	if (pxlink.flags&(PLPP|PLPQ|PLPB))
		{
		pxlink.flags |= PLST;
		if (!(pxlink.flags&PLPU))
			{
			pi_estr1 = pxlink.pname;
			switch (pxlink.pname[3])
				{
				case '1':
					pxlink.paddr = 0x378;
					break;
				case '2':
					pxlink.paddr = 0x278;
					break;
				case '3':
					pxlink.paddr = 0x3B8;
					break;
				case '4':
					pxlink.paddr = 0x2B8;
					break;
				default:
					return(PGE_BAA);
				}
			}
		if (pxflags & PONT)
			{
			if (pxdisp&PXHI)
				printf ("\n Opening Parallel Device PromICE");
			if ((pid = CreateFile("\\\\.\\PromICE",GENERIC_READ|GENERIC_WRITE,
						0,
						NULL,
						OPEN_EXISTING,
						FILE_ATTRIBUTE_NORMAL,
						NULL)) == (HANDLE)-1)
				{
				LPVOID lpMsgBuf;
 
				FormatMessage( 
					FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
					NULL,
					GetLastError(),
					MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
					(LPTSTR) &lpMsgBuf,
					0,
					NULL 
					);

				// Display the string.
				MessageBox( NULL, lpMsgBuf, "LoadICE: Open Parallel Port", MB_OK|MB_ICONSTOP );

				// Free the buffer.
				LocalFree( lpMsgBuf );
				return(PGE_NOD);
				}
			}
		if (pxflags & PO95)
			{
			pxlink.ppdat = (unsigned int)pxlink.paddr;
			if(!pxlink.ppdat)
				{
				return(PGE_BPN);
				}
			pxlink.ppin = pxlink.ppdat + 1;
			pxlink.ppout = pxlink.ppdat + 2;
			_outp(pxlink.ppdat, 0);
			if (piflags&PiAI && piflags&PiXP)
				pi_putp((char)pxaibchr);
			if (pxdisp&PXHI)
				printf ("\n Opening Parallel Port %s (@0x%X)"
					,pxlink.pname,pxlink.paddr);
			}
		}
	if (piflags&PiNE)
		printf("\nConnecting to PromICE via the FastPort Serial Port");
	else
		if (pxlink.flags&PLPQ)
			printf("\nConnecting to PromICE via the Parallel Port");
		else
			printf("\nConnecting to PromICE via the Serial Port");
	if (piflags&PiAI)
		{
		pi_toggle();
		pi_toggle();
		pi_toggle();
		}
	else
		pi_toggle();
	}
	return(PGE_NOE);
	}

/* `pi_toggle` - toggle reset signal to PROMICE */

void pi_toggle()
	{
	char c;

	if (piflags&PiNE)
		return;
	if (!(pxlink.flags&PLPQ) || (piflags&PiAI && !(piflags&PiXP)))
		{
		if (pxdisp&PXVL)
			printf("^");
		EscapeCommFunction(sid,SETDTR);
		pi_sleep(1);
		EscapeCommFunction(sid,CLRDTR);
		pi_sleep(1);
		}
	else
		{
		if (pxdisp&PXVL)
			printf("|");
		if (pxflags&PONT)
			{
			Pbuf[0] = PP_INITS;
			wlen = 1;
			DeviceIoControl(pid,IOCTL_PI_CONTROL,Pbuf,wlen,NULL,0,&rlen,NULL);
			pi_sleep(1);
			Pbuf[0] = PP_INITC;
			DeviceIoControl(pid,IOCTL_PI_CONTROL,Pbuf,wlen,NULL,0,&rlen,NULL);
			pi_sleep(1);
			}
		if (pxflags&PO95)
			{
			while(!pi_getp(&c));
			_outp(pxlink.ppout, PP_INITS);
			pi_sleep(1);
			_outp(pxlink.ppout, PP_INITC);
			pi_sleep(1);
			}
		}
	}

/* `pi_upp` - pass pport parameters on to the driver */

void pi_uppp(void)
	{
	ULONG tbuf[2],tlen;
	tbuf[0] = tbuf[1] = 0;
	tlen = sizeof(tbuf);
	if (piflags&PiFP)
		tbuf[0] = 1;
	if (piflags&PiZZ)
		tbuf[1] = ppxdl1;
	if (pxflags&PONT && !piflags&PiNE)
		DeviceIoControl(pid,IOCTL_PI_PARAMETER,tbuf,tlen,NULL,0,&rlen,NULL);
	}

/* `pi_cook` - restore the serial port */

void pi_cook()
	{
	if (piflags&PiNE)
		{
		shutdown(pxlink.paddr,1);
		shutdown(pxlink.saddr,1);
		closesocket(pxlink.paddr);
		closesocket(pxlink.saddr);
		}
	else
		{
		if (piflags&PiSW)
			{
			pi_sleep(1);
			}
		if (!(pxlink.flags&PLPQ))
			{
			CloseHandle(sid);
			}
		else
			{
			if (pxflags&PONT)
				CloseHandle(pid);
			piflags &= ~PiFP;
			}
		}
	}

void pi_cooks()
	{
	CloseHandle(sid);
	}

/* `pi_xmt` - send a block of data over the i/o device */

long pi_xmt(char *buf, long ct)
	{
	unsigned char id;
	unsigned char *po;
	int i, cnt, offset, n_write;

	pi_setime(PIC_TOT);
	if (pxlink.flags&(PLPP|PLPQ) && !(piflags&PiSO))
		{
		id = *(buf+PIID);
		if ((pxlink.flags&PLPB) || (pxrom[id].mid == 0))
			pptwo = 0;
		else
			pptwo = 1;
		if (pxlink.flags&PLPB)
			if (!(pxrom[id].flags&PRPP))
				{
				ppon[0] = id;
				ppoff[0] = idon;
				if (piflags&PiMU)
					{
					ppon[3] &= ~MO_LOAD;
					ppoff[3] &= ~MO_LOAD;
					}
				else
					{
					ppon[3] |= MO_LOAD;
					ppoff[3] |= MO_LOAD;
					}
				if (pl_once)
					{
					if (pxdisp&PLOG)
						write(pclog,ppoff,4);
					if (piflags&PiNE)
						{
						send(pxlink.paddr,ppoff,4,0);
						}
					else
						for (po=ppoff,i=0; i<4; i++)
							pi_putp(*po++); 
					pi_rcv();
					}
				if (pxdisp&PLOG)
					write(pclog,ppon,4);
				if (piflags&PiNE)
					send(pxlink.saddr,ppon,4,0);
				else
					for (po=ppon,i=0; i<4; i++)
						pi_put(*po++);
				pi_rcv();
				if (pl_once)
					{
					pxrom[pxrom[idon].mid].flags &= ~PRPP;
					pxrom[pxrom[idon].sid].flags &= ~PRPP;
					}
				pxrom[pxrom[id].mid].flags |= PRPP;
				pxrom[pxrom[id].sid].flags |= PRPP;
				idon = id;
				pl_once = 1;
				}
		if (piflags&PiNE)
			{
			cnt = ct;
			offset = 0;
			while ((n_write = send(pxlink.paddr, buf+offset, cnt,0)) != cnt)
				{
				if (n_write > 0)
					{
					pi_chktime();
					offset += n_write;
					cnt -= n_write;
					}
				}
			}
		else
			{
			if ((piflags&PiFP)&&(pxflags&PONT))
				{
				iocr = DeviceIoControl(pid,IOCTL_PI_WRITE_BLOCK,buf,ct,NULL,0,&rlen,NULL);
				if (!iocr)
					{
					pxerror = PGE_IOE;
					}
				}
			else
				{
				while (ct-- && !pxtout)
					pi_putp(*buf++);
				}
			}
		}
	else
		{
		while (ct-- && !pxtout)
			pi_put(*buf++);
		}
	if (pxtout)
		return(PGE_TMO);
	else
		return(PGE_NOE);
	}

/* `pi_rcv` - receive a standard response from the PROMICE */

long pi_rcv()
	{
	long i,j=0,k,l;
	DWORD rlen = 1;
	BOOL rstat;

	for (i=0;i<259;i++)
		pxrsp[i]= (char)0xff;
	pi_setime(PIC_TOT);
	if (pxlink.flags&PLPQ || piflags&PiLO)
		if (piflags&PiFP)
				do_back();
	if (pxlink.flags&PLPQ)
		{
		if (pxflags&PONT)
			{
			pxrspl = 259;
			iocr = DeviceIoControl(pid,IOCTL_PI_READ_BLOCK,NULL,0,pxrsp,pxrspl,&pxrspl,NULL);
			}
		if (pxflags&PO95)
			{
			for (i=0; i<4 && !pxtout; i++)
				while(pi_getp(&pxrsp[i]) && !pxtout);
			if (!pxtout)
				{
				if (pxrsp[PICT] == 0)
					pxrspl = PIC_MP;
				else
					pxrspl = (pxrsp[PICT]&0xff) + 3;
				for (i=4; i<pxrspl; i++)
					while(pi_getp(&pxrsp[i]) && !pxtout);
				}
			}
		}
	else
		{
		i=l=0;
		k=4;
		while(k>0)
			{
			if (piflags&PiNE)
				{
				while ((i=recv(pxlink.saddr,&pxrsp[l],k,0)) < 0)
					if (pxerror || (j++>pxtout))
						{
						if (!pxerror)
							pi_chktime();
						if (pxtout)
							return(PGE_TMO);
						}
				l+=i;
				k-=i;
				}
			else
				{
				rstat=ReadFile(sid,&pxrsp[l],k,&i,NULL);
					if (!rstat)
						{
						if (!pxerror)
							pi_chktime();
						if (pxtout)
							return(PGE_TMO);
						}
				if (rstat)
					{
					l+=i;
					k-=i;
					}
				}
			}
		if (pxrsp[PICT] == 0)
			pxrspl = PIC_MP;
		else
			pxrspl = (pxrsp[PICT]&0xff) + 3;
		i=l=4;
		k=pxrspl-4;
//		k=pxrspl-l;
		while(k>0)
			{
			if (piflags&PiNE)
				{
				while ((i=recv(pxlink.saddr,&pxrsp[l],k,0)) < 0)
					if (pxerror || (j++>PIC_DLY))
						{
						if (!pxtout)
							pi_chktime();
						if (pxtout)
							return(PGE_TMO);
						}
				l+=i;
				k-=i;
				}
			else
				{
				rstat=ReadFile(sid,&pxrsp[l],k,&i,NULL);
					if (!rstat)
						{
						if (!pxtout)
							pi_chktime();
						if (pxtout)
							return(PGE_TMO);
						}
				if (rstat)
					{
					l+=i;
					k-=i;
					}
				}
			}
		}
	if (pxtout)
		return(PGE_TMO);
	else
		return(PGE_NOE);
	}

/* `pi_put` - send byte over serial port */

void pi_put(char data)
	{
	DWORD l = 1;
	UCHAR ldata;

	ldata = data;
	if (pxlink.flags&PLPQ)
		{
		pi_putp(data);
		return;	
		}
	if (pxdisp&PXVL)
		printf(" %02X",data&0xff);
	if (piflags&PiNE)
		while (send(pxlink.saddr,&data,1,0)<0);
	else
		if (!WriteFile(sid,&ldata,l,&l,NULL))
			pxerror = PGE_TMO;
	if (!pxtout && pxdisp&PXVL)
		printf("+");
	}

/* `pi_putp` - send data over parallel port */

void pi_putp(char data)
	{
	long i;

	if (pxdisp&PXVL)
		printf(" %02X",data&0xff);
	if (pxflags&PONT)
		{
		Pbuf[0] = data;
		wlen = 1;
		DeviceIoControl(pid,IOCTL_PI_WRITE_CHAR,Pbuf,wlen,NULL,0,&rlen,NULL);
			if (!(piflags&PiFP))
				do_back();
		}
	if (pxflags&PO95)
		{
		if (pi_chksts((short)pxlink.ppin,(char)BUSY,1))
			{
			_outp(pxlink.ppdat, data);
			_outp(pxlink.ppout, STRON);
			if (piflags&PiZZ || pxlink.flags&PLST)
				for (i=0; i<ppxdl0; i++);
			_outp(pxlink.ppout, STROFF);
			if (!(piflags&PiFP))
				do_back();
			}
		}
	if (!pxtout && pxdisp&PXVL)
		printf(">");
	}

void do_back()
	{
	long i;

	if (pxflags&PONT)
		{
		DeviceIoControl(pid,IOCTL_PI_DO_BACK,Pbuf,wlen,NULL,0,&rlen,NULL);
		}
	if (pxflags&PO95)
		{
		if (pi_chksts((short)pxlink.ppin,(char)BUSY,1))
			{
			_outp(pxlink.ppout, B_ACK);
			if (piflags&PiZZ || pxlink.flags&PLST)
				for (i=0; i<ppxdl1; i++);
			_outp(pxlink.ppout, STROFF);
			}
		}
	}

/* `pi_getp` - read possible byte from the parallel port */

long pi_getp(char *cp)
	{
	static long delay=0;
	long i;

	if (pxlink.flags&PLPQ)
		{
		if (pxflags&PONT)
			{
			wlen = 1;
			rlen = 0;
			DeviceIoControl(pid,IOCTL_PI_READ_CHAR,NULL,0,Pbuf,wlen,&rlen,NULL);
			if (rlen == 0)
				{
				if (delay++ > PIC_DLY)
					{
					delay = 0;
					pi_chktime();
					}
				return(PGE_EOF);
				}
			else
				{
				*cp = Pbuf[0];
				if (pxdisp&PXVL)
					printf(" %02X<",*cp&0xff);
				return(PGE_NOE);
				}
			}
		if (pxflags&PO95)
			{
			if (!((char)_inp(pxlink.ppin) & BUSY))
				{
				delay = 0;
				_outp(pxlink.ppout, B_ACK);
				*cp = (char)(((char)_inp(pxlink.ppin)) >> 3) & (char)0x0f;
				_outp(pxlink.ppout, STROFF);
				if (pi_chksts((short)pxlink.ppin,(char)(char)BUSY,1))
					{
					_outp(pxlink.ppout, B_ACK);
					if (piflags&PiZZ || pxlink.flags&PLST)
						for (i=0; i<ppxdl1; i++);
					_outp(pxlink.ppout, STROFF);
					if (pi_chksts((short)pxlink.ppin,(char)BUSY,0))
						{
						_outp(pxlink.ppout, B_ACK);
						*cp = *cp|(char)(((char)_inp(pxlink.ppin)
							<<(char)1)&(char)0xf0);
						_outp(pxlink.ppout, STROFF);
						if (pi_chksts((short)pxlink.ppin,(char)BUSY,1))
							{
							_outp(pxlink.ppout, B_ACK);
							if (piflags&PiZZ || pxlink.flags&PLST)
								for (i=0; i<ppxdl1; i++);
							_outp(pxlink.ppout, STROFF);
							if (pxdisp&PXVL)
							printf("<%02X",*cp&0xff);
							return(PGE_NOE);
							}
						}
					}
				}
			return(PGE_TMO);
			}
		if (delay++ > PIC_DLY)
			{
			delay = 0;
			pi_chktime();
			}
		return(PGE_EOF);
		}
	else
		return(PGE_IOE);
	}

/* `pi_get` - read possible byte from the serial or parallel port */

long pi_get(char *cp)
	{
	static long delay = 0;
	DWORD rlen = 1;
	BOOL rstat;
	UCHAR data;

	if (pxlink.flags&PLPQ)
		return(pi_getp(cp));
	else
		{
		if (piflags&PiNE)
			{
			if (recv(pxlink.saddr,cp,1,0)>0)
				{
				if (pxdisp&PXVL)
					printf("-%02X",*cp&0xff);
				return(PGE_NOE);
				}
			return(PGE_EOF);
			}
		else
			{
			rstat = ReadFile(sid,&data,rlen,&rlen,NULL);
			if (rstat && (rlen == 1))
				{
				*cp = data;
				if (pxdisp&PXVL)
					printf("-%02X",*cp&0xff);
				return(PGE_NOE);
				}
			if (rstat && rlen) pi_beep();
			if (delay++ > PIC_DLY)
				{
				delay = 0;
				pi_chktime();
				}
			return(PGE_EOF);
			}
		}
	}

/* `pi_chksts` - check i/o status and timeout */

long pi_chksts(short port,char data,char bit)
	{
	long to;
	char pdata;

	if (pxtout)
		return(0);
	if (bit)
		{
		do
			{
			to = 0;
			while ((!(pdata=(char)(_inp(port)&data))) && (to++<PIC_DLY));
			if (pdata)
				return(1);
			pi_chktime();
			} while (!pxtout);
		return(0);
		}
	else
		{
		do
			{
			to = 0;
			while ((pdata=(char)(_inp(port)&data)) && (to++<PIC_DLY));
			if (!pdata)
				return(1);
			pi_chktime();
			} while (!pxtout);
		return(0);
		}
	}
	


/* `pi_sleep` - waste some time */

void pi_sleep(short t)
	{
	Sleep(t*200);	// milliseconds
	}

/* `pi_setime` - set timeout time */

void pi_setime(time_t ttime)
	{
	time_t t;

	pxtout = 0;
	t = time(NULL);
	pithen = t+(ttime*pxdelay);
	pitimer++;
	}

/* `pi_chktime`  - check if timeout happened */

long pi_chktime()
	{
	time_t t;

	if (pxnotot || piflags&PiNT)
		{
		if (kbhit())
			{
			pxtout = 1;
			return(0);
			}
		return(1);
		}
	if (!pitimer)
		pi_setime(PIC_TOT);
	t = time(NULL);
	if (pithen > t)
		return(1);
	pxtout = 1;
	pitimer = 0;
	return(0);
	}

/* `pi_beep` - make a beep sound */

void pi_beep()
	{
	printf("\7");
	}

/* `pi_ccw` - make the cursor spin */

void pi_ccw()
	{
	if (piflags&PiHC)
		{
		if (pxcurse > 1)
			return;
		if (picuct++ % 128)
			return;
		else
			putch('.');
		}
	else
		{
		switch (picuct++ % 4)
			{
			case 0:
				putch('|');
				break;
			case 1:
				putch('/');
				break;
			case 2:
				putch('-');
				break;
			case 3:
				putch('\\');
				break;
			}
		putch('\b');
		}
	}

/* `pi_cccw` - and now the other way */

void pi_cccw()
	{
	if (piflags&PiHC)
		{
		if (pxcurse > 1)
			return;
		if (picuct++ % 128)
			return;
		else
			putch('.');
		}
	else
		{
		switch (picuct++ % 4)
			{
			case 0:
				putch('|');
				break;
			case 1:
				putch('\\');
				break;
			case 2:
				putch('-');
				break;
			case 3:
				putch('/');
				break;
			}
		putch('\b');
		}
	}

#endif