Issues merging sketches together (Pro Micro - Button Box and Analog E-Brake)

Hey guys, this is my first time dealing with code like this. My understanding from some searching is that my answer may not be as straightforward as I’d hoped.

A quick overview since this might not even be possible. I’m trying to combine and modify two sketches to work for a couple of button boxes I’ve set up and an analog handbrake (pics and wiring diagram attached).

The sketches I am using are from amstudio.

I am also using the Keypad library by Mark Stanley and Alexander Brevig plus this Joystick library:

I have modified the button box sketch to suit my needs however I won’t know if it works until I test it. Here is what I have so far.

//BUTTON BOX 
//USE w ProMicro
//Tested in WIN10 + Assetto Corsa
//AMSTUDIO
//20.8.17

#include <Keypad.h>
#include <Joystick.h>

#define ENABLE_PULLUPS
#define NUMROTARIES 2
#define NUMBUTTONS 18
#define NUMROWS 4
#define NUMCOLS 5


byte buttons[NUMROWS][NUMCOLS] = {
  {0,1,2},
  {3,4,5,6,7},
  {8,9,10,11,12},
  {13,14,15,16,17},
};

struct rotariesdef {
  byte pin1;
  byte pin2;
  int ccwchar;
  int cwchar;
  volatile unsigned char state;
};

rotariesdef rotaries[NUMROTARIES] {
  {0,1,24,25,0},
  {2,3,26,27,0},
};

#define DIR_CCW 0x10
#define DIR_CW 0x20
#define R_START 0x0

#ifdef HALF_STEP
#define R_CCW_BEGIN 0x1
#define R_CW_BEGIN 0x2
#define R_START_M 0x3
#define R_CW_BEGIN_M 0x4
#define R_CCW_BEGIN_M 0x5
const unsigned char ttable[6][4] = {
  // R_START (00)
  {R_START_M,            R_CW_BEGIN,     R_CCW_BEGIN,  R_START},
  // R_CCW_BEGIN
  {R_START_M | DIR_CCW, R_START,        R_CCW_BEGIN,  R_START},
  // R_CW_BEGIN
  {R_START_M | DIR_CW,  R_CW_BEGIN,     R_START,      R_START},
  // R_START_M (11)
  {R_START_M,            R_CCW_BEGIN_M,  R_CW_BEGIN_M, R_START},
  // R_CW_BEGIN_M
  {R_START_M,            R_START_M,      R_CW_BEGIN_M, R_START | DIR_CW},
  // R_CCW_BEGIN_M
  {R_START_M,            R_CCW_BEGIN_M,  R_START_M,    R_START | DIR_CCW},
};
#else
#define R_CW_FINAL 0x1
#define R_CW_BEGIN 0x2
#define R_CW_NEXT 0x3
#define R_CCW_BEGIN 0x4
#define R_CCW_FINAL 0x5
#define R_CCW_NEXT 0x6

const unsigned char ttable[7][4] = {
  // R_START
  {R_START,    R_CW_BEGIN,  R_CCW_BEGIN, R_START},
  // R_CW_FINAL
  {R_CW_NEXT,  R_START,     R_CW_FINAL,  R_START | DIR_CW},
  // R_CW_BEGIN
  {R_CW_NEXT,  R_CW_BEGIN,  R_START,     R_START},
  // R_CW_NEXT
  {R_CW_NEXT,  R_CW_BEGIN,  R_CW_FINAL,  R_START},
  // R_CCW_BEGIN
  {R_CCW_NEXT, R_START,     R_CCW_BEGIN, R_START},
  // R_CCW_FINAL
  {R_CCW_NEXT, R_CCW_FINAL, R_START,     R_START | DIR_CCW},
  // R_CCW_NEXT
  {R_CCW_NEXT, R_CCW_FINAL, R_CCW_BEGIN, R_START},
};
#endif

byte rowPins[NUMROWS] = {20,19,18,15}; 
byte colPins[NUMCOLS] = {14,16,10,9,8}; 

Keypad buttbx = Keypad( makeKeymap(buttons), rowPins, colPins, NUMROWS, NUMCOLS); 

