altra64/src/memorypak.c

449 lines
12 KiB
C

//
// Copyright (c) 2017 The Altra64 project contributors
// Portions (c) 2013 saturnu (Alt64) based on libdragon, Neo64Menu, ED64IO, libn64-hkz, libmikmod
// See LICENSE file in the project root for full license information.
//
#include <libdragon.h>
#include <string.h>
#include <stdio.h>
#include "constants.h"
#include "types.h"
#include "mempak.h"
#include "memorypak.h"
#include "ff.h"
#include "menu.h"
#include "debug.h"
#include "strlib.h"
#include "sys.h"
enum MemoryPakFormat
{
None,
DexDrive,
Z64
};
static uint8_t mempak_data[128 * 256];
char *mempak_path;
char ___TranslateNotes(char *bNote, char *Text)
{
#pragma warning(disable : 4305 4309)
char cReturn = 0x00;
const char aSpecial[] = {0x21, 0x22, 0x23, 0x60, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x3A, 0x3D, 0x3F, 0x40, 0x74, 0xA9, 0xAE};
// { '!' , '\"', '#' , '`' , '*' , '+' , ',' , '-' , '.' , '/' , ':' , '=' , '?' , '>' , 'tm', '(r)','(c)' };
#pragma warning(default : 4305 4309)
int i = 16;
do
{
char b = bNote[i];
if ((b > 0) && i < 32)
{
if (b <= 0x0F) // translate Icons as Spaces
*Text = 0x20;
else if (b <= 0x19) // Numbers
*Text = 0x20 + b;
else if (b <= 0x33) // Characters
*Text = 0x47 + b;
else if (b <= 0x44) // special Symbols
*Text = aSpecial[b - 0x34];
else if (b <= 0x94) // Japan
*Text = 0xC0 + (b % 40);
else // unknown
*Text = (char)0xA4;
++i;
++Text;
}
else
{
*Text = '\0';
if (b)
{
i = 12;
Text = &cReturn;
}
else
i = 13;
}
} while (i != 13);
return cReturn;
}
char ___CountBlocks(char *bMemPakBinary, char *aNoteSizes)
{
int wRemainingBlocks = 123;
char bNextIndex;
int i = 0;
while (i < 16 && wRemainingBlocks <= 123)
{
aNoteSizes[i] = 0;
bNextIndex = bMemPakBinary[0x307 + (i * 0x20)];
while ((bNextIndex >= 5) && (aNoteSizes[i] < wRemainingBlocks))
{
aNoteSizes[i]++;
bNextIndex = bMemPakBinary[0x101 + (bNextIndex * 2)];
}
if (aNoteSizes[i] > wRemainingBlocks)
wRemainingBlocks = 0xFF;
else
wRemainingBlocks -= aNoteSizes[i];
i++;
}
return wRemainingBlocks;
}
//old method to write a file to the mempak at controller 1
int file_to_mpk(display_context_t disp, u8 *filename)
{
enum MemoryPakFormat memorypak_format;
u8 buff[64];
FRESULT result;
FIL file;
UINT bytesread;
result = f_open(&file, filename, FA_READ);
if (result == FR_OK)
{
//int fsize = f_size(&file);
u8 *pch;
pch = strrchr(filename, '.');
sprintf(buff, "%s", (pch + 2));
if (strcmp(buff, "64") == 0)
{
TRACE(disp, "Dexdrive format");
memorypak_format = DexDrive;
//skip header
result = f_lseek (
&file, /* [IN] File object */
4160 /* [IN] File read/write pointer */
);
}
TRACE(disp, "Z64 format");
memorypak_format = Z64;
result =
f_read (
&file, /* [IN] File object */
mempak_data, /* [OUT] Buffer to store read data */
32768, /* [IN] Number of bytes to read */
&bytesread /* [OUT] Number of bytes read */
);
f_close(&file);
int err = 0;
for (int j = 0; j < 128; j++)
{
err |= write_mempak_sector(0, j, &mempak_data[j * MEMPAK_BLOCK_SIZE]);
}
}
else
{
memorypak_format = None;
}
return (int)memorypak_format; //TODO: should return enum
}
void view_mpk_file(display_context_t disp, char *mpk_filename)
{
u8 buff[64];
FRESULT result;
FIL file;
UINT bytesread;
result = f_open(&file, mpk_filename, FA_READ);
if (result == FR_OK)
{
//int fsize = f_size(&file);
u8 *pch;
pch = strrchr(mpk_filename, '.');
sprintf(buff, "%s", (pch + 2));
if (strcmp(buff, "64") == 0) //DEXDRIVE format
{
//skip header
result = f_lseek (
&file, /* [IN] File object */
4160 /* [IN] File read/write pointer */
);
}
result =
f_read (
&file, /* [IN] File object */
mempak_data, /* [OUT] Buffer to store read data */
32768, /* [IN] Number of bytes to read */
&bytesread /* [OUT] Number of bytes read */
);
f_close(&file);
printText("File contents:", 11, 5, disp);
printText(" ", 11, -1, disp);
int notes_c = 0;
char szBuffer[40],
cAppendix;
int bFirstChar;
int i = 0,
nNotes = 0,
iSum = 0,
iRemainingBlocks;
char aNoteSizes[16];
for (i = 0x10A; i < 0x200; i++)
iSum += mempak_data[i];
if (((iSum % 256) == mempak_data[0x101]))
{
iRemainingBlocks = ___CountBlocks(mempak_data, aNoteSizes);
if (iRemainingBlocks <= 123)
{
for (notes_c = 0; notes_c < 16; notes_c++)
{
if (mempak_data[0x300 + (notes_c * 32)] ||
mempak_data[0x301 + (notes_c * 32)] ||
mempak_data[0x302 + (notes_c * 32)])
{
cAppendix = ___TranslateNotes(&mempak_data[0x300 + (notes_c * 32)], szBuffer);
if (cAppendix != '\0')
sprintf(szBuffer, "%s. %c", szBuffer, cAppendix);
bFirstChar = 1;
for (i = 0; i < (int)strlen(szBuffer); i++)
{
if (szBuffer[i] == ' ')
bFirstChar = 1;
else
{
if (bFirstChar && (szBuffer[i] >= 'a') && (szBuffer[i] <= 'z'))
{
bFirstChar = 0;
szBuffer[i] -= 0x20;
}
}
}
printText(szBuffer, 11, -1, disp);
switch (mempak_data[0x303 + (notes_c * 32)])
{
case 0x00:
sprintf(szBuffer, "None");
break;
case 0x37:
sprintf(szBuffer, "Beta");
break;
case 0x41:
sprintf(szBuffer, "NTSC");
break;
case 0x44:
sprintf(szBuffer, "Germany");
break;
case 0x45:
sprintf(szBuffer, "USA");
break;
case 0x46:
sprintf(szBuffer, "France");
break;
case 0x49:
sprintf(szBuffer, "Italy");
break;
case 0x4A:
sprintf(szBuffer, "Japan");
break;
case 0x50:
sprintf(szBuffer, "Europe");
break;
case 0x53:
sprintf(szBuffer, "Spain");
break;
case 0x55:
sprintf(szBuffer, "Australia");
break;
case 0x58:
case 0x59:
sprintf(szBuffer, "PAL");
break;
default:
sprintf(szBuffer, "Unknown(%02X)", mempak_data[0x303 + (notes_c * 32)]);
}
sprintf(szBuffer, "%i", aNoteSizes[notes_c]);
nNotes++;
}
}
}
int free_c = 0;
for (free_c = nNotes; free_c < 16; free_c++)
printText("[free]", 11, -1, disp);
char buff[512];
printText(" ", 11, -1, disp);
printText("Free space:", 11, -1, disp);
sprintf(buff, "%i blocks", iRemainingBlocks);
printText(buff, 11, -1, disp);
}
else
{
printText("empty", 11, -1, disp);
}
}
}
void view_mpk(display_context_t disp)
{
int err;
printText("Mempak content:", 11, 5, disp);
struct controller_data output;
get_accessories_present( &output);
/* Make sure they don't have a rumble pak inserted instead */
switch (identify_accessory(0))
{
case ACCESSORY_NONE:
printText(" ", 11, -1, disp);
printText("no Mempak", 11, -1, disp);
break;
case ACCESSORY_MEMPAK:
if ((err = validate_mempak(0)))
{
if (err == -3)
{
printText(" ", 11, -1, disp);
printText("not formatted", 11, -1, disp);
}
else
{
printText(" ", 11, -1, disp);
printText("read error", 11, -1, disp);
}
}
else
{
printText(" ", 11, -1, disp);
for (int j = 0; j < 16; j++)
{
entry_structure_t entry;
get_mempak_entry(0, j, &entry);
if (entry.valid)
{
char tmp[512];
sprintf(tmp, "%s", entry.name);
printText(tmp, 11, -1, disp);
}
else
{
printText("[free]", 11, -1, disp);
}
}
char buff[512];
printText(" ", 11, -1, disp);
printText("Free space:", 11, -1, disp);
sprintf(buff, "%d blocks", get_mempak_free_space(0));
printText(buff, 11, -1, disp);
}
break;
case ACCESSORY_RUMBLEPAK:
printText("RumblePak inserted", 11, -1, disp);
break;
default:
break;
}
}
//old function to dump a mempak to a file
void mpk_to_file(display_context_t disp, char *mpk_filename, int quick)
{
u8 buff[MAX_SUPPORTED_PATH_LEN];
u8 v = 0;
u8 ok = 0;
if (quick)
sprintf(buff, "/"ED64_FIRMWARE_PATH"/%s/%s", mempak_path, mpk_filename);
else
sprintf(buff, "/"ED64_FIRMWARE_PATH"/%s/%s.MPK", mempak_path, mpk_filename);
FRESULT fr;
FILINFO fno;
fr = f_stat(buff, &fno);
if(fr == FR_OK)
{
printText("File exists", 9, -1, disp);
if (quick)
printText("override", 9, -1, disp);
else
while (fr == FR_OK)
{
sprintf(buff, "/"ED64_FIRMWARE_PATH"/%s/%s.%i.MPK", mempak_path, mpk_filename, v);
fr = f_stat(buff, &fno);
if (fr == FR_OK)
v++;
else
break;
}
}
FRESULT result;
FIL file;
result = f_open(&file, buff, FA_WRITE | FA_OPEN_ALWAYS);
if (result == FR_OK)
{
controller_init();
int err = 0;
for (int j = 0; j < 128; j++)
{
err |= read_mempak_sector(0, j, &mempak_data[j * 256]);
}
UINT bw;
result =
f_write (
&file, /* [IN] Pointer to the file object structure */
mempak_data, /* [IN] Pointer to the data to be written */
32768, /* [IN] Number of bytes to write */
&bw /* [OUT] Pointer to the variable to return number of bytes written */
);
f_close(&file);
sprintf(buff, "File: %s%i.MPK", mpk_filename, v);
printText(buff, 9, -1, disp);
printText("backup done...", 9, -1, disp);
}
}