[38a6d09] | 1 | #include <avr/io.h>
|
---|
| 2 |
|
---|
| 3 | #include <stdbool.h>
|
---|
| 4 |
|
---|
[703832c] | 5 | // The UART is on PD2 (Rx) and PD3 (Tx)
|
---|
| 6 | // The gamepads are all connected on port B
|
---|
[5b8020c] | 7 | #define GRIP_PORT PORTB
|
---|
| 8 | #define GRIP_DDR DDRB
|
---|
| 9 | #define GRIP_PIN PINB
|
---|
| 10 | #define GRIP_DAT_A (1 << 0)
|
---|
| 11 | #define GRIP_CLK_A (1 << 1)
|
---|
| 12 | #define GRIP_DAT_B (1 << 3)
|
---|
| 13 | #define GRIP_CLK_B (1 << 2)
|
---|
[5b8c7e2] | 14 | #define GRIP_DAT_C (1 << 7)
|
---|
| 15 | #define GRIP_CLK_C (1 << 6)
|
---|
| 16 | #define GRIP_DAT_D (1 << 5)
|
---|
| 17 | #define GRIP_CLK_D (1 << 4)
|
---|
[5b8020c] | 18 |
|
---|
[38a6d09] | 19 | class GrIP
|
---|
| 20 | {
|
---|
| 21 | public:
|
---|
| 22 | GrIP()
|
---|
| 23 | {
|
---|
| 24 | word = 0;
|
---|
| 25 | count = 0;
|
---|
| 26 | state = 0;
|
---|
| 27 | }
|
---|
| 28 |
|
---|
[703832c] | 29 | // Push the next bit and returns true if it completes a word.
|
---|
| 30 | // The whole 24 bit word is stored in "word" and consists of:
|
---|
| 31 | // - One 7-bit sync pattern: always 0111111
|
---|
| 32 | // - Three 6-bit blocks starting with a 0 followed by 5 button bits
|
---|
[5b8020c] | 33 | bool PushBit(uint32_t bit)
|
---|
[38a6d09] | 34 | {
|
---|
[703832c] | 35 | word = (word >> 1) | ((bit & 1) << 31);
|
---|
[38a6d09] | 36 | count++;
|
---|
| 37 |
|
---|
| 38 | switch (state) {
|
---|
| 39 | case 0:
|
---|
[703832c] | 40 | if ((word & 0xFE000000) != 0x7C000000) return false;
|
---|
| 41 | count = 7;
|
---|
[38a6d09] | 42 | state = 1;
|
---|
| 43 | break;
|
---|
| 44 | case 1:
|
---|
| 45 | if (count == 24) {
|
---|
| 46 | state = 0;
|
---|
| 47 | count = 0;
|
---|
[5b8020c] | 48 | return true;
|
---|
[38a6d09] | 49 | }
|
---|
| 50 | break;
|
---|
| 51 | }
|
---|
[5b8020c] | 52 |
|
---|
| 53 | return false;
|
---|
| 54 | }
|
---|
| 55 |
|
---|
[703832c] | 56 | public:
|
---|
[5b8020c] | 57 | uint32_t word;
|
---|
[703832c] | 58 | private:
|
---|
[5b8020c] | 59 | uint8_t count;
|
---|
[703832c] | 60 | uint8_t state; // 0 = looking for sync, 1 = synchronized (we received 0111111)
|
---|
[38a6d09] | 61 | };
|
---|
| 62 |
|
---|
[5b8020c] | 63 |
|
---|
[703832c] | 64 | extern "C" void GrIP_Init() {
|
---|
[38a6d09] | 65 | // GrIP input
|
---|
[5b8c7e2] | 66 | GRIP_PORT = 0xFF; // Enable pull-ups
|
---|
[5b8020c] | 67 | GRIP_DDR = 0; // Port as input
|
---|
[703832c] | 68 | }
|
---|
[5b8020c] | 69 |
|
---|
[703832c] | 70 | extern "C" uint8_t GrIP_Read(uint32_t* v, uint8_t k2) {
|
---|
[5b8c7e2] | 71 | // Initial value of oldv for edge detection
|
---|
| 72 | uint8_t oldv = GRIP_PIN;
|
---|
[703832c] | 73 | static uint8_t k = 0;
|
---|
| 74 | if (k2 != 0)
|
---|
| 75 | k = k2 - 1;
|
---|
| 76 | else {
|
---|
| 77 | k++; if (k > 3) k = 0;
|
---|
| 78 | }
|
---|
[38a6d09] | 79 |
|
---|
[5b8020c] | 80 | // Because the CPU is too slow, if we try to scan all pads at once we
|
---|
| 81 | // don't manage to decode them (missed transitions). So we scan them
|
---|
| 82 | // one at a time.
|
---|
| 83 | // To scan all 4 gamepads this will take about 4 milliseconds, which
|
---|
| 84 | // is not the best we could do, but is okay. When we have the real
|
---|
| 85 | // hardware (with the CPU running at full 16MHz speed instead of crappy
|
---|
| 86 | // 1MHz here), we can try to interleave them again (one just has to put
|
---|
| 87 | // them all into a single for loop instead of separate loops for each).
|
---|
| 88 | // Then we get to 1ms to scan all 4 pads in parallel, cool! And it
|
---|
| 89 | // also fixes the problem mentionned below that when less pads are
|
---|
| 90 | // connected, it will not slowdown waiting for one of them to timeout.
|
---|
[703832c] | 91 | //
|
---|
| 92 | // When a gamepad is plugged, the loop seems to complete in around 1000 iterations.
|
---|
| 93 | // When no gamepad is plugged, that's a timeout.
|
---|
[5b8020c] | 94 |
|
---|
| 95 | // Process pad1
|
---|
[5b8c7e2] | 96 | GrIP pad;
|
---|
[703832c] | 97 | uint16_t i;
|
---|
[5b8020c] | 98 |
|
---|
[703832c] | 99 | if (k == 0)
|
---|
| 100 | for (i = 0; i < 2048; i++) {
|
---|
[5b8020c] | 101 | uint8_t newv = GRIP_PIN;
|
---|
| 102 | if (!(newv & GRIP_CLK_A)) { // clock is down
|
---|
| 103 | if (oldv & GRIP_CLK_A) { // and it was up at previous read
|
---|
| 104 | // Read bit
|
---|
| 105 | uint32_t bit = (newv & GRIP_DAT_A) != 0;
|
---|
[5b8c7e2] | 106 | if (pad.PushBit(bit)) {
|
---|
[703832c] | 107 | *v = pad.word;
|
---|
[5b8020c] | 108 | break;
|
---|
| 109 | }
|
---|
| 110 | }
|
---|
| 111 | }
|
---|
| 112 | oldv = newv;
|
---|
| 113 | }
|
---|
[38a6d09] | 114 |
|
---|
[5b8020c] | 115 | // Process pad 2
|
---|
[703832c] | 116 | if (k == 1)
|
---|
| 117 | for (i = 0; i < 2048; i++) {
|
---|
[5b8020c] | 118 | uint8_t newv = GRIP_PIN;
|
---|
| 119 | if (!(newv & GRIP_CLK_B)) { // clock is down
|
---|
| 120 | if (oldv & GRIP_CLK_B) { // and it was up at previous read
|
---|
| 121 | // Read bit
|
---|
| 122 | uint32_t bit = (newv & GRIP_DAT_B) != 0;
|
---|
[5b8c7e2] | 123 | if (pad.PushBit(bit)) {
|
---|
[703832c] | 124 | *v = pad.word;
|
---|
[5b8c7e2] | 125 | break;
|
---|
| 126 | }
|
---|
| 127 | }
|
---|
| 128 | }
|
---|
| 129 | oldv = newv;
|
---|
| 130 | }
|
---|
| 131 |
|
---|
| 132 | // Process pad 3
|
---|
[703832c] | 133 | if (k == 2)
|
---|
| 134 | for (i = 0; i < 2048; i++) {
|
---|
[5b8c7e2] | 135 | uint8_t newv = GRIP_PIN;
|
---|
| 136 | if (!(newv & GRIP_CLK_C)) { // clock is down
|
---|
| 137 | if (oldv & GRIP_CLK_C) { // and it was up at previous read
|
---|
| 138 | // Read bit
|
---|
| 139 | uint32_t bit = (newv & GRIP_DAT_C) != 0;
|
---|
| 140 | if (pad.PushBit(bit)) {
|
---|
[703832c] | 141 | *v = pad.word;
|
---|
[5b8c7e2] | 142 | break;
|
---|
| 143 | }
|
---|
| 144 | }
|
---|
| 145 | }
|
---|
| 146 | oldv = newv;
|
---|
| 147 | }
|
---|
| 148 |
|
---|
| 149 | // Process pad 4
|
---|
[703832c] | 150 | if (k == 3)
|
---|
| 151 | for (i = 0; i < 2048; i++) {
|
---|
[5b8c7e2] | 152 | uint8_t newv = GRIP_PIN;
|
---|
| 153 | if (!(newv & GRIP_CLK_D)) { // clock is down
|
---|
| 154 | if (oldv & GRIP_CLK_D) { // and it was up at previous read
|
---|
| 155 | // Read bit
|
---|
| 156 | uint32_t bit = (newv & GRIP_DAT_D) != 0;
|
---|
| 157 | if (pad.PushBit(bit)) {
|
---|
[703832c] | 158 | *v = pad.word;
|
---|
[5b8020c] | 159 | break;
|
---|
| 160 | }
|
---|
| 161 | }
|
---|
[bbcd1f8] | 162 | }
|
---|
[5b8020c] | 163 | oldv = newv;
|
---|
[bbcd1f8] | 164 | }
|
---|
[5b8c7e2] | 165 |
|
---|
[703832c] | 166 | return k;
|
---|
[38a6d09] | 167 | }
|
---|
| 168 |
|
---|
| 169 |
|
---|