USB HID Joystick Example (modified USBMouse)

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 
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