Document pinout, refactor SnesNes, finish DebugGamepad

This commit is contained in:
Travis Burtrum 2020-12-27 20:21:42 -05:00
parent 55fba5b6ff
commit 5f7b8ab5d4
6 changed files with 235 additions and 92 deletions

View File

@ -23,33 +23,33 @@ Wiring
![DB-25 Pinout](images/db25pins.jpg) ![DB-25 Pinout](images/db25pins.jpg)
| DB-25 Male Pins | Arduino Pro Micro GPIO | ESP32 GPIO | | DB-25 Pins | Arduino Pro Micro GPIO | ESP32 GPIO | RADIO | SNES | PSX |
|--------------|---------------------------------------------|-----------------------------------------| |---------------|------------------------|------------|----------|--------|--------|
| 1 | 1 | | | 1 | 1 | | - | - | - |
| 2 | 2 | | | 2 | 2 | | - | LATCH | DATA |
| 3 | 3 | | | 3 | 3 | | - | CLOCK | CMD |
| 4 | 4 | | | 4 | 4 | | - | - | ATT |
| 5 | 5 | | | 5 | 5 | | - | - | CLK |
| 6 | 6 | | | 6 | 6 | | - | - | - |
| 7 | 7 | | | 7 | 7 | | CE | - | - |
| 8 | 8 | | | 8 | 8 | | CSN | - | - |
| 9 | 9 | | | 9 | 9 | | - | - | - |
| 10 | 10 | | | 10 | 10 | | - | - | - |
| 11 | 11 | | | 11 | 0 | | - | - | - |
| 12 | - | | | 12 | - | | - | - | - |
| 13 | - | | | 13 | - | | - | - | - |
| 14 | 14 | | | 14 | 14 | | MISO | - | - |
| 15 | 15 | | | 15 | 15 | | SCLK | - | - |
| 16 | 16 | | | 16 | 16 | | MOSI | - | - |
| 17 | - | | | 17 | - | | - | - | - |
| 18 | 18 | | | 18 | 18 | | - | DATA1 | - |
| 19 | 19 | | | 19 | 19 | | - | DATA2 | - |
| 20 | 20 | | | 20 | 20 | | - | DATA3 | - |
| 21 | 21 | | | 21 | 21 | | - | DATA4 | - |
| 22 | - | | | 22 | - | | - | - | - |
| 23 | 3.3V VCC | | | 23 | - | | 3.3V VCC | - | - |
| 24 | 5V VCC | | | 24 | 5V VCC | | 5V VCC | 5V VCC | 5V VCC |
| 25 | GND | | | 25 | GND | | GND | GND | - |

View File

