Jeff Griffin

Quart: OpenELEC branch commit breakdown

Posted on March 15, 2013

I've been putting off dealing with the documentation of all the snags I've run into thus far and decided to just take a look at the commit log and rationalize each one.  Some of these are fairly specific to my situation, while others may have broader implications.

Isolating and using SDL input

Once the gamecon module was added to the build, this was the first and largest hurdle to jump in getting gamepad input in OpenELEC for Raspberry Pi. Here's the situation:

the gamepad device is simply not utilized, or even logged as enabled, though running evtest shows that it's blocked. The first place you might look for a solution, understanding that you're using Linux window events, is LinuxInputDevices.cpp. Scrolling down and seeing the Linux input device type enumeration confirms the supposition that you are on the right track.

Your supposition, as it turns out, is bad and you should feel bad because the GetInfo method is going to be called to determine what type your little device falls into, and it will do this:

...since the button counting loop stopped at BTN_JOYSTICK (this is the index at witch joystick/gamepad buttons start), num_buttons is 0 and your gamepad is left as LI_DEVICE_NONE. Unfortunately the solution is not just to bump the index limit up on the loop, because there is no codepath in the application loop for CLinuxInputDevice into CButtonTranslator's TranslateJoystickString method.

There are only two paths to TranslateJoystickString in CApplication. One is the event server, the other uses SDL.  The latter seemed an easier, cleaner option to me.  Theoretically, it would just mean the inclusion of libSDL in the build.

This is from the graphic configuration script in the OpenELEC build system.

We start to see how a problem like this could happen, because right now it's relegated to users running XBMC in Linux without X, who require joystick support sans event server.  One could make an argument of course that you can use SDL input without the rest, which is what I did.

The solution was mostly just changing a few variables. I commented out the lines above and changed some defines in system.h.  The only real functional issue was that after XBMC's CLinuxInputDevice assigns LI_DEVICE_NONE to the gamepad devices it continues to hold onto block file descriptors, so when SDL uses evdev to grab the device, it's blocked as well.  This is addressed in SDL_input_only.patch, after the call to GetInfo.

"Sticky" buttons in SDL

This was absolutely infuriating, and took a good bit of GDB to figure out.  The failure mode is that a button will behave as though it is being held down, often after advancing a menu, so depending on the next focused item on each screen you may be in for a fun guided tour through the UI.  The offender this time was the SDL joystick class. As it turns out, evdev drivers can miss an event.  I get a sense that it happens when the system is taxed, so the situation is exacerbated on RPi, but certainly not unique to it.  When an event is missed evdev transmits a SYN_DROPPED event, at which point it can be polled to correct internal buffers.  Unfortunately there is no concept of SYN_DROPPED as of SDL 1.2.15.  Fortunately a contributor named Simon has proposed a patch, which was merged in last month, and addresses this issue with regard to axes, but not buttons.  I modified it to poll the button states and merged those changes back into the 1.2.15 joystick class with this patch.

Gamecon driver initialization

Originally I was going to fix these issues by using the js* devices in SDL and applying calibrations with jscal (I added linuxconsole package to my build in order to support it), but I really wanted the D-Pad to be supported properly as a HAT input, which is unique to evdev.  As a result, I made some changes to the initialization numbers in gamecon.  The problems are these:

1. Analog trigger axes come to rest at the low end of their value range.  As a result XBMC thinks that the triggers are always being pulled negative.  Creating a unattainable "false bottom" for analog triggers equidistant from the resting and max values prevents this.

2. The theoretical range for all Gamecube axes is 0-255.  These values are possible, but only when the controllers are taken out of their frames, because the plastic limits their range of motion.  The following is a quote from the Linux Kernel Documentation(italics added for emphasis):

input_set_abs_params(button_dev, ABS_X, 0, 255, 4, 8);

This setting would be appropriate for a joystick X axis, with the minimum of 0, maximum of 255 (which the joystick *must* be able to reach, no problem if it sometimes reports more, but it must be able to always reach the min and max values), with noise in the data up to +- 4, and with a center flat position of size 8.

I tested the four controllers I own and unfortunately, there's a good bit of variance between them.  The values I ended up with represent worst case ranges (ensuring all the axes of all four gamepads were well within reach of the mins and maxes) and midpoints that represent axes at rest within precision.

Even if these values do not perfectly suit all Gamecube gamepads, they should be an improvement over the unattainable 0-255.

That more-or-less covers it to where I am today.  I'm happy to say that XBMC is fully functional, and I'm using it in my bedroom now with no input device other than a Gamecube controller.  There are some things I left out that are very specific to my hardware build.  I can cover some of those things (joystick module initialization, keybinding xml, etc.) when I can write a proper Quart how-to.  In the meantime, I need to try and get some of these things patched in officially and make this easier to replicate.

Comments (0) Trackbacks (0)

No comments yet.

Leave a comment

No trackbacks yet.