Nitrofs

From ProjectWiki
Jump to: navigation, search

Nitrofs Filesystem Driver for Nintendo DS

Contents

What is it?

Important!!!!; Small bug found in ndstool that may affect the nitrofs, read more here.

Nitrofs is a driver that allows accessing of files from a read-only nitro-filesystem appended to the end of a .nds file. This is how commercial carts store additional data and allows the homebrew app to only load into RAM what is currently needed by the game. In this way data such as large audio files, stage/level specific graphics, can be used without running out of memory.

Since all the game data is stored in one file along with the game or application itself there is no need to ask the end user to copy over alot of seperate files and clutter up their flashcard. :D Additionally this makes it slightly more difficult for inexperienced morons to change the graphics or audio of your game and call it their own than if all the data files were exposed as individual files on the flash card.

Am happy to announce that an implementation of this driver is finally included in the latest version of libnds!!! It is now part of libfilesystem. Yay \(^_^)/

If NitroFS is to be used with DeSmuME the following settings are required:<br> Emulation→GBA Slot→Compact Flash→folder<br> The most up-to-date information can be found at the desmume faq

Releases

Latest release : NitroFs Driver v0.8-turbo.tar.bz2 | Nitrofs Driver v0.7-turbo.tar.bz2
Previous releases : Nitrofs Driver v0.4.tar.bz2

The project archive contains three source files:

nitrofs.c - The nitro filesystem source.

nitrofs.h - The nitro filesystem header. This should only be included into the file where you have your nitroFSInit() call.

main.c - A working example that demonstrates using the filesystem, reading directories, and reading from a embedded audio file. In this case a wuvry song from the game Lotus Land Story by Zun which has the filename Th04_01.raw. Please enjoy.

The archive also contains an entire working example project and can be built by typing 'make' in the nitrotst directory as you would any other project using devkitPro.

Functional executable file of the latest test release in .nds format, as well as copies of the previous archives and raw source files, can be found here and may be useful for evaluation and testing.

Change Log

v0.2

  • Now the .nds file should work with both emulators and flashcards. (thx wintermutes) :DD
  • Fixed bug in fseek. SEEK_CUR should now work properly.

v0.3

  • ftell() now works as expected (v0.3)
  • Put back support for .gba and .sc.nds formatted files, now both .nds and .gba files should work in emulation
  • added stat() support

v0.3.1

  • added SEEK_END support..

v0.4

  • added errno values for several functions
  • added chdir functionality

v0.5.turbo

  • corrected SEEK_END so that the position argument is utilized
  • greatly improved file opening speed by around 106ms in dldi mode by reusing the .nds filehandle created at init for all subsequent operations.

v0.6.turbo

  • added full "." and ".." support. dirnext() will return . and .. first, and all relevent operations will support . and .. in pathnames.

v0.7.turbo

  • added errno values for several functions

v0.8.turbo

  • fixed problem with false GBA detection causing failures to initalize nitrofs properly
  • added documentation for auto-selection of filename

The latest 'turbo' release as mentioned improves file and directory opening and closing times, by using a single filehandle to access the .nds file when in FAT/DLDI mode. This is great for situations requiring reading a lot of seperate small files which most users will probaby desire, however it does take slightly longer when reading from multiple files at once. Details are here on the discussion page.

Older updates and more information on nitrofs can be found on the Discussion page. Feel free to ask questions, report bugs, or comments here. ^^

Creating the filesystem

You place all the stuff you want to have on the filesystem into a directory. For this example we have a directory named "MyNitroFS". This directory, its subdirectories, and all contents are then converted into nitro filesystem format and appended onto your executable using ndstool's -d option. Like So:

ndstool -c myhomebrew.nds -d MyNitroFS

Thats it, now all the stuffs in MyNitroFS dir is elegantly appended into one nice pretty file. XD

Important!!!! Bug found in ndstool affecting nitrofs, read more here.

Note: Do not use the -o option with ndstool for embedding wifi logos, this will break emulator support!

While its no longer necessary, if for whatever reason you need to use a .sc.nds or .ds.gba formatted file, dsbuild be used:

dsbuild myhomebrew.nds -o myhomebrew.ds.gba

In such a case nitrofs will automagically switch to gba mode and read the filesystem from gba's ROM space instead. This requires no changes to the code at all. ^^

Makefile Options

One complaint has always been, that without argv[0] support determining the filename required a #define or magical string within the file. Had knowns about the -D compiler option and that $(TARGET) is set to the name of the project directory, but only recently realized simply adding to arm9/Makefile: *

