/*****************************************************************************
* Program to "tweak" the ZVG vector board.
* 
* Used to adjust the internal ZVG registers that are used to time
* vector draws.
*
* Currently this program is very ugly in its use of the DOS screen, simply
* using "printf()" statements.  However it does show how to communicate
* with the ZVG using the 1284 commands available in ZVGPORT.C, and having
* this information available seems more important than a pretty screen.
*
* Version:      0.7
* Author:       Zonn Moore
* Created:      11/06/02
*
* History:
*    07/30/03
*       Move the generation of the logo to ZVGTWEAK.C.  Removed MAKELOGO.C.
*
* (c) Copyright 2002-2003, Zektor, LLC.  All Rights Reserved.
*****************************************************************************/
#include	<stdio.h>
#include	<stdlib.h>
#include	<string.h>
#include	<conio.h>
#include	<dos.h>
#include	<bios.h>
#include	<time.h>
#include	<go32.h>
#include	<sys\farptr.h>
#include	<sys\movedata.h>
#include	<sys\segments.h>

#include	"zvgframe.h"
#include	"zvgCmds.h"

ZvgID_s		ZvgID;
ZvgSpeeds_a	ZvgSpeeds;
ZvgMon_s		ZvgMon;

// Starting with a print out of the file 64x48.txt I drew the ZEKTOR logo
// centered on the paper.  Then numbered each vector.
//
// This array is each of those numbered vectors written as: xStart,yStart,xEnd,yEnd

int zektorLogo[] =
{
	// xStart, yStart, xEnd, yEnd

	// Z

	-17,  3, -17,  5,			// 1	
	-17,  5, -13,  5,			// 2	
	-13,  5, -17, -5,			// 3	
	-17, -5, -13, -5,			// 4	
	-13, -5, -13, -3,			// 5	

	// E

	 -7,  3,  -7,  5,			// 6	
	 -7,  5, -11,  5,			// 7	
	-11,  5,  -8,  0,			// 8	
	 -8,  0, -11, -5,			// 9	
	-11, -5,  -7, -5,			// 10
	 -7, -5,  -7, -3,			// 11

	// K

	 -5, -5,  -5,  5,			// 12
	 -1,  5,  -5,  0,			// 13
	 -5,  0,  -1, -5,			// 14

	// T

	  3, -5,   3,  5,			// 15
	  1,  3,   1,  5,			// 16
	  1,  5,   5,  5,			// 17
	  5,  5,   5,  3,			// 18

	// O

	  9, -5,   7,  0,			// 19
	  7,  0,   9,  5,			// 20
	  9,  5,  11,  0,			// 21
	 11,  0,   9, -5,			// 22

	// R

	 13, -5,  13,  5,			// 23
	 13,  5,  17,  3,			// 24
	 17,  3,  13,  0,			// 25
	 13,  0,  17, -5			// 26
};

// This was an after thought, and followed the ZEKTOR logo on the same peice of paper.

int dotComLogo[] =
{
	// .

	19, -5, 19, -5,

	// C

	24, -3, 22, -5,
	22, -5, 20,  0,
	20,  0, 22,  5,
	22,  5, 24,  3,

	// O

	28, -5, 26,  0,
	26,  0, 28,  5,
	28,  5, 30,  0,
	30,  0, 28, -5,

	// M

	32, -5, 32,  3,
	32,  3, 33,  5,
	33,  5, 34,  3,
	34,  3, 35,  5,
	35,  5, 36,  3,
	36,  3, 36, -5,
	34, -5, 34,  3
};

// Setup file pointer for reading ZVG command file.

/*****************************************************************************
* If something goes wrong just call this routine to return to DOS
*****************************************************************************/
void exitProg( void)
{
	zvgFrameClose();							// turn off DMA and free DMA buffers
	exit( 0);
}

