USB HID Joystick Example (modified USBMouse)
Dependencies: mbed
usbhid.cpp
00001 /* usbhid.cpp */ 00002 /* USB HID class device */ 00003 /* Copyright (c) Phil Wright 2008 */ 00004 00005 /* modified by Shinichiro Oba <http://mbed.org/users/bricklife/> */ 00006 00007 #include "mbed.h" 00008 #include "usbhid.h" 00009 #include "asciihid.h" 00010 00011 /* Endpoint packet sizes */ 00012 #define MAX_PACKET_SIZE_EP1 (64) 00013 00014 /* HID Class */ 00015 #define HID_CLASS (3) 00016 #define HID_SUBCLASS_NONE (0) 00017 #define HID_PROTOCOL_NONE (0) 00018 #define HID_DESCRIPTOR (33) 00019 #define REPORT_DESCRIPTOR (34) 00020 00021 /* Class requests */ 00022 #define GET_REPORT (0x1) 00023 #define GET_IDLE (0x2) 00024 #define SET_REPORT (0x9) 00025 #define SET_IDLE (0xa) 00026 00027 /* Descriptors */ 00028 unsigned char deviceDescriptor[] = { 00029 0x12, /* bLength */ 00030 DEVICE_DESCRIPTOR, /* bDescriptorType */ 00031 0x00, /* bcdUSB (LSB) */ 00032 0x02, /* bcdUSB (MSB) */ 00033 0x00, /* bDeviceClass */ 00034 0x00, /* bDeviceSubClass */ 00035 0x00, /* bDeviceprotocol */ 00036 MAX_PACKET_SIZE_EP0, /* bMaxPacketSize0 */ 00037 0x28, /* idVendor (LSB) */ 00038 0x0d, /* idVendor (MSB) */ 00039 0x05, /* idProduct (LSB) */ 00040 0x02, /* idProduct (MSB) */ 00041 0x00, /* bcdDevice (LSB) */ 00042 0x00, /* bcdDevice (MSB) */ 00043 0x00, /* iManufacturer */ 00044 0x00, /* iProduct */ 00045 0x00, /* iSerialNumber */ 00046 0x01 /* bNumConfigurations */ 00047 }; 00048 00049 unsigned char configurationDescriptor[] = { 00050 0x09, /* bLength */ 00051 CONFIGURATION_DESCRIPTOR, /* bDescriptorType */ 00052 0x09+0x09+0x09+0x07, /* wTotalLength (LSB) */ 00053 0x00, /* wTotalLength (MSB) */ 00054 0x01, /* bNumInterfaces */ 00055 0x01, /* bConfigurationValue */ 00056 0x00, /* iConfiguration */ 00057 0xc0, /* bmAttributes */ 00058 0x00, /* bMaxPower */ 00059 00060 0x09, /* bLength */ 00061 INTERFACE_DESCRIPTOR, /* bDescriptorType */ 00062 0x00, /* bInterfaceNumber */ 00063 0x00, /* bAlternateSetting */ 00064 0x01, /* bNumEndpoints */ 00065 HID_CLASS, /* bInterfaceClass */ 00066 HID_SUBCLASS_NONE, /* bInterfaceSubClass */ 00067 HID_PROTOCOL_NONE, /* bInterfaceProtocol */ 00068 0x00, /* iInterface */ 00069 00070 0x09, /* bLength */ 00071 HID_DESCRIPTOR, /* bDescriptorType */ 00072 0x11, /* bcdHID (LSB) */ 00073 0x01, /* bcdHID (MSB) */ 00074 0x00, /* bCountryCode */ 00075 0x01, /* bNumDescriptors */ 00076 REPORT_DESCRIPTOR, /* bDescriptorType */ 00077 0x79, /* wDescriptorLength (LSB) */ 00078 0x00, /* wDescriptorLength (MSB) */ 00079 00080 0x07, /* bLength */ 00081 ENDPOINT_DESCRIPTOR, /* bDescriptorType */ 00082 0x81, /* bEndpointAddress */ 00083 0x03, /* bmAttributes */ 00084 MAX_PACKET_SIZE_EP1, /* wMaxPacketSize (LSB) */ 00085 0x00, /* wMaxPacketSize (MSB) */ 00086 0x0a, /* bInterval */ 00087 }; 00088 00089 /* HID Class Report Descriptor */ 00090 /* Short items: size is 0, 1, 2 or 3 specifying 0, 1, 2 or 4 (four) bytes of data as per HID Class standard */ 00091 00092 /* Main items */ 00093 #define INPUT(size) (0x80 | size) 00094 #define OUTPUT(size) (0x90 | size) 00095 #define FEATURE(size) (0xb0 | size) 00096 #define COLLECTION(size) (0xa0 | size) 00097 #define END_COLLECTION(size) (0xc0 | size) 00098 00099 /* Global items */ 00100 #define USAGE_PAGE(size) (0x04 | size) 00101 #define LOGICAL_MIN(size) (0x14 | size) 00102 #define LOGICAL_MAX(size) (0x24 | size) 00103 #define PHYSICAL_MIN(size) (0x34 | size) 00104 #define PHYSICAL_MAX(size) (0x44 | size) 00105 #define UNIT_EXPONENT(size) (0x54 | size) 00106 #define UNIT(size) (0x64 | size) 00107 #define REPORT_SIZE(size) (0x74 | size) 00108 #define REPORT_ID(size) (0x84 | size) 00109 #define REPORT_COUNT(size) (0x94 | size) 00110 #define PUSH(size) (0xa4 | size) 00111 #define POP(size) (0xb4 | size) 00112 00113 /* Local items */ 00114 #define USAGE(size) (0x08 | size) 00115 #define USAGE_MIN(size) (0x18 | size) 00116 #define USAGE_MAX(size) (0x28 | size) 00117 #define DESIGNATOR_INDEX(size) (0x38 | size) 00118 #define DESIGNATOR_MIN(size) (0x48 | size) 00119 #define DESIGNATOR_MAX(size) (0x58 | size) 00120 #define STRING_INDEX(size) (0x78 | size) 00121 #define STRING_MIN(size) (0x88 | size) 00122 #define STRING_MAX(size) (0x98 | size) 00123 #define DELIMITER(size) (0xa8 | size) 00124 00125 #define REPORT_ID_KEYBOARD (1) 00126 #define REPORT_ID_MOUSE (2) 00127 00128 #define MAX_REPORT_SIZE (8) 00129 00130 unsigned char reportDescriptor[] = { 00131 /* Keyboard */ 00132 USAGE_PAGE(1), 0x01, 00133 USAGE(1), 0x06, 00134 COLLECTION(1), 0x01, 00135 REPORT_ID(1), REPORT_ID_KEYBOARD, 00136 USAGE_PAGE(1), 0x07, 00137 USAGE_MIN(1), 0xE0, 00138 USAGE_MAX(1), 0xE7, 00139 LOGICAL_MIN(1), 0x00, 00140 LOGICAL_MAX(1), 0x01, 00141 REPORT_SIZE(1), 0x01, 00142 REPORT_COUNT(1), 0x08, 00143 INPUT(1), 0x02, 00144 REPORT_COUNT(1), 0x01, 00145 REPORT_SIZE(1), 0x08, 00146 INPUT(1), 0x01, 00147 REPORT_COUNT(1), 0x05, 00148 REPORT_SIZE(1), 0x01, 00149 USAGE_PAGE(1), 0x08, 00150 USAGE_MIN(1), 0x01, 00151 USAGE_MAX(1), 0x05, 00152 OUTPUT(1), 0x02, 00153 REPORT_COUNT(1), 0x01, 00154 REPORT_SIZE(1), 0x03, 00155 OUTPUT(1), 0x01, 00156 REPORT_COUNT(1), 0x06, 00157 REPORT_SIZE(1), 0x08, 00158 LOGICAL_MIN(1), 0x00, 00159 LOGICAL_MAX(2), 0xff, 0x00, 00160 USAGE_PAGE(1), 0x07, 00161 USAGE_MIN(1), 0x00, 00162 USAGE_MAX(2), 0xff, 0x00, 00163 INPUT(1), 0x00, 00164 END_COLLECTION(0), 00165 00166 /* Mouse */ 00167 USAGE_PAGE(1), 0x01, 00168 USAGE(1), 0x02, 00169 COLLECTION(1), 0x01, 00170 USAGE(1), 0x01, 00171 COLLECTION(1), 0x00, 00172 REPORT_ID(1), REPORT_ID_MOUSE, 00173 REPORT_COUNT(1), 0x03, 00174 REPORT_SIZE(1), 0x01, 00175 USAGE_PAGE(1), 0x09, 00176 USAGE_MIN(1), 0x1, 00177 USAGE_MAX(1), 0x3, 00178 LOGICAL_MIN(1), 0x00, 00179 LOGICAL_MAX(1), 0x01, 00180 INPUT(1), 0x02, 00181 REPORT_COUNT(1), 0x01, 00182 REPORT_SIZE(1), 0x05, 00183 INPUT(1), 0x01, 00184 REPORT_COUNT(1), 0x03, 00185 REPORT_SIZE(1), 0x08, 00186 USAGE_PAGE(1), 0x01, 00187 USAGE(1), 0x30, 00188 USAGE(1), 0x31, 00189 USAGE(1), 0x38, 00190 LOGICAL_MIN(1), 0x81, 00191 LOGICAL_MAX(1), 0x7f, 00192 INPUT(1), 0x06, 00193 END_COLLECTION(0), 00194 END_COLLECTION(0), 00195 }; 00196 00197 volatile bool complete; 00198 volatile bool configured; 00199 unsigned char outputReport[MAX_REPORT_SIZE]; 00200 00201 usbhid::usbhid() 00202 { 00203 configured = false; 00204 connect(); 00205 } 00206 00207 void usbhid::deviceEventReset() 00208 { 00209 configured = false; 00210 00211 /* Must call base class */ 00212 usbdevice::deviceEventReset(); 00213 } 00214 00215 bool usbhid::requestSetConfiguration(void) 00216 { 00217 bool result; 00218 00219 /* Configure IN interrupt endpoint */ 00220 realiseEndpoint(EP1IN, MAX_PACKET_SIZE_EP1); 00221 enableEndpointEvent(EP1IN); 00222 00223 /* Must call base class */ 00224 result = usbdevice::requestSetConfiguration(); 00225 00226 if (result) 00227 { 00228 /* Now configured */ 00229 configured = true; 00230 } 00231 00232 return result; 00233 } 00234 00235 bool usbhid::requestGetDescriptor(void) 00236 { 00237 bool success = false; 00238 00239 switch (DESCRIPTOR_TYPE(transfer.setup.wValue)) 00240 { 00241 case DEVICE_DESCRIPTOR: 00242 transfer.remaining = sizeof(deviceDescriptor); 00243 transfer.ptr = deviceDescriptor; 00244 transfer.direction = DEVICE_TO_HOST; 00245 success = true; 00246 break; 00247 case CONFIGURATION_DESCRIPTOR: 00248 transfer.remaining = sizeof(configurationDescriptor); 00249 transfer.ptr = configurationDescriptor; 00250 transfer.direction = DEVICE_TO_HOST; 00251 success = true; 00252 break; 00253 case STRING_DESCRIPTOR: 00254 case INTERFACE_DESCRIPTOR: 00255 case ENDPOINT_DESCRIPTOR: 00256 /* TODO: Support is optional, not implemented here */ 00257 break; 00258 case HID_DESCRIPTOR: 00259 transfer.remaining = 0x09; /* TODO: Fix hard coded size/offset */ 00260 transfer.ptr = &configurationDescriptor[18]; 00261 transfer.direction = DEVICE_TO_HOST; 00262 success = true; 00263 break; 00264 case REPORT_DESCRIPTOR: 00265 transfer.remaining = sizeof(reportDescriptor); 00266 transfer.ptr = reportDescriptor; 00267 transfer.direction = DEVICE_TO_HOST; 00268 success = true; 00269 break; 00270 default: 00271 break; 00272 } 00273 00274 return success; 00275 } 00276 00277 bool usbhid::requestSetup(void) 00278 { 00279 /* Process class requests */ 00280 bool success = false; 00281 00282 if (transfer.setup.bmRequestType.Type == CLASS_TYPE) 00283 { 00284 switch (transfer.setup.bRequest) 00285 { 00286 case SET_REPORT: 00287 switch (transfer.setup.wValue & 0xff) 00288 { 00289 case REPORT_ID_KEYBOARD: 00290 /* TODO: LED state */ 00291 transfer.remaining = sizeof(outputReport); 00292 transfer.ptr = outputReport; 00293 transfer.direction = HOST_TO_DEVICE; 00294 success = true; 00295 break; 00296 default: 00297 break; 00298 } 00299 break; 00300 default: 00301 break; 00302 } 00303 } 00304 00305 if (success) 00306 { 00307 /* We've handled this request */ 00308 return true; 00309 } 00310 00311 return usbdevice::requestSetup(); 00312 } 00313 00314 bool usbhid::sendInputReport(unsigned char id, unsigned char *data, unsigned char size) 00315 { 00316 /* Send an Input Report */ 00317 /* If data is NULL an all zero report is sent */ 00318 00319 static unsigned char report[MAX_REPORT_SIZE+1]; /* +1 for report ID */ 00320 unsigned char i; 00321 00322 if (size > MAX_REPORT_SIZE) 00323 { 00324 return false; 00325 } 00326 00327 /* Add report ID */ 00328 report[0]=id; 00329 00330 /* Add report data */ 00331 if (data != NULL) 00332 { 00333 for (i=0; i<size; i++) 00334 { 00335 report[i+1] = *data++; 00336 } 00337 } 00338 else 00339 { 00340 for (i=0; i<size; i++) 00341 { 00342 report[i+1] = 0; 00343 } 00344 } 00345 00346 /* Block if not configured */ 00347 while (!configured); 00348 00349 /* Send report */ 00350 complete = false; 00351 disableEvents(); 00352 endpointWrite(EP1IN, report, size+1); /* +1 for report ID */ 00353 enableEvents(); 00354 00355 /* Wait for completion */ 00356 while(!complete && configured); 00357 return true; 00358 } 00359 00360 void usbhid::endpointEventEP1In(void) 00361 { 00362 complete = true; 00363 } 00364 00365 bool usbhid::keyboard(char c) 00366 { 00367 /* Send a simulated keyboard keypress. Returns true if successful. */ 00368 unsigned char report[8]={0,0,0,0,0,0,0,0}; 00369 00370 report[0] = keymap[c].modifier; 00371 report[2] = keymap[c].usage; 00372 00373 /* Key down */ 00374 if (!sendInputReport(REPORT_ID_KEYBOARD, report, 8)) 00375 { 00376 return false; 00377 } 00378 00379 /* Key up */ 00380 if (!sendInputReport(REPORT_ID_KEYBOARD, NULL, 8)) 00381 { 00382 return false; 00383 } 00384 00385 return true; 00386 } 00387 00388 bool usbhid::keyboard(char *string) 00389 { 00390 /* Send a string of characters. Returns true if successful. */ 00391 do { 00392 if (!keyboard(*string++)) 00393 { 00394 return false; 00395 } 00396 } while (*string != '\0'); 00397 00398 return true; 00399 } 00400 00401 bool usbhid::mouse(signed char x, signed char y, unsigned char buttons, signed char wheel) 00402 { 00403 /* Send a simulated mouse event. Returns true if successful. */ 00404 unsigned char report[4]={0,0,0,0}; 00405 00406 report[0] = buttons; 00407 report[1] = x; 00408 report[2] = y; 00409 report[3] = wheel; 00410 00411 if (!sendInputReport(REPORT_ID_MOUSE, report, 4)) 00412 { 00413 return false; 00414 } 00415 00416 return true; 00417 } 00418 00419 00420 // 00421 // USBJoystick 00422 // 00423 00424 unsigned char reportDescriptorJoystick[] = { 00425 USAGE_PAGE(1), 0x01, 00426 USAGE(1), 0x04, 00427 COLLECTION(1), 0x01, 00428 USAGE(1), 0x01, 00429 COLLECTION(1), 0x00, 00430 00431 USAGE_PAGE(1), 0x09, 00432 USAGE_MIN(1), 0x01, 00433 USAGE_MAX(1), 0x0C, 00434 LOGICAL_MIN(1), 0x00, 00435 LOGICAL_MAX(1), 0x01, 00436 PHYSICAL_MIN(1), 0x00, 00437 PHYSICAL_MAX(1), 0x01, 00438 REPORT_SIZE(1), 0x01, 00439 REPORT_COUNT(1), 0x0C, 00440 INPUT(1), 0x02, 00441 00442 USAGE_PAGE(1), 0x01, 00443 USAGE(1), 0x39, 00444 LOGICAL_MIN(1), 0x00, 00445 LOGICAL_MAX(1), 0x07, 00446 PHYSICAL_MIN(1), 0x00, 00447 PHYSICAL_MAX(2), 0x3B, 0x01, 00448 UNIT(1), 0x14, 00449 REPORT_SIZE(1), 0x04, 00450 REPORT_COUNT(1), 0x01, 00451 INPUT(1), 0x42, 00452 00453 USAGE_PAGE(1), 0x01, 00454 USAGE(1), 0x30, 00455 USAGE(1), 0x31, 00456 USAGE(1), 0x32, 00457 USAGE(1), 0x35, 00458 LOGICAL_MIN(1), 0x00, 00459 LOGICAL_MAX(2), 0xff, 0x00, 00460 PHYSICAL_MIN(1), 0x00, 00461 PHYSICAL_MAX(2), 0xff, 0x00, 00462 UNIT(2), 0x00, 0x00, 00463 REPORT_SIZE(1), 0x08, 00464 REPORT_COUNT(1), 0x04, 00465 INPUT(1), 0x02, 00466 00467 END_COLLECTION(0), 00468 END_COLLECTION(0), 00469 }; 00470 00471 USBJoystick::USBJoystick() 00472 { 00473 int reportDescriptorSize = sizeof(reportDescriptorJoystick); 00474 configurationDescriptor[25] = reportDescriptorSize & 0xff; 00475 configurationDescriptor[26] = (reportDescriptorSize >> 8) & 0xff; 00476 } 00477 00478 bool USBJoystick::requestGetDescriptor(void) 00479 { 00480 bool success = false; 00481 00482 switch (DESCRIPTOR_TYPE(transfer.setup.wValue)) 00483 { 00484 case REPORT_DESCRIPTOR: 00485 transfer.remaining = sizeof(reportDescriptorJoystick); 00486 transfer.ptr = reportDescriptorJoystick; 00487 transfer.direction = DEVICE_TO_HOST; 00488 success = true; 00489 break; 00490 default: 00491 success = usbhid::requestGetDescriptor(); 00492 break; 00493 } 00494 00495 return success; 00496 } 00497 00498 bool USBJoystick::sendInputReport(unsigned char *data, unsigned char size) 00499 { 00500 /* Send an Input Report */ 00501 /* If data is NULL an all zero report is sent */ 00502 00503 static unsigned char report[MAX_REPORT_SIZE]; 00504 unsigned char i; 00505 00506 if (size > MAX_REPORT_SIZE) 00507 { 00508 return false; 00509 } 00510 00511 /* Add report data */ 00512 if (data != NULL) 00513 { 00514 for (i=0; i<size; i++) 00515 { 00516 report[i] = *data++; 00517 } 00518 } 00519 else 00520 { 00521 for (i=0; i<size; i++) 00522 { 00523 report[i] = 0; 00524 } 00525 } 00526 00527 /* Block if not configured */ 00528 while (!configured); 00529 00530 /* Send report */ 00531 complete = false; 00532 disableEvents(); 00533 endpointWrite(EP1IN, report, size); 00534 enableEvents(); 00535 00536 /* Wait for completion */ 00537 while(!complete && configured); 00538 return true; 00539 } 00540 00541 bool USBJoystick::joystick(unsigned char stick, unsigned short buttons, signed char x, signed char y, signed char z, signed char rz) 00542 { 00543 unsigned char report[6] = {0, 0, 0, 0, 0, 0}; 00544 00545 unsigned char hatswitch; 00546 if (stick & JOYSTICK_UP) { 00547 hatswitch = 0; 00548 if (stick & JOYSTICK_RIGHT) hatswitch = 1; 00549 if (stick &JOYSTICK_LEFT) hatswitch = 7; 00550 } else if (stick & JOYSTICK_RIGHT) { 00551 hatswitch = 2; 00552 if (stick & JOYSTICK_DOWN) hatswitch = 3; 00553 } else if (stick & JOYSTICK_DOWN) { 00554 hatswitch = 4; 00555 if (stick & JOYSTICK_LEFT) hatswitch = 5; 00556 } else if (stick & JOYSTICK_LEFT) { 00557 hatswitch = 6; 00558 } else { 00559 hatswitch = 0xf; 00560 } 00561 00562 report[0] = buttons & 0xff; 00563 report[1] = ((hatswitch << 4) & 0xf0) | ((buttons >> 8) & 0x0f); 00564 report[2] = x + 0x80; 00565 report[3] = y + 0x80; 00566 report[4] = z + 0x80; 00567 report[5] = rz + 0x80; 00568 00569 if (!sendInputReport(report, 6)) { 00570 return false; 00571 } 00572 00573 return true; 00574 } 00575
Generated on Tue Jul 12 2022 19:38:12 by
1.7.2