diff --git a/README.md b/README.md index 834dcd0..59d8261 100644 --- a/README.md +++ b/README.md @@ -13,9 +13,9 @@ setup ctrulib is just a library and needs a toolchain to function. we built ctrulib to be used in conjunction with devkitARM. you may find instructions on how to install devkitARM here : http://devkitpro.org/wiki/Getting_Started -once devkitARM is installed, you will need to manually patch it with the following : http://mtheall.com/~fincs/3dsdkA/ +The most recent devkitARM (r43) includes 3DS support and a prebuilt libctru. -that done, just checkout ctrulib, build it, set your CTRULIB path and you should be good to go ! +To keep up to date with the most recent changes you'll want to checkout ctrulib, build it and install it. license ======= diff --git a/examples/app_launch/Makefile b/examples/app_launch/Makefile index 568eda2..c4c758e 100644 --- a/examples/app_launch/Makefile +++ b/examples/app_launch/Makefile @@ -6,11 +6,6 @@ ifeq ($(strip $(DEVKITARM)),) $(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM") endif -ifeq ($(strip $(CTRULIB)),) -# THIS IS TEMPORARY - in the future it should be at $(DEVKITPRO)/libctru -$(error "Please set CTRULIB in your environment. export CTRULIB=libctru") -endif - TOPDIR ?= $(CURDIR) include $(DEVKITARM)/3ds_rules diff --git a/examples/gpu/Makefile b/examples/gpu/Makefile index 568eda2..c4c758e 100644 --- a/examples/gpu/Makefile +++ b/examples/gpu/Makefile @@ -6,11 +6,6 @@ ifeq ($(strip $(DEVKITARM)),) $(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM") endif -ifeq ($(strip $(CTRULIB)),) -# THIS IS TEMPORARY - in the future it should be at $(DEVKITPRO)/libctru -$(error "Please set CTRULIB in your environment. export CTRULIB=libctru") -endif - TOPDIR ?= $(CURDIR) include $(DEVKITARM)/3ds_rules diff --git a/examples/gpu/source/main.c b/examples/gpu/source/main.c index 17a4bee..5747637 100644 --- a/examples/gpu/source/main.c +++ b/examples/gpu/source/main.c @@ -9,6 +9,7 @@ #include #include +#include #include #include <3ds.h> @@ -167,8 +168,8 @@ void renderFrame() //setup lighting (this is specific to our shader) vect3Df_s lightDir=vnormf(vect3Df(cos(lightAngle), -1.0f, sin(lightAngle))); - GPU_SetUniform(SHDR_GetUniformRegister(shader, "lightDirection", 0), (u32*)(float[]){0.0f, -lightDir.z, -lightDir.y, -lightDir.x}, 4); - GPU_SetUniform(SHDR_GetUniformRegister(shader, "lightAmbient", 0), (u32*)(float[]){0.7f, 0.4f, 0.4f, 0.4f}, 4); + GPU_SetUniform(SHDR_GetUniformRegister(shader, "lightDirection", 0), (u32*)(float[]){0.0f, -lightDir.z, -lightDir.y, -lightDir.x}, 1); + GPU_SetUniform(SHDR_GetUniformRegister(shader, "lightAmbient", 0), (u32*)(float[]){0.7f, 0.4f, 0.4f, 0.4f}, 1); //initialize projection matrix to standard perspective stuff gsMatrixMode(GS_PROJECTION); diff --git a/examples/http/Makefile b/examples/http/Makefile new file mode 100644 index 0000000..c4c758e --- /dev/null +++ b/examples/http/Makefile @@ -0,0 +1,170 @@ +#--------------------------------------------------------------------------------- +.SUFFIXES: +#--------------------------------------------------------------------------------- + +ifeq ($(strip $(DEVKITARM)),) +$(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM") +endif + +TOPDIR ?= $(CURDIR) +include $(DEVKITARM)/3ds_rules + +#--------------------------------------------------------------------------------- +# TARGET is the name of the output +# BUILD is the directory where object files & intermediate files will be placed +# SOURCES is a list of directories containing source code +# DATA is a list of directories containing data files +# INCLUDES is a list of directories containing header files +# +# NO_SMDH: if set to anything, no SMDH file is generated. +# APP_TITLE is the name of the app stored in the SMDH file (Optional) +# APP_DESCRIPTION is the description of the app stored in the SMDH file (Optional) +# APP_AUTHOR is the author of the app stored in the SMDH file (Optional) +# ICON is the filename of the icon (.png), relative to the project folder. +# If not set, it attempts to use one of the following (in this order): +# - .png +# - icon.png +# - /default_icon.png +#--------------------------------------------------------------------------------- +TARGET := $(notdir $(CURDIR)) +BUILD := build +SOURCES := source +DATA := data +INCLUDES := include + +#--------------------------------------------------------------------------------- +# options for code generation +#--------------------------------------------------------------------------------- +ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=softfp + +CFLAGS := -g -Wall -O2 -mword-relocations \ + -fomit-frame-pointer -ffast-math \ + $(ARCH) + +CFLAGS += $(INCLUDE) -DARM11 -D_3DS + +CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11 + +ASFLAGS := -g $(ARCH) +LDFLAGS = -specs=3dsx.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map) + +LIBS := -lctru -lm + +#--------------------------------------------------------------------------------- +# list of directories containing libraries, this must be the top level containing +# include and lib +#--------------------------------------------------------------------------------- +LIBDIRS := $(CTRULIB) + + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(BUILD),$(notdir $(CURDIR))) +#--------------------------------------------------------------------------------- + +export OUTPUT := $(CURDIR)/$(TARGET) +export TOPDIR := $(CURDIR) + +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ + $(foreach dir,$(DATA),$(CURDIR)/$(dir)) + +export DEPSDIR := $(CURDIR)/$(BUILD) + +CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) +CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) +SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) +BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) + +#--------------------------------------------------------------------------------- +# use CXX for linking C++ projects, CC for standard C +#--------------------------------------------------------------------------------- +ifeq ($(strip $(CPPFILES)),) +#--------------------------------------------------------------------------------- + export LD := $(CC) +#--------------------------------------------------------------------------------- +else +#--------------------------------------------------------------------------------- + export LD := $(CXX) +#--------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------- + +export OFILES := $(addsuffix .o,$(BINFILES)) \ + $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) + +export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + -I$(CURDIR)/$(BUILD) + +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) + +ifeq ($(strip $(ICON)),) + icons := $(wildcard *.png) + ifneq (,$(findstring $(TARGET).png,$(icons))) + export APP_ICON := $(TOPDIR)/$(TARGET).png + else + ifneq (,$(findstring icon.png,$(icons))) + export APP_ICON := $(TOPDIR)/icon.png + endif + endif +else + export APP_ICON := $(TOPDIR)/$(ICON) +endif + +.PHONY: $(BUILD) clean all + +#--------------------------------------------------------------------------------- +all: $(BUILD) + +$(BUILD): + @[ -d $@ ] || mkdir -p $@ + @make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(BUILD) $(TARGET).3dsx $(OUTPUT).smdh $(TARGET).elf + + +#--------------------------------------------------------------------------------- +else + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +ifeq ($(strip $(NO_SMDH)),) +.PHONY: all +all : $(OUTPUT).3dsx $(OUTPUT).smdh +endif +$(OUTPUT).3dsx : $(OUTPUT).elf +$(OUTPUT).elf : $(OFILES) + +#--------------------------------------------------------------------------------- +# you need a rule like this for each extension you use as binary data +#--------------------------------------------------------------------------------- +%.bin.o : %.bin +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + +# WARNING: This is not the right way to do this! TODO: Do it right! +#--------------------------------------------------------------------------------- +%.vsh.o : %.vsh +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @python $(AEMSTRO)/aemstro_as.py $< ../$(notdir $<).shbin + @bin2s ../$(notdir $<).shbin | $(PREFIX)as -o $@ + @echo "extern const u8" `(echo $(notdir $<).shbin | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"_end[];" > `(echo $(notdir $<).shbin | tr . _)`.h + @echo "extern const u8" `(echo $(notdir $<).shbin | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"[];" >> `(echo $(notdir $<).shbin | tr . _)`.h + @echo "extern const u32" `(echo $(notdir $<).shbin | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`_size";" >> `(echo $(notdir $<).shbin | tr . _)`.h + @rm ../$(notdir $<).shbin + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------------- diff --git a/examples/http/README.md b/examples/http/README.md new file mode 100644 index 0000000..8472ee2 --- /dev/null +++ b/examples/http/README.md @@ -0,0 +1,4 @@ +# http + +This is an example for using HTTPC. This downloads a raw image for displaying on the top-screen. The URL used here is a LAN-only one, hence this URL must be changed before building+running this example. + diff --git a/examples/http/source/main.c b/examples/http/source/main.c new file mode 100644 index 0000000..bb93652 --- /dev/null +++ b/examples/http/source/main.c @@ -0,0 +1,131 @@ +#include +#include + +#include <3ds.h> + +Result http_download(httpcContext *context)//This error handling needs updated with proper text printing once ctrulib itself supports that. +{ + Result ret=0; + u8* framebuf_top, *framebuf_bottom; + u32 statuscode=0; + u32 size=0, contentsize=0; + u8 *buf; + + framebuf_bottom = gfxGetFramebuffer(GFX_BOTTOM, GFX_LEFT, NULL, NULL); + memset(framebuf_bottom, 0x40, 240*320*3); + gfxFlushBuffers(); + gfxSwapBuffers(); + + framebuf_bottom = gfxGetFramebuffer(GFX_BOTTOM, GFX_LEFT, NULL, NULL); + memset(framebuf_bottom, 0x40, 240*320*3); + gfxFlushBuffers(); + gfxSwapBuffers(); + gspWaitForVBlank(); + + ret = httpcBeginRequest(context); + if(ret!=0)return ret; + + ret = httpcGetResponseStatusCode(context, &statuscode, 0); + if(ret!=0)return ret; + + if(statuscode!=200)return -2; + + ret=httpcGetDownloadSizeState(context, NULL, &contentsize); + if(ret!=0)return ret; + + buf = (u8*)malloc(contentsize); + if(buf==NULL)return -1; + memset(buf, 0, contentsize); + + framebuf_bottom = gfxGetFramebuffer(GFX_BOTTOM, GFX_LEFT, NULL, NULL); + memset(framebuf_bottom, 0xc0, 240*320*3); + gfxFlushBuffers(); + gfxSwapBuffers(); + + framebuf_bottom = gfxGetFramebuffer(GFX_BOTTOM, GFX_LEFT, NULL, NULL); + memset(framebuf_bottom, 0xc0, 240*320*3); + gfxFlushBuffers(); + gfxSwapBuffers(); + gspWaitForVBlank(); + + framebuf_top = gfxGetFramebuffer(GFX_TOP, GFX_LEFT, NULL, NULL); + framebuf_bottom = gfxGetFramebuffer(GFX_BOTTOM, GFX_LEFT, NULL, NULL); + + ret = httpcDownloadData(context, buf, contentsize, NULL); + if(ret!=0) + { + free(buf); + return ret; + } + + size = contentsize; + if(size>(240*400*3))size = 240*400*3; + + memset(framebuf_bottom, 0xff, 240*320*3); + memcpy(framebuf_top, buf, size); + + gfxFlushBuffers(); + gfxSwapBuffers(); + + framebuf_top = gfxGetFramebuffer(GFX_TOP, GFX_LEFT, NULL, NULL); + framebuf_bottom = gfxGetFramebuffer(GFX_BOTTOM, GFX_LEFT, NULL, NULL); + + memset(framebuf_bottom, 0xff, 240*320*3); + memcpy(framebuf_top, buf, size); + + gfxFlushBuffers(); + gfxSwapBuffers(); + gspWaitForVBlank(); + + free(buf); + + return 0; +} + +int main() +{ + Result ret=0; + httpcContext context; + + // Initialize services + srvInit(); + aptInit(); + hidInit(NULL); + gfxInit(); + //gfxSet3D(true); // uncomment if using stereoscopic 3D + httpcInit(); + + ret = httpcOpenContext(&context, "http://10.0.0.3/httpexample_rawimg.bin", 0);//Change this to your own URL. + + if(ret==0) + { + ret=http_download(&context); + httpcCloseContext(&context); + } + + // Main loop + while (aptMainLoop()) + { + gspWaitForVBlank(); + hidScanInput(); + + // Your code goes here + + u32 kDown = hidKeysDown(); + if (kDown & KEY_START) + break; // break in order to return to hbmenu + + // Flush and swap framebuffers + gfxFlushBuffers(); + gfxSwapBuffers(); + } + + // Exit services + httpcExit(); + gfxExit(); + hidExit(); + aptExit(); + srvExit(); + return 0; +} + diff --git a/examples/libapplet_launch/Makefile b/examples/libapplet_launch/Makefile new file mode 100644 index 0000000..c4c758e --- /dev/null +++ b/examples/libapplet_launch/Makefile @@ -0,0 +1,170 @@ +#--------------------------------------------------------------------------------- +.SUFFIXES: +#--------------------------------------------------------------------------------- + +ifeq ($(strip $(DEVKITARM)),) +$(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM") +endif + +TOPDIR ?= $(CURDIR) +include $(DEVKITARM)/3ds_rules + +#--------------------------------------------------------------------------------- +# TARGET is the name of the output +# BUILD is the directory where object files & intermediate files will be placed +# SOURCES is a list of directories containing source code +# DATA is a list of directories containing data files +# INCLUDES is a list of directories containing header files +# +# NO_SMDH: if set to anything, no SMDH file is generated. +# APP_TITLE is the name of the app stored in the SMDH file (Optional) +# APP_DESCRIPTION is the description of the app stored in the SMDH file (Optional) +# APP_AUTHOR is the author of the app stored in the SMDH file (Optional) +# ICON is the filename of the icon (.png), relative to the project folder. +# If not set, it attempts to use one of the following (in this order): +# - .png +# - icon.png +# - /default_icon.png +#--------------------------------------------------------------------------------- +TARGET := $(notdir $(CURDIR)) +BUILD := build +SOURCES := source +DATA := data +INCLUDES := include + +#--------------------------------------------------------------------------------- +# options for code generation +#--------------------------------------------------------------------------------- +ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=softfp + +CFLAGS := -g -Wall -O2 -mword-relocations \ + -fomit-frame-pointer -ffast-math \ + $(ARCH) + +CFLAGS += $(INCLUDE) -DARM11 -D_3DS + +CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11 + +ASFLAGS := -g $(ARCH) +LDFLAGS = -specs=3dsx.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map) + +LIBS := -lctru -lm + +#--------------------------------------------------------------------------------- +# list of directories containing libraries, this must be the top level containing +# include and lib +#--------------------------------------------------------------------------------- +LIBDIRS := $(CTRULIB) + + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(BUILD),$(notdir $(CURDIR))) +#--------------------------------------------------------------------------------- + +export OUTPUT := $(CURDIR)/$(TARGET) +export TOPDIR := $(CURDIR) + +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ + $(foreach dir,$(DATA),$(CURDIR)/$(dir)) + +export DEPSDIR := $(CURDIR)/$(BUILD) + +CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) +CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) +SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) +BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) + +#--------------------------------------------------------------------------------- +# use CXX for linking C++ projects, CC for standard C +#--------------------------------------------------------------------------------- +ifeq ($(strip $(CPPFILES)),) +#--------------------------------------------------------------------------------- + export LD := $(CC) +#--------------------------------------------------------------------------------- +else +#--------------------------------------------------------------------------------- + export LD := $(CXX) +#--------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------- + +export OFILES := $(addsuffix .o,$(BINFILES)) \ + $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) + +export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + -I$(CURDIR)/$(BUILD) + +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) + +ifeq ($(strip $(ICON)),) + icons := $(wildcard *.png) + ifneq (,$(findstring $(TARGET).png,$(icons))) + export APP_ICON := $(TOPDIR)/$(TARGET).png + else + ifneq (,$(findstring icon.png,$(icons))) + export APP_ICON := $(TOPDIR)/icon.png + endif + endif +else + export APP_ICON := $(TOPDIR)/$(ICON) +endif + +.PHONY: $(BUILD) clean all + +#--------------------------------------------------------------------------------- +all: $(BUILD) + +$(BUILD): + @[ -d $@ ] || mkdir -p $@ + @make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(BUILD) $(TARGET).3dsx $(OUTPUT).smdh $(TARGET).elf + + +#--------------------------------------------------------------------------------- +else + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +ifeq ($(strip $(NO_SMDH)),) +.PHONY: all +all : $(OUTPUT).3dsx $(OUTPUT).smdh +endif +$(OUTPUT).3dsx : $(OUTPUT).elf +$(OUTPUT).elf : $(OFILES) + +#--------------------------------------------------------------------------------- +# you need a rule like this for each extension you use as binary data +#--------------------------------------------------------------------------------- +%.bin.o : %.bin +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + +# WARNING: This is not the right way to do this! TODO: Do it right! +#--------------------------------------------------------------------------------- +%.vsh.o : %.vsh +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @python $(AEMSTRO)/aemstro_as.py $< ../$(notdir $<).shbin + @bin2s ../$(notdir $<).shbin | $(PREFIX)as -o $@ + @echo "extern const u8" `(echo $(notdir $<).shbin | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"_end[];" > `(echo $(notdir $<).shbin | tr . _)`.h + @echo "extern const u8" `(echo $(notdir $<).shbin | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"[];" >> `(echo $(notdir $<).shbin | tr . _)`.h + @echo "extern const u32" `(echo $(notdir $<).shbin | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`_size";" >> `(echo $(notdir $<).shbin | tr . _)`.h + @rm ../$(notdir $<).shbin + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------------- diff --git a/examples/libapplet_launch/README.md b/examples/libapplet_launch/README.md new file mode 100644 index 0000000..3b1478b --- /dev/null +++ b/examples/libapplet_launch/README.md @@ -0,0 +1,7 @@ +libapplet_launch +======= + +Example for launching library applets. This launches the extrapad library applet(Circle Pad Pro calibration applet) when the B button is pressed. + +This is not usable from the homebrew launcher. + diff --git a/examples/libapplet_launch/source/main.c b/examples/libapplet_launch/source/main.c new file mode 100644 index 0000000..d4244a3 --- /dev/null +++ b/examples/libapplet_launch/source/main.c @@ -0,0 +1,50 @@ +#include <3ds.h> + +int main() +{ + u32 val, i; + + // Initialize services + srvInit(); + aptInit(); + hidInit(NULL); + gfxInit(); + //gfxSet3D(true); // uncomment if using stereoscopic 3D + + val = 0x22447899; + + // Main loop + while (aptMainLoop()) + { + gspWaitForVBlank(); + hidScanInput(); + + // Your code goes here + + u32 kDown = hidKeysDown(); + if (kDown & KEY_START) + break; // break in order to return to hbmenu + + if (kDown & KEY_B)APT_LaunchLibraryApplet(0x408, 0, NULL, 0);//Launch the extrapad library applet when button B is pressed. + + // Example rendering code that displays a white pixel + // Please note that the 3DS screens are sideways (thus 240x400 and 240x320) + u32* fb = (u32*)gfxGetFramebuffer(GFX_TOP, GFX_LEFT, NULL, NULL); + + for(i=0; i<(0x46500>>2); i++)fb[i] = val; + + val+= 0x44; + + // Flush and swap framebuffers + gfxFlushBuffers(); + gfxSwapBuffers(); + } + + // Exit services + gfxExit(); + hidExit(); + aptExit(); + srvExit(); + return 0; +} + diff --git a/examples/mic/Makefile b/examples/mic/Makefile index 568eda2..c4c758e 100644 --- a/examples/mic/Makefile +++ b/examples/mic/Makefile @@ -6,11 +6,6 @@ ifeq ($(strip $(DEVKITARM)),) $(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM") endif -ifeq ($(strip $(CTRULIB)),) -# THIS IS TEMPORARY - in the future it should be at $(DEVKITPRO)/libctru -$(error "Please set CTRULIB in your environment. export CTRULIB=libctru") -endif - TOPDIR ?= $(CURDIR) include $(DEVKITARM)/3ds_rules diff --git a/examples/mic/source/main.c b/examples/mic/source/main.c index 8e6fc11..89ece51 100644 --- a/examples/mic/source/main.c +++ b/examples/mic/source/main.c @@ -11,13 +11,14 @@ int main() u8 *audiobuf; u32 audiobuf_size = 0x100000, audiobuf_pos = 0; u8 control=0x40; + u32 audio_initialized = 0; srvInit(); aptInit(); gfxInit(); hidInit(NULL); - CSND_initialize(NULL); + if(CSND_initialize(NULL)==0)audio_initialized = 1; sharedmem = (u32*)memalign(0x1000, sharedmem_size); audiobuf = linearAlloc(audiobuf_size); @@ -26,52 +27,63 @@ int main() while(aptMainLoop()) { - framebuf = gfxGetFramebuffer(GFX_TOP, GFX_LEFT, NULL, NULL); hidScanInput(); + gspWaitForVBlank(); - if(hidKeysDown() & KEY_A) + u32 kDown = hidKeysDown(); + if (kDown & KEY_START) + break; // break in order to return to hbmenu + + if(audio_initialized) { - audiobuf_pos = 0; - - CSND_setchannel_playbackstate(0x8, 0);//Stop audio playback. - CSND_sharedmemtype0_cmdupdatestate(0); - - MIC_SetRecording(1); - - memset(framebuf, 0x20, 0x46500); - } - - if((hidKeysHeld() & KEY_A) && audiobuf_pos < audiobuf_size) - { - audiobuf_pos+= MIC_ReadAudioData(&audiobuf[audiobuf_pos], audiobuf_size-audiobuf_pos, 1); - if(audiobuf_pos > audiobuf_size)audiobuf_pos = audiobuf_size; - - memset(framebuf, 0x60, 0x46500); - } - - if(hidKeysUp() & KEY_A) - { - MIC_SetRecording(0); - GSPGPU_FlushDataCache(NULL, audiobuf, audiobuf_pos); - CSND_playsound(0x8, CSND_LOOP_DISABLE, CSND_ENCODING_PCM16, 16000, (u32*)audiobuf, NULL, audiobuf_pos, 2, 0); - - memset(framebuf, 0xe0, 0x46500); - - gfxFlushBuffers(); - gfxSwapBuffers(); - framebuf = gfxGetFramebuffer(GFX_TOP, GFX_LEFT, NULL, NULL); - memset(framebuf, 0xe0, 0x46500); + + if(kDown & KEY_A) + { + audiobuf_pos = 0; + + CSND_setchannel_playbackstate(0x8, 0);//Stop audio playback. + CSND_sharedmemtype0_cmdupdatestate(0); + + MIC_SetRecording(1); + + memset(framebuf, 0x20, 0x46500); + } + + if((hidKeysHeld() & KEY_A) && audiobuf_pos < audiobuf_size) + { + audiobuf_pos+= MIC_ReadAudioData(&audiobuf[audiobuf_pos], audiobuf_size-audiobuf_pos, 1); + if(audiobuf_pos > audiobuf_size)audiobuf_pos = audiobuf_size; + + memset(framebuf, 0x60, 0x46500); + } + + if(hidKeysUp() & KEY_A) + { + MIC_SetRecording(0); + GSPGPU_FlushDataCache(NULL, audiobuf, audiobuf_pos); + CSND_playsound(0x8, CSND_LOOP_DISABLE, CSND_ENCODING_PCM16, 16000, (u32*)audiobuf, NULL, audiobuf_pos, 2, 0); + + memset(framebuf, 0xe0, 0x46500); + + gfxFlushBuffers(); + gfxSwapBuffers(); + + framebuf = gfxGetFramebuffer(GFX_TOP, GFX_LEFT, NULL, NULL); + memset(framebuf, 0xe0, 0x46500); + } } gfxFlushBuffers(); gfxSwapBuffers(); - gspWaitForVBlank(); } MIC_Shutdown(); - CSND_shutdown(); + if(audio_initialized)CSND_shutdown(); + + free(sharedmem); + linearFree(audiobuf); hidExit(); gfxExit(); diff --git a/examples/mvd/Makefile b/examples/mvd/Makefile index 568eda2..c4c758e 100644 --- a/examples/mvd/Makefile +++ b/examples/mvd/Makefile @@ -6,11 +6,6 @@ ifeq ($(strip $(DEVKITARM)),) $(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM") endif -ifeq ($(strip $(CTRULIB)),) -# THIS IS TEMPORARY - in the future it should be at $(DEVKITPRO)/libctru -$(error "Please set CTRULIB in your environment. export CTRULIB=libctru") -endif - TOPDIR ?= $(CURDIR) include $(DEVKITARM)/3ds_rules diff --git a/examples/mvd/source/main.c b/examples/mvd/source/main.c index b573f88..3908a18 100644 --- a/examples/mvd/source/main.c +++ b/examples/mvd/source/main.c @@ -1,4 +1,6 @@ #include +#include + #include <3ds.h> #include "costable.h" diff --git a/examples/sdmc/Makefile b/examples/sdmc/Makefile index 568eda2..c4c758e 100644 --- a/examples/sdmc/Makefile +++ b/examples/sdmc/Makefile @@ -6,11 +6,6 @@ ifeq ($(strip $(DEVKITARM)),) $(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM") endif -ifeq ($(strip $(CTRULIB)),) -# THIS IS TEMPORARY - in the future it should be at $(DEVKITPRO)/libctru -$(error "Please set CTRULIB in your environment. export CTRULIB=libctru") -endif - TOPDIR ?= $(CURDIR) include $(DEVKITARM)/3ds_rules diff --git a/examples/sdmc/source/main.c b/examples/sdmc/source/main.c index 6b5a29b..c65292f 100644 --- a/examples/sdmc/source/main.c +++ b/examples/sdmc/source/main.c @@ -5,6 +5,7 @@ //this example shows you how to load a binary image file from the SD card and display it on the lower screen //for this to work you should copy test.bin to the root of your SD card //this file was generated with GIMP by saving a 240x320 image to raw RGB +#include #include <3ds.h> #include "costable.h" @@ -100,6 +101,7 @@ int main(int argc, char** argv) //closing all handles is super important svcCloseHandle(fileHandle); //closing all services even more so + fsExit(); gfxExit(); hidExit(); aptExit(); diff --git a/libctru/Makefile b/libctru/Makefile index d1174a3..37ed8e8 100644 --- a/libctru/Makefile +++ b/libctru/Makefile @@ -9,7 +9,7 @@ endif include $(DEVKITARM)/base_rules export LIBCTRU_MAJOR := 0 -export LIBCTRU_MINOR := 1 +export LIBCTRU_MINOR := 2 export LIBCTRU_PATCH := 0 @@ -105,6 +105,8 @@ dist-bin: all dist-src: @tar -cjf libctru-src-$(VERSION).tar.bz2 include source Makefile Doxyfile Doxyfile.internal default_icon.png +dist: dist-src dist-bin + install: dist-bin mkdir -p $(DEVKITPRO)/libctru bzip2 -cd libctru-$(VERSION).tar.bz2 | tar -x -C $(DEVKITPRO)/libctru diff --git a/libctru/include/3ds.h b/libctru/include/3ds.h index 65bf5a7..beec914 100644 --- a/libctru/include/3ds.h +++ b/libctru/include/3ds.h @@ -15,6 +15,7 @@ extern "C" { #include <3ds/services/ac.h> #include <3ds/services/apt.h> #include <3ds/services/cfgnor.h> +#include <3ds/services/cfgu.h> #include <3ds/services/csnd.h> #include <3ds/services/fs.h> #include <3ds/services/gsp.h> diff --git a/libctru/include/3ds/gfx.h b/libctru/include/3ds/gfx.h index 7953ca6..e7b33d3 100644 --- a/libctru/include/3ds/gfx.h +++ b/libctru/include/3ds/gfx.h @@ -1,5 +1,6 @@ #pragma once #include <3ds/types.h> +#include <3ds/services/gsp.h> typedef enum { @@ -20,6 +21,8 @@ void gfxExit(); //control stuff void gfxSet3D(bool enable); +void gfxSetScreenFormat(gfxScreen_t screen, GSP_FramebufferFormats format); +void gfxSetDoubleBuffering(bool doubleBuffering); void gfxFlushBuffers(); void gfxSwapBuffers(); void gfxSwapBuffersGpu(); diff --git a/libctru/include/3ds/gpu/shdr.h b/libctru/include/3ds/gpu/shdr.h index 459aa0b..02b5128 100644 --- a/libctru/include/3ds/gpu/shdr.h +++ b/libctru/include/3ds/gpu/shdr.h @@ -59,7 +59,7 @@ typedef struct{ DVLB_s* SHDR_ParseSHBIN(u32* shbinData, u32 shbinSize); void SHDR_UseProgram(DVLB_s* dvlb, u8 id); void SHDR_FreeDVLB(DVLB_s* dvlb); -s8 SHDR_GetUniformRegister(DVLB_s* dvlb, char* name, u8 programID); +s8 SHDR_GetUniformRegister(DVLB_s* dvlb, const char* name, u8 programID); void DVLP_SendCode(DVLP_s* dvlp); void DVLP_SendOpDesc(DVLP_s* dvlp); diff --git a/libctru/include/3ds/linear.h b/libctru/include/3ds/linear.h index 8fe2c7d..8722f81 100644 --- a/libctru/include/3ds/linear.h +++ b/libctru/include/3ds/linear.h @@ -2,7 +2,7 @@ // Functions for allocating/deallocating memory from linear heap void* linearAlloc(size_t size); // returns a 16-byte aligned address -void* linearMemAlign(size_t size, size_t alignment); // WARNING: wastes 'alignment' bytes +void* linearMemAlign(size_t size, size_t alignment); void* linearRealloc(void* mem, size_t size); // not implemented yet void linearFree(void* mem); u32 linearSpaceFree(); // get free linear space in bytes diff --git a/libctru/include/3ds/services/apt.h b/libctru/include/3ds/services/apt.h index af8fd5b..15db7b7 100644 --- a/libctru/include/3ds/services/apt.h +++ b/libctru/include/3ds/services/apt.h @@ -17,7 +17,9 @@ typedef enum{ APP_EXITING, APP_SUSPENDING, APP_SLEEPMODE, - APP_PREPARE_SLEEPMODE + APP_PREPARE_SLEEPMODE, + APP_APPLETSTARTED, + APP_APPLETCLOSED }APP_STATUS; enum { @@ -58,6 +60,7 @@ Result APT_Enable(Handle* handle, u32 a); Result APT_GetAppletManInfo(Handle* handle, u8 inval, u8 *outval8, u32 *outval32, NS_APPID *menu_appid, NS_APPID *active_appid); Result APT_PrepareToJumpToHomeMenu(Handle* handle); Result APT_JumpToHomeMenu(Handle* handle, u32 a, u32 b, u32 c); +Result APT_IsRegistered(Handle* handle, NS_APPID appID, u8* out); Result APT_InquireNotification(Handle* handle, u32 appID, u8* signalType); Result APT_NotifyToWait(Handle* handle, NS_APPID appID); Result APT_AppletUtility(Handle* handle, u32* out, u32 a, u32 size1, u8* buf1, u32 size2, u8* buf2); @@ -76,4 +79,7 @@ Result APT_CheckNew3DS_System(Handle* handle, u8 *out); Result APT_CheckNew3DS(Handle* handle, u8 *out); Result APT_PrepareToDoAppJump(Handle* handle, u8 flags, u64 programID, u8 mediatype); Result APT_DoAppJump(Handle* handle, u32 NSbuf0Size, u32 NSbuf1Size, u8 *NSbuf0Ptr, u8 *NSbuf1Ptr); +Result APT_PrepareToStartLibraryApplet(Handle* handle, NS_APPID appID); +Result APT_StartLibraryApplet(Handle* handle, NS_APPID appID, Handle inhandle, u32 *parambuf, u32 parambufsize); +Result APT_LaunchLibraryApplet(NS_APPID appID, Handle inhandle, u32 *parambuf, u32 parambufsize);//This should be used for launching library applets, this uses the above APT_StartLibraryApplet/APT_PrepareToStartLibraryApplet funcs + apt*Session(). parambuf is used for APT params input, when the applet closes the output param block is copied here. This is not usable from the homebrew launcher. This is broken: when the applet does get launched at all, the applet process doesn't actually get terminated when the applet gets closed. diff --git a/libctru/include/3ds/services/cfgu.h b/libctru/include/3ds/services/cfgu.h new file mode 100644 index 0000000..036e7d2 --- /dev/null +++ b/libctru/include/3ds/services/cfgu.h @@ -0,0 +1,10 @@ +#pragma once + +Result initCfgu(void); +Result exitCfgu(void); + +Result CFGU_GetRegionCanadaUSA(u8* value); +Result CFGU_GetSystemModel(u8* model); +Result CFGU_GetModelNintendo2DS(u8* value); +Result CFGU_GetCountryCodeString(u16 code, u16* string); +Result CFGU_GetCountryCodeID(u16 string, u16* code); diff --git a/libctru/include/3ds/services/fs.h b/libctru/include/3ds/services/fs.h index 36526f9..b062f8d 100644 --- a/libctru/include/3ds/services/fs.h +++ b/libctru/include/3ds/services/fs.h @@ -1,5 +1,4 @@ #pragma once -#include #include <3ds/types.h> /*! @file FS.h @@ -128,25 +127,11 @@ typedef struct u64 fileSize; //!< file size } FS_dirent; -/*! Create an FS_path from a type and data pointer. - * - * @param[in] type Path type. - * @param[in] path Pointer to path data. - * - * @returns FS_path - * - * @sa FS_pathType - */ -static inline FS_path -FS_makePath(FS_pathType type, - const char *path) -{ - return (FS_path){type, strlen(path)+1, (const u8*)path}; -} - Result fsInit(void); Result fsExit(void); +FS_path FS_makePath(FS_pathType type, const char *path); + Result FSUSER_Initialize(Handle* handle); Result FSUSER_OpenArchive(Handle* handle, FS_archive* archive); Result FSUSER_OpenDirectory(Handle* handle, Handle* out, FS_archive archive, FS_path dirLowPath); @@ -156,9 +141,11 @@ Result FSUSER_CloseArchive(Handle* handle, FS_archive* archive); Result FSUSER_CreateDirectory(Handle* handle, FS_archive archive, FS_path dirLowPath); Result FSUSER_DeleteFile(Handle *handle, FS_archive archive, FS_path fileLowPath); Result FSUSER_DeleteDirectory(Handle *handle, FS_archive archive, FS_path dirLowPath); +Result FSUSER_RenameFile(Handle *handle, FS_archive srcArchive, FS_path srcFileLowPath, FS_archive destArchive, FS_path destFileLowPath); +Result FSUSER_RenameDirectory(Handle *handle, FS_archive srcArchive, FS_path srcDirLowPath, FS_archive destArchive, FS_path destDirLowPath); Result FSUSER_GetSdmcArchiveResource(Handle *handle, u32 *sectorSize, u32 *clusterSize, u32 *numClusters, u32 *freeClusters); -Result FSUSER_IsSdmcDetected(Handle *handle, u32 *detected); -Result FSUSER_IsSdmcWritable(Handle *handle, u32 *writable); +Result FSUSER_IsSdmcDetected(Handle *handle, u8 *detected); +Result FSUSER_IsSdmcWritable(Handle *handle, u8 *writable); Result FSFILE_Close(Handle handle); Result FSFILE_Read(Handle handle, u32 *bytesRead, u64 offset, void *buffer, u32 size); diff --git a/libctru/include/3ds/services/gsp.h b/libctru/include/3ds/services/gsp.h index d324b9a..e65245d 100644 --- a/libctru/include/3ds/services/gsp.h +++ b/libctru/include/3ds/services/gsp.h @@ -15,11 +15,11 @@ typedef struct typedef enum { - GSP_RGBA8_OES=0, - GSP_BGR8_OES=1, - GSP_RGB565_OES=2, - GSP_RGB5_A1_OES=3, - GSP_RGBA4_OES=4 + GSP_RGBA8_OES=0, //pixel_size = 4-bytes + GSP_BGR8_OES=1, //pixel_size = 3-bytes + GSP_RGB565_OES=2, //pixel_size = 2-bytes + GSP_RGB5_A1_OES=3, //pixel_size = 2-bytes + GSP_RGBA4_OES=4 //pixel_size = 2-bytes }GSP_FramebufferFormats; typedef struct//See this for GSP_CaptureInfoEntry and GSP_CaptureInfo: http://3dbrew.org/wiki/GSPGPU:ImportDisplayCaptureInfo diff --git a/libctru/include/3ds/services/httpc.h b/libctru/include/3ds/services/httpc.h index 5e53e6f..06bc877 100644 --- a/libctru/include/3ds/services/httpc.h +++ b/libctru/include/3ds/services/httpc.h @@ -1,5 +1,32 @@ #pragma once +typedef struct { + Handle servhandle; + u32 httphandle; +} httpcContext; + +typedef enum{ + HTTPCREQSTAT_INPROGRESS_REQSENT = 0x5, + HTTPCREQSTAT_DLREADY = 0x7 +} httpcReqStatus; + +#define HTTPC_RESULTCODE_DOWNLOADPENDING 0xd840a02b + +Result httpcInit(); +void httpcExit(); + +Result httpcOpenContext(httpcContext *context, char* url, u32 use_defaultproxy);//use_defaultproxy should be zero normally, unless you don't want HTTPC_SetProxyDefault() to be used automatically. +Result httpcCloseContext(httpcContext *context); +Result httpcBeginRequest(httpcContext *context); +Result httpcReceiveData(httpcContext *context, u8* buffer, u32 size); +Result httpcGetRequestState(httpcContext *context, httpcReqStatus* out); +Result httpcGetDownloadSizeState(httpcContext *context, u32* downloadedsize, u32* contentsize); +Result httpcGetResponseStatusCode(httpcContext *context, u32* out, u64 delay);//delay isn't used yet. This writes the HTTP status code from the server to out. + +Result httpcDownloadData(httpcContext *context, u8* buffer, u32 size, u32 *downloadedsize);//The *entire* content must be downloaded before using httpcCloseContext(), otherwise httpcCloseContext() will hang. + +//Using the below functions directly is not recommended, use the above functions. See also the http example. + Result HTTPC_Initialize(Handle handle); Result HTTPC_InitializeConnectionSession(Handle handle, Handle contextHandle); Result HTTPC_CreateContext(Handle handle, char* url, Handle* contextHandle); @@ -8,3 +35,7 @@ Result HTTPC_SetProxyDefault(Handle handle, Handle contextHandle); Result HTTPC_AddRequestHeaderField(Handle handle, Handle contextHandle, char* name, char* value); Result HTTPC_BeginRequest(Handle handle, Handle contextHandle); Result HTTPC_ReceiveData(Handle handle, Handle contextHandle, u8* buffer, u32 size); +Result HTTPC_GetRequestState(Handle handle, Handle contextHandle, httpcReqStatus* out); +Result HTTPC_GetDownloadSizeState(Handle handle, Handle contextHandle, u32* downloadedsize, u32* contentsize); +Result HTTPC_GetResponseStatusCode(Handle handle, Handle contextHandle, u32* out); + diff --git a/libctru/include/3ds/services/ptm.h b/libctru/include/3ds/services/ptm.h index 7c595b9..586b456 100644 --- a/libctru/include/3ds/services/ptm.h +++ b/libctru/include/3ds/services/ptm.h @@ -3,5 +3,8 @@ Result ptmInit(); Result ptmExit(); +Result PTMU_GetShellState(Handle* servhandle, u8 *out); Result PTMU_GetBatteryLevel(Handle* servhandle, u8 *out); Result PTMU_GetBatteryChargeState(Handle* servhandle, u8 *out); +Result PTMU_GetPedometerState(Handle* servhandle, u8 *out); +Result PTMU_GetTotalStepCount(Handle* servhandle, u32 *steps); diff --git a/libctru/include/3ds/svc.h b/libctru/include/3ds/svc.h index 0a023e2..ab0230c 100644 --- a/libctru/include/3ds/svc.h +++ b/libctru/include/3ds/svc.h @@ -2,8 +2,7 @@ svc.h _ Syscall wrappers. */ -#ifndef SVC_H -#define SVC_H +#pragma once typedef enum { MEMOP_FREE =1, // Free heap @@ -42,8 +41,17 @@ typedef enum { ARBITER_KERNEL4 =4, } ArbitrationType; +static inline void* getThreadLocalStorage(void) +{ + void* ret; + asm volatile("mrc p15, 0, %[data], c13, c0, 3" : [data] "=r" (ret)); + return ret; +} -u32* getThreadCommandBuffer(void); +static inline u32* getThreadCommandBuffer(void) +{ + return (u32*)((u8*)getThreadLocalStorage() + 0x80); +} s32 svcControlMemory(u32* addr_out, u32 addr0, u32 addr1, u32 size, MemOp op, MemPerm perm); s32 svcQueryMemory(MemInfo* info, PageInfo* out, u32 addr); @@ -51,8 +59,11 @@ void __attribute__((noreturn)) svcExitProcess(); s32 svcCreateThread(Handle* thread, ThreadFunc entrypoint, u32 arg, u32* stack_top, s32 thread_priority, s32 processor_id); void __attribute__((noreturn)) svcExitThread(); void svcSleepThread(s64 ns); +s32 svcSetThreadPriority(Handle thread, s32 prio); s32 svcCreateMutex(Handle* mutex, bool initially_locked); s32 svcReleaseMutex(Handle handle); +s32 svcCreateSemaphore(Handle* semaphore, s32 initial_count, s32 max_count); +s32 svcReleaseSemaphore(s32* count, Handle semaphore, s32 release_count); s32 svcCreateEvent(Handle* event, u8 reset_type); s32 svcSignalEvent(Handle handle); s32 svcClearEvent(Handle handle); @@ -75,6 +86,5 @@ s32 svcGetProcessInfo(s64* out, Handle process, u32 type); s32 svcConnectToPort(volatile Handle* out, const char* portName); s32 svcSendSyncRequest(Handle session); s32 svcGetProcessId(u32 *out, Handle handle); +s32 svcGetThreadId(u32 *out, Handle handle); s32 svcOutputDebugString(const char* str, int length); - -#endif diff --git a/libctru/include/3ds/types.h b/libctru/include/3ds/types.h index b844bcb..2f7d01a 100644 --- a/libctru/include/3ds/types.h +++ b/libctru/include/3ds/types.h @@ -4,7 +4,6 @@ #pragma once -#include #include #include #include diff --git a/libctru/include/poll.h b/libctru/include/poll.h index 4315a43..8b34a7a 100644 --- a/libctru/include/poll.h +++ b/libctru/include/poll.h @@ -2,17 +2,12 @@ #include <3ds/types.h> -/* only POLLIN confirmed to work so far */ -#define POLLIN 0x001 -#define POLLPRI 0x002 -#define POLLOUT 0x004 -#define POLLERR 0x008 -#define POLLHUP 0x010 -#define POLLNVAL 0x020 -#define POLLRDNORM 0x040 -#define POLLRDBAND 0x080 -#define POLLWRNORM 0x100 -#define POLLWRBAND 0x200 +#define POLLIN 0x01 +#define POLLPRI 0x02 +#define POLLHUP 0x04 // unknown ??? +#define POLLERR 0x08 // probably +#define POLLOUT 0x10 +#define POLLNVAL 0x20 typedef u32 nfds_t; diff --git a/libctru/source/allocator/linear.cpp b/libctru/source/allocator/linear.cpp index 0a47275..b0a4b27 100644 --- a/libctru/source/allocator/linear.cpp +++ b/libctru/source/allocator/linear.cpp @@ -1,9 +1,57 @@ #include <3ds.h> +#include <3ds/util/rbtree.h> + #include "mem_pool.h" extern u32 __linear_heap, __linear_heap_size; static MemPool sLinearPool; +static rbtree_t sAddrMap; + +struct addrMapNode +{ + rbtree_node node; + MemChunk chunk; +}; + +#define getAddrMapNode(x) rbtree_item((x), addrMapNode, node) + +static int addrMapNodeComparator(const rbtree_node_t* _lhs, const rbtree_node_t* _rhs) +{ + auto lhs = getAddrMapNode(_lhs)->chunk.addr; + auto rhs = getAddrMapNode(_rhs)->chunk.addr; + if (lhs < rhs) + return -1; + if (lhs > rhs) + return 1; + return 0; +} + +static void addrMapNodeDestructor(rbtree_node_t* a) +{ + free(getAddrMapNode(a)); +} + +static addrMapNode* getNode(void* addr) +{ + addrMapNode n; + n.chunk.addr = (u8*)addr; + auto p = rbtree_find(&sAddrMap, &n.node); + return p ? getAddrMapNode(p) : nullptr; +} + +static addrMapNode* newNode(const MemChunk& chunk) +{ + auto p = (addrMapNode*)malloc(sizeof(addrMapNode)); + if (!p) return nullptr; + p->chunk = chunk; + return p; +} + +static void delNode(addrMapNode* node) +{ + rbtree_remove(&sAddrMap, &node->node, addrMapNodeDestructor); +} static bool linearInit() { @@ -11,6 +59,7 @@ static bool linearInit() if (blk) { sLinearPool.AddBlock(blk); + rbtree_init(&sAddrMap, addrMapNodeComparator); return true; } return false; @@ -36,19 +85,19 @@ void* linearMemAlign(size_t size, size_t alignment) if (!sLinearPool.Ready() && !linearInit()) return nullptr; - // Reserve memory for MemChunk structure - size += alignment; - // Allocate the chunk MemChunk chunk; if (!sLinearPool.Allocate(chunk, size, shift)) return nullptr; - // Copy the MemChunk structure and return memory - auto addr = chunk.addr; - *(MemChunk*)addr = chunk; - *(u32*)(addr + alignment - sizeof(u32)) = alignment; - return addr + alignment; + auto node = newNode(chunk); + if (!node) + { + sLinearPool.Deallocate(chunk); + return nullptr; + } + if (rbtree_insert(&sAddrMap, &node->node)); + return chunk.addr; } void* linearAlloc(size_t size) @@ -64,10 +113,14 @@ void* linearRealloc(void* mem, size_t size) void linearFree(void* mem) { - // Find MemChunk structure and free the chunk - u32 alignment = *((u32*)mem - 1); - auto pChunk = (MemChunk*)((u8*)mem - alignment); - sLinearPool.Deallocate(*pChunk); + auto node = getNode(mem); + if (!node) return; + + // Free the chunk + sLinearPool.Deallocate(node->chunk); + + // Free the node + delNode(node); } u32 linearSpaceFree() diff --git a/libctru/source/allocator/mem_pool.h b/libctru/source/allocator/mem_pool.h index b75d195..97ca60b 100644 --- a/libctru/source/allocator/mem_pool.h +++ b/libctru/source/allocator/mem_pool.h @@ -1,5 +1,6 @@ #pragma once #include <3ds.h> +#include struct MemChunk { diff --git a/libctru/source/gfx.c b/libctru/source/gfx.c index d32dcc6..df99fcc 100644 --- a/libctru/source/gfx.c +++ b/libctru/source/gfx.c @@ -12,16 +12,46 @@ u8* gfxTopLeftFramebuffers[2]; u8* gfxTopRightFramebuffers[2]; u8* gfxBottomFramebuffers[2]; -u8 currentBuffer; -bool enable3d; +static u8 currentBuffer; +static bool enable3d; +static int doubleBuf = 1; Handle gspEvent, gspSharedMemHandle; +static GSP_FramebufferFormats topFormat = GSP_BGR8_OES; +static GSP_FramebufferFormats botFormat = GSP_BGR8_OES; + void gfxSet3D(bool enable) { enable3d=enable; } +void gfxSetScreenFormat(gfxScreen_t screen, GSP_FramebufferFormats format) { + if(screen==GFX_TOP) + topFormat = format; + else + botFormat = format; +} + +void gfxSetDoubleBuffering(bool doubleBuffering) { + doubleBuf = doubleBuffering ? 1 : 0; // make sure they're the integer values '1' and '0' +} + +static u32 __get_bytes_per_pixel(GSP_FramebufferFormats format) { + switch(format) { + case GSP_RGBA8_OES: + return 4; + case GSP_BGR8_OES: + return 3; + case GSP_RGB565_OES: + case GSP_RGB5_A1_OES: + case GSP_RGBA4_OES: + return 2; + } + + return 3; +} + void gfxSetFramebufferInfo(gfxScreen_t screen, u8 id) { if(screen==GFX_TOP) @@ -30,17 +60,17 @@ void gfxSetFramebufferInfo(gfxScreen_t screen, u8 id) topFramebufferInfo.framebuf0_vaddr=(u32*)gfxTopLeftFramebuffers[id]; if(enable3d)topFramebufferInfo.framebuf1_vaddr=(u32*)gfxTopRightFramebuffers[id]; else topFramebufferInfo.framebuf1_vaddr=topFramebufferInfo.framebuf0_vaddr; - topFramebufferInfo.framebuf_widthbytesize=240*3; + topFramebufferInfo.framebuf_widthbytesize=240*__get_bytes_per_pixel(topFormat); u8 bit5=(enable3d!=0); - topFramebufferInfo.format=((1)<<8)|((1^bit5)<<6)|((bit5)<<5)|GSP_BGR8_OES; + topFramebufferInfo.format=((1)<<8)|((1^bit5)<<6)|((bit5)<<5)|topFormat; topFramebufferInfo.framebuf_dispselect=id; topFramebufferInfo.unk=0x00000000; }else{ bottomFramebufferInfo.active_framebuf=id; bottomFramebufferInfo.framebuf0_vaddr=(u32*)gfxBottomFramebuffers[id]; bottomFramebufferInfo.framebuf1_vaddr=0x00000000; - bottomFramebufferInfo.framebuf_widthbytesize=240*3; - bottomFramebufferInfo.format=GSP_BGR8_OES; + bottomFramebufferInfo.framebuf_widthbytesize=240*__get_bytes_per_pixel(botFormat); + bottomFramebufferInfo.format=botFormat; bottomFramebufferInfo.framebuf_dispselect=id; bottomFramebufferInfo.unk=0x00000000; } @@ -51,7 +81,7 @@ void gfxWriteFramebufferInfo(gfxScreen_t screen) u8* framebufferInfoHeader=gfxSharedMemory+0x200+gfxThreadID*0x80; if(screen==GFX_BOTTOM)framebufferInfoHeader+=0x40; GSP_FramebufferInfo* framebufferInfo=(GSP_FramebufferInfo*)&framebufferInfoHeader[0x4]; - framebufferInfoHeader[0x0]^=1; + framebufferInfoHeader[0x0]^=doubleBuf; framebufferInfo[framebufferInfoHeader[0x0]]=(screen==GFX_TOP)?(topFramebufferInfo):(bottomFramebufferInfo); framebufferInfoHeader[0x1]=1; } @@ -106,7 +136,7 @@ void gfxExit() // Exit event handler gspExitEventHandler(); - // Free framebuffers (let's pretend linearFree is actually implemented...) + // Free framebuffers linearFree(gfxTopRightFramebuffers[1]); linearFree(gfxTopRightFramebuffers[0]); linearFree(gfxBottomFramebuffers[1]); @@ -134,10 +164,10 @@ u8* gfxGetFramebuffer(gfxScreen_t screen, gfx3dSide_t side, u16* width, u16* hei if(screen==GFX_TOP) { if(height)*height=400; - return (side==GFX_LEFT || !enable3d)?(gfxTopLeftFramebuffers[currentBuffer^1]):(gfxTopRightFramebuffers[currentBuffer^1]); + return (side==GFX_LEFT || !enable3d)?(gfxTopLeftFramebuffers[currentBuffer^doubleBuf]):(gfxTopRightFramebuffers[currentBuffer^doubleBuf]); }else{ if(height)*height=320; - return gfxBottomFramebuffers[currentBuffer^1]; + return gfxBottomFramebuffers[currentBuffer^doubleBuf]; } } @@ -150,7 +180,7 @@ void gfxFlushBuffers() void gfxSwapBuffers() { - currentBuffer^=1; + currentBuffer^=doubleBuf; gfxSetFramebufferInfo(GFX_TOP, currentBuffer); gfxSetFramebufferInfo(GFX_BOTTOM, currentBuffer); GSPGPU_SetBufferSwap(NULL, GFX_TOP, &topFramebufferInfo); @@ -159,7 +189,7 @@ void gfxSwapBuffers() void gfxSwapBuffersGpu() { - currentBuffer^=1; + currentBuffer^=doubleBuf; gfxSetFramebufferInfo(GFX_TOP, currentBuffer); gfxSetFramebufferInfo(GFX_BOTTOM, currentBuffer); gfxWriteFramebufferInfo(GFX_TOP); diff --git a/libctru/source/gpu/shdr.c b/libctru/source/gpu/shdr.c index dd0a60e..7c4d1cb 100644 --- a/libctru/source/gpu/shdr.c +++ b/libctru/source/gpu/shdr.c @@ -56,7 +56,7 @@ DVLB_s* SHDR_ParseSHBIN(u32* shbinData, u32 shbinSize) return ret; } -s8 SHDR_GetUniformRegister(DVLB_s* dvlb, char* name, u8 programID) +s8 SHDR_GetUniformRegister(DVLB_s* dvlb, const char* name, u8 programID) { if(!dvlb || !name)return -1; diff --git a/libctru/source/initSystem.c b/libctru/source/initSystem.c index efd1376..039f862 100644 --- a/libctru/source/initSystem.c +++ b/libctru/source/initSystem.c @@ -26,16 +26,18 @@ void __destroy_handle_list(void); void __attribute__((noreturn)) __ctru_exit(int rc) { + u32 tmp=0; + // Run the global destructors __libc_fini_array(); // TODO: APT exit goes here // Unmap the linear heap - svcControlMemory(&__linear_heap, __linear_heap, 0x0, __linear_heap_size, MEMOP_FREE, 0x0); + svcControlMemory(&tmp, __linear_heap, 0x0, __linear_heap_size, MEMOP_FREE, 0x0); // Unmap the application heap - svcControlMemory(&heapBase, heapBase, 0x0, __heap_size, MEMOP_FREE, 0x0); + svcControlMemory(&tmp, heapBase, 0x0, __heap_size, MEMOP_FREE, 0x0); // Close some handles __destroy_handle_list(); @@ -50,13 +52,15 @@ void __attribute__((noreturn)) __ctru_exit(int rc) void initSystem(void (*retAddr)(void)) { + u32 tmp=0; + // Register newlib exit() syscall __syscalls.exit = __ctru_exit; __system_retAddr = __service_ptr ? retAddr : NULL; // Allocate the application heap heapBase = 0x08000000; - svcControlMemory(&heapBase, heapBase, 0x0, __heap_size, MEMOP_ALLOC, 0x3); + svcControlMemory(&tmp, heapBase, 0x0, __heap_size, MEMOP_ALLOC, 0x3); // Allocate the linear heap svcControlMemory(&__linear_heap, 0x0, 0x0, __linear_heap_size, MEMOP_ALLOC_LINEAR, 0x3); diff --git a/libctru/source/os.c b/libctru/source/os.c index fb2bd97..e2677ed 100644 --- a/libctru/source/os.c +++ b/libctru/source/os.c @@ -49,7 +49,7 @@ u64 osGetTime() { break; } - u64 offset = (svcGetSystemTick() - dt->update_tick) / TICKS_PER_MSEC; + u64 offset = (u32)((u32)(svcGetSystemTick() - dt->update_tick) / TICKS_PER_MSEC); return dt->date_time + offset; } diff --git a/libctru/source/sdmc_dev.c b/libctru/source/sdmc_dev.c index 11b498c..1450574 100644 --- a/libctru/source/sdmc_dev.c +++ b/libctru/source/sdmc_dev.c @@ -1,7 +1,11 @@ #include #include #include +#include #include +#include + +#include #include <3ds.h> /*! @internal @@ -95,14 +99,63 @@ static FS_archive sdmcArchive = /*! @endcond */ +static char __cwd[PATH_MAX+1] = "/"; +static char __fixedpath[PATH_MAX+1]; + +static const char *sdmc_fixpath(const char *path) +{ + // Move the path pointer to the start of the actual path + if (strchr (path, ':') != NULL) + { + path = strchr (path, ':') + 1; + } + + if (strchr (path, ':') != NULL) return NULL; + + + if (path[0]=='/') return path; + + strncpy(__fixedpath,__cwd,PATH_MAX); + strncat(__fixedpath,path,PATH_MAX); + __fixedpath[PATH_MAX] = 0; + + return __fixedpath; + +} + +extern int __system_argc; +extern char** __system_argv; + /*! Initialize SDMC device */ Result sdmcInit(void) { Result rc; + rc = FSUSER_OpenArchive(NULL, &sdmcArchive); + + if(rc == 0) - AddDevice(&sdmc_devoptab); + { + + int dev = AddDevice(&sdmc_devoptab); + + if (dev != -1) { + setDefaultDevice(dev); + if (__system_argc != 0 && __system_argv[0] != NULL) + { + if (FindDevice(__system_argv[0]) == dev) + { + strncpy(__fixedpath,__system_argv[0],PATH_MAX); + char *last_slash = strrchr(__fixedpath,'/'); + if (last_slash != NULL) { + last_slash[0] = 0; + chdir(__fixedpath); + } + } + } + } + } return rc; } @@ -141,10 +194,15 @@ sdmc_open(struct _reent *r, Result rc; u32 sdmc_flags = 0; u32 attributes = FS_ATTRIBUTE_NONE; - char *pathptr = NULL; + const char *pathptr = NULL; - pathptr = strchr(path, '/'); - if(pathptr==NULL)pathptr = (char*)path; + pathptr = sdmc_fixpath(path); + + if(pathptr==NULL) + { + r->_errno=EINVAL; + return -1; + } /* get pointer to our data */ sdmc_file_t *file = (sdmc_file_t*)fileStruct; @@ -483,8 +541,32 @@ static int sdmc_chdir(struct _reent *r, const char *name) { - r->_errno = ENOSYS; - return -1; + Handle fd; + Result rc; + const char *pathptr = NULL; + + pathptr = sdmc_fixpath(name); + + if(pathptr==NULL) + { + r->_errno=EINVAL; + return -1; + } + + rc = FSUSER_OpenDirectory(NULL, &fd, sdmcArchive, FS_makePath(PATH_CHAR, pathptr)); + if(rc == 0) + { + FSDIR_Close(fd); + strncpy(__cwd,pathptr,PATH_MAX); + } + else + { + r->_errno=EINVAL; + return -1; + } + + return 0; + } /*! Rename a file @@ -520,10 +602,15 @@ sdmc_mkdir(struct _reent *r, int mode) { Result rc; - char *pathptr = NULL; + const char *pathptr = NULL; - pathptr = strchr(path, '/'); - if(pathptr==NULL)pathptr = (char*)path; + pathptr = sdmc_fixpath(path); + + if(pathptr==NULL) + { + r->_errno=EINVAL; + return -1; + } /* TODO: Use mode to set directory attributes. */ @@ -551,10 +638,15 @@ sdmc_diropen(struct _reent *r, { Handle fd; Result rc; - char *pathptr = NULL; + const char *pathptr = NULL; - pathptr = strchr(path, '/'); - if(pathptr==NULL)pathptr = (char*)path; + pathptr = sdmc_fixpath(path); + + if(pathptr==NULL) + { + r->_errno=EINVAL; + return NULL; + } /* get pointer to our data */ sdmc_dir_t *dir = (sdmc_dir_t*)(dirState->dirStruct); @@ -684,7 +776,7 @@ sdmc_statvfs(struct _reent *r, { Result rc; u32 clusterSize, numClusters, freeClusters; - u32 writable = 0; + u8 writable = 0; rc = FSUSER_GetSdmcArchiveResource(NULL, NULL, @@ -786,7 +878,7 @@ sdmc_fsync(struct _reent *r, * @returns 0 for success * @returns -1 for error */ -static int +static int sdmc_chmod(struct _reent *r, const char *path, mode_t mode) diff --git a/libctru/source/services/apt.c b/libctru/source/services/apt.c index ba8e131..242abc1 100644 --- a/libctru/source/services/apt.c +++ b/libctru/source/services/apt.c @@ -36,6 +36,13 @@ Handle aptSleepSync = 0; u32 aptParameters[0x1000/4]; //TEMP +static u32 __ns_capinfo[0x20>>2]; + +static NS_APPID __apt_launchapplet_appID; +static Handle __apt_launchapplet_inhandle; +static u32 *__apt_launchapplet_parambuf; +static u32 __apt_launchapplet_parambufsize; + static void aptAppStarted(void); static Result __apt_initservicehandle() @@ -96,7 +103,7 @@ void aptWaitStatusEvent() svcClearEvent(aptStatusEvent); } -void aptAppletUtility_Exit_RetToApp() +void aptAppletUtility_Exit_RetToApp(u32 type) { u8 buf1[4], buf2[4]; @@ -125,6 +132,13 @@ void aptAppletUtility_Exit_RetToApp() aptOpenSession(); APT_AppletUtility(NULL, NULL, 0x4, 0x1, buf1, 0x1, buf2); aptCloseSession(); + + if(type) + { + aptOpenSession(); + APT_AppletUtility(NULL, NULL, 0x4, 0x1, buf1, 0x1, buf2); + aptCloseSession(); + } } NS_APPID aptGetMenuAppID() @@ -142,8 +156,6 @@ void aptReturnToMenu() { NS_APPID menu_appid; u32 tmp0 = 1, tmp1 = 0; - u32 ns_capinfo[0x20>>2]; - u32 tmp_params[0x20>>2]; if(__system_runflags&RUNFLAG_APTWORKAROUND) { @@ -173,20 +185,19 @@ void aptReturnToMenu() GSPGPU_SaveVramSysArea(NULL); // Capture screen. - memset(tmp_params, 0, 0x20); - memset(ns_capinfo, 0, 0x20); + memset(__ns_capinfo, 0, 0x20); - aptInitCaptureInfo(ns_capinfo); + aptInitCaptureInfo(__ns_capinfo); menu_appid = aptGetMenuAppID(); // Send capture-screen info to menu. aptOpenSession(); - APT_SendParameter(NULL, currentAppId, menu_appid, 0x20, ns_capinfo, 0x0, 0x10); + APT_SendParameter(NULL, currentAppId, menu_appid, 0x20, __ns_capinfo, 0x0, 0x10); aptCloseSession(); aptOpenSession(); - APT_SendCaptureBufferInfo(NULL, 0x20, ns_capinfo); + APT_SendCaptureBufferInfo(NULL, 0x20, __ns_capinfo); aptCloseSession(); // Release GSP module. @@ -214,6 +225,54 @@ void aptReturnToMenu() aptWaitStatusEvent(); } +void aptAppletStarted() +{ + u8 buf1[4], buf2[4]; + + memset(buf1, 0, 4); + + // Set status to SUSPENDED. + svcClearEvent(aptStatusEvent); + aptSetStatus(APP_SUSPENDED); + + aptOpenSession(); + APT_SendCaptureBufferInfo(NULL, 0x20, __ns_capinfo); + aptCloseSession(); + + aptOpenSession(); + APT_ReplySleepQuery(NULL, currentAppId, 0x0); + aptCloseSession(); + + aptOpenSession(); + APT_StartLibraryApplet(NULL, __apt_launchapplet_appID, __apt_launchapplet_inhandle, __apt_launchapplet_parambuf, __apt_launchapplet_parambufsize); + aptCloseSession(); + + buf1[0]=0x00; + aptOpenSession(); + APT_AppletUtility(NULL, NULL, 0x4, 0x1, buf1, 0x1, buf2); + aptCloseSession(); + + aptOpenSession(); + APT_NotifyToWait(NULL, currentAppId); + aptCloseSession(); + + buf1[0]=0x00; + aptOpenSession(); + APT_AppletUtility(NULL, NULL, 0x4, 0x1, buf1, 0x1, buf2); + aptCloseSession(); +} + +void aptAppletClosed() +{ + aptAppletUtility_Exit_RetToApp(1); + + GSPGPU_AcquireRight(NULL, 0x0); + GSPGPU_RestoreVramSysArea(NULL); + + svcClearEvent(aptStatusEvent); + aptSetStatus(APP_RUNNING); +} + static void __handle_notification() { u8 type; Result ret=0; @@ -292,10 +351,19 @@ static bool __handle_incoming_parameter() { aptAppStarted(); return true; + case 0x3: // "Launched library applet finished loading" + if (aptGetStatus() == APP_SUSPENDED) return true; + aptSetStatus(APP_APPLETSTARTED); + return true; + case 0xA: // "Launched library applet closed" + if (aptGetStatus() == APP_SUSPENDED) return true; + if(__apt_launchapplet_parambuf && __apt_launchapplet_parambufsize)memcpy(__apt_launchapplet_parambuf, aptParameters, __apt_launchapplet_parambufsize); + aptSetStatus(APP_APPLETCLOSED); + return true; case 0xB: // Just returned from menu. GSPGPU_AcquireRight(NULL, 0x0); GSPGPU_RestoreVramSysArea(NULL); - aptAppletUtility_Exit_RetToApp(); + aptAppletUtility_Exit_RetToApp(0); aptSetStatus(APP_RUNNING); return true; @@ -377,7 +445,7 @@ Result aptInit(void) void aptExit() { - if(!(__system_runflags&RUNFLAG_APTWORKAROUND))aptAppletUtility_Exit_RetToApp(); + if(!(__system_runflags&RUNFLAG_APTWORKAROUND))aptAppletUtility_Exit_RetToApp(0); // This is only executed when application-termination was triggered via the home-menu power-off screen. if(aptGetStatusPower() == 1) @@ -420,6 +488,12 @@ bool aptMainLoop() case APP_SUSPENDING: aptReturnToMenu(); break; + case APP_APPLETSTARTED: + aptAppletStarted(); + break; + case APP_APPLETCLOSED: + aptAppletClosed(); + break; case APP_PREPARE_SLEEPMODE: aptSignalReadyForSleep(); // Fall through @@ -479,7 +553,7 @@ void aptSetStatus(APP_STATUS status) //if(prevstatus != APP_NOTINITIALIZED) //{ - if(status == APP_RUNNING || status == APP_EXITING || status == APP_SLEEPMODE) + if(status == APP_RUNNING || status == APP_EXITING || status == APP_APPLETSTARTED || status == APP_APPLETCLOSED) svcSignalEvent(aptStatusEvent); //} @@ -596,6 +670,21 @@ Result APT_GetAppletManInfo(Handle* handle, u8 inval, u8 *outval8, u32 *outval32 return cmdbuf[1]; } +Result APT_IsRegistered(Handle* handle, NS_APPID appID, u8* out) +{ + if(!handle)handle=&aptuHandle; + u32* cmdbuf=getThreadCommandBuffer(); + cmdbuf[0]=0x90040; //request header code + cmdbuf[1]=appID; + + Result ret=0; + if((ret=svcSendSyncRequest(*handle)))return ret; + + if(out)*out=cmdbuf[2]; + + return cmdbuf[1]; +} + Result APT_InquireNotification(Handle* handle, u32 appID, u8* signalType) { if(!handle)handle=&aptuHandle; @@ -949,3 +1038,105 @@ Result APT_DoAppJump(Handle* handle, u32 NSbuf0Size, u32 NSbuf1Size, u8 *NSbuf0P return cmdbuf[1]; } +Result APT_PrepareToStartLibraryApplet(Handle* handle, NS_APPID appID) +{ + if(!handle)handle=&aptuHandle; + + u32* cmdbuf=getThreadCommandBuffer(); + cmdbuf[0]=0x180040; //request header code + cmdbuf[1]=appID; + + Result ret=0; + if((ret=svcSendSyncRequest(*handle)))return ret; + + return cmdbuf[1]; +} + +Result APT_StartLibraryApplet(Handle* handle, NS_APPID appID, Handle inhandle, u32 *parambuf, u32 parambufsize) +{ + if(!handle)handle=&aptuHandle; + + u32* cmdbuf=getThreadCommandBuffer(); + cmdbuf[0]=0x1E0084; //request header code + cmdbuf[1]=appID; + cmdbuf[2]=parambufsize; + cmdbuf[3]=0; + cmdbuf[4]=inhandle; + cmdbuf[5]=(parambufsize<<14)|2; + cmdbuf[6]=(u32)parambuf; + + Result ret=0; + if((ret=svcSendSyncRequest(*handle)))return ret; + + return cmdbuf[1]; +} + +Result APT_LaunchLibraryApplet(NS_APPID appID, Handle inhandle, u32 *parambuf, u32 parambufsize) +{ + Result ret=0; + u8 tmp=0; + + u8 buf1[4]; + u8 buf2[4]; + + aptOpenSession(); + APT_ReplySleepQuery(NULL, currentAppId, 0); + aptCloseSession(); + + memset(buf1, 0, 4); + aptOpenSession(); + APT_AppletUtility(NULL, NULL, 0x4, 0x1, buf1, 0x1, buf2); + aptCloseSession(); + + aptOpenSession(); + APT_ReplySleepQuery(NULL, currentAppId, 0); + aptCloseSession(); + + aptOpenSession(); + ret=APT_PrepareToStartLibraryApplet(NULL, appID); + aptCloseSession(); + if(ret!=0)return ret; + + memset(buf1, 0, 4); + aptOpenSession(); + APT_AppletUtility(NULL, NULL, 0x4, 0x1, buf1, 0x1, buf2); + aptCloseSession(); + + while(1) + { + aptOpenSession(); + ret=APT_IsRegistered(NULL, appID, &tmp); + aptCloseSession(); + if(ret!=0)return ret; + + if(tmp!=0)break; + } + + // Set status to SUSPENDED. + svcClearEvent(aptStatusEvent); + aptSetStatus(APP_SUSPENDED); + + // Save Vram + GSPGPU_SaveVramSysArea(NULL); + + // Capture screen. + memset(__ns_capinfo, 0, 0x20); + + aptInitCaptureInfo(__ns_capinfo); + + // Send capture-screen info to the library applet. + aptOpenSession(); + APT_SendParameter(NULL, currentAppId, appID, 0x20, __ns_capinfo, 0x0, 0x2); + aptCloseSession(); + + // Release GSP module. + GSPGPU_ReleaseRight(NULL); + + __apt_launchapplet_appID = appID; + __apt_launchapplet_inhandle = inhandle; + __apt_launchapplet_parambuf = parambuf; + __apt_launchapplet_parambufsize = parambufsize; + + return 0; +} + diff --git a/libctru/source/services/cfgu.c b/libctru/source/services/cfgu.c new file mode 100644 index 0000000..14ac5c4 --- /dev/null +++ b/libctru/source/services/cfgu.c @@ -0,0 +1,89 @@ +#include +#include <3ds.h> + +static Handle CFGU_handle = 0; + +Result initCfgu() +{ + return srvGetServiceHandle(&CFGU_handle, "cfg:u"); +} + +Result exitCfgu() +{ + Result ret = svcCloseHandle(CFGU_handle); + CFGU_handle = 0; + + return ret; +} + +Result CFGU_GetRegionCanadaUSA(u8* value) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = 0x00040000; + + if((ret = svcSendSyncRequest(CFGU_handle))!=0)return ret; + + *value = (u8)cmdbuf[2]; + + return (Result)cmdbuf[1]; +} + +Result CFGU_GetSystemModel(u8* model) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = 0x00050000; + + if((ret = svcSendSyncRequest(CFGU_handle))!=0)return ret; + + *model = (u8)cmdbuf[2]; + + return (Result)cmdbuf[1]; +} + +Result CFGU_GetModelNintendo2DS(u8* value) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = 0x00060000; + + if((ret = svcSendSyncRequest(CFGU_handle))!=0)return ret; + + *value = (u8)cmdbuf[2]; + + return (Result)cmdbuf[1]; +} + +Result CFGU_GetCountryCodeString(u16 code, u16* string) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = 0x00090040; + cmdbuf[1] = (u32)code; + + if((ret = svcSendSyncRequest(CFGU_handle))!=0)return ret; + + *string = (u16)cmdbuf[2]; + + return (Result)cmdbuf[1]; +} + +Result CFGU_GetCountryCodeID(u16 string, u16* code) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = 0x000A0040; + cmdbuf[1] = (u32)string; + + if((ret = svcSendSyncRequest(CFGU_handle))!=0)return ret; + + *code = (u16)cmdbuf[2]; + + return (Result)cmdbuf[1]; +} diff --git a/libctru/source/services/fs.c b/libctru/source/services/fs.c index 47946f8..113f980 100644 --- a/libctru/source/services/fs.c +++ b/libctru/source/services/fs.c @@ -14,6 +14,22 @@ static Handle fsuHandle; // used to determine whether or not we should do FSUSER_Initialize on fsuHandle Handle __get_handle_from_list(char* name); +/*! Create an FS_path from a type and data pointer. + * + * @param[in] type Path type. + * @param[in] path Pointer to path data. + * + * @returns FS_path + * + * @sa FS_pathType + */ +FS_path +FS_makePath(FS_pathType type, + const char *path) +{ + return (FS_path){type, strlen(path)+1, (const u8*)path}; +} + /*! Initialize FS service * * @returns error @@ -298,11 +314,76 @@ FSUSER_DeleteFile(Handle *handle, return cmdbuf[1]; } -/* stub */ +/*! Renames or moves a file. + * + * @param[in] handle fs:USER handle + * @param[in] srcArchive Open archive of source + * @param[in] srcFileLowPath File path to source + * @param[in] destArchive Open archive of destination + * @param[in] destFileLowPath File path to destination + * + * @returns error + * + * @internal + * + * #### Request + * + * Index Word | Description + * -----------|------------------------- + * 0 | Header code [0x08050244] + * 1 | 0 + * 2 | srcArchive.handleLow + * 3 | srcArchive.handleHigh + * 4 | srcFileLowPath.type + * 5 | srcFileLowPath.size + * 6 | destArchive.handleLow + * 7 | destArchive.handleHigh + * 8 | destFileLowPath.type + * 9 | destFileLowPath.size + * 10 | (srcFileLowPath.size << 14) \| 0x402 + * 11 | srcFileLowPath.data + * 12 | (destFileLowPath.size << 14) \| 0x802 + * 13 | destFileLowPath.data + * + * #### Response + * + * Index Word | Description + * -----------|------------------------- + * 0 | Header code + * 1 | Result code + */ Result -FSUSER_RenameFile(void) +FSUSER_RenameFile(Handle *handle, + FS_archive srcArchive, + FS_path srcFileLowPath, + FS_archive destArchive, + FS_path destFileLowPath) { - return -1; + if(!handle) + handle = &fsuHandle; + + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = 0x08050244; + cmdbuf[1] = 0; + cmdbuf[2] = srcArchive.handleLow; + cmdbuf[3] = srcArchive.handleHigh; + cmdbuf[4] = srcFileLowPath.type; + cmdbuf[5] = srcFileLowPath.size; + cmdbuf[6] = destArchive.handleLow; + cmdbuf[7] = destArchive.handleHigh; + cmdbuf[8] = destFileLowPath.type; + cmdbuf[9] = destFileLowPath.size; + cmdbuf[10] = (srcFileLowPath.size << 14) | 0x402; + cmdbuf[11] = (u32)srcFileLowPath.data; + cmdbuf[12] = (destFileLowPath.size << 14) | 0x802; + cmdbuf[13] = (u32)destFileLowPath.data; + + Result ret = 0; + if((ret = svcSendSyncRequest(*handle))) + return ret; + + return cmdbuf[1]; } /*! Delete a directory @@ -433,11 +514,76 @@ FSUSER_CreateDirectory(Handle *handle, return cmdbuf[1]; } -/* stub */ +/*! Renames or moves a directory. + * + * @param[in] handle fs:USER handle + * @param[in] srcArchive Open archive of source + * @param[in] srcDirLowPath Dir path to source + * @param[in] destArchive Open archive of destination + * @param[in] destDirLowPath Dir path to destination + * + * @returns error + * + * @internal + * + * #### Request + * + * Index Word | Description + * -----------|------------------------- + * 0 | Header code [0x080A0244] + * 1 | 0 + * 2 | srcArchive.handleLow + * 3 | srcArchive.handleHigh + * 4 | srcDirLowPath.type + * 5 | srcDirLowPath.size + * 6 | destArchive.handleLow + * 7 | destArchive.handleHigh + * 8 | destDirLowPath.type + * 9 | destDirLowPath.size + * 10 | (srcDirLowPath.size << 14) \| 0x402 + * 11 | srcDirLowPath.data + * 12 | (destDirLowPath.size << 14) \| 0x802 + * 13 | destDirLowPath.data + * + * #### Response + * + * Index Word | Description + * -----------|------------------------- + * 0 | Header code + * 1 | Result code + */ Result -FSUSER_RenameDirectory(void) +FSUSER_RenameDirectory(Handle *handle, + FS_archive srcArchive, + FS_path srcDirLowPath, + FS_archive destArchive, + FS_path destDirLowPath) { - return -1; + if(!handle) + handle = &fsuHandle; + + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = 0x080A0244; + cmdbuf[1] = 0; + cmdbuf[2] = srcArchive.handleLow; + cmdbuf[3] = srcArchive.handleHigh; + cmdbuf[4] = srcDirLowPath.type; + cmdbuf[5] = srcDirLowPath.size; + cmdbuf[6] = destArchive.handleLow; + cmdbuf[7] = destArchive.handleHigh; + cmdbuf[8] = destDirLowPath.type; + cmdbuf[9] = destDirLowPath.size; + cmdbuf[10] = (srcDirLowPath.size << 14) | 0x402; + cmdbuf[11] = (u32)srcDirLowPath.data; + cmdbuf[12] = (destDirLowPath.size << 14) | 0x802; + cmdbuf[13] = (u32)destDirLowPath.data; + + Result ret = 0; + if((ret = svcSendSyncRequest(*handle))) + return ret; + + return cmdbuf[1]; } /*! Open a directory @@ -693,7 +839,7 @@ FSUSER_GetSdmcArchiveResource(Handle *handle, */ Result FSUSER_IsSdmcDetected(Handle *handle, - u32 *detected) + u8 *detected) { if(!handle) handle = &fsuHandle; @@ -737,7 +883,7 @@ FSUSER_IsSdmcDetected(Handle *handle, */ Result FSUSER_IsSdmcWritable(Handle *handle, - u32 *writable) + u8 *writable) { if(!handle) handle = &fsuHandle; @@ -1201,6 +1347,7 @@ FSDIR_Close(Handle handle) Result ret = 0; if((ret = svcSendSyncRequest(handle))) return ret; - - return cmdbuf[1]; + ret = cmdbuf[1]; + if(!ret)ret = svcCloseHandle(handle); + return ret; } diff --git a/libctru/source/services/httpc.c b/libctru/source/services/httpc.c index d9e7ec7..00cb8a7 100644 --- a/libctru/source/services/httpc.c +++ b/libctru/source/services/httpc.c @@ -1,13 +1,138 @@ #include #include <3ds.h> +Handle __httpc_servhandle = 0; + +Result httpcInit() +{ + Result ret=0; + + if(__httpc_servhandle)return 0; + if((ret=srvGetServiceHandle(&__httpc_servhandle, "http:C")))return ret; + + //*((u32*)0x600) = __httpc_servhandle; + + ret = HTTPC_Initialize(__httpc_servhandle); + if(ret!=0)return ret; + + return 0; +} + +void httpcExit() +{ + if(__httpc_servhandle==0)return; + + svcCloseHandle(__httpc_servhandle); +} + +Result httpcOpenContext(httpcContext *context, char* url, u32 use_defaultproxy) +{ + Result ret=0; + + ret = HTTPC_CreateContext(__httpc_servhandle, url, &context->httphandle); + if(ret!=0)return ret; + + ret = srvGetServiceHandle(&context->servhandle, "http:C"); + if(ret!=0)return ret; + + ret = HTTPC_InitializeConnectionSession(context->servhandle, context->httphandle); + if(ret!=0)return ret; + + if(use_defaultproxy==0)return 0; + + ret = HTTPC_SetProxyDefault(context->servhandle, context->httphandle); + if(ret!=0)return ret; + + return 0; +} + +Result httpcCloseContext(httpcContext *context) +{ + Result ret=0; + + ret = HTTPC_CloseContext(context->servhandle, context->httphandle); + + svcCloseHandle(context->servhandle); + + return ret; +} + +Result httpcAddRequestHeaderField(httpcContext *context, char* name, char* value) +{ + return HTTPC_AddRequestHeaderField(context->servhandle, context->httphandle, name, value); +} + +Result httpcBeginRequest(httpcContext *context) +{ + return HTTPC_BeginRequest(context->servhandle, context->httphandle); +} + +Result httpcReceiveData(httpcContext *context, u8* buffer, u32 size) +{ + return HTTPC_ReceiveData(context->servhandle, context->httphandle, buffer, size); +} + +Result httpcGetRequestState(httpcContext *context, httpcReqStatus* out) +{ + return HTTPC_GetRequestState(context->servhandle, context->httphandle, out); +} + +Result httpcGetDownloadSizeState(httpcContext *context, u32* downloadedsize, u32* contentsize) +{ + return HTTPC_GetDownloadSizeState(context->servhandle, context->httphandle, downloadedsize, contentsize); +} + +Result httpcGetResponseStatusCode(httpcContext *context, u32* out, u64 delay) +{ + return HTTPC_GetResponseStatusCode(context->servhandle, context->httphandle, out); +} + +Result httpcDownloadData(httpcContext *context, u8* buffer, u32 size, u32 *downloadedsize) +{ + Result ret=0; + u32 contentsize=0; + u32 pos=0, sz=0; + + if(downloadedsize)*downloadedsize = 0; + + ret=httpcGetDownloadSizeState(context, NULL, &contentsize); + if(ret!=0)return ret; + + while(pos < size) + { + sz = size - pos; + + ret=httpcReceiveData(context, &buffer[pos], sz); + + if(ret==HTTPC_RESULTCODE_DOWNLOADPENDING) + { + ret=httpcGetDownloadSizeState(context, &pos, NULL); + if(ret!=0)return ret; + } + else if(ret!=0) + { + return ret; + } + else + { + pos+= sz; + } + + if(downloadedsize)*downloadedsize = pos; + } + + return 0; +} + Result HTTPC_Initialize(Handle handle) { u32* cmdbuf=getThreadCommandBuffer(); cmdbuf[0]=0x10044; //request header code cmdbuf[1]=0x1000; //unk - cmdbuf[2]=0x20; //unk + cmdbuf[2]=0x20;//processID header, following word is set to processID by the arm11kernel. + cmdbuf[4]=0; + cmdbuf[5]=0;//Some sort of handle. Result ret=0; if((ret=svcSendSyncRequest(handle)))return ret; @@ -124,3 +249,50 @@ Result HTTPC_ReceiveData(Handle handle, Handle contextHandle, u8* buffer, u32 si return cmdbuf[1]; } + +Result HTTPC_GetRequestState(Handle handle, Handle contextHandle, httpcReqStatus* out) +{ + u32* cmdbuf=getThreadCommandBuffer(); + + cmdbuf[0]=0x50040; //request header code + cmdbuf[1]=contextHandle; + + Result ret=0; + if((ret=svcSendSyncRequest(handle)))return ret; + + *out = cmdbuf[2]; + + return cmdbuf[1]; +} + +Result HTTPC_GetDownloadSizeState(Handle handle, Handle contextHandle, u32* downloadedsize, u32* contentsize) +{ + u32* cmdbuf=getThreadCommandBuffer(); + + cmdbuf[0]=0x60040; //request header code + cmdbuf[1]=contextHandle; + + Result ret=0; + if((ret=svcSendSyncRequest(handle)))return ret; + + if(downloadedsize)*downloadedsize = cmdbuf[2]; + if(contentsize)*contentsize = cmdbuf[3]; + + return cmdbuf[1]; +} + +Result HTTPC_GetResponseStatusCode(Handle handle, Handle contextHandle, u32* out) +{ + u32* cmdbuf=getThreadCommandBuffer(); + + cmdbuf[0]=0x220040; //request header code + cmdbuf[1]=contextHandle; + + Result ret=0; + if((ret=svcSendSyncRequest(handle)))return ret; + + *out = cmdbuf[2]; + + return cmdbuf[1]; +} + diff --git a/libctru/source/services/mic.c b/libctru/source/services/mic.c index 395792b..463f94d 100644 --- a/libctru/source/services/mic.c +++ b/libctru/source/services/mic.c @@ -63,9 +63,6 @@ Result MIC_Shutdown() MIC_cmd5(); - ret = svcUnmapMemoryBlock(MIC_sharedmem_handle, (u32)MIC_sharedmem); - if(ret!=0)return ret; - ret = svcCloseHandle(MIC_sharedmem_handle); if(ret!=0)return ret; @@ -207,7 +204,7 @@ Result MIC_GetEventHandle(Handle *handle) if((ret = svcSendSyncRequest(MIC_handle))!=0)return ret; - if(handle)*handle = cmdbuf[2]; + if(handle)*handle = cmdbuf[3]; return (Result)cmdbuf[1]; } diff --git a/libctru/source/services/pm.c b/libctru/source/services/pm.c index 185b37d..6c74ed2 100644 --- a/libctru/source/services/pm.c +++ b/libctru/source/services/pm.c @@ -1,4 +1,5 @@ #include +#include #include <3ds.h> static Handle pmHandle; diff --git a/libctru/source/services/ptm.c b/libctru/source/services/ptm.c index 8fa21fc..e9abfb6 100644 --- a/libctru/source/services/ptm.c +++ b/libctru/source/services/ptm.c @@ -13,6 +13,21 @@ Result ptmExit() return svcCloseHandle(ptmHandle); } +Result PTMU_GetShellState(Handle* servhandle, u8 *out) +{ + if(!servhandle)servhandle=&ptmHandle; + Result ret=0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = 0x00060000; + + if((ret = svcSendSyncRequest(*servhandle))!=0)return ret; + + *out = (u8)cmdbuf[2]; + + return (Result)cmdbuf[1]; +} + Result PTMU_GetBatteryLevel(Handle* servhandle, u8 *out) { if(!servhandle)servhandle=&ptmHandle; @@ -42,3 +57,33 @@ Result PTMU_GetBatteryChargeState(Handle* servhandle, u8 *out) return (Result)cmdbuf[1]; } + +Result PTMU_GetPedometerState(Handle* servhandle, u8 *out) +{ + if(!servhandle)servhandle=&ptmHandle; + Result ret=0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = 0x00090000; + + if((ret = svcSendSyncRequest(*servhandle))!=0)return ret; + + *out = (u8)cmdbuf[2]; + + return (Result)cmdbuf[1]; +} + +Result PTMU_GetTotalStepCount(Handle* servhandle, u32 *steps) +{ + if(!servhandle)servhandle=&ptmHandle; + Result ret=0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = 0x000C0000; + + if((ret = svcSendSyncRequest(*servhandle))!=0)return ret; + + *steps = cmdbuf[2]; + + return (Result)cmdbuf[1]; +} diff --git a/libctru/source/services/soc/soc_common.h b/libctru/source/services/soc/soc_common.h index 004235d..f5cfe96 100644 --- a/libctru/source/services/soc/soc_common.h +++ b/libctru/source/services/soc/soc_common.h @@ -1,5 +1,6 @@ #pragma once +#include #include <3ds.h> extern Handle SOCU_handle; diff --git a/libctru/source/services/soc/soc_ioctl.c b/libctru/source/services/soc/soc_ioctl.c index 6fce0d7..4125646 100644 --- a/libctru/source/services/soc/soc_ioctl.c +++ b/libctru/source/services/soc/soc_ioctl.c @@ -16,15 +16,24 @@ int ioctl(int fd, int request, ...) switch(request) { case FIONBIO: value = va_arg(ap, int*); - if(value == NULL) ret = -1; - else if(*value) { - flags = fcntl(fd, F_GETFL, 0); - ret = fcntl(fd, F_SETFL, flags | O_NONBLOCK); + if(value == NULL) { + errno = EFAULT; + ret = -1; } - else { - flags = fcntl(fd, F_GETFL, 0); - ret = fcntl(fd, F_SETFL, flags & ~O_NONBLOCK); + + flags = fcntl(fd, F_GETFL, 0); + if(flags == -1) { + errno = SOC_GetErrno(); + va_end(ap); + return -1; } + + if(*value) ret = fcntl(fd, F_SETFL, flags | O_NONBLOCK); + else ret = fcntl(fd, F_SETFL, flags & ~O_NONBLOCK); + + if(ret != 0) + errno = SOC_GetErrno(); + break; default: @@ -33,5 +42,7 @@ int ioctl(int fd, int request, ...) break; } + va_end(ap); + return ret; } diff --git a/libctru/source/svc.s b/libctru/source/svc.s index f918369..4969df8 100644 --- a/libctru/source/svc.s +++ b/libctru/source/svc.s @@ -1,72 +1,69 @@ .arm .align 4 -/* THIS DOES NOT BELONG HERE */ -.global getThreadCommandBuffer -.type getThreadCommandBuffer, %function -getThreadCommandBuffer: - mrc p15, 0, r0, c13, c0, 3 - add r0, #0x80 - bx lr - - .global svcControlMemory .type svcControlMemory, %function svcControlMemory: - stmfd sp!, {r0, r4} - ldr r0, [sp, #0x8] - ldr r4, [sp, #0x8+0x4] - svc 0x01 - ldr r2, [sp], #4 - str r1, [r2] - ldr r4, [sp], #4 - bx lr + push {r0, r4} + ldr r0, [sp, #0x8] + ldr r4, [sp, #0x8+0x4] + svc 0x01 + ldr r2, [sp], #4 + str r1, [r2] + ldr r4, [sp], #4 + bx lr .global svcQueryMemory .type svcQueryMemory, %function svcQueryMemory: - stmfd sp!, {r0,r1,r4-r6} - svc 2 - ldr r6, [sp] - str r1, [r6] - str r2, [r6,#4] - str r3, [r6,#8] - str r4, [r6,#0xc] - ldr r6, [sp,#4] - str r5, [r6] - add sp, sp, #8 - ldmfd sp!, {r4-r6} - bx lr + push {r0, r1, r4-r6} + svc 0x02 + ldr r6, [sp] + str r1, [r6] + str r2, [r6, #4] + str r3, [r6, #8] + str r4, [r6, #0xc] + ldr r6, [sp, #4] + str r5, [r6] + add sp, sp, #8 + pop {r4-r6} + bx lr .global svcExitProcess .type svcExitProcess, %function svcExitProcess: svc 0x03 - bx lr + bx lr .global svcCreateThread .type svcCreateThread, %function svcCreateThread: - stmfd sp!, {r0, r4} - ldr r0, [sp, #0x8] - ldr r4, [sp, #0x8+0x4] - svc 0x08 - ldr r2, [sp], #4 - str r1, [r2] - ldr r4, [sp], #4 - bx lr + push {r0, r4} + ldr r0, [sp, #0x8] + ldr r4, [sp, #0x8+0x4] + svc 0x08 + ldr r2, [sp], #4 + str r1, [r2] + ldr r4, [sp], #4 + bx lr .global svcExitThread .type svcExitThread, %function svcExitThread: svc 0x09 - bx lr + bx lr .global svcSleepThread .type svcSleepThread, %function svcSleepThread: svc 0x0A - bx lr + bx lr + +.global svcSetThreadPriority +.type svcSetThreadPriority, %function +svcSetThreadPriority: + svc 0x0C + bx lr .global svcCreateMutex .type svcCreateMutex, %function @@ -75,61 +72,61 @@ svcCreateMutex: svc 0x13 ldr r3, [sp], #4 str r1, [r3] - bx lr + bx lr .global svcReleaseMutex .type svcReleaseMutex, %function svcReleaseMutex: svc 0x14 - bx lr + bx lr .global svcCreateEvent .type svcCreateEvent, %function svcCreateEvent: - str r0, [sp,#-4]! + str r0, [sp, #-4]! svc 0x17 ldr r2, [sp], #4 str r1, [r2] - bx lr + bx lr .global svcSignalEvent .type svcSignalEvent, %function svcSignalEvent: svc 0x18 - bx lr + bx lr .global svcClearEvent .type svcClearEvent, %function svcClearEvent: svc 0x19 - bx lr + bx lr .global svcCreateTimer .type svcCreateTimer, %function svcCreateTimer: - str r0, [sp,#-4]! + str r0, [sp, #-4]! svc 0x1A ldr r2, [sp], #4 str r1, [r2] - bx lr + bx lr .global svcSetTimer .type svcSetTimer, %function svcSetTimer: svc 0x1B - bx lr + bx lr .global svcCancelTimer .type svcCancelTimer, %function svcCancelTimer: svc 0x1C - bx lr + bx lr .global svcClearTimer .type svcClearTimer, %function svcClearTimer: svc 0x1D - bx lr + bx lr .global svcCreateMemoryBlock .type svcCreateMemoryBlock, %function @@ -139,70 +136,72 @@ svcCreateMemoryBlock: svc 0x1E ldr r2, [sp], #4 str r1, [r2] - bx lr + bx lr .global svcMapMemoryBlock .type svcMapMemoryBlock, %function svcMapMemoryBlock: svc 0x1F - bx lr + bx lr .global svcUnmapMemoryBlock .type svcUnmapMemoryBlock, %function svcUnmapMemoryBlock: svc 0x20 - bx lr + bx lr .global svcCreateAddressArbiter .type svcCreateAddressArbiter, %function svcCreateAddressArbiter: svc 0x21 - bx lr + bx lr .global svcArbitrateAddress .type svcArbitrateAddress, %function svcArbitrateAddress: - push {r4,r5} + push {r4, r5} add sp, #8 ldr r5, [sp] ldr r4, [sp, #4] sub sp, #8 svc 0x22 - pop {r4,r5} - bx lr + pop {r4, r5} + bx lr .global svcCloseHandle .type svcCloseHandle, %function svcCloseHandle: svc 0x23 - bx lr + bx lr .global svcWaitSynchronization .type svcWaitSynchronization, %function svcWaitSynchronization: svc 0x24 - bx lr + bx lr .global svcWaitSynchronizationN .type svcWaitSynchronizationN, %function svcWaitSynchronizationN: str r5, [sp, #-4]! + str r4, [sp, #-4]! mov r5, r0 - ldr r0, [sp, #0x4] - ldr r4, [sp, #0x4+0x4] + ldr r0, [sp, #0x8] + ldr r4, [sp, #0x8+0x4] svc 0x25 str r1, [r5] + ldr r4, [sp], #4 ldr r5, [sp], #4 - bx lr + bx lr .global svcDuplicateHandle .type svcDuplicateHandle, %function svcDuplicateHandle: - str r0, [sp,#-0x4]! + str r0, [sp, #-0x4]! svc 0x27 ldr r3, [sp], #4 str r1, [r3] - bx lr + bx lr .global svcGetSystemTick .type svcGetSystemTick, %function @@ -213,34 +212,34 @@ svcGetSystemTick: .global svcGetSystemInfo .type svcGetSystemInfo, %function svcGetSystemInfo: - stmfd sp!, {r0, r4} - svc 0x2A - ldr r4, [sp], #4 - str r1, [r4] - str r2, [r4, #4] - str r3, [r4, #8] - ldr r4, [sp], #4 - bx lr + push {r0, r4} + svc 0x2A + ldr r4, [sp], #4 + str r1, [r4] + str r2, [r4, #4] + str r3, [r4, #8] + ldr r4, [sp], #4 + bx lr .global svcGetProcessInfo .type svcGetProcessInfo, %function svcGetProcessInfo: - stmfd sp!, {r0, r4} - svc 0x2B - ldr r4, [sp], #4 - str r1, [r4] - str r2, [r4, #4] - ldr r4, [sp], #4 - bx lr + push {r0,r4} + svc 0x2B + ldr r4, [sp], #4 + str r1, [r4] + str r2, [r4, #4] + ldr r4, [sp], #4 + bx lr .global svcConnectToPort .type svcConnectToPort, %function svcConnectToPort: - str r0, [sp,#-0x4]! + str r0, [sp, #-0x4]! svc 0x2D ldr r3, [sp], #4 str r1, [r3] - bx lr + bx lr .global svcSendSyncRequest .type svcSendSyncRequest, %function @@ -251,18 +250,44 @@ svcSendSyncRequest: .global svcGetProcessId .type svcGetProcessId, %function svcGetProcessId: - str r0, [sp,#-0x4]! + str r0, [sp, #-0x4]! svc 0x35 ldr r3, [sp], #4 str r1, [r3] - bx lr + bx lr .global svcOutputDebugString .type svcOutputDebugString, %function svcOutputDebugString: - str r0, [sp,#-0x4]! - svc 0x3D - ldr r2, [sp], #4 - str r1, [r2] - bx lr + str r0, [sp, #-0x4]! + svc 0x3D + ldr r2, [sp], #4 + str r1, [r2] + bx lr +.global svcCreateSemaphore +.type svcCreateSemaphore, %function +svcCreateSemaphore: + push {r0} + svc 0x15 + pop {r3} + str r1, [r3] + bx lr + +.global svcReleaseSemaphore +.type svcReleaseSemaphore, %function +svcReleaseSemaphore: + push {r0} + svc 0x16 + pop {r3} + str r1, [r3] + bx lr + +.global svcGetThreadId +.type svcGetThreadId, %function +svcGetThreadId: + str r0, [sp, #-0x4]! + svc 0x37 + ldr r3, [sp], #4 + str r1, [r3] + bx lr diff --git a/template/Makefile b/template/Makefile index 568eda2..1ed1097 100644 --- a/template/Makefile +++ b/template/Makefile @@ -6,11 +6,6 @@ ifeq ($(strip $(DEVKITARM)),) $(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM") endif -ifeq ($(strip $(CTRULIB)),) -# THIS IS TEMPORARY - in the future it should be at $(DEVKITPRO)/libctru -$(error "Please set CTRULIB in your environment. export CTRULIB=libctru") -endif - TOPDIR ?= $(CURDIR) include $(DEVKITARM)/3ds_rules @@ -118,6 +113,10 @@ else export APP_ICON := $(TOPDIR)/$(ICON) endif +ifeq ($(strip $(NO_SMDH)),) + export _3DSXFLAGS += --smdh=$(CURDIR)/$(TARGET).smdh +endif + .PHONY: $(BUILD) clean all #--------------------------------------------------------------------------------- @@ -142,10 +141,11 @@ DEPENDS := $(OFILES:.o=.d) # main targets #--------------------------------------------------------------------------------- ifeq ($(strip $(NO_SMDH)),) -.PHONY: all -all : $(OUTPUT).3dsx $(OUTPUT).smdh -endif +$(OUTPUT).3dsx : $(OUTPUT).elf $(OUTPUT).smdh +else $(OUTPUT).3dsx : $(OUTPUT).elf +endif + $(OUTPUT).elf : $(OFILES) #--------------------------------------------------------------------------------- diff --git a/template/source/main.c b/template/source/main.c index c377493..df717a6 100644 --- a/template/source/main.c +++ b/template/source/main.c @@ -1,3 +1,5 @@ +#include + #include <3ds.h> int main()