1 | #include <avr/io.h>
|
---|
2 |
|
---|
3 | #include <stdbool.h>
|
---|
4 |
|
---|
5 | // The UART is on PD2 (Rx) and PD3 (Tx)
|
---|
6 | // The gamepads are all connected on port B
|
---|
7 | #define GRIP_PORT PORTD
|
---|
8 | #define GRIP_DDR DDRD
|
---|
9 | #define GRIP_PIN PIND
|
---|
10 | #define GRIP_CLK_A (1 << 0)
|
---|
11 | #define GRIP_DAT_A (1 << 1)
|
---|
12 | #define GRIP_CLK_B (1 << 2)
|
---|
13 | #define GRIP_DAT_B (1 << 3)
|
---|
14 | #define GRIP_CLK_C (1 << 4)
|
---|
15 | #define GRIP_DAT_C (1 << 5)
|
---|
16 | #define GRIP_CLK_D (1 << 6)
|
---|
17 | #define GRIP_DAT_D (1 << 7)
|
---|
18 |
|
---|
19 | class GrIP
|
---|
20 | {
|
---|
21 | public:
|
---|
22 | GrIP()
|
---|
23 | {
|
---|
24 | word = 0;
|
---|
25 | count = 0;
|
---|
26 | state = 0;
|
---|
27 | }
|
---|
28 |
|
---|
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
|
---|
33 | bool PushBit(uint32_t bit)
|
---|
34 | {
|
---|
35 | word = (word >> 1) | ((bit & 1) << 31);
|
---|
36 | count++;
|
---|
37 |
|
---|
38 | switch (state) {
|
---|
39 | case 0:
|
---|
40 | if ((word & 0xFE000000) != 0x7C000000) return false;
|
---|
41 | count = 7;
|
---|
42 | state = 1;
|
---|
43 | break;
|
---|
44 | case 1:
|
---|
45 | if (count == 24) {
|
---|
46 | state = 0;
|
---|
47 | count = 0;
|
---|
48 | return true;
|
---|
49 | }
|
---|
50 | break;
|
---|
51 | }
|
---|
52 |
|
---|
53 | return false;
|
---|
54 | }
|
---|
55 |
|
---|
56 | public:
|
---|
57 | uint32_t word;
|
---|
58 | private:
|
---|
59 | uint8_t count;
|
---|
60 | uint8_t state; // 0 = looking for sync, 1 = synchronized (we received 0111111)
|
---|
61 | };
|
---|
62 |
|
---|
63 |
|
---|
64 | extern "C" void GrIP_Init() {
|
---|
65 | // GrIP input
|
---|
66 | GRIP_PORT = 0xFF; // Enable pull-ups
|
---|
67 | GRIP_DDR = 0; // Port as input
|
---|
68 | }
|
---|
69 |
|
---|
70 | extern "C" uint8_t GrIP_Read(uint32_t* v, uint8_t k2) {
|
---|
71 | // Initial value of oldv for edge detection
|
---|
72 | uint8_t oldv = GRIP_PIN;
|
---|
73 | static uint8_t k = 0;
|
---|
74 | if (k2 != 0)
|
---|
75 | k = k2 - 1;
|
---|
76 | else {
|
---|
77 | k++; if (k > 3) k = 0;
|
---|
78 | }
|
---|
79 |
|
---|
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.
|
---|
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.
|
---|
94 |
|
---|
95 | // Process pad1
|
---|
96 | GrIP pad;
|
---|
97 | uint16_t i;
|
---|
98 |
|
---|
99 | if (k == 0)
|
---|
100 | for (i = 0; i < 2048; i++) {
|
---|
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;
|
---|
106 | if (pad.PushBit(bit)) {
|
---|
107 | *v = pad.word;
|
---|
108 | break;
|
---|
109 | }
|
---|
110 | }
|
---|
111 | }
|
---|
112 | oldv = newv;
|
---|
113 | }
|
---|
114 |
|
---|
115 | // Process pad 2
|
---|
116 | if (k == 1)
|
---|
117 | for (i = 0; i < 2048; i++) {
|
---|
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;
|
---|
123 | if (pad.PushBit(bit)) {
|
---|
124 | *v = pad.word;
|
---|
125 | break;
|
---|
126 | }
|
---|
127 | }
|
---|
128 | }
|
---|
129 | oldv = newv;
|
---|
130 | }
|
---|
131 |
|
---|
132 | // Process pad 3
|
---|
133 | if (k == 2)
|
---|
134 | for (i = 0; i < 2048; i++) {
|
---|
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)) {
|
---|
141 | *v = pad.word;
|
---|
142 | break;
|
---|
143 | }
|
---|
144 | }
|
---|
145 | }
|
---|
146 | oldv = newv;
|
---|
147 | }
|
---|
148 |
|
---|
149 | // Process pad 4
|
---|
150 | if (k == 3)
|
---|
151 | for (i = 0; i < 2048; i++) {
|
---|
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)) {
|
---|
158 | *v = pad.word;
|
---|
159 | break;
|
---|
160 | }
|
---|
161 | }
|
---|
162 | }
|
---|
163 | oldv = newv;
|
---|
164 | }
|
---|
165 |
|
---|
166 | return k;
|
---|
167 | }
|
---|
168 |
|
---|
169 |
|
---|