/* * Copyright (c) 2020-2022 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 #include "mcmitm_config.hpp" namespace ams::mitm { namespace { constexpr const char *config_file_location = "sdmc:/config/MissionControl/missioncontrol.ini"; SetLanguage g_system_language; MissionControlConfig g_global_config = { .general = { .enable_rumble = true, .enable_motion = true }, .misc = { .disable_dualshock4_lightbar = false, .disable_dualsense_lightbar = false, .disable_dualsense_player_leds = false, .dualsense_vibration_intensity = 4 } }; void ParseBoolean(const char *value, bool *out) { if (strcasecmp(value, "true") == 0) *out = true; else if (strcasecmp(value, "false") == 0) *out = false; } void ParseInt(const char *value, int *out, int min=INT_MIN, int max=INT_MAX) { int tmp = std::strtol(value, nullptr, 10); if ((tmp >= min) && (tmp <= max)) *out = tmp; } 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(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(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 if (strcasecmp(section, "misc") == 0) { if (strcasecmp(name, "disable_dualshock4_lightbar") == 0) ParseBoolean(value, &config->misc.disable_dualshock4_lightbar); else if (strcasecmp(name, "disable_dualsense_lightbar") == 0) ParseBoolean(value, &config->misc.disable_dualsense_lightbar); else if (strcasecmp(name, "disable_dualsense_player_leds") == 0) ParseBoolean(value, &config->misc.disable_dualsense_player_leds); else if (strcasecmp(name, "dualsense_vibration_intensity") == 0) ParseInt(value, &config->misc.dualsense_vibration_intensity, 1, 8); } else { return 0; } return 1; } } void ParseIniConfig() { /* 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); } void InitializeConfig() { ParseIniConfig(); R_ABORT_UNLESS(setInitialize()); ON_SCOPE_EXIT { setExit(); }; u64 language_code = 0; R_ABORT_UNLESS(setGetSystemLanguage(&language_code)); R_ABORT_UNLESS(setMakeLanguage(language_code, &g_system_language)); } MissionControlConfig *GetGlobalConfig() { return &g_global_config; } SetLanguage GetSystemLanguage() { return g_system_language; } }