diff --git a/examples/graphics/printing/hello-world/Makefile b/examples/graphics/printing/hello-world/Makefile new file mode 100755 index 0000000..c4c758e --- /dev/null +++ b/examples/graphics/printing/hello-world/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/graphics/printing/hello-world/source/main.c b/examples/graphics/printing/hello-world/source/main.c new file mode 100644 index 0000000..a954290 --- /dev/null +++ b/examples/graphics/printing/hello-world/source/main.c @@ -0,0 +1,63 @@ +/* + Hello World example made by Aurelio Mannara for ctrulib + This code was modified for the last time on: 12/12/2014 21:00 UTC+1 + + This wouldn't be possible without the amazing work done by: + -Smealum + -fincs + -WinterMute + -yellows8 + -plutoo + -mtheall + -Many others who worked on 3DS and I'm surely forgetting about +*/ + +#include <3ds.h> +#include + +int main(int argc, char **argv) +{ + // Initialize services + srvInit(); + aptInit(); + gfxInit(); + hidInit(NULL); + + //Initialize console on top screen. Using NULL as the second argument tells the console library to use the internal console structure as current one + consoleInit(GFX_TOP, NULL); + + //Move the cursor to row 15 and column 19 and then prints "Hello World!" + //To move the cursor you have tu print "\x1b[r;cH", where r and c are respectively + //the row and column where you want your cursor to move + //The top screen has 30 rows and 50 columns + //The bottom screen has 30 rows and 40 columns + printf("\x1b[15;19HHello World!"); + + printf("\x1b[29;15HPress Start to exit."); + + // Main loop + while (aptMainLoop()) + { + //Scan all the inputs. This should be done once for each frame + hidScanInput(); + + //hidKeysDown returns information about which buttons have been just pressed (and they weren't in the previous frame) + u32 kDown = hidKeysDown(); + + if (kDown & KEY_START) break; // break in order to return to hbmenu + + // Flush and swap framebuffers + gfxFlushBuffers(); + gfxSwapBuffers(); + + //Wait for VBlank + gspWaitForVBlank(); + } + + // Exit services + gfxExit(); + hidExit(); + aptExit(); + srvExit(); + return 0; +} diff --git a/template/Makefile b/examples/qtm/Makefile similarity index 100% rename from template/Makefile rename to examples/qtm/Makefile diff --git a/examples/qtm/README.md b/examples/qtm/README.md new file mode 100644 index 0000000..2ad4cc6 --- /dev/null +++ b/examples/qtm/README.md @@ -0,0 +1,6 @@ +# qtm + +This is an example for using New3DS QTM for head-tracking. + +This is currently not usable from the homebrew launcher. + diff --git a/examples/qtm/source/main.c b/examples/qtm/source/main.c new file mode 100644 index 0000000..5464a42 --- /dev/null +++ b/examples/qtm/source/main.c @@ -0,0 +1,92 @@ +#include +#include +#include <3ds.h> + +int main() +{ + u32 pos; + u32 x, y; + Result ret; + bool qtm_usable; + qtmHeadtrackingInfo qtminfo; + u32 colors[4] = {0x0000FF, 0x00FF00, 0xFF0000, 0xFFFFFF}; + + // Initialize services + srvInit(); + aptInit(); + hidInit(NULL); + gfxInit(); + //gfxSet3D(true); // uncomment if using stereoscopic 3D + + qtmInit(); + + consoleInit(GFX_BOTTOM, NULL); + + printf("qtm example\n"); + + qtm_usable = qtmCheckInitialized(); + if(!qtm_usable)printf("QTM is not usable, therefore this example won't do anything with QTM.\n"); + + // Main loop + while (aptMainLoop()) + { + gspWaitForVBlank(); + hidScanInput(); + + u32 kDown = hidKeysDown(); + if (kDown & KEY_START) + break; // break in order to return to hbmenu + + if(qtm_usable) + { + u8* fb = gfxGetFramebuffer(GFX_TOP, GFX_LEFT, NULL, NULL); + memset(fb, 0, 400*240*3); + + ret = qtmGetHeadtrackingInfo(0, &qtminfo); + if(ret==0) + { + consoleClear(); + + for(pos=0; pos<5; pos++) + { + printf("flags[%x]=0x%x", (unsigned int)pos, qtminfo.flags[pos]); + if(pos<4)printf(", "); + } + + printf("\nfloatdata_x08: %f\n", qtminfo.floatdata_x08); + + printf("coords0: "); + for(pos=0; pos<4; pos++) + { + printf("[%x].x=%f, y=%f", (unsigned int)pos, qtminfo.coords0[pos].x, qtminfo.coords0[pos].y); + if(pos<3)printf(", "); + } + + printf("\n"); + + if(qtmCheckHeadFullyDetected(&qtminfo)) + { + for(pos=0; pos<4; pos++) + { + ret = qtmConvertCoordToScreen(&qtminfo.coords0[pos], NULL, NULL, &x, &y); + + if(ret==0)memcpy(&fb[(x*240 + y) * 3], &colors[pos], 3); + } + } + } + } + + // Flush and swap framebuffers + gfxFlushBuffers(); + gfxSwapBuffers(); + } + + // Exit services + qtmExit(); + gfxExit(); + hidExit(); + aptExit(); + srvExit(); + return 0; +} + diff --git a/examples/sdmc/README.md b/examples/sdmc/README.md index 69ab596..4658c41 100644 --- a/examples/sdmc/README.md +++ b/examples/sdmc/README.md @@ -1,6 +1,5 @@ sdmc ======= -very simple example of how to access SD files with ctrulib; requires proper exheader flags for direct SDMC access. +very simple example of how to access SD files with libctru; -**WARNING/TODO**: THIS EXAMPLE IS OUTDATED AND NEEDS TO BE FIXED - PLEASE DO NOT LOOK AT IT UNTIL IT IS UPDATED diff --git a/examples/sdmc/source/costable.c b/examples/sdmc/source/costable.c new file mode 100644 index 0000000..7788b2d --- /dev/null +++ b/examples/sdmc/source/costable.c @@ -0,0 +1,50 @@ +#include <3ds/types.h> + +s32 costable[] = { 4096, 4095, 4094, 4093, 4091, 4088, 4084, 4080, 4076, 4071, 4065, + 4058, 4051, 4044, 4035, 4026, 4017, 4007, 3996, 3985, 3973, 3960, + 3947, 3934, 3919, 3904, 3889, 3873, 3856, 3839, 3821, 3803, 3784, + 3765, 3744, 3724, 3703, 3681, 3659, 3636, 3612, 3588, 3564, 3539, + 3513, 3487, 3461, 3434, 3406, 3378, 3349, 3320, 3290, 3260, 3229, + 3198, 3167, 3135, 3102, 3069, 3035, 3002, 2967, 2932, 2897, 2861, + 2825, 2788, 2751, 2714, 2676, 2638, 2599, 2560, 2521, 2481, 2441, + 2401, 2360, 2318, 2277, 2235, 2193, 2150, 2107, 2064, 2020, 1976, + 1932, 1888, 1843, 1798, 1753, 1707, 1662, 1616, 1569, 1523, 1476, + 1429, 1382, 1334, 1287, 1239, 1191, 1143, 1095, 1046, 997, 949, + 900, 851, 801, 752, 703, 653, 603, 554, 504, 454, 404, 354, 304, + 254, 204, 153, 103, 53, 3, -46, -97, -147, -197, -247, -297, -347, + -398, -448, -497, -547, -597, -647, -696, -746, -795, -844, -893, + -942, -991, -1040, -1088, -1137, -1185, -1233, -1281, -1328, -1376, + -1423, -1470, -1517, -1563, -1610, -1656, -1701, -1747, -1792, -1837, + -1882, -1927, -1971, -2015, -2058, -2102, -2144, -2187, -2229, -2271, + -2313, -2354, -2395, -2436, -2476, -2516, -2555, -2594, -2633, -2671, + -2709, -2747, -2784, -2820, -2857, -2892, -2928, -2963, -2997, -3031, + -3065, -3098, -3130, -3163, -3194, -3225, -3256, -3286, -3316, -3345, + -3374, -3402, -3430, -3457, -3484, -3510, -3536, -3561, -3585, -3609, + -3633, -3656, -3678, -3700, -3721, -3742, -3762, -3782, -3801, -3819, + -3837, -3854, -3871, -3887, -3902, -3917, -3932, -3946, -3959, -3971, + -3983, -3995, -4005, -4016, -4025, -4034, -4042, -4050, -4057, -4064, + -4070, -4075, -4080, -4084, -4087, -4090, -4092, -4094, -4095, -4095, + -4095, -4094, -4093, -4091, -4088, -4085, -4081, -4076, -4071, -4066, + -4059, -4052, -4045, -4036, -4028, -4018, -4008, -3997, -3986, -3974, + -3962, -3949, -3935, -3921, -3906, -3891, -3875, -3858, -3841, -3824, + -3805, -3787, -3767, -3747, -3727, -3705, -3684, -3662, -3639, -3615, + -3592, -3567, -3542, -3517, -3491, -3464, -3437, -3409, -3381, -3353, + -3324, -3294, -3264, -3233, -3202, -3171, -3139, -3106, -3073, -3040, + -3006, -2972, -2937, -2902, -2866, -2830, -2793, -2756, -2719, -2681, + -2643, -2604, -2565, -2526, -2486, -2446, -2406, -2365, -2324, -2282, + -2240, -2198, -2156, -2113, -2069, -2026, -1982, -1938, -1894, -1849, + -1804, -1759, -1713, -1668, -1622, -1575, -1529, -1482, -1435, -1388, + -1341, -1293, -1245, -1197, -1149, -1101, -1052, -1004, -955, -906, + -857, -808, -758, -709, -660, -610, -560, -510, -460, -411, -360, + -310, -260, -210, -160, -110, -60, -9, 40, 90, 140, 191, 241, 291, + 341, 391, 441, 491, 541, 591, 640, 690, 739, 789, 838, 887, 936, + 985, 1033, 1082, 1130, 1179, 1227, 1274, 1322, 1370, 1417, 1464, + 1511, 1557, 1604, 1650, 1695, 1741, 1786, 1831, 1876, 1921, 1965, + 2009, 2053, 2096, 2139, 2182, 2224, 2266, 2308, 2349, 2390, 2431, + 2471, 2511, 2550, 2589, 2628, 2666, 2704, 2742, 2779, 2816, 2852, + 2888, 2923, 2958, 2993, 3027, 3060, 3093, 3126, 3158, 3190, 3221, + 3252, 3282, 3312, 3342, 3370, 3399, 3426, 3454, 3480, 3507, 3532, + 3557, 3582, 3606, 3630, 3653, 3675, 3697, 3718, 3739, 3759, 3779, + 3798, 3817, 3835, 3852, 3869, 3885, 3900, 3915, 3930, 3944, 3957, + 3970, 3982, 3993, 4004, 4014, 4024, 4033, 4041, 4049, 4056, 4063, + 4069, 4074, 4079, 4083, 4087, 4090, 4092, 4094, 4095}; diff --git a/examples/sdmc/source/costable.h b/examples/sdmc/source/costable.h index 1c9b8ec..f53eb36 100644 --- a/examples/sdmc/source/costable.h +++ b/examples/sdmc/source/costable.h @@ -1,6 +1,6 @@ #ifndef COSTABLE_H #define COSTABLE_H -s32 costable[] = {4096, 4095, 4094, 4093, 4091, 4088, 4084, 4080, 4076, 4071, 4065, 4058, 4051, 4044, 4035, 4026, 4017, 4007, 3996, 3985, 3973, 3960, 3947, 3934, 3919, 3904, 3889, 3873, 3856, 3839, 3821, 3803, 3784, 3765, 3744, 3724, 3703, 3681, 3659, 3636, 3612, 3588, 3564, 3539, 3513, 3487, 3461, 3434, 3406, 3378, 3349, 3320, 3290, 3260, 3229, 3198, 3167, 3135, 3102, 3069, 3035, 3002, 2967, 2932, 2897, 2861, 2825, 2788, 2751, 2714, 2676, 2638, 2599, 2560, 2521, 2481, 2441, 2401, 2360, 2318, 2277, 2235, 2193, 2150, 2107, 2064, 2020, 1976, 1932, 1888, 1843, 1798, 1753, 1707, 1662, 1616, 1569, 1523, 1476, 1429, 1382, 1334, 1287, 1239, 1191, 1143, 1095, 1046, 997, 949, 900, 851, 801, 752, 703, 653, 603, 554, 504, 454, 404, 354, 304, 254, 204, 153, 103, 53, 3, -46, -97, -147, -197, -247, -297, -347, -398, -448, -497, -547, -597, -647, -696, -746, -795, -844, -893, -942, -991, -1040, -1088, -1137, -1185, -1233, -1281, -1328, -1376, -1423, -1470, -1517, -1563, -1610, -1656, -1701, -1747, -1792, -1837, -1882, -1927, -1971, -2015, -2058, -2102, -2144, -2187, -2229, -2271, -2313, -2354, -2395, -2436, -2476, -2516, -2555, -2594, -2633, -2671, -2709, -2747, -2784, -2820, -2857, -2892, -2928, -2963, -2997, -3031, -3065, -3098, -3130, -3163, -3194, -3225, -3256, -3286, -3316, -3345, -3374, -3402, -3430, -3457, -3484, -3510, -3536, -3561, -3585, -3609, -3633, -3656, -3678, -3700, -3721, -3742, -3762, -3782, -3801, -3819, -3837, -3854, -3871, -3887, -3902, -3917, -3932, -3946, -3959, -3971, -3983, -3995, -4005, -4016, -4025, -4034, -4042, -4050, -4057, -4064, -4070, -4075, -4080, -4084, -4087, -4090, -4092, -4094, -4095, -4095, -4095, -4094, -4093, -4091, -4088, -4085, -4081, -4076, -4071, -4066, -4059, -4052, -4045, -4036, -4028, -4018, -4008, -3997, -3986, -3974, -3962, -3949, -3935, -3921, -3906, -3891, -3875, -3858, -3841, -3824, -3805, -3787, -3767, -3747, -3727, -3705, -3684, -3662, -3639, -3615, -3592, -3567, -3542, -3517, -3491, -3464, -3437, -3409, -3381, -3353, -3324, -3294, -3264, -3233, -3202, -3171, -3139, -3106, -3073, -3040, -3006, -2972, -2937, -2902, -2866, -2830, -2793, -2756, -2719, -2681, -2643, -2604, -2565, -2526, -2486, -2446, -2406, -2365, -2324, -2282, -2240, -2198, -2156, -2113, -2069, -2026, -1982, -1938, -1894, -1849, -1804, -1759, -1713, -1668, -1622, -1575, -1529, -1482, -1435, -1388, -1341, -1293, -1245, -1197, -1149, -1101, -1052, -1004, -955, -906, -857, -808, -758, -709, -660, -610, -560, -510, -460, -411, -360, -310, -260, -210, -160, -110, -60, -9, 40, 90, 140, 191, 241, 291, 341, 391, 441, 491, 541, 591, 640, 690, 739, 789, 838, 887, 936, 985, 1033, 1082, 1130, 1179, 1227, 1274, 1322, 1370, 1417, 1464, 1511, 1557, 1604, 1650, 1695, 1741, 1786, 1831, 1876, 1921, 1965, 2009, 2053, 2096, 2139, 2182, 2224, 2266, 2308, 2349, 2390, 2431, 2471, 2511, 2550, 2589, 2628, 2666, 2704, 2742, 2779, 2816, 2852, 2888, 2923, 2958, 2993, 3027, 3060, 3093, 3126, 3158, 3190, 3221, 3252, 3282, 3312, 3342, 3370, 3399, 3426, 3454, 3480, 3507, 3532, 3557, 3582, 3606, 3630, 3653, 3675, 3697, 3718, 3739, 3759, 3779, 3798, 3817, 3835, 3852, 3869, 3885, 3900, 3915, 3930, 3944, 3957, 3970, 3982, 3993, 4004, 4014, 4024, 4033, 4041, 4049, 4056, 4063, 4069, 4074, 4079, 4083, 4087, 4090, 4092, 4094, 4095}; +extern s32 costable[]; #endif diff --git a/examples/sdmc/source/main.c b/examples/sdmc/source/main.c index c65292f..b946f0a 100644 --- a/examples/sdmc/source/main.c +++ b/examples/sdmc/source/main.c @@ -3,9 +3,11 @@ /////////////////////////////////////// //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 +//for this to work you should copy test.bin to same folder as your .3dsx //this file was generated with GIMP by saving a 240x320 image to raw RGB #include +#include +#include #include <3ds.h> #include "costable.h" @@ -42,42 +44,33 @@ void renderEffect() int main(int argc, char** argv) { - //initialize the services we're going to be using - srvInit(); //needed for everything - aptInit(); //needed for everything - hidInit(NULL); //needed for input + gfxInit(); //makes displaying to screen easier - fsInit(); //needed for filesystem stuff - u64 size; - u32 bytesRead; - Handle fileHandle; - //setup SDMC archive - FS_archive sdmcArchive=(FS_archive){ARCH_SDMC, (FS_path){PATH_EMPTY, 1, (u8*)""}}; - //create file path struct (note : FS_makePath actually only supports PATH_CHAR, it will change in the future) - FS_path filePath=FS_makePath(PATH_CHAR, "/test.bin"); + FILE *file = fopen("test.bin","rb"); + if (file == NULL) goto exit; - //open file - Result ret=FSUSER_OpenFileDirectly(NULL, &fileHandle, sdmcArchive, filePath, FS_OPEN_READ, FS_ATTRIBUTE_NONE); - //check for errors : exit if there is one - if(ret)goto exit; + // seek to end of file + fseek(file,0,SEEK_END); - //get file size - ret=FSFILE_GetSize(fileHandle, &size); - if(ret)goto exit; + // file pointer tells us the size + off_t size = ftell(file); - //allocate a buffer on linear heap (could just be a malloc fwiw) - buffer=linearAlloc(size); + // seek back to start + fseek(file,0,SEEK_SET); + + //allocate a buffer + buffer=malloc(size); if(!buffer)goto exit; //read contents ! - ret=FSFILE_Read(fileHandle, &bytesRead, 0x0, buffer, size); - if(ret || size!=bytesRead)goto exit; + off_t bytesRead = fread(buffer,1,size,file); //close the file because we like being nice and tidy - ret=FSFILE_Close(fileHandle); - if(ret)goto exit; - + fclose(file); + + if(size!=bytesRead)goto exit; + while(aptMainLoop()) { //exit when user hits B @@ -98,13 +91,8 @@ int main(int argc, char** argv) //cleanup and return //returning from main() returns to hbmenu when run under ninjhax exit: - //closing all handles is super important - svcCloseHandle(fileHandle); + //closing all services even more so - fsExit(); gfxExit(); - hidExit(); - aptExit(); - srvExit(); return 0; } diff --git a/examples/templates/application/Makefile b/examples/templates/application/Makefile new file mode 100644 index 0000000..1ed1097 --- /dev/null +++ b/examples/templates/application/Makefile @@ -0,0 +1,175 @@ +#--------------------------------------------------------------------------------- +.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 + +ifeq ($(strip $(NO_SMDH)),) + export _3DSXFLAGS += --smdh=$(CURDIR)/$(TARGET).smdh +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)),) +$(OUTPUT).3dsx : $(OUTPUT).elf $(OUTPUT).smdh +else +$(OUTPUT).3dsx : $(OUTPUT).elf +endif + +$(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/templates/application/README.md b/examples/templates/application/README.md new file mode 100644 index 0000000..8a43ac1 --- /dev/null +++ b/examples/templates/application/README.md @@ -0,0 +1,3 @@ +# template + +This is a template for starting new 3DS libctru projects. diff --git a/template/source/main.c b/examples/templates/application/source/main.c similarity index 100% rename from template/source/main.c rename to examples/templates/application/source/main.c diff --git a/examples/templates/library/Makefile b/examples/templates/library/Makefile new file mode 100644 index 0000000..2e8b155 --- /dev/null +++ b/examples/templates/library/Makefile @@ -0,0 +1,121 @@ +#--------------------------------------------------------------------------------- +.SUFFIXES: +#--------------------------------------------------------------------------------- + +ifeq ($(strip $(DEVKITARM)),) +$(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM") +endif + +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 +#--------------------------------------------------------------------------------- +TARGET := $(shell basename $(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\ + $(ARCH) + +CFLAGS += $(INCLUDE) -DARM11 -D_3DS +CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions + +ASFLAGS := -g $(ARCH) + +#--------------------------------------------------------------------------------- +# 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)/lib/lib$(TARGET).a + +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) + +.PHONY: $(BUILD) clean all + +#--------------------------------------------------------------------------------- +all: $(BUILD) + +lib: + @[ -d $@ ] || mkdir -p $@ + +$(BUILD): lib + @[ -d $@ ] || mkdir -p $@ + @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(BUILD) lib + +#--------------------------------------------------------------------------------- +else + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +$(OUTPUT) : $(OFILES) + +#--------------------------------------------------------------------------------- +%.bin.o : %.bin +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------------- diff --git a/examples/templates/library/README.md b/examples/templates/library/README.md new file mode 100644 index 0000000..8089b6e --- /dev/null +++ b/examples/templates/library/README.md @@ -0,0 +1,3 @@ +# template + +This is a template for starting new 3DS library projects. diff --git a/examples/templates/library/include/templatelib.h b/examples/templates/library/include/templatelib.h new file mode 100644 index 0000000..1d02448 --- /dev/null +++ b/examples/templates/library/include/templatelib.h @@ -0,0 +1,6 @@ +#ifndef _templatelib_h_ +#define _templatelib_h_ + +int myLibFunction(); + +#endif // _templatelib_h_ diff --git a/examples/templates/library/source/templatelib.c b/examples/templates/library/source/templatelib.c new file mode 100644 index 0000000..570d9e5 --- /dev/null +++ b/examples/templates/library/source/templatelib.c @@ -0,0 +1,6 @@ +int myLibFunction() { + + + return 42; + +} diff --git a/libctru/Makefile b/libctru/Makefile index 37ed8e8..5ee809b 100644 --- a/libctru/Makefile +++ b/libctru/Makefile @@ -29,7 +29,9 @@ SOURCES := source \ source/gpu \ source/services \ source/services/soc \ - source/util + source/util \ + source/system + DATA := data INCLUDES := include diff --git a/libctru/data/default_font.bin b/libctru/data/default_font.bin new file mode 100644 index 0000000..73436fc Binary files /dev/null and b/libctru/data/default_font.bin differ diff --git a/libctru/include/3ds.h b/libctru/include/3ds.h index beec914..1713255 100644 --- a/libctru/include/3ds.h +++ b/libctru/include/3ds.h @@ -9,8 +9,10 @@ extern "C" { #include <3ds/svc.h> #include <3ds/srv.h> #include <3ds/linear.h> +#include <3ds/vram.h> #include <3ds/os.h> #include <3ds/gfx.h> +#include <3ds/console.h> #include <3ds/services/ac.h> #include <3ds/services/apt.h> @@ -27,6 +29,8 @@ extern "C" { #include <3ds/services/soc.h> #include <3ds/services/mic.h> #include <3ds/services/mvd.h> +#include <3ds/services/qtm.h> +#include <3ds/services/hb.h> #include <3ds/gpu/gx.h> #include <3ds/gpu/gpu.h> diff --git a/libctru/include/3ds/console.h b/libctru/include/3ds/console.h new file mode 100644 index 0000000..48c7224 --- /dev/null +++ b/libctru/include/3ds/console.h @@ -0,0 +1,159 @@ + + +/*! \file console.h + \brief 3ds stdio support. + +
+Provides stdio integration for printing to the 3DS screen as well as debug print +functionality provided by stderr. + +General usage is to initialize the console by: +consoleDemoInit() +or to customize the console usage by: +consoleInit() + +*/ + +#ifndef CONSOLE_H +#define CONSOLE_H + +#include <3ds/types.h> + +#ifdef __cplusplus +extern "C" { +#endif + +typedef bool(* ConsolePrint)(void* con, char c); + +//! a font struct for the console. +typedef struct ConsoleFont +{ + u8* gfx; //!< A pointer to the font graphics + u16 asciiOffset; //!< Offset to the first valid character in the font table + u16 numChars; //!< Number of characters in the font graphics + +}ConsoleFont; + +/** \brief console structure used to store the state of a console render context. + +Default values from consoleGetDefault(); +
+PrintConsole defaultConsole =
+{
+	//Font:
+	{
+		(u8*)default_font_bin, //font gfx
+		0, //first ascii character in the set
+		128, //number of characters in the font set
+	},
+	0,0, //cursorX cursorY
+	0,0, //prevcursorX prevcursorY
+	40, //console width
+	30, //console height
+	0,  //window x
+	0,  //window y
+	32, //window width
+	24, //window height
+	3, //tab size
+	0, //font character offset
+	0,  //print callback
+	false //console initialized
+};
+
+*/ +typedef struct PrintConsole +{ + ConsoleFont font; //!< font of the console. + + u16 *frameBuffer; //!< framebuffer address. + + int cursorX; /*!< Current X location of the cursor (as a tile offset by default) */ + int cursorY; /*!< Current Y location of the cursor (as a tile offset by default) */ + + int prevCursorX; /*!< Internal state */ + int prevCursorY; /*!< Internal state */ + + int consoleWidth; /*!< Width of the console hardware layer in characters */ + int consoleHeight; /*!< Height of the console hardware layer in characters */ + + int windowX; /*!< Window X location in characters (not implemented) */ + int windowY; /*!< Window Y location in characters (not implemented) */ + int windowWidth; /*!< Window width in characters (not implemented) */ + int windowHeight; /*!< Window height in characters (not implemented) */ + + int tabSize; /*!< Size of a tab*/ + int fg; /*!< foreground color*/ + int bg; /*!< background color*/ + int flags; /*!< reverse/bright flags*/ + + ConsolePrint PrintChar; /*!< callback for printing a character. Should return true if it has handled rendering the graphics + (else the print engine will attempt to render via tiles) */ + + bool consoleInitialised; /*!< True if the console is initialized */ +}PrintConsole; + +#define CONSOLE_COLOR_BOLD (1<<0) +#define CONSOLE_COLOR_FAINT (1<<1) +#define CONSOLE_ITALIC (1<<2) +#define CONSOLE_UNDERLINE (1<<3) +#define CONSOLE_BLINK_SLOW (1<<4) +#define CONSOLE_BLINK_FAST (1<<5) +#define CONSOLE_COLOR_REVERSE (1<<6) +#define CONSOLE_CONCEAL (1<<7) +#define CONSOLE_CROSSED_OUT (1<<8) + +//! Console debug devices supported by libnds. +typedef enum { + debugDevice_NULL, //!< swallows prints to stderr + debugDevice_3DMOO, //!< Directs stderr debug statements to 3dmoo + debugDevice_CONSOLE, //!< Directs stderr debug statements to 3DS console window +} debugDevice; + +/*! \brief Loads the font into the console + \param console pointer to the console to update, if NULL it will update the current console + \param font the font to load +*/ +void consoleSetFont(PrintConsole* console, ConsoleFont* font); + +/*! \brief Sets the print window + \param console console to set, if NULL it will set the current console window + \param x x location of the window + \param y y location of the window + \param width width of the window + \param height height of the window +*/ +void consoleSetWindow(PrintConsole* console, int x, int y, int width, int height); + +/*! \brief Gets a pointer to the console with the default values + this should only be used when using a single console or without changing the console that is returned, other wise use consoleInit() + \return A pointer to the console with the default values +*/ +PrintConsole* consoleGetDefault(void); + +/*! \brief Make the specified console the render target + \param console A pointer to the console struct (must have been initialized with consoleInit(PrintConsole* console) + \return a pointer to the previous console +*/ +PrintConsole *consoleSelect(PrintConsole* console); + +/*! \brief Initialise the console. + \param screen The screen to use for the console + \param console A pointer to the console data to initialze (if it's NULL, the default console will be used) + \return A pointer to the current console. +*/ +PrintConsole* consoleInit(gfxScreen_t screen, PrintConsole* console); + +/*! \brief Initializes debug console output on stderr to the specified device + \param device The debug device (or devices) to output debug print statements to +*/ +void consoleDebugInit(debugDevice device); + + +//! Clears the screan by using iprintf("\x1b[2J"); +void consoleClear(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libctru/include/3ds/gfx.h b/libctru/include/3ds/gfx.h index e7b33d3..9cfcae0 100644 --- a/libctru/include/3ds/gfx.h +++ b/libctru/include/3ds/gfx.h @@ -2,6 +2,9 @@ #include <3ds/types.h> #include <3ds/services/gsp.h> +#define RGB565(r,g,b) (((b)&0x1f)|(((g)&0x3f)<<5)|(((r)&0x1f)<<11)) +#define RGB8_to_565(r,g,b) (((b)>>3)&0x1f)|((((g)>>2)&0x3f)<<5)|((((r)>>3)&0x1f)<<11) + typedef enum { GFX_TOP = 0, @@ -22,7 +25,8 @@ void gfxExit(); //control stuff void gfxSet3D(bool enable); void gfxSetScreenFormat(gfxScreen_t screen, GSP_FramebufferFormats format); -void gfxSetDoubleBuffering(bool doubleBuffering); +GSP_FramebufferFormats gfxGetScreenFormat(gfxScreen_t screen); +void gfxSetDoubleBuffering(gfxScreen_t screen, bool doubleBuffering); void gfxFlushBuffers(); void gfxSwapBuffers(); void gfxSwapBuffersGpu(); diff --git a/libctru/include/3ds/services/hb.h b/libctru/include/3ds/services/hb.h new file mode 100644 index 0000000..c575984 --- /dev/null +++ b/libctru/include/3ds/services/hb.h @@ -0,0 +1,27 @@ +#ifndef HB_H +#define HB_H + +// WARNING ! THIS FILE PROVIDES AN INTERFACE TO A NON-OFFICIAL SERVICE PROVIDED BY NINJHAX +// BY USING COMMANDS FROM THIS SERVICE YOU WILL LIKELY MAKE YOUR APPLICATION INCOMPATIBLE WITH OTHER HOMEBREW LAUNCHING METHODS +// A GOOD WAY TO COPE WITH THIS IS TO CHECK THE OUTPUT OF initHb FOR ERRORS + +#include <3ds/types.h> + +Result hbInit(); +void hbExit(); + +// flushes/invalidates entire data/instruction cache +// can be useful when writing code to executable pages +Result HB_FlushInvalidateCache(void); + +// fetches the address for ninjhax bootloader addresses, useful for running 3dsx executables +// void (*callBootloader)(Handle hb, Handle file); +// void (*setArgs)(u32* src, u32 length); +Result HB_GetBootloaderAddresses(void** load3dsx, void** setArgv); + +// changes the permissions of a given number of pages at address addr to mode +// should it fail, the appropriate kernel error code will be returned and *reprotectedPages (if not NULL) +// will be set to the number of sequential pages which were successfully reprotected + 1 +Result HB_ReprotectMemory(u32* addr, u32 pages, u32 mode, u32* reprotectedPages); + +#endif diff --git a/libctru/include/3ds/services/hid.h b/libctru/include/3ds/services/hid.h index 4ba6aa7..87a99cf 100644 --- a/libctru/include/3ds/services/hid.h +++ b/libctru/include/3ds/services/hid.h @@ -102,4 +102,5 @@ Result HIDUSER_EnableAccelerometer(); Result HIDUSER_DisableAccelerometer(); Result HIDUSER_EnableGyroscope(); Result HIDUSER_DisableGyroscope(); - +Result HIDUSER_GetGyroscopeRawToDpsCoefficient(float *coeff); +Result HIDUSER_GetSoundVolume(u8 *volume); //Return the volume slider value (0-63) diff --git a/libctru/include/3ds/services/pm.h b/libctru/include/3ds/services/pm.h index cb5c948..27b827a 100644 --- a/libctru/include/3ds/services/pm.h +++ b/libctru/include/3ds/services/pm.h @@ -14,7 +14,7 @@ About: Launches a title titleid TitleId of title to launch launch_flags use if you know of any */ -Result PM_LaunchTitle(u8 mediatype, u64 titleid); +Result PM_LaunchTitle(u8 mediatype, u64 titleid, u32 launch_flags); /* PM_GetTitleExheaderFlags() About: Writes to a buffer the launch flags (8 bytes) from a title exheader. @@ -28,7 +28,7 @@ Result PM_GetTitleExheaderFlags(u8 mediatype, u64 titleid, u8* out); /* PM_SetFIRMLaunchParams() About: Sets the FIRM launch params from in - size size of FIRM launch params + size size of FIRM launch params in ptr to location of FIRM launch params */ Result PM_SetFIRMLaunchParams(u32 size, u8* in); @@ -36,7 +36,7 @@ Result PM_SetFIRMLaunchParams(u32 size, u8* in); /* PM_GetFIRMLaunchParams() About: Sets the FIRM launch params from in - size size of buffer to store FIRM launch params + size size of buffer to store FIRM launch params out ptr to location to write FIRM launch params */ Result PM_GetFIRMLaunchParams(u32 size, u8* out); @@ -45,7 +45,7 @@ Result PM_GetFIRMLaunchParams(u32 size, u8* out); About: Same as PM_SetFIRMLaunchParams(), but also triggers a FIRM launch firm_titleid_low TitleID low of firm title to launch - size size of FIRM launch params + size size of FIRM launch params in ptr to location of FIRM launch params */ -Result PM_LaunchFIRMSetParams(u64 firm_titleid_low, u32 size, u8* in); \ No newline at end of file +Result PM_LaunchFIRMSetParams(u32 firm_titleid_low, u32 size, u8* in); diff --git a/libctru/include/3ds/services/qtm.h b/libctru/include/3ds/services/qtm.h new file mode 100644 index 0000000..931195e --- /dev/null +++ b/libctru/include/3ds/services/qtm.h @@ -0,0 +1,25 @@ +#pragma once + +//See also: http://3dbrew.org/wiki/QTM_Services + +typedef struct { + float x; + float y; +} qtmHeadtrackingInfoCoord; + +typedef struct { + u8 flags[5]; + u8 padding[3]; + float floatdata_x08;//"not used by System_Settings." + qtmHeadtrackingInfoCoord coords0[4]; + u32 unk_x2c[5];//"Not used by System_Settings." +} qtmHeadtrackingInfo; + +Result qtmInit(); +void qtmExit(); +bool qtmCheckInitialized(); + +Result qtmGetHeadtrackingInfo(u64 val, qtmHeadtrackingInfo *out);//val is normally 0. +bool qtmCheckHeadFullyDetected(qtmHeadtrackingInfo *info); +Result qtmConvertCoordToScreen(qtmHeadtrackingInfoCoord *coord, float *screen_width, float *screen_height, u32 *x, u32 *y);//screen_* can be NULL to use the default values for the top-screen. + diff --git a/libctru/include/3ds/svc.h b/libctru/include/3ds/svc.h index ab0230c..271408f 100644 --- a/libctru/include/3ds/svc.h +++ b/libctru/include/3ds/svc.h @@ -16,10 +16,11 @@ typedef enum { } MemOp; typedef enum { - MEMPERM_READ =1, - MEMPERM_WRITE =2, - MEMPERM_EXECUTE=4, - MEMPERM_MAX =0xFFFFFFFF //force 4-byte + MEMPERM_READ = 1, + MEMPERM_WRITE = 2, + MEMPERM_EXECUTE = 4, + MEMPERM_DONTCARE = 0x10000000, + MEMPERM_MAX = 0xFFFFFFFF //force 4-byte } MemPerm; typedef struct { diff --git a/libctru/include/3ds/vram.h b/libctru/include/3ds/vram.h new file mode 100644 index 0000000..9743410 --- /dev/null +++ b/libctru/include/3ds/vram.h @@ -0,0 +1,8 @@ +#pragma once + +// Functions for allocating/deallocating VRAM +void* vramAlloc(size_t size); // returns a 16-byte aligned address +void* vramMemAlign(size_t size, size_t alignment); +void* vramRealloc(void* mem, size_t size); // not implemented yet +void vramFree(void* mem); +u32 vramSpaceFree(); // get free VRAM space in bytes diff --git a/libctru/source/allocator/addrmap.h b/libctru/source/allocator/addrmap.h new file mode 100644 index 0000000..11e8183 --- /dev/null +++ b/libctru/source/allocator/addrmap.h @@ -0,0 +1,48 @@ +#pragma once + +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); +} diff --git a/libctru/source/allocator/linear.cpp b/libctru/source/allocator/linear.cpp index b0a4b27..0ad052c 100644 --- a/libctru/source/allocator/linear.cpp +++ b/libctru/source/allocator/linear.cpp @@ -1,57 +1,16 @@ -#include <3ds.h> -#include <3ds/util/rbtree.h> +extern "C" +{ + #include <3ds/types.h> + #include <3ds/linear.h> + #include <3ds/util/rbtree.h> +} #include "mem_pool.h" +#include "addrmap.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() { diff --git a/libctru/source/allocator/mem_pool.h b/libctru/source/allocator/mem_pool.h index 97ca60b..87013e6 100644 --- a/libctru/source/allocator/mem_pool.h +++ b/libctru/source/allocator/mem_pool.h @@ -1,5 +1,5 @@ #pragma once -#include <3ds.h> +#include <3ds/types.h> #include struct MemChunk diff --git a/libctru/source/allocator/vram.cpp b/libctru/source/allocator/vram.cpp new file mode 100644 index 0000000..4918729 --- /dev/null +++ b/libctru/source/allocator/vram.cpp @@ -0,0 +1,86 @@ +extern "C" +{ + #include <3ds/types.h> + #include <3ds/vram.h> + #include <3ds/util/rbtree.h> +} + +#include "mem_pool.h" +#include "addrmap.h" + +static MemPool sVramPool; + +static bool vramInit() +{ + auto blk = MemBlock::Create((u8*)0x1F000000, 0x00600000); + if (blk) + { + sVramPool.AddBlock(blk); + rbtree_init(&sAddrMap, addrMapNodeComparator); + return true; + } + return false; +} + +void* vramMemAlign(size_t size, size_t alignment) +{ + // Enforce minimum alignment + if (alignment < 16) + alignment = 16; + + // Convert alignment to shift amount + int shift; + for (shift = 4; shift < 32; shift ++) + { + if ((1U<node)); + return chunk.addr; +} + +void* vramAlloc(size_t size) +{ + return vramMemAlign(size, 16); +} + +void* vramRealloc(void* mem, size_t size) +{ + // TODO + return NULL; +} + +void vramFree(void* mem) +{ + auto node = getNode(mem); + if (!node) return; + + // Free the chunk + sVramPool.Deallocate(node->chunk); + + // Free the node + delNode(node); +} + +u32 vramSpaceFree() +{ + return sVramPool.GetFreeSpace(); +} diff --git a/libctru/source/console.c b/libctru/source/console.c new file mode 100644 index 0000000..c6469f2 --- /dev/null +++ b/libctru/source/console.c @@ -0,0 +1,751 @@ +#include +#include +#include +#include <3ds/gfx.h> +#include <3ds/console.h> +#include <3ds/svc.h> + +#include "default_font_bin.h" + +//set up the palette for color printing +static u16 colorTable[] = { + RGB8_to_565( 0, 0, 0), // black + RGB8_to_565(128, 0, 0), // red + RGB8_to_565( 0,128, 0), // green + RGB8_to_565(128,128, 0), // yellow + RGB8_to_565( 0, 0,128), // blue + RGB8_to_565(128, 0,128), // magenta + RGB8_to_565( 0,128,128), // cyan + RGB8_to_565(192,192,192), // white + + RGB8_to_565(128,128,128), // bright black + RGB8_to_565(255, 0, 0), // bright red + RGB8_to_565( 0,255, 0), // bright green + RGB8_to_565(255,255, 0), // bright yellow + RGB8_to_565( 0, 0,255), // bright blue + RGB8_to_565(255, 0,255), // bright magenta + RGB8_to_565( 0,255,255), // bright cyan + RGB8_to_565(255,255,255), // bright white + + RGB8_to_565( 0, 0, 0), // faint black + RGB8_to_565( 64, 0, 0), // faint red + RGB8_to_565( 0, 64, 0), // faint green + RGB8_to_565( 64, 64, 0), // faint yellow + RGB8_to_565( 0, 0, 64), // faint blue + RGB8_to_565( 64, 0, 64), // faint magenta + RGB8_to_565( 0, 64, 64), // faint cyan + RGB8_to_565( 96, 96, 96), // faint white +}; + +PrintConsole defaultConsole = +{ + //Font: + { + (u8*)default_font_bin, //font gfx + 0, //first ascii character in the set + 128 //number of characters in the font set + }, + (u16*)NULL, + 0,0, //cursorX cursorY + 0,0, //prevcursorX prevcursorY + 40, //console width + 30, //console height + 0, //window x + 0, //window y + 40, //window width + 30, //window height + 3, //tab size + 7, // foreground color + 0, // background color + 0, // flags + 0, //print callback + false //console initialized +}; + +PrintConsole currentCopy; + +PrintConsole* currentConsole = ¤tCopy; + +PrintConsole* consoleGetDefault(void){return &defaultConsole;} + +void consolePrintChar(char c); +void consoleDrawChar(int c); + +//--------------------------------------------------------------------------------- +static void consoleCls(char mode) { +//--------------------------------------------------------------------------------- + + int i = 0; + int colTemp,rowTemp; + + switch (mode) + { + case '[': + case '0': + { + colTemp = currentConsole->cursorX ; + rowTemp = currentConsole->cursorY ; + + while(i++ < ((currentConsole->windowHeight * currentConsole->windowWidth) - (rowTemp * currentConsole->consoleWidth + colTemp))) + consolePrintChar(' '); + + currentConsole->cursorX = colTemp; + currentConsole->cursorY = rowTemp; + break; + } + case '1': + { + colTemp = currentConsole->cursorX ; + rowTemp = currentConsole->cursorY ; + + currentConsole->cursorY = 0; + currentConsole->cursorX = 0; + + while (i++ < (rowTemp * currentConsole->windowWidth + colTemp)) + consolePrintChar(' '); + + currentConsole->cursorX = colTemp; + currentConsole->cursorY = rowTemp; + break; + } + case '2': + { + currentConsole->cursorY = 0; + currentConsole->cursorX = 0; + + while(i++ < currentConsole->windowHeight * currentConsole->windowWidth) + consolePrintChar(' '); + + currentConsole->cursorY = 0; + currentConsole->cursorX = 0; + break; + } + } +} +//--------------------------------------------------------------------------------- +static void consoleClearLine(char mode) { +//--------------------------------------------------------------------------------- + + int i = 0; + int colTemp; + + switch (mode) + { + case '[': + case '0': + { + colTemp = currentConsole->cursorX ; + + while(i++ < (currentConsole->windowWidth - colTemp)) { + consolePrintChar(' '); + } + + currentConsole->cursorX = colTemp; + + break; + } + case '1': + { + colTemp = currentConsole->cursorX ; + + currentConsole->cursorX = 0; + + while(i++ < ((currentConsole->windowWidth - colTemp)-2)) { + consolePrintChar(' '); + } + + currentConsole->cursorX = colTemp; + + break; + } + case '2': + { + colTemp = currentConsole->cursorX ; + + currentConsole->cursorX = 0; + + while(i++ < currentConsole->windowWidth) { + consolePrintChar(' '); + } + + currentConsole->cursorX = colTemp; + + break; + } + } +} + + +//--------------------------------------------------------------------------------- +ssize_t con_write(struct _reent *r,int fd,const char *ptr, size_t len) { +//--------------------------------------------------------------------------------- + + char chr; + + int i, count = 0; + char *tmp = (char*)ptr; + + if(!tmp || len<=0) return -1; + + i = 0; + + while(i= '0' && chr <= '9') || chr == ';') + continue; + + switch (chr) { + //--------------------------------------- + // Cursor directional movement + //--------------------------------------- + case 'A': + consumed = 0; + assigned = sscanf(escapeseq,"[%dA%n", ¶meter, &consumed); + if (assigned==0) parameter = 1; + if (consumed) + currentConsole->cursorY = (currentConsole->cursorY - parameter) < 0 ? 0 : currentConsole->cursorY - parameter; + escaping = false; + break; + case 'B': + consumed = 0; + assigned = sscanf(escapeseq,"[%dB%n", ¶meter, &consumed); + if (assigned==0) parameter = 1; + if (consumed) + currentConsole->cursorY = (currentConsole->cursorY + parameter) > currentConsole->windowHeight - 1 ? currentConsole->windowHeight - 1 : currentConsole->cursorY + parameter; + escaping = false; + break; + case 'C': + consumed = 0; + assigned = sscanf(escapeseq,"[%dC%n", ¶meter, &consumed); + if (assigned==0) parameter = 1; + if (consumed) + currentConsole->cursorX = (currentConsole->cursorX + parameter) > currentConsole->windowWidth - 1 ? currentConsole->windowWidth - 1 : currentConsole->cursorX + parameter; + escaping = false; + break; + case 'D': + consumed = 0; + assigned = sscanf(escapeseq,"[%dD%n", ¶meter, &consumed); + if (assigned==0) parameter = 1; + if (consumed) + currentConsole->cursorX = (currentConsole->cursorX - parameter) < 0 ? 0 : currentConsole->cursorX - parameter; + escaping = false; + break; + //--------------------------------------- + // Cursor position movement + //--------------------------------------- + case 'H': + case 'f': + { + int x, y; + char c; + if(sscanf(escapeseq,"[%d;%d%c", &y, &x, &c) == 3 && (c == 'f' || c == 'H')) { + currentConsole->cursorX = x; + currentConsole->cursorY = y; + escaping = false; + break; + } + + x = y = 1; + if(sscanf(escapeseq,"[%d;%c", &y, &c) == 2 && (c == 'f' || c == 'H')) { + currentConsole->cursorX = x; + currentConsole->cursorY = y; + escaping = false; + break; + } + + x = y = 1; + if(sscanf(escapeseq,"[;%d%c", &x, &c) == 2 && (c == 'f' || c == 'H')) { + currentConsole->cursorX = x; + currentConsole->cursorY = y; + escaping = false; + break; + } + + x = y = 1; + if(sscanf(escapeseq,"[;%c", &c) == 1 && (c == 'f' || c == 'H')) { + currentConsole->cursorX = x; + currentConsole->cursorY = y; + escaping = false; + break; + } + + // invalid format + escaping = false; + break; + } + //--------------------------------------- + // Screen clear + //--------------------------------------- + case 'J': + if(escapelen <= 3) + consoleCls(escapeseq[escapelen-2]); + escaping = false; + break; + //--------------------------------------- + // Line clear + //--------------------------------------- + case 'K': + if(escapelen <= 3) + consoleClearLine(escapeseq[escapelen-2]); + escaping = false; + break; + //--------------------------------------- + // Save cursor position + //--------------------------------------- + case 's': + if(escapelen == 2) { + currentConsole->prevCursorX = currentConsole->cursorX ; + currentConsole->prevCursorY = currentConsole->cursorY ; + } + escaping = false; + break; + //--------------------------------------- + // Load cursor position + //--------------------------------------- + case 'u': + if(escapelen == 2) { + currentConsole->cursorX = currentConsole->prevCursorX ; + currentConsole->cursorY = currentConsole->prevCursorY ; + } + escaping = false; + break; + //--------------------------------------- + // Color scan codes + //--------------------------------------- + case 'm': + escapeseq++; + escapelen--; + + do { + parameter = 0; + if (escapelen == 1) { + consumed = 1; + } else if (strchr(escapeseq,';')) { + sscanf(escapeseq,"%d;%n", ¶meter, &consumed); + } else { + sscanf(escapeseq,"%dm%n", ¶meter, &consumed); + } + + escapeseq += consumed; + escapelen -= consumed; + + switch(parameter) { + case 0: // reset + currentConsole->flags = 0; + currentConsole->bg = 0; + currentConsole->fg = 7; + break; + + case 1: // bold + currentConsole->flags &= ~CONSOLE_COLOR_FAINT; + currentConsole->flags |= CONSOLE_COLOR_BOLD; + break; + + case 2: // faint + currentConsole->flags &= ~CONSOLE_COLOR_BOLD; + currentConsole->flags |= CONSOLE_COLOR_FAINT; + break; + + case 3: // italic + currentConsole->flags |= CONSOLE_ITALIC; + break; + + case 4: // underline + currentConsole->flags |= CONSOLE_UNDERLINE; + break; + + case 5: // blink slow + currentConsole->flags &= ~CONSOLE_BLINK_FAST; + currentConsole->flags |= CONSOLE_BLINK_SLOW; + break; + + case 6: // blink fast + currentConsole->flags &= ~CONSOLE_BLINK_SLOW; + currentConsole->flags |= CONSOLE_BLINK_FAST; + break; + + case 7: // reverse video + currentConsole->flags |= CONSOLE_COLOR_REVERSE; + break; + + case 8: // conceal + currentConsole->flags |= CONSOLE_CONCEAL; + break; + + case 9: // crossed-out + currentConsole->flags |= CONSOLE_CROSSED_OUT; + break; + + case 21: // bold off + currentConsole->flags &= ~CONSOLE_COLOR_BOLD; + break; + + case 22: // normal color + currentConsole->flags &= ~CONSOLE_COLOR_BOLD; + currentConsole->flags &= ~CONSOLE_COLOR_FAINT; + break; + + case 23: // italic off + currentConsole->flags &= ~CONSOLE_ITALIC; + break; + + case 24: // underline off + currentConsole->flags &= ~CONSOLE_UNDERLINE; + break; + + case 25: // blink off + currentConsole->flags &= ~CONSOLE_BLINK_SLOW; + currentConsole->flags &= ~CONSOLE_BLINK_FAST; + break; + + case 27: // reverse off + currentConsole->flags &= ~CONSOLE_COLOR_REVERSE; + break; + + case 29: // crossed-out off + currentConsole->flags &= ~CONSOLE_CROSSED_OUT; + break; + + case 30 ... 37: // writing color + currentConsole->fg = parameter - 30; + break; + + case 39: // reset foreground color + currentConsole->fg = 7; + break; + + case 40 ... 47: // screen color + currentConsole->bg = parameter - 40; + break; + + case 49: // reset background color + currentConsole->fg = 0; + break; + } + } while (escapelen > 0); + + escaping = false; + break; + + default: + // some sort of unsupported escape; just gloss over it + escaping = false; + break; + } + } while (escaping); + continue; + } + + consolePrintChar(chr); + } + + return count; +} + +static const devoptab_t dotab_stdout = { + "con", + 0, + NULL, + NULL, + con_write, + NULL, + NULL, + NULL +}; + +//--------------------------------------------------------------------------------- +ssize_t debug_write(struct _reent *r, int fd, const char *ptr, size_t len) { +//--------------------------------------------------------------------------------- + svcOutputDebugString(ptr,len); + return len; +} + +static const devoptab_t dotab_3dmoo = { + "3dmoo", + 0, + NULL, + NULL, + debug_write, + NULL, + NULL, + NULL +}; + + +static const devoptab_t dotab_null = { + "null", + 0, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL +}; + +//--------------------------------------------------------------------------------- +PrintConsole* consoleInit(gfxScreen_t screen, PrintConsole* console) { +//--------------------------------------------------------------------------------- + + static bool firstConsoleInit = true; + + if(firstConsoleInit) { + devoptab_list[STD_OUT] = &dotab_stdout; + devoptab_list[STD_ERR] = &dotab_stdout; + + setvbuf(stdout, NULL , _IONBF, 0); + setvbuf(stderr, NULL , _IONBF, 0); + + firstConsoleInit = false; + } + + if(console) { + currentConsole = console; + } else { + console = currentConsole; + } + + *currentConsole = defaultConsole; + + console->consoleInitialised = 1; + + gfxSetScreenFormat(screen,GSP_RGB565_OES); + gfxSetDoubleBuffering(screen,false); + console->frameBuffer = (u16*)gfxGetFramebuffer(screen, GFX_LEFT, NULL, NULL); + + if(screen==GFX_TOP) { + console->consoleWidth = 50; + console->windowWidth = 50; + } + + + consoleCls('2'); + + return currentConsole; + +} + +//--------------------------------------------------------------------------------- +void consoleDebugInit(debugDevice device){ +//--------------------------------------------------------------------------------- + + int buffertype = _IONBF; + + switch(device) { + + case debugDevice_3DMOO: + devoptab_list[STD_ERR] = &dotab_3dmoo; + buffertype = _IOLBF; + break; + case debugDevice_CONSOLE: + devoptab_list[STD_ERR] = &dotab_stdout; + break; + case debugDevice_NULL: + devoptab_list[STD_ERR] = &dotab_null; + break; + } + setvbuf(stderr, NULL , buffertype, 0); + +} + +//--------------------------------------------------------------------------------- +PrintConsole *consoleSelect(PrintConsole* console){ +//--------------------------------------------------------------------------------- + PrintConsole *tmp = currentConsole; + currentConsole = console; + return tmp; +} + +//--------------------------------------------------------------------------------- +void consoleSetFont(PrintConsole* console, ConsoleFont* font){ +//--------------------------------------------------------------------------------- + + if(!console) console = currentConsole; + + console->font = *font; + +} + +//--------------------------------------------------------------------------------- +static void newRow() { +//--------------------------------------------------------------------------------- + + + currentConsole->cursorY ++; + + + if(currentConsole->cursorY >= currentConsole->windowHeight) { + currentConsole->cursorY --; + u16 *dst = ¤tConsole->frameBuffer[(currentConsole->windowX * 8 * 240) + (239 - (currentConsole->windowY * 8))]; + u16 *src = dst - 8; + + int i,j; + + for (i=0; iwindowWidth*8; i++) { + u32 *from = (u32*)((int)src & ~3); + u32 *to = (u32*)((int)dst & ~3); + for (j=0;j<(((currentConsole->windowHeight-1)*8)/2);j++) *(to--) = *(from--); + dst += 240; + src += 240; + } + + consoleClearLine('2'); + } +} +//--------------------------------------------------------------------------------- +void consoleDrawChar(int c) { +//--------------------------------------------------------------------------------- + c -= currentConsole->font.asciiOffset; + if ( c < 0 || c > currentConsole->font.numChars ) return; + + u8 *fontdata = currentConsole->font.gfx + (8 * c); + + int writingColor = currentConsole->fg; + int screenColor = currentConsole->bg; + + if (currentConsole->flags & CONSOLE_COLOR_BOLD) { + writingColor += 8; + } else if (currentConsole->flags & CONSOLE_COLOR_FAINT) { + writingColor += 16; + } + + if (currentConsole->flags & CONSOLE_COLOR_REVERSE) { + int tmp = writingColor; + writingColor = screenColor; + screenColor = tmp; + } + + u16 bg = colorTable[screenColor]; + u16 fg = colorTable[writingColor]; + + u8 b1 = *(fontdata++); + u8 b2 = *(fontdata++); + u8 b3 = *(fontdata++); + u8 b4 = *(fontdata++); + u8 b5 = *(fontdata++); + u8 b6 = *(fontdata++); + u8 b7 = *(fontdata++); + u8 b8 = *(fontdata++); + + if (currentConsole->flags & CONSOLE_UNDERLINE) b8 = 0xff; + + if (currentConsole->flags & CONSOLE_CROSSED_OUT) b4 = 0xff; + + u8 mask = 0x80; + + + int i; + + int x = (currentConsole->cursorX + currentConsole->windowX) * 8; + int y = ((currentConsole->cursorY + currentConsole->windowY) *8 ); + + u16 *screen = ¤tConsole->frameBuffer[(x * 240) + (239 - (y + 7))]; + + for (i=0;i<8;i++) { + if (b8 & mask) { *(screen++) = fg; }else{ *(screen++) = bg; } + if (b7 & mask) { *(screen++) = fg; }else{ *(screen++) = bg; } + if (b6 & mask) { *(screen++) = fg; }else{ *(screen++) = bg; } + if (b5 & mask) { *(screen++) = fg; }else{ *(screen++) = bg; } + if (b4 & mask) { *(screen++) = fg; }else{ *(screen++) = bg; } + if (b3 & mask) { *(screen++) = fg; }else{ *(screen++) = bg; } + if (b2 & mask) { *(screen++) = fg; }else{ *(screen++) = bg; } + if (b1 & mask) { *(screen++) = fg; }else{ *(screen++) = bg; } + mask >>= 1; + screen += 240 - 8; + } + +} + +//--------------------------------------------------------------------------------- +void consolePrintChar(char c) { +//--------------------------------------------------------------------------------- + if (c==0) return; + + if(currentConsole->PrintChar) + if(currentConsole->PrintChar(currentConsole, c)) + return; + + if(currentConsole->cursorX >= currentConsole->windowWidth) { + currentConsole->cursorX = 0; + + newRow(); + } + + switch(c) { + /* + The only special characters we will handle are tab (\t), carriage return (\r), line feed (\n) + and backspace (\b). + Carriage return & line feed will function the same: go to next line and put cursor at the beginning. + For everything else, use VT sequences. + + Reason: VT sequences are more specific to the task of cursor placement. + The special escape sequences \b \f & \v are archaic and non-portable. + */ + case 8: + currentConsole->cursorX--; + + if(currentConsole->cursorX < 0) { + if(currentConsole->cursorY > 0) { + currentConsole->cursorX = currentConsole->windowX - 1; + currentConsole->cursorY--; + } else { + currentConsole->cursorX = 0; + } + } + + consoleDrawChar(' '); + break; + + case 9: + currentConsole->cursorX += currentConsole->tabSize - ((currentConsole->cursorX)%(currentConsole->tabSize)); + break; + case 10: + newRow(); + case 13: + currentConsole->cursorX = 0; + break; + default: + consoleDrawChar(c); + ++currentConsole->cursorX ; + break; + } +} + +//--------------------------------------------------------------------------------- +void consoleClear(void) { +//--------------------------------------------------------------------------------- + iprintf("\x1b[2J"); +} + +//--------------------------------------------------------------------------------- +void consoleSetWindow(PrintConsole* console, int x, int y, int width, int height){ +//--------------------------------------------------------------------------------- + + if(!console) console = currentConsole; + + console->windowWidth = width; + console->windowHeight = height; + console->windowX = x; + console->windowY = y; + + console->cursorX = 0; + console->cursorY = 0; + +} + + diff --git a/libctru/source/gfx.c b/libctru/source/gfx.c index df99fcc..9c9aded 100644 --- a/libctru/source/gfx.c +++ b/libctru/source/gfx.c @@ -1,7 +1,10 @@ #include #include #include -#include <3ds.h> +#include <3ds/types.h> +#include <3ds/gfx.h> +#include <3ds/svc.h> +#include <3ds/linear.h> GSP_FramebufferInfo topFramebufferInfo, bottomFramebufferInfo; @@ -12,9 +15,9 @@ u8* gfxTopLeftFramebuffers[2]; u8* gfxTopRightFramebuffers[2]; u8* gfxBottomFramebuffers[2]; -static u8 currentBuffer; static bool enable3d; -static int doubleBuf = 1; +static u8 currentBuffer[2]; +static int doubleBuf[2] = {1,1}; Handle gspEvent, gspSharedMemHandle; @@ -33,8 +36,15 @@ void gfxSetScreenFormat(gfxScreen_t screen, GSP_FramebufferFormats format) { botFormat = format; } -void gfxSetDoubleBuffering(bool doubleBuffering) { - doubleBuf = doubleBuffering ? 1 : 0; // make sure they're the integer values '1' and '0' +GSP_FramebufferFormats gfxGetScreenFormat(gfxScreen_t screen) { + if(screen==GFX_TOP) + return topFormat; + else + return botFormat; +} + +void gfxSetDoubleBuffering( gfxScreen_t screen, bool doubleBuffering) { + doubleBuf[screen] = doubleBuffering ? 1 : 0; // make sure they're the integer values '1' and '0' } static u32 __get_bytes_per_pixel(GSP_FramebufferFormats format) { @@ -81,7 +91,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]^=doubleBuf; + framebufferInfoHeader[0x0]^=doubleBuf[screen]; framebufferInfo[framebufferInfoHeader[0x0]]=(screen==GFX_TOP)?(topFramebufferInfo):(bottomFramebufferInfo); framebufferInfoHeader[0x1]=1; } @@ -93,7 +103,6 @@ void gfxInit() gfxSharedMemory=(u8*)0x10002000; GSPGPU_AcquireRight(NULL, 0x0); - GSPGPU_SetLcdForceBlack(NULL, 0x0); //setup our gsp shared mem section svcCreateEvent(&gspEvent, 0x0); @@ -124,11 +133,14 @@ void gfxInit() //GSP shared mem : 0x2779F000 gxCmdBuf=(u32*)(gfxSharedMemory+0x800+gfxThreadID*0x200); - currentBuffer=0; + currentBuffer[0]=0; + currentBuffer[1]=0; // Initialize event handler and wait for VBlank gspInitEventHandler(gspEvent, (vu8*)gfxSharedMemory, gfxThreadID); gspWaitForVBlank(); + + GSPGPU_SetLcdForceBlack(NULL, 0x0); } void gfxExit() @@ -153,7 +165,7 @@ void gfxExit() svcCloseHandle(gspEvent); GSPGPU_ReleaseRight(NULL); - + gspExit(); } @@ -164,10 +176,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^doubleBuf]):(gfxTopRightFramebuffers[currentBuffer^doubleBuf]); + return (side==GFX_LEFT || !enable3d)?(gfxTopLeftFramebuffers[currentBuffer[0]^doubleBuf[0]]):(gfxTopRightFramebuffers[currentBuffer[0]^doubleBuf[0]]); }else{ if(height)*height=320; - return gfxBottomFramebuffers[currentBuffer^doubleBuf]; + return gfxBottomFramebuffers[currentBuffer[1]^doubleBuf[1]]; } } @@ -180,18 +192,20 @@ void gfxFlushBuffers() void gfxSwapBuffers() { - currentBuffer^=doubleBuf; - gfxSetFramebufferInfo(GFX_TOP, currentBuffer); - gfxSetFramebufferInfo(GFX_BOTTOM, currentBuffer); + currentBuffer[0]^=doubleBuf[0]; + currentBuffer[1]^=doubleBuf[1]; + gfxSetFramebufferInfo(GFX_TOP, currentBuffer[0]); + gfxSetFramebufferInfo(GFX_BOTTOM, currentBuffer[1]); GSPGPU_SetBufferSwap(NULL, GFX_TOP, &topFramebufferInfo); GSPGPU_SetBufferSwap(NULL, GFX_BOTTOM, &bottomFramebufferInfo); } void gfxSwapBuffersGpu() { - currentBuffer^=doubleBuf; - gfxSetFramebufferInfo(GFX_TOP, currentBuffer); - gfxSetFramebufferInfo(GFX_BOTTOM, currentBuffer); + currentBuffer[0]^=doubleBuf[0]; + currentBuffer[1]^=doubleBuf[1]; + gfxSetFramebufferInfo(GFX_TOP, currentBuffer[0]); + gfxSetFramebufferInfo(GFX_BOTTOM, currentBuffer[1]); gfxWriteFramebufferInfo(GFX_TOP); gfxWriteFramebufferInfo(GFX_BOTTOM); } diff --git a/libctru/source/gpu/gpu.c b/libctru/source/gpu/gpu.c index 303da75..5a1c978 100644 --- a/libctru/source/gpu/gpu.c +++ b/libctru/source/gpu/gpu.c @@ -4,7 +4,10 @@ #include #include -#include <3ds.h> +#include <3ds/types.h> +#include <3ds/gpu/gpu.h> +#include <3ds/gpu/gx.h> +#include <3ds/gpu/shdr.h> u32* gpuCmdBuf; u32 gpuCmdBufSize; diff --git a/libctru/source/gpu/shdr.c b/libctru/source/gpu/shdr.c index c38638e..566520d 100644 --- a/libctru/source/gpu/shdr.c +++ b/libctru/source/gpu/shdr.c @@ -4,8 +4,9 @@ #include #include -#include <3ds.h> - +#include <3ds/types.h> +#include <3ds/gpu/gpu.h> +#include <3ds/gpu/shdr.h> //please don't feed this an invalid SHBIN DVLB_s* SHDR_ParseSHBIN(u32* shbinData, u32 shbinSize) diff --git a/libctru/source/initSystem.c b/libctru/source/initSystem.c deleted file mode 100644 index 039f862..0000000 --- a/libctru/source/initSystem.c +++ /dev/null @@ -1,118 +0,0 @@ -#include -#include -#include <3ds.h> - -// System globals we define here -int __system_argc; -char** __system_argv; -void (*__system_retAddr)(void); -u32 __linear_heap; - -// Data from _prm structure -extern void* __service_ptr; // used to detect if we're run from a homebrew launcher -extern u32 __heap_size, __linear_heap_size; -extern const char* __system_arglist; - -// newlib definitions we need -void __libc_init_array(void); -void __libc_fini_array(void); -extern char* fake_heap_start; -extern char* fake_heap_end; - -static void initArgv(); -static u32 heapBase; - -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(&tmp, __linear_heap, 0x0, __linear_heap_size, MEMOP_FREE, 0x0); - - // Unmap the application heap - svcControlMemory(&tmp, heapBase, 0x0, __heap_size, MEMOP_FREE, 0x0); - - // Close some handles - __destroy_handle_list(); - - // Jump to the loader if it provided a callback - if (__system_retAddr) - __system_retAddr(); - - // Since above did not jump, end this process - svcExitProcess(); -} - -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(&tmp, heapBase, 0x0, __heap_size, MEMOP_ALLOC, 0x3); - - // Allocate the linear heap - svcControlMemory(&__linear_heap, 0x0, 0x0, __linear_heap_size, MEMOP_ALLOC_LINEAR, 0x3); - - // Set up newlib heap - fake_heap_start = (char*)heapBase; - fake_heap_end = fake_heap_start + __heap_size; - - // Build argc/argv if present - initArgv(); - - // TODO: APT init goes here - - // Run the global constructors - __libc_init_array(); -} - -void initArgv() -{ - int i; - const char* temp = __system_arglist; - - // Check if the argument list is present - if (!temp) - return; - - // Retrieve argc - __system_argc = *(u32*)temp; - temp += sizeof(u32); - - // Find the end of the argument data - for (i = 0; i < __system_argc; i ++) - { - for (; *temp; temp ++); - temp ++; - } - - // Reserve heap memory for argv data - u32 argSize = temp - __system_arglist - sizeof(u32); - __system_argv = (char**)fake_heap_start; - fake_heap_start += sizeof(char**)*(__system_argc + 1); - char* argCopy = fake_heap_start; - fake_heap_start += argSize; - - // Fill argv array - memcpy(argCopy, &__system_arglist[4], argSize); - temp = argCopy; - for (i = 0; i < __system_argc; i ++) - { - __system_argv[i] = (char*)temp; - for (; *temp; temp ++); - temp ++; - } - __system_argv[__system_argc] = NULL; -} diff --git a/libctru/source/os.c b/libctru/source/os.c index e2677ed..d0287ad 100644 --- a/libctru/source/os.c +++ b/libctru/source/os.c @@ -1,4 +1,7 @@ -#include <3ds.h> +#include <3ds/types.h> +#include <3ds/os.h> +#include <3ds/svc.h> + #define TICKS_PER_MSEC 268123.480 @@ -10,9 +13,9 @@ typedef struct { static volatile u32* __datetime_selector = (u32*) 0x1FF81000; -static volatile datetime_t* __datetime1 = +static volatile datetime_t* __datetime0 = (datetime_t*) 0x1FF81020; -static volatile datetime_t* __datetime2 = +static volatile datetime_t* __datetime1 = (datetime_t*) 0x1FF81040; @@ -38,19 +41,27 @@ u32 osConvertOldLINEARMemToNew(u32 vaddr) // Returns number of milliseconds since 1st Jan 1900 00:00. u64 osGetTime() { - volatile datetime_t* dt; + u32 s1, s2 = *__datetime_selector & 1; + datetime_t dt; - switch(*__datetime_selector & 1) { - case 0: - dt = __datetime1; - break; - case 1: - dt = __datetime2; - break; - } + do { + s1 = s2; + if(!s1) + dt = *__datetime0; + else + dt = *__datetime1; + s2 = *__datetime_selector & 1; + } while(s2 != s1); - u64 offset = (u32)((u32)(svcGetSystemTick() - dt->update_tick) / TICKS_PER_MSEC); - return dt->date_time + offset; + u64 delta = svcGetSystemTick() - dt.update_tick; + + // Work around the VFP not supporting 64-bit integer <--> floating point conversion + double temp = (u32)(delta >> 32); + temp *= 0x100000000ULL; + temp += (u32)delta; + + u32 offset = temp / TICKS_PER_MSEC; + return dt.date_time + offset; } u32 osGetFirmVersion() { diff --git a/libctru/source/sdmc_dev.c b/libctru/source/sdmc_dev.c index 1450574..2a6a833 100644 --- a/libctru/source/sdmc_dev.c +++ b/libctru/source/sdmc_dev.c @@ -6,7 +6,11 @@ #include #include -#include <3ds.h> +#include <3ds/types.h> +#include <3ds/sdmc.h> +#include <3ds/services/fs.h> + + /*! @internal * @@ -126,11 +130,14 @@ static const char *sdmc_fixpath(const char *path) extern int __system_argc; extern char** __system_argv; +static bool sdmcInitialised = false; + /*! Initialize SDMC device */ Result sdmcInit(void) { - Result rc; + Result rc = 0; + if (sdmcInitialised) return rc; rc = FSUSER_OpenArchive(NULL, &sdmcArchive); @@ -157,18 +164,24 @@ Result sdmcInit(void) } } + sdmcInitialised = true; + return rc; } /*! Clean up SDMC device */ Result sdmcExit(void) { - Result rc; + Result rc = 0; + + if (!sdmcInitialised) return rc; rc = FSUSER_CloseArchive(NULL, &sdmcArchive); if(rc == 0) RemoveDevice("sdmc"); + sdmcInitialised = false; + return rc; } @@ -240,7 +253,20 @@ sdmc_open(struct _reent *r, if(flags & O_CREAT) sdmc_flags |= FS_OPEN_CREATE; - /* TODO: Test O_EXCL. */ + /* Test O_EXCL. */ + if((flags & O_CREAT) && (flags & O_EXCL)) + { + rc = FSUSER_CreateFile(NULL, sdmcArchive, FS_makePath(PATH_CHAR, pathptr), 0); + if(rc != 0) + { + r->_errno = rc; + if(rc == 0x82044BE) + r->_errno = EEXIST; + if(rc == 0x86044D2) + r->_errno = ENOSPC; + return -1; + } + } /* set attributes */ /*if(!(mode & S_IWUSR)) @@ -251,6 +277,16 @@ sdmc_open(struct _reent *r, sdmc_flags, attributes); if(rc == 0) { + if((flags & O_ACCMODE) != O_RDONLY && (flags & O_TRUNC)) + { + rc = FSFILE_SetSize(fd, 0); + if(rc != 0) + { + FSFILE_Close(fd); + r->_errno = rc; + return -1; + } + } file->fd = fd; file->flags = (flags & (O_ACCMODE|O_APPEND|O_SYNC)); file->offset = 0; diff --git a/libctru/source/services/ac.c b/libctru/source/services/ac.c index 9e957c3..3579a21 100644 --- a/libctru/source/services/ac.c +++ b/libctru/source/services/ac.c @@ -1,5 +1,8 @@ #include -#include <3ds.h> +#include <3ds/types.h> +#include <3ds/svc.h> +#include <3ds/srv.h> +#include <3ds/services/ac.h> static Handle acHandle; diff --git a/libctru/source/services/am.c b/libctru/source/services/am.c index dc16ba9..4105e89 100644 --- a/libctru/source/services/am.c +++ b/libctru/source/services/am.c @@ -1,5 +1,8 @@ #include -#include <3ds.h> +#include <3ds/types.h> +#include <3ds/svc.h> +#include <3ds/srv.h> +#include <3ds/services/am.h> static Handle amHandle = 0; diff --git a/libctru/source/services/apt.c b/libctru/source/services/apt.c index 242abc1..1d9bc48 100644 --- a/libctru/source/services/apt.c +++ b/libctru/source/services/apt.c @@ -4,7 +4,12 @@ #include #include -#include <3ds.h> +#include <3ds/types.h> +#include <3ds/svc.h> +#include <3ds/srv.h> +#include <3ds/services/apt.h> +#include <3ds/services/gsp.h> + #define APT_HANDLER_STACKSIZE (0x1000) @@ -405,10 +410,14 @@ void aptEventHandler(u32 arg) svcExitThread(); } +static bool aptInitialised = false; + Result aptInit(void) { Result ret=0; + if (aptInitialised) return ret; + // Initialize APT stuff, escape load screen. ret = __apt_initservicehandle(); if(ret!=0)return ret; @@ -440,11 +449,15 @@ Result aptInit(void) } else aptAppStarted(); + aptInitialised = true; + return 0; } void aptExit() { + if (!aptInitialised) return; + 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. @@ -471,6 +484,8 @@ void aptExit() svcCloseHandle(aptStatusMutex); svcCloseHandle(aptLockHandle); svcCloseHandle(aptStatusEvent); + + aptInitialised = false; } bool aptMainLoop() diff --git a/libctru/source/services/cfgnor.c b/libctru/source/services/cfgnor.c index 2041b99..e467655 100644 --- a/libctru/source/services/cfgnor.c +++ b/libctru/source/services/cfgnor.c @@ -1,5 +1,8 @@ #include -#include <3ds.h> +#include <3ds/types.h> +#include <3ds/svc.h> +#include <3ds/srv.h> +#include <3ds/services/cfgnor.h> Handle CFGNOR_handle = 0; diff --git a/libctru/source/services/cfgu.c b/libctru/source/services/cfgu.c index 14ac5c4..c28a6cc 100644 --- a/libctru/source/services/cfgu.c +++ b/libctru/source/services/cfgu.c @@ -1,5 +1,8 @@ #include -#include <3ds.h> +#include <3ds/types.h> +#include <3ds/svc.h> +#include <3ds/srv.h> +#include <3ds/services/cfgu.h> static Handle CFGU_handle = 0; diff --git a/libctru/source/services/csnd.c b/libctru/source/services/csnd.c index 77b1686..52f95ec 100644 --- a/libctru/source/services/csnd.c +++ b/libctru/source/services/csnd.c @@ -1,6 +1,10 @@ #include #include -#include <3ds.h> +#include <3ds/types.h> +#include <3ds/svc.h> +#include <3ds/srv.h> +#include <3ds/os.h> +#include <3ds/services/csnd.h> //See here regarding CSND shared-mem commands, etc: http://3dbrew.org/wiki/CSND_Shared_Memory diff --git a/libctru/source/services/fs.c b/libctru/source/services/fs.c index 6c75a51..2c610b3 100644 --- a/libctru/source/services/fs.c +++ b/libctru/source/services/fs.c @@ -1,5 +1,8 @@ #include -#include <3ds.h> +#include <3ds/types.h> +#include <3ds/svc.h> +#include <3ds/srv.h> +#include <3ds/services/fs.h> /*! @internal * @@ -34,12 +37,21 @@ FS_makePath(FS_pathType type, * * @returns error */ + +static bool fsInitialised = false; + Result fsInit(void) { - Result ret; + Result ret = 0; + + if (fsInitialised) return ret; + if((ret=srvGetServiceHandle(&fsuHandle, "fs:USER"))!=0)return ret; if(__get_handle_from_list("fs:USER")==0)ret=FSUSER_Initialize(NULL); + + fsInitialised = true; + return ret; } @@ -50,6 +62,10 @@ fsInit(void) Result fsExit(void) { + if (!fsInitialised) return 0; + + fsInitialised = false; + return svcCloseHandle(fsuHandle); } diff --git a/libctru/source/services/gsp.c b/libctru/source/services/gsp.c index 7240fbc..9a88c3a 100644 --- a/libctru/source/services/gsp.c +++ b/libctru/source/services/gsp.c @@ -4,7 +4,10 @@ #include #include -#include <3ds.h> +#include <3ds/types.h> +#include <3ds/svc.h> +#include <3ds/srv.h> +#include <3ds/services/gsp.h> #define GSP_EVENT_STACK_SIZE 0x1000 diff --git a/libctru/source/services/gx.c b/libctru/source/services/gx.c index 3e79fa0..4257710 100644 --- a/libctru/source/services/gx.c +++ b/libctru/source/services/gx.c @@ -3,7 +3,11 @@ */ #include -#include <3ds.h> +#include <3ds/types.h> +#include <3ds/svc.h> +#include <3ds/srv.h> +#include <3ds/gpu/gx.h> +#include <3ds/services/gsp.h> u32* gxCmdBuf; diff --git a/libctru/source/services/hb.c b/libctru/source/services/hb.c new file mode 100644 index 0000000..96d5a03 --- /dev/null +++ b/libctru/source/services/hb.c @@ -0,0 +1,67 @@ +#include <3ds/types.h> +#include <3ds/svc.h> +#include <3ds/srv.h> +#include <3ds/services/hb.h> + +static Handle hbHandle; + +Result hbInit() +{ + return srvGetServiceHandle(&hbHandle, "hb:HB"); +} + +void hbExit() +{ + svcCloseHandle(hbHandle); +} + +Result HB_FlushInvalidateCache(void) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = 0x00010042; + cmdbuf[1] = 0x00000000; + cmdbuf[2] = 0x00000000; + cmdbuf[3] = 0xFFFF8001; + + if((ret = svcSendSyncRequest(hbHandle))!=0) return ret; + + return (Result)cmdbuf[1]; +} + +Result HB_GetBootloaderAddresses(void** load3dsx, void** setArgv) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = 0x00060000; + + if((ret = svcSendSyncRequest(hbHandle))!=0) return ret; + + if(load3dsx)*load3dsx=(void*)cmdbuf[2]; + if(setArgv)*setArgv=(void*)cmdbuf[3]; + + return (Result)cmdbuf[1]; +} + +Result HB_ReprotectMemory(u32* addr, u32 pages, u32 mode, u32* reprotectedPages) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = 0x000900C0; + cmdbuf[1] = (u32)addr; + cmdbuf[2] = pages; + cmdbuf[3] = mode; + + if((ret = svcSendSyncRequest(hbHandle))!=0) return ret; + + if(reprotectedPages) + { + if(!ret)*reprotectedPages=(u32)cmdbuf[2]; + else *reprotectedPages=0; + } + + return (Result)cmdbuf[1]; +} diff --git a/libctru/source/services/hid.c b/libctru/source/services/hid.c index d48f30c..5d99369 100644 --- a/libctru/source/services/hid.c +++ b/libctru/source/services/hid.c @@ -3,7 +3,12 @@ */ #include #include -#include <3ds.h> +#include <3ds/types.h> +#include <3ds/svc.h> +#include <3ds/srv.h> +#include <3ds/services/apt.h> +#include <3ds/services/hid.h> +#include <3ds/services/irrst.h> Handle hidHandle; Handle hidMemHandle; @@ -18,13 +23,16 @@ static circlePosition cPos; static accelVector aVec; static angularRate gRate; +static bool hidInitialised; Result hidInit(u32* sharedMem) { u8 val=0; + Result ret=0; + + if(hidInitialised) return ret; if(!sharedMem)sharedMem=(u32*)HID_SHAREDMEM_DEFAULT; - Result ret=0; // Request service. if((ret=srvGetServiceHandle(&hidHandle, "hid:USER")))return ret; @@ -44,6 +52,7 @@ Result hidInit(u32* sharedMem) } // Reset internal state. + hidInitialised = true; kOld = kHeld = kDown = kUp = 0; return ret; @@ -56,6 +65,8 @@ cleanup1: void hidExit() { + if(!hidInitialised) return; + // Unmap HID sharedmem and close handles. u8 val=0; int i; for(i=0; i<5; i++)svcCloseHandle(hidEvents[i]); @@ -69,6 +80,8 @@ void hidExit() { irrstExit(); } + + hidInitialised = false; } void hidWaitForEvent(HID_Event id, bool nextEvent) @@ -245,3 +258,28 @@ Result HIDUSER_DisableGyroscope() return cmdbuf[1]; } +Result HIDUSER_GetGyroscopeRawToDpsCoefficient(float *coeff) +{ + u32* cmdbuf=getThreadCommandBuffer(); + cmdbuf[0]=0x150000; //request header code + + Result ret=0; + if((ret=svcSendSyncRequest(hidHandle)))return ret; + + *coeff = (float)cmdbuf[2]; + + return cmdbuf[1]; +} + +Result HIDUSER_GetSoundVolume(u8 *volume) +{ + u32* cmdbuf=getThreadCommandBuffer(); + cmdbuf[0]=0x170000; //request header code + + Result ret=0; + if((ret=svcSendSyncRequest(hidHandle)))return ret; + + *volume = (u8)cmdbuf[2]; + + return cmdbuf[1]; +} diff --git a/libctru/source/services/httpc.c b/libctru/source/services/httpc.c index 00cb8a7..a9f1eb9 100644 --- a/libctru/source/services/httpc.c +++ b/libctru/source/services/httpc.c @@ -1,5 +1,8 @@ #include -#include <3ds.h> +#include <3ds/types.h> +#include <3ds/svc.h> +#include <3ds/srv.h> +#include <3ds/services/httpc.h> Handle __httpc_servhandle = 0; @@ -33,15 +36,26 @@ Result httpcOpenContext(httpcContext *context, char* url, u32 use_defaultproxy) if(ret!=0)return ret; ret = srvGetServiceHandle(&context->servhandle, "http:C"); - if(ret!=0)return ret; + if(ret!=0) { + HTTPC_CloseContext(__httpc_servhandle, context->httphandle); + return ret; + } ret = HTTPC_InitializeConnectionSession(context->servhandle, context->httphandle); - if(ret!=0)return ret; + if(ret!=0) { + HTTPC_CloseContext(__httpc_servhandle, context->httphandle); + svcCloseHandle(context->servhandle); + return ret; + } if(use_defaultproxy==0)return 0; ret = HTTPC_SetProxyDefault(context->servhandle, context->httphandle); - if(ret!=0)return ret; + if(ret!=0) { + HTTPC_CloseContext(__httpc_servhandle, context->httphandle); + svcCloseHandle(context->servhandle); + return ret; + } return 0; } @@ -51,7 +65,6 @@ Result httpcCloseContext(httpcContext *context) Result ret=0; ret = HTTPC_CloseContext(context->servhandle, context->httphandle); - svcCloseHandle(context->servhandle); return ret; diff --git a/libctru/source/services/ir.c b/libctru/source/services/ir.c index 22ec39a..874319b 100644 --- a/libctru/source/services/ir.c +++ b/libctru/source/services/ir.c @@ -1,6 +1,9 @@ #include #include -#include <3ds.h> +#include <3ds/types.h> +#include <3ds/svc.h> +#include <3ds/srv.h> +#include <3ds/services/ir.h> static Handle iru_handle=0; static Handle iru_sharedmem_handle=0; diff --git a/libctru/source/services/irrst.c b/libctru/source/services/irrst.c index c7a54ff..1536640 100644 --- a/libctru/source/services/irrst.c +++ b/libctru/source/services/irrst.c @@ -3,7 +3,10 @@ */ #include #include -#include <3ds.h> +#include <3ds/types.h> +#include <3ds/svc.h> +#include <3ds/srv.h> +#include <3ds/services/irrst.h> Handle irrstHandle; Handle irrstMemHandle; diff --git a/libctru/source/services/mic.c b/libctru/source/services/mic.c index 463f94d..da30a8d 100644 --- a/libctru/source/services/mic.c +++ b/libctru/source/services/mic.c @@ -1,6 +1,9 @@ #include #include -#include <3ds.h> +#include <3ds/types.h> +#include <3ds/svc.h> +#include <3ds/srv.h> +#include <3ds/services/mic.h> //See also: http://3dbrew.org/wiki/MIC_Services diff --git a/libctru/source/services/mvd.c b/libctru/source/services/mvd.c index ac3190f..89fd732 100644 --- a/libctru/source/services/mvd.c +++ b/libctru/source/services/mvd.c @@ -4,7 +4,12 @@ #include #include -#include <3ds.h> +#include <3ds/types.h> +#include <3ds/svc.h> +#include <3ds/srv.h> +#include <3ds/os.h> +#include <3ds/linear.h> +#include <3ds/services/mvd.h> Handle mvdstdHandle; static u32 mvdstdInitialized = 0; diff --git a/libctru/source/services/ns.c b/libctru/source/services/ns.c index ffd7294..7b36552 100644 --- a/libctru/source/services/ns.c +++ b/libctru/source/services/ns.c @@ -1,5 +1,8 @@ #include -#include <3ds.h> +#include <3ds/types.h> +#include <3ds/svc.h> +#include <3ds/srv.h> +#include <3ds/services/ns.h> static Handle nsHandle; diff --git a/libctru/source/services/pm.c b/libctru/source/services/pm.c index 6c74ed2..7a5fdfd 100644 --- a/libctru/source/services/pm.c +++ b/libctru/source/services/pm.c @@ -1,6 +1,9 @@ #include #include -#include <3ds.h> +#include <3ds/types.h> +#include <3ds/svc.h> +#include <3ds/srv.h> +#include <3ds/services/pm.h> static Handle pmHandle; diff --git a/libctru/source/services/ps.c b/libctru/source/services/ps.c index 6ea4fb2..f850954 100644 --- a/libctru/source/services/ps.c +++ b/libctru/source/services/ps.c @@ -1,11 +1,14 @@ #include -#include <3ds.h> +#include <3ds/types.h> +#include <3ds/svc.h> +#include <3ds/srv.h> +#include <3ds/services/ps.h> static Handle psHandle; Result psInit() { - return srvGetServiceHandle(&psHandle, "ps:ps"); + return srvGetServiceHandle(&psHandle, "ps:ps"); } Result psExit() @@ -17,7 +20,7 @@ Result PS_EncryptDecryptAes(u32 size, u8* in, u8* out, u32 aes_algo, u32 key_typ { Result ret = 0; u32 *cmdbuf = getThreadCommandBuffer(); - + u32 *_iv = (u32*)iv; cmdbuf[0] = 0x000401C4; @@ -32,14 +35,14 @@ Result PS_EncryptDecryptAes(u32 size, u8* in, u8* out, u32 aes_algo, u32 key_typ cmdbuf[9] = (u32)in; cmdbuf[10] = (size << 0x8) | 0x14; cmdbuf[11] = (u32)out; - + if((ret = svcSendSyncRequest(psHandle))!=0)return ret; _iv[0] = cmdbuf[2]; _iv[1] = cmdbuf[3]; _iv[2] = cmdbuf[4]; _iv[3] = cmdbuf[5]; - + return (Result)cmdbuf[1]; } @@ -47,7 +50,7 @@ Result PS_EncryptSignDecryptVerifyAesCcm(u8* in, u32 in_size, u8* out, u32 out_s { Result ret = 0; u32 *cmdbuf = getThreadCommandBuffer(); - + u32 *_nonce = (u32*)nonce; cmdbuf[0] = 0x00050284; @@ -65,9 +68,9 @@ Result PS_EncryptSignDecryptVerifyAesCcm(u8* in, u32 in_size, u8* out, u32 out_s cmdbuf[9] = (u32)in; cmdbuf[10] = (out_size << 0x8) | 0x14; cmdbuf[11] = (u32)out; - + if((ret = svcSendSyncRequest(psHandle))!=0)return ret; - + return (Result)cmdbuf[1]; } @@ -75,13 +78,13 @@ Result PS_GetLocalFriendCodeSeed(u64* seed) { Result ret = 0; u32 *cmdbuf = getThreadCommandBuffer(); - + cmdbuf[0] = 0x000A0000; - + if((ret = svcSendSyncRequest(psHandle))!=0)return ret; *seed = (u64)cmdbuf[2] | (u64)cmdbuf[3] << 32; - + return (Result)cmdbuf[1]; } @@ -89,12 +92,12 @@ Result PS_GetDeviceId(u32* device_id) { Result ret = 0; u32 *cmdbuf = getThreadCommandBuffer(); - + cmdbuf[0] = 0x000B0000; - + if((ret = svcSendSyncRequest(psHandle))!=0)return ret; *device_id = cmdbuf[2]; - + return (Result)cmdbuf[1]; -} \ No newline at end of file +} diff --git a/libctru/source/services/ptm.c b/libctru/source/services/ptm.c index e9abfb6..1c30206 100644 --- a/libctru/source/services/ptm.c +++ b/libctru/source/services/ptm.c @@ -1,5 +1,9 @@ #include -#include <3ds.h> +#include <3ds/types.h> +#include <3ds/svc.h> +#include <3ds/srv.h> +#include <3ds/services/ptm.h> + static Handle ptmHandle; diff --git a/libctru/source/services/qtm.c b/libctru/source/services/qtm.c new file mode 100644 index 0000000..95a78e1 --- /dev/null +++ b/libctru/source/services/qtm.c @@ -0,0 +1,87 @@ +/* + qtm.c - New3DS head-tracking +*/ +#include +#include +#include <3ds/types.h> +#include <3ds/svc.h> +#include <3ds/srv.h> +#include <3ds/services/qtm.h> + +Handle qtmHandle; + +static bool qtmInitialized = false; + +Result qtmInit() +{ + Result ret=0; + + if(qtmInitialized)return 0; + + if((ret=srvGetServiceHandle(&qtmHandle, "qtm:u")))return ret; + + qtmInitialized = true; + + return 0; +} + +void qtmExit() +{ + if(!qtmInitialized)return; + + svcCloseHandle(qtmHandle); + qtmInitialized = false; +} + +bool qtmCheckInitialized() +{ + return qtmInitialized; +} + +Result qtmGetHeadtrackingInfo(u64 val, qtmHeadtrackingInfo *out) +{ + u32* cmdbuf=getThreadCommandBuffer(); + + if(!qtmInitialized)return -1; + + cmdbuf[0]=0x00020080; //request header code + memcpy(&cmdbuf[1], &val, 8); + + Result ret=0; + if((ret=svcSendSyncRequest(qtmHandle)))return ret; + + ret = (Result)cmdbuf[1]; + if(ret!=0)return ret; + + if(out)memcpy(out, &cmdbuf[2], sizeof(qtmHeadtrackingInfo)); + + return 0; +} + +bool qtmCheckHeadFullyDetected(qtmHeadtrackingInfo *info) +{ + if(info==NULL)return false; + + if(info->flags[0] && info->flags[1] && info->flags[2])return true; + return false; +} + +Result qtmConvertCoordToScreen(qtmHeadtrackingInfoCoord *coord, float *screen_width, float *screen_height, u32 *x, u32 *y) +{ + float width = 200.0f; + float height = 160.0f; + + if(coord==NULL || x==NULL || y==NULL)return -1; + + if(screen_width)width = (*screen_width) / 2; + if(screen_height)height = (*screen_height) / 2; + + if(coord->x > 1.0f || coord->x < -1.0f)return -2; + if(coord->y > 1.0f || coord->y < -1.0f)return -2; + + *x = (u32)((coord->x * width) + width); + *y = (u32)((coord->y * height) + height); + + return 0; +} + diff --git a/libctru/source/services/soc/soc_common.h b/libctru/source/services/soc/soc_common.h index f5cfe96..5cf5dee 100644 --- a/libctru/source/services/soc/soc_common.h +++ b/libctru/source/services/soc/soc_common.h @@ -1,7 +1,10 @@ #pragma once #include -#include <3ds.h> +#include <3ds/types.h> +#include <3ds/svc.h> +#include <3ds/srv.h> +#include <3ds/services/soc.h> extern Handle SOCU_handle; extern int SOCU_errno; diff --git a/libctru/source/services/soc/soc_inet_aton.c b/libctru/source/services/soc/soc_inet_aton.c index 6e1f206..57f2bd4 100644 --- a/libctru/source/services/soc/soc_inet_aton.c +++ b/libctru/source/services/soc/soc_inet_aton.c @@ -54,23 +54,20 @@ int inet_aton(const char *cp, struct in_addr *inp) switch(num_bytes) { case 0: - return 0; - - case 1: break; - case 2: + case 1: if(val > 0xFFFFFF) return 0; val |= bytes[0] << 24; break; - case 3: + case 2: if(val > 0xFFFF) return 0; val |= bytes[0] << 24; val |= bytes[1] << 16; break; - case 4: + case 3: if(val > 0xFF) return 0; val |= bytes[0] << 24; val |= bytes[1] << 16; diff --git a/libctru/source/srv.c b/libctru/source/srv.c index ad6e510..366eca6 100644 --- a/libctru/source/srv.c +++ b/libctru/source/srv.c @@ -3,7 +3,9 @@ */ #include -#include <3ds.h> +#include <3ds/types.h> +#include <3ds/srv.h> +#include <3ds/svc.h> /* @@ -70,10 +72,13 @@ void __destroy_handle_list(void) { __service_ptr->num = 0; } + Result srvInit() { Result rc = 0; + if(g_srv_handle != 0) return rc; + if((rc = svcConnectToPort(&g_srv_handle, "srv:")))return rc; if((rc = srvRegisterClient())) { diff --git a/libctru/source/svc.s b/libctru/source/svc.s index 4969df8..555eb13 100644 --- a/libctru/source/svc.s +++ b/libctru/source/svc.s @@ -100,7 +100,7 @@ svcSignalEvent: svcClearEvent: svc 0x19 bx lr - + .global svcCreateTimer .type svcCreateTimer, %function svcCreateTimer: @@ -109,19 +109,19 @@ svcCreateTimer: ldr r2, [sp], #4 str r1, [r2] bx lr - + .global svcSetTimer .type svcSetTimer, %function svcSetTimer: svc 0x1B bx lr - + .global svcCancelTimer .type svcCancelTimer, %function svcCancelTimer: svc 0x1C bx lr - + .global svcClearTimer .type svcClearTimer, %function svcClearTimer: @@ -259,10 +259,7 @@ svcGetProcessId: .global svcOutputDebugString .type svcOutputDebugString, %function svcOutputDebugString: - str r0, [sp, #-0x4]! svc 0x3D - ldr r2, [sp], #4 - str r1, [r2] bx lr .global svcCreateSemaphore diff --git a/libctru/source/system/allocateHeaps.c b/libctru/source/system/allocateHeaps.c new file mode 100644 index 0000000..4009f8e --- /dev/null +++ b/libctru/source/system/allocateHeaps.c @@ -0,0 +1,24 @@ +#include <3ds/types.h> +#include <3ds/svc.h> + +extern char* fake_heap_start; +extern char* fake_heap_end; +u32 __linear_heap; +u32 __heapBase; +extern u32 __heap_size, __linear_heap_size; + + +void __attribute__((weak)) __system_allocateHeaps() { + u32 tmp=0; + + // Allocate the application heap + __heapBase = 0x08000000; + 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); + // Set up newlib heap + fake_heap_start = (char*)__heapBase; + fake_heap_end = fake_heap_start + __heap_size; + +} \ No newline at end of file diff --git a/libctru/source/system/appExit.c b/libctru/source/system/appExit.c new file mode 100644 index 0000000..d2e9d48 --- /dev/null +++ b/libctru/source/system/appExit.c @@ -0,0 +1,17 @@ +#include <3ds/types.h> +#include <3ds/srv.h> +#include <3ds/gfx.h> +#include <3ds/sdmc.h> +#include <3ds/services/apt.h> +#include <3ds/services/fs.h> +#include <3ds/services/hid.h> + +void __attribute__((weak)) __appExit() { + // Exit services + sdmcExit(); + fsExit(); + + hidExit(); + aptExit(); + srvExit(); +} diff --git a/libctru/source/system/appInit.c b/libctru/source/system/appInit.c new file mode 100644 index 0000000..ac90ae6 --- /dev/null +++ b/libctru/source/system/appInit.c @@ -0,0 +1,17 @@ +#include <3ds/types.h> +#include <3ds/srv.h> +#include <3ds/gfx.h> +#include <3ds/sdmc.h> +#include <3ds/services/apt.h> +#include <3ds/services/fs.h> +#include <3ds/services/hid.h> + +void __attribute__((weak)) __appInit() { + // Initialize services + srvInit(); + aptInit(); + hidInit(NULL); + + fsInit(); + sdmcInit(); +} diff --git a/libctru/source/system/ctru_exit.c b/libctru/source/system/ctru_exit.c new file mode 100644 index 0000000..058ea7c --- /dev/null +++ b/libctru/source/system/ctru_exit.c @@ -0,0 +1,38 @@ +#include <3ds/types.h> +#include <3ds/svc.h> + +extern u32 __linear_heap; +extern u32 __heapBase; +extern u32 __heap_size, __linear_heap_size; +extern void (*__system_retAddr)(void); + +void __destroy_handle_list(void); +void __appExit(); + +void __libc_fini_array(void); + +void __attribute__((weak)) __attribute__((noreturn)) __ctru_exit(int rc) +{ + u32 tmp=0; + + // Run the global destructors + __libc_fini_array(); + + __appExit(); + + // Unmap the linear heap + svcControlMemory(&tmp, __linear_heap, 0x0, __linear_heap_size, MEMOP_FREE, 0x0); + + // Unmap the application heap + svcControlMemory(&tmp, __heapBase, 0x0, __heap_size, MEMOP_FREE, 0x0); + + // Close some handles + __destroy_handle_list(); + + // Jump to the loader if it provided a callback + if (__system_retAddr) + __system_retAddr(); + + // Since above did not jump, end this process + svcExitProcess(); +} diff --git a/libctru/source/system/initArgv.c b/libctru/source/system/initArgv.c new file mode 100644 index 0000000..0fae5dd --- /dev/null +++ b/libctru/source/system/initArgv.c @@ -0,0 +1,50 @@ +#include <3ds/types.h> + +#include + +// System globals we define here +int __system_argc; +char** __system_argv; +extern const char* __system_arglist; + +extern char* fake_heap_start; +extern char* fake_heap_end; + +void __system_initArgv() +{ + int i; + const char* temp = __system_arglist; + + // Check if the argument list is present + if (!temp) + return; + + // Retrieve argc + __system_argc = *(u32*)temp; + temp += sizeof(u32); + + // Find the end of the argument data + for (i = 0; i < __system_argc; i ++) + { + for (; *temp; temp ++); + temp ++; + } + + // Reserve heap memory for argv data + u32 argSize = temp - __system_arglist - sizeof(u32); + __system_argv = (char**)fake_heap_start; + fake_heap_start += sizeof(char**)*(__system_argc + 1); + char* argCopy = fake_heap_start; + fake_heap_start += argSize; + + // Fill argv array + memcpy(argCopy, &__system_arglist[4], argSize); + temp = argCopy; + for (i = 0; i < __system_argc; i ++) + { + __system_argv[i] = (char*)temp; + for (; *temp; temp ++); + temp ++; + } + __system_argv[__system_argc] = NULL; +} diff --git a/libctru/source/system/initSystem.c b/libctru/source/system/initSystem.c new file mode 100644 index 0000000..080d125 --- /dev/null +++ b/libctru/source/system/initSystem.c @@ -0,0 +1,37 @@ +#include +#include +#include <3ds/types.h> +#include <3ds/svc.h> + +void (*__system_retAddr)(void); + +// Data from _prm structure +extern void* __service_ptr; // used to detect if we're run from a homebrew launcher + +void __system_allocateHeaps(); +void __system_initArgv(); +void __appInit(); + +// newlib definitions we need +void __libc_init_array(void); + + +void __ctru_exit(int rc); + +void __attribute__((weak)) initSystem(void (*retAddr)(void)) +{ + + // Register newlib exit() syscall + __syscalls.exit = __ctru_exit; + __system_retAddr = __service_ptr ? retAddr : NULL; + + __system_allocateHeaps(); + + // Build argc/argv if present + __system_initArgv(); + + __appInit(); + + // Run the global constructors + __libc_init_array(); +} diff --git a/template/README.md b/template/README.md deleted file mode 100644 index c10896a..0000000 --- a/template/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# template - -This is a template for starting new 3DS/ctrulib projects.