/*****************************************************************************
* Print current monitor information.
*****************************************************************************/
void pMonitor( void)
{
	putchar( '\n');
	printf( "\nZ-Shift:             %3u", ZvgMon.zShift);
	printf( "\nOvershoot:           %3u", ZvgMon.oShoot);
	printf( "\nJumpFactor:          %3u", ZvgMon.jumpFactor);
	printf( "\nPoint Intensity:     %3u", ZvgMon.point_i);
	printf( "\nMin Color Intensity: %3u", ZvgMon.min_i);
	printf( "\nMax Color Intensity: %3u", ZvgMon.max_i);
	printf( "\nScale:               %3u", ZvgMon.scale);
	printf( "\nSettling:            %3u", ZvgMon.settle);
	putchar( '\n');
}

int drawDisplay( void)
{
	uint	ii, xStart, yStart, xEnd, yEnd;

	zvgFrameSetRGB15( 31, 31, 31);

	// Draw a full size box, if setup properly, this will be drawn off the edges
	// of the screen.

	zvgFrameVector( X_MIN_O, Y_MAX_O, X_MAX_O, Y_MAX_O);
	zvgFrameVector( X_MAX_O, Y_MAX_O, X_MAX_O, Y_MIN_O);
	zvgFrameVector( X_MAX_O, Y_MIN_O, X_MIN_O, Y_MIN_O);
	zvgFrameVector( X_MIN_O, Y_MIN_O, X_MIN_O, Y_MAX_O);

	// Draw a box at the edges of the visible screen

	zvgFrameVector( X_MIN, Y_MAX, X_MAX, Y_MAX);
	zvgFrameVector( X_MAX, Y_MAX, X_MAX, Y_MIN);
	zvgFrameVector( X_MAX, Y_MIN, X_MIN, Y_MIN);
	zvgFrameVector( X_MIN, Y_MIN, X_MIN, Y_MAX);

	// place a "normal" size ZEKTOR logo in middle of screen

	for (ii = 0; ii < sizeof( zektorLogo) / sizeof( *zektorLogo); ii += 4)
	{
		// place logo in center of screen, 16x larger than it was drawn.

		xStart =	zektorLogo[ii] * 16;
		yStart =	zektorLogo[ii+1] * 16;
		xEnd = zektorLogo[ii+2] * 16;
		yEnd = zektorLogo[ii+3] * 16;

		// print vector

//		printf( "\nXStart=%5d, YStart=%5d, XEnd=%5d, YEnd=%5d", xStart, yStart, xEnd, yEnd);

		// encode vector into command buffer

		zvgFrameVector( xStart, yStart, xEnd, yEnd);
	}

	// place a smaller logo in the lower right corner followed by a .COM

	for (ii = 0; ii < sizeof( zektorLogo) / sizeof( *zektorLogo); ii += 4)
	{
		// draw logo on screen 6x size, and down 300 points and to the right 156 points

		xStart =	zektorLogo[ii] * 6 + 156;
		yStart =	zektorLogo[ii+1] * 6 - 300;
		xEnd = zektorLogo[ii+2] * 6 + 156;
		yEnd = zektorLogo[ii+3] * 6 - 300;

//		printf( "\nXStart=%5d, YStart=%5d, XEnd=%5d, YEnd=%5d", xStart, yStart, xEnd, yEnd);

		// encode vector into command buffer

		zvgFrameVector( xStart, yStart, xEnd, yEnd);
	}

	// Add ".com" to above logo

	for (ii = 0; ii < sizeof( dotComLogo) / sizeof( *dotComLogo); ii += 4)
	{
		// draw .com on screen 6x size, and down 300 points and to the right 156 points

		xStart =	dotComLogo[ii] * 6 + 156;
		yStart =	dotComLogo[ii+1] * 6 - 300;
		xEnd = dotComLogo[ii+2] * 6 + 156;
		yEnd = dotComLogo[ii+3] * 6 - 300;

//		printf( "\nXStart=%5d, YStart=%5d, XEnd=%5d, YEnd=%5d", xStart, yStart, xEnd, yEnd);

		// encode vector into command buffer

		zvgFrameVector( xStart, yStart, xEnd, yEnd);
	}

	// Draw a small logo in the upper left corner

	for (ii = 0; ii < sizeof( zektorLogo) / sizeof( *zektorLogo); ii += 4)
	{
		// draw on screen 2x size, and up 195 points and to the left 290 points

		xStart =	zektorLogo[ii] * 2 - 290;
		yStart =	zektorLogo[ii+1] * 2 + 195;
		xEnd = zektorLogo[ii+2] * 2 - 290;
		yEnd = zektorLogo[ii+3] * 2 + 195;

//		printf( "\nXStart=%5d, YStart=%5d, XEnd=%5d, YEnd=%5d", xStart, yStart, xEnd, yEnd);

		// encode vector into command buffer

		zvgFrameVector( xStart, yStart, xEnd, yEnd);
	}

	// Place real big logo on top of everything.  This logo should go off the edges
	// of a properly sized screen.

	for (ii = 0; ii < sizeof( zektorLogo) / sizeof( *zektorLogo); ii += 4)
	{
		// place logo in center of screen, 32x larger than it was drawn.

		xStart =	zektorLogo[ii] * 32;
		yStart =	zektorLogo[ii+1] * 32;
		xEnd = zektorLogo[ii+2] * 32;
		yEnd = zektorLogo[ii+3] * 32;

//		printf( "\nXStart=%5d, YStart=%5d, XEnd=%5d, YEnd=%5d", xStart, yStart, xEnd, yEnd);

		// encode vector into command buffer

		zvgFrameVector( xStart, yStart, xEnd, yEnd);
	}
	return (errOk);
}

