-
-
Save skogaby/59331321ba9427996ff1c941a32b05f4 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Before you can use this code, make sure to download needed libraries | |
* - https://github.com/dmadison/ArduinoXInput | |
* - https://github.com/FastLED/FastLED | |
* | |
* You will also need to add this to your arduino IDE's hardware folder | |
* - https://github.com/dmadison/ArduinoXInput_AVR | |
* | |
* This file was created with the Arduino Leonardo or Pro Micro board in mind. | |
* | |
* USAGE: This will cover your basic XInput controller for ONGEKI | |
*/ | |
#include <EEPROM.h> | |
#include <FastLED.h> | |
#include <XInput.h> | |
// Constants to define which buttons are on which pins | |
#define BUTTON_L_R 5 | |
#define BUTTON_L_G 4 | |
#define BUTTON_L_B 6 | |
#define BUTTON_R_R 2 | |
#define BUTTON_R_G 1 | |
#define BUTTON_R_B 0 | |
#define MENU_L 7 | |
#define MENU_R 8 | |
#define SIDE_L 9 | |
#define SIDE_R 10 | |
// Pin that the lever potentiometer outputs to | |
#define LEVER_PIN A0 | |
// Min and max values for the triggers for XInput | |
#define TRIGGER_MIN 0 | |
#define TRIGGER_MAX 512 | |
// Flag to check in EEPROM for whether we've calibrated | |
#define CALIBRATION_FLAG 0xAE | |
// LED config for the button lights | |
#define LED_PIN 11 | |
#define NUM_LEDS 12 | |
CRGB leds[NUM_LEDS]; | |
// All the button pins | |
byte buttonPins[] = { | |
BUTTON_L_R, BUTTON_L_G, BUTTON_L_B, // Left face buttons | |
BUTTON_R_R, BUTTON_R_G, BUTTON_R_B, // Right face buttons | |
MENU_L, MENU_R, // Menu buttons | |
SIDE_L, SIDE_R // Side buttons | |
}; | |
// The min and max values of the lever pot, so we can map them to the trigger values correctly | |
int leverMin; | |
int leverMax; | |
int leverCenter; | |
int leverValue; | |
// Function prototypes | |
void setFinalLEDColors(); | |
void setAllLEDs(CRGB color); | |
void calibrateLever(); | |
// Init | |
void setup() { | |
// Pin setup | |
pinMode(LEVER_PIN, INPUT); | |
for (int i = 0; i < sizeof(buttonPins); i++) { | |
pinMode(buttonPins[i], INPUT_PULLUP); | |
} | |
// LED setup | |
FastLED.addLeds<WS2812B, LED_PIN, GRB>(leds, NUM_LEDS); | |
// Controller setup | |
XInput.setTriggerRange(TRIGGER_MIN, TRIGGER_MAX); | |
XInput.setAutoSend(false); | |
XInput.begin(); | |
// Flash all LEDs 3 times | |
for (int i = 0; i < 3; i++) { | |
setAllLEDs(CRGB::Purple); | |
delay(500); | |
setAllLEDs(CRGB::Yellow); | |
delay(500); | |
} | |
// Calibrate the lever | |
calibrateLever(); | |
// Set the final LED colors | |
setFinalLEDColors(); | |
} | |
// Main loop | |
void loop() { | |
// Read all the inputs and set the outputs according to how Segatools processes the XInput. | |
// The left RGB buttons are mapped to the d-pad: up (green), left (red), and right (blue) | |
XInput.setDpad(!digitalRead(BUTTON_L_G), !digitalRead(BUTTON_L_G), !digitalRead(BUTTON_L_R), !digitalRead(BUTTON_L_B), false); | |
// The right RGB buttons, side buttons, and menu buttons are mapped to controller buttons | |
XInput.setButton(BUTTON_X, !digitalRead(BUTTON_R_R)); | |
XInput.setButton(BUTTON_Y, !digitalRead(BUTTON_R_G)); | |
XInput.setButton(BUTTON_B, !digitalRead(BUTTON_R_B)); | |
XInput.setButton(BUTTON_LB, !digitalRead(SIDE_L)); | |
XInput.setButton(BUTTON_RB, !digitalRead(SIDE_R)); | |
XInput.setButton(BUTTON_BACK, !digitalRead(MENU_L)); | |
XInput.setButton(BUTTON_START, !digitalRead(MENU_R)); | |
// The lever is mapped to the triggers. Left half of the lever maps to left trigger, | |
// right half of the lever maps to right trigger. Both triggers unpressed is center of the lever. | |
leverValue = analogRead(LEVER_PIN); | |
XInput.setTrigger(TRIGGER_LEFT, min(TRIGGER_MAX, max(0, map(leverValue, leverCenter, leverMin, TRIGGER_MIN, TRIGGER_MAX)))); | |
XInput.setTrigger(TRIGGER_RIGHT, min(TRIGGER_MAX, max(0, map(leverValue, leverCenter, leverMax, TRIGGER_MIN, TRIGGER_MAX)))); | |
// Send control data to the computer | |
XInput.send(); | |
} | |
// Initialize the LEDs to the correct colors | |
void setFinalLEDColors() { | |
leds[0] = CRGB::Purple; // Side-L | |
leds[1] = CRGB::Purple; // Side-L | |
leds[2] = CRGB::Yellow; // Menu-R | |
leds[3] = CRGB::Blue; // Right Blue | |
leds[4] = CRGB::Green; // Right Green | |
leds[5] = CRGB::Red; // Right Red | |
leds[6] = CRGB::Blue; // Left Blue | |
leds[7] = CRGB::Green; // Left Green | |
leds[8] = CRGB::Red; // Left Red | |
leds[9] = CRGB::Red; // Menu-L | |
leds[10] = CRGB::Purple; // Side-R | |
leds[11] = CRGB::Purple; // Side-R | |
FastLED.show(); | |
} | |
// Sets all the LEDs to the given color | |
void setAllLEDs(CRGB color) { | |
for (int i = 0; i < NUM_LEDS; i++) { | |
leds[i] = color; | |
} | |
FastLED.show(); | |
} | |
// Calibrate the lever so we can map the pot values to trigger inputs | |
void calibrateLever() { | |
// We'll only calibrate if: | |
// * We have never calibrated before according to the flag in EEPROM, or | |
// * The left-side RGB buttons are being held | |
boolean needsCalibration = false; | |
byte calibrationFlag; | |
EEPROM.get(0, calibrationFlag); | |
if (calibrationFlag != CALIBRATION_FLAG) { | |
needsCalibration = true; | |
} | |
// If the flag was set in EEPROM, still check the buttons | |
if (!digitalRead(BUTTON_L_R) && | |
!digitalRead(BUTTON_L_G) && | |
!digitalRead(BUTTON_L_B)) { | |
needsCalibration = true; | |
} | |
if (needsCalibration) { | |
// Recalibrate if needed and store the values in EEPROM. | |
// First, just set all the lights red. | |
setAllLEDs(CRGB::Red); | |
// Now, we'll wait for input from the Menu-L button, this signifies that | |
// we should read the current value as leverMin | |
while (digitalRead(MENU_L)) { | |
delay(50); | |
} | |
leverMin = analogRead(LEVER_PIN); | |
// Next, set the lights yellow so we know step 1 is done | |
setAllLEDs(CRGB::Yellow); | |
// Now, wait for input from the Menu-R button, this signifies that | |
// we should read the current value as leverMax | |
while (digitalRead(MENU_R)) { | |
delay(50); | |
} | |
leverMax = analogRead(LEVER_PIN); | |
// Pre-calculate the values we need during lever->trigger conversion | |
leverCenter = ((leverMax + leverMin) / 2); | |
// Write leverMin and leverMax to EEPROM, as well as the calibration flag | |
EEPROM.put(0, CALIBRATION_FLAG); | |
EEPROM.put(1, leverMin); | |
EEPROM.put(5, leverMax); | |
// Finally, set all the lights to green | |
setAllLEDs(CRGB::Green); | |
delay(2000); | |
} else { | |
// Just load leverMin and leverMax from EEPROM | |
EEPROM.get(1, leverMin); | |
EEPROM.get(5, leverMax); | |
leverCenter = ((leverMax + leverMin) / 2); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment