Day 8 - DS Hardware ← Previous

Day 9 - Filesystem

NOTE: This page is adapted from the Dutch tutorials. If you have any questions you can send them to the e-mail address at the bottom of the page.

Introduction

EFSlib (Embedded File System) is a library that allows you to append assets to your NDS file and read them. And... why? Well, you have a 4MB limit for assets embedded in the executable. To break the limit you must separate the assets from the code and have them in memory when neccessary. This tutorial will show you how to use EFSlib.

Integrating EFSlib with your project

First you have to copy the files efs_lib.h and efs_lib.c from the folder PAlib/examples/FAT/EFS/source to your project’s source folder and the EFS patcher (efs.exe) from PAlib/examples/FAT/EFS to your project’s root folder.

Second you must edit the Makefile. Remove the ‘#’ character in the line that starts with ‘#USE_EFS = YES’.

Third, you have to #include the efs_lib.h file in your main.c(pp). After doing so the include section should look like this:

#include <PA9.h>
#include "efs_lib.h"

Integrating EFSlib under Linux

For those of you who (like myself) use Linux, I decided to add this little note. In order to use EFS under Linux there’s a couple things you need to do. First, if you don’t already have it installed, install the Linux wine utility. Then add the three needed files just like above. Lastly, modify your PAlib/lib/PA_Makefile like so:

At the point where you find this:

#---------------------------------------------------------------------------------
%.ds.gba: %.nds
	@echo built ... $(notdir $@)
	@dsbuild $< 
ifeq ($(strip $(USE_EFS)), YES)
	@$(CURDIR)/../efs $(OUTPUT).ds.gba
endif

#---------------------------------------------------------------------------------
%.nds: %.bin
ifeq ($(strip $(USE_EFS)), YES)
	@ndstool -c $@ -9 $(TARGET).bin $(ARM7BIN) $(LOGO) $(ICON) "$(TEXT1);$(TEXT2);$(TEXT3)" -d ../efsroot
	@$(CURDIR)/../efs $(OUTPUT).nds
else
	@ndstool -c $@ -9 $(TARGET).bin $(ARM7BIN) $(LOGO) $(ICON) "$(TEXT1);$(TEXT2);$(TEXT3)"
endif

Add “wine” just before the “$(CURDIR)” variables [2] like this:

#---------------------------------------------------------------------------------
%.ds.gba: %.nds
	@echo built ... $(notdir $@)
	@dsbuild $< 
ifeq ($(strip $(USE_EFS)), YES)
	@ wine $(CURDIR)/../efs.exe $(OUTPUT).ds.gba
endif

#---------------------------------------------------------------------------------
%.nds: %.bin
ifeq ($(strip $(USE_EFS)), YES)
	@ndstool -c $@ -9 $(TARGET).bin $(ARM7BIN) $(LOGO) $(ICON) "$(TEXT1);$(TEXT2);$(TEXT3)" -d ../efsroot
	@ wine $(CURDIR)/../efs.exe $(OUTPUT).nds
else
	@ndstool -c $@ -9 $(TARGET).bin $(ARM7BIN) $(LOGO) $(ICON) "$(TEXT1);$(TEXT2);$(TEXT3)"
endif

And there you have it. Everything else is the same.

Fix - Wine must point to efs.exe file or it will fail (iSubaru)

Basic EFS usage

To add files to the EFS filesystem you just have to put them in the efsroot folder. If you don’t have it just create it :P

Well, now to the code! EFS is actually pretty easy to initialize:

#include <PA9.h>
#include "efs_lib.h"
 
int main(){
	PA_Init();
	PA_InitVBL();
 
	// Now for the EFSlib initialization
	if(!EFS_Init(EFS_AND_FAT | EFS_DEFAULT_DEVICE, NULL)){
		// Inform the user if there was an error
		PA_InitText(1, 1);
		PA_OutputSimpleText(1, 1, 1, "Error init'ing EFS!\n Make sure you DLDI patched\n the .nds file.");
		while(true) PA_WaitForVBL(); // infinite loop = hang
	}
 
	// Here goes the rest of your code
}
 

EFS usage primer

So, how do you actually read your assets from EFS? Well, guess what... You can use the standard C file functions! But the point here is how to actually load them to memory, so I guess I’ll just show you an example...

#include <PA9.h>
#include "efs_lib.h"
 
// Function to load data from the filesystem. You can just copypaste it to your project.
void* loadData(const char* file, void* ptr, u32* size){
	// Get the file size, additionally checks for file existance
	struct stat info;
	if(stat(file, &info) != 0) return NULL;
 
	// If the user didn't allocate memory for us then do it
	if(!ptr) if(!(ptr = malloc(info.st_size))) return NULL;
 
	// Else check the size of the buffer
	else if(*size < info.st_size) return NULL;
 
	// As the above checks succeeded the file is ensured to exist
	FILE* f = fopen(file, "rb");
	fread(ptr, 1, info.st_size, f);
	fclose(f);
 
	// Return the data and the size.
	if(size) *size = info.st_size;
	return ptr;
}
 
int main(){
	PA_Init();
	PA_InitVBL();
 
	// Now for the EFSlib initialization
	if(!EFS_Init(EFS_AND_FAT | EFS_DEFAULT_DEVICE, NULL)){
		// Inform the user if there was an error
		PA_InitText(1, 1);
		PA_OutputSimpleText(1, 1, 1, "Error init'ing EFS!\n Make sure you DLDI patched\n the .nds file.");
		while(true) PA_WaitForVBL(); // infinite loop = hang
	}
 
	// We're now going to display a JPEG image (copy a .jpg file to the efsroot folder to make this work)
	PA_Init16bitBg(1, 3);
	void* myJpeg = loadData("/photo.jpg", NULL, NULL); // load the JPEG - just don't care about the NULLs ok?
	PA_LoadJpeg(1, myJpeg);
 
	while(true){
		PA_WaitForVBL();
	}
}
 

This loadData() function also comes with some documentation :P Here’s how to use it:

u32 myData_size; // this var will contain the size of the file
// If you don't want the function to return the size of the file
// just pass a NULL as the third parameter, this was done in
// the example above.
void* myData = loadData("/myFile.bin", NULL, &myData_size);

If you have a preallocated buffer:

u8 myData[128];
u32 myData_size = 128; // pass the size of the buffer
loadData("/myFile.bin", myData, &myData_size);

Also, don’t forget to check the return value! It is NULL if an error occured.

Save files

Although EFS supports writing it’s a bad idea to write to the .nds file because save files can’t be removed. Instead you can write them to the user’s flashcard (that’s explained in the day 21), just forget about fatInitDefault() and be sure to prepend fat:/ to the file name.

Next → Day 12 - Quick Demos

 
day9.txt · Last modified: 10/02/2010 15:20 by 83.30.40.121
 
Recent changes RSS feed Creative Commons License Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki