Update analog input support
This commit is contained in:
parent
89b4b0af68
commit
73470d1507
136
ESP32-S3-Analog/ESP32-S3-Analog.ino
Normal file
136
ESP32-S3-Analog/ESP32-S3-Analog.ino
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
#define CHANNELS 4
|
||||||
|
|
||||||
|
// SAMPLE_CACHE_LENGTH must be power of 2 (8, 16, 32, etc.)
|
||||||
|
// See cache.h for implementation
|
||||||
|
#define SAMPLE_CACHE_LENGTH 16
|
||||||
|
|
||||||
|
// The thresholds are also dependent on SAMPLE_CACHE_LENGTH, if you
|
||||||
|
// changed SAMPLE_CACHE_LENGTH, you should also adjust thresholds
|
||||||
|
#define MAX_THRES 5000
|
||||||
|
#define HIT_THRES 1000
|
||||||
|
|
||||||
|
// If the reset time is too short, the game may not be able to
|
||||||
|
// receive the input. From testing I found 40 seems to be the
|
||||||
|
// minimum value so that the game won't miss any hit. If the game
|
||||||
|
// occassionally miss the drum input, increase this value
|
||||||
|
#define RESET_TIME 40
|
||||||
|
|
||||||
|
// Sensitivity multipliers for each channel, 1.0 as the baseline
|
||||||
|
#define L_DON_SENS 1.0
|
||||||
|
#define L_KAT_SENS 1.0
|
||||||
|
#define R_DON_SENS 1.0
|
||||||
|
#define R_KAT_SENS 1.0
|
||||||
|
|
||||||
|
// Input pins for each channel
|
||||||
|
#define L_DON_IN 4
|
||||||
|
#define L_KAT_IN 5
|
||||||
|
#define R_DON_IN 6
|
||||||
|
#define R_KAT_IN 7
|
||||||
|
|
||||||
|
// Output LED pins for each channel (just for visualization)
|
||||||
|
#define L_DON_LED 10
|
||||||
|
#define L_KAT_LED 11
|
||||||
|
#define R_DON_LED 12
|
||||||
|
#define R_KAT_LED 13
|
||||||
|
|
||||||
|
#include "USB.h"
|
||||||
|
#include "Joystick_ESP32S2.h"
|
||||||
|
#include "cache.h"
|
||||||
|
|
||||||
|
Cache<int, SAMPLE_CACHE_LENGTH> inputWindow[CHANNELS];
|
||||||
|
unsigned long power[CHANNELS];
|
||||||
|
unsigned long lastPower[CHANNELS];
|
||||||
|
|
||||||
|
bool triggered;
|
||||||
|
unsigned long triggeredTime[CHANNELS];
|
||||||
|
|
||||||
|
const byte inPins[] = {L_DON_IN, L_KAT_IN, R_DON_IN, R_KAT_IN};
|
||||||
|
const byte outPins[] = {L_DON_LED, L_KAT_LED, R_DON_LED, R_KAT_LED};
|
||||||
|
const float sensitivities[] = {L_DON_SENS, L_KAT_SENS, R_DON_SENS, R_KAT_SENS};
|
||||||
|
uint axisValues[] = {0, 0, 0, 0};
|
||||||
|
|
||||||
|
uint shifter = 0;
|
||||||
|
int outputValue = 0;
|
||||||
|
uint resetTimer = 0;
|
||||||
|
|
||||||
|
short maxIndex;
|
||||||
|
float maxPower;
|
||||||
|
|
||||||
|
unsigned long lastTime;
|
||||||
|
|
||||||
|
Joystick_ Joystick(JOYSTICK_DEFAULT_REPORT_ID, JOYSTICK_TYPE_GAMEPAD, 10, 4,
|
||||||
|
true, true, true, true, true, true,
|
||||||
|
false, false, false, false, false);
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(250000);
|
||||||
|
for (byte i = 0; i < CHANNELS; i++) {
|
||||||
|
power[i] = 0;
|
||||||
|
lastPower[i] = 0;
|
||||||
|
triggered = false;
|
||||||
|
pinMode(inPins[i], INPUT);
|
||||||
|
pinMode(outPins[i], OUTPUT);
|
||||||
|
}
|
||||||
|
maxIndex = -1;
|
||||||
|
maxPower = 0;
|
||||||
|
lastTime = micros();
|
||||||
|
USB.PID(0x4869);
|
||||||
|
USB.VID(0x4869);
|
||||||
|
USB.productName("Taiko Controller");
|
||||||
|
USB.manufacturerName("GitHub Community");
|
||||||
|
USB.begin();
|
||||||
|
Joystick.begin(false);
|
||||||
|
Joystick.setXAxisRange(-1024, 1023);
|
||||||
|
Joystick.setYAxisRange(-1024, 1023);
|
||||||
|
Joystick.setZAxisRange(-1024, 1023);
|
||||||
|
Joystick.setRxAxisRange(-1024, 1023);
|
||||||
|
Joystick.setRyAxisRange(-1024, 1023);
|
||||||
|
Joystick.setRzAxisRange(-1024, 1023);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
|
||||||
|
for (byte i = 0; i < CHANNELS; i++) {
|
||||||
|
inputWindow[i].put(analogRead(inPins[i]));
|
||||||
|
power[i] = sensitivities[i] * (power[i] - inputWindow[i].get(1) + inputWindow[i].get());
|
||||||
|
|
||||||
|
if (lastPower[i] > maxPower && power[i] < lastPower[i]) {
|
||||||
|
maxPower = lastPower[i];
|
||||||
|
maxIndex = i;
|
||||||
|
}
|
||||||
|
lastPower[i] = power[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!triggered && maxPower >= HIT_THRES) {
|
||||||
|
triggered = true;
|
||||||
|
digitalWrite(outPins[maxIndex], HIGH);
|
||||||
|
outputValue = (int)(1023 * (maxPower >= MAX_THRES ? 1 : maxPower / MAX_THRES));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (triggered && resetTimer >= RESET_TIME) {
|
||||||
|
triggered = false;
|
||||||
|
resetTimer = 0;
|
||||||
|
digitalWrite(outPins[maxIndex], LOW);
|
||||||
|
maxPower = 0;
|
||||||
|
maxIndex = -1;
|
||||||
|
outputValue = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (byte i = 0; i < CHANNELS; i++) {
|
||||||
|
if (triggered && i == maxIndex) {
|
||||||
|
axisValues[i] = outputValue;
|
||||||
|
} else {
|
||||||
|
axisValues[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Joystick.setXAxis(axisValues[0]);
|
||||||
|
Joystick.setYAxis(axisValues[1]);
|
||||||
|
Joystick.setRxAxis(axisValues[2]);
|
||||||
|
Joystick.setRyAxis(axisValues[3]);
|
||||||
|
Joystick.sendState();
|
||||||
|
|
||||||
|
if (triggered) {
|
||||||
|
resetTimer++;
|
||||||
|
}
|
||||||
|
}
|
694
ESP32-S3-Analog/Joystick_ESP32S2.cpp
Normal file
694
ESP32-S3-Analog/Joystick_ESP32S2.cpp
Normal file
@ -0,0 +1,694 @@
|
|||||||
|
/*
|
||||||
|
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_ESP32S2.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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
217
ESP32-S3-Analog/Joystick_ESP32S2.h
Normal file
217
ESP32-S3-Analog/Joystick_ESP32S2.h
Normal file
@ -0,0 +1,217 @@
|
|||||||
|
/*
|
||||||
|
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
|
||||||
|
|
||||||
|
Edited by Schnoog to make it running on ESP32-S2/s3 devices
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef JOYSTICK_h
|
||||||
|
#define JOYSTICK_h
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include "USB.h"
|
||||||
|
#include "USBHID.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//================================================================================
|
||||||
|
// 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_: public USBHIDDevice
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
|
||||||
|
USBHID HID;
|
||||||
|
|
||||||
|
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:
|
||||||
|
uint8_t *customHidReportDescriptor;
|
||||||
|
int hidReportDescriptorSize;
|
||||||
|
|
||||||
|
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, uint8_t interval_ms = 2);
|
||||||
|
|
||||||
|
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();
|
||||||
|
uint16_t _onGetDescriptor(uint8_t* buffer);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // JOYSTICK_h
|
31
ESP32-S3-Analog/cache.h
Normal file
31
ESP32-S3-Analog/cache.h
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
/***************************************************************
|
||||||
|
* *
|
||||||
|
* Taiko Sanro - Arduino *
|
||||||
|
* Cache data structure *
|
||||||
|
* *
|
||||||
|
* Chris *
|
||||||
|
* wisaly@gmail.com *
|
||||||
|
* *
|
||||||
|
***************************************************************/
|
||||||
|
|
||||||
|
#ifndef CACHE_H
|
||||||
|
#define CACHE_H
|
||||||
|
|
||||||
|
template <class T, int L>
|
||||||
|
class Cache {
|
||||||
|
public:
|
||||||
|
Cache() { memset(data_, 0, sizeof(data_)); }
|
||||||
|
inline void put(T value) {
|
||||||
|
current_ = (current_ + 1) & (L - 1);
|
||||||
|
data_[current_] = value;
|
||||||
|
}
|
||||||
|
inline T get(int offset = 0) const {
|
||||||
|
return data_[(current_ + offset) & (L - 1)];
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
T data_[L];
|
||||||
|
int current_ = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // CACHE_H
|
BIN
ESP32-S3-Analog/extra/bnusio.dll
Normal file
BIN
ESP32-S3-Analog/extra/bnusio.dll
Normal file
Binary file not shown.
37
README.md
37
README.md
@ -91,3 +91,40 @@ This project aims to help you develop your own hardware taiko at home.
|
|||||||
Using a bridge rectifier, all negative values are converted to positive. In other words, it's like the `abs()` function, ensuring that we don't lose any negative voltages.
|
Using a bridge rectifier, all negative values are converted to positive. In other words, it's like the `abs()` function, ensuring that we don't lose any negative voltages.
|
||||||
|
|
||||||
![Why using bridge rectifiers](./images/bridge_signal.png)
|
![Why using bridge rectifiers](./images/bridge_signal.png)
|
||||||
|
|
||||||
|
# Taiko Controller - Analog Input Mode (Beta)
|
||||||
|
|
||||||
|
With ESP32-S2 or ESP32-S3 controllers, instead of keyboard emulation, the drum controller can work as a gamepad and send its axes values to the game (which also must support analog input). In this way, the game can recognize different force levels of the hit.
|
||||||
|
|
||||||
|
If you prefer to use the Arduino Micro/Leonardo board, please refer to the [Arduino XInput Library](https://github.com/dmadison/ArduinoXInput) to implement the gamepad.
|
||||||
|
|
||||||
|
## What You Need
|
||||||
|
|
||||||
|
1. Make your drum or use Taiko Force Lv.5.
|
||||||
|
|
||||||
|
2. Flash `ESP32-S3-Analog/ESP32-S3-Analog.ino` to your controller.
|
||||||
|
|
||||||
|
3. A working ***game***, with these modifications:
|
||||||
|
|
||||||
|
- Backup and replace the `bnusio.dll` file in the game folder with the one here in the `extra/` folder.
|
||||||
|
|
||||||
|
This file is compiled from [this fork](https://github.com/ShikyC/TaikoArcadeLoader/tree/Refactor) and you can compile it by yourself if you want.
|
||||||
|
|
||||||
|
*This modified library only works with a specific game version. If it breaks your game, please clone the original repository, make the corrensponding modifications, and compile it.*
|
||||||
|
|
||||||
|
- Open the `gamecontrollerdb.txt` file in the game folder and add one entry under `#Windows`:
|
||||||
|
|
||||||
|
`030052a8694800006948000000000000,Taiko Controller,+leftx:+a0,+lefty:+a1,+rightx:+a3,+righty:+a4,platform:Windows,`
|
||||||
|
|
||||||
|
This will tell the game that our ESP32 controller is a gamepad called "Taiko Controller", and map the axis to the standard SDL2 library so that the game can recognize the analog inputs.
|
||||||
|
|
||||||
|
- Open the `config.toml` file and add the following lines at the end:
|
||||||
|
|
||||||
|
```
|
||||||
|
[controller]
|
||||||
|
analog = true
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that with `analog = true`, all the keyboard drum inputs are disabled. Sorry for this but it need further refactoring to make them work together. If you want to switch back to keyboard inputs, set `analog = false`.
|
||||||
|
|
||||||
|
4. Launch the game and enjoy!
|
@ -91,3 +91,40 @@
|
|||||||
ブリッジ整流器を使用すると、すべての負の値が正の値に変換されます。言い換えれば、それは`abs()`関数のようなもので、負の電圧を失わないことを保証します。
|
ブリッジ整流器を使用すると、すべての負の値が正の値に変換されます。言い換えれば、それは`abs()`関数のようなもので、負の電圧を失わないことを保証します。
|
||||||
|
|
||||||
![ブリッジ整流器の使用理由](./images/bridge_signal.png)
|
![ブリッジ整流器の使用理由](./images/bridge_signal.png)
|
||||||
|
|
||||||
|
# Taiko Controller - アナログ入力モード(Beta)
|
||||||
|
|
||||||
|
ESP32-S2またはESP32-S3コントローラーを使用すると、キーボードエミュレーションの代わりに、ドラムコントローラーがゲームパッドとして機能し、その軸の値をゲームに送信できます(ゲームもアナログ入力をサポートしている必要があります)。この方法では、ゲームはヒットの異なる力のレベルを認識できます。
|
||||||
|
|
||||||
|
Arduino Micro/Leonardoボードを使用する場合は、[Arduino XInputライブラリ](https://github.com/dmadison/ArduinoXInput)を参照して、ゲームパッドを実装してください。
|
||||||
|
|
||||||
|
## 必要なもの
|
||||||
|
|
||||||
|
1. 自分のドラムを作るか、Taiko Force Lv.5を使用してください。詳細はメインブランチをチェックしてください。
|
||||||
|
|
||||||
|
2. `ESP32-S3-Analog/ESP32-S3-Analog.ino`をコントローラーにフラッシュします。
|
||||||
|
|
||||||
|
3. 以下の変更を加えたゲーム:
|
||||||
|
|
||||||
|
- ゲームフォルダ内の`bnusio.dll`ファイルをバックアップし、`extra/`フォルダーこちらのファイルで置き換えてください。
|
||||||
|
|
||||||
|
このファイルは[このフォーク](https://github.com/ShikyC/TaikoArcadeLoader/tree/Refactor)からコンパイルされており、必要に応じて自分でコンパイルすることができます。
|
||||||
|
|
||||||
|
*この変更されたライブラリは特定のゲームバージョンでのみ機能します。ゲームが壊れた場合は、元のリポジトリをクローンして、対応する変更を加え、コンパイルしてください。*
|
||||||
|
|
||||||
|
- ゲームフォルダ内の`gamecontrollerdb.txt`ファイルを開き、`#Windows`の下に次のエントリを追加します:
|
||||||
|
|
||||||
|
`030052a8694800006948000000000000,Taiko Controller,+leftx:+a0,+lefty:+a1,+rightx:+a3,+righty:+a4,platform:Windows,`
|
||||||
|
|
||||||
|
これにより、ゲームはESP32コントローラーが「Taiko Controller」というゲームパッドであることを認識し、標準のSDL2ライブラリに軸をマップするため、ゲームがアナログ入力を認識できるようになります。
|
||||||
|
|
||||||
|
- `config.toml`ファイルを開き、最後に次の行を追加します:
|
||||||
|
|
||||||
|
```
|
||||||
|
[controller]
|
||||||
|
analog = true
|
||||||
|
```
|
||||||
|
|
||||||
|
`analog = true`で、すべてのキーボードドラム入力が無効になります。これはさらなるリファクタリングが必要ですが、一緒に機能させるために申し訳ありません。キーボード入力に戻したい場合は、`analog = false`に設定してください。
|
||||||
|
|
||||||
|
4. ゲームを起動して楽しんでください!
|
@ -91,3 +91,40 @@
|
|||||||
使用桥式整流器,所有负值都转换为正值。换句话说,就像`abs()`函数,确保我们不会丢失任何负电压。
|
使用桥式整流器,所有负值都转换为正值。换句话说,就像`abs()`函数,确保我们不会丢失任何负电压。
|
||||||
|
|
||||||
![为什么使用桥式整流器](./images/bridge_signal.png)
|
![为什么使用桥式整流器](./images/bridge_signal.png)
|
||||||
|
|
||||||
|
# Taiko Controller - 模拟输入模式
|
||||||
|
|
||||||
|
使用ESP32-S2或ESP32-S3控制器,代替键盘仿真,鼓控制器可以作为游戏手柄工作,并将其轴值发送给游戏(游戏也必须支持模拟输入)。这样,游戏可以识别击打的不同力度级别。
|
||||||
|
|
||||||
|
如果您更喜欢使用Arduino Micro/Leonardo板,请参考[Arduino XInput库](https://github.com/dmadison/ArduinoXInput)来实现游戏手柄。
|
||||||
|
|
||||||
|
## 你需要什么
|
||||||
|
|
||||||
|
1. 制作你的鼓或使用Taiko Force Lv.5。详情请查看主分支。
|
||||||
|
|
||||||
|
2. 将`ESP32-S3-Analog/ESP32-S3-Analog.ino`刷写到你的控制器。
|
||||||
|
|
||||||
|
3. 一个能正常运行的***游戏***,并进行以下修改:
|
||||||
|
|
||||||
|
- 备份并替换游戏文件夹中的`bnusio.dll`文件,使用这里`extra/`文件夹中的文件。
|
||||||
|
|
||||||
|
这个文件是从[这个仓库](https://github.com/ShikyC/TaikoArcadeLoader/tree/Refactor)编译的,如果你愿意,你也可以自己编译。
|
||||||
|
|
||||||
|
*这个修改过的库只适用于特定版本的游戏。如果它破坏了你的游戏,请克隆[原始仓库](https://github.com/BroGamer4256/TaikoArcadeLoader),进行相应的修改,并编译它。*
|
||||||
|
|
||||||
|
- 打开游戏文件夹中的`gamecontrollerdb.txt`文件,并在`#Windows`下添加一条条目:
|
||||||
|
|
||||||
|
`030052a8694800006948000000000000,Taiko Controller,+leftx:+a0,+lefty:+a1,+rightx:+a3,+righty:+a4,platform:Windows,`
|
||||||
|
|
||||||
|
这将告诉游戏我们的ESP32控制器是一个名为“Taiko Controller”的游戏手柄,并将轴映射到标准SDL2库,以便游戏能够识别模拟输入。
|
||||||
|
|
||||||
|
- 打开`config.toml`文件,并在末尾添加以下行:
|
||||||
|
|
||||||
|
```
|
||||||
|
[controller]
|
||||||
|
analog = true
|
||||||
|
```
|
||||||
|
|
||||||
|
请注意,使用`analog = true`时,所有键盘鼓输入都将被禁用。对此表示抱歉,但它需要进一步重构才能同时工作。如果你想切换回键盘输入,请设置`analog = false`。
|
||||||
|
|
||||||
|
4. 开始游玩咚!
|
||||||
|
Loading…
Reference in New Issue
Block a user