diff --git a/README.md b/README.md index c8ba695..7789549 100644 --- a/README.md +++ b/README.md @@ -71,6 +71,7 @@ Use controllers from other consoles natively on your Nintendo Switch via Bluetoo * __AtGames Legends Pinball Controller + Arcade Control Panel__ * __Hyperkin Scout__ * __Betop 2585N2__ +* __Atari Wireless Modern Controller__ **Not all Xbox One wireless controllers support Bluetooth. Older variants use a proprietary 2.4Ghz protocol and cannot be used with the Switch. See [here](https://support.xbox.com/help/hardware-network/accessories/connect-and-troubleshoot-xbox-one-bluetooth-issues) for information on identifying the Bluetooth variant.* diff --git a/mc_mitm/source/controllers/atari_controller.cpp b/mc_mitm/source/controllers/atari_controller.cpp new file mode 100644 index 0000000..f680b64 --- /dev/null +++ b/mc_mitm/source/controllers/atari_controller.cpp @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2020-2023 ndeadly + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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, see . + */ +#include "atari_controller.hpp" +#include + +namespace ams::controller { + + namespace { + + const constexpr float stick_scale_factor = float(UINT12_MAX) / UINT16_MAX; + + } + + void AtariController::ProcessInputData(const bluetooth::HidReport *report) { + auto atari_report = reinterpret_cast(&report->data); + + switch(atari_report->id) { + case 0x01: + this->MapInputReport0x01(atari_report); break; + case 0x02: + this->MapInputReport0x02(atari_report); break; + default: + break; + } + } + + void AtariController::MapInputReport0x01(const AtariReportData *src) { + m_left_stick.SetData( + static_cast( stick_scale_factor * src->input0x01.left_stick.x + 0x7ff) & UINT12_MAX, + static_cast(-stick_scale_factor * src->input0x01.left_stick.y + 0x7ff) & UINT12_MAX + ); + m_right_stick.SetData( + static_cast( stick_scale_factor * src->input0x01.right_stick.x + 0x7ff) & UINT12_MAX, + static_cast(-stick_scale_factor * src->input0x01.right_stick.y + 0x7ff) & UINT12_MAX + ); + + m_buttons.dpad_down = (src->input0x01.buttons.dpad == AtariDPad_S) || + (src->input0x01.buttons.dpad == AtariDPad_SE) || + (src->input0x01.buttons.dpad == AtariDPad_SW); + m_buttons.dpad_up = (src->input0x01.buttons.dpad == AtariDPad_N) || + (src->input0x01.buttons.dpad == AtariDPad_NE) || + (src->input0x01.buttons.dpad == AtariDPad_NW); + m_buttons.dpad_right = (src->input0x01.buttons.dpad == AtariDPad_E) || + (src->input0x01.buttons.dpad == AtariDPad_NE) || + (src->input0x01.buttons.dpad == AtariDPad_SE); + m_buttons.dpad_left = (src->input0x01.buttons.dpad == AtariDPad_W) || + (src->input0x01.buttons.dpad == AtariDPad_NW) || + (src->input0x01.buttons.dpad == AtariDPad_SW); + + m_buttons.A = src->input0x01.buttons.B; + m_buttons.B = src->input0x01.buttons.A; + m_buttons.X = src->input0x01.buttons.Y; + m_buttons.Y = src->input0x01.buttons.X; + + m_buttons.R = src->input0x01.buttons.RB; + m_buttons.L = src->input0x01.buttons.LB; + m_buttons.ZR = src->input0x01.right_trigger > (m_trigger_threshold * 0x3ff); + m_buttons.ZL = src->input0x01.left_trigger > (m_trigger_threshold * 0x3ff); + + m_buttons.lstick_press = src->input0x01.buttons.L3; + m_buttons.rstick_press = src->input0x01.buttons.R3; + + m_buttons.minus = src->input0x01.buttons.back; + m_buttons.plus = src->input0x01.buttons.menu; + + m_buttons.home = src->input0x01.buttons.home; + + + } + + void AtariController::MapInputReport0x02(const AtariReportData *src) { + AMS_UNUSED(src); + } + +} diff --git a/mc_mitm/source/controllers/atari_controller.hpp b/mc_mitm/source/controllers/atari_controller.hpp new file mode 100644 index 0000000..01d0b50 --- /dev/null +++ b/mc_mitm/source/controllers/atari_controller.hpp @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2020-2023 ndeadly + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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, see . + */ +#pragma once +#include "emulated_switch_controller.hpp" + +namespace ams::controller { + + enum AtariDPadDirection { + AtariDPad_Released, + AtariDPad_N, + AtariDPad_NE, + AtariDPad_E, + AtariDPad_SE, + AtariDPad_S, + AtariDPad_SW, + AtariDPad_W, + AtariDPad_NW, + }; + + struct AtariStickData { + s16 x; + s16 y; + } PACKED; + + struct AtariButtonData { + u8 A : 1; + u8 B : 1; + u8 X : 1; + u8 Y : 1; + u8 LB : 1; + u8 RB : 1; + u8 L3 : 1; + u8 R3 : 1; + + u8 back : 1; + u8 menu : 1; + u8 home : 1; + u8 : 1; + u8 dpad : 4; + } PACKED; + + struct AtariInputReport0x01 { + AtariButtonData buttons; + AtariStickData left_stick; + AtariStickData right_stick; + u16 left_trigger; + u16 right_trigger; + } PACKED; + + struct AtariInputReport0x02 { + + } PACKED; + + struct AtariReportData { + u8 id; + union { + AtariInputReport0x01 input0x01; + AtariInputReport0x02 input0x02; + }; + } PACKED; + + class AtariController final : public EmulatedSwitchController { + + public: + static constexpr const HardwareID hardware_ids[] = { + {0x3250, 0x1002} // Atari VCS Wireless Modern Controller + }; + + AtariController(const bluetooth::Address *address, HardwareID id) + : EmulatedSwitchController(address, id) { } + + void ProcessInputData(const bluetooth::HidReport *report) override; + + private: + void MapInputReport0x01(const AtariReportData *src); + void MapInputReport0x02(const AtariReportData *src); + + }; + +} diff --git a/mc_mitm/source/controllers/controller_management.cpp b/mc_mitm/source/controllers/controller_management.cpp index 2b4c9bd..db048dc 100644 --- a/mc_mitm/source/controllers/controller_management.cpp +++ b/mc_mitm/source/controllers/controller_management.cpp @@ -195,6 +195,12 @@ namespace ams::controller { } } + for (auto hwId : AtariController::hardware_ids) { + if ( (device->vid == hwId.vid) && (device->pid == hwId.pid) ) { + return ControllerType_Atari; + } + } + return ControllerType_Unknown; } @@ -293,6 +299,9 @@ namespace ams::controller { case ControllerType_Betop: controller = std::make_shared(address, id); break; + case ControllerType_Atari: + controller = std::make_shared(address, id); + break; default: controller = std::make_shared(address, id); break; diff --git a/mc_mitm/source/controllers/controller_management.hpp b/mc_mitm/source/controllers/controller_management.hpp index e8e3fae..41b32f7 100644 --- a/mc_mitm/source/controllers/controller_management.hpp +++ b/mc_mitm/source/controllers/controller_management.hpp @@ -41,6 +41,7 @@ #include "atgames_controller.hpp" #include "hyperkin_controller.hpp" #include "betop_controller.hpp" +#include "atari_controller.hpp" namespace ams::controller { @@ -72,6 +73,7 @@ namespace ams::controller { ControllerType_AtGames, ControllerType_Hyperkin, ControllerType_Betop, + ControllerType_Atari, ControllerType_Unknown, };