Available for pre-order
View Purchasing OptionsProject update 6 of 15
Here’s a couple of quick updates today… I’ll have a more substantive update later in the week.
I want to go over what’s going on "under the hood" and highlight some interesting things about how the HackEEG drivers work.
HackEEG uses a text-based protocol to communicate with the Arduino Due that’s attached to the HackEEG. The message format used is mainly JSON Lines. (MessagePack is used for high-speed streaming.) These formats are important for a couple of reasons. First of all, it means that it’s easy to write software that talks to the HackEEG, if you need to access HackEEG from something other than Python. Both JSON and MessagePack have easy to use implementations in many computer languages.
The second reason is that it’s fast– the JSON Lines implementation can do 8,000 samples per second, and the MessagePack protocol is twice as fast, at 16,000 samples per second. It may not be obvious, since JSON is a general-purpose text-based format– doesn’t that add a lot of overhead? But these libaries are popular and used by developers worldwide– many people have put a lot of effort into making them perform well. This is one of the benefits of using open source software. Why invent another proprietary format?
Here’s a quick example. The HackEEG board has a blue status LED that is connected to one of the ADS1299 GPIO pins. If we can get this light to blink, we know that communication with the ADS1299 chip is okay. We can send the command:
{'COMMAND': 'boardledon', 'PARAMETERS': []}
And we receive:
{"STATUS_CODE":200,"STATUS_TEXT":"Ok"}
And the light turns on! Pretty simple!
To turn it off:
{'COMMAND': 'boardledoff', 'PARAMETERS': []}
And we get back:
{"STATUS_CODE":200,"STATUS_TEXT":"Ok"}
And the board LED turns off.
All the ADS1299 status registers can be programmed this way. To enable channel 1 with 24x gain (like EEG readings use), in Python we do:
self.hackeeg.wreg(ads1299.CHnSET + 1, ads1299.ELECTRODE_INPUT | ads1299.GAIN_24X)
In JSON, that would be:
{'COMMAND': 'wreg', 'PARAMETERS': [5, 96]}
To start reading data continuously, we issue the rdatac
command. Give the sdatac
command to stop.
{'COMMAND': 'rdatac', 'PARAMETERS': []}
And we get back a stream of JSON objects, one sample per line:
{'C': 200, 'D': 'g8i06QEAAADAAAARFLgYo/0u7tIm0BLZUzC6truuwtq0G+Y='}
{'C': 200, 'D': 'T9C06QIAAADAAAARBhIYMGUu4p8mxHjZV9y6u0Cuxza0ISc='}
...
That big string of characters is a byte-array encoded in (base64)[https://en.wikipedia.org/wiki/Base64] format. It decodes like this:
timestamp:3920939139 sample_number: 1| gpio:0 loff_statp:0 loff_statn:0 1:1119416 2:1614845 3:3075794 4:2543634 5:-2534608 6:-4540741 7:-5324070 8:-4973594
timestamp:3920941135 sample_number: 2| gpio:0 loff_statp:0 loff_statn:0 1:1115666 2:1585253 3:3072671 4:2540664 5:-2533412 6:-4539584 7:-5322954 8:-4972249
MessagePack mode is somewhat misnamed– it should really be called "MessagePack streaming mode" because all communication other than data streaming is done by JSON Lines, just as before. JSON Lines is fast enough for that. But when data starts streaming, it is streamed in the MessagePack binary format. This format uses the same fields and format as the JSON Lines protocol, but MessagePack encodes the data in a very compact binary representation. This lets us avoid having to base64 encode the ADS1299 sample data, and we also do without needing to parse JSON’s curly braces and quotes. The MessagePack encoders and parsers are much faster, and this is what lets us reach 16,000 samples per second.
To enter MessagePack mode:
{'COMMAND': 'messagepack', 'PARAMETERS': []}
When you give the rdatac
command, data will start streaming in MessagePack.
I’ll update the driver documentation later this week and document the entire protocol.
Last week I moved all the hardware and software from my personal Github account to Starcat’s account. You can find HackEEG hardware and software on Github here now: