BizHawk/psx/octoshock/psx/input/gamepad.cpp

239 lines
4.3 KiB
C++

/******************************************************************************/
/* Mednafen Sony PS1 Emulation Module */
/******************************************************************************/
/* gamepad.cpp:
** Copyright (C) 2011-2016 Mednafen Team
**
** This program is free software; you can redistribute it and/or
** modify it under the terms of the GNU General Public License
** as published by the Free Software Foundation; either version 2
** of the License, or (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software Foundation, Inc.,
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "../psx.h"
#include "../frontio.h"
#include "gamepad.h"
namespace MDFN_IEN_PSX
{
class InputDevice_Gamepad : public InputDevice
{
public:
InputDevice_Gamepad();
virtual ~InputDevice_Gamepad();
virtual void Power(void);
virtual void UpdateInput(const void *data);
virtual void SyncState(bool isReader, EW::NewState *ns);
//
//
//
virtual void SetDTR(bool new_dtr);
virtual bool GetDSR(void);
virtual bool Clock(bool TxD, int32 &dsr_pulse_delay);
private:
//non-serialized state
IO_Gamepad* io;
bool dtr;
uint8 buttons[2];
int32 command_phase;
uint32 bitpos;
uint8 receive_buffer;
uint8 command;
uint8 transmit_buffer[3];
uint32 transmit_pos;
uint32 transmit_count;
};
InputDevice_Gamepad::InputDevice_Gamepad()
{
Power();
}
InputDevice_Gamepad::~InputDevice_Gamepad()
{
}
void InputDevice_Gamepad::Power(void)
{
dtr = 0;
buttons[0] = buttons[1] = 0;
command_phase = 0;
bitpos = 0;
receive_buffer = 0;
command = 0;
memset(transmit_buffer, 0, sizeof(transmit_buffer));
transmit_pos = 0;
transmit_count = 0;
}
void InputDevice_Gamepad::SyncState(bool isReader, EW::NewState *ns)
{
NSS(dtr);
NSS(buttons);
NSS(command_phase);
NSS(bitpos);
NSS(receive_buffer);
NSS(command);
NSS(transmit_buffer);
NSS(transmit_pos);
NSS(transmit_count);
}
void InputDevice_Gamepad::UpdateInput(const void *data)
{
io = (IO_Gamepad*)data;
buttons[0] = io->buttons[0];
buttons[1] = io->buttons[1];
}
void InputDevice_Gamepad::SetDTR(bool new_dtr)
{
if(!dtr && new_dtr)
{
command_phase = 0;
bitpos = 0;
transmit_pos = 0;
transmit_count = 0;
}
else if(dtr && !new_dtr)
{
//if(bitpos || transmit_count)
// printf("[PAD] Abort communication!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
}
dtr = new_dtr;
}
bool InputDevice_Gamepad::GetDSR(void)
{
if(!dtr)
return(0);
if(!bitpos && transmit_count)
return(1);
return(0);
}
bool InputDevice_Gamepad::Clock(bool TxD, int32 &dsr_pulse_delay)
{
bool ret = 1;
dsr_pulse_delay = 0;
if(!dtr)
return(1);
if(transmit_count)
ret = (transmit_buffer[transmit_pos] >> bitpos) & 1;
receive_buffer &= ~(1 << bitpos);
receive_buffer |= TxD << bitpos;
bitpos = (bitpos + 1) & 0x7;
if(!bitpos)
{
//printf("[PAD] Receive: %02x -- command_phase=%d\n", receive_buffer, command_phase);
if(transmit_count)
{
transmit_pos++;
transmit_count--;
}
switch(command_phase)
{
case 0:
if(receive_buffer != 0x01)
command_phase = -1;
else
{
transmit_buffer[0] = 0x41;
transmit_pos = 0;
transmit_count = 1;
command_phase++;
}
break;
case 1:
command = receive_buffer;
command_phase++;
transmit_buffer[0] = 0x5A;
//if(command != 0x42)
// fprintf(stderr, "Gamepad unhandled command: 0x%02x\n", command);
//assert(command == 0x42);
if(command == 0x42)
{
//printf("PAD COmmand 0x42, sl=%u\n", GPU->GetScanlineNum());
transmit_buffer[1] = 0xFF ^ buttons[0];
transmit_buffer[2] = 0xFF ^ buttons[1];
transmit_pos = 0;
transmit_count = 3;
io->active = true;
}
else
{
command_phase = -1;
transmit_buffer[1] = 0;
transmit_buffer[2] = 0;
transmit_pos = 0;
transmit_count = 0;
}
break;
}
}
if(!bitpos && transmit_count)
dsr_pulse_delay = 0x40; //0x100;
return(ret);
}
InputDevice *Device_Gamepad_Create(void)
{
return new InputDevice_Gamepad();
}
}