#include <stdio.h>
#include <conio.h>
#include <string.h>
#include <time.h>


#include "parport.h"
#include "apuplay.h"

int ByteTransferCount=0;
int ParallelPortCount=0;

int bootcode=0;

#define SETUP_LOOPS 2

int port0;

//void InstallPortTalkDriver(void);
//unsigned char StartPortTalkDriver(void);

/*****************************************************************************

Parallel port - 8 data, 4 control, 5 status
data
	D0 - pin2 - MOSI
	D1 - pin3 - SCK
	D6 - pin8 - /CART (pad 49 of cartritge connector)
	D7 - pin9 - /RESET (of Atmel)

status
	S4 - pin13 - MISO
	S5 - pin12 - ready to receive (from atmel)

gnd
	pins 18-25
	connect to ground of board

*********************

SERIAL COMMUNICATION:

MOSI (PC -> Atmel)		Atmel - 1 input, and ParallelPort - 1 output
MISO (PC <- Atmel)		Atmel - 1 output, and ParallelPort - 1 input
SCK  (PC -> Atmel)		Atmel - 1 input, and ParallelPort - 1 output

MSB is sent/received first...

Atmel chip is expected to have the data ready by the time the
the clock goes high (so it should be sitting there, ready with its
first bit on the line before the computer initiates the transfer).
It should transition its data when the clock is low.

The computer is expected to have data on the line by the time it 
puts the clock high.
It should transition its data when the clock is low.

Clock up and clock down must not be less than 2 clock cycles.
(not a problem ... one bit set takes less 1 us ... 8 clock cycles).

Start up state... SCK is low.

The sequence 0x01, 0x02 ... 0x0F is sent and received to make sure the systems 
are synchronized.  This is needed because the Atmel chip may be running before the 
parallel port gets initialized.  This will prevent any false commands when the 
parallelport is being plugged in, etc.

************************************************************************/

/******************** D E F I N I T I O N S ****************************/

#define OUTPUT_PIN	0x01
#define SCK_PIN		0x02
#define CART_PIN	0x40
#define RESET_PIN	0x80

#define _RD_PIN		0x08
#define WR_PIN		0x04
#define _ADDR1		0x02
#define _ADDR0		0x01

#define INPUT_PIN	0x10
#define RDY_PIN		0x20

/******************** S T R U C T U R E S ******************************/


/******************** G L O B A L S ************************************/


int port0=0;
int ready_line=0;     //holds the last state of the "ready to receive line"

/******************** F U N C T I O N S ********************************/

void sleep(int msec)
{
	clock_t time;

	//wait for a number of msec.
	time = clock();
	while ( clock()-time < 0.001*msec*CLOCKS_PER_SEC) {}
} //end of sleep()

int xfer_byte(int send_data)
{
	int i;
	int byte=0,temp;
	int data_in=0;

	/*****************************************************************
	;xfer_byte - uses SPI, Serial Communication
	;Input: 
	;	data to send to Atmel chip
	;
	;Returns: 
	;	data received from Atmel chip
	;
	;Note:
	;Expects MSB first...
	;
	;Atmel chip is expected to have the data ready by the time the
	;the clock goes high (so it should be sitting there, ready with its
	;first bit on the line before the computer initiates the transfer).
	;It should transition its data when the clock is low.
	;
	;The computer is expected to have data on the line by the time it 
	;puts the clock high.
	;It should transition its data when the clock is low.
	;
	;*****************************************************************/

	for(i=0x80; i!=0x00; i=(i>>1) )
	{
		ParallelPortCount+=4;

		ClrPins(data_pins,SCK_PIN);  //put clock low

		if(send_data & i)
			SetPins(data_pins,OUTPUT_PIN);	//put MOSI (data out) high
		else
			ClrPins(data_pins,OUTPUT_PIN);  //put MOSI (data out) low

		_outp(DATA,data_pins);		//send data + Clock low

		SetPins(data_pins,SCK_PIN);	//put clock high

//		_outp(DATA,data_pins);		//send data + Clock high
		_outp(DATA,data_pins);		//send again (as a kind of pause)

		//get bit from Atmel chip...
		temp=_inp(STATUS);
		if(temp & INPUT_PIN)
			data_in += i;
		
		ClrPins(data_pins,SCK_PIN);	//put clock low
	//	_outp(DATA,data_pins);		//send data, clock low
	}
	_outp(DATA,data_pins);
	ByteTransferCount+=1;
	return data_in;
} //end of xfer_byte()

