N64 to USB HID interface

Dependencies:   mbed

Committer:
igor_m
Date:
Wed Dec 10 14:22:30 2014 +0000
Revision:
5:eb93a4f91396
Parent:
0:547c5459faa6
Initial Release

Who changed what in which revision?

UserRevisionLine numberNew contents of line
igor_m 0:547c5459faa6 1 /* usbhid.cpp */
igor_m 0:547c5459faa6 2 /* USB HID class device */
igor_m 0:547c5459faa6 3 /* Copyright (c) Phil Wright 2008 */
igor_m 0:547c5459faa6 4
igor_m 0:547c5459faa6 5 /* modified by Shinichiro Oba <http://mbed.org/users/bricklife/> */
igor_m 0:547c5459faa6 6
igor_m 0:547c5459faa6 7 #include "mbed.h"
igor_m 0:547c5459faa6 8 #include "usbhid.h"
igor_m 0:547c5459faa6 9 #include "asciihid.h"
igor_m 0:547c5459faa6 10
igor_m 0:547c5459faa6 11 /* Endpoint packet sizes */
igor_m 0:547c5459faa6 12 #define MAX_PACKET_SIZE_EP1 (64)
igor_m 0:547c5459faa6 13
igor_m 0:547c5459faa6 14 /* HID Class */
igor_m 0:547c5459faa6 15 #define HID_CLASS (3)
igor_m 0:547c5459faa6 16 #define HID_SUBCLASS_NONE (0)
igor_m 0:547c5459faa6 17 #define HID_PROTOCOL_NONE (0)
igor_m 0:547c5459faa6 18 #define HID_DESCRIPTOR (33)
igor_m 0:547c5459faa6 19 #define REPORT_DESCRIPTOR (34)
igor_m 0:547c5459faa6 20
igor_m 0:547c5459faa6 21 /* Class requests */
igor_m 0:547c5459faa6 22 #define GET_REPORT (0x1)
igor_m 0:547c5459faa6 23 #define GET_IDLE (0x2)
igor_m 0:547c5459faa6 24 #define SET_REPORT (0x9)
igor_m 0:547c5459faa6 25 #define SET_IDLE (0xa)
igor_m 0:547c5459faa6 26
igor_m 0:547c5459faa6 27 /* Descriptors */
igor_m 0:547c5459faa6 28 unsigned char deviceDescriptor[] = {
igor_m 0:547c5459faa6 29 0x12, /* bLength */
igor_m 0:547c5459faa6 30 DEVICE_DESCRIPTOR, /* bDescriptorType */
igor_m 0:547c5459faa6 31 0x00, /* bcdUSB (LSB) */
igor_m 0:547c5459faa6 32 0x02, /* bcdUSB (MSB) */
igor_m 0:547c5459faa6 33 0x00, /* bDeviceClass */
igor_m 0:547c5459faa6 34 0x00, /* bDeviceSubClass */
igor_m 0:547c5459faa6 35 0x00, /* bDeviceprotocol */
igor_m 0:547c5459faa6 36 MAX_PACKET_SIZE_EP0, /* bMaxPacketSize0 */
igor_m 0:547c5459faa6 37 0x28, /* idVendor (LSB) */
igor_m 0:547c5459faa6 38 0x0d, /* idVendor (MSB) */
igor_m 0:547c5459faa6 39 0x05, /* idProduct (LSB) */
igor_m 0:547c5459faa6 40 0x02, /* idProduct (MSB) */
igor_m 0:547c5459faa6 41 0x00, /* bcdDevice (LSB) */
igor_m 0:547c5459faa6 42 0x00, /* bcdDevice (MSB) */
igor_m 0:547c5459faa6 43 0x00, /* iManufacturer */
igor_m 0:547c5459faa6 44 0x00, /* iProduct */
igor_m 0:547c5459faa6 45 0x00, /* iSerialNumber */
igor_m 0:547c5459faa6 46 0x01 /* bNumConfigurations */
igor_m 0:547c5459faa6 47 };
igor_m 0:547c5459faa6 48
igor_m 0:547c5459faa6 49 unsigned char configurationDescriptor[] = {
igor_m 0:547c5459faa6 50 0x09, /* bLength */
igor_m 0:547c5459faa6 51 CONFIGURATION_DESCRIPTOR, /* bDescriptorType */
igor_m 0:547c5459faa6 52 0x09+0x09+0x09+0x07, /* wTotalLength (LSB) */
igor_m 0:547c5459faa6 53 0x00, /* wTotalLength (MSB) */
igor_m 0:547c5459faa6 54 0x01, /* bNumInterfaces */
igor_m 0:547c5459faa6 55 0x01, /* bConfigurationValue */
igor_m 0:547c5459faa6 56 0x00, /* iConfiguration */
igor_m 0:547c5459faa6 57 0xc0, /* bmAttributes */
igor_m 0:547c5459faa6 58 0x00, /* bMaxPower */
igor_m 0:547c5459faa6 59
igor_m 0:547c5459faa6 60 0x09, /* bLength */
igor_m 0:547c5459faa6 61 INTERFACE_DESCRIPTOR, /* bDescriptorType */
igor_m 0:547c5459faa6 62 0x00, /* bInterfaceNumber */
igor_m 0:547c5459faa6 63 0x00, /* bAlternateSetting */
igor_m 0:547c5459faa6 64 0x01, /* bNumEndpoints */
igor_m 0:547c5459faa6 65 HID_CLASS, /* bInterfaceClass */
igor_m 0:547c5459faa6 66 HID_SUBCLASS_NONE, /* bInterfaceSubClass */
igor_m 0:547c5459faa6 67 HID_PROTOCOL_NONE, /* bInterfaceProtocol */
igor_m 0:547c5459faa6 68 0x00, /* iInterface */
igor_m 0:547c5459faa6 69
igor_m 0:547c5459faa6 70 0x09, /* bLength */
igor_m 0:547c5459faa6 71 HID_DESCRIPTOR, /* bDescriptorType */
igor_m 0:547c5459faa6 72 0x11, /* bcdHID (LSB) */
igor_m 0:547c5459faa6 73 0x01, /* bcdHID (MSB) */
igor_m 0:547c5459faa6 74 0x00, /* bCountryCode */
igor_m 0:547c5459faa6 75 0x01, /* bNumDescriptors */
igor_m 0:547c5459faa6 76 REPORT_DESCRIPTOR, /* bDescriptorType */
igor_m 0:547c5459faa6 77 0x79, /* wDescriptorLength (LSB) */
igor_m 0:547c5459faa6 78 0x00, /* wDescriptorLength (MSB) */
igor_m 0:547c5459faa6 79
igor_m 0:547c5459faa6 80 0x07, /* bLength */
igor_m 0:547c5459faa6 81 ENDPOINT_DESCRIPTOR, /* bDescriptorType */
igor_m 0:547c5459faa6 82 0x81, /* bEndpointAddress */
igor_m 0:547c5459faa6 83 0x03, /* bmAttributes */
igor_m 0:547c5459faa6 84 MAX_PACKET_SIZE_EP1, /* wMaxPacketSize (LSB) */
igor_m 0:547c5459faa6 85 0x00, /* wMaxPacketSize (MSB) */
igor_m 0:547c5459faa6 86 0x0a, /* bInterval */
igor_m 0:547c5459faa6 87 };
igor_m 0:547c5459faa6 88
igor_m 0:547c5459faa6 89 /* HID Class Report Descriptor */
igor_m 0:547c5459faa6 90 /* Short items: size is 0, 1, 2 or 3 specifying 0, 1, 2 or 4 (four) bytes of data as per HID Class standard */
igor_m 0:547c5459faa6 91
igor_m 0:547c5459faa6 92 /* Main items */
igor_m 0:547c5459faa6 93 #define INPUT(size) (0x80 | size)
igor_m 0:547c5459faa6 94 #define OUTPUT(size) (0x90 | size)
igor_m 0:547c5459faa6 95 #define FEATURE(size) (0xb0 | size)
igor_m 0:547c5459faa6 96 #define COLLECTION(size) (0xa0 | size)
igor_m 0:547c5459faa6 97 #define END_COLLECTION(size) (0xc0 | size)
igor_m 0:547c5459faa6 98
igor_m 0:547c5459faa6 99 /* Global items */
igor_m 0:547c5459faa6 100 #define USAGE_PAGE(size) (0x04 | size)
igor_m 0:547c5459faa6 101 #define LOGICAL_MIN(size) (0x14 | size)
igor_m 0:547c5459faa6 102 #define LOGICAL_MAX(size) (0x24 | size)
igor_m 0:547c5459faa6 103 #define PHYSICAL_MIN(size) (0x34 | size)
igor_m 0:547c5459faa6 104 #define PHYSICAL_MAX(size) (0x44 | size)
igor_m 0:547c5459faa6 105 #define UNIT_EXPONENT(size) (0x54 | size)
igor_m 0:547c5459faa6 106 #define UNIT(size) (0x64 | size)
igor_m 0:547c5459faa6 107 #define REPORT_SIZE(size) (0x74 | size)
igor_m 0:547c5459faa6 108 #define REPORT_ID(size) (0x84 | size)
igor_m 0:547c5459faa6 109 #define REPORT_COUNT(size) (0x94 | size)
igor_m 0:547c5459faa6 110 #define PUSH(size) (0xa4 | size)
igor_m 0:547c5459faa6 111 #define POP(size) (0xb4 | size)
igor_m 0:547c5459faa6 112
igor_m 0:547c5459faa6 113 /* Local items */
igor_m 0:547c5459faa6 114 #define USAGE(size) (0x08 | size)
igor_m 0:547c5459faa6 115 #define USAGE_MIN(size) (0x18 | size)
igor_m 0:547c5459faa6 116 #define USAGE_MAX(size) (0x28 | size)
igor_m 0:547c5459faa6 117 #define DESIGNATOR_INDEX(size) (0x38 | size)
igor_m 0:547c5459faa6 118 #define DESIGNATOR_MIN(size) (0x48 | size)
igor_m 0:547c5459faa6 119 #define DESIGNATOR_MAX(size) (0x58 | size)
igor_m 0:547c5459faa6 120 #define STRING_INDEX(size) (0x78 | size)
igor_m 0:547c5459faa6 121 #define STRING_MIN(size) (0x88 | size)
igor_m 0:547c5459faa6 122 #define STRING_MAX(size) (0x98 | size)
igor_m 0:547c5459faa6 123 #define DELIMITER(size) (0xa8 | size)
igor_m 0:547c5459faa6 124
igor_m 0:547c5459faa6 125 #define REPORT_ID_KEYBOARD (1)
igor_m 0:547c5459faa6 126 #define REPORT_ID_MOUSE (2)
igor_m 0:547c5459faa6 127
igor_m 0:547c5459faa6 128 #define MAX_REPORT_SIZE (8)
igor_m 0:547c5459faa6 129
igor_m 0:547c5459faa6 130 unsigned char reportDescriptor[] = {
igor_m 0:547c5459faa6 131 /* Keyboard */
igor_m 0:547c5459faa6 132 USAGE_PAGE(1), 0x01,
igor_m 0:547c5459faa6 133 USAGE(1), 0x06,
igor_m 0:547c5459faa6 134 COLLECTION(1), 0x01,
igor_m 0:547c5459faa6 135 REPORT_ID(1), REPORT_ID_KEYBOARD,
igor_m 0:547c5459faa6 136 USAGE_PAGE(1), 0x07,
igor_m 0:547c5459faa6 137 USAGE_MIN(1), 0xE0,
igor_m 0:547c5459faa6 138 USAGE_MAX(1), 0xE7,
igor_m 0:547c5459faa6 139 LOGICAL_MIN(1), 0x00,
igor_m 0:547c5459faa6 140 LOGICAL_MAX(1), 0x01,
igor_m 0:547c5459faa6 141 REPORT_SIZE(1), 0x01,
igor_m 0:547c5459faa6 142 REPORT_COUNT(1), 0x08,
igor_m 0:547c5459faa6 143 INPUT(1), 0x02,
igor_m 0:547c5459faa6 144 REPORT_COUNT(1), 0x01,
igor_m 0:547c5459faa6 145 REPORT_SIZE(1), 0x08,
igor_m 0:547c5459faa6 146 INPUT(1), 0x01,
igor_m 0:547c5459faa6 147 REPORT_COUNT(1), 0x05,
igor_m 0:547c5459faa6 148 REPORT_SIZE(1), 0x01,
igor_m 0:547c5459faa6 149 USAGE_PAGE(1), 0x08,
igor_m 0:547c5459faa6 150 USAGE_MIN(1), 0x01,
igor_m 0:547c5459faa6 151 USAGE_MAX(1), 0x05,
igor_m 0:547c5459faa6 152 OUTPUT(1), 0x02,
igor_m 0:547c5459faa6 153 REPORT_COUNT(1), 0x01,
igor_m 0:547c5459faa6 154 REPORT_SIZE(1), 0x03,
igor_m 0:547c5459faa6 155 OUTPUT(1), 0x01,
igor_m 0:547c5459faa6 156 REPORT_COUNT(1), 0x06,
igor_m 0:547c5459faa6 157 REPORT_SIZE(1), 0x08,
igor_m 0:547c5459faa6 158 LOGICAL_MIN(1), 0x00,
igor_m 0:547c5459faa6 159 LOGICAL_MAX(2), 0xff, 0x00,
igor_m 0:547c5459faa6 160 USAGE_PAGE(1), 0x07,
igor_m 0:547c5459faa6 161 USAGE_MIN(1), 0x00,
igor_m 0:547c5459faa6 162 USAGE_MAX(2), 0xff, 0x00,
igor_m 0:547c5459faa6 163 INPUT(1), 0x00,
igor_m 0:547c5459faa6 164 END_COLLECTION(0),
igor_m 0:547c5459faa6 165
igor_m 0:547c5459faa6 166 /* Mouse */
igor_m 0:547c5459faa6 167 USAGE_PAGE(1), 0x01,
igor_m 0:547c5459faa6 168 USAGE(1), 0x02,
igor_m 0:547c5459faa6 169 COLLECTION(1), 0x01,
igor_m 0:547c5459faa6 170 USAGE(1), 0x01,
igor_m 0:547c5459faa6 171 COLLECTION(1), 0x00,
igor_m 0:547c5459faa6 172 REPORT_ID(1), REPORT_ID_MOUSE,
igor_m 0:547c5459faa6 173 REPORT_COUNT(1), 0x03,
igor_m 0:547c5459faa6 174 REPORT_SIZE(1), 0x01,
igor_m 0:547c5459faa6 175 USAGE_PAGE(1), 0x09,
igor_m 0:547c5459faa6 176 USAGE_MIN(1), 0x1,
igor_m 0:547c5459faa6 177 USAGE_MAX(1), 0x3,
igor_m 0:547c5459faa6 178 LOGICAL_MIN(1), 0x00,
igor_m 0:547c5459faa6 179 LOGICAL_MAX(1), 0x01,
igor_m 0:547c5459faa6 180 INPUT(1), 0x02,
igor_m 0:547c5459faa6 181 REPORT_COUNT(1), 0x01,
igor_m 0:547c5459faa6 182 REPORT_SIZE(1), 0x05,
igor_m 0:547c5459faa6 183 INPUT(1), 0x01,
igor_m 0:547c5459faa6 184 REPORT_COUNT(1), 0x03,
igor_m 0:547c5459faa6 185 REPORT_SIZE(1), 0x08,
igor_m 0:547c5459faa6 186 USAGE_PAGE(1), 0x01,
igor_m 0:547c5459faa6 187 USAGE(1), 0x30,
igor_m 0:547c5459faa6 188 USAGE(1), 0x31,
igor_m 0:547c5459faa6 189 USAGE(1), 0x38,
igor_m 0:547c5459faa6 190 LOGICAL_MIN(1), 0x81,
igor_m 0:547c5459faa6 191 LOGICAL_MAX(1), 0x7f,
igor_m 0:547c5459faa6 192 INPUT(1), 0x06,
igor_m 0:547c5459faa6 193 END_COLLECTION(0),
igor_m 0:547c5459faa6 194 END_COLLECTION(0),
igor_m 0:547c5459faa6 195 };
igor_m 0:547c5459faa6 196
igor_m 0:547c5459faa6 197 volatile bool complete;
igor_m 0:547c5459faa6 198 volatile bool configured;
igor_m 0:547c5459faa6 199 unsigned char outputReport[MAX_REPORT_SIZE];
igor_m 0:547c5459faa6 200
igor_m 0:547c5459faa6 201 usbhid::usbhid() {
igor_m 0:547c5459faa6 202 configured = false;
igor_m 0:547c5459faa6 203 connect();
igor_m 0:547c5459faa6 204 }
igor_m 0:547c5459faa6 205
igor_m 0:547c5459faa6 206 void usbhid::deviceEventReset() {
igor_m 0:547c5459faa6 207 configured = false;
igor_m 0:547c5459faa6 208
igor_m 0:547c5459faa6 209 /* Must call base class */
igor_m 0:547c5459faa6 210 usbdevice::deviceEventReset();
igor_m 0:547c5459faa6 211 }
igor_m 0:547c5459faa6 212
igor_m 0:547c5459faa6 213 bool usbhid::requestSetConfiguration(void) {
igor_m 0:547c5459faa6 214 bool result;
igor_m 0:547c5459faa6 215
igor_m 0:547c5459faa6 216 /* Configure IN interrupt endpoint */
igor_m 0:547c5459faa6 217 realiseEndpoint(EP1IN, MAX_PACKET_SIZE_EP1);
igor_m 0:547c5459faa6 218 enableEndpointEvent(EP1IN);
igor_m 0:547c5459faa6 219
igor_m 0:547c5459faa6 220 /* Must call base class */
igor_m 0:547c5459faa6 221 result = usbdevice::requestSetConfiguration();
igor_m 0:547c5459faa6 222
igor_m 0:547c5459faa6 223 if (result) {
igor_m 0:547c5459faa6 224 /* Now configured */
igor_m 0:547c5459faa6 225 configured = true;
igor_m 0:547c5459faa6 226 }
igor_m 0:547c5459faa6 227
igor_m 0:547c5459faa6 228 return result;
igor_m 0:547c5459faa6 229 }
igor_m 0:547c5459faa6 230
igor_m 0:547c5459faa6 231 bool usbhid::requestGetDescriptor(void) {
igor_m 0:547c5459faa6 232 bool success = false;
igor_m 0:547c5459faa6 233
igor_m 0:547c5459faa6 234 switch (DESCRIPTOR_TYPE(transfer.setup.wValue)) {
igor_m 0:547c5459faa6 235 case DEVICE_DESCRIPTOR:
igor_m 0:547c5459faa6 236 transfer.remaining = sizeof(deviceDescriptor);
igor_m 0:547c5459faa6 237 transfer.ptr = deviceDescriptor;
igor_m 0:547c5459faa6 238 transfer.direction = DEVICE_TO_HOST;
igor_m 0:547c5459faa6 239 success = true;
igor_m 0:547c5459faa6 240 break;
igor_m 0:547c5459faa6 241 case CONFIGURATION_DESCRIPTOR:
igor_m 0:547c5459faa6 242 transfer.remaining = sizeof(configurationDescriptor);
igor_m 0:547c5459faa6 243 transfer.ptr = configurationDescriptor;
igor_m 0:547c5459faa6 244 transfer.direction = DEVICE_TO_HOST;
igor_m 0:547c5459faa6 245 success = true;
igor_m 0:547c5459faa6 246 break;
igor_m 0:547c5459faa6 247 case STRING_DESCRIPTOR:
igor_m 0:547c5459faa6 248 case INTERFACE_DESCRIPTOR:
igor_m 0:547c5459faa6 249 case ENDPOINT_DESCRIPTOR:
igor_m 0:547c5459faa6 250 /* TODO: Support is optional, not implemented here */
igor_m 0:547c5459faa6 251 break;
igor_m 0:547c5459faa6 252 case HID_DESCRIPTOR:
igor_m 0:547c5459faa6 253 transfer.remaining = 0x09; /* TODO: Fix hard coded size/offset */
igor_m 0:547c5459faa6 254 transfer.ptr = &configurationDescriptor[18];
igor_m 0:547c5459faa6 255 transfer.direction = DEVICE_TO_HOST;
igor_m 0:547c5459faa6 256 success = true;
igor_m 0:547c5459faa6 257 break;
igor_m 0:547c5459faa6 258 case REPORT_DESCRIPTOR:
igor_m 0:547c5459faa6 259 transfer.remaining = sizeof(reportDescriptor);
igor_m 0:547c5459faa6 260 transfer.ptr = reportDescriptor;
igor_m 0:547c5459faa6 261 transfer.direction = DEVICE_TO_HOST;
igor_m 0:547c5459faa6 262 success = true;
igor_m 0:547c5459faa6 263 break;
igor_m 0:547c5459faa6 264 default:
igor_m 0:547c5459faa6 265 break;
igor_m 0:547c5459faa6 266 }
igor_m 0:547c5459faa6 267
igor_m 0:547c5459faa6 268 return success;
igor_m 0:547c5459faa6 269 }
igor_m 0:547c5459faa6 270
igor_m 0:547c5459faa6 271 bool usbhid::requestSetup(void) {
igor_m 0:547c5459faa6 272 /* Process class requests */
igor_m 0:547c5459faa6 273 bool success = false;
igor_m 0:547c5459faa6 274
igor_m 0:547c5459faa6 275 if (transfer.setup.bmRequestType.Type == CLASS_TYPE) {
igor_m 0:547c5459faa6 276 switch (transfer.setup.bRequest) {
igor_m 0:547c5459faa6 277 case SET_REPORT:
igor_m 0:547c5459faa6 278 switch (transfer.setup.wValue & 0xff) {
igor_m 0:547c5459faa6 279 case REPORT_ID_KEYBOARD:
igor_m 0:547c5459faa6 280 /* TODO: LED state */
igor_m 0:547c5459faa6 281 transfer.remaining = sizeof(outputReport);
igor_m 0:547c5459faa6 282 transfer.ptr = outputReport;
igor_m 0:547c5459faa6 283 transfer.direction = HOST_TO_DEVICE;
igor_m 0:547c5459faa6 284 success = true;
igor_m 0:547c5459faa6 285 break;
igor_m 0:547c5459faa6 286 default:
igor_m 0:547c5459faa6 287 break;
igor_m 0:547c5459faa6 288 }
igor_m 0:547c5459faa6 289 break;
igor_m 0:547c5459faa6 290 default:
igor_m 0:547c5459faa6 291 break;
igor_m 0:547c5459faa6 292 }
igor_m 0:547c5459faa6 293 }
igor_m 0:547c5459faa6 294
igor_m 0:547c5459faa6 295 if (success) {
igor_m 0:547c5459faa6 296 /* We've handled this request */
igor_m 0:547c5459faa6 297 return true;
igor_m 0:547c5459faa6 298 }
igor_m 0:547c5459faa6 299
igor_m 0:547c5459faa6 300 return usbdevice::requestSetup();
igor_m 0:547c5459faa6 301 }
igor_m 0:547c5459faa6 302
igor_m 0:547c5459faa6 303 bool usbhid::sendInputReport(unsigned char id, unsigned char *data, unsigned char size) {
igor_m 0:547c5459faa6 304 /* Send an Input Report */
igor_m 0:547c5459faa6 305 /* If data is NULL an all zero report is sent */
igor_m 0:547c5459faa6 306
igor_m 0:547c5459faa6 307 static unsigned char report[MAX_REPORT_SIZE+1]; /* +1 for report ID */
igor_m 0:547c5459faa6 308 unsigned char i;
igor_m 0:547c5459faa6 309
igor_m 0:547c5459faa6 310 if (size > MAX_REPORT_SIZE) {
igor_m 0:547c5459faa6 311 return false;
igor_m 0:547c5459faa6 312 }
igor_m 0:547c5459faa6 313
igor_m 0:547c5459faa6 314 /* Add report ID */
igor_m 0:547c5459faa6 315 report[0]=id;
igor_m 0:547c5459faa6 316
igor_m 0:547c5459faa6 317 /* Add report data */
igor_m 0:547c5459faa6 318 if (data != NULL) {
igor_m 0:547c5459faa6 319 for (i=0; i<size; i++) {
igor_m 0:547c5459faa6 320 report[i+1] = *data++;
igor_m 0:547c5459faa6 321 }
igor_m 0:547c5459faa6 322 } else {
igor_m 0:547c5459faa6 323 for (i=0; i<size; i++) {
igor_m 0:547c5459faa6 324 report[i+1] = 0;
igor_m 0:547c5459faa6 325 }
igor_m 0:547c5459faa6 326 }
igor_m 0:547c5459faa6 327
igor_m 0:547c5459faa6 328 /* Block if not configured */
igor_m 0:547c5459faa6 329 while (!configured);
igor_m 0:547c5459faa6 330
igor_m 0:547c5459faa6 331 /* Send report */
igor_m 0:547c5459faa6 332 complete = false;
igor_m 0:547c5459faa6 333 disableEvents();
igor_m 0:547c5459faa6 334 endpointWrite(EP1IN, report, size+1); /* +1 for report ID */
igor_m 0:547c5459faa6 335 enableEvents();
igor_m 0:547c5459faa6 336
igor_m 0:547c5459faa6 337 /* Wait for completion */
igor_m 0:547c5459faa6 338 while (!complete && configured);
igor_m 0:547c5459faa6 339 return true;
igor_m 0:547c5459faa6 340 }
igor_m 0:547c5459faa6 341
igor_m 0:547c5459faa6 342 void usbhid::endpointEventEP1In(void) {
igor_m 0:547c5459faa6 343 complete = true;
igor_m 0:547c5459faa6 344 }
igor_m 0:547c5459faa6 345
igor_m 0:547c5459faa6 346 bool usbhid::keyboard(char c) {
igor_m 0:547c5459faa6 347 /* Send a simulated keyboard keypress. Returns true if successful. */
igor_m 0:547c5459faa6 348 unsigned char report[8]={0,0,0,0,0,0,0,0};
igor_m 0:547c5459faa6 349
igor_m 0:547c5459faa6 350 report[0] = keymap[c].modifier;
igor_m 0:547c5459faa6 351 report[2] = keymap[c].usage;
igor_m 0:547c5459faa6 352
igor_m 0:547c5459faa6 353 /* Key down */
igor_m 0:547c5459faa6 354 if (!sendInputReport(REPORT_ID_KEYBOARD, report, 8)) {
igor_m 0:547c5459faa6 355 return false;
igor_m 0:547c5459faa6 356 }
igor_m 0:547c5459faa6 357
igor_m 0:547c5459faa6 358 /* Key up */
igor_m 0:547c5459faa6 359 if (!sendInputReport(REPORT_ID_KEYBOARD, NULL, 8)) {
igor_m 0:547c5459faa6 360 return false;
igor_m 0:547c5459faa6 361 }
igor_m 0:547c5459faa6 362
igor_m 0:547c5459faa6 363 return true;
igor_m 0:547c5459faa6 364 }
igor_m 0:547c5459faa6 365
igor_m 0:547c5459faa6 366 bool usbhid::keyboard(char *string) {
igor_m 0:547c5459faa6 367 /* Send a string of characters. Returns true if successful. */
igor_m 0:547c5459faa6 368 do {
igor_m 0:547c5459faa6 369 if (!keyboard(*string++)) {
igor_m 0:547c5459faa6 370 return false;
igor_m 0:547c5459faa6 371 }
igor_m 0:547c5459faa6 372 } while (*string != '\0');
igor_m 0:547c5459faa6 373
igor_m 0:547c5459faa6 374 return true;
igor_m 0:547c5459faa6 375 }
igor_m 0:547c5459faa6 376
igor_m 0:547c5459faa6 377 bool usbhid::mouse(signed char x, signed char y, unsigned char buttons, signed char wheel) {
igor_m 0:547c5459faa6 378 /* Send a simulated mouse event. Returns true if successful. */
igor_m 0:547c5459faa6 379 unsigned char report[4]={0,0,0,0};
igor_m 0:547c5459faa6 380
igor_m 0:547c5459faa6 381 report[0] = buttons;
igor_m 0:547c5459faa6 382 report[1] = x;
igor_m 0:547c5459faa6 383 report[2] = y;
igor_m 0:547c5459faa6 384 report[3] = wheel;
igor_m 0:547c5459faa6 385
igor_m 0:547c5459faa6 386 if (!sendInputReport(REPORT_ID_MOUSE, report, 4)) {
igor_m 0:547c5459faa6 387 return false;
igor_m 0:547c5459faa6 388 }
igor_m 0:547c5459faa6 389
igor_m 0:547c5459faa6 390 return true;
igor_m 0:547c5459faa6 391 }
igor_m 0:547c5459faa6 392
igor_m 0:547c5459faa6 393
igor_m 0:547c5459faa6 394 //
igor_m 0:547c5459faa6 395 // USBJoystick
igor_m 0:547c5459faa6 396 //
igor_m 0:547c5459faa6 397
igor_m 0:547c5459faa6 398 unsigned char reportDescriptorJoystick[] = {
igor_m 0:547c5459faa6 399 0x05, 0x01, // USAGE_PAGE (Generic Desktop)
igor_m 5:eb93a4f91396 400 0x09, 0x05, // USAGE (Game Pad)
igor_m 0:547c5459faa6 401 0xa1, 0x01, // COLLECTION (Application)
igor_m 0:547c5459faa6 402 0xa1, 0x00, // COLLECTION (Physical)
igor_m 0:547c5459faa6 403 0x05, 0x09, // USAGE_PAGE (Button)
igor_m 0:547c5459faa6 404 0x19, 0x01, // USAGE_MINIMUM (Button 1)
igor_m 5:eb93a4f91396 405 0x29, 0x05, // USAGE_MAXIMUM (Button 5)
igor_m 0:547c5459faa6 406 0x15, 0x00, // LOGICAL_MINIMUM (0)
igor_m 0:547c5459faa6 407 0x25, 0x01, // LOGICAL_MAXIMUM (1)
igor_m 5:eb93a4f91396 408 0x95, 0x05, // REPORT_COUNT (5)
igor_m 0:547c5459faa6 409 0x75, 0x01, // REPORT_SIZE (1)
igor_m 0:547c5459faa6 410 0x81, 0x02, // INPUT (Data,Var,Abs)
igor_m 5:eb93a4f91396 411 0x75, 0x03, // REPORT_SIZE (3)
igor_m 5:eb93a4f91396 412 0x95, 0x01, // REPORT_COUNT (1)
igor_m 5:eb93a4f91396 413 0x81, 0x03, // INPUT (Cnst,Var,Abs)
igor_m 5:eb93a4f91396 414 0x19, 0x06, // USAGE_MINIMUM (Button 6)
igor_m 5:eb93a4f91396 415 0x29, 0x0c, // USAGE_MAXIMUM (Button 12)
igor_m 5:eb93a4f91396 416 0x15, 0x00, // LOGICAL_MINIMUM (0)
igor_m 5:eb93a4f91396 417 0x25, 0x01, // LOGICAL_MAXIMUM (1)
igor_m 5:eb93a4f91396 418 0x95, 0x07, // REPORT_COUNT (7)
igor_m 5:eb93a4f91396 419 0x75, 0x01, // REPORT_SIZE (1)
igor_m 5:eb93a4f91396 420 0x81, 0x02, // INPUT (Data,Var,Abs)
igor_m 5:eb93a4f91396 421 0x95, 0x01, // REPORT_COUNT (1)
igor_m 5:eb93a4f91396 422 0x75, 0x01, // REPORT_SIZE (1)
igor_m 5:eb93a4f91396 423 0x81, 0x03, // INPUT (Cnst,Var,Abs)
igor_m 0:547c5459faa6 424 0x05, 0x01, // USAGE_PAGE (Generic Desktop)
igor_m 0:547c5459faa6 425 0x09, 0x30, // USAGE (X)
igor_m 0:547c5459faa6 426 0x09, 0x31, // USAGE (Y)
igor_m 5:eb93a4f91396 427 0x09, 0x33, // USAGE (Rx)
igor_m 5:eb93a4f91396 428 0x09, 0x34, // USAGE (Ry)
igor_m 0:547c5459faa6 429 0x15, 0x81, // LOGICAL_MINIMUM (-127)
igor_m 0:547c5459faa6 430 0x25, 0x7f, // LOGICAL_MAXIMUM (127)
igor_m 0:547c5459faa6 431 0x75, 0x08, // REPORT_SIZE (8)
igor_m 5:eb93a4f91396 432 0x95, 0x04, // REPORT_COUNT (4)
igor_m 5:eb93a4f91396 433 0x81, 0x02, // INPUT (Data,Var,Abs)
igor_m 5:eb93a4f91396 434 0x05, 0x01, // USAGE_PAGE (Generic Desktop)
igor_m 5:eb93a4f91396 435 0x09, 0x36, // USAGE (Slider)
igor_m 5:eb93a4f91396 436 0x09, 0x37, // USAGE (Dial)
igor_m 5:eb93a4f91396 437 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255)
igor_m 5:eb93a4f91396 438 0x15, 0x00, // LOGICAL_MINIMUM (0)
igor_m 5:eb93a4f91396 439 0x75, 0x08, // REPORT_SIZE (8)
igor_m 0:547c5459faa6 440 0x95, 0x02, // REPORT_COUNT (2)
igor_m 0:547c5459faa6 441 0x81, 0x02, // INPUT (Data,Var,Abs)
igor_m 5:eb93a4f91396 442 0xc0, // END_COLLECTION
igor_m 0:547c5459faa6 443 0xc0 // END_COLLECTION
igor_m 0:547c5459faa6 444 };
igor_m 0:547c5459faa6 445
igor_m 0:547c5459faa6 446 USBJoystick::USBJoystick() {
igor_m 0:547c5459faa6 447 int reportDescriptorSize = sizeof(reportDescriptorJoystick);
igor_m 0:547c5459faa6 448 configurationDescriptor[25] = reportDescriptorSize & 0xff;
igor_m 0:547c5459faa6 449 configurationDescriptor[26] = (reportDescriptorSize >> 8) & 0xff;
igor_m 0:547c5459faa6 450 }
igor_m 0:547c5459faa6 451
igor_m 0:547c5459faa6 452 bool USBJoystick::requestGetDescriptor(void) {
igor_m 0:547c5459faa6 453 bool success = false;
igor_m 0:547c5459faa6 454
igor_m 0:547c5459faa6 455 switch (DESCRIPTOR_TYPE(transfer.setup.wValue)) {
igor_m 0:547c5459faa6 456 case REPORT_DESCRIPTOR:
igor_m 0:547c5459faa6 457 transfer.remaining = sizeof(reportDescriptorJoystick);
igor_m 0:547c5459faa6 458 transfer.ptr = reportDescriptorJoystick;
igor_m 0:547c5459faa6 459 transfer.direction = DEVICE_TO_HOST;
igor_m 0:547c5459faa6 460 success = true;
igor_m 0:547c5459faa6 461 break;
igor_m 0:547c5459faa6 462 default:
igor_m 0:547c5459faa6 463 success = usbhid::requestGetDescriptor();
igor_m 0:547c5459faa6 464 break;
igor_m 0:547c5459faa6 465 }
igor_m 0:547c5459faa6 466
igor_m 0:547c5459faa6 467 return success;
igor_m 0:547c5459faa6 468 }
igor_m 0:547c5459faa6 469
igor_m 0:547c5459faa6 470 bool USBJoystick::sendInputReport(unsigned char *data, unsigned char size) {
igor_m 0:547c5459faa6 471 /* Send an Input Report */
igor_m 0:547c5459faa6 472 /* If data is NULL an all zero report is sent */
igor_m 0:547c5459faa6 473
igor_m 0:547c5459faa6 474 static unsigned char report[MAX_REPORT_SIZE];
igor_m 0:547c5459faa6 475 unsigned char i;
igor_m 0:547c5459faa6 476
igor_m 0:547c5459faa6 477 if (size > MAX_REPORT_SIZE) {
igor_m 0:547c5459faa6 478 return false;
igor_m 0:547c5459faa6 479 }
igor_m 0:547c5459faa6 480
igor_m 0:547c5459faa6 481 /* Add report data */
igor_m 0:547c5459faa6 482 if (data != NULL) {
igor_m 0:547c5459faa6 483 for (i=0; i<size; i++) {
igor_m 0:547c5459faa6 484 report[i] = *data++;
igor_m 0:547c5459faa6 485 }
igor_m 0:547c5459faa6 486 } else {
igor_m 0:547c5459faa6 487 for (i=0; i<size; i++) {
igor_m 0:547c5459faa6 488 report[i] = 0;
igor_m 0:547c5459faa6 489 }
igor_m 0:547c5459faa6 490 }
igor_m 0:547c5459faa6 491
igor_m 0:547c5459faa6 492 /* Block if not configured */
igor_m 0:547c5459faa6 493 while (!configured);
igor_m 0:547c5459faa6 494
igor_m 0:547c5459faa6 495 /* Send report */
igor_m 0:547c5459faa6 496 complete = false;
igor_m 0:547c5459faa6 497 disableEvents();
igor_m 0:547c5459faa6 498 endpointWrite(EP1IN, report, size);
igor_m 0:547c5459faa6 499 enableEvents();
igor_m 0:547c5459faa6 500
igor_m 0:547c5459faa6 501 /* Wait for completion */
igor_m 0:547c5459faa6 502 while (!complete && configured);
igor_m 0:547c5459faa6 503 return true;
igor_m 0:547c5459faa6 504 }
igor_m 0:547c5459faa6 505
igor_m 5:eb93a4f91396 506 bool USBJoystick::joystick(unsigned char buttons1, unsigned short buttons2, signed char x, signed char y, signed char cx, signed char cy, unsigned char L, unsigned char R) {
igor_m 5:eb93a4f91396 507 unsigned char report[9] = {0, 0, 0, 0, 0, 0, 0, 0};
igor_m 0:547c5459faa6 508 report[0] = buttons1;
igor_m 0:547c5459faa6 509 report[1] = buttons2;
igor_m 0:547c5459faa6 510 report[2] = x ;
igor_m 5:eb93a4f91396 511 report[3] = -y ;
igor_m 5:eb93a4f91396 512 report[4] = cx ;
igor_m 5:eb93a4f91396 513 report[5] = cy ;
igor_m 5:eb93a4f91396 514 report[6] = L ;
igor_m 5:eb93a4f91396 515 report[7] = R ;
igor_m 0:547c5459faa6 516
igor_m 0:547c5459faa6 517
igor_m 5:eb93a4f91396 518 if (!sendInputReport(report, 8)) {
igor_m 0:547c5459faa6 519 return false;
igor_m 0:547c5459faa6 520 }
igor_m 0:547c5459faa6 521
igor_m 0:547c5459faa6 522 return true;
igor_m 0:547c5459faa6 523 }
igor_m 0:547c5459faa6 524