From 2040e0d300252163be3b588f3ea2a4318dd0593e Mon Sep 17 00:00:00 2001 From: ndeadly <24677491+ndeadly@users.noreply.github.com> Date: Tue, 3 May 2022 19:10:48 +0200 Subject: [PATCH 1/6] Update bug report template and readme --- .github/ISSUE_TEMPLATE/bug_report.yaml | 6 ++++-- README.md | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml index a3bc21c5..76d13939 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yaml +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -12,7 +12,8 @@ body: label: Switch Firmware Version description: Which Nintendo Switch firmware (HOS) version are you running? options: - - 14.1.0 (Latest) + - 14.1.1 (Latest) + - 14.1.0 - 14.0.0 - 13.2.1 - 13.2.0 @@ -34,7 +35,8 @@ body: label: Atmosphère Version description: Which version of Atmosphère are you using? options: - - 1.3.1 (Latest) + - 1.3.2 (Latest) + - 1.3.1 - 1.3.0 - 1.2.6 - 1.2.5 diff --git a/README.md b/README.md index f4ef3c90..c6221445 100644 --- a/README.md +++ b/README.md @@ -118,7 +118,7 @@ A template for the config .ini file will be installed to `/config/MissionControl - `[general]` These are general settings for mission control features. - `enable_rumble` Enables/disables rumble support for unofficial controllers. - - `enable_motion` Enables/disables motion controls support. Not currently used + - `enable_motion` Enables/disables motion controls support. - `[bluetooth]` These settings can be used to spoof your switch bluetooth to appear as another device. This may be useful (in conjunction with a link key) if you want to use your controller across multiple devices without having to re-pair every time you switch. Note that changing these settings will invalidate your console information stored in any previously paired controllers and will require re-pairing. From b076bc2cc40824140b94fa106ba186c1bc8b7e39 Mon Sep 17 00:00:00 2001 From: Carter Dewey Date: Wed, 2 Nov 2022 04:13:38 -0400 Subject: [PATCH 2/6] More cross-platform mcmitm_version.cpp target (#532) --- Makefile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 139486a4..7ae7d778 100644 --- a/Makefile +++ b/Makefile @@ -5,15 +5,16 @@ GIT_BRANCH := $(shell git symbolic-ref --short HEAD | sed s/[^a-zA-Z0-9_-]/_/g) GIT_HASH := $(shell git rev-parse --short HEAD) GIT_TAG := $(shell git describe --tags `git rev-list --tags --max-count=1`) -VERSION := $(shell [[ $(GIT_TAG) =~ ^v([0-9]+).([0-9]+).([0-9]+) ]] && printf '0x%02X%02X%02X' $${BASH_REMATCH[1]} $${BASH_REMATCH[2]} $${BASH_REMATCH[3]}) +VERSION := $(shell printf "0x%02X%02X%02X" $(shell echo "$(GIT_TAG)" | sed -E 's/^v([0-9]+).([0-9]+).([0-9]+)/\1 \2 \3/g')) BUILD_VERSION := $(GIT_TAG:v%=%)-$(GIT_BRANCH)-$(GIT_HASH) +BUILD_DATE := $(shell date) TARGETS := mcmitm_version.cpp mc_mitm all: $(TARGETS) mcmitm_version.cpp: .git/HEAD .git/index - echo "namespace ams::mitm { unsigned int mc_version = $(VERSION); const char *mc_build_name = \"$(BUILD_VERSION)\"; const char *mc_build_date = \"$$(date)\"; }" > mc_mitm/source/$@ + echo "namespace ams::mitm { unsigned int mc_version = $(VERSION); const char *mc_build_name = \"$(BUILD_VERSION)\"; const char *mc_build_date = \"$(BUILD_DATE)\"; }" > mc_mitm/source/$@ mc_mitm: $(MAKE) -C $@ From 2a320cbcb05c479011ecbc945d6890658a0d0dce Mon Sep 17 00:00:00 2001 From: Banz99 <42299919+Banz99@users.noreply.github.com> Date: Wed, 2 Nov 2022 22:19:23 +0100 Subject: [PATCH 3/6] Add PID and GetDeviceInfo's response type spoofing for NSO controllers. --- mc_mitm/config.ini | 2 ++ mc_mitm/source/btm_mitm/btm_mitm_service.cpp | 8 ++++++++ .../source/controllers/switch_controller.cpp | 17 +++++++++++++---- .../source/controllers/switch_controller.hpp | 1 + mc_mitm/source/mcmitm_config.cpp | 11 +++++++---- mc_mitm/source/mcmitm_config.hpp | 1 + 6 files changed, 32 insertions(+), 8 deletions(-) diff --git a/mc_mitm/config.ini b/mc_mitm/config.ini index b9769b13..c0017c62 100644 --- a/mc_mitm/config.ini +++ b/mc_mitm/config.ini @@ -19,3 +19,5 @@ ;enable_dualsense_player_leds=false ; Set Dualsense vibration intensity, 12.5% per increment. Valid range [1-8] where 1=12.5%, 8=100% [default 4(50%)] ;dualsense_vibration_intensity=4 +; Change the controller type reported by NSO controllers, allowing to be completely remapped as valid pro controllers +;spoof_nso_as_pro_controller=true diff --git a/mc_mitm/source/btm_mitm/btm_mitm_service.cpp b/mc_mitm/source/btm_mitm/btm_mitm_service.cpp index 11720f7f..42c92581 100644 --- a/mc_mitm/source/btm_mitm/btm_mitm_service.cpp +++ b/mc_mitm/source/btm_mitm/btm_mitm_service.cpp @@ -16,6 +16,8 @@ #include "btm_mitm_service.hpp" #include "btm_shim.h" #include "../controllers/controller_management.hpp" +#include "../mcmitm_config.hpp" +#include "../controllers/switch_controller.hpp" namespace ams::mitm::btm { @@ -83,6 +85,9 @@ namespace ams::mitm::btm { if (!controller::IsOfficialSwitchControllerName(device->name.name)) { std::strncpy(device->name.name, controller::pro_controller_name, sizeof(device->name) - 1); } + else if (mitm::GetGlobalConfig()->misc.spoof_nso_as_pro_controller && ams::controller::IsNsoController(device->profile_info.hid_device_info.vid, device->profile_info.hid_device_info.pid)) { + device->profile_info.hid_device_info.pid = 0x2009; + } } return ams::ResultSuccess(); @@ -97,6 +102,9 @@ namespace ams::mitm::btm { if (!controller::IsOfficialSwitchControllerName(device->name)) { std::strncpy(device->name, controller::pro_controller_name, sizeof(device->name) - 1); } + else if (mitm::GetGlobalConfig()->misc.spoof_nso_as_pro_controller && ams::controller::IsNsoController(device->profile_info.hid_device_info.vid, device->profile_info.hid_device_info.pid)) { + device->profile_info.hid_device_info.pid = 0x2009; + } } return ams::ResultSuccess(); diff --git a/mc_mitm/source/controllers/switch_controller.cpp b/mc_mitm/source/controllers/switch_controller.cpp index 09de8650..b9118815 100644 --- a/mc_mitm/source/controllers/switch_controller.cpp +++ b/mc_mitm/source/controllers/switch_controller.cpp @@ -42,6 +42,12 @@ namespace ams::controller { } + bool IsNsoController(uint16_t vid, uint16_t pid) { + if (vid == 0x057e && (pid == 0x2017 || pid == 0x2019 || pid == 0x201a)) + return true; + else return false; + } + Result LedsMaskToPlayerNumber(uint8_t led_mask, uint8_t *player_number) { *player_number = led_player_mappings[led_mask & 0xf]; if (*player_number == SwitchPlayerNumber_Unknown) @@ -67,7 +73,7 @@ namespace ams::controller { if (this->HasSetTsiDisableFlag()) m_settsi_supported = false; - return ams::ResultSuccess(); + return ams::ResultSuccess(); } bool SwitchController::HasSetTsiDisableFlag() { @@ -111,9 +117,12 @@ namespace ams::controller { } } } + else if (input_report->type0x21.hid_command_response.id == HidCommand_GetDeviceInfo && mitm::GetGlobalConfig()->misc.spoof_nso_as_pro_controller && IsNsoController(m_id.vid, m_id.pid)) { + input_report->type0x21.hid_command_response.data.get_device_info.type = 0x03; + } } - this->ApplyButtonCombos(&input_report->buttons); + this->ApplyButtonCombos(&input_report->buttons); return bluetooth::hid::report::WriteHidDataReport(m_address, &m_input_report); } @@ -149,7 +158,7 @@ namespace ams::controller { return btdrvWriteHidData(m_address, report); } - Result SwitchController::WriteDataReport(const bluetooth::HidReport *report, uint8_t response_id, bluetooth::HidReport *out_report) { + Result SwitchController::WriteDataReport(const bluetooth::HidReport *report, uint8_t response_id, bluetooth::HidReport *out_report) { auto response = std::make_shared(BtdrvHidEventType_Data); response->SetUserData(response_id); m_future_responses.push(response); @@ -206,7 +215,7 @@ namespace ams::controller { } auto response_data = response->GetData(); - + Result result; const bluetooth::HidReport *get_report; if (hos::GetVersion() >= hos::Version_9_0_0) { diff --git a/mc_mitm/source/controllers/switch_controller.hpp b/mc_mitm/source/controllers/switch_controller.hpp index 44186a0b..0cbabafd 100644 --- a/mc_mitm/source/controllers/switch_controller.hpp +++ b/mc_mitm/source/controllers/switch_controller.hpp @@ -321,6 +321,7 @@ namespace ams::controller { } __attribute__ ((__packed__)); Result LedsMaskToPlayerNumber(uint8_t led_mask, uint8_t *player_number); + bool IsNsoController(uint16_t vid, uint16_t pid); std::string GetControllerDirectory(const bluetooth::Address *address); diff --git a/mc_mitm/source/mcmitm_config.cpp b/mc_mitm/source/mcmitm_config.cpp index e07e7078..a25fa9bb 100644 --- a/mc_mitm/source/mcmitm_config.cpp +++ b/mc_mitm/source/mcmitm_config.cpp @@ -33,7 +33,8 @@ namespace ams::mitm { .enable_dualshock4_lightbar = true, .enable_dualsense_lightbar = true, .enable_dualsense_player_leds = true, - .dualsense_vibration_intensity = 4 + .dualsense_vibration_intensity = 4, + .spoof_nso_as_pro_controller = false } }; @@ -41,7 +42,7 @@ namespace ams::mitm { if (strcasecmp(value, "true") == 0) *out = true; else if (strcasecmp(value, "false") == 0) - *out = false; + *out = false; } void ParseInt(const char *value, int *out, int min=INT_MIN, int max=INT_MAX) { @@ -75,9 +76,9 @@ namespace ams::mitm { if (strcasecmp(section, "general") == 0) { if (strcasecmp(name, "enable_rumble") == 0) - ParseBoolean(value, &config->general.enable_rumble); + ParseBoolean(value, &config->general.enable_rumble); else if (strcasecmp(name, "enable_motion") == 0) - ParseBoolean(value, &config->general.enable_motion); + ParseBoolean(value, &config->general.enable_motion); } else if (strcasecmp(section, "bluetooth") == 0) { if (strcasecmp(name, "host_name") == 0) @@ -94,6 +95,8 @@ namespace ams::mitm { ParseBoolean(value, &config->misc.enable_dualsense_player_leds); else if (strcasecmp(name, "dualsense_vibration_intensity") == 0) ParseInt(value, &config->misc.dualsense_vibration_intensity, 1, 8); + else if (strcasecmp(name, "spoof_nso_as_pro_controller") == 0) + ParseBoolean(value, &config->misc.spoof_nso_as_pro_controller); } else { return 0; diff --git a/mc_mitm/source/mcmitm_config.hpp b/mc_mitm/source/mcmitm_config.hpp index a9913b8a..fa9f7a9a 100644 --- a/mc_mitm/source/mcmitm_config.hpp +++ b/mc_mitm/source/mcmitm_config.hpp @@ -33,6 +33,7 @@ namespace ams::mitm { bool enable_dualsense_lightbar; bool enable_dualsense_player_leds; int dualsense_vibration_intensity; + bool spoof_nso_as_pro_controller; } misc; }; From 7d4f3a73cab89941a7932e7e26413358adc8468f Mon Sep 17 00:00:00 2001 From: Banz99 <42299919+Banz99@users.noreply.github.com> Date: Wed, 2 Nov 2022 23:41:45 +0100 Subject: [PATCH 4/6] Prevent SPI flash writes when emulating a Pro Controller Report default Pro controller color values to its request. --- .../source/controllers/switch_controller.cpp | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/mc_mitm/source/controllers/switch_controller.cpp b/mc_mitm/source/controllers/switch_controller.cpp index b9118815..3452bb04 100644 --- a/mc_mitm/source/controllers/switch_controller.cpp +++ b/mc_mitm/source/controllers/switch_controller.cpp @@ -115,10 +115,15 @@ namespace ams::controller { uint8_t data[] = {0xff, 0xd7, 0x00, 0x00, 0x57, 0xb7, 0x00, 0x57, 0xb7, 0x00, 0x57, 0xb7}; std::memcpy(input_report->type0x21.hid_command_response.data.serial_flash_read.data, data, sizeof(data)); } + else if (mitm::GetGlobalConfig()->misc.spoof_nso_as_pro_controller && IsNsoController(m_id.vid, m_id.pid)) { + uint8_t data[] = {0x32, 0x32, 0x32, 0xe6, 0xe6, 0xe6, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46}; + std::memcpy(input_report->type0x21.hid_command_response.data.serial_flash_read.data, data, sizeof(data)); + } } } else if (input_report->type0x21.hid_command_response.id == HidCommand_GetDeviceInfo && mitm::GetGlobalConfig()->misc.spoof_nso_as_pro_controller && IsNsoController(m_id.vid, m_id.pid)) { input_report->type0x21.hid_command_response.data.get_device_info.type = 0x03; + input_report->type0x21.hid_command_response.data.get_device_info._unk2 = 0x02; } } @@ -151,6 +156,28 @@ namespace ams::controller { } Result SwitchController::HandleOutputDataReport(const bluetooth::HidReport *report) { + auto output_report = reinterpret_cast(&report->data); + if (output_report->id == 0x01 && mitm::GetGlobalConfig()->misc.spoof_nso_as_pro_controller && IsNsoController(m_id.vid, m_id.pid) && (output_report->type0x01.hid_command.id == HidCommand_SerialFlashWrite || output_report->type0x01.hid_command.id == HidCommand_SerialFlashSectorErase)) { + SwitchInputReport input_report = { + .id = 0x21, + .timer = 1, + .conn_info = 1, + .battery = BATTERY_MAX, + .vibrator = 0, + }; + + input_report.type0x21.hid_command_response = { + .ack = 0x80, + .id = output_report->type0x01.hid_command.id, + .data = { + .serial_flash_write = { + .status = 0x1 //Force write protected response just to be safe + } + } + }; + + return bluetooth::hid::report::WriteHidDataReport(m_address, &m_input_report); + } return this->WriteDataReport(report); } From 28b28a90bfa14dff9adcb251ea38c30f81f970ae Mon Sep 17 00:00:00 2001 From: Banz99 <42299919+Banz99@users.noreply.github.com> Date: Thu, 3 Nov 2022 00:17:42 +0100 Subject: [PATCH 5/6] Fix wrong default value in config.ini --- mc_mitm/config.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mc_mitm/config.ini b/mc_mitm/config.ini index c0017c62..d62d5b0d 100644 --- a/mc_mitm/config.ini +++ b/mc_mitm/config.ini @@ -19,5 +19,5 @@ ;enable_dualsense_player_leds=false ; Set Dualsense vibration intensity, 12.5% per increment. Valid range [1-8] where 1=12.5%, 8=100% [default 4(50%)] ;dualsense_vibration_intensity=4 -; Change the controller type reported by NSO controllers, allowing to be completely remapped as valid pro controllers -;spoof_nso_as_pro_controller=true +; Change the controller type reported by NSO controllers, allowing to be completely remapped as valid pro controllers [default false] +;spoof_nso_as_pro_controller=false From 8a3dc149073fee25a6ca2074c845bfcdbc7f1384 Mon Sep 17 00:00:00 2001 From: Banz99 <42299919+Banz99@users.noreply.github.com> Date: Thu, 3 Nov 2022 10:33:50 +0100 Subject: [PATCH 6/6] Remap the NSO N64 controller in a more user friendly way when emulating a Pro Controller. --- .../source/controllers/switch_controller.cpp | 53 +++++++++++++++++++ .../source/controllers/switch_controller.hpp | 1 + 2 files changed, 54 insertions(+) diff --git a/mc_mitm/source/controllers/switch_controller.cpp b/mc_mitm/source/controllers/switch_controller.cpp index 3452bb04..fdcf6182 100644 --- a/mc_mitm/source/controllers/switch_controller.cpp +++ b/mc_mitm/source/controllers/switch_controller.cpp @@ -40,6 +40,21 @@ namespace ams::controller { SwitchPlayerNumber_Four, //1111 }; + + bool ApplyN64Remapping(SwitchButtonData *buttons) { + bool alternatescheme = buttons->Y; //C-Up + buttons->Y = buttons->ZR; //C-Down -> Y + buttons->ZR = buttons->rstick_press; //ZR -> ZR + buttons->rstick_press = 0; + if (alternatescheme) { + buttons->lstick_press = buttons->L; //L -> LEFT STICK PRESS + buttons->rstick_press = buttons->R; //R -> RIGHT STICK PRESS + buttons->L = 0; + buttons->R = 0; + } + return alternatescheme; + } + } bool IsNsoController(uint16_t vid, uint16_t pid) { @@ -125,6 +140,44 @@ namespace ams::controller { input_report->type0x21.hid_command_response.data.get_device_info.type = 0x03; input_report->type0x21.hid_command_response.data.get_device_info._unk2 = 0x02; } + else if (input_report->type0x21.hid_command_response.id == HidCommand_SerialFlashRead && mitm::GetGlobalConfig()->misc.spoof_nso_as_pro_controller && m_id.vid == 0x057e && m_id.pid == 0x2019) { + if (input_report->type0x21.hid_command_response.data.serial_flash_read.address == 0x603d) { //Factory calibration + input_report->type0x21.hid_command_response.data.serial_flash_read.data[0x9] = 0xFF - input_report->type0x21.hid_command_response.data.serial_flash_read.data[0x0]; + input_report->type0x21.hid_command_response.data.serial_flash_read.data[0xA] = 0xFF - input_report->type0x21.hid_command_response.data.serial_flash_read.data[0x1]; + input_report->type0x21.hid_command_response.data.serial_flash_read.data[0xB] = 0xFF - input_report->type0x21.hid_command_response.data.serial_flash_read.data[0x2]; + memcpy(&input_report->type0x21.hid_command_response.data.serial_flash_read.data[0xC], &input_report->type0x21.hid_command_response.data.serial_flash_read.data[0x3], 3); + input_report->type0x21.hid_command_response.data.serial_flash_read.data[0x10] = 0xFF - input_report->type0x21.hid_command_response.data.serial_flash_read.data[0x6]; + input_report->type0x21.hid_command_response.data.serial_flash_read.data[0x11] = 0xFF - input_report->type0x21.hid_command_response.data.serial_flash_read.data[0x7]; + input_report->type0x21.hid_command_response.data.serial_flash_read.data[0x12] = 0xFF - input_report->type0x21.hid_command_response.data.serial_flash_read.data[0x8]; + } + else if (input_report->type0x21.hid_command_response.data.serial_flash_read.address == 0x8010) { //User Calibration + if (input_report->type0x21.hid_command_response.data.serial_flash_read.data[0] != 0xFF && input_report->type0x21.hid_command_response.data.serial_flash_read.data[1] != 0xFF) { + input_report->type0x21.hid_command_response.data.serial_flash_read.data[0xB] = input_report->type0x21.hid_command_response.data.serial_flash_read.data[0]; + input_report->type0x21.hid_command_response.data.serial_flash_read.data[0xC] = input_report->type0x21.hid_command_response.data.serial_flash_read.data[0x1]; + input_report->type0x21.hid_command_response.data.serial_flash_read.data[0xD] = 0xFF - input_report->type0x21.hid_command_response.data.serial_flash_read.data[0x2]; + input_report->type0x21.hid_command_response.data.serial_flash_read.data[0xE] = 0xFF - input_report->type0x21.hid_command_response.data.serial_flash_read.data[0x3]; + input_report->type0x21.hid_command_response.data.serial_flash_read.data[0xF] = 0xFF - input_report->type0x21.hid_command_response.data.serial_flash_read.data[0x4]; + memcpy(&input_report->type0x21.hid_command_response.data.serial_flash_read.data[0x10], &input_report->type0x21.hid_command_response.data.serial_flash_read.data[0x5], 3); + input_report->type0x21.hid_command_response.data.serial_flash_read.data[0x13] = 0xFF - input_report->type0x21.hid_command_response.data.serial_flash_read.data[0x8]; + input_report->type0x21.hid_command_response.data.serial_flash_read.data[0x14] = 0xFF - input_report->type0x21.hid_command_response.data.serial_flash_read.data[0x9]; + input_report->type0x21.hid_command_response.data.serial_flash_read.data[0x15] = 0xFF - input_report->type0x21.hid_command_response.data.serial_flash_read.data[0xA]; + } + } + else if (input_report->type0x21.hid_command_response.data.serial_flash_read.address == 0x6080) { //Copy left stick parameters + memcpy(&m_n64_left_stick_param, &input_report->type0x21.hid_command_response.data.serial_flash_read.data[0x6],sizeof(SwitchAnalogStickParameters)); + } + else if (input_report->type0x21.hid_command_response.data.serial_flash_read.address == 0x6098) { //Paste left stick parameters on top of the right one (all 0XFF because there isn't one) + memcpy(&input_report->type0x21.hid_command_response.data.serial_flash_read.data, &m_n64_left_stick_param, sizeof(SwitchAnalogStickParameters)); + } + } + } + + if (mitm::GetGlobalConfig()->misc.spoof_nso_as_pro_controller && m_id.vid == 0x057e && m_id.pid == 0x2019) { + if (ApplyN64Remapping(&input_report->buttons)) { + input_report->right_stick.SetData(input_report->left_stick.GetX(), input_report->left_stick.GetY()); + input_report->left_stick.SetData(STICK_ZERO, STICK_ZERO); + } + else input_report->right_stick.SetData(STICK_ZERO, STICK_ZERO); } this->ApplyButtonCombos(&input_report->buttons); diff --git a/mc_mitm/source/controllers/switch_controller.hpp b/mc_mitm/source/controllers/switch_controller.hpp index 0cbabafd..2a403625 100644 --- a/mc_mitm/source/controllers/switch_controller.hpp +++ b/mc_mitm/source/controllers/switch_controller.hpp @@ -359,6 +359,7 @@ namespace ams::controller { virtual Result HandleOutputDataReport(const bluetooth::HidReport *report); private: bool HasSetTsiDisableFlag(); + SwitchAnalogStickParameters m_n64_left_stick_param; protected: Result WriteDataReport(const bluetooth::HidReport *report);