diff --git a/libraries/ArduinoJoystickLibrary/src/DynamicHID.cpp b/libraries/ArduinoJoystickLibrary/src/DynamicHID.cpp new file mode 100644 index 0000000..6c46a2c --- /dev/null +++ b/libraries/ArduinoJoystickLibrary/src/DynamicHID.cpp @@ -0,0 +1,169 @@ +/* + Modified by Matthew Heironimus to support HID Report Descriptors to be in + standard RAM in addition to program memory (PROGMEM). + + Copyright (c) 2015, Arduino LLC + Original code (pre-library): Copyright (c) 2011, Peter Barrett + + Permission to use, copy, modify, and/or distribute this software for + any purpose with or without fee is hereby granted, provided that the + above copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR + BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES + OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + SOFTWARE. + */ + +#include "DynamicHID.h" + +#if defined(USBCON) + +#ifdef _VARIANT_ARDUINO_DUE_X_ +#define USB_SendControl USBD_SendControl +#define USB_Send USBD_Send +#endif + +DynamicHID_& DynamicHID() +{ + static DynamicHID_ obj; + return obj; +} + +int DynamicHID_::getInterface(uint8_t* interfaceCount) +{ + *interfaceCount += 1; // uses 1 + DYNAMIC_HIDDescriptor hidInterface = { + D_INTERFACE(pluggedInterface, 1, USB_DEVICE_CLASS_HUMAN_INTERFACE, DYNAMIC_HID_SUBCLASS_NONE, DYNAMIC_HID_PROTOCOL_NONE), + D_HIDREPORT(descriptorSize), + D_ENDPOINT(USB_ENDPOINT_IN(pluggedEndpoint), USB_ENDPOINT_TYPE_INTERRUPT, USB_EP_SIZE, 0x01) + }; + return USB_SendControl(0, &hidInterface, sizeof(hidInterface)); +} + +int DynamicHID_::getDescriptor(USBSetup& setup) +{ + // Check if this is a HID Class Descriptor request + if (setup.bmRequestType != REQUEST_DEVICETOHOST_STANDARD_INTERFACE) { return 0; } + if (setup.wValueH != DYNAMIC_HID_REPORT_DESCRIPTOR_TYPE) { return 0; } + + // In a HID Class Descriptor wIndex cointains the interface number + if (setup.wIndex != pluggedInterface) { return 0; } + + int total = 0; + DynamicHIDSubDescriptor* node; + for (node = rootNode; node; node = node->next) { + int res = USB_SendControl((node->inProgMem ? TRANSFER_PGM : 0), node->data, node->length); + if (res == -1) + return -1; + total += res; + } + + // Reset the protocol on reenumeration. Normally the host should not assume the state of the protocol + // due to the USB specs, but Windows and Linux just assumes its in report mode. + protocol = DYNAMIC_HID_REPORT_PROTOCOL; + + return total; +} + +uint8_t DynamicHID_::getShortName(char *name) +{ + name[0] = 'H'; + name[1] = 'I'; + name[2] = 'D'; + name[3] = 'A' + (descriptorSize & 0x0F); + name[4] = 'A' + ((descriptorSize >> 4) & 0x0F); + return 5; +} + +void DynamicHID_::AppendDescriptor(DynamicHIDSubDescriptor *node) +{ + if (!rootNode) { + rootNode = node; + } else { + DynamicHIDSubDescriptor *current = rootNode; + while (current->next) { + current = current->next; + } + current->next = node; + } + descriptorSize += node->length; +} + +int DynamicHID_::SendReport(uint8_t id, const void* data, int len) +{ + uint8_t p[len + 1]; + p[0] = id; + memcpy(&p[1], data, len); + return USB_Send(pluggedEndpoint | TRANSFER_RELEASE, p, len + 1); +} + +bool DynamicHID_::setup(USBSetup& setup) +{ + if (pluggedInterface != setup.wIndex) { + return false; + } + + uint8_t request = setup.bRequest; + uint8_t requestType = setup.bmRequestType; + + if (requestType == REQUEST_DEVICETOHOST_CLASS_INTERFACE) + { + if (request == DYNAMIC_HID_GET_REPORT) { + // TODO: DYNAMIC_HID_GetReport(); + return true; + } + if (request == DYNAMIC_HID_GET_PROTOCOL) { + // TODO: Send8(protocol); + return true; + } + if (request == DYNAMIC_HID_GET_IDLE) { + // TODO: Send8(idle); + } + } + + if (requestType == REQUEST_HOSTTODEVICE_CLASS_INTERFACE) + { + if (request == DYNAMIC_HID_SET_PROTOCOL) { + // The USB Host tells us if we are in boot or report mode. + // This only works with a real boot compatible device. + protocol = setup.wValueL; + return true; + } + if (request == DYNAMIC_HID_SET_IDLE) { + idle = setup.wValueL; + return true; + } + if (request == DYNAMIC_HID_SET_REPORT) + { + //uint8_t reportID = setup.wValueL; + //uint16_t length = setup.wLength; + //uint8_t data[length]; + // Make sure to not read more data than USB_EP_SIZE. + // You can read multiple times through a loop. + // The first byte (may!) contain the reportID on a multreport. + //USB_RecvControl(data, length); + } + } + + return false; +} + +DynamicHID_::DynamicHID_(void) : PluggableUSBModule(1, 1, epType), + rootNode(NULL), descriptorSize(0), + protocol(DYNAMIC_HID_REPORT_PROTOCOL), idle(1) +{ + epType[0] = EP_TYPE_INTERRUPT_IN; + PluggableUSB().plug(this); +} + +int DynamicHID_::begin(void) +{ + return 0; +} + +#endif /* if defined(USBCON) */ diff --git a/libraries/ArduinoJoystickLibrary/src/DynamicHID.h b/libraries/ArduinoJoystickLibrary/src/DynamicHID.h new file mode 100644 index 0000000..0a9a6ef --- /dev/null +++ b/libraries/ArduinoJoystickLibrary/src/DynamicHID.h @@ -0,0 +1,144 @@ +/* + Modified by Matthew Heironimus to support HID Report Descriptors to be in + standard RAM in addition to program memory (PROGMEM). + + Copyright (c) 2015, Arduino LLC + Original code (pre-library): Copyright (c) 2011, Peter Barrett + + Permission to use, copy, modify, and/or distribute this software for + any purpose with or without fee is hereby granted, provided that the + above copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR + BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES + OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + SOFTWARE. + */ + +#ifndef DYNAMIC_HID_h +#define DYNAMIC_HID_h + +#include +#include + +#ifdef _VARIANT_ARDUINO_DUE_X_ + // The following values are the same as AVR's USBAPI.h + // Reproduced here because SAM doesn't have these in + // its own USBAPI.H + #define USB_EP_SIZE 64 + #define TRANSFER_PGM 0x80 + + #include "USB/PluggableUSB.h" +#else + #include "PluggableUSB.h" +#endif + +#if defined(USBCON) + +#define _USING_DYNAMIC_HID + +// DYNAMIC_HID 'Driver' +// ------------ +#define DYNAMIC_HID_GET_REPORT 0x01 +#define DYNAMIC_HID_GET_IDLE 0x02 +#define DYNAMIC_HID_GET_PROTOCOL 0x03 +#define DYNAMIC_HID_SET_REPORT 0x09 +#define DYNAMIC_HID_SET_IDLE 0x0A +#define DYNAMIC_HID_SET_PROTOCOL 0x0B + +#define DYNAMIC_HID_DESCRIPTOR_TYPE 0x21 +#define DYNAMIC_HID_REPORT_DESCRIPTOR_TYPE 0x22 +#define DYNAMIC_HID_PHYSICAL_DESCRIPTOR_TYPE 0x23 + +// HID subclass HID1.11 Page 8 4.2 Subclass +#define DYNAMIC_HID_SUBCLASS_NONE 0 +#define DYNAMIC_HID_SUBCLASS_BOOT_INTERFACE 1 + +// HID Keyboard/Mouse bios compatible protocols HID1.11 Page 9 4.3 Protocols +#define DYNAMIC_HID_PROTOCOL_NONE 0 +#define DYNAMIC_HID_PROTOCOL_KEYBOARD 1 +#define DYNAMIC_HID_PROTOCOL_MOUSE 2 + +// Normal or bios protocol (Keyboard/Mouse) HID1.11 Page 54 7.2.5 Get_Protocol Request +// "protocol" variable is used for this purpose. +#define DYNAMIC_HID_BOOT_PROTOCOL 0 +#define DYNAMIC_HID_REPORT_PROTOCOL 1 + +// HID Request Type HID1.11 Page 51 7.2.1 Get_Report Request +#define DYNAMIC_HID_REPORT_TYPE_INPUT 1 +#define DYNAMIC_HID_REPORT_TYPE_OUTPUT 2 +#define DYNAMIC_HID_REPORT_TYPE_FEATURE 3 + +typedef struct +{ + uint8_t len; // 9 + uint8_t dtype; // 0x21 + uint8_t addr; + uint8_t versionL; // 0x101 + uint8_t versionH; // 0x101 + uint8_t country; + uint8_t desctype; // 0x22 report + uint8_t descLenL; + uint8_t descLenH; +} DYNAMIC_HIDDescDescriptor; + +typedef struct +{ + InterfaceDescriptor hid; + DYNAMIC_HIDDescDescriptor desc; + EndpointDescriptor in; +} DYNAMIC_HIDDescriptor; + +class DynamicHIDSubDescriptor { +public: + DynamicHIDSubDescriptor *next = NULL; + DynamicHIDSubDescriptor(const void *d, const uint16_t l, const bool ipm = true) : data(d), length(l), inProgMem(ipm) { } + + const void* data; + const uint16_t length; + const bool inProgMem; +}; + +class DynamicHID_ : public PluggableUSBModule +{ +public: + DynamicHID_(void); + int begin(void); + int SendReport(uint8_t id, const void* data, int len); + void AppendDescriptor(DynamicHIDSubDescriptor* node); + +protected: + // Implementation of the PluggableUSBModule + int getInterface(uint8_t* interfaceCount); + int getDescriptor(USBSetup& setup); + bool setup(USBSetup& setup); + uint8_t getShortName(char* name); + +private: + #ifdef _VARIANT_ARDUINO_DUE_X_ + uint32_t epType[1]; + #else + uint8_t epType[1]; + #endif + + DynamicHIDSubDescriptor* rootNode; + uint16_t descriptorSize; + + uint8_t protocol; + uint8_t idle; +}; + +// Replacement for global singleton. +// This function prevents static-initialization-order-fiasco +// https://isocpp.org/wiki/faq/ctors#static-init-order-on-first-use +DynamicHID_& DynamicHID(); + +#define D_HIDREPORT(length) { 9, 0x21, 0x01, 0x01, 0, 1, 0x22, lowByte(length), highByte(length) } + +#endif // USBCON + +#endif // DYNAMIC_HID_h diff --git a/libraries/ArduinoJoystickLibrary/src/Joystick.cpp b/libraries/ArduinoJoystickLibrary/src/Joystick.cpp new file mode 100644 index 0000000..c91841c --- /dev/null +++ b/libraries/ArduinoJoystickLibrary/src/Joystick.cpp @@ -0,0 +1,682 @@ +/* + Joystick.cpp + + Copyright (c) 2015-2017, Matthew Heironimus + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "Joystick.h" + +#if defined(_USING_DYNAMIC_HID) + +#define JOYSTICK_REPORT_ID_INDEX 7 +#define JOYSTICK_AXIS_MINIMUM 0 +#define JOYSTICK_AXIS_MAXIMUM 65535 +#define JOYSTICK_SIMULATOR_MINIMUM 0 +#define JOYSTICK_SIMULATOR_MAXIMUM 65535 + +#define JOYSTICK_INCLUDE_X_AXIS B00000001 +#define JOYSTICK_INCLUDE_Y_AXIS B00000010 +#define JOYSTICK_INCLUDE_Z_AXIS B00000100 +#define JOYSTICK_INCLUDE_RX_AXIS B00001000 +#define JOYSTICK_INCLUDE_RY_AXIS B00010000 +#define JOYSTICK_INCLUDE_RZ_AXIS B00100000 + +#define JOYSTICK_INCLUDE_RUDDER B00000001 +#define JOYSTICK_INCLUDE_THROTTLE B00000010 +#define JOYSTICK_INCLUDE_ACCELERATOR B00000100 +#define JOYSTICK_INCLUDE_BRAKE B00001000 +#define JOYSTICK_INCLUDE_STEERING B00010000 + +Joystick_::Joystick_( + uint8_t hidReportId, + uint8_t joystickType, + uint8_t buttonCount, + uint8_t hatSwitchCount, + bool includeXAxis, + bool includeYAxis, + bool includeZAxis, + bool includeRxAxis, + bool includeRyAxis, + bool includeRzAxis, + bool includeRudder, + bool includeThrottle, + bool includeAccelerator, + bool includeBrake, + bool includeSteering) +{ + // Set the USB HID Report ID + _hidReportId = hidReportId; + + // Save Joystick Settings + _buttonCount = buttonCount; + _hatSwitchCount = hatSwitchCount; + _includeAxisFlags = 0; + _includeAxisFlags |= (includeXAxis ? JOYSTICK_INCLUDE_X_AXIS : 0); + _includeAxisFlags |= (includeYAxis ? JOYSTICK_INCLUDE_Y_AXIS : 0); + _includeAxisFlags |= (includeZAxis ? JOYSTICK_INCLUDE_Z_AXIS : 0); + _includeAxisFlags |= (includeRxAxis ? JOYSTICK_INCLUDE_RX_AXIS : 0); + _includeAxisFlags |= (includeRyAxis ? JOYSTICK_INCLUDE_RY_AXIS : 0); + _includeAxisFlags |= (includeRzAxis ? JOYSTICK_INCLUDE_RZ_AXIS : 0); + _includeSimulatorFlags = 0; + _includeSimulatorFlags |= (includeRudder ? JOYSTICK_INCLUDE_RUDDER : 0); + _includeSimulatorFlags |= (includeThrottle ? JOYSTICK_INCLUDE_THROTTLE : 0); + _includeSimulatorFlags |= (includeAccelerator ? JOYSTICK_INCLUDE_ACCELERATOR : 0); + _includeSimulatorFlags |= (includeBrake ? JOYSTICK_INCLUDE_BRAKE : 0); + _includeSimulatorFlags |= (includeSteering ? JOYSTICK_INCLUDE_STEERING : 0); + + // Build Joystick HID Report Description + + // Button Calculations + uint8_t buttonsInLastByte = _buttonCount % 8; + uint8_t buttonPaddingBits = 0; + if (buttonsInLastByte > 0) + { + buttonPaddingBits = 8 - buttonsInLastByte; + } + + // Axis Calculations + uint8_t axisCount = (includeXAxis == true) + + (includeYAxis == true) + + (includeZAxis == true) + + (includeRxAxis == true) + + (includeRyAxis == true) + + (includeRzAxis == true); + + uint8_t simulationCount = (includeRudder == true) + + (includeThrottle == true) + + (includeAccelerator == true) + + (includeBrake == true) + + (includeSteering == true); + + uint8_t tempHidReportDescriptor[150]; + int hidReportDescriptorSize = 0; + + // USAGE_PAGE (Generic Desktop) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x05; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x01; + + // USAGE (Joystick - 0x04; Gamepad - 0x05; Multi-axis Controller - 0x08) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x09; + tempHidReportDescriptor[hidReportDescriptorSize++] = joystickType; + + // COLLECTION (Application) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0xa1; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x01; + + // REPORT_ID (Default: 3) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x85; + tempHidReportDescriptor[hidReportDescriptorSize++] = _hidReportId; + + if (_buttonCount > 0) { + + // USAGE_PAGE (Button) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x05; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x09; + + // USAGE_MINIMUM (Button 1) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x19; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x01; + + // USAGE_MAXIMUM (Button 32) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x29; + tempHidReportDescriptor[hidReportDescriptorSize++] = _buttonCount; + + // LOGICAL_MINIMUM (0) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x15; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x00; + + // LOGICAL_MAXIMUM (1) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x25; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x01; + + // REPORT_SIZE (1) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x75; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x01; + + // REPORT_COUNT (# of buttons) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x95; + tempHidReportDescriptor[hidReportDescriptorSize++] = _buttonCount; + + // UNIT_EXPONENT (0) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x55; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x00; + + // UNIT (None) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x65; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x00; + + // INPUT (Data,Var,Abs) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x81; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x02; + + if (buttonPaddingBits > 0) { + + // REPORT_SIZE (1) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x75; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x01; + + // REPORT_COUNT (# of padding bits) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x95; + tempHidReportDescriptor[hidReportDescriptorSize++] = buttonPaddingBits; + + // INPUT (Const,Var,Abs) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x81; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x03; + + } // Padding Bits Needed + + } // Buttons + + if ((axisCount > 0) || (_hatSwitchCount > 0)) { + + // USAGE_PAGE (Generic Desktop) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x05; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x01; + + } + + if (_hatSwitchCount > 0) { + + // USAGE (Hat Switch) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x09; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x39; + + // LOGICAL_MINIMUM (0) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x15; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x00; + + // LOGICAL_MAXIMUM (7) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x25; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x07; + + // PHYSICAL_MINIMUM (0) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x35; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x00; + + // PHYSICAL_MAXIMUM (315) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x46; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x3B; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x01; + + // UNIT (Eng Rot:Angular Pos) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x65; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x14; + + // REPORT_SIZE (4) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x75; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x04; + + // REPORT_COUNT (1) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x95; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x01; + + // INPUT (Data,Var,Abs) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x81; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x02; + + if (_hatSwitchCount > 1) { + + // USAGE (Hat Switch) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x09; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x39; + + // LOGICAL_MINIMUM (0) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x15; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x00; + + // LOGICAL_MAXIMUM (7) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x25; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x07; + + // PHYSICAL_MINIMUM (0) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x35; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x00; + + // PHYSICAL_MAXIMUM (315) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x46; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x3B; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x01; + + // UNIT (Eng Rot:Angular Pos) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x65; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x14; + + // REPORT_SIZE (4) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x75; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x04; + + // REPORT_COUNT (1) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x95; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x01; + + // INPUT (Data,Var,Abs) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x81; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x02; + + } else { + + // Use Padding Bits + + // REPORT_SIZE (1) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x75; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x01; + + // REPORT_COUNT (4) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x95; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x04; + + // INPUT (Const,Var,Abs) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x81; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x03; + + } // One or Two Hat Switches? + + } // Hat Switches + + if (axisCount > 0) { + + // USAGE (Pointer) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x09; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x01; + + // LOGICAL_MINIMUM (0) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x15; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x00; + + // LOGICAL_MAXIMUM (65535) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x27; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0XFF; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0XFF; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x00; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x00; + + // REPORT_SIZE (16) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x75; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x10; + + // REPORT_COUNT (axisCount) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x95; + tempHidReportDescriptor[hidReportDescriptorSize++] = axisCount; + + // COLLECTION (Physical) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0xA1; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x00; + + if (includeXAxis == true) { + // USAGE (X) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x09; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x30; + } + + if (includeYAxis == true) { + // USAGE (Y) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x09; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x31; + } + + if (includeZAxis == true) { + // USAGE (Z) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x09; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x32; + } + + if (includeRxAxis == true) { + // USAGE (Rx) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x09; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x33; + } + + if (includeRyAxis == true) { + // USAGE (Ry) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x09; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x34; + } + + if (includeRzAxis == true) { + // USAGE (Rz) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x09; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x35; + } + + // INPUT (Data,Var,Abs) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x81; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x02; + + // END_COLLECTION (Physical) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0xc0; + + } // X, Y, Z, Rx, Ry, and Rz Axis + + if (simulationCount > 0) { + + // USAGE_PAGE (Simulation Controls) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x05; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x02; + + // LOGICAL_MINIMUM (0) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x15; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x00; + + // LOGICAL_MAXIMUM (65535) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x27; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0XFF; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0XFF; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x00; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x00; + + // REPORT_SIZE (16) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x75; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x10; + + // REPORT_COUNT (simulationCount) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x95; + tempHidReportDescriptor[hidReportDescriptorSize++] = simulationCount; + + // COLLECTION (Physical) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0xA1; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x00; + + if (includeRudder == true) { + // USAGE (Rudder) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x09; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0xBA; + } + + if (includeThrottle == true) { + // USAGE (Throttle) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x09; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0xBB; + } + + if (includeAccelerator == true) { + // USAGE (Accelerator) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x09; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0xC4; + } + + if (includeBrake == true) { + // USAGE (Brake) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x09; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0xC5; + } + + if (includeSteering == true) { + // USAGE (Steering) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x09; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0xC8; + } + + // INPUT (Data,Var,Abs) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x81; + tempHidReportDescriptor[hidReportDescriptorSize++] = 0x02; + + // END_COLLECTION (Physical) + tempHidReportDescriptor[hidReportDescriptorSize++] = 0xc0; + + } // Simulation Controls + + // END_COLLECTION + tempHidReportDescriptor[hidReportDescriptorSize++] = 0xc0; + + // Create a copy of the HID Report Descriptor template that is just the right size + uint8_t *customHidReportDescriptor = new uint8_t[hidReportDescriptorSize]; + memcpy(customHidReportDescriptor, tempHidReportDescriptor, hidReportDescriptorSize); + + // Register HID Report Description + DynamicHIDSubDescriptor *node = new DynamicHIDSubDescriptor(customHidReportDescriptor, hidReportDescriptorSize, false); + DynamicHID().AppendDescriptor(node); + + // Setup Joystick State + if (buttonCount > 0) { + _buttonValuesArraySize = _buttonCount / 8; + if ((_buttonCount % 8) > 0) { + _buttonValuesArraySize++; + } + _buttonValues = new uint8_t[_buttonValuesArraySize]; + } + + // Calculate HID Report Size + _hidReportSize = _buttonValuesArraySize; + _hidReportSize += (_hatSwitchCount > 0); + _hidReportSize += (axisCount * 2); + _hidReportSize += (simulationCount * 2); + + // Initialize Joystick State + _xAxis = 0; + _yAxis = 0; + _zAxis = 0; + _xAxisRotation = 0; + _yAxisRotation = 0; + _zAxisRotation = 0; + _throttle = 0; + _rudder = 0; + _accelerator = 0; + _brake = 0; + _steering = 0; + for (int index = 0; index < JOYSTICK_HATSWITCH_COUNT_MAXIMUM; index++) + { + _hatSwitchValues[index] = JOYSTICK_HATSWITCH_RELEASE; + } + for (int index = 0; index < _buttonValuesArraySize; index++) + { + _buttonValues[index] = 0; + } +} + +void Joystick_::begin(bool initAutoSendState) +{ + _autoSendState = initAutoSendState; + sendState(); +} + +void Joystick_::end() +{ +} + +void Joystick_::setButton(uint8_t button, uint8_t value) +{ + if (value == 0) + { + releaseButton(button); + } + else + { + pressButton(button); + } +} +void Joystick_::pressButton(uint8_t button) +{ + if (button >= _buttonCount) return; + + int index = button / 8; + int bit = button % 8; + + bitSet(_buttonValues[index], bit); + if (_autoSendState) sendState(); +} +void Joystick_::releaseButton(uint8_t button) +{ + if (button >= _buttonCount) return; + + int index = button / 8; + int bit = button % 8; + + bitClear(_buttonValues[index], bit); + if (_autoSendState) sendState(); +} + +void Joystick_::setXAxis(int32_t value) +{ + _xAxis = value; + if (_autoSendState) sendState(); +} +void Joystick_::setYAxis(int32_t value) +{ + _yAxis = value; + if (_autoSendState) sendState(); +} +void Joystick_::setZAxis(int32_t value) +{ + _zAxis = value; + if (_autoSendState) sendState(); +} + +void Joystick_::setRxAxis(int32_t value) +{ + _xAxisRotation = value; + if (_autoSendState) sendState(); +} +void Joystick_::setRyAxis(int32_t value) +{ + _yAxisRotation = value; + if (_autoSendState) sendState(); +} +void Joystick_::setRzAxis(int32_t value) +{ + _zAxisRotation = value; + if (_autoSendState) sendState(); +} + +void Joystick_::setRudder(int32_t value) +{ + _rudder = value; + if (_autoSendState) sendState(); +} +void Joystick_::setThrottle(int32_t value) +{ + _throttle = value; + if (_autoSendState) sendState(); +} +void Joystick_::setAccelerator(int32_t value) +{ + _accelerator = value; + if (_autoSendState) sendState(); +} +void Joystick_::setBrake(int32_t value) +{ + _brake = value; + if (_autoSendState) sendState(); +} +void Joystick_::setSteering(int32_t value) +{ + _steering = value; + if (_autoSendState) sendState(); +} + +void Joystick_::setHatSwitch(int8_t hatSwitchIndex, int16_t value) +{ + if (hatSwitchIndex >= _hatSwitchCount) return; + + _hatSwitchValues[hatSwitchIndex] = value; + if (_autoSendState) sendState(); +} + +int Joystick_::buildAndSet16BitValue(bool includeValue, int32_t value, int32_t valueMinimum, int32_t valueMaximum, int32_t actualMinimum, int32_t actualMaximum, uint8_t dataLocation[]) +{ + int32_t convertedValue; + uint8_t highByte; + uint8_t lowByte; + int32_t realMinimum = min(valueMinimum, valueMaximum); + int32_t realMaximum = max(valueMinimum, valueMaximum); + + if (includeValue == false) return 0; + + if (value < realMinimum) { + value = realMinimum; + } + if (value > realMaximum) { + value = realMaximum; + } + + if (valueMinimum > valueMaximum) { + // Values go from a larger number to a smaller number (e.g. 1024 to 0) + value = realMaximum - value + realMinimum; + } + + convertedValue = map(value, realMinimum, realMaximum, actualMinimum, actualMaximum); + + highByte = (uint8_t)(convertedValue >> 8); + lowByte = (uint8_t)(convertedValue & 0x00FF); + + dataLocation[0] = lowByte; + dataLocation[1] = highByte; + + return 2; +} + +int Joystick_::buildAndSetAxisValue(bool includeAxis, int32_t axisValue, int32_t axisMinimum, int32_t axisMaximum, uint8_t dataLocation[]) +{ + return buildAndSet16BitValue(includeAxis, axisValue, axisMinimum, axisMaximum, JOYSTICK_AXIS_MINIMUM, JOYSTICK_AXIS_MAXIMUM, dataLocation); +} + +int Joystick_::buildAndSetSimulationValue(bool includeValue, int32_t value, int32_t valueMinimum, int32_t valueMaximum, uint8_t dataLocation[]) +{ + return buildAndSet16BitValue(includeValue, value, valueMinimum, valueMaximum, JOYSTICK_SIMULATOR_MINIMUM, JOYSTICK_SIMULATOR_MAXIMUM, dataLocation); +} + +void Joystick_::sendState() +{ + uint8_t data[_hidReportSize]; + int index = 0; + + // Load Button State + for (; index < _buttonValuesArraySize; index++) + { + data[index] = _buttonValues[index]; + } + + // Set Hat Switch Values + if (_hatSwitchCount > 0) { + + // Calculate hat-switch values + uint8_t convertedHatSwitch[JOYSTICK_HATSWITCH_COUNT_MAXIMUM]; + for (int hatSwitchIndex = 0; hatSwitchIndex < JOYSTICK_HATSWITCH_COUNT_MAXIMUM; hatSwitchIndex++) + { + if (_hatSwitchValues[hatSwitchIndex] < 0) + { + convertedHatSwitch[hatSwitchIndex] = 8; + } + else + { + convertedHatSwitch[hatSwitchIndex] = (_hatSwitchValues[hatSwitchIndex] % 360) / 45; + } + } + + // Pack hat-switch states into a single byte + data[index++] = (convertedHatSwitch[1] << 4) | (B00001111 & convertedHatSwitch[0]); + + } // Hat Switches + + // Set Axis Values + index += buildAndSetAxisValue(_includeAxisFlags & JOYSTICK_INCLUDE_X_AXIS, _xAxis, _xAxisMinimum, _xAxisMaximum, &(data[index])); + index += buildAndSetAxisValue(_includeAxisFlags & JOYSTICK_INCLUDE_Y_AXIS, _yAxis, _yAxisMinimum, _yAxisMaximum, &(data[index])); + index += buildAndSetAxisValue(_includeAxisFlags & JOYSTICK_INCLUDE_Z_AXIS, _zAxis, _zAxisMinimum, _zAxisMaximum, &(data[index])); + index += buildAndSetAxisValue(_includeAxisFlags & JOYSTICK_INCLUDE_RX_AXIS, _xAxisRotation, _rxAxisMinimum, _rxAxisMaximum, &(data[index])); + index += buildAndSetAxisValue(_includeAxisFlags & JOYSTICK_INCLUDE_RY_AXIS, _yAxisRotation, _ryAxisMinimum, _ryAxisMaximum, &(data[index])); + index += buildAndSetAxisValue(_includeAxisFlags & JOYSTICK_INCLUDE_RZ_AXIS, _zAxisRotation, _rzAxisMinimum, _rzAxisMaximum, &(data[index])); + + // Set Simulation Values + index += buildAndSetSimulationValue(_includeSimulatorFlags & JOYSTICK_INCLUDE_RUDDER, _rudder, _rudderMinimum, _rudderMaximum, &(data[index])); + index += buildAndSetSimulationValue(_includeSimulatorFlags & JOYSTICK_INCLUDE_THROTTLE, _throttle, _throttleMinimum, _throttleMaximum, &(data[index])); + index += buildAndSetSimulationValue(_includeSimulatorFlags & JOYSTICK_INCLUDE_ACCELERATOR, _accelerator, _acceleratorMinimum, _acceleratorMaximum, &(data[index])); + index += buildAndSetSimulationValue(_includeSimulatorFlags & JOYSTICK_INCLUDE_BRAKE, _brake, _brakeMinimum, _brakeMaximum, &(data[index])); + index += buildAndSetSimulationValue(_includeSimulatorFlags & JOYSTICK_INCLUDE_STEERING, _steering, _steeringMinimum, _steeringMaximum, &(data[index])); + + DynamicHID().SendReport(_hidReportId, data, _hidReportSize); +} + +#endif diff --git a/libraries/ArduinoJoystickLibrary/src/Joystick.h b/libraries/ArduinoJoystickLibrary/src/Joystick.h new file mode 100644 index 0000000..de4900b --- /dev/null +++ b/libraries/ArduinoJoystickLibrary/src/Joystick.h @@ -0,0 +1,218 @@ +/* + Joystick.h + + Copyright (c) 2015-2017, Matthew Heironimus + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef JOYSTICK_h +#define JOYSTICK_h + +#include "DynamicHID/DynamicHID.h" + +#if ARDUINO < 10606 +#error The Joystick library requires Arduino IDE 1.6.6 or greater. Please update your IDE. +#endif // ARDUINO < 10606 + +#if ARDUINO > 10606 +#if !defined(USBCON) +#error The Joystick library can only be used with a USB MCU (e.g. Arduino Leonardo, Arduino Micro, etc.). +#endif // !defined(USBCON) +#endif // ARDUINO > 10606 + +#if !defined(_USING_DYNAMIC_HID) + +#warning "Using legacy HID core (non pluggable)" + +#else // !defined(_USING_DYNAMIC_HID) + +//================================================================================ +// Joystick (Gamepad) + +#define JOYSTICK_DEFAULT_REPORT_ID 0x03 +#define JOYSTICK_DEFAULT_BUTTON_COUNT 32 +#define JOYSTICK_DEFAULT_AXIS_MINIMUM 0 +#define JOYSTICK_DEFAULT_AXIS_MAXIMUM 1023 +#define JOYSTICK_DEFAULT_SIMULATOR_MINIMUM 0 +#define JOYSTICK_DEFAULT_SIMULATOR_MAXIMUM 1023 +#define JOYSTICK_DEFAULT_HATSWITCH_COUNT 2 +#define JOYSTICK_HATSWITCH_COUNT_MAXIMUM 2 +#define JOYSTICK_HATSWITCH_RELEASE -1 +#define JOYSTICK_TYPE_JOYSTICK 0x04 +#define JOYSTICK_TYPE_GAMEPAD 0x05 +#define JOYSTICK_TYPE_MULTI_AXIS 0x08 + +class Joystick_ +{ +private: + + // Joystick State + int32_t _xAxis; + int32_t _yAxis; + int32_t _zAxis; + int32_t _xAxisRotation; + int32_t _yAxisRotation; + int32_t _zAxisRotation; + int32_t _throttle; + int32_t _rudder; + int32_t _accelerator; + int32_t _brake; + int32_t _steering; + int16_t _hatSwitchValues[JOYSTICK_HATSWITCH_COUNT_MAXIMUM]; + uint8_t *_buttonValues = NULL; + + // Joystick Settings + bool _autoSendState; + uint8_t _buttonCount; + uint8_t _buttonValuesArraySize = 0; + uint8_t _hatSwitchCount; + uint8_t _includeAxisFlags; + uint8_t _includeSimulatorFlags; + int32_t _xAxisMinimum = JOYSTICK_DEFAULT_AXIS_MINIMUM; + int32_t _xAxisMaximum = JOYSTICK_DEFAULT_AXIS_MAXIMUM; + int32_t _yAxisMinimum = JOYSTICK_DEFAULT_AXIS_MINIMUM; + int32_t _yAxisMaximum = JOYSTICK_DEFAULT_AXIS_MAXIMUM; + int32_t _zAxisMinimum = JOYSTICK_DEFAULT_AXIS_MINIMUM; + int32_t _zAxisMaximum = JOYSTICK_DEFAULT_AXIS_MAXIMUM; + int32_t _rxAxisMinimum = JOYSTICK_DEFAULT_AXIS_MINIMUM; + int32_t _rxAxisMaximum = JOYSTICK_DEFAULT_AXIS_MAXIMUM; + int32_t _ryAxisMinimum = JOYSTICK_DEFAULT_AXIS_MINIMUM; + int32_t _ryAxisMaximum = JOYSTICK_DEFAULT_AXIS_MAXIMUM; + int32_t _rzAxisMinimum = JOYSTICK_DEFAULT_AXIS_MINIMUM; + int32_t _rzAxisMaximum = JOYSTICK_DEFAULT_AXIS_MAXIMUM; + int32_t _rudderMinimum = JOYSTICK_DEFAULT_SIMULATOR_MINIMUM; + int32_t _rudderMaximum = JOYSTICK_DEFAULT_SIMULATOR_MAXIMUM; + int32_t _throttleMinimum = JOYSTICK_DEFAULT_SIMULATOR_MINIMUM; + int32_t _throttleMaximum = JOYSTICK_DEFAULT_SIMULATOR_MAXIMUM; + int32_t _acceleratorMinimum = JOYSTICK_DEFAULT_SIMULATOR_MINIMUM; + int32_t _acceleratorMaximum = JOYSTICK_DEFAULT_SIMULATOR_MAXIMUM; + int32_t _brakeMinimum = JOYSTICK_DEFAULT_SIMULATOR_MINIMUM; + int32_t _brakeMaximum = JOYSTICK_DEFAULT_SIMULATOR_MAXIMUM; + int32_t _steeringMinimum = JOYSTICK_DEFAULT_SIMULATOR_MINIMUM; + int32_t _steeringMaximum = JOYSTICK_DEFAULT_SIMULATOR_MAXIMUM; + + uint8_t _hidReportId; + uint8_t _hidReportSize; + +protected: + int buildAndSet16BitValue(bool includeValue, int32_t value, int32_t valueMinimum, int32_t valueMaximum, int32_t actualMinimum, int32_t actualMaximum, uint8_t dataLocation[]); + int buildAndSetAxisValue(bool includeAxis, int32_t axisValue, int32_t axisMinimum, int32_t axisMaximum, uint8_t dataLocation[]); + int buildAndSetSimulationValue(bool includeValue, int32_t value, int32_t valueMinimum, int32_t valueMaximum, uint8_t dataLocation[]); + +public: + Joystick_( + uint8_t hidReportId = JOYSTICK_DEFAULT_REPORT_ID, + uint8_t joystickType = JOYSTICK_TYPE_JOYSTICK, + uint8_t buttonCount = JOYSTICK_DEFAULT_BUTTON_COUNT, + uint8_t hatSwitchCount = JOYSTICK_DEFAULT_HATSWITCH_COUNT, + bool includeXAxis = true, + bool includeYAxis = true, + bool includeZAxis = true, + bool includeRxAxis = true, + bool includeRyAxis = true, + bool includeRzAxis = true, + bool includeRudder = true, + bool includeThrottle = true, + bool includeAccelerator = true, + bool includeBrake = true, + bool includeSteering = true); + + void begin(bool initAutoSendState = true); + void end(); + + // Set Range Functions + inline void setXAxisRange(int32_t minimum, int32_t maximum) + { + _xAxisMinimum = minimum; + _xAxisMaximum = maximum; + } + inline void setYAxisRange(int32_t minimum, int32_t maximum) + { + _yAxisMinimum = minimum; + _yAxisMaximum = maximum; + } + inline void setZAxisRange(int32_t minimum, int32_t maximum) + { + _zAxisMinimum = minimum; + _zAxisMaximum = maximum; + } + inline void setRxAxisRange(int32_t minimum, int32_t maximum) + { + _rxAxisMinimum = minimum; + _rxAxisMaximum = maximum; + } + inline void setRyAxisRange(int32_t minimum, int32_t maximum) + { + _ryAxisMinimum = minimum; + _ryAxisMaximum = maximum; + } + inline void setRzAxisRange(int32_t minimum, int32_t maximum) + { + _rzAxisMinimum = minimum; + _rzAxisMaximum = maximum; + } + inline void setRudderRange(int32_t minimum, int32_t maximum) + { + _rudderMinimum = minimum; + _rudderMaximum = maximum; + } + inline void setThrottleRange(int32_t minimum, int32_t maximum) + { + _throttleMinimum = minimum; + _throttleMaximum = maximum; + } + inline void setAcceleratorRange(int32_t minimum, int32_t maximum) + { + _acceleratorMinimum = minimum; + _acceleratorMaximum = maximum; + } + inline void setBrakeRange(int32_t minimum, int32_t maximum) + { + _brakeMinimum = minimum; + _brakeMaximum = maximum; + } + inline void setSteeringRange(int32_t minimum, int32_t maximum) + { + _steeringMinimum = minimum; + _steeringMaximum = maximum; + } + + // Set Axis Values + void setXAxis(int32_t value); + void setYAxis(int32_t value); + void setZAxis(int32_t value); + void setRxAxis(int32_t value); + void setRyAxis(int32_t value); + void setRzAxis(int32_t value); + + // Set Simulation Values + void setRudder(int32_t value); + void setThrottle(int32_t value); + void setAccelerator(int32_t value); + void setBrake(int32_t value); + void setSteering(int32_t value); + + void setButton(uint8_t button, uint8_t value); + void pressButton(uint8_t button); + void releaseButton(uint8_t button); + + void setHatSwitch(int8_t hatSwitch, int16_t value); + + void sendState(); +}; + +#endif // !defined(_USING_DYNAMIC_HID) +#endif // JOYSTICK_h