diff --git a/test/psx.ino b/test/psx.ino new file mode 100644 index 0000000..31b2cfb --- /dev/null +++ b/test/psx.ino @@ -0,0 +1,441 @@ +#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 PSX +//PSX: DATA CMD ATT CLK +const uint8_t inputPinsPort1[] = { 2, 3, 4, 5 }; +const uint8_t inputPinsPort2[] = { 6, 7, 8, 9 }; + + + +//#define KONAMI + + +void KonamiCode(uint8_t j, uint8_t swap_ab = 0); + +//-----PSX/PLAYSTATION----- +#ifdef PSX + +#include +Psx Psx; + +//#define EVENTS_TOTAL 4+2 //4 directions, 2 fire-buttons +#define BITS 16 +#define EVENTS_TOTAL BITS + +void setupJoysticks() { + /*pinMode(inputPinsPort1[0], INPUT); + pinMode(inputPinsPort2[0], INPUT); + pinMode(inputPinsPort1[1], OUTPUT); + pinMode(inputPinsPort2[1], OUTPUT); + pinMode(inputPinsPort1[2], OUTPUT); + pinMode(inputPinsPort2[2], OUTPUT); + pinMode(inputPinsPort1[3], OUTPUT); + pinMode(inputPinsPort2[3], OUTPUT);*/ + Psx.setupPins(inputPinsPort1[0], inputPinsPort1[1], inputPinsPort1[2], inputPinsPort1[3], 10); +} + +void readJoysticks(uint8_t *status1, uint8_t *status2) { + uint16_t data = Psx.read(); + for (uint8_t i=0; i < BITS; i++) { + status1[i] = ~bitRead(data,i) & 1; + status2[i] = 1; + } +} + +void interpretJoystickState(uint8_t j, uint8_t *status) { + Joystick[j].setYAxis(0); + Joystick[j].setXAxis(0); + if (!status[3]) Joystick[j].setYAxis(-127); //UP (0) + if (!status[1]) Joystick[j].setYAxis(127); //DOWN (1) + if (!status[0]) Joystick[j].setXAxis(-127); //LEFT (2) + if (!status[2]) Joystick[j].setXAxis(127); //RIGHT (3) + Joystick[j].setButton(0, !status[4]); //BUTTON1 (Start) + Joystick[j].setButton(1, !status[7]); //BUTTON2 (Select) + Joystick[j].setButton(2, !status[9]); //BUTTON3 (A) + Joystick[j].setButton(3, !status[10]); //BUTTON4 (B) + Joystick[j].setButton(4, !status[8]); //BUTTON5 (X) + Joystick[j].setButton(5, !status[11]); //BUTTON6 (Y) + Joystick[j].setButton(6, !status[15]); //BUTTON7 (LB) + Joystick[j].setButton(7, !status[14]); //BUTTON8 (RB) + Joystick[j].setButton(8, !status[13]); //BUTTON9 (LT) + Joystick[j].setButton(9, !status[12]); //BUTTON10 (RT) +} + + +#endif +//--------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); + pinMode(inputPinsPort2[inputlist[i]], INPUT); + } + + 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; + +} +