/*	PiMSDOS.c - Edit 1

	LoadICE Version 4
	Copyright (C) 1990-96 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
	For MSDOS
*/

#ifdef MSDOS
#include <stdio.h>
#include <io.h>
#ifdef TCC
#include <mem.h>
#else
#include <memory.h>
#endif

#include <conio.h>
#include <time.h>
#include <dos.h>
#include <process.h>

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

#ifdef ANSI
long pi_raw(void);
void pi_toggle(void);
void pi_cook(void);
long pi_switch(void);
long pi_aitty(void);
void pi_sleep(short time);
void pi_setime(time_t time);
long pi_chktime();
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);
long pi_rcv(void);
void pi_ccw(void);
void pi_cccw(void);
static void pi_putp2(char data);
static void do_back(void);
static void do_back2(void);

#else
long pi_raw();
void pi_toggle();
void pi_cook();
long pi_aitty();
long pi_switch();
void pi_sleep();
void pi_setime();
long pi_chktime();
void pi_put();
void pi_putp();
void pi_puts();
long pi_get();
long pi_getp();
void pi_putp();
long pi_rcv();
void pi_ccw();
void pi_cccw();
static void pi_putp2();
static void do_back();
static void do_back2();
#endif

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;
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;

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

long pi_raw()
	{
	unsigned far *partbl;
	unsigned far *comtbl;

	pl_once = 0;
	if (!(pxlink.flags&PLPQ) || (piflags&PiAI && !(piflags&PiXP)))
		{
		pi_estr1 = pxlink.name;
		if (!(pxlink.flags&PLSU))
			{
			comtbl = (unsigned far *)&pxlink.saddr;
			printf("\n Getting COM address from BIOS");
			switch (pxlink.name[3])
				{
				case '1':
					movedata(0x40,0x0,FP_SEG(comtbl),FP_OFF(comtbl),2);
					break;
				case '2':
					movedata(0x40,0x2,FP_SEG(comtbl),FP_OFF(comtbl),2);
					break;
				case '3':
					movedata(0x40,0x4,FP_SEG(comtbl),FP_OFF(comtbl),2);
					break;
				case '4':
					movedata(0x40,0x6,FP_SEG(comtbl),FP_OFF(comtbl),2);
					break;
				default:
					return(PGE_BAA);
				}
			}
		if(!pxlink.saddr)
			{
			return(PGE_BAA);
			}
		if (pxlink.brate == 0)
			pxlink.brate = 57600;
		if (pxdisp&PXHI)
			printf("\n Opening Serial Port %s (@0x%X) @BR-%ld",
				pxlink.name,pxlink.saddr,pxlink.brate);
		if (piflags&PiAI && !(piflags&PiXP))
			pi_put((char)pxaibchr);
		pxiereg = (char)inp(IEREG);
		pxlcreg = (char)inp(LCREG);
		outp(IEREG, 0);
		outp(LCREG, (char)128);
		pxdllsb = (char)inp(DLLSB);
		pxdlmsb = (char)inp(DLMSB);
		outp(DLLSB, (char)(0xFF & CDIV));
		outp(DLMSB, (char)((0xFF00 & CDIV) >> 8));
		outp(IDREG, FIFON);
		outp(IDREG, FIFOC);
		if (piflags&PiSW)
			{
			outp(LCREG,LC1STP|LCBRK); /* 1 stpBit+Brk if AISwitch */
			pi_sleep(1);
			outp(LCREG,LC1STP);
			}
		else
			{
			outp(LCREG, LC2STP);	/* MUST BE TWO STOP BITS FOR DAISY CHAIN */
			}
		}
	if (pxlink.flags&(PLPP|PLPQ|PLPB))
		{
		pxlink.flags |= PLST;
		if (!(pxlink.flags&PLPU))
			{
			pi_estr1 = pxlink.pname;
			partbl = (unsigned far *)& pxlink.paddr;
			printf("\n Getting LPT address from BIOS");
			switch (pxlink.pname[3])
				{
				case '1':
					movedata(0x40,0x8,FP_SEG(partbl),FP_OFF(partbl),2);
					break;
				case '2':
					movedata(0x40,0xa,FP_SEG(partbl),FP_OFF(partbl),2);
					break;
				case '3':
					movedata(0x40,0xc,FP_SEG(partbl),FP_OFF(partbl),2);
					break;
				case '4':
					movedata(0x40,0xd,FP_SEG(partbl),FP_OFF(partbl),2);
					break;
				default:
					return(PGE_BAA);
				}
			}
		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);
		}
	pi_toggle();
	pi_toggle();
	pi_toggle();
	return(PGE_NOE);
	}

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

