|
1 | 1 | #include "GameControllers.h" |
2 | 2 | #include "dwt.h" |
3 | 3 |
|
| 4 | +#define FLEXIBLE_TIMING // work with controllers that don't have 4us bit timing |
| 5 | + |
4 | 6 | static const uint8_t maxFails = 4; |
5 | 7 | static const uint32_t cyclesPerUS = (SystemCoreClock / 1000000ul); |
6 | 8 | 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; |
8 | 11 | static const uint32_t halfBitReceiveCycles = cyclesPerUS * 2; |
| 12 | +#endif |
9 | 13 | static const uint32_t halfBitTimeoutCycles = cyclesPerUS * 6; |
10 | 14 |
|
11 | 15 | // Timeout for controller response: |
@@ -49,6 +53,65 @@ void GameCubeController::sendBits(uint32_t data, uint8_t bits) { |
49 | 53 | } while (bits); |
50 | 54 | } |
51 | 55 |
|
| 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 |
52 | 115 | // bits must be greater than 0 |
53 | 116 | bool GameCubeController::receiveBits(void* data0, uint32_t bits) { |
54 | 117 | uint8_t* data = (uint8_t*)data0; |
@@ -102,6 +165,7 @@ bool GameCubeController::receiveBits(void* data0, uint32_t bits) { |
102 | 165 |
|
103 | 166 | return true; |
104 | 167 | } |
| 168 | +#endif |
105 | 169 |
|
106 | 170 | bool GameCubeController::readWithRumble(GameCubeData_t* data, bool rumble) { |
107 | 171 | if (fails >= maxFails) { |
|
0 commit comments