A optical beam breaker detector that appears to aPC as a USB keyboard, typing characters when the beam is broken

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