Skip to content

Commit a1eb7a9

Browse files
committed
genesis
1 parent 516d821 commit a1eb7a9

File tree

6 files changed

+296
-6
lines changed

6 files changed

+296
-6
lines changed

LICENSE

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
MIT License
22

3-
Copyright (c) 2017 arpruss
3+
Copyright (c) 2017-19 arpruss and (c) 2017 Jon Thysell <http://jonthysell.com>
4+
45

56
Permission is hereby granted, free of charge, to any person obtaining a copy
67
of this software and associated documentation files (the "Software"), to deal

src/GameControllers.h

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
#include <Arduino.h>
55
#include "debouncer.h"
6+
#include "SegaController.h"
67
#define NUNCHUCK_SOFT_I2C // currently, HardWire doesn't work well for hotplugging
78
// Also, it probably won't well with SPI remap
89

@@ -19,19 +20,25 @@
1920

2021
#define INPUT_NOT_IMPLEMENTED ((unsigned)-1)
2122

22-
#define DDR_PAD_EMULATES_STICK
23-
2423
typedef struct {
2524
gpio_dev* device;
2625
uint32_t mask;
2726
uint32_t pinNumber;
2827
} PortData;
2928

29+
const uint16_t gcmaskA = 0x01;
30+
const uint16_t gcmaskB = 0x02;
31+
const uint16_t gcmaskX = 0x04;
32+
const uint16_t gcmaskY = 0x08;
3033
const uint16_t gcmaskDLeft = 0x100;
3134
const uint16_t gcmaskDRight = 0x200;
3235
const uint16_t gcmaskDDown = 0x400;
3336
const uint16_t gcmaskDUp = 0x800;
3437
const uint16_t gcmaskDPad = 0xF00;
38+
const uint16_t gcmaskStart = 0x10;
39+
const uint16_t buttonMaskC = 0x20;
40+
const uint16_t buttonMaskZ = 0x40;
41+
const uint16_t buttonMaskMode = 0x80;
3542

