Data Streaming Protocol

Overview

The data is sent in a continuous data stream from the Muse when the start streaming 's' has been sent. It expects a keep-alive 'k' command at least every 10s, otherwise it assumes the listener died. Data streaming can be stopped immediately by sending 'h'.

All packets have a leading byte as header that contains a nibble for packet type and a nibble for flags. Packets are either static sized or dynamic. In the static case the length is deducted from the current settings and data type, in the dynamic case there is a length field. Also headers can be dynamic sized, the size can be deducted from the flags in the header byte.

There is a synchronization packet sent in a fixed interval based on the amount of packets sent in between, which is used by the client side to identify the start of the data stream. It used to be used to pick up the stream if corruption was ever encountered. Since Bluetooth gives us reliable transmission, it serves no purpose and should be ignored; in the cosmically unlikely event that a cosmic ray flips a bit in RAM, the safe and practical thing to do is to just drop and restart the connection.

If a payload does not round up to full bytes the remainder is bitstuffed. All readings are bitpacked, so 3 readings of 10 bits each are packed into a 32bit payload.

Headers are bitwise big-endian: byte 0xe8 corresponds to an EEG packet (type 0xe) with dropped samples (flag bit 4 set). All 16-bit values are bytewise big-endian. Sync packets are as they're written: 0xff, 0xff, 0xaa, 0x55. Error packets don't matter and you should never see one. (For what it's worth, they're little-endian.)

10-bit bitpacked samples are both bitwise and bytewise little-endian. Each sample's lower bits are the upper bits of the first byte, and its upper bits are the lower bits of the second byte. The first sample uses the first two bytes, and the last sample uses the last two bytes. For the byte sequence 0x12, 0x34, 0x56, the first sample has value 0x12 (decimal 18), and the second, 0x18d (decimal 397). The 0x5 is unused; if there were another sample, 0x5 would make up its lower 4 bits. To illustrate:

0x12     0x34     0x56
00010010 00110100 01010110
00 00010010 0110 001101
0x12        0x18d

Header

The first nibble in the first byte of the header declares the type, the second nibble is a bit array, which is used in special circumstances. In most cases this second nibble will be zero, indicating everything is nice and in order. The additional header data is attached in the order of magnitude of the flags, highest flag comes first, lowest last.

Type nibble

These are identifiers, so all 16 values can be used and will translate into a single data type. These packet types are currently defined:

 0xF First nibble of sync packet
 0xE Uncompressed EEG
 0xD Error Flags
 0xC Compressed EEG
 0xB Battery
 0xA Accelerometer
 0x9 DRL/REF
 0x0 Invalid

Flag nibble

These are OR-ed together, so there are only 4 flags available. If this field is zero there is no more information in the header and payload starts right away.

There is currently one flag:
  • Bit 4 ( 0x8 ) - representing "samples have been dropped"
    • If this flag is set, a two-byte number (short) is concatenated to the header. The two extra bytes specify numbers of samples dropped by the Muse since the last successful package of same type. Currently only EEG and Accelerometer samples transmit information about dropped samples, as the rest of the data types are less critical.

Payloads

Payloads are determined by the type nibble, each type has it's own packing and unpacking methods for the types.

Uncompressed EEG

The payload contains a set of uncompressed EEG data samples.
There are 4 channels with 10 bit sample width each. The order is the one specified in eegChannelLayout in the status output.


Diagram:

Compressed EEG Packet

Compressed EEG packets exist because iOS only supports 6kbps (that is bits per second, not bytes), or 768 bytes per second. We send 4 channels of 10 bit wide samples. See the compressed EEG packet page for details. 

DRL / REF

If data is compressed this packet is transmitted, which contains the DRL and REF electrode reading. This happens on a smaller frequency than regular EEG channels and is used to determine if the Muse is touching the forehead or not.
Payload is 10-bit DRL reading and 10-bit REF reading.
1 byte header, 3 byte payload

Accelerometer Packet

Packet header can contain dropped sample count. The payload contains three 10-bit wide samples. 

Diagram:

Battery Packet

Four 16bit integers (total of 8 bytes), representing:
  1. Percentage of battery charge remaining * 100
  2. Millivolts of battery as measured from the fuel gauge
  3. Millivolts of the battery as measured from ADC
  4. Temperature in Celsius

Error Packet

This is internal health information raised by checks in the firmware. 32bit flag field, so payload length is 4 byte. It would be highly unusual to receive a packet of this type. It is safe to simply drop this type of packet.
Contents: 1 byte header, 4 byte payload

Sync Packet

Sync packet consists of the following 4 bytes: FF FF AA 55.
It is sent every 4 packets of any kind during streaming mode.

This was used at one point to recover from packets being garbled. This is a legacy packet and is really not needed by the protocol, but for now it remains in the firmware as it it harmless. You can safely ignore it.





Comments