Bluetooth connection to Linux


#1

Hi, I have got two MUSE devices today:-)
I wonder if I can just get the raw data from MUSE through bluetooth (via serial port) on Linux (Raspberry Pi)? Do I have to use MUSE SDK to get the data. Actually I prefer API for C instead of Java.
I can see and pair with MUSE bluetooth from my Linux box (The bluetooth manager can receive data from MUSE), but I can’t read anything from the serial port (/dev/rfcomm0). Is there any known reason for this?
Paul


#2

By the way, I have tested my serial port reading software with Neurosky Brainlink. It worked just fine. I am trying to compare a few different wireless EEG devices used for psychological study.
Paul


#3

Hi ZHuang,
This is thankfully very easy. Just connect to your device, and send the ASCII encoded message “s” to start receiving binary data from it (don’t forget to give it a “k” every 10 seconds to keep it streaming!)
The hard part is interpretting the compressed EEG data


#4

Hey there,

Yep, Hashmeer is right, you have to send the start message to begin data transmission.

You don’t have to use the SDK (and for now there isn’t an ARM build of it that would run on Raspberry Pi), you just need to follow the Muse Communication Protocol, which is specified here: https://sites.google.com/a/interaxon.ca/muse-developer-site/muse-communication-protocol


#5

Perfect! Everything is working now. Many thanks to Hashmeer and Tom. I will have a look at MCP soon. If you have some source code in C for MCP that would be great so that I can port it to Raspberry Pi. Otherwise I will take the pain to write my own code for MCP:-)


#6

The compressed packets seem to incur more coding workload. Could I configure MUSE to use uncompressed packets only? In theory it seems I can by reading the serial commands:-)


#7

This has been asked a few times before, please see this discussion: http://forum.choosemuse.com/forum/developer-forum/2827-disable-eeg-data-compression
I’m about 90% of the way into a C# solution for MCP (I’m able to parse all streamed packet types, except compressed, but I’m very close to this, and I have a simple UI with a scrolling chart). I’ll post the source as soon as it’s working, maybe that could help you. I don’t know much about processing binary in C, but I imagine that it’s very different to C#, so maybe it won’t help you too much


#8

Hi zhuang,

I’m afraid the aswer is NO, at least for the consumer Muse.
You can use the serial commands to send data and configure Muse - the option for compressed or uncompressed packets is built into Muse’s available profiles - you set the profile you want with the % serial command, but there’s no profile built into the consumer Muse that allows for uncompresses packets.

As Hashmeer said, that is the hard part of the coding.
There is a Pseudo-code for Parsing Compressed Data at the end of the MCP Documentation page at: this link:


It would be much easier if instead of giving us a pseudo-code they could give us a piece of real code in any programming language.

See other discussions on this matter at:

http://forum.choosemuse.com/forum/developer-forum/3264-setting-uncompressed-data-mode

http://forum.choosemuse.com/forum/developer-forum/2827-disable-eeg-data-compression


#9

HI Hashmeer, I am very interested of a C# solution, please let me know the link to access your preliminary code when you are ready to share.


#10

DavTomas, no problems!


#11

Thanks Hashmeer and Eduardo for your information. I am working on the C version at the moment, but have the following problem.

I have the raw data (ground truth).

ff ff aa 55 e0 5d c2 48 5b 80 c0 5 8 78 40 81 1 50 e1 f0 c5 c7 ed 7b 7 fb 63 4e 3b 4d 3c f3 ac 6c 4c 4d 4c 3 71 2e 61 91 11 7b 50 f5 72 67 9e dc 30 4a 85 c1 58 c9 23 68 c8 6d c0 c c 58

I only worry about the first diff packet started with the first “c0”.

Below are my result (The problem is that it seems the diff packet is not long enough for decoding)

The medians for the raw data (in hex):
3a0 300 680 10

The medians for the diff packet:
5 20 7 50

The diff data length is 0x150 and is 42 bytes long and I print their binary as below:

