Merge pull request #15 from ShikyC/refactor

Refactor
This commit is contained in:
ShikyC 2024-01-29 00:33:39 -08:00 committed by GitHub
commit b9564f702d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 324 additions and 161 deletions

View File

@ -1,166 +1,25 @@
// Enable this mode to pass raw analog data to the game without any post-
// processing.
// The game has a built-in mechanism to calculate which sensor is triggered
// and the force of the hit, so it's recommended to enable this mode.
// This also the provides the most similar experience with the arcade.
// If turned on, the microcontroller will ony do a fast sigle-pass convolution
// over the piezoelectric sensors' inputs, and then pass the data to the game
// directly.
#define RAW_ANALOG_MODE 1
/********************************************************
#define PLAYERS 2
#define CHANNELS 4
ESP32 is not fast enough to process 16 channels of input
simultaneously, so you can choose one of the 2 modes:
// SAMPLE_CACHE_LENGTH must be power of 2 (8, 16, 32, etc.)
// See cache.h for implementation
#define SAMPLE_CACHE_LENGTH 16
- MODE_TWO_PLAYERS: Allows the controller to connect 2
drums, but the sensitivity values are flashed to the
board so you can't adjust them without re-flash the
firmware. If you use the provided board, connect the
2 drums and ignore the adjustable resistors.
// The maximum value of a hit (not the minumum value to trigger a heavy hit)
// To configure the light and heavy thresholds, do it in the game settings
#define MAX_THRES 5000
- MODE_ADJUSTABLE: Allows you to adjust the sensitivity
values with the potentiometer as you play, but only
the P1 side of the board will be enabled (you can
configurate it as 1P or 2P in Params.h file).
#if !RAW_ANALOG_MODE
// The minimum value to trigger a light hit
#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
#define MODE_TWO_PLAYERS
#ifdef MODE_TWO_PLAYERS
#include "two_players.h"
#elif defined(MODE_ADJUSTABLE)
#include "adjustable.h"
#endif
// Sensitivity multipliers for each channel, 1.0 as the baseline
#define P1_L_DON_SENS 1.0
#define P1_L_KAT_SENS 1.0
#define P1_R_DON_SENS 1.0
#define P1_R_KAT_SENS 1.0
#define P2_L_DON_SENS 1.0
#define P2_L_KAT_SENS 1.0
#define P2_R_DON_SENS 1.0
#define P2_R_KAT_SENS 1.0
// Input pins for each channel
#define P1_L_DON_IN 4
#define P1_L_KAT_IN 5
#define P1_R_DON_IN 6
#define P1_R_KAT_IN 7
#define P2_L_DON_IN 8
#define P2_L_KAT_IN 1
#define P2_R_DON_IN 9
#define P2_R_KAT_IN 10
#define AXIS_RANGE 1023
#include "USB.h"
#include "Joystick_ESP32S2.h"
#include "cache.h"
const byte inPins[PLAYERS][CHANNELS] = {
P1_L_DON_IN, P1_L_KAT_IN, P1_R_DON_IN, P1_R_KAT_IN,
P2_L_DON_IN, P2_L_KAT_IN, P2_R_DON_IN, P2_R_KAT_IN
};
const float sensitivities[PLAYERS][CHANNELS] = {
P1_L_DON_SENS, P1_L_KAT_SENS, P1_R_DON_SENS, P1_R_KAT_SENS,
P2_L_DON_SENS, P2_L_KAT_SENS, P2_R_DON_SENS, P2_R_KAT_SENS
};
Cache<int, SAMPLE_CACHE_LENGTH> inputWindow[PLAYERS][CHANNELS];
unsigned long power[PLAYERS][CHANNELS];
#if !RAW_ANALOG_MODE
unsigned long lastPower[PLAYERS][CHANNELS];
bool triggered[PLAYERS];
unsigned long triggeredTime[PLAYERS][CHANNELS];
int outputValue[PLAYERS] = {0, 0};
uint resetTimer[PLAYERS] = {0, 0};
short maxIndex[PLAYERS] = {0, 0};
float maxPower[PLAYERS] = {0, 0};
#endif
uint axisValues[PLAYERS][CHANNELS] = {0, 0, 0, 0, 0, 0, 0, 0};
Joystick_ Joystick(JOYSTICK_DEFAULT_REPORT_ID, JOYSTICK_TYPE_GAMEPAD, 10, 4,
true, true, false, true, true, false,
false, false, false, false, false);
void setup() {
for (byte p = 0; p < PLAYERS; p++) {
for (byte i = 0; i < CHANNELS; i++) {
power[p][i] = 0;
#if !RAW_ANALOG_MODE
lastPower[p][i] = 0;
triggered[p] = false;
#endif
pinMode(inPins[p][i], INPUT);
}
#if !RAW_ANALOG_MODE
maxIndex[p] = -1;
maxPower[p] = 0;
#endif
}
USB.PID(0x4869);
USB.VID(0x4869);
USB.productName("Taiko Controller");
USB.manufacturerName("GitHub Community");
USB.begin();
Joystick.begin(false);
Joystick.setXAxisRange(-AXIS_RANGE, AXIS_RANGE);
Joystick.setYAxisRange(-AXIS_RANGE, AXIS_RANGE);
Joystick.setRxAxisRange(-AXIS_RANGE, AXIS_RANGE);
Joystick.setRyAxisRange(-AXIS_RANGE, AXIS_RANGE);
}
void loop() {
for (byte p = 0; p < PLAYERS; p++) {
for (byte i = 0; i < CHANNELS; i++) {
inputWindow[p][i].put(analogRead(inPins[p][i]));
power[p][i] = power[p][i] - inputWindow[p][i].get(1) + inputWindow[p][i].get();
#if !RAW_ANALOG_MODE
if (lastPower[p][i] > maxPower[p] && power[p][i] < lastPower[p][i]) {
maxPower[p] = lastPower[p][i];
maxIndex[p] = i;
}
lastPower[p][i] = power[p][i];
#else
float v = power[p][i] * sensitivities[p][i];
axisValues[p][i] = AXIS_RANGE * (v >= MAX_THRES ? 1 : (v / MAX_THRES));
#endif
}
#if !RAW_ANALOG_MODE
if (!triggered[p] && maxPower[p] >= HIT_THRES) {
triggered[p] = true;
outputValue[p] = (int)(AXIS_RANGE * (maxPower[p] >= MAX_THRES ? 1 : maxPower[p] / MAX_THRES));
}
if (triggered[p] && resetTimer[p] >= RESET_TIME) {
triggered[p] = false;
resetTimer[p] = 0;
maxPower[p] = 0;
maxIndex[p] = -1;
outputValue[p] = 0;
}
for (byte i = 0; i < CHANNELS; i++) {
if (triggered[p] && i == maxIndex[p]) {
axisValues[p][i] = outputValue[p];
} else {
axisValues[p][i] = 0;
}
}
if (triggered[p]) {
resetTimer[p]++;
}
#endif
}
Joystick.setXAxis(axisValues[0][0] > axisValues[0][1] ? axisValues[0][0] : -axisValues[0][1]);
Joystick.setYAxis(axisValues[0][2] > axisValues[0][3] ? axisValues[0][2] : -axisValues[0][3]);
Joystick.setRxAxis(axisValues[1][0] > axisValues[1][1] ? axisValues[1][0] : -axisValues[1][1]);
Joystick.setRyAxis(axisValues[1][2] > axisValues[1][3] ? axisValues[1][2] : -axisValues[1][3]);
Joystick.sendState();
}

View File

@ -0,0 +1,122 @@
#include "params.h"
const byte inPins[CHANNELS] = {
P1_L_DON_IN, P1_L_KAT_IN, P1_R_DON_IN, P1_R_KAT_IN
};
const byte sensitivityPins[CHANNELS] = {
P1_L_DON_SENS_IN, P1_L_KAT_SENS_IN, P1_R_DON_SENS_IN, P1_R_KAT_SENS_IN
};
Cache<int, SAMPLE_CACHE_LENGTH> inputWindow[CHANNELS];
unsigned long power[CHANNELS];
#ifndef RAW_ANALOG_MODE
unsigned long lastPower[PLAYERS][CHANNELS];
bool triggered[PLAYERS];
unsigned long triggeredTime[PLAYERS][CHANNELS];
int outputValue[PLAYERS] = {0, 0};
uint resetTimer[PLAYERS] = {0, 0};
short maxIndex[PLAYERS] = {0, 0};
float maxPower[PLAYERS] = {0, 0};
#endif
uint axisValues[CHANNELS] = {0, 0, 0, 0};
Joystick_ Joystick(JOYSTICK_DEFAULT_REPORT_ID, JOYSTICK_TYPE_GAMEPAD, 10, 4,
true, true, false, true, true, false,
false, false, false, false, false);
void setup() {
for (byte i = 0; i < CHANNELS; i++) {
power[i] = 0;
#ifndef RAW_ANALOG_MODE
lastPower[i] = 0;
triggered = false;
#endif
pinMode(inPins[i], INPUT);
pinMode(sensitivityPins[i], INPUT);
}
#ifndef RAW_ANALOG_MODE
maxIndex = -1;
maxPower = 0;
#endif
USB.PID(0x4869);
USB.VID(0x4869);
USB.productName("Taiko Controller");
USB.manufacturerName("GitHub Community");
USB.begin();
Joystick.begin(false);
Joystick.setXAxisRange(-AXIS_RANGE, AXIS_RANGE);
Joystick.setYAxisRange(-AXIS_RANGE, AXIS_RANGE);
Joystick.setRxAxisRange(-AXIS_RANGE, AXIS_RANGE);
Joystick.setRyAxisRange(-AXIS_RANGE, AXIS_RANGE);
}
void loop() {
for (byte i = 0; i < CHANNELS; i++) {
inputWindow[i].put(analogRead(inPins[i]));
power[i] = power[i] - inputWindow[i].get(1) + inputWindow[i].get();
#ifndef RAW_ANALOG_MODE
if (lastPower[i] > maxPower && power[i] < lastPower[i]) {
maxPower = lastPower[i];
maxIndex = i;
}
lastPower[i] = power[i];
#else
float x = analogRead(sensitivityPins[i]) / 2048.0 - 1;
float x2 = x * x;
float x3 = x2 * x;
float x4 = x3 * x;
float v = (1.0 + x + 0.5 * x2 + 0.166667 * x3) * power[i];
axisValues[i] = AXIS_RANGE * (v >= MAX_THRES ? 1 : (v / MAX_THRES));
#endif
}
#ifndef RAW_ANALOG_MODE
if (!triggered && maxPower >= HIT_THRES) {
triggered = true;
digitalWrite(outPins[maxIndex], HIGH);
outputValue = (int)(AXIS_RANGE * (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;
}
}
if (triggered) {
resetTimer++;
}
#endif
#if PLAYER_SELECT == 1
Joystick.setXAxis(axisValues[0] > axisValues[1] ? axisValues[0] : -axisValues[1]);
Joystick.setYAxis(axisValues[2] > axisValues[3] ? axisValues[2] : -axisValues[3]);
Joystick.setRxAxis(0);
Joystick.setRyAxis(0);
#elif PLAYER_SELECT == 2
Joystick.setXAxis(0);
Joystick.setYAxis(0);
Joystick.setRxAxis(axisValues[0] > axisValues[1] ? axisValues[0] : -axisValues[1]);
Joystick.setRyAxis(axisValues[2] > axisValues[3] ? axisValues[2] : -axisValues[3]);
#else
Joystick.setXAxis(0);
Joystick.setYAxis(0);
Joystick.setRxAxis(0);
Joystick.setRyAxis(0);
#endif
Joystick.sendState();
}

View File

@ -20,7 +20,7 @@
Edited by Schnoog to make it running on ESP32-S2/s3 devices
*/
#include "Joystick_ESP32S2.h"
#include "joystick.h"
#define JOYSTICK_REPORT_ID_INDEX 7
#define JOYSTICK_AXIS_MINIMUM 0

