Basic serial-debug demo of reading and parsing data from Neurosky's Mindwave Mobile EEG headset via BlueSMIRF Silver bluetooth modem.

Dependencies:   mbed

Basic demo of reading data packets from Neurosky's Mindwave Mobile headset via BlueSMIRF Silver bluetooth modem. Adapted from http://developer.neurosky.com/docs/doku.php?id=mindwave_mobile_and_arduino

Connect pin9 to BlueSMIRF's RX and pin10 to BlueSMIRF's TX, also hook up GND to GND and VCC to the mbed's 3V3 supply.

To prepare the BlueSMIRF to auto-connect to the Mindwave Mobile:

First wire it up and power it using the mbed's power pins. Once it's powered, pair your computer to the Mindwave Mobile headset to you can find out its MAC address. Write that down as you will need it.

Next pair your computer to the BlueSMIRF so we can configure it. It will appear as RN-42-5922 or similar (it's a Roving Networks RN-42 unit).

Now we can use a terminal program to connect to the serial modem created on your computer that connects wirelessly to the BlueSMIRF - by default it's at 115200 baud, 8 N 1 - when you're connected the light will go green.

If you've got a successful serial connection, put it into command mode by typing three dollar signs $$$ - if successful you should see a prompt saying 'CMD'. If not, power it down and try again till you get a CMD prompt.

At that prompt we need to change some defaults so that the BlueSMIRF is set to master mode, 57600 baud and sends a pincode of '0000', and seeks to connect to the headset's MAC address. To do this, type:

SP,0000
SM,3
SR,<the 12 digit MAC address of the headset written down earlier>
SU,57.6
D

You should see AOK after each line, and after the D it will print out its settings so you can check it's now AUTO, 57600, using 0000 and the right MAC address. All being well, type three minuses '---' to exit command mode.

To check it's working, close the terminal you've been using, reboot the BlueSMIRF (flashing red light) and switch on the Mindwave Mobile headset - the light on the BlueSMIRF should go green when it connects and the flashing blue light on the Mindwave Mobile headset should go steady blue.

Committer:
RorschachUK
Date:
Tue Jun 04 17:53:54 2013 +0000
Revision:
1:fac5c6ba2f07
Parent:
0:7a3f4ba1851c
EEG data is big-endian not little-endian

Who changed what in which revision?

UserRevisionLine numberNew contents of line
RorschachUK 0:7a3f4ba1851c 1 /* Mindwave Mobile demo - Bob Stone June 2013
RorschachUK 0:7a3f4ba1851c 2 * Basic demo of reading data packets from Neurosky's Mindwave Mobile headset
RorschachUK 0:7a3f4ba1851c 3 * via BlueSMIRF Silver bluetooth modem.
RorschachUK 0:7a3f4ba1851c 4 * Adapted from http://developer.neurosky.com/docs/doku.php?id=mindwave_mobile_and_arduino
RorschachUK 0:7a3f4ba1851c 5 *
RorschachUK 0:7a3f4ba1851c 6 * Connect pin9 to BlueSMIRF's RX and pin10 to BlueSMIRF's TX,
RorschachUK 0:7a3f4ba1851c 7 * also hook up GND to GND and VCC to the mbed's 3V3 supply.
RorschachUK 0:7a3f4ba1851c 8 *
RorschachUK 0:7a3f4ba1851c 9 * To prepare the BlueSMIRF to auto-connect to the Mindwave Mobile:
RorschachUK 0:7a3f4ba1851c 10 *
RorschachUK 0:7a3f4ba1851c 11 * First wire it up and power it using the mbed's power pins. Once it's powered,
RorschachUK 0:7a3f4ba1851c 12 * pair your computer to the Mindwave Mobile headset to you can
RorschachUK 0:7a3f4ba1851c 13 * find out its MAC address. Write that down as you will need it.
RorschachUK 0:7a3f4ba1851c 14 *
RorschachUK 0:7a3f4ba1851c 15 * Next pair your computer to the BlueSMIRF so we can configure it. It will
RorschachUK 0:7a3f4ba1851c 16 * appear as RN-42-5922 or similar (it's a Roving Networks RN-42 unit).
RorschachUK 0:7a3f4ba1851c 17 *
RorschachUK 0:7a3f4ba1851c 18 * Now we can use a terminal program to connect to the serial modem created on
RorschachUK 0:7a3f4ba1851c 19 * your computer that connects wirelessly to the BlueSMIRF - by default it's at
RorschachUK 0:7a3f4ba1851c 20 * 115200 baud, 8 N 1 - when you're connected the light will go green.
RorschachUK 0:7a3f4ba1851c 21 *
RorschachUK 0:7a3f4ba1851c 22 * If you've got a successful serial connection, put it into command mode by
RorschachUK 0:7a3f4ba1851c 23 * typing three dollar signs $$$ - if successful you should see a prompt saying
RorschachUK 0:7a3f4ba1851c 24 * 'CMD'. If not, power it down and try again till you get a CMD prompt.
RorschachUK 0:7a3f4ba1851c 25 *
RorschachUK 0:7a3f4ba1851c 26 * At that prompt we need to change some defaults so that the BlueSMIRF is set to
RorschachUK 0:7a3f4ba1851c 27 * master mode, 57600 baud and sends a pincode of '0000', and seeks to connect to
RorschachUK 0:7a3f4ba1851c 28 * the headset's MAC address. To do this, type:
RorschachUK 0:7a3f4ba1851c 29 * SP,0000
RorschachUK 0:7a3f4ba1851c 30 * SM,3
RorschachUK 0:7a3f4ba1851c 31 * SR,<the 12 digit MAC address of the headset written down earlier>
RorschachUK 0:7a3f4ba1851c 32 * SU,57.6
RorschachUK 0:7a3f4ba1851c 33 * D
RorschachUK 0:7a3f4ba1851c 34 * You should see AOK after each line, and after the D it will print out its
RorschachUK 0:7a3f4ba1851c 35 * settings so you can check it's now AUTO, 57600, using 0000 and the right MAC
RorschachUK 0:7a3f4ba1851c 36 * address. All being well, type three minuses '---' to exit command mode.
RorschachUK 0:7a3f4ba1851c 37 *
RorschachUK 0:7a3f4ba1851c 38 * To check it's working, close the terminal you've been using, reboot the
RorschachUK 0:7a3f4ba1851c 39 * BlueSMIRF (flashing red light) and switch on the Mindwave Mobile headset
RorschachUK 0:7a3f4ba1851c 40 * - the light on the BlueSMIRF should go green when it connects and the
RorschachUK 0:7a3f4ba1851c 41 * flashing blue light on the Mindwave Mobile headset should go steady blue.
RorschachUK 0:7a3f4ba1851c 42 */
RorschachUK 0:7a3f4ba1851c 43 #include "mbed.h"
RorschachUK 0:7a3f4ba1851c 44 Serial pc(USBTX, USBRX); //for debug
RorschachUK 0:7a3f4ba1851c 45 Serial blueSmirf(p9, p10); //for bluetooth comms (TX, RX)
RorschachUK 0:7a3f4ba1851c 46
RorschachUK 0:7a3f4ba1851c 47 //*****************************
RorschachUK 0:7a3f4ba1851c 48 //User routines to process data
RorschachUK 0:7a3f4ba1851c 49 //*****************************
RorschachUK 0:7a3f4ba1851c 50
RorschachUK 1:fac5c6ba2f07 51 /** This will be called if you blink.
RorschachUK 1:fac5c6ba2f07 52 */
RorschachUK 0:7a3f4ba1851c 53 void blinked(void)
RorschachUK 0:7a3f4ba1851c 54 {
RorschachUK 0:7a3f4ba1851c 55 printf("\nBlink!\n\n");
RorschachUK 0:7a3f4ba1851c 56 }
RorschachUK 0:7a3f4ba1851c 57
RorschachUK 1:fac5c6ba2f07 58 /** This will be called when processed eSense data comes in, about once a second.
RorschachUK 1:fac5c6ba2f07 59 *
RorschachUK 1:fac5c6ba2f07 60 * @param poorQuality will be 0 if connections are good, 200 if connections are useless, and somewhere in between if connection dodgy.
RorschachUK 1:fac5c6ba2f07 61 * @param attention processed percentage denoting focus and attention. 0 to 100
RorschachUK 1:fac5c6ba2f07 62 * @param meditation processed percentage denoting calmness and serenity. 0 to 100
RorschachUK 1:fac5c6ba2f07 63 * @param timeSinceLastPacket time since last packet processed, in milliseconds.
RorschachUK 1:fac5c6ba2f07 64 */
RorschachUK 0:7a3f4ba1851c 65 void eSenseData(int poorQuality, int attention, int meditation, int timeSinceLastPacket)
RorschachUK 0:7a3f4ba1851c 66 {
RorschachUK 0:7a3f4ba1851c 67 if (poorQuality < 200) {
RorschachUK 0:7a3f4ba1851c 68 printf("PoorQuality: %d", poorQuality);
RorschachUK 0:7a3f4ba1851c 69 }
RorschachUK 0:7a3f4ba1851c 70 if (attention > 0) {
RorschachUK 0:7a3f4ba1851c 71 printf(" Attention: %d", attention);
RorschachUK 0:7a3f4ba1851c 72 }
RorschachUK 0:7a3f4ba1851c 73 if (meditation > 0) {
RorschachUK 0:7a3f4ba1851c 74 printf(" Meditation: %d", meditation);
RorschachUK 0:7a3f4ba1851c 75 }
RorschachUK 0:7a3f4ba1851c 76 printf(" Time since last packet: %d", timeSinceLastPacket);
RorschachUK 0:7a3f4ba1851c 77 printf("\n");
RorschachUK 0:7a3f4ba1851c 78 }
RorschachUK 0:7a3f4ba1851c 79
RorschachUK 1:fac5c6ba2f07 80 /** This will be called when processed meter reading data arrives, about once a second.
RorschachUK 1:fac5c6ba2f07 81 * This is a breakdown of frequencies in the wave data into 8 named bands, these are:
RorschachUK 1:fac5c6ba2f07 82 * 0: Delta (0.5-2.75 Hz)
RorschachUK 1:fac5c6ba2f07 83 * 1: Theta (3.5-6.75 Hz)
RorschachUK 1:fac5c6ba2f07 84 * 2: Low-Alpha (7.5-9.25 Hz)
RorschachUK 1:fac5c6ba2f07 85 * 3: High-Alpha (10-11.75 Hz)
RorschachUK 1:fac5c6ba2f07 86 * 4: Low-Beta (13-16.75 Hz)
RorschachUK 1:fac5c6ba2f07 87 * 5: High-Beta (18-29.75 Hz)
RorschachUK 1:fac5c6ba2f07 88 * 6: Low-Gamma (31-39.75 Hz)
RorschachUK 1:fac5c6ba2f07 89 * 7: High-Gamma (41-49.75 Hz)
RorschachUK 1:fac5c6ba2f07 90 *
RorschachUK 1:fac5c6ba2f07 91 * @param meters array of meter data for different frequency bands
RorschachUK 1:fac5c6ba2f07 92 */
RorschachUK 0:7a3f4ba1851c 93 void meterData(int meter[8])
RorschachUK 0:7a3f4ba1851c 94 {
RorschachUK 0:7a3f4ba1851c 95 printf("Meters: ");
RorschachUK 0:7a3f4ba1851c 96 for (int j=0; j<8; j++) {
RorschachUK 0:7a3f4ba1851c 97 printf("%d = %d, ", j, meter[j]);
RorschachUK 0:7a3f4ba1851c 98 }
RorschachUK 0:7a3f4ba1851c 99 printf("\n");
RorschachUK 0:7a3f4ba1851c 100 }
RorschachUK 0:7a3f4ba1851c 101
RorschachUK 1:fac5c6ba2f07 102 /** This will be called when wave data arrives.
RorschachUK 1:fac5c6ba2f07 103 * There will be a lot of these, 512 a second, so if you're planning to do anything
RorschachUK 1:fac5c6ba2f07 104 * here, don't let it take long. Best not to printf this out as it will just choke.
RorschachUK 1:fac5c6ba2f07 105 *
RorschachUK 1:fac5c6ba2f07 106 * param wave Raw wave data point
RorschachUK 1:fac5c6ba2f07 107 */
RorschachUK 0:7a3f4ba1851c 108 void waveData(int wave)
RorschachUK 0:7a3f4ba1851c 109 {
RorschachUK 0:7a3f4ba1851c 110 }
RorschachUK 0:7a3f4ba1851c 111
RorschachUK 0:7a3f4ba1851c 112 //*****************
RorschachUK 0:7a3f4ba1851c 113 //End User routines
RorschachUK 0:7a3f4ba1851c 114 //*****************
RorschachUK 0:7a3f4ba1851c 115
RorschachUK 0:7a3f4ba1851c 116 //System routines to obtain and parse data
RorschachUK 1:fac5c6ba2f07 117
RorschachUK 1:fac5c6ba2f07 118 /** Simplify serial comms
RorschachUK 1:fac5c6ba2f07 119 */
RorschachUK 0:7a3f4ba1851c 120 unsigned char ReadOneByte()
RorschachUK 0:7a3f4ba1851c 121 {
RorschachUK 0:7a3f4ba1851c 122 int ByteRead;
RorschachUK 0:7a3f4ba1851c 123
RorschachUK 0:7a3f4ba1851c 124 while(!blueSmirf.readable());
RorschachUK 0:7a3f4ba1851c 125 ByteRead = blueSmirf.getc();
RorschachUK 0:7a3f4ba1851c 126
RorschachUK 0:7a3f4ba1851c 127 return ByteRead;
RorschachUK 0:7a3f4ba1851c 128 }
RorschachUK 1:fac5c6ba2f07 129
RorschachUK 1:fac5c6ba2f07 130 /** Main loop, sets up and keeps listening for serial
RorschachUK 1:fac5c6ba2f07 131 */
RorschachUK 0:7a3f4ba1851c 132 int main()
RorschachUK 0:7a3f4ba1851c 133 {
RorschachUK 0:7a3f4ba1851c 134 Timer t; //packet timer
RorschachUK 0:7a3f4ba1851c 135 t.start();
RorschachUK 0:7a3f4ba1851c 136 Timer blinkTimer; //used for detecting blinks
RorschachUK 0:7a3f4ba1851c 137 int time;
RorschachUK 0:7a3f4ba1851c 138 int generatedChecksum = 0;
RorschachUK 0:7a3f4ba1851c 139 int checksum = 0;
RorschachUK 0:7a3f4ba1851c 140 int payloadLength = 0;
RorschachUK 0:7a3f4ba1851c 141 int payloadData[64] = {0};
RorschachUK 0:7a3f4ba1851c 142 int poorQuality = 0;
RorschachUK 0:7a3f4ba1851c 143 int attention = 0;
RorschachUK 0:7a3f4ba1851c 144 int meditation = 0;
RorschachUK 0:7a3f4ba1851c 145 int wave = 0;
RorschachUK 0:7a3f4ba1851c 146 int meter[8] = {0};
RorschachUK 0:7a3f4ba1851c 147
RorschachUK 0:7a3f4ba1851c 148 bool eSensePacket = false;
RorschachUK 0:7a3f4ba1851c 149 bool meterPacket = false;
RorschachUK 0:7a3f4ba1851c 150 bool wavePacket = false;
RorschachUK 0:7a3f4ba1851c 151
RorschachUK 0:7a3f4ba1851c 152 blueSmirf.baud(57600);
RorschachUK 0:7a3f4ba1851c 153 pc.baud(115200);
RorschachUK 0:7a3f4ba1851c 154 printf("\n\nStarted\n\n");
RorschachUK 0:7a3f4ba1851c 155 blinkTimer.reset();
RorschachUK 0:7a3f4ba1851c 156
RorschachUK 0:7a3f4ba1851c 157 while(1) {
RorschachUK 0:7a3f4ba1851c 158 // Look for sync bytes
RorschachUK 0:7a3f4ba1851c 159 if(ReadOneByte() == 170) {
RorschachUK 0:7a3f4ba1851c 160 if(ReadOneByte() == 170) {
RorschachUK 0:7a3f4ba1851c 161 //Synchronised to start of packet
RorschachUK 0:7a3f4ba1851c 162 payloadLength = ReadOneByte();
RorschachUK 0:7a3f4ba1851c 163 if(payloadLength > 169) //Payload length can not be greater than 169
RorschachUK 0:7a3f4ba1851c 164 return;
RorschachUK 0:7a3f4ba1851c 165
RorschachUK 0:7a3f4ba1851c 166 generatedChecksum = 0;
RorschachUK 0:7a3f4ba1851c 167 for(int i = 0; i < payloadLength; i++) {
RorschachUK 0:7a3f4ba1851c 168 payloadData[i] = ReadOneByte(); //Read payload into memory
RorschachUK 0:7a3f4ba1851c 169 generatedChecksum += payloadData[i];
RorschachUK 0:7a3f4ba1851c 170 }
RorschachUK 0:7a3f4ba1851c 171
RorschachUK 0:7a3f4ba1851c 172 checksum = ReadOneByte(); //Read checksum byte from stream
RorschachUK 0:7a3f4ba1851c 173 generatedChecksum = 255 - (generatedChecksum & 0xFF); //Take one's compliment of generated checksum
RorschachUK 0:7a3f4ba1851c 174
RorschachUK 0:7a3f4ba1851c 175 if(checksum == generatedChecksum) {
RorschachUK 0:7a3f4ba1851c 176 //Packet seems OK
RorschachUK 0:7a3f4ba1851c 177 poorQuality = 200;
RorschachUK 0:7a3f4ba1851c 178 attention = 0;
RorschachUK 0:7a3f4ba1851c 179 meditation = 0;
RorschachUK 0:7a3f4ba1851c 180 wave = 0;
RorschachUK 0:7a3f4ba1851c 181 for(int i = 0; i < payloadLength; i++) { // Parse the payload
RorschachUK 0:7a3f4ba1851c 182 switch (payloadData[i]) {
RorschachUK 0:7a3f4ba1851c 183 case 2: //quality
RorschachUK 0:7a3f4ba1851c 184 i++;
RorschachUK 0:7a3f4ba1851c 185 poorQuality = payloadData[i];
RorschachUK 0:7a3f4ba1851c 186 eSensePacket = true;
RorschachUK 0:7a3f4ba1851c 187 break;
RorschachUK 0:7a3f4ba1851c 188 case 4: //attention
RorschachUK 0:7a3f4ba1851c 189 i++;
RorschachUK 0:7a3f4ba1851c 190 attention = payloadData[i];
RorschachUK 0:7a3f4ba1851c 191 eSensePacket = true;
RorschachUK 0:7a3f4ba1851c 192 break;
RorschachUK 0:7a3f4ba1851c 193 case 5: //meditation
RorschachUK 0:7a3f4ba1851c 194 i++;
RorschachUK 0:7a3f4ba1851c 195 meditation = payloadData[i];
RorschachUK 0:7a3f4ba1851c 196 eSensePacket = true;
RorschachUK 0:7a3f4ba1851c 197 break;
RorschachUK 0:7a3f4ba1851c 198 case 0x80: //wave
RorschachUK 0:7a3f4ba1851c 199 wave = payloadData[i+2] * 256 + payloadData[i+3];
RorschachUK 0:7a3f4ba1851c 200 //We also want to try to detect blinks via analysing wave data
RorschachUK 0:7a3f4ba1851c 201 time = blinkTimer.read_ms();
RorschachUK 0:7a3f4ba1851c 202 if (wave > 32767) wave -= 65535; //cope with negatives
RorschachUK 0:7a3f4ba1851c 203 if (wave>200 && blinkTimer.read_ms() == 0) {
RorschachUK 0:7a3f4ba1851c 204 blinkTimer.start();
RorschachUK 0:7a3f4ba1851c 205 } else if (wave<-90 && time > 10 && time < 100) {
RorschachUK 0:7a3f4ba1851c 206 blinkTimer.stop();
RorschachUK 0:7a3f4ba1851c 207 blinkTimer.reset();
RorschachUK 0:7a3f4ba1851c 208 blinked();
RorschachUK 0:7a3f4ba1851c 209 } else if (time>500) {
RorschachUK 0:7a3f4ba1851c 210 blinkTimer.stop();
RorschachUK 0:7a3f4ba1851c 211 blinkTimer.reset();
RorschachUK 0:7a3f4ba1851c 212 }
RorschachUK 0:7a3f4ba1851c 213 i = i + 3;
RorschachUK 0:7a3f4ba1851c 214 wavePacket = true;
RorschachUK 0:7a3f4ba1851c 215 break;
RorschachUK 0:7a3f4ba1851c 216 case 0x83: //meter readings for different frequency bands
RorschachUK 0:7a3f4ba1851c 217 for (int j=0; j<8; j++) {
RorschachUK 1:fac5c6ba2f07 218 //documentation is inconsistent about whether these values are big-endian or little-endian,
RorschachUK 1:fac5c6ba2f07 219 //and claims both in different places. But wave data is big-endian so assuming that here.
RorschachUK 1:fac5c6ba2f07 220 meter[j] = payloadData[i+j*3+2]*65536 + payloadData[i+j*3+3]*256 + payloadData[i+j*3+4];
RorschachUK 0:7a3f4ba1851c 221 }
RorschachUK 0:7a3f4ba1851c 222 meterPacket = true;
RorschachUK 0:7a3f4ba1851c 223 i = i + 25;
RorschachUK 0:7a3f4ba1851c 224 break;
RorschachUK 0:7a3f4ba1851c 225 default:
RorschachUK 0:7a3f4ba1851c 226 break;
RorschachUK 0:7a3f4ba1851c 227 } // switch
RorschachUK 0:7a3f4ba1851c 228 } // for loop
RorschachUK 0:7a3f4ba1851c 229
RorschachUK 0:7a3f4ba1851c 230 //Call routines to process data
RorschachUK 0:7a3f4ba1851c 231 if(eSensePacket) {
RorschachUK 0:7a3f4ba1851c 232 eSenseData(poorQuality, attention, meditation, t.read_ms());
RorschachUK 0:7a3f4ba1851c 233 eSensePacket = false;
RorschachUK 0:7a3f4ba1851c 234 }
RorschachUK 0:7a3f4ba1851c 235 if (meterPacket) {
RorschachUK 0:7a3f4ba1851c 236 meterData(meter);
RorschachUK 0:7a3f4ba1851c 237 t.reset();
RorschachUK 0:7a3f4ba1851c 238 meterPacket=false;
RorschachUK 0:7a3f4ba1851c 239 }
RorschachUK 0:7a3f4ba1851c 240 if (wavePacket) {
RorschachUK 0:7a3f4ba1851c 241 waveData(wave);
RorschachUK 0:7a3f4ba1851c 242 wavePacket=false;
RorschachUK 0:7a3f4ba1851c 243 }
RorschachUK 0:7a3f4ba1851c 244 } else {
RorschachUK 0:7a3f4ba1851c 245 // Checksum Error
RorschachUK 0:7a3f4ba1851c 246 } // end if else for checksum
RorschachUK 0:7a3f4ba1851c 247 } // end if read 0xAA byte
RorschachUK 0:7a3f4ba1851c 248 } // end if read 0xAA byte
RorschachUK 0:7a3f4ba1851c 249 }
RorschachUK 0:7a3f4ba1851c 250 }