BizHawk/waterbox/ss/input/mission.cpp

161 lines
4.2 KiB
C++

/******************************************************************************/
/* Mednafen Sega Saturn Emulation Module */
/******************************************************************************/
/* mission.cpp:
** Copyright (C) 2017 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.
*/
/*
Real mission stick has bugs and quirks that aren't emulated here(like apparently latching/updating the physical input state at the end of the
read sequence instead of near the beginning like other controllers do, resulting in increased latency).
*/
#include "common.h"
#include "mission.h"
namespace MDFN_IEN_SS
{
IODevice_Mission::IODevice_Mission(const bool dual_) : dbuttons(0), afeswitches(0), afspeed(0), dual(dual_)
{
}
IODevice_Mission::~IODevice_Mission()
{
}
void IODevice_Mission::Power(void)
{
phase = -1;
tl = true;
data_out = 0x01;
// Power-on state not tested:
afcounter = 0;
afphase = false;
}
void IODevice_Mission::UpdateInput(const uint8 *data, const int32 time_elapsed)
{
const uint32 dtmp = MDFN_de32lsb(&data[0]);
dbuttons = (dbuttons & 0xF) | ((dtmp & 0xFFF) << 4);
afeswitches = ((dtmp >> 12) & 0x8FF) << 4;
afspeed = (dtmp >> 20) & 0x7;
int offs = 4;
for (unsigned stick = 0; stick < (dual ? 2 : 1); stick++)
{
for (unsigned axis = 0; axis < 3; axis++)
{
axes[stick][axis] = data[offs++];
}
}
//printf("Update: %02x %02x %02x\n", axes[0][0], axes[0][1], axes[0][2]);
}
uint8 IODevice_Mission::UpdateBus(const uint8 smpc_out, const uint8 smpc_out_asserted)
{
uint8 tmp;
if(smpc_out & 0x40)
{
phase = -1;
tl = true;
data_out = 0x01;
}
else
{
if((bool)(smpc_out & 0x20) != tl)
{
if(phase < (dual ? 21 : 13))
{
tl = !tl;
phase++;
}
if(!phase)
{
unsigned dbaf = dbuttons & ((afphase - 1) | ~afeswitches);
unsigned c = 0;
// Digital Left
dbuttons |= ((axes[0][0] <= 0x56) ? 0x4 : 0);
dbuttons &= ~((axes[0][0] >= 0x6C) ? 0x4 : 0);
// Digital Right
dbuttons |= ((axes[0][0] >= 0xAB) ? 0x8 : 0);
dbuttons &= ~((axes[0][0] <= 0x95) ? 0x8 : 0);
// Digital Up
dbuttons |= ((axes[0][1] <= 0x54) ? 0x1 : 0);
dbuttons &= ~((axes[0][1] >= 0x6A) ? 0x1 : 0);
// Digital Down
dbuttons |= ((axes[0][1] >= 0xA9) ? 0x2 : 0);
dbuttons &= ~((axes[0][1] <= 0x94) ? 0x2 : 0);
if(!afcounter)
{
static const uint8 speedtab[7] = { 12, 8, 7, 5, 4, 4/* ? */, 1 };
afphase = !afphase;
afcounter = speedtab[afspeed];
}
afcounter--;
buffer[c++] = 0x1;
buffer[c++] = dual ? 0x9 : 0x5;
buffer[c++] = (((dbaf >> 0) & 0xF) ^ 0xF);
buffer[c++] = (((dbaf >> 4) & 0xF) ^ 0xF);
buffer[c++] = (((dbaf >> 8) & 0xF) ^ 0xF);
buffer[c++] = (((dbaf >> 12) & 0xF) ^ 0xF);
for(unsigned stick = 0; stick < (dual ? 2 : 1); stick++)
{
if(stick)
{
// Not sure, looks like something buggy.
buffer[c++] = 0x0;
buffer[c++] = 0x0;
}
buffer[c++] = (axes[stick][0] >> 4) & 0xF;
buffer[c++] = (axes[stick][0] >> 0) & 0xF;
buffer[c++] = (axes[stick][1] >> 4) & 0xF;
buffer[c++] = (axes[stick][1] >> 0) & 0xF;
buffer[c++] = (axes[stick][2] >> 4) & 0xF;
buffer[c++] = (axes[stick][2] >> 0) & 0xF;
}
buffer[c++] = 0x0;
buffer[c++] = 0x1;
}
data_out = buffer[phase];
}
}
tmp = (tl << 4) | data_out;
return (smpc_out & (smpc_out_asserted | 0xE0)) | (tmp &~ smpc_out_asserted);
}
}