-
Notifications
You must be signed in to change notification settings - Fork 151
/
Brain.cpp
350 lines (295 loc) · 9.8 KB
/
Brain.cpp
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
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
#include "Arduino.h"
#include "Brain.h"
Brain::Brain(Stream &_brainStream) {
brainStream = &_brainStream;
// Keep the rest of the initialization process in a separate method in case
// we overload the constructor.
init();
}
void Brain::init() {
// It's up to the calling code to start the stream
// Usually Serial.begin(9600);
freshPacket = false;
inPacket = false;
packetIndex = 0;
packetLength = 0;
eegPowerLength = 0;
hasPower = false;
checksum = 0;
checksumAccumulator = 0;
signalQuality = 200;
attention = 0;
meditation = 0;
clearEegPower();
}
boolean Brain::update() {
if (brainStream->available()) {
latestByte = brainStream->read();
// Build a packet if we know we're and not just listening for sync bytes.
if (inPacket) {
// First byte after the sync bytes is the length of the upcoming packet.
if (packetIndex == 0) {
packetLength = latestByte;
// Catch error if packet is too long
if (packetLength > MAX_PACKET_LENGTH) {
// Packet exceeded max length
// Send an error
sprintf(latestError, "ERROR: Packet too long %i", packetLength);
inPacket = false;
}
}
else if (packetIndex <= packetLength) {
// Run of the mill data bytes.
// Print them here
// Store the byte in an array for parsing later.
packetData[packetIndex - 1] = latestByte;
// Keep building the checksum.
checksumAccumulator += latestByte;
}
else if (packetIndex > packetLength) {
// We're at the end of the data payload.
// Check the checksum.
checksum = latestByte;
checksumAccumulator = 255 - checksumAccumulator;
// Do they match?
if (checksum == checksumAccumulator) {
boolean parseSuccess = parsePacket();
if (parseSuccess) {
freshPacket = true;
}
else {
// Parsing failed, send an error.
sprintf(latestError, "ERROR: Could not parse");
// good place to print the packet if debugging
}
}
else {
// Checksum mismatch, send an error.
sprintf(latestError, "ERROR: Checksum");
// good place to print the packet if debugging
}
// End of packet
// Reset, prep for next packet
inPacket = false;
}
packetIndex++;
}
// Look for the start of the packet
if ((latestByte == 170) && (lastByte == 170) && !inPacket) {
// Start of packet
inPacket = true;
packetIndex = 0;
checksumAccumulator = 0;
}
// Keep track of the last byte so we can find the sync byte pairs.
lastByte = latestByte;
}
if (freshPacket) {
freshPacket = false;
return true;
}
else {
return false;
}
}
void Brain::clearPacket() {
for (uint8_t i = 0; i < MAX_PACKET_LENGTH; i++) {
packetData[i] = 0;
}
}
void Brain::clearEegPower() {
// Zero the power bands.
for(uint8_t i = 0; i < EEG_POWER_BANDS; i++) {
eegPower[i] = 0;
}
}
boolean Brain::parsePacket() {
// Loop through the packet, extracting data.
// Based on mindset_communications_protocol.pdf from the Neurosky Mindset SDK.
// Returns true if passing succeeds
hasPower = false;
boolean parseSuccess = true;
// int rawValue = 0;
clearEegPower(); // clear the eeg power to make sure we're honest about missing values
for (uint8_t i = 0; i < packetLength; i++) {
switch (packetData[i]) {
case 0x2:
signalQuality = packetData[++i];
break;
case 0x4:
attention = packetData[++i];
break;
case 0x5:
meditation = packetData[++i];
break;
case 0x83:
// ASIC_EEG_POWER: eight big-endian 3-uint8_t unsigned integer values representing delta, theta, low-alpha high-alpha, low-beta, high-beta, low-gamma, and mid-gamma EEG band power values
// The next uint8_t sets the length, usually 24 (Eight 24-bit numbers... big endian?)
// We dont' use this value so let's skip it and just increment i
i++;
// Extract the values
for (int j = 0; j < EEG_POWER_BANDS; j++) {
uint8_t a,b,c;
a = packetData[++i];
b = packetData[++i];
c = packetData[++i];
eegPower[j] = ((uint32_t)a << 16) | ((uint32_t)b << 8) | (uint32_t)c;
}
hasPower = true;
// This seems to happen once during start-up on the force trainer. Strange. Wise to wait a couple of packets before
// you start reading.
break;
case 0x80:
// We dont' use this value so let's skip it and just increment i
// uint8_t packetLength = packetData[++i];
// rawValue = ((int)packetData[++i] << 8) | packetData[++i];
i += 3;
break;
default:
// Broken packet ?
/*
Serial.print(F("parsePacket UNMATCHED data 0x"));
Serial.print(packetData[i], HEX);
Serial.print(F(" in position "));
Serial.print(i, DEC);
printPacket();
*/
parseSuccess = false;
break;
}
}
return parseSuccess;
}
// Keeping this around for debug use
void Brain::printCSV() {
// Print the CSV over serial
brainStream->print(signalQuality, DEC);
brainStream->print(",");
brainStream->print(attention, DEC);
brainStream->print(",");
brainStream->print(meditation, DEC);
if (hasPower) {
for(int i = 0; i < EEG_POWER_BANDS; i++) {
brainStream->print(",");
brainStream->print(eegPower[i], DEC);
}
}
brainStream->println("");
}
char* Brain::readErrors() {
return latestError;
}
char* Brain::readCSV() {
// spit out a big string?
// find out how big this really needs to be
// should be popped off the stack once it goes out of scope?
// make the character array as small as possible
if(hasPower) {
sprintf(csvBuffer,"%d,%d,%d,%lu,%lu,%lu,%lu,%lu,%lu,%lu,%lu",
signalQuality,
attention,
meditation,
eegPower[0],
eegPower[1],
eegPower[2],
eegPower[3],
eegPower[4],
eegPower[5],
eegPower[6],
eegPower[7]
);
return csvBuffer;
}
else {
sprintf(csvBuffer,"%d,%d,%d",
signalQuality,
attention,
meditation
);
return csvBuffer;
}
}
// For debugging, print the entire contents of the packet data array.
void Brain::printPacket() {
brainStream->print("[");
for (uint8_t i = 0; i < MAX_PACKET_LENGTH; i++) {
brainStream->print(packetData[i], DEC);
if (i < MAX_PACKET_LENGTH - 1) {
brainStream->print(", ");
}
}
brainStream->println("]");
}
void Brain::printDebug() {
brainStream->println("");
brainStream->println("--- Start Packet ---");
brainStream->print("Signal Quality: ");
brainStream->println(signalQuality, DEC);
brainStream->print("Attention: ");
brainStream->println(attention, DEC);
brainStream->print("Meditation: ");
brainStream->println(meditation, DEC);
if (hasPower) {
brainStream->println("");
brainStream->println("EEG POWER:");
brainStream->print("Delta: ");
brainStream->println(eegPower[0], DEC);
brainStream->print("Theta: ");
brainStream->println(eegPower[1], DEC);
brainStream->print("Low Alpha: ");
brainStream->println(eegPower[2], DEC);
brainStream->print("High Alpha: ");
brainStream->println(eegPower[3], DEC);
brainStream->print("Low Beta: ");
brainStream->println(eegPower[4], DEC);
brainStream->print("High Beta: ");
brainStream->println(eegPower[5], DEC);
brainStream->print("Low Gamma: ");
brainStream->println(eegPower[6], DEC);
brainStream->print("Mid Gamma: ");
brainStream->println(eegPower[7], DEC);
}
brainStream->println("");
brainStream->print("Checksum Calculated: ");
brainStream->println(checksumAccumulator, DEC);
brainStream->print("Checksum Expected: ");
brainStream->println(checksum, DEC);
brainStream->println("--- End Packet ---");
brainStream->println("");
}
uint8_t Brain::readSignalQuality() {
return signalQuality;
}
uint8_t Brain::readAttention() {
return attention;
}
uint8_t Brain::readMeditation() {
return meditation;
}
uint32_t* Brain::readPowerArray() {
return eegPower;
}
uint32_t Brain::readDelta() {
return eegPower[0];
}
uint32_t Brain::readTheta() {
return eegPower[1];
}
uint32_t Brain::readLowAlpha() {
return eegPower[2];
}
uint32_t Brain::readHighAlpha() {
return eegPower[3];
}
uint32_t Brain::readLowBeta() {
return eegPower[4];
}
uint32_t Brain::readHighBeta() {
return eegPower[5];
}
uint32_t Brain::readLowGamma() {
return eegPower[6];
}
uint32_t Brain::readMidGamma() {
return eegPower[7];
}