/* ppilib.c -- Parallel Port Interface Library  10-OCT-2004 BPA */

#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <string.h>
#include <ctype.h>
#include <dos.h>
#include <math.h>

#define	DATA	0x378		/* printer port I/O addresses */
#define STAT	0x379
#define CTL	0x37A

#define	ADCLO	0               /* select different functions */
#define	ADCHI	1
#define	ADADR	2
#define	ADSTRT	3
#define	DAC	4
#define	SM	5
#define	DOUT	6
#define	DIN	7

#define ENBIT	8		/* to avoid decoder spikes */
#define ADEOC	128		/* connected to S7 bar of status byte */
#define FALSE	0
#define TRUE	1


void setDAC(int dat)	/* input 0 to 255 */
{
outp(DATA, dat);		/* DAC goes from -5 to 5 for 0 to 255 */
outp(CTL,DAC);
outp(CTL, ENBIT+DAC);
outp(CTL,DAC);
outp(CTL,0);
}


int setVoltage(double val)	/* input from -5000 to 5000 mV */
{
static const double m = 10000.0 / 255;
int	dat;

if( (val < -5000.0) || (val > 5000.0) ) return FALSE;

dat = (int) (128.0 + val / m);
outp(DATA, dat);		/* DAC goes from -5 to 5 for 0 to 255 */
outp(CTL,DAC);
outp(CTL, ENBIT+DAC);
outp(CTL,DAC);
outp(CTL,0);
return TRUE;
}

int selectADC(int chan)
{
if( (chan < 0) || (chan > 7) )
	return FALSE;
outp(DATA, chan);
outp(CTL,ADADR);
outp(CTL, ENBIT+ADADR);
outp(CTL,ADADR);
outp(CTL,0);
return TRUE;
}

int getRawADC(void)		/* returns  0 to 255. used internally */
{
int	lo,hi,dat;

outp(CTL,ADSTRT);
outp(CTL, ENBIT+ADSTRT);
outp(CTL,ADSTRT);

while(inp(STAT) & ADEOC) ;		/* wait for EOC bar to go LOW */

outp(CTL, ADCLO);
outp(CTL, ENBIT+ADCLO);

lo = (inp(STAT) >> 3) & 15;

outp(CTL, ADCHI);
outp(CTL, ENBIT+ADCHI);
hi = (inp(STAT) >> 3) & 15;

dat = (hi << 4) | lo;
return dat;
}

double zeroTo5000(void)		/* returns  0 to 5000 mV */
{
static const double m = 5000.0 / 255;
return (double) m * getRawADC();
}

double minus5000To5000(void)	/* returns  -5000 to 5000 mV */
{
static const double m = 10000.0 / 255;
return (double) m * getRawADC() - 5000;
}


static int smDelay = 300;

int setMotorDelay(int k)
{
if( (k < 200) || (k <0 )) return FALSE;
smDelay = k;
return TRUE;
}

void rotateMotor(int nsteps , int dir)
{
static int pos = 0;
static int seq[4] = {12, 6, 3 ,9};
int i;

for( i = 0; i < nsteps; ++i)
	{
	if(dir)
	   if(pos == 3) pos = 0; else ++pos;
	else
	   if(pos == 0) pos = 3; else --pos;

	outp(DATA , seq[pos]);
	outp(CTL , SM);
	outp(CTL , SM + ENBIT);
	outp(CTL , SM);
	outp(CTL , 0);
	delay(smDelay);
	}
}


int readInputs(void)
{
outp(CTL, DIN);
outp(CTL, ENBIT + DIN);
outp(CTL, DIN);
return (inp(STAT) >> 3) & 15;
}


void writeOutputs(int dat)
{
outp(DATA, dat);
outp(CTL,DOUT);
outp(CTL, ENBIT+ DOUT);
outp(CTL,DOUT);
}


void writeStepper(int dat)
{
outp(DATA, dat);
outp(CTL,SM);
outp(CTL, ENBIT+ SM);
outp(CTL,SM);
}


/*--------------------- Timer Routines --------------------------*/

#define 	TimerResolution    1193181.667
int far* 	p = (int*) 0x40006cL;

static union {
	int   i[2];
	long  l;
	} strt, stop;

int hob , lob;

void markStart(void)
{
disable();
outp(0x43,0);
lob = inp(0x40);
hob = inp(0x40);
enable();
strt.i[0] = ~((hob << 8) | lob);
strt.i[1] = *p;
}

double elapsedTime(void)
{
double result;
long   l;

disable();
outp(0x43,0);
lob = inp(0x40);
hob = inp(0x40);
enable();
stop.i[0] = ~((hob << 8) | lob);
stop.i[1] = *p;
l = stop.l - strt.l;

result = ((l<0)?4294967296.0 + (long)l : (long)l);
return result / TimerResolution;
}

void wait(double val)
{
double current, strt = elapsedTime();

do { current = elapsedTime(); } while(current-strt < val/1000000.0);
}

void initTimer(void)
{
markStart();
delay(1);
elapsedTime();
	/* otherwise the first call to elapsedTime retunrs wrong */
}
/*------------------------Graphics Routines--------------------*/

