AppleWin/source/SNESMAX.cpp

243 lines
9.9 KiB
C++

/*
AppleWin : An Apple //e emulator for Windows
Copyright (C) 1994-1996, Michael O'Brien
Copyright (C) 1999-2001, Oliver Schmidt
Copyright (C) 2002-2005, Tom Charlesworth
Copyright (C) 2006-2007, Tom Charlesworth, Michael Pohoreski
AppleWin 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.
AppleWin 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 AppleWin; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
SNESMAX.CPP
Emulate a SNES MAX controller serial interface card
2 ports (one for each of the two possible joysticks)
Latch = write any data to C0n0
Clock = write any data to C0n1
Data = read from C0n0
n = 8 + slot number
Data
Bit 0 = Not Used
Bit 1 = Not Used
Bit 2 = Not Used
Bit 3 = Not Used
Bit 4 = Not Used
Bit 5 = Not Used
Bit 6 = Controller 2, Active Low
Bit 7 = Controller 1, Active Low
Once data is read, button presses (for each controller) should be stored in the following structure
Byte 0: B:Y:Sl:St:U:D:L:R
Byte 1: A:X:Fl:Fr:x:x:x:x
The variable controllerXButtons will stored in the reverse order.
Alex Lukacz Aug 2021
*/
#include "StdAfx.h"
#include "SNESMAX.h"
#include "Memory.h"
#include "YamlHelper.h"
BYTE __stdcall SNESMAXCard::IORead(WORD pc, WORD addr, BYTE bWrite, BYTE value, ULONG nExecutedCycles)
{
const UINT slot = ((addr & 0xff) >> 4) - 8;
SNESMAXCard* pCard = (SNESMAXCard*)MemGetSlotParameters(slot);
BYTE output = MemReadFloatingBus(nExecutedCycles);
switch (addr & 0xF)
{
case 0:
output = (output & 0x3F) | ((pCard->m_controller2Buttons & 0x1) << 6) | ((pCard->m_controller1Buttons & 0x1) << 7);
break;
default:
break;
}
return output;
}
BYTE __stdcall SNESMAXCard::IOWrite(WORD pc, WORD addr, BYTE bWrite, BYTE value, ULONG nExecutedCycles)
{
const UINT slot = ((addr & 0xff) >> 4) - 8;
SNESMAXCard* pCard = (SNESMAXCard*)MemGetSlotParameters(slot);
UINT xAxis = 0;
UINT yAxis = 0;
JOYINFOEX infoEx;
MMRESULT result = 0;
infoEx.dwSize = sizeof(infoEx);
infoEx.dwFlags = JOY_RETURNPOV | JOY_RETURNBUTTONS;
UINT& controller1Buttons = pCard->m_controller1Buttons; // ref to object's controller1Buttons
UINT& controller2Buttons = pCard->m_controller2Buttons; // ref to object's controller2Buttons
switch (addr & 0xF)
{
case 0: // Latch
pCard->m_buttonIndex = 0;
controller1Buttons = 0;
controller2Buttons = 0;
result = joyGetPosEx(JOYSTICKID1, &infoEx);
if (result == JOYERR_NOERROR)
{
xAxis = (infoEx.dwXpos >> 8) & 0xFF;
yAxis = (infoEx.dwYpos >> 8) & 0xFF;
controller1Buttons = controller1Buttons | ((yAxis < 103 || infoEx.dwPOV == 0 || infoEx.dwPOV == 4500 || infoEx.dwPOV == 31500) << 4); // U Button
controller1Buttons = controller1Buttons | ((yAxis > 153 || (infoEx.dwPOV >= 13500 && infoEx.dwPOV <= 22500)) << 5); // D Button
controller1Buttons = controller1Buttons | ((xAxis < 103 || (infoEx.dwPOV >= 22500 && infoEx.dwPOV <= 31500)) << 6); // L Button
controller1Buttons = controller1Buttons | ((xAxis > 153 || (infoEx.dwPOV >= 4500 && infoEx.dwPOV <= 13500)) << 7); // R Button
// controller1Buttons = controller1Buttons | 0 * 0x1000; // spare Button
// controller1Buttons = controller1Buttons | 0 * 0x2000; // spare Button
// controller1Buttons = controller1Buttons | 0 * 0x4000; // spare Button
// controller1Buttons = controller1Buttons | 0 * 0x8000; // spare Button
if (pCard->m_altControllerType[0])
{
// 8BitDo NES30 PRO
controller1Buttons = controller1Buttons | ((infoEx.dwButtons & 0x0002) >> 1); // B Button
controller1Buttons = controller1Buttons | ((infoEx.dwButtons & 0x0010) >> 3); // Y Button
controller1Buttons = controller1Buttons | ((infoEx.dwButtons & 0x0400) >> 8); // Sl Button
controller1Buttons = controller1Buttons | ((infoEx.dwButtons & 0x0800) >> 8); // St Button
controller1Buttons = controller1Buttons | ((infoEx.dwButtons & 0x0001) << 8); // A Button
controller1Buttons = controller1Buttons | ((infoEx.dwButtons & 0x0008) << 6); // X Button
controller1Buttons = controller1Buttons | ((infoEx.dwButtons & 0x0100) << 2) | ((infoEx.dwButtons & 0x0040) << 4); // Fl Button
controller1Buttons = controller1Buttons | ((infoEx.dwButtons & 0x0200) << 2) | ((infoEx.dwButtons & 0x0080) << 4); // Fr Button
}
else
{
// Logitech F310, Dualshock 4
controller1Buttons = controller1Buttons | ((infoEx.dwButtons & 0x0002) >> 1); // B Button
controller1Buttons = controller1Buttons | ((infoEx.dwButtons & 0x0001) << 1); // Y Button
controller1Buttons = controller1Buttons | ((infoEx.dwButtons & 0x0100) >> 6); // Sl Button
controller1Buttons = controller1Buttons | ((infoEx.dwButtons & 0x0200) >> 6); // St Button
controller1Buttons = controller1Buttons | ((infoEx.dwButtons & 0x0004) << 6); // A Button
controller1Buttons = controller1Buttons | ((infoEx.dwButtons & 0x0008) << 6); // X Button
controller1Buttons = controller1Buttons | ((infoEx.dwButtons & 0x0010) << 6) | ((infoEx.dwButtons & 0x0040) << 4); // Fl Button
controller1Buttons = controller1Buttons | ((infoEx.dwButtons & 0x0020) << 6) | ((infoEx.dwButtons & 0x0080) << 4); // Fr Button
}
controller1Buttons = controller1Buttons | 0x10000; // Controller plugged in status.
}
controller1Buttons = ~controller1Buttons;
result = joyGetPosEx(JOYSTICKID2, &infoEx);
if (result == JOYERR_NOERROR)
{
xAxis = (infoEx.dwXpos >> 8) & 0xFF;
yAxis = (infoEx.dwYpos >> 8) & 0xFF;
controller2Buttons = controller2Buttons | ((yAxis < 103 || infoEx.dwPOV == 0 || infoEx.dwPOV == 4500 || infoEx.dwPOV == 31500) << 4); // U Button
controller2Buttons = controller2Buttons | ((yAxis > 153 || (infoEx.dwPOV >= 13500 && infoEx.dwPOV <= 22500)) << 5); // D Button
controller2Buttons = controller2Buttons | ((xAxis < 103 || (infoEx.dwPOV >= 22500 && infoEx.dwPOV <= 31500)) << 6); // L Button
controller2Buttons = controller2Buttons | ((xAxis > 153 || (infoEx.dwPOV >= 4500 && infoEx.dwPOV <= 13500)) << 7); // R Button
// controller2Buttons = controller2Buttons | 0 * 0x1000; // spare Button
// controller2Buttons = controller2Buttons | 0 * 0x2000; // spare Button
// controller2Buttons = controller2Buttons | 0 * 0x4000; // spare Button
// controller2Buttons = controller2Buttons | 0 * 0x8000; // spare Button
if (pCard->m_altControllerType[1])
{
// 8BitDo NES30 PRO
controller2Buttons = controller2Buttons | ((infoEx.dwButtons & 0x0002) >> 1); // B Button
controller2Buttons = controller2Buttons | ((infoEx.dwButtons & 0x0010) >> 3); // Y Button
controller2Buttons = controller2Buttons | ((infoEx.dwButtons & 0x0400) >> 8); // Sl Button
controller2Buttons = controller2Buttons | ((infoEx.dwButtons & 0x0800) >> 8); // St Button
controller2Buttons = controller2Buttons | ((infoEx.dwButtons & 0x0001) << 8); // A Button
controller2Buttons = controller2Buttons | ((infoEx.dwButtons & 0x0008) << 6); // X Button
controller2Buttons = controller2Buttons | ((infoEx.dwButtons & 0x0100) << 2) | ((infoEx.dwButtons & 0x0040) << 4); // Fl Button
controller2Buttons = controller2Buttons | ((infoEx.dwButtons & 0x0200) << 2) | ((infoEx.dwButtons & 0x0080) << 4); // Fr Button
}
else
{
// Logitech F310, Dualshock 4
controller2Buttons = controller2Buttons | ((infoEx.dwButtons & 0x0002) >> 1); // B Button
controller2Buttons = controller2Buttons | ((infoEx.dwButtons & 0x0001) << 1); // Y Button
controller2Buttons = controller2Buttons | ((infoEx.dwButtons & 0x0100) >> 6); // Sl Button
controller2Buttons = controller2Buttons | ((infoEx.dwButtons & 0x0200) >> 6); // St Button
controller2Buttons = controller2Buttons | ((infoEx.dwButtons & 0x0004) << 6); // A Button
controller2Buttons = controller2Buttons | ((infoEx.dwButtons & 0x0008) << 6); // X Button
controller2Buttons = controller2Buttons | ((infoEx.dwButtons & 0x0010) << 6) | ((infoEx.dwButtons & 0x0040) << 4); // Fl Button
controller2Buttons = controller2Buttons | ((infoEx.dwButtons & 0x0020) << 6) | ((infoEx.dwButtons & 0x0080) << 4); // Fr Button
}
controller2Buttons = controller2Buttons | 0x10000; // Controller plugged in status.
}
controller2Buttons = ~controller2Buttons;
break;
case 1: // Clock
if (pCard->m_buttonIndex <= 16)
{
pCard->m_buttonIndex++;
controller1Buttons = controller1Buttons >> 1;
controller2Buttons = controller2Buttons >> 1;
}
break;
default:
break;
}
return 0;
}
void SNESMAXCard::InitializeIO(LPBYTE pCxRomPeripheral)
{
RegisterIoHandler(m_slot, &SNESMAXCard::IORead, &SNESMAXCard::IOWrite, IO_Null, IO_Null, this, NULL);
}
//===========================================================================
static const UINT kUNIT_VERSION = 1;
#define SS_YAML_KEY_BUTTON_INDEX "Button Index"
const std::string& SNESMAXCard::GetSnapshotCardName(void)
{
static const std::string name("SNES MAX");
return name;
}
void SNESMAXCard::SaveSnapshot(YamlSaveHelper& yamlSaveHelper)
{
YamlSaveHelper::Slot slot(yamlSaveHelper, GetSnapshotCardName(), m_slot, kUNIT_VERSION);
YamlSaveHelper::Label unit(yamlSaveHelper, "%s:\n", SS_YAML_KEY_STATE);
yamlSaveHelper.SaveUint(SS_YAML_KEY_BUTTON_INDEX, m_buttonIndex);
}
bool SNESMAXCard::LoadSnapshot(YamlLoadHelper& yamlLoadHelper, UINT version)
{
if (version < 1 || version > kUNIT_VERSION)
ThrowErrorInvalidVersion(version);
m_buttonIndex = yamlLoadHelper.LoadUint(SS_YAML_KEY_BUTTON_INDEX);
// Initialise with no buttons pressed (loaded state maybe part way through reading the buttons)
m_controller1Buttons = 0xff;
m_controller2Buttons = 0xff;
return true;
}