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 $@ diff --git a/mc_mitm/config.ini b/mc_mitm/config.ini index b9769b13..d62d5b0d 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 [default false] +;spoof_nso_as_pro_controller=false 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..fdcf6182 100644 --- a/mc_mitm/source/controllers/switch_controller.cpp +++ b/mc_mitm/source/controllers/switch_controller.cpp @@ -40,6 +40,27 @@ 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) { + if (vid == 0x057e && (pid == 0x2017 || pid == 0x2019 || pid == 0x201a)) + return true; + else return false; } Result LedsMaskToPlayerNumber(uint8_t led_mask, uint8_t *player_number) { @@ -67,7 +88,7 @@ namespace ams::controller { if (this->HasSetTsiDisableFlag()) m_settsi_supported = false; - return ams::ResultSuccess(); + return ams::ResultSuccess(); } bool SwitchController::HasSetTsiDisableFlag() { @@ -109,11 +130,57 @@ 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; + } + 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); + this->ApplyButtonCombos(&input_report->buttons); return bluetooth::hid::report::WriteHidDataReport(m_address, &m_input_report); } @@ -142,6 +209,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); } @@ -149,7 +238,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 +295,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..2a403625 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); @@ -358,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); 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; };