mc.mitm: add support for loading global module config ini at startup and overriding bluetooth adapter name and address

This commit is contained in:
ndeadly 2021-02-21 00:16:23 +01:00
parent d664c074fd
commit d5ddeaac36
15 changed files with 220 additions and 19 deletions

View file

@ -31,10 +31,13 @@ dist: all
mkdir -p dist/atmosphere/contents/$(MC_MITM_TID)/flags
touch dist/atmosphere/contents/$(MC_MITM_TID)/flags/boot2.flag
cp mc_mitm/toolbox.json dist/atmosphere/contents/$(MC_MITM_TID)/toolbox.json
cp -r exefs_patches dist/atmosphere/
mkdir -p dist/atmosphere/config_templates
cp mc_mitm/config.ini dist/atmosphere/config_templates/missioncontrol.ini
cd dist; zip -r $(PROJECT_NAME)-$(BUILD_VERSION).zip ./*; cd ../;

@ -1 +1 @@
Subproject commit 17960517bad5d2d07effb28b744ac8d907d571e0
Subproject commit bc08912dd31bb172467add8e24b4f0adac431939

11
mc_mitm/config.ini Normal file
View file

@ -0,0 +1,11 @@
[general]
; Enable vibration support for unofficial controllers
enable_rumble=true
; Enable motion controls support for unoffical controllers
enable_motion=true
[bluetooth]
; Override host name of Bluetooth adapter
host_name=Nintendo Switch!
; Override host mac address of Bluetooth adapter
host_address=04:20:69:04:20:69

View file

@ -35,12 +35,21 @@ namespace ams::bluetooth::core {
os::SystemEventType g_system_event_user_fwd;
os::EventType g_data_read_event;
os::Event g_enable_event(os::EventClearMode_ManualClear);
}
bool IsInitialized(void) {
return g_is_initialized;
}
void SignalEnabled(void) {
g_enable_event.Signal();
}
void WaitEnabled(void) {
g_enable_event.Wait();
}
os::SystemEventType *GetSystemEvent(void) {
return &g_system_event;
}

View file

@ -21,6 +21,8 @@
namespace ams::bluetooth::core {
bool IsInitialized(void);
void SignalEnabled(void);
void WaitEnabled(void);
os::SystemEventType *GetSystemEvent(void);
os::SystemEventType *GetForwardEvent(void);

View file

@ -62,7 +62,6 @@ namespace ams::mitm::bluetooth {
s32 g_btdrv_mitm_thread_priority = utils::ConvertToUserPriority(17);
void BtdrvMitmThreadFunction(void *arg) {
R_ABORT_UNLESS((g_server_manager.RegisterMitmServer<BtdrvMitmService>(PortIndex_BtdrvMitm, BtdrvMitmServiceName)));
g_server_manager.LoopProcess();
}

View file

@ -19,6 +19,7 @@
#include "bluetooth/bluetooth_core.hpp"
#include "bluetooth/bluetooth_hid.hpp"
#include "bluetooth/bluetooth_ble.hpp"
#include "../mcmitm_initialization.hpp"
#include "../controllers/controller_management.hpp"
#include <switch.h>
#include <cstring>
@ -40,6 +41,16 @@ namespace ams::mitm::bluetooth {
return ams::ResultSuccess();
}
Result BtdrvMitmService::EnableBluetooth(void) {
R_TRY(btdrvEnableBluetoothFwd(this->forward_service.get()));
ams::bluetooth::core::SignalEnabled();
// Wait until mc.mitm module initialisation has completed before returning
ams::mitm::WaitInitialized();
return ams::ResultSuccess();
}
Result BtdrvMitmService::FinalizeBluetooth(void) {
// Only btm should be able to make this call
if (this->client_info.program_id == ncm::SystemProgramId::Btm) {

View file

@ -19,6 +19,7 @@
#define AMS_BTDRV_MITM_INTERFACE_INFO(C, H) \
AMS_SF_METHOD_INFO(C, H, 1, Result, InitializeBluetooth, (sf::OutCopyHandle out_handle), (out_handle)) \
AMS_SF_METHOD_INFO(C, H, 2, Result, EnableBluetooth, (void), ()) \
AMS_SF_METHOD_INFO(C, H, 4, Result, FinalizeBluetooth, (void), ()) \
AMS_SF_METHOD_INFO(C, H, 15, Result, GetEventInfo, (sf::Out<ams::bluetooth::EventType> out_type, const sf::OutPointerBuffer &out_buffer), (out_type, out_buffer)) \
AMS_SF_METHOD_INFO(C, H, 16, Result, InitializeHid, (sf::OutCopyHandle out_handle, u16 version), (out_handle, version)) \
@ -58,6 +59,7 @@ namespace ams::mitm::bluetooth {
public:
Result InitializeBluetooth(sf::OutCopyHandle out_handle);
Result EnableBluetooth(void);
Result FinalizeBluetooth(void);
Result GetEventInfo(sf::Out<ams::bluetooth::EventType> out_type, const sf::OutPointerBuffer &out_buffer);
Result InitializeHid(sf::OutCopyHandle out_handle, u16 version);

View file

@ -23,6 +23,10 @@ Result btdrvInitializeBluetoothFwd(Service* srv, Handle *out_handle) {
);
}
Result btdrvEnableBluetoothFwd(Service* srv) {
return serviceMitmDispatch(srv, 2);
}
Result btdrvFinalizeBluetoothFwd(Service* srv) {
return serviceMitmDispatch(srv, 4);
}

View file

@ -21,6 +21,7 @@ extern "C" {
#endif
Result btdrvInitializeBluetoothFwd(Service* srv, Handle *out_handle);
Result btdrvEnableBluetoothFwd(Service* srv);
Result btdrvFinalizeBluetoothFwd(Service* srv);
Result btdrvInitializeHidFwd(Service* srv, Handle *out_handle, u16 version);
Result btdrvWriteHidDataFwd(Service* srv, const BtdrvAddress *address, const BtdrvHidReport *data);

View file

@ -0,0 +1,108 @@
/*
* Copyright (c) 2020-2021 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 <http://www.gnu.org/licenses/>.
*/
#include <stratosphere.hpp>
#include <cstring>
#include "mcmitm_config.hpp"
namespace ams::mitm {
namespace {
constexpr const char *config_file_location = "sdmc:/atmosphere/config/missioncontrol.ini";
MissionControlConfig g_global_config = {
.general = {
.enable_rumble = true,
.enable_motion = true
}
};
void ParseBoolean(const char *value, bool *out) {
if (strcasecmp(value, "true") == 0)
*out = true;
else if (strcasecmp(value, "false") == 0)
*out = false;
}
void ParseBluetoothAddress(const char *value, bluetooth::Address *out) {
// Check length of address string is correct
if (std::strlen(value) != 3*sizeof(bluetooth::Address) - 1) return;
// Parse bluetooth mac address
char buf[2 + 1];
bluetooth::Address address = {};
for (uint32_t i = 0; i < sizeof(bluetooth::Address); ++i) {
// Convert hex pair to number
std::memcpy(buf, &value[i*3], 2);
address.address[i] = static_cast<uint8_t>(std::strtoul(buf, nullptr, 16));
// Check for colon separator
if ((i < sizeof(bluetooth::Address) - 1) && (value[i*3 + 2] != ':'))
return;
}
*out = address;
}
int ConfigIniHandler(void *user, const char *section, const char *name, const char *value) {
auto config = reinterpret_cast<MissionControlConfig *>(user);
if (strcasecmp(section, "general") == 0) {
if (strcasecmp(name, "enable_rumble") == 0)
ParseBoolean(value, &config->general.enable_rumble);
else if (strcasecmp(name, "enable_motion") == 0)
ParseBoolean(value, &config->general.enable_motion);
}
else if (strcasecmp(section, "bluetooth") == 0) {
if (strcasecmp(name, "host_name") == 0)
std::strncpy(config->bluetooth.host_name, value, sizeof(config->bluetooth.host_name));
else if (strcasecmp(name, "host_address") == 0)
ParseBluetoothAddress(value, &config->bluetooth.host_address);
}
else {
return 0;
}
return 1;
}
}
MissionControlConfig *GetGlobalConfig(void) {
return &g_global_config;
}
void ParseIniConfig(void) {
const char *mount_name = "sdmc";
if (R_FAILED(fs::MountSdCard(mount_name))) {
return;
}
ON_SCOPE_EXIT { fs::Unmount(mount_name); };
/* Open the file. */
fs::FileHandle file;
{
if (R_FAILED(fs::OpenFile(std::addressof(file), config_file_location, fs::OpenMode_Read))) {
return;
}
}
ON_SCOPE_EXIT { fs::CloseFile(file); };
/* Parse the config. */
util::ini::ParseFile(file, &g_global_config, ConfigIniHandler);
}
}

