OpenRetroPad/src/SnesNes.cpp

239 lines
5.4 KiB
C++

#include "Arduino.h"
#ifndef GAMEPAD_COUNT
#define GAMEPAD_COUNT 2
#endif
#define BUTTON_COUNT 12 // SNES has 12, NES only has 8
//individual data pin for each controller
static const int DATA_PIN[GAMEPAD_COUNT] = {
18,
#if GAMEPAD_COUNT > 1
19,
#endif
#if GAMEPAD_COUNT > 2
20,
#endif
#if GAMEPAD_COUNT > 3
21,
#endif
};
//shared pins between all controllers
#if defined(CONFIG_BT_ENABLED)
// ESP32
static const int LATCH_PIN = 16; // brown
static const int CLOCK_PIN = 17; // white
#else
// micro
static const int LATCH_PIN = 2; // brown
static const int CLOCK_PIN = 3; // white
#endif
// power red, ground black
#include "gamepad/Gamepad.h"
static const int translateToNES[12] = {1, 8, 2, 3, 4, 5, 6, 7, 0, 8, 8, 8};
class GameControllers {
public:
enum Type
{
NES = 0,
SNES = 1,
};
enum Button
{
B = 0,
Y = 1,
SELECT = 2,
START = 3,
UP = 4,
DOWN = 5,
LEFT = 6,
RIGHT = 7,
A = 8,
X = 9,
L = 10,
R = 11,
};
Type types[GAMEPAD_COUNT];
int latchPin;
int clockPin;
int dataPins[GAMEPAD_COUNT];
long buttons[GAMEPAD_COUNT][12];
int changedControllers[GAMEPAD_COUNT];
///This has to be initialized once for the shared pins latch and clock
void init(int latch, int clock) {
latchPin = latch;
clockPin = clock;
pinMode(latchPin, OUTPUT);
digitalWrite(latchPin, LOW);
pinMode(clockPin, OUTPUT);
digitalWrite(clockPin, HIGH);
for (int c = 0; c < GAMEPAD_COUNT; c++) {
for (int i = 0; i < 12; i++) {
buttons[c][i] = -1;
}
types[c] = NES; // todo: if SNES button is ever pressed, change type to SNES, maybe buttons to manually toggle?
dataPins[c] = -1;
}
}
///This sets the controller type and initializes its individual data pin
void setController(int controller, Type type, int dataPin) {
types[controller] = type;
dataPins[controller] = dataPin;
pinMode(dataPins[controller], INPUT_PULLUP);
}
void poll(void (*controllerChanged)(const int controller)) {
memset(changedControllers, 0, GAMEPAD_COUNT);
digitalWrite(latchPin, HIGH);
delayMicroseconds(12);
digitalWrite(latchPin, LOW);
delayMicroseconds(6);
for (int i = 0; i < 12; i++) {
for (int c = 0; c < GAMEPAD_COUNT; c++)
if (dataPins[c] > -1) {
if (digitalRead(dataPins[c])) {
if (-1 != buttons[c][i]) {
buttons[c][i] = -1;
changedControllers[c] = 1;
}
} else {
//++buttons[c][i];
//changedControllers[c] = 1;
if (0 != buttons[c][i]) {
buttons[c][i] = 0;
changedControllers[c] = 1;
}
}
}
digitalWrite(clockPin, LOW);
delayMicroseconds(6);
digitalWrite(clockPin, HIGH);
delayMicroseconds(6);
}
for (int c = 0; c < GAMEPAD_COUNT; c++) {
// have any buttons changed state?
if (1 == changedControllers[c]) {
controllerChanged(c);
}
}
}
int translate(int controller, Button b) const {
if (types[controller] == SNES)
return b;
return translateToNES[b];
}
///returns if button is currently down
bool down(int controller, Button b) const {
return buttons[controller][translate(controller, b)] >= 0;
}
};
static const int translateToHid[12] = {
BUTTON_B,
BUTTON_Y,
BUTTON_SELECT,
BUTTON_START,
DPAD_UP,
DPAD_DOWN,
DPAD_LEFT,
DPAD_RIGHT,
BUTTON_A,
BUTTON_X,
BUTTON_L,
BUTTON_R,
};
GameControllers controllers;
GAMEPAD_CLASS gamepad;
void setup() {
gamepad.begin();
//initialize shared pins
controllers.init(LATCH_PIN, CLOCK_PIN);
//activate first controller ans set the type to SNES
for (int c = 0; c < GAMEPAD_COUNT; c++) {
controllers.setController(c, GameControllers::NES, DATA_PIN[c]);
}
}
/*
void controllerChangedDebug(const int c) {
Serial.print("controllerChanged!!!!: ");
Serial.println(c);
Serial.print("c: ");
Serial.print(c);
for (uint8_t btn = 0; btn < 12; btn++) {
Serial.print("; ");
Serial.print(btn);
Serial.print(", ");
Serial.print(controllers.buttons[c][controllers.translate(c, static_cast<GameControllers::Button>(btn))]);
}
Serial.println("");
}
*/
void controllerChanged(const int c) {
//controllerChangedDebug(c);
gamepad.buttons(c, 0);
// if start and select are held at the same time, send menu and only menu
if (controllers.down(c, GameControllers::START) && controllers.down(c, GameControllers::SELECT)) {
gamepad.press(c, BUTTON_MENU);
} else {
// actually send buttons held
for (uint8_t btn = 0; btn < 12; btn++) {
if (btn > 3 && btn < 8)
continue; // skip dpad
if (controllers.down(c, static_cast<GameControllers::Button>(btn))) {
gamepad.press(c, translateToHid[btn]);
}
}
}
if (controllers.down(c, GameControllers::DOWN)) {
if (controllers.down(c, GameControllers::RIGHT)) {
gamepad.setHatSync(c, DPAD_DOWN_RIGHT);
} else if (controllers.down(c, GameControllers::LEFT)) {
gamepad.setHatSync(c, DPAD_DOWN_LEFT);
} else {
gamepad.setHatSync(c, DPAD_DOWN);
}
} else if (controllers.down(c, GameControllers::UP)) {
if (controllers.down(c, GameControllers::RIGHT)) {
gamepad.setHatSync(c, DPAD_UP_RIGHT);
} else if (controllers.down(c, GameControllers::LEFT)) {
gamepad.setHatSync(c, DPAD_UP_LEFT);
} else {
gamepad.setHatSync(c, DPAD_UP);
}
} else if (controllers.down(c, GameControllers::RIGHT)) {
gamepad.setHatSync(c, DPAD_RIGHT);
} else if (controllers.down(c, GameControllers::LEFT)) {
gamepad.setHatSync(c, DPAD_LEFT);
} else {
gamepad.setHatSync(c, DPAD_CENTERED);
}
}
void loop() {
if (gamepad.isConnected()) {
controllers.poll(controllerChanged); //read all controllers at once
}
}