Skip to content

Commit 890d374

Browse files
committed
flexible timing to support Hori controllers
1 parent 2c701a9 commit 890d374

File tree

1 file changed

+65
-1
lines changed

1 file changed

+65
-1
lines changed

src/gamecube.cpp

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
#include "GameControllers.h"
22
#include "dwt.h"
33

4+
#define FLEXIBLE_TIMING // work with controllers that don't have 4us bit timing
5+
46
static const uint8_t maxFails = 4;
57
static const uint32_t cyclesPerUS = (SystemCoreClock / 1000000ul);
68
static const uint32_t quarterBitSendingCycles = cyclesPerUS * 5 / 4;
7-
static const uint32_t bitReceiveCycles = cyclesPerUS * 4;
9+
#ifndef FLEXIBLE_TIMING
10+
//static const uint32_t bitReceiveCycles = cyclesPerUS * 4;
811
static const uint32_t halfBitReceiveCycles = cyclesPerUS * 2;
12+
#endif
913
static const uint32_t halfBitTimeoutCycles = cyclesPerUS * 6;
1014

1115
// Timeout for controller response:
@@ -49,6 +53,65 @@ void GameCubeController::sendBits(uint32_t data, uint8_t bits) {
4953
} while (bits);
5054
}
5155

56+
57+
#ifdef FLEXIBLE_TIMING
58+
// This version should work with controllers whose timing is off, like some Hori pads ( https://www.raphnet.net/electronique/gc_n64_usb/index_en.php )
59+
60+
// bits must be greater than 0
61+
bool GameCubeController::receiveBits(void* data0, uint32_t bits) {
62+
uint8_t* data = (uint8_t*)data0;
63+
uint8_t bitmap = 0x80;
64+
uint32_t lowTime;
65+
uint32_t highTime;
66+
67+
// wait for start of transmission (low)
68+
DWT->CYCCNT = 0;
69+
while (gpio_read_bit(port.device, port.pinNumber)) {
70+
if (DWT->CYCCNT >= responseTimeoutCycles)
71+
return false;
72+
}
73+
74+
DWT->CYCCNT = 0; // for measuring low time
75+
76+
*data = 0;
77+
do {
78+
while (!gpio_read_bit(port.device, port.pinNumber)) {
79+
if (DWT->CYCCNT >= halfBitTimeoutCycles)
80+
return false;
81+
}
82+
lowTime = DWT->CYCCNT;
83+
84+
DWT->CYCCNT = 0;
85+
while (gpio_read_bit(port.device, port.pinNumber)) {
86+
if (DWT->CYCCNT >= halfBitTimeoutCycles)
87+
return false;
88+
}
89+
highTime = DWT->CYCCNT;
90+
DWT->CYCCNT = 0; // for measuring low time of next bit
91+
92+
if (highTime > lowTime) {
93+
*data |= bitmap;
94+
}
95+
96+
bitmap >>= 1;
97+
bits--;
98+
if (bitmap == 0) {
99+
data++;
100+
bitmap = 0x80;
101+
if (bits)
102+
*data = 0;
103+
}
104+
} while (bits);
105+
106+
// wait for end of stop bit, just in case
107+
while (!gpio_read_bit(port.device, port.pinNumber)) {
108+
if (DWT->CYCCNT >= halfBitTimeoutCycles)
109+
return false;
110+
}
111+
112+
return true;
113+
}
114+
#else
52115
// bits must be greater than 0
53116
bool GameCubeController::receiveBits(void* data0, uint32_t bits) {
54117
uint8_t* data = (uint8_t*)data0;
@@ -102,6 +165,7 @@ bool GameCubeController::receiveBits(void* data0, uint32_t bits) {
102165

103166
return true;
104167
}
168+
#endif
105169

106170
bool GameCubeController::readWithRumble(GameCubeData_t* data, bool rumble) {
107171
if (fails >= maxFails) {

0 commit comments

Comments
 (0)