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