Rlyeh's Minimal Library Updated ![ver0.3]


ks5202

Still Fresh
Joined
Nov 14, 2005
Messages
16
/*
GP2X minimal library v0.3 by rlyeh, 2005.

+ GP2X video library with double buffering.
+ GP2X joystick library.
+ GP2X soundring buffer library.

Thanks to Squidge and Robster, for the help & previous work! :)
*/

#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <sys/soundcard.h>
#include <linux/fb.h>

extern void sound_frame(void *blah, void *bufferg, int samples);


enum { GP2X_UP=0x1,GP2X_LEFT=0x4,GP2X_DOWN=0x10,GP2X_RIGHT=0x40,
GP2X_START=1<<8,GP2X_SELECT=1<<9,GP2X_L=1<<10,GP2X_R=1<<11,
GP2X_A=1<<12,GP2X_B=1<<13,GP2X_X=1<<14,GP2X_Y=1<<15,
GP2X_VOLM=1<<22,GP2X_VOLP=1<<23,GP2X_PUSH=1<<27,GP2X_BUFFSIZE=44100/50 };

unsigned long gp2x_dev[4], gp2x_physvram[4];
unsigned short *gp2x_memregs, *gp2x_screen, *gp2x_logvram[2], gp2x_sound_buffer[2+GP2X_BUFFSIZE*4];


void gp2x_video_flip(void)
{
unsigned long address=gp2x_physvram[gp2x_physvram[3]];

gp2x_screen=gp2x_logvram[gp2x_physvram[3]^=1];

gp2x_memregs[0x290E>>1]=(unsigned short)(address & 0xffff);
gp2x_memregs[0x2910>>1]=(unsigned short)(address >> 16);
gp2x_memregs[0x2912>>1]=(unsigned short)(address & 0xffff);
gp2x_memregs[0x2914>>1]=(unsigned short)(address >> 16);
}

unsigned long gp2x_joystick_read(void)
{
unsigned long value=(gp2x_memregs[0x1198>>1] & 0x00FF);

if(value==0xFD) value=0xFA;
if(value==0xF7) value=0xEB;
if(value==0xDF) value=0xAF;
if(value==0x7F) value=0xBE;

return ~((gp2x_memregs[0x1184>>1] & 0xFF00) | value | (gp2x_memregs[0x1186>>1] << 16));
}

void gp2x_sound_play(void)
{
if( !gp2x_dev[3] ) return;

sound_frame(NULL, &gp2x_sound_buffer[2], gp2x_sound_buffer[0]);
write( gp2x_dev[3], &gp2x_sound_buffer[2], gp2x_sound_buffer[1]);
}

void gp2x_init(int rate, int bits, int stereo)
{
struct fb_fix_screeninfo fixed_info;

gp2x_dev[0] = open("/dev/fb0", O_RDWR);
gp2x_dev[1] = open("/dev/fb1", O_RDWR);
gp2x_dev[2] = open("/dev/mem", O_RDWR);
gp2x_dev[3] = open("/dev/dsp", O_WRONLY);

gp2x_memregs=(unsigned short *)mmap(0, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, gp2x_dev[2], 0xc0000000);

ioctl (gp2x_dev[0], FBIOGET_FSCREENINFO, &fixed_info);
gp2x_logvram[0]=(unsigned short *)mmap(0, 320*240*2, PROT_WRITE, MAP_SHARED, gp2x_dev[0], 0);
gp2x_physvram[0]=fixed_info.smem_start;

ioctl (gp2x_dev[1], FBIOGET_FSCREENINFO, &fixed_info);
gp2x_logvram[1]=(unsigned short *)mmap(0, 320*240*2, PROT_WRITE, MAP_SHARED, gp2x_dev[1], 0);
gp2x_physvram[1]=fixed_info.smem_start;

gp2x_screen=gp2x_logvram[gp2x_physvram[3]=0];

gp2x_sound_buffer[1]=(gp2x_sound_buffer[0]=GP2X_BUFFSIZE/(44100/rate)) << (stereo + (bits==16));

ioctl(gp2x_dev[3], SNDCTL_DSP_SETFMT, &bits);
ioctl(gp2x_dev[3], SNDCTL_DSP_STEREO, &stereo);
ioctl(gp2x_dev[3], SNDCTL_DSP_SPEED, &rate);
}

void gp2x_deinit(void)
{
close(gp2x_dev[0]);
close(gp2x_dev[1]);
close(gp2x_dev[2]);
close(gp2x_dev[3]);

chdir("/usr/gp2x");
execl("gp2xmenu",NULL);
}


/*

EXAMPLE
=======

now supply your own function for 16 bits, stereo:

void sound_frame(void *blah, void *bufferg, int samples)
{
signed short *buffer=(signed short *)bufferg;
while(samples--)
{
*buffer++=0; //Left channel
*buffer++=0; //Right channel
}
}

or for 8 bits, mono:

void sound_frame(void *blah, void *bufferg, int samples)
{
unsigned char *buffer=(unsigned char *)bufferg;
while(samples--)
{
*buffer++=0; //Central channel
}
}

etc... and done:

int main(int argc, char *argv[])
{
gp2x_init(44100,16,1);

while(1)
{
gp2x_screen[160+120*320]=(gp2x_joystick_read()&GP2X_X?0xFFFF:0); //pixel is RGB:565
gp2x_video_flip();
gp2x_sound_play();
}

gp2x_deinit();
}

*/

