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 Male Pins | Arduino Pro Micro GPIO | ESP32 GPIO |
|--------------|---------------------------------------------|-----------------------------------------|
| 1 | 1 | |
| 2 | 2 | |
| 3 | 3 | |
| 4 | 4 | |
| 5 | 5 | |
| 6 | 6 | |
| 7 | 7 | |
| 8 | 8 | |
| 9 | 9 | |
| 10 | 10 | |
| 11 | 11 | |
| 12 | - | |
| 13 | - | |
| 14 | 14 | |
| 15 | 15 | |
| 16 | 16 | |
| 17 | - | |
| 18 | 18 | |
| 19 | 19 | |
| 20 | 20 | |
| 21 | 21 | |
| 22 | - | |
| 23 | 3.3V VCC | |
| 24 | 5V VCC | |
| 25 | GND | |
| DB-25 Pins | Arduino Pro Micro GPIO | ESP32 GPIO | RADIO | SNES | PSX |
|---------------|------------------------|------------|----------|--------|--------|
| 1 | 1 | | - | - | - |
| 2 | 2 | | - | LATCH | DATA |
| 3 | 3 | | - | CLOCK | CMD |
| 4 | 4 | | - | - | ATT |
| 5 | 5 | | - | - | CLK |
| 6 | 6 | | - | - | - |
| 7 | 7 | | CE | - | - |
| 8 | 8 | | CSN | - | - |
| 9 | 9 | | - | - | - |
| 10 | 10 | | - | - | - |
| 11 | 0 | | - | - | - |
| 12 | - | | - | - | - |
| 13 | - | | - | - | - |
| 14 | 14 | | MISO | - | - |
| 15 | 15 | | SCLK | - | - |
| 16 | 16 | | MOSI | - | - |
| 17 | - | | - | - | - |
| 18 | 18 | | - | DATA1 | - |
| 19 | 19 | | - | DATA2 | - |
| 20 | 20 | | - | DATA3 | - |
| 21 | 21 | | - | DATA4 | - |
| 22 | - | | - | - | - |
| 23 | - | | 3.3V VCC | - | - |
| 24 | 5V VCC | | 5V VCC | 5V VCC | 5V VCC |
| 25 | GND | | GND | GND | - |

View File

@ -5,14 +5,14 @@
/-------------\
PIN # USAGE
PIN # USAGE (colors from my extension cable, check your own)
GND
DATA
VCC +3.3V ONLY
GND - red
DATA - white
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
#define POLL_DELAY 14
@ -123,6 +123,8 @@ void print_report(ControllerReport &controller) {
#endif
void setup() {
// n64 low because it *should* be 3.3V
digitalWrite(DATA_PIN, LOW);
#ifdef DEBUG
Serial.begin(115200);
if (controller.begin()) {
@ -172,7 +174,7 @@ void loop() {
gamepad.press(c, BUTTON_B);
}
if (report.z) {
gamepad.press(c, BUTTON_TR);
gamepad.press(c, BUTTON_TL2);
}
if (report.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
CMD/COMMAND
N/C (9 Volts unused)
GND
VCC
ATT
CLK/CLOCK
N/C
ACK
DATA - brown
CMD/COMMAND - orange
N/C (9 Volts unused) - white
GND - black
5V VCC - red
ATT - yellow
CLK/CLOCK - blue
N/C - -
ACK - green
*/

View File

@ -32,9 +32,14 @@ static const int CLOCK_PIN = 3; // white
#endif
// power red, ground black
//#define DEBUG
#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 {
public:
@ -59,12 +64,12 @@ class GameControllers {
L = 10,
R = 11,
};
Type types[GAMEPAD_COUNT];
int latchPin;
int clockPin;
int dataPins[GAMEPAD_COUNT];
long buttons[GAMEPAD_COUNT][12];
int maxButtons = 12;
int changedControllers[GAMEPAD_COUNT];
@ -76,13 +81,6 @@ class GameControllers {
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
@ -90,6 +88,9 @@ class GameControllers {
types[controller] = type;
dataPins[controller] = dataPin;
pinMode(dataPins[controller], INPUT_PULLUP);
for (int i = 0; i < 12; i++) {
buttons[controller][i] = -1;
}
}
void poll(void (*controllerChanged)(const int controller)) {
@ -99,28 +100,33 @@ class GameControllers {
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;
}
//Serial.print("snes: ");
for (int i = 0; i < maxButtons; i++) {
for (int c = 0; c < GAMEPAD_COUNT; c++) {
if (digitalRead(dataPins[c])) {
// up
//Serial.print("-");
if (-1 != buttons[c][i]) {
buttons[c][i] = -1;
changedControllers[c] = 1;
}
} else {
// down
//Serial.print(i);
//++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);
}
//Serial.println();
for (int c = 0; c < GAMEPAD_COUNT; c++) {
// 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)
return b;
return translateToNES[b];
}
///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;
}
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] = {
@ -161,19 +183,10 @@ 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 dummyControllerChanged(const int c) {
}
/*
#ifdef DEBUG
void controllerChangedDebug(const int c) {
Serial.print("controllerChanged!!!!: ");
Serial.println(c);
@ -183,14 +196,62 @@ void controllerChangedDebug(const int c) {
Serial.print("; ");
Serial.print(btn);
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("");
}
*/
#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) {
//controllerChangedDebug(c);
#ifdef DEBUG
controllerChangedDebug(c);
#endif // DEBUG
gamepad.buttons(c, 0);
// 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);
} 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]);
}
}
controllers.pressAll(c, pushButton);
}
if (controllers.down(c, GameControllers::DOWN)) {
if (controllers.down(c, GameControllers::RIGHT)) {

View File

@ -9,6 +9,19 @@
#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 {
public:
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) {
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);
}

View File

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