Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
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 configured = false; 00203 connect(); 00204 } 00205 00206 void usbhid::deviceEventReset() { 00207 configured = false; 00208 00209 /* Must call base class */ 00210 usbdevice::deviceEventReset(); 00211 } 00212 00213 bool usbhid::requestSetConfiguration(void) { 00214 bool result; 00215 00216 /* Configure IN interrupt endpoint */ 00217 realiseEndpoint(EP1IN, MAX_PACKET_SIZE_EP1); 00218 enableEndpointEvent(EP1IN); 00219 00220 /* Must call base class */ 00221 result = usbdevice::requestSetConfiguration(); 00222 00223 if (result) { 00224 /* Now configured */ 00225 configured = true; 00226 } 00227 00228 return result; 00229 } 00230 00231 bool usbhid::requestGetDescriptor(void) { 00232 bool success = false; 00233 00234 switch (DESCRIPTOR_TYPE(transfer.setup.wValue)) { 00235 case DEVICE_DESCRIPTOR: 00236 transfer.remaining = sizeof(deviceDescriptor); 00237 transfer.ptr = deviceDescriptor; 00238 transfer.direction = DEVICE_TO_HOST; 00239 success = true; 00240 break; 00241 case CONFIGURATION_DESCRIPTOR: 00242 transfer.remaining = sizeof(configurationDescriptor); 00243 transfer.ptr = configurationDescriptor; 00244 transfer.direction = DEVICE_TO_HOST; 00245 success = true; 00246 break; 00247 case STRING_DESCRIPTOR: 00248 case INTERFACE_DESCRIPTOR: 00249 case ENDPOINT_DESCRIPTOR: 00250 /* TODO: Support is optional, not implemented here */ 00251 break; 00252 case HID_DESCRIPTOR: 00253 transfer.remaining = 0x09; /* TODO: Fix hard coded size/offset */ 00254 transfer.ptr = &configurationDescriptor[18]; 00255 transfer.direction = DEVICE_TO_HOST; 00256 success = true; 00257 break; 00258 case REPORT_DESCRIPTOR: 00259 transfer.remaining = sizeof(reportDescriptor); 00260 transfer.ptr = reportDescriptor; 00261 transfer.direction = DEVICE_TO_HOST; 00262 success = true; 00263 break; 00264 default: 00265 break; 00266 } 00267 00268 return success; 00269 } 00270 00271 bool usbhid::requestSetup(void) { 00272 /* Process class requests */ 00273 bool success = false; 00274 00275 if (transfer.setup.bmRequestType.Type == CLASS_TYPE) { 00276 switch (transfer.setup.bRequest) { 00277 case SET_REPORT: 00278 switch (transfer.setup.wValue & 0xff) { 00279 case REPORT_ID_KEYBOARD: 00280 /* TODO: LED state */ 00281 transfer.remaining = sizeof(outputReport); 00282 transfer.ptr = outputReport; 00283 transfer.direction = HOST_TO_DEVICE; 00284 success = true; 00285 break; 00286 default: 00287 break; 00288 } 00289 break; 00290 default: 00291 break; 00292 } 00293 } 00294 00295 if (success) { 00296 /* We've handled this request */ 00297 return true; 00298 } 00299 00300 return usbdevice::requestSetup(); 00301 } 00302 00303 bool usbhid::sendInputReport(unsigned char id, unsigned char *data, unsigned char size) { 00304 /* Send an Input Report */ 00305 /* If data is NULL an all zero report is sent */ 00306 00307 static unsigned char report[MAX_REPORT_SIZE+1]; /* +1 for report ID */ 00308 unsigned char i; 00309 00310 if (size > MAX_REPORT_SIZE) { 00311 return false; 00312 } 00313 00314 /* Add report ID */ 00315 report[0]=id; 00316 00317 /* Add report data */ 00318 if (data != NULL) { 00319 for (i=0; i<size; i++) { 00320 report[i+1] = *data++; 00321 } 00322 } else { 00323 for (i=0; i<size; i++) { 00324 report[i+1] = 0; 00325 } 00326 } 00327 00328 /* Block if not configured */ 00329 while (!configured); 00330 00331 /* Send report */ 00332 complete = false; 00333 disableEvents(); 00334 endpointWrite(EP1IN, report, size+1); /* +1 for report ID */ 00335 enableEvents(); 00336 00337 /* Wait for completion */ 00338 while (!complete && configured); 00339 return true; 00340 } 00341 00342 void usbhid::endpointEventEP1In(void) { 00343 complete = true; 00344 } 00345 00346 bool usbhid::keyboard(char c) { 00347 /* Send a simulated keyboard keypress. Returns true if successful. */ 00348 unsigned char report[8]={0,0,0,0,0,0,0,0}; 00349 00350 report[0] = keymap[c].modifier; 00351 report[2] = keymap[c].usage; 00352 00353 /* Key down */ 00354 if (!sendInputReport(REPORT_ID_KEYBOARD, report, 8)) { 00355 return false; 00356 } 00357 00358 /* Key up */ 00359 if (!sendInputReport(REPORT_ID_KEYBOARD, NULL, 8)) { 00360 return false; 00361 } 00362 00363 return true; 00364 } 00365 00366 bool usbhid::keyboard(char *string) { 00367 /* Send a string of characters. Returns true if successful. */ 00368 do { 00369 if (!keyboard(*string++)) { 00370 return false; 00371 } 00372 } while (*string != '\0'); 00373 00374 return true; 00375 } 00376 00377 bool usbhid::mouse(signed char x, signed char y, unsigned char buttons, signed char wheel) { 00378 /* Send a simulated mouse event. Returns true if successful. */ 00379 unsigned char report[4]={0,0,0,0}; 00380 00381 report[0] = buttons; 00382 report[1] = x; 00383 report[2] = y; 00384 report[3] = wheel; 00385 00386 if (!sendInputReport(REPORT_ID_MOUSE, report, 4)) { 00387 return false; 00388 } 00389 00390 return true; 00391 } 00392 00393 00394 // 00395 // USBJoystick 00396 // 00397 00398 unsigned char reportDescriptorJoystick[] = { 00399 0x05, 0x01, // USAGE_PAGE (Generic Desktop) 00400 0x09, 0x05, // USAGE (Game Pad) 00401 0xa1, 0x01, // COLLECTION (Application) 00402 0xa1, 0x00, // COLLECTION (Physical) 00403 0x05, 0x09, // USAGE_PAGE (Button) 00404 0x19, 0x01, // USAGE_MINIMUM (Button 1) 00405 0x29, 0x05, // USAGE_MAXIMUM (Button 5) 00406 0x15, 0x00, // LOGICAL_MINIMUM (0) 00407 0x25, 0x01, // LOGICAL_MAXIMUM (1) 00408 0x95, 0x05, // REPORT_COUNT (5) 00409 0x75, 0x01, // REPORT_SIZE (1) 00410 0x81, 0x02, // INPUT (Data,Var,Abs) 00411 0x75, 0x03, // REPORT_SIZE (3) 00412 0x95, 0x01, // REPORT_COUNT (1) 00413 0x81, 0x03, // INPUT (Cnst,Var,Abs) 00414 0x19, 0x06, // USAGE_MINIMUM (Button 6) 00415 0x29, 0x0c, // USAGE_MAXIMUM (Button 12) 00416 0x15, 0x00, // LOGICAL_MINIMUM (0) 00417 0x25, 0x01, // LOGICAL_MAXIMUM (1) 00418 0x95, 0x07, // REPORT_COUNT (7) 00419 0x75, 0x01, // REPORT_SIZE (1) 00420 0x81, 0x02, // INPUT (Data,Var,Abs) 00421 0x95, 0x01, // REPORT_COUNT (1) 00422 0x75, 0x01, // REPORT_SIZE (1) 00423 0x81, 0x03, // INPUT (Cnst,Var,Abs) 00424 0x05, 0x01, // USAGE_PAGE (Generic Desktop) 00425 0x09, 0x30, // USAGE (X) 00426 0x09, 0x31, // USAGE (Y) 00427 0x09, 0x33, // USAGE (Rx) 00428 0x09, 0x34, // USAGE (Ry) 00429 0x15, 0x81, // LOGICAL_MINIMUM (-127) 00430 0x25, 0x7f, // LOGICAL_MAXIMUM (127) 00431 0x75, 0x08, // REPORT_SIZE (8) 00432 0x95, 0x04, // REPORT_COUNT (4) 00433 0x81, 0x02, // INPUT (Data,Var,Abs) 00434 0x05, 0x01, // USAGE_PAGE (Generic Desktop) 00435 0x09, 0x36, // USAGE (Slider) 00436 0x09, 0x37, // USAGE (Dial) 00437 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) 00438 0x15, 0x00, // LOGICAL_MINIMUM (0) 00439 0x75, 0x08, // REPORT_SIZE (8) 00440 0x95, 0x02, // REPORT_COUNT (2) 00441 0x81, 0x02, // INPUT (Data,Var,Abs) 00442 0xc0, // END_COLLECTION 00443 0xc0 // END_COLLECTION 00444 }; 00445 00446 USBJoystick::USBJoystick() { 00447 int reportDescriptorSize = sizeof(reportDescriptorJoystick); 00448 configurationDescriptor[25] = reportDescriptorSize & 0xff; 00449 configurationDescriptor[26] = (reportDescriptorSize >> 8) & 0xff; 00450 } 00451 00452 bool USBJoystick::requestGetDescriptor(void) { 00453 bool success = false; 00454 00455 switch (DESCRIPTOR_TYPE(transfer.setup.wValue)) { 00456 case REPORT_DESCRIPTOR: 00457 transfer.remaining = sizeof(reportDescriptorJoystick); 00458 transfer.ptr = reportDescriptorJoystick; 00459 transfer.direction = DEVICE_TO_HOST; 00460 success = true; 00461 break; 00462 default: 00463 success = usbhid::requestGetDescriptor(); 00464 break; 00465 } 00466 00467 return success; 00468 } 00469 00470 bool USBJoystick::sendInputReport(unsigned char *data, unsigned char size) { 00471 /* Send an Input Report */ 00472 /* If data is NULL an all zero report is sent */ 00473 00474 static unsigned char report[MAX_REPORT_SIZE]; 00475 unsigned char i; 00476 00477 if (size > MAX_REPORT_SIZE) { 00478 return false; 00479 } 00480 00481 /* Add report data */ 00482 if (data != NULL) { 00483 for (i=0; i<size; i++) { 00484 report[i] = *data++; 00485 } 00486 } else { 00487 for (i=0; i<size; i++) { 00488 report[i] = 0; 00489 } 00490 } 00491 00492 /* Block if not configured */ 00493 while (!configured); 00494 00495 /* Send report */ 00496 complete = false; 00497 disableEvents(); 00498 endpointWrite(EP1IN, report, size); 00499 enableEvents(); 00500 00501 /* Wait for completion */ 00502 while (!complete && configured); 00503 return true; 00504 } 00505 00506 bool USBJoystick::joystick(unsigned char buttons1, unsigned short buttons2, signed char x, signed char y, signed char cx, signed char cy, unsigned char L, unsigned char R) { 00507 unsigned char report[9] = {0, 0, 0, 0, 0, 0, 0, 0}; 00508 report[0] = buttons1; 00509 report[1] = buttons2; 00510 report[2] = x ; 00511 report[3] = -y ; 00512 report[4] = cx ; 00513 report[5] = cy ; 00514 report[6] = L ; 00515 report[7] = R ; 00516 00517 00518 if (!sendInputReport(report, 8)) { 00519 return false; 00520 } 00521 00522 return true; 00523 } 00524
Generated on Tue Jul 12 2022 21:12:15 by
1.7.2