// --------------------------------------------
// 32 digital buttons to USB interface
// 
// KEYCODES MUST be set into _keymapper table.
// Note : Key mapping is set to Mame frontend
// Target : Teensy 2.0
// IDE : Arduino 1.0.5
// --------------------------------------------
// WEB : buzz.computer@free.fr
// Update : 13/10/2014
// --------------------------------------------

// Input bits 
// ports 0 to 7 (D0 to D7)
 
// Address selection bank (2 bits)
#define SEL_A 8 // Bit 0
#define SEL_B 9 // Bit 1

// -----
// KEYS
// -----
// Player 1
// --------
// J1_UP
// J1_DOWN
// J1_LEFT
// J1_RIGHT
// J1_B1 (LEFT-UP)
// J1_B2 (MIDDLE-UP)
// J1_B3 (RIGHT-UP)
// J1_B4 (LEFT-DOWN)
// J1_B5 (MIDDLE-DOWN)
// J1_B6 (RIGHT-DOWN)
// J1_B7 (LEFT-FRONT)
// J1_B8 (LEFT-BACK)

// Player 2
// --------
// J2_UP
// J2_DOWN
// J2_LEFT
// J2_RIGHT
// J2_B1 (LEFT-UP)
// J2_B2 (MIDDLE-UP)
// J2_B3 (RIGHT-UP)
// J2_B4 (LEFT-DOWN)
// J2_B5 (MIDDLE-DOWN)
// J2_B6 (RIGHT-DOWN)
// J2_B7 (RIGHT-FRONT)
// J2_B8 (RIGHT-BACK)

// Mame
// MAME_START
// MAME_STOP
// MAME_COINS
// MAME_EXTRA
// MAME_1_PLAYER
// MAME_2_PLAYER

// Each input are associated to a default MAME key
int _keymapper[] = { // 0x4000 => Key, 0x8000 => Modifier
  // Bank 0
  KEY_UP, // J1_UP
  KEY_DOWN, // J1_DOWN
  KEY_LEFT, // J1_LEFT
  KEY_RIGHT, // J1_RIGHT
  KEY_R, // J2_UP
  KEY_F, // J2_DOWN
  KEY_D, // J2_LEFT
  KEY_G, // J2_RIGHT

  // Bank 1
  MODIFIERKEY_LEFT_CTRL, // J1_B1 (LEFT-UP)    => Fire 1
  MODIFIERKEY_LEFT_ALT, // J1_B2 (MIDDLE-UP)   => Fire 2
  KEY_SPACE, // J1_B3 (RIGHT-UP)               => Fire 3
  MODIFIERKEY_LEFT_CTRL, // J1_B7 (LEFT-FRONT) => Fire 1
  KEY_A, // J2_B1 (LEFT-UP)                    => Fire 1
  KEY_S, // J2_B2 (MIDDLE-UP)                  => Fire 2
  KEY_Q, // J2_B3 (RIGHT-UP)                   => Fire 3
  KEY_A, // J2_B7 (LEFT-FRONT)                 => Fire 1

  // Bank 2
  MODIFIERKEY_LEFT_SHIFT, // J1_B4 (LEFT-DOWN) => Fire 4
  KEY_Z, // J1_B5 (MIDDLE-DOWN)                => Fire 5
  KEY_X, // J1_B6 (RIGHT-DOWN)                 => Fire 6
  KEY_T, // J1_B8 (RIGHT-BACK) => Tilt
  KEY_W, // J2_B4 (LEFT-DOWN)
  0, // J2_B5 (MIDDLE-DOWN) => Not set by default
  0, // J2_B6 (RIGHT-DOWN) => Not set by default
  KEY_T, // J2_B8 (RIGHT-BACK) => Tilt

  // Bank 3
  KEY_ENTER, // MAME_START
  KEY_ESC, // MAME_STOP
  KEY_6, // MAME_COINS
  KEY_P, // MAME_EXTRA              => Pause
  KEY_1, // MAME_1_PLAYER
  KEY_2, // MAME_2_PLAYER
  0, // None
  0  // None
};

void setup() {
  // Bank are configured as inputs
  for (byte i = 0; i < 8; ++i) {
    pinMode (i, INPUT_PULLUP); // PULLUP is mandatory here
  }
 
  // Bank selection bits
  pinMode (SEL_A, OUTPUT);
  pinMode (SEL_B, OUTPUT);
  digitalWrite (SEL_A, 0); // Bank 0 (Bit 0)
  digitalWrite (SEL_B, 0); // Bank 0 (Bit 1)
}

bool isModifier (int value) {
  if (value & 0x8000) return true;
  return false;
}

bool isKey (int value) {
  if (value & 0x4000) return true;
  return false; 
}

void checkAndSend () {
  int modifier = 0;
  
  // Iterate over 4 banks
  for (byte bank = 0; bank < 4; ++bank) {
    // Switch the bank first
    digitalWrite(SEL_A, bank & 0x01); // Bit 0
    digitalWrite(SEL_B, bank & 0x02); // Bit 1
   
    // Get the 8 inputs
    for (byte i = 0; i < 8; ++i) { 
       int value = digitalRead(i);
       if (!value) { // Button pressed
         int keycode = _keymapper[(bank*8)+i];
         if (isModifier (keycode)) {
           modifier |= keycode; 
         }
         else if (isKey(keycode)) {
           Keyboard.set_key1(keycode);
           Keyboard.send_now();
         }  
      } 
    } // 8 Inputs
  } // Bank
  
  // Modifiers 
  Keyboard.set_modifier (modifier); 
  Keyboard.set_key1 (0); // Stop sending key
  Keyboard.send_now(); // To update modifier   
}

void loop() {
  checkAndSend();
  delay (20); // Just wait
}  