72
ESP32-S3-Analog/params.h Normal file
View File

@ -0,0 +1,72 @@
// Enable this mode to pass raw analog data to the game without any post-
// processing.
// The game has a built-in mechanism to calculate which sensor is triggered
// and the force of the hit, so it's recommended to enable this mode.
// This also the provides the most similar experience with the arcade.
// To disable this mode, remove or comment out this line
#define RAW_ANALOG_MODE
// For MODE_ADJUSTABLE
// Select which player this board is. 1 for P1 and 2 for P2.
#define PLAYER_SELECT 1
// For MODE_TWO_PLAYERS
// Sensitivity multipliers for each channel, 1.0 as the baseline.
#define P1_L_DON_SENS 1.0
#define P1_L_KAT_SENS 1.0
#define P1_R_DON_SENS 1.0
#define P1_R_KAT_SENS 1.0
#define P2_L_DON_SENS 1.0
#define P2_L_KAT_SENS 1.0
#define P2_R_DON_SENS 1.0
#define P2_R_KAT_SENS 1.0
/********************************************************
CHANGING THE FOLLOWING PARAMETERS ARE NOT RECOMMENDED
UNLESS YOU KNOW HOW THEY WORKS
**********************************************************/
// Cache length must be the power of 2 (8, 16, 32, etc.)
// See cache.h for the reason
#define SAMPLE_CACHE_LENGTH 32
// The maximum value of a hit (not the minumum value to trigger a heavy hit)
// To configure the light and heavy thresholds, do it in the game settings
#define MAX_THRES 5000
// Input pins for each channel
#define P1_L_DON_IN 4
#define P1_L_KAT_IN 5
#define P1_R_DON_IN 6
#define P1_R_KAT_IN 7
#define P2_L_DON_IN 8
#define P2_L_KAT_IN 1
#define P2_R_DON_IN 9
#define P2_R_KAT_IN 10
// Sensitivity adjustment potentiometer input pins
#define P1_L_DON_SENS_IN 15
#define P1_L_KAT_SENS_IN 16
#define P1_R_DON_SENS_IN 17
#define P1_R_KAT_SENS_IN 18
#define AXIS_RANGE 1023
#define PLAYERS 2
#define CHANNELS 4
#ifndef RAW_ANALOG_MODE
// The minimum value to trigger a light hit
#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
#endif
#include <USB.h>
#include "joystick.h"
#include "cache.h"