3643
typedef struct {
3744
uint16_t buttons;
@@ -56,6 +63,7 @@ typedef struct {
5663

5764
class GameController {
5865
protected:
66+
bool dpadToJoystick = true;
5967
void setPortData(PortData *p, unsigned pin) {
6068
if (pin == INPUT_NOT_IMPLEMENTED) {
6169
p->device = NULL;
@@ -73,6 +81,12 @@ class GameController {
7381
bool begin(void) {
7482
return true;
7583
}
84+
void setDPadToJoystick(bool value) {
85+
dpadToJoystick = value;
86+
}
87+
bool getDPadToJoystick() {
88+
return dpadToJoystick;
89+
}
7690
};
7791

7892
class NunchuckController : public GameController {
@@ -144,4 +158,17 @@ class GameCubeController : public GameController {
144158
GameCubeController(unsigned pin);
145159
};
146160

161+
#define NUM_GENESIS_PINS 7
162+
enum GenesisPins { GENESIS_PIN_1 = 0, GENESIS_PIN_2, GENESIS_PIN_3, GENESIS_PIN_4, GENESIS_PIN_5, GENESIS_PIN_6, GENESIS_PIN_7, GENESIS_PIN_9 };
163+
#define GENESIS_PIN_SELECT = GENESIS_PIN_7;
164+
165+
class GenesisController : public GameController {
166+
private:
167+
SegaController* sega;
168+
public:
169+
bool begin(void);
170+
bool read(GameControllerData_t* data);
171+
GenesisController(unsigned pin1, unsigned pin2, unsigned pin3, unsigned pin4, unsigned pin6, unsigned pin7, unsigned pin9);
172+
};
173+
147174
#endif // _NINTENDO_CONTROLLER_H

src/SegaController.cpp

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
//
2+
// SegaController.cpp
3+
//
4+
// Author:
5+
// Jon Thysell <[email protected]>
6+
//
7+
// Copyright (c) 2017 Jon Thysell <http://jonthysell.com>
8+
//
9+
// Permission is hereby granted, free of charge, to any person obtaining a copy
10+
// of this software and associated documentation files (the "Software"), to deal
11+
// in the Software without restriction, including without limitation the rights
12+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13+
// copies of the Software, and to permit persons to whom the Software is
14+
// furnished to do so, subject to the following conditions:
15+
//
16+
// The above copyright notice and this permission notice shall be included in
17+
// all copies or substantial portions of the Software.
18+
//
19+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25+
// THE SOFTWARE.
26+
27+
#include "Arduino.h"
28+
#include "SegaController.h"
29+
30+
SegaController::SegaController(unsigned db9_pin_7, unsigned db9_pin_1, unsigned db9_pin_2, unsigned db9_pin_3, unsigned db9_pin_4, unsigned db9_pin_6, unsigned db9_pin_9)
31+
{
32+
// Set pins
33+
_selectPin = db9_pin_7;
34+
35+
_inputPins[0] = db9_pin_1;
36+
_inputPins[1] = db9_pin_2;
37+
_inputPins[2] = db9_pin_3;
38+
_inputPins[3] = db9_pin_4;
39+
_inputPins[4] = db9_pin_6;
40+
_inputPins[5] = db9_pin_9;
41+
42+
// Setup output pin
43+
pinMode(_selectPin, OUTPUT);
44+
digitalWrite(_selectPin, HIGH);
45+
46+
// Setup input pins
47+
for (byte i = 0; i < SC_INPUT_PINS; i++)
48+
{
49+
pinMode(_inputPins[i], INPUT_PULLUP);
50+
}
51+
52+
_currentState = 0;
53+
_sixButtonMode = false;
54+
_lastReadTime = millis();
55+
}
56+
57+
word SegaController::getState()
58+
{
59+
if (max(millis() - _lastReadTime, 0) < SC_READ_DELAY_MS)
60+
{
61+
// Not enough time has elapsed, return previously read state
62+
return _currentState;
63+
}
64+
65+
noInterrupts();
66+
67+
// Clear current state
68+
_currentState = 0;
69+
70+
for (byte cycle = 0; cycle < SC_CYCLES; cycle++)
71+
{
72+
readCycle(cycle);
73+
}
74+
75+
// When a controller disconnects, revert to three-button polling
76+
if (!(_currentState & SC_CTL_ON))
77+
{
78+
_sixButtonMode = false;
79+
}
80+
81+
interrupts();
82+
83+
_lastReadTime = millis();
84+
85+
return _currentState;
86+
}
87+
88+
void SegaController::readCycle(byte cycle)
89+
{
90+
// Set the select pin low/high
91+
digitalWrite(_selectPin, cycle % 2);
92+
93+
delayMicroseconds(50);
94+
95+
// Read flags
96+
switch (cycle)
97+
{
98+
case 2:
99+
// Check that a controller is connected
100+
_currentState |= (digitalRead(_inputPins[2]) == LOW && digitalRead(_inputPins[3]) == LOW) * SC_CTL_ON;
101+
102+
// Check controller is connected before reading A/Start to prevent bad reads when inserting/removing cable
103+
if (_currentState & SC_CTL_ON)
104+
{
105+
// Read input pins for A, Start
106+
if (digitalRead(_inputPins[4]) == LOW) { _currentState |= SC_BTN_A; }
107+
if (digitalRead(_inputPins[5]) == LOW) { _currentState |= SC_BTN_START; }
108+
}
109+
break;
110+
case 3:
111+
// Read input pins for Up, Down, Left, Right, B, C
112+
if (digitalRead(_inputPins[0]) == LOW) { _currentState |= SC_BTN_UP; }
113+
if (digitalRead(_inputPins[1]) == LOW) { _currentState |= SC_BTN_DOWN; }
114+
if (digitalRead(_inputPins[2]) == LOW) { _currentState |= SC_BTN_LEFT; }
115+
if (digitalRead(_inputPins[3]) == LOW) { _currentState |= SC_BTN_RIGHT; }
116+
if (digitalRead(_inputPins[4]) == LOW) { _currentState |= SC_BTN_B; }
117+
if (digitalRead(_inputPins[5]) == LOW) { _currentState |= SC_BTN_C; }
118+
break;
119+
case 4:
120+
_sixButtonMode = (digitalRead(_inputPins[0]) == LOW && digitalRead(_inputPins[1]) == LOW);
121+
break;
122+
case 5:
123+
if (_sixButtonMode)
124+
{
125+
// Read input pins for X, Y, Z, Mode
126+
if (digitalRead(_inputPins[0]) == LOW) { _currentState |= SC_BTN_Z; }
127+
if (digitalRead(_inputPins[1]) == LOW) { _currentState |= SC_BTN_Y; }
128+
if (digitalRead(_inputPins[2]) == LOW) { _currentState |= SC_BTN_X; }
129+
if (digitalRead(_inputPins[3]) == LOW) { _currentState |= SC_BTN_MODE; }
130+
}
131+
break;
132+
}
133+
}

src/SegaController.h

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
//
2+
// SegaController.h
3+
//
4+
// Author:
5+
// Jon Thysell <[email protected]>
6+
//
7+
// Copyright (c) 2017 Jon Thysell <http://jonthysell.com>
8+
//
9+
// Permission is hereby granted, free of charge, to any person obtaining a copy
10+
// of this software and associated documentation files (the "Software"), to deal
11+
// in the Software without restriction, including without limitation the rights
12+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13+
// copies of the Software, and to permit persons to whom the Software is
14+
// furnished to do so, subject to the following conditions:
15+
//
16+
// The above copyright notice and this permission notice shall be included in
17+
// all copies or substantial portions of the Software.
18+
//
19+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25+
// THE SOFTWARE.
26+
27+
#ifndef SegaController_h
28+
#define SegaController_h
29+
30+
enum
31+
{
32+
SC_CTL_ON = 1, // The controller is connected
33+
SC_BTN_UP = 2,
34+
SC_BTN_DOWN = 4,
35+
SC_BTN_LEFT = 8,
36+
SC_BTN_RIGHT = 16,
37+
SC_BTN_START = 32,
38+
SC_BTN_A = 64,
39+
SC_BTN_B = 128,
40+
SC_BTN_C = 256,
41+
SC_BTN_X = 512,
42+
SC_BTN_Y = 1024,
43+
SC_BTN_Z = 2048,
44+
SC_BTN_MODE = 4096,
45+
SC_BTN_1 = 128, // Master System compatibility
46+
SC_BTN_2 = 256 // Master System compatibility
47+
};
48+
49+
const byte SC_INPUT_PINS = 6;
50+
51+
const byte SC_CYCLES = 8;
52+
53+
const unsigned long SC_READ_DELAY_MS = 5; // Must be >= 3 to give 6-button controller time to reset
54+
55+
class SegaController {
56+
public:
57+
SegaController(unsigned db9_pin_7, unsigned db9_pin_1, unsigned db9_pin_2, unsigned db9_pin_3, unsigned db9_pin_4, unsigned db9_pin_6, unsigned db9_pin_9);
58+
59+
word getState();
60+
61+
private:
62+
void readCycle(byte cycle);
63+
64+
word _currentState;
65+
66+
unsigned long _lastReadTime;
67+
68+
boolean _sixButtonMode;
69+
70+
unsigned _selectPin; // output select pin
71+
unsigned _inputPins[SC_INPUT_PINS];
72+
};
73+
74+
#endif

src/gamecube.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,7 @@ bool GameCubeController::readWithRumble(GameControllerData_t* data, bool rumble)
9999
data->cY = 1023-rescale(gcData.cY);
100100
data->shoulderLeft = rescale(gcData.shoulderLeft);
101101
data->shoulderRight = rescale(gcData.shoulderRight);
102-
#ifdef DDR_PAD_EMULATES_STICK
103-
if (0 == (gcData.buttons & 0x20) && gcData.joystickX == 1 && gcData.joystickY == 1 && gcData.cX == 1 && gcData.cY == 1 &&
102+
if (dpadToJoystick && 0 == (gcData.buttons & 0x20) && gcData.joystickX == 1 && gcData.joystickY == 1 && gcData.cX == 1 && gcData.cY == 1 &&
104103
gcData.shoulderLeft == 1 && gcData.shoulderRight == 1 && gcData.buttons ) {
105104
data->joystickX = 512;
106105
data->joystickY = 512;
@@ -119,7 +118,6 @@ bool GameCubeController::readWithRumble(GameControllerData_t* data, bool rumble)
119118
data->joystickY = 1023;
120119
}
121120
}
122-
#endif
123121
return true;
124122
}
125123
else {

src/genesis.cpp

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
#include "GameControllers.h"
2+
#include "dwt.h"
3+
4+
static const uint32_t genesisReadDelayMS = 5+1;
5+
6+
static const uint8_t maxFails = 4;
7+
static const uint32_t cyclesPerUS = (SystemCoreClock / 1000000ul);
8+
static const uint32_t quarterBitSendingCycles = cyclesPerUS * 5 / 4;
9+
static const uint32_t bitReceiveCycles = cyclesPerUS * 4;
10+
static const uint32_t halfBitReceiveCycles = cyclesPerUS * 2;
11+
12+
GenesisController::GenesisController(unsigned pin1, unsigned pin2, unsigned pin3, unsigned pin4, unsigned pin6, unsigned pin7, unsigned pin9) {
13+
sega = new SegaController(pin7, pin1, pin2, pin3, pin4, pin6, pin9);
14+
}
15+
16+
bool GenesisController::begin() {
17+
return true;
18+
}
19+
20+
bool GenesisController::read(GameControllerData_t* data) {
21+
word state = sega->getState();
22+
memset(data, 0, sizeof(*data));
23+
data->joystickX = 512;
24+
data->joystickY = 512;
25+
data->cX = 512;
26+
data->cY = 512;
27+
if (state & SC_CTL_ON) {
28+
data->buttons = ( (state & SC_BTN_A) ? gcmaskA : 0 ) |
29+
( (state & SC_BTN_B) ? gcmaskB : 0 ) |
30+
( (state & SC_BTN_C) ? buttonMaskC : 0 ) |
31+
( (state & SC_BTN_X) ? gcmaskX : 0 ) |
32+
( (state & SC_BTN_Y) ? gcmaskY : 0 ) |
33+
( (state & SC_BTN_Z) ? buttonMaskZ : 0 ) |
34+
( (state & SC_BTN_MODE) ? buttonMaskMode : 0 ) |
35+
( (state & SC_BTN_START) ? gcmaskStart : 0);
36+
if (dpadToJoystick) {
37+
if (state & SC_BTN_LEFT)
38+
data->joystickX = 0;
39+
else if (state & SC_BTN_RIGHT)
40+
data->joystickX = 1023;
41+
42+
if (state & SC_BTN_UP)
43+
data->joystickY = 0;
44+
else if (state & SC_BTN_DOWN)
45+
data->joystickY = 1023;
46+
}
47+
else {
48+
data->buttons |= ( (state & SC_BTN_UP) ? gcmaskDUp : 0 ) |
49+
( (state & SC_BTN_DOWN) ? gcmaskDUp : 0 ) |
50+
( (state & SC_BTN_LEFT) ? gcmaskDLeft : 0 ) |
51+
( (state & SC_BTN_RIGHT) ? gcmaskDRight : 0 );
52+
}
53+
return true;
54+
}
55+
return false;
56+
}
57+

0 commit comments

Comments
 (0)