Joystick enabled version of USBHID -library. Has full Playstation 3 functionality including button pressures and a working home-button implementation, while maintaining full PC/MAC/linux -compatibility. basic operation of the lib: #include "mbed.h" #include "usbhid.h" USBJoystick joystick; int main() { while(1) { char dpad = 0xf; /*only the rightmost 4 bits matter*/ short button = 0xff; /*only the rightmost 13 bits matter*/ /*buttons are square, cross, circle, triangle, l1, r1, l2, r2, l3, r3, home.*/ char stick1x = 0; char stick1y = 0; char stick2x = 0; char stick2y = 0; joystick.joystick(dpad, buttons, stick1x, stick1y, stick2x, stick2y); wait_ms(5); } }

Revision:
0:237d5ef643e9
diff -r 000000000000 -r 237d5ef643e9 usbhid.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usbhid.cpp	Fri May 11 13:35:59 2012 +0000
@@ -0,0 +1,660 @@
+/* usbhid.cpp */
+/* USB HID class device */
+/* Copyright (c) Phil Wright 2008 */
+
+/* modified by Shinichiro Oba <http://mbed.org/users/bricklife/> */
+
+/* additional modification (PS3 home button functionality) by Panu Kauppinen*/
+
+#include "mbed.h"
+#include "usbhid.h"
+#include "asciihid.h"
+
+/* Endpoint packet sizes */
+#define MAX_PACKET_SIZE_EP1 (64)
+
+/* HID Class */
+#define HID_CLASS         (3)
+#define HID_SUBCLASS_NONE (0)
+#define HID_PROTOCOL_NONE (0)
+#define HID_DESCRIPTOR    (33)
+#define REPORT_DESCRIPTOR (34)
+
+/* Class requests */
+#define GET_REPORT (0x1)
+#define GET_IDLE   (0x2)
+#define SET_REPORT (0x9)
+#define SET_IDLE   (0xa)
+
+    
+/* HID Class Report Descriptor */
+/* Short items: size is 0, 1, 2 or 3 specifying 0, 1, 2 or 4 (four) bytes of data as per HID Class standard */
+
+/* Main items */
+#define INPUT(size)             (0x80 | size)
+#define OUTPUT(size)            (0x90 | size)
+#define FEATURE(size)           (0xb0 | size)
+#define COLLECTION(size)        (0xa0 | size)
+#define END_COLLECTION(size)    (0xc0 | size)
+
+/* Global items */
+#define USAGE_PAGE(size)        (0x04 | size)
+#define LOGICAL_MIN(size)       (0x14 | size)
+#define LOGICAL_MAX(size)       (0x24 | size)
+#define PHYSICAL_MIN(size)      (0x34 | size)
+#define PHYSICAL_MAX(size)      (0x44 | size)
+#define UNIT_EXPONENT(size)     (0x54 | size)
+#define UNIT(size)              (0x64 | size)
+#define REPORT_SIZE(size)       (0x74 | size)
+#define REPORT_ID(size)         (0x84 | size)
+#define REPORT_COUNT(size)      (0x94 | size)
+#define PUSH(size)              (0xa4 | size)
+#define POP(size)               (0xb4 | size)
+
+/* Local items */
+#define USAGE(size)             (0x08 | size)
+#define USAGE_MIN(size)         (0x18 | size)
+#define USAGE_MAX(size)         (0x28 | size)
+#define DESIGNATOR_INDEX(size)  (0x38 | size)
+#define DESIGNATOR_MIN(size)    (0x48 | size)
+#define DESIGNATOR_MAX(size)    (0x58 | size)
+#define STRING_INDEX(size)      (0x78 | size)
+#define STRING_MIN(size)        (0x88 | size)
+#define STRING_MAX(size)        (0x98 | size)
+#define DELIMITER(size)         (0xa8 | size)
+
+#define REPORT_ID_KEYBOARD      (1)
+#define REPORT_ID_MOUSE         (2)
+
+#define MAX_REPORT_SIZE         (64)
+
+unsigned char reportDescriptor[] = {
+/* Keyboard */
+USAGE_PAGE(1),      0x01,
+USAGE(1),           0x06,
+COLLECTION(1),      0x01,
+REPORT_ID(1),       REPORT_ID_KEYBOARD,
+USAGE_PAGE(1),      0x07,
+USAGE_MIN(1),       0xE0,
+USAGE_MAX(1),       0xE7,
+LOGICAL_MIN(1),     0x00,
+LOGICAL_MAX(1),     0x01,
+REPORT_SIZE(1),     0x01,
+REPORT_COUNT(1),    0x08,
+INPUT(1),           0x02,
+REPORT_COUNT(1),    0x01,
+REPORT_SIZE(1),     0x08,
+INPUT(1),           0x01,
+REPORT_COUNT(1),    0x05,
+REPORT_SIZE(1),     0x01,
+USAGE_PAGE(1),      0x08,
+USAGE_MIN(1),       0x01,
+USAGE_MAX(1),       0x05,
+OUTPUT(1),          0x02,
+REPORT_COUNT(1),    0x01,
+REPORT_SIZE(1),     0x03,
+OUTPUT(1),          0x01,
+REPORT_COUNT(1),    0x06,
+REPORT_SIZE(1),     0x08,
+LOGICAL_MIN(1),     0x00,
+LOGICAL_MAX(2),     0xff, 0x00,
+USAGE_PAGE(1),      0x07,
+USAGE_MIN(1),       0x00,
+USAGE_MAX(2),       0xff, 0x00,
+INPUT(1),           0x00,
+END_COLLECTION(0),
+
+/* Mouse */
+USAGE_PAGE(1),      0x01, 
+USAGE(1),           0x02, 
+COLLECTION(1),      0x01, 
+USAGE(1),           0x01, 
+COLLECTION(1),      0x00, 
+REPORT_ID(1),       REPORT_ID_MOUSE,
+REPORT_COUNT(1),    0x03,
+REPORT_SIZE(1),     0x01,
+USAGE_PAGE(1),      0x09,
+USAGE_MIN(1),       0x1,
+USAGE_MAX(1),       0x3,
+LOGICAL_MIN(1),     0x00,
+LOGICAL_MAX(1),     0x01,
+INPUT(1),           0x02,
+REPORT_COUNT(1),    0x01,
+REPORT_SIZE(1),     0x05,
+INPUT(1),           0x01,
+REPORT_COUNT(1),    0x03,
+REPORT_SIZE(1),     0x08,
+USAGE_PAGE(1),      0x01,
+USAGE(1),           0x30,
+USAGE(1),           0x31,
+USAGE(1),           0x38,
+LOGICAL_MIN(1),     0x81,
+LOGICAL_MAX(1),     0x7f,
+INPUT(1),           0x06,
+END_COLLECTION(0),
+END_COLLECTION(0),
+};
+
+
+
+
+/* Descriptors */
+unsigned char deviceDescriptor[] = {
+    0x12,                    /* bLength */
+    DEVICE_DESCRIPTOR,       /* bDescriptorType */
+    0x10,                    /* bcdUSB (LSB) */
+    0x01,                    /* bcdUSB (MSB) */
+    0x00,                    /* bDeviceClass */
+    0x00,                    /* bDeviceSubClass */
+    0x00,                    /* bDeviceprotocol */
+    MAX_PACKET_SIZE_EP0,     /* bMaxPacketSize0 */
+    0xC4,                    /* idVendor (LSB) */
+    0x10,                    /* idVendor (MSB) */
+    0xC0,                    /* idProduct (LSB) */
+    0x82,                    /* idProduct (MSB) */
+    0x01,                    /* bcdDevice (LSB) */
+    0x00,                    /* bcdDevice (MSB) */
+    0x01,                    /* iManufacturer */
+    0x02,                    /* iProduct */
+    0x00,                    /* iSerialNumber */
+    0x01                     /* bNumConfigurations */
+    };
+    
+unsigned char configurationDescriptor[] = {
+    0x09,                        /* bLength */
+    CONFIGURATION_DESCRIPTOR,    /* bDescriptorType */
+    0x09+0x09+0x09+0x07,         /* wTotalLength (LSB) */
+    0x00,                        /* wTotalLength (MSB) */
+    0x01,                        /* bNumInterfaces */
+    0x01,                        /* bConfigurationValue */
+    0x00,                        /* iConfiguration */
+    0x80,                        /* bmAttributes */
+    0x32,                        /* bMaxPower */
+    
+    0x09,                        /* bLength */
+    INTERFACE_DESCRIPTOR,        /* bDescriptorType */    
+    0x00,                        /* bInterfaceNumber */
+    0x00,                        /* bAlternateSetting */
+    0x01,                        /* bNumEndpoints */
+    HID_CLASS,                   /* bInterfaceClass */
+    HID_SUBCLASS_NONE,           /* bInterfaceSubClass */
+    HID_PROTOCOL_NONE,           /* bInterfaceProtocol */
+    0x00,                        /* iInterface */
+    
+    0x09,                        /* bLength */
+    HID_DESCRIPTOR,              /* bDescriptorType */
+    0x11,                        /* bcdHID (LSB) */
+    0x01,                        /* bcdHID (MSB) */
+    0x00,                        /* bCountryCode */
+    0x01,                        /* bNumDescriptors */
+    REPORT_DESCRIPTOR,           /* bDescriptorType */
+    0x79,                        /* wDescriptorLength (LSB) */
+    0x00,                        /* wDescriptorLength (MSB) */
+        
+    0x07,                        /* bLength */
+    ENDPOINT_DESCRIPTOR,         /* bDescriptorType */
+    0x81,                        /* bEndpointAddress */
+    0x03,                        /* bmAttributes */
+    MAX_PACKET_SIZE_EP1,         /* wMaxPacketSize (LSB) */
+    0x00,                        /* wMaxPacketSize (MSB) */
+    0x05,                        /* bInterval */
+    };
+
+
+    
+volatile bool complete;
+volatile bool configured;
+unsigned char outputReport[MAX_REPORT_SIZE];
+
+usbhid::usbhid()
+{
+    configured = false;
+    connect();
+}
+
+void usbhid::deviceEventReset()
+{
+    configured = false;
+    
+    /* Must call base class */ 
+    usbdevice::deviceEventReset();
+}
+
+bool usbhid::requestSetConfiguration(void)
+{
+    bool result;
+    
+    /* Configure IN interrupt endpoint */
+    realiseEndpoint(EP1IN, MAX_PACKET_SIZE_EP1);
+    enableEndpointEvent(EP1IN);
+    
+    /* Must call base class */
+    result = usbdevice::requestSetConfiguration();
+    
+    if (result)
+    {
+        /* Now configured */
+        configured = true;
+    }
+    
+    return result;
+}
+
+bool usbhid::requestGetDescriptor(void)
+{
+    bool success = false;
+
+        
+    switch (DESCRIPTOR_TYPE(transfer.setup.wValue))
+    {
+        case DEVICE_DESCRIPTOR:
+            transfer.remaining = sizeof(deviceDescriptor);
+            transfer.ptr = deviceDescriptor;
+            transfer.direction = DEVICE_TO_HOST;
+            success = true;
+            break;
+        case CONFIGURATION_DESCRIPTOR:
+            transfer.remaining =  sizeof(configurationDescriptor);
+            transfer.ptr = configurationDescriptor;
+            transfer.direction = DEVICE_TO_HOST;
+            success = true;
+            break;
+        case STRING_DESCRIPTOR:
+        case INTERFACE_DESCRIPTOR:
+        case ENDPOINT_DESCRIPTOR:
+            /* TODO: Support is optional, not implemented here */
+            break;
+        case HID_DESCRIPTOR:
+            transfer.remaining = 0x09; /* TODO: Fix hard coded size/offset */
+            transfer.ptr = &configurationDescriptor[18];
+            transfer.direction = DEVICE_TO_HOST;
+            success = true;            
+            break;
+        case REPORT_DESCRIPTOR:
+            transfer.remaining = sizeof(reportDescriptor);
+            transfer.ptr = reportDescriptor;
+            transfer.direction = DEVICE_TO_HOST;
+            success = true;            
+            break;
+        default:
+            break;    
+    }
+    
+    return success;
+}
+
+bool usbhid::requestSetup(void)
+{
+    /* Process class requests */
+    bool success = false;
+
+    if (transfer.setup.bmRequestType.Type == CLASS_TYPE)
+    {
+        switch (transfer.setup.bRequest)
+        {
+             case SET_REPORT:
+                 switch (transfer.setup.wValue & 0xff)
+                 {
+                    case REPORT_ID_KEYBOARD:                     
+                        /* TODO: LED state */
+                        transfer.remaining = sizeof(outputReport);
+                        transfer.ptr = outputReport;
+                        transfer.direction = HOST_TO_DEVICE;
+                        success = true;    
+                        break;
+                    default:
+                        break;
+                 }
+                 break;
+             default:
+                 break;
+        }
+    }
+        
+    if (success)
+    {
+        /* We've handled this request */
+        return true;
+    }
+    
+    return usbdevice::requestSetup();
+}
+
+bool usbhid::sendInputReport(unsigned char id, unsigned char *data, unsigned char size)
+{
+    /* Send an Input Report */
+    /* If data is NULL an all zero report is sent */
+    
+    static unsigned char report[MAX_REPORT_SIZE+1]; /* +1 for report ID */
+    unsigned char i;
+
+    if (size > MAX_REPORT_SIZE)
+    {
+        return false;
+    }
+    
+    /* Add report ID */
+    report[0]=id;
+
+    /* Add report data */
+    if (data != NULL)
+    {    
+        for (i=0; i<size; i++)
+        {
+            report[i+1] = *data++;
+        }
+    }
+    else
+    {    
+        for (i=0; i<size; i++)
+        {
+            report[i+1] = 0;
+        }
+    }    
+    
+    /* Block if not configured */
+    while (!configured);
+    
+    /* Send report */
+    complete = false;
+    disableEvents();
+    endpointWrite(EP1IN, report, size+1); /* +1 for report ID */
+    enableEvents();
+    
+    /* Wait for completion */
+    while(!complete && configured);    
+    return true;
+}
+    
+void usbhid::endpointEventEP1In(void)
+{
+    complete = true;
+}
+
+bool usbhid::keyboard(char c)
+{
+    /* Send a simulated keyboard keypress. Returns true if successful. */    
+    unsigned char report[8]={0,0,0,0,0,0,0,0};
+
+    report[0] = keymap[c].modifier;
+    report[2] = keymap[c].usage;
+
+    /* Key down */
+    if (!sendInputReport(REPORT_ID_KEYBOARD, report, 8))
+    {
+        return false;
+    }
+
+    /* Key up */
+    if (!sendInputReport(REPORT_ID_KEYBOARD, NULL, 8))
+    {
+        return false;
+    }    
+
+    return true;
+}
+
+bool usbhid::keyboard(char *string)
+{
+    /* Send a string of characters. Returns true if successful. */
+    do {
+        if (!keyboard(*string++))
+        {
+            return false;
+        }
+    } while (*string != '\0');
+
+    return true;
+}
+
+bool usbhid::mouse(signed char x, signed char y, unsigned char buttons, signed char wheel)
+{
+    /* Send a simulated mouse event. Returns true if successful. */    
+    unsigned char report[4]={0,0,0,0};
+
+    report[0] = buttons;
+    report[1] = x;
+    report[2] = y;
+    report[3] = wheel;
+    
+    if (!sendInputReport(REPORT_ID_MOUSE, report, 4))
+    {
+        return false;
+    }    
+
+    return true;
+}
+
+
+//
+// USBJoystick
+//
+
+unsigned char magic_init_bytes[] = {0x21, 0x26, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00}; // PS3 will request these bytes as a class type report 0x0300
+
+/* Joystick */
+unsigned char reportDescriptorJoystick[] = {
+0x05, 0x01, // USAGE_PAGE (Generic Desktop)
+0x09, 0x05, // USAGE (Gamepad)
+0xa1, 0x01, // COLLECTION (Application)
+
+0x15, 0x00, //   LOGICAL_MINIMUM (0)
+0x25, 0x01, //   LOGICAL_MAXIMUM (1)
+0x35, 0x00, //   PHYSICAL_MINIMUM (0)
+0x45, 0x01, //   PHYSICAL_MAXIMUM (1)
+0x75, 0x01, //   REPORT_SIZE (1)
+0x95, 0x0d, //   REPORT_COUNT (13)
+0x05, 0x09, //   USAGE_PAGE (Button)
+0x19, 0x01, //   USAGE_MINIMUM (Button 1)
+0x29, 0x0d, //   USAGE_MAXIMUM (Button 13)
+0x81, 0x02, //   INPUT (Data,Var,Abs)
+0x95, 0x03, //   REPORT_COUNT (3)
+0x81, 0x01, //   INPUT (Cnst,Ary,Abs)
+0x05, 0x01, //   USAGE_PAGE (Generic Desktop)
+0x25, 0x07, //   LOGICAL_MAXIMUM (7)
+0x46, 0x3b, 0x01, //   PHYSICAL_MAXIMUM (315)
+0x75, 0x04, //   REPORT_SIZE (4)
+0x95, 0x01, //   REPORT_COUNT (1)
+0x65, 0x14, //   UNIT (Eng Rot:Angular Pos)
+0x09, 0x39, //   USAGE (Hat switch)
+0x81, 0x42, //   INPUT (Data,Var,Abs,Null)
+0x65, 0x00, //   UNIT (None)
+0x95, 0x01, //   REPORT_COUNT (1)
+0x81, 0x01, //   INPUT (Cnst,Ary,Abs)
+
+0x26, 0xff, 0x00, //   LOGICAL_MAXIMUM (255)
+0x46, 0xff, 0x00, //   PHYSICAL_MAXIMUM (255)
+0x09, 0x30, //   USAGE (X)
+0x09, 0x31, //   USAGE (Y)
+0x09, 0x32, //   USAGE (Z)
+0x09, 0x35, //   USAGE (Rz)
+0x75, 0x08, //   REPORT_SIZE (8)
+0x95, 0x04, //   REPORT_COUNT (4)
+0x81, 0x02, //   INPUT (Data,Var,Abs)
+
+0x06, 0x00, 0xff, //   USAGE_PAGE (Vendor Specific)
+0x09, 0x20, //   Unknown
+0x09, 0x21, //   Unknown
+0x09, 0x22, //   Unknown
+0x09, 0x23, //   Unknown
+0x09, 0x24, //   Unknown
+0x09, 0x25, //   Unknown
+0x09, 0x26, //   Unknown
+0x09, 0x27, //   Unknown
+0x09, 0x28, //   Unknown
+0x09, 0x29, //   Unknown
+0x09, 0x2a, //   Unknown
+0x09, 0x2b, //   Unknown
+0x95, 0x0c, //   REPORT_COUNT (12)
+0x81, 0x02, //   INPUT (Data,Var,Abs)
+0x0a, 0x21, 0x26, //   Unknown
+0x95, 0x08, //   REPORT_COUNT (8)
+0xb1, 0x02, //   FEATURE (Data,Var,Abs)
+
+0xc0, // END_COLLECTION
+};
+
+USBJoystick::USBJoystick()
+{
+    int reportDescriptorSize = sizeof(reportDescriptorJoystick);
+    configurationDescriptor[25] = reportDescriptorSize & 0xff;
+    configurationDescriptor[26] = (reportDescriptorSize >> 8) & 0xff;
+}
+
+bool USBJoystick::requestGetDescriptor(void)
+{
+    bool success = false;
+        
+    switch (DESCRIPTOR_TYPE(transfer.setup.wValue))
+    {
+        case REPORT_DESCRIPTOR:
+            transfer.remaining = sizeof(reportDescriptorJoystick);
+            transfer.ptr = reportDescriptorJoystick;
+            transfer.direction = DEVICE_TO_HOST;
+            success = true;            
+            break;
+        default:
+            success = usbhid::requestGetDescriptor();
+            break;    
+    }
+    
+    return success;
+}
+
+bool USBJoystick::sendInputReport(unsigned char *data, unsigned char size)
+{
+    /* Send an Input Report */
+    /* If data is NULL an all zero report is sent */
+    
+    static unsigned char report[MAX_REPORT_SIZE];
+    unsigned char i;
+
+    if (size > MAX_REPORT_SIZE)
+    {
+        return false;
+    }
+    
+    /* Add report data */
+    if (data != NULL)
+    {    
+        for (i=0; i<size; i++)
+        {
+            report[i] = *data++;
+        }
+    }
+    else
+    {
+        for (i=0; i<size; i++)
+        {
+            report[i] = 0;
+        }
+    }    
+    
+    /* Block if not configured */
+    while (!configured);
+
+    
+    /* Send report */
+    complete = false;
+
+    disableEvents();
+    endpointWrite(EP1IN, report, size);
+    enableEvents();
+
+  
+    /* Wait for completion */
+    while(!complete && configured);    
+    
+    
+    return true;
+}
+
+bool USBJoystick::joystick(unsigned char stick, unsigned short buttons, signed char x, signed char y, signed char z, signed char rz)
+{
+    unsigned char report[8+8+3] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+    
+    unsigned char hatswitch;
+    if (stick & JOYSTICK_UP) {
+        hatswitch = 0;
+        if (stick & JOYSTICK_RIGHT) hatswitch = 1;
+        if (stick & JOYSTICK_LEFT) hatswitch = 7;
+    } else if (stick & JOYSTICK_RIGHT) {
+        hatswitch = 2;
+        if (stick & JOYSTICK_DOWN) hatswitch = 3;
+    } else if (stick & JOYSTICK_DOWN) {
+        hatswitch = 4;
+        if (stick & JOYSTICK_LEFT) hatswitch = 5;
+    } else if (stick & JOYSTICK_LEFT) {
+        hatswitch = 6;
+    } else {
+        hatswitch = 0xf;
+    }
+
+    report[0] = buttons & 0xff;         //buttons 1-8
+    report[1] = ( buttons >> 8 ) & 0xff;//buttons 9-13
+    report[2] = ((hatswitch ) & 0x0f);  // d-pad
+    report[3] = x + 0x80;               //sticks
+    report[4] = y + 0x80;
+    report[5] = z + 0x80;
+    report[6] = rz + 0x80;
+
+    report[7] = 0x00;    //unknown
+    report[8] = 0x00;    //unknown
+    report[9] = 0x00;    //unknown
+    report[10] = 0x00;   //unknown
+
+    report[11] = 0x00;   //button pressures    
+    report[12] = 0x00;   //button pressures
+    report[13] = 0x00;   //button pressures
+    report[14] = 0x00;   //button pressures
+
+    report[15] = 0x00;   //trigger pressures
+    report[16] = 0x00;   //trigger pressures
+    report[17] = 0x00;   //trigger pressures
+    report[18] = 0x00;   //trigger pressures
+
+    if (!sendInputReport(report, 19)) {
+        return false;
+    }
+
+
+    return true;
+}
+
+bool USBJoystick::requestSetup(void)
+{
+    /* Process class requests */
+    bool success = false;
+
+    if (transfer.setup.bmRequestType.Type == CLASS_TYPE)
+    {
+        switch (transfer.setup.bRequest)
+        {
+             case GET_REPORT:
+                 switch (transfer.setup.wValue & 0xffff)
+                 {
+                    case 0x0300:    //vendor specific request
+                    
+                        transfer.ptr = (unsigned char*)magic_init_bytes;
+                        transfer.remaining = sizeof(magic_init_bytes);
+                        transfer.direction = DEVICE_TO_HOST;
+                        success = true;
+                        
+                        break;
+                    default:
+                        break;
+                 }
+                 break;
+             default:
+                 break;
+        }
+    }
+        
+    if (success)
+    {
+        /* We've handled this request */
+        return true;
+    }
+    
+    return usbdevice::requestSetup();
+}