Adapt various input devices to various output devices.
https://github.com/OpenRetroPad/OpenRetroPad
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
289 lines
6.4 KiB
289 lines
6.4 KiB
/* ------------------------------------------------------------------------- |
|
Saturn controller socket (looking face-on at the front of the socket): |
|
___________________ |
|
/ 1 2 3 4 5 6 7 8 9 \ |
|
|___________________| |
|
|
|
Saturn controller plug (looking face-on at the front of the controller plug): |
|
___________________ |
|
/ 9 8 7 6 5 4 3 2 1 \ |
|
|___________________| |
|
|
|
Saturn |
|
----------------- |
|
1 VCC - black |
|
2 DATA1 - white |
|
3 DATA0 - gray |
|
4 SEL1 - blue |
|
5 SEL0 - green |
|
6 TL (5V) - yellow |
|
7 DATA3 - orange |
|
8 DATA2 - red |
|
9 GND - brown |
|
|
|
NOTE: The receiver of the Retro Bit 2.4GHz controller needs to be plugged |
|
in after the adapter has been connected to USB and the RETROBIT_WL |
|
define needs to be uncommented. |
|
------------------------------------------------------------------------- */ |
|
#include "Arduino.h" |
|
|
|
#include <digitalWriteFast.h> |
|
//#define digitalWriteFast digitalWrite |
|
//#define digitalReadFast digitalRead |
|
|
|
#ifndef GAMEPAD_COUNT |
|
#define GAMEPAD_COUNT 2 |
|
#endif |
|
|
|
#include "gamepad/Gamepad.h" |
|
|
|
// How many microseconds to wait after setting select lines? (2µs is enough according to the Saturn developer's manual) |
|
// 20µs is a "safe" value that seems to work for original Saturn controllers and Retrobit wired controllers |
|
#define SELECT_PAUSE 10 |
|
|
|
// Uncomment to support the Retro Bit 2.4GHz wireless controller (this will increase lag a lot) |
|
//#define RETROBIT_WL |
|
|
|
#include "pins.h" |
|
|
|
// pins |
|
#define P1_2 OR_PIN_2 |
|
#define P1_3 OR_PIN_3 |
|
#define P1_6 OR_PIN_4 |
|
#define P1_7 OR_PIN_1 |
|
#define P1_8 OR_PIN_11 |
|
|
|
#define PX_4 OR_PIN_6 |
|
#define PX_5 OR_PIN_5 |
|
|
|
#if GAMEPAD_COUNT == 2 |
|
|
|
#define P2_2 OR_PIN_20 |
|
#define P2_3 OR_PIN_21 |
|
#define P2_6 OR_PIN_10 |
|
#define P2_7 OR_PIN_18 |
|
#define P2_8 OR_PIN_19 |
|
|
|
#endif |
|
|
|
// Set up USB HID gamepads |
|
GAMEPAD_CLASS gamepad; |
|
|
|
ScratchGamepad currentGamepad; |
|
|
|
// Read R, X, Y, Z |
|
void read1() { |
|
// Set select outputs to 00 |
|
digitalWriteFast(PX_4, LOW); |
|
digitalWriteFast(PX_5, LOW); |
|
delayMicroseconds(SELECT_PAUSE); |
|
if (!digitalReadFast(P1_3)) { |
|
// Z |
|
currentGamepad.press(0, BUTTON_R); |
|
} |
|
if (!digitalReadFast(P1_2)) { |
|
// Y |
|
currentGamepad.press(0, BUTTON_X); |
|
} |
|
if (!digitalReadFast(P1_8)) { |
|
// X |
|
currentGamepad.press(0, BUTTON_L); |
|
} |
|
if (!digitalReadFast(P1_7)) { |
|
// R |
|
currentGamepad.press(0, BUTTON_R2); |
|
} |
|
#if GAMEPAD_COUNT == 2 |
|
if (!digitalReadFast(P2_3)) { |
|
// Z |
|
currentGamepad.press(1, BUTTON_R); |
|
} |
|
if (!digitalReadFast(P2_2)) { |
|
// Y |
|
currentGamepad.press(1, BUTTON_X); |
|
} |
|
if (!digitalReadFast(P2_8)) { |
|
// X |
|
currentGamepad.press(1, BUTTON_L); |
|
} |
|
if (!digitalReadFast(P2_7)) { |
|
// R |
|
currentGamepad.press(1, BUTTON_R2); |
|
} |
|
#endif |
|
} |
|
|
|
// Read ST, A, C, B |
|
void read2() { |
|
// Toggle select outputs (01->10 or 10->01) |
|
digitalWriteFast(PX_4, HIGH); |
|
digitalWriteFast(PX_5, LOW); |
|
delayMicroseconds(SELECT_PAUSE); |
|
if (!digitalReadFast(P1_3)) { |
|
// B |
|
currentGamepad.press(0, BUTTON_B); |
|
} |
|
if (!digitalReadFast(P1_2)) { |
|
// C |
|
currentGamepad.press(0, BUTTON_A); |
|
} |
|
if (!digitalReadFast(P1_8)) { |
|
// A |
|
currentGamepad.press(0, BUTTON_Y); |
|
} |
|
if (!digitalReadFast(P1_7)) { |
|
// ST |
|
currentGamepad.press(0, BUTTON_START); |
|
} |
|
#if GAMEPAD_COUNT == 2 |
|
if (!digitalReadFast(P2_3)) { |
|
// B |
|
currentGamepad.press(1, BUTTON_B); |
|
} |
|
if (!digitalReadFast(P2_2)) { |
|
// C |
|
currentGamepad.press(1, BUTTON_A); |
|
} |
|
if (!digitalReadFast(P2_8)) { |
|
// A |
|
currentGamepad.press(1, BUTTON_Y); |
|
} |
|
if (!digitalReadFast(P2_7)) { |
|
// ST |
|
currentGamepad.press(1, BUTTON_START); |
|
} |
|
#endif |
|
} |
|
|
|
// Read DR, DL, DD, DU |
|
void read3() { |
|
// Set select outputs to 10 from 11 (toggle) |
|
digitalWriteFast(PX_4, LOW); |
|
digitalWriteFast(PX_5, HIGH); |
|
delayMicroseconds(SELECT_PAUSE); |
|
if (!digitalReadFast(P1_3)) { |
|
// UP |
|
currentGamepad.pressDpad(0, DPAD_BIT_UP); |
|
} |
|
if (!digitalReadFast(P1_2)) { |
|
// DOWN |
|
currentGamepad.pressDpad(0, DPAD_BIT_DOWN); |
|
} |
|
if (!digitalReadFast(P1_8)) { |
|
// LEFT |
|
currentGamepad.pressDpad(0, DPAD_BIT_LEFT); |
|
} |
|
if (!digitalReadFast(P1_7)) { |
|
// RIGHT |
|
currentGamepad.pressDpad(0, DPAD_BIT_RIGHT); |
|
} |
|
#if GAMEPAD_COUNT == 2 |
|
if (!digitalReadFast(P2_3)) { |
|
// UP |
|
currentGamepad.pressDpad(1, DPAD_BIT_UP); |
|
} |
|
if (!digitalReadFast(P2_2)) { |
|
// DOWN |
|
currentGamepad.pressDpad(1, DPAD_BIT_DOWN); |
|
} |
|
if (!digitalReadFast(P2_8)) { |
|
// LEFT |
|
currentGamepad.pressDpad(1, DPAD_BIT_LEFT); |
|
} |
|
if (!digitalReadFast(P2_7)) { |
|
// RIGHT |
|
currentGamepad.pressDpad(1, DPAD_BIT_RIGHT); |
|
} |
|
#endif |
|
} |
|
|
|
// Read L, *, *, * |
|
void read4() { |
|
// Set select outputs to 11 |
|
digitalWriteFast(PX_4, HIGH); |
|
digitalWriteFast(PX_5, HIGH); |
|
delayMicroseconds(SELECT_PAUSE); |
|
if (!digitalReadFast(P1_7)) { |
|
// L |
|
currentGamepad.press(0, BUTTON_L2); |
|
} |
|
#if GAMEPAD_COUNT == 2 |
|
if (!digitalReadFast(P2_7)) { |
|
// L |
|
currentGamepad.press(1, BUTTON_L2); |
|
} |
|
#endif |
|
} |
|
|
|
void setup() { |
|
gamepad.begin(); |
|
|
|
// Set P1 data pins as inputs and enable pull-up resistors |
|
pinMode(P1_3, INPUT_PULLUP); |
|
pinMode(P1_2, INPUT_PULLUP); |
|
pinMode(P1_7, INPUT_PULLUP); |
|
pinMode(P1_8, INPUT_PULLUP); |
|
digitalWrite(P1_3, HIGH); |
|
digitalWrite(P1_2, HIGH); |
|
digitalWrite(P1_7, HIGH); |
|
digitalWrite(P1_8, HIGH); |
|
|
|
// Set P1 TL as input and enable pull-up resistor |
|
pinMode(P1_6, INPUT_PULLUP); |
|
digitalWrite(P1_6, HIGH); |
|
|
|
#if GAMEPAD_COUNT == 2 |
|
// Set P2 data pins as inputs and enable pull-up resistors |
|
pinMode(P2_3, INPUT_PULLUP); |
|
pinMode(P2_2, INPUT_PULLUP); |
|
pinMode(P2_7, INPUT_PULLUP); |
|
pinMode(P2_8, INPUT_PULLUP); |
|
digitalWrite(P2_3, HIGH); |
|
digitalWrite(P2_2, HIGH); |
|
digitalWrite(P2_7, HIGH); |
|
digitalWrite(P2_8, HIGH); |
|
|
|
// Set P2 TL as input and enable pull-up resistor |
|
pinMode(P2_6, INPUT_PULLUP); |
|
digitalWrite(P2_6, HIGH); |
|
#endif |
|
|
|
// Set P1+P2 select pins as outputs and set them HIGH |
|
pinMode(PX_4, OUTPUT); |
|
pinMode(PX_5, OUTPUT); |
|
digitalWrite(PX_4, HIGH); |
|
digitalWrite(PX_5, HIGH); |
|
|
|
// Wait for the controller(s) to settle |
|
delay(100); |
|
} |
|
|
|
void loop() { |
|
// Read all button and axes states |
|
read3(); |
|
read2(); |
|
read1(); |
|
read4(); |
|
|
|
// Send data to USB if values have changed |
|
for (uint8_t gp = 0; gp < GAMEPAD_COUNT; gp++) { |
|
if (currentGamepad.changed(gp, gamepad)) { |
|
const auto hat = gamepad.getHat(gp); |
|
if (hat == DPAD_DOWN && gamepad.isPressed(gp, BUTTON_START)) { |
|
gamepad.buttons(gp, 0); |
|
gamepad.press(gp, BUTTON_MENU); |
|
gamepad.setHatSync(gp, DPAD_CENTERED); |
|
currentGamepad.changed(gp, gamepad); |
|
return; |
|
} |
|
gamepad.setHatSync(gp, hat); |
|
} |
|
// Clear button data |
|
currentGamepad.reset(gp); |
|
} |
|
|
|
#ifdef RETROBIT_WL |
|
// This delay is needed for the retro bit 2.4GHz wireless controller, making it more or less useless with this adapter |
|
delay(17); |
|
#endif |
|
}
|
|
|