Chris BAYLEY / Mbed 2 deprecated RC_Simulator

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 DigitalOut errorLED (LED1);
00201 DigitalOut okLED (LED2);
00202 
00203 usbhid::usbhid() {
00204     configured = false;
00205     connect();
00206 
00207 }
00208 
00209 void usbhid::deviceEventReset() {
00210     configured = false;
00211 
00212     /* Must call base class */
00213     usbdevice::deviceEventReset();
00214 }
00215 
00216 bool usbhid::requestSetConfiguration(void) {
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         /* Now configured */
00228         configured = true;
00229     }
00230 
00231     return result;
00232 }
00233 
00234 bool usbhid::requestGetDescriptor(void) {
00235     bool success = false;
00236 
00237     switch (DESCRIPTOR_TYPE(transfer.setup.wValue)) {
00238         case DEVICE_DESCRIPTOR:
00239             transfer.remaining = sizeof(deviceDescriptor);
00240             transfer.ptr = deviceDescriptor;
00241             transfer.direction = DEVICE_TO_HOST;
00242             success = true;
00243             break;
00244         case CONFIGURATION_DESCRIPTOR:
00245             transfer.remaining =  sizeof(configurationDescriptor);
00246             transfer.ptr = configurationDescriptor;
00247             transfer.direction = DEVICE_TO_HOST;
00248             success = true;
00249             break;
00250         case STRING_DESCRIPTOR:
00251         case INTERFACE_DESCRIPTOR:
00252         case ENDPOINT_DESCRIPTOR:
00253             /* TODO: Support is optional, not implemented here */
00254             break;
00255         case HID_DESCRIPTOR:
00256             transfer.remaining = 0x09; /* TODO: Fix hard coded size/offset */
00257             transfer.ptr = &configurationDescriptor[18];
00258             transfer.direction = DEVICE_TO_HOST;
00259             success = true;
00260             break;
00261         case REPORT_DESCRIPTOR:
00262             transfer.remaining = sizeof(reportDescriptor);
00263             transfer.ptr = reportDescriptor;
00264             transfer.direction = DEVICE_TO_HOST;
00265             success = true;
00266             break;
00267         default:
00268             break;
00269     }
00270 
00271     return success;
00272 }
00273 
00274 bool usbhid::requestSetup(void) {
00275     /* Process class requests */
00276     bool success = false;
00277 
00278     if (transfer.setup.bmRequestType.Type == CLASS_TYPE) {
00279         switch (transfer.setup.bRequest) {
00280             case SET_REPORT:
00281                 switch (transfer.setup.wValue & 0xff) {
00282                     case REPORT_ID_KEYBOARD:
00283                         /* TODO: LED state */
00284                         transfer.remaining = sizeof(outputReport);
00285                         transfer.ptr = outputReport;
00286                         transfer.direction = HOST_TO_DEVICE;
00287                         success = true;
00288                         break;
00289                     default:
00290                         break;
00291                 }
00292                 break;
00293             default:
00294                 break;
00295         }
00296     }
00297 
00298     if (success) {
00299         /* We've handled this request */
00300         return true;
00301     }
00302 
00303     return usbdevice::requestSetup();
00304 }
00305 
00306 bool usbhid::sendInputReport(unsigned char id, unsigned char *data, unsigned char size) {
00307     /* Send an Input Report */
00308     /* If data is NULL an all zero report is sent */
00309 
00310     static unsigned char report[MAX_REPORT_SIZE+1]; /* +1 for report ID */
00311     unsigned char i;
00312 
00313     if (size > MAX_REPORT_SIZE) {
00314         return false;
00315     }
00316 
00317     /* Add report ID */
00318     report[0]=id;
00319 
00320     /* Add report data */
00321     if (data != NULL) {
00322         for (i=0; i<size; i++) {
00323             report[i+1] = *data++;
00324         }
00325     } else {
00326         for (i=0; i<size; i++) {
00327             report[i+1] = 0;
00328         }
00329     }
00330 
00331     /* Block if not configured */
00332     while (!configured);
00333 
00334     /* Send report */
00335     complete = false;
00336     disableEvents();
00337     endpointWrite(EP1IN, report, size+1); /* +1 for report ID */
00338     enableEvents();
00339 
00340     /* Wait for completion */
00341     while (!complete && configured);
00342     return true;
00343 }
00344 
00345 void usbhid::endpointEventEP1In(void) {
00346     complete = true;
00347 }
00348 
00349 bool usbhid::keyboard(char c) {
00350     /* Send a simulated keyboard keypress. Returns true if successful. */
00351     unsigned char report[8]={0,0,0,0,0,0,0,0};
00352 
00353     report[0] = keymap[c].modifier;
00354     report[2] = keymap[c].usage;
00355 
00356     /* Key down */
00357     if (!sendInputReport(REPORT_ID_KEYBOARD, report, 8)) {
00358         return false;
00359     }
00360 
00361     /* Key up */
00362     if (!sendInputReport(REPORT_ID_KEYBOARD, NULL, 8)) {
00363         return false;
00364     }
00365 
00366     return true;
00367 }
00368 
00369 bool usbhid::keyboard(char *string) {
00370     /* Send a string of characters. Returns true if successful. */
00371     do {
00372         if (!keyboard(*string++)) {
00373             return false;
00374         }
00375     } while (*string != '\0');
00376 
00377     return true;
00378 }
00379 
00380 bool usbhid::mouse(signed char x, signed char y, unsigned char buttons, signed char wheel) {
00381     /* Send a simulated mouse event. Returns true if successful. */
00382     unsigned char report[4]={0,0,0,0};
00383 
00384     report[0] = buttons;
00385     report[1] = x;
00386     report[2] = y;
00387     report[3] = wheel;
00388 
00389     if (!sendInputReport(REPORT_ID_MOUSE, report, 4)) {
00390         return false;
00391     }
00392 
00393     return true;
00394 }
00395 
00396 
00397 //
00398 // USBJoystick
00399 // Edit for different configurations (channels)
00400 
00401 unsigned char reportDescriptorJoystick[] = {
00402     USAGE_PAGE(1),      0x01, //Generic Desktop
00403     USAGE(1),           0x04, //Joystiq
00404     COLLECTION(1),      0x01, //Application
00405     USAGE(1),           0x01,//Pointer
00406     COLLECTION(1),      0x00,//Physical
00407 
00408     USAGE_PAGE(1),      0x09,//Buttons
00409     USAGE_MIN(1),       0x01,//Button 1
00410     USAGE_MAX(1),       0x02,//Button 12  .....Changed here
00411     LOGICAL_MIN(1),     0x00,//00
00412     LOGICAL_MAX(1),     0x01,//01
00413     PHYSICAL_MIN(1),    0x00,//00
00414     PHYSICAL_MAX(1),    0x01,//01
00415     REPORT_SIZE(1),     0x01,// 1 Bit size
00416     REPORT_COUNT(1),    0x02,// 2 report
00417     INPUT(1),           0x02,// Data , Var , Abs
00418 
00419     REPORT_SIZE(1),     0x06,// 6 padding bits
00420     REPORT_COUNT(1),    0x01,
00421     INPUT(1),           0x03,// cnst , Vsr , Abs
00422 
00423 //USAGE_PAGE(1),      0x01, //Generic Desktop
00424 //USAGE(1),           0x39,// Hat switch
00425 //LOGICAL_MIN(1),     0x00,// 00
00426 //LOGICAL_MAX(1),     0x07,//07
00427 //PHYSICAL_MIN(1),    0x00,//00
00428 //PHYSICAL_MAX(2),    0x3B, 0x01,//315
00429 //UNIT(1),            0x14,//English Rotation : Angular Position
00430 //REPORT_SIZE(1),     0x04,//04
00431 //REPORT_COUNT(1),    0x01,//01
00432 //INPUT(1),           0x42,//Data, Var, Abs, Null
00433 /*
00434     0x05, 0x02,                    //   USAGE_PAGE (Simulation Controls)
00435     0x09, 0xbb,                    //   USAGE (Throttle)
00436     0x09, 0xba,                    // USAGE (rudder)
00437     0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
00438     0x26, 0xff,0x00,               //   LOGICAL_MAXIMUM (255)
00439     0x75, 0x08,                    //   REPORT_SIZE (8)
00440     0x95, 0x02,                    //   REPORT_COUNT (2)
00441     0x81, 0x02,                    //   INPUT (Data,Var,Abs)
00442 */
00443     USAGE_PAGE(1),      0x01,//Generic Desktop
00444     USAGE(1),           0x32,//z
00445     USAGE(1),           0x35,//Rz
00446     USAGE(1),           0x30,//x
00447     USAGE(1),           0x31,//y
00448     LOGICAL_MIN(1),     0x00,//00
00449     LOGICAL_MAX(2),     0xff, 0x00,//255
00450     PHYSICAL_MIN(1),    0x00,//00
00451     PHYSICAL_MAX(2),    0xff, 0x00,//255
00452     UNIT(2),            0x00, 0x00,//None 2 bytes
00453     REPORT_SIZE(1),     0x08,//8 bits
00454     REPORT_COUNT(1),    0x04,//4 reports (channels)
00455     INPUT(1),           0x02,//Data, Var , Abs
00456 
00457     END_COLLECTION(0),
00458     END_COLLECTION(0),
00459 };
00460 
00461 USBJoystick::USBJoystick() {
00462     int reportDescriptorSize = sizeof(reportDescriptorJoystick);
00463     configurationDescriptor[25] = reportDescriptorSize & 0xff;
00464     configurationDescriptor[26] = (reportDescriptorSize >> 8) & 0xff;
00465 
00466 }
00467 
00468 bool USBJoystick::requestGetDescriptor(void) {
00469 
00470     bool success = false;
00471 
00472     switch (DESCRIPTOR_TYPE(transfer.setup.wValue)) {
00473         case REPORT_DESCRIPTOR:
00474             transfer.remaining = sizeof(reportDescriptorJoystick);
00475             transfer.ptr = reportDescriptorJoystick;
00476             transfer.direction = DEVICE_TO_HOST;
00477             success = true;
00478             break;
00479         default:
00480             success = usbhid::requestGetDescriptor();
00481             break;
00482     }
00483 
00484     return success;
00485 }
00486 
00487 bool USBJoystick::sendInputReport(unsigned char *data, unsigned char size) {
00488     /* Send an Input Report */
00489     /* If data is NULL an all zero report is sent */
00490 
00491     static unsigned char report[MAX_REPORT_SIZE];
00492     unsigned char i;
00493 
00494     if (size > MAX_REPORT_SIZE) {
00495         return false;
00496     }
00497 
00498     /* Add report data */
00499     if (data != NULL) {
00500         for (i=0; i<size; i++) {
00501             report[i] = *data++;
00502         }
00503     } else {
00504         for (i=0; i<size; i++) {
00505             report[i] = 0;
00506         }
00507     }
00508 
00509     /* Block if not configured */
00510     while (!configured) {
00511         //errorLED=1; delete here
00512     }
00513     //okLED=1; delete here
00514     /* Send report */
00515     complete = false;
00516     disableEvents();
00517     endpointWrite(EP1IN, report, size);
00518     enableEvents();
00519 
00520     /* Wait for completion */
00521     while (!complete && configured);
00522     return true;
00523 }
00524 
00525 bool USBJoystick::joystick(unsigned char throttle, unsigned char rudder, unsigned char x, unsigned char y, bool button1, bool button2) {
00526 
00527     unsigned char report[6] = {0, 0, 0, 0, 0,0};
00528     unsigned char buttons=0x00;
00529 
00530     if (button1) buttons= buttons | 0x01;
00531     if (button2) buttons= buttons | 0x02;
00532     report[0] = buttons;//Buttons
00533     report[1] = throttle; //Throttle
00534     report[2] = rudder; //Rudder
00535     report[3] = x; //X
00536     report[4] = y;//Y
00537     
00538 
00539 
00540     if (!sendInputReport(report, 5)) {
00541        
00542         return false;
00543 
00544     }
00545     // okLED=1;.....Delete here
00546     return true;
00547 }
00548