11100001 11110000 11000101 11000111 11101101 01111011 00000111 11111011 01100011 01001110 00111011 01001101 00111100 11110011 10101100 01101100 01001100 01001101 01001100 00000011 01110001 00101110 01100001 10010001 00010001 01111011 01010000 11110101 01110010 01100111 10011110 11011100 00110000 01001010 10000101 11000001 01011000 11001001 00100011 01101000 11001000 01101101

and my parse result is (format is quotient, remainder, sign, max1less, maxbits, bitpos). I manually checked the result and it seems correct based on my understanding of the compressed code. Could anyone kindly let me know if I did anything wrong or simply give me the right result for the above raw data?

3 0 1 3 3 6
5 0 1 3 3 15
2 0 -1 3 3 21
0 4 1 3 3 26
0 1 -1 3 3 30
4 3 -1 3 3 39
0 4 -1 3 3 44
0 3 1 3 3 49
0 0 -1 3 3 53
7 3 -1 3 3 65
1 0 -1 3 3 70
1 2 1 3 3 75
3 0 -1 3 3 82
2 3 -1 3 3 89
0 1 -1 3 3 93
0 2 1 3 3 97
4 15 1 0 5 108
0 29 1 0 5 115
2 6 -1 0 5 124
1 4 -1 0 5 132
1 4 -1 0 5 140
1 20 -1 0 5 148
1 0 1 0 5 156
0 27 -1 0 5 163
0 4 -1 0 5 170
0 28 -1 0 5 177
1 3 1 0 5 185
0 17 1 0 5 192
0 8 -1 0 5 199
0 30 -1 0 5 206
1 20 1 0 5 214
0 30 -1 0 5 221
0 4 -1 1 3 226
1 1 1 1 3 232
2 2 -1 1 3 239
1 2 -1 1 3 245
1 5 -1 1 3 251
2 0 1 1 3 257
2 0 1 1 3 263
0 3 -1 1 3 268
0 4 1 1 3 273
0 0 -1 1 3 277
0 6 1 1 3 282
0 0 1 1 3 286
1 4 -1 1 3 292
0 0 -1 1 3 296
1 1 1 1 3 302
1 1 1 1 3 308
0 61 1 48 7 317
0 25 1 48 7 325
0 13 -1 48 7 333
0 32 1 48 7 341
0 0 1 48 7 349
0 0 1 48 7 357
0 0 1 48 7 365
0 0 1 48 7 373
0 0 1 48 7 381
0 0 1 48 7 389
0 0 1 48 7 397
0 0 1 48 7 405
0 0 1 48 7 413
0 0 1 48 7 421
0 0 1 48 7 429
0 0 1 48 7 437


#12

Thanks Hashmeer and Eduardo for your information. I am working on the C version at the moment, but have the following problem.

I have the raw data (ground truth).

ff ff aa 55 e0 5d c2 48 5b 80 c0 5 8 78 40 81 1 50 e1 f0 c5 c7 ed 7b 7 fb 63 4e 3b 4d 3c f3 ac 6c 4c 4d 4c 3 71 2e 61 91 11 7b 50 f5 72 67 9e dc 30 4a 85 c1 58 c9 23 68 c8 6d c0 c c 58

I only worry about the first diff packet started with the first “c0”.

Below is my result (The problem is that it seems the diff packet is not long enough for decoding)

The medians for the raw data (in hex):
3a0 300 680 10

The medians for the diff packet:
5 20 7 50

The diff data length is 0x150 and is 42 bytes long and I print their binary as below:

11100001 11110000 11000101 11000111 11101101 01111011 00000111 11111011 01100011 01001110 00111011 01001101 00111100 11110011 10101100 01101100 01001100 01001101 01001100 00000011 01110001 00101110 01100001 10010001 00010001 01111011 01010000 11110101 01110010 01100111 10011110 11011100 00110000 01001010 10000101 11000001 01011000 11001001 00100011 01101000 11001000 01101101

and my parse result is as below (format is quotient, remainder, sign, max1less, maxbits, bitpos in decimal). I manually checked the result and it seems correct based on my understanding of the compressed code. Could anyone kindly let me know if I did anything wrong or simply give me the right result for the above raw data?