void pi_toggle()
	{
	char c;

	if (!(pxlink.flags&PLPQ) || (piflags&PiAI && !(piflags&PiXP)))
		{
		if (pxdisp&PXVL)
			printf("^");
		outp(MCREG,MCRSTS);
		pi_sleep(1);
		outp(MCREG,MCRSTC);
		pi_sleep(1);
		}
	else
		{
		if (pxdisp&PXVL)
			printf("|");
		while(!pi_getp(&c));
		outp(pxlink.ppout, PP_INITS);
		pi_sleep(1);
		outp(pxlink.ppout, PP_INITC);
		pi_sleep(1);
		}
	}

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

void pi_cook()
	{
	char c;
	char d;

	if (piflags&PiSW)
		{
		outp(LCREG,LC1STP|LCBRK);
		pi_sleep(1);
		outp(LCREG,LC1STP);
		}
	if (!(pxlink.flags&PLPQ))
		{
		while (!(inp(LSREG) & TSRMT));
		outp(LCREG, (char)128);
		outp(DLLSB,pxdllsb);
		outp(DLMSB,pxdlmsb);
		outp(LCREG,pxlcreg);
		outp(IEREG,pxiereg);
		}
	else
		piflags &= ~PiFP;
	}

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

#ifdef ANSI
long pi_xmt(char *buf, long ct)
#else
long pi_xmt(buf, ct)
char *buf;
long ct;
#endif
	{
	unsigned char id;
	unsigned char *po;
	short i;

	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);
					for (po=ppoff,i=0; i<4; i++)
						pi_putp(*po++);
					pi_rcv();
					}
				if (pxdisp&PLOG)
					write(pclog,ppon,4);
				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;
				}
		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;

	for (i=0;i<259;i++)
		pxrsp[i]=0xff;
	pi_setime(PIC_TOT);
	if (pxlink.flags&PLPQ || piflags&PiLO)
		if (piflags&PiFP)
			if (pptwo)
				do_back2();
			else
				do_back();
	if (pxlink.flags&PLPQ)
		{
		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
		{
		for (i=0; i<4; i++)
			while(pi_get(&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_get(&pxrsp[i]) && !pxtout);
			}
		}
	if (pxtout)
		return(PGE_TMO);
	else
		return(PGE_NOE);
	}

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

#ifdef ANSI
void pi_put(char data)
#else
void pi_put(data)
char data;
#endif
	{
	if (pxlink.flags&PLPQ)
		{
		pi_putp(data);
		return;	
		}
	if (pxdisp&PXVL)
		printf(" %02X",data&0xff);
	if (pi_chksts(LSREG,BUFMT,1))
		outp(TXBUF, data);
	if (!pxtout && pxdisp&PXVL)
		printf("+");
	}

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

