diff --git a/.gitignore b/.gitignore index c343fec..2ee7377 100644 --- a/.gitignore +++ b/.gitignore @@ -4,7 +4,4 @@ *.nro *.nso *.nsp -build/ -dist/ - .vscode diff --git a/.gitmodules b/.gitmodules index aad773b..71677fb 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "application/libs/borealis"] path = application/libs/borealis url = git@github.com:natinusala/borealis.git +[submodule "sysmodule/vendor/ulog"] + path = sysmodule/vendor/ulog + url = git@github.com:ShawnFeng0/ulog.git diff --git a/README.md b/README.md index cd0042f..ea644f7 100644 --- a/README.md +++ b/README.md @@ -1,30 +1,53 @@ -# SplitNX +# SplitNX # + LiveSplit Server plugin for autosplitting on the Nintendo Switch! -Simply `make dist` and add the files within the dist folder to your SD card. Must run with CFW (Use Atmosphere or Kosmos or it will probably not work). -Includes both basic autosplitting from memory and manual splitting with controller. -All controls require you to hold all 4 shoulder buttons then press: -A - Split/Start -B - Undo Split -X - Skip Split -Y - Reset +## Usage ## + +### Splitting With a Controller ### + +This is the easiest way to use splitting for newcomers, and is always on. +Certain button combinations will trigger splits for livesplit. These +key-combos currently can not be changed. -The autosplitting is read in from `/split/splitter.txt` on your SD card which has the following format: +To trigger hold all 4 "Shoulder Buttons" (ZL/L/R/ZR), and then press one of: -First line: IP of computer + - `+`: Attempt to connect to livesplit server + - `-`: Reload configuration file. + - `A`: Split/Start + - `B`: Undo + - `X`: Skip + - `Y`: Reset + - Left on the DPAD: write first memory address value in autosplitter to log file. -Second line: Port of LiveSplit Server +### Splitting Based on Memory Values ### -Every line after that will correspond to a memory autosplit corresponding with the index of the split in LiveSplit (so the 3rd line will describe autosplitting for the first split, and so on): +Similar to how autosplit scripts work it is possible to automatically split +based on the condition of a piece of memory. The format is described below, +but we don't describe how to identify these values as that's highly dependent +on each game. +TODO(xxx): document file which just contains memory autosplit. + + + +## Building ## + +### SysModule ### -This is super rough, just wanted to get something working for now, and I may or may not improve it later. If anyone wants to improve it then by all means go for it. Would be great to get it to hook into the already implemented AutoSplitters for LiveSplit but I have no clue how to do that. +The sysmodule is the actual thing always running on your switch, listening for +keypresses, and communicating with LiveSplit. -Any questions feel free to ask. +Inside the `sysmodule` directory: -Example of it running: https://youtu.be/K0eXAhT2AB4 +1. Ensure you have `switch-mpg123` installed: `dkp-pacman -S switch-mpg123` +2. Run `make dist`. +3. Copy the files within the `dist` folder to your SD Card. +4. Boot up your switch with CFW (Atmosphere/Kosmos). \ No newline at end of file diff --git a/sysmodule/.gitignore b/sysmodule/.gitignore new file mode 100644 index 0000000..e45d326 --- /dev/null +++ b/sysmodule/.gitignore @@ -0,0 +1,3 @@ +/build/ +/out/ +/dist/ \ No newline at end of file diff --git a/sysmodule/Makefile b/sysmodule/Makefile index 447527e..1b7027e 100644 --- a/sysmodule/Makefile +++ b/sysmodule/Makefile @@ -40,9 +40,9 @@ include $(TOPDIR)/../switch_rules TARGET := $(notdir $(CURDIR)) BUILD := build OUTDIR := out -SOURCES := source +SOURCES := source vendor/ulog/src DATA := data -INCLUDES := include +INCLUDES := include vendor/ulog/include ROMFS := romfs APP_TITLEID := 2200000000000100 APP_TITLE := SplitNX @@ -88,6 +88,8 @@ export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ export DEPSDIR := $(CURDIR)/$(BUILD) +HFILES := $(foreach dir,$(INCLUDES),$(notdir $(wildcard $(dir)/*.h))) +HPPFILES := $(foreach dir,$(INCLUDES),$(notdir $(wildcard $(dir)/*.hpp))) CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) @@ -107,12 +109,12 @@ else endif #--------------------------------------------------------------------------------- -export OFILES_BIN := $(addsuffix .o,$(BINFILES)) -export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) -export OFILES := $(OFILES_BIN) $(OFILES_SRC) -export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES))) +export OFILES_BIN := $(addsuffix .o,$(BINFILES)) +export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) +export OFILES := $(OFILES_BIN) $(OFILES_SRC) +export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES))) -export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ +export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ -I$(CURDIR)/$(BUILD) @@ -160,28 +162,55 @@ ifneq ($(ROMFS),) export NROFLAGS += --romfsdir=$(CURDIR)/$(ROMFS) endif -.PHONY: $(BUILD) clean all +.PHONY: $(BUILD) clean all style #--------------------------------------------------------------------------------- all: $(BUILD) $(BUILD): @[ -d $@ ] || mkdir -p $@ + @[ -d $(CURDIR)/$(OUTDIR) ] || mkdir -p $(CURDIR)/$(OUTDIR) @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile #--------------------------------------------------------------------------------- clean: @echo clean ... ifeq ($(strip $(APP_JSON)),) - @rm -fr $(BUILD) $(TARGET).nro $(TARGET).nacp $(TARGET).elf + @rm -fr $(BUILD) $(OUTDIR) $(CURDIR)/dist/ $(TARGET).nro $(TARGET).nacp $(TARGET).elf else - @rm -fr $(BUILD) $(TARGET).nsp $(TARGET).nso $(TARGET).npdm $(TARGET).elf + @rm -fr $(BUILD) $(OUTDIR) $(CURDIR)/dist/ $(TARGET).nsp $(TARGET).nso $(TARGET).npdm $(TARGET).elf endif +#--------------------------------------------------------------------------------- +style: + @for src in $(CFILES) ; do \ + echo "Formatting $$src..." ; \ + if [ -f "source/$$src" ]; then clang-format-11 -style=webkit -i "source/$$src" ; fi ; \ + done + @for src in $(CPPFILES) ; do \ + echo "Formatting $$src..." ; \ + clang-format-11 -style=webkit -i "source/$$src" ; \ + done + @for src in $(HFILES) ; do \ + echo "Formatting $$src..." ; \ + clang-format-11 -style=webkit -i "include/$$src" ; \ + done + @for src in $(HPPFILES) ; do \ + echo "Formatting $$src..." ; \ + clang-format-11 -style=webkit -i "include/$$src" ; \ + done + @echo "Done" + +#--------------------------------------------------------------------------------- +dist: all $(OUTPUT).nsp + @[ -d $(CURDIR)/dist/ ] || mkdir -p $(CURDIR)/dist/atmosphere/contents/$(APP_TITLEID)/flags + @cp -f $(OUTPUT).nsp $(CURDIR)/dist/atmosphere/contents/$(APP_TITLEID)/exefs.nsp + @touch $(CURDIR)/dist/atmosphere/contents/$(APP_TITLEID)/flags/boot2.flag + @echo '{"name": "SplitNX-Sysmodule", "tid": "$(APP_TITLEID)", "requires_reboot": true}' > $(CURDIR)/dist/atmosphere/contents/$(APP_TITLEID)/toolbox.json #--------------------------------------------------------------------------------- else -.PHONY: all +.PHONY: all style DEPENDS := $(OFILES:.o=.d) diff --git a/sysmodule/include/dmntcht.h b/sysmodule/include/dmntcht.h index 62f8957..706b63c 100644 --- a/sysmodule/include/dmntcht.h +++ b/sysmodule/include/dmntcht.h @@ -62,33 +62,33 @@ Result dmntchtInitialize(void); void dmntchtExit(void); Service* dmntchtGetServiceSession(void); -Result dmntchtHasCheatProcess(bool *out); -Result dmntchtGetCheatProcessEvent(Event *event); -Result dmntchtGetCheatProcessMetadata(DmntCheatProcessMetadata *out_metadata); +Result dmntchtHasCheatProcess(bool* out); +Result dmntchtGetCheatProcessEvent(Event* event); +Result dmntchtGetCheatProcessMetadata(DmntCheatProcessMetadata* out_metadata); Result dmntchtForceOpenCheatProcess(void); -Result dmntchtGetCheatProcessMappingCount(u64 *out_count); -Result dmntchtGetCheatProcessMappings(MemoryInfo *buffer, u64 max_count, u64 offset, u64 *out_count); -Result dmntchtReadCheatProcessMemory(u64 address, void *buffer, size_t size); -Result dmntchtWriteCheatProcessMemory(u64 address, const void *buffer, size_t size); -Result dmntchtQueryCheatProcessMemory(MemoryInfo *mem_info, u64 address); +Result dmntchtGetCheatProcessMappingCount(u64* out_count); +Result dmntchtGetCheatProcessMappings(MemoryInfo* buffer, u64 max_count, u64 offset, u64* out_count); +Result dmntchtReadCheatProcessMemory(u64 address, void* buffer, size_t size); +Result dmntchtWriteCheatProcessMemory(u64 address, const void* buffer, size_t size); +Result dmntchtQueryCheatProcessMemory(MemoryInfo* mem_info, u64 address); Result dmntchtPauseCheatProcess(void); Result dmntchtResumeCheatProcess(void); -Result dmntchtGetCheatCount(u64 *out_count); -Result dmntchtGetCheats(DmntCheatEntry *buffer, u64 max_count, u64 offset, u64 *out_count); -Result dmntchtGetCheatById(DmntCheatEntry *out_cheat, u32 cheat_id); +Result dmntchtGetCheatCount(u64* out_count); +Result dmntchtGetCheats(DmntCheatEntry* buffer, u64 max_count, u64 offset, u64* out_count); +Result dmntchtGetCheatById(DmntCheatEntry* out_cheat, u32 cheat_id); Result dmntchtToggleCheat(u32 cheat_id); -Result dmntchtAddCheat(DmntCheatDefinition *cheat, bool enabled, u32 *out_cheat_id); +Result dmntchtAddCheat(DmntCheatDefinition* cheat, bool enabled, u32* out_cheat_id); Result dmntchtRemoveCheat(u32 cheat_id); -Result dmntchtReadStaticRegister(u64 *out, u8 which); +Result dmntchtReadStaticRegister(u64* out, u8 which); Result dmntchtWriteStaticRegister(u8 which, u64 value); Result dmntchtResetStaticRegisters(); -Result dmntchtGetFrozenAddressCount(u64 *out_count); -Result dmntchtGetFrozenAddresses(DmntFrozenAddressEntry *buffer, u64 max_count, u64 offset, u64 *out_count); -Result dmntchtGetFrozenAddress(DmntFrozenAddressEntry *out, u64 address); -Result dmntchtEnableFrozenAddress(u64 address, u64 width, u64 *out_value); +Result dmntchtGetFrozenAddressCount(u64* out_count); +Result dmntchtGetFrozenAddresses(DmntFrozenAddressEntry* buffer, u64 max_count, u64 offset, u64* out_count); +Result dmntchtGetFrozenAddress(DmntFrozenAddressEntry* out, u64 address); +Result dmntchtEnableFrozenAddress(u64 address, u64 width, u64* out_value); Result dmntchtDisableFrozenAddress(u64 address); #ifdef __cplusplus diff --git a/sysmodule/include/service_guard.h b/sysmodule/include/service_guard.h index d7ce9a7..d319114 100644 --- a/sysmodule/include/service_guard.h +++ b/sysmodule/include/service_guard.h @@ -4,11 +4,11 @@ extern "C" { #endif -#include -#include #include -#include +#include #include +#include +#include typedef struct ServiceGuard { Mutex mutex; @@ -39,24 +39,24 @@ NX_INLINE void serviceGuardExit(ServiceGuard* g, void (*cleanupFunc)(void)) mutexUnlock(&g->mutex); } -#define NX_GENERATE_SERVICE_GUARD_PARAMS(name, _paramdecl, _parampass) \ -\ -static ServiceGuard g_##name##Guard; \ -NX_INLINE Result _##name##Initialize _paramdecl; \ -static void _##name##Cleanup(void); \ -\ -Result name##Initialize _paramdecl \ -{ \ - Result rc = 0; \ - if (serviceGuardBeginInit(&g_##name##Guard)) \ - rc = _##name##Initialize _parampass; \ - return serviceGuardEndInit(&g_##name##Guard, rc, _##name##Cleanup); \ -} \ -\ -void name##Exit(void) \ -{ \ - serviceGuardExit(&g_##name##Guard, _##name##Cleanup); \ -} +#define NX_GENERATE_SERVICE_GUARD_PARAMS(name, _paramdecl, _parampass) \ + \ + static ServiceGuard g_##name##Guard; \ + NX_INLINE Result _##name##Initialize _paramdecl; \ + static void _##name##Cleanup(void); \ + \ + Result name##Initialize _paramdecl \ + { \ + Result rc = 0; \ + if (serviceGuardBeginInit(&g_##name##Guard)) \ + rc = _##name##Initialize _parampass; \ + return serviceGuardEndInit(&g_##name##Guard, rc, _##name##Cleanup); \ + } \ + \ + void name##Exit(void) \ + { \ + serviceGuardExit(&g_##name##Guard, _##name##Cleanup); \ + } #define NX_GENERATE_SERVICE_GUARD(name) NX_GENERATE_SERVICE_GUARD_PARAMS(name, (void), ()) diff --git a/sysmodule/include/splitter.hpp b/sysmodule/include/splitter.hpp index 208ff0d..d90933d 100644 --- a/sysmodule/include/splitter.hpp +++ b/sysmodule/include/splitter.hpp @@ -1,21 +1,19 @@ #pragma once -#include #include +#include -#include #include #include +#include #include #include - bool doOperator(u64 param1, u64 param2, std::string op); u64 readMemory(u64 address, size_t size, std::string type); -struct split -{ +struct split { u64 address; u64 value; size_t size; @@ -24,8 +22,7 @@ struct split bool valid = false; }; -class Splitter -{ +class Splitter { public: Splitter(std::string filename); void Reload(std::string filename); @@ -37,7 +34,7 @@ class Splitter void Skip(); void SetLoading(bool); - void test_it(); + void debug_first_mem(); private: bool connected; diff --git a/sysmodule/source/dmntcht.c b/sysmodule/source/dmntcht.c index dd5faaa..6893b17 100644 --- a/sysmodule/source/dmntcht.c +++ b/sysmodule/source/dmntcht.c @@ -14,38 +14,43 @@ * along with this program. If not, see . */ #define NX_SERVICE_ASSUME_NON_DOMAIN -#include "../service_guard.h" #include "dmntcht.h" +#include "service_guard.h" static Service g_dmntchtSrv; NX_GENERATE_SERVICE_GUARD(dmntcht); -Result _dmntchtInitialize(void) { +Result _dmntchtInitialize(void) +{ return smGetService(&g_dmntchtSrv, "dmnt:cht"); } -void _dmntchtCleanup(void) { +void _dmntchtCleanup(void) +{ serviceClose(&g_dmntchtSrv); } -Service* dmntchtGetServiceSession(void) { +Service* dmntchtGetServiceSession(void) +{ return &g_dmntchtSrv; } -Result dmntchtHasCheatProcess(bool *out) { +Result dmntchtHasCheatProcess(bool* out) +{ u8 tmp; Result rc = serviceDispatchOut(&g_dmntchtSrv, 65000, tmp); - if (R_SUCCEEDED(rc) && out) *out = tmp & 1; + if (R_SUCCEEDED(rc) && out) + *out = tmp & 1; return rc; } -Result dmntchtGetCheatProcessEvent(Event *event) { +Result dmntchtGetCheatProcessEvent(Event* event) +{ Handle evt_handle; Result rc = serviceDispatch(&g_dmntchtSrv, 65001, .out_handle_attrs = { SfOutHandleAttr_HipcCopy }, - .out_handles = &evt_handle, - ); + .out_handles = &evt_handle, ); if (R_SUCCEEDED(rc)) { eventLoadRemote(event, evt_handle, true); @@ -54,111 +59,127 @@ Result dmntchtGetCheatProcessEvent(Event *event) { return rc; } -Result dmntchtGetCheatProcessMetadata(DmntCheatProcessMetadata *out_metadata) { +Result dmntchtGetCheatProcessMetadata(DmntCheatProcessMetadata* out_metadata) +{ return serviceDispatchOut(&g_dmntchtSrv, 65002, *out_metadata); } -static Result _dmntchtCmdVoid(Service* srv, u32 cmd_id) { +static Result _dmntchtCmdVoid(Service* srv, u32 cmd_id) +{ return serviceDispatch(srv, cmd_id); } -Result dmntchtForceOpenCheatProcess(void) { +Result dmntchtForceOpenCheatProcess(void) +{ return _dmntchtCmdVoid(&g_dmntchtSrv, 65003); } -Result dmntchtPauseCheatProcess(void) { +Result dmntchtPauseCheatProcess(void) +{ return _dmntchtCmdVoid(&g_dmntchtSrv, 65004); } -Result dmntchtResumeCheatProcess(void) { +Result dmntchtResumeCheatProcess(void) +{ return _dmntchtCmdVoid(&g_dmntchtSrv, 65005); } -static Result _dmntchtGetCount(u64 *out_count, u32 cmd_id) { +static Result _dmntchtGetCount(u64* out_count, u32 cmd_id) +{ return serviceDispatchOut(&g_dmntchtSrv, cmd_id, *out_count); } -static Result _dmntchtGetEntries(void *buffer, u64 buffer_size, u64 offset, u64 *out_count, u32 cmd_id) { +static Result _dmntchtGetEntries(void* buffer, u64 buffer_size, u64 offset, u64* out_count, u32 cmd_id) +{ return serviceDispatchInOut(&g_dmntchtSrv, cmd_id, offset, *out_count, .buffer_attrs = { SfBufferAttr_Out | SfBufferAttr_HipcMapAlias }, - .buffers = { { buffer, buffer_size } }, - ); + .buffers = { { buffer, buffer_size } }, ); } -static Result _dmntchtCmdInU32NoOut(u32 in, u32 cmd_id) { +static Result _dmntchtCmdInU32NoOut(u32 in, u32 cmd_id) +{ return serviceDispatchIn(&g_dmntchtSrv, cmd_id, in); } -Result dmntchtGetCheatProcessMappingCount(u64 *out_count) { +Result dmntchtGetCheatProcessMappingCount(u64* out_count) +{ return _dmntchtGetCount(out_count, 65100); } -Result dmntchtGetCheatProcessMappings(MemoryInfo *buffer, u64 max_count, u64 offset, u64 *out_count) { +Result dmntchtGetCheatProcessMappings(MemoryInfo* buffer, u64 max_count, u64 offset, u64* out_count) +{ return _dmntchtGetEntries(buffer, sizeof(*buffer) * max_count, offset, out_count, 65101); } -Result dmntchtReadCheatProcessMemory(u64 address, void *buffer, size_t size) { +Result dmntchtReadCheatProcessMemory(u64 address, void* buffer, size_t size) +{ const struct { u64 address; u64 size; } in = { address, size }; return serviceDispatchIn(&g_dmntchtSrv, 65102, in, .buffer_attrs = { SfBufferAttr_Out | SfBufferAttr_HipcMapAlias }, - .buffers = { { buffer, size } }, - ); + .buffers = { { buffer, size } }, ); } -Result dmntchtWriteCheatProcessMemory(u64 address, const void *buffer, size_t size) { +Result dmntchtWriteCheatProcessMemory(u64 address, const void* buffer, size_t size) +{ const struct { u64 address; u64 size; } in = { address, size }; return serviceDispatchIn(&g_dmntchtSrv, 65103, in, .buffer_attrs = { SfBufferAttr_In | SfBufferAttr_HipcMapAlias }, - .buffers = { { buffer, size } }, - ); + .buffers = { { buffer, size } }, ); } -Result dmntchtQueryCheatProcessMemory(MemoryInfo *mem_info, u64 address){ +Result dmntchtQueryCheatProcessMemory(MemoryInfo* mem_info, u64 address) +{ return serviceDispatchInOut(&g_dmntchtSrv, 65104, address, *mem_info); } -Result dmntchtGetCheatCount(u64 *out_count) { +Result dmntchtGetCheatCount(u64* out_count) +{ return _dmntchtGetCount(out_count, 65200); } -Result dmntchtGetCheats(DmntCheatEntry *buffer, u64 max_count, u64 offset, u64 *out_count) { +Result dmntchtGetCheats(DmntCheatEntry* buffer, u64 max_count, u64 offset, u64* out_count) +{ return _dmntchtGetEntries(buffer, sizeof(*buffer) * max_count, offset, out_count, 65201); } -Result dmntchtGetCheatById(DmntCheatEntry *out, u32 cheat_id) { +Result dmntchtGetCheatById(DmntCheatEntry* out, u32 cheat_id) +{ return serviceDispatchIn(&g_dmntchtSrv, 65202, cheat_id, .buffer_attrs = { SfBufferAttr_Out | SfBufferAttr_HipcMapAlias | SfBufferAttr_FixedSize }, - .buffers = { { out, sizeof(*out) } }, - ); + .buffers = { { out, sizeof(*out) } }, ); } -Result dmntchtToggleCheat(u32 cheat_id) { +Result dmntchtToggleCheat(u32 cheat_id) +{ return _dmntchtCmdInU32NoOut(cheat_id, 65203); } -Result dmntchtAddCheat(DmntCheatDefinition *cheat_def, bool enabled, u32 *out_cheat_id) { +Result dmntchtAddCheat(DmntCheatDefinition* cheat_def, bool enabled, u32* out_cheat_id) +{ const u8 in = enabled != 0; return serviceDispatchInOut(&g_dmntchtSrv, 65204, in, *out_cheat_id, .buffer_attrs = { SfBufferAttr_In | SfBufferAttr_HipcMapAlias | SfBufferAttr_FixedSize }, - .buffers = { { cheat_def, sizeof(*cheat_def) } }, - ); + .buffers = { { cheat_def, sizeof(*cheat_def) } }, ); } -Result dmntchtRemoveCheat(u32 cheat_id) { +Result dmntchtRemoveCheat(u32 cheat_id) +{ return _dmntchtCmdInU32NoOut(cheat_id, 65205); } -Result dmntchtReadStaticRegister(u64 *out, u8 which) { +Result dmntchtReadStaticRegister(u64* out, u8 which) +{ return serviceDispatchInOut(&g_dmntchtSrv, 65206, which, *out); } -Result dmntchtWriteStaticRegister(u8 which, u64 value) { +Result dmntchtWriteStaticRegister(u8 which, u64 value) +{ const struct { u64 which; u64 value; @@ -167,23 +188,28 @@ Result dmntchtWriteStaticRegister(u8 which, u64 value) { return serviceDispatchIn(&g_dmntchtSrv, 65207, in); } -Result dmntchtResetStaticRegisters() { +Result dmntchtResetStaticRegisters() +{ return _dmntchtCmdVoid(&g_dmntchtSrv, 65208); } -Result dmntchtGetFrozenAddressCount(u64 *out_count) { +Result dmntchtGetFrozenAddressCount(u64* out_count) +{ return _dmntchtGetCount(out_count, 65300); } -Result dmntchtGetFrozenAddresses(DmntFrozenAddressEntry *buffer, u64 max_count, u64 offset, u64 *out_count) { +Result dmntchtGetFrozenAddresses(DmntFrozenAddressEntry* buffer, u64 max_count, u64 offset, u64* out_count) +{ return _dmntchtGetEntries(buffer, sizeof(*buffer) * max_count, offset, out_count, 65301); } -Result dmntchtGetFrozenAddress(DmntFrozenAddressEntry *out, u64 address) { +Result dmntchtGetFrozenAddress(DmntFrozenAddressEntry* out, u64 address) +{ return serviceDispatchInOut(&g_dmntchtSrv, 65302, address, *out); } -Result dmntchtEnableFrozenAddress(u64 address, u64 width, u64 *out_value) { +Result dmntchtEnableFrozenAddress(u64 address, u64 width, u64* out_value) +{ const struct { u64 address; u64 width; @@ -191,6 +217,7 @@ Result dmntchtEnableFrozenAddress(u64 address, u64 width, u64 *out_value) { return serviceDispatchInOut(&g_dmntchtSrv, 65303, in, *out_value); } -Result dmntchtDisableFrozenAddress(u64 address) { +Result dmntchtDisableFrozenAddress(u64 address) +{ return serviceDispatchIn(&g_dmntchtSrv, 65304, address); } diff --git a/sysmodule/source/main.cpp b/sysmodule/source/main.cpp index a859da7..1ee3f5b 100644 --- a/sysmodule/source/main.cpp +++ b/sysmodule/source/main.cpp @@ -1,42 +1,40 @@ -#include +#include #include +#include #include -#include -#include +#include +#include #include -//#include -#include "splitter.hpp" #include "dmntcht.h" +#include "splitter.hpp" +#include "ulog/ulog.h" -std::fstream logger; - -extern "C" -{ +extern "C" { #define INNER_HEAP_SIZE 0x80000 - extern u32 __start__; +extern u32 __start__; - size_t nx_inner_heap_size = INNER_HEAP_SIZE; - char nx_inner_heap[INNER_HEAP_SIZE]; +size_t nx_inner_heap_size = INNER_HEAP_SIZE; +char nx_inner_heap[INNER_HEAP_SIZE]; - void __libnx_initheap(void); - void __appInit(void); - void __appExit(void); +void __libnx_initheap(void); +void __appInit(void); +void __appExit(void); } u32 __nx_applet_type = AppletType_None; void __libnx_initheap(void) { - void *addr = nx_inner_heap; + void* addr = nx_inner_heap; size_t size = nx_inner_heap_size; - extern char *fake_heap_start; - extern char *fake_heap_end; + extern char* fake_heap_start; + extern char* fake_heap_end; - fake_heap_start = (char *)addr; - fake_heap_end = (char *)addr + size; + fake_heap_start = (char*)addr; + fake_heap_end = (char*)addr + size; } void __appInit(void) @@ -46,11 +44,6 @@ void __appInit(void) if (R_FAILED(rc)) fatalThrow(MAKERESULT(Module_Libnx, LibnxError_InitFail_SM)); - // rc = twiliInitialize(); - // if (R_FAILED(rc)) - // fatalThrow(rc); - // twiliBindStdio(); - rc = hidInitialize(); if (R_FAILED(rc)) fatalThrow(rc); @@ -58,7 +51,7 @@ void __appInit(void) rc = hidPermitVibration(true); if (R_FAILED(rc)) fatalThrow(rc); - + rc = fsInitialize(); if (R_FAILED(rc)) fatalThrow(MAKERESULT(Module_Libnx, LibnxError_InitFail_FS)); @@ -91,7 +84,6 @@ void __appInit(void) cfg.sb_efficiency = 1; rc = socketInitialize(&cfg); - //logger.open("/splitnx.log"); } void __appExit(void) @@ -101,21 +93,46 @@ void __appExit(void) fsdevUnmountAll(); fsExit(); hidExit(); - //twiliExit(); smExit(); } -int main(int argc, char *argv[]) { +void ensureAppDir() +{ + struct stat st = { 0 }; + if (stat("/switch/SplitNX", &st) == -1) { + mkdir("/switch/SplitNX", 0700); + } +} + +static uint64_t get_time_us() +{ + struct timespec tp = { 0, 0 }; + clock_gettime(CLOCK_REALTIME, &tp); + return static_cast(tp.tv_sec) * 1000 * 1000 + tp.tv_nsec / 1000; +} + +static int put_str(void* handle, const char* str) +{ + auto* file_handle = reinterpret_cast(handle); + return fprintf(file_handle, "%s", str); +} + +int main(int argc, char* argv[]) +{ + ensureAppDir(); + logger_set_time_callback(get_time_us); + auto* fptr = fopen("/switch/SplitNX/debug.log", "w"); + logger_init(fptr, put_str); Splitter splitter = Splitter("/switch/SplitNX/splitter.txt"); - while (appletMainLoop()) - { + LOGGER_DEBUG("Starting SplitNx."); + + while (appletMainLoop()) { hidScanInput(); u64 kDown = hidKeysDown(CONTROLLER_P1_AUTO); u64 kHeld = hidKeysHeld(CONTROLLER_P1_AUTO); - if (!(~kHeld & (KEY_ZR | KEY_R)) && !(kHeld & KEY_ZL) && !(kHeld & KEY_L)) - { + if (!(~kHeld & (KEY_ZR | KEY_R)) && !(kHeld & KEY_ZL) && !(kHeld & KEY_L)) { if (kDown & KEY_PLUS) splitter.Connect(); else if (kDown & KEY_A) @@ -127,7 +144,7 @@ int main(int argc, char *argv[]) { else if (kDown & KEY_Y) splitter.Reset(); else if (kDown & KEY_DLEFT) - splitter.test_it(); + splitter.debug_first_mem(); else if (kDown & KEY_MINUS) splitter.Reload("/switch/SplitNX/splitter.txt"); } @@ -136,5 +153,8 @@ int main(int argc, char *argv[]) { splitter.Update(); } + LOGGER_DEBUG("Closing SplitNx."); + + fclose(fptr); return 0; } diff --git a/sysmodule/source/mp3.c b/sysmodule/source/mp3.c index 7f393e1..c1d07d5 100644 --- a/sysmodule/source/mp3.c +++ b/sysmodule/source/mp3.c @@ -1,33 +1,33 @@ -#include -#include -#include #include #include +#include +#include +#include #include - #define BUF_COUNT 2 -static size_t buffSize; -static mpg123_handle *mh = NULL; -static uint32_t rate; -static uint8_t channels; +static size_t buffSize; +static mpg123_handle* mh = NULL; +static uint32_t rate; +static uint8_t channels; -AudioOutBuffer* audout_released_buf; +AudioOutBuffer* audout_released_buf; -AudioOutBuffer audiobuf[BUF_COUNT]; -u8* buffData[BUF_COUNT]; -int curBuf = 0; -#define swapbuf (curBuf = (curBuf+1)%(BUF_COUNT)) +AudioOutBuffer audiobuf[BUF_COUNT]; +u8* buffData[BUF_COUNT]; +int curBuf = 0; +#define swapbuf (curBuf = (curBuf + 1) % (BUF_COUNT)) static Mutex mp3Mutex; -void mp3MutInit() { - mutexInit(&mp3Mutex); - - buffSize = 0x1000; - for(int curBuf = 0; curBuf < BUF_COUNT; curBuf++) { +void mp3MutInit() +{ + mutexInit(&mp3Mutex); + + buffSize = 0x1000; + for (int curBuf = 0; curBuf < BUF_COUNT; curBuf++) { buffData[curBuf] = memalign(0x1000, buffSize); } @@ -37,40 +37,34 @@ void mp3MutInit() { int initMp3(const char* file) { - int err = 0; - int encoding = 0; + int err = 0; + int encoding = 0; - if((err = mpg123_init()) != MPG123_OK) - return err; + if ((err = mpg123_init()) != MPG123_OK) + return err; mpg123_pars* pars = mpg123_new_pars(&err); mpg123_par(pars, MPG123_FORCE_RATE, audoutGetSampleRate(), 0); mpg123_par(pars, MPG123_FORCE_STEREO, 1, 0); - if((mh = mpg123_parnew(pars, NULL, &err)) == NULL) - { - printf("Error: %s\n", mpg123_plain_strerror(err)); - return err; - } - - + if ((mh = mpg123_parnew(pars, NULL, &err)) == NULL) { + printf("Error: %s\n", mpg123_plain_strerror(err)); + return err; + } - if(mpg123_open(mh, file) != MPG123_OK || - mpg123_getformat(mh, (long *) &rate, (int *) &channels, &encoding) != MPG123_OK) - { - printf("Trouble with mpg123: %s\n", mpg123_strerror(mh)); - return -1; - } + if (mpg123_open(mh, file) != MPG123_OK || mpg123_getformat(mh, (long*)&rate, (int*)&channels, &encoding) != MPG123_OK) { + printf("Trouble with mpg123: %s\n", mpg123_strerror(mh)); + return -1; + } - /* + /* * Ensure that this output format will not change (it might, when we allow * it). */ - mpg123_format_none(mh); - mpg123_format(mh, rate, channels, encoding); + mpg123_format_none(mh); + mpg123_format(mh, rate, channels, encoding); - - return 0; + return 0; } /** @@ -80,7 +74,7 @@ int initMp3(const char* file) */ uint32_t rateMp3(void) { - return rate; + return rate; } /** @@ -90,7 +84,7 @@ uint32_t rateMp3(void) */ uint8_t channelMp3(void) { - return channels; + return channels; } /** @@ -101,10 +95,10 @@ uint8_t channelMp3(void) */ uint64_t decodeMp3(void* buffer) { - memset(buffer, 0, buffSize); - size_t done = 0; - mpg123_read(mh, buffer, buffSize, &done); - return done / (sizeof(int16_t)); + memset(buffer, 0, buffSize); + size_t done = 0; + mpg123_read(mh, buffer, buffSize, &done); + return done / (sizeof(int16_t)); } /** @@ -115,14 +109,15 @@ void exitMp3(void) /*for(int curBuf = 0; curBuf < BUF_COUNT; curBuf++) { free(buffData[curBuf]); }*/ - mpg123_close(mh); - mpg123_delete(mh); - mpg123_exit(); + mpg123_close(mh); + mpg123_delete(mh); + mpg123_exit(); } -int fillBuf() { +int fillBuf() +{ int count = decodeMp3(buffData[curBuf]); - if(count == 0) + if (count == 0) return count; audiobuf[curBuf].next = 0; audiobuf[curBuf].buffer = buffData[curBuf]; @@ -134,33 +129,30 @@ int fillBuf() { return count; } - -void playMp3(const char* file) { - mutexLock(&mp3Mutex); +void playMp3(const char* file) +{ + mutexLock(&mp3Mutex); initMp3(file); u32 released_count = 0; int toPlayCount = 0; - for(int curBuf = 0; curBuf < BUF_COUNT/2; curBuf++) + for (int curBuf = 0; curBuf < BUF_COUNT / 2; curBuf++) toPlayCount += fillBuf() > 0; - int lastFill = 1; - while(appletMainLoop() && lastFill) - { - for(int curBuf = 0; curBuf < BUF_COUNT/2; curBuf++) { + while (appletMainLoop() && lastFill) { + for (int curBuf = 0; curBuf < BUF_COUNT / 2; curBuf++) { lastFill = fillBuf(); - toPlayCount += lastFill > 0; - } - for(int curBuf = 0; curBuf < BUF_COUNT/2 && toPlayCount--; curBuf++) + toPlayCount += lastFill > 0; + } + for (int curBuf = 0; curBuf < BUF_COUNT / 2 && toPlayCount--; curBuf++) audoutWaitPlayFinish(&audout_released_buf, &released_count, 1000000000L); - } - while(toPlayCount--) - audoutWaitPlayFinish(&audout_released_buf, &released_count, 1000000000L); + while (toPlayCount--) + audoutWaitPlayFinish(&audout_released_buf, &released_count, 1000000000L); exitMp3(); - mutexUnlock(&mp3Mutex); + mutexUnlock(&mp3Mutex); } \ No newline at end of file diff --git a/sysmodule/source/splitter.cpp b/sysmodule/source/splitter.cpp index e87fca7..488ad08 100644 --- a/sysmodule/source/splitter.cpp +++ b/sysmodule/source/splitter.cpp @@ -1,15 +1,14 @@ #include "splitter.hpp" #include "dmntcht.h" +#include "ulog/ulog.h" #include #include extern "C" { - #include "mp3.h" +#include "mp3.h" } -extern std::fstream logger; - Splitter::Splitter(std::string filename) { mp3MutInit(); @@ -18,7 +17,8 @@ Splitter::Splitter(std::string filename) Reload(filename); } -void Splitter::Reload(std::string filename) { +void Splitter::Reload(std::string filename) +{ std::fstream file; file.open(filename, std::fstream::in); file >> ip; @@ -27,37 +27,30 @@ void Splitter::Reload(std::string filename) { split s; s.valid = true; splits.clear(); - while (file >> s.type >> std::hex >> s.address >> std::dec >> s.op >> s.size >> s.value) - { + while (file >> s.type >> std::hex >> s.address >> std::dec >> s.op >> s.size >> s.value) { if (s.op.find("load") != std::string::npos) { s.op = s.op.substr(4); loading = s; - } - else + } else splits.push_back(s); } file.close(); - std::cout << splits.size() << std::endl; + LOGGER_DEBUG("Found %ld splits", splits.size()); } void Splitter::Update() { if (!connected) return; - - std::fstream file; - file.open("/splitnx.log", std::fstream::app); + if (send_msg("getsplitindex\r\n") == -1) { connected = false; playMp3("/switch/SplitNX/disconnect.mp3"); - } - else - { - std::cout << "updated" << std::endl; + } else { + LOGGER_DEBUG("updated configuration"); std::string ind; - if (recv_msg(ind) > 0) - { + if (recv_msg(ind) > 0) { size_t i = std::stoi(ind); if (i < 0 || i > splits.size()) return; @@ -65,24 +58,20 @@ void Splitter::Update() split s = splits[i]; auto val = readMemory(s.address, s.size, s.type); - file << "Memory addr " << std::hex << s.address << ": " << val << std::endl; - + LOGGER_DEBUG("Memory addr %ld: %lu", s.address, val); + if (doOperator(val, s.value, s.op)) Split(); } - if (loading.valid) - { + if (loading.valid) { SetLoading(doOperator(readMemory(loading.address, loading.size, loading.type), loading.value, loading.op)); } } - file.close(); } -void Splitter::test_it() { - std::fstream file; - file.open("/splitnx.log", std::fstream::app); - file << "Memory: " << readMemory(splits[0].address, splits[0].size, splits[0].type) << std::endl; - file.close(); +void Splitter::debug_first_mem() +{ + LOGGER_INFO("Memory: %lu", readMemory(splits[0].address, splits[0].size, splits[0].type)); } void Splitter::Connect() @@ -95,12 +84,11 @@ void Splitter::Connect() serv_addr.sin_port = htons(port); inet_aton(ip.c_str(), &serv_addr.sin_addr); - connected = (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) == 0); + connected = (connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) == 0); if (connected) playMp3("/switch/SplitNX/connect.mp3"); else playMp3("/switch/SplitNX/disconnect.mp3"); - } void Splitter::Split() @@ -123,13 +111,12 @@ void Splitter::Skip() send_msg("skipsplit\r\n"); } -void Splitter::SetLoading(bool loadingState) +void Splitter::SetLoading(bool loadingState) { - if (loadingState) + if (loadingState) send_msg("pausegametime\r\n"); else send_msg("unpausegametime\r\n"); - } ssize_t Splitter::send_msg(std::string msg) @@ -137,7 +124,7 @@ ssize_t Splitter::send_msg(std::string msg) return send(sock, msg.c_str(), msg.length(), 0); } -ssize_t Splitter::recv_msg(std::string &msg) +ssize_t Splitter::recv_msg(std::string& msg) { char buff[64]; ssize_t ret = recv(sock, buff, 32, 0); @@ -171,7 +158,7 @@ u64 readMemory(u64 address, size_t size, std::string type) u64 offset = 0; if (type == "heap") offset = metadata.heap_extents.base; - if (type == "main") + if (type == "main") offset = metadata.main_nso_extents.base; u64 val; diff --git a/sysmodule/vendor/ulog b/sysmodule/vendor/ulog new file mode 160000 index 0000000..738736d --- /dev/null +++ b/sysmodule/vendor/ulog @@ -0,0 +1 @@ +Subproject commit 738736d0e1a13851976442420dd62ac0f1979051