RC_Simulator.....By Jafar Qutteineh with mods to connect my Futaba 9C to \'RC Helicopter\' by http://www.alphamacsoftware.com/
Diff: USBHID/usbhid.cpp
- Revision:
- 0:65b9d8f621d2
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHID/usbhid.cpp Thu Dec 15 03:24:33 2011 +0000 @@ -0,0 +1,548 @@ +/* usbhid.cpp */ +/* USB HID class device */ +/* Copyright (c) Phil Wright 2008 */ + +/* modified by Shinichiro Oba <http://mbed.org/users/bricklife/> */ + +#include "mbed.h" +#include "usbhid.h" +#include "asciihid.h" + +/* Endpoint packet sizes */ +#define MAX_PACKET_SIZE_EP1 (64) + +/* HID Class */ +#define HID_CLASS (3) +#define HID_SUBCLASS_NONE (0) +#define HID_PROTOCOL_NONE (0) +#define HID_DESCRIPTOR (33) +#define REPORT_DESCRIPTOR (34) + +/* Class requests */ +#define GET_REPORT (0x1) +#define GET_IDLE (0x2) +#define SET_REPORT (0x9) +#define SET_IDLE (0xa) + +/* Descriptors */ +unsigned char deviceDescriptor[] = { + 0x12, /* bLength */ + DEVICE_DESCRIPTOR, /* bDescriptorType */ + 0x00, /* bcdUSB (LSB) */ + 0x02, /* bcdUSB (MSB) */ + 0x00, /* bDeviceClass */ + 0x00, /* bDeviceSubClass */ + 0x00, /* bDeviceprotocol */ + MAX_PACKET_SIZE_EP0, /* bMaxPacketSize0 */ + 0x28, /* idVendor (LSB) */ + 0x0d, /* idVendor (MSB) */ + 0x05, /* idProduct (LSB) */ + 0x02, /* idProduct (MSB) */ + 0x00, /* bcdDevice (LSB) */ + 0x00, /* bcdDevice (MSB) */ + 0x00, /* iManufacturer */ + 0x00, /* iProduct */ + 0x00, /* iSerialNumber */ + 0x01 /* bNumConfigurations */ +}; + +unsigned char configurationDescriptor[] = { + 0x09, /* bLength */ + CONFIGURATION_DESCRIPTOR, /* bDescriptorType */ + 0x09+0x09+0x09+0x07, /* wTotalLength (LSB) */ + 0x00, /* wTotalLength (MSB) */ + 0x01, /* bNumInterfaces */ + 0x01, /* bConfigurationValue */ + 0x00, /* iConfiguration */ + 0xc0, /* bmAttributes */ + 0x00, /* bMaxPower */ + + 0x09, /* bLength */ + INTERFACE_DESCRIPTOR, /* bDescriptorType */ + 0x00, /* bInterfaceNumber */ + 0x00, /* bAlternateSetting */ + 0x01, /* bNumEndpoints */ + HID_CLASS, /* bInterfaceClass */ + HID_SUBCLASS_NONE, /* bInterfaceSubClass */ + HID_PROTOCOL_NONE, /* bInterfaceProtocol */ + 0x00, /* iInterface */ + + 0x09, /* bLength */ + HID_DESCRIPTOR, /* bDescriptorType */ + 0x11, /* bcdHID (LSB) */ + 0x01, /* bcdHID (MSB) */ + 0x00, /* bCountryCode */ + 0x01, /* bNumDescriptors */ + REPORT_DESCRIPTOR, /* bDescriptorType */ + 0x79, /* wDescriptorLength (LSB) */ + 0x00, /* wDescriptorLength (MSB) */ + + 0x07, /* bLength */ + ENDPOINT_DESCRIPTOR, /* bDescriptorType */ + 0x81, /* bEndpointAddress */ + 0x03, /* bmAttributes */ + MAX_PACKET_SIZE_EP1, /* wMaxPacketSize (LSB) */ + 0x00, /* wMaxPacketSize (MSB) */ + 0x0a, /* bInterval */ +}; + +/* HID Class Report Descriptor */ +/* Short items: size is 0, 1, 2 or 3 specifying 0, 1, 2 or 4 (four) bytes of data as per HID Class standard */ + +/* Main items */ +#define INPUT(size) (0x80 | size) +#define OUTPUT(size) (0x90 | size) +#define FEATURE(size) (0xb0 | size) +#define COLLECTION(size) (0xa0 | size) +#define END_COLLECTION(size) (0xc0 | size) + +/* Global items */ +#define USAGE_PAGE(size) (0x04 | size) +#define LOGICAL_MIN(size) (0x14 | size) +#define LOGICAL_MAX(size) (0x24 | size) +#define PHYSICAL_MIN(size) (0x34 | size) +#define PHYSICAL_MAX(size) (0x44 | size) +#define UNIT_EXPONENT(size) (0x54 | size) +#define UNIT(size) (0x64 | size) +#define REPORT_SIZE(size) (0x74 | size) +#define REPORT_ID(size) (0x84 | size) +#define REPORT_COUNT(size) (0x94 | size) +#define PUSH(size) (0xa4 | size) +#define POP(size) (0xb4 | size) + +/* Local items */ +#define USAGE(size) (0x08 | size) +#define USAGE_MIN(size) (0x18 | size) +#define USAGE_MAX(size) (0x28 | size) +#define DESIGNATOR_INDEX(size) (0x38 | size) +#define DESIGNATOR_MIN(size) (0x48 | size) +#define DESIGNATOR_MAX(size) (0x58 | size) +#define STRING_INDEX(size) (0x78 | size) +#define STRING_MIN(size) (0x88 | size) +#define STRING_MAX(size) (0x98 | size) +#define DELIMITER(size) (0xa8 | size) + +#define REPORT_ID_KEYBOARD (1) +#define REPORT_ID_MOUSE (2) + +#define MAX_REPORT_SIZE (8) + +unsigned char reportDescriptor[] = { + /* Keyboard */ + USAGE_PAGE(1), 0x01, + USAGE(1), 0x06, + COLLECTION(1), 0x01, + REPORT_ID(1), REPORT_ID_KEYBOARD, + USAGE_PAGE(1), 0x07, + USAGE_MIN(1), 0xE0, + USAGE_MAX(1), 0xE7, + LOGICAL_MIN(1), 0x00, + LOGICAL_MAX(1), 0x01, + REPORT_SIZE(1), 0x01, + REPORT_COUNT(1), 0x08, + INPUT(1), 0x02, + REPORT_COUNT(1), 0x01, + REPORT_SIZE(1), 0x08, + INPUT(1), 0x01, + REPORT_COUNT(1), 0x05, + REPORT_SIZE(1), 0x01, + USAGE_PAGE(1), 0x08, + USAGE_MIN(1), 0x01, + USAGE_MAX(1), 0x05, + OUTPUT(1), 0x02, + REPORT_COUNT(1), 0x01, + REPORT_SIZE(1), 0x03, + OUTPUT(1), 0x01, + REPORT_COUNT(1), 0x06, + REPORT_SIZE(1), 0x08, + LOGICAL_MIN(1), 0x00, + LOGICAL_MAX(2), 0xff, 0x00, + USAGE_PAGE(1), 0x07, + USAGE_MIN(1), 0x00, + USAGE_MAX(2), 0xff, 0x00, + INPUT(1), 0x00, + END_COLLECTION(0), + + /* Mouse */ + USAGE_PAGE(1), 0x01, + USAGE(1), 0x02, + COLLECTION(1), 0x01, + USAGE(1), 0x01, + COLLECTION(1), 0x00, + REPORT_ID(1), REPORT_ID_MOUSE, + REPORT_COUNT(1), 0x03, + REPORT_SIZE(1), 0x01, + USAGE_PAGE(1), 0x09, + USAGE_MIN(1), 0x1, + USAGE_MAX(1), 0x3, + LOGICAL_MIN(1), 0x00, + LOGICAL_MAX(1), 0x01, + INPUT(1), 0x02, + REPORT_COUNT(1), 0x01, + REPORT_SIZE(1), 0x05, + INPUT(1), 0x01, + REPORT_COUNT(1), 0x03, + REPORT_SIZE(1), 0x08, + USAGE_PAGE(1), 0x01, + USAGE(1), 0x30, + USAGE(1), 0x31, + USAGE(1), 0x38, + LOGICAL_MIN(1), 0x81, + LOGICAL_MAX(1), 0x7f, + INPUT(1), 0x06, + END_COLLECTION(0), + END_COLLECTION(0), +}; + +volatile bool complete; +volatile bool configured; +unsigned char outputReport[MAX_REPORT_SIZE]; +DigitalOut errorLED (LED1); +DigitalOut okLED (LED2); + +usbhid::usbhid() { + configured = false; + connect(); + +} + +void usbhid::deviceEventReset() { + configured = false; + + /* Must call base class */ + usbdevice::deviceEventReset(); +} + +bool usbhid::requestSetConfiguration(void) { + bool result; + + /* Configure IN interrupt endpoint */ + realiseEndpoint(EP1IN, MAX_PACKET_SIZE_EP1); + enableEndpointEvent(EP1IN); + + /* Must call base class */ + result = usbdevice::requestSetConfiguration(); + + if (result) { + /* Now configured */ + configured = true; + } + + return result; +} + +bool usbhid::requestGetDescriptor(void) { + bool success = false; + + switch (DESCRIPTOR_TYPE(transfer.setup.wValue)) { + case DEVICE_DESCRIPTOR: + transfer.remaining = sizeof(deviceDescriptor); + transfer.ptr = deviceDescriptor; + transfer.direction = DEVICE_TO_HOST; + success = true; + break; + case CONFIGURATION_DESCRIPTOR: + transfer.remaining = sizeof(configurationDescriptor); + transfer.ptr = configurationDescriptor; + transfer.direction = DEVICE_TO_HOST; + success = true; + break; + case STRING_DESCRIPTOR: + case INTERFACE_DESCRIPTOR: + case ENDPOINT_DESCRIPTOR: + /* TODO: Support is optional, not implemented here */ + break; + case HID_DESCRIPTOR: + transfer.remaining = 0x09; /* TODO: Fix hard coded size/offset */ + transfer.ptr = &configurationDescriptor[18]; + transfer.direction = DEVICE_TO_HOST; + success = true; + break; + case REPORT_DESCRIPTOR: + transfer.remaining = sizeof(reportDescriptor); + transfer.ptr = reportDescriptor; + transfer.direction = DEVICE_TO_HOST; + success = true; + break; + default: + break; + } + + return success; +} + +bool usbhid::requestSetup(void) { + /* Process class requests */ + bool success = false; + + if (transfer.setup.bmRequestType.Type == CLASS_TYPE) { + switch (transfer.setup.bRequest) { + case SET_REPORT: + switch (transfer.setup.wValue & 0xff) { + case REPORT_ID_KEYBOARD: + /* TODO: LED state */ + transfer.remaining = sizeof(outputReport); + transfer.ptr = outputReport; + transfer.direction = HOST_TO_DEVICE; + success = true; + break; + default: + break; + } + break; + default: + break; + } + } + + if (success) { + /* We've handled this request */ + return true; + } + + return usbdevice::requestSetup(); +} + +bool usbhid::sendInputReport(unsigned char id, unsigned char *data, unsigned char size) { + /* Send an Input Report */ + /* If data is NULL an all zero report is sent */ + + static unsigned char report[MAX_REPORT_SIZE+1]; /* +1 for report ID */ + unsigned char i; + + if (size > MAX_REPORT_SIZE) { + return false; + } + + /* Add report ID */ + report[0]=id; + + /* Add report data */ + if (data != NULL) { + for (i=0; i<size; i++) { + report[i+1] = *data++; + } + } else { + for (i=0; i<size; i++) { + report[i+1] = 0; + } + } + + /* Block if not configured */ + while (!configured); + + /* Send report */ + complete = false; + disableEvents(); + endpointWrite(EP1IN, report, size+1); /* +1 for report ID */ + enableEvents(); + + /* Wait for completion */ + while (!complete && configured); + return true; +} + +void usbhid::endpointEventEP1In(void) { + complete = true; +} + +bool usbhid::keyboard(char c) { + /* Send a simulated keyboard keypress. Returns true if successful. */ + unsigned char report[8]={0,0,0,0,0,0,0,0}; + + report[0] = keymap[c].modifier; + report[2] = keymap[c].usage; + + /* Key down */ + if (!sendInputReport(REPORT_ID_KEYBOARD, report, 8)) { + return false; + } + + /* Key up */ + if (!sendInputReport(REPORT_ID_KEYBOARD, NULL, 8)) { + return false; + } + + return true; +} + +bool usbhid::keyboard(char *string) { + /* Send a string of characters. Returns true if successful. */ + do { + if (!keyboard(*string++)) { + return false; + } + } while (*string != '\0'); + + return true; +} + +bool usbhid::mouse(signed char x, signed char y, unsigned char buttons, signed char wheel) { + /* Send a simulated mouse event. Returns true if successful. */ + unsigned char report[4]={0,0,0,0}; + + report[0] = buttons; + report[1] = x; + report[2] = y; + report[3] = wheel; + + if (!sendInputReport(REPORT_ID_MOUSE, report, 4)) { + return false; + } + + return true; +} + + +// +// USBJoystick +// Edit for different configurations (channels) + +unsigned char reportDescriptorJoystick[] = { + USAGE_PAGE(1), 0x01, //Generic Desktop + USAGE(1), 0x04, //Joystiq + COLLECTION(1), 0x01, //Application + USAGE(1), 0x01,//Pointer + COLLECTION(1), 0x00,//Physical + + USAGE_PAGE(1), 0x09,//Buttons + USAGE_MIN(1), 0x01,//Button 1 + USAGE_MAX(1), 0x02,//Button 12 .....Changed here + LOGICAL_MIN(1), 0x00,//00 + LOGICAL_MAX(1), 0x01,//01 + PHYSICAL_MIN(1), 0x00,//00 + PHYSICAL_MAX(1), 0x01,//01 + REPORT_SIZE(1), 0x01,// 1 Bit size + REPORT_COUNT(1), 0x02,// 2 report + INPUT(1), 0x02,// Data , Var , Abs + + REPORT_SIZE(1), 0x06,// 6 padding bits + REPORT_COUNT(1), 0x01, + INPUT(1), 0x03,// cnst , Vsr , Abs + +//USAGE_PAGE(1), 0x01, //Generic Desktop +//USAGE(1), 0x39,// Hat switch +//LOGICAL_MIN(1), 0x00,// 00 +//LOGICAL_MAX(1), 0x07,//07 +//PHYSICAL_MIN(1), 0x00,//00 +//PHYSICAL_MAX(2), 0x3B, 0x01,//315 +//UNIT(1), 0x14,//English Rotation : Angular Position +//REPORT_SIZE(1), 0x04,//04 +//REPORT_COUNT(1), 0x01,//01 +//INPUT(1), 0x42,//Data, Var, Abs, Null +/* + 0x05, 0x02, // USAGE_PAGE (Simulation Controls) + 0x09, 0xbb, // USAGE (Throttle) + 0x09, 0xba, // USAGE (rudder) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x26, 0xff,0x00, // LOGICAL_MAXIMUM (255) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x02, // REPORT_COUNT (2) + 0x81, 0x02, // INPUT (Data,Var,Abs) +*/ + USAGE_PAGE(1), 0x01,//Generic Desktop + USAGE(1), 0x32,//z + USAGE(1), 0x35,//Rz + USAGE(1), 0x30,//x + USAGE(1), 0x31,//y + LOGICAL_MIN(1), 0x00,//00 + LOGICAL_MAX(2), 0xff, 0x00,//255 + PHYSICAL_MIN(1), 0x00,//00 + PHYSICAL_MAX(2), 0xff, 0x00,//255 + UNIT(2), 0x00, 0x00,//None 2 bytes + REPORT_SIZE(1), 0x08,//8 bits + REPORT_COUNT(1), 0x04,//4 reports (channels) + INPUT(1), 0x02,//Data, Var , Abs + + END_COLLECTION(0), + END_COLLECTION(0), +}; + +USBJoystick::USBJoystick() { + int reportDescriptorSize = sizeof(reportDescriptorJoystick); + configurationDescriptor[25] = reportDescriptorSize & 0xff; + configurationDescriptor[26] = (reportDescriptorSize >> 8) & 0xff; + +} + +bool USBJoystick::requestGetDescriptor(void) { + + bool success = false; + + switch (DESCRIPTOR_TYPE(transfer.setup.wValue)) { + case REPORT_DESCRIPTOR: + transfer.remaining = sizeof(reportDescriptorJoystick); + transfer.ptr = reportDescriptorJoystick; + transfer.direction = DEVICE_TO_HOST; + success = true; + break; + default: + success = usbhid::requestGetDescriptor(); + break; + } + + return success; +} + +bool USBJoystick::sendInputReport(unsigned char *data, unsigned char size) { + /* Send an Input Report */ + /* If data is NULL an all zero report is sent */ + + static unsigned char report[MAX_REPORT_SIZE]; + unsigned char i; + + if (size > MAX_REPORT_SIZE) { + return false; + } + + /* Add report data */ + if (data != NULL) { + for (i=0; i<size; i++) { + report[i] = *data++; + } + } else { + for (i=0; i<size; i++) { + report[i] = 0; + } + } + + /* Block if not configured */ + while (!configured) { + //errorLED=1; delete here + } + //okLED=1; delete here + /* Send report */ + complete = false; + disableEvents(); + endpointWrite(EP1IN, report, size); + enableEvents(); + + /* Wait for completion */ + while (!complete && configured); + return true; +} + +bool USBJoystick::joystick(unsigned char throttle, unsigned char rudder, unsigned char x, unsigned char y, bool button1, bool button2) { + + unsigned char report[6] = {0, 0, 0, 0, 0,0}; + unsigned char buttons=0x00; + + if (button1) buttons= buttons | 0x01; + if (button2) buttons= buttons | 0x02; + report[0] = buttons;//Buttons + report[1] = throttle; //Throttle + report[2] = rudder; //Rudder + report[3] = x; //X + report[4] = y;//Y + + + + if (!sendInputReport(report, 5)) { + + return false; + + } + // okLED=1;.....Delete here + return true; +} +