int xfer_byte_ready(int send_data)
{
	int data_in;
	clock_t time;

	/*****************************************************************
	;Input:
	; 	data to send to Atmel chip
	;
	;Returns: 
	;	data received from Atmel chip
	;
	;Note:
	;Sends data using xfer_byte() but waits for "ready to send" signal
	;from the Atmel chip first.
	;
	;Will not send/receive byte until the "ready to send" line from the 
	;Atmel chip is toggled.  First byte should not be sent until this
	;line is set high.
	;
	;*****************************************************************/

	//wait for Atmel to be ready ... time out after 250 ms
	time = clock();
	while( ready_line == (_inp(STATUS) & RDY_PIN) )
	{
		ParallelPortCount+=1;
		if(clock()-time > 1.250*CLOCKS_PER_SEC)
		{
//			printf("\nERROR: Atmel timed out.  ");
//			printf("No Ready-to-Receive signal was sent.\n");
			return -1;		
		}
	}
	
	ready_line = (_inp(STATUS) & RDY_PIN);

	data_in = xfer_byte(send_data);

	return data_in;
} //end of xfer_byte_ready()

void ResetChip(void)
{
	//reset the Atmel chip
//	ClrPins(data_pins, RESET_PIN + SCK_PIN + OUTPUT_PIN);
//	_outp(DATA, data_pins);

	ClrPins(data_pins, SCK_PIN + OUTPUT_PIN);
	_outp(DATA, data_pins);
	_outp(DATA, data_pins);
	ClrPins(data_pins, RESET_PIN);
	_outp(DATA, data_pins);


	//wait about 50 msec.
	sleep(250);

	//turn Atmel on
	SetPins(data_pins,RESET_PIN);	//put #RESET high
	_outp(DATA, data_pins);


	//wait about 50 msec for it to setup..
	sleep(250);
} //end of ResetChip()


int _stdcall InitSerialSend(void)
{
	int i, data_in;

	//reset the Atmel chip
	ResetChip();

	//initialize the serial send
	ready_line=0;
	for(i=0x01;i<=0x0F;i++)
	{
		data_in=xfer_byte_ready(i);
		if(i!=data_in)
		{
//			printf("\nERROR: Serial initialization failed.  ");
//			printf("Sent: 0x%.2X    Received: 0x%.2X\n", i, data_in);
/*
			if (data_in==0xFF)
			{
//				printf("\nIs the Device Connected to the parallel port?");
//				printf("\nIs the Device connected to power?");
//				printf("\nIs the Power turned on?");
			}

			if (data_in==0x00)
			{
				printf("\nIs MOSI/MISO/SCK shorted to ground?");
			}

*/
			return 0;
		}
	}

	return -1;
} //end of InitSerialSend()

int _stdcall WriteSPC700 (int address, int data)
{
	int dummy=0, i;
/*
	SetPins(data_pins, RESET_PIN);
	ClrPins(data_pins, SCK_PIN);

	address = (address << 2) + 0x02;
	xfer_byte_ready ( address );
	xfer_byte_ready ( data ); 
*/

	ClrPins(control_pins, INPUT_MODE);
		_outp(CONTROL, control_pins);

	SetPins(control_pins, _ADDR0 + _ADDR1);
	ClrPins(control_pins, address);
	for (i=0; i<SETUP_LOOPS; i++)
		_outp(CONTROL, control_pins);
	
	ClrPins(control_pins, WR_PIN);
	ClrPins(control_pins, _RD_PIN);

	_outp(DATA, data);
	
for (i=0; i<SETUP_LOOPS; i++)	
	_outp(CONTROL, control_pins);
		

	SetPins(control_pins, WR_PIN);
	for (i=0; i<SETUP_LOOPS; i++)	
	_outp(CONTROL, control_pins);


	return dummy;
}

int _stdcall ReadSPC700 (int address)
{
	/*
	SetPins(data_pins, RESET_PIN);
	ClrPins(data_pins, SCK_PIN);

	address = (address << 2) + 0x02;
	if (xfer_byte_ready ( address + 0x80 )==-1)
	{
		TogglePins(ready_line,RDY_PIN);
		if (xfer_byte_ready ( address + 0x80 )==-1)
		{
			return -1;
		}
	}
	return xfer_byte_ready ( 0 ); 
/*/
	int data, i;
	if (!(control_pins & INPUT_MODE))
	{ 
		SetPins(control_pins, _ADDR0 + _ADDR1 + INPUT_MODE);
	}
	else
	{
		SetPins(control_pins, _ADDR0 + _ADDR1);
	} 
	SetPins(control_pins, WR_PIN);
	ClrPins(control_pins, address);
	SetPins(control_pins, _RD_PIN);
	_outp(CONTROL, control_pins);

	for (i=0; i<SETUP_LOOPS; i++)
		data=_inp(DATA);
	

	ClrPins(control_pins, _RD_PIN);
	
	for (i=0; i<SETUP_LOOPS; i++)
		_outp(CONTROL, control_pins);
	
	return data;

}

