Lufa joystick hex

Hey guys,

Does someone have a firmware for me to upload to my arduino that makes my arduino a hid game controller.
and an example on how to use it,
i already have a keyboard and mouse, but i need to make a joystick out of it.
i hope somebody can help me

thanks in advance

Kevin Walter

I heard that it is possible, but only with an arduino Uno

Yeh i know that, i have an arduino uno, so it wont be a problem for me.
but i need a firmware file that can act like a game controller

I've put together joystick HID firmware for the UNO and mega2560 based on the LUFA project. This turns the Arduino into a basic analog X-Y joystick with two buttons. The firmware hex file, source, and demo sketch are available here on Arduino Hacking blog.

Thanks dhunt. Your info has been really helpful to me.

I was looking at your joystick demo and had a few questions.

Will a ps3 console detect this HID and have it work?

How would I go about adding more buttons to interface with?

How would I go about sending more than 1 button press? I'm assuming you can just lessen/remove the delay, correct?

Hi stutter.

I don't have a ps3 console so I don't know if it will work. If you can plug standard USB joysticks into the ps3 then I think it should be fine.

You can modify the JoystickReport array in Descriptors.c file to add more buttons or more analog inputs. For example this version has 6 buttons:

USB_Descriptor_HIDReport_Datatype_t PROGMEM JoystickReport[] =
{
	0x05, 0x01,          /* Usage Page (Generic Desktop)                       */
	0x09, 0x04,          /* Usage (Joystick)                                   */
	0xa1, 0x01,          /* Collection (Application)                           */
	0x09, 0x01,          /*   Usage (Pointer)                                  */
	0xa1, 0x00,          /*   Collection (Physical)                            */
	0x05, 0x01,          /*     Usage Page (Generic Desktop)                   */
	0x09, 0x30,          /*     Usage (X)                                      */
	0x09, 0x31,          /*     Usage (Y)                                      */
	0x15, 0x9c,          /*     Logical Minimum (-100)                         */
	0x25, 0x64,          /*     Logical Maximum (100)                          */
	0x75, 0x08,          /*     Report Size (8)                                */
	0x95, 0x02,          /*     Report Count (2)                               */
	0x81, 0x82,          /*     Input (Data, Variable, Absolute, Volatile)     */
	0xc0,                /*   End Collection                                   */
	0x05, 0x09,          /*   Usage Page (Button)                              */
	0x09, 0x06,	     /*   Usage (Button 6)				   */
	0x09, 0x05,          /*   Usage (Button 5)                                 */
	0x09, 0x04,          /*   Usage (Button 4)                                 */
	0x09, 0x03,	     /*   Usage (Button 3)				   */
	0x09, 0x02,          /*   Usage (Button 2)                                 */
	0x09, 0x01,          /*   Usage (Button 1)                                 */
	0x15, 0x00,          /*   Logical Minimum (0)                              */
	0x25, 0x01,          /*   Logical Maximum (1)                              */
	0x75, 0x01,          /*   Report Size (1)                                  */
	0x95, 0x02,          /*   Report Count (2)                                 */
	0x81, 0x02,          /*   Input (Data, Variable, Absolute)                 */
	0x75, 0x02,          /*   Report Size (2)                                  */
	0x95, 0x01,          /*   Report Count (1)                                 */
	0x81, 0x01,          /*   Input (Constant)                                 */
	0xc0                 /* End Collection                                     */
};

You can send more than one button at a time by setting more than one bit. E.g.

joyReport.buttons = 3; /* both buttons pressed */

And yes the delays can be removed.

Cheers,
Darran.

Thanks for the replies Darran.

I couldn't get the extra buttons to work. Once I got it to load up but the extra buttons didn't show up on usb controller. The other problem I saw was the numbering. If you label buttons 01, 02, 03, 04 ect.. you can't deal with simultaneous buttons since 01 and 02 = 03. I thought about doing it like 01, 02, 04, 08 ect.. but then I can only have 8 buttons.

I dug around and found someone who used LUFA to make a ps3 HID controller which is pretty much what I want. I was messing around and replaced his USB_Descriptor_HIDReport_Datatype_t PROGMEM JoystickReport[] over yours. I was able to get the pc to detect all the axis and 13 buttons. The big problem is I don't know how to communicate with it using Arduino to send it button presses. I'll dig around the code more to try to make sense of it but any help with greatly be appreciated.

Fyi, your original 2 button joystick does work on the PS3.

I managed to finally add more buttons.

