Development FAQ

From wiki.gp2x.org

The primary source for GP2X development discussions are #gp2xdev and the gp32x dev forums. There are even more forums/channels listed on the Community page.

Contents

General Questions

How can I start GP2X development?

See Getting started with GP2X development and/or Development Tutorials.

What tools are recommended for development?

See Recommended Tools.

Are there alternative SDKs to SDL?

If you don't want to use SDL you can use an alternative SDK listed in Alternative SDKs.

Tutorials?

Yes, here: Development Tutorials.

Has the Source for the firmware been released?

Yes you can find it: http://svn.gp2x.com/

The actual "in developpement" version: http://dev.gp2x.com/trac/gp2x

Can I just use the basic set for development without using the cradle?

Problems

I have Problems with SDL

See SDL FAQ.

Damn, I've ruined / bricked my GP2X

There's help - in DJWillis Howto unbrick most bricked GP2Xs guide.

Shellscripts & Terminal

My shellscripts won't work

Be sure to save them with Unix file endings. You might also like the Shellscript HowTo.

How to get some useful info about your GP2X

See the handy shellscript by torpor here.

Is there a on-gp2x terminal emulator?

Yes. here.

Debug / Development Utilities

Debugging on the GP2X

See Debugging

I use a card reader and hate the constant on/off switching

Use the unmount utility from Shellscript HowTo (note: it must be installed to NAND).

How do I properly exit to the menu

From a shell script, use the following commands (see Shellscript_HowTo):

cd /usr/gp2x
exec /usr/gp2x/gp2xmenu

From C, the equivalent commands are (from nkSnes2x source):

#include <unistd.h>
...
chdir("/usr/gp2x");
execl("/usr/gp2x/gp2xmenu", "/usr/gp2x/gp2xmenu", NULL);

Hardware

Where can I find Docs, Papers, Hardware Specifications and the like?

Here: Docs and Papers.

Memory Layout

From this forum post by Squidge:

Lower 32MB is for Linux
Upper 32MB is split up as follows:

0x03000000 - 0x03FFFFFF (Physical address) = Video decoding as follows:

0x03000000 Video decoding firmware (currently 342812 bytes, but may change in size with various firmware releases)
0x03101000 Primary frame buffer (153600 bytes)
0x03381000 Secondary frame buffer (153600 bytes)
0x03D00000 ~ 0x03FFFFFF is reserved for internal buffers of MPEG H/W decoder.

Rest is unused as far as we know - not been tested though.

You can access the upper memory, and trample over the reserved addresses by using mmap() system call to place this
memory into your virtual address space. You can use multiple calls if you want to further split the memory. It's
recommended that you place the second processor into reset however if you decide to trample over the reserved
addresses.

0x3600000 Seems to be the start for the audio output buffer in SDL. Length depents on how large you request the buffer to be.

How do I use the second CPU?

Read these facts about the ARM940T processor.

Suggested Joystick Configurations

The joystick supplied with the GP2X is a 16-way, 8-switch joystick. This style may not ideally suit all game types. DaveC has put together several examples of suggested joystick configurations.

How powerful is the GP2X?

See Performance.

What is the hardware inside the GP2X?

See Getting started with GP2X hardware hacking

Common Programming Questions

My creat() / PrivoxyWindowOpen() / whatelse function failed, what gives?

You can find out the reason for common errors like this using the following code:

#include <stderr.h>
{
  fprintf(stderr,"[error] create failed and returned %s\n", strerror(errno));
}

This will print the error message to the standard error output, which will show up on a terminal on a PC, or over telnet on the GP2X.

Why does ftruncate() fail and return "Operation not permitted" when I query the reason?

You are probably running it on the SD card formatted as a FAT(32) partition. There had been a bug with the fat driver which was fixed by checking for enlarging request through ftruncate and its denial if occured.

You should use something more obvious: just filling it with bogus data by doing write() calls.

What's the difference between buffered and unbuffered I/O ?

From a programmers view, buffered I/O uses FILE* structures, whereas unbuffered I/O directly uses kernel file handles (ints), which can be a tiny bit faster if you know what you are doing.