#ifdef ANSI
void pi_putp(char data)
#else
void pi_putp(data)
char data;
#endif
	{
	long i;

	if (pptwo)
		{
		pi_putp2(data);
		return;
		}
	if (pxdisp&PXVL)
		printf(" %02X",data&0xff);
	if (pi_chksts(pxlink.ppin,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 (pi_chksts(pxlink.ppin,BUSY,1))
		{
		outp(pxlink.ppout, B_ACK);
		if (piflags&PiZZ || pxlink.flags&PLST)
			for (i=0; i<ppxdl1; i++);
		outp(pxlink.ppout, STROFF);
		}
	}

/* `pi_putp2` -  use Autofeed as strobe and Out of paper as busy */

#ifdef ANSI
static	void pi_putp2(char data)
#else
static	void pi_putp2(data)
char data;
#endif
	{
	long i;

	if (pxdisp&PXVL)
		printf(" %02X",data&0xff);
	if (pi_chksts(pxlink.ppin,PAPER,0))
		{
		outp(pxlink.ppdat, data);
		outp(pxlink.ppout, AUTOON);
		if (piflags&PiZZ || pxlink.flags&PLST)
			for (i=0; i<ppxdl2; i++);
		outp(pxlink.ppout, AUTOOFF);
		if (!(piflags&PiFP))
			do_back2();
		}
	if (!pxtout && pxdisp&PXVL)
		printf("*");
	}

#ifdef ANSI
static void do_back2(void)
#else
static void do_back2()
#endif
	{
	long i;
	if (pi_chksts(pxlink.ppin,PAPER,0))
		{
		outp(pxlink.ppout, B_ACK);
		if (piflags&PiZZ || pxlink.flags&PLST)
			for (i=0; i<ppxdl1; i++);
		outp(pxlink.ppout, AUTOOFF);
		}
	}

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

#ifdef ANSI
long pi_getp(char *cp)
#else
long pi_getp(cp)
char *cp;
#endif
	{
	static long delay=0;
	long i;

	if (pxlink.flags&PLPQ)
		{
		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(pxlink.ppin,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(pxlink.ppin,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(pxlink.ppin,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 */

#ifdef ANSI
long pi_get(char *cp)
#else
long pi_get(cp)
char *cp;
#endif
	{
	static long delay = 0;

	if (pxlink.flags&PLPQ)
		return(pi_getp(cp));
	else
		{
		if (inp(LSREG) & RDA)
			{
			delay = 0;
			*cp = (char)inp(RXBUF);
			if (pxdisp&PXVL)
				printf("-%02X",*cp&0xff);
			return(PGE_NOE);
			}
		else
			if (inp(LSREG) & OVR)
				pxerror = PGE_OVR;
		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 */

#ifdef ANSI
void pi_sleep(short t)
#else
void pi_sleep(t)
short t;
#endif
	{
	clock_t x;

	x = clock();
	while (clock() < (x+t*4));
	}

/* `pi_setime` - set timeout time */

void pi_setime(time_t ttime)
	{
	time_t t;

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

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

long pi_chktime()
	{
	time_t t;

	if (pxnotot || piflags&PiNT)
		{
		if (kbhit())
			{
			pxtout = 1;
			return(0);
			}
		return(1);
		}

	t = time(NULL);
	if (pithen > t)
		return(1);
	pxtout = 1;
	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 (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 (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_switch` - connect thru the switch */

long pi_switch()
	{
	char c;
	char aiport[PIC_CL];
	short i;

	pxnotot = 1;
	while (pi_get(&c))
		{
		pi_put(13);
		pi_sleep(1);
		}
	if (pxdisp&PXLO)
		printf("%c",c);
	if (c != '>')
		{
		do
			{
			while (pi_get(&c));
			if (pxdisp&PXLO)
				printf("%c",c);
			} while (c != '>');
		}
	if (pxdisp&PXLO)
		printf("AI");
	pi_puts("ai");
	i = 0;
	do
		{
		while (pi_get(&c));
		if (pxdisp&PXLO)
			printf("%c",c);
		aiport[i++] = c;
		} while (c != '>');
	*(pxaicstr+5) = aiport[i-6];
	*(pxaicstr+6) = aiport[i-5];
	*(pxaicstr+7) = aiport[i-4];
	if (pxdisp&PXHI)
		printf("\nConnecting via AISwitch, command '%s'",pxaicstr);
	pi_puts(pxaicstr);
	pxnotot = 0;
	return(PGE_NOE);
	}

/* `pi_puts` - send a whole string to the AISwitch */

#ifdef ANSI
void pi_puts(char *str)
#else
void pi_puts(str)
char *str;
#endif
	{
	char c,ec;

	while (*str)
		{
		c = *str++;
		pi_put(c);
		while(pi_get(&ec));
		}
	pi_put(13);
	while(pi_get(&ec));
	}

/* `pi_aitty` - set up AI in tty mode */

long pi_aitty()
	{
	return(PGE_NOE);
	}

#endif
