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

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers USBHostXpad.cpp Source File

USBHostXpad.cpp

00001 /*
00002  * Xbox 360 Wireless Controller for Windows library
00003  * for mbed USBHost library
00004  * Copyright (c) 2013 Hiroshi Suga
00005  *
00006  * VID=0x045e PID=0x0719
00007  *
00008  * Reference:
00009  *  https://github.com/Grumbel/xboxdrv/blob/master/PROTOCOL
00010  *  http://tattiebogle.net/index.php/ProjectRoot/Xbox360Controller
00011  */
00012 
00013 #include "USBHostXpad.h"
00014 
00015 #if 1 or USBHOST_XPAD
00016 
00017 #include "dbg.h"
00018 
00019 #define DEVICE_TO_HOST  0x80
00020 #define HOST_TO_DEVICE  0x00
00021 
00022 USBHostXpad::USBHostXpad()
00023 {
00024     host = USBHost::getHostInst();
00025     init();
00026 }
00027 
00028 void USBHostXpad::init() {
00029     dev_connected = false;
00030     dev = NULL;
00031     int_in = NULL;
00032     int_out = NULL;
00033     xpad_intf = -1;
00034     xpad_device_found = false;
00035     nb_ep = 0;
00036     dev_type = TYPE_UNKNOWN;
00037     dev_started = false;
00038 }
00039 
00040 bool USBHostXpad::connected()
00041 {
00042     return dev_connected;
00043 }
00044 
00045 bool USBHostXpad::connect()
00046 {
00047 
00048     if (dev_connected) {
00049         return true;
00050     }
00051 
00052     for (int i = 0; i < MAX_DEVICE_CONNECTED; i++) {
00053         if ((dev = host->getDevice(i)) != NULL) {
00054             
00055             //USB_DBG("Trying to connect MSD device\r\n");
00056             
00057             if(host->enumerate(dev, this)) break;
00058 
00059             if (xpad_device_found) {
00060                 int_in = dev->getEndpoint(xpad_intf, INTERRUPT_ENDPOINT, IN);
00061                 int_out = dev->getEndpoint(xpad_intf, INTERRUPT_ENDPOINT, OUT);
00062                 
00063                 if (!int_in || !int_out) continue;
00064 
00065                 USB_INFO("New MSD device: VID:%04x PID:%04x [dev: %p - intf: %d]", dev->getVid(), dev->getPid(), dev, xpad_intf);
00066                 dev->setName("XPAD", xpad_intf);
00067                 host->registerDriver(dev, xpad_intf, this, &USBHostXpad::init);
00068                 int_in->attach(this, &USBHostXpad::rxHandler);
00069                 host->interruptRead(dev, int_in, report, int_in->getSize(), false);
00070 
00071                 Thread::wait(100);
00072                 led(LED_OFF);
00073                 dev_connected = true;
00074                 return true;
00075             }
00076 
00077         }
00078     }
00079     init();
00080     return false;
00081 }
00082 
00083 void USBHostXpad::rxHandler() {
00084     int len_listen = int_in->getSize();
00085     int len = int_in->getLengthTransferred();
00086 
00087 /*
00088     for (int i = 0; i < len_listen; i ++) {
00089         std::printf(" %02x", report[i]);
00090     }
00091     std::printf("\r\n");
00092 */
00093     if (dev_type == TYPE_XBOX) {
00094         parseMessage();
00095     } else
00096     if (report[0] == 0x08) {
00097         if (report[1] == 0x80) {
00098             // Connection Status Messages
00099             start();
00100         } else
00101         if (report[1] == 0x00) {
00102             // Disconnected Status Messages
00103             dev_started = false;
00104         }
00105     } else
00106     if (report[0] == 0x00) {
00107         if ((report[1] == 0x14) ||
00108             (report[1] == 0x01 && report[2] == 0x00 && report[3] == 0xf0)) {
00109             // Event data
00110             parseMessage();
00111         } else
00112         if (report[1] == 0x0f) {
00113             // On connection
00114             led(LED1_ON);
00115             start();
00116             dev_started = true;
00117         } else
00118         if (report[1] == 0x00) {
00119             if (report[3] == 0x13) {
00120                 // Battery charge level
00121                 battery = report[4];
00122             } else
00123             if (report[3] == 0xf0) {
00124                 // Device low power mode (HID updates will stop until controller inputs change)
00125 //                restart();
00126             }
00127         } else
00128         if (report[1] == 0xf8) {
00129             // Status Messages ?
00130         }
00131     } else {
00132         // Unknown
00133         USB_INFO("rxHandler len:%d data:%02x %02x %02x %02x", len, report[0], report[1], report[2], report[3]);
00134     }
00135 
00136     if (dev) {
00137         host->interruptRead(dev, int_in, report, len_listen, false);
00138     }
00139 }
00140 
00141 /*virtual*/ void USBHostXpad::setVidPid(uint16_t vid, uint16_t pid)
00142 {
00143     // we don't check VID/PID for MSD driver
00144     if (vid == 0x045e && (pid == 0x0202 || pid == 0x0285 || pid == 0x0287 || pid == 0x0289)) {
00145         dev_type = TYPE_XBOX;
00146     } else
00147     if (vid == 0x045e && pid == 0x028e) {
00148         dev_type = TYPE_XBOX360;
00149     } else
00150     if (vid == 0x045e && pid == 0x0719) {
00151         dev_type = TYPE_XBOX360W;
00152     }
00153     USB_INFO("setVidPid vid:%04x pid:%04x xbox:%d", vid, pid, dev_type);
00154 }
00155 
00156 /*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
00157 {
00158     USB_INFO("parseInterface class:%02x subclass:%02x protocol:%02x [nb: %d - intf: %d]", intf_class, intf_subclass, intf_protocol, intf_nb, xpad_intf);
00159     if ((xpad_intf == -1) && (intf_class == 0x58) && (intf_subclass == 0x42) && (intf_protocol == 0x00)) {
00160         xpad_intf = intf_nb; // XBOX ?
00161         return true;
00162     }
00163     if ((xpad_intf == -1) && (intf_class == 0xff) && (intf_subclass == 0x5d) && (intf_protocol == 0x81)) {
00164         xpad_intf = intf_nb; // XBOX360W
00165         return true;
00166     }
00167     return false;
00168 }
00169 
00170 /*virtual*/ bool USBHostXpad::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used
00171 {
00172     USB_INFO("useEndpoint nb:%d type:%d dir:%d", intf_nb, type, dir);
00173     if (intf_nb == xpad_intf) {
00174         if (type == INTERRUPT_ENDPOINT) {
00175             nb_ep ++;
00176             if (nb_ep == 2) {
00177                 xpad_device_found = true;
00178             }
00179             return true;
00180         }
00181     }
00182     return false;
00183 }
00184 
00185 
00186 void USBHostXpad::parseMessage()
00187 {
00188     uint8_t *data = report;
00189 
00190     switch (dev_type) {
00191     case TYPE_XBOX:
00192         buttons = ((uint32_t)report[3] << 8) | report[2];
00193         if (report[4]) buttons |= XPAD_PAD_A;
00194         if (report[5]) buttons |= XPAD_PAD_B;
00195         if (report[6]) buttons |= XPAD_PAD_X;
00196         if (report[7]) buttons |= XPAD_PAD_Y;
00197         trigger_l = data[10];
00198         trigger_r = data[11];
00199 
00200         stick_lx = ((int16_t)report[13] << 8) | report[12];
00201         stick_ly = ((int16_t)report[15] << 8) | report[14];
00202         stick_rx = ((int16_t)report[17] << 8) | report[16];
00203         stick_ry = ((int16_t)report[19] << 8) | report[18];
00204         break;
00205     case TYPE_XBOX360W:
00206         data += 4;
00207     case TYPE_XBOX360:
00208         buttons = ((uint32_t)data[3] << 8) | data[2];
00209         trigger_l = data[4];
00210         trigger_r = data[5];
00211 
00212         stick_lx = ((int16_t)data[7] << 8) | data[6];
00213         stick_ly = ((int16_t)data[9] << 8) | data[8];
00214         stick_rx = ((int16_t)data[11] << 8) | data[10];
00215         stick_ry = ((int16_t)data[13] << 8) | data[12];
00216         break;
00217     default:
00218         return;
00219     }
00220 
00221     if (onUpdate) {
00222         (*onUpdate)(buttons, stick_lx, stick_ly, stick_rx, stick_ry, trigger_l, trigger_r);
00223     }
00224 }
00225 
00226 bool USBHostXpad::restart ()
00227 {
00228     unsigned char odata[32];
00229     memset(odata, 0, sizeof(odata));
00230     odata[0] = 0x08;
00231     odata[2] = 0x0f;
00232     odata[3] = 0xc0;
00233     if (dev) {
00234         for (int i = 0; i < 4; i ++) {
00235             host->interruptWrite(dev, int_out, odata, 12);
00236         }
00237     }
00238     return true;
00239 }
00240 
00241 int USBHostXpad::read (PAD pad)
00242 {
00243     switch (pad) {
00244     case XPAD_BUTTONS:
00245         return buttons;
00246     case XPAD_STICK_LX:
00247         return stick_lx;
00248     case XPAD_STICK_LY:
00249         return stick_ly;
00250     case XPAD_STICK_RX:
00251         return stick_rx;
00252     case XPAD_STICK_RY:
00253         return stick_ry;
00254     case XPAD_TRIGGER_L:
00255         return trigger_l;
00256     case XPAD_TRIGGER_R:
00257         return trigger_r;
00258     case XPAD_BATTERY:
00259         return battery;
00260     default:
00261         return (buttons & pad) ? 1 : 0;
00262     }
00263 }
00264 
00265 bool USBHostXpad::start()
00266 {
00267     unsigned char odata[32];
00268     memset(odata, 0, sizeof(odata));
00269     odata[3] = 0x40;
00270     if (dev) {
00271         if (host->interruptWrite(dev, int_out, odata, 12) != USB_TYPE_OK) {
00272             return false;
00273         }
00274     }
00275     return true;
00276 }
00277 
00278 bool USBHostXpad::stop()
00279 {
00280     unsigned char odata[32];
00281     memset(odata, 0, sizeof(odata));
00282     odata[2] = 0x08;
00283     odata[3] = 0xc0;
00284     if (dev) {
00285         if (host->interruptWrite(dev, int_out, odata, 12) != USB_TYPE_OK) {
00286             return false;
00287         }
00288     }
00289     return true;
00290 }
00291 
00292 bool USBHostXpad::led(LED cmd)
00293 {
00294     unsigned char odata[32];
00295     memset(odata, 0, sizeof(odata));
00296     switch (dev_type) {
00297     case TYPE_XBOX:
00298         return true;
00299     case TYPE_XBOX360:
00300         odata[0] = 0x01;
00301         odata[1] = 0x03;
00302         odata[2] = cmd;
00303         break;
00304     case TYPE_XBOX360W:
00305         odata[2] = 0x08;
00306         odata[3] = 0x40 + (cmd % 0x0e);
00307         break;
00308     default:
00309         return false;
00310     }
00311     if (dev) {
00312         if (host->interruptWrite(dev, int_out, odata, 12) != USB_TYPE_OK) {
00313             return false;
00314         }
00315     }
00316     return true;
00317 }
00318 
00319 bool USBHostXpad::rumble(uint8_t large, uint8_t small)
00320 {
00321     unsigned char odata[32];
00322     memset(odata, 0, sizeof(odata));
00323     switch (dev_type) {
00324     case TYPE_XBOX:
00325         odata[1] = 0x06;
00326         odata[3] = small;
00327         odata[5] = large;
00328         break;
00329     case TYPE_XBOX360:
00330         odata[1] = 0x08;
00331         odata[3] = large;
00332         odata[4] = small;
00333         break;
00334     case TYPE_XBOX360W:
00335         odata[1] = 0x01;
00336         odata[2] = 0x0f;
00337         odata[3] = 0xc0;
00338         odata[5] = large;
00339         odata[6] = small;
00340         break;
00341     default:
00342         return false;
00343     }
00344     if (dev) {
00345         if (host->interruptWrite(dev, int_out, odata, 12) != USB_TYPE_OK) {
00346             return false;
00347         }
00348     }
00349     return true;
00350 }
00351 
00352 #endif
00353