//
// Project UnReality: The First Nintendo 64 Emulator
// Copyright (C) 1997-1998, Cold Fusion Entertainment
// All rights reserved
//
// This source code is unpublished propietary information of Cold Fusion Entertainment.  No portion of this software
// may be disclosed to any third party or copied or duplicated in any form, in whole or in part, without the prior
// written consent of Cold Fusion Entertainment.
// 

//
// $Log: JOY.CPP $
// Revision 1.2  1998/04/02 21:18:19  BREAKPOINT
// Implemented new memory mapping routines and changed ROM loading code.
// Revision 1.1  1998/03/08 19:09:09  unknown
// Initial revision
//

static char *rcsid = "$Id: JOY.CPP 1.2 1998/04/02 21:18:19 BREAKPOINT Exp $";

//---------------------------------------------------------------------------------------------------------------------

#include <stdio.h>
#include <string.h>
#include <types.h>
#include "mmio.h"
#include "joy.h"
#include "emu.h"
#include "unreal.h"
#include "input.h"

uchar pifram[64];				// The current PIF RAM block we will send back to the user program.
uchar last_pifram[64];			// The last command block we received from the user program.

void InitPIFRam(void)
{
	memset(pifram, 0, 64);
}

void TransferPIFRam(void)
{
	uchar *ptr;

	// Get pointer to PIF RAM area.
	ptr = (uchar *)FindMemoryPtr(PIF_RAM_BASE_REG);

	// Send it up.  Note, we *DO* have to dword swap the data!
	dswap(ptr, pifram, 16);
}

void GetControllerStatus(int cont)
{
	char buf[128];
	uchar *ptr;
	ContStatusBlock cs;

	sprintf(buf, "%%%%%% Retrieving controller %d status", cont);
	Log(TYPE_WRITE, buf, 0);

	ptr = pifram + (cont * sizeof(ContStatusBlock));
	memset(&cs, 0, sizeof(ContStatusBlock));

	if (cfg.Cont[cont].Controller_Active)
	{
		cs.errno    = 0x00;
		cs.type_msb = 0x00;
		cs.type_lsb = 0x01;
		cs.status   = 0x00;
	}
	else
	{
		cs.errno    = 0x80;
		cs.type_msb = 0x00;
		cs.type_lsb = 0x00;
		cs.status   = 0x00;
	}

	memcpy(ptr, &cs, sizeof(ContStatusBlock));
}

void GetControllerPosition(int cont)
{
	char buf[128];
	uchar *ptr;
	ContDataBlock cd;

	sprintf(buf, "%%%%%% Retrieving controller %d position", cont);
	Log(TYPE_WRITE, buf, 0);

	ptr = pifram + (cont * sizeof(ContDataBlock));
	memset(&cd, 0, sizeof(ContDataBlock));

	if (cfg.Cont[cont].Controller_Active)
	{
		cd.errno      = 0x00;
		cd.button_msb = 0x00;
		cd.button_lsb = 0x00;

		PollDeviceData(cont);
		if (DeviceButtonPressed(BUTTON_A))          cd.button_msb |= CONT_A;
		if (DeviceButtonPressed(BUTTON_B))          cd.button_msb |= CONT_B;
		if (DeviceButtonPressed(BUTTON_Z))          cd.button_msb |= CONT_Z;
		if (DeviceButtonPressed(BUTTON_L))          cd.button_lsb |= CONT_L;
		if (DeviceButtonPressed(BUTTON_R))          cd.button_lsb |= CONT_R;
		if (DeviceButtonPressed(BUTTON_START))      cd.button_msb |= CONT_START;
		if (DeviceButtonPressed(BUTTON_C_UP))       cd.button_lsb |= CONT_C_UP;
		if (DeviceButtonPressed(BUTTON_C_LEFT))     cd.button_lsb |= CONT_C_LEFT;
		if (DeviceButtonPressed(BUTTON_C_RIGHT))    cd.button_lsb |= CONT_C_RIGHT;
		if (DeviceButtonPressed(BUTTON_C_DOWN))     cd.button_lsb |= CONT_C_DOWN;
		if (DeviceButtonPressed(BUTTON_DPAD_UP))    cd.button_msb |= CONT_DPAD_UP;
		if (DeviceButtonPressed(BUTTON_DPAD_LEFT))  cd.button_msb |= CONT_DPAD_LEFT;
		if (DeviceButtonPressed(BUTTON_DPAD_RIGHT)) cd.button_msb |= CONT_DPAD_RIGHT;
		if (DeviceButtonPressed(BUTTON_DPAD_DOWN))  cd.button_msb |= CONT_DPAD_DOWN;

		DevicePosition(&cd.stick_x, &cd.stick_y);
	}
	else
	{
		cd.errno      = 0x80;
		cd.button_msb = 0x00;
		cd.button_lsb = 0x00;
		cd.stick_x    = 0;
		cd.stick_y    = 0;
	}

	memcpy(ptr, &cd, sizeof(ContDataBlock));
}

void ProcessJoypadBlock(LPVOID ptr)
{
	ulong *sptr = (ulong *)ptr;
	int curr_cont;
	bool done;

	// If given a command block, save it and exit immediately.  We'll generate an interrupt and then the user program
	// will read from PIF RAM which will call this function again with a NULL parameter.  We can process then.
	if (ptr != NULL)
	{
		memcpy(last_pifram, ptr, 64);
		return;
	}
	else
	{
		sptr = (ulong *)last_pifram;
	}

	InitPIFRam();
	curr_cont = 0;

	done = FALSE;
	while (!done)
	{
		if ((*sptr == 0xFF010300) && (*(sptr + 1) == 0xFFFFFFFF))
			GetControllerStatus(curr_cont);

		if ((*sptr == 0xFF010401) && (*(sptr + 1) == 0xFFFFFFFF))
			GetControllerPosition(curr_cont);

		if (((*sptr == 0xFE000000) && (*(sptr + 1) == 0x00000000)) || ((*sptr == 0x00000000) && (*(sptr + 1) == 0x00000001)))
			done = TRUE;

		if ((++curr_cont) == 8)
			done = TRUE;

		sptr += 2;
	}

	TransferPIFRam();
}
