Files
UnoSDVXCon/SDVXCon.ino
Sirawat Pitaksarit 19fa5dadb8 readme
2016-08-26 01:02:16 +09:00

796 lines
13 KiB
C++

// Arduino Uno Sound Voltex Controller Script
// By 5argon
// https://github.com/5argon/SDVXArduinoUno
// Contact - @5argondesu
//Sketch -> Include Library > Manage Library... > Search for "Encoder" then install it.
#include <Encoder.h>
//Uncomment to send serial button/knob message to Arduino debug console to test if your connection work or not without the game.
//When debugging, serial message also activates pin 1 (TX), so if your config used pin 1 this may causes problems.
//When actually using, you MUST comment out; As debug message is the same channel as keyboard message.
//(If you forgot, a push of some button might quit your works without saving and shutdown your computer at the same time.)
//#define SERIAL_DEBUGGING
// -- Setup your button connections to the Arduino Uno pins here. --
//Button switch. The other side should be connecting to GND. (Switch is in pull-up mode when not pressed)
int const BTA = 0;
int const BTB = 12;
int const BTC = 6;
int const BTD = 11;
int const FXL = 5;
int const FXR = 7;
int const START = 555; //My controller don't have a start button
//Button's LED. From the pin below to LED + resistor to GND.
int const BTLA = A5;
int const BTLB = A4;
int const BTLC = A2;
int const BTLD = A0;
int const FXLL = 8;
int const FXLR = 10;
int const STARTL = 556; //My controller don't have a start button
//Encoders. If you are using a Copal, the white cable is A and the green cable is B. (Red goes to 5V and black goes to GND)
//VOLL is the left encoder, VOLR is the right encoder. Please DO NOT use pin 13 on Uno. (LED connected pin)
//You MUST connect one of each encoder's white or green cable to pin 2 and 3. These 2 pins on an Uno are special external interrupt pins. (It's fast)
//For example, VOLLA = 2 and VOLLRA = 3. (both encoder's white). The green cable can choose any pin.
//In short, this will make both encoder good. Without this you will die on Firestorm EXH.
int const VOLLA = 2;
int const VOLLB = 4;
int const VOLRA = 3;
int const VOLRB = 9;
// -- Key mapping --
// Go to http://www.usb.org/developers/hidpage/Hut1_12v2.pdf page 53
// For the list of key specifications from official USB devs.
// Or this for Japanese keyboards http://www2d.biglobe.ne.jp/~msyk/keyboard/layout/usbkeycode.html (look at the last column, it's in HEX)
uint8_t keyBTA = 22; //s
uint8_t keyBTB = 7; //d
uint8_t keyBTC = 14; //k
uint8_t keyBTD = 15; //l
uint8_t keyFXL = 6; //c
uint8_t keyFXR = 16; //m
//日本人の方はこちらです
//uint8_t keyFXL = 0x8A; //無変換
//uint8_t keyFXR = 0x8B; //変換
uint8_t keySTART = 43; //Enter
uint8_t keyVOLLCCW = 20; //q
uint8_t keyVOLLCW = 26; //w
uint8_t keyVOLRCCW = 18; //o
uint8_t keyVOLRCW = 19; //p
// -- More options --
//If you experience double presses of buttons when you pressed only once, try increasing this value.
unsigned const long debounceDelay = 5;
//Bigger value makes the knob less sensitive. Note that it should not be 0. When it's 0 when you spin quickly the knob will report both CW and CCW directions.
//Value too low can also make the knob go either direction randomly when you just touch the knob.
unsigned const long spinTolerance = 4;
// ----
Encoder encL(VOLLA,VOLLB);
Encoder encR(VOLRA,VOLRB);
long encLPosition, encRPosition = 0;
uint8_t buf[8] = { 0 };
typedef enum KnobState {
CW,
CCW,
Stop
} KnobState;
bool BTAState, BTBState, BTCState, BTDState, FXLState, FXRState, StartState = LOW;
bool BTAHwState, BTBHwState, BTCHwState, BTDHwState, FXLHwState, FXRHwState, StartHwState = LOW;
KnobState VOLLState, VOLRState = Stop;
unsigned long BTADebounce, BTBDebounce, BTCDebounce, BTDDebounce, FXLDebounce, FXRDebounce, StartDebounce = 0;
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
setupButton(BTA);
setupButton(BTB);
setupButton(BTC);
setupButton(BTD);
setupButton(FXL);
setupButton(FXR);
setupLED(BTLA);
setupLED(BTLB);
setupLED(BTLC);
setupLED(BTLD);
setupLED(FXLL);
setupLED(FXLR);
pinMode(12,OUTPUT);
digitalWrite(12,HIGH);
}
void setupButton(int button)
{
pinMode(button, INPUT_PULLUP);
}
void setupLED(int led)
{
pinMode(led, OUTPUT);
}
void checkButton(int button)
{
int hardwareState = digitalRead(button);
if(hardwareState != getButtonHwState(button))
{
setDebounce(button,millis());
}
if((millis() - getDebounce(button)) > debounceDelay)
{
if(hardwareState == HIGH)
{
if(getButtonState(button) == HIGH)
{
lightOff(button);
setButtonState(button,LOW);
buttonReleaseAction(button);
}
}
else
{
if(getButtonState(button) == LOW)
{
lightOn(button);
releaseKey(button);
setButtonState(button,HIGH);
buttonPressAction(button);
}
}
}
setButtonHwState(button,hardwareState);
}
void lightOff(int inputPin)
{
digitalWrite(buttonToLight(inputPin), LOW);
}
void lightOn(int inputPin)
{
digitalWrite(buttonToLight(inputPin), HIGH);
}
void checkKnob(int knobA, int knobB)
{
int readPosition;
if(knobA == VOLLA || knobB == VOLLB)
{
readPosition = encL.read();
if(readPosition > (long)(encLPosition + spinTolerance))
{
knobLActionCCW();
encLPosition = readPosition;
}
else if(readPosition < (long)(encLPosition - spinTolerance) )
{
knobLActionCW();
encLPosition = readPosition;
}
else
{
knobLActionStop();
}
}
else
{
readPosition = encR.read();
if(readPosition > (long)(encRPosition + spinTolerance))
{
knobRActionCCW();
encRPosition = readPosition;
}
else if(readPosition < (long)(encRPosition - spinTolerance) )
{
knobRActionCW();
encRPosition = readPosition;
}
else
{
knobRActionStop();
}
}
}
void knobLActionCW()
{
debugInput("Spin",VOLLA);
setVolLState(CW);
}
void knobLActionCCW()
{
debugInput("Spin",VOLLB);
setVolLState(CCW);
}
void knobRActionCW()
{
debugInput("Spin",VOLRA);
setVolRState(CW);
}
void knobRActionCCW()
{
debugInput("Spin",VOLRB);
setVolRState(CCW);
}
void knobLActionStop()
{
setVolLState(Stop);
}
void knobRActionStop()
{
setVolRState(Stop);
}
void setVolLState(KnobState state)
{
//only set and send if state changes.
if(VOLLState != state)
{
VOLLState = state;
serialFromState();
}
}
void setVolRState(KnobState state)
{
//only set and send if state changes.
if(VOLRState != state)
{
VOLRState = state;
serialFromState();
}
}
void buttonPressAction(int button)
{
debugInput("Pressed",button);
serialFromState();
}
void buttonReleaseAction(int button)
{
debugInput("Released",button);
serialFromState();
}
void serialFromState()
{
//USB HID limits to 6 keys, which SDVX has 6 + 2 knobs.
//We prioritize buttons first as the knobs can be repeatedly pressed and released.
//Check buttons
int buttons[6] = {BTA,BTB,BTC,BTD,FXL,FXR};
int slotIndex = 2;
for( int i = 0; i < 6; i++)
{
if(getButtonState(buttons[i]) == HIGH)
{
buf[slotIndex] = getKey(buttons[i]);
slotIndex++;
}
}
//Check knobs, if there are more spaces in the message.
if(slotIndex < 8)
{
if(VOLLState == CW)
{
buf[slotIndex] = getKey(VOLLB);
slotIndex++;
}
else if (VOLLState == CCW)
{
buf[slotIndex] = getKey(VOLLA);
slotIndex++;
}
}
if(slotIndex < 8)
{
if(VOLRState == CW)
{
buf[slotIndex] = getKey(VOLRB);
slotIndex++;
}
else if (VOLRState == CCW)
{
buf[slotIndex] = getKey(VOLRA);
slotIndex++;
}
}
//Fill remainings with zeroes. This will be a key-release also.
for(int i = slotIndex; i < 8; i++)
{
buf[slotIndex] = 0;
}
//Send the message
Serial.write(buf, 8);
}
uint8_t getKey(int inputPin)
{
switch(inputPin)
{
case BTA:
{
return keyBTA;
break;
}
case BTB:
{
return keyBTB;
break;
}
case BTC:
{
return keyBTC;
break;
}
case BTD:
{
return keyBTD;
break;
}
case FXL:
{
return keyFXL;
break;
}
case FXR:
{
return keyFXR;
break;
}
case START:
{
return keySTART;
break;
}
case VOLLA:
{
return keyVOLLCCW;
break;
}
case VOLLB:
{
return keyVOLLCW;
break;
}
case VOLRA:
{
return keyVOLRCCW;
break;
}
case VOLRB:
{
return keyVOLRCW;
break;
}
}
}
void debugInput(String message, int inputPort)
{
#ifdef SERIAL_DEBUGGING
Serial.print(message);
Serial.print(" - ");
Serial.println(getName(inputPort));
#endif
}
void setButtonState(int button, bool state)
{
switch(button)
{
case BTA:
{
BTAState = state;
break;
}
case BTB:
{
BTBState = state;
break;
}
case BTC:
{
BTCState = state;
break;
}
case BTD:
{
BTDState = state;
break;
}
case FXL:
{
FXLState = state;
break;
}
case FXR:
{
FXRState = state;
break;
}
case START:
{
StartState = state;
break;
}
}
}
bool getButtonState(int button)
{
switch(button)
{
case BTA:
{
return BTAState;
break;
}
case BTB:
{
return BTBState;
break;
}
case BTC:
{
return BTCState;
break;
}
case BTD:
{
return BTDState;
break;
}
case FXL:
{
return FXLState;
break;
}
case FXR:
{
return FXRState;
break;
}
case START:
{
return StartState;
break;
}
}
}
String getName(int inputPort)
{
switch(inputPort)
{
case BTA:
{
return "BTA";
break;
}
case BTB:
{
return "BTB";
break;
}
case BTC:
{
return "BTC";
break;
}
case BTD:
{
return "BTD";
break;
}
case FXL:
{
return "FXL";
break;
}
case FXR:
{
return "FXR";
break;
}
case START:
{
return "Start";
break;
}
case VOLLA:
{
return "VOL-L CW";
break;
}
case VOLLB:
{
return "VOL-L CCW";
break;
}
case VOLRA:
{
return "VOL-R CW";
break;
}
case VOLRB:
{
return "VOL-R CCW";
break;
}
}
}
bool getButtonHwState(int button)
{
switch(button)
{
case BTA:
{
return BTAHwState;
break;
}
case BTB:
{
return BTBHwState;
break;
}
case BTC:
{
return BTCHwState;
break;
}
case BTD:
{
return BTDHwState;
break;
}
case FXL:
{
return FXLHwState;
break;
}
case FXR:
{
return FXRHwState;
break;
}
case START:
{
return StartHwState;
break;
}
}
}
void setButtonHwState(int button, bool state)
{
switch(button)
{
case BTA:
{
BTAHwState = state;
break;
}
case BTB:
{
BTBHwState = state;
break;
}
case BTC:
{
BTCHwState = state;
break;
}
case BTD:
{
BTDHwState = state;
break;
}
case FXL:
{
FXLHwState = state;
break;
}
case FXR:
{
FXRHwState = state;
break;
}
case START:
{
StartState = state;
break;
}
}
}
void setDebounce(int button, unsigned long value)
{
switch(button)
{
case BTA:
{
BTADebounce = value;
break;
}
case BTB:
{
BTBDebounce = value;
break;
}
case BTC:
{
BTCDebounce = value;
break;
}
case BTD:
{
BTDDebounce = value;
break;
}
case FXL:
{
FXLDebounce = value;
break;
}
case FXR:
{
FXRDebounce = value;
break;
}
case START:
{
StartDebounce = value;
break;
}
}
}
unsigned long getDebounce(int button)
{
switch(button)
{
case BTA:
{
return BTADebounce;
break;
}
case BTB:
{
return BTBDebounce;
break;
}
case BTC:
{
return BTCDebounce;
break;
}
case BTD:
{
return BTDDebounce;
break;
}
case FXL:
{
return FXLDebounce;
break;
}
case FXR:
{
return FXRDebounce;
break;
}
case START:
{
return StartDebounce;
}
}
}
int buttonToLight(int button)
{
switch(button)
{
case BTA:
{
return BTLA;
break;
}
case BTB:
{
return BTLB;
break;
}
case BTC:
{
return BTLC;
break;
}
case BTD:
{
return BTLD;
break;
}
case FXL:
{
return FXLL;
break;
}
case FXR:
{
return FXLR;
break;
}
case START:
{
return STARTL;
break;
}
}
}
void loop() {
checkButton(BTA);
checkButton(BTB);
checkButton(BTC);
checkButton(BTD);
checkButton(FXL);
checkButton(FXR);
checkKnob(VOLLA, VOLLB);
checkKnob(VOLRA, VOLRB);
}
void pressKey()
{
//buf[2] = 128;
//Serial.write(buf, 8);
}
void releaseKey(int button)
{
//buf[0] = 0;
// buf[2] = 0;
// Serial.write(buf, 8); // Release key
}