Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
ndeadly committed Aug 19, 2021
2 parents 9547d51 + 0ebba1a commit 6fdc8ee
Show file tree
Hide file tree
Showing 55 changed files with 429 additions and 195 deletions.
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ dist: all
cp -r exefs_patches dist/atmosphere/

mkdir -p dist/config/MissionControl
mkdir -p dist/config/MissionControl/controllers
cp mc_mitm/config.ini dist/config/MissionControl/missioncontrol.ini.template

cd dist; zip -r $(PROJECT_NAME)-$(BUILD_VERSION).zip ./*; cd ../;
Expand Down
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ Use controllers from other consoles natively on your Nintendo Switch via Bluetoo
* Make use of native HOS menus for controller pairing, button remapping (firmware 10.0.0+) etc.
* Rumble support*
* Low input lag.
* File-based virtual controller memory allowing for data such as analog stick calibration to be stored and retrieved.
* Spoofing of host Bluetooth adapter name and address.
* `mc.mitm` module adds extension IPC commands that can be used to interact with the `bluetooth` process without interfering with the state of the system.

Expand All @@ -37,6 +38,7 @@ Use controllers from other consoles natively on your Nintendo Switch via Bluetoo
* __Sony DualShock4 Controller__
* __Sony Dualsense Controller__
* __Microsoft Xbox One S/X Controller (not to be confused with Series S/X controllers - these use Bluetooth LE, which isn't currently supported)__*
* __Microsoft Xbox Elite Wireless Controller Series 2__
* __NVidia Shield Controller__
* __Ouya Controller__
* __Gamestick Controller__
Expand All @@ -50,6 +52,7 @@ Use controllers from other consoles natively on your Nintendo Switch via Bluetoo
* __GameSir G3s__
* __GameSir G4s__
* __GameSir T1s__
* __GameSir T2a__
* __Hori Onyx__
* __8bitDo SN30 Pro Xbox Cloud Gaming Edition__
* __8BitDo ZERO (Most other 8BitDo controllers have a Switch mode available. May require firmware update)__
Expand Down Expand Up @@ -86,7 +89,7 @@ Mission Control runs as a background process and makes use of the system's nativ

Controllers that successfully pair but haven't been supported yet will display with red buttons on the `Controllers` menu to indicate their controls are not being mapped. Please open an issue to request support for such controllers.

Most native features *should* just work (with the exception of things like firmware update). If you find something that's broken please create an issue.
Most native features *should* just work (with the exception of things like firmware update). If you find something that's broken please open a support issue on this github page.

### Pairing controllers
The supported controllers each have their own methods to enter pairing/sync mode. Below are instructions on entering this mode for each supported type.
Expand Down Expand Up @@ -167,7 +170,6 @@ Below is a list of features I am currently working on or would like to look into
* Motion controls currently unsupported.
* Non-Switch controllers cannot be used to wake the system from sleep.
* Controllers using the Bluetooth LE (BLE) standard are currently not supported and will not connect to the system.
* Xbox One Elite V2 controllers cannot complete the pairing process with the console and in some cases cause it to crash. Without access to a physical controller there's not a lot I can do to debug the process.
* Xbox One, Wii/WiiU and (especially) some Dualshock v1 controllers can take some time to be detected and subsequently pair with the Console. Be patient and re-enter the sync mode of the controller several times if neccessary. Once synced, controllers should work as usual.
* ~~Xbox One button layout was changed at some point in a firmware update. Please ensure your controller firmware is up to date if you have issues with incorrect button mappings.~~ Both layouts are now supported.
* Reported controller battery levels may not be correct. I'm relying entirely on reverse engineering notes found on the internet for these. In many cases I don't own the controller and there is simply no information available, so these controllers will always show full battery. Any help in improving this is most welcome.
Expand Down Expand Up @@ -259,6 +261,7 @@ The resulting package can be installed as described above.
* __misson20000__ for his handy debug monitor [Twili](https://github.com/misson20000/twili) and IPC logger [Ilia](https://github.com/misson20000/ilia)
* __dekuNukem__, __CTCaer__, __shinyquagsire23__ and others for their work in reversing and documenting the switch controller communication protocol.
* __friedkeenan__ for helping to test Wii extension controller support.
* __DatenThielt__ for helping debug the bluetooth service remotely with his Xbox Elite Series 2 controller in order for me to develop patches to enable it to be successfully paired with the console.
* Everyone else over at the __ReSwitched__ discord server who helped answering technical questions.

### Support
Expand Down
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
16 changes: 12 additions & 4 deletions mc_mitm/source/bluetooth_mitm/bluetooth/bluetooth_core.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ namespace ams::bluetooth::core {
os::Event g_enable_event(os::EventClearMode_ManualClear);
os::Event g_data_read_event(os::EventClearMode_AutoClear);

bluetooth::Address ReverseBluetoothAddress(bluetooth::Address address) {
uint64_t tmp = util::SwapBytes48(*reinterpret_cast<uint64_t *>(&address));
return *reinterpret_cast<bluetooth::Address *>(&tmp);
}

}

bool IsInitialized() {
Expand Down Expand Up @@ -150,8 +155,9 @@ namespace ams::bluetooth::core {
// Fetch host adapter address
bluetooth::Address host_address;
R_ABORT_UNLESS(btdrvLegacyGetAdapterProperty(BtdrvBluetoothPropertyType_Address, &host_address, sizeof(bluetooth::Address)));
// Reverse host address
*reinterpret_cast<uint64_t *>(&pin) = util::SwapBytes(*reinterpret_cast<uint64_t *>(&host_address)) >> 16;

// Set reversed bluetooth address as pin code
*reinterpret_cast<bluetooth::Address *>(&pin) = ReverseBluetoothAddress(host_address);
pin_length = sizeof(bluetooth::Address);
}

Expand All @@ -167,9 +173,11 @@ namespace ams::bluetooth::core {
// Fetch host adapter address
BtdrvAdapterProperty property;
R_ABORT_UNLESS(btdrvGetAdapterProperty(BtdrvAdapterPropertyType_Address, &property));
// Reverse host address

bluetooth::Address host_address = *reinterpret_cast<bluetooth::Address *>(property.data);
*reinterpret_cast<uint64_t *>(&pin.code) = util::SwapBytes(*reinterpret_cast<uint64_t *>(&host_address)) >> 16;

// Set reversed bluetooth address as pin code
*reinterpret_cast<bluetooth::Address *>(&pin.code) = ReverseBluetoothAddress(host_address);
pin.length = sizeof(bluetooth::Address);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
#include "bluetooth_circular_buffer.hpp"
#include "../btdrv_shim.h"
#include "../btdrv_mitm_flags.hpp"
#include "../../mcmitm_utils.hpp"
#include "../../utils.hpp"
#include "../../controllers/controller_management.hpp"
#include <mutex>
#include <cstring>
Expand All @@ -30,7 +30,7 @@ namespace ams::bluetooth::hid::report {

os::ThreadType g_event_handler_thread;
alignas(os::ThreadStackAlignment) uint8_t g_event_handler_thread_stack[0x1000];
s32 g_event_handler_thread_priority = mitm::utils::ConvertToUserPriority(17);
s32 g_event_handler_thread_priority = utils::ConvertToUserPriority(17);

// This is only required on fw < 7.0.0
bluetooth::HidReportEventInfo g_event_info;
Expand Down
2 changes: 1 addition & 1 deletion mc_mitm/source/bluetooth_mitm/bluetoothmitm_module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
*/
#include "bluetoothmitm_module.hpp"
#include "btdrv_mitm_service.hpp"
#include "../mcmitm_utils.hpp"
#include "../utils.hpp"
#include <stratosphere.hpp>