void  WriteSPC700_16 (int address, int data0, int data1)
{
	/*
	address=(address<<2)+0x02;

	xfer_byte_ready ( address + 0x40 );
	xfer_byte_ready ( data0 );
	xfer_byte_ready ( data1 ); 
	/*/
	WriteSPC700(address, data1);
	WriteSPC700(address, data0);

}

int _stdcall WriteSPC700_WP0I (int address, int data)
{
	/*
	address=(address<<2)+0x02;
	xfer_byte_ready ( address + 0x20 );
	return xfer_byte_ready ( data ); 

	/*/
	int i;
	i = 0;
	WriteSPC700(address, data);
	WriteSPC700(0,port0);
	while (ReadSPC700(0)!=port0)
	{
		i++;
		if (i > 1024)
			return 1;
	}
	port0++;
	if (port0 == 256)
		port0 = 0;

	return 0;
	

}

int WrSPC700_WP0I (int address, int data)
{
	address=(address<<2)+0x02;
	xfer_byte_ready ( address + 0x20 );
	return xfer_byte_ready ( data );

}

int _stdcall SetPort0 (short data)
{
	
//	xfer_byte_ready ( 0x10 );
//	return xfer_byte_ready ( data );
	
	port0=data;
	return 0;
}

void InitTrans (void)
{
	while (ReadSPC700(0x01) != 0xBB);
	WriteSPC700(0x03,0x00);
	WriteSPC700(0x02,0x02);
//	WriteSPC700_16(0x02,0x02,0x00);
	WriteSPC700(0x01,0x01);
	WriteSPC700(0x00,0xCC);
//	WriteSPC700_16(0x00,0xCC,0x01);
	while (ReadSPC700(0x00) != 0xCC);
}

int _stdcall Write16bytes (char byte1, char byte2, char byte3, char byte4, char byte5, char byte6, char byte7, char byte8, char byte9, char byte10, char byte11, char byte12, char byte13, char byte14, char byte15, char byte16)
{
	/*
	int address=1;
	int xfer_error;
	address=(address<<2)+0x02;
	xfer_error = xfer_byte_ready ( address + 0x01 );
	if (xfer_error == -1)
		return xfer_error;
	xfer_byte_ready ( byte1 );
	xfer_byte_ready ( byte2 );
	xfer_byte_ready ( byte3 );
	xfer_byte_ready ( byte4 );
	xfer_byte_ready ( byte5 );
	xfer_byte_ready ( byte6 );
	xfer_byte_ready ( byte7 );
	xfer_byte_ready ( byte8 );
	xfer_byte_ready ( byte9 );
	xfer_byte_ready ( byte10 );
	xfer_byte_ready ( byte11 );
	xfer_byte_ready ( byte12 );
	xfer_byte_ready ( byte13 );
	xfer_byte_ready ( byte14 );
	xfer_byte_ready ( byte15 );
	return xfer_byte_ready ( byte16 ); 

	/*/

	int i;
	i = 0;
	i+=WriteSPC700_WP0I (1, byte1);
	i+=WriteSPC700_WP0I (1, byte2);
	i+=WriteSPC700_WP0I (1, byte3);
	i+=WriteSPC700_WP0I (1, byte4);

	if (i > 0)
		return i;
	
	i+=WriteSPC700_WP0I (1, byte5);
	i+=WriteSPC700_WP0I (1, byte6);
	i+=WriteSPC700_WP0I (1, byte7);
	i+=WriteSPC700_WP0I (1, byte8);

	if (i > 0)
		return i;
	
	i+=WriteSPC700_WP0I (1, byte9);
	i+=WriteSPC700_WP0I (1, byte10);
	i+=WriteSPC700_WP0I (1, byte11);
	i+=WriteSPC700_WP0I (1, byte12);

	if (i > 0)
		return i;
	
	i+=WriteSPC700_WP0I (1, byte13);
	i+=WriteSPC700_WP0I (1, byte14);
	i+=WriteSPC700_WP0I (1, byte15);
	i+=WriteSPC700_WP0I (1, byte16);
	

	
	return i; 
}

int _stdcall ResetAPU(void)	//Reset the APU by whatever means it needs reset.
{
	
	ClrPins(control_pins,WR_PIN);		//Once the OR gate is in place
	SetPins(control_pins,_RD_PIN);		//Pulling both /RD and /WR low
		_outp(CONTROL, control_pins);	//Will Reset the APU, since
	sleep(50);							// /RESET will be tied to the
	SetPins(control_pins,WR_PIN);		//output of the OR gate.
	ClrPins(control_pins,_RD_PIN);
		_outp(CONTROL, control_pins);
	sleep(50);
	return 0;
	return InitSerialSend();
}


int _stdcall GetID6xTag(char ID666tag[], char XID6tag[], short tagID)
{
	
	return ID666tag[0] + ID666tag[1] + ID666tag[2] + ID666tag[3];
}