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.
Dependencies: mbed FastIO FastPWM USBDevice
Diff: USBJoystick/USBJoystick.cpp
- Revision:
- 35:e959ffba78fd
- Parent:
- 33:d832bcab089e
- Child:
- 37:ed52738445fc
--- a/USBJoystick/USBJoystick.cpp Thu Dec 03 07:34:57 2015 +0000 +++ b/USBJoystick/USBJoystick.cpp Sat Dec 19 06:37:19 2015 +0000 @@ -22,11 +22,12 @@ #include "config.h" // Pinscape configuration + + // Length of our joystick reports. Important: This must be kept in sync // with the actual joystick report format sent in update(). const int reportLen = 14; -#ifdef ENABLE_JOYSTICK bool USBJoystick::update(int16_t x, int16_t y, int16_t z, uint32_t buttons, uint16_t status) { _x = x; @@ -39,7 +40,7 @@ // send the report return update(); } - + bool USBJoystick::update() { HID_REPORT report; @@ -62,6 +63,30 @@ return sendTO(&report, 100); } +bool USBJoystick::kbUpdate(uint8_t data[8]) +{ + // set up the report + HID_REPORT report; + report.data[0] = REPORT_ID_KB; // report ID = keyboard + memcpy(&report.data[1], data, 8); // copy the kb report data + report.length = 9; // length = ID prefix + kb report length + + // send it to endpoint 4 (the keyboard interface endpoint) + return writeTO(EP4IN, report.data, report.length, MAX_PACKET_SIZE_EPINT, 100); +} + +bool USBJoystick::mediaUpdate(uint8_t data) +{ + // set up the report + HID_REPORT report; + report.data[0] = REPORT_ID_MEDIA; // report ID = media + report.data[1] = data; // key pressed bits + report.length = 2; + + // send it + return writeTO(EP4IN, report.data, report.length, MAX_PACKET_SIZE_EPINT, 100); +} + bool USBJoystick::updateExposure(int &idx, int npix, const uint16_t *pix) { HID_REPORT report; @@ -91,10 +116,10 @@ } // send the report - return send(&report); + return sendTO(&report, 100); } -bool USBJoystick::reportConfig(int numOutputs, int unitNo) +bool USBJoystick::reportConfig(int numOutputs, int unitNo, int plungerZero, int plungerMax) { HID_REPORT report; @@ -111,9 +136,13 @@ // write the unit number put(4, unitNo); + // write the plunger zero and max values + put(6, plungerZero); + put(8, plungerMax); + // send the report report.length = reportLen; - return send(&report); + return sendTO(&report, 100); } bool USBJoystick::move(int16_t x, int16_t y) @@ -136,8 +165,6 @@ return update(); } -#else /* ENABLE_JOYSTICK */ - bool USBJoystick::updateStatus(uint32_t status) { HID_REPORT report; @@ -152,9 +179,6 @@ return sendTO(&report, 100); } -#endif /* ENABLE_JOYSTICK */ - - void USBJoystick::_init() { _x = 0; @@ -166,93 +190,183 @@ } -uint8_t * USBJoystick::reportDesc() -{ -#ifdef ENABLE_JOYSTICK - // Joystick reports are enabled. Use the full joystick report - // format. - static uint8_t reportDescriptor[] = - { - USAGE_PAGE(1), 0x01, // Generic desktop - USAGE(1), 0x04, // Joystick - COLLECTION(1), 0x01, // Application +// -------------------------------------------------------------------------- +// +// USB HID Report Descriptor - Joystick +// +static uint8_t reportDescriptorJS[] = +{ + USAGE_PAGE(1), 0x01, // Generic desktop + USAGE(1), 0x04, // Joystick + COLLECTION(1), 0x01, // Application + + // input report (device to host) + + USAGE_PAGE(1), 0x06, // generic device controls - for config status + USAGE(1), 0x00, // undefined device control + LOGICAL_MINIMUM(1), 0x00, // 8-bit values + LOGICAL_MAXIMUM(1), 0xFF, + REPORT_SIZE(1), 0x08, // 8 bits per report + REPORT_COUNT(1), 0x04, // 4 reports (4 bytes) + INPUT(1), 0x02, // Data, Variable, Absolute + + USAGE_PAGE(1), 0x09, // Buttons + USAGE_MINIMUM(1), 0x01, // { buttons } + USAGE_MAXIMUM(1), 0x20, // { 1-32 } + LOGICAL_MINIMUM(1), 0x00, // 1-bit buttons - 0... + LOGICAL_MAXIMUM(1), 0x01, // ...to 1 + REPORT_SIZE(1), 0x01, // 1 bit per report + REPORT_COUNT(1), 0x20, // 32 reports + UNIT_EXPONENT(1), 0x00, // Unit_Exponent (0) + UNIT(1), 0x00, // Unit (None) + INPUT(1), 0x02, // Data, Variable, Absolute + + USAGE_PAGE(1), 0x01, // Generic desktop + USAGE(1), 0x30, // X axis + USAGE(1), 0x31, // Y axis + USAGE(1), 0x32, // Z axis + LOGICAL_MINIMUM(2), 0x00,0xF0, // each value ranges -4096 + LOGICAL_MAXIMUM(2), 0x00,0x10, // ...to +4096 + REPORT_SIZE(1), 0x10, // 16 bits per report + REPORT_COUNT(1), 0x03, // 3 reports (X, Y, Z) + INPUT(1), 0x02, // Data, Variable, Absolute - // input report (device to host) + // output report (host to device) + REPORT_SIZE(1), 0x08, // 8 bits per report + REPORT_COUNT(1), 0x08, // output report count - 8-byte LedWiz format + 0x09, 0x01, // usage + 0x91, 0x01, // Output (array) + + END_COLLECTION(0) +}; + +// +// USB HID Report Descriptor - Keyboard/Media Control +// +static uint8_t reportDescriptorKB[] = +{ + USAGE_PAGE(1), 0x01, // Generic Desktop + USAGE(1), 0x06, // Keyboard + COLLECTION(1), 0x01, // Application + REPORT_ID(1), REPORT_ID_KB, - USAGE_PAGE(1), 0x06, // generic device controls - for config status - USAGE(1), 0x00, // undefined device control - LOGICAL_MINIMUM(1), 0x00, // 8-bit values - LOGICAL_MAXIMUM(1), 0xFF, - REPORT_SIZE(1), 0x08, // 8 bits per report - REPORT_COUNT(1), 0x04, // 4 reports (4 bytes) - INPUT(1), 0x02, // Data, Variable, Absolute + USAGE_PAGE(1), 0x07, // Key Codes + USAGE_MINIMUM(1), 0xE0, + USAGE_MAXIMUM(1), 0xE7, + LOGICAL_MINIMUM(1), 0x00, + LOGICAL_MAXIMUM(1), 0x01, + REPORT_SIZE(1), 0x01, + REPORT_COUNT(1), 0x08, + INPUT(1), 0x02, // Data, Variable, Absolute + REPORT_COUNT(1), 0x01, + REPORT_SIZE(1), 0x08, + INPUT(1), 0x01, // Constant + + REPORT_COUNT(1), 0x05, + REPORT_SIZE(1), 0x01, + USAGE_PAGE(1), 0x08, // LEDs + USAGE_MINIMUM(1), 0x01, + USAGE_MAXIMUM(1), 0x05, + OUTPUT(1), 0x02, // Data, Variable, Absolute + REPORT_COUNT(1), 0x01, + REPORT_SIZE(1), 0x03, + OUTPUT(1), 0x01, // Constant - USAGE_PAGE(1), 0x09, // Buttons - USAGE_MINIMUM(1), 0x01, // { buttons } - USAGE_MAXIMUM(1), 0x20, // { 1-32 } - LOGICAL_MINIMUM(1), 0x00, // 1-bit buttons - 0... - LOGICAL_MAXIMUM(1), 0x01, // ...to 1 - REPORT_SIZE(1), 0x01, // 1 bit per report - REPORT_COUNT(1), 0x20, // 32 reports - UNIT_EXPONENT(1), 0x00, // Unit_Exponent (0) - UNIT(1), 0x00, // Unit (None) - INPUT(1), 0x02, // Data, Variable, Absolute - - USAGE_PAGE(1), 0x01, // Generic desktop - USAGE(1), 0x30, // X axis - USAGE(1), 0x31, // Y axis - USAGE(1), 0x32, // Z axis - LOGICAL_MINIMUM(2), 0x00,0xF0, // each value ranges -4096 - LOGICAL_MAXIMUM(2), 0x00,0x10, // ...to +4096 - REPORT_SIZE(1), 0x10, // 16 bits per report - REPORT_COUNT(1), 0x03, // 3 reports (X, Y, Z) - INPUT(1), 0x02, // Data, Variable, Absolute - - // output report (host to device) - REPORT_SIZE(1), 0x08, // 8 bits per report - REPORT_COUNT(1), 0x08, // output report count - 8-byte LedWiz format - 0x09, 0x01, // usage - 0x91, 0x01, // Output (array) + REPORT_COUNT(1), 0x06, + REPORT_SIZE(1), 0x08, + LOGICAL_MINIMUM(1), 0x00, + LOGICAL_MAXIMUM(1), 0x65, + USAGE_PAGE(1), 0x07, // Key Codes + USAGE_MINIMUM(1), 0x00, + USAGE_MAXIMUM(1), 0x65, + INPUT(1), 0x00, // Data, Array + END_COLLECTION(0), - END_COLLECTION(0) + // Media Control + USAGE_PAGE(1), 0x0C, + USAGE(1), 0x01, + COLLECTION(1), 0x01, + REPORT_ID(1), REPORT_ID_MEDIA, + USAGE_PAGE(1), 0x0C, + LOGICAL_MINIMUM(1), 0x00, + LOGICAL_MAXIMUM(1), 0x01, + REPORT_SIZE(1), 0x01, + REPORT_COUNT(1), 0x07, + USAGE(1), 0xE9, // Volume Up + USAGE(1), 0xEA, // Volume Down + USAGE(1), 0xE2, // Mute + USAGE(1), 0xB5, // Next Track + USAGE(1), 0xB6, // Previous Track + USAGE(1), 0xB7, // Stop + USAGE(1), 0xCD, // Play / Pause + INPUT(1), 0x02, // Input (Data, Variable, Absolute) + REPORT_COUNT(1), 0x01, + INPUT(1), 0x01, + END_COLLECTION(0), +}; - }; -#else /* defined(ENABLE_JOYSTICK) */ +// +// USB HID Report Descriptor - LedWiz only, with no joystick or keyboard +// input reporting +// +static uint8_t reportDescriptorLW[] = +{ + USAGE_PAGE(1), 0x01, // Generic desktop + USAGE(1), 0x00, // Undefined - // Joystick reports are disabled. We still want to appear - // as a USB device for the LedWiz output emulation, but we - // don't want to appear as a joystick. + COLLECTION(1), 0x01, // Application - static uint8_t reportDescriptor[] = - { - USAGE_PAGE(1), 0x01, // Generic desktop - USAGE(1), 0x00, // Undefined + // input report (device to host) + USAGE_PAGE(1), 0x06, // generic device controls - for config status + USAGE(1), 0x00, // undefined device control + LOGICAL_MINIMUM(1), 0x00, // 8-bit values + LOGICAL_MAXIMUM(1), 0xFF, + REPORT_SIZE(1), 0x08, // 8 bits per report + REPORT_COUNT(1), reportLen, // standard report length (same as if we were in joystick mode) + INPUT(1), 0x02, // Data, Variable, Absolute + + // output report (host to device) + REPORT_SIZE(1), 0x08, // 8 bits per report + REPORT_COUNT(1), 0x08, // output report count (LEDWiz messages) + 0x09, 0x01, // usage + 0x91, 0x01, // Output (array) + + END_COLLECTION(0) +}; + - COLLECTION(1), 0x01, // Application - - // input report (device to host) - USAGE_PAGE(1), 0x06, // generic device controls - for config status - USAGE(1), 0x00, // undefined device control - LOGICAL_MINIMUM(1), 0x00, // 8-bit values - LOGICAL_MAXIMUM(1), 0xFF, - REPORT_SIZE(1), 0x08, // 8 bits per report - REPORT_COUNT(1), reportLen, // standard report length (same as if we were in joystick mode) - INPUT(1), 0x02, // Data, Variable, Absolute - - // output report (host to device) - REPORT_SIZE(1), 0x08, // 8 bits per report - REPORT_COUNT(1), 0x08, // output report count (LEDWiz messages) - 0x09, 0x01, // usage - 0x91, 0x01, // Output (array) - - END_COLLECTION(0) - }; - -#endif /* defined(ENABLE_JOYSTICK) */ - - reportLength = sizeof(reportDescriptor); - return reportDescriptor; -} +uint8_t * USBJoystick::reportDescN(int idx) +{ + if (enableJoystick) + { + // Joystick reports are enabled. Use the full joystick report + // format, or full keyboard report format, depending on which + // interface is being requested. + switch (idx) + { + case 0: + // joystick interface + reportLength = sizeof(reportDescriptorJS); + return reportDescriptorJS; + + case 1: + // keyboard interface + reportLength = sizeof(reportDescriptorKB); + return reportDescriptorKB; + + default: + // unknown interface + reportLength = 0; + return 0; + } + } + else + { + // Joystick reports are disabled. Use the LedWiz-only format. + reportLength = sizeof(reportDescriptorLW); + return reportDescriptorLW; + } +} uint8_t * USBJoystick::stringImanufacturerDesc() { static uint8_t stringImanufacturerDescriptor[] = { @@ -282,3 +396,206 @@ }; return stringIproductDescriptor; } + +#define DEFAULT_CONFIGURATION (1) + +uint8_t * USBJoystick::configurationDesc() +{ + int rptlen0 = reportDescLengthN(0); + int rptlen1 = reportDescLengthN(1); + if (useKB) + { + int cfglenKB = ((1 * CONFIGURATION_DESCRIPTOR_LENGTH) + + (2 * INTERFACE_DESCRIPTOR_LENGTH) + + (2 * HID_DESCRIPTOR_LENGTH) + + (4 * ENDPOINT_DESCRIPTOR_LENGTH)); + static uint8_t configurationDescriptorWithKB[] = + { + CONFIGURATION_DESCRIPTOR_LENGTH,// bLength + CONFIGURATION_DESCRIPTOR, // bDescriptorType + LSB(cfglenKB), // wTotalLength (LSB) + MSB(cfglenKB), // wTotalLength (MSB) + 0x02, // bNumInterfaces - TWO INTERFACES (JOYSTICK + KEYBOARD) + DEFAULT_CONFIGURATION, // bConfigurationValue + 0x00, // iConfiguration + C_RESERVED | C_SELF_POWERED, // bmAttributes + C_POWER(0), // bMaxPowerHello World from Mbed + + // INTERFACE 0 - JOYSTICK/LEDWIZ + INTERFACE_DESCRIPTOR_LENGTH, // bLength + INTERFACE_DESCRIPTOR, // bDescriptorType + 0x00, // bInterfaceNumber - first interface = 0 + 0x00, // bAlternateSetting + 0x02, // bNumEndpoints + HID_CLASS, // bInterfaceClass + HID_SUBCLASS_NONE, // bInterfaceSubClass + HID_PROTOCOL_NONE, // bInterfaceProtocol + 0x00, // iInterface + + HID_DESCRIPTOR_LENGTH, // bLength + HID_DESCRIPTOR, // bDescriptorType + LSB(HID_VERSION_1_11), // bcdHID (LSB) + MSB(HID_VERSION_1_11), // bcdHID (MSB) + 0x00, // bCountryCode + 0x01, // bNumDescriptors + REPORT_DESCRIPTOR, // bDescriptorType + LSB(rptlen0), // wDescriptorLength (LSB) + MSB(rptlen0), // wDescriptorLength (MSB) + + ENDPOINT_DESCRIPTOR_LENGTH, // bLength + ENDPOINT_DESCRIPTOR, // bDescriptorType + PHY_TO_DESC(EPINT_IN), // bEndpointAddress - EPINT == EP1 + E_INTERRUPT, // bmAttributes + LSB(MAX_PACKET_SIZE_EPINT), // wMaxPacketSize (LSB) + MSB(MAX_PACKET_SIZE_EPINT), // wMaxPacketSize (MSB) + 1, // bInterval (milliseconds) + + ENDPOINT_DESCRIPTOR_LENGTH, // bLength + ENDPOINT_DESCRIPTOR, // bDescriptorType + PHY_TO_DESC(EPINT_OUT), // bEndpointAddress - EPINT == EP1 + E_INTERRUPT, // bmAttributes + LSB(MAX_PACKET_SIZE_EPINT), // wMaxPacketSize (LSB) + MSB(MAX_PACKET_SIZE_EPINT), // wMaxPacketSize (MSB) + 1, // bInterval (milliseconds) + + // INTERFACE 1 - KEYBOARD + INTERFACE_DESCRIPTOR_LENGTH, // bLength + INTERFACE_DESCRIPTOR, // bDescriptorType + 0x01, // bInterfaceNumber - second interface = 1 + 0x00, // bAlternateSetting + 0x02, // bNumEndpoints + HID_CLASS, // bInterfaceClass + 1, // bInterfaceSubClass - KEYBOARD + 1, // bInterfaceProtocol - KEYBOARD + 0x00, // iInterface + + HID_DESCRIPTOR_LENGTH, // bLength + HID_DESCRIPTOR, // bDescriptorType + LSB(HID_VERSION_1_11), // bcdHID (LSB) + MSB(HID_VERSION_1_11), // bcdHID (MSB) + 0x00, // bCountryCode + 0x01, // bNumDescriptors + REPORT_DESCRIPTOR, // bDescriptorType + LSB(rptlen1), // wDescriptorLength (LSB) + MSB(rptlen1), // wDescriptorLength (MSB) + + ENDPOINT_DESCRIPTOR_LENGTH, // bLength + ENDPOINT_DESCRIPTOR, // bDescriptorType + PHY_TO_DESC(EP4IN), // bEndpointAddress + E_INTERRUPT, // bmAttributes + LSB(MAX_PACKET_SIZE_EPINT), // wMaxPacketSize (LSB) + MSB(MAX_PACKET_SIZE_EPINT), // wMaxPacketSize (MSB) + 1, // bInterval (milliseconds) + + ENDPOINT_DESCRIPTOR_LENGTH, // bLength + ENDPOINT_DESCRIPTOR, // bDescriptorType + PHY_TO_DESC(EP4OUT), // bEndpointAddress + E_INTERRUPT, // bmAttributes + LSB(MAX_PACKET_SIZE_EPINT), // wMaxPacketSize (LSB) + MSB(MAX_PACKET_SIZE_EPINT), // wMaxPacketSize (MSB) + 1, // bInterval (milliseconds) + }; + + // Keyboard + joystick interfaces + return configurationDescriptorWithKB; + } + else + { + // No keyboard - joystick interface only + int cfglenNoKB = ((1 * CONFIGURATION_DESCRIPTOR_LENGTH) + + (1 * INTERFACE_DESCRIPTOR_LENGTH) + + (1 * HID_DESCRIPTOR_LENGTH) + + (2 * ENDPOINT_DESCRIPTOR_LENGTH)); + static uint8_t configurationDescriptorNoKB[] = + { + CONFIGURATION_DESCRIPTOR_LENGTH,// bLength + CONFIGURATION_DESCRIPTOR, // bDescriptorType + LSB(cfglenNoKB), // wTotalLength (LSB) + MSB(cfglenNoKB), // wTotalLength (MSB) + 0x01, // bNumInterfaces + DEFAULT_CONFIGURATION, // bConfigurationValue + 0x00, // iConfiguration + C_RESERVED | C_SELF_POWERED, // bmAttributes + C_POWER(0), // bMaxPowerHello World from Mbed + + INTERFACE_DESCRIPTOR_LENGTH, // bLength + INTERFACE_DESCRIPTOR, // bDescriptorType + 0x00, // bInterfaceNumber + 0x00, // bAlternateSetting + 0x02, // bNumEndpoints + HID_CLASS, // bInterfaceClass + 1, // bInterfaceSubClass + 1, // bInterfaceProtocol (keyboard) + 0x00, // iInterface + + HID_DESCRIPTOR_LENGTH, // bLength + HID_DESCRIPTOR, // bDescriptorType + LSB(HID_VERSION_1_11), // bcdHID (LSB) + MSB(HID_VERSION_1_11), // bcdHID (MSB) + 0x00, // bCountryCode + 0x01, // bNumDescriptors + REPORT_DESCRIPTOR, // bDescriptorType + (uint8_t)(LSB(rptlen0)), // wDescriptorLength (LSB) + (uint8_t)(MSB(rptlen0)), // wDescriptorLength (MSB) + + ENDPOINT_DESCRIPTOR_LENGTH, // bLength + ENDPOINT_DESCRIPTOR, // bDescriptorType + PHY_TO_DESC(EPINT_IN), // bEndpointAddress + E_INTERRUPT, // bmAttributes + LSB(MAX_PACKET_SIZE_EPINT), // wMaxPacketSize (LSB) + MSB(MAX_PACKET_SIZE_EPINT), // wMaxPacketSize (MSB) + 1, // bInterval (milliseconds) + + ENDPOINT_DESCRIPTOR_LENGTH, // bLength + ENDPOINT_DESCRIPTOR, // bDescriptorType + PHY_TO_DESC(EPINT_OUT), // bEndpointAddress + E_INTERRUPT, // bmAttributes + LSB(MAX_PACKET_SIZE_EPINT), // wMaxPacketSize (LSB) + MSB(MAX_PACKET_SIZE_EPINT), // wMaxPacketSize (MSB) + 1, // bInterval (milliseconds) + }; + + return configurationDescriptorNoKB; + } +} + +// Set the configuration. We need to set up the endpoints for +// our active interfaces. +bool USBJoystick::USBCallback_setConfiguration(uint8_t configuration) +{ + // we only have one valid configuration + if (configuration != DEFAULT_CONFIGURATION) + return false; + + // Configure endpoint 1 - we use this in all cases, for either + // the combined joystick/ledwiz interface or just the ledwiz interface + addEndpoint(EPINT_IN, MAX_PACKET_SIZE_EPINT); + addEndpoint(EPINT_OUT, MAX_PACKET_SIZE_EPINT); + readStart(EPINT_OUT, MAX_HID_REPORT_SIZE); + + // if the keyboard is enabled, configure endpoint 4 for the kb interface + if (useKB) + { + addEndpoint(EP4IN, MAX_PACKET_SIZE_EPINT); + addEndpoint(EP4OUT, MAX_PACKET_SIZE_EPINT); + readStart(EP4OUT, MAX_PACKET_SIZE_EPINT); + } + + // success + return true; +} + +// Handle messages on endpoint 4 - this is the keyboard interface. +// The host uses this to send updates for the keyboard indicator LEDs +// (caps lock, num lock, etc). We don't do anything with these, but +// we at least need to read them to keep the pipe from clogging up. +bool USBJoystick::EP4_OUT_callback() +{ + // read this message + uint32_t bytesRead = 0; + uint8_t led[65]; + USBDevice::readEP(EP4OUT, led, &bytesRead, MAX_HID_REPORT_SIZE); + + // start the next read + return readStart(EP4OUT, MAX_HID_REPORT_SIZE); +}