commit c5bcadc8c4233eb964690f5a0694a75baa7e003b Author: Maschell Date: Wed Oct 14 13:54:25 2020 +0200 WIP diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d1cd803 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +.idea/ +cmake-build-debug/ +build/ +*.rpx +*.elf +CMakeLists.txt diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..dbcc60d --- /dev/null +++ b/Makefile @@ -0,0 +1,135 @@ +#------------------------------------------------------------------------------- +.SUFFIXES: +#------------------------------------------------------------------------------- + +ifeq ($(strip $(DEVKITPRO)),) +$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=/devkitpro") +endif + +TOPDIR ?= $(CURDIR) + +include $(DEVKITPRO)/wut/share/wut_rules + +#------------------------------------------------------------------------------- +# TARGET is the name of the output +# BUILD is the directory where object files & intermediate files will be placed +# SOURCES is a list of directories containing source code +# DATA is a list of directories containing data files +# INCLUDES is a list of directories containing header files +#------------------------------------------------------------------------------- +TARGET := $(notdir $(CURDIR)) +BUILD := build +SOURCES := source +DATA := data +INCLUDES := include + +#------------------------------------------------------------------------------- +# options for code generation +#------------------------------------------------------------------------------- +CFLAGS := -g -Wall -O2 -ffunction-sections \ + $(MACHDEP) + +CFLAGS += $(INCLUDE) -D__WIIU__ -D__WUT__ + +CXXFLAGS := $(CFLAGS) + +ASFLAGS := -g $(ARCH) +LDFLAGS = -g $(ARCH) $(RPXSPECS) -Wl,-Map,$(notdir $*.map) + +LIBS := -lwut -liosuhax + +#------------------------------------------------------------------------------- +# list of directories containing libraries, this must be the top level +# containing include and lib +#------------------------------------------------------------------------------- +LIBDIRS := $(PORTLIBS) $(WUT_ROOT) $(WUT_ROOT)/usr + + +#------------------------------------------------------------------------------- +# 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_BIN := $(addsuffix .o,$(BINFILES)) +export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) +export OFILES := $(OFILES_BIN) $(OFILES_SRC) +export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES))) + +export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + -I$(CURDIR)/$(BUILD) + +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) + +.PHONY: $(BUILD) clean all + +#------------------------------------------------------------------------------- +all: $(BUILD) + +$(BUILD): + @[ -d $@ ] || mkdir -p $@ + @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile + +#------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(BUILD) $(TARGET).rpx $(TARGET).elf + +#------------------------------------------------------------------------------- +else +.PHONY: all + +DEPENDS := $(OFILES:.o=.d) + +#------------------------------------------------------------------------------- +# main targets +#------------------------------------------------------------------------------- +all : $(OUTPUT).rpx + +$(OUTPUT).rpx : $(OUTPUT).elf +$(OUTPUT).elf : $(OFILES) + +$(OFILES_SRC) : $(HFILES_BIN) + +#------------------------------------------------------------------------------- +# you need a rule like this for each extension you use as binary data +#------------------------------------------------------------------------------- +%.bin.o %_bin.h : %.bin +#------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + +-include $(DEPENDS) + +#------------------------------------------------------------------------------- +endif +#------------------------------------------------------------------------------- diff --git a/source/ScreenUtils.cpp b/source/ScreenUtils.cpp new file mode 100644 index 0000000..b593368 --- /dev/null +++ b/source/ScreenUtils.cpp @@ -0,0 +1,48 @@ +/**************************************************************************** + * Copyright (C) 2018 Maschell + * + * 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 . + ****************************************************************************/ +#include +#include "ScreenUtils.h" + +void ScreenUtils::printTextOnScreen(ConsoleScreenID screen, int x, int y, const char *msg) { + if (!msg) { + return; + } + if (screen != CONSOLE_SCREEN_DRC) { // Draw TV if it's not DRC exclusive. + OSScreenPutFontEx(SCREEN_TV, x, y, msg); + } + if (screen != CONSOLE_SCREEN_TV) { // Draw DRC if it's not TV exclusive. + OSScreenPutFontEx(SCREEN_DRC, x, y, msg); + } +} + +void ScreenUtils::OSScreenClear(ConsoleScreenID screen, uint32_t color) { + if (screen != CONSOLE_SCREEN_DRC) { // Clear TV if it's not DRC exclusive. + OSScreenClearBufferEx(SCREEN_TV, color); + } + if (screen != CONSOLE_SCREEN_TV) { // Clear DRC if it's not TV exclusive. + OSScreenClearBufferEx(SCREEN_DRC, color); + } +} + +void ScreenUtils::flipBuffers(ConsoleScreenID screen) { + if (screen != CONSOLE_SCREEN_DRC) { // Flip TV buffer if it's not DRC exclusive. + OSScreenFlipBuffersEx(SCREEN_TV); + } + if (screen != CONSOLE_SCREEN_TV) { // Flip DRC buffer if it's not TV exclusive. + OSScreenFlipBuffersEx(SCREEN_DRC); + } +} diff --git a/source/ScreenUtils.h b/source/ScreenUtils.h new file mode 100644 index 0000000..3c1ad44 --- /dev/null +++ b/source/ScreenUtils.h @@ -0,0 +1,55 @@ +/**************************************************************************** + * Copyright (C) 2018-2020 Maschell + * + * 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 . + ****************************************************************************/ +#pragma once + +//! Defines the ID of a display usable with OSScreen. +typedef enum ConsoleScreenID { + //! Represents the TV connected to the system. + CONSOLE_SCREEN_TV = 0, + //! Represents the screen in the DRC (gamepad). + CONSOLE_SCREEN_DRC = 1, + //! Represents both screens + CONSOLE_SCREEN_BOTH = 2, +} ConsoleScreenID; + +class ScreenUtils { +public: + /** + Clears the screen for the given screens + \param screen defines on which screens should be printed + \param x defines the x position (character position) where the text should be printed + \param y defines on which line the text should be printed + \param msg C string that contains the text to be printed. + **/ + static void printTextOnScreen(ConsoleScreenID screen, int x, int y, const char *msg); + + /** + Clears the screen for the given screens + \param screen defines which screens should be cleared + **/ + static void OSScreenClear(ConsoleScreenID screen, uint32_t i); + + /** + Flips the buffer for the given screens + \param screen defines which screens should be flipped. + **/ + static void flipBuffers(ConsoleScreenID screen); + +private: + ScreenUtils() = default; + ~ScreenUtils() = default; +}; \ No newline at end of file diff --git a/source/WiiUScreen.cpp b/source/WiiUScreen.cpp new file mode 100644 index 0000000..35937ba --- /dev/null +++ b/source/WiiUScreen.cpp @@ -0,0 +1,91 @@ +#include "WiiUScreen.h" +#include "ScreenUtils.h" +#include +#include +#include + +void *WiiUScreen::sBufferTV = nullptr; +void *WiiUScreen::sBufferDRC = nullptr; +uint32_t WiiUScreen::sBufferSizeTV = 0; +uint32_t WiiUScreen::sBufferSizeDRC = 0; +bool WiiUScreen::sConsoleHasForeground = true; +uint32_t WiiUScreen::consoleColor = 0x993333FF; +uint32_t WiiUScreen::consoleCursorY = 0; + + +uint32_t WiiUScreen::ProcCallbackAcquired(void *context) { + MEMHeapHandle heap = MEMGetBaseHeapHandle(MEM_BASE_HEAP_MEM1); + if (sBufferSizeTV) { + sBufferTV = MEMAllocFromFrmHeapEx(heap, sBufferSizeTV, 4); + } + + if (sBufferSizeDRC) { + sBufferDRC = MEMAllocFromFrmHeapEx(heap, sBufferSizeDRC, 4); + } + + sConsoleHasForeground = true; + OSScreenSetBufferEx(SCREEN_TV, sBufferTV); + OSScreenSetBufferEx(SCREEN_DRC, sBufferDRC); + return 0; +} + +uint32_t WiiUScreen::ProcCallbackReleased(void *context) { + MEMHeapHandle heap = MEMGetBaseHeapHandle(MEM_BASE_HEAP_MEM1); + MEMFreeByStateToFrmHeap(heap, CONSOLE_FRAME_HEAP_TAG); + sConsoleHasForeground = FALSE; + return 0; +} + +bool WiiUScreen::Init() { + OSScreenInit(); + sBufferSizeTV = OSScreenGetBufferSizeEx(SCREEN_TV); + sBufferSizeDRC = OSScreenGetBufferSizeEx(SCREEN_DRC); + + WiiUScreen::ProcCallbackAcquired(nullptr); + OSScreenEnableEx(SCREEN_TV, 1); + OSScreenEnableEx(SCREEN_DRC, 1); + + ScreenUtils::OSScreenClear(CONSOLE_SCREEN_BOTH, WiiUScreen::consoleColor); + + ProcUIRegisterCallback(PROCUI_CALLBACK_ACQUIRE, WiiUScreen::ProcCallbackAcquired, nullptr, 100); + ProcUIRegisterCallback(PROCUI_CALLBACK_RELEASE, WiiUScreen::ProcCallbackReleased, nullptr, 100); + return true; +} + +void WiiUScreen::DeInit() { + if (sConsoleHasForeground) { + OSScreenShutdown(); + WiiUScreen::ProcCallbackReleased(NULL); + } +} + +void WiiUScreen::drawLinef(const char *fmt, ...) { + char *buf = (char *) MEMAllocFromDefaultHeapEx(PRINTF_BUFFER_LENGTH, 4); + va_list va; + + if (!buf) { + return; + } + + va_start(va, fmt); + vsnprintf(buf, PRINTF_BUFFER_LENGTH, fmt, va); + + WiiUScreen::drawLine(buf); + + MEMFreeToDefaultHeap(buf); + va_end(va); +} + +void WiiUScreen::drawLine(const char *msg) { + ScreenUtils::printTextOnScreen(CONSOLE_SCREEN_BOTH, 0, consoleCursorY++, msg); +} + + +void WiiUScreen::flush() { + ScreenUtils::flipBuffers(CONSOLE_SCREEN_BOTH); +} + +void WiiUScreen::clearScreen() { + ScreenUtils::OSScreenClear(CONSOLE_SCREEN_BOTH, WiiUScreen::consoleColor); + consoleCursorY = 0; +} diff --git a/source/WiiUScreen.h b/source/WiiUScreen.h new file mode 100644 index 0000000..8e2e5cb --- /dev/null +++ b/source/WiiUScreen.h @@ -0,0 +1,45 @@ +#pragma once + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#define NUM_LINES (16) +#define LINE_LENGTH (128) +#define CONSOLE_FRAME_HEAP_TAG (0x000DECAF) +#define PRINTF_BUFFER_LENGTH 2048 + + +class WiiUScreen { + +public: + static uint32_t ProcCallbackAcquired(void *context); + + static uint32_t ProcCallbackReleased(void *context); + + static bool Init(); + + static void DeInit(); + + static void drawLinef(const char *fmt, ...); + + static void drawLine(const char *fmt); + static void flush(); + + static void clearScreen(); + +private: + static void *sBufferTV, *sBufferDRC; + static uint32_t sBufferSizeTV, sBufferSizeDRC; + static bool sConsoleHasForeground; + static uint32_t consoleColor; + static uint32_t consoleCursorY; +}; \ No newline at end of file diff --git a/source/logger.h b/source/logger.h new file mode 100644 index 0000000..9f3243b --- /dev/null +++ b/source/logger.h @@ -0,0 +1,23 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#define __FILENAME_X__ (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__) +#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILENAME_X__) + +#define DEBUG_FUNCTION_LINE(FMT, ARGS...)do { \ + WHBLogPrintf("[%23s]%30s@L%04d: " FMT "",__FILENAME__,__FUNCTION__, __LINE__, ## ARGS); \ + } while (0); + +#define DEBUG_FUNCTION_LINE_WRITE(FMT, ARGS...)do { \ + WHBLogWritef("[%23s]%30s@L%04d: " FMT "",__FILENAME__,__FUNCTION__, __LINE__, ## ARGS); \ + } while (0); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/source/main.cpp b/source/main.cpp new file mode 100644 index 0000000..c9f691e --- /dev/null +++ b/source/main.cpp @@ -0,0 +1,105 @@ +#include +#include +#include +#include + +#include +#include + +#include +#include +#include "WiiUScreen.h" +#include "logger.h" + +void initIOSUHax(); + +void deInitIOSUHax(); + +int +hello_thread() { + int last_tm_sec = -1; + uint32_t ip = 0; + + WHBLogPrintf("Hello!"); + + if (!nn::ac::GetAssignedAddress(&ip)) { + WHBLogPrintf("GetAssignedAddress failed!"); + } + + WHBLogPrintf("My IP is: %u.%u.%u.%u", + (ip >> 24) & 0xFF, + (ip >> 16) & 0xFF, + (ip >> 8) & 0xFF, + (ip >> 0) & 0xFF); + + while (WHBProcIsRunning()) { + OSCalendarTime tm; + OSTicksToCalendarTime(OSGetTime(), &tm); + + if (tm.tm_sec != last_tm_sec) { + WiiUScreen::clearScreen(); + WiiUScreen::drawLine("Hello World from a std::thread!"); + WiiUScreen::drawLinef("%02d/%02d/%04d %02d:%02d:%02d I'm still here.", + tm.tm_mday, tm.tm_mon + 1, tm.tm_year, + tm.tm_hour, tm.tm_min, tm.tm_sec); + last_tm_sec = tm.tm_sec; + WiiUScreen::flush(); + } + + OSSleepTicks(OSMillisecondsToTicks(100)); + } + + WHBLogPrintf("Exiting... good bye."); + OSSleepTicks(OSMillisecondsToTicks(1000)); + return 0; +} + +int main(int argc, char **argv) { + WHBProcInit(); + WiiUScreen::Init(); + + initIOSUHax(); + + hello_thread(); + + deInitIOSUHax(); + + WiiUScreen::DeInit(); + WHBProcShutdown(); + + return 0; +} + +int sFSAFd = -1; +bool sIosuhaxMount = false; + +void initIOSUHax() { + sIosuhaxMount = false; + auto fsaFd = -1; + int res = IOSUHAX_Open(nullptr); + if (res < 0) { + DEBUG_FUNCTION_LINE("IOSUHAX_open failed"); + OSFatal("IOSUHAX_open failed, please start this installer with an CFW"); + } else { + sIosuhaxMount = true; + sFSAFd = IOSUHAX_FSA_Open(); + if (fsaFd < 0) { + DEBUG_FUNCTION_LINE("IOSUHAX_FSA_Open failed"); + } else { + mount_fs("storage_slc_installer", fsaFd, nullptr, "/vol/system"); + mount_fs("storage_mlc_installer", fsaFd, nullptr, "/vol/storage_mlc01"); + } + DEBUG_FUNCTION_LINE("IOSUHAX done"); + } +} + +void deInitIOSUHax() { + if (sIosuhaxMount) { + unmount_fs("storage_slc_installer"); + unmount_fs("storage_mlc_installer"); + if (sFSAFd >= 0) { + IOSUHAX_FSA_Close(sFSAFd); + } + IOSUHAX_Close(); + } +} \ No newline at end of file