-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathControllerTeensy.ino
More file actions
214 lines (180 loc) · 5.5 KB
/
ControllerTeensy.ino
File metadata and controls
214 lines (180 loc) · 5.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
#include <ADC.h>
#include <ADC_Module.h>
#include <RingBuffer.h>
#include <RingBufferDMA.h>
#define CPU_RESTART_ADDR (uint32_t *)0xE000ED0C
#define CPU_RESTART_VAL 0x5FA0004
#define Bluetooth Serial1
struct InputPacket {
unsigned short x;
unsigned short y;
bool button1;
bool button2;
//unsigned short battery;
bool operator!=(const InputPacket& rhs) {
return (x != rhs.x) || (y != rhs.y) ||
(button1 != rhs.button1) || (button2 != rhs.button2);
}
};
struct OutputPacket {
bool restart; // Restart flag
unsigned short hapticStr; // Haptic motor strength
unsigned short hapticDur; // Haptic motor duration
};
const int RATE = 10; // Delay between packets in ms
// Pins for the inputs
const int PIN_X = A11;
const int PIN_Y = A10;
const int PIN_B1 = 8;
const int PIN_B2 = 9;
const int PIN_HAPT = A9;
// Deliminator bytes
const char START = 17;
const char END = 18;
const char ESCAPE = 19;
InputPacket prevPack; // The last packet sent
IntervalTimer pulseTimer;
ADC *adc;
void setup() {
// Initialize the Serial
Serial.begin(9600); // USB Serial
Bluetooth.begin(115200); // Bluetooth Serial
adc = new ADC();
// Set up the pins
pinMode(PIN_B1, INPUT_PULLUP);
pinMode(PIN_B2, INPUT_PULLUP);
pinMode(PIN_X, INPUT);
pinMode(PIN_Y, INPUT);
pinMode(PIN_HAPT, OUTPUT);
analogWriteResolution(10);
pinMode(13, OUTPUT);
digitalWrite(13, HIGH);
}
void reboot() {
*CPU_RESTART_ADDR = CPU_RESTART_VAL;
}
void stopPulse() {
analogWrite(PIN_HAPT, 0);
pulseTimer.end();
}
OutputPacket parse(int avail) {
char *buf = new char[avail];
Bluetooth.readBytes(buf, avail);
int n = 0; // Number of bytes in current packet
int sInd = -1; // Index of last START byte
bool lit = false; // Indicates whether the last byte was an ESCAPE
int lastInd = -1; // Start point of the last valid index
for (int i = 0; i < avail; i++) {
if (sInd < 0) {
if (buf[i] == START) {
sInd = i;
n = 0;
lit = false;
}
} else if (!lit) {
if (buf[i] == START) {
// ERROR, restart
sInd = i;
n = 0;
lit = false;
} else if (buf[i] == ESCAPE) {
// If escape, skip this character
lit = true;
} else if (buf[i] == END) {
// Check if the byte number is right
if (n == 5) {
// Valid packet
lastInd = sInd;
sInd = i;
n = 0;
lit = false;
} else {
// Invalid Packet
// Start looking for another packet
sInd = -1;
n = 0;
lit = false;
}
} else {
n++;
}
} else {
lit = false;
n++;
if (buf[i] != START && buf[i] != END && buf[i] != ESCAPE) {
// The controller should never set a non-special byte after an escape
sInd = -1;
n = 0;
}
}
}
if (lastInd >= 0) {
char *packet = new char[5];
int ind = 0;
lit = false; // Interpret the next bit literally
for (int i = lastInd + 1; i < avail; i++) {
if (!lit) {
if (buf[i] == ESCAPE) {
// If escape occured, next byte is literal
lit = true;
} else if (buf[i] == END) {
// End of packet
break;
} else {
//text += buf[i] + " ";
packet[ind] = buf[i];
ind++;
}
} else {
//text += buf[i] + " ";
packet[ind] = buf[i];
ind++;
lit = false;
}
}
OutputPacket pack;
pack.restart = static_cast<bool>(packet[0]);
pack.hapticStr = static_cast<unsigned short>(packet[2] | (packet[1] << 8));
pack.hapticDur = static_cast<unsigned short>(packet[4] | (packet[3] << 8));
delete [] packet;
return pack;
}
delete [] buf;
}
void loop() {
// Create the packet
InputPacket pack;
pack.x = adc->analogRead(PIN_X, ADC_0);
//delay(10);
pack.y = adc->analogRead(PIN_Y, ADC_1);
pack.button1 = !digitalRead(PIN_B1);
pack.button2 = !digitalRead(PIN_B2);
// Check for input
int avail = Bluetooth.available();
if (avail > 0) {
OutputPacket outPack = parse(avail);
if (outPack.restart) {
reboot();
}
if (outPack.hapticStr > 0) {
analogWrite(PIN_HAPT, outPack.hapticStr);
pulseTimer.begin(stopPulse, outPack.hapticDur * 1000);
}
}
// Only send if there are changes
if (pack != prevPack) {
prevPack = pack;
// Cast the packet to its byte form
char *data = reinterpret_cast<char *>(&pack);
Bluetooth.write(START);
for (int i = 0; i < 6; i++) {
if (data[i] == START || data[i] == END || data[i] == ESCAPE) {
// If the data happen to be a special code, send an escape code before
Bluetooth.write(ESCAPE);
}
Bluetooth.write(data[i]);
}
Bluetooth.write(END);
}
delay(RATE);
}