@ -5,14 +5,14 @@
/-------------\ /-------------\
PIN # USAGE PIN # USAGE (colors from my extension cable, check your own)
GND GND - red
DATA DATA - white
VCC +3.3V ONLY VCC +3.3V ONLY - black
*/ */
#define DATA_PIN 7 #define DATA_PIN 2
// how often to poll, 100? 14? polling must not occur faster than every 20 ms // how often to poll, 100? 14? polling must not occur faster than every 20 ms
#define POLL_DELAY 14 #define POLL_DELAY 14
@ -123,6 +123,8 @@ void print_report(ControllerReport &controller) {
#endif #endif
void setup() { void setup() {
// n64 low because it *should* be 3.3V
digitalWrite(DATA_PIN, LOW);
#ifdef DEBUG #ifdef DEBUG
Serial.begin(115200); Serial.begin(115200);
if (controller.begin()) { if (controller.begin()) {
@ -172,7 +174,7 @@ void loop() {
gamepad.press(c, BUTTON_B); gamepad.press(c, BUTTON_B);
} }
if (report.z) { if (report.z) {
gamepad.press(c, BUTTON_TR); gamepad.press(c, BUTTON_TL2);
} }
if (report.l) { if (report.l) {
gamepad.press(c, BUTTON_L); gamepad.press(c, BUTTON_L);

View File

@ -8,17 +8,17 @@
\_____________________________/ \_____________________________/
PIN # USAGE PIN # USAGE (colors from my extension cable, check your own)
DATA DATA - brown
CMD/COMMAND CMD/COMMAND - orange
N/C (9 Volts unused) N/C (9 Volts unused) - white
GND GND - black
VCC 5V VCC - red
ATT ATT - yellow
CLK/CLOCK CLK/CLOCK - blue
N/C N/C - -
ACK ACK - green
*/ */

View File

@ -32,9 +32,14 @@ static const int CLOCK_PIN = 3; // white
#endif #endif
// power red, ground black // power red, ground black
//#define DEBUG
#include "gamepad/Gamepad.h" #include "gamepad/Gamepad.h"
static const int translateToNES[12] = {1, 8, 2, 3, 4, 5, 6, 7, 0, 8, 8, 8}; static const uint8_t translateToNES[12] = {1, 8, 2, 3, 4, 5, 6, 7, 0, 8, 8, 8};
static const uint8_t nesButtons[4] = {0, 2, 3, 8};
static const uint8_t snesButtons[8] = {0, 1, 2, 3, 8, 9, 10, 11};
class GameControllers { class GameControllers {
public: public:
@ -59,12 +64,12 @@ class GameControllers {
L = 10, L = 10,
R = 11, R = 11,
}; };
Type types[GAMEPAD_COUNT]; Type types[GAMEPAD_COUNT];
int latchPin; int latchPin;
int clockPin; int clockPin;
int dataPins[GAMEPAD_COUNT]; int dataPins[GAMEPAD_COUNT];
long buttons[GAMEPAD_COUNT][12]; long buttons[GAMEPAD_COUNT][12];
int maxButtons = 12;
int changedControllers[GAMEPAD_COUNT]; int changedControllers[GAMEPAD_COUNT];
@ -76,13 +81,6 @@ class GameControllers {
digitalWrite(latchPin, LOW); digitalWrite(latchPin, LOW);
pinMode(clockPin, OUTPUT); pinMode(clockPin, OUTPUT);
digitalWrite(clockPin, HIGH); 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 ///This sets the controller type and initializes its individual data pin
@ -90,6 +88,9 @@ class GameControllers {
types[controller] = type; types[controller] = type;
dataPins[controller] = dataPin; dataPins[controller] = dataPin;
pinMode(dataPins[controller], INPUT_PULLUP); pinMode(dataPins[controller], INPUT_PULLUP);
for (int i = 0; i < 12; i++) {
buttons[controller][i] = -1;
}
} }
void poll(void (*controllerChanged)(const int controller)) { void poll(void (*controllerChanged)(const int controller)) {
@ -99,28 +100,33 @@ class GameControllers {
delayMicroseconds(12); delayMicroseconds(12);
digitalWrite(latchPin, LOW); digitalWrite(latchPin, LOW);
delayMicroseconds(6); delayMicroseconds(6);
for (int i = 0; i < 12; i++) { //Serial.print("snes: ");
for (int c = 0; c < GAMEPAD_COUNT; c++) for (int i = 0; i < maxButtons; i++) {
if (dataPins[c] > -1) { for (int c = 0; c < GAMEPAD_COUNT; c++) {
if (digitalRead(dataPins[c])) { if (digitalRead(dataPins[c])) {
if (-1 != buttons[c][i]) { // up
buttons[c][i] = -1; //Serial.print("-");
changedControllers[c] = 1; if (-1 != buttons[c][i]) {
} buttons[c][i] = -1;
} else { changedControllers[c] = 1;
//++buttons[c][i]; }
//changedControllers[c] = 1; } else {
if (0 != buttons[c][i]) { // down
buttons[c][i] = 0; //Serial.print(i);
changedControllers[c] = 1; //++buttons[c][i];
} //changedControllers[c] = 1;
if (0 != buttons[c][i]) {
buttons[c][i] = 0;
changedControllers[c] = 1;
} }
} }
}
digitalWrite(clockPin, LOW); digitalWrite(clockPin, LOW);
delayMicroseconds(6); delayMicroseconds(6);
digitalWrite(clockPin, HIGH); digitalWrite(clockPin, HIGH);
delayMicroseconds(6); delayMicroseconds(6);
} }
//Serial.println();
for (int c = 0; c < GAMEPAD_COUNT; c++) { for (int c = 0; c < GAMEPAD_COUNT; c++) {
// have any buttons changed state? // have any buttons changed state?
@ -130,16 +136,32 @@ class GameControllers {
} }
} }
int translate(int controller, Button b) const { uint8_t translate(int controller, uint8_t b) {
if (types[controller] == SNES) if (types[controller] == SNES)
return b; return b;
return translateToNES[b]; return translateToNES[b];
} }
///returns if button is currently down ///returns if button is currently down
bool down(int controller, Button b) const { bool down(int controller, uint8_t b) {
return buttons[controller][translate(controller, b)] >= 0; return buttons[controller][translate(controller, b)] >= 0;
} }
void pressAll(int controller, void (*pushButton)(const int controller, const uint8_t btn)) {
if (types[controller] == SNES) {
for (uint8_t i = 0; i < sizeof(snesButtons); i++) {
if (buttons[controller][snesButtons[i]] >= 0) {
pushButton(controller, snesButtons[i]);
}
}
} else {
for (uint8_t i = 0; i < sizeof(nesButtons); i++) {
if (buttons[controller][translateToNES[nesButtons[i]]] >= 0) {
pushButton(controller, nesButtons[i]);
}
}
}
}
}; };
static const int translateToHid[12] = { static const int translateToHid[12] = {
@ -161,19 +183,10 @@ GameControllers controllers;
GAMEPAD_CLASS gamepad; GAMEPAD_CLASS gamepad;
void setup() { void dummyControllerChanged(const int c) {
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]);
}
} }
/* #ifdef DEBUG
void controllerChangedDebug(const int c) { void controllerChangedDebug(const int c) {
Serial.print("controllerChanged!!!!: "); Serial.print("controllerChanged!!!!: ");
Serial.println(c); Serial.println(c);
@ -183,14 +196,62 @@ void controllerChangedDebug(const int c) {
Serial.print("; "); Serial.print("; ");
Serial.print(btn); Serial.print(btn);
Serial.print(", "); Serial.print(", ");
Serial.print(controllers.buttons[c][controllers.translate(c, static_cast<GameControllers::Button>(btn))]); Serial.print(controllers.buttons[c][controllers.translate(c, btn)]);
Serial.print(",");
Serial.print(controllers.buttons[c][btn]);
} }
Serial.println(""); Serial.println("");
} }
*/ #endif // DEBUG
void setup() {
bool allNes = true;
#ifdef DEBUG
delay(5000);
#endif // DEBUG
gamepad.begin();
//initialize shared pins
controllers.init(LATCH_PIN, CLOCK_PIN);
//activate first controller and set the type to SNES
for (int c = 0; c < GAMEPAD_COUNT; c++) {
controllers.setController(c, GameControllers::SNES, DATA_PIN[c]);
}
// poll controllers once to detect NES vs SNES
controllers.poll(dummyControllerChanged);
for (int c = 0; c < GAMEPAD_COUNT; c++) {
// for NES, A+X+L+R are down always, re-initialize
if (controllers.down(c, GameControllers::A) && controllers.down(c, GameControllers::X) && controllers.down(c, GameControllers::L) && controllers.down(c, GameControllers::R)) {
#ifdef DEBUG
Serial.println("detected NES");
#endif // DEBUG
controllers.types[c] = GameControllers::NES;
} else {
#ifdef DEBUG
Serial.println("detected SNES");
#endif // DEBUG
allNes = false;
}
}
if (allNes) {
#ifdef DEBUG
Serial.println("detected ONLY NES");
#endif // DEBUG
controllers.maxButtons = 8;
}
}
void pushButton(const int c, const uint8_t btn) {
gamepad.press(c, translateToHid[btn]);
}
void controllerChanged(const int c) { void controllerChanged(const int c) {
//controllerChangedDebug(c); #ifdef DEBUG
controllerChangedDebug(c);
#endif // DEBUG
gamepad.buttons(c, 0); gamepad.buttons(c, 0);
// if start and select are held at the same time, send menu and only menu // if start and select are held at the same time, send menu and only menu
@ -198,13 +259,7 @@ void controllerChanged(const int c) {
gamepad.press(c, BUTTON_MENU); gamepad.press(c, BUTTON_MENU);
} else { } else {
// actually send buttons held // actually send buttons held
for (uint8_t btn = 0; btn < 12; btn++) { controllers.pressAll(c, pushButton);
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::DOWN)) {
if (controllers.down(c, GameControllers::RIGHT)) { if (controllers.down(c, GameControllers::RIGHT)) {

View File

@ -9,6 +9,19 @@
#include "../common.h" #include "../common.h"
void print_axis(int16_t i) {
char buf[6];
sprintf(buf, i < 0 ? "%05d" : "+%05d", i);
Serial.print(buf);
}
void print_trigger(char i) {
char buf[4] = {0}; // why the hell is this initializer required...
// todo: probably not right
sprintf(buf, "%03u", (uint8_t)i);
Serial.print(buf);
}
class DebugGamepad : public AbstractGamepad { class DebugGamepad : public AbstractGamepad {
public: public:
DebugGamepad() : AbstractGamepad() { DebugGamepad() : AbstractGamepad() {
@ -20,7 +33,80 @@ class DebugGamepad : public AbstractGamepad {
} }
virtual void setAxis(const uint8_t cIdx, int16_t x, int16_t y, int16_t z, int16_t rZ, char rX, char rY, signed char hat) { virtual void setAxis(const uint8_t cIdx, int16_t x, int16_t y, int16_t z, int16_t rZ, char rX, char rY, signed char hat) {
Serial.println("DebugGamepad.setAxis"); Serial.print("DebugGamepad.setAxis ");
Serial.print(cIdx);
Serial.print(" b: ");
Serial.print(this->isPressed(cIdx, BUTTON_A) ? "A" : "-");
Serial.print("+");
Serial.print(this->isPressed(cIdx, BUTTON_B) ? "B" : "-");
Serial.print("+");
Serial.print(this->isPressed(cIdx, BUTTON_X) ? "X" : "-");
Serial.print("+");
Serial.print(this->isPressed(cIdx, BUTTON_Y) ? "Y" : "-");
Serial.print("+");
Serial.print(this->isPressed(cIdx, BUTTON_SELECT) ? "SL" : "--");
Serial.print("+");
Serial.print(this->isPressed(cIdx, BUTTON_START) ? "ST" : "--");
Serial.print("+");
Serial.print(this->isPressed(cIdx, BUTTON_MENU) ? "M" : "-");
Serial.print("+");
Serial.print(this->isPressed(cIdx, BUTTON_TL) ? "TL" : "--");
Serial.print("+");
Serial.print(this->isPressed(cIdx, BUTTON_TR) ? "TR" : "--");
Serial.print("+");
Serial.print(this->isPressed(cIdx, BUTTON_TL2) ? "TL2" : "---");
Serial.print("+");
Serial.print(this->isPressed(cIdx, BUTTON_TR2) ? "TR2" : "---");
Serial.print("+");
Serial.print(this->isPressed(cIdx, BUTTON_THUMBL) ? "THL" : "---");
Serial.print("+");
Serial.print(this->isPressed(cIdx, BUTTON_THUMBR) ? "THR" : "---");
Serial.print(" h: ");
switch (hat) {
case DPAD_CENTER:
Serial.print("--");
break;
case DPAD_UP:
Serial.print("U-");
break;
case DPAD_UP_RIGHT:
Serial.print("UR");
break;
case DPAD_RIGHT:
Serial.print("-R");
break;
case DPAD_DOWN_RIGHT:
Serial.print("DR");
break;
case DPAD_DOWN:
Serial.print("D-");
break;
case DPAD_DOWN_LEFT:
Serial.print("DL");
break;
case DPAD_LEFT:
Serial.print("-L");
break;
case DPAD_UP_LEFT:
Serial.print("UL");
break;
default:
Serial.print("++");
break;
}
Serial.print(" X,Y: ");
print_axis(x);
Serial.print(",");
print_axis(y);
Serial.print(" Z,RZ: ");
print_axis(z);
Serial.print(",");
print_axis(rZ);
Serial.print(" rx: ");
print_trigger(rX);
Serial.print(" ry: ");
print_trigger(rY);
Serial.println();
AbstractGamepad::setAxis(cIdx, x, y, z, rZ, rX, rY, hat); AbstractGamepad::setAxis(cIdx, x, y, z, rZ, rX, rY, hat);
} }

View File

@ -4,7 +4,7 @@
// number of button presses we wait for USB-HID to connect // number of button presses we wait for USB-HID to connect
// works within 1 for me but who knows... // works within 1 for me but who knows...
#ifndef GAMEPAD_USBRADIO_DETECT_BUTTONS #ifndef GAMEPAD_USBRADIO_DETECT_BUTTONS
#define GAMEPAD_USBRADIO_DETECT_BUTTONS 1 #define GAMEPAD_USBRADIO_DETECT_BUTTONS 4
#endif #endif
#ifndef GAMEPAD_CLASS #ifndef GAMEPAD_CLASS