summaryrefslogtreecommitdiff
path: root/src/code/mempak.c
diff options
context:
space:
mode:
authorTharo <17233964+Thar0@users.noreply.github.com>2022-11-16 07:32:07 +0000
committerGitHub <noreply@github.com>2022-11-16 02:32:07 -0500
commitacc077a24c4fc75b98ccdd30e47b45ee897bb236 (patch)
treef3f7b0b22fc1cbd6054107e0e8fdc3ca25014e3f /src/code/mempak.c
parent6451fbc24faa8a8fb21a5125c5b64351037d215c (diff)
Mempak doc (#1382)
* Mempak doc * Format * Suggested changes * Further changes
Diffstat (limited to 'src/code/mempak.c')
-rw-r--r--src/code/mempak.c233
1 files changed, 160 insertions, 73 deletions
diff --git a/src/code/mempak.c b/src/code/mempak.c
index 2ccf15135..4d00b311a 100644
--- a/src/code/mempak.c
+++ b/src/code/mempak.c
@@ -1,184 +1,271 @@
+/**
+ * @file mempak.c
+ *
+ * This file implements an interface for a controller memory pak filesystem (pfs), with operations to create, delete,
+ * read, write and check the size of files, as well as obtain a listing of which files currently exist.
+ *
+ * Each file is assigned an uppercase ASCII letter as an identifier, the game name for each is marked as
+ * 'ZELDA DEMO TOOL', encoded according to the N64 Font Code described in section 26.3 of the N64 Programming Manual.
+ */
#include "global.h"
+#define MEMPAK_MAX_FILES 11
+
OSPfs sMempakPfsHandle;
s32 sMempakFreeBytes;
-s32 sMempakFiles[10];
+s32 sMempakFiles[MEMPAK_MAX_FILES];
u16 sMempakCompanyCode = 1;
u32 sMempakGameCode = 1;
-// "ZELDA DEMO TOOL "
-u8 sMempakGameName[0x10] = { 0x33, 0x1E, 0x25, 0x1D, 0x1A, 0x0F, 0x1D, 0x1E,
- 0x26, 0x28, 0x0F, 0x2D, 0x28, 0x28, 0x25, 0x0F };
-u8 sMempakExtName[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
-
-s32 Mempak_Init(s32 controllerNb) {
- OSMesgQueue* mq;
+// NCH is a heavily abbreviated "N64 font code CHaracter"
+// Conversion from A-Z to N64 Font Code
+#define NCH(c) ((c)-0x27)
+// Conversion from spaces to N64 Font Code
+#define NCH_SPC (0x0F)
+
+u8 sMempakGameName[PFS_FILE_NAME_LEN] = {
+ NCH('Z'), NCH('E'), NCH('L'), NCH('D'), NCH('A'), NCH_SPC, NCH('D'), NCH('E'),
+ NCH('M'), NCH('O'), NCH_SPC, NCH('T'), NCH('O'), NCH('O'), NCH('L'), NCH_SPC,
+};
+
+u8 sMempakExtName[PFS_FILE_EXT_LEN] = { 0 };
+
+/**
+ * Initializes the memory pak filesystem for a memory pak in the controller plugged into the specified port. Subsequent
+ * memory pak operations will use the same controller port.
+ *
+ * @return true if the operation completed successfully, false otherwise
+ */
+s32 Mempak_Init(s32 controllerNum) {
+ OSMesgQueue* serialEventQueue;
s32 pad;
s32 ret = false;
- mq = PadMgr_AcquireSerialEventQueue(&gPadMgr);
+ serialEventQueue = PadMgr_AcquireSerialEventQueue(&gPadMgr);
- if (!osPfsInitPak(mq, &sMempakPfsHandle, controllerNb)) {
+ if (osPfsInitPak(serialEventQueue, &sMempakPfsHandle, controllerNum) == 0) {
ret = true;
}
osPfsFreeBlocks(&sMempakPfsHandle, &sMempakFreeBytes);
- PadMgr_ReleaseSerialEventQueue(&gPadMgr, mq);
-
+ PadMgr_ReleaseSerialEventQueue(&gPadMgr, serialEventQueue);
return ret;
}
-s32 Mempak_GetFreeBytes(s32 controllerNb) {
+s32 Mempak_GetFreeBytes(s32 controllerNum) {
return sMempakFreeBytes;
}
-s32 Mempak_FindFile(s32 controllerNb, char start, char end) {
- OSMesgQueue* mq;
+/**
+ * Checks if the files identified by letters between `start` and `end` (inclusive) exist on the memory pak.
+ *
+ * This must be called before performing any individual file operations.
+ *
+ * @param controllerNum Unused, the controller used is that which was last passed to `Mempak_Init`
+ * @param start Start file letter
+ * @param end End file letter (inclusive)
+ * @return a bitfield where set bits indicate that the file exists
+ */
+s32 Mempak_FindFiles(s32 controllerNum, char start, char end) {
+ OSMesgQueue* serialEventQueue;
s32 error;
- char idx;
+ char letter;
u32 bit = 1;
- s32 flag = 0;
+ s32 bits = 0;
- mq = PadMgr_AcquireSerialEventQueue(&gPadMgr);
+ serialEventQueue = PadMgr_AcquireSerialEventQueue(&gPadMgr);
- for (idx = start; idx <= end; idx++) {
- sMempakExtName[0] = idx - 0x27;
+ for (letter = start; letter <= end; letter++) {
+ sMempakExtName[0] = NCH(letter);
error = osPfsFindFile(&sMempakPfsHandle, sMempakCompanyCode, sMempakGameCode, sMempakGameName, sMempakExtName,
- &sMempakFiles[idx - 'A']);
+ &sMempakFiles[MEMPAK_LETTER_TO_INDEX(letter)]);
if (error == 0) {
- flag |= bit;
+ bits |= bit;
} else {
- sMempakFiles[idx - 'A'] = -1;
+ sMempakFiles[MEMPAK_LETTER_TO_INDEX(letter)] = -1;
}
bit <<= 1;
- osSyncPrintf("mempak: find '%c' (%d)\n", idx, error);
+ osSyncPrintf("mempak: find '%c' (%d)\n", letter, error);
}
- PadMgr_ReleaseSerialEventQueue(&gPadMgr, mq);
- osSyncPrintf("mempak: find '%c' - '%c' %02x\n", start, end, flag);
-
- return flag;
+ PadMgr_ReleaseSerialEventQueue(&gPadMgr, serialEventQueue);
+ osSyncPrintf("mempak: find '%c' - '%c' %02x\n", start, end, bits);
+ return bits;
}
-s32 Mempak_Write(s32 controllerNb, char idx, void* buffer, s32 offset, s32 size) {
- OSMesgQueue* mq;
+/**
+ * Writes data to the file identified with `letter`.
+ *
+ * @param controllerNum Unused, the controller used is that which was last passed to `Mempak_Init`
+ * @param letter Memory pak file letter, in the range 'A' to ('A' + MEMPAK_MAX_FILES)
+ * @param buffer Buffer containing data to write
+ * @param offset Offset into the file to write to
+ * @param size Size in bytes
+ * @return true if the operation completed successfully, false otherwise
+ */
+s32 Mempak_Write(s32 controllerNum, char letter, void* buffer, s32 offset, s32 size) {
+ OSMesgQueue* serialEventQueue;
s32 error;
s32 ret = false;
s32 pad;
- mq = PadMgr_AcquireSerialEventQueue(&gPadMgr);
+ serialEventQueue = PadMgr_AcquireSerialEventQueue(&gPadMgr);
if (size < sMempakFreeBytes) {
- error = osPfsReadWriteFile(&sMempakPfsHandle, sMempakFiles[idx - 'A'], 1, offset, size, buffer);
+ error = osPfsReadWriteFile(&sMempakPfsHandle, sMempakFiles[MEMPAK_LETTER_TO_INDEX(letter)], PFS_WRITE, offset,
+ size, buffer);
if (error == 0) {
ret = true;
}
- osSyncPrintf("mempak: write %d byte '%c' (%d)->%d\n", size, idx, sMempakFiles[idx - 'A'], error);
+ osSyncPrintf("mempak: write %d byte '%c' (%d)->%d\n", size, letter,
+ sMempakFiles[MEMPAK_LETTER_TO_INDEX(letter)], error);
}
- PadMgr_ReleaseSerialEventQueue(&gPadMgr, mq);
-
+ PadMgr_ReleaseSerialEventQueue(&gPadMgr, serialEventQueue);
return ret;
}
-s32 Mempak_Read(s32 controllerNb, char idx, void* buffer, s32 offset, s32 size) {
- OSMesgQueue* mq;
+/**
+ * Reads data from the file identified with `letter`.
+ *
+ * @param controllerNum Unused, the controller used is that which was last passed to `Mempak_Init`
+ * @param letter Memory pak file letter, in the range 'A' to ('A' + MEMPAK_MAX_FILES)
+ * @param buffer Buffer to read data into
+ * @param offset Offset into the file to read from
+ * @param size Size in bytes
+ * @return true if the operation completed successfully, false otherwise
+ */
+s32 Mempak_Read(s32 controllerNum, char letter, void* buffer, s32 offset, s32 size) {
+ OSMesgQueue* serialEventQueue;
s32 error;
s32 ret = false;
s32 pad;
- mq = PadMgr_AcquireSerialEventQueue(&gPadMgr);
+ serialEventQueue = PadMgr_AcquireSerialEventQueue(&gPadMgr);
if (size < sMempakFreeBytes) {
- error = osPfsReadWriteFile(&sMempakPfsHandle, sMempakFiles[idx - 'A'], 0, offset, size, buffer);
+ error = osPfsReadWriteFile(&sMempakPfsHandle, sMempakFiles[MEMPAK_LETTER_TO_INDEX(letter)], PFS_READ, offset,
+ size, buffer);
if (error == 0) {
ret = true;
}
- osSyncPrintf("mempak: read %d byte '%c' (%d)<-%d\n", size, idx, sMempakFiles[idx - 'A'], error);
+ osSyncPrintf("mempak: read %d byte '%c' (%d)<-%d\n", size, letter, sMempakFiles[MEMPAK_LETTER_TO_INDEX(letter)],
+ error);
}
- PadMgr_ReleaseSerialEventQueue(&gPadMgr, mq);
+ PadMgr_ReleaseSerialEventQueue(&gPadMgr, serialEventQueue);
return ret;
}
-s32 Mempak_Alloc(s32 controllerNb, char* idx, s32 size) {
- OSMesgQueue* mq;
+/**
+ * Creates a new file on the memory pak.
+ *
+ * @param controllerNum Unused, the controller used is that which was last passed to `Mempak_Init`
+ * @param letter Memory pak file letter, in the range 'A' to ('A' + MEMPAK_MAX_FILES).
+ * If this points to a valid file letter the new file will be created using that letter, otherwise it will create
+ * a file using the first free letter and return it through this argument. If no letters are free, the last letter
+ * ('A' + MEMPAK_MAX_FILES - 1) is used.
+ * @param size File size
+ * @return true if the operation completed successfully, false otherwise
+ */
+s32 Mempak_CreateFile(s32 controllerNum, char* letter, s32 size) {
+ OSMesgQueue* serialEventQueue;
s32 error;
- s32 ret = 0;
+ s32 ret = false;
s32 i;
s32 pad;
- mq = PadMgr_AcquireSerialEventQueue(&gPadMgr);
+ serialEventQueue = PadMgr_AcquireSerialEventQueue(&gPadMgr);
+
+ if (*letter >= MEMPAK_INDEX_TO_LETTER(0) && *letter < MEMPAK_INDEX_TO_LETTER(MEMPAK_MAX_FILES)) {
+ // Create file with specific letter
+
+ sMempakExtName[0] = NCH(*letter);
+ if (-1 == sMempakFiles[MEMPAK_LETTER_TO_INDEX(*letter)]) {
+ // File does not already exist
- if (*idx >= 'A' && *idx < 'L') {
- sMempakExtName[0] = *idx - 0x27;
- if (-1 == sMempakFiles[*idx - 'A']) {
error = osPfsAllocateFile(&sMempakPfsHandle, sMempakCompanyCode, sMempakGameCode, sMempakGameName,
- sMempakExtName, size, &sMempakFiles[*idx - 'A']);
+ sMempakExtName, size, &sMempakFiles[MEMPAK_LETTER_TO_INDEX(*letter)]);
if (error == 0) {
- ret = 1;
+ ret = true;
}
- osSyncPrintf("mempak: alloc %d byte '%c' (%d)\n", size, *idx, error);
+ osSyncPrintf("mempak: alloc %d byte '%c' (%d)\n", size, *letter, error);
} else {
- sMempakExtName[0] = *idx - 0x27;
+ // File already exists, delete then alloc
+
+ sMempakExtName[0] = NCH(*letter);
if (osPfsDeleteFile(&sMempakPfsHandle, sMempakCompanyCode, sMempakGameCode, sMempakGameName,
sMempakExtName) == 0) {
- ret = 1;
+ ret = true;
}
error = osPfsAllocateFile(&sMempakPfsHandle, sMempakCompanyCode, sMempakGameCode, sMempakGameName,
- sMempakExtName, size, &sMempakFiles[*idx - 'A']);
+ sMempakExtName, size, &sMempakFiles[MEMPAK_LETTER_TO_INDEX(*letter)]);
if (error == 0) {
- ret |= 1;
+ ret |= true;
}
- osSyncPrintf("mempak: resize %d byte '%c' (%d)\n", size, *idx, error);
+ osSyncPrintf("mempak: resize %d byte '%c' (%d)\n", size, *letter, error);
}
} else {
- for (i = 0; i < ARRAY_COUNT(sMempakFiles); i++) {
+ // Find first free letter and create a file identified by it
+ for (i = 0; i < MEMPAK_MAX_FILES - 1; i++) {
if (sMempakFiles[i] == -1) {
break;
}
}
+ *letter = MEMPAK_INDEX_TO_LETTER(i);
- *idx = i + 'A';
- sMempakExtName[0] = *idx - 0x27;
+ sMempakExtName[0] = NCH(*letter);
error = osPfsAllocateFile(&sMempakPfsHandle, sMempakCompanyCode, sMempakGameCode, sMempakGameName,
sMempakExtName, size, &sMempakFiles[i]);
- osSyncPrintf("mempak: alloc %d byte '%c' (%d) with search\n", size, *idx, error);
+ osSyncPrintf("mempak: alloc %d byte '%c' (%d) with search\n", size, *letter, error);
if (error == 0) {
- ret = 1;
+ ret = true;
}
}
- PadMgr_ReleaseSerialEventQueue(&gPadMgr, mq);
-
+ PadMgr_ReleaseSerialEventQueue(&gPadMgr, serialEventQueue);
return ret;
}
-s32 Mempak_DeleteFile(s32 controllerNb, char idx) {
- OSMesgQueue* mq;
+/**
+ * Deletes the file identified with `letter`.
+ *
+ * @param controllerNum Unused, the controller used is that which was last passed to `Mempak_Init`
+ * @param letter Memory pak file letter, in the range 'A' to ('A' + MEMPAK_MAX_FILES)
+ * @return true if the operation completed successfully, false otherwise
+ */
+s32 Mempak_DeleteFile(s32 controllerNum, char letter) {
+ OSMesgQueue* serialEventQueue;
s32 error;
s32 ret = false;
- mq = PadMgr_AcquireSerialEventQueue(&gPadMgr);
+ serialEventQueue = PadMgr_AcquireSerialEventQueue(&gPadMgr);
- sMempakExtName[0] = idx - 0x27;
+ sMempakExtName[0] = NCH(letter);
error = osPfsDeleteFile(&sMempakPfsHandle, sMempakCompanyCode, sMempakGameCode, sMempakGameName, sMempakExtName);
if (error == 0) {
ret = true;
}
- osSyncPrintf("mempak: delete '%c' (%d)\n", idx, error);
- PadMgr_ReleaseSerialEventQueue(&gPadMgr, mq);
+ osSyncPrintf("mempak: delete '%c' (%d)\n", letter, error);
+ PadMgr_ReleaseSerialEventQueue(&gPadMgr, serialEventQueue);
return ret;
}
-s32 Mempak_GetFileSize(s32 controllerNb, char idx) {
- OSMesgQueue* mq = PadMgr_AcquireSerialEventQueue(&gPadMgr);
+/**
+ * Gets the size of the file identified with `letter`.
+ *
+ * @param controllerNum Unused, the controller used is that which was last passed to `Mempak_Init`
+ * @param letter Memory pak file letter, in the range 'A' to ('A' + MEMPAK_MAX_FILES)
+ * @return the size of the file, or 0 if the operation failed for any reason
+ */
+s32 Mempak_GetFileSize(s32 controllerNum, char letter) {
+ OSMesgQueue* serialEventQueue = PadMgr_AcquireSerialEventQueue(&gPadMgr);
OSPfsState state;
- s32 error = osPfsFileState(&sMempakPfsHandle, sMempakFiles[idx - 'A'], &state);
+ s32 error = osPfsFileState(&sMempakPfsHandle, sMempakFiles[MEMPAK_LETTER_TO_INDEX(letter)], &state);
s32 pad;
- PadMgr_ReleaseSerialEventQueue(&gPadMgr, mq);
+ PadMgr_ReleaseSerialEventQueue(&gPadMgr, serialEventQueue);
if (error != 0) {
return 0;