source: avrstuff/grip2hid/grip.cpp@ 7d84448

main
Last change on this file since 7d84448 was d604513, checked in by Adrien Destugues <pulkomandy@…>, 3 years ago

Adjust software to the production PCB

  • Use the right MCU, port, etc.
  • Change USB IDs to V-USB shared one for USB Joysticks
  • Set vendor and product descriptions
  • Add makefile rule to program the AVR fuses
  • Property mode set to 100644
File size: 4.0 KB
Line 
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
19class GrIP
20{
21public:
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
56public:
57 uint32_t word;
58private:
59 uint8_t count;
60 uint8_t state; // 0 = looking for sync, 1 = synchronized (we received 0111111)
61};
62
63
64extern "C" void GrIP_Init() {
65 // GrIP input
66 GRIP_PORT = 0xFF; // Enable pull-ups
67 GRIP_DDR = 0; // Port as input
68}
69
70extern "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
Note: See TracBrowser for help on using the repository browser.