From f5670f870e86ea7543e77bd71dd633a75a166c47 Mon Sep 17 00:00:00 2001 From: Tillmann Karras Date: Sat, 10 Sep 2022 19:58:52 +0100 Subject: [PATCH] Add emulated Shinkansen controller --- Source/Core/Core/CMakeLists.txt | 2 + Source/Core/Core/HW/Wiimote.cpp | 6 + Source/Core/Core/HW/Wiimote.h | 2 + .../HW/WiimoteEmu/Extension/Shinkansen.cpp | 114 ++++++++++++++++++ .../Core/HW/WiimoteEmu/Extension/Shinkansen.h | 50 ++++++++ .../Core/Core/HW/WiimoteEmu/ExtensionPort.h | 1 + Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp | 9 ++ Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.h | 2 + Source/Core/DolphinLib.props | 2 + .../Config/Mapping/WiimoteEmuExtension.cpp | 19 +++ .../Config/Mapping/WiimoteEmuExtension.h | 2 + 11 files changed, 209 insertions(+) create mode 100644 Source/Core/Core/HW/WiimoteEmu/Extension/Shinkansen.cpp create mode 100644 Source/Core/Core/HW/WiimoteEmu/Extension/Shinkansen.h diff --git a/Source/Core/Core/CMakeLists.txt b/Source/Core/Core/CMakeLists.txt index 26787fcd3d..fe7b849782 100644 --- a/Source/Core/Core/CMakeLists.txt +++ b/Source/Core/Core/CMakeLists.txt @@ -296,6 +296,8 @@ add_library(core HW/WiimoteEmu/Extension/Guitar.h HW/WiimoteEmu/Extension/Nunchuk.cpp HW/WiimoteEmu/Extension/Nunchuk.h + HW/WiimoteEmu/Extension/Shinkansen.cpp + HW/WiimoteEmu/Extension/Shinkansen.h HW/WiimoteEmu/Extension/TaTaCon.cpp HW/WiimoteEmu/Extension/TaTaCon.h HW/WiimoteEmu/Extension/Turntable.cpp diff --git a/Source/Core/Core/HW/Wiimote.cpp b/Source/Core/Core/HW/Wiimote.cpp index 476a265f76..580bff8aee 100644 --- a/Source/Core/Core/HW/Wiimote.cpp +++ b/Source/Core/Core/HW/Wiimote.cpp @@ -152,6 +152,12 @@ ControllerEmu::ControlGroup* GetTaTaConGroup(int number, WiimoteEmu::TaTaConGrou return static_cast(s_config.GetController(number))->GetTaTaConGroup(group); } +ControllerEmu::ControlGroup* GetShinkansenGroup(int number, WiimoteEmu::ShinkansenGroup group) +{ + return static_cast(s_config.GetController(number)) + ->GetShinkansenGroup(group); +} + void Shutdown() { s_config.UnregisterHotplugCallback(); diff --git a/Source/Core/Core/HW/Wiimote.h b/Source/Core/Core/HW/Wiimote.h index ee59aec2e1..a15671cc93 100644 --- a/Source/Core/Core/HW/Wiimote.h +++ b/Source/Core/Core/HW/Wiimote.h @@ -28,6 +28,7 @@ enum class TurntableGroup; enum class UDrawTabletGroup; enum class DrawsomeTabletGroup; enum class TaTaConGroup; +enum class ShinkansenGroup; } // namespace WiimoteEmu enum @@ -92,6 +93,7 @@ ControllerEmu::ControlGroup* GetUDrawTabletGroup(int number, WiimoteEmu::UDrawTa ControllerEmu::ControlGroup* GetDrawsomeTabletGroup(int number, WiimoteEmu::DrawsomeTabletGroup group); ControllerEmu::ControlGroup* GetTaTaConGroup(int number, WiimoteEmu::TaTaConGroup group); +ControllerEmu::ControlGroup* GetShinkansenGroup(int number, WiimoteEmu::ShinkansenGroup group); bool NetPlay_GetButtonPress(int wiimote, bool pressed); } // namespace Wiimote diff --git a/Source/Core/Core/HW/WiimoteEmu/Extension/Shinkansen.cpp b/Source/Core/Core/HW/WiimoteEmu/Extension/Shinkansen.cpp new file mode 100644 index 0000000000..81e4a52070 --- /dev/null +++ b/Source/Core/Core/HW/WiimoteEmu/Extension/Shinkansen.cpp @@ -0,0 +1,114 @@ +// Copyright 2022 Dolphin Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "Core/HW/WiimoteEmu/Extension/Shinkansen.h" + +#include + +#include "Common/Assert.h" +#include "Common/Common.h" +#include "Common/CommonTypes.h" +#include "Core/HW/WiimoteEmu/WiimoteEmu.h" + +#include "InputCommon/ControllerEmu/ControlGroup/Buttons.h" +#include "InputCommon/ControllerEmu/ControlGroup/MixedTriggers.h" + +namespace WiimoteEmu +{ +// TODO: check this (only the last byte is known good) +constexpr std::array shinkansen_id{{0x00, 0x00, 0xa4, 0x20, 0x01, 0x10}}; + +Shinkansen::Shinkansen() : Extension3rdParty("Shinkansen", _trans("Shinkansen Controller")) +{ + // Button layout on the controller: + // + // Up Select Start D + // Left Right A C + // Down B + // + groups.emplace_back(m_buttons = new ControllerEmu::Buttons(_trans("Buttons"))); + m_buttons->AddInput(ControllerEmu::Translate, _trans("Left")); + m_buttons->AddInput(ControllerEmu::Translate, _trans("Down")); + m_buttons->AddInput(ControllerEmu::Translate, _trans("Right")); + m_buttons->AddInput(ControllerEmu::Translate, _trans("Up")); + m_buttons->AddInput(ControllerEmu::DoNotTranslate, "A"); + m_buttons->AddInput(ControllerEmu::DoNotTranslate, "B"); + m_buttons->AddInput(ControllerEmu::DoNotTranslate, "C"); + m_buttons->AddInput(ControllerEmu::DoNotTranslate, "D"); + m_buttons->AddInput(ControllerEmu::Translate, _trans("Select")); + m_buttons->AddInput(ControllerEmu::Translate, _trans("Start")); + + // For easier axis mapping the right lever is inverted in Dolphin, + // so that the train coasts when no trigger is squeezed. + groups.emplace_back(m_levers = new ControllerEmu::MixedTriggers(_trans("Levers"))); + m_levers->AddInput(ControllerEmu::Translate, _trans("L")); + m_levers->AddInput(ControllerEmu::Translate, _trans("R")); + m_levers->AddInput(ControllerEmu::Translate, _trans("L-Analog")); + m_levers->AddInput(ControllerEmu::Translate, _trans("R-Analog")); + + groups.emplace_back(m_led = new ControllerEmu::ControlGroup(_trans("Light"))); + m_led->AddOutput(ControllerEmu::Translate, _trans("Doors Locked")); +} + +void Shinkansen::Update() +{ + DataFormat ext_data = {}; + + u16 digital = 0; + const u16 lever_bitmasks[2] = {}; + double analog[2] = {}; + m_levers->GetState(&digital, lever_bitmasks, analog); + // The game requires these specific values, all other values are treated like 0/255 (which are + // guesses). + const u8 brake_values[] = {0, 53, 79, 105, 132, 159, 187, 217, 250}; + const u8 power_values[] = {255, 229, 208, 189, 170, 153, 135, 118, 101, 85, 68, 51, 35, 17}; + ext_data.brake = brake_values[size_t(analog[0] * (sizeof(brake_values) - 1))]; + ext_data.power = power_values[size_t(analog[1] * (sizeof(power_values) - 1))]; + + // Note: This currently assumes a little-endian host. + const u16 button_bitmasks[] = { + 0x0200, // Left + 0x0040, // Down + 0x0080, // Right + 0x0100, // Up + 0x2000, // A + 0x4000, // B + 0x1000, // C + 0x0800, // D + 0x0010, // Select + 0x0004, // Start + }; + m_buttons->GetState(&ext_data.buttons, button_bitmasks); + ext_data.buttons ^= 0xFFFF; + Common::BitCastPtr(&m_reg.controller_data) = ext_data; + + const auto lock = GetStateLock(); + m_led->controls[0]->control_ref->State(m_reg.identifier[1]); +} + +void Shinkansen::Reset() +{ + EncryptedExtension::Reset(); + + m_reg = {}; + m_reg.identifier = shinkansen_id; + m_reg.calibration.fill(0xff); +} + +ControllerEmu::ControlGroup* Shinkansen::GetGroup(ShinkansenGroup group) +{ + switch (group) + { + case ShinkansenGroup::Levers: + return m_levers; + case ShinkansenGroup::Buttons: + return m_buttons; + case ShinkansenGroup::Light: + return m_led; + default: + ASSERT(false); + return nullptr; + } +} + +} // namespace WiimoteEmu diff --git a/Source/Core/Core/HW/WiimoteEmu/Extension/Shinkansen.h b/Source/Core/Core/HW/WiimoteEmu/Extension/Shinkansen.h new file mode 100644 index 0000000000..d237f484ad --- /dev/null +++ b/Source/Core/Core/HW/WiimoteEmu/Extension/Shinkansen.h @@ -0,0 +1,50 @@ +// Copyright 2022 Dolphin Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "Core/HW/WiimoteEmu/Extension/Extension.h" + +namespace ControllerEmu +{ +class Buttons; +class ControlGroup; +class MixedTriggers; +} // namespace ControllerEmu + +namespace WiimoteEmu +{ +enum class ShinkansenGroup +{ + Buttons, + Levers, + Light, +}; + +class Shinkansen : public Extension3rdParty +{ +public: + Shinkansen(); + + void Update() override; + void Reset() override; + ControllerEmu::ControlGroup* GetGroup(ShinkansenGroup group); + +private: + ControllerEmu::Buttons* m_buttons; + ControllerEmu::MixedTriggers* m_levers; + ControllerEmu::ControlGroup* m_led; + + struct DataFormat + { + u8 unk0; + u8 unk1; + u8 brake; + u8 power; + u8 unk4; + u8 unk5; + u16 buttons; + }; +}; + +} // namespace WiimoteEmu diff --git a/Source/Core/Core/HW/WiimoteEmu/ExtensionPort.h b/Source/Core/Core/HW/WiimoteEmu/ExtensionPort.h index 7b7ca9bb78..86b1fd31f9 100644 --- a/Source/Core/Core/HW/WiimoteEmu/ExtensionPort.h +++ b/Source/Core/Core/HW/WiimoteEmu/ExtensionPort.h @@ -21,6 +21,7 @@ enum ExtensionNumber : u8 UDRAW_TABLET, DRAWSOME_TABLET, TATACON, + SHINKANSEN, MAX }; diff --git a/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp b/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp index b266464021..ca071a5e10 100644 --- a/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp +++ b/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp @@ -30,6 +30,7 @@ #include "Core/HW/WiimoteEmu/Extension/Drums.h" #include "Core/HW/WiimoteEmu/Extension/Guitar.h" #include "Core/HW/WiimoteEmu/Extension/Nunchuk.h" +#include "Core/HW/WiimoteEmu/Extension/Shinkansen.h" #include "Core/HW/WiimoteEmu/Extension/TaTaCon.h" #include "Core/HW/WiimoteEmu/Extension/Turntable.h" #include "Core/HW/WiimoteEmu/Extension/UDrawTablet.h" @@ -247,6 +248,7 @@ Wiimote::Wiimote(const unsigned int index) : m_index(index) m_attachments->AddAttachment(std::make_unique()); m_attachments->AddAttachment(std::make_unique()); m_attachments->AddAttachment(std::make_unique()); + m_attachments->AddAttachment(std::make_unique()); m_attachments->AddSetting(&m_motion_plus_setting, {_trans("Attach MotionPlus")}, true); @@ -400,6 +402,13 @@ ControllerEmu::ControlGroup* Wiimote::GetTaTaConGroup(TaTaConGroup group) const ->GetGroup(group); } +ControllerEmu::ControlGroup* Wiimote::GetShinkansenGroup(ShinkansenGroup group) const +{ + return static_cast( + m_attachments->GetAttachmentList()[ExtensionNumber::SHINKANSEN].get()) + ->GetGroup(group); +} + bool Wiimote::ProcessExtensionPortEvent() { // WiiBrew: Following a connection or disconnection event on the Extension Port, diff --git a/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.h b/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.h index 31448c6e3c..ae51b04ace 100644 --- a/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.h +++ b/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.h @@ -62,6 +62,7 @@ enum class TurntableGroup; enum class UDrawTabletGroup; enum class DrawsomeTabletGroup; enum class TaTaConGroup; +enum class ShinkansenGroup; template void UpdateCalibrationDataChecksum(T& data, int cksum_bytes) @@ -123,6 +124,7 @@ public: ControllerEmu::ControlGroup* GetUDrawTabletGroup(UDrawTabletGroup group) const; ControllerEmu::ControlGroup* GetDrawsomeTabletGroup(DrawsomeTabletGroup group) const; ControllerEmu::ControlGroup* GetTaTaConGroup(TaTaConGroup group) const; + ControllerEmu::ControlGroup* GetShinkansenGroup(ShinkansenGroup group) const; void Update() override; void EventLinked() override; diff --git a/Source/Core/DolphinLib.props b/Source/Core/DolphinLib.props index 4c08f0a6d8..6cc746ba5f 100644 --- a/Source/Core/DolphinLib.props +++ b/Source/Core/DolphinLib.props @@ -322,6 +322,7 @@ + @@ -940,6 +941,7 @@ + diff --git a/Source/Core/DolphinQt/Config/Mapping/WiimoteEmuExtension.cpp b/Source/Core/DolphinQt/Config/Mapping/WiimoteEmuExtension.cpp index 5765056725..ed850181f9 100644 --- a/Source/Core/DolphinQt/Config/Mapping/WiimoteEmuExtension.cpp +++ b/Source/Core/DolphinQt/Config/Mapping/WiimoteEmuExtension.cpp @@ -14,6 +14,7 @@ #include "Core/HW/WiimoteEmu/Extension/Drums.h" #include "Core/HW/WiimoteEmu/Extension/Guitar.h" #include "Core/HW/WiimoteEmu/Extension/Nunchuk.h" +#include "Core/HW/WiimoteEmu/Extension/Shinkansen.h" #include "Core/HW/WiimoteEmu/Extension/TaTaCon.h" #include "Core/HW/WiimoteEmu/Extension/Turntable.h" #include "Core/HW/WiimoteEmu/Extension/UDrawTablet.h" @@ -32,6 +33,7 @@ WiimoteEmuExtension::WiimoteEmuExtension(MappingWindow* window) : MappingWidget( CreateUDrawTabletLayout(); CreateDrawsomeTabletLayout(); CreateTaTaConLayout(); + CreateShinkansenLayout(); CreateMainLayout(); ChangeExtensionType(WiimoteEmu::ExtensionNumber::NONE); @@ -224,6 +226,21 @@ void WiimoteEmuExtension::CreateTaTaConLayout() m_tatacon_box->setLayout(hbox); } +void WiimoteEmuExtension::CreateShinkansenLayout() +{ + auto* hbox = new QHBoxLayout(); + m_shinkansen_box = new QGroupBox(tr("Shinkansen"), this); + + hbox->addWidget(CreateGroupBox( + tr("Levers"), Wiimote::GetShinkansenGroup(GetPort(), WiimoteEmu::ShinkansenGroup::Levers))); + hbox->addWidget(CreateGroupBox( + tr("Buttons"), Wiimote::GetShinkansenGroup(GetPort(), WiimoteEmu::ShinkansenGroup::Buttons))); + hbox->addWidget(CreateGroupBox( + tr("Light"), Wiimote::GetShinkansenGroup(GetPort(), WiimoteEmu::ShinkansenGroup::Light))); + + m_shinkansen_box->setLayout(hbox); +} + void WiimoteEmuExtension::CreateMainLayout() { m_main_layout = new QHBoxLayout(); @@ -237,6 +254,7 @@ void WiimoteEmuExtension::CreateMainLayout() m_main_layout->addWidget(m_udraw_tablet_box); m_main_layout->addWidget(m_drawsome_tablet_box); m_main_layout->addWidget(m_tatacon_box); + m_main_layout->addWidget(m_shinkansen_box); setLayout(m_main_layout); } @@ -269,4 +287,5 @@ void WiimoteEmuExtension::ChangeExtensionType(u32 type) m_udraw_tablet_box->setHidden(type != ExtensionNumber::UDRAW_TABLET); m_drawsome_tablet_box->setHidden(type != ExtensionNumber::DRAWSOME_TABLET); m_tatacon_box->setHidden(type != ExtensionNumber::TATACON); + m_shinkansen_box->setHidden(type != ExtensionNumber::SHINKANSEN); } diff --git a/Source/Core/DolphinQt/Config/Mapping/WiimoteEmuExtension.h b/Source/Core/DolphinQt/Config/Mapping/WiimoteEmuExtension.h index a767611ef4..43b5ebbdd5 100644 --- a/Source/Core/DolphinQt/Config/Mapping/WiimoteEmuExtension.h +++ b/Source/Core/DolphinQt/Config/Mapping/WiimoteEmuExtension.h @@ -33,6 +33,7 @@ private: void CreateUDrawTabletLayout(); void CreateDrawsomeTabletLayout(); void CreateTaTaConLayout(); + void CreateShinkansenLayout(); void CreateMainLayout(); // Main @@ -46,4 +47,5 @@ private: QGroupBox* m_udraw_tablet_box; QGroupBox* m_drawsome_tablet_box; QGroupBox* m_tatacon_box; + QGroupBox* m_shinkansen_box; };