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