From 1cc3040d86c9003b18109d131dc1b6ea8c54f917 Mon Sep 17 00:00:00 2001 From: Phillip Stephens Date: Wed, 16 Apr 2025 02:16:45 -0700 Subject: [PATCH] Initial CARD stubout --- cmake/aurora_card.cmake | 8 + cmake/kabufuda.cmake | 57 +++++++ include/dolphin/card.h | 181 +++++++++++++++++++++ lib/dolphin/card.cpp | 347 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 593 insertions(+) create mode 100644 cmake/aurora_card.cmake create mode 100644 cmake/kabufuda.cmake create mode 100644 include/dolphin/card.h create mode 100644 lib/dolphin/card.cpp diff --git a/cmake/aurora_card.cmake b/cmake/aurora_card.cmake new file mode 100644 index 0000000..acb0c7a --- /dev/null +++ b/cmake/aurora_card.cmake @@ -0,0 +1,8 @@ +add_library(aurora_card STATIC + lib/dolphin/card.cpp +) + +add_library(aurora::card ALIAS aurora_card) + +target_link_libraries(aurora_card PUBLIC aurora::core) +target_include_directories(aurora_card PRIVATE include) diff --git a/cmake/kabufuda.cmake b/cmake/kabufuda.cmake new file mode 100644 index 0000000..9df5a91 --- /dev/null +++ b/cmake/kabufuda.cmake @@ -0,0 +1,57 @@ +add_library(kabufuda STATIC + include/kabufuda/Constants.hpp + include/kabufuda/AsyncIO.hpp + include/kabufuda/BlockAllocationTable.hpp lib/kabufuda/BlockAllocationTable.cpp + include/kabufuda/Card.hpp lib/kabufuda/Card.cpp + include/kabufuda/Directory.hpp lib/kabufuda/Directory.cpp + include/kabufuda/File.hpp lib/kabufuda/File.cpp + include/kabufuda/Util.hpp lib/kabufuda/Util.cpp + include/kabufuda/SRAM.hpp lib/kabufuda/SRAM.cpp +) + +if (WIN32) + if (MSVC) + target_compile_options(kabufuda PRIVATE + # Enforce various standards compliant behavior. + $<$:/permissive-> + + # Enable standard volatile semantics. + $<$:/volatile:iso> + + # Reports the proper value for the __cplusplus preprocessor macro. + $<$:/Zc:__cplusplus> + + # Use latest C++ standard. + $<$:/std:c++latest> + ) + if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") + # Flags for MSVC (not clang-cl) + target_compile_options(kabufuda PRIVATE + # Allow constexpr variables to have explicit external linkage. + $<$:/Zc:externConstexpr> + + # Assume that new throws exceptions, allowing better code generation. + $<$:/Zc:throwingNew> + ) + endif () + endif () + + target_sources(kabufuda PRIVATE + lib/kabufuda/AsyncIOWin32.cpp + ) +elseif (NX OR EMSCRIPTEN) + target_sources(kabufuda PRIVATE + lib/kabufuda/AsyncIONX.cpp + ) +else () + target_sources(kabufuda PRIVATE + lib/kabufuda/AsyncIOPosix.cpp + ) + if (NOT APPLE) + target_link_libraries(kabufuda PUBLIC rt) + endif () +endif () + +target_include_directories(kabufuda PUBLIC $) + +add_subdirectory(test) diff --git a/include/dolphin/card.h b/include/dolphin/card.h new file mode 100644 index 0000000..84da03b --- /dev/null +++ b/include/dolphin/card.h @@ -0,0 +1,181 @@ +#ifndef _DOLPHIN_CARD +#define _DOLPHIN_CARD + +#include "dolphin/types.h" + +#ifdef __cplusplus +extern "C" { +#endif +#define CARD_ENCODE_ANSI 0u +#define CARD_ENCODE_SJIS 1u + +/* Sizes */ +#define CARD_WORKAREA_SIZE (5 * 8 * 1024) +#define CARD_READ_SIZE 512 +#define CARD_MAX_FILE 127 +#define CARD_COMMENT_SIZE 64 +#define CARD_FILENAME_MAX 32 +#define CARD_ICON_MAX 8 +#define CARD_ICON_WIDTH 32 +#define CARD_ICON_HEIGHT 32 +#define CARD_BANNER_WIDTH 96 +#define CARD_BANNER_HEIGHT 32 + +/* Icon animation */ +#define CARD_MODE_NORMAL 0 +#define CARD_MODE_FAST 1 + +#define CARDGetBannerFormat(stat) (((stat)->bannerFormat) & CARD_STAT_BANNER_MASK) +#define CARDGetIconAnim(stat) (((stat)->bannerFormat) & CARD_STAT_ANIM_MASK) +#define CARDGetIconFormat(stat, n) (((stat)->iconFormat >> (2 * (n))) & CARD_STAT_ICON_MASK) +#define CARDGetIconSpeed(stat, n) (((stat)->iconSpeed >> (2 * (n))) & CARD_STAT_SPEED_MASK) +#define CARDSetBannerFormat(stat, f) \ + ((stat)->bannerFormat = (u8)(((stat)->bannerFormat & ~CARD_STAT_BANNER_MASK) | (f))) +#define CARDSetIconAnim(stat, f) \ + ((stat)->bannerFormat = (u8)(((stat)->bannerFormat & ~CARD_STAT_ANIM_MASK) | (f))) +#define CARDSetIconFormat(stat, n, f) \ + ((stat)->iconFormat = \ + (u16)(((stat)->iconFormat & ~(CARD_STAT_ICON_MASK << (2 * (n)))) | ((f) << (2 * (n))))) +#define CARDSetIconSpeed(stat, n, f) \ + ((stat)->iconSpeed = \ + (u16)(((stat)->iconSpeed & ~(CARD_STAT_SPEED_MASK << (2 * (n)))) | ((f) << (2 * (n))))) +#define CARDSetIconAddress(stat, addr) ((stat)->iconAddr = (u32)(addr)) +#define CARDSetCommentAddress(stat, addr) ((stat)->commentAddr = (u32)(addr)) +#define CARDGetFileNo(fileInfo) ((fileInfo)->fileNo) + +#define CARD_RESULT_UNLOCKED 1 +#define CARD_RESULT_READY 0 +#define CARD_RESULT_BUSY -1 +#define CARD_RESULT_WRONGDEVICE -2 +#define CARD_RESULT_NOCARD -3 +#define CARD_RESULT_NOFILE -4 +#define CARD_RESULT_IOERROR -5 +#define CARD_RESULT_BROKEN -6 +#define CARD_RESULT_EXIST -7 +#define CARD_RESULT_NOENT -8 +#define CARD_RESULT_INSSPACE -9 +#define CARD_RESULT_NOPERM -10 +#define CARD_RESULT_LIMIT -11 +#define CARD_RESULT_NAMETOOLONG -12 +#define CARD_RESULT_ENCODING -13 +#define CARD_RESULT_CANCELED -14 +#define CARD_RESULT_FATAL_ERROR -128 + +#define CARD_STAT_ICON_NONE 0 +#define CARD_STAT_ICON_C8 1 +#define CARD_STAT_ICON_RGB5A3 2 +#define CARD_STAT_ICON_MASK 3 + +#define CARD_STAT_BANNER_NONE 0 +#define CARD_STAT_BANNER_C8 1 +#define CARD_STAT_BANNER_RGB5A3 2 +#define CARD_STAT_BANNER_MASK 3 + +#define CARD_STAT_ANIM_LOOP 0x00 +#define CARD_STAT_ANIM_BOUNCE 0x04 +#define CARD_STAT_ANIM_MASK 0x04 + +#define CARD_STAT_SPEED_END 0 +#define CARD_STAT_SPEED_FAST 1 +#define CARD_STAT_SPEED_MIDDLE 2 +#define CARD_STAT_SPEED_SLOW 3 +#define CARD_STAT_SPEED_MASK 3 + +#define CARD_ATTR_PUBLIC 0x04u +#define CARD_ATTR_NO_COPY 0x08u +#define CARD_ATTR_NO_MOVE 0x10u +#define CARD_ATTR_GLOBAL 0x20u +#define CARD_ATTR_COMPANY 0x40u + +typedef struct CARDFileInfo { + s32 chan; + s32 fileNo; + + s32 offset; + s32 length; + u16 iBlock; + u16 __padding; +} CARDFileInfo; + +typedef struct CARDStat { + char fileName[CARD_FILENAME_MAX]; + u32 length; + u32 time; // seconds since 01/01/2000 midnight + u8 gameName[4]; + u8 company[2]; + + u8 bannerFormat; + u8 __padding; + u32 iconAddr; // offset to the banner, bannerTlut, icon, iconTlut data set. + u16 iconFormat; + u16 iconSpeed; + u32 commentAddr; // offset to the pair of 32 byte character strings. + + u32 offsetBanner; + u32 offsetBannerTlut; + u32 offsetIcon[CARD_ICON_MAX]; + u32 offsetIconTlut; + u32 offsetData; +} CARDStat; + +typedef void (*CARDCallback)(s32 chan, s32 result); + +#ifdef TARGET_PC +void CARDInit(const char* memcardFile, const char* game, const char* maker); +void CARDSetGameAndMaker(s32 chan, const char* game, const char* maker); +#else +void CARDInit(void); +#endif +BOOL CARDGetFastMode(void); +BOOL CARDSetFastMode(BOOL enable); + +s32 CARDCheck(s32 chan); +s32 CARDCheckAsync(s32 chan, CARDCallback callback); +s32 CARDCheckEx(s32 chan, s32* xferBytes); +s32 CARDCheckExAsync(s32 chan, s32* xferBytes, CARDCallback callback); +s32 CARDCreate(s32 chan, const char* fileName, u32 size, CARDFileInfo* fileInfo); +s32 CARDCreateAsync(s32 chan, const char* fileName, u32 size, CARDFileInfo* fileInfo, + CARDCallback callback); +s32 CARDDelete(s32 chan, const char* fileName); +s32 CARDDeleteAsync(s32 chan, const char* fileName, CARDCallback callback); +s32 CARDFastDelete(s32 chan, s32 fileNo); +s32 CARDFastDeleteAsync(s32 chan, s32 fileNo, CARDCallback callback); +s32 CARDFastOpen(s32 chan, s32 fileNo, CARDFileInfo* fileInfo); +s32 CARDFormat(s32 chan); +s32 CARDFormatAsync(s32 chan, CARDCallback callback); +s32 CARDFreeBlocks(s32 chan, s32* byteNotUsed, s32* filesNotUsed); +s32 CARDGetAttributes(s32 chan, s32 fileNo, u8* attr); +s32 CARDGetEncoding(s32 chan, u16* encode); +s32 CARDGetMemSize(s32 chan, u16* size); +s32 CARDGetResultCode(s32 chan); +s32 CARDGetSectorSize(s32 chan, u32* size); +s32 CARDGetSerialNo(s32 chan, u64* serialNo); +s32 CARDGetStatus(s32 chan, s32 fileNo, CARDStat* stat); +s32 CARDGetXferredBytes(s32 chan); +s32 CARDMount(s32 chan, void* workArea, CARDCallback detachCallback); +s32 CARDMountAsync(s32 chan, void* workArea, CARDCallback detachCallback, + CARDCallback attachCallback); +s32 CARDOpen(s32 chan, const char* fileName, CARDFileInfo* fileInfo); +BOOL CARDProbe(s32 chan); +s32 CARDProbeEx(s32 chan, s32* memSize, s32* sectorSize); +s32 CARDRename(s32 chan, const char* oldName, const char* newName); +s32 CARDRenameAsync(s32 chan, const char* oldName, const char* newName, CARDCallback callback); +s32 CARDSetAttributesAsync(s32 chan, s32 fileNo, u8 attr, CARDCallback callback); +s32 CARDSetAttributes(s32 chan, s32 fileNo, u8 attr); +s32 CARDSetStatus(s32 chan, s32 fileNo, CARDStat* stat); +s32 CARDSetStatusAsync(s32 chan, s32 fileNo, CARDStat* stat, CARDCallback callback); +s32 CARDUnmount(s32 chan); +s32 CARDGetCurrentMode(s32 chan, u32* mode); +s32 CARDCancel(CARDFileInfo* fileInfo); +s32 CARDClose(CARDFileInfo* fileInfo); +s32 CARDRead(CARDFileInfo* fileInfo, void* addr, s32 length, s32 offset); +s32 CARDReadAsync(CARDFileInfo* fileInfo, void* addr, s32 length, s32 offset, + CARDCallback callback); +s32 CARDWrite(CARDFileInfo* fileInfo, const void* addr, s32 length, s32 offset); +s32 CARDWriteAsync(CARDFileInfo* fileInfo, const void* addr, s32 length, s32 offset, + CARDCallback callback); + +#ifdef __cplusplus +} +#endif +#endif // _DOLPHIN_CARD diff --git a/lib/dolphin/card.cpp b/lib/dolphin/card.cpp new file mode 100644 index 0000000..ff08949 --- /dev/null +++ b/lib/dolphin/card.cpp @@ -0,0 +1,347 @@ +#include "dolphin/card.h" +#include "dolphin/types.h" + +#include +#include "../logging.hpp" + +namespace { +aurora::Module Log("aurora::card"); +std::array CardChannels = {{ + kabufuda::Card{nullptr, nullptr}, + kabufuda::Card{nullptr, nullptr}, +}}; + +bool Initialized = false; +} // namespace + +extern "C" { + +void CARDInit(const char* game, const char* maker) { + if (Initialized) { + return; + } + Initialized = true; + Log.info("CARD API Initialized BUILT <{} {}>", __DATE__, __TIME__); + + CardChannels[0] = kabufuda::Card{game, maker}; + CardChannels[1] = kabufuda::Card{game, maker}; +} + +void CARDSetGameAndMaker(const s32 chan, const char* game, const char* maker) { + if (chan < 0 || chan >= 2) { + return; + } + + CardChannels[chan].setCurrentGame(game); + CardChannels[chan].setCurrentMaker(maker); +} + +BOOL CARDGetFastMode() { + // TODO? + return false; +} + +BOOL CARDSetFastMode() { + // TODO? + return false; +} + +s32 CARDCheck(const s32 chan) { + if (chan < 0 || chan >= 2) { + return CARD_RESULT_FATAL_ERROR; + } + + // TODO + return CARD_RESULT_NOCARD; +} + +s32 CARDCheckAsync(const s32 chan, CARDCallback callback) { + if (chan < 0 || chan >= 2) { + return CARD_RESULT_FATAL_ERROR; + } + // TODO + return CARD_RESULT_NOCARD; +} + +s32 CARDCheckEx(s32 chan, s32* xferBytes) { + if (chan < 0 || chan >= 2) { + return CARD_RESULT_FATAL_ERROR; + } + // TODO: + return CARD_RESULT_NOCARD; +} + +s32 CARDCheckExAsync(s32 chan, s32* xferBytes, CARDCallback callback) { + if (chan < 0 || chan >= 2) { + return CARD_RESULT_FATAL_ERROR; + } + // TODO: + return CARD_RESULT_NOCARD; +} + +s32 CARDCreate(s32 chan, const char* fileName, u32 size, CARDFileInfo* fileInfo) { + if (chan < 0 || chan >= 2) { + return CARD_RESULT_FATAL_ERROR; + } + // TODO: + return CARD_RESULT_NOCARD; +} + +s32 CARDCreateAsync(s32 chan, const char* fileName, u32 size, CARDFileInfo* fileInfo, CARDCallback callback) { + if (chan < 0 || chan >= 2) { + return CARD_RESULT_FATAL_ERROR; + } + // TODO: + return CARD_RESULT_NOCARD; +} + +s32 CARDDelete(s32 chan, const char* fileName) { + if (chan < 0 || chan >= 2) { + return CARD_RESULT_FATAL_ERROR; + } + // TODO: + return CARD_RESULT_NOCARD; +} + +s32 CARDDeleteAsync(s32 chan, const char* fileName, CARDCallback callback) { + if (chan < 0 || chan >= 2) { + return CARD_RESULT_FATAL_ERROR; + } + // TODO: + return CARD_RESULT_NOCARD; +} + +s32 CARDFastDelete(s32 chan, s32 fileNo) { + if (chan < 0 || chan >= 2) { + return CARD_RESULT_FATAL_ERROR; + } + // TODO: + return CARD_RESULT_NOCARD; +} + +s32 CARDFastDeleteAsync(s32 chan, s32 fileNo, CARDCallback callback); +{ + if (chan < 0 || chan >= 2) { + return CARD_RESULT_FATAL_ERROR; + } + // TODO: + return CARD_RESULT_NOCARD; +} + +s32 CARDFastOpen(s32 chan, s32 fileNo, CARDFileInfo* fileInfo) { + if (chan < 0 || chan >= 2) { + return CARD_RESULT_FATAL_ERROR; + } + // TODO: + return CARD_RESULT_NOCARD; +} + +s32 CARDFormat(s32 chan) { + if (chan < 0 || chan >= 2) { + return CARD_RESULT_FATAL_ERROR; + } + // TODO: + return CARD_RESULT_NOCARD; +} +s32 CARDFormatAsync(s32 chan, CARDCallback callback) { + if (chan < 0 || chan >= 2) { + return CARD_RESULT_FATAL_ERROR; + } + // TODO: + return CARD_RESULT_NOCARD; +} +s32 CARDFreeBlocks(s32 chan, s32* byteNotUsed, s32* filesNotUsed) { + if (chan < 0 || chan >= 2) { + return CARD_RESULT_FATAL_ERROR; + } + // TODO: + return CARD_RESULT_NOCARD; +} +s32 CARDGetAttributes(s32 chan, s32 fileNo, u8* attr) { + if (chan < 0 || chan >= 2) { + return CARD_RESULT_FATAL_ERROR; + } + // TODO: + return CARD_RESULT_NOCARD; +} + +s32 CARDGetEncoding(s32 chan, u16* encode) { + if (chan < 0 || chan >= 2) { + return CARD_RESULT_FATAL_ERROR; + } + // TODO: + return CARD_RESULT_NOCARD; +} +s32 CARDGetMemSize(s32 chan, u16* size) { + if (chan < 0 || chan >= 2) { + return CARD_RESULT_FATAL_ERROR; + } + // TODO: + return CARD_RESULT_NOCARD; +} +s32 CARDGetResultCode(s32 chan) { + if (chan < 0 || chan >= 2) { + return CARD_RESULT_FATAL_ERROR; + } + // TODO: + return CARD_RESULT_NOCARD; +} +s32 CARDGetSectorSize(s32 chan, u32* size) { + if (chan < 0 || chan >= 2) { + return CARD_RESULT_FATAL_ERROR; + } + // TODO: + return CARD_RESULT_NOCARD; +} +s32 CARDGetSerialNo(s32 chan, u64* serialNo) { + if (chan < 0 || chan >= 2) { + return CARD_RESULT_FATAL_ERROR; + } + // TODO: + return CARD_RESULT_NOCARD; +} +s32 CARDGetStatus(s32 chan, s32 fileNo, CARDStat* stat) { + if (chan < 0 || chan >= 2) { + return CARD_RESULT_FATAL_ERROR; + } + // TODO: + return CARD_RESULT_NOCARD; +} +s32 CARDGetXferredBytes(s32 chan) { + if (chan < 0 || chan >= 2) { + return CARD_RESULT_FATAL_ERROR; + } + // TODO: + return CARD_RESULT_NOCARD; +} +s32 CARDMount(s32 chan, void* workArea, CARDCallback detachCallback) { + if (chan < 0 || chan >= 2) { + return CARD_RESULT_FATAL_ERROR; + } + // TODO: + return CARD_RESULT_NOCARD; +} +s32 CARDMountAsync(s32 chan, void* workArea, CARDCallback detachCallback, CARDCallback attachCallback) { + if (chan < 0 || chan >= 2) { + return CARD_RESULT_FATAL_ERROR; + } + // TODO: + return CARD_RESULT_NOCARD; +} +s32 CARDOpen(s32 chan, const char* fileName, CARDFileInfo* fileInfo) { + if (chan < 0 || chan >= 2) { + return CARD_RESULT_FATAL_ERROR; + } + // TODO: + return CARD_RESULT_NOCARD; +} + +BOOL CARDProbe(s32 chan) { + if (chan < 0 || chan >= 2) { + return CARD_RESULT_FATAL_ERROR; + } + // TODO: + return CARD_RESULT_NOCARD; +} + +s32 CARDProbeEx(s32 chan, s32* memSize, s32* sectorSize) { + if (chan < 0 || chan >= 2) { + return CARD_RESULT_FATAL_ERROR; + } + // TODO: + return CARD_RESULT_NOCARD; +} + +s32 CARDRename(s32 chan, const char* oldName, const char* newName) { + if (chan < 0 || chan >= 2) { + return CARD_RESULT_FATAL_ERROR; + } + // TODO: + return CARD_RESULT_NOCARD; +} +s32 CARDRenameAsync(s32 chan, const char* oldName, const char* newName, CARDCallback callback) { + if (chan < 0 || chan >= 2) { + return CARD_RESULT_FATAL_ERROR; + } + // TODO: + return CARD_RESULT_NOCARD; +} + +s32 CARDSetAttributesAsync(s32 chan, s32 fileNo, u8 attr, CARDCallback callback) { + if (chan < 0 || chan >= 2) { + return CARD_RESULT_FATAL_ERROR; + } + // TODO: + return CARD_RESULT_NOCARD; +} + +s32 CARDSetAttributes(s32 chan, s32 fileNo, u8 attr) { + if (chan < 0 || chan >= 2) { + return CARD_RESULT_FATAL_ERROR; + } + // TODO: + return CARD_RESULT_NOCARD; +} + +s32 CARDSetStatus(s32 chan, s32 fileNo, CARDStat* stat) { + if (chan < 0 || chan >= 2) { + return CARD_RESULT_FATAL_ERROR; + } + // TODO: + return CARD_RESULT_NOCARD; +} + +s32 CARDSetStatusAsync(s32 chan, s32 fileNo, CARDStat* stat, CARDCallback callback) { + if (chan < 0 || chan >= 2) { + return CARD_RESULT_FATAL_ERROR; + } + // TODO: + return CARD_RESULT_NOCARD; +} + +s32 CARDUnmount(s32 chan) { + if (chan < 0 || chan >= 2) { + return CARD_RESULT_FATAL_ERROR; + } + // TODO: + return CARD_RESULT_NOCARD; +} + +s32 CARDGetCurrentMode(s32 chan, u32* mode) { + if (chan < 0 || chan >= 2) { + return CARD_RESULT_FATAL_ERROR; + } + // TODO: + return CARD_RESULT_NOCARD; +} + +s32 CARDCancel(CARDFileInfo* fileInfo) { + // TODO:ge + return CARD_RESULT_NOCARD; +} + +s32 CARDClose(CARDFileInfo* fileInfo) { + // TODO: + return CARD_RESULT_NOCARD; +} + +s32 CARDRead(CARDFileInfo* fileInfo, void* addr, s32 length, s32 offset) { + // TODO: + return CARD_RESULT_NOCARD; +} + +s32 CARDReadAsync(CARDFileInfo* fileInfo, void* addr, s32 length, s32 offset, CARDCallback callback) { + // TODO: + return CARD_RESULT_NOCARD; +} + +s32 CARDWrite(CARDFileInfo* fileInfo, const void* addr, s32 length, s32 offset) { + // TODO: + return CARD_RESULT_NOCARD; +} + +s32 CARDWriteAsync(CARDFileInfo* fileInfo, const void* addr, s32 length, s32 offset, CARDCallback callback) { + // TODO: + return CARD_RESULT_NOCARD; +} +} \ No newline at end of file