Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Diff: USBHID/usbhid.cpp
- Revision:
- 0:3dbb22992c94
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHID/usbhid.cpp Sat Jul 02 17:27:05 2011 +0000
@@ -0,0 +1,546 @@
+/* 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), 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), 0x02,//2 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;
+}
+