mbed USBHost Gamepad driver sample

Committer:
YuuichiAkagawa
Date:
Wed Jan 14 13:27:08 2015 +0000
Revision:
2:7345e2afa41e
Parent:
0:00fe0ab09333
recommit

Who changed what in which revision?

UserRevisionLine numberNew contents of line
YuuichiAkagawa 0:00fe0ab09333 1 /* mbed USBHost Gamepad driver sample
YuuichiAkagawa 0:00fe0ab09333 2 * Copyright (c) 2014 Yuuichi Akagawa
YuuichiAkagawa 0:00fe0ab09333 3 *
YuuichiAkagawa 0:00fe0ab09333 4 * modified from mbed USBHostMouse
YuuichiAkagawa 0:00fe0ab09333 5 *
YuuichiAkagawa 0:00fe0ab09333 6 * mbed USBHost Library
YuuichiAkagawa 0:00fe0ab09333 7 * Copyright (c) 2006-2013 ARM Limited
YuuichiAkagawa 0:00fe0ab09333 8 *
YuuichiAkagawa 0:00fe0ab09333 9 * Licensed under the Apache License, Version 2.0 (the "License");
YuuichiAkagawa 0:00fe0ab09333 10 * you may not use this file except in compliance with the License.
YuuichiAkagawa 0:00fe0ab09333 11 * You may obtain a copy of the License at
YuuichiAkagawa 0:00fe0ab09333 12 *
YuuichiAkagawa 0:00fe0ab09333 13 * http://www.apache.org/licenses/LICENSE-2.0
YuuichiAkagawa 0:00fe0ab09333 14 *
YuuichiAkagawa 0:00fe0ab09333 15 * Unless required by applicable law or agreed to in writing, software
YuuichiAkagawa 0:00fe0ab09333 16 * distributed under the License is distributed on an "AS IS" BASIS,
YuuichiAkagawa 0:00fe0ab09333 17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
YuuichiAkagawa 0:00fe0ab09333 18 * See the License for the specific language governing permissions and
YuuichiAkagawa 0:00fe0ab09333 19 * limitations under the License.
YuuichiAkagawa 0:00fe0ab09333 20 */
YuuichiAkagawa 0:00fe0ab09333 21 #include "USBHostGamepad.h"
YuuichiAkagawa 0:00fe0ab09333 22 //#if USBHOST_GAMEPAD
YuuichiAkagawa 0:00fe0ab09333 23
YuuichiAkagawa 0:00fe0ab09333 24 USBHostGamepad::USBHostGamepad() {
YuuichiAkagawa 0:00fe0ab09333 25 host = USBHost::getHostInst();
YuuichiAkagawa 0:00fe0ab09333 26 init();
YuuichiAkagawa 0:00fe0ab09333 27 }
YuuichiAkagawa 0:00fe0ab09333 28
YuuichiAkagawa 0:00fe0ab09333 29 void USBHostGamepad::init() {
YuuichiAkagawa 0:00fe0ab09333 30 dev = NULL;
YuuichiAkagawa 0:00fe0ab09333 31 int_in = NULL;
YuuichiAkagawa 0:00fe0ab09333 32 onUpdate = NULL;
YuuichiAkagawa 0:00fe0ab09333 33 report_id = 0;
YuuichiAkagawa 0:00fe0ab09333 34 dev_connected = false;
YuuichiAkagawa 0:00fe0ab09333 35 gamepad_device_found = false;
YuuichiAkagawa 0:00fe0ab09333 36 gamepad_intf = -1;
YuuichiAkagawa 0:00fe0ab09333 37
YuuichiAkagawa 0:00fe0ab09333 38 btnX = 0;
YuuichiAkagawa 0:00fe0ab09333 39 btnY = 0;
YuuichiAkagawa 0:00fe0ab09333 40 btnABCD = 0;
YuuichiAkagawa 0:00fe0ab09333 41 btnSpecial = 0;
YuuichiAkagawa 0:00fe0ab09333 42 }
YuuichiAkagawa 0:00fe0ab09333 43
YuuichiAkagawa 0:00fe0ab09333 44 bool USBHostGamepad::connected() {
YuuichiAkagawa 0:00fe0ab09333 45 return dev_connected;
YuuichiAkagawa 0:00fe0ab09333 46 }
YuuichiAkagawa 0:00fe0ab09333 47
YuuichiAkagawa 0:00fe0ab09333 48 bool USBHostGamepad::connect() {
YuuichiAkagawa 0:00fe0ab09333 49 int len_listen;
YuuichiAkagawa 0:00fe0ab09333 50
YuuichiAkagawa 0:00fe0ab09333 51 if (dev_connected) {
YuuichiAkagawa 0:00fe0ab09333 52 return true;
YuuichiAkagawa 0:00fe0ab09333 53 }
YuuichiAkagawa 0:00fe0ab09333 54
YuuichiAkagawa 0:00fe0ab09333 55 for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++) {
YuuichiAkagawa 0:00fe0ab09333 56 if ((dev = host->getDevice(i)) != NULL) {
YuuichiAkagawa 0:00fe0ab09333 57
YuuichiAkagawa 0:00fe0ab09333 58 if(host->enumerate(dev, this))
YuuichiAkagawa 0:00fe0ab09333 59 break;
YuuichiAkagawa 0:00fe0ab09333 60
YuuichiAkagawa 0:00fe0ab09333 61 if (gamepad_device_found) {
YuuichiAkagawa 0:00fe0ab09333 62
YuuichiAkagawa 0:00fe0ab09333 63 int_in = dev->getEndpoint(gamepad_intf, INTERRUPT_ENDPOINT, IN);
YuuichiAkagawa 0:00fe0ab09333 64 if (!int_in)
YuuichiAkagawa 0:00fe0ab09333 65 break;
YuuichiAkagawa 0:00fe0ab09333 66
YuuichiAkagawa 0:00fe0ab09333 67 USB_INFO("New Gamepad/Joystick device: VID:%04x PID:%04x [dev: %p - intf: %d]", dev->getVid(), dev->getPid(), dev, gamepad_intf);
YuuichiAkagawa 0:00fe0ab09333 68 #if DEBUG > 3
YuuichiAkagawa 0:00fe0ab09333 69 //Parse HID Report Descriptor
YuuichiAkagawa 0:00fe0ab09333 70 parseHidDescr();
YuuichiAkagawa 0:00fe0ab09333 71 #endif
YuuichiAkagawa 0:00fe0ab09333 72 dev->setName("Gamepad", gamepad_intf);
YuuichiAkagawa 0:00fe0ab09333 73 host->registerDriver(dev, gamepad_intf, this, &USBHostGamepad::init);
YuuichiAkagawa 0:00fe0ab09333 74
YuuichiAkagawa 0:00fe0ab09333 75 int_in->attach(this, &USBHostGamepad::rxHandler);
YuuichiAkagawa 0:00fe0ab09333 76 len_listen = int_in->getSize();
YuuichiAkagawa 0:00fe0ab09333 77 if (len_listen > sizeof(report)) {
YuuichiAkagawa 0:00fe0ab09333 78 len_listen = sizeof(report);
YuuichiAkagawa 0:00fe0ab09333 79 }
YuuichiAkagawa 0:00fe0ab09333 80 host->interruptRead(dev, int_in, report, len_listen, false);
YuuichiAkagawa 0:00fe0ab09333 81
YuuichiAkagawa 0:00fe0ab09333 82 dev_connected = true;
YuuichiAkagawa 0:00fe0ab09333 83 return true;
YuuichiAkagawa 0:00fe0ab09333 84 }
YuuichiAkagawa 0:00fe0ab09333 85 }
YuuichiAkagawa 0:00fe0ab09333 86 }
YuuichiAkagawa 0:00fe0ab09333 87 init();
YuuichiAkagawa 0:00fe0ab09333 88 return false;
YuuichiAkagawa 0:00fe0ab09333 89 }
YuuichiAkagawa 0:00fe0ab09333 90
YuuichiAkagawa 0:00fe0ab09333 91 void USBHostGamepad::rxHandler() {
YuuichiAkagawa 0:00fe0ab09333 92 int len_listen = int_in->getSize();
YuuichiAkagawa 0:00fe0ab09333 93 #if DEBUG > 3
YuuichiAkagawa 0:00fe0ab09333 94 USB_DBG("USBHostGamepad::rxHandler() len_listen=%d\r\n", len_listen);
YuuichiAkagawa 0:00fe0ab09333 95 for (int i = 0; i < len_listen; i++)
YuuichiAkagawa 0:00fe0ab09333 96 printf("%02X ", report[i]);
YuuichiAkagawa 0:00fe0ab09333 97 printf("\r\n\r\n");
YuuichiAkagawa 0:00fe0ab09333 98 #endif
YuuichiAkagawa 0:00fe0ab09333 99 if (onUpdate) {
YuuichiAkagawa 0:00fe0ab09333 100 (*onUpdate)(report[0], report[1], report[5], report[6]);
YuuichiAkagawa 0:00fe0ab09333 101 }
YuuichiAkagawa 0:00fe0ab09333 102
YuuichiAkagawa 0:00fe0ab09333 103 // update gamepad state
YuuichiAkagawa 0:00fe0ab09333 104 btnX = report[0];
YuuichiAkagawa 0:00fe0ab09333 105 btnY = report[1];
YuuichiAkagawa 0:00fe0ab09333 106 btnABCD = report[5];
YuuichiAkagawa 0:00fe0ab09333 107 btnSpecial = report[6];
YuuichiAkagawa 0:00fe0ab09333 108
YuuichiAkagawa 0:00fe0ab09333 109 if (len_listen > sizeof(report)) {
YuuichiAkagawa 0:00fe0ab09333 110 len_listen = sizeof(report);
YuuichiAkagawa 0:00fe0ab09333 111 }
YuuichiAkagawa 0:00fe0ab09333 112
YuuichiAkagawa 0:00fe0ab09333 113 if (dev)
YuuichiAkagawa 0:00fe0ab09333 114 host->interruptRead(dev, int_in, report, len_listen, false);
YuuichiAkagawa 0:00fe0ab09333 115 }
YuuichiAkagawa 0:00fe0ab09333 116
YuuichiAkagawa 0:00fe0ab09333 117 /*virtual*/ void USBHostGamepad::setVidPid(uint16_t vid, uint16_t pid)
YuuichiAkagawa 0:00fe0ab09333 118 {
YuuichiAkagawa 0:00fe0ab09333 119 // we don't check VID/PID for gamepad driver
YuuichiAkagawa 0:00fe0ab09333 120 }
YuuichiAkagawa 0:00fe0ab09333 121
YuuichiAkagawa 0:00fe0ab09333 122 /*virtual*/ bool USBHostGamepad::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
YuuichiAkagawa 0:00fe0ab09333 123 {
YuuichiAkagawa 0:00fe0ab09333 124 if ((gamepad_intf == -1) &&
YuuichiAkagawa 0:00fe0ab09333 125 (intf_class == HID_CLASS) &&
YuuichiAkagawa 0:00fe0ab09333 126 (intf_subclass == 0x00) &&
YuuichiAkagawa 0:00fe0ab09333 127 (intf_protocol == 0x00)) {
YuuichiAkagawa 0:00fe0ab09333 128 gamepad_intf = intf_nb;
YuuichiAkagawa 0:00fe0ab09333 129 return true;
YuuichiAkagawa 0:00fe0ab09333 130 }
YuuichiAkagawa 0:00fe0ab09333 131 return false;
YuuichiAkagawa 0:00fe0ab09333 132 }
YuuichiAkagawa 0:00fe0ab09333 133
YuuichiAkagawa 0:00fe0ab09333 134 /*virtual*/ bool USBHostGamepad::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used
YuuichiAkagawa 0:00fe0ab09333 135 {
YuuichiAkagawa 0:00fe0ab09333 136 if (intf_nb == gamepad_intf) {
YuuichiAkagawa 0:00fe0ab09333 137 if (type == INTERRUPT_ENDPOINT && dir == IN) {
YuuichiAkagawa 0:00fe0ab09333 138 gamepad_device_found = true;
YuuichiAkagawa 0:00fe0ab09333 139 return true;
YuuichiAkagawa 0:00fe0ab09333 140 }
YuuichiAkagawa 0:00fe0ab09333 141 }
YuuichiAkagawa 0:00fe0ab09333 142 return false;
YuuichiAkagawa 0:00fe0ab09333 143 }
YuuichiAkagawa 0:00fe0ab09333 144
YuuichiAkagawa 0:00fe0ab09333 145 USB_TYPE USBHostGamepad::getReportDescriptor(USBDeviceConnected * dev, uint8_t * buf, uint16_t max_len_buf, uint16_t * len_rep_descr)
YuuichiAkagawa 0:00fe0ab09333 146 {
YuuichiAkagawa 0:00fe0ab09333 147 USB_TYPE t = host->controlRead( dev,
YuuichiAkagawa 0:00fe0ab09333 148 USB_DEVICE_TO_HOST | USB_RECIPIENT_INTERFACE | USB_REQUEST_TYPE_STANDARD,
YuuichiAkagawa 0:00fe0ab09333 149 HID_GET_DESCRIPTOR,
YuuichiAkagawa 0:00fe0ab09333 150 0x2200,
YuuichiAkagawa 0:00fe0ab09333 151 0, buf, max_len_buf);
YuuichiAkagawa 0:00fe0ab09333 152 if (len_rep_descr)
YuuichiAkagawa 0:00fe0ab09333 153 *len_rep_descr = max_len_buf;
YuuichiAkagawa 0:00fe0ab09333 154
YuuichiAkagawa 0:00fe0ab09333 155 return t;
YuuichiAkagawa 0:00fe0ab09333 156 }
YuuichiAkagawa 0:00fe0ab09333 157
YuuichiAkagawa 0:00fe0ab09333 158 /*
YuuichiAkagawa 0:00fe0ab09333 159 * HID Report Descriptor parser
YuuichiAkagawa 0:00fe0ab09333 160 */
YuuichiAkagawa 0:00fe0ab09333 161 bool USBHostGamepad::parseHidDescr()
YuuichiAkagawa 0:00fe0ab09333 162 {
YuuichiAkagawa 0:00fe0ab09333 163 bool ret = true;
YuuichiAkagawa 0:00fe0ab09333 164 uint8_t *buf;
YuuichiAkagawa 0:00fe0ab09333 165 uint16_t desclen = host->getLengthReportDescr();
YuuichiAkagawa 0:00fe0ab09333 166
YuuichiAkagawa 0:00fe0ab09333 167 //allocate report descriptor's buffer
YuuichiAkagawa 0:00fe0ab09333 168 buf = (uint8_t *)malloc(desclen);
YuuichiAkagawa 0:00fe0ab09333 169 if(buf == NULL){
YuuichiAkagawa 0:00fe0ab09333 170 return false;
YuuichiAkagawa 0:00fe0ab09333 171 }
YuuichiAkagawa 0:00fe0ab09333 172 getReportDescriptor(dev, buf, desclen);
YuuichiAkagawa 0:00fe0ab09333 173 #if (DEBUG > 3)
YuuichiAkagawa 0:00fe0ab09333 174 USB_DBG("HID REPORT DESCRIPTOR:\r\n");
YuuichiAkagawa 0:00fe0ab09333 175 for (int i = 0; i < desclen; i++)
YuuichiAkagawa 0:00fe0ab09333 176 printf("%02X ", buf[i]);
YuuichiAkagawa 0:00fe0ab09333 177 printf("\r\n\r\n");
YuuichiAkagawa 0:00fe0ab09333 178 #endif
YuuichiAkagawa 0:00fe0ab09333 179 if( buf[0] == 0x05 //Usage page
YuuichiAkagawa 0:00fe0ab09333 180 && buf[1] == 0x01 //Generic Desktop
YuuichiAkagawa 0:00fe0ab09333 181 && buf[2] == 0x09 //Usage
YuuichiAkagawa 0:00fe0ab09333 182 ){
YuuichiAkagawa 0:00fe0ab09333 183 if( buf[3] == 0x04 ){
YuuichiAkagawa 0:00fe0ab09333 184 USB_DBG("GAMEPAD");
YuuichiAkagawa 0:00fe0ab09333 185 }else if( buf[3] == 0x05){
YuuichiAkagawa 0:00fe0ab09333 186 USB_DBG("JOYSTICK");
YuuichiAkagawa 0:00fe0ab09333 187 }else{
YuuichiAkagawa 0:00fe0ab09333 188 ret = false;
YuuichiAkagawa 0:00fe0ab09333 189 }
YuuichiAkagawa 0:00fe0ab09333 190 }
YuuichiAkagawa 0:00fe0ab09333 191 free(buf);
YuuichiAkagawa 0:00fe0ab09333 192 return ret;
YuuichiAkagawa 0:00fe0ab09333 193 }
YuuichiAkagawa 0:00fe0ab09333 194 //#endif