Xbox 360 Wireless Controller for Windows library. sample: http://mbed.org/users/okini3939/code/USBHostXpad_HelloWorld/

Dependents:   x4180_Tank Totaleprogramma Handmatig Totaleprogramma1

Fork of USBHostXpad by Suga koubou

Revision:
3:53ce7778a155
Parent:
2:2749f4e649db
Child:
4:4254192898a9
--- a/USBHostXpad.cpp	Wed Dec 11 05:03:05 2013 +0000
+++ b/USBHostXpad.cpp	Fri Dec 13 07:36:09 2013 +0000
@@ -6,7 +6,8 @@
  * VID=0x045e PID=0x0719
  *
  * Reference:
- * https://github.com/Grumbel/xboxdrv/blob/master/PROTOCOL
+ *  https://github.com/Grumbel/xboxdrv/blob/master/PROTOCOL
+ *  http://tattiebogle.net/index.php/ProjectRoot/Xbox360Controller
  */
 
 #include "USBHostXpad.h"
@@ -32,6 +33,8 @@
     xpad_intf = -1;
     xpad_device_found = false;
     nb_ep = 0;
+    dev_type = TYPE_UNKNOWN;
+    dev_started = false;
 }
 
 bool USBHostXpad::connected()
@@ -46,23 +49,20 @@
         return true;
     }
 
