source: avrstuff/grip2hid/main.cpp@ 5b8020c

main
Last change on this file since 5b8020c was 5b8020c, checked in by Adrien Destugues <pulkomandy@…>, 5 years ago

grip2hid: make it work with 2 pads

The CPU on the AT90USBKEY is apparently too slow to manage two pads in
parallel, so scan them one at a time instead.

  • Property mode set to 100644
File size: 3.1 KB
Line 
1#include <avr/io.h>
2#include <avr/interrupt.h>
3#include <avr/wdt.h>
4#include <avr/pgmspace.h>
5#include <util/delay.h>
6
7#include <string.h>
8#include <stdbool.h>
9
10#include "../libs/usart/usart.h"
11
12#define GRIP_PORT PORTB
13#define GRIP_DDR DDRB
14#define GRIP_PIN PINB
15#define GRIP_DAT_A (1 << 0)
16#define GRIP_CLK_A (1 << 1)
17#define GRIP_DAT_B (1 << 3)
18#define GRIP_CLK_B (1 << 2)
19
20class GrIP
21{
22public:
23 GrIP()
24 {
25 word = 0;
26 count = 0;
27 state = 0;
28 }
29
30 bool PushBit(uint32_t bit)
31 {
32 word = (word << 1) | (bit & 1);
33 count++;
34
35 switch (state) {
36 case 0:
37 if ((word & 0x3F) != 0x1F) return false;
38 count = 6;
39 state = 1;
40 break;
41 case 1:
42 if (count == 24) {
43 state = 0;
44 count = 0;
45 return true;
46 }
47 break;
48 }
49
50 return false;
51 }
52
53 void Dump() {
54 USARTWriteHex(word >> 16);
55 USARTWriteHex(word >> 8);
56 USARTWriteHex(word);
57 }
58
59private:
60 uint32_t word;
61 uint8_t count;
62 uint8_t state;
63};
64
65
66int main() {
67 GrIP pad[2];
68
69 wdt_enable(WDTO_2S);
70
71 // debug LEDs - output
72 DDRD |= 0x7C;
73 PORTD = 0;
74
75 // GrIP input
76 GRIP_PORT = 0; // Disable pull-ups
77 GRIP_DDR = 0; // Port as input
78 uint8_t oldv = GRIP_PIN;
79
80 USARTInit();
81 USARTWriteChar('h');
82 USARTWriteChar('\r');
83 USARTWriteChar('\n');
84
85
86 for (;;) {
87 // Because the CPU is too slow, if we try to scan all pads at once we
88 // don't manage to decode them (missed transitions). So we scan them
89 // one at a time.
90 // To scan all 4 gamepads this will take about 4 milliseconds, which
91 // is not the best we could do, but is okay. When we have the real
92 // hardware (with the CPU running at full 16MHz speed instead of crappy
93 // 1MHz here), we can try to interleave them again (one just has to put
94 // them all into a single for loop instead of separate loops for each).
95 // Then we get to 1ms to scan all 4 pads in parallel, cool! And it
96 // also fixes the problem mentionned below that when less pads are
97 // connected, it will not slowdown waiting for one of them to timeout.
98
99 // FIXME the loop to 255 here to wait for a bit isn't too nice. We
100 // should rather use a timer with a known period?
101 // Process pad1
102 uint8_t i;
103 for (i = 0; i < 255; i++) {
104 wdt_reset();
105
106 uint8_t newv = GRIP_PIN;
107
108 if (!(newv & GRIP_CLK_A)) { // clock is down
109 if (oldv & GRIP_CLK_A) { // and it was up at previous read
110 // Read bit
111 uint32_t bit = (newv & GRIP_DAT_A) != 0;
112 i = 0;
113 if (pad[0].PushBit(bit)) {
114 pad[0].Dump();
115 USARTWriteChar(' ');
116 break;
117 }
118 }
119 }
120 oldv = newv;
121 }
122
123 // Process pad 2
124 for (i = 0; i < 255; i++) {
125 wdt_reset();
126
127 uint8_t newv = GRIP_PIN;
128 if (!(newv & GRIP_CLK_B)) { // clock is down
129 if (oldv & GRIP_CLK_B) { // and it was up at previous read
130 // Read bit
131 uint32_t bit = (newv & GRIP_DAT_B) != 0;
132 i = 0;
133 if (pad[1].PushBit(bit)) {
134 pad[1].Dump();
135 USARTWriteChar(' ');
136 break;
137 }
138 }
139 }
140 oldv = newv;
141 }
142 USARTWriteChar('\r');
143 USARTWriteChar('\n');
144 }
145
146 return 0;
147}
148
149
Note: See TracBrowser for help on using the repository browser.