Upload files to "libraries/ArduinoJoystickLibrary/src"

This commit is contained in:
2026-01-14 14:14:53 -05:00
parent 297fe2a209
commit aeb8b09cc8
4 changed files with 1213 additions and 0 deletions

View File

@@ -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) */

View File

@@ -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 <stdint.h>
#include <Arduino.h>
#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

View File

@@ -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

View File

@@ -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