mirror of
https://github.com/wiiu-env/ftpiiu_plugin.git
synced 2024-12-23 11:21:49 +01:00
NDS support
This commit is contained in:
parent
fc02e1ee38
commit
214ab229c6
6
.gitignore
vendored
6
.gitignore
vendored
@ -1,9 +1,12 @@
|
|||||||
|
*.nds
|
||||||
|
*.nds.xz
|
||||||
*.3dsx
|
*.3dsx
|
||||||
*.3dsx.xz
|
*.3dsx.xz
|
||||||
*.cia
|
*.cia
|
||||||
*.cia.xz
|
*.cia.xz
|
||||||
*.elf
|
*.elf
|
||||||
*.nacp
|
*.nacp
|
||||||
|
*.nds
|
||||||
*.nro
|
*.nro
|
||||||
*.nro.xz
|
*.nro.xz
|
||||||
*.nso
|
*.nso
|
||||||
@ -11,9 +14,12 @@
|
|||||||
*.smdh
|
*.smdh
|
||||||
.gdb_history
|
.gdb_history
|
||||||
3ds/build
|
3ds/build
|
||||||
|
3ds-classic/build
|
||||||
3ds/romfs/*.t3x
|
3ds/romfs/*.t3x
|
||||||
linux/build
|
linux/build
|
||||||
linux/ftpd
|
linux/ftpd
|
||||||
|
nds/build
|
||||||
switch/build
|
switch/build
|
||||||
|
switch-classic/build
|
||||||
switch/romfs/*.zst
|
switch/romfs/*.zst
|
||||||
switch/romfs/shaders/*.dksh
|
switch/romfs/shaders/*.dksh
|
||||||
|
116
Makefile
116
Makefile
@ -1,24 +1,20 @@
|
|||||||
.PHONY: all nro 3dsx cia clean linux 3dslink nxlink format release release-3dsx release-cia release-3ds release-nro
|
.PHONY: all all-classic format clean
|
||||||
|
.PHONY: dslink 3dslink 3dslink-classic nxlink-classic
|
||||||
|
.PHONY: nds 3dsx cia nro linux
|
||||||
|
.PHONY: 3dsx-classic cia-classic nro-classic
|
||||||
|
.PHONY: release release-nds release-3dsx release-cia release-nro
|
||||||
|
.PHONY: release-3dsx-classic release-cia-classic release-nro-classic
|
||||||
|
|
||||||
TARGET := $(notdir $(CURDIR))
|
export GITREV := $(shell git rev-parse HEAD 2>/dev/null | cut -c1-6)
|
||||||
|
|
||||||
export GITREV := $(shell git rev-parse HEAD 2>/dev/null | cut -c1-8)
|
|
||||||
export VERSION_MAJOR := 3
|
export VERSION_MAJOR := 3
|
||||||
export VERSION_MINOR := 0
|
export VERSION_MINOR := 0
|
||||||
export VERSION_MICRO := 0
|
export VERSION_MICRO := 0
|
||||||
export VERSION := $(VERSION_MAJOR).$(VERSION_MINOR).$(VERSION_MICRO)-rc3
|
export VERSION := $(VERSION_MAJOR).$(VERSION_MINOR).$(VERSION_MICRO)
|
||||||
|
|
||||||
ifneq ($(strip $(GITREV)),)
|
###########################################################################
|
||||||
export VERSION := $(VERSION)-$(GITREV)
|
all: nds 3dsx nro linux
|
||||||
endif
|
|
||||||
|
|
||||||
all: 3dsx nro linux
|
all-classic: nds 3dsx-classic nro-classic linux
|
||||||
|
|
||||||
nxlink:
|
|
||||||
@$(MAKE) -f Makefile.switch nxlink
|
|
||||||
|
|
||||||
3dslink:
|
|
||||||
@$(MAKE) -f Makefile.3ds 3dslink
|
|
||||||
|
|
||||||
format:
|
format:
|
||||||
@clang-format -style=file -i $(filter-out \
|
@clang-format -style=file -i $(filter-out \
|
||||||
@ -40,40 +36,86 @@ format:
|
|||||||
source/imgui/imgui_internal.h, \
|
source/imgui/imgui_internal.h, \
|
||||||
$(shell find source include -type f -name \*.c -o -name \*.cpp -o -name \*.h))
|
$(shell find source include -type f -name \*.c -o -name \*.cpp -o -name \*.h))
|
||||||
|
|
||||||
release: release-3ds release-nro
|
clean:
|
||||||
@xz -c <3ds/$(TARGET).3dsx >ftpd.3dsx.xz
|
@$(MAKE) -f Makefile.nds clean
|
||||||
@xz -c <3ds/$(TARGET).cia >ftpd.cia.xz
|
@$(MAKE) -f Makefile.3ds clean
|
||||||
@xz -c <switch/$(TARGET).nro >ftpd.nro.xz
|
@$(MAKE) -f Makefile.3ds clean CLASSIC="-DCLASSIC"
|
||||||
|
@$(MAKE) -f Makefile.switch clean
|
||||||
|
@$(MAKE) -f Makefile.switch clean CLASSIC="-DCLASSIC"
|
||||||
|
@$(MAKE) -f Makefile.linux clean
|
||||||
|
@$(RM) ftpd.nds.xz ftpd*.3dsx.xz ftpd*.cia.xz ftpd*.nro.xz
|
||||||
|
|
||||||
nro:
|
###########################################################################
|
||||||
@$(MAKE) -f Makefile.switch all
|
dslink:
|
||||||
|
@$(MAKE) -f Makefile.nds dslink
|
||||||
|
|
||||||
release-nro:
|
3dslink:
|
||||||
@$(MAKE) DEFINES=-DNDEBUG -f Makefile.switch all
|
@$(MAKE) -f Makefile.3ds 3dslink
|
||||||
|
|
||||||
|
3dslink-classic:
|
||||||
|
@$(MAKE) -f Makefile.3ds 3dslink CLASSIC="-DCLASSIC"
|
||||||
|
|
||||||
|
nxlink:
|
||||||
|
@$(MAKE) -f Makefile.switch nxlink
|
||||||
|
|
||||||
|
nxlink-classic:
|
||||||
|
@$(MAKE) -f Makefile.switch nxlink CLASSIC="-DCLASSIC"
|
||||||
|
|
||||||
|
###########################################################################
|
||||||
|
nds:
|
||||||
|
@$(MAKE) -f Makefile.nds CLASSIC="-DCLASSIC"
|
||||||
|
|
||||||
3dsx:
|
3dsx:
|
||||||
@$(MAKE) -f Makefile.3ds 3dsx
|
@$(MAKE) -f Makefile.3ds 3dsx
|
||||||
|
|
||||||
release-3dsx:
|
3dsx-classic:
|
||||||
@$(MAKE) DEFINES=-DNDEBUG -f Makefile.3ds 3dsx
|
@$(MAKE) -f Makefile.3ds 3dsx CLASSIC="-DCLASSIC"
|
||||||
|
|
||||||
cia: 3dsx
|
cia: 3dsx
|
||||||
@$(MAKE) -f Makefile.3ds cia
|
@$(MAKE) -f Makefile.3ds cia
|
||||||
|
|
||||||
release-cia: release-3dsx
|
cia-classic: 3dsx-classic
|
||||||
@$(MAKE) DEFINES=-NDEBUG -f Makefile.3ds cia
|
@$(MAKE) -f Makefile.3ds cia CLASSIC="-DCLASSIC"
|
||||||
|
|
||||||
release-3ds:
|
nro:
|
||||||
# can't let these run in parallel with each other due to using same
|
@$(MAKE) -f Makefile.switch all
|
||||||
# .elf file name
|
|
||||||
@$(MAKE) DEFINES=-DNDEBUG -f Makefile.3ds 3dsx
|
nro-classic:
|
||||||
@$(MAKE) DEFINES=-DNDEBUG -f Makefile.3ds cia
|
@$(MAKE) -f Makefile.switch all CLASSIC="-DCLASSIC"
|
||||||
|
|
||||||
linux:
|
linux:
|
||||||
@$(MAKE) -f Makefile.linux
|
@$(MAKE) -f Makefile.linux
|
||||||
|
|
||||||
clean:
|
###########################################################################
|
||||||
@$(MAKE) -f Makefile.switch clean
|
release: release-nds \
|
||||||
@$(MAKE) -f Makefile.3ds clean
|
release-3dsx release-3dsx-classic \
|
||||||
@$(MAKE) -f Makefile.linux clean
|
release-cia release-cia-classic \
|
||||||
@$(RM) ftpd.3dsx.xz ftpd.cia.xz ftpd.nro.xz
|
release-nro release-nro-classic
|
||||||
|
@xz -c <nds/ftpd.nds >ftpd.nds.xz
|
||||||
|
@xz -c <3ds/ftpd.3dsx >ftpd.3dsx.xz
|
||||||
|
@xz -c <3ds-classic/ftpd-classic.3dsx >ftpd-classic.3dsx.xz
|
||||||
|
@xz -c <3ds/ftpd.cia >ftpd.cia.xz
|
||||||
|
@xz -c <3ds-classic/ftpd-classic.cia >ftpd-classic.cia.xz
|
||||||
|
@xz -c <switch/ftpd.nro >ftpd.nro.xz
|
||||||
|
@xz -c <switch-classic/ftpd-classic.nro >ftpd-classic.nro.xz
|
||||||
|
|
||||||
|
release-nds:
|
||||||
|
@$(MAKE) -f Makefile.nds DEFINES=-DNDEBUG
|
||||||
|
|
||||||
|
release-3dsx:
|
||||||
|
@$(MAKE) -f Makefile.3ds 3dsx DEFINES=-DNDEBUG
|
||||||
|
|
||||||
|
release-3dsx-classic:
|
||||||
|
@$(MAKE) -f Makefile.3ds 3dsx DEFINES=-DNDEBUG CLASSIC="-DCLASSIC"
|
||||||
|
|
||||||
|
release-cia: release-3dsx
|
||||||
|
@$(MAKE) -f Makefile.3ds cia DEFINES=-DNDEBUG
|
||||||
|
|
||||||
|
release-cia-classic: release-3dsx-classic
|
||||||
|
@$(MAKE) -f Makefile.3ds cia DEFINES=-DNDEBUG CLASSIC="-DCLASSIC"
|
||||||
|
|
||||||
|
release-nro:
|
||||||
|
@$(MAKE) -f Makefile.switch all DEFINES=-DNDEBUG
|
||||||
|
|
||||||
|
release-nro-classic:
|
||||||
|
@$(MAKE) -f Makefile.switch all DEFINES=-DNDEBUG CLASSIC="-DCLASSIC"
|
||||||
|
34
Makefile.3ds
34
Makefile.3ds
@ -31,16 +31,24 @@ include $(DEVKITARM)/3ds_rules
|
|||||||
# - icon.png
|
# - icon.png
|
||||||
# - <libctru folder>/default_icon.png
|
# - <libctru folder>/default_icon.png
|
||||||
#---------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------
|
||||||
TARGET := 3ds/$(notdir $(CURDIR))
|
SOURCES := source source/3ds
|
||||||
BUILD := 3ds/build
|
|
||||||
SOURCES := source source/3ds source/imgui
|
|
||||||
DATA := data
|
DATA := data
|
||||||
INCLUDES := include
|
INCLUDES := include
|
||||||
GRAPHICS := 3ds/gfx
|
|
||||||
ROMFS := 3ds/romfs
|
|
||||||
GFXBUILD := $(ROMFS)
|
|
||||||
|
|
||||||
APP_TITLE := ftpd
|
ifeq ($(strip $(CLASSIC)),)
|
||||||
|
APP_TITLE := ftpd pro
|
||||||
|
TARGET := 3ds/ftpd
|
||||||
|
BUILD := 3ds/build
|
||||||
|
SOURCES += source/imgui
|
||||||
|
GRAPHICS := 3ds/gfx
|
||||||
|
ROMFS := 3ds/romfs
|
||||||
|
GFXBUILD := $(ROMFS)
|
||||||
|
else
|
||||||
|
APP_TITLE := ftpd classic
|
||||||
|
TARGET := 3ds-classic/ftpd-classic
|
||||||
|
BUILD := 3ds-classic/build
|
||||||
|
endif
|
||||||
|
|
||||||
APP_DESCRIPTION := v$(VERSION)
|
APP_DESCRIPTION := v$(VERSION)
|
||||||
APP_AUTHOR := mtheall
|
APP_AUTHOR := mtheall
|
||||||
|
|
||||||
@ -52,16 +60,17 @@ RSF_FILE := meta/ftpd-cia.rsf
|
|||||||
#---------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------
|
||||||
# options for code generation
|
# options for code generation
|
||||||
#---------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------
|
||||||
OPTIMIZE := -O2
|
OPTIMIZE := -O0
|
||||||
ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=hard -mtp=soft
|
ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=hard -mtp=soft
|
||||||
|
|
||||||
CFLAGS := -g -Wall $(OPTIMIZE) -mword-relocations \
|
CFLAGS := -g -Wall $(OPTIMIZE) -mword-relocations \
|
||||||
-fomit-frame-pointer -ffunction-sections -fdata-sections \
|
-fomit-frame-pointer -ffunction-sections -fdata-sections \
|
||||||
$(ARCH) $(DEFINES)
|
$(ARCH) $(DEFINES) $(CLASSIC)
|
||||||
|
|
||||||
CFLAGS += $(INCLUDE) -DARM11 -D_3DS \
|
CFLAGS += $(INCLUDE) -DARM11 -D_3DS \
|
||||||
-DSTATUS_STRING="\"ftpd v$(VERSION)\"" \
|
-DSTATUS_STRING="\"ftpd v$(VERSION)\"" \
|
||||||
-DIMGUI_DISABLE_INCLUDE_IMCONFIG_H=1
|
-DIMGUI_DISABLE_INCLUDE_IMCONFIG_H=1 \
|
||||||
|
-DNO_IPV6
|
||||||
|
|
||||||
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++17
|
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++17
|
||||||
|
|
||||||
@ -96,11 +105,14 @@ export DEPSDIR := $(CURDIR)/$(BUILD)
|
|||||||
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
|
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
|
||||||
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
|
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
|
||||||
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
|
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
|
||||||
PICAFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.v.pica)))
|
|
||||||
SHLISTFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.shlist)))
|
SHLISTFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.shlist)))
|
||||||
GFXFILES := $(foreach dir,$(GRAPHICS),$(notdir $(wildcard $(dir)/*.t3s)))
|
GFXFILES := $(foreach dir,$(GRAPHICS),$(notdir $(wildcard $(dir)/*.t3s)))
|
||||||
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
|
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
|
||||||
|
|
||||||
|
ifeq ($(strip $(CLASSIC)),)
|
||||||
|
PICAFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.v.pica)))
|
||||||
|
endif
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------
|
||||||
# use CXX for linking C++ projects, CC for standard C
|
# use CXX for linking C++ projects, CC for standard C
|
||||||
#---------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------
|
||||||
|
@ -2,8 +2,9 @@ TARGET := linux/ftpd
|
|||||||
BUILD := linux/build
|
BUILD := linux/build
|
||||||
|
|
||||||
CFILES := $(wildcard source/linux/*.c)
|
CFILES := $(wildcard source/linux/*.c)
|
||||||
OFILES := $(patsubst source/%,$(BUILD)/%,$(CFILES:.c=.c.o))
|
|
||||||
CXXFILES := $(wildcard source/*.cpp source/imgui/*.cpp source/linux/*.cpp)
|
CXXFILES := $(wildcard source/*.cpp source/imgui/*.cpp source/linux/*.cpp)
|
||||||
|
|
||||||
|
OFILES := $(patsubst source/%,$(BUILD)/%,$(CFILES:.c=.c.o))
|
||||||
OXXFILES := $(patsubst source/%,$(BUILD)/%,$(CXXFILES:.cpp=.cpp.o))
|
OXXFILES := $(patsubst source/%,$(BUILD)/%,$(CXXFILES:.cpp=.cpp.o))
|
||||||
|
|
||||||
CPPFLAGS := -g -Wall -pthread -Iinclude -Isource/linux \
|
CPPFLAGS := -g -Wall -pthread -Iinclude -Isource/linux \
|
||||||
|
219
Makefile.nds
Normal file
219
Makefile.nds
Normal file
@ -0,0 +1,219 @@
|
|||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
.SUFFIXES:
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
ifeq ($(strip $(DEVKITARM)),)
|
||||||
|
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
|
||||||
|
endif
|
||||||
|
|
||||||
|
include $(DEVKITARM)/ds_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
|
||||||
|
# INCLUDES is a list of directories containing extra header files
|
||||||
|
# DATA is a list of directories containing binary files embedded using bin2o
|
||||||
|
# GRAPHICS is a list of directories containing image files to be converted with grit
|
||||||
|
# AUDIO is a list of directories containing audio to be converted by maxmod
|
||||||
|
# ICON is the image used to create the game icon, leave blank to use default rule
|
||||||
|
# NITRO is a directory that will be accessible via NitroFS
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
TARGET := nds/ftpd
|
||||||
|
BUILD := nds/build
|
||||||
|
SOURCES := source source/nds
|
||||||
|
INCLUDES := include
|
||||||
|
DATA :=
|
||||||
|
GRAPHICS :=
|
||||||
|
AUDIO :=
|
||||||
|
ICON :=
|
||||||
|
|
||||||
|
# specify a directory which contains the nitro filesystem
|
||||||
|
# this is relative to the Makefile
|
||||||
|
NITRO :=
|
||||||
|
|
||||||
|
# These set the information text in the nds file
|
||||||
|
GAME_TITLE := ftpd classic
|
||||||
|
GAME_SUBTITLE1 := v$(VERSION)
|
||||||
|
GAME_SUBTITLE2 := (c) mtheall
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# options for code generation
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
ARCH := -marm -mthumb-interwork -march=armv5te -mtune=arm946e-s
|
||||||
|
|
||||||
|
CFLAGS := -g -Wall -Os \
|
||||||
|
$(ARCH) $(INCLUDE) -DARM9 -DNDS \
|
||||||
|
-DSTATUS_STRING="\"ftpd v$(VERSION)\"" \
|
||||||
|
-DIMGUI_DISABLE_INCLUDE_IMCONFIG_H=1 \
|
||||||
|
-DNO_IPV6 -DCLASSIC
|
||||||
|
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++17
|
||||||
|
ASFLAGS := -g $(ARCH)
|
||||||
|
LDFLAGS = -specs=ds_arm9.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# any extra libraries we wish to link with the project (order is important)
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
LIBS := -lfat -ldswifi9 -lnds9
|
||||||
|
|
||||||
|
# automatigically add libraries for NitroFS
|
||||||
|
ifneq ($(strip $(NITRO)),)
|
||||||
|
LIBS := -lfilesystem -lfat $(LIBS)
|
||||||
|
endif
|
||||||
|
# automagically add maxmod library
|
||||||
|
ifneq ($(strip $(AUDIO)),)
|
||||||
|
LIBS := -lmm9 $(LIBS)
|
||||||
|
endif
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# list of directories containing libraries, this must be the top level containing
|
||||||
|
# include and lib
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
LIBDIRS := $(LIBNDS) $(PORTLIBS)
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# no real need to edit anything past this point unless you need to add additional
|
||||||
|
# rules for different file extensions
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
ifneq ($(TOPDIR)/$(BUILD),$(CURDIR))
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
export OUTPUT := $(CURDIR)/$(TARGET)
|
||||||
|
export TOPDIR := $(CURDIR)
|
||||||
|
|
||||||
|
export VPATH := $(CURDIR)/$(subst /,,$(dir $(ICON)))\
|
||||||
|
$(foreach dir,$(SOURCES),$(CURDIR)/$(dir))\
|
||||||
|
$(foreach dir,$(DATA),$(CURDIR)/$(dir))\
|
||||||
|
$(foreach dir,$(GRAPHICS),$(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)))
|
||||||
|
PNGFILES := $(foreach dir,$(GRAPHICS),$(notdir $(wildcard $(dir)/*.png)))
|
||||||
|
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
|
||||||
|
|
||||||
|
# prepare NitroFS directory
|
||||||
|
ifneq ($(strip $(NITRO)),)
|
||||||
|
export NITRO_FILES := $(CURDIR)/$(NITRO)
|
||||||
|
endif
|
||||||
|
|
||||||
|
# get audio list for maxmod
|
||||||
|
ifneq ($(strip $(AUDIO)),)
|
||||||
|
export MODFILES := $(foreach dir,$(notdir $(wildcard $(AUDIO)/*.*)),$(CURDIR)/$(AUDIO)/$(dir))
|
||||||
|
|
||||||
|
# place the soundbank file in NitroFS if using it
|
||||||
|
ifneq ($(strip $(NITRO)),)
|
||||||
|
export SOUNDBANK := $(NITRO_FILES)/soundbank.bin
|
||||||
|
|
||||||
|
# otherwise, needs to be loaded from memory
|
||||||
|
else
|
||||||
|
export SOUNDBANK := soundbank.bin
|
||||||
|
BINFILES += $(SOUNDBANK)
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# 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))\
|
||||||
|
$(PNGFILES:.png=.o)\
|
||||||
|
$(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
|
||||||
|
export INCLUDE := $(foreach dir,$(INCLUDES),-iquote $(CURDIR)/$(dir))\
|
||||||
|
$(foreach dir,$(LIBDIRS),-I$(dir)/include)\
|
||||||
|
-I$(CURDIR)/$(BUILD)
|
||||||
|
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
|
||||||
|
|
||||||
|
ifeq ($(strip $(ICON)),)
|
||||||
|
icons := $(wildcard *.bmp)
|
||||||
|
|
||||||
|
ifneq (,$(findstring $(TARGET).bmp,$(icons)))
|
||||||
|
export GAME_ICON := $(CURDIR)/$(TARGET).bmp
|
||||||
|
else
|
||||||
|
ifneq (,$(findstring icon.bmp,$(icons)))
|
||||||
|
export GAME_ICON := $(CURDIR)/icon.bmp
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
else
|
||||||
|
ifeq ($(suffix $(ICON)), .grf)
|
||||||
|
export GAME_ICON := $(CURDIR)/$(ICON)
|
||||||
|
else
|
||||||
|
export GAME_ICON := $(CURDIR)/$(BUILD)/$(notdir $(basename $(ICON))).grf
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
.PHONY: $(BUILD) clean dslink
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
$(BUILD):
|
||||||
|
@mkdir -p $@
|
||||||
|
@$(MAKE) -C $(BUILD) -f $(CURDIR)/Makefile.nds
|
||||||
|
|
||||||
|
dslink: $(BUILD)
|
||||||
|
@dslink $(OUTPUT).nds
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
clean:
|
||||||
|
@echo clean ...
|
||||||
|
@rm -fr $(BUILD) $(TARGET).elf $(TARGET).nds $(SOUNDBANK)
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
else
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# main targets
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
$(OUTPUT).nds: $(OUTPUT).elf $(GAME_ICON)
|
||||||
|
$(OUTPUT).elf: $(OFILES)
|
||||||
|
|
||||||
|
# need to build soundbank first
|
||||||
|
$(OFILES): $(SOUNDBANK)
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# rule to build solution from music files
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
$(SOUNDBANK) : $(MODFILES)
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
mmutil $^ -d -o$@ -hsoundbank.h
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
%.bin.o: %.bin
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
@echo $(notdir $<)
|
||||||
|
$(bin2o)
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# This rule creates assembly source files using grit
|
||||||
|
# grit takes an image file and a .grit describing how the file is to be processed
|
||||||
|
# add additional rules like this for each image extension
|
||||||
|
# you use in the graphics folders
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
%.s %.h: %.png %.grit
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
grit $< -fts -o$*
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# Convert non-GRF game icon to GRF if needed
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
$(GAME_ICON): $(notdir $(ICON))
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
@echo convert $(notdir $<)
|
||||||
|
@grit $< -g -gt -gB4 -gT FF00FF -m! -p -pe 16 -fh! -ftr
|
||||||
|
|
||||||
|
-include $(DEPSDIR)/*.d
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------------
|
||||||
|
endif
|
||||||
|
#---------------------------------------------------------------------------------------
|
@ -37,18 +37,26 @@ include $(DEVKITPRO)/libnx/switch_rules
|
|||||||
# of a homebrew executable (.nro). This is intended to be used for sysmodules.
|
# of a homebrew executable (.nro). This is intended to be used for sysmodules.
|
||||||
# NACP building is skipped as well.
|
# NACP building is skipped as well.
|
||||||
#---------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------
|
||||||
APP_TITLE := ftpd snap! $(VERSION)
|
|
||||||
APP_AUTHOR := mtheall, TuxSH, WinterMute
|
APP_AUTHOR := mtheall, TuxSH, WinterMute
|
||||||
ICON := meta/ftpd.jpg
|
ICON := meta/ftpd.jpg
|
||||||
APP_VERSION := $(VERSION)
|
APP_VERSION := $(VERSION)
|
||||||
|
|
||||||
TARGET := switch/$(notdir $(CURDIR))
|
SOURCES := source source/switch
|
||||||
BUILD := switch/build
|
|
||||||
SOURCES := source source/imgui source/switch
|
|
||||||
DATA := data
|
DATA := data
|
||||||
INCLUDES := include
|
INCLUDES := include
|
||||||
|
|
||||||
|
ifeq ($(strip $(CLASSIC)),)
|
||||||
|
APP_TITLE := ftpd pro $(VERSION)
|
||||||
|
TARGET := switch/ftpd
|
||||||
|
BUILD := switch/build
|
||||||
|
SOURCES += source/imgui
|
||||||
GRAPHICS := switch/gfx
|
GRAPHICS := switch/gfx
|
||||||
ROMFS := switch/romfs
|
ROMFS := switch/romfs
|
||||||
|
else
|
||||||
|
APP_TITLE := ftpd classic $(VERSION)
|
||||||
|
TARGET := switch-classic/ftpd-classic
|
||||||
|
BUILD := switch-classic/build
|
||||||
|
endif
|
||||||
|
|
||||||
# Output folders for autogenerated files in romfs
|
# Output folders for autogenerated files in romfs
|
||||||
OUT_SHADERS := shaders
|
OUT_SHADERS := shaders
|
||||||
@ -61,7 +69,7 @@ ARCH := -march=armv8-a+crc+crypto -mtune=cortex-a57 -mtp=soft -fPIE
|
|||||||
|
|
||||||
CFLAGS := -g -Wall -Wno-narrowing $(OPTIMIZE) \
|
CFLAGS := -g -Wall -Wno-narrowing $(OPTIMIZE) \
|
||||||
-ffunction-sections -fdata-sections \
|
-ffunction-sections -fdata-sections \
|
||||||
$(ARCH) $(DEFINES)
|
$(ARCH) $(DEFINES) $(CLASSIC)
|
||||||
|
|
||||||
CFLAGS += $(INCLUDE) -D__SWITCH__ \
|
CFLAGS += $(INCLUDE) -D__SWITCH__ \
|
||||||
-DSTATUS_STRING="\"ftpd v$(VERSION)\"" \
|
-DSTATUS_STRING="\"ftpd v$(VERSION)\"" \
|
||||||
|
26
README.md
26
README.md
@ -9,6 +9,7 @@ FTP Server for 3DS/Switch/Linux.
|
|||||||
- Cutting-edge graphics.
|
- Cutting-edge graphics.
|
||||||
|
|
||||||
## Latest Builds
|
## Latest Builds
|
||||||
|
NDS: https://mtheall.com/~mtheall/ftpd.nds
|
||||||
|
|
||||||
CIA: https://mtheall.com/~mtheall/ftpd.cia
|
CIA: https://mtheall.com/~mtheall/ftpd.cia
|
||||||
|
|
||||||
@ -18,12 +19,35 @@ NRO: https://mtheall.com/~mtheall/ftpd.nro
|
|||||||
|
|
||||||
CIA QR Code
|
CIA QR Code
|
||||||
|
|
||||||
![ftpd.cia](https://github.com/mtheall/ftpd/raw/master/ftpd_qr.png)
|
![ftpd.cia](https://github.com/mtheall/ftpd/raw/feature/v3.0.0/ftpd-qr.png)
|
||||||
|
|
||||||
|
## Classic Builds
|
||||||
|
|
||||||
|
CIA: https://mtheall.com/~mtheall/ftpd-classic.cia
|
||||||
|
|
||||||
|
3DSX: https://mtheall.com/~mtheall/ftpd-classic.3dsx
|
||||||
|
|
||||||
|
NRO: https://mtheall.com/~mtheall/ftpd-classic.nro
|
||||||
|
|
||||||
|
CIA QR Code
|
||||||
|
|
||||||
|
![ftpd-classic.cia](https://github.com/mtheall/ftpd/raw/feature/v3.0.0/ftpd-classic-qr.png)
|
||||||
|
|
||||||
## Build and install
|
## Build and install
|
||||||
|
|
||||||
You must set up the [development environment](https://devkitpro.org/wiki/Getting_Started).
|
You must set up the [development environment](https://devkitpro.org/wiki/Getting_Started).
|
||||||
|
|
||||||
|
### NDS
|
||||||
|
|
||||||
|
The following pacman packages are required to build `nds/ftpd.nds`:
|
||||||
|
|
||||||
|
devkitARM
|
||||||
|
dswifi
|
||||||
|
libfat-nds
|
||||||
|
libnds
|
||||||
|
|
||||||
|
They are available as part of the `nds-dev` meta-package.
|
||||||
|
|
||||||
### 3DSX
|
### 3DSX
|
||||||
|
|
||||||
The following pacman packages are required to build `3ds/ftpd.3dsx`:
|
The following pacman packages are required to build `3ds/ftpd.3dsx`:
|
||||||
|
BIN
ftpd-classic-qr.png
Normal file
BIN
ftpd-classic-qr.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.0 KiB |
BIN
ftpd-qr.png
Normal file
BIN
ftpd-qr.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.0 KiB |
BIN
ftpd_qr.png
BIN
ftpd_qr.png
Binary file not shown.
Before Width: | Height: | Size: 621 B |
@ -69,11 +69,13 @@ private:
|
|||||||
/// \brief Thread entry point
|
/// \brief Thread entry point
|
||||||
void threadFunc ();
|
void threadFunc ();
|
||||||
|
|
||||||
|
#ifndef NDS
|
||||||
/// \brief Thread
|
/// \brief Thread
|
||||||
platform::Thread m_thread;
|
platform::Thread m_thread;
|
||||||
|
|
||||||
/// \brief Mutex
|
/// \brief Mutex
|
||||||
platform::Mutex m_lock;
|
platform::Mutex m_lock;
|
||||||
|
#endif
|
||||||
|
|
||||||
/// \brief Listen socket
|
/// \brief Listen socket
|
||||||
UniqueSocket m_socket;
|
UniqueSocket m_socket;
|
||||||
|
@ -58,16 +58,30 @@ private:
|
|||||||
/// \brief Command buffer size
|
/// \brief Command buffer size
|
||||||
constexpr static auto COMMAND_BUFFERSIZE = 4096;
|
constexpr static auto COMMAND_BUFFERSIZE = 4096;
|
||||||
|
|
||||||
|
#ifdef NDS
|
||||||
|
/// \brief Response buffer size
|
||||||
|
constexpr static auto RESPONSE_BUFFERSIZE = 4096;
|
||||||
|
|
||||||
|
/// \brief Transfer buffersize
|
||||||
|
constexpr static auto XFER_BUFFERSIZE = 8192;
|
||||||
|
#else
|
||||||
/// \brief Response buffer size
|
/// \brief Response buffer size
|
||||||
constexpr static auto RESPONSE_BUFFERSIZE = 32768;
|
constexpr static auto RESPONSE_BUFFERSIZE = 32768;
|
||||||
|
|
||||||
/// \brief Transfer buffersize
|
/// \brief Transfer buffersize
|
||||||
constexpr static auto XFER_BUFFERSIZE = 65536;
|
constexpr static auto XFER_BUFFERSIZE = 65536;
|
||||||
|
#endif
|
||||||
|
|
||||||
/// \brief File buffersize
|
/// \brief File buffersize
|
||||||
constexpr static auto FILE_BUFFERSIZE = 4 * XFER_BUFFERSIZE;
|
constexpr static auto FILE_BUFFERSIZE = 4 * XFER_BUFFERSIZE;
|
||||||
|
|
||||||
#ifdef _3DS
|
#if defined(NDS)
|
||||||
|
/// \brief Socket buffer size
|
||||||
|
constexpr static auto SOCK_BUFFERSIZE = 4096;
|
||||||
|
|
||||||
|
/// \brief Amount of file position history to keep
|
||||||
|
constexpr static auto POSITION_HISTORY = 60;
|
||||||
|
#elif defined(_3DS)
|
||||||
/// \brief Socket buffer size
|
/// \brief Socket buffer size
|
||||||
constexpr static auto SOCK_BUFFERSIZE = 32768;
|
constexpr static auto SOCK_BUFFERSIZE = 32768;
|
||||||
|
|
||||||
@ -184,8 +198,10 @@ private:
|
|||||||
/// \brief Transfer upload
|
/// \brief Transfer upload
|
||||||
bool storeTransfer ();
|
bool storeTransfer ();
|
||||||
|
|
||||||
|
#ifndef NDS
|
||||||
/// \brief Mutex
|
/// \brief Mutex
|
||||||
platform::Mutex m_lock;
|
platform::Mutex m_lock;
|
||||||
|
#endif
|
||||||
|
|
||||||
/// \brief Command socket
|
/// \brief Command socket
|
||||||
SharedSocket m_commandSocket;
|
SharedSocket m_commandSocket;
|
||||||
|
@ -20,8 +20,12 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#ifdef _3DS
|
#if defined(NDS)
|
||||||
|
#include <nds.h>
|
||||||
|
#elif defined(_3DS)
|
||||||
#include <3ds.h>
|
#include <3ds.h>
|
||||||
|
#elif defined(__SWITCH__)
|
||||||
|
#include <switch.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
@ -29,6 +33,12 @@
|
|||||||
#include <functional>
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
#ifdef CLASSIC
|
||||||
|
extern PrintConsole g_statusConsole;
|
||||||
|
extern PrintConsole g_logConsole;
|
||||||
|
extern PrintConsole g_sessionConsole;
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace platform
|
namespace platform
|
||||||
{
|
{
|
||||||
/// \brief Initialize platform
|
/// \brief Initialize platform
|
||||||
@ -66,16 +76,14 @@ struct steady_clock
|
|||||||
constexpr static bool is_steady = true;
|
constexpr static bool is_steady = true;
|
||||||
|
|
||||||
/// \brief Current timestamp
|
/// \brief Current timestamp
|
||||||
static time_point now () noexcept
|
static time_point now () noexcept;
|
||||||
{
|
|
||||||
return time_point (duration (svcGetSystemTick ()));
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
#else
|
#else
|
||||||
/// \brief Steady clock
|
/// \brief Steady clock
|
||||||
using steady_clock = std::chrono::steady_clock;
|
using steady_clock = std::chrono::steady_clock;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef NDS
|
||||||
/// \brief Platform thread
|
/// \brief Platform thread
|
||||||
class Thread
|
class Thread
|
||||||
{
|
{
|
||||||
@ -132,4 +140,5 @@ private:
|
|||||||
/// \brief pimpl
|
/// \brief pimpl
|
||||||
std::unique_ptr<privateData_t> m_d;
|
std::unique_ptr<privateData_t> m_d;
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,14 @@
|
|||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
|
#ifdef NDS
|
||||||
|
struct sockaddr_storage
|
||||||
|
{
|
||||||
|
unsigned short ss_family;
|
||||||
|
char ss_data[sizeof (struct sockaddr_in) - sizeof (unsigned short)];
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
/// \brief Socket address
|
/// \brief Socket address
|
||||||
class SockAddr
|
class SockAddr
|
||||||
{
|
{
|
||||||
|
@ -26,6 +26,28 @@
|
|||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
#ifdef NDS
|
||||||
|
struct pollfd
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
int events;
|
||||||
|
int revents;
|
||||||
|
};
|
||||||
|
|
||||||
|
using socklen_t = int;
|
||||||
|
using nfds_t = unsigned int;
|
||||||
|
|
||||||
|
extern "C" int poll (struct pollfd *fds_, nfds_t nfds_, int timeout_);
|
||||||
|
|
||||||
|
#define POLLIN (1 << 0)
|
||||||
|
#define POLLPRI (1 << 1)
|
||||||
|
#define POLLOUT (1 << 2)
|
||||||
|
#define POLLERR (1 << 3)
|
||||||
|
#define POLLHUP (1 << 4)
|
||||||
|
#else
|
||||||
|
#include <poll.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
class Socket;
|
class Socket;
|
||||||
using UniqueSocket = std::unique_ptr<Socket>;
|
using UniqueSocket = std::unique_ptr<Socket>;
|
||||||
using SharedSocket = std::shared_ptr<Socket>;
|
using SharedSocket = std::shared_ptr<Socket>;
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#ifndef CLASSIC
|
||||||
#include "imgui_citro3d.h"
|
#include "imgui_citro3d.h"
|
||||||
|
|
||||||
#include <citro3d.h>
|
#include <citro3d.h>
|
||||||
@ -692,3 +693,4 @@ void imgui::citro3d::render (C3D_RenderTarget *const top_, C3D_RenderTarget *con
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef CLASSIC
|
||||||
#include <citro3d.h>
|
#include <citro3d.h>
|
||||||
|
|
||||||
namespace imgui
|
namespace imgui
|
||||||
@ -35,3 +36,4 @@ void exit ();
|
|||||||
void render (C3D_RenderTarget *top_, C3D_RenderTarget *bottom_);
|
void render (C3D_RenderTarget *top_, C3D_RenderTarget *bottom_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#ifndef CLASSIC
|
||||||
#include "imgui_ctru.h"
|
#include "imgui_ctru.h"
|
||||||
|
|
||||||
#include "imgui.h"
|
#include "imgui.h"
|
||||||
@ -25,8 +26,6 @@
|
|||||||
#include "fs.h"
|
#include "fs.h"
|
||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
|
|
||||||
#include <3ds.h>
|
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
@ -174,3 +173,4 @@ void imgui::ctru::newFrame ()
|
|||||||
updateTouch (io);
|
updateTouch (io);
|
||||||
updateGamepads (io);
|
updateGamepads (io);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef CLASSIC
|
||||||
namespace imgui
|
namespace imgui
|
||||||
{
|
{
|
||||||
namespace ctru
|
namespace ctru
|
||||||
@ -31,3 +32,4 @@ bool init ();
|
|||||||
void newFrame ();
|
void newFrame ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
@ -28,20 +28,29 @@
|
|||||||
|
|
||||||
#include "imgui.h"
|
#include "imgui.h"
|
||||||
|
|
||||||
#include <3ds.h>
|
|
||||||
#include <citro3d.h>
|
#include <citro3d.h>
|
||||||
#include <tex3ds.h>
|
#include <tex3ds.h>
|
||||||
|
|
||||||
|
#ifndef CLASSIC
|
||||||
#include "gfx.h"
|
#include "gfx.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <arpa/inet.h>
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
#include <cstring>
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
|
||||||
|
#ifdef CLASSIC
|
||||||
|
PrintConsole g_statusConsole;
|
||||||
|
PrintConsole g_logConsole;
|
||||||
|
PrintConsole g_sessionConsole;
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
/// \brief Thread stack size
|
/// \brief Thread stack size
|
||||||
@ -60,6 +69,9 @@ u32 *s_socuBuffer = nullptr;
|
|||||||
/// \brief ac:u fence
|
/// \brief ac:u fence
|
||||||
platform::Mutex s_acuFence;
|
platform::Mutex s_acuFence;
|
||||||
|
|
||||||
|
#ifdef CLASSIC
|
||||||
|
in_addr_t s_addr = 0;
|
||||||
|
#else
|
||||||
/// \brief Clear color
|
/// \brief Clear color
|
||||||
constexpr auto CLEAR_COLOR = 0x204B7AFF;
|
constexpr auto CLEAR_COLOR = 0x204B7AFF;
|
||||||
|
|
||||||
@ -103,6 +115,7 @@ C3D_RenderTarget *s_bottom = nullptr;
|
|||||||
C3D_Tex s_gfxTexture;
|
C3D_Tex s_gfxTexture;
|
||||||
/// \brief Texture atlas metadata
|
/// \brief Texture atlas metadata
|
||||||
Tex3DS_Texture s_gfxT3x;
|
Tex3DS_Texture s_gfxT3x;
|
||||||
|
#endif
|
||||||
|
|
||||||
/// \brief Get network visibility
|
/// \brief Get network visibility
|
||||||
bool getNetworkVisibility ()
|
bool getNetworkVisibility ()
|
||||||
@ -113,7 +126,20 @@ bool getNetworkVisibility ()
|
|||||||
// get wifi status
|
// get wifi status
|
||||||
std::uint32_t wifi = 0;
|
std::uint32_t wifi = 0;
|
||||||
if (R_FAILED (ACU_GetWifiStatus (&wifi)) || !wifi)
|
if (R_FAILED (ACU_GetWifiStatus (&wifi)) || !wifi)
|
||||||
|
{
|
||||||
|
#ifdef CLASSIC
|
||||||
|
s_addr = 0;
|
||||||
|
#endif
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CLASSIC
|
||||||
|
if (!s_addr)
|
||||||
|
s_addr = gethostid ();
|
||||||
|
|
||||||
|
if (s_addr == INADDR_BROADCAST)
|
||||||
|
s_addr = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -146,6 +172,7 @@ void startNetwork ()
|
|||||||
/// \brief Draw citro3d logo
|
/// \brief Draw citro3d logo
|
||||||
void drawLogo ()
|
void drawLogo ()
|
||||||
{
|
{
|
||||||
|
#ifndef CLASSIC
|
||||||
// get citro3d logo subtexture
|
// get citro3d logo subtexture
|
||||||
auto subTex = Tex3DS_GetSubTexture (s_gfxT3x, gfx_c3dlogo_idx);
|
auto subTex = Tex3DS_GetSubTexture (s_gfxT3x, gfx_c3dlogo_idx);
|
||||||
|
|
||||||
@ -176,11 +203,13 @@ void drawLogo ()
|
|||||||
ImVec2 (x2, y2 + screenHeight * 0.5f),
|
ImVec2 (x2, y2 + screenHeight * 0.5f),
|
||||||
uv1,
|
uv1,
|
||||||
uv2);
|
uv2);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Draw status
|
/// \brief Draw status
|
||||||
void drawStatus ()
|
void drawStatus ()
|
||||||
{
|
{
|
||||||
|
#ifndef CLASSIC
|
||||||
constexpr unsigned batteryLevels[] = {
|
constexpr unsigned batteryLevels[] = {
|
||||||
gfx_battery0_idx,
|
gfx_battery0_idx,
|
||||||
gfx_battery0_idx,
|
gfx_battery0_idx,
|
||||||
@ -250,13 +279,37 @@ void drawStatus ()
|
|||||||
// draw wifi icon
|
// draw wifi icon
|
||||||
ImGui::GetForegroundDrawList ()->AddImage (
|
ImGui::GetForegroundDrawList ()->AddImage (
|
||||||
&s_gfxTexture, p3, p4, uv3, uv4, ImGui::GetColorU32 (ImGuiCol_Text));
|
&s_gfxTexture, p3, p4, uv3, uv4, ImGui::GetColorU32 (ImGuiCol_Text));
|
||||||
|
#endif
|
||||||
|
|
||||||
// draw current timestamp
|
// draw current timestamp
|
||||||
char buffer[64];
|
char timeBuffer[16];
|
||||||
auto const now = std::time (nullptr);
|
auto const now = std::time (nullptr);
|
||||||
std::strftime (buffer, sizeof (buffer), "%H:%M:%S", std::localtime (&now));
|
std::strftime (timeBuffer, sizeof (timeBuffer), "%H:%M:%S", std::localtime (&now));
|
||||||
ImGui::GetForegroundDrawList ()->AddText (
|
|
||||||
ImVec2 (p3.x - 65.0f, style.FramePadding.y), ImGui::GetColorU32 (ImGuiCol_Text), buffer);
|
#ifdef CLASSIC
|
||||||
|
static std::string statusString;
|
||||||
|
|
||||||
|
std::string newStatusString (256, '\0');
|
||||||
|
newStatusString.resize (std::sprintf (&newStatusString[0],
|
||||||
|
"\x1b[0;0H\x1b[32;1m%s \x1b[36;1m%s%s \x1b[37;1m%s\x1b[K",
|
||||||
|
STATUS_STRING,
|
||||||
|
s_addr ? inet_ntoa (in_addr{s_addr}) : "Waiting",
|
||||||
|
s_addr ? ":5000" : "",
|
||||||
|
timeBuffer));
|
||||||
|
|
||||||
|
if (newStatusString != statusString)
|
||||||
|
{
|
||||||
|
statusString = std::move (newStatusString);
|
||||||
|
|
||||||
|
consoleSelect (&g_statusConsole);
|
||||||
|
std::fputs (statusString.c_str (), stdout);
|
||||||
|
std::fflush (stdout);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
ImGui::GetForegroundDrawList ()->AddText (ImVec2 (p3.x - 65.0f, style.FramePadding.y),
|
||||||
|
ImGui::GetColorU32 (ImGuiCol_Text),
|
||||||
|
timeBuffer);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -267,16 +320,28 @@ bool platform::init ()
|
|||||||
|
|
||||||
acInit ();
|
acInit ();
|
||||||
ptmuInit ();
|
ptmuInit ();
|
||||||
|
#ifndef CLASSIC
|
||||||
romfsInit ();
|
romfsInit ();
|
||||||
|
#endif
|
||||||
gfxInitDefault ();
|
gfxInitDefault ();
|
||||||
gfxSet3D (false);
|
gfxSet3D (false);
|
||||||
sdmcWriteSafe (false);
|
|
||||||
|
#ifdef CLASSIC
|
||||||
|
consoleInit (GFX_TOP, &g_statusConsole);
|
||||||
|
consoleInit (GFX_TOP, &g_logConsole);
|
||||||
|
consoleInit (GFX_BOTTOM, &g_sessionConsole);
|
||||||
|
|
||||||
|
consoleSetWindow (&g_statusConsole, 0, 0, 50, 1);
|
||||||
|
consoleSetWindow (&g_logConsole, 0, 1, 50, 29);
|
||||||
|
consoleSetWindow (&g_sessionConsole, 0, 0, 40, 30);
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
consoleDebugInit (debugDevice_SVC);
|
consoleDebugInit (debugDevice_SVC);
|
||||||
std::setvbuf (stderr, nullptr, _IOLBF, 0);
|
std::setvbuf (stderr, nullptr, _IOLBF, 0);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef CLASSIC
|
||||||
// initialize citro3d
|
// initialize citro3d
|
||||||
C3D_Init (C3D_DEFAULT_CMDBUF_SIZE);
|
C3D_Init (C3D_DEFAULT_CMDBUF_SIZE);
|
||||||
|
|
||||||
@ -317,6 +382,7 @@ bool platform::init ()
|
|||||||
// citro3d logo doesn't quite show with the default transparency
|
// citro3d logo doesn't quite show with the default transparency
|
||||||
style.Colors[ImGuiCol_WindowBg].w = 0.8f;
|
style.Colors[ImGuiCol_WindowBg].w = 0.8f;
|
||||||
style.ScaleAllSizes (0.5f);
|
style.ScaleAllSizes (0.5f);
|
||||||
|
#endif
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -342,6 +408,7 @@ bool platform::loop ()
|
|||||||
if (hidKeysDown () & KEY_START)
|
if (hidKeysDown () & KEY_START)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
#ifndef CLASSIC
|
||||||
auto &io = ImGui::GetIO ();
|
auto &io = ImGui::GetIO ();
|
||||||
|
|
||||||
// setup display metrics
|
// setup display metrics
|
||||||
@ -350,6 +417,7 @@ bool platform::loop ()
|
|||||||
|
|
||||||
imgui::ctru::newFrame ();
|
imgui::ctru::newFrame ();
|
||||||
ImGui::NewFrame ();
|
ImGui::NewFrame ();
|
||||||
|
#endif
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -359,6 +427,12 @@ void platform::render ()
|
|||||||
drawLogo ();
|
drawLogo ();
|
||||||
drawStatus ();
|
drawStatus ();
|
||||||
|
|
||||||
|
#ifdef CLASSIC
|
||||||
|
drawLog ();
|
||||||
|
gfxFlushBuffers ();
|
||||||
|
gspWaitForVBlank ();
|
||||||
|
gfxSwapBuffers ();
|
||||||
|
#else
|
||||||
ImGui::Render ();
|
ImGui::Render ();
|
||||||
|
|
||||||
C3D_FrameBegin (C3D_FRAME_SYNCDRAW);
|
C3D_FrameBegin (C3D_FRAME_SYNCDRAW);
|
||||||
@ -370,10 +444,12 @@ void platform::render ()
|
|||||||
imgui::citro3d::render (s_top, s_bottom);
|
imgui::citro3d::render (s_top, s_bottom);
|
||||||
|
|
||||||
C3D_FrameEnd (0);
|
C3D_FrameEnd (0);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void platform::exit ()
|
void platform::exit ()
|
||||||
{
|
{
|
||||||
|
#ifndef CLASSIC
|
||||||
imgui::citro3d::exit ();
|
imgui::citro3d::exit ();
|
||||||
|
|
||||||
// free graphics
|
// free graphics
|
||||||
@ -386,6 +462,7 @@ void platform::exit ()
|
|||||||
|
|
||||||
// deinitialize citro3d
|
// deinitialize citro3d
|
||||||
C3D_Fini ();
|
C3D_Fini ();
|
||||||
|
#endif
|
||||||
|
|
||||||
if (s_socuActive)
|
if (s_socuActive)
|
||||||
socExit ();
|
socExit ();
|
||||||
@ -393,11 +470,19 @@ void platform::exit ()
|
|||||||
std::free (s_socuBuffer);
|
std::free (s_socuBuffer);
|
||||||
|
|
||||||
gfxExit ();
|
gfxExit ();
|
||||||
|
#ifndef CLASSIC
|
||||||
romfsExit ();
|
romfsExit ();
|
||||||
|
#endif
|
||||||
ptmuExit ();
|
ptmuExit ();
|
||||||
acExit ();
|
acExit ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
platform::steady_clock::time_point platform::steady_clock::now () noexcept
|
||||||
|
{
|
||||||
|
return time_point (duration (svcGetSystemTick ()));
|
||||||
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
/// \brief Platform thread pimpl
|
/// \brief Platform thread pimpl
|
||||||
class platform::Thread::privateData_t
|
class platform::Thread::privateData_t
|
||||||
|
@ -23,11 +23,15 @@
|
|||||||
#include "fs.h"
|
#include "fs.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
|
#include "socket.h"
|
||||||
|
|
||||||
#include "imgui.h"
|
#include "imgui.h"
|
||||||
|
|
||||||
|
#ifdef NDS
|
||||||
|
#include <dswifi9.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <poll.h>
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
@ -37,20 +41,26 @@
|
|||||||
#include <thread>
|
#include <thread>
|
||||||
using namespace std::chrono_literals;
|
using namespace std::chrono_literals;
|
||||||
|
|
||||||
|
#ifdef NDS
|
||||||
|
#define LOCKED(x) x
|
||||||
|
#else
|
||||||
#define LOCKED(x) \
|
#define LOCKED(x) \
|
||||||
do \
|
do \
|
||||||
{ \
|
{ \
|
||||||
auto const lock = std::scoped_lock (m_lock); \
|
auto const lock = std::scoped_lock (m_lock); \
|
||||||
x; \
|
x; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
/// \brief Application start time
|
/// \brief Application start time
|
||||||
auto const s_startTime = std::time (nullptr);
|
auto const s_startTime = std::time (nullptr);
|
||||||
|
|
||||||
|
#ifndef NDS
|
||||||
/// \brief Mutex for s_freeSpace
|
/// \brief Mutex for s_freeSpace
|
||||||
platform::Mutex s_lock;
|
platform::Mutex s_lock;
|
||||||
|
#endif
|
||||||
|
|
||||||
/// \brief Free space string
|
/// \brief Free space string
|
||||||
std::string s_freeSpace;
|
std::string s_freeSpace;
|
||||||
@ -61,16 +71,54 @@ FtpServer::~FtpServer ()
|
|||||||
{
|
{
|
||||||
m_quit = true;
|
m_quit = true;
|
||||||
|
|
||||||
|
#ifndef NDS
|
||||||
m_thread.join ();
|
m_thread.join ();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
FtpServer::FtpServer (std::uint16_t const port_) : m_port (port_), m_quit (false)
|
FtpServer::FtpServer (std::uint16_t const port_) : m_port (port_), m_quit (false)
|
||||||
{
|
{
|
||||||
|
#ifndef NDS
|
||||||
m_thread = platform::Thread (std::bind (&FtpServer::threadFunc, this));
|
m_thread = platform::Thread (std::bind (&FtpServer::threadFunc, this));
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void FtpServer::draw ()
|
void FtpServer::draw ()
|
||||||
{
|
{
|
||||||
|
#ifdef NDS
|
||||||
|
loop ();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CLASSIC
|
||||||
|
{
|
||||||
|
#ifndef NDS
|
||||||
|
auto const lock = std::scoped_lock (s_lock);
|
||||||
|
#endif
|
||||||
|
if (!s_freeSpace.empty ())
|
||||||
|
{
|
||||||
|
consoleSelect (&g_statusConsole);
|
||||||
|
std::printf ("\x1b[0;%uH\x1b[32;1m%s",
|
||||||
|
static_cast<unsigned> (g_statusConsole.windowWidth - s_freeSpace.size () + 1),
|
||||||
|
s_freeSpace.c_str ());
|
||||||
|
std::fflush (stdout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
#ifndef NDS
|
||||||
|
auto lock = std::scoped_lock (m_lock);
|
||||||
|
#endif
|
||||||
|
consoleSelect (&g_sessionConsole);
|
||||||
|
std::fputs ("\x1b[2J", stdout);
|
||||||
|
for (auto &session : m_sessions)
|
||||||
|
{
|
||||||
|
session->draw ();
|
||||||
|
if (&session != &m_sessions.back ())
|
||||||
|
std::fputc ('\n', stdout);
|
||||||
|
std::fflush (stdout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
auto const &io = ImGui::GetIO ();
|
auto const &io = ImGui::GetIO ();
|
||||||
auto const width = io.DisplaySize.x;
|
auto const width = io.DisplaySize.x;
|
||||||
auto const height = io.DisplaySize.y;
|
auto const height = io.DisplaySize.y;
|
||||||
@ -135,6 +183,7 @@ void FtpServer::draw ()
|
|||||||
}
|
}
|
||||||
|
|
||||||
ImGui::End ();
|
ImGui::End ();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
UniqueFtpServer FtpServer::create (std::uint16_t const port_)
|
UniqueFtpServer FtpServer::create (std::uint16_t const port_)
|
||||||
@ -150,8 +199,11 @@ void FtpServer::updateFreeSpace ()
|
|||||||
if (::statvfs ("sdmc:/", &st) != 0)
|
if (::statvfs ("sdmc:/", &st) != 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
auto freeSpace = fs::printSize (static_cast<std::uint64_t> (st.f_bsize) * st.f_bfree);
|
||||||
|
|
||||||
auto const lock = std::scoped_lock (s_lock);
|
auto const lock = std::scoped_lock (s_lock);
|
||||||
s_freeSpace = fs::printSize (static_cast<std::uint64_t> (st.f_bsize) * st.f_bfree);
|
if (freeSpace != s_freeSpace)
|
||||||
|
s_freeSpace = std::move (freeSpace);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -164,7 +216,9 @@ void FtpServer::handleNetworkFound ()
|
|||||||
{
|
{
|
||||||
struct sockaddr_in addr;
|
struct sockaddr_in addr;
|
||||||
addr.sin_family = AF_INET;
|
addr.sin_family = AF_INET;
|
||||||
#if defined(_3DS) || defined(__SWITCH__)
|
#if defined(NDS)
|
||||||
|
addr.sin_addr = Wifi_GetIPInfo (nullptr, nullptr, nullptr, nullptr);
|
||||||
|
#elif defined(_3DS) || defined(__SWITCH__)
|
||||||
addr.sin_addr.s_addr = gethostid ();
|
addr.sin_addr.s_addr = gethostid ();
|
||||||
#else
|
#else
|
||||||
addr.sin_addr.s_addr = INADDR_ANY;
|
addr.sin_addr.s_addr = INADDR_ANY;
|
||||||
@ -234,8 +288,10 @@ void FtpServer::loop ()
|
|||||||
std::vector<UniqueFtpSession> deadSessions;
|
std::vector<UniqueFtpSession> deadSessions;
|
||||||
{
|
{
|
||||||
// remove dead sessions
|
// remove dead sessions
|
||||||
|
#ifndef NDS
|
||||||
auto lock = std::scoped_lock (m_lock);
|
auto lock = std::scoped_lock (m_lock);
|
||||||
auto it = std::begin (m_sessions);
|
#endif
|
||||||
|
auto it = std::begin (m_sessions);
|
||||||
while (it != std::end (m_sessions))
|
while (it != std::end (m_sessions))
|
||||||
{
|
{
|
||||||
auto &session = *it;
|
auto &session = *it;
|
||||||
@ -256,9 +312,11 @@ void FtpServer::loop ()
|
|||||||
if (!FtpSession::poll (m_sessions))
|
if (!FtpSession::poll (m_sessions))
|
||||||
handleNetworkLost ();
|
handleNetworkLost ();
|
||||||
}
|
}
|
||||||
|
#ifndef NDS
|
||||||
// avoid busy polling in background thread
|
// avoid busy polling in background thread
|
||||||
else
|
else
|
||||||
platform::Thread::sleep (16ms);
|
platform::Thread::sleep (16ms);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void FtpServer::threadFunc ()
|
void FtpServer::threadFunc ()
|
||||||
|
@ -21,21 +21,12 @@
|
|||||||
#include "ftpSession.h"
|
#include "ftpSession.h"
|
||||||
|
|
||||||
#include "ftpServer.h"
|
#include "ftpServer.h"
|
||||||
|
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
#include "platform.h"
|
||||||
|
|
||||||
#include "imgui.h"
|
#include "imgui.h"
|
||||||
|
|
||||||
#ifdef _3DS
|
|
||||||
#include <3ds.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __SWITCH__
|
|
||||||
#include <switch.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <poll.h>
|
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
@ -49,16 +40,20 @@
|
|||||||
#include <mutex>
|
#include <mutex>
|
||||||
using namespace std::chrono_literals;
|
using namespace std::chrono_literals;
|
||||||
|
|
||||||
#if defined(_3DS) || defined(__SWITCH__)
|
#if defined(NDS) || defined(_3DS) || defined(__SWITCH__)
|
||||||
#define lstat stat
|
#define lstat stat
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef NDS
|
||||||
|
#define LOCKED(x) x
|
||||||
|
#else
|
||||||
#define LOCKED(x) \
|
#define LOCKED(x) \
|
||||||
do \
|
do \
|
||||||
{ \
|
{ \
|
||||||
auto const lock = std::scoped_lock (m_lock); \
|
auto const lock = std::scoped_lock (m_lock); \
|
||||||
x; \
|
x; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
@ -297,7 +292,9 @@ FtpSession::FtpSession (UniqueSocket commandSocket_)
|
|||||||
|
|
||||||
bool FtpSession::dead ()
|
bool FtpSession::dead ()
|
||||||
{
|
{
|
||||||
|
#ifndef NDS
|
||||||
auto const lock = std::scoped_lock (m_lock);
|
auto const lock = std::scoped_lock (m_lock);
|
||||||
|
#endif
|
||||||
if (m_commandSocket || m_pasvSocket || m_dataSocket)
|
if (m_commandSocket || m_pasvSocket || m_dataSocket)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -306,8 +303,19 @@ bool FtpSession::dead ()
|
|||||||
|
|
||||||
void FtpSession::draw ()
|
void FtpSession::draw ()
|
||||||
{
|
{
|
||||||
|
#ifndef NDS
|
||||||
auto const lock = std::scoped_lock (m_lock);
|
auto const lock = std::scoped_lock (m_lock);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CLASSIC
|
||||||
|
if (m_filePosition)
|
||||||
|
{
|
||||||
|
std::fputs (fs::printSize (m_filePosition).c_str (), stdout);
|
||||||
|
std::fputc (' ', stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::fputs (m_workItem.empty () ? m_cwd.c_str () : m_workItem.c_str (), stdout);
|
||||||
|
#else
|
||||||
#ifdef _3DS
|
#ifdef _3DS
|
||||||
ImGui::BeginChild (m_windowName.c_str (), ImVec2 (0.0f, 45.0f), true);
|
ImGui::BeginChild (m_windowName.c_str (), ImVec2 (0.0f, 45.0f), true);
|
||||||
#else
|
#else
|
||||||
@ -362,6 +370,7 @@ void FtpSession::draw ()
|
|||||||
}
|
}
|
||||||
|
|
||||||
ImGui::EndChild ();
|
ImGui::EndChild ();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
UniqueFtpSession FtpSession::create (UniqueSocket commandSocket_)
|
UniqueFtpSession FtpSession::create (UniqueSocket commandSocket_)
|
||||||
@ -571,7 +580,9 @@ void FtpSession::setState (State const state_, bool const closePasv_, bool const
|
|||||||
if (state_ == State::COMMAND)
|
if (state_ == State::COMMAND)
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
|
#ifndef NDS
|
||||||
auto lock = std::scoped_lock (m_lock);
|
auto lock = std::scoped_lock (m_lock);
|
||||||
|
#endif
|
||||||
|
|
||||||
m_restartPosition = 0;
|
m_restartPosition = 0;
|
||||||
m_fileSize = 0;
|
m_fileSize = 0;
|
||||||
@ -1294,6 +1305,7 @@ void FtpSession::xferDir (char const *const args_, XferDirMode const mode_, bool
|
|||||||
|
|
||||||
void FtpSession::readCommand (int const events_)
|
void FtpSession::readCommand (int const events_)
|
||||||
{
|
{
|
||||||
|
#ifndef NDS
|
||||||
// check out-of-band data
|
// check out-of-band data
|
||||||
if (events_ & POLLPRI)
|
if (events_ & POLLPRI)
|
||||||
{
|
{
|
||||||
@ -1333,6 +1345,7 @@ void FtpSession::readCommand (int const events_)
|
|||||||
m_commandBuffer.clear ();
|
m_commandBuffer.clear ();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (events_ & POLLIN)
|
if (events_ & POLLIN)
|
||||||
{
|
{
|
||||||
@ -1591,9 +1604,9 @@ bool FtpSession::listTransfer ()
|
|||||||
auto const dp = static_cast<DIR *> (m_dir);
|
auto const dp = static_cast<DIR *> (m_dir);
|
||||||
auto const magic = *reinterpret_cast<u32 *> (dp->dirData->dirStruct);
|
auto const magic = *reinterpret_cast<u32 *> (dp->dirData->dirStruct);
|
||||||
|
|
||||||
if (magic == SDMC_DIRITER_MAGIC)
|
if (magic == ARCHIVE_DIRITER_MAGIC)
|
||||||
{
|
{
|
||||||
auto const dir = reinterpret_cast<sdmc_dir_t const *> (dp->dirData->dirStruct);
|
auto const dir = reinterpret_cast<archive_dir_t const *> (dp->dirData->dirStruct);
|
||||||
auto const entry = &dir->entry_data[dir->index];
|
auto const entry = &dir->entry_data[dir->index];
|
||||||
|
|
||||||
if (entry->attributes & FS_ATTRIBUTE_DIRECTORY)
|
if (entry->attributes & FS_ATTRIBUTE_DIRECTORY)
|
||||||
@ -1619,7 +1632,7 @@ bool FtpSession::listTransfer ()
|
|||||||
if (getmtime)
|
if (getmtime)
|
||||||
{
|
{
|
||||||
std::uint64_t mtime = 0;
|
std::uint64_t mtime = 0;
|
||||||
auto const rc = sdmc_getmtime (fullPath.c_str (), &mtime);
|
auto const rc = archive_getmtime (fullPath.c_str (), &mtime);
|
||||||
if (rc != 0)
|
if (rc != 0)
|
||||||
error ("sdmc_getmtime %s 0x%lx\n", fullPath.c_str (), rc);
|
error ("sdmc_getmtime %s 0x%lx\n", fullPath.c_str (), rc);
|
||||||
else
|
else
|
||||||
@ -2060,7 +2073,7 @@ void FtpSession::PASV (char const *args_)
|
|||||||
|
|
||||||
// create an address to bind
|
// create an address to bind
|
||||||
struct sockaddr_in addr = m_commandSocket->sockName ();
|
struct sockaddr_in addr = m_commandSocket->sockName ();
|
||||||
#ifdef _3DS
|
#if defined(NDS) || defined(_3DS)
|
||||||
static std::uint16_t ephemeralPort = 5001;
|
static std::uint16_t ephemeralPort = 5001;
|
||||||
if (ephemeralPort > 10000)
|
if (ephemeralPort > 10000)
|
||||||
ephemeralPort = 5001;
|
ephemeralPort = 5001;
|
||||||
@ -2256,7 +2269,7 @@ void FtpSession::RMD (char const *args_)
|
|||||||
// remove the directory
|
// remove the directory
|
||||||
if (::rmdir (path.c_str ()) != 0)
|
if (::rmdir (path.c_str ()) != 0)
|
||||||
{
|
{
|
||||||
sendResponse ("550 %s\r\n", std::strerror (errno));
|
sendResponse ("550 %d %s\r\n", __LINE__, std::strerror (errno));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,6 +37,10 @@ constexpr auto MAX_LOGS = 250;
|
|||||||
constexpr auto MAX_LOGS = 10000;
|
constexpr auto MAX_LOGS = 10000;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef CLASSIC
|
||||||
|
bool s_logUpdated = true;
|
||||||
|
#endif
|
||||||
|
|
||||||
/// \brief Message prefix
|
/// \brief Message prefix
|
||||||
static char const *const s_prefix[] = {
|
static char const *const s_prefix[] = {
|
||||||
[DEBUG] = "[DEBUG]",
|
[DEBUG] = "[DEBUG]",
|
||||||
@ -66,21 +70,62 @@ struct Message
|
|||||||
/// \brief Log messages
|
/// \brief Log messages
|
||||||
std::vector<Message> s_messages;
|
std::vector<Message> s_messages;
|
||||||
|
|
||||||
|
#ifndef NDS
|
||||||
/// \brief Log lock
|
/// \brief Log lock
|
||||||
platform::Mutex s_lock;
|
platform::Mutex s_lock;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void drawLog ()
|
void drawLog ()
|
||||||
{
|
{
|
||||||
|
#ifndef NDS
|
||||||
auto const lock = std::scoped_lock (s_lock);
|
auto const lock = std::scoped_lock (s_lock);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (s_messages.size () > MAX_LOGS)
|
#ifdef CLASSIC
|
||||||
|
if (!s_logUpdated)
|
||||||
|
return;
|
||||||
|
|
||||||
|
s_logUpdated = false;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
auto const maxLogs =
|
||||||
|
#ifdef CLASSIC
|
||||||
|
g_logConsole.windowHeight;
|
||||||
|
#else
|
||||||
|
MAX_LOGS;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (s_messages.size () > static_cast<unsigned> (maxLogs))
|
||||||
{
|
{
|
||||||
auto const begin = std::begin (s_messages);
|
auto const begin = std::begin (s_messages);
|
||||||
auto const end = std::next (begin, s_messages.size () - MAX_LOGS);
|
auto const end = std::next (begin, s_messages.size () - maxLogs);
|
||||||
s_messages.erase (begin, end);
|
s_messages.erase (begin, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CLASSIC
|
||||||
|
char const *const s_colors[] = {
|
||||||
|
[DEBUG] = "\x1b[33;1m", // yellow
|
||||||
|
[INFO] = "\x1b[37;1m", // white
|
||||||
|
[ERROR] = "\x1b[31;1m", // red
|
||||||
|
[COMMAND] = "\x1b[32;1m", // green
|
||||||
|
[RESPONSE] = "\x1b[36;1m", // cyan
|
||||||
|
};
|
||||||
|
|
||||||
|
auto it = std::begin (s_messages);
|
||||||
|
if (s_messages.size () > static_cast<unsigned> (g_logConsole.windowHeight))
|
||||||
|
it = std::next (it, s_messages.size () - g_logConsole.windowHeight);
|
||||||
|
|
||||||
|
consoleSelect (&g_logConsole);
|
||||||
|
while (it != std::end (s_messages))
|
||||||
|
{
|
||||||
|
std::fputs (s_colors[it->level], stdout);
|
||||||
|
std::fputs (it->message.c_str (), stdout);
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
std::fflush (stdout);
|
||||||
|
s_messages.clear ();
|
||||||
|
#else
|
||||||
ImVec4 const s_colors[] = {
|
ImVec4 const s_colors[] = {
|
||||||
[DEBUG] = ImVec4 (1.0f, 1.0f, 0.4f, 1.0f), // yellow
|
[DEBUG] = ImVec4 (1.0f, 1.0f, 0.4f, 1.0f), // yellow
|
||||||
[INFO] = ImGui::GetStyleColorVec4 (ImGuiCol_Text), // normal
|
[INFO] = ImGui::GetStyleColorVec4 (ImGuiCol_Text), // normal
|
||||||
@ -101,6 +146,7 @@ void drawLog ()
|
|||||||
// auto-scroll if scroll bar is at end
|
// auto-scroll if scroll bar is at end
|
||||||
if (ImGui::GetScrollY () >= ImGui::GetScrollMaxY ())
|
if (ImGui::GetScrollY () >= ImGui::GetScrollMaxY ())
|
||||||
ImGui::SetScrollHereY (1.0f);
|
ImGui::SetScrollHereY (1.0f);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void debug (char const *const fmt_, ...)
|
void debug (char const *const fmt_, ...)
|
||||||
@ -157,17 +203,25 @@ void addLog (LogLevel const level_, char const *const fmt_, va_list ap_)
|
|||||||
return;
|
return;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
thread_local static char buffer[1024];
|
#ifndef NDS
|
||||||
|
thread_local
|
||||||
|
#endif
|
||||||
|
static char buffer[1024];
|
||||||
|
|
||||||
std::vsnprintf (buffer, sizeof (buffer), fmt_, ap_);
|
std::vsnprintf (buffer, sizeof (buffer), fmt_, ap_);
|
||||||
buffer[sizeof (buffer) - 1] = '\0';
|
buffer[sizeof (buffer) - 1] = '\0';
|
||||||
|
|
||||||
|
#ifndef NDS
|
||||||
auto const lock = std::scoped_lock (s_lock);
|
auto const lock = std::scoped_lock (s_lock);
|
||||||
|
#endif
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
std::fprintf (stderr, "%s", s_prefix[level_]);
|
// std::fprintf (stderr, "%s", s_prefix[level_]);
|
||||||
std::fputs (buffer, stderr);
|
// std::fputs (buffer, stderr);
|
||||||
#endif
|
#endif
|
||||||
s_messages.emplace_back (level_, buffer);
|
s_messages.emplace_back (level_, buffer);
|
||||||
|
#ifdef CLASSIC
|
||||||
|
s_logUpdated = true;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void addLog (LogLevel const level_, std::string_view const message_)
|
void addLog (LogLevel const level_, std::string_view const message_)
|
||||||
@ -185,10 +239,15 @@ void addLog (LogLevel const level_, std::string_view const message_)
|
|||||||
c = '?';
|
c = '?';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef NDS
|
||||||
auto const lock = std::scoped_lock (s_lock);
|
auto const lock = std::scoped_lock (s_lock);
|
||||||
|
#endif
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
std::fprintf (stderr, "%s", s_prefix[level_]);
|
// std::fprintf (stderr, "%s", s_prefix[level_]);
|
||||||
std::fwrite (msg.data (), 1, msg.size (), stderr);
|
// std::fwrite (msg.data (), 1, msg.size (), stderr);
|
||||||
#endif
|
#endif
|
||||||
s_messages.emplace_back (level_, msg);
|
s_messages.emplace_back (level_, msg);
|
||||||
|
#ifdef CLASSIC
|
||||||
|
s_logUpdated = true;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -29,19 +29,25 @@
|
|||||||
|
|
||||||
int main (int argc_, char *argv_[])
|
int main (int argc_, char *argv_[])
|
||||||
{
|
{
|
||||||
|
#ifndef CLASSIC
|
||||||
IMGUI_CHECKVERSION ();
|
IMGUI_CHECKVERSION ();
|
||||||
ImGui::CreateContext ();
|
ImGui::CreateContext ();
|
||||||
|
#endif
|
||||||
|
|
||||||
if (!platform::init ())
|
if (!platform::init ())
|
||||||
{
|
{
|
||||||
|
#ifndef CLASSIC
|
||||||
ImGui::DestroyContext ();
|
ImGui::DestroyContext ();
|
||||||
|
#endif
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef CLASSIC
|
||||||
auto &style = ImGui::GetStyle ();
|
auto &style = ImGui::GetStyle ();
|
||||||
|
|
||||||
// turn off window rounding
|
// turn off window rounding
|
||||||
style.WindowRounding = 0.0f;
|
style.WindowRounding = 0.0f;
|
||||||
|
#endif
|
||||||
|
|
||||||
auto server = FtpServer::create (5000);
|
auto server = FtpServer::create (5000);
|
||||||
|
|
||||||
@ -56,5 +62,8 @@ int main (int argc_, char *argv_[])
|
|||||||
server.reset ();
|
server.reset ();
|
||||||
|
|
||||||
platform::exit ();
|
platform::exit ();
|
||||||
|
|
||||||
|
#ifndef CLASSIC
|
||||||
ImGui::DestroyContext ();
|
ImGui::DestroyContext ();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
130
source/nds/platform.cpp
Normal file
130
source/nds/platform.cpp
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
// ftpd is a server implementation based on the following:
|
||||||
|
// - RFC 959 (https://tools.ietf.org/html/rfc959)
|
||||||
|
// - RFC 3659 (https://tools.ietf.org/html/rfc3659)
|
||||||
|
// - suggested implementation details from https://cr.yp.to/ftp/filesystem.html
|
||||||
|
//
|
||||||
|
// Copyright (C) 2020 Michael Theall
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#include "platform.h"
|
||||||
|
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
|
#include <dswifi9.h>
|
||||||
|
#include <fat.h>
|
||||||
|
|
||||||
|
#include <netinet/in.h>
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
#ifndef CLASSIC
|
||||||
|
#error "NDS must be built in classic mode"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
PrintConsole g_statusConsole;
|
||||||
|
PrintConsole g_logConsole;
|
||||||
|
PrintConsole g_sessionConsole;
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
struct in_addr s_addr = {0};
|
||||||
|
}
|
||||||
|
|
||||||
|
bool platform::networkVisible ()
|
||||||
|
{
|
||||||
|
switch (Wifi_AssocStatus ())
|
||||||
|
{
|
||||||
|
case ASSOCSTATUS_DISCONNECTED:
|
||||||
|
case ASSOCSTATUS_CANNOTCONNECT:
|
||||||
|
s_addr.s_addr = 0;
|
||||||
|
Wifi_AutoConnect ();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ASSOCSTATUS_SEARCHING:
|
||||||
|
case ASSOCSTATUS_AUTHENTICATING:
|
||||||
|
case ASSOCSTATUS_ASSOCIATING:
|
||||||
|
case ASSOCSTATUS_ACQUIRINGDHCP:
|
||||||
|
s_addr.s_addr = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ASSOCSTATUS_ASSOCIATED:
|
||||||
|
if (!s_addr.s_addr)
|
||||||
|
s_addr = Wifi_GetIPInfo (nullptr, nullptr, nullptr, nullptr);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool platform::init ()
|
||||||
|
{
|
||||||
|
sassert (fatInitDefault (), "Failed to initialize fat");
|
||||||
|
|
||||||
|
videoSetMode (MODE_0_2D);
|
||||||
|
videoSetModeSub (MODE_0_2D);
|
||||||
|
|
||||||
|
vramSetBankA (VRAM_A_MAIN_BG);
|
||||||
|
vramSetBankC (VRAM_C_SUB_BG);
|
||||||
|
|
||||||
|
consoleInit (&g_statusConsole, 0, BgType_Text4bpp, BgSize_T_256x256, 4, 0, true, true);
|
||||||
|
g_logConsole = g_statusConsole;
|
||||||
|
consoleInit (&g_sessionConsole, 0, BgType_Text4bpp, BgSize_T_256x256, 4, 0, false, true);
|
||||||
|
|
||||||
|
consoleSetWindow (&g_statusConsole, 0, 0, 32, 1);
|
||||||
|
consoleSetWindow (&g_logConsole, 0, 1, 32, 23);
|
||||||
|
consoleSetWindow (&g_sessionConsole, 0, 0, 32, 24);
|
||||||
|
|
||||||
|
consoleDebugInit (DebugDevice_NOCASH);
|
||||||
|
std::setvbuf (stderr, nullptr, _IONBF, 0);
|
||||||
|
|
||||||
|
Wifi_InitDefault (INIT_ONLY);
|
||||||
|
Wifi_AutoConnect ();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool platform::loop ()
|
||||||
|
{
|
||||||
|
scanKeys ();
|
||||||
|
|
||||||
|
if (keysDown () & KEY_START)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void platform::render ()
|
||||||
|
{
|
||||||
|
swiWaitForVBlank ();
|
||||||
|
consoleSelect (&g_statusConsole);
|
||||||
|
std::printf ("\n%s %s%s",
|
||||||
|
STATUS_STRING,
|
||||||
|
s_addr.s_addr ? inet_ntoa (s_addr) : "Waiting on WiFi",
|
||||||
|
s_addr.s_addr ? ":5000" : "");
|
||||||
|
std::fflush (stdout);
|
||||||
|
drawLog ();
|
||||||
|
}
|
||||||
|
|
||||||
|
void platform::exit ()
|
||||||
|
{
|
||||||
|
info ("Press any key to exit\n");
|
||||||
|
render ();
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
swiWaitForVBlank ();
|
||||||
|
scanKeys ();
|
||||||
|
} while (!keysDown ());
|
||||||
|
}
|
@ -47,7 +47,7 @@ SockAddr::SockAddr (struct sockaddr const &addr_)
|
|||||||
std::memcpy (&m_addr, &addr_, sizeof (struct sockaddr_in));
|
std::memcpy (&m_addr, &addr_, sizeof (struct sockaddr_in));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#ifndef _3DS
|
#ifndef NO_IPV6
|
||||||
case AF_INET6:
|
case AF_INET6:
|
||||||
std::memcpy (&m_addr, &addr_, sizeof (struct sockaddr_in6));
|
std::memcpy (&m_addr, &addr_, sizeof (struct sockaddr_in6));
|
||||||
break;
|
break;
|
||||||
@ -114,7 +114,7 @@ std::uint16_t SockAddr::port () const
|
|||||||
case AF_INET:
|
case AF_INET:
|
||||||
return ntohs (reinterpret_cast<struct sockaddr_in const *> (&m_addr)->sin_port);
|
return ntohs (reinterpret_cast<struct sockaddr_in const *> (&m_addr)->sin_port);
|
||||||
|
|
||||||
#ifndef _3DS
|
#ifndef NO_IPV6
|
||||||
case AF_INET6:
|
case AF_INET6:
|
||||||
return ntohs (reinterpret_cast<struct sockaddr_in6 const *> (&m_addr)->sin6_port);
|
return ntohs (reinterpret_cast<struct sockaddr_in6 const *> (&m_addr)->sin6_port);
|
||||||
#endif
|
#endif
|
||||||
@ -130,12 +130,16 @@ char const *SockAddr::name (char *buffer_, std::size_t size_) const
|
|||||||
switch (m_addr.ss_family)
|
switch (m_addr.ss_family)
|
||||||
{
|
{
|
||||||
case AF_INET:
|
case AF_INET:
|
||||||
|
#ifdef NDS
|
||||||
|
return inet_ntoa (reinterpret_cast<struct sockaddr_in const *> (&m_addr)->sin_addr);
|
||||||
|
#else
|
||||||
return inet_ntop (AF_INET,
|
return inet_ntop (AF_INET,
|
||||||
&reinterpret_cast<struct sockaddr_in const *> (&m_addr)->sin_addr,
|
&reinterpret_cast<struct sockaddr_in const *> (&m_addr)->sin_addr,
|
||||||
buffer_,
|
buffer_,
|
||||||
size_);
|
size_);
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef _3DS
|
#ifndef NO_IPV6
|
||||||
case AF_INET6:
|
case AF_INET6:
|
||||||
return inet_ntop (AF_INET6,
|
return inet_ntop (AF_INET6,
|
||||||
&reinterpret_cast<struct sockaddr_in6 const *> (&m_addr)->sin6_addr,
|
&reinterpret_cast<struct sockaddr_in6 const *> (&m_addr)->sin6_addr,
|
||||||
@ -151,11 +155,15 @@ char const *SockAddr::name (char *buffer_, std::size_t size_) const
|
|||||||
|
|
||||||
char const *SockAddr::name () const
|
char const *SockAddr::name () const
|
||||||
{
|
{
|
||||||
#if defined(_3DS)
|
#ifdef NDS
|
||||||
|
return inet_ntoa (reinterpret_cast<struct sockaddr_in const *> (&m_addr)->sin_addr);
|
||||||
|
#else
|
||||||
|
#ifdef NO_IPV6
|
||||||
thread_local static char buffer[INET_ADDRSTRLEN];
|
thread_local static char buffer[INET_ADDRSTRLEN];
|
||||||
#else
|
#else
|
||||||
thread_local static char buffer[INET6_ADDRSTRLEN];
|
thread_local static char buffer[INET6_ADDRSTRLEN];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return name (buffer, sizeof (buffer));
|
return name (buffer, sizeof (buffer));
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -26,8 +26,6 @@
|
|||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include <poll.h>
|
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cerrno>
|
#include <cerrno>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
@ -42,8 +40,13 @@ Socket::~Socket ()
|
|||||||
if (m_connected)
|
if (m_connected)
|
||||||
info ("Closing connection to [%s]:%u\n", m_peerName.name (), m_peerName.port ());
|
info ("Closing connection to [%s]:%u\n", m_peerName.name (), m_peerName.port ());
|
||||||
|
|
||||||
|
#ifdef NDS
|
||||||
|
if (::closesocket (m_fd) != 0)
|
||||||
|
error ("closesocket: %s\n", std::strerror (errno));
|
||||||
|
#else
|
||||||
if (::close (m_fd) != 0)
|
if (::close (m_fd) != 0)
|
||||||
error ("close: %s\n", std::strerror (errno));
|
error ("close: %s\n", std::strerror (errno));
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
Socket::Socket (int const fd_) : m_fd (fd_), m_listening (false), m_connected (false)
|
Socket::Socket (int const fd_) : m_fd (fd_), m_listening (false), m_connected (false)
|
||||||
@ -77,11 +80,17 @@ UniqueSocket Socket::accept ()
|
|||||||
|
|
||||||
int Socket::atMark ()
|
int Socket::atMark ()
|
||||||
{
|
{
|
||||||
|
#ifdef NDS
|
||||||
|
errno = ENOSYS;
|
||||||
|
return -1;
|
||||||
|
#else
|
||||||
auto const rc = ::sockatmark (m_fd);
|
auto const rc = ::sockatmark (m_fd);
|
||||||
|
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
error ("sockatmark: %s\n", std::strerror (errno));
|
error ("sockatmark: %s\n", std::strerror (errno));
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Socket::bind (SockAddr const &addr_)
|
bool Socket::bind (SockAddr const &addr_)
|
||||||
@ -96,7 +105,7 @@ bool Socket::bind (SockAddr const &addr_)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#ifndef _3DS
|
#ifndef NO_IPV6
|
||||||
case AF_INET6:
|
case AF_INET6:
|
||||||
if (::bind (m_fd, addr_, sizeof (struct sockaddr_in6)) != 0)
|
if (::bind (m_fd, addr_, sizeof (struct sockaddr_in6)) != 0)
|
||||||
{
|
{
|
||||||
@ -171,11 +180,16 @@ bool Socket::shutdown (int const how_)
|
|||||||
|
|
||||||
bool Socket::setLinger (bool const enable_, std::chrono::seconds const time_)
|
bool Socket::setLinger (bool const enable_, std::chrono::seconds const time_)
|
||||||
{
|
{
|
||||||
|
#ifdef NDS
|
||||||
|
errno = ENOSYS;
|
||||||
|
return -1;
|
||||||
|
#else
|
||||||
struct linger linger;
|
struct linger linger;
|
||||||
linger.l_onoff = enable_;
|
linger.l_onoff = enable_;
|
||||||
linger.l_linger = time_.count ();
|
linger.l_linger = time_.count ();
|
||||||
|
|
||||||
if (::setsockopt (m_fd, SOL_SOCKET, SO_LINGER, &linger, sizeof (linger)) != 0)
|
auto const rc = ::setsockopt (m_fd, SOL_SOCKET, SO_LINGER, &linger, sizeof (linger));
|
||||||
|
if (rc != 0)
|
||||||
{
|
{
|
||||||
error ("setsockopt(SO_LINGER, %s, %lus): %s\n",
|
error ("setsockopt(SO_LINGER, %s, %lus): %s\n",
|
||||||
enable_ ? "on" : "off",
|
enable_ ? "on" : "off",
|
||||||
@ -185,10 +199,21 @@ bool Socket::setLinger (bool const enable_, std::chrono::seconds const time_)
|
|||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Socket::setNonBlocking (bool const nonBlocking_)
|
bool Socket::setNonBlocking (bool const nonBlocking_)
|
||||||
{
|
{
|
||||||
|
#ifdef NDS
|
||||||
|
unsigned long enable = nonBlocking_;
|
||||||
|
|
||||||
|
auto const rc = ::ioctl (m_fd, FIONBIO, &enable);
|
||||||
|
if (rc != 0)
|
||||||
|
{
|
||||||
|
error ("fcntl(FIONBIO, %d): %s\n", nonBlocking_, std::strerror (errno));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#else
|
||||||
auto flags = ::fcntl (m_fd, F_GETFL, 0);
|
auto flags = ::fcntl (m_fd, F_GETFL, 0);
|
||||||
if (flags == -1)
|
if (flags == -1)
|
||||||
{
|
{
|
||||||
@ -206,6 +231,7 @@ bool Socket::setNonBlocking (bool const nonBlocking_)
|
|||||||
error ("fcntl(F_SETFL, %d): %s\n", flags, std::strerror (errno));
|
error ("fcntl(F_SETFL, %d): %s\n", flags, std::strerror (errno));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -335,3 +361,61 @@ int Socket::poll (PollInfo *const info_,
|
|||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef NDS
|
||||||
|
extern "C" int poll (struct pollfd *const fds_, nfds_t const nfds_, int const timeout_)
|
||||||
|
{
|
||||||
|
fd_set readFds;
|
||||||
|
fd_set writeFds;
|
||||||
|
fd_set exceptFds;
|
||||||
|
|
||||||
|
FD_ZERO (&readFds);
|
||||||
|
FD_ZERO (&writeFds);
|
||||||
|
FD_ZERO (&exceptFds);
|
||||||
|
|
||||||
|
for (nfds_t i = 0; i < nfds_; ++i)
|
||||||
|
{
|
||||||
|
if (fds_[i].events & POLLIN)
|
||||||
|
FD_SET (fds_[i].fd, &readFds);
|
||||||
|
if (fds_[i].events & POLLOUT)
|
||||||
|
FD_SET (fds_[i].fd, &writeFds);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct timeval tv;
|
||||||
|
tv.tv_sec = timeout_ / 1000;
|
||||||
|
tv.tv_usec = (timeout_ % 1000) * 1000;
|
||||||
|
auto const rc = ::select (nfds_, &readFds, &writeFds, &exceptFds, &tv);
|
||||||
|
if (rc < 0)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
for (nfds_t i = 0; i < nfds_; ++i)
|
||||||
|
{
|
||||||
|
bool counted = false;
|
||||||
|
fds_[i].revents = 0;
|
||||||
|
|
||||||
|
if (FD_ISSET (fds_[i].fd, &readFds))
|
||||||
|
{
|
||||||
|
counted = true;
|
||||||
|
fds_[i].revents |= POLLIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FD_ISSET (fds_[i].fd, &writeFds))
|
||||||
|
{
|
||||||
|
counted = true;
|
||||||
|
fds_[i].revents |= POLLOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FD_ISSET (fds_[i].fd, &exceptFds))
|
||||||
|
{
|
||||||
|
counted = true;
|
||||||
|
fds_[i].revents |= POLLERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (counted)
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#ifndef CLASSIC
|
||||||
#include "imgui_deko3d.h"
|
#include "imgui_deko3d.h"
|
||||||
|
|
||||||
#include "fs.h"
|
#include "fs.h"
|
||||||
@ -528,3 +529,4 @@ void imgui::deko3d::render (dk::UniqueDevice &device_,
|
|||||||
// submit final commands
|
// submit final commands
|
||||||
queue_.submitCommands (cmdBuf_.finishList ());
|
queue_.submitCommands (cmdBuf_.finishList ());
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#ifndef CLASSIC
|
||||||
#include "imgui_nx.h"
|
#include "imgui_nx.h"
|
||||||
|
|
||||||
#include "imgui.h"
|
#include "imgui.h"
|
||||||
@ -25,8 +26,6 @@
|
|||||||
#include "fs.h"
|
#include "fs.h"
|
||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
|
|
||||||
#include <switch.h>
|
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
@ -1512,3 +1511,4 @@ void imgui::nx::exit ()
|
|||||||
// deinitialize applet hooks
|
// deinitialize applet hooks
|
||||||
appletUnhook (&s_appletHookCookie);
|
appletUnhook (&s_appletHookCookie);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
@ -63,7 +63,7 @@ void userAppInit ()
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
s_fd = nxlinkStdio ();
|
// s_fd = nxlinkStdioForDebug ();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
|
|
||||||
#include "fs.h"
|
#include "fs.h"
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
#include "imgui_deko3d.h"
|
#include "imgui_deko3d.h"
|
||||||
#include "imgui_nx.h"
|
#include "imgui_nx.h"
|
||||||
@ -29,8 +30,7 @@
|
|||||||
|
|
||||||
#include <zstd.h>
|
#include <zstd.h>
|
||||||
|
|
||||||
#include <switch.h>
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
|
||||||
#include <cerrno>
|
#include <cerrno>
|
||||||
@ -41,8 +41,17 @@
|
|||||||
#include <numeric>
|
#include <numeric>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
|
#ifdef CLASSIC
|
||||||
|
PrintConsole g_statusConsole;
|
||||||
|
PrintConsole g_logConsole;
|
||||||
|
PrintConsole g_sessionConsole;
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
#ifdef CLASSIC
|
||||||
|
in_addr_t s_addr = 0;
|
||||||
|
#else
|
||||||
/// \brief Texture index
|
/// \brief Texture index
|
||||||
enum TextureIndex
|
enum TextureIndex
|
||||||
{
|
{
|
||||||
@ -385,26 +394,52 @@ void deko3dExit ()
|
|||||||
s_depthMemBlock = nullptr;
|
s_depthMemBlock = nullptr;
|
||||||
s_device = nullptr;
|
s_device = nullptr;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/// \brief Draw time status
|
/// \brief Draw time status
|
||||||
void drawTimeStatus ()
|
void drawTimeStatus ()
|
||||||
{
|
{
|
||||||
|
#ifndef CLASSIC
|
||||||
auto const &io = ImGui::GetIO ();
|
auto const &io = ImGui::GetIO ();
|
||||||
auto const &style = ImGui::GetStyle ();
|
auto const &style = ImGui::GetStyle ();
|
||||||
|
#endif
|
||||||
|
|
||||||
// draw current timestamp
|
// draw current timestamp
|
||||||
char buffer[64];
|
char timeBuffer[64];
|
||||||
auto const now = std::time (nullptr);
|
auto const now = std::time (nullptr);
|
||||||
std::strftime (buffer, sizeof (buffer), "%H:%M:%S", std::localtime (&now));
|
std::strftime (timeBuffer, sizeof (timeBuffer), "%H:%M:%S", std::localtime (&now));
|
||||||
|
|
||||||
|
#ifdef CLASSIC
|
||||||
|
static std::string statusString;
|
||||||
|
|
||||||
|
std::string newStatusString (256, '\0');
|
||||||
|
newStatusString.resize (std::sprintf (&newStatusString[0],
|
||||||
|
"\x1b[0;0H\x1b[32;1m%s \x1b[36;1m%s%s \x1b[37;1m%s\x1b[K",
|
||||||
|
STATUS_STRING,
|
||||||
|
s_addr ? inet_ntoa (in_addr{s_addr}) : "Waiting",
|
||||||
|
s_addr ? ":5000" : "",
|
||||||
|
timeBuffer));
|
||||||
|
|
||||||
|
if (newStatusString != statusString)
|
||||||
|
{
|
||||||
|
statusString = std::move (newStatusString);
|
||||||
|
|
||||||
|
consoleSelect (&g_statusConsole);
|
||||||
|
std::fputs (statusString.c_str (), stdout);
|
||||||
|
std::fflush (stdout);
|
||||||
|
}
|
||||||
|
#else
|
||||||
ImGui::GetForegroundDrawList ()->AddText (
|
ImGui::GetForegroundDrawList ()->AddText (
|
||||||
ImVec2 (io.DisplaySize.x - 240.0f, style.FramePadding.y),
|
ImVec2 (io.DisplaySize.x - 240.0f, style.FramePadding.y),
|
||||||
ImGui::GetColorU32 (ImGuiCol_Text),
|
ImGui::GetColorU32 (ImGuiCol_Text),
|
||||||
buffer);
|
timeBuffer);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Draw network status
|
/// \brief Draw network status
|
||||||
void drawNetworkStatus ()
|
void drawNetworkStatus ()
|
||||||
{
|
{
|
||||||
|
#ifndef CLASSIC
|
||||||
TextureIndex netIcon = AIRPLANE_ICON;
|
TextureIndex netIcon = AIRPLANE_ICON;
|
||||||
|
|
||||||
NifmInternetConnectionType type;
|
NifmInternetConnectionType type;
|
||||||
@ -447,11 +482,13 @@ void drawNetworkStatus ()
|
|||||||
ImVec2 (0, 0),
|
ImVec2 (0, 0),
|
||||||
ImVec2 (1, 1),
|
ImVec2 (1, 1),
|
||||||
ImGui::GetColorU32 (ImGuiCol_Text));
|
ImGui::GetColorU32 (ImGuiCol_Text));
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Draw power status
|
/// \brief Draw power status
|
||||||
void drawPowerStatus ()
|
void drawPowerStatus ()
|
||||||
{
|
{
|
||||||
|
#ifndef CLASSIC
|
||||||
std::uint32_t batteryCharge = 0;
|
std::uint32_t batteryCharge = 0;
|
||||||
psmGetBatteryChargePercentage (&batteryCharge);
|
psmGetBatteryChargePercentage (&batteryCharge);
|
||||||
|
|
||||||
@ -480,8 +517,10 @@ void drawPowerStatus ()
|
|||||||
|
|
||||||
char buffer[16];
|
char buffer[16];
|
||||||
std::sprintf (buffer, "%3u%%", batteryCharge);
|
std::sprintf (buffer, "%3u%%", batteryCharge);
|
||||||
|
|
||||||
ImGui::GetForegroundDrawList ()->AddText (
|
ImGui::GetForegroundDrawList ()->AddText (
|
||||||
ImVec2 (x1 - 70.0f, y1), ImGui::GetColorU32 (ImGuiCol_Text), buffer);
|
ImVec2 (x1 - 70.0f, y1), ImGui::GetColorU32 (ImGuiCol_Text), buffer);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Draw status
|
/// \brief Draw status
|
||||||
@ -495,10 +534,21 @@ void drawStatus ()
|
|||||||
|
|
||||||
bool platform::init ()
|
bool platform::init ()
|
||||||
{
|
{
|
||||||
|
#ifdef CLASSIC
|
||||||
|
consoleInit (&g_statusConsole);
|
||||||
|
consoleInit (&g_logConsole);
|
||||||
|
consoleInit (&g_sessionConsole);
|
||||||
|
|
||||||
|
consoleSetWindow (&g_statusConsole, 0, 0, 80, 1);
|
||||||
|
consoleSetWindow (&g_logConsole, 0, 1, 80, 29);
|
||||||
|
consoleSetWindow (&g_sessionConsole, 0, 30, 80, 15);
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
std::setvbuf (stderr, nullptr, _IOLBF, 0);
|
std::setvbuf (stderr, nullptr, _IOLBF, 0);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef CLASSIC
|
||||||
if (!imgui::nx::init ())
|
if (!imgui::nx::init ())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -511,6 +561,7 @@ bool platform::init ()
|
|||||||
s_imageDescriptors[0],
|
s_imageDescriptors[0],
|
||||||
dkMakeTextureHandle (0, 0),
|
dkMakeTextureHandle (0, 0),
|
||||||
FB_NUM);
|
FB_NUM);
|
||||||
|
#endif
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -523,6 +574,11 @@ bool platform::networkVisible ()
|
|||||||
if (R_FAILED (nifmGetInternetConnectionStatus (&type, &wifi, &status)))
|
if (R_FAILED (nifmGetInternetConnectionStatus (&type, &wifi, &status)))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
#ifdef CLASSIC
|
||||||
|
if (!s_addr)
|
||||||
|
s_addr = gethostid ();
|
||||||
|
#endif
|
||||||
|
|
||||||
return status == NifmInternetConnectionStatus_Connected;
|
return status == NifmInternetConnectionStatus_Connected;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -537,6 +593,7 @@ bool platform::loop ()
|
|||||||
if (keysDown & KEY_PLUS)
|
if (keysDown & KEY_PLUS)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
#ifndef CLASSIC
|
||||||
imgui::nx::newFrame ();
|
imgui::nx::newFrame ();
|
||||||
ImGui::NewFrame ();
|
ImGui::NewFrame ();
|
||||||
|
|
||||||
@ -554,6 +611,7 @@ bool platform::loop ()
|
|||||||
imgui::deko3d::makeTextureID (dkMakeTextureHandle (1, 1)),
|
imgui::deko3d::makeTextureID (dkMakeTextureHandle (1, 1)),
|
||||||
ImVec2 (x1, y1),
|
ImVec2 (x1, y1),
|
||||||
ImVec2 (x2, y2));
|
ImVec2 (x2, y2));
|
||||||
|
#endif
|
||||||
|
|
||||||
drawStatus ();
|
drawStatus ();
|
||||||
|
|
||||||
@ -562,6 +620,12 @@ bool platform::loop ()
|
|||||||
|
|
||||||
void platform::render ()
|
void platform::render ()
|
||||||
{
|
{
|
||||||
|
#ifdef CLASSIC
|
||||||
|
drawLog ();
|
||||||
|
consoleUpdate (&g_statusConsole);
|
||||||
|
consoleUpdate (&g_logConsole);
|
||||||
|
consoleUpdate (&g_sessionConsole);
|
||||||
|
#else
|
||||||
ImGui::Render ();
|
ImGui::Render ();
|
||||||
|
|
||||||
auto &io = ImGui::GetIO ();
|
auto &io = ImGui::GetIO ();
|
||||||
@ -595,10 +659,16 @@ void platform::render ()
|
|||||||
|
|
||||||
// present image
|
// present image
|
||||||
s_queue.presentImage (s_swapchain, slot);
|
s_queue.presentImage (s_swapchain, slot);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void platform::exit ()
|
void platform::exit ()
|
||||||
{
|
{
|
||||||
|
#ifdef CLASSIC
|
||||||
|
consoleExit (&g_sessionConsole);
|
||||||
|
consoleExit (&g_logConsole);
|
||||||
|
consoleExit (&g_statusConsole);
|
||||||
|
#else
|
||||||
imgui::nx::exit ();
|
imgui::nx::exit ();
|
||||||
|
|
||||||
// wait for queue to be idle
|
// wait for queue to be idle
|
||||||
@ -606,6 +676,7 @@ void platform::exit ()
|
|||||||
|
|
||||||
imgui::deko3d::exit ();
|
imgui::deko3d::exit ();
|
||||||
deko3dExit ();
|
deko3dExit ();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
Loading…
Reference in New Issue
Block a user