From 7e00ed2054030186b3690d00a23eabc6be9719f2 Mon Sep 17 00:00:00 2001 From: TuxSH Date: Fri, 2 Feb 2018 15:35:22 +0100 Subject: [PATCH] Switch port (wip, squash later) --- .gitignore | 4 ++ Makefile | 8 ++- Makefile.switch | 184 +++++++++++++++++++++++++++++++++++++++++++++++ source/console.c | 91 +++++++++++++++++++++++ source/ftp.c | 82 ++++++++++++++++++--- source/main.c | 42 ++++++++++- 6 files changed, 397 insertions(+), 14 deletions(-) create mode 100644 Makefile.switch diff --git a/.gitignore b/.gitignore index 0fdcfa7..f74bdbc 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,7 @@ ftpd *.cia *.smdh *.elf +*.nso +*.pfs0 +*.nacp +*.nro diff --git a/Makefile b/Makefile index af5b3b2..fcf471f 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: all 3dsx cia clean linux +.PHONY: all switch 3dsx cia clean linux export GITREV := $(shell git rev-parse HEAD 2>/dev/null | cut -c1-8) export VERSION_MAJOR := 2 @@ -12,15 +12,19 @@ endif all: 3dsx +switch: + @$(MAKE) -f Makefile.switch all + 3dsx: @$(MAKE) -f Makefile.3ds 3dsx cia: @$(MAKE) -f Makefile.3ds cia - + linux: @$(MAKE) -f Makefile.linux clean: + @$(MAKE) -f Makefile.switch clean @$(MAKE) -f Makefile.3ds clean @$(MAKE) -f Makefile.linux clean diff --git a/Makefile.switch b/Makefile.switch new file mode 100644 index 0000000..ab607d8 --- /dev/null +++ b/Makefile.switch @@ -0,0 +1,184 @@ +#--------------------------------------------------------------------------------- +.SUFFIXES: +#--------------------------------------------------------------------------------- + +ifeq ($(strip $(DEVKITPRO)),) +$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=/devkitpro") +endif + +TOPDIR ?= $(CURDIR) +include $(DEVKITPRO)/libnx/switch_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 +# EXEFS_SRC is the optional input directory containing data copied into exefs, if anything this normally should only contain "main.npdm". +# +# NO_ICON: if set to anything, do not use icon. +# NO_NACP: if set to anything, no .nacp file is generated. +# APP_TITLE is the name of the app stored in the .nacp file (Optional) +# APP_AUTHOR is the author of the app stored in the .nacp file (Optional) +# APP_VERSION is the version of the app stored in the .nacp file (Optional) +# APP_TITLEID is the titleID of the app stored in the .nacp file (Optional) +# ICON is the filename of the icon (.jpg), relative to the project folder. +# If not set, it attempts to use one of the following (in this order): +# - .jpg +# - icon.jpg +# - /default_icon.jpg +#--------------------------------------------------------------------------------- +TARGET := $(notdir $(CURDIR)) +BUILD := build +SOURCES := source +DATA := data +INCLUDES := include +EXEFS_SRC := exefs_src + +#--------------------------------------------------------------------------------- +# options for code generation +#--------------------------------------------------------------------------------- +ARCH := -march=armv8-a -mtp=soft -fPIE + +CFLAGS := -g -Wall -O2 \ + -ffast-math \ + $(ARCH) $(DEFINES) + +CFLAGS += $(INCLUDE) -DSWITCH -D_SWITCH -DSTATUS_STRING="\"ftpd v$(VERSION)\"" + +CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11 + +ASFLAGS := -g $(ARCH) +LDFLAGS = -specs=$(DEVKITPRO)/libnx/switch.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map) + +LIBS := -lnx + +#--------------------------------------------------------------------------------- +# list of directories containing libraries, this must be the top level containing +# include and lib +#--------------------------------------------------------------------------------- +LIBDIRS := $(PORTLIBS) $(LIBNX) + + +#--------------------------------------------------------------------------------- +# 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) + +export BUILD_EXEFS_SRC := $(TOPDIR)/$(EXEFS_SRC) + +ifeq ($(strip $(ICON)),) + icons := $(wildcard *.jpg) + ifneq (,$(findstring $(TARGET).jpg,$(icons))) + export APP_ICON := $(TOPDIR)/$(TARGET).jpg + else + ifneq (,$(findstring icon.jpg,$(icons))) + export APP_ICON := $(TOPDIR)/icon.jpg + endif + endif +else + export APP_ICON := $(TOPDIR)/$(ICON) +endif + +ifeq ($(strip $(NO_ICON)),) + export NROFLAGS += --icon=$(APP_ICON) +endif + +ifeq ($(strip $(NO_NACP)),) + export NROFLAGS += --nacp=$(CURDIR)/$(TARGET).nacp +endif + +ifneq ($(APP_TITLEID),) + export NACPFLAGS += --titleid=$(APP_TITLEID) +endif + +.PHONY: $(BUILD) clean all + +#--------------------------------------------------------------------------------- +all: $(BUILD) + +$(BUILD): + @[ -d $@ ] || mkdir -p $@ + @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile.switch + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(BUILD) $(TARGET).pfs0 $(TARGET).nso $(TARGET).nro $(TARGET).nacp $(TARGET).elf + + +#--------------------------------------------------------------------------------- +else +.PHONY: all + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +all : $(OUTPUT).pfs0 $(OUTPUT).nro + +$(OUTPUT).pfs0 : $(OUTPUT).nso + +$(OUTPUT).nso : $(OUTPUT).elf + +ifeq ($(strip $(NO_NACP)),) +$(OUTPUT).nro : $(OUTPUT).elf $(OUTPUT).nacp +else +$(OUTPUT).nro : $(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) + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------------- diff --git a/source/console.c b/source/console.c index e4618b9..10e67a6 100644 --- a/source/console.c +++ b/source/console.c @@ -191,6 +191,97 @@ console_render(void) gspWaitForVBlank(); gfxSwapBuffers(); } + +#elif defined(_SWITCH) +#include + +static PrintConsole status_console; +static PrintConsole main_console; +#if ENABLE_LOGGING +static bool disable_logging = false; +#endif + +/*! initialize console subsystem */ +void +console_init(void) +{ + consoleInit(&status_console); + consoleSetWindow(&status_console, 0, 0, 50, 1); + + consoleInit( &main_console); + consoleSetWindow(&main_console, 0, 1, 50, 29); + + consoleSelect(&main_console); +} + +/*! set status bar contents + * + * @param[in] fmt format string + * @param[in] ... format arguments + */ +void +console_set_status(const char *fmt, ...) +{ + va_list ap; + + consoleSelect(&status_console); + va_start(ap, fmt); + vprintf(fmt, ap); +#ifdef ENABLE_LOGGING + vfprintf(stderr, fmt, ap); +#endif + va_end(ap); + consoleSelect(&main_console); +} + +/*! add text to the console + * + * @param[in] fmt format string + * @param[in] ... format arguments + */ +void +console_print(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vprintf(fmt, ap); +#ifdef ENABLE_LOGGING + if(!disable_logging) + vfprintf(stderr, fmt, ap); +#endif + va_end(ap); +} + +/*! print debug message + * + * @param[in] fmt format string + * @param[in] ... format arguments + */ +void +debug_print(const char *fmt, ...) +{ +#ifdef ENABLE_LOGGING + va_list ap; + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); +#endif +} + + +/*! draw console to screen */ +void +console_render(void) +{ + /* flush framebuffer */ + gfxFlushBuffers(); + gfxSwapBuffers(); + gfxWaitForVsync(); + +} + #else /* this is a lot easier when you have a real console */ diff --git a/source/ftp.c b/source/ftp.c index 1507116..3d02085 100644 --- a/source/ftp.c +++ b/source/ftp.c @@ -26,6 +26,9 @@ #ifdef _3DS #include <3ds.h> #define lstat stat +#elif defined(_SWITCH) +#include +#define lstat stat #else #include #define BIT(x) (1<<(x)) @@ -252,6 +255,10 @@ static bool lcd_power = true; /*! aptHook cookie */ static aptHookCookie cookie; +#elif defined(_SWITCH) + +/*! appletHook cookie */ +static AppletHookCookie cookie; #endif /*! server listen address */ @@ -730,7 +737,7 @@ ftp_session_fill_dirent_type(ftp_session_t *session, const struct stat *st, type = "file"; else if(S_ISDIR(st->st_mode)) type = "dir"; -#ifndef _3DS +#if !defined(_3DS) && !defined(_SWITCH) else if(S_ISLNK(st->st_mode)) type = "os.unix=symlink"; else if(S_ISCHR(st->st_mode)) @@ -842,7 +849,7 @@ ftp_session_fill_dirent_type(ftp_session_t *session, const struct stat *st, "%c%c%c%c%c%c%c%c%c%c %lu 3DS 3DS %lld ", S_ISREG(st->st_mode) ? '-' : S_ISDIR(st->st_mode) ? 'd' : -#ifndef _3DS +#if !defined(_3DS) && !defined(_SWITCH) S_ISLNK(st->st_mode) ? 'l' : S_ISCHR(st->st_mode) ? 'c' : S_ISBLK(st->st_mode) ? 'b' : @@ -1738,7 +1745,7 @@ ftp_session_poll(ftp_session_t *session) static void update_free_space(void) { -#ifdef _3DS +#if defined(_3DS) || defined(_SWITCH) #define KiB (1024.0) #define MiB (1024.0*KiB) #define GiB (1024.0*MiB) @@ -1784,7 +1791,7 @@ update_free_space(void) static int update_status(void) { -#ifdef _3DS +#if defined(_3DS) || defined(_SWITCH) console_set_status("\n" GREEN STATUS_STRING " " #ifdef ENABLE_LOGGING "DEBUG " @@ -1805,12 +1812,13 @@ update_status(void) return -1; } - rc = gethostname(hostname, sizeof(hostname)); + strcpy(hostname, "banana"); + /*rc = gethostname(hostname, sizeof(hostname)); if(rc != 0) { console_print(RED "gethostname: %d %s\n" RESET, errno, strerror(errno)); return -1; - } + }*/ console_set_status(GREEN STATUS_STRING " " #ifdef ENABLE_LOGGING @@ -1862,6 +1870,23 @@ apt_hook(APT_HookType type, break; } } +#elif defined(_SWITCH) +/*! Handle applet events + * + * @param[in] type Event type + * @param[in] closure Callback closure + */ +static void +applet_hook(AppletHookType type, + void *closure) +{ + /* stubbed for now */ + switch(type) + { + default: + break; + } +} #endif /*! initialize ftp subsystem */ @@ -1923,9 +1948,34 @@ ftp_init(void) ret = socInit(SOCU_buffer, SOCU_BUFFERSIZE); if(ret != 0) { - console_print(RED "socInit: 0x%08X\n" RESET, (unsigned int)ret); + console_print(RED "socInit: %08X\n" RESET, (unsigned int)ret); goto soc_fail; } +#elif defined(_SWITCH) + /* we have a lot of memory available so let's use c.a. 360MB */ + static const SocketInitConfig socketInitConfig = { + .bsdsockets_version = 1, + + .tcp_tx_buf_size = 20 << 20, + .tcp_rx_buf_size = 20 << 20, + .tcp_tx_buf_max_size = 20 << 20, + .tcp_rx_buf_max_size = 20 << 20, + + /* we aren't using UDP at all, let's just use the default sizes */ + .udp_tx_buf_size = 0x2400, + .udp_rx_buf_size = 0xA500, + + .sb_efficiency = 8, + }; + Result ret = socketInitialize(&socketInitConfig); + if(ret != 0) + { + console_print(RED "socketInitialize: %X\n" RESET, (unsigned int)ret); + return -1; + } + + /* register applet hook */ + appletHook(&cookie, applet_hook, NULL); #endif /* allocate socket to listen for clients */ @@ -2001,7 +2051,7 @@ memalign_fail: void ftp_exit(void) { -#ifdef _3DS +#if defined(_3DS) Result ret; #endif @@ -2027,6 +2077,13 @@ ftp_exit(void) console_print(RED "socExit: 0x%08X\n" RESET, (unsigned int)ret); free(SOCU_buffer); } +#elif defined(_SWITCH) + /* deinitialize socket driver */ + console_render(); + console_print(CYAN "Waiting for socketExit()...\n" RESET); + + socketExit(); + #endif } @@ -2089,6 +2146,13 @@ ftp_loop(void) lcd_power = !lcd_power; apt_hook(APTHOOK_ONRESTORE, NULL); } +#elif defined(_SWITCH) + /* check if the user wants to exit */ + hidScanInput(); + u32 down = hidKeysDown(CONTROLLER_P1_AUTO); + + if(down & KEY_B) + return LOOP_EXIT; #endif return LOOP_CONTINUE; @@ -3401,7 +3465,7 @@ FTP_DECLARE(PASV) /* grab a new port */ session->pasv_addr.sin_port = htons(next_data_port()); -#ifdef _3DS +#if defined(_3DS) || defined(_SWITCH) console_print(YELLOW "binding to %s:%u\n" RESET, inet_ntoa(session->pasv_addr.sin_addr), ntohs(session->pasv_addr.sin_port)); diff --git a/source/main.c b/source/main.c index 60a0bd7..ba79099 100644 --- a/source/main.c +++ b/source/main.c @@ -1,3 +1,4 @@ + #include #include #include @@ -5,6 +6,8 @@ #include #ifdef _3DS #include <3ds.h> +#elif defined(_SWITCH) +#include #endif #include "console.h" #include "ftp.h" @@ -28,7 +31,15 @@ loop(loop_status_t (*callback)(void)) if(status != LOOP_CONTINUE) return status; } - + return LOOP_EXIT; +#elif defined(_SWITCH) + while(appletMainLoop()) + { + status = callback(); + console_render(); + if(status != LOOP_CONTINUE) + return status; + } return LOOP_EXIT; #else while(status == LOOP_CONTINUE) @@ -55,6 +66,24 @@ wait_for_b(void) /* B was not pressed */ return LOOP_CONTINUE; } +#elif defined(_SWITCH) +/*! wait until the B button is pressed + * + * @returns loop status + */ +static loop_status_t +wait_for_b(void) +{ + /* update button state */ + hidScanInput(); + + /* check if B was pressed */ + if(hidKeysDown(CONTROLLER_P1_AUTO) & KEY_B) + return LOOP_EXIT; + + /* B was not pressed */ + return LOOP_CONTINUE; +} #endif /*! entry point @@ -76,6 +105,9 @@ main(int argc, gfxInitDefault(); gfxSet3D(false); sdmcWriteSafe(false); +#elif defined(_SWITCH) + gfxInitResolution(644, 480); + gfxInitDefault(); #endif /* initialize console subsystem */ @@ -123,7 +155,7 @@ main(int argc, status = LOOP_EXIT; } -#ifdef _3DS +#if defined(_3DS) || defined(_SWITCH) console_print("Press B to exit\n"); #endif @@ -139,7 +171,11 @@ log_fail: /* deinitialize 3DS services */ gfxExit(); acExit(); -#endif +#elif defined(_SWITCH) + loop(wait_for_b); + /* deinitialize Switch services */ + gfxExit(); +#endif return 0; }