--------------------------------------------
http://retrodev.info

-- NK's Speaker Changed sound test. --

First, Speaker was stereo.
But, came out well for stereo sound system as basis establishment is and change a little establishment price by Mono.
Circuit of internal organs speaker need to be normally and change a little basis establishment price.
And right and left was normally at refreshing in sound player after first booting case of earphone.
However, volume adjustment defect be mistaken ...
Earphone will study solution method after test much more.
 
Where are the diagonal switches? Are they in the gaps in that enum. eg. GP2X_UPLEFT = 0x20?

What is the meaning of GP2X_VOLM and GP2X_VOLP? I know they are for the volume buttons, but what do the M and P mean? Which one is volume up and which one is volume down?
 
Where are the diagonal switches? Are they in the gaps in that enum. eg. GP2X_UPLEFT = 0x20?
Rlyeh (like me) reads the diagonal then outputs the result as if GP2X_LEFT and GP2X_UP were pressed together instead, so it handles like a normal 4 way stick instead of 8 way. Much easier to work with. If you want the diagonal values then the stick starts with up at 1<<0 and goes anticlockwise to upright at 1<<7 (so you would define GP2X_UPLEFT as 1<<1).
 
Last edited by a moderator:
Ahh, yes, that's what I meant in my example, ie. 0x2 instead of 0x20. Good. That means that I can access the diagonal switches.

Can someone explain what his joystick read function does? What are the four magic values that get replaced by four other magic values? Is that the replacement of UPLEFT with UP and LEFT? What is the purpose of the memory locations 1184 and 1186? Is this documented in the MagicEyes PDFs somewhere?
 
What are the four magic values that get replaced by four other magic values?

They are bitpatterns.

Is that the replacement of UPLEFT with UP and LEFT?

I'm assuming pretty much :)

What is the purpose of the memory locations 1184 and 1186? Is this documented in the MagicEyes PDFs somewhere?

1184 and 1186 (actually, 0xC0001184 & 0xC0001186, as they are offset) are documented in the Magiceyes PDF as GPIO (General Purpose I/O) ports. They are the ports GPH decided to stick the buttons and joystick to.
 
Last edited by a moderator:
Which PDF was it? um.pdf seems to be a user manual for MagicEye's DEPSS development system. I'm just trying to find out where this information can be found so I can start doing some coding myself without having to wait for you guys to release something. And where did you find out what ports GPH used for what?
 
You need to read the datasheet, not the user manual. As for finding out which ports what things were on; well, I wrote a small program that output the values of all of them, and then pressed various buttons and looked to see what changed :)
 
Ok, I'll try to find the datasheet. There were several PDFs that showed as totally blank pages in Acrobat Reader. The datasheet may have been one of them.

In Rlyeh's Minimal SDK, why is he right-shifting the port number by one bit? I can see where the 0xC0000000 offset is specified in the call to mmap, but why the ">>1" on the port number?

Thanks for your help, Squidge (and woogal, Rlyeh and everyone else doing dev on this thing already). I'm just trying to get a better understanding of how this works before my unit arrives next week.
 
Ok, I'll try to find the datasheet. There were several PDFs that showed as totally blank pages in Acrobat Reader. The datasheet may have been one of them.

In Rlyeh's Minimal SDK, why is he right-shifting the port number by one bit? I can see where the 0xC0000000 offset is specified in the call to mmap, but why the ">>1" on the port number?

Thanks for your help, Squidge (and woogal, Rlyeh and everyone else doing dev on this thing already). I'm just trying to get a better understanding of how this works before my unit arrives next week.

Well, for example, 0x1186 is the actual register value, but since you are accessing a short, the compiler will automatically double this (as it takes the 0x1186 as the element, which each one taking up 2 bytes). So Rlyeh divides by 2 first, which is normally quicker by using a shift, rather than a divide. If you access by byte instead, you wouldn't need it, but you wouldn't get the correct data either, as the registers are 16-bit wide.
 
Last edited by a moderator:
Ahh, ok. I had to think about that for a while before it clicked as to what you meant. I think he should have kept them as a macro like he did in the first version he released. It would be all too easy to forget to divide the port by two to get the proper array index.

Another way to do this without bit-shifting every time you access a port would be to use a typecast.

unsigned char *gp2x_memregs;
#define PORT(p) (*(unsigned short *)(gp2x_memregs + (p)))

value = PORT(0x1186);
PORT(0x290E) = (unsigned short)(address & 0xFFFF);

But, as in all coding problems, there is more than one way to skin a cat, so each to their own I suppose. It depends on what the coder prefers at the time.
 
Back
Top