PRODUCT ID: 1601
Some notes on what I have learnt.
So I'm a bit of an old school c/c++ coder and don't know anything about X11 coding. Give me a framebuffer to write too and I'm off on my own. ;)
So I am working on a little front end for my RPi which is running Octoprint on my k8200 3D Printer. The rendering of my frontend is easy, I'm using SDL for this. The RPi has sdl 1.2 in the repositories and for the most part works well with the PiTFT. Here are a couple things I have worked out about the rendering.
1) One line you may want to add to your code to make life easier is.
Code: Select all
SDL_putenv((char*)"SDL_FBDEV=/dev/fb1");
2) SDL can not synchronise with the VSYNC, I asked about and looked at the docs and looks to me that VSYNC is only available on a pin on the driver chip. The side effect of this is that your app will be running very high frame rates making the display 'tear'
Not got a good fix for this for a game, but for my app I should really be updating the UI based on events anyway. So I will brush that under the carpet.
Now here is the biggest issue I have run into. Taken a while to get sorted as I'm working full time and doing a degree (about half way throw now).
SDL 1.2 has some very poor code for reading the touch screen. It assumes the touch screen is the same orientation as the display and the same resolution. No good for our PiTFT. So over to using 'input_event' and my own code. I wanted to high light this as it took a lot of searching about. The linux 'input_event' is very poorly documented. There is lots of it but it's all duplicated from the header files and is only good for confusing me. ;)
Maybe someone knows of a good tutorial?
So to do this touch input code you need to run it in a thread because it will be blocking on a file read. Also you'll need a little util function I wrote that wraps select() up in something a little more usable.
Retuns <0 for error, 0 for no data and > 0 for bytes read.
Code: Select all
int read_timeout(int fd, void *buf, size_t count,int theTimeout) //timeout in seconds.
{
if( theTimeout < 1 )
{
return ::read(fd,buf,count);
}
// Initialize file descriptor sets
fd_set read_fds, write_fds, except_fds;
FD_ZERO(&read_fds);
FD_ZERO(&write_fds);
FD_ZERO(&except_fds);
FD_SET(fd, &read_fds);
// Set timeout to theTimeout seconds
struct timeval timeout;
timeout.tv_sec = theTimeout;
timeout.tv_usec = 0;
// Wait for input to become ready or until the time out; the first parameter is
// 1 more than the largest file descriptor in any of the sets
int ret = select(fd + 1, &read_fds, &write_fds, &except_fds, &timeout);
if( ret == 1 )
{
return ::read(fd,buf,count);
}
return ret;
}
Here is the main guts of the thread code that reads the touch screen. It auto calibrates so you first touch the four corners and then off you go. This is using a few of my own classes. When I get time I'll write a self contained version with just one header / cpp file. But may be a week or so I have an assignment due on the degree course. :)
I just hope this has help someone in the future because I was a bit lost with this.
You'll see readingData.Enter() and readingData.Exit() this is just a semiphore code. You could chance it and remove it.
Code: Select all
/*!
This is the code that is run inside the thread.
*/
virtual void Main()
{
inputDevice = open(MOUSEFILE, O_RDONLY);
if( inputDevice == 0 )
{
Error("Failed to open touch screen device");
return;
}
while( Quit == false )
{
struct input_event ie;
if( read_timeout(inputDevice,&ie,sizeof(ie),5) > 0 )
{
switch(ie.type)
{
case EV_SYN:
break;
case EV_ABS:
if(ie.code == ABS_X )
{
UpdateX(ie.value);
}
else if(ie.code == ABS_Y )
{
UpdateY(ie.value);
}
else if(ie.code == 24 )
{
if( readingData.Enter() )
{
touchPressure = ie.value;
readingData.Exit();
}
}
else
{
Debug("%d %d\n",ie.code,ie.value);
}
break;
}
// Debug("rawPosition(%f,%f)",rawPosition.x,rawPosition.y);
}
};
Debug(config.toString());
Debug("Closing file");
close(inputDevice);
Debug("Returning from thread");
}
private:
CriticalSection readingData;
int inputDevice;
Vector2 rawPosition;
void UpdateX(int value)
{
if( config.min.x > value )
{
config.min.x = value;
}
if( config.max.x < value )
{
config.max.x = value;
}
if( readingData.Enter() )
{
float dx = (float)(config.max.x - config.min.x);
if( dx != 0 )
{
rawPosition.x = (float)(value - config.min.x) / dx;
}
readingData.Exit();
}
}
void UpdateY(int value)
{
if( config.min.y > value )
{
config.min.y = value;
}
if( config.max.y < value )
{
config.max.y = value;
}
if( readingData.Enter() )
{
float dy = (float)(config.max.y - config.min.y);
if( dy != 0 )
{
rawPosition.y = (float)(value - config.min.y) / dy;
}
readingData.Exit();
}
}
Richard e Collins. :)