USB_Descriptor_HIDReport_Datatype_t PROGMEM JoystickReport[] =
{
	0x05, 0x01,          /* Usage Page (Generic Desktop)                       */
	0x09, 0x04,          /* Usage (Joystick)                                   */
	0xa1, 0x01,          /* Collection (Application)                           */
	0x09, 0x01,          /*   Usage (Pointer)                                  */
	0xa1, 0x00,          /*   Collection (Physical)                            */
	0x05, 0x01,          /*     Usage Page (Generic Desktop)                   */
	0x09, 0x30,          /*     Usage (X)                                      */
	0x09, 0x31,          /*     Usage (Y)                                      */
	0x15, 0x9c,          /*     Logical Minimum (-100)                         */
	0x25, 0x64,          /*     Logical Maximum (100)                          */
	0x75, 0x08,          /*     Report Size (8)                                */
	0x95, 0x02,          /*     Report Count (2)                               */
	0x81, 0x82,          /*     Input (Data, Variable, Absolute, Volatile)     */
	0xc0,                /*   End Collection                                   */
	0x05, 0x09,          /*   Usage Page (Button)                              */
	0x19, 0x01,          /*   Usage Minimum(Button 1)                          */
	0x29, 0x06,          /*   Usage Maximum(Button 6)                          */
	0x15, 0x00,          /*   Logical Minimum (0)                              */
	0x25, 0x01,          /*   Logical Maximum (1)                              */
	0x75, 0x01,          /*   Report Size (1)                                  */
	0x95, 0x06,          /*   Report Count (6)                                 */
	0x81, 0x02,          /*   Input (Data, Variable, Absolute)                 */
	0x75, 0x02,          /*   Report Size (2)                                  */
	0x95, 0x01,          /*   Report Count (1)                                 */
	0x81, 0x01,          /*   Input (Constant)                                 */
	0xc0                 /* End Collection                                     */
};

I still have the problem when I add more than 6 buttons. When I try 7 or above, my computer fails to recognize arduino as a joystick.

Edit: I manages to get my pc to detect more than 6 buttons by changing the report size to 3. However, I can't send the right signals to the joystick anymore. I think the data struc is off.

Hey stutter,

the buttons 1 - 6 are mapped on to bits 0 - 5 in the buttons byte, so you can send multiple buttons by turning on multiple bits. E.g. button 6 is 0x20, button 6 and button 1 is 0x21.

If you add a 7th button you need to drop the final report descriptor size down to 1 - its a filler up to to 8 bits (hence its 2 for 6 buttons, and 6 for 2 buttons).

You can find out more about descriptors from http://www.usb.org/developers/devclass_docs/HID1_11.pdf.

You could add 30 buttons like this:

        0x95, 0x1E,          /*   Report Count (30)                                */
        0x75, 0x01,          /*   Report Size (1)                                  */
        0x05, 0x09,          /*   Usage Page (Button)                              */
        0x19, 0x01,          /*     Usage Minimum (Button 1)                       */
        0x29, 0x1E,          /*     Usage Maximum (Button 30)                      */
        0x15, 0x00,          /*   Logical Minimum (0)                              */
        0x25, 0x01,          /*   Logical Maximum (1)                              */
        0x81, 0x02,          /*   Input (Data, Variable, Absolute)                 */
        0x75, 0x02,          /*   Report Size (2)                                  */
        0x95, 0x01,          /*   Report Count (1)                                 */
        0x81, 0x01,          /*   Input (Constant)                                 */

Then you would need to change Arduiuno-joystick.h to make the report bigger:

typedef struct {
    int8_t  x; /**< Current absolute joystick X position, as a signed 8-bit integer */
    int8_t  y; /**< Current absolute joystick Y position, as a signed 8-bit integer */
    uint32_t button; /**< Bit mask of the currently pressed joystick buttons */
} USB_JoystickReport_Data_t;

and change Arduino-joystick.c to handle the bigger report:

bool CALLBACK_HID_Device_CreateHIDReport(
    USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo,
    uint8_t* const ReportID,
    const uint8_t ReportType,
    void* ReportData,
    uint16_t* const ReportSize)
{
    USB_JoystickReport_Data_t *reportp = (USB_JoystickReport_Data_t*)ReportData;

    RingBuff_Count_t BufferCount = RingBuffer_GetCount(&USARTtoUSB_Buffer);

    if (BufferCount >= sizeof(joyReport)) {
	uint8_t ind;
	for (ind=0; ind<sizeof(joyReport); ind++) {
	    ((uint8_t *)&joyReport)[ind] = RingBuffer_Remove(&USARTtoUSB_Buffer);
	}

	LEDs_TurnOnLEDs(LEDS_LED1);
	led1_ticks = LED_ON_TICKS;
    }

    *reportp = joyReport;

    *ReportSize = sizeof(USB_JoystickReport_Data_t);
    return false;
}

And finally change the sketch to support the bigger report:

typedef struct t_joyReport {
    int8_t x;
    int8_t y;
    uint32_t buttons;
} t_joyReport;

t_joyReport joyReport;

void setup();
void loop();
void sentJoyReport(struct t_joyReport *report);

void setup()
{
    Serial.begin(115200);
    delay(200);
}

void sendJoyReport(struct t_joyReport *report)
{
    Serial.write((uint8_t *)report, sizeof(t_joyReport));
}

void loop()
{
    int button;

    joyReport.x = 0;
    joyReport.y = 0;
    /* Send all buttons in sequence */
    for (button=0; button<30; button++) {
        joyReport.buttons = 1L<<button;
        sendJoyReport(&joyReport);
        delay(100);
    }

    joyReport.buttons = 0;
    sendJoyReport(&joyReport);
}

Awesome, I got it to work the way I want. Thanks again!

dhunt:
I've put together joystick HID firmware for the UNO and mega2560 based on the LUFA project. This turns the Arduino into a basic analog X-Y joystick with two buttons. The firmware hex file, source, and demo sketch are available here on Arduino Hacking blog.

Sorry for the bump.

@dhunt do you still have this firmware by any chance?
The link is broken unfortunately.

I'm trying compile the LUFA demo Joystick project with the board set to UNO.
But the board doesn't have the Buttons.h and Joystick.h file, and copying it in from USBKEY doesn't work either.

Hope you can help. :slight_smile: