/* Joystick_ESP32S2.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 Edited by Schnoog to make it running on ESP32-S2/s3 devices */ #include "joystick.h" #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]; 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 //org: uint8_t *customHidReportDescriptor = new uint8_t[hidReportDescriptorSize]; customHidReportDescriptor = new uint8_t[hidReportDescriptorSize]; memcpy(customHidReportDescriptor, tempHidReportDescriptor, hidReportDescriptorSize); // Register HID Report Description HID.addDevice(this, hidReportDescriptorSize); // 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; } } uint16_t Joystick_::_onGetDescriptor(uint8_t* buffer){ memcpy(buffer, customHidReportDescriptor,hidReportDescriptorSize); return hidReportDescriptorSize; } void Joystick_::begin(bool initAutoSendState, uint8_t intervalMs) { HID.begin(); _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])); if (HID.ready()) { HID.SendReport(_hidReportId, data, sizeof(data),0); } }