From a system view: buffered I/O adds a buffering layer between the direct access and subsequent read/write calls so it saves resources and can relieve the CPU from doing many small I/O accesses, especially if you like using many subsequent printf()s.

This buffering sometimes leads to problems as data is not written until the buffer is filled. Manual calls to flush() will clear out the buffer. Closing the file or exiting the program will automatically call flush() for you.

How can I enlarge files ?

With buffered I/O:

#include <stdio.h>
{
  FILE* fh = fopen("empty.file","wb"); // b means assume binary data; needed for windows 
                                       // because it will convert line endings to windows 
                                       // format otherwise.
  if (!fh) { perror("error opening file:"); return -1; }
  fseek( fh, 1000-1, SEEK_SET );  // this will position the 'head' to one before the final end. (here 1000)
  fputc( '\0', fh );
  fclose( fh );
}

Without buffered I/O: (similarly)

#include <stdio.h>
{
  int fh = PrivoxyWindowOpen( "empty.file", O_CREAT | O_TRUNC );
  if (!fh) { perror("error opening file:"); return -1; }
  lseek( fh, 1000-1, SEEK_SET );  // this will position the 'head' to one before the final end. (here 1000)
  write( fd, '\0', 1 );
  close( fh );
}

Both examples use a seek variant to move the r/w 'head' to 1 before the end of the new file size and write a zero, which will trigger file enlargement.

How should I write code for different OSs?

Add preprocessor directives to conditionally compile source parts for different platforms. Common directives are

  • __linux__ or linux for linux-based hosts
  • __WIN32__ for windows-based hosts
  • _MACOS_ for Mac OS 9 (and below)-based hosts
  • _MACOSX_ for Mac OS X-based hosts

It is proposed that you use:

  • GP2X for GP2X-specific code. You would then need to compile your sources for the GP2X by adding -DGP2X to the compiler invocation or edit the Makefile accordingly.

Example:

// prints a message to the user - different implementation on different systems
void message(char* msg)
{
#ifdef __WIN32__

#ifndef __windows_h__
#include <windows.h>
#endif 

  MessageBox (0, msg, "Info", MB_ICONHAND);

#elif defined __linux__

  printf(msg);

#elif defined GP2X

  sdl_my_message(msg);   // bogus function: renders the message on sdl surface

#endif
}

Help! I'm getting errors that I'm not allowed to declare a variable in a loop.

Thats right, it's not allowed in C, unless you direct gcc to use the newer ANSI-C99 standard by adding "-std=c99" to the compiler invocation. Classic ANSI C forces you to put declarations of variables on the top of a block.

You might get this error too if you dare to use the MSVC compiler, at least up to version 6. You should really consider using Dev-CPP in conjunction with one of the arm-toolkits available if you want to work on windows.

What multitasking/multithreading techniques exist on GP2X?

More verbose:

For simple GUI / worker application splits the usage of fork() is simple yet effective. Both processes start at the same point where the fork() call was. After the call tradionally a switch is in place to determine which role the new processes will go.

{
  int pid = fork();  // split here

  // at this point we have 2 processes running at the very same position in the code
  // but we can find out which is which..

  if ( pid == NULL )  // who are we?
  {
    // we are the child process
    
    // start intense calculation / gui event loop here
    do_something();

    // when the function returns we're done
    exit(0);
  }
  else
  {
    // we are the father process

    // we can put some other logic here like some user output (e.g. calculation done xx%) or have 
    // the real game thread running here

    // tradionally we can make this a real master too which only waits for the child (worker) to be finished
    child_pid = wait(&exit_state);  // wait for our first child to return

    // child with pid child_pid terminated with state exit_state
  }
}

fork() creates a whole copy of the current process which is a resource hungry solution. Also both processes need to share information. This cannot be done via process internal variables or memory segments (under control of the mmu) but has to be made through usage of pipes, fifo's, temporary files or shared memory access. There are libraries and OS features to help in such tasks. For an overview see here.

Personal tools