Wednesday, 1 May 2013

USB Gamepad

Another thing that I have recently implemented is a USBGamepad class. It's very similar to other previously described HID devices. Let's take a look at report descriptor:
 
reportDesc.usagePage(ReportDescriptor.PAGE_GENERIC_DESKTOP);
reportDesc.usage(GenericDesktopPage.GAMEPAD);
reportDesc.collection(ReportDescriptor.COLLECTION_APPLICATION);
reportDesc.collection(ReportDescriptor.COLLECTION_PHYSICAL);
reportDesc.reportId(1);
//buttons
reportDesc.usagePage(ReportDescriptor.PAGE_BUTTON);
reportDesc.usageMinimum(1);
reportDesc.usageMaximum(16);
reportDesc.logicalMinimum(0);
reportDesc.logicalMaximum(1);
reportDesc.reportCount(16);
reportDesc.reportSize(1);
reportDesc.input(ReportDescriptor.DATA | ReportDescriptor.VARIABLE | ReportDescriptor.ABSOLUTE);
//axis
reportDesc.usagePage(ReportDescriptor.PAGE_GENERIC_DESKTOP);
reportDesc.usage(GenericDesktopPage.X);
reportDesc.usage(GenericDesktopPage.Y);
reportDesc.usage(GenericDesktopPage.Z);
reportDesc.usage(GenericDesktopPage.rX);
reportDesc.logicalMinimum(-127);
reportDesc.logicalMaximum(127);
reportDesc.reportSize(8);
reportDesc.reportCount(4);
reportDesc.input(ReportDescriptor.DATA | ReportDescriptor.VARIABLE | ReportDescriptor.ABSOLUTE);
reportDesc.collectionEnd();
reportDesc.collectionEnd();
view raw gistfile1.java hosted with ❤ by GitHub

 
As you can see, my gamepad implementation supports up to 16 buttons and 4 axes. First byte of USB report is always set to 1 (report ID), next two bytes are an array containing data about state of buttons, followed by 4 bytes, one for each axis. Endpoint 1 has polling interval set to 8 ms in order to reduce latency, what is very important in case of a gamepad device. There are following methods offered by this class:
 
public synchronized void setButton(int button, boolean state);
public synchronized void setAxis(int axis, byte value);
public synchronized void sendReport();
view raw gistfile1.java hosted with ❤ by GitHub

 
In order to demonstrate USBGamepad class in action I have prepared simple GamepadDemo app. As you can see there are 8 buttons (multi-touch is supported). Data for X and Y axes is gathered from accelerometer, Z and rX axes are not used. Application sends data every 25 ms, but I guess any interval greater than 8 ms (endpoint polling interval) should be ok.
 
GamepadDemo app.


Devices and Printers

On the screen above you can see that Windows sees InputStick as a USB game controller device. I didn't check this class on any other operating system beside Windows, but if a physical gamepad is supported, then InputStick will also work.

Here's a video of me playing GRID with my phone as a controller (it's a bit difficult to steer when you have camera between yourself and phone) :

No comments:

Post a Comment