CFLAGS+=$(INCLUDE) -DARM9 -DNDSFILENAME=\"$(TARGET).nds\"

or for arm9 only builds: *

CFLAGS+=$(INCLUDE) -DARM9 -DNDSFILENAME=\"$(notdir $(OUTPUT)).nds\"

This is equivalent to:

#define NDSFILENAME "nameofmy.nds"

within the .c file calling nitroFSInit(), which may still be used if desired.

  • May need to tweak the examples for different Makefiles

Reading from nitrofs

Firstly, you'll need this includes:

#include <nds.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include "nitrofs.h" //only needed in the file where nitroFSInit() function is called.
#include <fat.h>

Then you will need to initialize the FAT driver, and the nitrofs driver:

fatInitDefault();
nitroFSInit("myndsfile.nds"); //See Notes Below
  • Replace 'myndsfile.nds' with the name of your .nds file so the driver knows where to find it. There may be problems if the end user places the homebrew file in an odd place like in an /apps/ directory. You could try to avoid this using the argv[0] argument passed to main() here (which points to the current file) however as of this writing it is not supported on all cards or loaders. So for now its prolly safest to just inform the end user that the file must be placed in the root directory of the card.

Some card's loaders will copy bits of the header to GBA slot RAM if present when loading which would previously confuse nitroFSInit() causing it attempt to read off GBA instead of fat. To solve this problem first made nitroFSInit check for a non NULL filename and then to try to read from FAT before reading from GBA.

nitroFSInit(NULL); //Force nitrofs to read from GBA slot

Lastly open a file as you would on any other system specifying nitro: as the drive:

fd=open("nitro:/Th04_01.raw",O_RDONLY);
read(fd, myBuffer, mybufferSize);
close(fd);

(Author's Note: Really dislike that they did not use Unix style nodes for drives and devices such as '/dev/device' or '/media/drive'. Instead opting for DOS 'drive:' style.. but jaja.. it works :D )

You may want to add some error checking and reporting in case the filename or filepath passed to nitroFSInit are incorrect, the card does not support DLDI. This can be done somewhat like this:

//Path to this executable containing nitrofs (if not defined already in Makefile)
#ifndef NDSFILENAME
#define NDSFILENAME "myndsfile.nds"
#endif
 
int fd;
int nitroOk;	//make sure nitroFs started ok
bool imfat;   //indicate fat driver loaded properly
printf("initalizing fat\n");
if(fatInitDefault()) {
	printf("Success...\n");
	nitroOk=nitroFSInit(NDSFILENAME);
        imfat=true;
} else {
	nitroOk=nitroFSInit(NULL);
        imfat=false;
}
printf("initalizing nitrofs\n");
if(nitroOk) {
        printf("Success...\n");
	fd=open("nitro:/myreadonlynitrofsfile.txt", O_RDONLY);
	if(fd>=0) {
		len=read(fd,sample,st.st_size);
		close(fd);
	} else {
		printf("read only file open failed\n");
	}
} else {
	printf("Failed... (normal for some emulators. Dont worry, yet :p)\n");
	printf("Failed...\n");
	if(imfat) { //error if fat was initialized...
		printf("Cannot open %s please check filename and path are correct.\n",FILENAME);
	} else { //error if fat/dldi failed
		printf("FAT/DLDI error, please to ensure your card supports DLDI.\n\n");
	}
}

FAQ

Isn't there already a way to do this?

The previous solutions for appending filesystems to .nds files were kinda suxy. For one thing they were not always compatible with most emulators and cards, or did not use the stdio subsystem as a proper filesystem driver should, instead requiring nonstandard open/close/read calls.

Before there were pretty much two options, GBFS and EFS. GBFS would work on emulators, but not off slot-1 cards, EFS would work off slot1 using DLDI but was was not compatible with most emulators. If you wanted to run your game on emulators AND off slot-1 flash cards you had to use two seperate libraries and use alot of #ifdef #else #endif type stuff because they used different function names, as well as neither (afaik) used stdio calls.

Since nitrofs v0.1 was released EFS has been updated to use stdio calls and fallback to gba reads.

Why can't you make it read/write instead of read only?

Because if DLDI/FAT is not enabled (as is on emulators), it attempts to read it in slot-2 gba mode which is read only. This project was partly created to help solve compatibility issues between different cards and emulators as well as do things in a way that more closely resembles a factory cart which is read only as well. Some people just want to do things in way that more closely resembles actual Nintendo libraries and possibly have dreams of one day doing a commercial release of their homebrew. [1] <_<


Personal tools
irssi scripts
eggdrop scripts