#define	UP	72
#define DOWN	80
#define LEFT	75
#define RIGHT	77
#define ESC	27

#include <graphics.h>
#define XLIM	639		/* VGA mode 640 x 480 */
#define YLIM	479
#define XOFF	80
#define YOFF	40
#define	XMIN	XOFF		/* border */
#define	XMAX	(XLIM-XOFF)
#define	YMIN	YOFF
#define	YMAX	(YLIM-YOFF)

float	xmin, ymin, xmax, ymax, dx, dy;

void initialize(void)
{
int	driver, mode, result;
  driver = DETECT;	 		/* Request auto-detection */
  initgraph(&driver, &mode, "" );	/* Enter graphics mode */
  result = graphresult();		/* Read result of initialization */
  if( result != grOk ){			/* Error occured during init */
    printf(" Graphics System Error: %s\n", grapherrormsg(result) );
    exit( 1 );
  }
}



void setWorld(double x1, double y1, double x2, double y2)
{
/* Calculate the scale factors to be used by functions drawPoint etc. */
xmin = x1;
ymin = y1;
xmax = x2;
ymax = y2;

dx = (xmax - xmin) / (XMAX-XMIN);
dy = (ymax - ymin) / (YMAX-YMIN);
setcolor(WHITE);
rectangle(XOFF-1, YOFF-1, XMAX+1, YMAX+1);
}


void drawPoint(double x, double y, int color)
{
int crtx, crty;

crtx= XOFF + (int) ( (x-xmin) / dx);
crty = (int) ( (y-ymin) / dy);
crty = YLIM - (crty + YOFF);
putpixel(crtx,crty,color);
}

void box(double x1, double y1, double x2, double y2, int color)
{
int ix1, iy1, ix2, iy2;

ix1 = XOFF + (int) ( (x1-xmin) / dx);
iy1 = YLIM - YOFF - (int) ( (y1-ymin) / dy);
ix2 = XOFF + (int) ( (x2-xmin) / dx);
iy2 = YLIM - YOFF - (int) ( (y2-ymin) / dy);
setcolor(color);
rectangle(ix1,iy1,ix2,iy2);
}


void block(double x1, double y1, double x2, double y2, int color)
{
int ix1, iy1, ix2, iy2;

ix1 = XOFF + (int) ( (x1-xmin) / dx);
iy1 = YLIM - YOFF - (int) ( (y1-ymin) / dy);
ix2 = XOFF + (int) ( (x2-xmin) / dx);
iy2 = YLIM - YOFF - (int) ( (y2-ymin) / dy);
setfillstyle(SOLID_FILL,color);
bar(ix1,iy1,ix2,iy2);
}

void drawLine(double x1, double y1, double x2, double y2)
{
int ix1, iy1, ix2, iy2;

ix1 = XOFF + (int) ( (x1-xmin) / dx);
iy1 = YLIM - YOFF - (int) ( (y1-ymin) / dy);
ix2 = XOFF + (int) ( (x2-xmin) / dx);
iy2 = YLIM - YOFF - (int) ( (y2-ymin) / dy);
line(ix1,iy1,ix2,iy2);
}

void drawBar(double x1, double y1, double x2, double y2)
{
int ix1, iy1, ix2, iy2;

ix1 = XOFF + (int) ( (x1-xmin) / dx);
iy1 = YLIM - YOFF - (int) ( (y1-ymin) / dy);
ix2 = XOFF + (int) ( (x2-xmin) / dx);
iy2 = YLIM - YOFF - (int) ( (y2-ymin) / dy);
bar(ix1,iy1,ix2,iy2);
}


void drawText(double x, double y, char *p)
{
int crtx, crty;

crtx= XOFF + (int) ( (x-xmin) / dx);
crty = (int) ( (y-ymin) / dy);
crty = YLIM - (crty + YOFF);
outtextxy(crtx,crty,p);
}


void drawGrid(char *xlabel, char *ylabel)
{
double x, y, dx, dy;
char	ss[20];

dx = (xmax - xmin) / 10;
dy = (ymax - ymin) / 10;

setcolor(GREEN);
settextjustify(1,1);
if(xlabel)
	drawText((xmin+xmax)/2, ymin-dy/2, xlabel);
if(ylabel)
	{
	settextstyle(DEFAULT_FONT,1,1);
	drawText(xmin-dx, (ymin+ymax)/2, ylabel);
	settextstyle(DEFAULT_FONT,0,1);
	}
for(x=xmin+dx; x < xmax; x += dx)
	{
	drawLine(x, ymin, x,ymax);
	sprintf(ss,"%4.0f",x);
	drawText(x, ymin-dy/4, ss);
	}
for(y=ymin+dy; y < ymax; y += dy)
	{
	drawLine(xmin, y, xmax, y);
	sprintf(ss,"%4.0f",y);
	drawText(xmin-dx/2, y, ss);
	}

settextjustify(0,0);

dx /= 10;
dy /= 10;
for(x=xmin; x < xmax; x += dx)
	drawLine(x, 0, x, dy);
for(y=ymin; y < ymax; y += dy)
	drawLine(0, y, dx, y);
setcolor(WHITE);
}
/*--------------------------------------------------------------*/