namespace ams::mitm::bluetooth {
Expand Down
2 changes: 1 addition & 1 deletion mc_mitm/source/btm_mitm/btmmitm_module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
*/
#include "btmmitm_module.hpp"
#include "btm_mitm_service.hpp"
#include "../mcmitm_utils.hpp"
#include "../utils.hpp"
#include <stratosphere.hpp>

namespace ams::mitm::btm {
Expand Down
12 changes: 7 additions & 5 deletions mc_mitm/source/controllers/8bitdo_controller.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ namespace ams::controller {
EightBitDoButtonDataV1 buttons;
} __attribute__((packed));

struct EightBitDoReportData{
struct EightBitDoReportData {
uint8_t id;
union {
EightBitDoInputReport0x01V1 input0x01_v1;
Expand All @@ -139,19 +139,21 @@ namespace ams::controller {
class EightBitDoController : public EmulatedSwitchController {

public:
static constexpr const HardwareID hardware_ids[] = {
static constexpr const HardwareID hardware_ids[] = {
{0x05a0, 0x3232}, // 8BitDo Zero
{0x2dc8, 0x2100} // 8BitDo SN30 Pro for Xbox Cloud Gaming
};

EightBitDoController(const bluetooth::Address *address)
: EmulatedSwitchController(address) { };
EightBitDoController(const bluetooth::Address *address, HardwareID id)
: EmulatedSwitchController(address, id) { }

bool SupportsSetTsiCommand(void) { return !((m_id.vid == 0x05a0) && (m_id.pid == 0x3232)); }

void UpdateControllerState(const bluetooth::HidReport *report);

private:
void HandleInputReport0x01(const EightBitDoReportData *src, EightBitDoReportFormat fmt);
void HandleInputReport0x03(const EightBitDoReportData *src, EightBitDoReportFormat);
void HandleInputReport0x03(const EightBitDoReportData *src, EightBitDoReportFormat fmt);

};

Expand Down
10 changes: 5 additions & 5 deletions mc_mitm/source/controllers/atgames_controller.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ namespace ams::controller {

} __attribute__((packed));

struct AtGamesReportData{
struct AtGamesReportData {
uint8_t id;
union {
AtGamesInputReport0x01 input0x01;
Expand All @@ -68,12 +68,12 @@ namespace ams::controller {
class AtGamesController : public EmulatedSwitchController {

public:
static constexpr const HardwareID hardware_ids[] = {
static constexpr const HardwareID hardware_ids[] = {
{0x1d6b, 0x0246}, // AtGames Legends Pinball
};
};

AtGamesController(const bluetooth::Address *address)
: EmulatedSwitchController(address) { };
AtGamesController(const bluetooth::Address *address, HardwareID id)
: EmulatedSwitchController(address, id) { }

void UpdateControllerState(const bluetooth::HidReport *report);

Expand Down
54 changes: 28 additions & 26 deletions mc_mitm/source/controllers/controller_management.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -193,79 +193,81 @@ namespace ams::controller {
void AttachHandler(const bluetooth::Address *address) {
std::scoped_lock lk(g_controller_lock);

bluetooth::DevicesSettings device;
R_ABORT_UNLESS(btdrvGetPairedDeviceInfo(*address, &device));
bluetooth::DevicesSettings device_settings;
R_ABORT_UNLESS(btdrvGetPairedDeviceInfo(*address, &device_settings));

switch (Identify(&device)) {
HardwareID id = { device_settings.vid, device_settings.pid };

switch (Identify(&device_settings)) {
case ControllerType_Switch:
g_controllers.push_back(std::make_unique<SwitchController>(address));
g_controllers.push_back(std::make_unique<SwitchController>(address, id));
break;
case ControllerType_Wii:
g_controllers.push_back(std::make_unique<WiiController>(address));
g_controllers.push_back(std::make_unique<WiiController>(address, id));
break;
case ControllerType_Dualshock4:
g_controllers.push_back(std::make_unique<Dualshock4Controller>(address));
g_controllers.push_back(std::make_unique<Dualshock4Controller>(address, id));
break;
case ControllerType_Dualsense:
g_controllers.push_back(std::make_unique<DualsenseController>(address));
g_controllers.push_back(std::make_unique<DualsenseController>(address, id));
break;
case ControllerType_XboxOne:
g_controllers.push_back(std::make_unique<XboxOneController>(address));
g_controllers.push_back(std::make_unique<XboxOneController>(address, id));
break;
case ControllerType_Ouya:
g_controllers.push_back(std::make_unique<OuyaController>(address));
g_controllers.push_back(std::make_unique<OuyaController>(address, id));
break;
case ControllerType_Gamestick:
g_controllers.push_back(std::make_unique<GamestickController>(address));
g_controllers.push_back(std::make_unique<GamestickController>(address, id));
break;
case ControllerType_Gembox:
g_controllers.push_back(std::make_unique<GemboxController>(address));
g_controllers.push_back(std::make_unique<GemboxController>(address, id));
break;
case ControllerType_Ipega:
g_controllers.push_back(std::make_unique<IpegaController>(address));
g_controllers.push_back(std::make_unique<IpegaController>(address, id));
break;
case ControllerType_Xiaomi:
g_controllers.push_back(std::make_unique<XiaomiController>(address));
g_controllers.push_back(std::make_unique<XiaomiController>(address, id));
break;
case ControllerType_Gamesir:
g_controllers.push_back(std::make_unique<GamesirController>(address));
g_controllers.push_back(std::make_unique<GamesirController>(address, id));
break;
case ControllerType_Steelseries:
g_controllers.push_back(std::make_unique<SteelseriesController>(address));
g_controllers.push_back(std::make_unique<SteelseriesController>(address, id));
break;
case ControllerType_NvidiaShield:
g_controllers.push_back(std::make_unique<NvidiaShieldController>(address));
g_controllers.push_back(std::make_unique<NvidiaShieldController>(address, id));
break;
case ControllerType_8BitDo:
g_controllers.push_back(std::make_unique<EightBitDoController>(address));
g_controllers.push_back(std::make_unique<EightBitDoController>(address, id));
break;
case ControllerType_PowerA:
g_controllers.push_back(std::make_unique<PowerAController>(address));
g_controllers.push_back(std::make_unique<PowerAController>(address, id));
break;
case ControllerType_MadCatz:
g_controllers.push_back(std::make_unique<MadCatzController>(address));
g_controllers.push_back(std::make_unique<MadCatzController>(address, id));
break;
case ControllerType_Mocute:
g_controllers.push_back(std::make_unique<MocuteController>(address));
g_controllers.push_back(std::make_unique<MocuteController>(address, id));
break;
case ControllerType_Razer:
g_controllers.push_back(std::make_unique<RazerController>(address));
g_controllers.push_back(std::make_unique<RazerController>(address, id));
break;
case ControllerType_ICade:
g_controllers.push_back(std::make_unique<ICadeController>(address));
g_controllers.push_back(std::make_unique<ICadeController>(address, id));
break;
case ControllerType_LanShen:
g_controllers.push_back(std::make_unique<LanShenController>(address));
g_controllers.push_back(std::make_unique<LanShenController>(address, id));
break;
case ControllerType_AtGames:
g_controllers.push_back(std::make_unique<AtGamesController>(address));
g_controllers.push_back(std::make_unique<AtGamesController>(address, id));
break;
default:
g_controllers.push_back(std::make_unique<UnknownController>(address));
g_controllers.push_back(std::make_unique<UnknownController>(address, id));
break;
}

g_controllers.back()->Initialize();
R_ABORT_UNLESS(g_controllers.back()->Initialize());
}

void RemoveHandler(const bluetooth::Address *address) {
Expand Down
8 changes: 4 additions & 4 deletions mc_mitm/source/controllers/controller_management.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,18 +69,18 @@ namespace ams::controller {
ControllerType_Unknown,
};

class UnknownController : public EmulatedSwitchController{
class UnknownController : public EmulatedSwitchController {
public:
UnknownController(const bluetooth::Address *address)
: EmulatedSwitchController(address) {
UnknownController(const bluetooth::Address *address, HardwareID id)
: EmulatedSwitchController(address, id) {
m_colours.buttons = {0xff, 0x00, 0x00};
};
};

ControllerType Identify(const bluetooth::DevicesSettings *device);
bool IsAllowedDeviceClass(const bluetooth::DeviceClass *cod);
bool IsOfficialSwitchControllerName(const std::string& name);

void AttachHandler(const bluetooth::Address *address);
void RemoveHandler(const bluetooth::Address *address);
SwitchController *LocateHandler(const bluetooth::Address *address);
Expand Down
17 changes: 9 additions & 8 deletions mc_mitm/source/controllers/dualsense_controller.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ namespace ams::controller {
uint8_t amp_motor_right;
} __attribute__((packed));

struct DualsenseOutputReport0x31 {
struct DualsenseOutputReport0x31 {
struct {
uint8_t data[75];
};
Expand Down Expand Up @@ -110,15 +110,15 @@ namespace ams::controller {
class DualsenseController : public EmulatedSwitchController {

public:
static constexpr const HardwareID hardware_ids[] = {
static constexpr const HardwareID hardware_ids[] = {
{0x054c, 0x0ce6} // Sony Dualsense Controller
};
};

DualsenseController(const bluetooth::Address *address)
: EmulatedSwitchController(address)
, m_led_flags(0)
, m_led_colour({0, 0, 0})
, m_rumble_state({0, 0}) { };
DualsenseController(const bluetooth::Address *address, HardwareID id)
: EmulatedSwitchController(address, id)
, m_led_flags(0)
, m_led_colour({0, 0, 0})
, m_rumble_state({0, 0}) { }

Result Initialize(void);
Result SetVibration(const SwitchRumbleData *rumble_data);
Expand All @@ -140,4 +140,5 @@ namespace ams::controller {
RGBColour m_led_colour;
DualsenseRumbleData m_rumble_state;
};

}
Loading

0 comments on commit 6fdc8ee

Please sign in to comment.