1. For downloading SimTools plugins you need a Download Package. Get it with virtual coins that you receive for forum activity or Buy Download Package - We have a zero Spam tolerance so read our forum rules first.

    Buy Download Package Now!
  2. Do not try to cheat our system and do not post an unnecessary amount of useless posts only to earn credits here. We have a zero spam tolerance policy and this will cause a ban of your user account. Otherwise we wish you a pleasant stay here! Read the forum rules
  3. We have a few rules which you need to read and accept before posting anything here! Following these rules will keep the forum clean and your stay pleasant here. Do not following these rules will lead to permanent exclusion from this website: Read the forum rules.

G27 Shifter and buttons - Standalone USB.

Discussion in 'DIY peripherals' started by Archie, Jan 24, 2017.

  1. Archie

    Archie Eternal tinkerer

    Joined:
    Dec 31, 2014
    Messages:
    1,083
    Location:
    Wollongong, NSW, AU
    Balance:
    3,686Coins
    Ratings:
    +1,369 / 4 / -0
    My Motion Simulator:
    2DOF, DC motor, JRK
    Hi Everyone,

    As happy as I am with my Fanatec wheel (CSR) I can't afford to get the SQ shifter.

    The standard ones on the Fanatec are plain awful, but the G27 Shifter is actually still OK for the job.
    (Especially because my G27 shifter has a nice heavy gear knob for added "clunk")

    I found this code on Github and modified to just pull out the Shifter part.

    It's recognised in Windows as a USB-HID device and the buttons and Shifter work well.
    You need to mess about with the X/Y values to match the Shifter position, but that is easy enough - It's outlined on the original github README.md.

    I had to reverse Pin 1 and 0 on my build. Not sure why, you can read the Issue on Github here, however I have left the code "as is" just in case my Pro Micro board is the issue and not the code.

    https://github.com/functionreturnfunction/G27_Pedals_and_Shifter/issues/11

    I used the following parts:

    1 x DB9 Male
    http://www.ebay.com.au/itm/111159749065
    1 x Pro Micro ATmega32U4 5V 16MHz (Sparkfun clone)
    http://www.ebay.com.au/itm/201252082703

    You can read more about the original project from the link below:

    https://github.com/functionreturnfunction/G27_Pedals_and_Shifter

    IMG_9883.JPG
    IMG_9882.JPG
    IMG_9881.JPG
    IMG_9880.JPG



    Code:
    // G27_Shifter_USB
    
    #include <HID.h>
    #include <G27PedalsShifter.h>
    
    #define USE_SHIFTER
    
    // 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        350 //Gears 1,2
    #define SHIFTER_XAXIS_56        600 //Gears 5,6, R
    #define SHIFTER_YAXIS_135       800 //Gears 1,3,5
    #define SHIFTER_YAXIS_246       90 //Gears 2,4,6, R
    
    // MISC.
    #define MAX_AXIS            1023
    #define SIGNAL_SETTLE_DELAY 10
    
    // 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) {
        G27.setButton(i, LOW);
      }
    
      if (gear > 0) {
        G27.setButton(gear - 1, HIGH);
      }
    
      for (byte i = BUTTON_RED_CENTERRIGHT; i <= BUTTON_DPAD_TOP; ++i) {
        G27.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_SHIFTER)
      G27.begin(false);
    #endif
    
      // shifter
      pinMode(SHIFTER_MODE_PIN, OUTPUT);
      pinMode(SHIFTER_CLOCK_PIN, OUTPUT);
    
      digitalWrite(SHIFTER_MODE_PIN, HIGH);
      digitalWrite(SHIFTER_CLOCK_PIN, HIGH);
    }
    
    void loop() {
      // shifter
      int buttonStates[16];
      getButtonStates(buttonStates);
      int shifterPosition[2];
      getShifterPosition(shifterPosition);
      int gear = getCurrentGear(shifterPosition, buttonStates);
    
    #if defined(DEBUG_SHIFTER)
      describeButtonStates(buttonStates, shifterPosition, gear);
    #elif defined(USE_SHIFTER)
      setButtonStates(buttonStates, gear);
    #endif
    
    #if !defined(DEBUG_SHIFTER) || !defined(DEBUG_PEDALS)
      G27.sendState();
    #endif
    }
    
    • Like Like x 1
    • Informative Informative x 1
    Last edited: Jan 24, 2017
  2. Ads Master

    Ads Master

    Balance:
    Coins
    Ratings:
    +0 / 0 / -0
  3. Archie

    Archie Eternal tinkerer

    Joined:
    Dec 31, 2014
    Messages:
    1,083
    Location:
    Wollongong, NSW, AU
    Balance:
    3,686Coins
    Ratings:
    +1,369 / 4 / -0
    My Motion Simulator:
    2DOF, DC motor, JRK
    Some more pics..

    It's tiny and weighs nothing. Could likely integrate straight into the shifter!

    IMG_9888.JPG

    Appears as a Game Controller.

    IMG_9886.JPG


    1st Gear engaged and pressing the Red button. All other buttons work as
    does the D-PAD.

    IMG_9885.JPG

    Attached Files:

    • Like Like x 2
    • Creative Creative x 1
  4. mm982566

    mm982566 New Member

    Joined:
    Sep 22, 2017
    Messages:
    18
    Location:
    广东东莞
    Balance:
    178Coins
    Ratings:
    +2 / 0 / -0
    My Motion Simulator:
    2DOF
    This code I compile the times wrong, as if there is a G27 called not declared, can you help me? Thank you
  5. mm982566

    mm982566 New Member

    Joined:
    Sep 22, 2017
    Messages:
    18
    Location:
    广东东莞
    Balance:
    178Coins
    Ratings:
    +2 / 0 / -0
    My Motion Simulator:
    2DOF
    This code I compile the times wrong, as if there is a G27 called not declared, can you help me? Thank you
  6. Archie

    Archie Eternal tinkerer

    Joined:
    Dec 31, 2014
    Messages:
    1,083
    Location:
    Wollongong, NSW, AU
    Balance:
    3,686Coins
    Ratings:
    +1,369 / 4 / -0
    My Motion Simulator:
    2DOF, DC motor, JRK
    Can you give more details of the issues??
    When does the error happen?
    Do you have the correct SparkFun style board?
  7. mm982566

    mm982566 New Member

    Joined:
    Sep 22, 2017
    Messages:
    18
    Location:
    广东东莞
    Balance:
    178Coins
    Ratings:
    +2 / 0 / -0
    My Motion Simulator:
    2DOF
    At first I wanted to use Arduino to download the Pro micro and then make a mistake. I want to change the method, I want to compile it first. Hex firmware is downloaded in, but there is no way to compile it. If convenient, can you compile the hex firmware? thank you
  8. Fernando Igor

    Fernando Igor Member

    Joined:
    Jul 24, 2017
    Messages:
    53
    Occupation:
    Programmer
    Location:
    Fortaleza, Brazil
    Balance:
    856Coins
    Ratings:
    +18 / 0 / -0
    My Motion Simulator:
    DC motor, Arduino
    ERROR: The G27 was not declared in the function.
    The G27 object is declared in the ./lib/G27PedalsShifter.cpp file, probably the arduino IDE is not loading correctly.

    Try:
    1)

    rename folder "lib" to "G27PedalsShifter"
    and copy (or cut) the folder to:

    "C: /../ installationDirectory / Arduino / libraries /"

    2)
    in the main file, change the line:
    #include "./lib/G27PedalsShifter.h"
    to
    #include "G27PedalsShifter.h"
  9. mm982566

    mm982566 New Member

    Joined:
    Sep 22, 2017
    Messages:
    18
    Location:
    广东东莞
    Balance:
    178Coins
    Ratings:
    +2 / 0 / -0
    My Motion Simulator:
    2DOF
    Same error message.
    But thank you anyway.
  10. Fernando Igor

    Fernando Igor Member

    Joined:
    Jul 24, 2017
    Messages:
    53
    Occupation:
    Programmer
    Location:
    Fortaleza, Brazil
    Balance:
    856Coins
    Ratings:
    +18 / 0 / -0
    My Motion Simulator:
    DC motor, Arduino
  11. mm982566

    mm982566 New Member

    Joined:
    Sep 22, 2017
    Messages:
    18
    Location:
    广东东莞
    Balance:
    178Coins
    Ratings:
    +2 / 0 / -0
    My Motion Simulator:
    2DOF
  12. Archie

    Archie Eternal tinkerer

    Joined:
    Dec 31, 2014
    Messages:
    1,083
    Location:
    Wollongong, NSW, AU
    Balance:
    3,686Coins
    Ratings:
    +1,369 / 4 / -0
    My Motion Simulator:
    2DOF, DC motor, JRK
    • Funny Funny x 1
    • Friendly Friendly x 1
  13. mm982566

    mm982566 New Member

    Joined:
    Sep 22, 2017
    Messages:
    18
    Location:
    广东东莞
    Balance:
    178Coins
    Ratings:
    +2 / 0 / -0
    My Motion Simulator:
    2DOF
  14. mm982566

    mm982566 New Member

    Joined:
    Sep 22, 2017
    Messages:
    18
    Location:
    广东东莞
    Balance:
    178Coins
    Ratings:
    +2 / 0 / -0
    My Motion Simulator:
    2DOF
    I can't use it in European truck simulation. I don't know how to solve it. Thank you.
  15. donovan

    donovan New Member

    Joined:
    Apr 7, 2014
    Messages:
    24
    Balance:
    87Coins
    Ratings:
    +8 / 0 / -0
    My Motion Simulator:
    2DOF, 3DOF, Arduino
  16. Archie

    Archie Eternal tinkerer

    Joined:
    Dec 31, 2014
    Messages:
    1,083
    Location:
    Wollongong, NSW, AU
    Balance:
    3,686Coins
    Ratings:
    +1,369 / 4 / -0
    My Motion Simulator:
    2DOF, DC motor, JRK
    I know I am reviving my own old thread here, but by Pro Micro USB connector snapped so I had to program a new one.

    I then realised that my steps were not complete when I followed my own guide. :oops:

    you will need to add the "Sparkfun" boards to the Arduino IDE and then compile for the "Pro Micro" board.
    If you don't do this step you will get compile errors that 'G27' variable is out of scope.

    Here is the link to how to install the boards into the Arduino IDE.

    https://github.com/sparkfun/arduino_boards

    Tested on the latest Arduino Build and works just fine! :)
    • Like Like x 1
    • Useful Useful x 1
  17. Archie

    Archie Eternal tinkerer

    Joined:
    Dec 31, 2014
    Messages:
    1,083
    Location:
    Wollongong, NSW, AU
    Balance:
    3,686Coins
    Ratings:
    +1,369 / 4 / -0
    My Motion Simulator:
    2DOF, DC motor, JRK
    • Like Like x 1