mirror of
https://github.com/d0k3/GodMode9.git
synced 2025-06-26 13:42:47 +00:00
At least this shows something now...
... still faulty, though.
This commit is contained in:
parent
c15c559802
commit
6adf9d254d
@ -9,12 +9,7 @@
|
|||||||
|
|
||||||
#include "font.h"
|
#include "font.h"
|
||||||
#include "draw.h"
|
#include "draw.h"
|
||||||
#include "fs.h"
|
// #include "fs.h"
|
||||||
#ifdef USE_THEME
|
|
||||||
#include "theme.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static char debugstr[DBG_N_CHARS_X * DBG_N_CHARS_Y] = { 0 };
|
|
||||||
|
|
||||||
void ClearScreen(u8* screen, int width, int color)
|
void ClearScreen(u8* screen, int width, int color)
|
||||||
{
|
{
|
||||||
@ -26,15 +21,15 @@ void ClearScreen(u8* screen, int width, int color)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClearScreenFull(bool clear_top, bool clear_bottom)
|
void ClearScreenFull(bool clear_top, bool clear_bottom, int color)
|
||||||
{
|
{
|
||||||
if (clear_top) {
|
if (clear_top) {
|
||||||
ClearScreen(TOP_SCREEN0, SCREEN_WIDTH_TOP, STD_COLOR_BG);
|
ClearScreen(TOP_SCREEN0, SCREEN_WIDTH_TOP, color);
|
||||||
ClearScreen(TOP_SCREEN1, SCREEN_WIDTH_TOP, STD_COLOR_BG);
|
ClearScreen(TOP_SCREEN1, SCREEN_WIDTH_TOP, color);
|
||||||
}
|
}
|
||||||
if (clear_bottom) {
|
if (clear_bottom) {
|
||||||
ClearScreen(BOT_SCREEN0, SCREEN_WIDTH_BOT, STD_COLOR_BG);
|
ClearScreen(BOT_SCREEN0, SCREEN_WIDTH_BOT, color);
|
||||||
ClearScreen(BOT_SCREEN1, SCREEN_WIDTH_BOT, STD_COLOR_BG);
|
ClearScreen(BOT_SCREEN1, SCREEN_WIDTH_BOT, color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,7 +62,7 @@ void DrawString(u8* screen, const char *str, int x, int y, int color, int bgcolo
|
|||||||
DrawCharacter(screen, str[i], x + i * 8, y, color, bgcolor);
|
DrawCharacter(screen, str[i], x + i * 8, y, color, bgcolor);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DrawStringF(int x, int y, bool use_top, const char *format, ...)
|
void DrawStringF(bool use_top, int x, int y, int color, int bgcolor, const char *format, ...)
|
||||||
{
|
{
|
||||||
char str[512] = {}; // 512 should be more than enough
|
char str[512] = {}; // 512 should be more than enough
|
||||||
va_list va;
|
va_list va;
|
||||||
@ -78,16 +73,16 @@ void DrawStringF(int x, int y, bool use_top, const char *format, ...)
|
|||||||
|
|
||||||
for (char* text = strtok(str, "\n"); text != NULL; text = strtok(NULL, "\n"), y += 10) {
|
for (char* text = strtok(str, "\n"); text != NULL; text = strtok(NULL, "\n"), y += 10) {
|
||||||
if (use_top) {
|
if (use_top) {
|
||||||
DrawString(TOP_SCREEN0, text, x, y, STD_COLOR_FONT, STD_COLOR_BG);
|
DrawString(TOP_SCREEN0, text, x, y, color, bgcolor);
|
||||||
DrawString(TOP_SCREEN1, text, x, y, STD_COLOR_FONT, STD_COLOR_BG);
|
DrawString(TOP_SCREEN1, text, x, y, color, bgcolor);
|
||||||
} else {
|
} else {
|
||||||
DrawString(BOT_SCREEN0, text, x, y, STD_COLOR_FONT, STD_COLOR_BG);
|
DrawString(BOT_SCREEN0, text, x, y, color, bgcolor);
|
||||||
DrawString(BOT_SCREEN1, text, x, y, STD_COLOR_FONT, STD_COLOR_BG);
|
DrawString(BOT_SCREEN1, text, x, y, color, bgcolor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Screenshot(const char* path)
|
/*void Screenshot(const char* path)
|
||||||
{
|
{
|
||||||
u8* buffer = (u8*) 0x21000000; // careful, this area is used by other functions in Decrypt9
|
u8* buffer = (u8*) 0x21000000; // careful, this area is used by other functions in Decrypt9
|
||||||
u8* buffer_t = buffer + (400 * 240 * 3);
|
u8* buffer_t = buffer + (400 * 240 * 3);
|
||||||
@ -125,66 +120,22 @@ void Screenshot(const char* path)
|
|||||||
FileWrite(bmp_header, 54, 0);
|
FileWrite(bmp_header, 54, 0);
|
||||||
FileWrite(buffer, 400 * 240 * 3 * 2, 54);
|
FileWrite(buffer, 400 * 240 * 3 * 2, 54);
|
||||||
FileClose();
|
FileClose();
|
||||||
}
|
}*/
|
||||||
|
|
||||||
void DebugClear()
|
void ShowError(const char *format, ...)
|
||||||
{
|
{
|
||||||
memset(debugstr, 0x00, DBG_N_CHARS_X * DBG_N_CHARS_Y);
|
char str[128] = {}; // 128 should be more than enough
|
||||||
ClearScreen(TOP_SCREEN0, SCREEN_WIDTH_TOP, DBG_COLOR_BG);
|
|
||||||
ClearScreen(TOP_SCREEN1, SCREEN_WIDTH_TOP, DBG_COLOR_BG);
|
|
||||||
#if defined USE_THEME && defined GFX_DEBUG_BG
|
|
||||||
LoadThemeGfx(GFX_DEBUG_BG, true);
|
|
||||||
#endif
|
|
||||||
LogWrite("");
|
|
||||||
LogWrite(NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DebugSet(const char **strs)
|
|
||||||
{
|
|
||||||
if (strs != NULL) for (int y = 0; y < DBG_N_CHARS_Y; y++) {
|
|
||||||
int pos_dbgstr = DBG_N_CHARS_X * (DBG_N_CHARS_Y - 1 - y);
|
|
||||||
snprintf(debugstr + pos_dbgstr, DBG_N_CHARS_X, "%-*.*s", DBG_N_CHARS_X - 1, DBG_N_CHARS_X - 1, strs[y]);
|
|
||||||
}
|
|
||||||
|
|
||||||
int pos_y = DBG_START_Y;
|
|
||||||
for (char* str = debugstr + (DBG_N_CHARS_X * (DBG_N_CHARS_Y - 1)); str >= debugstr; str -= DBG_N_CHARS_X) {
|
|
||||||
if (str[0] != '\0') {
|
|
||||||
DrawString(TOP_SCREEN0, str, DBG_START_X, pos_y, DBG_COLOR_FONT, DBG_COLOR_BG);
|
|
||||||
DrawString(TOP_SCREEN1, str, DBG_START_X, pos_y, DBG_COLOR_FONT, DBG_COLOR_BG);
|
|
||||||
pos_y += DBG_STEP_Y;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Debug(const char *format, ...)
|
|
||||||
{
|
|
||||||
static bool adv_output = true;
|
|
||||||
char tempstr[128] = { 0 }; // 128 instead of DBG_N_CHARS_X for log file
|
|
||||||
va_list va;
|
va_list va;
|
||||||
|
|
||||||
va_start(va, format);
|
va_start(va, format);
|
||||||
vsnprintf(tempstr, 128, format, va);
|
vsnprintf(str, 128, format, va);
|
||||||
va_end(va);
|
va_end(va);
|
||||||
|
|
||||||
if (adv_output) {
|
ClearScreenFull(true, false, COLOR_BLACK);
|
||||||
memmove(debugstr + DBG_N_CHARS_X, debugstr, DBG_N_CHARS_X * (DBG_N_CHARS_Y - 1));
|
DrawStringF(true, 80, 80, COLOR_WHITE, COLOR_BLACK, str);
|
||||||
} else {
|
|
||||||
adv_output = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (*tempstr != '\r') { // not a good way of doing this - improve this later
|
|
||||||
snprintf(debugstr, DBG_N_CHARS_X, "%-*.*s", DBG_N_CHARS_X - 1, DBG_N_CHARS_X - 1, tempstr);
|
|
||||||
LogWrite(tempstr);
|
|
||||||
} else {
|
|
||||||
snprintf(debugstr, DBG_N_CHARS_X, "%-*.*s", DBG_N_CHARS_X - 1, DBG_N_CHARS_X - 1, tempstr + 1);
|
|
||||||
adv_output = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
DebugSet(NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !defined(USE_THEME) || !defined(ALT_PROGRESS)
|
/*void ShowProgress(u64 current, u64 total)
|
||||||
void ShowProgress(u64 current, u64 total)
|
|
||||||
{
|
{
|
||||||
const u32 progX = SCREEN_WIDTH_TOP - 40;
|
const u32 progX = SCREEN_WIDTH_TOP - 40;
|
||||||
const u32 progY = SCREEN_HEIGHT - 20;
|
const u32 progY = SCREEN_HEIGHT - 20;
|
||||||
@ -198,5 +149,4 @@ void ShowProgress(u64 current, u64 total)
|
|||||||
DrawString(TOP_SCREEN0, " ", progX, progY, DBG_COLOR_FONT, DBG_COLOR_BG);
|
DrawString(TOP_SCREEN0, " ", progX, progY, DBG_COLOR_FONT, DBG_COLOR_BG);
|
||||||
DrawString(TOP_SCREEN1, " ", progX, progY, DBG_COLOR_FONT, DBG_COLOR_BG);
|
DrawString(TOP_SCREEN1, " ", progX, progY, DBG_COLOR_FONT, DBG_COLOR_BG);
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
#endif
|
|
||||||
|
@ -17,23 +17,6 @@
|
|||||||
#define COLOR_WHITE RGB(0xFF, 0xFF, 0xFF)
|
#define COLOR_WHITE RGB(0xFF, 0xFF, 0xFF)
|
||||||
#define COLOR_TRANSPARENT RGB(0xFF, 0x00, 0xEF) // otherwise known as 'super fuchsia'
|
#define COLOR_TRANSPARENT RGB(0xFF, 0x00, 0xEF) // otherwise known as 'super fuchsia'
|
||||||
|
|
||||||
#ifndef USE_THEME
|
|
||||||
#define STD_COLOR_BG COLOR_BLACK
|
|
||||||
#define STD_COLOR_FONT COLOR_WHITE
|
|
||||||
|
|
||||||
#define DBG_COLOR_BG COLOR_BLACK
|
|
||||||
#define DBG_COLOR_FONT COLOR_WHITE
|
|
||||||
|
|
||||||
#define DBG_START_Y 10
|
|
||||||
#define DBG_END_Y (SCREEN_HEIGHT - 10)
|
|
||||||
#define DBG_START_X 10
|
|
||||||
#define DBG_END_X (SCREEN_WIDTH_TOP - 10)
|
|
||||||
#define DBG_STEP_Y 10
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define DBG_N_CHARS_Y ((DBG_END_Y - DBG_START_Y) / DBG_STEP_Y)
|
|
||||||
#define DBG_N_CHARS_X (((DBG_END_X - DBG_START_X) / 8) + 1)
|
|
||||||
|
|
||||||
#ifdef EXEC_GATEWAY
|
#ifdef EXEC_GATEWAY
|
||||||
#define TOP_SCREEN0 (u8*)(*(u32*)((uint32_t)0x080FFFC0 + 4 * (*(u32*)0x080FFFD8 & 1)))
|
#define TOP_SCREEN0 (u8*)(*(u32*)((uint32_t)0x080FFFC0 + 4 * (*(u32*)0x080FFFD8 & 1)))
|
||||||
#define BOT_SCREEN0 (u8*)(*(u32*)((uint32_t)0x080FFFD0 + 4 * (*(u32*)0x080FFFDC & 1)))
|
#define BOT_SCREEN0 (u8*)(*(u32*)((uint32_t)0x080FFFD0 + 4 * (*(u32*)0x080FFFDC & 1)))
|
||||||
@ -49,15 +32,13 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
void ClearScreen(unsigned char *screen, int width, int color);
|
void ClearScreen(unsigned char *screen, int width, int color);
|
||||||
void ClearScreenFull(bool clear_top, bool clear_bottom);
|
void ClearScreenFull(bool clear_top, bool clear_bottom, int color);
|
||||||
|
|
||||||
void DrawCharacter(unsigned char *screen, int character, int x, int y, int color, int bgcolor);
|
void DrawCharacter(unsigned char *screen, int character, int x, int y, int color, int bgcolor);
|
||||||
void DrawString(unsigned char *screen, const char *str, int x, int y, int color, int bgcolor);
|
void DrawString(unsigned char *screen, const char *str, int x, int y, int color, int bgcolor);
|
||||||
void DrawStringF(int x, int y, bool use_top, const char *format, ...);
|
void DrawStringF(bool use_top, int x, int y, int color, int bgcolor, const char *format, ...);
|
||||||
|
|
||||||
void Screenshot(const char* path);
|
void Screenshot(const char* path);
|
||||||
void DebugClear();
|
|
||||||
void DebugSet(const char **strs);
|
|
||||||
void Debug(const char *format, ...);
|
|
||||||
|
|
||||||
|
void ShowError(const char *format, ...);
|
||||||
void ShowProgress(u64 current, u64 total);
|
void ShowProgress(u64 current, u64 total);
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
#include "diskio.h" /* FatFs lower layer API */
|
#include "diskio.h" /* FatFs lower layer API */
|
||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
#include "sdmmc.h"
|
#include "sdmmc.h"
|
||||||
#include "3dsnand.h"
|
#include "nandio.h"
|
||||||
|
|
||||||
#define TYPE_SDCARD 0
|
#define TYPE_SDCARD 0
|
||||||
#define TYPE_SYSNAND 1
|
#define TYPE_SYSNAND 1
|
||||||
@ -53,6 +53,7 @@ FATpartition DriveInfo[28] = {
|
|||||||
{ 0xC00000, TYPE_EMUNAND, P_TWLP } // 27 - EMUNAND3 N3DS TWLP
|
{ 0xC00000, TYPE_EMUNAND, P_TWLP } // 27 - EMUNAND3 N3DS TWLP
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static bool mode_n3ds = false;
|
||||||
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------*/
|
/*-----------------------------------------------------------------------*/
|
||||||
@ -78,6 +79,7 @@ DSTATUS disk_initialize (
|
|||||||
BYTE pdrv /* Physical drive nmuber to identify the drive */
|
BYTE pdrv /* Physical drive nmuber to identify the drive */
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
mode_n3ds = (GetUnitPlatform() == PLATFORM_N3DS);
|
||||||
sdmmc_sdcard_init();
|
sdmmc_sdcard_init();
|
||||||
return RES_OK;
|
return RES_OK;
|
||||||
}
|
}
|
||||||
@ -96,6 +98,9 @@ DRESULT disk_read (
|
|||||||
UINT count /* Number of sectors to read */
|
UINT count /* Number of sectors to read */
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
if ((pdrv >= 4) && mode_n3ds)
|
||||||
|
pdrv += 12;
|
||||||
|
|
||||||
if (DriveInfo[pdrv].type == TYPE_SDCARD) {
|
if (DriveInfo[pdrv].type == TYPE_SDCARD) {
|
||||||
if (sdmmc_sdcard_readsectors(sector, count, buff)) {
|
if (sdmmc_sdcard_readsectors(sector, count, buff)) {
|
||||||
return RES_PARERR;
|
return RES_PARERR;
|
||||||
@ -127,6 +132,9 @@ DRESULT disk_write (
|
|||||||
UINT count /* Number of sectors to write */
|
UINT count /* Number of sectors to write */
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
if ((pdrv >= 4) && mode_n3ds)
|
||||||
|
pdrv += 12;
|
||||||
|
|
||||||
if (DriveInfo[pdrv].type == TYPE_SDCARD) {
|
if (DriveInfo[pdrv].type == TYPE_SDCARD) {
|
||||||
if (sdmmc_sdcard_writesectors(sector, count, (BYTE *)buff)) {
|
if (sdmmc_sdcard_writesectors(sector, count, (BYTE *)buff)) {
|
||||||
return RES_PARERR;
|
return RES_PARERR;
|
||||||
@ -161,6 +169,9 @@ DRESULT disk_ioctl (
|
|||||||
void *buff /* Buffer to send/receive control data */
|
void *buff /* Buffer to send/receive control data */
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
if ((pdrv >= 4) && mode_n3ds)
|
||||||
|
pdrv += 12;
|
||||||
|
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case GET_SECTOR_SIZE:
|
case GET_SECTOR_SIZE:
|
||||||
*((DWORD*) buff) = 0x200;
|
*((DWORD*) buff) = 0x200;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
#include "fatfs/aes.h"
|
#include "fatfs/aes.h"
|
||||||
#include "fatfs/3dsnand.h"
|
#include "fatfs/nandio.h"
|
||||||
#include "fatfs/sdmmc.h"
|
#include "fatfs/sdmmc.h"
|
||||||
|
|
||||||
// see: http://3dbrew.org/wiki/Flash_Filesystem
|
// see: http://3dbrew.org/wiki/Flash_Filesystem
|
||||||
@ -20,25 +20,25 @@ static u32 emunand_offset = 0;
|
|||||||
|
|
||||||
u32 CheckEmuNand(void)
|
u32 CheckEmuNand(void)
|
||||||
{
|
{
|
||||||
u8* buffer = BUFFER_ADDRESS;
|
u8 header[0x200];
|
||||||
u32 nand_size_sectors = getMMCDevice(0)->total_size;
|
u32 nand_size_sectors = getMMCDevice(0)->total_size;
|
||||||
u32 multi_sectors = (GetUnitPlatform() == PLATFORM_3DS) ? EMUNAND_MULTI_OFFSET_O3DS : EMUNAND_MULTI_OFFSET_N3DS;
|
u32 multi_sectors = (GetUnitPlatform() == PLATFORM_3DS) ? EMUNAND_MULTI_OFFSET_O3DS : EMUNAND_MULTI_OFFSET_N3DS;
|
||||||
u32 ret = EMUNAND_NOT_READY;
|
u32 ret = EMUNAND_NOT_READY;
|
||||||
|
|
||||||
// check the MBR for presence of a hidden partition
|
// check the MBR for presence of a hidden partition
|
||||||
sdmmc_sdcard_readsectors(0, 1, buffer);
|
sdmmc_sdcard_readsectors(0, 1, header);
|
||||||
u32 hidden_sectors = getle32(buffer + 0x1BE + 0x8);
|
u32 hidden_sectors = getle32(header + 0x1BE + 0x8);
|
||||||
|
|
||||||
for (u32 offset_sector = 0; offset_sector + nand_size_sectors < hidden_sectors; offset_sector += multi_sectors) {
|
for (u32 offset_sector = 0; offset_sector + nand_size_sectors < hidden_sectors; offset_sector += multi_sectors) {
|
||||||
// check for Gateway type EmuNAND
|
// check for Gateway type EmuNAND
|
||||||
sdmmc_sdcard_readsectors(offset_sector + nand_size_sectors, 1, buffer);
|
sdmmc_sdcard_readsectors(offset_sector + nand_size_sectors, 1, header);
|
||||||
if (memcmp(buffer + 0x100, "NCSD", 4) == 0) {
|
if (memcmp(header + 0x100, "NCSD", 4) == 0) {
|
||||||
ret |= EMUNAND_GATEWAY << (2 * (offset_sector / multi_sectors));
|
ret |= EMUNAND_GATEWAY << (2 * (offset_sector / multi_sectors));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// check for RedNAND type EmuNAND
|
// check for RedNAND type EmuNAND
|
||||||
sdmmc_sdcard_readsectors(offset_sector + 1, 1, buffer);
|
sdmmc_sdcard_readsectors(offset_sector + 1, 1, header);
|
||||||
if (memcmp(buffer + 0x100, "NCSD", 4) == 0) {
|
if (memcmp(header + 0x100, "NCSD", 4) == 0) {
|
||||||
ret |= EMUNAND_REDNAND << (2 * (offset_sector / multi_sectors));
|
ret |= EMUNAND_REDNAND << (2 * (offset_sector / multi_sectors));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
324
source/fs.c
324
source/fs.c
@ -1,226 +1,74 @@
|
|||||||
#include "fs.h"
|
|
||||||
#include "draw.h"
|
#include "draw.h"
|
||||||
|
#include "fs.h"
|
||||||
#include "fatfs/ff.h"
|
#include "fatfs/ff.h"
|
||||||
|
#include "fatfs/nandio.h"
|
||||||
|
|
||||||
static FATFS fs;
|
// don't use this area for anything else!
|
||||||
static FIL file;
|
static FATFS* fs = (FATFS*) 0x20316000;
|
||||||
static DIR dir;
|
// reserve one MB for this, just to be safe
|
||||||
|
static DirStruct* curdir_contents = (DirStruct*)0x21000000;
|
||||||
|
// this is the main buffer
|
||||||
|
// static u8* main_buffer = (u8*)0x21100000;
|
||||||
|
// number of currently open file systems
|
||||||
|
static u32 numfs = 0;
|
||||||
|
|
||||||
bool InitFS()
|
bool InitFS()
|
||||||
{
|
{
|
||||||
#ifndef EXEC_GATEWAY
|
#ifndef EXEC_GATEWAY
|
||||||
// TODO: Magic?
|
// TODO: Magic?
|
||||||
*(u32*)0x10000020 = 0;
|
*(u32*)0x10000020 = 0;
|
||||||
*(u32*)0x10000020 = 0x340;
|
*(u32*)0x10000020 = 0x340;
|
||||||
#endif
|
#endif
|
||||||
bool ret = (f_mount(&fs, "0:", 0) == FR_OK);
|
u32 emunand_state = CheckEmuNand();
|
||||||
#ifdef WORK_DIR
|
for (numfs = 0; numfs < 16; numfs++) {
|
||||||
f_chdir(WORK_DIR);
|
char fsname[8];
|
||||||
#endif
|
snprintf(fsname, 7, "%lu:", numfs);
|
||||||
return ret;
|
if ((numfs >= 4) && (emunand_state >> (2*((numfs-4)/3)) != EMUNAND_GATEWAY))
|
||||||
|
break;
|
||||||
|
if (f_mount(fs, fsname, 0) != FR_OK) {
|
||||||
|
ShowError("Initialising failed! (%lu/%s)", numfs, fsname);
|
||||||
|
DeinitFS();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeinitFS()
|
void DeinitFS()
|
||||||
{
|
{
|
||||||
LogWrite(NULL);
|
for (u32 i = 0; i < numfs; i++) {
|
||||||
f_mount(NULL, "0:", 1);
|
char fsname[8];
|
||||||
|
snprintf(fsname, 7, "%lu:", numfs);
|
||||||
|
f_mount(NULL, fsname, 1);
|
||||||
|
}
|
||||||
|
numfs = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FileOpen(const char* path)
|
bool GetRootDirContentsWorker(DirStruct* contents)
|
||||||
{
|
{
|
||||||
unsigned flags = FA_READ | FA_WRITE | FA_OPEN_EXISTING;
|
static const char* drvname[16] = {
|
||||||
if (*path == '/')
|
"sdcard",
|
||||||
path++;
|
"sysctrn", "systwln", "systwlp",
|
||||||
bool ret = (f_open(&file, path, flags) == FR_OK);
|
"emu0ctrn", "emu0twln", "emu0twlp",
|
||||||
#ifdef WORK_DIR
|
"emu1ctrn", "emu1twln", "emu1twlp",
|
||||||
f_chdir("/"); // temporarily change the current directory
|
"emu2ctrn", "emu2twln", "emu2twlp",
|
||||||
if (!ret) ret = (f_open(&file, path, flags) == FR_OK);
|
"emu3ctrn", "emu3twln", "emu3twlp"
|
||||||
f_chdir(WORK_DIR);
|
};
|
||||||
#endif
|
|
||||||
f_lseek(&file, 0);
|
|
||||||
f_sync(&file);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DebugFileOpen(const char* path)
|
for (u32 pdrv = 0; (pdrv < numfs) && (pdrv < MAX_ENTRIES); pdrv++) {
|
||||||
{
|
memset(contents->entry[pdrv].path, 0x00, 16);
|
||||||
Debug("Opening %s ...", path);
|
snprintf(contents->entry[pdrv].path + 0, 4, "%lu:", pdrv);
|
||||||
if (!FileOpen(path)) {
|
snprintf(contents->entry[pdrv].path + 4, 4, "%s", drvname[pdrv]);
|
||||||
Debug("Could not open %s!", path);
|
contents->entry[pdrv].name = contents->entry[pdrv].path + 4;
|
||||||
return false;
|
contents->entry[pdrv].size = 0;
|
||||||
|
contents->entry[pdrv].type = T_FAT_ROOT;
|
||||||
|
contents->n_entries = pdrv;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return contents->n_entries;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FileCreate(const char* path, bool truncate)
|
bool GetDirContentsWorker(DirStruct* contents, char* fpath, int fsize, bool recursive)
|
||||||
{
|
|
||||||
unsigned flags = FA_READ | FA_WRITE;
|
|
||||||
flags |= truncate ? FA_CREATE_ALWAYS : FA_OPEN_ALWAYS;
|
|
||||||
if (*path == '/')
|
|
||||||
path++;
|
|
||||||
bool ret = (f_open(&file, path, flags) == FR_OK);
|
|
||||||
f_lseek(&file, 0);
|
|
||||||
f_sync(&file);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DebugFileCreate(const char* path, bool truncate) {
|
|
||||||
Debug("Creating %s ...", path);
|
|
||||||
if (!FileCreate(path, truncate)) {
|
|
||||||
Debug("Could not create %s!", path);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t FileCopyTo(const char* dest, void* buf, size_t bufsize)
|
|
||||||
{
|
|
||||||
unsigned flags = FA_READ | FA_WRITE | FA_CREATE_ALWAYS;
|
|
||||||
size_t fsize = f_size(&file);
|
|
||||||
size_t result = fsize;
|
|
||||||
FIL dfile;
|
|
||||||
// make sure the containing folder exists
|
|
||||||
char tmp[256] = { 0 };
|
|
||||||
strncpy(tmp, dest, sizeof(tmp) - 1);
|
|
||||||
for (char* p = tmp + 1; *p; p++) {
|
|
||||||
if (*p == '/') {
|
|
||||||
char s = *p;
|
|
||||||
*p = 0;
|
|
||||||
f_mkdir(tmp);
|
|
||||||
*p = s;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// do the actual copying
|
|
||||||
if (f_open(&dfile, dest, flags) != FR_OK)
|
|
||||||
return 0;
|
|
||||||
f_lseek(&dfile, 0);
|
|
||||||
f_sync(&dfile);
|
|
||||||
f_lseek(&file, 0);
|
|
||||||
f_sync(&file);
|
|
||||||
for (size_t pos = 0; pos < fsize; pos += bufsize) {
|
|
||||||
UINT bytes_read = 0;
|
|
||||||
UINT bytes_written = 0;
|
|
||||||
ShowProgress(pos, fsize);
|
|
||||||
f_read(&file, buf, bufsize, &bytes_read);
|
|
||||||
f_write(&dfile, buf, bytes_read, &bytes_written);
|
|
||||||
if (bytes_read != bytes_written) {
|
|
||||||
result = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ShowProgress(0, 0);
|
|
||||||
f_close(&dfile);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t FileRead(void* buf, size_t size, size_t foffset)
|
|
||||||
{
|
|
||||||
UINT bytes_read = 0;
|
|
||||||
f_lseek(&file, foffset);
|
|
||||||
f_read(&file, buf, size, &bytes_read);
|
|
||||||
return bytes_read;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DebugFileRead(void* buf, size_t size, size_t foffset) {
|
|
||||||
size_t bytesRead = FileRead(buf, size, foffset);
|
|
||||||
if(bytesRead != size) {
|
|
||||||
Debug("ERROR, file is too small!");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t FileWrite(void* buf, size_t size, size_t foffset)
|
|
||||||
{
|
|
||||||
UINT bytes_written = 0;
|
|
||||||
f_lseek(&file, foffset);
|
|
||||||
f_write(&file, buf, size, &bytes_written);
|
|
||||||
f_sync(&file);
|
|
||||||
return bytes_written;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DebugFileWrite(void* buf, size_t size, size_t foffset)
|
|
||||||
{
|
|
||||||
size_t bytesWritten = FileWrite(buf, size, foffset);
|
|
||||||
if(bytesWritten != size) {
|
|
||||||
Debug("ERROR, SD card may be full!");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t FileGetSize()
|
|
||||||
{
|
|
||||||
return f_size(&file);
|
|
||||||
}
|
|
||||||
|
|
||||||
void FileClose()
|
|
||||||
{
|
|
||||||
f_close(&file);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DirMake(const char* path)
|
|
||||||
{
|
|
||||||
FRESULT res = f_mkdir(path);
|
|
||||||
bool ret = (res == FR_OK) || (res == FR_EXIST);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DebugDirMake(const char* path)
|
|
||||||
{
|
|
||||||
Debug("Creating dir %s ...", path);
|
|
||||||
if (!DirMake(path)) {
|
|
||||||
Debug("Could not create %s!", path);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DirOpen(const char* path)
|
|
||||||
{
|
|
||||||
return (f_opendir(&dir, path) == FR_OK);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DebugDirOpen(const char* path)
|
|
||||||
{
|
|
||||||
Debug("Opening %s ...", path);
|
|
||||||
if (!DirOpen(path)) {
|
|
||||||
Debug("Could not open %s!", path);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DirRead(char* fname, int fsize)
|
|
||||||
{
|
|
||||||
FILINFO fno;
|
|
||||||
fno.lfname = fname;
|
|
||||||
fno.lfsize = fsize;
|
|
||||||
bool ret = false;
|
|
||||||
while (f_readdir(&dir, &fno) == FR_OK) {
|
|
||||||
if (fno.fname[0] == 0) break;
|
|
||||||
if ((fno.fname[0] != '.') && !(fno.fattrib & AM_DIR)) {
|
|
||||||
if (fname[0] == 0)
|
|
||||||
strcpy(fname, fno.fname);
|
|
||||||
ret = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DirClose()
|
|
||||||
{
|
|
||||||
f_closedir(&dir);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool GetFileListWorker(char** list, int* lsize, char* fpath, int fsize, bool recursive, bool inc_files, bool inc_dirs)
|
|
||||||
{
|
{
|
||||||
DIR pdir;
|
DIR pdir;
|
||||||
FILINFO fno;
|
FILINFO fno;
|
||||||
@ -241,13 +89,23 @@ bool GetFileListWorker(char** list, int* lsize, char* fpath, int fsize, bool rec
|
|||||||
if (fno.fname[0] == 0) {
|
if (fno.fname[0] == 0) {
|
||||||
ret = true;
|
ret = true;
|
||||||
break;
|
break;
|
||||||
} else if ((inc_files && !(fno.fattrib & AM_DIR)) || (inc_dirs && (fno.fattrib & AM_DIR))) {
|
} else {
|
||||||
snprintf(*list, *lsize, "%s\n", fpath);
|
DirEntry* entry = &(contents->entry[contents->n_entries]);
|
||||||
for(;(*list)[0] != '\0' && (*lsize) > 1; (*list)++, (*lsize)--);
|
snprintf(entry->path, 256, "%s", fpath);
|
||||||
if ((*lsize) <= 1) break;
|
entry->name = entry->path + (fpath - fname);
|
||||||
|
if (fno.fattrib & AM_DIR) {
|
||||||
|
entry->type = T_FAT_DIR;
|
||||||
|
entry->size = 0;
|
||||||
|
} else {
|
||||||
|
entry->type = T_FAT_FILE;
|
||||||
|
entry->size = fno.fsize;
|
||||||
|
}
|
||||||
|
contents->n_entries++;
|
||||||
|
if (contents->n_entries >= MAX_ENTRIES)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if (recursive && (fno.fattrib & AM_DIR)) {
|
if (recursive && (fno.fattrib & AM_DIR)) {
|
||||||
if (!GetFileListWorker(list, lsize, fpath, fsize, recursive, inc_files, inc_dirs))
|
if (!GetDirContentsWorker(contents, fpath, fsize, recursive))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -256,53 +114,23 @@ bool GetFileListWorker(char** list, int* lsize, char* fpath, int fsize, bool rec
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GetFileList(const char* path, char* list, int lsize, bool recursive, bool inc_files, bool inc_dirs)
|
DirStruct* GetDirContents(const char* path)
|
||||||
{
|
{
|
||||||
|
curdir_contents->n_entries = 0;
|
||||||
|
if (strncmp(path, "", 256) == 0) { // root directory
|
||||||
|
if (!GetRootDirContentsWorker(curdir_contents))
|
||||||
|
curdir_contents->n_entries = 0; // not required, but so what?
|
||||||
|
} else {
|
||||||
char fpath[256]; // 256 is the maximum length of a full path
|
char fpath[256]; // 256 is the maximum length of a full path
|
||||||
strncpy(fpath, path, 256);
|
strncpy(fpath, path, 256);
|
||||||
return GetFileListWorker(&list, &lsize, fpath, 256, recursive, inc_files, inc_dirs);
|
if (!GetDirContentsWorker(curdir_contents, fpath, 256, false))
|
||||||
}
|
curdir_contents->n_entries = 0;
|
||||||
|
|
||||||
size_t LogWrite(const char* text)
|
|
||||||
{
|
|
||||||
#ifdef LOG_FILE
|
|
||||||
static FIL lfile;
|
|
||||||
static bool lready = false;
|
|
||||||
static size_t lstart = 0;
|
|
||||||
|
|
||||||
if ((text == NULL) && lready) {
|
|
||||||
f_sync(&lfile);
|
|
||||||
f_close(&lfile);
|
|
||||||
lready = false;
|
|
||||||
return lstart; // return the current log start
|
|
||||||
} else if (text == NULL) {
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!lready) {
|
return curdir_contents;
|
||||||
unsigned flags = FA_READ | FA_WRITE | FA_OPEN_ALWAYS;
|
|
||||||
lready = (f_open(&lfile, LOG_FILE, flags) == FR_OK);
|
|
||||||
if (!lready) return 0;
|
|
||||||
lstart = f_size(&lfile);
|
|
||||||
f_lseek(&lfile, lstart);
|
|
||||||
f_sync(&lfile);
|
|
||||||
}
|
|
||||||
|
|
||||||
const char newline = '\n';
|
|
||||||
UINT bytes_written;
|
|
||||||
UINT tlen = strnlen(text, 128);
|
|
||||||
f_write(&lfile, text, tlen, &bytes_written);
|
|
||||||
if (bytes_written != tlen) return 0;
|
|
||||||
f_write(&lfile, &newline, 1, &bytes_written);
|
|
||||||
if (bytes_written != 1) return 0;
|
|
||||||
|
|
||||||
return f_size(&lfile); // return the current position
|
|
||||||
#else
|
|
||||||
return 0;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint64_t ClustersToBytes(FATFS* fs, DWORD clusters)
|
/*static uint64_t ClustersToBytes(FATFS* fs, DWORD clusters)
|
||||||
{
|
{
|
||||||
uint64_t sectors = clusters * fs->csize;
|
uint64_t sectors = clusters * fs->csize;
|
||||||
#if _MAX_SS != _MIN_SS
|
#if _MAX_SS != _MIN_SS
|
||||||
@ -326,4 +154,4 @@ uint64_t RemainingStorageSpace()
|
|||||||
uint64_t TotalStorageSpace()
|
uint64_t TotalStorageSpace()
|
||||||
{
|
{
|
||||||
return ClustersToBytes(&fs, fs.n_fatent - 2);
|
return ClustersToBytes(&fs, fs.n_fatent - 2);
|
||||||
}
|
}*/
|
||||||
|
60
source/fs.h
60
source/fs.h
@ -3,71 +3,35 @@
|
|||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
T_NAND_BASE,
|
T_NAND_BASE, // might not be needed
|
||||||
T_NONFAT_ROOT,
|
T_NONFAT_ROOT, // might not be needed
|
||||||
T_FAT_ROOT,
|
T_FAT_ROOT,
|
||||||
T_FAT_FILE,
|
T_FAT_FILE,
|
||||||
T_FAT_DIR
|
T_FAT_DIR
|
||||||
} EntryType;
|
} EntryType;
|
||||||
|
|
||||||
|
#define MAX_ENTRIES 1024
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char* name; // should point to the correct portion of the path
|
char* name; // should point to the correct portion of the path
|
||||||
char path[256];
|
char path[256];
|
||||||
u32 size;
|
u32 size;
|
||||||
u32 offset;
|
EntryType type;
|
||||||
EntryType entryType;
|
|
||||||
} DirEntry;
|
} DirEntry;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
u32 n_entries;
|
||||||
|
DirEntry entry[MAX_ENTRIES];
|
||||||
|
} DirStruct;
|
||||||
|
|
||||||
bool InitFS();
|
bool InitFS();
|
||||||
void DeinitFS();
|
void DeinitFS();
|
||||||
|
|
||||||
/** Opens existing files */
|
/** Get directory content under a given path **/
|
||||||
bool FileOpen(const char* path);
|
DirStruct* GetDirContents(const char* path);
|
||||||
bool DebugFileOpen(const char* path);
|
|
||||||
|
|
||||||
/** Opens new files (and creates them if they don't already exist) */
|
|
||||||
bool FileCreate(const char* path, bool truncate);
|
|
||||||
bool DebugFileCreate(const char* path, bool truncate);
|
|
||||||
|
|
||||||
/** Copies currently opened file to destination (must provide buffer) */
|
|
||||||
size_t FileCopyTo(const char* dest, void* buf, size_t bufsize);
|
|
||||||
|
|
||||||
/** Reads contents of the opened file */
|
|
||||||
size_t FileRead(void* buf, size_t size, size_t foffset);
|
|
||||||
bool DebugFileRead(void* buf, size_t size, size_t foffset);
|
|
||||||
|
|
||||||
/** Writes to the opened file */
|
|
||||||
size_t FileWrite(void* buf, size_t size, size_t foffset);
|
|
||||||
bool DebugFileWrite(void* buf, size_t size, size_t foffset);
|
|
||||||
|
|
||||||
/** Gets the size of the opened file */
|
|
||||||
size_t FileGetSize();
|
|
||||||
|
|
||||||
/** Creates a directory */
|
|
||||||
bool DirMake(const char* path);
|
|
||||||
bool DebugDirMake(const char* path);
|
|
||||||
|
|
||||||
/** Opens an existing directory */
|
|
||||||
bool DirOpen(const char* path);
|
|
||||||
bool DebugDirOpen(const char* path);
|
|
||||||
|
|
||||||
/** Reads next file name to fname from opened directory,
|
|
||||||
returns false if all files in directory are processed.
|
|
||||||
fname needs to be allocated to fsize bytes minimum. */
|
|
||||||
bool DirRead(char* fname, int fsize);
|
|
||||||
|
|
||||||
/** Get list of files under a given path **/
|
|
||||||
bool GetFileList(const char* path, char* list, int lsize, bool recursive, bool inc_files, bool inc_dirs);
|
|
||||||
|
|
||||||
/** Writes text to a constantly open log file **/
|
|
||||||
size_t LogWrite(const char* text);
|
|
||||||
|
|
||||||
/** Gets remaining space on SD card in bytes */
|
/** Gets remaining space on SD card in bytes */
|
||||||
uint64_t RemainingStorageSpace();
|
uint64_t RemainingStorageSpace();
|
||||||
|
|
||||||
/** Gets total space on SD card in bytes */
|
/** Gets total space on SD card in bytes */
|
||||||
uint64_t TotalStorageSpace();
|
uint64_t TotalStorageSpace();
|
||||||
|
|
||||||
void FileClose();
|
|
||||||
|
|
||||||
void DirClose();
|
|
||||||
|
49
source/godmode.c
Normal file
49
source/godmode.c
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
#include "godmode.h"
|
||||||
|
#include "draw.h"
|
||||||
|
#include "hid.h"
|
||||||
|
#include "fs.h"
|
||||||
|
|
||||||
|
void DrawDirContents(DirStruct* contents, u32 offset, u32 cursor) {
|
||||||
|
const int str_width = 38;
|
||||||
|
const u32 stp_y = 10;
|
||||||
|
const u32 pos_x = 10;
|
||||||
|
u32 pos_y = 10;
|
||||||
|
|
||||||
|
for (u32 i = 0; pos_y < SCREEN_HEIGHT; i++) {
|
||||||
|
char tempstr[str_width + 1];
|
||||||
|
u32 offset_i = offset + i;
|
||||||
|
u32 color_font;
|
||||||
|
u32 color_bg;
|
||||||
|
if (offset_i < contents->n_entries) {
|
||||||
|
color_font = COLOR_WHITE;
|
||||||
|
color_bg = COLOR_BLACK;
|
||||||
|
snprintf(tempstr, str_width + 1, "%-*.*s", str_width, str_width, contents->entry[offset_i].name);
|
||||||
|
} else {
|
||||||
|
color_font = COLOR_BLACK;
|
||||||
|
color_bg = COLOR_WHITE;
|
||||||
|
snprintf(tempstr, str_width + 1, "%-*.*s", str_width, str_width, "");
|
||||||
|
}
|
||||||
|
DrawStringF(false, pos_x, pos_y, color_font, color_bg, tempstr);
|
||||||
|
pos_y += stp_y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 GodMode() {
|
||||||
|
u32 exit_mode = GODMODE_EXIT_REBOOT;
|
||||||
|
DirStruct* contents;
|
||||||
|
|
||||||
|
ClearScreenFull(true, true, COLOR_BLACK);
|
||||||
|
if (!InitFS()) {
|
||||||
|
// ShowError("Could not initialize fs!");
|
||||||
|
InputWait();
|
||||||
|
return exit_mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
contents = GetDirContents("");
|
||||||
|
DrawDirContents(contents, 0, 0);
|
||||||
|
InputWait();
|
||||||
|
|
||||||
|
DeinitFS();
|
||||||
|
|
||||||
|
return exit_mode;
|
||||||
|
}
|
8
source/godmode.h
Normal file
8
source/godmode.h
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
#define GODMODE_EXIT_REBOOT 0
|
||||||
|
#define GODMODE_EXIT_POWEROFF 1
|
||||||
|
|
||||||
|
u32 GodMode();
|
@ -1,4 +1,5 @@
|
|||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
#include "godmode.h"
|
||||||
#include "draw.h"
|
#include "draw.h"
|
||||||
#include "fs.h"
|
#include "fs.h"
|
||||||
#include "i2c.h"
|
#include "i2c.h"
|
||||||
@ -19,12 +20,6 @@ void PowerOff()
|
|||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
ClearScreenFull(true, true);
|
(GodMode() == GODMODE_EXIT_REBOOT) ? Reboot() : PowerOff();
|
||||||
InitFS();
|
|
||||||
|
|
||||||
u32 godmode_exit = 0;
|
|
||||||
|
|
||||||
DeinitFS();
|
|
||||||
(godmode_exit == 0) ? Reboot() : PowerOff();
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user