Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rust package #355

Merged
merged 21 commits into from
Oct 9, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,12 @@ jobs:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
VERSION: ${{ github.event.inputs.version }}
- name: Prepare Rust Package
run: |
cd $env:GITHUB_WORKSPACE\rust-package\brainflow
(gc .\Cargo.toml).replace('0.0.0', $env:VERSION) | Out-File -encoding ASCII Cargo.toml
env:
VERSION: ${{ github.event.inputs.version }}
# publish packages
- name: Publish Packages
if: github.event.inputs.publish == 'true'
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,8 @@ java-package/brainflow/src/main/resources/
matlab-package/brainflow/inc/
matlab-package/brainflow/lib/
python-package/brainflow/lib/
rust-package/brainflow/lib/
rust-package/brainflow/inc/

# CMake & GNU Make
CMakeCache.txt
Expand Down
9 changes: 8 additions & 1 deletion docs/BuildBrainFlow.rst
Original file line number Diff line number Diff line change
Expand Up @@ -250,5 +250,12 @@ Compilation instructions:
# for x86
cmake -G Ninja -DCMAKE_TOOLCHAIN_FILE=E:\android-ndk-r21d-windows-x86_64\android-ndk-r21d\build\cmake\android.toolchain.cmake -DANDROID_NATIVE_API_LEVEL=android-19 -DANDROID_ABI=x86 ..

# to build(should be run for each ABI from previous step)
# to build(should be run for each ABI from previous step**
cmake --build . --target install --config Release -j 2 --parallel 2


Rust
----

** For brainflow developers **
Run `cargo build --features="generate_binding"` to generate the binding.
20 changes: 20 additions & 0 deletions rust-package/brainflow/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Created by https://www.toptal.com/developers/gitignore/api/rust
# Edit at https://www.toptal.com/developers/gitignore?templates=rust

### Rust ###
# Generated by Cargo
# will have compiled files and executables
debug/
target/

# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
Cargo.lock

