/*Arculator 2.2 by Sarah Walker
  Printer port subsystem*/
#include "arc.h"
#include "config.h"
#include "ioc.h"
#include "joystick.h"
#include "plat_joystick.h"
#include "printer.h"

void printer_set_busy(int busy);
void printer_set_ack(int ack);

/*GamesPad :

  D1 = reset - low edge reloads shift registers
  D2 = clock - low edge clocks shift registers
  BUSY = pad 1 data. Active low
  !ACK = pad 2 data. Active _high_*/
static struct
{
	int reset;
	int clock;
	uint16_t data[2];
	int data_out[2];
} gamespad;

static void gamespad_write(uint8_t val)
{
//        rpclog("gamespad_write: %02x\n", val);
	if (!(val & 2) && gamespad.reset)
	{
		int c;

		for (c = 0; c < 2; c++)
		{
			gamespad.data[c] = 0;

			if (joystick_state[c].axis[1] < -16383)
				gamespad.data[c] |= 0x010;
			if (joystick_state[c].axis[1] > 16383)
				gamespad.data[c] |= 0x020;
			if (joystick_state[c].axis[0] < -16383)
				gamespad.data[c] |= 0x040;
			if (joystick_state[c].axis[0] > 16383)
				gamespad.data[c] |= 0x080;

			if (joystick_state[c].button[0])
				gamespad.data[c] |= 0x100;
			if (joystick_state[c].button[1])
				gamespad.data[c] |= 0x001;
			if (joystick_state[c].button[2])
				gamespad.data[c] |= 0x200;
			if (joystick_state[c].button[3])
				gamespad.data[c] |= 0x002;
			if (joystick_state[c].button[4])
				gamespad.data[c] |= 0x400;
			if (joystick_state[c].button[5])
				gamespad.data[c] |= 0x800;
			if (joystick_state[c].button[6])
				gamespad.data[c] |= 0x004;
			if (joystick_state[c].button[7])
				gamespad.data[c] |= 0x008;
		}
//                rpclog("Latch %04x %04x\n", gamespad.data[0], gamespad.data[1]);
	}
	if (!(val & 4) && gamespad.clock)
	{
		gamespad.data_out[0] = gamespad.data[0] & 1;
		gamespad.data_out[1] = gamespad.data[1] & 1;

		printer_set_busy(!gamespad.data_out[0]);
		printer_set_ack(gamespad.data_out[1]);

//                rpclog("Clock  %04x %i\n", gamespad.data[0], gamespad.data_out[0]);
		gamespad.data[0] >>= 1;
		gamespad.data[1] >>= 1;
	}

	gamespad.reset = (val & 2);
	gamespad.clock = (val & 4);
}

uint8_t gamespad_read(void)
{
	uint8_t temp = 0x3f;

	if (!gamespad.data_out[0])
		temp |= 0x80;
	if (gamespad.data_out[1])
		temp |= 0x40;
//        rpclog("gamespad_read: %02x  %08x\n", temp, armregs[3]);
	return temp;
}

static void serial_port_write(uint8_t val)
{
	int busy = 0, ack = 0;

	if (!(val & 0x01))
	{
		if ((joystick_state[0].axis[1] < -16383))
			busy = 1;
		if ((joystick_state[1].axis[1] < -16383))
			ack = 1;
	}
	if (!(val & 0x02))
	{
		if ((joystick_state[0].axis[1] > 16383))
			busy = 1;
		if ((joystick_state[1].axis[1] > 16383))
			ack = 1;
	}
	if (!(val & 0x04))
	{
		if ((joystick_state[0].axis[0] < -16383))
			busy = 1;
		if ((joystick_state[1].axis[0] < -16383))
			ack = 1;
	}
	if (!(val & 0x08))
	{
		if ((joystick_state[0].axis[0] > 16383))
			busy = 1;
		if ((joystick_state[1].axis[0] > 16383))
			ack = 1;
	}
	if (!(val & 0x10))
	{
		if ((joystick_state[0].button[0]))
			busy = 1;
		if ((joystick_state[1].button[0]))
			ack = 1;
	}
	if (!(val & 0x20))
		busy = ack = 1;
	if (!(val & 0x40))
	{
		if ((joystick_state[0].button[1]))
			busy = 1;
		if ((joystick_state[1].button[1]))
			ack = 1;
	}

	printer_set_busy(busy);
	printer_set_ack(!ack);
}

#define PRINTER_BUSY 0x80
#define PRINTER_ACK  0x40
#define PRINTER_IRQ  0x04

static int printer_busy, printer_ack;
static int printer_irq_pending;

void printer_set_busy(int busy)
{
	if (fdctype != FDC_82C711)
	{
		if (busy)
			ioc_irqa(IOC_IRQA_PRINTER_BUSY);
		else
			ioc_irqac(IOC_IRQA_PRINTER_BUSY);
	}

	printer_busy = busy;
}
void printer_set_ack(int ack)
{
	if (fdctype != FDC_82C711)
	{
		if (ack && !printer_ack)
			ioc_irqa(IOC_IRQA_PRINTER_ACK);
		else
			ioc_irqac(IOC_IRQA_PRINTER_ACK);
	}
	else
	{
		printer_irq_pending = 1;
		if (ack && !printer_ack)
			ioc_irqa(IOC_IRQA_PRINTER_LATCH);
	}

	printer_ack = ack;
}
int printer_get_ack(void)
{
	return printer_ack;
}

void printer_data_write(uint8_t val)
{
//        rpclog("printer_data_write %02x\n", val);
	if (joystick_gamespad_present)
		gamespad_write(val);
	else if (joystick_serial_port_present)
		serial_port_write(val);
}

uint8_t printer_status_read(void)
{
	uint8_t temp = 0x3f;

	if (printer_busy)
		temp |= PRINTER_BUSY;
	if (printer_ack)
		temp |= PRINTER_ACK;
	if (printer_irq_pending)
		temp &= ~PRINTER_IRQ;
	printer_irq_pending = 0;
//        rpclog("Read status %02x\n", temp);

	return temp;
}
