1
0
mirror of https://github.com/mcgurk/Arduino-USB-HID-RetroJoystickAdapter synced 2024-11-14 05:05:01 -05:00
Arduino-USB-HID-RetroJoysti.../RetroJoystickAdapter.ino

386 lines
11 KiB
Arduino
Raw Normal View History

2016-09-05 15:28:34 -04:00
#include "Joystick2.h"
/*
#define ATARI
//DB9 (8=GND): 1 2 3 4 5 6 7 8 9
const uint8_t inputPinsPort1[] = {10, 16, 14, 15, A1, 0, 0, 0, 3};
const uint8_t inputPinsPort2[] = { 5, 6, 7, 8, A2, 0, 0, 0, 4};
*/
//#define NES
#define SNES
//Connector (Connect also GND and 5V): CUP, OUT0, D1
const uint8_t inputPinsPort1[] = { 7, 8, 9 };
const uint8_t inputPinsPort2[] = { 2, 3, 4 };
/*
//#define GENESIS_3
#define GENESIS_6
//DB9 (8=GND, 5=VCC): 1 2 3 4 5 6 7 8 9
const uint8_t inputPinsPort1[] = {10, 16, 14, 15, A0, 3, A3, 0, A1};
const uint8_t inputPinsPort2[] = { 5, 6, 7, 8, 9, 4, 2, 0, A2};
*/
//#define KONAMI
void KonamiCode(uint8_t j, uint8_t swap_ab = 0);
//--------ATARI/SMS--------
#ifdef ATARI
#define EVENTS_TOTAL 4+2 //4 directions, 2 fire-buttons
void setupJoysticks() {
for (int i=0; i < 9; i++) {
pinMode(inputPinsPort1[i], INPUT_PULLUP);
pinMode(inputPinsPort2[i], INPUT_PULLUP);
}
}
void readJoysticks(uint8_t *status1, uint8_t *status2) {
for (uint8_t i=0; i < 4; i++) {
status1[i] = digitalRead(inputPinsPort1[i]); //AXES1
status2[i] = digitalRead(inputPinsPort2[i]); //AXES2
}
status1[4] = digitalRead(inputPinsPort1[8]); //A1
status1[5] = digitalRead(inputPinsPort1[4]); //B1
status2[4] = digitalRead(inputPinsPort2[8]); //A2
status2[5] = digitalRead(inputPinsPort2[4]); //B2
}
void interpretJoystickState(uint8_t j, uint8_t *status) {
Joystick[j].setYAxis(0);
Joystick[j].setXAxis(0);
if (!status[0]) Joystick[j].setYAxis(-127); //UP
if (!status[1]) Joystick[j].setYAxis(127); //DOWN
if (!status[2]) Joystick[j].setXAxis(-127); //LEFT
if (!status[3]) Joystick[j].setXAxis(127); //RIGHT
Joystick[j].setButton(2, !status[4]); //BUTTON3 (A)
Joystick[j].setButton(3, !status[5]); //BUTTON4 (B)
}
#endif
//--------Megadrive/Genesis (6-button)--------
//https://www.cs.cmu.edu/~chuck/infopg/segasix.txt
#if defined(GENESIS_3) || defined(GENESIS_6)
#define MODE_SELECT_PORT1 inputPinsPort1[6]
#define MODE_SELECT_PORT2 inputPinsPort2[6]
#define VCC_PORT1 inputPinsPort1[4]
#define VCC_PORT2 inputPinsPort2[4]
#ifdef GENESIS_3
#define EVENTS_TOTAL 4+3+1 //4 directions, 3 fire-buttons and Start
#else
#define EVENTS_TOTAL 4+6+1 //4 directions, 6 fire-buttons and Start
#endif
void modeSelect(uint8_t m) {
digitalWrite(MODE_SELECT_PORT1, m);
digitalWrite(MODE_SELECT_PORT2, m);
delayMicroseconds(20);
}
void setupJoysticks() {
if (VCC_PORT1 != 0) {
pinMode(VCC_PORT1, OUTPUT);
digitalWrite(VCC_PORT1, HIGH);
}
if (VCC_PORT2 != 0) {
pinMode(VCC_PORT2, OUTPUT);
digitalWrite(VCC_PORT2, HIGH);
}
const uint8_t inputlist[] = {0,1,2,3,5,8};
for (int i=0; i < 6; i++) {
pinMode(inputPinsPort1[inputlist[i]], INPUT_PULLUP);
pinMode(inputPinsPort2[inputlist[i]], INPUT_PULLUP);
}
pinMode(MODE_SELECT_PORT1, OUTPUT);
pinMode(MODE_SELECT_PORT2, OUTPUT);
modeSelect(HIGH);
}
void readJoysticks(uint8_t *status1, uint8_t *status2) {
modeSelect(LOW);
status1[4] = digitalRead(inputPinsPort1[5]); //A1
status1[5] = digitalRead(inputPinsPort1[8]); //Start1
status2[4] = digitalRead(inputPinsPort2[5]); //A2
status2[5] = digitalRead(inputPinsPort2[8]); //Start2
modeSelect(HIGH);
for (uint8_t i=0; i < 4; i++) {
status1[i] = digitalRead(inputPinsPort1[i]); //AXES1
status2[i] = digitalRead(inputPinsPort2[i]); //AXES2
}
status1[6] = digitalRead(inputPinsPort1[5]); //B1
status1[7] = digitalRead(inputPinsPort1[8]); //C1
status2[6] = digitalRead(inputPinsPort2[5]); //B2
status2[7] = digitalRead(inputPinsPort2[8]); //C2
#ifdef GENESIS_6
//read X,Y,Z
modeSelect(LOW);
modeSelect(HIGH);
modeSelect(LOW);
modeSelect(HIGH);
status1[8] = digitalRead(inputPinsPort1[2]); //X1
status1[9] = digitalRead(inputPinsPort1[1]); //Y1
status1[10] = digitalRead(inputPinsPort1[0]); //Z1
status2[8] = digitalRead(inputPinsPort2[2]); //X2
status2[9] = digitalRead(inputPinsPort2[1]); //Y2
status2[10] = digitalRead(inputPinsPort2[0]); //Z2
#endif
delayMicroseconds(1000);
}
void interpretJoystickState(uint8_t j, uint8_t *status) {
#ifdef KONAMI
if (!status[8] && !status[9] && !status[10] && !status[0]) { //X+Y+Z+UP
KonamiCode(0,0);
return;
}
if (!status[8] && !status[9] && !status[10] && !status[1]) { //X+Y+Z+DOWN
KonamiCode(0,1);
return;
}
#endif
Joystick[j].setYAxis(0);
Joystick[j].setXAxis(0);
if (!status[0]) Joystick[j].setYAxis(-127); //UP
if (!status[1]) Joystick[j].setYAxis(127); //DOWN
if (!status[2]) Joystick[j].setXAxis(-127); //LEFT
if (!status[3]) Joystick[j].setXAxis(127); //RIGHT
Joystick[j].setButton(0, !status[5]); //BUTTON1 (START)
Joystick[j].setButton(1, !status[7]); //BUTTON2 (C) ("Select")
Joystick[j].setButton(2, !status[4]); //BUTTON3 (A)
Joystick[j].setButton(3, !status[6]); //BUTTON4 (B)
#ifdef GENESIS_6
Joystick[j].setButton(4, !status[8]); //BUTTON5 (X)
Joystick[j].setButton(5, !status[9]); //BUTTON6 (Y)
Joystick[j].setButton(6, !status[10]); //BUTTON7 (Z) ("LB")
#endif
}
#endif
//--------NES--------
// http://www.mit.edu/~tarvizo/nes-controller.html
#if defined(NES) || defined(SNES)
#define CLOCK1 inputPinsPort1[0]
#define LATCH1 inputPinsPort1[1]
#define DATA1 inputPinsPort1[2]
#define CLOCK2 inputPinsPort2[0]
#define LATCH2 inputPinsPort2[1]
#define DATA2 inputPinsPort2[2]
#ifdef NES
#define BITS 8
#else
#define BITS 16
#endif
#define EVENTS_TOTAL BITS
void setupJoysticks() {
pinMode(LATCH1, OUTPUT);
pinMode(CLOCK1, OUTPUT);
pinMode(DATA1, INPUT);
pinMode(LATCH2, OUTPUT);
pinMode(CLOCK2, OUTPUT);
pinMode(DATA2, INPUT);
}
#define latchlow digitalWrite(LATCH1, LOW); digitalWrite(LATCH2, LOW);
#define latchhigh digitalWrite(LATCH1, HIGH); digitalWrite(LATCH2, HIGH)
#define clocklow digitalWrite(CLOCK1, LOW); digitalWrite(CLOCK2, LOW)
#define clockhigh digitalWrite(CLOCK1, HIGH); digitalWrite(CLOCK2, HIGH)
#define wait delayMicroseconds(12)
void readJoysticks(uint8_t *status1, uint8_t *status2) {
latchlow;
clocklow;
latchhigh;
wait;
latchlow;
for (int i = 0; i < BITS; i++) {
status1[i] = digitalRead(DATA1);
status2[i] = digitalRead(DATA2);
clockhigh;
wait;
clocklow;
wait;
}
}
void interpretJoystickState(uint8_t j, uint8_t *status) {
#ifdef KONAMI
if (!status[1] && !status[9] && !status[11] && !status[4]) { //X+Y+Z+UP
KonamiCode(0,0);
return;
}
if (!status[1] && !status[9] && !status[11] && !status[5]) { //X+Y+Z+DOWN
KonamiCode(0,1);
return;
}
#endif
Joystick[j].setYAxis(0);
Joystick[j].setXAxis(0);
if (!status[4]) Joystick[j].setYAxis(-127); //UP
if (!status[5]) Joystick[j].setYAxis(127); //DOWN
if (!status[6]) Joystick[j].setXAxis(-127); //LEFT
if (!status[7]) Joystick[j].setXAxis(127); //RIGHT
#ifdef NES
Joystick[j].setButton(0, !status[3]); //BUTTON1 (Start)
Joystick[j].setButton(1, !status[2]); //BUTTON2 (Select)
Joystick[j].setButton(2, !status[0]); //BUTTON3 (A)
Joystick[j].setButton(3, !status[1]); //BUTTON4 (B)
#else
Joystick[j].setButton(0, !status[3]); //BUTTON1 (Start)
Joystick[j].setButton(1, !status[2]); //BUTTON2 (Select)
Joystick[j].setButton(2, !status[8]); //BUTTON3 (A)
Joystick[j].setButton(3, !status[0]); //BUTTON4 (B)
Joystick[j].setButton(4, !status[9]); //BUTTON5 (X)
Joystick[j].setButton(5, !status[1]); //BUTTON6 (Y)
Joystick[j].setButton(6, !status[10]); //BUTTON7 (L1) ("LB")
Joystick[j].setButton(7, !status[11]); //BUTTON8 (R1) ("RB")
#endif
}
#endif
//--------Konami code---------
void releaseAll(uint8_t j) {
delay(50);
Joystick[j].setButton(0, 0); //BUTTON1 (Start)
Joystick[j].setButton(1, 0); //BUTTON2 (Select)
Joystick[j].setButton(2, 0); //BUTTON3 (A)
Joystick[j].setButton(3, 0); //BUTTON4 (B)
Joystick[j].setButton(4, 0); //BUTTON5 (X)
Joystick[j].setButton(5, 0); //BUTTON6 (Y)
Joystick[j].setButton(6, 0); //BUTTON7 (LB)
Joystick[j].setButton(7, 0); //BUTTON6 (RB)
Joystick[j].setButton(8, 0); //BUTTON7 (LT)
Joystick[j].setButton(9, 0); //BUTTON6 (RT)
Joystick[j].setButton(10, 0); //BUTTON7 (L-thumb)
Joystick[j].setButton(11, 0); //BUTTON7 (R-thumb)
Joystick[j].setYAxis(0);
Joystick[j].setXAxis(0);
Joystick[j].sendState();
delay(50);
}
void KonamiCode(uint8_t j, uint8_t swap_ab = 0) {
//https://en.wikipedia.org/wiki/Konami_Code
//https://en.wikipedia.org/wiki/List_of_Konami_code_games
//UP, UP, DOWN, DOWN, LEFT, RIGHT, LEFT, RIGHT, B, A
releaseAll(j);
delay(200);
Joystick[j].setYAxis(-127); Joystick[j].sendState(); //UP
releaseAll(j);
Joystick[j].setYAxis(-127); Joystick[j].sendState(); //UP
releaseAll(j);
Joystick[j].setYAxis(127); Joystick[j].sendState(); //DOWN
releaseAll(j);
Joystick[j].setYAxis(127); Joystick[j].sendState(); //DOWN
releaseAll(j);
Joystick[j].setXAxis(-127); Joystick[j].sendState(); //LEFT
releaseAll(j);
Joystick[j].setXAxis(127); Joystick[j].sendState(); //RIGHT
releaseAll(j);
Joystick[j].setXAxis(-127); Joystick[j].sendState(); //LEFT
releaseAll(j);
Joystick[j].setXAxis(127); Joystick[j].sendState(); //RIGHT
releaseAll(j);
if (swap_ab) {
Joystick[j].setButton(2, 1); Joystick[j].sendState(); //BUTTON1 (A)
releaseAll(j);
Joystick[j].setButton(3, 1); Joystick[j].sendState(); //BUTTON2 (B)
releaseAll(j);
} else {
Joystick[j].setButton(3, 1); Joystick[j].sendState(); //BUTTON2 (B)
releaseAll(j);
Joystick[j].setButton(2, 1); Joystick[j].sendState(); //BUTTON1 (A)
releaseAll(j);
}
delay(200);
}
uint8_t lastStatusPort1[EVENTS_TOTAL];
uint8_t newStatusPort1[EVENTS_TOTAL];
uint8_t lastStatusPort2[EVENTS_TOTAL];
uint8_t newStatusPort2[EVENTS_TOTAL];
void setup() {
//clear statusarrays (1=OFF, 0=ON)
for (uint8_t i = 0; i < EVENTS_TOTAL; i++) {
lastStatusPort1[i] = 1;
newStatusPort1[i] = 1;
lastStatusPort2[i] = 1;
newStatusPort2[i] = 1;
}
setupJoysticks();
Joystick[0].begin(false);
Joystick[1].begin(false);
}
uint8_t flag1 = 0;
uint8_t flag2 = 0;
void loop() {
readJoysticks(newStatusPort1, newStatusPort2);
//check for changes - do not raise a flag if nothing changes
for (uint8_t i=0; i < EVENTS_TOTAL; i++) {
if (newStatusPort1[i] != lastStatusPort1[i]) {
lastStatusPort1[i] = newStatusPort1[i];
flag1 = 1;
}
if (newStatusPort2[i] != lastStatusPort2[i]) {
lastStatusPort2[i] = newStatusPort2[i];
flag2 = 1;
}
}
if (flag1) interpretJoystickState(0, newStatusPort1);
if (flag2) interpretJoystickState(1, newStatusPort2);
//minimize port1 time advantage - try to send both states as simultaneous as possible
if (flag1) Joystick[0].sendState();
if (flag2) Joystick[1].sendState();
flag1 = 0;
flag2 = 0;
}