int main( int argc, char *argv[])
{
	uint	err;
	char	cc;

	fputs( "\nZVGTWEAK - Fine tune the ZVG vector generator. Version 0.5", stdout);
	fputs( "\n(c) Copyright 2002, Zektor, LLC.  All rights reserved.\n", stdout);

	if (argc < 2)
	{	fputs( "\nUse: ZVGTWEAK frameFile port\n", stdout);
		fputs( "\nWhere:", stdout);
		fputs( "\n   frameFile = Filename of ZVG frame file.", stdout);
		exit( 0);
	}

	err = errOk;

	// Setup the ZVG subsytem, this routine initializes the timers and calibrates any timing
	// needed by the the zvgPort routines.

	err = zvgFrameOpen();

	if (err)
	{	zvgError( err);
		exitProg();
	}

	// Display banner

	zvgBanner( ZvgSpeeds, &ZvgID);

	pMonitor();

	if ((err = zvgReadSpeedInfo( ZvgSpeeds)) != errOk)
	{	zvgError( err);
		exitProg();
	}

	// Print the current value of the speed tables used by the ZVG

	printf( "\nSpeed tables: %uus, %uus, %uus, %uus\n", ZvgSpeeds[0], ZvgSpeeds[1], ZvgSpeeds[2], ZvgSpeeds[3]);

	// Dump frame over and over to the ZVG while looking for key presses

	tmrSetFrameRate( 60);			// set frame rate to 60 frames per second

	err = errOk;

	while (err == errOk)
	{
		drawDisplay();

		if (kbhit())
		{
			// read key

			cc = getch();

			// I have arbitrarily picked a bunch of keys to adjust ZVG parameters.
			// This will be replaced with an on screen display, allowing the
			// user to tab to the desired value and use the up/down (left/right?)
			// arrows to adjust these parameters. -Zonn

			switch (cc)
			{
				// Lower the min monitor intensity

			case ';':
				if (ZvgMon.min_i > 0)
				{	ZvgMon.min_i--;
					zvgDmaPutc( zcMIN_I);
					zvgDmaPutc( ZvgMon.min_i);
					printf( "\nMin Intensity=%u", ZvgMon.min_i);
				}
				break;  

				// Raise the min monitor intensity

			case '\'':
				if (ZvgMon.min_i != 255)
				{	ZvgMon.min_i++;
					zvgDmaPutc( zcMIN_I);
					zvgDmaPutc( ZvgMon.min_i);
					printf( "\nMin Intensity=%u", ZvgMon.min_i);
				}
				break;  

				// Lower the max monitor intensity

			case ':':
				if (ZvgMon.max_i > 0)
				{	ZvgMon.max_i--;
					zvgDmaPutc( zcMAX_I);
					zvgDmaPutc( ZvgMon.max_i);
					printf( "\nMax Intensity=%u", ZvgMon.max_i);
				}
				break;  

				// Raise the max monitor intensity

			case '"':
				if (ZvgMon.max_i != 255)
				{	ZvgMon.max_i++;
					zvgDmaPutc( zcMAX_I);
					zvgDmaPutc( ZvgMon.max_i);
					printf( "\nMax Intensity=%u", ZvgMon.max_i);
				}
				break;  

				// Move the Z-shift towards the start of vector
				// This has the effect of brightening the starting point
				// of a vector, and at the same time dimming the ending point

			case '[':
													
				if (ZvgMon.zShift > 0)
				{	ZvgMon.zShift--;
					zvgDmaPutc( zcZSHIFT);
					zvgDmaPutc( ZvgMon.zShift);
					printf( "\nZ-Shift=%u", ZvgMon.zShift);
				}
				break;  

				// Move the Z-shift away from the start of vector

			case ']':
				if (ZvgMon.zShift != 255)
				{	ZvgMon.zShift++;
					zvgDmaPutc( zcZSHIFT);
					zvgDmaPutc( ZvgMon.zShift);
					printf( "\nZ-Shift=%u", ZvgMon.zShift);
				}
				break;

				// Remove length from the Z-overshoot.  This effectively dims the
				// ending point of the vector, and has no effect on the starting
				// point.
  
			case '{':
				if (ZvgMon.oShoot > 0)
				{	ZvgMon.oShoot--;
					zvgDmaPutc( zcOSHOOT);
					zvgDmaPutc( ZvgMon.oShoot);
					printf( "\nOvershoot=%u", ZvgMon.oShoot);
				}
				break;  

				// Add length to the Z-overshoot.  This effectively brightens the
				// ending point of the vector, and has no effect on the starting
				// point.
  
			case '}':
				if (ZvgMon.oShoot != 255)
				{	ZvgMon.oShoot++;
					zvgDmaPutc( zcOSHOOT);
					zvgDmaPutc( ZvgMon.oShoot);
					printf( "\nOvershoot=%u", ZvgMon.oShoot);
				}
				break;

				// Lower the jump factor.  When a new vector is jumped to (its
				// starting point is not shared with the ending point of the previous
				// vector), this value is multiplied with the distance of the
				// jump to determine how long to wait for the trace to make it to
				// the new destination. Lower values of the jump factor will increase
				// the Frames per Second rate, but eventually the monitor will not
				// be able to keep up

			case '_':
				if (ZvgMon.jumpFactor > 0)
				{	ZvgMon.jumpFactor--;
					zvgDmaPutc( zcJUMP);
					zvgDmaPutc( ZvgMon.jumpFactor);
					printf( "\nJumpFactor=%u", ZvgMon.jumpFactor);
				}
				break;  

				// Raise the jump factor.

			case '+':
				if (ZvgMon.jumpFactor != 255)
				{	ZvgMon.jumpFactor++;
					zvgDmaPutc( zcJUMP);
					zvgDmaPutc( ZvgMon.jumpFactor);
					printf( "\nJumpFactor=%u", ZvgMon.jumpFactor);
				}
				break;

				// Lower the amount of time the ZVG waits while a POINT is being
				// drawn.  The longer the trace is left in one spot, the brighter
				// the point will appear.

			case ',':
				if (ZvgMon.point_i > 0)
				{	ZvgMon.point_i--;
					zvgDmaPutc( zcPOINT_I);
					zvgDmaPutc( ZvgMon.point_i);
					printf( "\nPoint Intensity=%u", ZvgMon.point_i);
				}
				break;  

				// Raise the amount of time the ZVG waitw while a POINT is being
				// drawn.

			case '.':
				if (ZvgMon.point_i != 255)
				{	ZvgMon.point_i++;
					zvgDmaPutc( zcPOINT_I);
					zvgDmaPutc( ZvgMon.point_i);
					printf( "\nPoint Intensity=%u", ZvgMon.point_i);
				}
				break;

				// Lower the minimum settling time.  After the Jump factor time
				// is calculated, it is checked against this value for a minimum
				// settling time. Changes in the firmware have pretty much obsoleted
				// this command, and it should probably just be left at one.
				// (Internally the ZVG treats a 0 as a 1)

			case '<':
				if (ZvgMon.settle > 1)
				{	ZvgMon.settle--;
					zvgDmaPutc( zcSETTLE);
					zvgDmaPutc( ZvgMon.settle);
					printf( "\nSettling=%u", ZvgMon.settle);
				}
				break;  

				// Raise the minimum settling time.

			case '>':
				if (ZvgMon.settle != 255)
				{	ZvgMon.settle++;
					zvgDmaPutc( zcSETTLE);
					zvgDmaPutc( ZvgMon.settle);
					printf( "\nSettling=%u", ZvgMon.settle);
				}
				break;

				// This decreases the screen size. This is done in hardware on the
				// ZVG and no resolution is lost by changing the screen size.

				// This Vectrex monitor is so sensitive, the only way to write to
				// it is to lower this value, along with removing the 2x jumpers
				// on the ZVG.

			case '-':
				if (ZvgMon.scale > 0)
				{	ZvgMon.scale--;
					zvgDmaPutc( zcSCALE);
					zvgDmaPutc( ZvgMon.scale);
					printf( "\nScale=%u", ZvgMon.scale);
				}
				break;  

				// This increases the screen size.

			case '=':
				if (ZvgMon.scale != 255)
				{	ZvgMon.scale++;
					zvgDmaPutc( zcSCALE);
					zvgDmaPutc( ZvgMon.scale);
					printf( "\nScale=%u", ZvgMon.scale);
				}
				break;

				// Save the current value in the ZVG, to the ZVG's EEPROM.
				// This allow the parameters to survive a power failure.
				// FYI: There are separate EEPROM locations for each table
				// speed.

			case 'S':
				zvgDmaPutc( zcSAVE_EE);
				fputs( "\nCurrent values saved to EEPROM.", stdout);
				break;

				// Reload the values from the EEPROM, incase you've screwed
				// something up and want to get back to where you were.

			case 'L':
				zvgDmaPutc( zcLOAD_EE);
				fputs( "\nMonitor values re-loaded from EEPROM.", stdout);
				zvgReadMonitorInfo( &ZvgMon);
				pMonitor();
				break;

				// Reset the values to the factor default, incase you've *really*
				// screwed something up!  If the values save in EEPROM are
				// screwed up you will have to save these values back to EEPROM
				// if you don't want them reappearing.

			case 'R':
				zvgDmaPutc( zcRESET_MON);
				fputs( "\nMonitor values reset to factory defaults.", stdout);
				zvgReadMonitorInfo( &ZvgMon);
				pMonitor();
				break;

				// just dump the parameters ZVGTWEAK is using.

			case 'v':
			case 'V':
				pMonitor();
				break;

				// re-read the information from the ZVG, if for some reason we've
				// got out of sync.

			case 'q':
			case 'Q':
				zvgReadMonitorInfo( &ZvgMon);
				pMonitor();
				break;	
			}

			fflush( stdout);					// send any text needing sending

			if (cc == 0x1B)
				break;							// if ESC pressed, leave loop
		}

		// wait for start of next frame

		tmrWaitFrame();

		err = zvgFrameSend();				// send frame of DMA and swap buffers
	}

	if (err)
		zvgError( err);

	// restore ZVG stuff

	zvgFrameClose();
	exitProg();
	return (0);
}
