//////////////////////////////////////////////////////////////////////////////
// psxpad.cpp                                                               //
//////////////////////////////////////////////////////////////////////////////
/*
wiring info:

 =========================
 | o o o | o o o | o o o |  PSX controller plug when looking at pins
  `---------------------'
   1 2 3   4 5 6   7 8 9

  Controller       Parallel port
   1 - Data         [10],11,12,13,15
   2 - Command      2
   3 - +7.6V        Dual-shock power: +7.6V external
   4 - Ground       Signal/power ground: pin 18-25
   5 - +3.6V        Power supply: pin 5-9 via diodes or external
   6 - Select       3
   7 - Clock        4
   9 - Ack          10,11,[12],13,15 - NOT USED HERE -
*/

//////////////////////////////////////////////////////////////////////////////
// includes                                                                 //
//////////////////////////////////////////////////////////////////////////////
#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include <math.h>

//////////////////////////////////////////////////////////////////////////////
// defines                                                                  //
//////////////////////////////////////////////////////////////////////////////
#define PORT	0x378  // parallel base port
#define POWER	0xF8   // power
#define SEL		0x00
#define CMD		0x01   // command
#define DSEL	0x02   // ~select / deselect
#define CLK		0x04   // clock
#define INP		(_inp(PORT+1)>>6&1)  // data input

//////////////////////////////////////////////////////////////////////////////
// variables                                                                //
//////////////////////////////////////////////////////////////////////////////
double m_small = 0;		// small motor
bool m_big = false;		// big motor
int jx1,jy1,jx2,jy2;
int b1=0xFF, b2=0xFF;

//////////////////////////////////////////////////////////////////////////////
// Delay                                                                    //
//////////////////////////////////////////////////////////////////////////////
void Delay(long n)
{
	for (volatile long delay=0; delay<200*n; delay++) {};
}

//////////////////////////////////////////////////////////////////////////////
// Transfer                                                                 //
//////////////////////////////////////////////////////////////////////////////
unsigned char Transfer(unsigned char out)
{
	#define output (out>>bit&1)
	unsigned char in = 0;
	for (int bit=0; bit<8; bit++)
	{
		Delay(1);
		_outp(PORT, POWER | output | CLK);
		_outp(PORT, POWER | output);
		Delay(1);
		_outp(PORT, POWER | output | CLK);
		in |= (INP << bit);
	}
	Delay(1);	// ?
	return in;
}

//////////////////////////////////////////////////////////////////////////////
// Begin                                                                    //
//////////////////////////////////////////////////////////////////////////////
void Begin(n)
{
	_outp(PORT, POWER+SEL); Delay(5);
	Transfer(0x01);
	Transfer(n);
	Transfer(0x00);
}

//////////////////////////////////////////////////////////////////////////////
// End                                                                      //
//////////////////////////////////////////////////////////////////////////////
#define End()
{
	_outp(PORT, POWER+DSEL); Delay(5);
}

//////////////////////////////////////////////////////////////////////////////
// Test                                                                     //
//////////////////////////////////////////////////////////////////////////////
void Test()
{
	Begin(0x43);
	Transfer(0x01);
	Transfer(0x00);
	End();

	Begin(0x4D);
	Transfer(0x01);
	Transfer(0x00);
	Transfer(0xFF);
	Transfer(0xFF);
	Transfer(0xFF);
	Transfer(0xFF);
	End();

	/*Begin(0x42+1);
	Transfer(0x00);
	Transfer(0x00);
	Transfer(0x00);
	Transfer(0x00);
	Transfer(0x00);
	Transfer(0x00);
	End();*/

	Begin(0x42);
	b1 = Transfer((int)m_small);
	b2 = Transfer(m_big ? 0xFF : 0x00);
	jx2 = Transfer(0) - 128;
	jy2 = Transfer(0) - 128;
	jx1 = Transfer(0) - 128;
	jy1 = Transfer(0) - 128;
	End();
}

//////////////////////////////////////////////////////////////////////////////
// Clip                                                                     //
//////////////////////////////////////////////////////////////////////////////
int Clip(int n)
{
	if (n < 0) n = 0;
	if (n > 255) n = 255;
	return n;
}

//////////////////////////////////////////////////////////////////////////////
// main                                                                     //
//////////////////////////////////////////////////////////////////////////////
int main()
{
	// open & close giveio device for direct port access
	if ((_winmajor < 4) || (_winmajor > 9)) return 0;
	HANDLE h = CreateFile("\\\\.\\giveio", 0, 0, NULL, OPEN_ALWAYS, 0, NULL);
	if (h == INVALID_HANDLE_VALUE) return -1;
	CloseHandle(h);

	double a = 0.0;

	while (1)
	{
		Test();
		printf("\r%02X %02X (%d,%d) (%d,%d)", b1,b2, jx1,jy1, jx2,jy2);

		if (kbhit())
		{
			char key = getch();
			if (key == 27) break;
			
			if (key == ' ') m_big = !m_big;
			if (key == 'H') if (m_small < 255) m_small++;
			if (key == 'P') if (m_small > 0) m_small--;
		}

		static bool bla = false;
		if (~b1 & 4) bla = true;
		if (bla) m_small = 255; else m_small = Clip(jy2*2);

		Sleep(1);
	}
	printf("\n");

	_outp(PORT, DSEL); // power off + deselect

	return 0;
}
