Xbox 360 Wireless Controller for Windows library. sample: http://mbed.org/users/okini3939/code/USBHostXpad_HelloWorld/
Dependents: USBHostXpad_HelloWorld USBHostXpad_HelloWorld
Xbox 360 Wireless Controller for Windows
Microsoftの XBOX 360 ワイヤレスコントローラーを、パソコン用のUSB接続型レシーバーで mbed に接続して使えるライブラリです。
USB Host 機能を使いますので mbed LPC1768 専用です。
たまに処理が停止する不具合があります。
USBHostXpad.cpp@2:2749f4e649db, 2013-12-11 (annotated)
- Committer:
- okini3939
- Date:
- Wed Dec 11 05:03:05 2013 +0000
- Revision:
- 2:2749f4e649db
- Parent:
- 1:5bb153989f33
- Child:
- 3:53ce7778a155
add read function
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
okini3939 | 0:bd0f6bf72a8b | 1 | /* |
okini3939 | 0:bd0f6bf72a8b | 2 | * Xbox 360 Wireless Controller for Windows library |
okini3939 | 0:bd0f6bf72a8b | 3 | * for mbed USBHost library |
okini3939 | 0:bd0f6bf72a8b | 4 | * Copyright (c) 2013 Hiroshi Suga |
okini3939 | 0:bd0f6bf72a8b | 5 | * |
okini3939 | 0:bd0f6bf72a8b | 6 | * VID=0x045e PID=0x0719 |
okini3939 | 0:bd0f6bf72a8b | 7 | * |
okini3939 | 1:5bb153989f33 | 8 | * Reference: |
okini3939 | 1:5bb153989f33 | 9 | * https://github.com/Grumbel/xboxdrv/blob/master/PROTOCOL |
okini3939 | 0:bd0f6bf72a8b | 10 | */ |
okini3939 | 0:bd0f6bf72a8b | 11 | |
okini3939 | 0:bd0f6bf72a8b | 12 | #include "USBHostXpad.h" |
okini3939 | 0:bd0f6bf72a8b | 13 | |
okini3939 | 0:bd0f6bf72a8b | 14 | #if 1 or USBHOST_XPAD |
okini3939 | 0:bd0f6bf72a8b | 15 | |
okini3939 | 0:bd0f6bf72a8b | 16 | #include "dbg.h" |
okini3939 | 0:bd0f6bf72a8b | 17 | |
okini3939 | 0:bd0f6bf72a8b | 18 | #define DEVICE_TO_HOST 0x80 |
okini3939 | 0:bd0f6bf72a8b | 19 | #define HOST_TO_DEVICE 0x00 |
okini3939 | 0:bd0f6bf72a8b | 20 | |
okini3939 | 0:bd0f6bf72a8b | 21 | USBHostXpad::USBHostXpad() |
okini3939 | 0:bd0f6bf72a8b | 22 | { |
okini3939 | 0:bd0f6bf72a8b | 23 | host = USBHost::getHostInst(); |
okini3939 | 0:bd0f6bf72a8b | 24 | init(); |
okini3939 | 0:bd0f6bf72a8b | 25 | } |
okini3939 | 0:bd0f6bf72a8b | 26 | |
okini3939 | 0:bd0f6bf72a8b | 27 | void USBHostXpad::init() { |
okini3939 | 0:bd0f6bf72a8b | 28 | dev_connected = false; |
okini3939 | 0:bd0f6bf72a8b | 29 | dev = NULL; |
okini3939 | 0:bd0f6bf72a8b | 30 | int_in = NULL; |
okini3939 | 0:bd0f6bf72a8b | 31 | int_out = NULL; |
okini3939 | 0:bd0f6bf72a8b | 32 | xpad_intf = -1; |
okini3939 | 0:bd0f6bf72a8b | 33 | xpad_device_found = false; |
okini3939 | 0:bd0f6bf72a8b | 34 | nb_ep = 0; |
okini3939 | 0:bd0f6bf72a8b | 35 | } |
okini3939 | 0:bd0f6bf72a8b | 36 | |
okini3939 | 0:bd0f6bf72a8b | 37 | bool USBHostXpad::connected() |
okini3939 | 0:bd0f6bf72a8b | 38 | { |
okini3939 | 0:bd0f6bf72a8b | 39 | return dev_connected; |
okini3939 | 0:bd0f6bf72a8b | 40 | } |
okini3939 | 0:bd0f6bf72a8b | 41 | |
okini3939 | 0:bd0f6bf72a8b | 42 | bool USBHostXpad::connect() |
okini3939 | 0:bd0f6bf72a8b | 43 | { |
okini3939 | 0:bd0f6bf72a8b | 44 | |
okini3939 | 0:bd0f6bf72a8b | 45 | if (dev_connected) { |
okini3939 | 0:bd0f6bf72a8b | 46 | return true; |
okini3939 | 0:bd0f6bf72a8b | 47 | } |
okini3939 | 0:bd0f6bf72a8b | 48 | |
okini3939 | 0:bd0f6bf72a8b | 49 | for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++) { |
okini3939 | 0:bd0f6bf72a8b | 50 | if ((dev = host->getDevice(i)) != NULL) { |
okini3939 | 0:bd0f6bf72a8b | 51 | |
okini3939 | 0:bd0f6bf72a8b | 52 | USB_DBG("Trying to connect MSD device\r\n"); |
okini3939 | 0:bd0f6bf72a8b | 53 | |
okini3939 | 0:bd0f6bf72a8b | 54 | if(host->enumerate(dev, this)) |
okini3939 | 0:bd0f6bf72a8b | 55 | break; |
okini3939 | 0:bd0f6bf72a8b | 56 | |
okini3939 | 0:bd0f6bf72a8b | 57 | if (xpad_device_found) { |
okini3939 | 0:bd0f6bf72a8b | 58 | int_in = dev->getEndpoint(xpad_intf, INTERRUPT_ENDPOINT, IN); |
okini3939 | 0:bd0f6bf72a8b | 59 | int_out = dev->getEndpoint(xpad_intf, INTERRUPT_ENDPOINT, OUT); |
okini3939 | 0:bd0f6bf72a8b | 60 | |
okini3939 | 0:bd0f6bf72a8b | 61 | if (!int_in || !int_out) |
okini3939 | 0:bd0f6bf72a8b | 62 | continue; |
okini3939 | 0:bd0f6bf72a8b | 63 | |
okini3939 | 0:bd0f6bf72a8b | 64 | USB_INFO("New MSD device: VID:%04x PID:%04x [dev: %p - intf: %d]", dev->getVid(), dev->getPid(), dev, xpad_intf); |
okini3939 | 0:bd0f6bf72a8b | 65 | USB_INFO("endpoint in:%08x out:%08x", int_in, int_out); |
okini3939 | 0:bd0f6bf72a8b | 66 | dev->setName("XPAD", xpad_intf); |
okini3939 | 0:bd0f6bf72a8b | 67 | host->registerDriver(dev, xpad_intf, this, &USBHostXpad::init); |
okini3939 | 1:5bb153989f33 | 68 | int_in->attach(this, &USBHostXpad::rxHandler); |
okini3939 | 1:5bb153989f33 | 69 | host->interruptRead(dev, int_in, report, int_in->getSize(), false); |
okini3939 | 0:bd0f6bf72a8b | 70 | |
okini3939 | 1:5bb153989f33 | 71 | Thread::wait(100); |
okini3939 | 2:2749f4e649db | 72 | led(LED_OFF); |
okini3939 | 0:bd0f6bf72a8b | 73 | dev_connected = true; |
okini3939 | 0:bd0f6bf72a8b | 74 | return true; |
okini3939 | 0:bd0f6bf72a8b | 75 | } |
okini3939 | 0:bd0f6bf72a8b | 76 | |
okini3939 | 1:5bb153989f33 | 77 | } |
okini3939 | 1:5bb153989f33 | 78 | } |
okini3939 | 0:bd0f6bf72a8b | 79 | init(); |
okini3939 | 0:bd0f6bf72a8b | 80 | return false; |
okini3939 | 0:bd0f6bf72a8b | 81 | } |
okini3939 | 0:bd0f6bf72a8b | 82 | |
okini3939 | 0:bd0f6bf72a8b | 83 | void USBHostXpad::rxHandler() { |
okini3939 | 0:bd0f6bf72a8b | 84 | int len_listen = int_in->getSize(); |
okini3939 | 0:bd0f6bf72a8b | 85 | int len = int_in->getLengthTransferred(); |
okini3939 | 0:bd0f6bf72a8b | 86 | |
okini3939 | 1:5bb153989f33 | 87 | /* |
okini3939 | 0:bd0f6bf72a8b | 88 | for (int i = 0; i < len_listen; i ++) { |
okini3939 | 0:bd0f6bf72a8b | 89 | std::printf(" %02x", report[i]); |
okini3939 | 0:bd0f6bf72a8b | 90 | } |
okini3939 | 0:bd0f6bf72a8b | 91 | std::printf("\r\n"); |
okini3939 | 1:5bb153989f33 | 92 | */ |
okini3939 | 0:bd0f6bf72a8b | 93 | if (report[0] == 0x08 && report[1] == 0x80) { |
okini3939 | 1:5bb153989f33 | 94 | // Connection Status Messages |
okini3939 | 1:5bb153989f33 | 95 | send(0x00, 0x00, 0x00, 0x40); |
okini3939 | 0:bd0f6bf72a8b | 96 | goto exit; |
okini3939 | 0:bd0f6bf72a8b | 97 | } else |
okini3939 | 0:bd0f6bf72a8b | 98 | if (report[0] == 0x00 && report[1] == 0x0f) { |
okini3939 | 1:5bb153989f33 | 99 | // On connection |
okini3939 | 2:2749f4e649db | 100 | led(LED1_ON); |
okini3939 | 1:5bb153989f33 | 101 | send(0x00, 0x00, 0x00, 0x40); |
okini3939 | 1:5bb153989f33 | 102 | goto exit; |
okini3939 | 1:5bb153989f33 | 103 | } else |
okini3939 | 1:5bb153989f33 | 104 | if (report[0] == 0x00 && report[1] == 0xf8) { |
okini3939 | 1:5bb153989f33 | 105 | // Battery Status Msg (maybe) |
okini3939 | 0:bd0f6bf72a8b | 106 | goto exit; |
okini3939 | 0:bd0f6bf72a8b | 107 | } else |
okini3939 | 1:5bb153989f33 | 108 | if (report[0] == 0x00 && report[1] == 0x00 && report[2] == 0x00 && report[3] == 0xf0) { |
okini3939 | 1:5bb153989f33 | 109 | // Battery Full ? |
okini3939 | 0:bd0f6bf72a8b | 110 | goto exit; |
okini3939 | 0:bd0f6bf72a8b | 111 | } else |
okini3939 | 1:5bb153989f33 | 112 | if (report[0] != 0x00 || report[1] != 0x01 || report[2] != 0x00 || report[3] != 0xf0) { |
okini3939 | 1:5bb153989f33 | 113 | // Unknown |
okini3939 | 1:5bb153989f33 | 114 | USB_INFO("rxHandler len:%d data:%02x %02x %02x %02x", len, report[0], report[1], report[2], report[3]); |
okini3939 | 0:bd0f6bf72a8b | 115 | goto exit; |
okini3939 | 0:bd0f6bf72a8b | 116 | } |
okini3939 | 1:5bb153989f33 | 117 | // Event data |
okini3939 | 0:bd0f6bf72a8b | 118 | |
okini3939 | 0:bd0f6bf72a8b | 119 | buttons = ((uint32_t)report[7] << 8) | report[6]; |
okini3939 | 0:bd0f6bf72a8b | 120 | trigger_l = report[8]; |
okini3939 | 0:bd0f6bf72a8b | 121 | trigger_r = report[9]; |
okini3939 | 0:bd0f6bf72a8b | 122 | |
okini3939 | 0:bd0f6bf72a8b | 123 | stick_lx = ((int16_t)report[11] << 8) | report[10]; |
okini3939 | 0:bd0f6bf72a8b | 124 | stick_ly = ((int16_t)report[13] << 8) | report[12]; |
okini3939 | 0:bd0f6bf72a8b | 125 | stick_rx = ((int16_t)report[15] << 8) | report[14]; |
okini3939 | 0:bd0f6bf72a8b | 126 | stick_ry = ((int16_t)report[17] << 8) | report[16]; |
okini3939 | 0:bd0f6bf72a8b | 127 | |
okini3939 | 0:bd0f6bf72a8b | 128 | if (onUpdate) { |
okini3939 | 0:bd0f6bf72a8b | 129 | (*onUpdate)(buttons, stick_lx, stick_ly, stick_rx, stick_ry, trigger_l, trigger_r); |
okini3939 | 0:bd0f6bf72a8b | 130 | } |
okini3939 | 0:bd0f6bf72a8b | 131 | exit: |
okini3939 | 0:bd0f6bf72a8b | 132 | if (dev) |
okini3939 | 0:bd0f6bf72a8b | 133 | host->interruptRead(dev, int_in, report, len_listen, false); |
okini3939 | 0:bd0f6bf72a8b | 134 | } |
okini3939 | 0:bd0f6bf72a8b | 135 | |
okini3939 | 0:bd0f6bf72a8b | 136 | /*virtual*/ void USBHostXpad::setVidPid(uint16_t vid, uint16_t pid) |
okini3939 | 0:bd0f6bf72a8b | 137 | { |
okini3939 | 0:bd0f6bf72a8b | 138 | // we don't check VID/PID for MSD driver |
okini3939 | 0:bd0f6bf72a8b | 139 | } |
okini3939 | 0:bd0f6bf72a8b | 140 | |
okini3939 | 0:bd0f6bf72a8b | 141 | /*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 |
okini3939 | 0:bd0f6bf72a8b | 142 | { |
okini3939 | 0:bd0f6bf72a8b | 143 | USB_INFO("parseInterface class:%02x subclass:%02x protocol:%02x [nb: %d - intf: %d]", intf_class, intf_subclass, intf_protocol, intf_nb, xpad_intf); |
okini3939 | 0:bd0f6bf72a8b | 144 | if ((xpad_intf == -1) && |
okini3939 | 0:bd0f6bf72a8b | 145 | (intf_class == 0xff) && |
okini3939 | 0:bd0f6bf72a8b | 146 | (intf_subclass == 0x5d) && |
okini3939 | 0:bd0f6bf72a8b | 147 | (intf_protocol == 0x81)) { |
okini3939 | 0:bd0f6bf72a8b | 148 | xpad_intf = intf_nb; |
okini3939 | 0:bd0f6bf72a8b | 149 | return true; |
okini3939 | 0:bd0f6bf72a8b | 150 | } |
okini3939 | 0:bd0f6bf72a8b | 151 | return false; |
okini3939 | 0:bd0f6bf72a8b | 152 | } |
okini3939 | 0:bd0f6bf72a8b | 153 | |
okini3939 | 0:bd0f6bf72a8b | 154 | /*virtual*/ bool USBHostXpad::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used |
okini3939 | 0:bd0f6bf72a8b | 155 | { |
okini3939 | 0:bd0f6bf72a8b | 156 | USB_INFO("useEndpoint nb:%d type:%d dir:%d", intf_nb, type, dir); |
okini3939 | 0:bd0f6bf72a8b | 157 | if (intf_nb == xpad_intf) { |
okini3939 | 0:bd0f6bf72a8b | 158 | if (type == INTERRUPT_ENDPOINT) { |
okini3939 | 0:bd0f6bf72a8b | 159 | nb_ep ++; |
okini3939 | 0:bd0f6bf72a8b | 160 | if (nb_ep == 2) |
okini3939 | 0:bd0f6bf72a8b | 161 | xpad_device_found = true; |
okini3939 | 0:bd0f6bf72a8b | 162 | return true; |
okini3939 | 0:bd0f6bf72a8b | 163 | } |
okini3939 | 0:bd0f6bf72a8b | 164 | } |
okini3939 | 0:bd0f6bf72a8b | 165 | return false; |
okini3939 | 0:bd0f6bf72a8b | 166 | } |
okini3939 | 0:bd0f6bf72a8b | 167 | |
okini3939 | 1:5bb153989f33 | 168 | void USBHostXpad::restart () |
okini3939 | 0:bd0f6bf72a8b | 169 | { |
okini3939 | 2:2749f4e649db | 170 | if (send(0x08, 0x00, 0x0f, 0xc0) == false) { |
okini3939 | 2:2749f4e649db | 171 | init(); |
okini3939 | 2:2749f4e649db | 172 | return; |
okini3939 | 2:2749f4e649db | 173 | } |
okini3939 | 1:5bb153989f33 | 174 | send(0x08, 0x00, 0x0f, 0xc0); |
okini3939 | 1:5bb153989f33 | 175 | send(0x08, 0x00, 0x0f, 0xc0); |
okini3939 | 1:5bb153989f33 | 176 | send(0x08, 0x00, 0x0f, 0xc0); |
okini3939 | 0:bd0f6bf72a8b | 177 | } |
okini3939 | 0:bd0f6bf72a8b | 178 | |
okini3939 | 1:5bb153989f33 | 179 | bool USBHostXpad::send(int val1, int val2, int val3, int val4) |
okini3939 | 0:bd0f6bf72a8b | 180 | { |
okini3939 | 1:5bb153989f33 | 181 | unsigned char odata[32]; |
okini3939 | 1:5bb153989f33 | 182 | memset(odata, 0, sizeof(odata)); |
okini3939 | 1:5bb153989f33 | 183 | odata[0] = val1; |
okini3939 | 1:5bb153989f33 | 184 | odata[1] = val2; |
okini3939 | 1:5bb153989f33 | 185 | odata[2] = val3; |
okini3939 | 1:5bb153989f33 | 186 | odata[3] = val4; |
okini3939 | 1:5bb153989f33 | 187 | |
okini3939 | 0:bd0f6bf72a8b | 188 | if (dev) |
okini3939 | 1:5bb153989f33 | 189 | if (host->interruptWrite(dev, int_out, odata, 12) == USB_TYPE_ERROR) { |
okini3939 | 1:5bb153989f33 | 190 | init(); |
okini3939 | 1:5bb153989f33 | 191 | return false; |
okini3939 | 1:5bb153989f33 | 192 | } |
okini3939 | 0:bd0f6bf72a8b | 193 | return true; |
okini3939 | 0:bd0f6bf72a8b | 194 | } |
okini3939 | 0:bd0f6bf72a8b | 195 | |
okini3939 | 2:2749f4e649db | 196 | int USBHostXpad::read (TYPE type) { |
okini3939 | 2:2749f4e649db | 197 | switch (type) { |
okini3939 | 2:2749f4e649db | 198 | case XPAD_STICK_LX: |
okini3939 | 2:2749f4e649db | 199 | return stick_lx; |
okini3939 | 2:2749f4e649db | 200 | case XPAD_STICK_LY: |
okini3939 | 2:2749f4e649db | 201 | return stick_ly; |
okini3939 | 2:2749f4e649db | 202 | case XPAD_STICK_RX: |
okini3939 | 2:2749f4e649db | 203 | return stick_rx; |
okini3939 | 2:2749f4e649db | 204 | case XPAD_STICK_RY: |
okini3939 | 2:2749f4e649db | 205 | return stick_ry; |
okini3939 | 2:2749f4e649db | 206 | case XPAD_TRIGGER_L: |
okini3939 | 2:2749f4e649db | 207 | return trigger_l; |
okini3939 | 2:2749f4e649db | 208 | case XPAD_TRIGGER_R: |
okini3939 | 2:2749f4e649db | 209 | return trigger_r; |
okini3939 | 2:2749f4e649db | 210 | default: |
okini3939 | 2:2749f4e649db | 211 | return (buttons & type) ? 1 : 0; |
okini3939 | 2:2749f4e649db | 212 | } |
okini3939 | 2:2749f4e649db | 213 | } |
okini3939 | 2:2749f4e649db | 214 | |
okini3939 | 2:2749f4e649db | 215 | bool USBHostXpad::led(LED cmd) |
okini3939 | 0:bd0f6bf72a8b | 216 | { |
okini3939 | 0:bd0f6bf72a8b | 217 | unsigned char odata[32]; |
okini3939 | 1:5bb153989f33 | 218 | memset(odata, 0, sizeof(odata)); |
okini3939 | 1:5bb153989f33 | 219 | odata[2] = 0x08; |
okini3939 | 1:5bb153989f33 | 220 | odata[3] = 0x40 + (cmd % 0x0e); |
okini3939 | 1:5bb153989f33 | 221 | if (dev) |
okini3939 | 1:5bb153989f33 | 222 | if (host->interruptWrite(dev, int_out, odata, 12) == USB_TYPE_ERROR) |
okini3939 | 1:5bb153989f33 | 223 | return false; |
okini3939 | 1:5bb153989f33 | 224 | return true; |
okini3939 | 1:5bb153989f33 | 225 | } |
okini3939 | 0:bd0f6bf72a8b | 226 | |
okini3939 | 1:5bb153989f33 | 227 | bool USBHostXpad::rumble(uint8_t large, uint8_t small) |
okini3939 | 1:5bb153989f33 | 228 | { |
okini3939 | 1:5bb153989f33 | 229 | unsigned char odata[32]; |
okini3939 | 1:5bb153989f33 | 230 | memset(odata, 0, sizeof(odata)); |
okini3939 | 0:bd0f6bf72a8b | 231 | odata[1] = 0x01; |
okini3939 | 1:5bb153989f33 | 232 | odata[2] = 0x0f; |
okini3939 | 1:5bb153989f33 | 233 | odata[3] = 0xc0; |
okini3939 | 1:5bb153989f33 | 234 | odata[5] = large; |
okini3939 | 1:5bb153989f33 | 235 | odata[6] = small; |
okini3939 | 1:5bb153989f33 | 236 | if (dev) |
okini3939 | 1:5bb153989f33 | 237 | if (host->interruptWrite(dev, int_out, odata, 12) == USB_TYPE_ERROR) |
okini3939 | 1:5bb153989f33 | 238 | return false; |
okini3939 | 0:bd0f6bf72a8b | 239 | return true; |
okini3939 | 0:bd0f6bf72a8b | 240 | } |
okini3939 | 0:bd0f6bf72a8b | 241 | |
okini3939 | 0:bd0f6bf72a8b | 242 | #endif |
okini3939 | 0:bd0f6bf72a8b | 243 |