We are trying to add as many devices as possible into BrainFlow and welcome all contributors.
By adding your device into BrainFlow you get Python, Java, C#, Julia, Matlab, Rust, etc SDKs. Also, now you can use your board with applications and frameworks built on top of BrainFlow API.
Steps
- fork and clone the repo, create a branch other than master
- add new board id to BoardIds enum in C code and to the same enum in all other bindings
- add new object creation to board controller C interface inside
prepare_session
method - add information about your board to brainflow_boards.cpp
- inherit your board from Board class and implement all pure virtual methods, store data in DataBuffer object, use synthetic board as a reference, try to reuse code from utils folder and helpers like
DynLibBoard
,BLELibBoard
, etc - add new files to
BOARD_CONTROLLER_SRC
variable in build.cmake, you may also need to add new directory totarget_include_directories
. - create a PR to upstream repo
- optional: add an emulator of your device and integrate it into CI pipelines
1. Fork the repo
Create a fork of BrainFlow repo on github and run:
git clone %url of your fork%
git checkout -b %feature branch name%
cd brainflow
2. Update enums
In each binding there is BoardIds
enum, you need to update them all and add new id.
For Cpp you can find it in brainflow_constants.h file. For some laguages it’s located in the same file as BoardShim
class. For Rust you need to run cargo build --features generate_binding
to update enums
3. Create new board object
Go to board_controller.cpp file and find prepare_session
method there. This method acts as a factory, you need to add new condition to switch
statement there.
case BoardIds::MUSE_2_BOARD:
board = std::shared_ptr<Board> (new Muse (board_id, params));
break;
Also, you need to include new header for your device.
4. Determine output channels and presets
BrainFlow returns data as 2d array, information about actual channels is static and determined by brainflow_boards.cpp file.
You need to register a new entry there and board id inside this json should match board id in BoardIds
enum.
/* For all real boards there are four required fields:
* name
* num_rows
* timestamp_channel
* marker_channel
* Nice to set:
* package_num
* sampling_rate
* Everything else is optional and up to device
*/
brainflow_boards_json["boards"]["41"]["default"] =
{
{"name", "Muse2016"},
{"sampling_rate", 256},
{"timestamp_channel", 5},
{"marker_channel", 6},
{"package_num_channel", 0},
{"num_rows", 7},
{"eeg_channels", {1, 2, 3, 4}},
{"eeg_names", "TP9,Fp1,Fp2,TP10"}
};
brainflow_boards_json["boards"]["41"]["auxiliary"] =
{
{"name", "Muse2016Aux"},
{"sampling_rate", 52},
{"timestamp_channel", 7},
{"marker_channel", 8},
{"package_num_channel", 0},
{"num_rows", 9},
{"accel_channels", {1, 2, 3}},
{"gyro_channels", {4, 5, 6}}
};
Available names for BrainFlowPresets are:
- default
- auxiliary
- ancillary
Default preset is required, other presets are optional.
5. Add new board class
You need to inherit your device from the Board class and implement all pure virtual methods.
BrainFlow has plenty of helpers for different types of IO protocols, it includes:
- serial port
- TCP/UDP sockets
- multicast and broadcasts sockets
- bluetooth
- BLE
You should reuse them as much as possible, check utils folder to see all possible helpers and interfaces for them. Also, you can use one of already supported devices with the similar IO protocol as a reference.
Good examples to use as a base are:
- Synthetic board to get familiar, it does not use IO helpers and generates data instead
- Enophone for classic bluetooth
- GanglionNative for BLE
- FreeEEG32 for serial port
- Unicorn for 3rd party binary library for IO
- Neurosity for TCP/IP
Generic rules to keep in mind:
- initialize as much as possible inside
prepare_session
method - send commands to start streaming and create extra threads for signal acquisition in
start_stream
- send commands to stop streaming and stop all threads in
stop_stream
- release all allocated resources in
release_session
Also, base Board class has some usefull methods and fields:
- board description from step 4 will be available as a json object
board_descr
- logging should be done via
safe_logger
method prepare_for_acquisition
should be called fromstart_stream
to allocate buffers and init streamers- data should be pushed via
push_package
method from data acquisition thread running in the background free_packages
should be called fromrelease_session
6. Update Cmake files
Add new files to BOARD_CONTROLLER_SRC
variable in build.cmake, you may also need to add new directory to target_include_directories
.
7. Test it and send a PR
Before PR make sure that you’ve tested everything and configured clang-format
tool. Check BraiinFlow docs for developers for more info about docs, codestyle, CI, etc. You will also need to add info about your device to BrainFlow docs
8. Emulator and CI pipelines
This step is optional but it will ensure that support for your device will not be broken in the future. You can add an emulator of your device and integrate tests with emulator into CI pipelines.
If you have any questions about this process feel free to ask them in BrainFlow Slack workspace.