mirror of
https://github.com/cathery/sys-con.git
synced 2025-03-12 22:14:30 +00:00
Merge branch 'master' into dev
yes
This commit is contained in:
commit
9cc04f8876
12
.vscode/c_cpp_properties.json
vendored
12
.vscode/c_cpp_properties.json
vendored
@ -3,7 +3,7 @@
|
||||
{
|
||||
"name": "AArch64 libnx",
|
||||
"includePath": [
|
||||
"${DEVKITPRO}/devkitA64/lib/gcc/aarch64-none-elf/9.2.0/include",
|
||||
"${DEVKITPRO}/devkitA64/lib/gcc/aarch64-none-elf/10.1.0/include",
|
||||
"${DEVKITPRO}/devkitA64/aarch64-none-elf/include",
|
||||
"${DEVKITPRO}/portlibs/switch/include",
|
||||
"${DEVKITPRO}/libnx/include",
|
||||
@ -17,12 +17,14 @@
|
||||
"SWITCH",
|
||||
"__SWITCH__",
|
||||
"ATMOSPHERE_BOARD_NINTENDO_SWITCH",
|
||||
"ATMOSPHERE_IS_STRATOSPHERE"
|
||||
"ATMOSPHERE_IS_STRATOSPHERE",
|
||||
"ATMOSPHERE_ARCH_ARM64",
|
||||
"ATMOSPHERE_OS_HORIZON"
|
||||
],
|
||||
"compilerPath": "${DEVKITPRO}/devkitA64/bin/aarch64-none-elf-g++",
|
||||
"cStandard": "c11",
|
||||
"cppStandard": "c++17",
|
||||
"intelliSenseMode": "gcc-x64"
|
||||
"cStandard": "gnu18",
|
||||
"cppStandard": "gnu++20",
|
||||
"intelliSenseMode": "gcc-arm64"
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
|
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@ -58,6 +58,7 @@
|
||||
"map": "cpp",
|
||||
"set": "cpp",
|
||||
"mutex": "cpp",
|
||||
"shared_mutex": "cpp"
|
||||
"shared_mutex": "cpp",
|
||||
"span": "cpp"
|
||||
},
|
||||
}
|
2
.vscode/tasks.json
vendored
2
.vscode/tasks.json
vendored
@ -5,7 +5,7 @@
|
||||
"label": "Build Release",
|
||||
"type": "shell",
|
||||
"promptOnClose": true,
|
||||
"command": "make -j8",
|
||||
"command": "make -j3",
|
||||
"presentation": {
|
||||
"reveal": "always",
|
||||
"panel": "shared"
|
||||
|
22
README.md
22
README.md
@ -1,25 +1,19 @@
|
||||
# sys-con
|
||||
|
||||
#### A Nintedo Switch sysmodule for third-party controller support. No man-in-the-middle required!
|
||||
###### \[Switch FW 5.0.0+\]
|
||||
#### A Nintendo Switch custom sysmodule for third-party controller support. No man-in-the-middle required!
|
||||
###### \[Switch FW 5.0.0+\] [Atmosphère only]
|
||||
|
||||
|
||||
|
||||
## Description
|
||||
This sysmodule aims to provide complete functionality for most popular game controllers not supported by Nintendo Switch.
|
||||
At the current moment, **only USB connection** is supported.
|
||||
At the current moment, **only USB connection** is supported.
|
||||
|
||||
This app is missing a lot of features. For more information, see the [issues page](https://github.com/cathery/sys-con/issues).
|
||||
|
||||
### ⚠ I can't support your generic 3rd party HID controller yet.
|
||||
It is a limitation of the firmware and I'm looking to work around it.
|
||||
|
||||
### ⚠ If you get the error 2003-0008 (0x1003):
|
||||
You're running too many sysmodules. Disable other memory demanding sysmodules like sys-ftpd or ldn_mitm.
|
||||
|
||||
### ⚠ If you have a second-generation Dualshock 4:
|
||||
You need to go to `sdmc:/config/sys-con/config_global.ini` and change the value of `use_dualshock_2nd_generation` from **false** to **true**.
|
||||
|
||||
|
||||
|
||||
## Install
|
||||
|
||||
@ -45,9 +39,13 @@ sys-con comes with a config folder located at `sdmc:/config/sys-con/`. It contai
|
||||
|
||||
## Building (For developers)
|
||||
|
||||
Like all other switch projects, you need to have [devkitPro](https://switchbrew.org/wiki/Setting_up_Development_Environment) set up on your system.
|
||||
Don't download the project as ZIP. It doesn't copy the submodules correctly and you will be left with empty folders.
|
||||
|
||||
This project uses libnx version 3.1.0 or later.
|
||||
Instead, clone the repository **recursively** using any git client you have. (Git Bash, Git GUI, Github Desktop, etc.)
|
||||
|
||||
Like all other switch projects, you need to have [devkitA64](https://switchbrew.org/wiki/Setting_up_Development_Environment) set up on your system.
|
||||
|
||||
This project uses libnx version **3.3.0**.
|
||||
|
||||
If you have **Visual Studio Code**, you can open the project as a folder and run the build tasks from inside the program. It also has Intellisense configured for switch development, if you have DEVKITPRO correctly defined in your environment variables. Handy!
|
||||
|
||||
|
@ -37,30 +37,34 @@ void SwitchVirtualGamepadHandler::OutputThreadLoop(void *handler)
|
||||
|
||||
Result SwitchVirtualGamepadHandler::InitInputThread()
|
||||
{
|
||||
R_TRY(m_inputThread.Initialize(&SwitchVirtualGamepadHandler::InputThreadLoop, this, 0x30).GetValue());
|
||||
m_inputThreadIsRunning = true;
|
||||
return m_inputThread.Start().GetValue();
|
||||
R_ABORT_UNLESS(threadCreate(&m_inputThread, &SwitchVirtualGamepadHandler::InputThreadLoop, this, input_thread_stack, sizeof(input_thread_stack), 0x30, -2));
|
||||
R_ABORT_UNLESS(threadStart(&m_inputThread));
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SwitchVirtualGamepadHandler::ExitInputThread()
|
||||
{
|
||||
m_inputThreadIsRunning = false;
|
||||
m_inputThread.CancelSynchronization();
|
||||
m_inputThread.Join();
|
||||
svcCancelSynchronization(m_inputThread.handle);
|
||||
threadWaitForExit(&m_inputThread);
|
||||
threadClose(&m_inputThread);
|
||||
}
|
||||
|
||||
Result SwitchVirtualGamepadHandler::InitOutputThread()
|
||||
{
|
||||
R_TRY(m_outputThread.Initialize(&SwitchVirtualGamepadHandler::OutputThreadLoop, this, 0x30).GetValue());
|
||||
m_outputThreadIsRunning = true;
|
||||
return m_outputThread.Start().GetValue();
|
||||
R_ABORT_UNLESS(threadCreate(&m_outputThread, &SwitchVirtualGamepadHandler::OutputThreadLoop, this, output_thread_stack, sizeof(output_thread_stack), 0x30, -2));
|
||||
R_ABORT_UNLESS(threadStart(&m_outputThread));
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SwitchVirtualGamepadHandler::ExitOutputThread()
|
||||
{
|
||||
m_outputThreadIsRunning = false;
|
||||
m_outputThread.CancelSynchronization();
|
||||
m_outputThread.Join();
|
||||
svcCancelSynchronization(m_outputThread.handle);
|
||||
threadWaitForExit(&m_outputThread);
|
||||
threadClose(&m_outputThread);
|
||||
}
|
||||
|
||||
static_assert(JOYSTICK_MAX == 32767 && JOYSTICK_MIN == -32767,
|
||||
|
@ -10,8 +10,11 @@ protected:
|
||||
u32 m_vibrationDeviceHandle;
|
||||
std::unique_ptr<IController> m_controller;
|
||||
|
||||
ams::os::StaticThread<0x1'000> m_inputThread;
|
||||
ams::os::StaticThread<0x1'000> m_outputThread;
|
||||
alignas(ams::os::ThreadStackAlignment) u8 input_thread_stack[0x1000];
|
||||
alignas(ams::os::ThreadStackAlignment) u8 output_thread_stack[0x1000];
|
||||
|
||||
Thread m_inputThread;
|
||||
Thread m_outputThread;
|
||||
|
||||
bool m_inputThreadIsRunning = false;
|
||||
bool m_outputThreadIsRunning = false;
|
||||
|
@ -20,9 +20,11 @@ namespace syscon::config
|
||||
UTimer filecheckTimer;
|
||||
Waiter filecheckTimerWaiter = waiterForUTimer(&filecheckTimer);
|
||||
|
||||
// Thread to check for any config changes
|
||||
void ConfigChangedCheckThreadFunc(void *arg);
|
||||
|
||||
ams::os::StaticThread<0x2'000> g_config_changed_check_thread(&ConfigChangedCheckThreadFunc, nullptr, 0x3E);
|
||||
alignas(ams::os::ThreadStackAlignment) u8 config_thread_stack[0x2000];
|
||||
Thread g_config_changed_check_thread;
|
||||
|
||||
bool is_config_changed_check_thread_running = false;
|
||||
|
||||
@ -338,14 +340,17 @@ namespace syscon::config
|
||||
return 1;
|
||||
utimerStart(&filecheckTimer);
|
||||
is_config_changed_check_thread_running = true;
|
||||
return g_config_changed_check_thread.Start().GetValue();
|
||||
R_ABORT_UNLESS(threadCreate(&g_config_changed_check_thread, &ConfigChangedCheckThreadFunc, nullptr, config_thread_stack, sizeof(config_thread_stack), 0x3E, -2));
|
||||
R_ABORT_UNLESS(threadStart(&g_config_changed_check_thread));
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Disable()
|
||||
{
|
||||
is_config_changed_check_thread_running = false;
|
||||
utimerStop(&filecheckTimer);
|
||||
g_config_changed_check_thread.CancelSynchronization();
|
||||
g_config_changed_check_thread.Join();
|
||||
svcCancelSynchronization(g_config_changed_check_thread.handle);
|
||||
threadWaitForExit(&g_config_changed_check_thread);
|
||||
threadClose(&g_config_changed_check_thread);
|
||||
}
|
||||
} // namespace syscon::config
|
@ -14,7 +14,7 @@ namespace syscon::controllers
|
||||
constexpr size_t MaxControllerHandlersSize = 10;
|
||||
std::vector<std::unique_ptr<SwitchVirtualGamepadHandler>> controllerHandlers;
|
||||
bool UseAbstractedPad;
|
||||
ams::os::Mutex controllerMutex;
|
||||
ams::os::Mutex controllerMutex(false);
|
||||
} // namespace
|
||||
|
||||
bool IsAtControllerLimit()
|
||||
|
@ -3,7 +3,7 @@
|
||||
#include "config_handler.h"
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
static ams::os::Mutex printMutex;
|
||||
static ams::os::Mutex printMutex(false);
|
||||
|
||||
void DiscardOldLogs()
|
||||
{
|
||||
@ -33,15 +33,12 @@ void WriteToLog(const char *fmt, ...)
|
||||
{
|
||||
std::scoped_lock printLock(printMutex);
|
||||
|
||||
u64 ts;
|
||||
TimeCalendarTime caltime;
|
||||
timeGetCurrentTime(TimeType_LocalSystemClock, &ts);
|
||||
timeToCalendarTimeWithMyRule(ts, &caltime, nullptr);
|
||||
ams::TimeSpan ts = ams::os::ConvertToTimeSpan(ams::os::GetSystemTick());
|
||||
|
||||
FILE *fp = fopen(LOG_PATH, "a");
|
||||
|
||||
//Print time
|
||||
fprintf(fp, "%04i-%02i-%02i %02i:%02i:%02i: ", caltime.year, caltime.month, caltime.day, caltime.hour, caltime.minute, caltime.second);
|
||||
fprintf(fp, "%02lid %02li:%02li:%02li: ", ts.GetDays(), ts.GetHours() % 24, ts.GetMinutes() % 60, ts.GetSeconds() % 60);
|
||||
|
||||
//Print the actual text
|
||||
va_list va;
|
||||
|
@ -7,12 +7,17 @@
|
||||
#include "config_handler.h"
|
||||
#include "psc_module.h"
|
||||
|
||||
#define APP_VERSION "0.6.0"
|
||||
#define APP_VERSION "0.6.2"
|
||||
|
||||
// libnx fake heap initialization
|
||||
extern "C"
|
||||
{
|
||||
// We aren't an applet, so disable applet functionality.
|
||||
u32 __nx_applet_type = AppletType_None;
|
||||
// We are a sysmodule, so don't use more FS sessions than needed.
|
||||
u32 __nx_fs_num_sessions = 1;
|
||||
// We don't need to reserve memory for fsdev, so don't use it.
|
||||
u32 __nx_fsdev_direntry_cache_size = 1;
|
||||
|
||||
#define INNER_HEAP_SIZE 0x40'000
|
||||
size_t nx_inner_heap_size = INNER_HEAP_SIZE;
|
||||
@ -57,7 +62,6 @@ extern "C" void __appInit(void)
|
||||
hosversionSet(MAKEHOSVERSION(fw.major, fw.minor, fw.micro));
|
||||
setsysExit();
|
||||
|
||||
R_ABORT_UNLESS(timeInitialize());
|
||||
R_ABORT_UNLESS(hiddbgInitialize());
|
||||
if (hosversionAtLeast(7, 0, 0))
|
||||
R_ABORT_UNLESS(hiddbgAttachHdlsWorkBuffer());
|
||||
@ -77,7 +81,6 @@ extern "C" void __appExit(void)
|
||||
hiddbgExit();
|
||||
fsdevUnmountAll();
|
||||
fsExit();
|
||||
timeExit();
|
||||
}
|
||||
|
||||
using namespace syscon;
|
||||
|
@ -11,11 +11,13 @@ namespace syscon::psc
|
||||
{
|
||||
PscPmModule pscModule;
|
||||
Waiter pscModuleWaiter;
|
||||
const uint16_t dependencies[] = {PscPmModuleId_Usb};
|
||||
const uint16_t dependencies[] = {PscPmModuleId_Fs};
|
||||
|
||||
//Thread to check for psc:pm state change (console waking up/going to sleep)
|
||||
void PscThreadFunc(void *arg);
|
||||
|
||||
ams::os::StaticThread<0x1'000> g_psc_thread(&PscThreadFunc, nullptr, 0x2C);
|
||||
alignas(ams::os::ThreadStackAlignment) u8 psc_thread_stack[0x1000];
|
||||
Thread g_psc_thread;
|
||||
|
||||
bool is_psc_thread_running = false;
|
||||
|
||||
@ -31,6 +33,7 @@ namespace syscon::psc
|
||||
{
|
||||
switch (pscState)
|
||||
{
|
||||
case PscPmState_Awake:
|
||||
case PscPmState_ReadyAwaken:
|
||||
//usb::CreateUsbEvents();
|
||||
break;
|
||||
@ -53,7 +56,9 @@ namespace syscon::psc
|
||||
R_TRY(pscmGetPmModule(&pscModule, PscPmModuleId(126), dependencies, sizeof(dependencies) / sizeof(uint16_t), true));
|
||||
pscModuleWaiter = waiterForEvent(&pscModule.event);
|
||||
is_psc_thread_running = true;
|
||||
return g_psc_thread.Start().GetValue();
|
||||
R_ABORT_UNLESS(threadCreate(&g_psc_thread, &PscThreadFunc, nullptr, psc_thread_stack, sizeof(psc_thread_stack), 0x2C, -2));
|
||||
R_ABORT_UNLESS(threadStart(&g_psc_thread));
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Exit()
|
||||
@ -64,7 +69,8 @@ namespace syscon::psc
|
||||
pscPmModuleClose(&pscModule);
|
||||
eventClose(&pscModule.event);
|
||||
|
||||
g_psc_thread.CancelSynchronization();
|
||||
g_psc_thread.Join();
|
||||
svcCancelSynchronization(g_psc_thread.handle);
|
||||
threadWaitForExit(&g_psc_thread);
|
||||
threadClose(&g_psc_thread);
|
||||
}
|
||||
}; // namespace syscon::psc
|
@ -19,15 +19,22 @@ namespace syscon::usb
|
||||
|
||||
constexpr size_t MaxUsbHsInterfacesSize = 16;
|
||||
|
||||
ams::os::Mutex usbMutex;
|
||||
ams::os::Mutex usbMutex(false);
|
||||
|
||||
//Thread that waits on generic usb event
|
||||
void UsbEventThreadFunc(void *arg);
|
||||
//Thread that waits on sony vendor usb event
|
||||
void UsbSonyEventThreadFunc(void *arg);
|
||||
//Thread that waits on any disconnected usb devices
|
||||
void UsbInterfaceChangeThreadFunc(void *arg);
|
||||
|
||||
ams::os::StaticThread<0x2'000> g_usb_event_thread(&UsbEventThreadFunc, nullptr, 0x3A);
|
||||
ams::os::StaticThread<0x2'000> g_sony_event_thread(&UsbSonyEventThreadFunc, nullptr, 0x3B);
|
||||
ams::os::StaticThread<0x2'000> g_usb_interface_change_thread(&UsbInterfaceChangeThreadFunc, nullptr, 0x2C);
|
||||
alignas(ams::os::ThreadStackAlignment) u8 usb_event_thread_stack[0x2000];
|
||||
alignas(ams::os::ThreadStackAlignment) u8 sony_event_thread_stack[0x2000];
|
||||
alignas(ams::os::ThreadStackAlignment) u8 usb_interface_change_thread_stack[0x2000];
|
||||
|
||||
Thread g_usb_event_thread;
|
||||
Thread g_sony_event_thread;
|
||||
Thread g_usb_interface_change_thread;
|
||||
|
||||
bool is_usb_event_thread_running = false;
|
||||
bool is_usb_interface_change_thread_running = false;
|
||||
@ -198,9 +205,13 @@ namespace syscon::usb
|
||||
is_usb_event_thread_running = true;
|
||||
is_usb_interface_change_thread_running = true;
|
||||
|
||||
R_TRY(g_usb_event_thread.Start().GetValue());
|
||||
R_TRY(g_sony_event_thread.Start().GetValue());
|
||||
R_TRY(g_usb_interface_change_thread.Start().GetValue());
|
||||
R_ABORT_UNLESS(threadCreate(&g_usb_event_thread, &UsbEventThreadFunc, nullptr, usb_event_thread_stack, sizeof(usb_event_thread_stack), 0x3A, -2));
|
||||
R_ABORT_UNLESS(threadCreate(&g_sony_event_thread, &UsbSonyEventThreadFunc, nullptr, sony_event_thread_stack, sizeof(sony_event_thread_stack), 0x3B, -2));
|
||||
R_ABORT_UNLESS(threadCreate(&g_usb_interface_change_thread, &UsbInterfaceChangeThreadFunc, nullptr, usb_interface_change_thread_stack, sizeof(usb_interface_change_thread_stack), 0x2C, -2));
|
||||
|
||||
R_ABORT_UNLESS(threadStart(&g_usb_event_thread));
|
||||
R_ABORT_UNLESS(threadStart(&g_sony_event_thread));
|
||||
R_ABORT_UNLESS(threadStart(&g_usb_interface_change_thread));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -209,13 +220,17 @@ namespace syscon::usb
|
||||
is_usb_event_thread_running = false;
|
||||
is_usb_interface_change_thread_running = false;
|
||||
|
||||
g_usb_event_thread.CancelSynchronization();
|
||||
g_sony_event_thread.CancelSynchronization();
|
||||
g_usb_interface_change_thread.CancelSynchronization();
|
||||
svcCancelSynchronization(g_usb_event_thread.handle);
|
||||
threadWaitForExit(&g_usb_event_thread);
|
||||
threadClose(&g_usb_event_thread);
|
||||
|
||||
g_usb_event_thread.Join();
|
||||
g_sony_event_thread.Join();
|
||||
g_usb_interface_change_thread.Join();
|
||||
svcCancelSynchronization(g_sony_event_thread.handle);
|
||||
threadWaitForExit(&g_sony_event_thread);
|
||||
threadClose(&g_sony_event_thread);
|
||||
|
||||
svcCancelSynchronization(g_usb_interface_change_thread.handle);
|
||||
threadWaitForExit(&g_usb_interface_change_thread);
|
||||
threadClose(&g_usb_interface_change_thread);
|
||||
|
||||
DestroyUsbEvents();
|
||||
controllers::Reset();
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 62f5667b5f020f4a871ccd8f0362f2625d92e616
|
||||
Subproject commit 797dfa782e85173652d017de38066f9a5c88622a
|
Loading…
x
Reference in New Issue
Block a user