-    for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++) {
+    for (int i = 0; i < MAX_DEVICE_CONNECTED; i++) {
         if ((dev = host->getDevice(i)) != NULL) {
             
             USB_DBG("Trying to connect MSD device\r\n");
             
-            if(host->enumerate(dev, this))
-                break;
+            if(host->enumerate(dev, this)) break;
 
             if (xpad_device_found) {
                 int_in = dev->getEndpoint(xpad_intf, INTERRUPT_ENDPOINT, IN);
                 int_out = dev->getEndpoint(xpad_intf, INTERRUPT_ENDPOINT, OUT);
                 
-                if (!int_in || !int_out)
-                    continue;
+                if (!int_in || !int_out) continue;
 
                 USB_INFO("New MSD device: VID:%04x PID:%04x [dev: %p - intf: %d]", dev->getVid(), dev->getPid(), dev, xpad_intf);
-                USB_INFO("endpoint in:%08x out:%08x", int_in, int_out);
                 dev->setName("XPAD", xpad_intf);
                 host->registerDriver(dev, xpad_intf, this, &USBHostXpad::init);
                 int_in->attach(this, &USBHostXpad::rxHandler);
@@ -90,62 +90,78 @@
     }
     std::printf("\r\n");
 */
-    if (report[0] == 0x08 && report[1] == 0x80) {
-        // Connection Status Messages
-        send(0x00, 0x00, 0x00, 0x40);
-        goto exit;
+    if (dev_type == TYPE_XBOX) {
+        parseMessage();
+    } else
+    if (report[0] == 0x08) {
+        if (report[1] == 0x80) {
+            // Connection Status Messages
+            start();
+        } else
+        if (report[1] == 0x00) {
+            // Disconnected Status Messages
+            dev_started = false;
+        }
     } else
-    if (report[0] == 0x00 && report[1] == 0x0f) {
-        // On connection
-        led(LED1_ON);
-        send(0x00, 0x00, 0x00, 0x40);
-        goto exit;
-    } else
-    if (report[0] == 0x00 && report[1] == 0xf8) {
-        // Battery Status Msg (maybe)
-        goto exit;
-    } else
-    if (report[0] == 0x00 && report[1] == 0x00 && report[2] == 0x00 && report[3] == 0xf0) {
-        // Battery Full ?
-        goto exit;
-    } else
-    if (report[0] != 0x00 || report[1] != 0x01 || report[2] != 0x00 || report[3] != 0xf0) {
+    if (report[0] == 0x00) {
+        if ((report[1] == 0x14) ||
+            (report[1] == 0x01 && report[2] == 0x00 && report[3] == 0xf0)) {
+            // Event data
+            parseMessage();
+        } else
+        if (report[1] == 0x0f) {
+            // On connection
+            led(LED1_ON);
+            start();
+            dev_started = true;
+        } else
+        if (report[1] == 0x00) {
+            if (report[3] == 0x13) {
+                // Battery charge level
+                battery = report[4];
+            } else
+            if (report[3] == 0xf0) {
+                // Device low power mode (HID updates will stop until controller inputs change)
+                restart();
+            }
+        } else
+        if (report[1] == 0xf8) {
+            // Status Messages ?
+        }
+    } else {
         // Unknown
         USB_INFO("rxHandler len:%d data:%02x %02x %02x %02x", len, report[0], report[1], report[2], report[3]);
-        goto exit;
     }
-    // Event data
-
-    buttons = ((uint32_t)report[7] << 8) | report[6];
-    trigger_l = report[8];
-    trigger_r = report[9];
 
-    stick_lx = ((int16_t)report[11] << 8) | report[10];
-    stick_ly = ((int16_t)report[13] << 8) | report[12];
-    stick_rx = ((int16_t)report[15] << 8) | report[14];
-    stick_ry = ((int16_t)report[17] << 8) | report[16];
-
-    if (onUpdate) {
-        (*onUpdate)(buttons, stick_lx, stick_ly, stick_rx, stick_ry, trigger_l, trigger_r);
+    if (dev) {
+        host->interruptRead(dev, int_in, report, len_listen, false);
     }
-exit:
-    if (dev)
-        host->interruptRead(dev, int_in, report, len_listen, false);
 }
 
 /*virtual*/ void USBHostXpad::setVidPid(uint16_t vid, uint16_t pid)
 {
     // we don't check VID/PID for MSD driver
+    if (vid == 0x045e && (pid == 0x0202 || pid == 0x0285 || pid == 0x0287 || pid == 0x0289)) {
+        dev_type = TYPE_XBOX;
+    } else
+    if (vid == 0x045e && pid == 0x028e) {
+        dev_type = TYPE_XBOX360;
+    } else
+    if (vid == 0x045e && pid == 0x0719) {
+        dev_type = TYPE_XBOX360W;
+    }
+    USB_INFO("setVidPid vid:%04x pid:%04x xbox:%d", vid, pid, dev_type);
 }
 
 /*virtual*/ bool USBHostXpad::parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) //Must return true if the interface should be parsed
 {
     USB_INFO("parseInterface class:%02x subclass:%02x protocol:%02x [nb: %d - intf: %d]", intf_class, intf_subclass, intf_protocol, intf_nb, xpad_intf);
-    if ((xpad_intf == -1) &&
-        (intf_class == 0xff) &&
-        (intf_subclass == 0x5d) &&
-        (intf_protocol == 0x81)) {
-        xpad_intf = intf_nb;
+    if ((xpad_intf == -1) && (intf_class == 0x58) && (intf_subclass == 0x42) && (intf_protocol == 0x00)) {
+        xpad_intf = intf_nb; // XBOX ?
+        return true;
+    }
+    if ((xpad_intf == -1) && (intf_class == 0xff) && (intf_subclass == 0x5d) && (intf_protocol == 0x81)) {
+        xpad_intf = intf_nb; // XBOX360W
         return true;
     }
     return false;
@@ -157,44 +173,76 @@
     if (intf_nb == xpad_intf) {
         if (type == INTERRUPT_ENDPOINT) {
             nb_ep ++;
-            if (nb_ep == 2)
+            if (nb_ep == 2) {
                 xpad_device_found = true;
+            }
             return true;
         }
     }
     return false;
 }
 
-void USBHostXpad::restart ()
+
+void USBHostXpad::parseMessage()
 {
-    if (send(0x08, 0x00, 0x0f, 0xc0) == false) {
-        init();
+    uint8_t *data = report;
+
+    switch (dev_type) {
+    case TYPE_XBOX:
+        buttons = ((uint32_t)report[3] << 8) | report[2];
+        if (report[4]) buttons |= XPAD_PAD_A;
+        if (report[5]) buttons |= XPAD_PAD_B;
+        if (report[6]) buttons |= XPAD_PAD_X;
+        if (report[7]) buttons |= XPAD_PAD_Y;
+        trigger_l = data[10];
+        trigger_r = data[11];
+
+        stick_lx = ((int16_t)report[13] << 8) | report[12];
+        stick_ly = ((int16_t)report[15] << 8) | report[14];
+        stick_rx = ((int16_t)report[17] << 8) | report[16];
+        stick_ry = ((int16_t)report[19] << 8) | report[18];
+        break;
+    case TYPE_XBOX360W:
+        data += 4;
+    case TYPE_XBOX360:
+        buttons = ((uint32_t)data[3] << 8) | data[2];
+        trigger_l = data[4];
+        trigger_r = data[5];
+
+        stick_lx = ((int16_t)data[7] << 8) | data[6];
+        stick_ly = ((int16_t)data[9] << 8) | data[8];
+        stick_rx = ((int16_t)data[11] << 8) | data[10];
+        stick_ry = ((int16_t)data[13] << 8) | data[12];
+        break;
+    default:
         return;
     }
-    send(0x08, 0x00, 0x0f, 0xc0);
-    send(0x08, 0x00, 0x0f, 0xc0);
-    send(0x08, 0x00, 0x0f, 0xc0);
+
+    if (onUpdate) {
+        (*onUpdate)(buttons, stick_lx, stick_ly, stick_rx, stick_ry, trigger_l, trigger_r);
+    }
 }
 
-bool USBHostXpad::send(int val1, int val2, int val3, int val4)
+bool USBHostXpad::restart ()
 {
     unsigned char odata[32];
     memset(odata, 0, sizeof(odata));
-    odata[0] = val1;
-    odata[1] = val2;
-    odata[2] = val3;
-    odata[3] = val4;
-
-    if (dev)
-        if (host->interruptWrite(dev, int_out, odata, 12) == USB_TYPE_ERROR) {
-            init();
-            return false;
+    odata[0] = 0x08;
+    odata[2] = 0x0f;
+    odata[3] = 0xc0;
+    if (dev) {
+        for (int i = 0; i < 4; i ++) {
+            host->interruptWrite(dev, int_out, odata, 12);
         }
+    }
     return true;
 }
 
-int USBHostXpad::read (TYPE type) {
-    switch (type) {
+int USBHostXpad::read (PAD pad)
+{
+    switch (pad) {
+    case XPAD_BUTTONS:
+        return buttons;
     case XPAD_STICK_LX:
         return stick_lx;
     case XPAD_STICK_LY:
@@ -207,20 +255,64 @@
         return trigger_l;
     case XPAD_TRIGGER_R:
         return trigger_r;
+    case XPAD_BATTERY:
+        return battery;
     default:
-        return (buttons & type) ? 1 : 0;
+        return (buttons & pad) ? 1 : 0;
+    }
+}
+
+bool USBHostXpad::start()
+{
+    unsigned char odata[32];
+    memset(odata, 0, sizeof(odata));
+    odata[3] = 0x40;
+    if (dev) {
+        if (host->interruptWrite(dev, int_out, odata, 12) != USB_TYPE_OK) {
+            return false;
+        }
     }
+    return true;
+}
+
+bool USBHostXpad::stop()
+{
+    unsigned char odata[32];
+    memset(odata, 0, sizeof(odata));
+    odata[2] = 0x08;
+    odata[3] = 0xc0;
+    if (dev) {
+        if (host->interruptWrite(dev, int_out, odata, 12) != USB_TYPE_OK) {
+            return false;
+        }
+    }
+    return true;
 }
 
 bool USBHostXpad::led(LED cmd)
 {
     unsigned char odata[32];
     memset(odata, 0, sizeof(odata));
-    odata[2] = 0x08;
-    odata[3] = 0x40 + (cmd % 0x0e);
-    if (dev)
-        if (host->interruptWrite(dev, int_out, odata, 12) == USB_TYPE_ERROR)
+    switch (dev_type) {
+    case TYPE_XBOX:
+        return true;
+    case TYPE_XBOX360:
+        odata[0] = 0x01;
+        odata[1] = 0x03;
+        odata[2] = cmd;
+        break;
+    case TYPE_XBOX360W:
+        odata[2] = 0x08;
+        odata[3] = 0x40 + (cmd % 0x0e);
+        break;
+    default:
+        return false;
+    }
+    if (dev) {
+        if (host->interruptWrite(dev, int_out, odata, 12) != USB_TYPE_OK) {
             return false;
+        }
+    }
     return true;
 }
 
@@ -228,14 +320,32 @@
 {
     unsigned char odata[32];
     memset(odata, 0, sizeof(odata));
-    odata[1] = 0x01;
-    odata[2] = 0x0f;
-    odata[3] = 0xc0;
-    odata[5] = large;
-    odata[6] = small;
-    if (dev)
-        if (host->interruptWrite(dev, int_out, odata, 12) == USB_TYPE_ERROR)
+    switch (dev_type) {
+    case TYPE_XBOX:
+        odata[1] = 0x06;
+        odata[3] = small;
+        odata[5] = large;
+        break;
+    case TYPE_XBOX360:
+        odata[1] = 0x08;
+        odata[3] = large;
+        odata[4] = small;
+        break;
+    case TYPE_XBOX360W:
+        odata[1] = 0x01;
+        odata[2] = 0x0f;
+        odata[3] = 0xc0;
+        odata[5] = large;
+        odata[6] = small;
+        break;
+    default:
+        return false;
+    }
+    if (dev) {
+        if (host->interruptWrite(dev, int_out, odata, 12) != USB_TYPE_OK) {
             return false;
+        }
+    }
     return true;
 }