Joystick_ Joystick(JOYSTICK_DEFAULT_REPORT_ID, 
  JOYSTICK_TYPE_JOYSTICK, 18, 0,
  false, false, false, false, false, false,
  false, false, false, false, false);

void setup() {
  Joystick.begin();
  rotary_init();}

void loop() { 

  CheckAllEncoders();

  CheckAllButtons();

}

void CheckAllButtons(void) {
      if (buttbx.getKeys())
    {
       for (int i=0; i<LIST_MAX; i++)   
        {
           if ( buttbx.key[i].stateChanged )   
            {
            switch (buttbx.key[i].kstate) {  
                    case PRESSED:
                    case HOLD:
                              Joystick.setButton(buttbx.key[i].kchar, 1);
                              break;
                    case RELEASED:
                    case IDLE:
                              Joystick.setButton(buttbx.key[i].kchar, 0);
                              break;
            }
           }   
         }
     }
}


void rotary_init() {
  for (int i=0;i<NUMROTARIES;i++) {
    pinMode(rotaries[i].pin1, INPUT);
    pinMode(rotaries[i].pin2, INPUT);
    #ifdef ENABLE_PULLUPS
      digitalWrite(rotaries[i].pin1, HIGH);
      digitalWrite(rotaries[i].pin2, HIGH);
    #endif
  }
}


unsigned char rotary_process(int _i) {
   unsigned char pinstate = (digitalRead(rotaries[_i].pin2) << 1) | digitalRead(rotaries[_i].pin1);
  rotaries[_i].state = ttable[rotaries[_i].state & 0xf][pinstate];
  return (rotaries[_i].state & 0x30);
}

void CheckAllEncoders(void) {
  for (int i=0;i<NUMROTARIES;i++) {
    unsigned char result = rotary_process(i);
    if (result == DIR_CCW) {
      Joystick.setButton(rotaries[i].ccwchar, 1); delay(50); Joystick.setButton(rotaries[i].ccwchar, 0);
    };
    if (result == DIR_CW) {
      Joystick.setButton(rotaries[i].cwchar, 1); delay(50); Joystick.setButton(rotaries[i].cwchar, 0);
    };
  }
}

// Analog eBrake-Handbrake
// PIN A0 to 10k pot output - Throttle Axis
// Use with Arduino ProMicro.
// Tested and working in DiRT RALLY + ASSETTO CORSA
// by AMSTUDIO
// 20.1.2017

void setup()

{pinMode(A3, INPUT); 
   Joystick.begin();}

const int pinToButtonMap = A3;

void loop()

{int pot = analogRead(A3);
int mapped = map(pot,0,1023,0,255);
{Joystick.setThrottle(mapped);}}

I assumed it would be a simple copy and paste of code but I get the following error.

C:\Users\User\Desktop\ButtonBoxandHB\ButtonBoxandHB.ino: In function 'void setup()':

ButtonBoxandHB:171:6: error: redefinition of 'void setup()'

 void setup()

      ^~~~~