# These are backup files generated by rustfmt
**/*.rs.bk

# MSVC Windows builds of rustc generate these, which store debugging information
*.pdb

# End of https://www.toptal.com/developers/gitignore/api/rust
32 changes: 32 additions & 0 deletions rust-package/brainflow/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
[package]
name = "brainflow"
version = "0.0.0"
authors = ["Andrey Parfenov <[email protected]>", "Daniel Hahne <[email protected]>"]
edition = "2018"
description = "BrainFlow is a library intended to obtain, parse and analyze EEG, EMG, ECG, and other kinds of data from biosensors."
repository = "https://github.com/brainflow-dev/brainflow"
license = "MIT"
readme = "README.md"
documentation = "https://brainflow.readthedocs.io"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[features]
generate_binding = []

[dependencies]
getset = "0.1.1"
libloading = "0.7.0"
ndarray = "0.15.3"
num = "0.4.0"
num-complex = "0.4.0"
num-derive = "0.3.3"
num-traits = "0.2.14"
once_cell = "1.8.0"
paste = "1.0.5"
serde = { version ="1.0.130", features=["derive"] }
serde_json = "1.0.68"
thiserror = "1.0.29"

[build-dependencies]
bindgen = "0.59.1"
75 changes: 75 additions & 0 deletions rust-package/brainflow/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
<p align="center">
<img width="400" height="160" src="https://live.staticflickr.com/65535/49908747533_f359f83610_w.jpg">
<br>
<a href="https://github.com/brainflow-dev/brainflow/releases">
<img alt="GitHub all releases" src="https://img.shields.io/github/downloads/brainflow-dev/brainflow/total?color=yellow&label=Downloads%28Github%29">
</a>
<a href="https://pypi.org/project/brainflow/">
<img alt="PYPI" src="https://static.pepy.tech/personalized-badge/brainflow?period=total&units=international_system&left_color=grey&right_color=yellow&left_text=Downloads(PYPI)">
</a>
<a href="https://www.nuget.org/packages/brainflow/">
<img alt="Nuget" src="https://img.shields.io/nuget/dt/brainflow?color=yellow&label=Downloads%28Nuget%29&logo=BrainFlow">
</a>
</p>

BrainFlow is a library intended to obtain, parse and analyze EEG, EMG, ECG, and other kinds of data from biosensors.

It provides a uniform SDK to work with biosensors with a primary focus on neurointerfaces, all features available for free and distributed under MIT license.

#### Advantages of BrainFlow:

* powerful API with many features to simplify development
* Straightforward API for data acquisition
* Powerful API for signal filtering, denoising, downsampling...
* Development tools like Synthetic board, Streaming board, logging API
* easy to use
* BrainFlow has many bindings, you can choose programming language you like
* All programming languages provide the same API, so it's simple to switch
* API is uniform for all boards, it makes applications on top of BrainFlow almost board agnostic
* easy to support and extend
* Code to read data and to perform signal processing is implemented only once in C/C++, bindings just call C/C++ methods
* Powerful CI/CD system which runs integrations tests for each commit automatically using BrainFlow's Emulator
* Simplified process to add new boards and methods

## Resources

* [***BrainFlow Docs, Dev and User guides and other information***](https://brainflow.readthedocs.io)
* [***BrainFlow's slack workspace***](https://openbraintalk.slack.com/)***, use this*** [***link to join***](https://c6ber255cc.execute-api.eu-west-1.amazonaws.com/Express/)
* [***For BrainFlow Developers***](https://brainflow.readthedocs.io/en/master/BrainFlowDev.html)

## Contribution guidelines

If you want to contribute to BrainFlow, be sure to review the [contribution guidelines](https://brainflow.readthedocs.io/en/stable/BrainFlowDev.html). This project adheres to [BrainFlow's code of conduct](https://github.com/brainflow-dev/brainflow/blob/master/CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code.

We use [GitHub issues](https://github.com/brainflow-dev/brainflow/issues) for tracking requests and bugs, please use BrainFlow's slack for general discussions.

The BrainFlow project strives to abide by generally accepted best practices in open-source software development.

## Build Status
| Build Type | Status |
|:---------------------------: |:-------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
| Windows Tests | [![GitHub Workflow Status (branch)](https://img.shields.io/github/workflow/status/brainflow-dev/brainflow/Run%20Windows/master?color=yellow&label=Windows%202019)](https://github.com/brainflow-dev/brainflow/actions/workflows/run_windows.yml) |
| Unix(Linix and MacOS) Tests | [![GitHub Workflow Status (branch)](https://img.shields.io/github/workflow/status/brainflow-dev/brainflow/Run%20Unix/master?color=yellow&label=Ubuntu%20and%20MacOS)](https://github.com/brainflow-dev/brainflow/actions/workflows/run_unix.yml) |
| Android Tests | [![GitHub Workflow Status (branch)](https://img.shields.io/github/workflow/status/brainflow-dev/brainflow/Run%20Android%20NDK/master?color=yellow&label=Android)](https://github.com/brainflow-dev/brainflow/actions/workflows/run_android.yml) |
| Alpine Tests | [![GitHub Workflow Status (branch)](https://img.shields.io/github/workflow/status/brainflow-dev/brainflow/Run%20Alpine/master?color=yellow&label=Alpine)](https://github.com/brainflow-dev/brainflow/actions/workflows/run_alpine.yml) |
| Valgrind Tests | [![GitHub Workflow Status (branch)](https://img.shields.io/github/workflow/status/brainflow-dev/brainflow/Run%20Valgrind/master?color=yellow&label=Valgrind)](https://github.com/brainflow-dev/brainflow/actions/workflows/valgrind.yml) |
| CppCheck | [![GitHub Workflow Status (branch)](https://img.shields.io/github/workflow/status/brainflow-dev/brainflow/CppCheck/master?color=yellow&label=Static%20Analyzer)](https://github.com/brainflow-dev/brainflow/actions/workflows/cppcheck.yml) |
| Clang-Format | [![GitHub Workflow Status (branch)](https://img.shields.io/github/workflow/status/brainflow-dev/brainflow/Clang%20Format/master?color=yellow&label=Code%20Style)](https://github.com/brainflow-dev/brainflow/actions/workflows/clang_format.yml) |

## Brainflow Bindings

We support bindings for:
* [Python](./python-package)
* [Java](./java-package/brainflow/)
* [R](./r-package/)
* [C++](./cpp-package/)
* [C#](./csharp-package/brainflow/)
* [Matlab](./matlab-package/brainflow)
* [Julia](.julia-package/brainflow)

## Partners and Sponsors

[![OpenBCI](https://live.staticflickr.com/65535/49913349191_0cbd41157c_w.jpg)](https://openbci.com/)

## License:
[MIT](https://github.com/brainflow-dev/brainflow/blob/master/LICENSE)
122 changes: 122 additions & 0 deletions rust-package/brainflow/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
#[cfg(feature = "generate_binding")]
use std::path::PathBuf;

#[cfg(feature = "generate_binding")]
fn generate_board_controller_binding() {
const ALLOW_UNCONVENTIONALS: &'static str = "#![allow(non_camel_case_types)]\n";

let header_path = PathBuf::from("inc");
let header_path = header_path.display();

let bindings = bindgen::Builder::default()
.header(format!("{}/board_controller.h", &header_path))
.header(format!("{}/board_info_getter.h", &header_path))
.raw_line(ALLOW_UNCONVENTIONALS)
.dynamic_library_name("BoardController")
.clang_arg("-std=c++11")
.clang_arg("-x")
.clang_arg("c++")
.generate()
.expect("Unable to generate bindings");

let binding_target_path = PathBuf::new()
.join("src")
.join("ffi")
.join("board_controller.rs");

bindings
.write_to_file(binding_target_path)
.expect("Could not write binding to `src/ffi/board_controller.rs`");
}

#[cfg(feature = "generate_binding")]
fn generate_data_handler_binding() {
const ALLOW_UNCONVENTIONALS: &'static str = "#![allow(non_camel_case_types)]\n";

let header_path = PathBuf::from("inc");
let header_path = header_path.display();

let bindings = bindgen::Builder::default()
.header(format!("{}/data_handler.h", &header_path))
.raw_line(ALLOW_UNCONVENTIONALS)
.dynamic_library_name("DataHandler")
.clang_arg("-std=c++11")
.clang_arg("-x")
.clang_arg("c++")
.generate()
.expect("Unable to generate bindings");

let binding_target_path = PathBuf::new()
.join("src")
.join("ffi")
.join("data_handler.rs");

bindings
.write_to_file(binding_target_path)
.expect("Could not write binding to `src/ffi/data_handler.rs`");
}

#[cfg(feature = "generate_binding")]
fn generate_ml_model_binding() {
const ALLOW_UNCONVENTIONALS: &'static str = "#![allow(non_camel_case_types)]\n";

let header_path = PathBuf::from("inc");
let header_path = header_path.display();

let bindings = bindgen::Builder::default()
.header(format!("{}/ml_module.h", &header_path))
.raw_line(ALLOW_UNCONVENTIONALS)
.dynamic_library_name("MlModule")
.clang_arg("-std=c++11")
.clang_arg("-x")
.clang_arg("c++")
.generate()
.expect("Unable to generate bindings");

let binding_target_path = PathBuf::new().join("src").join("ffi").join("ml_model.rs");

bindings
.write_to_file(binding_target_path)
.expect("Could not write binding to `src/ffi/ml_model.rs`");
}

#[cfg(feature = "generate_binding")]
fn generate_constants_binding() {
const ALLOW_UNCONVENTIONALS: &'static str = "#![allow(non_camel_case_types)]\n";

let header_path = PathBuf::from("inc");
let header_path = header_path.display();

let bindings = bindgen::Builder::default()
.header(format!("{}/brainflow_constants.h", &header_path))
.raw_line(ALLOW_UNCONVENTIONALS)
.clang_arg("-std=c++11")
.clang_arg("-x")
.clang_arg("c++")
.default_enum_style(bindgen::EnumVariation::Rust {
non_exhaustive: false,
})
.rustified_non_exhaustive_enum("BrainFlowExitCodes")
.rustified_non_exhaustive_enum("BoardIds")
.generate()
.expect("Unable to generate bindings");

let binding_target_path = PathBuf::new().join("src").join("ffi").join("constants.rs");

bindings
.write_to_file(binding_target_path)
.expect("Could not write binding to `src/ffi/constants.rs`");
}

#[cfg(feature = "generate_binding")]
fn generate_binding() {
generate_board_controller_binding();
generate_data_handler_binding();
generate_ml_model_binding();
generate_constants_binding();
}

fn main() {
#[cfg(feature = "generate_binding")]
generate_binding();
}
29 changes: 29 additions & 0 deletions rust-package/brainflow/examples/get_data_from_a_board.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
use std::thread;
use std::time::Duration;

use brainflow::board_shim::BoardShim;
use brainflow::brainflow_input_params::BrainFlowInputParamsBuilder;
use brainflow::BoardId;

fn main() {
brainflow::board_shim::enable_dev_board_logger().unwrap();
brainflow::ml_model::enable_ml_logger().unwrap();
let params = BrainFlowInputParamsBuilder::default()
.serial_port("/dev/ttyUSB0")
.build();
let board = BoardShim::new(BoardId::CytonBoard, params).unwrap();

dbg!("board instantiated");

board.prepare_session().unwrap();

board.start_stream(20, "").unwrap();
thread::sleep(Duration::from_secs(5));
board.stop_stream().unwrap();

let cnt = dbg!(board.get_board_data_count().unwrap());
let data = board.get_current_board_data(cnt).unwrap();
board.release_session().unwrap();

dbg!(data);
}
44 changes: 44 additions & 0 deletions rust-package/brainflow/src/board_id.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, FromPrimitive)]
pub enum BoardId {
PlaybackFileBoard = -3,
StreamingBoard = -2,
SyntheticBoard = -1,
CytonBoard = 0,
GanglionBoard = 1,
CytonDaisyBoard = 2,
GaleaBoard = 3,
GanglionWifiBoard = 4,
CytonWifiBoard = 5,
CytonDaisyWifiBoard = 6,
BrainbitBoard = 7,
UnicornBoard = 8,
CallibriEegBoard = 9,
CallibriEmgBoard = 10,
CallibriEcgBoard = 11,
FasciaBoard = 12,
Notion1Board = 13,
Notion2Board = 14,
IronbciBoard = 15,
GforceProBoard = 16,
Freeeeg32Board = 17,
BrainbitBledBoard = 18,
GforceDualBoard = 19,
GaleaSerialBoard = 20,
MuseSBledBoard = 21,
Muse2BledBoard = 22,
CrownBoard = 23,
AntNeuroEe410Board = 24,
AntNeuroEe411Board = 25,
AntNeuroEe430Board = 26,
AntNeuroEe211Board = 27,
AntNeuroEe212Board = 28,
AntNeuroEe213Board = 29,
AntNeuroEe214Board = 30,
AntNeuroEe215Board = 31,
AntNeuroEe221Board = 32,
AntNeuroEe222Board = 33,
AntNeuroEe223Board = 34,
AntNeuroEe224Board = 35,
AntNeuroEe225Board = 36,
EnophoneBoard = 37,
}
Loading