3 0 1 3 3 6
5 0 1 3 3 15
2 0 -1 3 3 21
0 4 1 3 3 26
0 1 -1 3 3 30
4 3 -1 3 3 39
0 4 -1 3 3 44
0 3 1 3 3 49
0 0 -1 3 3 53
7 3 -1 3 3 65
1 0 -1 3 3 70
1 2 1 3 3 75
3 0 -1 3 3 82
2 3 -1 3 3 89
0 1 -1 3 3 93
0 2 1 3 3 97
4 15 1 0 5 108
0 29 1 0 5 115
2 6 -1 0 5 124
1 4 -1 0 5 132
1 4 -1 0 5 140
1 20 -1 0 5 148
1 0 1 0 5 156
0 27 -1 0 5 163
0 4 -1 0 5 170
0 28 -1 0 5 177
1 3 1 0 5 185
0 17 1 0 5 192
0 8 -1 0 5 199
0 30 -1 0 5 206
1 20 1 0 5 214
0 30 -1 0 5 221
0 4 -1 1 3 226
1 1 1 1 3 232
2 2 -1 1 3 239
1 2 -1 1 3 245
1 5 -1 1 3 251
2 0 1 1 3 257
2 0 1 1 3 263
0 3 -1 1 3 268
0 4 1 1 3 273
0 0 -1 1 3 277
0 6 1 1 3 282
0 0 1 1 3 286
1 4 -1 1 3 292
0 0 -1 1 3 296
1 1 1 1 3 302
1 1 1 1 3 308
0 61 1 48 7 317
0 25 1 48 7 325
0 13 -1 48 7 333
0 32 1 48 7 341
0 0 1 48 7 349
0 0 1 48 7 357
0 0 1 48 7 365
0 0 1 48 7 373
0 0 1 48 7 381
0 0 1 48 7 389
0 0 1 48 7 397
0 0 1 48 7 405
0 0 1 48 7 413
0 0 1 48 7 421
0 0 1 48 7 429
0 0 1 48 7 437


#13

zhuang, wrong size maybe related to not reversing the bytes, check out our c# code here https://github.com/DavidVivancos/MuseDotNet


#14

Thanks David. The size seems to be unreasonably large if I reverse the order of the two bytes. I am confused about the reversing of the bytes in your program. Does it mean that every byte should be bit-wise reversed before processing including the diff data as well as the medians? or even the bytes for size?


#15

I wonder if the following medians are correctly decoded:
5 8 78 40 81
in binary:
00000101
00001000
01111000
01000000
10000001
after 10-bit transformation I have got:
5 202 7 205
After transformation of quantization:
5 20 7 50


#16

I am really confused about the decoding. Could David or any muse developer please show the right decoding result of the raw data below?
ff ff aa 55 e0 5d c2 48 5b 80 c0 5 8 78 40 81 1 50 e1 f0 c5 c7 ed 7b 7 fb 63 4e 3b 4d 3c f3 ac 6c 4c 4d 4c 3 71 2e 61 91 11 7b 50 f5 72 67 9e dc 30 4a 85 c1 58 c9 23 68 c8 6d c0 c c 58


#17

Hi zhuang,

Here’s a quick explanation of extracting the Medians and their quantization from the documentation.

The Medians are 10 bits as follows.

[SIZE=15px]Byte 1: [/SIZE][B][SIZE=15px]XXXX XXXX[/SIZE][/B][SIZE=15px] (LSB Median 1)[/SIZE]
[SIZE=15px]Byte 2: XXXX XX[/SIZE][B][SIZE=15px]XX [/SIZE][/B][SIZE=15px](Last 2 bits, MSB Median 1. First 6 bits, LSB Median 2)[/SIZE]
[SIZE=15px]Byte 3: [/SIZE][B][SIZE=15px]XXXX[/SIZE][/B][SIZE=15px] XXXX (Last 4 bits, MSB Median 2. First 4 bits, LSB Median 3)[/SIZE]
[SIZE=15px]Byte 4: XX[/SIZE][B][SIZE=15px]XX XXXX [/SIZE][/B][SIZE=15px](Last 6 bits, MSB Median 3. First 2 bits, LSB Median 4)[/SIZE]
[SIZE=15px]Byte 5: XXXX XXXX (MSB Median 4)[/SIZE]

