diff --git a/platformio.ini b/platformio.ini index 653e90d..fedf248 100644 --- a/platformio.ini +++ b/platformio.ini @@ -209,6 +209,42 @@ extends = micro, in-genesis, out-usbradio src_filter = ${in-genesis.src_filter} ${out-usbradio.src_filter} build_flags = ${in-genesis.build_flags} ${out-usbradio.build_flags} -DGAMEPAD_COUNT=1 +# psx input + +[in-psx] +src_filter = -<*> + +build_flags = ${common.build_flags} -DGAMEPAD_INPUT=3 -DGAMEPAD_COUNT=4 + +[env:esp32-psx-bt] +extends = esp32, in-psx, out-bt +src_filter = ${in-psx.src_filter} ${out-bt.src_filter} +build_flags = ${in-psx.build_flags} ${out-bt.build_flags} + +[env:esp32-psx-debug] +extends = esp32, in-psx, out-debug +src_filter = ${in-psx.src_filter} ${out-debug.src_filter} +build_flags = ${in-psx.build_flags} ${out-debug.build_flags} + +[env:micro-psx-usb] +extends = micro, in-psx, out-usb +src_filter = ${in-psx.src_filter} ${out-usb.src_filter} +build_flags = ${in-psx.build_flags} ${out-usb.build_flags} + +[env:micro-psx-debug] +extends = micro, in-psx, out-debug +src_filter = ${in-psx.src_filter} ${out-debug.src_filter} +build_flags = ${in-psx.build_flags} ${out-debug.build_flags} + +[env:micro-psx-radio] +extends = micro, in-psx, out-radio +src_filter = ${in-psx.src_filter} ${out-radio.src_filter} +build_flags = ${in-psx.build_flags} ${out-radio.build_flags} + +[env:micro-psx-usbradio] +extends = micro, in-psx, out-usbradio +src_filter = ${in-psx.src_filter} ${out-usbradio.src_filter} +build_flags = ${in-psx.build_flags} ${out-usbradio.build_flags} + # debug input [in-debug] diff --git a/src/Playstation.cpp b/src/Playstation.cpp new file mode 100644 index 0000000..6934b40 --- /dev/null +++ b/src/Playstation.cpp @@ -0,0 +1,326 @@ + +#include "Arduino.h" + +/* + LOOKING AT THE PLUG + ------------------------------- + PIN 1->| o o o | o o o | o o o | + \_____________________________/ + + +PIN # USAGE + + DATA + CMD/COMMAND + N/C (9 Volts unused) + GND + VCC + ATT + CLK/CLOCK + N/C + ACK + +*/ + +#define DATA1 2 +#define CMD1 3 +#define ATT1 4 +#define CLK1 5 + +#ifndef GAMEPAD_COUNT +#define GAMEPAD_COUNT 4 +#endif + +// not counting dpad +#define BUTTON_COUNT 12 + +#define JOYSTICK_STATE_SIZE 6 + +//#define DEBUG + +#include "gamepad/Gamepad.h" + +GAMEPAD_CLASS gamepad; + +enum +{ + // in data[1] + // in digital mode, right joysticks are these 4 buttons too + PS_BTN_O = 8192, + PS_BTN_X = 16384, + PS_BTN_SQUARE = 32768, + PS_BTN_TRIANGLE = 4096, + // shoulder + PS_BTN_R1 = 2048, + PS_BTN_R2 = 512, + PS_BTN_L1 = 1024, + PS_BTN_L2 = 256, + + // in data[2] + PS_BTN_START = 8, + PS_BTN_SELECT = 1, + + // in digital mode, left joysticks are the d-pad + PS_BTN_UP = 16, + PS_BTN_DOWN = 64, + PS_BTN_LEFT = 128, + PS_BTN_RIGHT = 32, + + PS_BTN_R3 = 4, + PS_BTN_L3 = 2, +}; + +// pressing one of these buttons on the controller... (read below) +static const uint16_t translateFromButton[BUTTON_COUNT] = { + PS_BTN_O, + PS_BTN_X, + PS_BTN_SQUARE, + PS_BTN_TRIANGLE, + PS_BTN_R1, + PS_BTN_R2, + PS_BTN_L1, + PS_BTN_L2, + PS_BTN_START, + PS_BTN_SELECT, + PS_BTN_R3, + PS_BTN_L3, +}; + +// ... translates to one of these buttons over HID +static const uint32_t translateToHid[BUTTON_COUNT] = { + BUTTON_A, + BUTTON_B, + BUTTON_Y, + BUTTON_X, + BUTTON_R1, + BUTTON_R2, + BUTTON_L1, + BUTTON_L2, + BUTTON_START, + BUTTON_SELECT, + BUTTON_R3, + BUTTON_L3, +}; + +class Joystick_ { + private: + uint8_t olddata[JOYSTICK_STATE_SIZE]; + + public: + uint8_t type; + uint8_t data[JOYSTICK_STATE_SIZE]; + + Joystick_() { + data[0] = 0; + data[1] = 0; + data[2] = 127; + data[3] = 127; + data[4] = 127; + data[5] = 127; + memcpy(olddata, data, JOYSTICK_STATE_SIZE); + } + + bool down(int button) const { + return *(uint16_t*)(data)&button; + } + + void updateState(uint8_t c) { + if (type != 0x73 && type != 0x53) { + data[2] = 127; + data[3] = 127; + data[4] = 127; + data[5] = 127; + } + if (type == 0x41 || type == 0x73 || type == 0x53) { + if (memcmp(olddata, data, JOYSTICK_STATE_SIZE)) { + memcpy(olddata, data, JOYSTICK_STATE_SIZE); + sendState(c); + } + } + } + + signed char getHat() { + if (down(PS_BTN_DOWN)) { + if (down(PS_BTN_RIGHT)) { + return DPAD_DOWN_RIGHT; + } else if (down(PS_BTN_LEFT)) { + return DPAD_DOWN_LEFT; + } else { + return DPAD_DOWN; + } + } else if (down(PS_BTN_UP)) { + if (down(PS_BTN_RIGHT)) { + return DPAD_UP_RIGHT; + } else if (down(PS_BTN_LEFT)) { + return DPAD_UP_LEFT; + } else { + return DPAD_UP; + } + } else if (down(PS_BTN_RIGHT)) { + return DPAD_RIGHT; + } else if (down(PS_BTN_LEFT)) { + return DPAD_LEFT; + } else { + return DPAD_CENTERED; + } + } + + int16_t translateAxis(uint8_t v) { + //map(value, fromLow, fromHigh, toLow, toHigh) + return v == 128 ? 0 : map(v, 0, 255, -32767, 32767); + } + + void sendState(uint8_t c) { +#ifdef DEBUG + uint16_t mask = 1; + Serial.print(c); + Serial.print(": type: 0x"); + Serial.print(type, HEX); + Serial.print(" hex: 0x"); + Serial.print(data[0], HEX); + Serial.print(" 0x"); + Serial.print(data[1], HEX); + Serial.print(" 0x"); + Serial.print(data[2], HEX); + Serial.print(" 0x"); + Serial.print(data[3], HEX); + Serial.print(" 0x"); + Serial.print(data[4], HEX); + Serial.print(" 0x"); + Serial.print(data[5], HEX); + + Serial.print(" dec: "); + Serial.print(data[0]); + Serial.print(" "); + Serial.print(data[1]); + Serial.print(" "); + Serial.print(data[2]); + Serial.print(" "); + Serial.print(data[3]); + Serial.print(" "); + Serial.print(data[4]); + Serial.print(" "); + Serial.print(data[5]); + Serial.println(); + + for (uint8_t _i = 0; _i <= 32; _i++) { + if (down(mask)) { + Serial.print("db: "); + Serial.println(mask); + } + mask *= 2; + } + + Serial.flush(); +#endif + + //gamepad.buttons(i, *(uint16_t*)(&data[0])); + //gamepad.setHatSync(i, DPAD_CENTERED); + gamepad.buttons(c, 0); + // if start and select are held at the same time, send menu and only menu + if (down(PS_BTN_START) && down(PS_BTN_SELECT)) { + gamepad.press(c, BUTTON_MENU); + } else { + // actually send buttons held + for (uint8_t btn = 0; btn < BUTTON_COUNT; btn++) { + if (down(translateFromButton[btn])) { + gamepad.press(c, translateToHid[btn]); + } + } + } + + gamepad.setAxis(c, translateAxis(data[4]), translateAxis(data[5]), translateAxis(data[2]), translateAxis(data[3]), 0, 0, getHat()); + } +}; + +Joystick_ Joystick[GAMEPAD_COUNT]; + +uint8_t shift(uint8_t _dataOut) // Does the actual shifting, both in and out simultaneously +{ + uint8_t _temp = 0; + uint8_t _dataIn = 0; + uint8_t _delay = 6; //2 unstable; //clock 250kHz + + delayMicroseconds(100); //max acknowledge waiting time 100us + for (uint8_t _i = 0; _i <= 7; _i++) { + if (_dataOut & (1 << _i)) // write bit + digitalWrite(CMD1, HIGH); + else + digitalWrite(CMD1, LOW); + + digitalWrite(CLK1, LOW); // read bit + delayMicroseconds(_delay); + _temp = digitalRead(DATA1); + if (_temp) { + _dataIn = _dataIn | (B00000001 << _i); + } + + digitalWrite(CLK1, HIGH); + delayMicroseconds(_delay); + } + return _dataIn; +} + +void setup() { +#ifdef DEBUG + Serial.begin(115200); +#endif + gamepad.begin(); + + pinMode(DATA1, INPUT_PULLUP); + pinMode(CMD1, OUTPUT); + pinMode(ATT1, OUTPUT); + pinMode(CLK1, OUTPUT); +} + +void loop() { + // http://problemkaputt.de/psx-spx.htm#controllerandmemorycardsignals + uint8_t head, padding, multitap; + + // first: read gamepad normally + digitalWrite(ATT1, LOW); + //digitalWrite(ATT2, LOW); + head = shift(0x01); + Joystick[0].type = shift(0x42); + padding = shift(0x01); //read multitap in next command + Joystick[0].data[0] = ~shift(0x00); //buttons + Joystick[0].data[1] = ~shift(0x00); //buttons + Joystick[0].data[2] = shift(0x00); //right analog + Joystick[0].data[3] = shift(0x00); //right analog + Joystick[0].data[4] = shift(0x00); //left analog + Joystick[0].data[5] = shift(0x00); //left analog + digitalWrite(ATT1, HIGH); + //digitalWrite(ATT2, HIGH); + + //delay(100); + + // second: check and read multitap + digitalWrite(ATT1, LOW); + head = shift(0x01); + multitap = shift(0x42); + padding = shift(0x00); //next time normal read + if (multitap == 0x80) { + for (uint8_t i = 0; i < GAMEPAD_COUNT; i++) { + Joystick[i].type = shift(0x00); + padding = shift(0x00); + Joystick[i].data[0] = ~shift(0x00); //buttons + Joystick[i].data[1] = ~shift(0x00); //buttons + Joystick[i].data[2] = shift(0x00); //right analog + Joystick[i].data[3] = shift(0x00); //right analog + Joystick[i].data[4] = shift(0x00); //left analog + Joystick[i].data[5] = shift(0x00); //left analog + } + } + digitalWrite(ATT1, HIGH); + +#ifdef DEBUGE + Serial.print(" multitap: "); + Serial.println(multitap, HEX); +#endif + + for (uint8_t i = 0; i < GAMEPAD_COUNT; i++) { + Joystick[i].updateState(i); + } + + delayMicroseconds(1000); +} diff --git a/src/gamepad/common.h b/src/gamepad/common.h index bca80a4..f980e6d 100644 --- a/src/gamepad/common.h +++ b/src/gamepad/common.h @@ -14,14 +14,20 @@ #define BUTTON_Y 16 #define BUTTON_TL 64 #define BUTTON_L 64 +#define BUTTON_L1 64 #define BUTTON_TR 128 #define BUTTON_R 128 +#define BUTTON_R1 128 #define BUTTON_TL2 256 +#define BUTTON_L2 256 #define BUTTON_TR2 512 +#define BUTTON_R2 512 #define BUTTON_SELECT 1024 #define BUTTON_START 2048 #define BUTTON_THUMBL 8192 +#define BUTTON_L3 8192 #define BUTTON_THUMBR 16384 +#define BUTTON_R3 16384 #define BUTTON_1 1 #define BUTTON_2 2