diff --git a/source/Sysmodule/source/config_handler.cpp b/source/Sysmodule/source/config_handler.cpp new file mode 100644 index 0000000..6272a30 --- /dev/null +++ b/source/Sysmodule/source/config_handler.cpp @@ -0,0 +1,322 @@ +#include "switch.h" +#include "config_handler.h" +#include "Controllers.h" +#include "ControllerConfig.h" +#include "log.h" +#include "ini.h" +#include +#include +#include "usb_module.h" + +namespace syscon::config +{ + namespace + { + ControllerConfig tempConfig; + GlobalConfig tempGlobalConfig; + RGBAColor tempColor; + char firmwarePath[100]; + + UTimer filecheckTimer; + Waiter filecheckTimerWaiter = waiterForUTimer(&filecheckTimer); + + void ConfigChangedCheckThreadFunc(void *arg); + + ams::os::StaticThread<0x2'000> g_config_changed_check_thread(&ConfigChangedCheckThreadFunc, nullptr, 0x3F); + + bool is_config_changed_check_thread_running = false; + + constexpr const char *keyNames[NUM_CONTROLLERBUTTONS] + { + "FACE_UP", + "FACE_RIGHT", + "FACE_DOWN", + "FACE_LEFT", + "LSTICK_CLICK", + "RSTICK_CLICK", + "LEFT_BUMPER", + "RIGHT_BUMPER", + "LEFT_TRIGGER", + "RIGHT_TRIGGER", + "BACK", + "START", + "DPAD_UP", + "DPAD_RIGHT", + "DPAD_DOWN", + "DPAD_LEFT", + "SYNC", + "GUIDE", + "TOUCHPAD", + }; + + ControllerButton StringToKey(const char *text) + { + for (int i = 0; i != NUM_CONTROLLERBUTTONS; ++i) + { + if (strcmp(keyNames[i], text) == 0) + { + return static_cast(i); + } + } + return NOT_SET; + } + + RGBAColor DecodeColorValue(const char *value) + { + RGBAColor color{255}; + uint8_t counter = 0; + int charIndex = 0; + while (value[charIndex] != '\0') + { + if (charIndex == 0) + color.values[counter++] = atoi(value + charIndex++); + if (value[charIndex++] == ',') + { + color.values[counter++] = atoi(value + charIndex); + if (counter == 4) + break; + } + } + return color; + } + + int ParseConfigLine(void *dummy, const char *section, const char *name, const char *value) + { + if (strcmp(section, "global") == 0) + { + if (strcmp(name, "use_dualshock_2nd_generation") == 0) + { + tempGlobalConfig.dualshock4_productID = (strcmp(value, "true") ? PRODUCT_DUALSHOCK4_1X : PRODUCT_DUALSHOCK4_2X); + return 1; + } + } + else + { + if (strncmp(name, "key_", 4) == 0) + { + ControllerButton button = StringToKey(name + 4); + ControllerButton buttonValue = StringToKey(value); + tempConfig.buttons[button] = buttonValue; + tempConfig.buttons[buttonValue] = button; + return 1; + } + else if (strcmp(name, "left_stick_deadzone") == 0) + { + tempConfig.leftStickDeadzonePercent = atoi(value); + return 1; + } + else if (strcmp(name, "right_stick_deadzone") == 0) + { + tempConfig.rightStickDeadzonePercent = atoi(value); + return 1; + } + else if (strcmp(name, "left_stick_rotation") == 0) + { + tempConfig.leftStickRotationDegrees = atoi(value); + return 1; + } + else if (strcmp(name, "right_stick_rotation") == 0) + { + tempConfig.rightStickRotationDegrees = atoi(value); + return 1; + } + else if (strcmp(name, "trigger_deadzone") == 0) + { + tempConfig.triggerDeadzonePercent = atoi(value); + return 1; + } + else if (strcmp(name, "swap_dpad_and_lstick") == 0) + { + tempConfig.swapDPADandLSTICK = (strcmp(value, "true") ? false : true); + return 1; + } + else if (strcmp(name, "firmware_path") == 0) + { + strcpy(firmwarePath, value); + return 1; + } + else if (strncmp(name, "color_", 6) == 0) + { + if (strcmp(name + 6, "body") == 0) + { + tempConfig.bodyColor = DecodeColorValue(value); + return 1; + } + else if (strcmp(name + 6, "buttons") == 0) + { + tempConfig.buttonsColor = DecodeColorValue(value); + return 1; + } + else if (strcmp(name + 6, "leftGrip") == 0) + { + tempConfig.leftGripColor = DecodeColorValue(value); + return 1; + } + else if (strcmp(name + 6, "rightGrip") == 0) + { + tempConfig.rightGripColor = DecodeColorValue(value); + return 1; + } + else if (strcmp(name + 6, "led") == 0) + { + tempColor = DecodeColorValue(value); + return 1; + } + } + } + + return 0; + } + + Result ReadFromConfig(const char *path) + { + tempConfig = ControllerConfig{}; + for (int i = 0; i != NUM_CONTROLLERBUTTONS; ++i) + { + tempConfig.buttons[i] = NOT_SET; + } + return ini_parse(path, ParseConfigLine, NULL); + } + + + void ConfigChangedCheckThreadFunc(void *arg) + { + while (is_config_changed_check_thread_running) + { + if (R_SUCCEEDED(waitSingle(filecheckTimerWaiter, 0))) + { + if (config::CheckForFileChanges()) + { + WriteToLog("File check succeeded! Loading configs..."); + config::LoadAllConfigs(); + usb::ReloadDualshock4Event(); + } + } + } + } + } + + void LoadGlobalConfig(const GlobalConfig &config) + { + config::globalConfig = config; + } + + void LoadAllConfigs() + { + if (R_SUCCEEDED(ReadFromConfig(GLOBALCONFIG))) + { + LoadGlobalConfig(tempGlobalConfig); + } + else + WriteToLog("Failed to read from global config!"); + + if (R_SUCCEEDED(ReadFromConfig(XBOXCONFIG))) + { + XboxController::LoadConfig(&tempConfig); + } + else + WriteToLog("Failed to read from xbox orig config!"); + + if (R_SUCCEEDED(ReadFromConfig(XBOXONECONFIG))) + XboxOneController::LoadConfig(&tempConfig); + else + WriteToLog("Failed to read from xbox one config!"); + + if (R_SUCCEEDED(ReadFromConfig(XBOX360CONFIG))) + { + Xbox360Controller::LoadConfig(&tempConfig); + Xbox360WirelessController::LoadConfig(&tempConfig); + } + else + WriteToLog("Failed to read from xbox 360 config!"); + + if (R_SUCCEEDED(ReadFromConfig(DUALSHOCK3CONFIG))) + Dualshock3Controller::LoadConfig(&tempConfig); + else + WriteToLog("Failed to read from dualshock 3 config!"); + + if (R_SUCCEEDED(ReadFromConfig(DUALSHOCK4CONFIG))) + Dualshock4Controller::LoadConfig(&tempConfig, tempColor); + else + WriteToLog("Failed to read from dualshock 4 config!"); + } + bool CheckForFileChanges() + { + static u64 globalConfigLastModified; + static u64 xboxConfigLastModified; + static u64 xbox360ConfigLastModified; + static u64 xboxOneConfigLastModified; + static u64 dualshock3ConfigLastModified; + static u64 dualshock4ConfigLastModified; + + // Maybe this should be called only once when initializing? + // I left it here in case this would cause issues when ejecting the SD card + FsFileSystem *fs = fsdevGetDeviceFileSystem("sdmc"); + + if (fs == nullptr) + return false; + + bool filesChanged = false; + FsTimeStampRaw timestamp; + + if (R_SUCCEEDED(fsFsGetFileTimeStampRaw(fs, GLOBALCONFIG, ×tamp))) + if (globalConfigLastModified != timestamp.modified) + { + globalConfigLastModified = timestamp.modified; + filesChanged = true; + } + + if (R_SUCCEEDED(fsFsGetFileTimeStampRaw(fs, XBOXCONFIG, ×tamp))) + if (xboxConfigLastModified != timestamp.modified) + { + xboxConfigLastModified = timestamp.modified; + filesChanged = true; + } + + if (R_SUCCEEDED(fsFsGetFileTimeStampRaw(fs, XBOX360CONFIG, ×tamp))) + if (xbox360ConfigLastModified != timestamp.modified) + { + xbox360ConfigLastModified = timestamp.modified; + filesChanged = true; + } + + if (R_SUCCEEDED(fsFsGetFileTimeStampRaw(fs, XBOXONECONFIG, ×tamp))) + if (xboxOneConfigLastModified != timestamp.modified) + { + xboxOneConfigLastModified = timestamp.modified; + filesChanged = true; + } + + if (R_SUCCEEDED(fsFsGetFileTimeStampRaw(fs, DUALSHOCK3CONFIG, ×tamp))) + if (dualshock3ConfigLastModified != timestamp.modified) + { + dualshock3ConfigLastModified = timestamp.modified; + filesChanged = true; + } + + if (R_SUCCEEDED(fsFsGetFileTimeStampRaw(fs, DUALSHOCK4CONFIG, ×tamp))) + if (dualshock4ConfigLastModified != timestamp.modified) + { + dualshock4ConfigLastModified = timestamp.modified; + filesChanged = true; + } + return filesChanged; + } + + Result Initialize() + { + config::LoadAllConfigs(); + utimerCreate(&filecheckTimer, 1e+9L, TimerType_Repeating); + utimerStart(&filecheckTimer); + is_config_changed_check_thread_running = true; + return g_config_changed_check_thread.Start().GetValue(); + } + + void Exit() + { + is_config_changed_check_thread_running = true; + utimerStop(&filecheckTimer); + g_config_changed_check_thread.CancelSynchronization(); + g_config_changed_check_thread.Join(); + } +} \ No newline at end of file diff --git a/source/Sysmodule/source/config_handler.h b/source/Sysmodule/source/config_handler.h new file mode 100644 index 0000000..438f4a5 --- /dev/null +++ b/source/Sysmodule/source/config_handler.h @@ -0,0 +1,31 @@ +#pragma once +#include "ControllerTypes.h" + +#define CONFIG_PATH "/config/sys-con/" + +#define GLOBALCONFIG CONFIG_PATH "config_global.ini" +#define XBOXCONFIG CONFIG_PATH "config_xboxorig.ini" +#define XBOX360CONFIG CONFIG_PATH "config_xbox360.ini" +#define XBOXONECONFIG CONFIG_PATH "config_xboxone.ini" +#define DUALSHOCK3CONFIG CONFIG_PATH "config_dualshock3.ini" +#define DUALSHOCK4CONFIG CONFIG_PATH "config_dualshock4.ini" + +namespace syscon::config +{ + struct GlobalConfig + { + uint16_t dualshock4_productID; + }; + + inline GlobalConfig globalConfig + { + .dualshock4_productID = PRODUCT_DUALSHOCK4_1X, + }; + + void LoadGlobalConfig(const GlobalConfig &config); + void LoadAllConfigs(); + bool CheckForFileChanges(); + + Result Initialize(); + void Exit(); +}; \ No newline at end of file diff --git a/source/Sysmodule/source/main.cpp b/source/Sysmodule/source/main.cpp index 443d0ee..6e1ad98 100644 --- a/source/Sysmodule/source/main.cpp +++ b/source/Sysmodule/source/main.cpp @@ -1,11 +1,10 @@ #include "switch.h" #include "log.h" -#include "mainLoop.h" #include #include "usb_module.h" #include "controller_handler.h" -#include "configFile.h" +#include "config_handler.h" #define APP_VERSION "0.6.0" @@ -78,11 +77,10 @@ using namespace syscon; int main(int argc, char *argv[]) { WriteToLog("\n\nNew sysmodule session started on version " APP_VERSION); + config::Initialize(); handler::Initialize(); usb::Initialize(); - LoadAllConfigs(); - while (true) { svcSleepThread(1e+8L); @@ -90,4 +88,5 @@ int main(int argc, char *argv[]) usb::Exit(); handler::Exit(); + config::Exit(); } diff --git a/source/Sysmodule/source/usb_module.cpp b/source/Sysmodule/source/usb_module.cpp index a18a7a0..c2c5c5e 100644 --- a/source/Sysmodule/source/usb_module.cpp +++ b/source/Sysmodule/source/usb_module.cpp @@ -1,6 +1,7 @@ #include "switch.h" #include "usb_module.h" #include "controller_handler.h" +#include "config_handler.h" #include "SwitchUSBDevice.h" @@ -22,7 +23,7 @@ namespace syscon::usb void UsbInterfaceChangeThreadFunc(void *arg); ams::os::StaticThread<0x2'000> g_usb_event_thread(&UsbEventThreadFunc, nullptr, 0x20); - ams::os::StaticThread<0x2'000> g_usb_interface_change_thread(&UsbInterfaceChangeThreadFunc, nullptr, 0x20); + ams::os::StaticThread<0x2'000> g_usb_interface_change_thread(&UsbInterfaceChangeThreadFunc, nullptr, 0x21); bool is_usb_event_thread_running = false; bool is_usb_interface_change_thread_running = false; @@ -157,10 +158,10 @@ namespace syscon::usb Result CreateDualshock4AvailableEvent() { - constexpr UsbHsInterfaceFilter filter { + const UsbHsInterfaceFilter filter{ .Flags = UsbHsInterfaceFilterFlags_idVendor | UsbHsInterfaceFilterFlags_idProduct, .idVendor = VENDOR_SONY, - .idProduct = PRODUCT_DUALSHOCK4_2X, + .idProduct = config::globalConfig.dualshock4_productID, }; return usbHsCreateInterfaceAvailableEvent(&g_usbDualshock4Event, true, Dualshock4EventIndex, &filter); } @@ -210,4 +211,10 @@ namespace syscon::usb handler::Reset(); } + + Result ReloadDualshock4Event() + { + usbHsDestroyInterfaceAvailableEvent(&g_usbDualshock4Event, Dualshock4EventIndex); + return CreateDualshock4AvailableEvent(); + } } \ No newline at end of file diff --git a/source/Sysmodule/source/usb_module.h b/source/Sysmodule/source/usb_module.h index 7296950..e85b9cd 100644 --- a/source/Sysmodule/source/usb_module.h +++ b/source/Sysmodule/source/usb_module.h @@ -8,4 +8,6 @@ namespace syscon::usb { Result Enable(); void Disable(); + + Result ReloadDualshock4Event(); } \ No newline at end of file