Therefore, in your case:

Median 1: 00 0000 0101 = 5, quantization = 1 from 160 * 80 * 40 * 20 * 11.
Median 2: 10 0000 0010 = 2, quantization = 16 from 16
1 * 80 * 40 * 20 * 11.
Median 3: 00 0000 0111 = 7, quantization = 1 from 160 * 80 * 40 * 20 * 11.
Median 4: 10 0000 0100 = 4, quantization = 16 from 16
1 * 80 * 40 * 20 * 11.

I hope that clarifies it for you.


#18

Hi Zhuang,

First packet is uncompressed.

ff ff aa 55 e0 5d c2 48 5b 80

FF FF AA 55, is the sync packet. Making sure we know the start of the first packet.

E0 is uncompressed header.

5D C2 48 5B 80 is the uncompressed values of the EEG.

In this case:
0101 1101
1100 0010
0100 1000
0101 1011
1000 0000

Which as above again breaks into 10 bits at 605, 560, 436 and 513 for channels 1 to 4 respectively, which translated to TP9, Fp1, Fp2 and TP10 on the default head positions from Muse.

The next byte is C0, which is the compression header.

See above for parsing the Medians.

1 50 = 256*1 + 80 = 336 bits in the packet. This is 42 bytes.

e1 f0 c5 c7 ed 7b 7 fb 63 4e 3b 4d 3c f3 ac 6c 4c 4d 4c 3 71 2e 61
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
91 11 7b 50 f5 72 67 9e dc 30 4a 85 c1 58 c9 23 68 c8 6d c0 c c 58
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42

Therefore following our packet we have the start of the next compressed packet.

Lets just look at the start of the payload.

E1 = 1110 0001, F0 = 1111 0000, C5 = 1011 0101, C7 = 1011 1110, ED = 1110 1101.

Our first Median is 5.

Quotient is Unary encoding, quite easy to read.
The remainder is in Truncated binary. 5 needs a remainder of 3 bits, since 4 is 100. 3 bits can represent 8 states and we have 5 required.
If you check the literature in the protocol documents you will see this means you have 2 free starts so 2, 3 and 4 will have an offset to make them uniquely identifiable.
As such with a median of 5, we expect to see 0 = 00, 1 = 01, 2 = 101, 3 = 110 and 4 = 111.
Sign is 0 for negative, 1 for positive.

So if we start with E1.
1110 00 0
1110 = Quotient of 3.
00 = Remainder of 0.
0 = Negative sign.
First difference should be (35+0)-1 = -15.

Next we would have:
111110 00 0
Quotient = 111110 = 5.
Remainder = 00 = 0.
Sign = 0 = -1
Difference = (55+0)-1 = -25

Next
10 110 1
Q = 10 = 1
R = 110 = 3
S = 1 = 1
Diff = (1*5 + 3)*1 = +8

Next
0 110 1
Q = 0 = 0
R = 110 = 3
S = 1 = 1
Diff = (0*5+3)*1 = +3

Next
11110 111 0
Q = 11110 = 4
R = 111 = 4
S = 0 = -1
Diff = (45 + 4)-1 = -24

And so on and so forth. Obviously you need to continue to parse in this fashion down the payload.

Once you reach 16 differences you will switch to the other channel and median. So after your 16th difference you can except to find remainders using the remainder of a Median of 2. So the remainder will either be 0 or 1, always 1 bit in this case.

I hope that clarifies it enough for you.

Thanks for your interest and persistence in getting it running.


#19

I tried various possible ways to decode the medians but none of them works. I am sure the length of each C0 packet is correct which is 0x150 (~42 bytes and no need to reverse) in the above code. However, the medians can’t match the diff data no matter what I do. It seems to me the medians are intentionally encrypted. I could be wrong, but if muse developers keep silent about how to decode the above C0 packet, I doubt muse is really happy to open for other developers to develop new applications with muse.


#20

Many thanks Farough for your detailed answer. This is very helpful. Sorry I didn’t realized the answers were in the second page already. My problem was that I applied the quantization to the median before decoding the diff data. Now it seems everything works fine. So far so good:-)