G27_Pedals_and_Shifter/G27_Pedals_and_Shifter.ino

415 lines
11 KiB
C++

// G27_Pedals_and_Shifter.ino
// by Jason Duncan
// Partially adapted from the work done by isrtv.com forums members pascalh and xxValiumxx:
// http://www.isrtv.com/forums/topic/13189-diy-g25-shifter-interface-with-h-pattern-sequential-and-handbrake-modes/
#include "Joystick.h"
// for debugging, gives serial output rather than working as a joystick
//#define DEBUG true
#if defined(DEBUG)
#define DEBUG_PEDALS true
#define DEBUG_SHIFTER true
#endif
//#define DEBUG_PEDALS true
//#define DEBUG_SHIFTER true
// red for brake, green for gas, blue for clutch
//#define PEDAL_COLORS true
// LED PINS
#define RED_PIN 3
#define GREEN_PIN 5
#define BLUE_PIN 6
// PEDAL PINS
//| DB9 | Original | Harness | Description | Pro Micro |
//| 1 | Black | Red | +5v | +5v |
//| 2 | Orange | Yellow | Throttle | pin 18 (A0) |
//| 3 | White | White | Brake | pin 19 (A1) |
//| 4 | Green | Green | Clutch | pin 20 (A2) |
//| 5 | | | | |
//| 6 | Red | Black | GND | GND |
//| 7 | | | | |
//| 8 | | | | |
//| 9 | Red | Black | GND | GND |
#define GAS_PIN 18
#define BRAKE_PIN 19
#define CLUTCH_PIN 20
// SHIFTER PINS
//| DB9 | Original | Harness | Shifter | Description | Pro Micro |
//| 1 | Purple | Purple | 1 | Button Clock | pin 0 |
//| 2 | Grey | Blue | 7 | Button Data | pin 1 |
//| 3 | Yellow | Yellow | 5 | Button !CS & !PL (Mode) | pin 4 |
//| 4 | Orange | Orange | 3 | Shifter X axis | pin 8 (A8) |
//| 5 | White | White | 2 | SPI input | |
//| 6 | Black | Black | 8 | GND | GND |
//| 7 | Red | Red | 6 | +5V | VCC |
//| 8 | Green | Green | 4 | Shifter Y axis | pin 9 (A9) |
//| 9 | Red | Red | 1 | +5V | VCC |
#define SHIFTER_CLOCK_PIN 0
#define SHIFTER_DATA_PIN 1
#define SHIFTER_MODE_PIN 4
#define SHIFTER_X_PIN 8
#define SHIFTER_Y_PIN 9
// BUTTON DEFINITIONS
#define BUTTON_REVERSE 1
#define BUTTON_RED_CENTERRIGHT 4
#define BUTTON_RED_CENTERLEFT 5
#define BUTTON_RED_RIGHT 6
#define BUTTON_RED_LEFT 7
#define BUTTON_BLACK_TOP 8
#define BUTTON_BLACK_RIGHT 9
#define BUTTON_BLACK_LEFT 10
#define BUTTON_BLACK_BOTTOM 11
#define BUTTON_DPAD_RIGHT 12
#define BUTTON_DPAD_LEFT 13
#define BUTTON_DPAD_BOTTOM 14
#define BUTTON_DPAD_TOP 15
#define OUTPUT_BLACK_TOP 7
#define OUTPUT_BLACK_LEFT 8
#define OUTPUT_BLACK_RIGHT 9
#define OUTPUT_BLACK_BOTTOM 10
#define OUTPUT_DPAD_TOP 11
#define OUTPUT_DPAD_LEFT 12
#define OUTPUT_DPAD_RIGHT 13
#define OUTPUT_DPAD_BOTTOM 14
#define OUTPUT_RED_LEFT 15
#define OUTPUT_RED_CENTERLEFT 16
#define OUTPUT_RED_CENTERRIGHT 17
#define OUTPUT_RED_RIGHT 18
// SHIFTER AXIS THRESHOLDS
#define SHIFTER_XAXIS_12 330 //Gears 1,2
#define SHIFTER_XAXIS_56 620 //Gears 5,6, R
#define SHIFTER_YAXIS_135 600 //Gears 1,3,5
#define SHIFTER_YAXIS_246 300 //Gears 2,4,6, R
// MISC.
#define MAX_AXIS 127
#define SIGNAL_SETTLE_DELAY 10
// PEDAL CODE
typedef struct pedal {
int pin, min, max, cur, axis;
};
typedef struct pedal Pedal;
void* gasPedal;
void* brakePedal;
void* clutchPedal;
int axisValue(void* in) {
Pedal* input = (Pedal*)in;
int range = input->max - input->min;
if (range == 0) {
return -MAX_AXIS;
}
long step1 = input->cur - input->min;
long step2 = step1 * (MAX_AXIS * 2);
float step3 = step2 / range;
int result = step3 - MAX_AXIS;
if (result < -MAX_AXIS) {
return -MAX_AXIS;
}
if (result > MAX_AXIS) {
return MAX_AXIS;
}
return result;
}
void processPedal(void* in) {
Pedal* input = (Pedal*)in;
input->cur = analogRead(input->pin);
// calibrate, we want the highest this pedal has been
input->max = input->cur > input->max ? input->cur : input->max;
// same for lowest, but bottom out at current value rather than 0
input->min = input->min == 0 || input->cur < input->min ? input->cur : input->min;
input->axis = axisValue(input);
}
void describePedal(char* name, char* axisName, void* in) {
Pedal* input = (Pedal*)in;
Serial.print("\nPIN: ");
Serial.print(input->pin);
Serial.print(" ");
Serial.print(name);
Serial.print(": ");
Serial.print(input->cur);
Serial.print(" MIN: ");
Serial.print(input->min);
Serial.print(" MAX: ");
Serial.print(input->max);
Serial.print(" ");
Serial.print(axisName);
Serial.print(" VALUE: ");
Serial.print(input->axis);
}
void setXAxis(void* in) {
Pedal* input = (Pedal*)in;
Joystick.setXAxis(input->axis);
}
void setYAxis(void* in) {
Pedal* input = (Pedal*)in;
Joystick.setYAxis(input->axis);
}
void setZAxis(void* in) {
Pedal* input = (Pedal*)in;
Joystick.setZAxis(input->axis);
}
void pedalColor(void* inGas, void* inBrake, void* inClutch){
Pedal* gas = (Pedal*)inGas;
Pedal* brake = (Pedal*)inBrake;
Pedal* clutch = (Pedal*)inClutch;
setColor(brake->axis + MAX_AXIS, gas->axis + MAX_AXIS, clutch->axis + MAX_AXIS);
}
// SHIFTER CODE
int buttonTable[] = {
// first four are unused
0, 0, 0, 0,
OUTPUT_RED_CENTERRIGHT,
OUTPUT_RED_CENTERLEFT,
OUTPUT_RED_RIGHT,
OUTPUT_RED_LEFT,
OUTPUT_BLACK_TOP,
OUTPUT_BLACK_RIGHT,
OUTPUT_BLACK_LEFT,
OUTPUT_BLACK_BOTTOM,
OUTPUT_DPAD_RIGHT,
OUTPUT_DPAD_LEFT,
OUTPUT_DPAD_BOTTOM,
OUTPUT_DPAD_TOP
};
void waitForSignalToSettle() {
delayMicroseconds(SIGNAL_SETTLE_DELAY);
}
void getButtonStates(int *ret) {
digitalWrite(SHIFTER_MODE_PIN, LOW); // Switch to parallel mode: digital inputs are read into shift register
waitForSignalToSettle();
digitalWrite(SHIFTER_MODE_PIN, HIGH); // Switch to serial mode: one data bit is output on each clock falling edge
#if defined(DEBUG_SHIFTER)
Serial.print("\nBUTTON STATES:");
#endif
for(int i = 0; i < 16; ++i) { // Iteration over both 8 bit registers
digitalWrite(SHIFTER_CLOCK_PIN, LOW); // Generate clock falling edge
waitForSignalToSettle();
ret[i] = digitalRead(SHIFTER_DATA_PIN);
#if defined(DEBUG_SHIFTER)
if (!(i % 4)) Serial.print("\n");
Serial.print(" button");
if (i < 10) Serial.print(0);
Serial.print(i);
Serial.print(" = ");
Serial.print(ret[i]);
#endif
digitalWrite(SHIFTER_CLOCK_PIN, HIGH); // Generate clock rising edge
waitForSignalToSettle();
}
}
void getShifterPosition(int *ret) {
ret[0] = analogRead(SHIFTER_X_PIN);
ret[1] = analogRead(SHIFTER_Y_PIN);
}
int getCurrentGear(int shifterPosition[], int btns[]) {
int gear = 0; // default to neutral
int x = shifterPosition[0], y = shifterPosition[1];
if (x < SHIFTER_XAXIS_12) // Shifter on the left?
{
if (y > SHIFTER_YAXIS_135) gear = 1; // 1st gear
if (y < SHIFTER_YAXIS_246) gear = 2; // 2nd gear
}
else if (x > SHIFTER_XAXIS_56) // Shifter on the right?
{
if (y > SHIFTER_YAXIS_135) gear = 5; // 5th gear
if (y < SHIFTER_YAXIS_246) gear = 6; // 6th gear
}
else // Shifter is in the middle
{
if (y > SHIFTER_YAXIS_135) gear = 3; // 3rd gear
if (y < SHIFTER_YAXIS_246) gear = 4; // 4th gear
}
if (gear != 6) btns[BUTTON_REVERSE] = 0; // Reverse gear is allowed only on 6th gear position
if (btns[BUTTON_REVERSE] == 1) gear = 7; // Reverse is 7th gear (for the sake of argument)
return gear;
}
void setButtonStates(int buttons[], int gear) {
// release virtual buttons for all gears
for (byte i = 0; i < 7; ++i) {
Joystick.setButton(i, LOW);
}
if (gear > 0) {
Joystick.setButton(gear - 1, HIGH);
}
for (byte i = BUTTON_RED_CENTERRIGHT; i <= BUTTON_DPAD_TOP; ++i) {
Joystick.setButton(buttonTable[i], buttons[i]);
}
}
void describeButtonStates(int buttons[], int shifterPosition[], int gear) {
Serial.print("\nSHIFTER X: ");
Serial.print(shifterPosition[0]);
Serial.print(" Y: ");
Serial.print(shifterPosition[1]);
Serial.print(" GEAR: ");
Serial.print(gear);
Serial.print(" REVERSE: ");
Serial.print(buttons[BUTTON_REVERSE]);
Serial.print(" RED BUTTONS:");
if (buttons[BUTTON_RED_LEFT]) {
Serial.print(" 1");
}
if (buttons[BUTTON_RED_CENTERLEFT]) {
Serial.print(" 2");
}
if (buttons[BUTTON_RED_CENTERLEFT]) {
Serial.print(" 3");
}
if (buttons[BUTTON_RED_RIGHT]) {
Serial.print(" 4");
}
Serial.print(" BLACK BUTTONS:");
if (buttons[BUTTON_BLACK_LEFT]) {
Serial.print(" LEFT");
}
if (buttons[BUTTON_BLACK_TOP]) {
Serial.print(" TOP");
}
if (buttons[BUTTON_BLACK_BOTTOM]) {
Serial.print(" BOTTOM");
}
if (buttons[BUTTON_BLACK_RIGHT]) {
Serial.print(" RIGHT");
}
Serial.print(" D-PAD:");
if (buttons[BUTTON_DPAD_LEFT]) {
Serial.print(" LEFT");
}
if (buttons[BUTTON_DPAD_TOP]) {
Serial.print(" UP");
}
if (buttons[BUTTON_DPAD_BOTTOM]) {
Serial.print(" DOWN");
}
if (buttons[BUTTON_DPAD_RIGHT]) {
Serial.print(" RIGHT");
}
}
void setup() {
Serial.begin(38400);
#if !defined(DEBUG_PEDALS) && !defined(DEBUG_SHIFTER)
Joystick.begin(false);
#endif
// lights
pinMode(RED_PIN, OUTPUT);
pinMode(GREEN_PIN, OUTPUT);
pinMode(BLUE_PIN, OUTPUT);
// shifter
pinMode(SHIFTER_MODE_PIN, OUTPUT);
pinMode(SHIFTER_CLOCK_PIN, OUTPUT);
digitalWrite(SHIFTER_MODE_PIN, HIGH);
digitalWrite(SHIFTER_CLOCK_PIN, HIGH);
// pedals
Pedal* gas = new Pedal();
Pedal* brake = new Pedal();
Pedal* clutch = new Pedal();
gas->pin = GAS_PIN;
brake->pin = BRAKE_PIN;
clutch->pin = CLUTCH_PIN;
gasPedal = gas;
brakePedal = brake;
clutchPedal = clutch;
}
void loop() {
// pedals
processPedal(gasPedal);
processPedal(brakePedal);
processPedal(clutchPedal);
#if defined(DEBUG_PEDALS)
describePedal("GAS", "X", gasPedal);
describePedal("BRAKE", "Y", brakePedal);
describePedal("CLUTCH", "Z", clutchPedal);
#else
setXAxis(gasPedal);
setYAxis(brakePedal);
setZAxis(clutchPedal);
#endif
#if defined(PEDAL_COLORS)
pedalColor(gasPedal, brakePedal, clutchPedal);
#endif
// shifter
int buttonStates[16];
getButtonStates(buttonStates);
int shifterPosition[2];
getShifterPosition(shifterPosition);
int gear = getCurrentGear(shifterPosition, buttonStates);
#if defined(DEBUG_SHIFTER)
describeButtonStates(buttonStates, shifterPosition, gear);
#else
setButtonStates(buttonStates, gear);
Joystick.sendState();
#endif
#if defined(DEBUG_PEDALS) || defined(DEBUG_SHIFTER)
Serial.print("\n----------------------------------------------------------------------------");
// slow the output down a bit
delay(500);
#endif
}
void setColor(int red, int green, int blue) {
analogWrite(RED_PIN, red);
analogWrite(GREEN_PIN, green);
analogWrite(BLUE_PIN, blue);
}