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.

Dependencies:   mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers usbhid.cpp Source File

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 }