View file

@ -0,0 +1,35 @@
/*
* Copyright (c) 2020-2021 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 <http://www.gnu.org/licenses/>.
*/
#include "bluetooth_mitm/bluetooth/bluetooth_types.hpp"
namespace ams::mitm {
struct MissionControlConfig {
struct {
bool enable_rumble;
bool enable_motion;
} general;
struct {
char host_name[0x20];
bluetooth::Address host_address;
} bluetooth;
};
MissionControlConfig *GetGlobalConfig(void);
void ParseIniConfig(void);
}

View file

@ -16,6 +16,8 @@
#include <stratosphere.hpp>
#include <switch.h>
#include "mcmitm_initialization.hpp"
#include "mcmitm_config.hpp"
#include "bluetooth_mitm/btdrv_mitm_service.hpp"
#include "bluetooth_mitm/bluetooth/bluetooth_events.hpp"
#include "bluetooth_mitm/bluetooth/bluetooth_core.hpp"
#include "bluetooth_mitm/bluetooth/bluetooth_hid.hpp"
@ -25,52 +27,67 @@ namespace ams::mitm {
namespace {
constexpr size_t InitializeThreadStackSize = 0x2000;
constexpr size_t InitializeThreadStackSize = 0x1000;
os::ThreadType g_initialize_thread;
alignas(os::ThreadStackAlignment) u8 g_initialize_thread_stack[InitializeThreadStackSize];
os::Event g_init_event(os::EventClearMode_ManualClear);
void WaitInterfacesInitialized(void) {
while (!(bluetooth::core::IsInitialized() && bluetooth::hid::IsInitialized() && (bluetooth::ble::IsInitialized() || (hos::GetVersion() < hos::Version_5_0_0)))) {
while (!(ams::bluetooth::core::IsInitialized() && ams::bluetooth::hid::IsInitialized() && (ams::bluetooth::ble::IsInitialized() || (hos::GetVersion() < hos::Version_5_0_0)))) {
svc::SleepThread(1'000'000ul);
}
}
void InitializeThreadFunc(void *arg) {
void InitializeThreadFunc(void *arg) {
// Wait for all bluetooth interfaces to be initialised
WaitInterfacesInitialized();
// Connect to btdrv service now that we're up and running
// Connect to btdrv service now that we're sure the mitm is up and running
sm::DoWithSession([&]() {
R_ABORT_UNLESS(btdrvInitialize());
});
// Start bluetooth event handling thread
bluetooth::events::Initialize();
ams::bluetooth::events::Initialize();
// Parse config ini
// Get global module settings
auto config = GetGlobalConfig();
// Set host name override
// Wait for system to call BluetoothEnable so the proceeding adapter properties aren't overwritten
ams::bluetooth::core::WaitEnabled();
// Set host address override
// Set bluetooth adapter host address override
ams::bluetooth::Address null_address = {};
if (std::memcmp(&config->bluetooth.host_address, &null_address, sizeof(ams::bluetooth::Address)) != 0) {
R_ABORT_UNLESS(btdrvSetAdapterProperty(BtdrvBluetoothPropertyType_Address, &config->bluetooth.host_address, sizeof(ams::bluetooth::Address)));
}
// Set bluetooth adapter host name override
if (std::strlen(config->bluetooth.host_name) > 0) {
R_ABORT_UNLESS(btdrvSetAdapterProperty(BtdrvBluetoothPropertyType_Name, config->bluetooth.host_name, std::strlen(config->bluetooth.host_name)));
}
g_init_event.Signal();
}
}
void StartInitialize(void) {
R_ABORT_UNLESS(os::CreateThread(&g_initialize_thread,
InitializeThreadFunc,
nullptr,
g_initialize_thread_stack,
sizeof(g_initialize_thread_stack),
9
-7
));
os::StartThread(&g_initialize_thread);
}
void WaitInitialized(void) {
g_init_event.Wait();
}
}

View file

@ -18,5 +18,6 @@
namespace ams::mitm {
void StartInitialize(void);
void WaitInitialized(void);
}

View file

@ -16,6 +16,7 @@
#include <switch.h>
#include <stratosphere.hpp>
#include "mcmitm_initialization.hpp"
#include "mcmitm_config.hpp"
#include "bluetooth_mitm/bluetoothmitm_module.hpp"
#include "btm_mitm/btmmitm_module.hpp"
@ -73,16 +74,12 @@ void __appInit(void) {
R_ABORT_UNLESS(pmdmntInitialize());
R_ABORT_UNLESS(pminfoInitialize());
});
R_ABORT_UNLESS(fsdevMountSdmc());
}
void __appExit(void) {
btdrvExit();
pminfoExit();
pmdmntExit();
fsdevUnmountAll();
fsExit();
}
@ -101,7 +98,8 @@ void WaitModules(void) {
}
int main(int argc, char **argv) {
mitm::StartInitialize();
ams::mitm::ParseIniConfig();
ams::mitm::StartInitialize();
LaunchModules();
WaitModules();
return 0;