C:\Users\User\Desktop\ButtonBoxandHB\ButtonBoxandHB.ino:97:6: note: 'void setup()' previously defined here

 void setup() {

      ^~~~~

C:\Users\User\Desktop\ButtonBoxandHB\ButtonBoxandHB.ino: In function 'void loop()':

ButtonBoxandHB:178:6: error: redefinition of 'void loop()'

 void loop()

      ^~~~

C:\Users\User\Desktop\ButtonBoxandHB\ButtonBoxandHB.ino:101:6: note: 'void loop()' previously defined here

 void loop() {

      ^~~~

exit status 1

redefinition of 'void setup()'

I understand the void functions have already been used in the button box sketch and cannot simply be used again in this manner however I am unsure how to modify them to work in this sketch. Removing them simply creates other errors.

Another issue is that I’m now unsure of how to code the additional switch for the handbrake (for certain games that don’t accept analog input) which I left out of the button matrix because I know the buttons can conflict when used together. Also how to incorporate the “toggle” switch for the ignition which I’d only want a button press when turned on then again when turned off.

I would really appreciate any guidance.

The basic idea is that you copy all the code from the second setup() and paste it into the first setup(). Then you do the same for the two loop()s.

You also need to make sure that the two codes aren't trying to use the same pins but that looks o.k. so far.

When you have that sorted out you can worry about the switches you're talking about. If you need help there you'll want to describe what they do rather better than "I'd only want a button press when turned on then again when turned off"...I have no idea what that means.

Steve

In a sketch you can only have 1 void setup() and 1 void loop()

slipstick:
The basic idea is that you copy all the code from the second setup() and paste it into the first setup(). Then you do the same for the two loop()s.

You also need to make sure that the two codes aren’t trying to use the same pins but that looks o.k. so far.

When you have that sorted out you can worry about the switches you’re talking about. If you need help there you’ll want to describe what they do rather better than “I’d only want a button press when turned on then again when turned off”…I have no idea what that means.

Steve

Ah that makes sense. I’ve done that and now I get no errors when verifying. I successfully uploaded the sketch and the buttons I configured do work however I had to tweak some of the values as I had two buttons that made the same input but I’ve managed to fix that. I also managed to get the rotary switches working.

After some muddling around with the potentiometer I got it working by renaming the joystick library that came bundled with the e-brake sketch which made it show up as a separate game controller. I had to that as the there are two different joystick libraries named the same that are needed for each sketch to work.

Now I have to add the two additional buttons to the sketch. The one for the handbrake (pins 4 and 5) plus the one for the ignition on (pins 6 and 7). I left these out of the matrix as to not interfere with it.

The ignition switch is a 3 position switch with ‘off’, ‘on’, and ‘start’. ‘Off’ isn’t wired, ‘on’ is wired to pins 6 and 7, and ‘start’ is a spring return switch which I’ve wired into the matrix. What I meant in my first post is that when the circuit is closed I want a momentary button press to go to the gamepad. When it is opened I want another momentary button press. Some games have an electronics on button before being able to start the car and it is just a simple button press. The same goes for turning the cars electronics off. The handbrake switch can stay as a regular push button.

So my question now is how can I incorporate such functions into the sketch?

//BUTTON BOX 
//USE w ProMicro
//Tested in WIN10 + Assetto Corsa
//AMSTUDIO
//20.8.17

#include <Keypad.h>
#include <Joystick.h>
#include <teststick.h>

#define ENABLE_PULLUPS
#define NUMROTARIES 2
#define NUMBUTTONS 18
#define NUMROWS 5
#define NUMCOLS 4


byte buttons[NUMROWS][NUMCOLS] = {
  {0,1,2},
  {3,4,5},
  {6,7,8,9},
  {10,11,12,13},
  {14,15,16,17},
};

struct rotariesdef {
  byte pin1;
  byte pin2;
  int ccwchar;
  int cwchar;
  volatile unsigned char state;
};

rotariesdef rotaries[NUMROTARIES] {
  {0,1,18,19,0},
  {2,3,20,21,0},
};

#define DIR_CCW 0x10
#define DIR_CW 0x20
#define R_START 0x0

#ifdef HALF_STEP
#define R_CCW_BEGIN 0x1
#define R_CW_BEGIN 0x2
#define R_START_M 0x3
#define R_CW_BEGIN_M 0x4
#define R_CCW_BEGIN_M 0x5
const unsigned char ttable[6][4] = {
  // R_START (00)
  {R_START_M,            R_CW_BEGIN,     R_CCW_BEGIN,  R_START},
  // R_CCW_BEGIN
  {R_START_M | DIR_CCW, R_START,        R_CCW_BEGIN,  R_START},
  // R_CW_BEGIN
  {R_START_M | DIR_CW,  R_CW_BEGIN,     R_START,      R_START},
  // R_START_M (11)
  {R_START_M,            R_CCW_BEGIN_M,  R_CW_BEGIN_M, R_START},
  // R_CW_BEGIN_M
  {R_START_M,            R_START_M,      R_CW_BEGIN_M, R_START | DIR_CW},
  // R_CCW_BEGIN_M
  {R_START_M,            R_CCW_BEGIN_M,  R_START_M,    R_START | DIR_CCW},
};
#else
#define R_CW_FINAL 0x1
#define R_CW_BEGIN 0x2
#define R_CW_NEXT 0x3
#define R_CCW_BEGIN 0x4
#define R_CCW_FINAL 0x5
#define R_CCW_NEXT 0x6

const unsigned char ttable[7][4] = {
  // R_START
  {R_START,    R_CW_BEGIN,  R_CCW_BEGIN, R_START},
  // R_CW_FINAL
  {R_CW_NEXT,  R_START,     R_CW_FINAL,  R_START | DIR_CW},
  // R_CW_BEGIN
  {R_CW_NEXT,  R_CW_BEGIN,  R_START,     R_START},
  // R_CW_NEXT
  {R_CW_NEXT,  R_CW_BEGIN,  R_CW_FINAL,  R_START},
  // R_CCW_BEGIN
  {R_CCW_NEXT, R_START,     R_CCW_BEGIN, R_START},
  // R_CCW_FINAL
  {R_CCW_NEXT, R_CCW_FINAL, R_START,     R_START | DIR_CCW},
  // R_CCW_NEXT
  {R_CCW_NEXT, R_CCW_FINAL, R_CCW_BEGIN, R_START},
};
#endif

byte rowPins[NUMROWS] = {14,10,16,9,8}; 
byte colPins[NUMCOLS] = {15,18,19,20}; 

Keypad buttbx = Keypad( makeKeymap(buttons), rowPins, colPins, NUMROWS, NUMCOLS); 

Joystick_ Joystick(JOYSTICK_DEFAULT_REPORT_ID, 
  JOYSTICK_TYPE_JOYSTICK, 22, 0,
  false, false, false, false, false, false,
  false, false, false, false, false);

void setup() {
  Joystick.begin();
  rotary_init();

pinMode(A3, INPUT); 
   teststick.begin();

const int pinToButtonMap = A3;}

void loop() { 

  CheckAllEncoders();

  CheckAllButtons();


int pot = analogRead(A3);
int mapped = map(pot,0,1023,0,255);
{teststick.setThrottle(mapped);}

}

void CheckAllButtons(void) {
      if (buttbx.getKeys())
    {
       for (int i=0; i<LIST_MAX; i++)   
        {
           if ( buttbx.key[i].stateChanged )   
            {
            switch (buttbx.key[i].kstate) {  
                    case PRESSED:
                    case HOLD:
                              Joystick.setButton(buttbx.key[i].kchar, 1);
                              break;
                    case RELEASED:
                    case IDLE:
                              Joystick.setButton(buttbx.key[i].kchar, 0);
                              break;
            }
           }   
         }
     }
}


void rotary_init() {
  for (int i=0;i<NUMROTARIES;i++) {
    pinMode(rotaries[i].pin1, INPUT);
    pinMode(rotaries[i].pin2, INPUT);
    #ifdef ENABLE_PULLUPS
      digitalWrite(rotaries[i].pin1, HIGH);
      digitalWrite(rotaries[i].pin2, HIGH);
    #endif
  }
}


unsigned char rotary_process(int _i) {
   unsigned char pinstate = (digitalRead(rotaries[_i].pin2) << 1) | digitalRead(rotaries[_i].pin1);
  rotaries[_i].state = ttable[rotaries[_i].state & 0xf][pinstate];
  return (rotaries[_i].state & 0x30);
}

void CheckAllEncoders(void) {
  for (int i=0;i<NUMROTARIES;i++) {
    unsigned char result = rotary_process(i);
    if (result == DIR_CCW) {
      Joystick.setButton(rotaries[i].ccwchar, 1); delay(50); Joystick.setButton(rotaries[i].ccwchar, 0);
    };
    if (result == DIR_CW) {
      Joystick.setButton(rotaries[i].cwchar, 1); delay(50); Joystick.setButton(rotaries[i].cwchar, 0);
    };
  }
}