View File

@ -0,0 +1,110 @@
#include "params.h"
const byte inPins[PLAYERS][CHANNELS] = {
P1_L_DON_IN, P1_L_KAT_IN, P1_R_DON_IN, P1_R_KAT_IN,
P2_L_DON_IN, P2_L_KAT_IN, P2_R_DON_IN, P2_R_KAT_IN
};
const float sensitivities[PLAYERS][CHANNELS] = {
P1_L_DON_SENS, P1_L_KAT_SENS, P1_R_DON_SENS, P1_R_KAT_SENS,
P2_L_DON_SENS, P2_L_KAT_SENS, P2_R_DON_SENS, P2_R_KAT_SENS
};
Cache<int, SAMPLE_CACHE_LENGTH> inputWindow[PLAYERS][CHANNELS];
unsigned long power[PLAYERS][CHANNELS];
#ifndef RAW_ANALOG_MODE
unsigned long lastPower[PLAYERS][CHANNELS];
bool triggered[PLAYERS];
unsigned long triggeredTime[PLAYERS][CHANNELS];
int outputValue[PLAYERS] = {0, 0};
uint resetTimer[PLAYERS] = {0, 0};
short maxIndex[PLAYERS] = {0, 0};
float maxPower[PLAYERS] = {0, 0};
#endif
uint axisValues[PLAYERS][CHANNELS] = {0, 0, 0, 0, 0, 0, 0, 0};
Joystick_ Joystick(JOYSTICK_DEFAULT_REPORT_ID, JOYSTICK_TYPE_GAMEPAD, 10, 4,
true, true, false, true, true, false,
false, false, false, false, false);
void setup() {
for (byte p = 0; p < PLAYERS; p++) {
for (byte i = 0; i < CHANNELS; i++) {
power[p][i] = 0;
#ifndef RAW_ANALOG_MODE
lastPower[p][i] = 0;
triggered[p] = false;
#endif
pinMode(inPins[p][i], INPUT);
}
#ifndef RAW_ANALOG_MODE
maxIndex[p] = -1;
maxPower[p] = 0;
#endif
}
USB.PID(0x4869);
USB.VID(0x4869);
USB.productName("Taiko Controller");
USB.manufacturerName("GitHub Community");
USB.begin();
Joystick.begin(false);
Joystick.setXAxisRange(-AXIS_RANGE, AXIS_RANGE);
Joystick.setYAxisRange(-AXIS_RANGE, AXIS_RANGE);
Joystick.setRxAxisRange(-AXIS_RANGE, AXIS_RANGE);
Joystick.setRyAxisRange(-AXIS_RANGE, AXIS_RANGE);
}
void loop() {
for (byte p = 0; p < PLAYERS; p++) {
for (byte i = 0; i < CHANNELS; i++) {
inputWindow[p][i].put(analogRead(inPins[p][i]));
power[p][i] = power[p][i] - inputWindow[p][i].get(1) + inputWindow[p][i].get();
#ifndef RAW_ANALOG_MODE
if (lastPower[p][i] > maxPower[p] && power[p][i] < lastPower[p][i]) {
maxPower[p] = lastPower[p][i];
maxIndex[p] = i;
}
lastPower[p][i] = power[p][i];
#else
float v = power[p][i] * sensitivities[p][i];
axisValues[p][i] = AXIS_RANGE * (v >= MAX_THRES ? 1 : (v / MAX_THRES));
#endif
}
#ifndef RAW_ANALOG_MODE
if (!triggered[p] && maxPower[p] >= HIT_THRES) {
triggered[p] = true;
outputValue[p] = (int)(AXIS_RANGE * (maxPower[p] >= MAX_THRES ? 1 : maxPower[p] / MAX_THRES));
}
if (triggered[p] && resetTimer[p] >= RESET_TIME) {
triggered[p] = false;
resetTimer[p] = 0;
maxPower[p] = 0;
maxIndex[p] = -1;
outputValue[p] = 0;
}
for (byte i = 0; i < CHANNELS; i++) {
if (triggered[p] && i == maxIndex[p]) {
axisValues[p][i] = outputValue[p];
} else {
axisValues[p][i] = 0;
}
}
if (triggered[p]) {
resetTimer[p]++;
}
#endif
}
Joystick.setXAxis(axisValues[0][0] > axisValues[0][1] ? axisValues[0][0] : -axisValues[0][1]);
Joystick.setYAxis(axisValues[0][2] > axisValues[0][3] ? axisValues[0][2] : -axisValues[0][3]);
Joystick.setRxAxis(axisValues[1][0] > axisValues[1][1] ? axisValues[1][0] : -axisValues[1][1]);
Joystick.setRyAxis(axisValues[1][2] > axisValues[1][3] ? axisValues[1][2] : -axisValues[1][3]);
Joystick.sendState();
}