source: avrstuff/grip2hid/grip.cpp@ e545350

main
Last change on this file since e545350 was 703832c, checked in by Adrien Destugues <pulkomandy@…>, 3 years ago

GrIP2HID: actually do HID (using the LUFA USB stack)

  • Property mode set to 100644
File size: 4.0 KB
RevLine 
[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]19class GrIP
20{
21public:
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]56public:
[5b8020c]57 uint32_t word;
[703832c]58private:
[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]64extern "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]70extern "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
Note: See TracBrowser for help on using the repository browser.