mirror of
https://github.com/knightfox75/nds_nflib.git
synced 2025-06-18 08:45:35 -04:00
391 lines
11 KiB
C
391 lines
11 KiB
C
// SPDX-License-Identifier: MIT
|
|
//
|
|
// Copyright (c) 2009-2014 Cesar Rincon "NightFox"
|
|
// Copyright (c) 2023-2024 Antonio Niño Díaz "AntonioND"
|
|
//
|
|
// NightFox LIB - Basic and debug functions
|
|
// http://www.nightfoxandco.com/
|
|
|
|
#ifdef BLOCKSDS
|
|
#define iprintf printf
|
|
#endif
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <nds.h>
|
|
|
|
#include "nf_basic.h"
|
|
|
|
// Folder used as root by NFLib
|
|
char NF_ROOTFOLDER[64];
|
|
|
|
__attribute__((noreturn)) void NF_Error(u32 code, const char *text, unsigned int value)
|
|
{
|
|
consoleDemoInit(); // Initialize demo text console
|
|
setBrightness(3, 0); // Set the brightness to the top
|
|
|
|
switch (code)
|
|
{
|
|
case 101: // File not found
|
|
iprintf("File %s not found.\n", text);
|
|
break;
|
|
|
|
case 102: // Not enough memory
|
|
iprintf("Out of memory.\n");
|
|
iprintf("%u bytes\n", value);
|
|
iprintf("can't be allocated.\n");
|
|
break;
|
|
|
|
case 103: // Not enough free slots
|
|
iprintf("Out of %s slots.\n", text);
|
|
iprintf("All %u slots are in use.\n", value);
|
|
break;
|
|
|
|
case 104: // Tiled background not found
|
|
iprintf("Tiled Bg %s\n", text);
|
|
iprintf("not found.\n");
|
|
break;
|
|
|
|
case 105: // Background hasn't been created
|
|
iprintf("Background number %u\n", value);
|
|
iprintf("on screen %s is\n", text);
|
|
iprintf("not created.\n");
|
|
break;
|
|
|
|
case 106: // Value out of range
|
|
iprintf("%s value out\n", text);
|
|
iprintf("of range (%u max).\n", value);
|
|
break;
|
|
|
|
case 107: // Not enough contiguous VRAM blocks (tiles)
|
|
iprintf("Can't allocate %d\n", (int)value);
|
|
iprintf("blocks of tiles for\n");
|
|
iprintf("%s background\n", text);
|
|
iprintf("Free %d KB of VRAM or try to\n", (value * 16384) / 1024);
|
|
iprintf("reload all BGs again\n");
|
|
break;
|
|
|
|
case 108: // Not enough contiguous VRAM blocks (maps)
|
|
iprintf("Can't allocate %d\n", (int)value);
|
|
iprintf("blocks of maps for\n");
|
|
iprintf("%s background\n", text);
|
|
iprintf("Free %d KB of VRAM or try to\n", (value * 2048) / 1024);
|
|
iprintf("reload all BGs again\n");
|
|
break;
|
|
|
|
case 109: // ID in use
|
|
iprintf("%s ID %u\n", text, value);
|
|
iprintf("is already in use.\n");
|
|
break;
|
|
|
|
case 110: // ID not loaded
|
|
iprintf("%s\n", text);
|
|
iprintf("%u not loaded.\n", value);
|
|
break;
|
|
|
|
case 111: // ID not in VRAM
|
|
iprintf("%s\n", text);
|
|
iprintf("%u not in VRAM.\n", value);
|
|
break;
|
|
|
|
case 112: // Sprite not created
|
|
iprintf("Sprite number %u\n", value);
|
|
iprintf("on screen %s is\n", text);
|
|
iprintf("not created.\n");
|
|
break;
|
|
|
|
case 113: // Not enough VRAM
|
|
iprintf("Out of VRAM.\n");
|
|
iprintf("%u bytes for %s\n", value, text);
|
|
iprintf("can't be allocated.\n");
|
|
break;
|
|
|
|
case 114: // Text layer doesn't exist
|
|
iprintf("Text layer on screen\n");
|
|
iprintf("%u layer doesn't exist.\n", value);
|
|
break;
|
|
|
|
case 115: // Invalid tiled background size (not a multiple of 256)
|
|
iprintf("Tiled BG %s\n", text);
|
|
iprintf("has wrong size.\n");
|
|
iprintf("Your bg sizes must be\n");
|
|
iprintf("a multiple of 256 pixels.\n");
|
|
break;
|
|
|
|
case 116: // File is too big
|
|
iprintf("File %s\n", text);
|
|
iprintf("is too big.\n");
|
|
iprintf("Max size for\n");
|
|
iprintf("file is %u KB.\n", value / 1024);
|
|
break;
|
|
|
|
case 117: // Invalid affine background size (only 256x256 and 512x512 allowed)
|
|
iprintf("Affine BG %s\n", text);
|
|
iprintf("has wrong size.\n");
|
|
iprintf("Your bg sizes must be\n");
|
|
iprintf("256x256 or 512x512 and\n");
|
|
iprintf("with 256 tiles or less.\n");
|
|
break;
|
|
|
|
case 118: // Invalid affine background layer
|
|
iprintf("Affine Bg %s\n", text);
|
|
iprintf("only can be created\n");
|
|
iprintf("on layers 2 or 3.\n");
|
|
break;
|
|
|
|
case 119: // Invalid texture size
|
|
iprintf("Texture ID %u illegal size.\n", value);
|
|
iprintf("Only power of 2 sizes can\n");
|
|
iprintf("be used (8 to 1024).\n");
|
|
break;
|
|
|
|
case 120: // Invalid sprite size
|
|
iprintf("Sprite ID %u illegal size.\n", value);
|
|
iprintf("8x8 Sprites can't be used\n");
|
|
iprintf("in 1D_128 mode.\n");
|
|
break;
|
|
|
|
case 121: // Failed to fseek()
|
|
iprintf("fseek() failed:\n");
|
|
iprintf("%s\n", text);
|
|
break;
|
|
|
|
case 122: // Failed to fread()
|
|
iprintf("fread() failed:\n");
|
|
iprintf("%s\n", text);
|
|
break;
|
|
|
|
case 123: // Failed to fclose()
|
|
iprintf("fclose() failed:\n");
|
|
iprintf("%s\n", text);
|
|
break;
|
|
}
|
|
|
|
// Print error code
|
|
iprintf("Error code %d.\n", (int)code);
|
|
|
|
// Stop program
|
|
while (1)
|
|
swiWaitForVBlank();
|
|
}
|
|
|
|
void NF_SetRootFolder(const char *folder)
|
|
{
|
|
if (strcmp(folder, "NITROFS") == 0)
|
|
{
|
|
// Initialize both NitroFS and FAT
|
|
|
|
// Define NitroFS as the root folder
|
|
snprintf(NF_ROOTFOLDER, sizeof(NF_ROOTFOLDER), "%s", "");
|
|
|
|
// Check if NitroFS exists. NitroFS must be mounted beforehand for this
|
|
// to work.
|
|
if (access("nitro:/", F_OK) == 0)
|
|
{
|
|
// NitroFS started ok. Set it as the NFLib root folder
|
|
chdir("nitro:/");
|
|
}
|
|
else
|
|
{
|
|
// NitroFS start error
|
|
|
|
// Initialize text console
|
|
consoleDemoInit();
|
|
|
|
if (NF_GetLanguage() == 5)
|
|
{
|
|
iprintf("Error iniciando NitroFS.\n");
|
|
iprintf("Programa detenido.\n\n");
|
|
iprintf("Verifica que tu flashcard\n");
|
|
iprintf("es compatible con Argv.\n");
|
|
iprintf("Si no lo es, intenta usar el\n");
|
|
iprintf("Homebrew Menu para ejecutarla.\n\n");
|
|
}
|
|
else
|
|
{
|
|
iprintf("NitroFS Init Error.\n");
|
|
iprintf("Abnormal termination.\n\n");
|
|
iprintf("Check if your flashcard is\n");
|
|
iprintf("Argv compatible.\n");
|
|
iprintf("If not, try to launch the ROM\n");
|
|
iprintf("using the Homebrew Menu.\n\n");
|
|
}
|
|
iprintf("https://github.com/devkitPro/nds-hb-menu/releases");
|
|
|
|
// Stop program
|
|
while (1)
|
|
swiWaitForVBlank();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Initialize FAT only
|
|
|
|
// Define the root folder of NFLib
|
|
snprintf(NF_ROOTFOLDER, sizeof(NF_ROOTFOLDER), "%s", folder);
|
|
|
|
// Check where the NDS is running from
|
|
bool init_ok = false;
|
|
|
|
// First, try to detect the drive where the NDS ROM is. If argv has been
|
|
// provided by the loader, it will contain the drive and the path of the
|
|
// ROM.
|
|
if (__system_argv->argvMagic == ARGV_MAGIC && __system_argv->argc >= 1)
|
|
{
|
|
if (strncmp(__system_argv->argv[0], "fat:", 4) == 0)
|
|
{
|
|
// If argv starts by "fat:", try to setup "fat:" as root
|
|
if (access("fat:/", F_OK) == 0)
|
|
{
|
|
chdir("fat:/");
|
|
init_ok = true;
|
|
}
|
|
}
|
|
else if (strncmp(__system_argv->argv[0], "sd:", 3) == 0)
|
|
{
|
|
// If argv starts by "sd:", try to setup "sd:" as root
|
|
if (access("sd:/", F_OK) == 0)
|
|
{
|
|
chdir("sd:/");
|
|
init_ok = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Second, try to bruteforce the detection. Check if there is access to
|
|
// the SD card of the DSi first. If not, try with DLDI.
|
|
if (!init_ok)
|
|
{
|
|
if (access("sd:/", F_OK) == 0)
|
|
{
|
|
chdir("sd:/");
|
|
init_ok = true;
|
|
}
|
|
else if (access("fat:/", F_OK) == 0)
|
|
{
|
|
chdir("fat:/");
|
|
init_ok = true;
|
|
}
|
|
}
|
|
|
|
// If that didn't work, give up.
|
|
if (!init_ok)
|
|
{
|
|
// NitroFS start error
|
|
|
|
// Initialize text console
|
|
consoleDemoInit();
|
|
|
|
if (NF_GetLanguage() == 5)
|
|
{
|
|
iprintf("Error iniciando FAT.\n");
|
|
iprintf("Programa detenido.\n\n");
|
|
iprintf("Verifica que tu flashcard es\n");
|
|
iprintf("compatible con DLDI y la ROM\n");
|
|
iprintf("este parcheada correctamente.\n");
|
|
}
|
|
else
|
|
{
|
|
iprintf("FAT Init Error.\n");
|
|
iprintf("Abnormal termination.\n\n");
|
|
iprintf("Check if your flashcard is\n");
|
|
iprintf("DLDI compatible and the ROM\n");
|
|
iprintf("is correctly patched.\n");
|
|
}
|
|
|
|
// Stop program
|
|
while (1)
|
|
swiWaitForVBlank();
|
|
}
|
|
}
|
|
}
|
|
|
|
void NF_DmaMemCopy(void *destination, const void *source, u32 size)
|
|
{
|
|
// Based on Coranac's function:
|
|
// http://www.coranac.com/2009/05/dma-vs-arm9-fight/
|
|
|
|
// Source and destination addresses
|
|
u32 src = (u32)source;
|
|
u32 dst = (u32)destination;
|
|
|
|
// Check if addresses are aligned to at least 16 bits
|
|
if ((src | dst) & 1)
|
|
{
|
|
// Not aligned. DMA can't be used, use memcpy()
|
|
memcpy(destination, source, size);
|
|
}
|
|
else
|
|
{
|
|
// Addresses are aligned, use DMA
|
|
|
|
// Wait until channel 3 is available
|
|
while (dmaBusy(3));
|
|
|
|
// Make sure that the data in the cache is sent to the main RAM
|
|
DC_FlushRange(source, size);
|
|
|
|
// Depending on the alignment use 32-bit or 16-bit copy modes
|
|
if ((src | dst | size) & 3)
|
|
dmaCopyHalfWords(3, source, destination, size);
|
|
else
|
|
dmaCopyWords(3, source, destination, size);
|
|
|
|
// Prevent the destination from being in cache, it would corrupt the
|
|
// data when it is flushed
|
|
DC_InvalidateRange(destination, size);
|
|
}
|
|
}
|
|
|
|
void NF_FileLoad(const char *path, char **buffer, size_t *size, size_t min_size)
|
|
{
|
|
FILE *f = fopen(path, "rb");
|
|
if (f == NULL)
|
|
NF_Error(101, path, 0);
|
|
|
|
// Get file size
|
|
if (fseek(f, 0, SEEK_END) != 0)
|
|
NF_Error(121, path, 0);
|
|
|
|
size_t size_ = ftell(f);
|
|
rewind(f);
|
|
|
|
// If the file size is smaller than the minimum size, pad it with zeroes
|
|
// with calloc().
|
|
char *buffer_;
|
|
if (size_ < min_size)
|
|
{
|
|
buffer_ = calloc(min_size, sizeof(char));
|
|
*size = min_size;
|
|
}
|
|
else
|
|
{
|
|
buffer_ = malloc(size_);
|
|
*size = size_;
|
|
}
|
|
|
|
if (buffer_ == NULL)
|
|
NF_Error(102, NULL, size_);
|
|
|
|
*buffer = buffer_;
|
|
|
|
// Read full file to the start of the buffer
|
|
if (fread(buffer_, 1, size_, f) != size_)
|
|
NF_Error(122, path, 0);
|
|
|
|
if (fclose(f) != 0)
|
|
NF_Error(123, path, 0);
|
|
}
|
|
|
|
bool NF_FileExists(const char *path)
|
|
{
|
|
FILE *f = fopen(path, "rb");
|
|
if (f == NULL)
|
|
return false;
|
|
|
|
if (fclose(f) != 0)
|
|
NF_Error(123, path, 0);
|
|
|
|
return true;
|
|
}
|