From a3ca1c8b841c0cdb00374861db54f947c40438c3 Mon Sep 17 00:00:00 2001 From: Daniel Hahne Date: Thu, 23 Sep 2021 21:03:55 +0200 Subject: [PATCH 01/21] Build brainflow-sys and generate bindings --- .gitmodules | 3 + rust-package/brainflow-sys/.gitignore | 20 ++ rust-package/brainflow-sys/Cargo.lock | 391 +++++++++++++++++++++ rust-package/brainflow-sys/Cargo.toml | 13 + rust-package/brainflow-sys/brainflow | 1 + rust-package/brainflow-sys/build.rs | 78 +++++ rust-package/brainflow-sys/src/lib.rs | 477 ++++++++++++++++++++++++++ rust-package/brainflow/Cargo.toml | 8 + rust-package/brainflow/src/lib.rs | 7 + 9 files changed, 998 insertions(+) create mode 100644 .gitmodules create mode 100644 rust-package/brainflow-sys/.gitignore create mode 100644 rust-package/brainflow-sys/Cargo.lock create mode 100644 rust-package/brainflow-sys/Cargo.toml create mode 160000 rust-package/brainflow-sys/brainflow create mode 100644 rust-package/brainflow-sys/build.rs create mode 100644 rust-package/brainflow-sys/src/lib.rs create mode 100644 rust-package/brainflow/Cargo.toml create mode 100644 rust-package/brainflow/src/lib.rs diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000..3421f05f4 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "rust-package/brainflow-sys/brainflow"] + path = rust-package/brainflow-sys/brainflow + url = git@github.com:brainflow-dev/brainflow.git diff --git a/rust-package/brainflow-sys/.gitignore b/rust-package/brainflow-sys/.gitignore new file mode 100644 index 000000000..389159a37 --- /dev/null +++ b/rust-package/brainflow-sys/.gitignore @@ -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 diff --git a/rust-package/brainflow-sys/Cargo.lock b/rust-package/brainflow-sys/Cargo.lock new file mode 100644 index 000000000..71575b7f4 --- /dev/null +++ b/rust-package/brainflow-sys/Cargo.lock @@ -0,0 +1,391 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aho-corasick" +version = "0.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5" +dependencies = [ + "memchr", +] + +[[package]] +name = "ansi_term" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" +dependencies = [ + "winapi", +] + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + +[[package]] +name = "bindgen" +version = "0.59.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "453c49e5950bb0eb63bb3df640e31618846c89d5b7faa54040d76e98e0134375" +dependencies = [ + "bitflags", + "cexpr", + "clang-sys", + "clap", + "env_logger", + "lazy_static", + "lazycell", + "log", + "peeking_take_while", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "which", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitvec" +version = "0.19.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8942c8d352ae1838c9dda0b0ca2ab657696ef2232a20147cf1b30ae1a9cb4321" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "brainflow-sys" +version = "0.1.0" +dependencies = [ + "bindgen", + "cmake", +] + +[[package]] +name = "cc" +version = "1.0.70" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d26a6ce4b6a484fa3edb70f7efa6fc430fd2b87285fe8b84304fd0936faa0dc0" + +[[package]] +name = "cexpr" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db507a7679252d2276ed0dd8113c6875ec56d3089f9225b2b42c30cc1f8e5c89" +dependencies = [ + "nom", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "clang-sys" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10612c0ec0e0a1ff0e97980647cb058a6e7aedb913d01d009c406b8b7d0b26ee" +dependencies = [ + "glob", + "libc", + "libloading", +] + +[[package]] +name = "clap" +version = "2.33.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002" +dependencies = [ + "ansi_term", + "atty", + "bitflags", + "strsim", + "textwrap", + "unicode-width", + "vec_map", +] + +[[package]] +name = "cmake" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb6210b637171dfba4cda12e579ac6dc73f5165ad56133e5d72ef3131f320855" +dependencies = [ + "cc", +] + +[[package]] +name = "env_logger" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a19187fea3ac7e84da7dacf48de0c45d63c6a76f9490dae389aead16c243fce3" +dependencies = [ + "atty", + "humantime", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "funty" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fed34cd105917e91daa4da6b3728c47b068749d6a62c59811f06ed2ac71d9da7" + +[[package]] +name = "glob" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + +[[package]] +name = "libc" +version = "0.2.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2a5ac8f984bfcf3a823267e5fde638acc3325f6496633a5da6bb6eb2171e103" + +[[package]] +name = "libloading" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f84d96438c15fcd6c3f244c8fce01d1e2b9c6b5623e9c711dc9286d8fc92d6a" +dependencies = [ + "cfg-if", + "winapi", +] + +[[package]] +name = "log" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "memchr" +version = "2.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" + +[[package]] +name = "nom" +version = "6.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c5c51b9083a3c620fa67a2a635d1ce7d95b897e957d6b28ff9a5da960a103a6" +dependencies = [ + "bitvec", + "funty", + "memchr", + "version_check", +] + +[[package]] +name = "peeking_take_while" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" + +[[package]] +name = "proc-macro2" +version = "1.0.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9f5105d4fdaab20335ca9565e106a5d9b82b6219b5ba735731124ac6711d23d" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "radium" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "941ba9d78d8e2f7ce474c015eea4d9c6d25b6a3327f9832ee29a4de27f91bbb8" + +[[package]] +name = "regex" +version = "1.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a26af418b574bd56588335b3a3659a65725d4e636eb1016c2f9e3b38c7cc759" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "shlex" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3" + +[[package]] +name = "strsim" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "termcolor" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +dependencies = [ + "unicode-width", +] + +[[package]] +name = "unicode-width" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" + +[[package]] +name = "unicode-xid" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" + +[[package]] +name = "vec_map" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" + +[[package]] +name = "version_check" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" + +[[package]] +name = "which" +version = "3.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d011071ae14a2f6671d0b74080ae0cd8ebf3a6f8c9589a2cd45f23126fe29724" +dependencies = [ + "libc", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "wyz" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214" diff --git a/rust-package/brainflow-sys/Cargo.toml b/rust-package/brainflow-sys/Cargo.toml new file mode 100644 index 000000000..308c403ed --- /dev/null +++ b/rust-package/brainflow-sys/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "brainflow-sys" +version = "0.1.0" +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[features] +generate_binding = ["bindgen"] + +[build-dependencies] +bindgen = { version = "0.59.1", optional = true } +cmake = "0.1" diff --git a/rust-package/brainflow-sys/brainflow b/rust-package/brainflow-sys/brainflow new file mode 160000 index 000000000..d103874f7 --- /dev/null +++ b/rust-package/brainflow-sys/brainflow @@ -0,0 +1 @@ +Subproject commit d103874f7683c53e0cd1762a9729beadcba9a7a6 diff --git a/rust-package/brainflow-sys/build.rs b/rust-package/brainflow-sys/build.rs new file mode 100644 index 000000000..c4115bf3c --- /dev/null +++ b/rust-package/brainflow-sys/build.rs @@ -0,0 +1,78 @@ +#[cfg(feature = "generate_binding")] +use std::{env, path::PathBuf}; + +use std::{fmt::Display, path::Path}; + +#[cfg(feature = "generate_binding")] +fn generate_binding() { + let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); + dbg!(&out_path); + let header_path = out_path.join("inc"); + dbg!(&header_path); + let header_path = header_path.display(); + + dbg!(&header_path); + dbg!(&out_path); + let bindings = bindgen::Builder::default() + // The input header we would like to generate + // bindings for. + .header(format!("{}/board_controller.h", &header_path)) + .header(format!("{}/board_info_getter.h", &header_path)) + .header(format!("{}/data_handler.h", &header_path)) + .header(format!("{}/ml_module.h", &header_path)) + .clang_arg("-std=c++11") + .clang_arg("-x") + .clang_arg("c++") + .enable_cxx_namespaces() + // .opaque_type("std::.*") + // Tell cargo to invalidate the built crate whenever any of the + // included header files changed. + .parse_callbacks(Box::new(bindgen::CargoCallbacks)) + // Finish the builder and generate the bindings. + .generate() + // Unwrap the Result and panic on failure. + .expect("Unable to generate bindings"); + + let binding_target_path = PathBuf::new().join("src").join("lib.rs"); + + bindings + .write_to_file(binding_target_path) + .expect("Could not write binding to `src/lib.rs`"); +} + +fn build() { + let brainflow_path = Path::new("brainflow"); + + println!( + "cargo:info=Brainflow source path used: {:?}.", + brainflow_path + .canonicalize() + .expect("Could not canonicalise to absolute path") + ); + + println!("cargo:info=Building Brainflow via CMake."); + let brainflow_build_dir = cmake::build(brainflow_path); + link(brainflow_build_dir.display()) +} + +fn link(brainflow_build_dir: impl Display) { + println!("cargo:rustc-link-lib={}=Brainflow", "static"); + println!("cargo:rustc-link-lib={}=DSPFilters", "static"); + println!("cargo:rustc-link-lib={}=BoardController", "dylib"); + println!("cargo:rustc-link-lib={}=DataHandler", "dylib"); + println!("cargo:rustc-link-lib={}=BrainBitLib", "dylib"); + println!("cargo:rustc-link-lib={}=MLModule", "dylib"); + println!("cargo:rustc-link-lib={}=MuseLib", "dylib"); + println!("cargo:rustc-link-lib={}=stdc++", "dylib"); + println!("cargo:rustc-link-search=native={}/lib", brainflow_build_dir); +} + +fn main() { + build(); + + #[cfg(feature = "generate_binding")] + generate_binding(); + + println!("cargo:rerun-if-changed=src/lib.rs"); + println!("cargo:rerun-if-changed=build.rs"); +} diff --git a/rust-package/brainflow-sys/src/lib.rs b/rust-package/brainflow-sys/src/lib.rs new file mode 100644 index 000000000..3d2451208 --- /dev/null +++ b/rust-package/brainflow-sys/src/lib.rs @@ -0,0 +1,477 @@ +/* automatically generated by rust-bindgen 0.59.1 */ + +#[allow(non_snake_case, non_camel_case_types, non_upper_case_globals)] +pub mod root { + #[allow(unused_imports)] + use self::super::root; + extern "C" { + pub fn get_board_descr( + board_id: ::std::os::raw::c_int, + board_descr: *mut ::std::os::raw::c_char, + len: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; + } + extern "C" { + pub fn get_sampling_rate( + board_id: ::std::os::raw::c_int, + sampling_rate: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; + } + extern "C" { + pub fn get_package_num_channel( + board_id: ::std::os::raw::c_int, + package_num_channel: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; + } + extern "C" { + pub fn get_timestamp_channel( + board_id: ::std::os::raw::c_int, + timestamp_channel: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; + } + extern "C" { + pub fn get_marker_channel( + board_id: ::std::os::raw::c_int, + marker_channel: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; + } + extern "C" { + pub fn get_battery_channel( + board_id: ::std::os::raw::c_int, + battery_channel: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; + } + extern "C" { + pub fn get_num_rows( + board_id: ::std::os::raw::c_int, + num_rows: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; + } + extern "C" { + pub fn get_eeg_names( + board_id: ::std::os::raw::c_int, + eeg_names: *mut ::std::os::raw::c_char, + len: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; + } + extern "C" { + pub fn get_exg_channels( + board_id: ::std::os::raw::c_int, + exg_channels: *mut ::std::os::raw::c_int, + len: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; + } + extern "C" { + pub fn get_eeg_channels( + board_id: ::std::os::raw::c_int, + eeg_channels: *mut ::std::os::raw::c_int, + len: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; + } + extern "C" { + pub fn get_emg_channels( + board_id: ::std::os::raw::c_int, + emg_channels: *mut ::std::os::raw::c_int, + len: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; + } + extern "C" { + pub fn get_ecg_channels( + board_id: ::std::os::raw::c_int, + ecg_channels: *mut ::std::os::raw::c_int, + len: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; + } + extern "C" { + pub fn get_eog_channels( + board_id: ::std::os::raw::c_int, + eog_channels: *mut ::std::os::raw::c_int, + len: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; + } + extern "C" { + pub fn get_ppg_channels( + board_id: ::std::os::raw::c_int, + ppg_channels: *mut ::std::os::raw::c_int, + len: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; + } + extern "C" { + pub fn get_eda_channels( + board_id: ::std::os::raw::c_int, + eda_channels: *mut ::std::os::raw::c_int, + len: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; + } + extern "C" { + pub fn get_accel_channels( + board_id: ::std::os::raw::c_int, + accel_channels: *mut ::std::os::raw::c_int, + len: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; + } + extern "C" { + pub fn get_analog_channels( + board_id: ::std::os::raw::c_int, + analog_channels: *mut ::std::os::raw::c_int, + len: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; + } + extern "C" { + pub fn get_gyro_channels( + board_id: ::std::os::raw::c_int, + gyro_channels: *mut ::std::os::raw::c_int, + len: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; + } + extern "C" { + pub fn get_other_channels( + board_id: ::std::os::raw::c_int, + other_channels: *mut ::std::os::raw::c_int, + len: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; + } + extern "C" { + pub fn get_temperature_channels( + board_id: ::std::os::raw::c_int, + temperature_channels: *mut ::std::os::raw::c_int, + len: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; + } + extern "C" { + pub fn get_resistance_channels( + board_id: ::std::os::raw::c_int, + resistance_channels: *mut ::std::os::raw::c_int, + len: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; + } + extern "C" { + pub fn get_device_name( + board_id: ::std::os::raw::c_int, + name: *mut ::std::os::raw::c_char, + len: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; + } + extern "C" { + pub fn prepare_session( + board_id: ::std::os::raw::c_int, + json_brainflow_input_params: *const ::std::os::raw::c_char, + ) -> ::std::os::raw::c_int; + } + extern "C" { + pub fn start_stream( + buffer_size: ::std::os::raw::c_int, + streamer_params: *const ::std::os::raw::c_char, + board_id: ::std::os::raw::c_int, + json_brainflow_input_params: *const ::std::os::raw::c_char, + ) -> ::std::os::raw::c_int; + } + extern "C" { + pub fn stop_stream( + board_id: ::std::os::raw::c_int, + json_brainflow_input_params: *const ::std::os::raw::c_char, + ) -> ::std::os::raw::c_int; + } + extern "C" { + pub fn release_session( + board_id: ::std::os::raw::c_int, + json_brainflow_input_params: *const ::std::os::raw::c_char, + ) -> ::std::os::raw::c_int; + } + extern "C" { + pub fn get_current_board_data( + num_samples: ::std::os::raw::c_int, + data_buf: *mut f64, + returned_samples: *mut ::std::os::raw::c_int, + board_id: ::std::os::raw::c_int, + json_brainflow_input_params: *const ::std::os::raw::c_char, + ) -> ::std::os::raw::c_int; + } + extern "C" { + pub fn get_board_data_count( + result: *mut ::std::os::raw::c_int, + board_id: ::std::os::raw::c_int, + json_brainflow_input_params: *const ::std::os::raw::c_char, + ) -> ::std::os::raw::c_int; + } + extern "C" { + pub fn get_board_data( + data_count: ::std::os::raw::c_int, + data_buf: *mut f64, + board_id: ::std::os::raw::c_int, + json_brainflow_input_params: *const ::std::os::raw::c_char, + ) -> ::std::os::raw::c_int; + } + extern "C" { + pub fn config_board( + config: *mut ::std::os::raw::c_char, + response: *mut ::std::os::raw::c_char, + response_len: *mut ::std::os::raw::c_int, + board_id: ::std::os::raw::c_int, + json_brainflow_input_params: *const ::std::os::raw::c_char, + ) -> ::std::os::raw::c_int; + } + extern "C" { + pub fn is_prepared( + prepared: *mut ::std::os::raw::c_int, + board_id: ::std::os::raw::c_int, + json_brainflow_input_params: *const ::std::os::raw::c_char, + ) -> ::std::os::raw::c_int; + } + extern "C" { + pub fn insert_marker( + marker_value: f64, + board_id: ::std::os::raw::c_int, + json_brainflow_input_params: *const ::std::os::raw::c_char, + ) -> ::std::os::raw::c_int; + } + extern "C" { + pub fn set_log_level(log_level: ::std::os::raw::c_int) -> ::std::os::raw::c_int; + } + extern "C" { + pub fn set_log_file(log_file: *const ::std::os::raw::c_char) -> ::std::os::raw::c_int; + } + extern "C" { + pub fn log_message( + log_level: ::std::os::raw::c_int, + message: *mut ::std::os::raw::c_char, + ) -> ::std::os::raw::c_int; + } + #[repr(C)] + #[derive(Debug, Copy, Clone)] + pub struct JNINativeInterface { + _unused: [u8; 0], + } + pub type JNIEnv = *const root::JNINativeInterface; + extern "C" { + pub fn java_set_jnienv(java_jnienv: *mut root::JNIEnv) -> ::std::os::raw::c_int; + } + extern "C" { + pub fn perform_lowpass( + data: *mut f64, + data_len: ::std::os::raw::c_int, + sampling_rate: ::std::os::raw::c_int, + cutoff: f64, + order: ::std::os::raw::c_int, + filter_type: ::std::os::raw::c_int, + ripple: f64, + ) -> ::std::os::raw::c_int; + } + extern "C" { + pub fn perform_highpass( + data: *mut f64, + data_len: ::std::os::raw::c_int, + sampling_rate: ::std::os::raw::c_int, + cutoff: f64, + order: ::std::os::raw::c_int, + filter_type: ::std::os::raw::c_int, + ripple: f64, + ) -> ::std::os::raw::c_int; + } + extern "C" { + pub fn perform_bandpass( + data: *mut f64, + data_len: ::std::os::raw::c_int, + sampling_rate: ::std::os::raw::c_int, + center_freq: f64, + band_width: f64, + order: ::std::os::raw::c_int, + filter_type: ::std::os::raw::c_int, + ripple: f64, + ) -> ::std::os::raw::c_int; + } + extern "C" { + pub fn perform_bandstop( + data: *mut f64, + data_len: ::std::os::raw::c_int, + sampling_rate: ::std::os::raw::c_int, + center_freq: f64, + band_width: f64, + order: ::std::os::raw::c_int, + filter_type: ::std::os::raw::c_int, + ripple: f64, + ) -> ::std::os::raw::c_int; + } + extern "C" { + pub fn remove_environmental_noise( + data: *mut f64, + data_len: ::std::os::raw::c_int, + sampling_rate: ::std::os::raw::c_int, + noise_type: ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; + } + extern "C" { + pub fn perform_rolling_filter( + data: *mut f64, + data_len: ::std::os::raw::c_int, + period: ::std::os::raw::c_int, + agg_operation: ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; + } + extern "C" { + pub fn perform_downsampling( + data: *mut f64, + data_len: ::std::os::raw::c_int, + period: ::std::os::raw::c_int, + agg_operation: ::std::os::raw::c_int, + output_data: *mut f64, + ) -> ::std::os::raw::c_int; + } + extern "C" { + pub fn perform_wavelet_transform( + data: *mut f64, + data_len: ::std::os::raw::c_int, + wavelet: *const ::std::os::raw::c_char, + decomposition_level: ::std::os::raw::c_int, + output_data: *mut f64, + decomposition_lengths: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; + } + extern "C" { + pub fn perform_inverse_wavelet_transform( + wavelet_coeffs: *mut f64, + original_data_len: ::std::os::raw::c_int, + wavelet: *const ::std::os::raw::c_char, + decomposition_level: ::std::os::raw::c_int, + decomposition_lengths: *mut ::std::os::raw::c_int, + output_data: *mut f64, + ) -> ::std::os::raw::c_int; + } + extern "C" { + pub fn perform_wavelet_denoising( + data: *mut f64, + data_len: ::std::os::raw::c_int, + wavelet: *const ::std::os::raw::c_char, + decomposition_level: ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; + } + extern "C" { + pub fn get_csp( + data: *const f64, + labels: *const f64, + n_epochs: ::std::os::raw::c_int, + n_channels: ::std::os::raw::c_int, + n_times: ::std::os::raw::c_int, + output_w: *mut f64, + output_d: *mut f64, + ) -> ::std::os::raw::c_int; + } + extern "C" { + pub fn get_window( + window_function: ::std::os::raw::c_int, + window_len: ::std::os::raw::c_int, + output_window: *mut f64, + ) -> ::std::os::raw::c_int; + } + extern "C" { + pub fn perform_fft( + data: *mut f64, + data_len: ::std::os::raw::c_int, + window_function: ::std::os::raw::c_int, + output_re: *mut f64, + output_im: *mut f64, + ) -> ::std::os::raw::c_int; + } + extern "C" { + pub fn perform_ifft( + input_re: *mut f64, + input_im: *mut f64, + data_len: ::std::os::raw::c_int, + restored_data: *mut f64, + ) -> ::std::os::raw::c_int; + } + extern "C" { + pub fn get_nearest_power_of_two( + value: ::std::os::raw::c_int, + output: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; + } + extern "C" { + pub fn get_psd( + data: *mut f64, + data_len: ::std::os::raw::c_int, + sampling_rate: ::std::os::raw::c_int, + window_function: ::std::os::raw::c_int, + output_ampl: *mut f64, + output_freq: *mut f64, + ) -> ::std::os::raw::c_int; + } + extern "C" { + pub fn detrend( + data: *mut f64, + data_len: ::std::os::raw::c_int, + detrend_operation: ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; + } + extern "C" { + pub fn get_psd_welch( + data: *mut f64, + data_len: ::std::os::raw::c_int, + nfft: ::std::os::raw::c_int, + overlap: ::std::os::raw::c_int, + sampling_rate: ::std::os::raw::c_int, + window_function: ::std::os::raw::c_int, + output_ampl: *mut f64, + output_freq: *mut f64, + ) -> ::std::os::raw::c_int; + } + extern "C" { + pub fn get_band_power( + ampl: *mut f64, + freq: *mut f64, + data_len: ::std::os::raw::c_int, + freq_start: f64, + freq_end: f64, + band_power: *mut f64, + ) -> ::std::os::raw::c_int; + } + extern "C" { + pub fn get_avg_band_powers( + raw_data: *mut f64, + rows: ::std::os::raw::c_int, + cols: ::std::os::raw::c_int, + sampling_rate: ::std::os::raw::c_int, + apply_filters: ::std::os::raw::c_int, + avg_band_powers: *mut f64, + stddev_band_powers: *mut f64, + ) -> ::std::os::raw::c_int; + } + extern "C" { + pub fn write_file( + data: *const f64, + num_rows: ::std::os::raw::c_int, + num_cols: ::std::os::raw::c_int, + file_name: *const ::std::os::raw::c_char, + file_mode: *const ::std::os::raw::c_char, + ) -> ::std::os::raw::c_int; + } + extern "C" { + pub fn read_file( + data: *mut f64, + num_rows: *mut ::std::os::raw::c_int, + num_cols: *mut ::std::os::raw::c_int, + file_name: *const ::std::os::raw::c_char, + num_elements: ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; + } + extern "C" { + pub fn get_num_elements_in_file( + file_name: *const ::std::os::raw::c_char, + num_elements: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; + } + extern "C" { + pub fn prepare(json_params: *const ::std::os::raw::c_char) -> ::std::os::raw::c_int; + } + extern "C" { + pub fn predict( + data: *mut f64, + data_len: ::std::os::raw::c_int, + output: *mut f64, + json_params: *const ::std::os::raw::c_char, + ) -> ::std::os::raw::c_int; + } + extern "C" { + pub fn release(json_params: *const ::std::os::raw::c_char) -> ::std::os::raw::c_int; + } +} diff --git a/rust-package/brainflow/Cargo.toml b/rust-package/brainflow/Cargo.toml new file mode 100644 index 000000000..60461b805 --- /dev/null +++ b/rust-package/brainflow/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "brainflow" +version = "0.1.0" +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/rust-package/brainflow/src/lib.rs b/rust-package/brainflow/src/lib.rs new file mode 100644 index 000000000..31e1bb209 --- /dev/null +++ b/rust-package/brainflow/src/lib.rs @@ -0,0 +1,7 @@ +#[cfg(test)] +mod tests { + #[test] + fn it_works() { + assert_eq!(2 + 2, 4); + } +} From 5fa089c74fdc3cb79a90235008c1302b7a681b0f Mon Sep 17 00:00:00 2001 From: Daniel Hahne Date: Thu, 23 Sep 2021 21:15:43 +0200 Subject: [PATCH 02/21] Add dep and gitignore --- rust-package/brainflow/.gitignore | 20 ++++++++++++++++++++ rust-package/brainflow/Cargo.toml | 1 + 2 files changed, 21 insertions(+) create mode 100644 rust-package/brainflow/.gitignore diff --git a/rust-package/brainflow/.gitignore b/rust-package/brainflow/.gitignore new file mode 100644 index 000000000..389159a37 --- /dev/null +++ b/rust-package/brainflow/.gitignore @@ -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 diff --git a/rust-package/brainflow/Cargo.toml b/rust-package/brainflow/Cargo.toml index 60461b805..20d7fcf34 100644 --- a/rust-package/brainflow/Cargo.toml +++ b/rust-package/brainflow/Cargo.toml @@ -6,3 +6,4 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +brainflow-sys = { path = "../brainflow-sys" } From 98734a088c399a2d60ad8c92b357cee5e50c08e2 Mon Sep 17 00:00:00 2001 From: Daniel Hahne Date: Thu, 23 Sep 2021 21:35:23 +0200 Subject: [PATCH 03/21] Refactor sys --- rust-package/brainflow-sys/Cargo.toml | 4 ++-- rust-package/brainflow-sys/build.rs | 19 ------------------- 2 files changed, 2 insertions(+), 21 deletions(-) diff --git a/rust-package/brainflow-sys/Cargo.toml b/rust-package/brainflow-sys/Cargo.toml index 308c403ed..a8d399a6d 100644 --- a/rust-package/brainflow-sys/Cargo.toml +++ b/rust-package/brainflow-sys/Cargo.toml @@ -2,8 +2,8 @@ name = "brainflow-sys" version = "0.1.0" edition = "2018" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +description = "FFI bindings to brainflow" +readme = "README.md" [features] generate_binding = ["bindgen"] diff --git a/rust-package/brainflow-sys/build.rs b/rust-package/brainflow-sys/build.rs index c4115bf3c..a0df84af0 100644 --- a/rust-package/brainflow-sys/build.rs +++ b/rust-package/brainflow-sys/build.rs @@ -6,31 +6,15 @@ use std::{fmt::Display, path::Path}; #[cfg(feature = "generate_binding")] fn generate_binding() { let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); - dbg!(&out_path); let header_path = out_path.join("inc"); - dbg!(&header_path); let header_path = header_path.display(); - dbg!(&header_path); - dbg!(&out_path); let bindings = bindgen::Builder::default() - // The input header we would like to generate - // bindings for. .header(format!("{}/board_controller.h", &header_path)) .header(format!("{}/board_info_getter.h", &header_path)) .header(format!("{}/data_handler.h", &header_path)) .header(format!("{}/ml_module.h", &header_path)) - .clang_arg("-std=c++11") - .clang_arg("-x") - .clang_arg("c++") - .enable_cxx_namespaces() - // .opaque_type("std::.*") - // Tell cargo to invalidate the built crate whenever any of the - // included header files changed. - .parse_callbacks(Box::new(bindgen::CargoCallbacks)) - // Finish the builder and generate the bindings. .generate() - // Unwrap the Result and panic on failure. .expect("Unable to generate bindings"); let binding_target_path = PathBuf::new().join("src").join("lib.rs"); @@ -72,7 +56,4 @@ fn main() { #[cfg(feature = "generate_binding")] generate_binding(); - - println!("cargo:rerun-if-changed=src/lib.rs"); - println!("cargo:rerun-if-changed=build.rs"); } From 473e10c3fd53c865735fc922d5550ca15f6b48a6 Mon Sep 17 00:00:00 2001 From: Daniel Hahne Date: Thu, 23 Sep 2021 22:24:37 +0200 Subject: [PATCH 04/21] Add enums, remove namespace, add readme, add cmake options --- rust-package/brainflow-sys/Cargo.toml | 5 + rust-package/brainflow-sys/README.md | 4 + rust-package/brainflow-sys/build.rs | 44 +- rust-package/brainflow-sys/src/lib.rs | 1101 ++++++++++++++----------- 4 files changed, 679 insertions(+), 475 deletions(-) create mode 100644 rust-package/brainflow-sys/README.md diff --git a/rust-package/brainflow-sys/Cargo.toml b/rust-package/brainflow-sys/Cargo.toml index a8d399a6d..16d474c89 100644 --- a/rust-package/brainflow-sys/Cargo.toml +++ b/rust-package/brainflow-sys/Cargo.toml @@ -6,7 +6,12 @@ description = "FFI bindings to brainflow" readme = "README.md" [features] +default = [] generate_binding = ["bindgen"] +use_libftdi = [] +use_openmp = [] +build_oymotion_sdk = [] +build_bluetooth = [] [build-dependencies] bindgen = { version = "0.59.1", optional = true } diff --git a/rust-package/brainflow-sys/README.md b/rust-package/brainflow-sys/README.md new file mode 100644 index 000000000..31a1afaa3 --- /dev/null +++ b/rust-package/brainflow-sys/README.md @@ -0,0 +1,4 @@ +# About +`brainflow-sys` is an FFI-Rust-binding to brainflow. + +Run with feature `generate_binging` to generate the actual binding src/lib.rs diff --git a/rust-package/brainflow-sys/build.rs b/rust-package/brainflow-sys/build.rs index a0df84af0..4a26bf2a0 100644 --- a/rust-package/brainflow-sys/build.rs +++ b/rust-package/brainflow-sys/build.rs @@ -5,15 +5,27 @@ use std::{fmt::Display, path::Path}; #[cfg(feature = "generate_binding")] fn generate_binding() { + const ALLOW_UNCONVENTIONALS: &'static str = "#![allow(non_camel_case_types)]\n"; + let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); let header_path = out_path.join("inc"); let header_path = header_path.display(); let bindings = bindgen::Builder::default() + .header(format!("{}/brainflow_constants.h", &header_path)) .header(format!("{}/board_controller.h", &header_path)) .header(format!("{}/board_info_getter.h", &header_path)) .header(format!("{}/data_handler.h", &header_path)) .header(format!("{}/ml_module.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"); @@ -35,7 +47,37 @@ fn build() { ); println!("cargo:info=Building Brainflow via CMake."); - let brainflow_build_dir = cmake::build(brainflow_path); + + let use_libftdi = if cfg!(feature = "use_libfidi") { + "ON" + } else { + "OFF" + }; + + let use_openmp = if cfg!(feature = "use_openmp") { + "ON" + } else { + "OFF" + }; + + let build_oymotion_sdk = if cfg!(feature = "build_oymotion_sdk") { + "ON" + } else { + "OFF" + }; + + let build_bluetooth = if cfg!(feature = "build_bluetooth") { + "ON" + } else { + "OFF" + }; + + let brainflow_build_dir = cmake::Config::new(brainflow_path) + .define("USE_LIBFTDI", use_libftdi) + .define("USE_OPENMP", use_openmp) + .define("BUILD_OYMOTION_SDK", build_oymotion_sdk) + .define("BUILD_BLUETOOTH", build_bluetooth) + .build(); link(brainflow_build_dir.display()) } diff --git a/rust-package/brainflow-sys/src/lib.rs b/rust-package/brainflow-sys/src/lib.rs index 3d2451208..e8b699a62 100644 --- a/rust-package/brainflow-sys/src/lib.rs +++ b/rust-package/brainflow-sys/src/lib.rs @@ -1,477 +1,630 @@ /* automatically generated by rust-bindgen 0.59.1 */ -#[allow(non_snake_case, non_camel_case_types, non_upper_case_globals)] -pub mod root { - #[allow(unused_imports)] - use self::super::root; - extern "C" { - pub fn get_board_descr( - board_id: ::std::os::raw::c_int, - board_descr: *mut ::std::os::raw::c_char, - len: *mut ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int; - } - extern "C" { - pub fn get_sampling_rate( - board_id: ::std::os::raw::c_int, - sampling_rate: *mut ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int; - } - extern "C" { - pub fn get_package_num_channel( - board_id: ::std::os::raw::c_int, - package_num_channel: *mut ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int; - } - extern "C" { - pub fn get_timestamp_channel( - board_id: ::std::os::raw::c_int, - timestamp_channel: *mut ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int; - } - extern "C" { - pub fn get_marker_channel( - board_id: ::std::os::raw::c_int, - marker_channel: *mut ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int; - } - extern "C" { - pub fn get_battery_channel( - board_id: ::std::os::raw::c_int, - battery_channel: *mut ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int; - } - extern "C" { - pub fn get_num_rows( - board_id: ::std::os::raw::c_int, - num_rows: *mut ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int; - } - extern "C" { - pub fn get_eeg_names( - board_id: ::std::os::raw::c_int, - eeg_names: *mut ::std::os::raw::c_char, - len: *mut ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int; - } - extern "C" { - pub fn get_exg_channels( - board_id: ::std::os::raw::c_int, - exg_channels: *mut ::std::os::raw::c_int, - len: *mut ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int; - } - extern "C" { - pub fn get_eeg_channels( - board_id: ::std::os::raw::c_int, - eeg_channels: *mut ::std::os::raw::c_int, - len: *mut ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int; - } - extern "C" { - pub fn get_emg_channels( - board_id: ::std::os::raw::c_int, - emg_channels: *mut ::std::os::raw::c_int, - len: *mut ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int; - } - extern "C" { - pub fn get_ecg_channels( - board_id: ::std::os::raw::c_int, - ecg_channels: *mut ::std::os::raw::c_int, - len: *mut ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int; - } - extern "C" { - pub fn get_eog_channels( - board_id: ::std::os::raw::c_int, - eog_channels: *mut ::std::os::raw::c_int, - len: *mut ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int; - } - extern "C" { - pub fn get_ppg_channels( - board_id: ::std::os::raw::c_int, - ppg_channels: *mut ::std::os::raw::c_int, - len: *mut ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int; - } - extern "C" { - pub fn get_eda_channels( - board_id: ::std::os::raw::c_int, - eda_channels: *mut ::std::os::raw::c_int, - len: *mut ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int; - } - extern "C" { - pub fn get_accel_channels( - board_id: ::std::os::raw::c_int, - accel_channels: *mut ::std::os::raw::c_int, - len: *mut ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int; - } - extern "C" { - pub fn get_analog_channels( - board_id: ::std::os::raw::c_int, - analog_channels: *mut ::std::os::raw::c_int, - len: *mut ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int; - } - extern "C" { - pub fn get_gyro_channels( - board_id: ::std::os::raw::c_int, - gyro_channels: *mut ::std::os::raw::c_int, - len: *mut ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int; - } - extern "C" { - pub fn get_other_channels( - board_id: ::std::os::raw::c_int, - other_channels: *mut ::std::os::raw::c_int, - len: *mut ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int; - } - extern "C" { - pub fn get_temperature_channels( - board_id: ::std::os::raw::c_int, - temperature_channels: *mut ::std::os::raw::c_int, - len: *mut ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int; - } - extern "C" { - pub fn get_resistance_channels( - board_id: ::std::os::raw::c_int, - resistance_channels: *mut ::std::os::raw::c_int, - len: *mut ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int; - } - extern "C" { - pub fn get_device_name( - board_id: ::std::os::raw::c_int, - name: *mut ::std::os::raw::c_char, - len: *mut ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int; - } - extern "C" { - pub fn prepare_session( - board_id: ::std::os::raw::c_int, - json_brainflow_input_params: *const ::std::os::raw::c_char, - ) -> ::std::os::raw::c_int; - } - extern "C" { - pub fn start_stream( - buffer_size: ::std::os::raw::c_int, - streamer_params: *const ::std::os::raw::c_char, - board_id: ::std::os::raw::c_int, - json_brainflow_input_params: *const ::std::os::raw::c_char, - ) -> ::std::os::raw::c_int; - } - extern "C" { - pub fn stop_stream( - board_id: ::std::os::raw::c_int, - json_brainflow_input_params: *const ::std::os::raw::c_char, - ) -> ::std::os::raw::c_int; - } - extern "C" { - pub fn release_session( - board_id: ::std::os::raw::c_int, - json_brainflow_input_params: *const ::std::os::raw::c_char, - ) -> ::std::os::raw::c_int; - } - extern "C" { - pub fn get_current_board_data( - num_samples: ::std::os::raw::c_int, - data_buf: *mut f64, - returned_samples: *mut ::std::os::raw::c_int, - board_id: ::std::os::raw::c_int, - json_brainflow_input_params: *const ::std::os::raw::c_char, - ) -> ::std::os::raw::c_int; - } - extern "C" { - pub fn get_board_data_count( - result: *mut ::std::os::raw::c_int, - board_id: ::std::os::raw::c_int, - json_brainflow_input_params: *const ::std::os::raw::c_char, - ) -> ::std::os::raw::c_int; - } - extern "C" { - pub fn get_board_data( - data_count: ::std::os::raw::c_int, - data_buf: *mut f64, - board_id: ::std::os::raw::c_int, - json_brainflow_input_params: *const ::std::os::raw::c_char, - ) -> ::std::os::raw::c_int; - } - extern "C" { - pub fn config_board( - config: *mut ::std::os::raw::c_char, - response: *mut ::std::os::raw::c_char, - response_len: *mut ::std::os::raw::c_int, - board_id: ::std::os::raw::c_int, - json_brainflow_input_params: *const ::std::os::raw::c_char, - ) -> ::std::os::raw::c_int; - } - extern "C" { - pub fn is_prepared( - prepared: *mut ::std::os::raw::c_int, - board_id: ::std::os::raw::c_int, - json_brainflow_input_params: *const ::std::os::raw::c_char, - ) -> ::std::os::raw::c_int; - } - extern "C" { - pub fn insert_marker( - marker_value: f64, - board_id: ::std::os::raw::c_int, - json_brainflow_input_params: *const ::std::os::raw::c_char, - ) -> ::std::os::raw::c_int; - } - extern "C" { - pub fn set_log_level(log_level: ::std::os::raw::c_int) -> ::std::os::raw::c_int; - } - extern "C" { - pub fn set_log_file(log_file: *const ::std::os::raw::c_char) -> ::std::os::raw::c_int; - } - extern "C" { - pub fn log_message( - log_level: ::std::os::raw::c_int, - message: *mut ::std::os::raw::c_char, - ) -> ::std::os::raw::c_int; - } - #[repr(C)] - #[derive(Debug, Copy, Clone)] - pub struct JNINativeInterface { - _unused: [u8; 0], - } - pub type JNIEnv = *const root::JNINativeInterface; - extern "C" { - pub fn java_set_jnienv(java_jnienv: *mut root::JNIEnv) -> ::std::os::raw::c_int; - } - extern "C" { - pub fn perform_lowpass( - data: *mut f64, - data_len: ::std::os::raw::c_int, - sampling_rate: ::std::os::raw::c_int, - cutoff: f64, - order: ::std::os::raw::c_int, - filter_type: ::std::os::raw::c_int, - ripple: f64, - ) -> ::std::os::raw::c_int; - } - extern "C" { - pub fn perform_highpass( - data: *mut f64, - data_len: ::std::os::raw::c_int, - sampling_rate: ::std::os::raw::c_int, - cutoff: f64, - order: ::std::os::raw::c_int, - filter_type: ::std::os::raw::c_int, - ripple: f64, - ) -> ::std::os::raw::c_int; - } - extern "C" { - pub fn perform_bandpass( - data: *mut f64, - data_len: ::std::os::raw::c_int, - sampling_rate: ::std::os::raw::c_int, - center_freq: f64, - band_width: f64, - order: ::std::os::raw::c_int, - filter_type: ::std::os::raw::c_int, - ripple: f64, - ) -> ::std::os::raw::c_int; - } - extern "C" { - pub fn perform_bandstop( - data: *mut f64, - data_len: ::std::os::raw::c_int, - sampling_rate: ::std::os::raw::c_int, - center_freq: f64, - band_width: f64, - order: ::std::os::raw::c_int, - filter_type: ::std::os::raw::c_int, - ripple: f64, - ) -> ::std::os::raw::c_int; - } - extern "C" { - pub fn remove_environmental_noise( - data: *mut f64, - data_len: ::std::os::raw::c_int, - sampling_rate: ::std::os::raw::c_int, - noise_type: ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int; - } - extern "C" { - pub fn perform_rolling_filter( - data: *mut f64, - data_len: ::std::os::raw::c_int, - period: ::std::os::raw::c_int, - agg_operation: ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int; - } - extern "C" { - pub fn perform_downsampling( - data: *mut f64, - data_len: ::std::os::raw::c_int, - period: ::std::os::raw::c_int, - agg_operation: ::std::os::raw::c_int, - output_data: *mut f64, - ) -> ::std::os::raw::c_int; - } - extern "C" { - pub fn perform_wavelet_transform( - data: *mut f64, - data_len: ::std::os::raw::c_int, - wavelet: *const ::std::os::raw::c_char, - decomposition_level: ::std::os::raw::c_int, - output_data: *mut f64, - decomposition_lengths: *mut ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int; - } - extern "C" { - pub fn perform_inverse_wavelet_transform( - wavelet_coeffs: *mut f64, - original_data_len: ::std::os::raw::c_int, - wavelet: *const ::std::os::raw::c_char, - decomposition_level: ::std::os::raw::c_int, - decomposition_lengths: *mut ::std::os::raw::c_int, - output_data: *mut f64, - ) -> ::std::os::raw::c_int; - } - extern "C" { - pub fn perform_wavelet_denoising( - data: *mut f64, - data_len: ::std::os::raw::c_int, - wavelet: *const ::std::os::raw::c_char, - decomposition_level: ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int; - } - extern "C" { - pub fn get_csp( - data: *const f64, - labels: *const f64, - n_epochs: ::std::os::raw::c_int, - n_channels: ::std::os::raw::c_int, - n_times: ::std::os::raw::c_int, - output_w: *mut f64, - output_d: *mut f64, - ) -> ::std::os::raw::c_int; - } - extern "C" { - pub fn get_window( - window_function: ::std::os::raw::c_int, - window_len: ::std::os::raw::c_int, - output_window: *mut f64, - ) -> ::std::os::raw::c_int; - } - extern "C" { - pub fn perform_fft( - data: *mut f64, - data_len: ::std::os::raw::c_int, - window_function: ::std::os::raw::c_int, - output_re: *mut f64, - output_im: *mut f64, - ) -> ::std::os::raw::c_int; - } - extern "C" { - pub fn perform_ifft( - input_re: *mut f64, - input_im: *mut f64, - data_len: ::std::os::raw::c_int, - restored_data: *mut f64, - ) -> ::std::os::raw::c_int; - } - extern "C" { - pub fn get_nearest_power_of_two( - value: ::std::os::raw::c_int, - output: *mut ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int; - } - extern "C" { - pub fn get_psd( - data: *mut f64, - data_len: ::std::os::raw::c_int, - sampling_rate: ::std::os::raw::c_int, - window_function: ::std::os::raw::c_int, - output_ampl: *mut f64, - output_freq: *mut f64, - ) -> ::std::os::raw::c_int; - } - extern "C" { - pub fn detrend( - data: *mut f64, - data_len: ::std::os::raw::c_int, - detrend_operation: ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int; - } - extern "C" { - pub fn get_psd_welch( - data: *mut f64, - data_len: ::std::os::raw::c_int, - nfft: ::std::os::raw::c_int, - overlap: ::std::os::raw::c_int, - sampling_rate: ::std::os::raw::c_int, - window_function: ::std::os::raw::c_int, - output_ampl: *mut f64, - output_freq: *mut f64, - ) -> ::std::os::raw::c_int; - } - extern "C" { - pub fn get_band_power( - ampl: *mut f64, - freq: *mut f64, - data_len: ::std::os::raw::c_int, - freq_start: f64, - freq_end: f64, - band_power: *mut f64, - ) -> ::std::os::raw::c_int; - } - extern "C" { - pub fn get_avg_band_powers( - raw_data: *mut f64, - rows: ::std::os::raw::c_int, - cols: ::std::os::raw::c_int, - sampling_rate: ::std::os::raw::c_int, - apply_filters: ::std::os::raw::c_int, - avg_band_powers: *mut f64, - stddev_band_powers: *mut f64, - ) -> ::std::os::raw::c_int; - } - extern "C" { - pub fn write_file( - data: *const f64, - num_rows: ::std::os::raw::c_int, - num_cols: ::std::os::raw::c_int, - file_name: *const ::std::os::raw::c_char, - file_mode: *const ::std::os::raw::c_char, - ) -> ::std::os::raw::c_int; - } - extern "C" { - pub fn read_file( - data: *mut f64, - num_rows: *mut ::std::os::raw::c_int, - num_cols: *mut ::std::os::raw::c_int, - file_name: *const ::std::os::raw::c_char, - num_elements: ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int; - } - extern "C" { - pub fn get_num_elements_in_file( - file_name: *const ::std::os::raw::c_char, - num_elements: *mut ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int; - } - extern "C" { - pub fn prepare(json_params: *const ::std::os::raw::c_char) -> ::std::os::raw::c_int; - } - extern "C" { - pub fn predict( - data: *mut f64, - data_len: ::std::os::raw::c_int, - output: *mut f64, - json_params: *const ::std::os::raw::c_char, - ) -> ::std::os::raw::c_int; - } - extern "C" { - pub fn release(json_params: *const ::std::os::raw::c_char) -> ::std::os::raw::c_int; - } +#![allow(non_camel_case_types)] + + +#[repr(i32)] +#[non_exhaustive] +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +pub enum BrainFlowExitCodes { + STATUS_OK = 0, + PORT_ALREADY_OPEN_ERROR = 1, + UNABLE_TO_OPEN_PORT_ERROR = 2, + SET_PORT_ERROR = 3, + BOARD_WRITE_ERROR = 4, + INCOMMING_MSG_ERROR = 5, + INITIAL_MSG_ERROR = 6, + BOARD_NOT_READY_ERROR = 7, + STREAM_ALREADY_RUN_ERROR = 8, + INVALID_BUFFER_SIZE_ERROR = 9, + STREAM_THREAD_ERROR = 10, + STREAM_THREAD_IS_NOT_RUNNING = 11, + EMPTY_BUFFER_ERROR = 12, + INVALID_ARGUMENTS_ERROR = 13, + UNSUPPORTED_BOARD_ERROR = 14, + BOARD_NOT_CREATED_ERROR = 15, + ANOTHER_BOARD_IS_CREATED_ERROR = 16, + GENERAL_ERROR = 17, + SYNC_TIMEOUT_ERROR = 18, + JSON_NOT_FOUND_ERROR = 19, + NO_SUCH_DATA_IN_JSON_ERROR = 20, + CLASSIFIER_IS_NOT_PREPARED_ERROR = 21, + ANOTHER_CLASSIFIER_IS_PREPARED_ERROR = 22, + UNSUPPORTED_CLASSIFIER_AND_METRIC_COMBINATION_ERROR = 23, +} +impl BoardIds { + pub const FIRST: BoardIds = BoardIds::PLAYBACK_FILE_BOARD; +} +impl BoardIds { + pub const LAST: BoardIds = BoardIds::ENOPHONE_BOARD; +} +#[repr(i32)] +#[non_exhaustive] +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +pub enum BoardIds { + PLAYBACK_FILE_BOARD = -3, + STREAMING_BOARD = -2, + SYNTHETIC_BOARD = -1, + CYTON_BOARD = 0, + GANGLION_BOARD = 1, + CYTON_DAISY_BOARD = 2, + GALEA_BOARD = 3, + GANGLION_WIFI_BOARD = 4, + CYTON_WIFI_BOARD = 5, + CYTON_DAISY_WIFI_BOARD = 6, + BRAINBIT_BOARD = 7, + UNICORN_BOARD = 8, + CALLIBRI_EEG_BOARD = 9, + CALLIBRI_EMG_BOARD = 10, + CALLIBRI_ECG_BOARD = 11, + FASCIA_BOARD = 12, + NOTION_1_BOARD = 13, + NOTION_2_BOARD = 14, + IRONBCI_BOARD = 15, + GFORCE_PRO_BOARD = 16, + FREEEEG32_BOARD = 17, + BRAINBIT_BLED_BOARD = 18, + GFORCE_DUAL_BOARD = 19, + GALEA_SERIAL_BOARD = 20, + MUSE_S_BLED_BOARD = 21, + MUSE_2_BLED_BOARD = 22, + CROWN_BOARD = 23, + ANT_NEURO_EE_410_BOARD = 24, + ANT_NEURO_EE_411_BOARD = 25, + ANT_NEURO_EE_430_BOARD = 26, + ANT_NEURO_EE_211_BOARD = 27, + ANT_NEURO_EE_212_BOARD = 28, + ANT_NEURO_EE_213_BOARD = 29, + ANT_NEURO_EE_214_BOARD = 30, + ANT_NEURO_EE_215_BOARD = 31, + ANT_NEURO_EE_221_BOARD = 32, + ANT_NEURO_EE_222_BOARD = 33, + ANT_NEURO_EE_223_BOARD = 34, + ANT_NEURO_EE_224_BOARD = 35, + ANT_NEURO_EE_225_BOARD = 36, + ENOPHONE_BOARD = 37, +} +#[repr(i32)] +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +pub enum IpProtocolType { + NONE = 0, + UDP = 1, + TCP = 2, +} +#[repr(i32)] +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +pub enum FilterTypes { + BUTTERWORTH = 0, + CHEBYSHEV_TYPE_1 = 1, + BESSEL = 2, +} +#[repr(i32)] +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +pub enum AggOperations { + MEAN = 0, + MEDIAN = 1, + EACH = 2, +} +#[repr(i32)] +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +pub enum WindowFunctions { + NO_WINDOW = 0, + HANNING = 1, + HAMMING = 2, + BLACKMAN_HARRIS = 3, +} +#[repr(i32)] +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +pub enum DetrendOperations { + NONE = 0, + CONSTANT = 1, + LINEAR = 2, +} +#[repr(i32)] +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +pub enum BrainFlowMetrics { + RELAXATION = 0, + CONCENTRATION = 1, +} +#[repr(i32)] +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +pub enum BrainFlowClassifiers { + REGRESSION = 0, + KNN = 1, + SVM = 2, + LDA = 3, +} +#[repr(i32)] +#[doc = " LogLevels enum to store all possible log levels"] +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +pub enum LogLevels { + LEVEL_TRACE = 0, + #[doc = " TRACE"] + LEVEL_DEBUG = 1, + #[doc = " DEBUG"] + LEVEL_INFO = 2, + #[doc = " INFO"] + LEVEL_WARN = 3, + #[doc = " WARN"] + LEVEL_ERROR = 4, + #[doc = " ERROR"] + LEVEL_CRITICAL = 5, + #[doc = " CRITICAL"] + LEVEL_OFF = 6, +} +#[repr(i32)] +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +pub enum NoiseTypes { + FIFTY = 0, + SIXTY = 1, +} +extern "C" { + pub fn get_board_descr( + board_id: ::std::os::raw::c_int, + board_descr: *mut ::std::os::raw::c_char, + len: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn get_sampling_rate( + board_id: ::std::os::raw::c_int, + sampling_rate: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn get_package_num_channel( + board_id: ::std::os::raw::c_int, + package_num_channel: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn get_timestamp_channel( + board_id: ::std::os::raw::c_int, + timestamp_channel: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn get_marker_channel( + board_id: ::std::os::raw::c_int, + marker_channel: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn get_battery_channel( + board_id: ::std::os::raw::c_int, + battery_channel: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn get_num_rows( + board_id: ::std::os::raw::c_int, + num_rows: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn get_eeg_names( + board_id: ::std::os::raw::c_int, + eeg_names: *mut ::std::os::raw::c_char, + len: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn get_exg_channels( + board_id: ::std::os::raw::c_int, + exg_channels: *mut ::std::os::raw::c_int, + len: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn get_eeg_channels( + board_id: ::std::os::raw::c_int, + eeg_channels: *mut ::std::os::raw::c_int, + len: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn get_emg_channels( + board_id: ::std::os::raw::c_int, + emg_channels: *mut ::std::os::raw::c_int, + len: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn get_ecg_channels( + board_id: ::std::os::raw::c_int, + ecg_channels: *mut ::std::os::raw::c_int, + len: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn get_eog_channels( + board_id: ::std::os::raw::c_int, + eog_channels: *mut ::std::os::raw::c_int, + len: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn get_ppg_channels( + board_id: ::std::os::raw::c_int, + ppg_channels: *mut ::std::os::raw::c_int, + len: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn get_eda_channels( + board_id: ::std::os::raw::c_int, + eda_channels: *mut ::std::os::raw::c_int, + len: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn get_accel_channels( + board_id: ::std::os::raw::c_int, + accel_channels: *mut ::std::os::raw::c_int, + len: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn get_analog_channels( + board_id: ::std::os::raw::c_int, + analog_channels: *mut ::std::os::raw::c_int, + len: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn get_gyro_channels( + board_id: ::std::os::raw::c_int, + gyro_channels: *mut ::std::os::raw::c_int, + len: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn get_other_channels( + board_id: ::std::os::raw::c_int, + other_channels: *mut ::std::os::raw::c_int, + len: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn get_temperature_channels( + board_id: ::std::os::raw::c_int, + temperature_channels: *mut ::std::os::raw::c_int, + len: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn get_resistance_channels( + board_id: ::std::os::raw::c_int, + resistance_channels: *mut ::std::os::raw::c_int, + len: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn get_device_name( + board_id: ::std::os::raw::c_int, + name: *mut ::std::os::raw::c_char, + len: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn prepare_session( + board_id: ::std::os::raw::c_int, + json_brainflow_input_params: *const ::std::os::raw::c_char, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn start_stream( + buffer_size: ::std::os::raw::c_int, + streamer_params: *const ::std::os::raw::c_char, + board_id: ::std::os::raw::c_int, + json_brainflow_input_params: *const ::std::os::raw::c_char, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn stop_stream( + board_id: ::std::os::raw::c_int, + json_brainflow_input_params: *const ::std::os::raw::c_char, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn release_session( + board_id: ::std::os::raw::c_int, + json_brainflow_input_params: *const ::std::os::raw::c_char, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn get_current_board_data( + num_samples: ::std::os::raw::c_int, + data_buf: *mut f64, + returned_samples: *mut ::std::os::raw::c_int, + board_id: ::std::os::raw::c_int, + json_brainflow_input_params: *const ::std::os::raw::c_char, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn get_board_data_count( + result: *mut ::std::os::raw::c_int, + board_id: ::std::os::raw::c_int, + json_brainflow_input_params: *const ::std::os::raw::c_char, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn get_board_data( + data_count: ::std::os::raw::c_int, + data_buf: *mut f64, + board_id: ::std::os::raw::c_int, + json_brainflow_input_params: *const ::std::os::raw::c_char, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn config_board( + config: *mut ::std::os::raw::c_char, + response: *mut ::std::os::raw::c_char, + response_len: *mut ::std::os::raw::c_int, + board_id: ::std::os::raw::c_int, + json_brainflow_input_params: *const ::std::os::raw::c_char, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn is_prepared( + prepared: *mut ::std::os::raw::c_int, + board_id: ::std::os::raw::c_int, + json_brainflow_input_params: *const ::std::os::raw::c_char, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn insert_marker( + marker_value: f64, + board_id: ::std::os::raw::c_int, + json_brainflow_input_params: *const ::std::os::raw::c_char, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn set_log_level(log_level: ::std::os::raw::c_int) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn set_log_file(log_file: *const ::std::os::raw::c_char) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn log_message( + log_level: ::std::os::raw::c_int, + message: *mut ::std::os::raw::c_char, + ) -> ::std::os::raw::c_int; +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct JNINativeInterface { + _unused: [u8; 0], +} +pub type JNIEnv = *const JNINativeInterface; +extern "C" { + pub fn java_set_jnienv(java_jnienv: *mut JNIEnv) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn perform_lowpass( + data: *mut f64, + data_len: ::std::os::raw::c_int, + sampling_rate: ::std::os::raw::c_int, + cutoff: f64, + order: ::std::os::raw::c_int, + filter_type: ::std::os::raw::c_int, + ripple: f64, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn perform_highpass( + data: *mut f64, + data_len: ::std::os::raw::c_int, + sampling_rate: ::std::os::raw::c_int, + cutoff: f64, + order: ::std::os::raw::c_int, + filter_type: ::std::os::raw::c_int, + ripple: f64, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn perform_bandpass( + data: *mut f64, + data_len: ::std::os::raw::c_int, + sampling_rate: ::std::os::raw::c_int, + center_freq: f64, + band_width: f64, + order: ::std::os::raw::c_int, + filter_type: ::std::os::raw::c_int, + ripple: f64, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn perform_bandstop( + data: *mut f64, + data_len: ::std::os::raw::c_int, + sampling_rate: ::std::os::raw::c_int, + center_freq: f64, + band_width: f64, + order: ::std::os::raw::c_int, + filter_type: ::std::os::raw::c_int, + ripple: f64, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn remove_environmental_noise( + data: *mut f64, + data_len: ::std::os::raw::c_int, + sampling_rate: ::std::os::raw::c_int, + noise_type: ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn perform_rolling_filter( + data: *mut f64, + data_len: ::std::os::raw::c_int, + period: ::std::os::raw::c_int, + agg_operation: ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn perform_downsampling( + data: *mut f64, + data_len: ::std::os::raw::c_int, + period: ::std::os::raw::c_int, + agg_operation: ::std::os::raw::c_int, + output_data: *mut f64, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn perform_wavelet_transform( + data: *mut f64, + data_len: ::std::os::raw::c_int, + wavelet: *const ::std::os::raw::c_char, + decomposition_level: ::std::os::raw::c_int, + output_data: *mut f64, + decomposition_lengths: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn perform_inverse_wavelet_transform( + wavelet_coeffs: *mut f64, + original_data_len: ::std::os::raw::c_int, + wavelet: *const ::std::os::raw::c_char, + decomposition_level: ::std::os::raw::c_int, + decomposition_lengths: *mut ::std::os::raw::c_int, + output_data: *mut f64, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn perform_wavelet_denoising( + data: *mut f64, + data_len: ::std::os::raw::c_int, + wavelet: *const ::std::os::raw::c_char, + decomposition_level: ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn get_csp( + data: *const f64, + labels: *const f64, + n_epochs: ::std::os::raw::c_int, + n_channels: ::std::os::raw::c_int, + n_times: ::std::os::raw::c_int, + output_w: *mut f64, + output_d: *mut f64, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn get_window( + window_function: ::std::os::raw::c_int, + window_len: ::std::os::raw::c_int, + output_window: *mut f64, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn perform_fft( + data: *mut f64, + data_len: ::std::os::raw::c_int, + window_function: ::std::os::raw::c_int, + output_re: *mut f64, + output_im: *mut f64, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn perform_ifft( + input_re: *mut f64, + input_im: *mut f64, + data_len: ::std::os::raw::c_int, + restored_data: *mut f64, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn get_nearest_power_of_two( + value: ::std::os::raw::c_int, + output: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn get_psd( + data: *mut f64, + data_len: ::std::os::raw::c_int, + sampling_rate: ::std::os::raw::c_int, + window_function: ::std::os::raw::c_int, + output_ampl: *mut f64, + output_freq: *mut f64, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn detrend( + data: *mut f64, + data_len: ::std::os::raw::c_int, + detrend_operation: ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn get_psd_welch( + data: *mut f64, + data_len: ::std::os::raw::c_int, + nfft: ::std::os::raw::c_int, + overlap: ::std::os::raw::c_int, + sampling_rate: ::std::os::raw::c_int, + window_function: ::std::os::raw::c_int, + output_ampl: *mut f64, + output_freq: *mut f64, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn get_band_power( + ampl: *mut f64, + freq: *mut f64, + data_len: ::std::os::raw::c_int, + freq_start: f64, + freq_end: f64, + band_power: *mut f64, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn get_avg_band_powers( + raw_data: *mut f64, + rows: ::std::os::raw::c_int, + cols: ::std::os::raw::c_int, + sampling_rate: ::std::os::raw::c_int, + apply_filters: ::std::os::raw::c_int, + avg_band_powers: *mut f64, + stddev_band_powers: *mut f64, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn write_file( + data: *const f64, + num_rows: ::std::os::raw::c_int, + num_cols: ::std::os::raw::c_int, + file_name: *const ::std::os::raw::c_char, + file_mode: *const ::std::os::raw::c_char, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn read_file( + data: *mut f64, + num_rows: *mut ::std::os::raw::c_int, + num_cols: *mut ::std::os::raw::c_int, + file_name: *const ::std::os::raw::c_char, + num_elements: ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn get_num_elements_in_file( + file_name: *const ::std::os::raw::c_char, + num_elements: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn prepare(json_params: *const ::std::os::raw::c_char) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn predict( + data: *mut f64, + data_len: ::std::os::raw::c_int, + output: *mut f64, + json_params: *const ::std::os::raw::c_char, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn release(json_params: *const ::std::os::raw::c_char) -> ::std::os::raw::c_int; } From d295605468d5ee15098026426aba709f5561530c Mon Sep 17 00:00:00 2001 From: Daniel Hahne Date: Thu, 23 Sep 2021 22:25:35 +0200 Subject: [PATCH 05/21] Add basic structure --- rust-package/brainflow/src/board_shim.rs | 3 +++ rust-package/brainflow/src/data_filter.rs | 1 + rust-package/brainflow/src/lib.rs | 12 +++++------- rust-package/brainflow/src/ml_model.rs | 1 + 4 files changed, 10 insertions(+), 7 deletions(-) create mode 100644 rust-package/brainflow/src/board_shim.rs create mode 100644 rust-package/brainflow/src/data_filter.rs create mode 100644 rust-package/brainflow/src/ml_model.rs diff --git a/rust-package/brainflow/src/board_shim.rs b/rust-package/brainflow/src/board_shim.rs new file mode 100644 index 000000000..2dfdf6dc6 --- /dev/null +++ b/rust-package/brainflow/src/board_shim.rs @@ -0,0 +1,3 @@ +use crate::ffi; + +pub struct BoardShim {} diff --git a/rust-package/brainflow/src/data_filter.rs b/rust-package/brainflow/src/data_filter.rs new file mode 100644 index 000000000..60dfb90f9 --- /dev/null +++ b/rust-package/brainflow/src/data_filter.rs @@ -0,0 +1 @@ +use crate::ffi; diff --git a/rust-package/brainflow/src/lib.rs b/rust-package/brainflow/src/lib.rs index 31e1bb209..a0f821bc7 100644 --- a/rust-package/brainflow/src/lib.rs +++ b/rust-package/brainflow/src/lib.rs @@ -1,7 +1,5 @@ -#[cfg(test)] -mod tests { - #[test] - fn it_works() { - assert_eq!(2 + 2, 4); - } -} +use brainflow_sys::root as ffi; + +mod board_shim; +mod data_filter; +mod ml_model; diff --git a/rust-package/brainflow/src/ml_model.rs b/rust-package/brainflow/src/ml_model.rs new file mode 100644 index 000000000..60dfb90f9 --- /dev/null +++ b/rust-package/brainflow/src/ml_model.rs @@ -0,0 +1 @@ +use crate::ffi; From 95a3cb92bd3feba1219a7851829ce607083a7820 Mon Sep 17 00:00:00 2001 From: Daniel Hahne Date: Sat, 25 Sep 2021 22:48:11 +0200 Subject: [PATCH 06/21] Begin with BoardShim --- rust-package/brainflow/Cargo.toml | 3 + rust-package/brainflow/README.md | 2 + rust-package/brainflow/src/board_shim.rs | 73 ++++++++++++++- .../brainflow/src/brainflow_input_params.rs | 14 +++ rust-package/brainflow/src/error.rs | 89 +++++++++++++++++++ rust-package/brainflow/src/lib.rs | 50 ++++++++++- 6 files changed, 225 insertions(+), 6 deletions(-) create mode 100644 rust-package/brainflow/README.md create mode 100644 rust-package/brainflow/src/brainflow_input_params.rs create mode 100644 rust-package/brainflow/src/error.rs diff --git a/rust-package/brainflow/Cargo.toml b/rust-package/brainflow/Cargo.toml index 20d7fcf34..8415b58e2 100644 --- a/rust-package/brainflow/Cargo.toml +++ b/rust-package/brainflow/Cargo.toml @@ -7,3 +7,6 @@ edition = "2018" [dependencies] brainflow-sys = { path = "../brainflow-sys" } +serde = { version ="1.0.130", features=["derive"] } +serde_json = "1.0.68" +thiserror = "1.0.29" diff --git a/rust-package/brainflow/README.md b/rust-package/brainflow/README.md new file mode 100644 index 000000000..c0c35553d --- /dev/null +++ b/rust-package/brainflow/README.md @@ -0,0 +1,2 @@ +# About +`brainflow` is a Rust interface to https://brainflow.readthedocs.io . diff --git a/rust-package/brainflow/src/board_shim.rs b/rust-package/brainflow/src/board_shim.rs index 2dfdf6dc6..3f31a381b 100644 --- a/rust-package/brainflow/src/board_shim.rs +++ b/rust-package/brainflow/src/board_shim.rs @@ -1,3 +1,72 @@ -use crate::ffi; +use std::{ffi::CString, os::raw::c_int}; -pub struct BoardShim {} +use crate::{brainflow_input_params::BrainFlowInputParams, check_brainflow_exit_code, ffi, Result}; + +pub struct BoardShim { + board_id: ffi::BoardIds, + input_params: BrainFlowInputParams, + json_input_params: CString, +} + +impl BoardShim { + pub fn new(board_id: ffi::BoardIds, input_params: BrainFlowInputParams) -> Result { + let json_input_params = serde_json::to_string(&input_params)?; + let json_input_params = CString::new(json_input_params)?; + Ok(Self { + board_id, + input_params, + json_input_params, + }) + } + + pub fn prepare_session(&self) -> Result<()> { + let res = unsafe { + ffi::prepare_session(self.board_id as c_int, self.json_input_params.as_ptr()) + }; + Ok(check_brainflow_exit_code(res)?) + } + + pub fn is_prepared(&self) -> Result { + let prepared: c_int = 0; + let res = unsafe { + ffi::is_prepared( + prepared as *mut c_int, + self.board_id as c_int, + self.json_input_params.as_ptr(), + ) + }; + check_brainflow_exit_code(res)?; + Ok(prepared > 0) + } +} + +pub fn set_log_level(log_level: ffi::LogLevels) -> Result<()> { + let res = unsafe { ffi::set_log_level(log_level as c_int) }; + Ok(check_brainflow_exit_code(res)?) +} + +pub fn enable_board_logger() -> Result<()> { + set_log_level(ffi::LogLevels::LEVEL_INFO) +} + +pub fn disable_board_logger() -> Result<()> { + set_log_level(ffi::LogLevels::LEVEL_OFF) +} + +pub fn enable_dev_board_logger() -> Result<()> { + set_log_level(ffi::LogLevels::LEVEL_TRACE) +} + +pub fn set_log_file>(log_file: S) -> Result<()> { + let log_file = log_file.as_ref(); + let log_file = CString::new(log_file)?; + let res = unsafe { ffi::set_log_file(log_file.as_ptr()) }; + Ok(check_brainflow_exit_code(res)?) +} + +pub fn log_message>(log_level: ffi::LogLevels, message: S) -> Result<()> { + let message = message.as_ref(); + let message = CString::new(message)?; + let res = unsafe { ffi::log_message(log_level as c_int, message.into_raw()) }; + Ok(check_brainflow_exit_code(res)?) +} diff --git a/rust-package/brainflow/src/brainflow_input_params.rs b/rust-package/brainflow/src/brainflow_input_params.rs new file mode 100644 index 000000000..3acc09c7c --- /dev/null +++ b/rust-package/brainflow/src/brainflow_input_params.rs @@ -0,0 +1,14 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Default, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)] +pub struct BrainFlowInputParams { + serial_port: String, + mac_address: String, + ip_address: String, + ip_port: usize, + ip_protocol: i32, + other_info: String, + timeout: usize, + serial_number: String, + file: String, +} diff --git a/rust-package/brainflow/src/error.rs b/rust-package/brainflow/src/error.rs new file mode 100644 index 000000000..d2a621f4b --- /dev/null +++ b/rust-package/brainflow/src/error.rs @@ -0,0 +1,89 @@ +use thiserror::Error; + +#[derive(Debug, Error)] +pub enum Error { + #[error("{0}")] + BrainFlowError(#[from] BrainFlowError), + + #[error("Interior nul byte found")] + NulError(#[from] std::ffi::NulError), + + /// Some JSON error + #[error("JSON error")] + JsonError(#[from] serde_json::Error), +} + +#[derive(Debug, Error)] +pub enum BrainFlowError { + #[error("")] + PortAlreadyOpenError, + + #[error("")] + UnableToOpenPortError, + + #[error("")] + SetPortError, + + #[error("")] + BoardWriteError, + + #[error("")] + IncommingMsgError, + + #[error("")] + InitialMsgError, + + #[error("")] + BoardNotReadyError, + + #[error("")] + StreamAlreadyRunError, + + #[error("")] + InvalidBufferSizeError, + + #[error("")] + StreamThreadError, + + #[error("")] + StreamThreadIsNotRunning, + + #[error("")] + EmptyBufferError, + + #[error("")] + InvalidArgumentsError, + + #[error("")] + UnsupportedBoardError, + + #[error("")] + BoardNotCreatedError, + + #[error("")] + AnotherBoardIsCreatedError, + + #[error("")] + GeneralError, + + #[error("")] + SyncTimeoutError, + + #[error("")] + JsonNotFoundError, + + #[error("")] + NoSuchDataInJsonError, + + #[error("")] + ClassifierIsNotPreparedError, + + #[error("")] + AnotherClassifierIsPreparedError, + + #[error("")] + UnsupportedClassifierAndMetricCombinationError, + + #[error("This error code is not (yet) supported by this Rust binding")] + ErrorIsNotSupportedInRustError, +} diff --git a/rust-package/brainflow/src/lib.rs b/rust-package/brainflow/src/lib.rs index a0f821bc7..7167fd9c4 100644 --- a/rust-package/brainflow/src/lib.rs +++ b/rust-package/brainflow/src/lib.rs @@ -1,5 +1,47 @@ -use brainflow_sys::root as ffi; +use brainflow_sys as ffi; +use error::{BrainFlowError, Error}; -mod board_shim; -mod data_filter; -mod ml_model; +pub mod board_shim; +pub mod brainflow_input_params; +pub mod data_filter; +mod error; +pub mod ml_model; + +type BrainFlowExitCode = i32; + +pub fn check_brainflow_exit_code( + value: BrainFlowExitCode, +) -> std::result::Result<(), BrainFlowError> { + if value == 0 { + Ok(()) + } else { + Err(match value { + 1 => BrainFlowError::PortAlreadyOpenError, + 2 => BrainFlowError::UnableToOpenPortError, + 3 => BrainFlowError::SetPortError, + 4 => BrainFlowError::BoardWriteError, + 5 => BrainFlowError::IncommingMsgError, + 6 => BrainFlowError::InitialMsgError, + 7 => BrainFlowError::BoardNotReadyError, + 8 => BrainFlowError::StreamAlreadyRunError, + 9 => BrainFlowError::InvalidBufferSizeError, + 10 => BrainFlowError::StreamThreadError, + 11 => BrainFlowError::StreamThreadIsNotRunning, + 12 => BrainFlowError::EmptyBufferError, + 13 => BrainFlowError::InvalidArgumentsError, + 14 => BrainFlowError::UnsupportedBoardError, + 15 => BrainFlowError::BoardNotCreatedError, + 16 => BrainFlowError::AnotherBoardIsCreatedError, + 17 => BrainFlowError::GeneralError, + 18 => BrainFlowError::SyncTimeoutError, + 19 => BrainFlowError::JsonNotFoundError, + 20 => BrainFlowError::NoSuchDataInJsonError, + 21 => BrainFlowError::ClassifierIsNotPreparedError, + 22 => BrainFlowError::AnotherClassifierIsPreparedError, + 23 => BrainFlowError::UnsupportedClassifierAndMetricCombinationError, + _ => BrainFlowError::ErrorIsNotSupportedInRustError, + }) + } +} + +type Result = std::result::Result; From b4c06f810cebe99aff308bcbf579d2fb3439b342 Mon Sep 17 00:00:00 2001 From: Daniel Hahne Date: Sun, 26 Sep 2021 11:02:56 +0200 Subject: [PATCH 07/21] Finish impl BoardShim non-static functions, start with example --- rust-package/brainflow/Cargo.toml | 4 + rust-package/brainflow/examples/cyton.rs | 16 ++ rust-package/brainflow/src/board_id.rs | 44 ++++ rust-package/brainflow/src/board_shim.rs | 211 ++++++++++++++++-- .../brainflow/src/brainflow_input_params.rs | 64 +++++- rust-package/brainflow/src/error.rs | 5 + rust-package/brainflow/src/lib.rs | 9 + 7 files changed, 335 insertions(+), 18 deletions(-) create mode 100644 rust-package/brainflow/examples/cyton.rs create mode 100644 rust-package/brainflow/src/board_id.rs diff --git a/rust-package/brainflow/Cargo.toml b/rust-package/brainflow/Cargo.toml index 8415b58e2..a2a3da4e5 100644 --- a/rust-package/brainflow/Cargo.toml +++ b/rust-package/brainflow/Cargo.toml @@ -7,6 +7,10 @@ edition = "2018" [dependencies] brainflow-sys = { path = "../brainflow-sys" } +getset = "0.1.1" +num = "0.4.0" +num-derive = "0.3.3" +num-traits = "0.2.14" serde = { version ="1.0.130", features=["derive"] } serde_json = "1.0.68" thiserror = "1.0.29" diff --git a/rust-package/brainflow/examples/cyton.rs b/rust-package/brainflow/examples/cyton.rs new file mode 100644 index 000000000..e233c09b7 --- /dev/null +++ b/rust-package/brainflow/examples/cyton.rs @@ -0,0 +1,16 @@ +use brainflow::board_shim::BoardShim; +use brainflow::brainflow_input_params::BrainFlowInputParamsBuilder; +use brainflow::BoardId; + +fn main() { + let params = BrainFlowInputParamsBuilder::default() + .serial_port("/dev/ttyUSB0") + .build(); + let board = BoardShim::new(BoardId::CytonBoard, params).unwrap(); + + dbg!("board instantiated"); + + board.prepare_session().unwrap(); + + dbg!(board.is_prepared().unwrap()); +} diff --git a/rust-package/brainflow/src/board_id.rs b/rust-package/brainflow/src/board_id.rs new file mode 100644 index 000000000..a0e5d54f6 --- /dev/null +++ b/rust-package/brainflow/src/board_id.rs @@ -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, +} diff --git a/rust-package/brainflow/src/board_shim.rs b/rust-package/brainflow/src/board_shim.rs index 3f31a381b..8f09e9b51 100644 --- a/rust-package/brainflow/src/board_shim.rs +++ b/rust-package/brainflow/src/board_shim.rs @@ -1,60 +1,222 @@ -use std::{ffi::CString, os::raw::c_int}; +use std::{ + ffi::CString, + os::raw::{c_double, c_int}, +}; -use crate::{brainflow_input_params::BrainFlowInputParams, check_brainflow_exit_code, ffi, Result}; +use ffi::LogLevels; + +use crate::{ + brainflow_input_params::BrainFlowInputParams, + check_brainflow_exit_code, + error::{BrainFlowError, Error}, + ffi, BoardId, Result, +}; pub struct BoardShim { - board_id: ffi::BoardIds, + board_id: BoardId, input_params: BrainFlowInputParams, - json_input_params: CString, + json_brainflow_input_params: CString, + num_rows: usize, } impl BoardShim { - pub fn new(board_id: ffi::BoardIds, input_params: BrainFlowInputParams) -> Result { + pub fn new(board_id: BoardId, input_params: BrainFlowInputParams) -> Result { + dbg!(&input_params); let json_input_params = serde_json::to_string(&input_params)?; let json_input_params = CString::new(json_input_params)?; + let num_rows = num_rows(board_id)?; Ok(Self { board_id, input_params, - json_input_params, + json_brainflow_input_params: json_input_params, + num_rows, }) } pub fn prepare_session(&self) -> Result<()> { let res = unsafe { - ffi::prepare_session(self.board_id as c_int, self.json_input_params.as_ptr()) + ffi::prepare_session( + self.board_id as c_int, + self.json_brainflow_input_params.as_ptr(), + ) }; Ok(check_brainflow_exit_code(res)?) } pub fn is_prepared(&self) -> Result { - let prepared: c_int = 0; + let mut prepared = 0; let res = unsafe { ffi::is_prepared( - prepared as *mut c_int, + &mut prepared, self.board_id as c_int, - self.json_input_params.as_ptr(), + self.json_brainflow_input_params.as_ptr(), ) }; check_brainflow_exit_code(res)?; Ok(prepared > 0) } + + pub fn start_stream>( + &self, + buffer_size: usize, + streamer_params: S, + ) -> Result<()> { + let streamer_params = CString::new(streamer_params.as_ref())?; + let res = unsafe { + ffi::start_stream( + buffer_size as c_int, + streamer_params.as_ptr(), + self.board_id as c_int, + self.json_brainflow_input_params.as_ptr(), + ) + }; + Ok(check_brainflow_exit_code(res)?) + } + + pub fn stop_stream(&self) -> Result<()> { + let res = unsafe { + ffi::stop_stream( + self.board_id as c_int, + self.json_brainflow_input_params.as_ptr(), + ) + }; + Ok(check_brainflow_exit_code(res)?) + } + + pub fn release_session(&self) -> Result<()> { + let res = unsafe { + ffi::release_session( + self.board_id as c_int, + self.json_brainflow_input_params.as_ptr(), + ) + }; + Ok(check_brainflow_exit_code(res)?) + } + + pub fn board_data_count(&self) -> Result { + let mut data_count = 0; + let res = unsafe { + ffi::get_board_data_count( + &mut data_count, + self.board_id as c_int, + self.json_brainflow_input_params.as_ptr(), + ) + }; + check_brainflow_exit_code(res)?; + Ok(data_count as usize) + } + + pub fn get_board_data_count(&self) -> Result { + self.board_data_count() + } + + pub fn board_data(&self, n_data_points: Option) -> Result>> { + let num_samples = if let Some(n) = n_data_points { + self.board_data_count()?.min(n) + } else { + self.board_data_count()? + }; + let mut data_buf = Vec::with_capacity(num_samples * self.num_rows); + let res = unsafe { + ffi::get_board_data( + num_samples as c_int, + data_buf.as_mut_ptr(), + self.board_id as c_int, + self.json_brainflow_input_params.as_ptr(), + ) + }; + check_brainflow_exit_code(res)?; + + let data_buf = data_buf.chunks(self.num_rows).map(|d| d.to_vec()).collect(); + Ok(data_buf) + } + + pub fn get_board_data(&self, n_data_points: Option) -> Result>> { + self.board_data(n_data_points) + } + + pub fn current_board_data(&self, num_samples: usize) -> Result>> { + let mut data_buf = Vec::with_capacity(num_samples * self.num_rows); + let mut len = 0; + let res = unsafe { + ffi::get_current_board_data( + num_samples as c_int, + data_buf.as_mut_ptr(), + &mut len, + self.board_id as c_int, + self.json_brainflow_input_params.as_ptr(), + ) + }; + check_brainflow_exit_code(res)?; + + let data_buf = data_buf.chunks(self.num_rows).map(|d| d.to_vec()).collect(); + Ok(data_buf) + } + + pub fn get_current_board_data(&self, num_samples: usize) -> Result>> { + self.current_board_data(num_samples) + } + + pub fn config_board>(&self, config: S) -> Result { + let config = CString::new(config.as_ref())?; + let mut response_len = 0; + let response = CString::new(Vec::with_capacity(8192))?; + let response = response.into_raw(); + let config = config.into_raw(); + let (res, response) = unsafe { + let res = ffi::config_board( + config, + response, + &mut response_len, + self.board_id as c_int, + self.json_brainflow_input_params.as_ptr(), + ); + let _ = CString::from_raw(config); + let response = CString::from_raw(response); + (res, response) + }; + check_brainflow_exit_code(res)?; + Ok(response.to_str()?.to_string()) + } + + pub fn insert_marker(&self, value: f64) -> Result<()> { + let res = unsafe { + ffi::insert_marker( + value as c_double, + self.board_id as c_int, + self.json_brainflow_input_params.as_ptr(), + ) + }; + Ok(check_brainflow_exit_code(res)?) + } + + pub fn board_id(&self) -> Result { + Ok(match &self.board_id { + BoardId::StreamingBoard | BoardId::PlaybackFileBoard => { + let id = self.input_params.other_info().parse::().unwrap(); + num::FromPrimitive::from_i32(id) + .ok_or(Error::BrainFlowError(BrainFlowError::InvalidArgumentsError))? + } + _ => self.board_id, + }) + } } -pub fn set_log_level(log_level: ffi::LogLevels) -> Result<()> { +pub fn set_log_level(log_level: LogLevels) -> Result<()> { let res = unsafe { ffi::set_log_level(log_level as c_int) }; Ok(check_brainflow_exit_code(res)?) } pub fn enable_board_logger() -> Result<()> { - set_log_level(ffi::LogLevels::LEVEL_INFO) + set_log_level(LogLevels::LEVEL_INFO) } pub fn disable_board_logger() -> Result<()> { - set_log_level(ffi::LogLevels::LEVEL_OFF) + set_log_level(LogLevels::LEVEL_OFF) } pub fn enable_dev_board_logger() -> Result<()> { - set_log_level(ffi::LogLevels::LEVEL_TRACE) + set_log_level(LogLevels::LEVEL_TRACE) } pub fn set_log_file>(log_file: S) -> Result<()> { @@ -64,9 +226,24 @@ pub fn set_log_file>(log_file: S) -> Result<()> { Ok(check_brainflow_exit_code(res)?) } -pub fn log_message>(log_level: ffi::LogLevels, message: S) -> Result<()> { +pub fn log_message>(log_level: LogLevels, message: S) -> Result<()> { let message = message.as_ref(); - let message = CString::new(message)?; - let res = unsafe { ffi::log_message(log_level as c_int, message.into_raw()) }; + let message = CString::new(message)?.into_raw(); + let res = unsafe { + let res = ffi::log_message(log_level as c_int, message); + let _ = CString::from_raw(message); + res + }; Ok(check_brainflow_exit_code(res)?) } + +pub fn num_rows(board_id: BoardId) -> Result { + let mut num_rows: i32 = 0; + let res = unsafe { ffi::get_num_rows(board_id as c_int, &mut num_rows) }; + check_brainflow_exit_code(res)?; + Ok(num_rows as usize) +} + +pub fn get_num_rows(board_id: BoardId) -> Result { + num_rows(board_id) +} diff --git a/rust-package/brainflow/src/brainflow_input_params.rs b/rust-package/brainflow/src/brainflow_input_params.rs index 3acc09c7c..b5a48548c 100644 --- a/rust-package/brainflow/src/brainflow_input_params.rs +++ b/rust-package/brainflow/src/brainflow_input_params.rs @@ -1,6 +1,8 @@ +use getset::Getters; use serde::{Deserialize, Serialize}; -#[derive(Debug, Default, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)] +#[derive(Debug, Default, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, Getters)] +#[getset(get = "pub", set = "pub")] pub struct BrainFlowInputParams { serial_port: String, mac_address: String, @@ -12,3 +14,63 @@ pub struct BrainFlowInputParams { serial_number: String, file: String, } + +#[derive(Default)] +pub struct BrainFlowInputParamsBuilder { + params: BrainFlowInputParams, +} + +impl BrainFlowInputParamsBuilder { + pub fn new() -> Self { + Default::default() + } + + pub fn serial_port>(mut self, port: S) -> Self { + self.params.serial_port = port.as_ref().to_string(); + self + } + + pub fn mac_address>(mut self, address: S) -> Self { + self.params.mac_address = address.as_ref().to_string(); + self + } + + pub fn ip_address>(mut self, address: S) -> Self { + self.params.ip_address = address.as_ref().to_string(); + self + } + + pub fn ip_port(mut self, port: usize) -> Self { + self.params.ip_port = port; + self + } + + pub fn ip_protocol(mut self, protocol: i32) -> Self { + self.params.ip_protocol = protocol; + self + } + + pub fn other_info>(mut self, info: S) -> Self { + self.params.other_info = info.as_ref().to_string(); + self + } + + pub fn timeout(mut self, timeout: usize) -> Self { + self.params.timeout = timeout; + self + } + + pub fn serial_number>(mut self, serial: S) -> Self { + self.params.serial_number = serial.as_ref().to_string(); + self + } + + pub fn file>(mut self, filename: S) -> Self { + self.params.file = filename.as_ref().to_string(); + self + } + + pub fn build(self) -> BrainFlowInputParams { + self.params + } +} diff --git a/rust-package/brainflow/src/error.rs b/rust-package/brainflow/src/error.rs index d2a621f4b..b999efa19 100644 --- a/rust-package/brainflow/src/error.rs +++ b/rust-package/brainflow/src/error.rs @@ -1,3 +1,5 @@ +use std::str::Utf8Error; + use thiserror::Error; #[derive(Debug, Error)] @@ -11,6 +13,9 @@ pub enum Error { /// Some JSON error #[error("JSON error")] JsonError(#[from] serde_json::Error), + + #[error("Cannot convert from Utf8")] + Utf8Error(#[from] Utf8Error), } #[derive(Debug, Error)] diff --git a/rust-package/brainflow/src/lib.rs b/rust-package/brainflow/src/lib.rs index 7167fd9c4..439266817 100644 --- a/rust-package/brainflow/src/lib.rs +++ b/rust-package/brainflow/src/lib.rs @@ -1,12 +1,21 @@ +extern crate num; +#[macro_use] +extern crate num_derive; + use brainflow_sys as ffi; use error::{BrainFlowError, Error}; +mod board_id; pub mod board_shim; pub mod brainflow_input_params; pub mod data_filter; mod error; pub mod ml_model; +pub use board_id::BoardId; + +use ffi::LogLevels; + type BrainFlowExitCode = i32; pub fn check_brainflow_exit_code( From 1bb84fd2ce91cd84194782ee500d505ae01e5a23 Mon Sep 17 00:00:00 2001 From: Daniel Hahne Date: Sun, 26 Sep 2021 22:21:27 +0200 Subject: [PATCH 08/21] *Finish* BoardShim, start with DataFilter --- rust-package/brainflow/Cargo.toml | 1 + rust-package/brainflow/examples/cyton.rs | 3 + rust-package/brainflow/src/board_shim.rs | 146 +++++++++++++-- rust-package/brainflow/src/data_filter.rs | 211 +++++++++++++++++++++- rust-package/brainflow/src/lib.rs | 2 - 5 files changed, 346 insertions(+), 17 deletions(-) diff --git a/rust-package/brainflow/Cargo.toml b/rust-package/brainflow/Cargo.toml index a2a3da4e5..80dc0a737 100644 --- a/rust-package/brainflow/Cargo.toml +++ b/rust-package/brainflow/Cargo.toml @@ -11,6 +11,7 @@ getset = "0.1.1" num = "0.4.0" num-derive = "0.3.3" num-traits = "0.2.14" +paste = "1.0.5" serde = { version ="1.0.130", features=["derive"] } serde_json = "1.0.68" thiserror = "1.0.29" diff --git a/rust-package/brainflow/examples/cyton.rs b/rust-package/brainflow/examples/cyton.rs index e233c09b7..1fcade165 100644 --- a/rust-package/brainflow/examples/cyton.rs +++ b/rust-package/brainflow/examples/cyton.rs @@ -12,5 +12,8 @@ fn main() { board.prepare_session().unwrap(); + dbg!(brainflow::board_shim::eeg_names(BoardId::CytonBoard).unwrap()); + dbg!(brainflow::board_shim::eeg_channels(BoardId::CytonBoard).unwrap()); + dbg!(board.is_prepared().unwrap()); } diff --git a/rust-package/brainflow/src/board_shim.rs b/rust-package/brainflow/src/board_shim.rs index 8f09e9b51..3ee41f6f4 100644 --- a/rust-package/brainflow/src/board_shim.rs +++ b/rust-package/brainflow/src/board_shim.rs @@ -1,3 +1,4 @@ +use paste::paste; use std::{ ffi::CString, os::raw::{c_double, c_int}, @@ -12,11 +13,12 @@ use crate::{ ffi, BoardId, Result, }; +const MAX_CHANNELS: usize = 512; + pub struct BoardShim { board_id: BoardId, input_params: BrainFlowInputParams, json_brainflow_input_params: CString, - num_rows: usize, } impl BoardShim { @@ -24,12 +26,10 @@ impl BoardShim { dbg!(&input_params); let json_input_params = serde_json::to_string(&input_params)?; let json_input_params = CString::new(json_input_params)?; - let num_rows = num_rows(board_id)?; Ok(Self { board_id, input_params, json_brainflow_input_params: json_input_params, - num_rows, }) } @@ -111,12 +111,13 @@ impl BoardShim { } pub fn board_data(&self, n_data_points: Option) -> Result>> { + let num_rows = num_rows(self.board_id)?; let num_samples = if let Some(n) = n_data_points { self.board_data_count()?.min(n) } else { self.board_data_count()? }; - let mut data_buf = Vec::with_capacity(num_samples * self.num_rows); + let mut data_buf = Vec::with_capacity(num_samples * num_rows); let res = unsafe { ffi::get_board_data( num_samples as c_int, @@ -127,7 +128,7 @@ impl BoardShim { }; check_brainflow_exit_code(res)?; - let data_buf = data_buf.chunks(self.num_rows).map(|d| d.to_vec()).collect(); + let data_buf = data_buf.chunks(num_samples).map(|d| d.to_vec()).collect(); Ok(data_buf) } @@ -136,7 +137,8 @@ impl BoardShim { } pub fn current_board_data(&self, num_samples: usize) -> Result>> { - let mut data_buf = Vec::with_capacity(num_samples * self.num_rows); + let num_rows = num_rows(self.board_id)?; + let mut data_buf = Vec::with_capacity(num_samples * num_rows); let mut len = 0; let res = unsafe { ffi::get_current_board_data( @@ -149,7 +151,7 @@ impl BoardShim { }; check_brainflow_exit_code(res)?; - let data_buf = data_buf.chunks(self.num_rows).map(|d| d.to_vec()).collect(); + let data_buf = data_buf.chunks(num_samples).map(|d| d.to_vec()).collect(); Ok(data_buf) } @@ -176,7 +178,11 @@ impl BoardShim { (res, response) }; check_brainflow_exit_code(res)?; - Ok(response.to_str()?.to_string()) + Ok(response + .to_str()? + .split_at(response_len as usize) + .0 + .to_string()) } pub fn insert_marker(&self, value: f64) -> Result<()> { @@ -237,13 +243,125 @@ pub fn log_message>(log_level: LogLevels, message: S) -> Result<() Ok(check_brainflow_exit_code(res)?) } -pub fn num_rows(board_id: BoardId) -> Result { - let mut num_rows: i32 = 0; - let res = unsafe { ffi::get_num_rows(board_id as c_int, &mut num_rows) }; +pub fn board_descr(board_id: BoardId) -> Result { + let mut response_len = 0; + let response = CString::new(Vec::with_capacity(16000))?; + let response = response.into_raw(); + let (res, response) = unsafe { + let res = ffi::get_board_descr(board_id as c_int, response, &mut response_len); + let response = CString::from_raw(response); + (res, response) + }; check_brainflow_exit_code(res)?; - Ok(num_rows as usize) + Ok(response + .to_str()? + .split_at(response_len as usize) + .0 + .to_string()) +} + +pub fn get_board_descr(board_id: BoardId) -> Result { + board_descr(board_id) +} + +macro_rules! gen_fn { + ($fn_name:ident, $return_type:ident, $initial_value:literal) => { + paste! { + pub fn $fn_name(board_id: BoardId) -> Result<$return_type> { + let mut value = $initial_value; + let res = unsafe { ffi::[](board_id as c_int, &mut value) }; + check_brainflow_exit_code(res)?; + Ok(value as $return_type) + } + + pub fn [](board_id: BoardId) -> Result<$return_type> { + $fn_name(board_id) + } + } + }; } -pub fn get_num_rows(board_id: BoardId) -> Result { - num_rows(board_id) +gen_fn!(sampling_rate, isize, -1); +gen_fn!(package_num_channel, isize, -1); +gen_fn!(timestamp_channel, isize, 0); +gen_fn!(marker_channel, isize, 0); +gen_fn!(battery_channel, isize, 0); +gen_fn!(num_rows, usize, 0); + +pub fn eeg_names(board_id: BoardId) -> Result> { + let mut response_len = 0; + let response = CString::new(Vec::with_capacity(16000))?; + let response = response.into_raw(); + let (res, response) = unsafe { + let res = ffi::get_eeg_names(board_id as c_int, response, &mut response_len); + let response = CString::from_raw(response); + (res, response) + }; + check_brainflow_exit_code(res)?; + let names = response.to_str()?.split_at(response_len as usize).0; + + Ok(names + .split(',') + .map(|s| s.to_string()) + .collect::>()) } + +pub fn get_eeg_names(board_id: BoardId) -> Result> { + eeg_names(board_id) +} + +pub fn device_name(board_id: BoardId) -> Result { + let mut response_len = 0; + let response = CString::new(Vec::with_capacity(4096))?; + let response = response.into_raw(); + let (res, response) = unsafe { + let res = ffi::get_device_name(board_id as c_int, response, &mut response_len); + let response = CString::from_raw(response); + (res, response) + }; + check_brainflow_exit_code(res)?; + Ok(response + .to_str()? + .split_at(response_len as usize) + .0 + .to_string()) +} + +macro_rules! gen_vec_fn { + ($fn_name:ident) => { + paste! { + pub fn $fn_name(board_id: BoardId) -> Result> { + let mut channels: Vec = Vec::with_capacity(MAX_CHANNELS); + let mut len = 0; + let res = unsafe { + ffi::[]( + board_id as c_int, + channels.as_mut_ptr() as *mut c_int, + &mut len, + ) + }; + check_brainflow_exit_code(res)?; + channels.resize(len as usize, 0); + Ok(channels) + } + + pub fn [](board_id: BoardId) -> Result> { + $fn_name(board_id) + } + } + }; +} + +gen_vec_fn!(eeg_channels); +gen_vec_fn!(exg_channels); +gen_vec_fn!(emg_channels); +gen_vec_fn!(ecg_channels); +gen_vec_fn!(eog_channels); +gen_vec_fn!(eda_channels); +gen_vec_fn!(ppg_channels); +gen_vec_fn!(accel_channels); +gen_vec_fn!(gyro_channels); +gen_vec_fn!(analog_channels); +gen_vec_fn!(other_channels); +gen_vec_fn!(temperature_channels); +gen_vec_fn!(resistance_channels); diff --git a/rust-package/brainflow/src/data_filter.rs b/rust-package/brainflow/src/data_filter.rs index 60dfb90f9..a7ad3b81b 100644 --- a/rust-package/brainflow/src/data_filter.rs +++ b/rust-package/brainflow/src/data_filter.rs @@ -1 +1,210 @@ -use crate::ffi; +use std::os::raw::c_int; +use std::{ffi::CString, os::raw::c_double}; + +use ffi::{AggOperations, FilterTypes, LogLevels, NoiseTypes}; + +use crate::error::{BrainFlowError, Error}; +use crate::{check_brainflow_exit_code, ffi, Result}; + +pub fn set_log_level(log_level: LogLevels) -> Result<()> { + let res = unsafe { ffi::set_log_level(log_level as c_int) }; + Ok(check_brainflow_exit_code(res)?) +} + +pub fn enable_data_logger() -> Result<()> { + set_log_level(LogLevels::LEVEL_INFO) +} + +pub fn disable_board_logger() -> Result<()> { + set_log_level(LogLevels::LEVEL_OFF) +} + +pub fn enable_dev_board_logger() -> Result<()> { + set_log_level(LogLevels::LEVEL_TRACE) +} + +pub fn set_log_file>(log_file: S) -> Result<()> { + let log_file = log_file.as_ref(); + let log_file = CString::new(log_file)?; + let res = unsafe { ffi::set_log_file(log_file.as_ptr()) }; + Ok(check_brainflow_exit_code(res)?) +} + +pub fn log_message>(log_level: LogLevels, message: S) -> Result<()> { + let message = message.as_ref(); + let message = CString::new(message)?.into_raw(); + let res = unsafe { + let res = ffi::log_message(log_level as c_int, message); + let _ = CString::from_raw(message); + res + }; + Ok(check_brainflow_exit_code(res)?) +} + +pub fn perform_lowpass( + mut data: Vec, + sampling_rate: usize, + cutoff: f64, + order: usize, + filter_type: FilterTypes, + ripple: f64, +) -> Result<()> { + let res = unsafe { + ffi::perform_lowpass( + data.as_mut_ptr() as *mut c_double, + data.len() as c_int, + sampling_rate as c_int, + cutoff as c_double, + order as c_int, + filter_type as c_int, + ripple as c_double, + ) + }; + Ok(check_brainflow_exit_code(res)?) +} + +pub fn perform_highpass( + mut data: Vec, + sampling_rate: usize, + cutoff: f64, + order: usize, + filter_type: FilterTypes, + ripple: f64, +) -> Result<()> { + let res = unsafe { + ffi::perform_highpass( + data.as_mut_ptr() as *mut c_double, + data.len() as c_int, + sampling_rate as c_int, + cutoff as c_double, + order as c_int, + filter_type as c_int, + ripple as c_double, + ) + }; + Ok(check_brainflow_exit_code(res)?) +} + +pub fn perform_bandpass( + mut data: Vec, + sampling_rate: usize, + center_freq: f64, + band_width: f64, + order: usize, + filter_type: FilterTypes, + ripple: f64, +) -> Result<()> { + let res = unsafe { + ffi::perform_bandpass( + data.as_mut_ptr() as *mut c_double, + data.len() as c_int, + sampling_rate as c_int, + center_freq as c_double, + band_width as c_double, + order as c_int, + filter_type as c_int, + ripple as c_double, + ) + }; + Ok(check_brainflow_exit_code(res)?) +} + +pub fn perform_bandstop( + mut data: Vec, + sampling_rate: usize, + center_freq: f64, + band_width: f64, + order: usize, + filter_type: FilterTypes, + ripple: f64, +) -> Result<()> { + let res = unsafe { + ffi::perform_bandstop( + data.as_mut_ptr() as *mut c_double, + data.len() as c_int, + sampling_rate as c_int, + center_freq as c_double, + band_width as c_double, + order as c_int, + filter_type as c_int, + ripple as c_double, + ) + }; + Ok(check_brainflow_exit_code(res)?) +} + +pub fn remove_environmental_noise( + mut data: Vec, + sampling_rate: usize, + noise_type: NoiseTypes, +) -> Result<()> { + let res = unsafe { + ffi::remove_environmental_noise( + data.as_mut_ptr() as *mut c_double, + data.len() as c_int, + sampling_rate as c_int, + noise_type as c_int, + ) + }; + Ok(check_brainflow_exit_code(res)?) +} + +pub fn perform_rolling_filter( + mut data: Vec, + period: usize, + agg_operation: AggOperations, +) -> Result<()> { + let res = unsafe { + ffi::perform_rolling_filter( + data.as_mut_ptr() as *mut c_double, + data.len() as c_int, + period as c_int, + agg_operation as c_int, + ) + }; + Ok(check_brainflow_exit_code(res)?) +} + +pub fn perform_downsampling( + mut data: Vec, + period: usize, + agg_operation: AggOperations, +) -> Result> { + if period == 0 { + return Err(Error::BrainFlowError(BrainFlowError::InvalidArgumentsError)); + } + let mut output = Vec::::with_capacity(data.len() / period as usize); + let res = unsafe { + ffi::perform_downsampling( + data.as_mut_ptr() as *mut c_double, + data.len() as c_int, + period as c_int, + agg_operation as c_int, + output.as_mut_ptr() as *mut c_double, + ) + }; + check_brainflow_exit_code(res)?; + Ok(output) +} + +pub fn perform_wavelet_transform>( + mut data: Vec, + wavelet: S, + decomposition_level: usize, +) -> Result> { + let mut output = Vec::::with_capacity(data.len() + 2 * decomposition_level * (40 + 1)); + let mut decomposition_lengths = Vec::::with_capacity(decomposition_level + 1); + let wavelet = CString::new(wavelet.as_ref())?; + let res = unsafe { + ffi::perform_wavelet_transform( + data.as_mut_ptr() as *mut c_double, + data.len() as c_int, + wavelet.as_ptr(), + decomposition_level as c_int, + output.as_mut_ptr() as *mut c_double, + decomposition_lengths.as_mut_ptr() as *mut c_int, + ) + }; + check_brainflow_exit_code(res)?; + Ok(output) +} diff --git a/rust-package/brainflow/src/lib.rs b/rust-package/brainflow/src/lib.rs index 439266817..7709b00a7 100644 --- a/rust-package/brainflow/src/lib.rs +++ b/rust-package/brainflow/src/lib.rs @@ -14,8 +14,6 @@ pub mod ml_model; pub use board_id::BoardId; -use ffi::LogLevels; - type BrainFlowExitCode = i32; pub fn check_brainflow_exit_code( From 3bcc4799e91be6554ef5356250380ff5ca3ed598 Mon Sep 17 00:00:00 2001 From: Daniel Hahne Date: Mon, 27 Sep 2021 22:56:34 +0200 Subject: [PATCH 09/21] Continue with data filters --- rust-package/brainflow/Cargo.toml | 2 + rust-package/brainflow/src/data_filter.rs | 266 ++++++++++++++++++++-- 2 files changed, 249 insertions(+), 19 deletions(-) diff --git a/rust-package/brainflow/Cargo.toml b/rust-package/brainflow/Cargo.toml index 80dc0a737..dfc4fe600 100644 --- a/rust-package/brainflow/Cargo.toml +++ b/rust-package/brainflow/Cargo.toml @@ -8,7 +8,9 @@ edition = "2018" [dependencies] brainflow-sys = { path = "../brainflow-sys" } getset = "0.1.1" +ndarray = "0.15.3" num = "0.4.0" +num-complex = "0.4.0" num-derive = "0.3.3" num-traits = "0.2.14" paste = "1.0.5" diff --git a/rust-package/brainflow/src/data_filter.rs b/rust-package/brainflow/src/data_filter.rs index a7ad3b81b..c8891787f 100644 --- a/rust-package/brainflow/src/data_filter.rs +++ b/rust-package/brainflow/src/data_filter.rs @@ -1,7 +1,11 @@ +use getset::Getters; +use ndarray::{Array1, Array2, ArrayBase, AsArray, Ix1, Ix3}; +use num::Complex; +use num_complex::Complex64; use std::os::raw::c_int; use std::{ffi::CString, os::raw::c_double}; -use ffi::{AggOperations, FilterTypes, LogLevels, NoiseTypes}; +use ffi::{AggOperations, DetrendOperations, FilterTypes, LogLevels, NoiseTypes, WindowFunctions}; use crate::error::{BrainFlowError, Error}; use crate::{check_brainflow_exit_code, ffi, Result}; @@ -42,7 +46,7 @@ pub fn log_message>(log_level: LogLevels, message: S) -> Result<() } pub fn perform_lowpass( - mut data: Vec, + data: &mut [f64], sampling_rate: usize, cutoff: f64, order: usize, @@ -60,11 +64,12 @@ pub fn perform_lowpass( ripple as c_double, ) }; - Ok(check_brainflow_exit_code(res)?) + check_brainflow_exit_code(res)?; + Ok(()) } pub fn perform_highpass( - mut data: Vec, + data: &mut [f64], sampling_rate: usize, cutoff: f64, order: usize, @@ -82,11 +87,12 @@ pub fn perform_highpass( ripple as c_double, ) }; - Ok(check_brainflow_exit_code(res)?) + check_brainflow_exit_code(res)?; + Ok(()) } pub fn perform_bandpass( - mut data: Vec, + data: &mut [f64], sampling_rate: usize, center_freq: f64, band_width: f64, @@ -106,11 +112,12 @@ pub fn perform_bandpass( ripple as c_double, ) }; - Ok(check_brainflow_exit_code(res)?) + check_brainflow_exit_code(res)?; + Ok(()) } pub fn perform_bandstop( - mut data: Vec, + data: &mut [f64], sampling_rate: usize, center_freq: f64, band_width: f64, @@ -130,11 +137,12 @@ pub fn perform_bandstop( ripple as c_double, ) }; - Ok(check_brainflow_exit_code(res)?) + check_brainflow_exit_code(res)?; + Ok(()) } pub fn remove_environmental_noise( - mut data: Vec, + data: &mut [f64], sampling_rate: usize, noise_type: NoiseTypes, ) -> Result<()> { @@ -146,11 +154,12 @@ pub fn remove_environmental_noise( noise_type as c_int, ) }; - Ok(check_brainflow_exit_code(res)?) + check_brainflow_exit_code(res)?; + Ok(()) } pub fn perform_rolling_filter( - mut data: Vec, + data: &mut [f64], period: usize, agg_operation: AggOperations, ) -> Result<()> { @@ -162,11 +171,12 @@ pub fn perform_rolling_filter( agg_operation as c_int, ) }; - Ok(check_brainflow_exit_code(res)?) + check_brainflow_exit_code(res)?; + Ok(()) } pub fn perform_downsampling( - mut data: Vec, + data: &mut [f64], period: usize, agg_operation: AggOperations, ) -> Result> { @@ -187,24 +197,242 @@ pub fn perform_downsampling( Ok(output) } +#[derive(Getters)] +#[getset(get = "pub")] +pub struct WaveletTransform { + coefficients: Vec, + decomposition_level: usize, + decomposition_lengths: Vec, + wavelet: String, + original_data_len: usize, +} + +impl WaveletTransform { + pub fn new( + capacity: usize, + decomposition_level: usize, + wavelet: String, + original_data_len: usize, + ) -> Self { + Self { + coefficients: Vec::with_capacity(capacity), + decomposition_level, + decomposition_lengths: Vec::with_capacity(decomposition_level + 1), + wavelet, + original_data_len, + } + } + + pub fn with_coefficients( + coefficients: Vec, + decomposition_level: usize, + decomposition_lengths: Vec, + wavelet: String, + original_data_len: usize, + ) -> Self { + Self { + coefficients, + decomposition_level, + decomposition_lengths, + wavelet, + original_data_len, + } + } +} + pub fn perform_wavelet_transform>( - mut data: Vec, + data: &mut [f64], wavelet: S, decomposition_level: usize, -) -> Result> { - let mut output = Vec::::with_capacity(data.len() + 2 * decomposition_level * (40 + 1)); - let mut decomposition_lengths = Vec::::with_capacity(decomposition_level + 1); +) -> Result { + let capacity = data.len() + 2 * decomposition_level * (40 + 1); + let mut wavelet_transform = WaveletTransform::new( + capacity, + decomposition_level, + wavelet.as_ref().to_string(), + data.len(), + ); let wavelet = CString::new(wavelet.as_ref())?; let res = unsafe { + let output = wavelet_transform.coefficients.as_mut_ptr() as *mut c_double; + let decomposition_lengths = + wavelet_transform.decomposition_lengths.as_mut_ptr() as *mut c_int; ffi::perform_wavelet_transform( data.as_mut_ptr() as *mut c_double, data.len() as c_int, wavelet.as_ptr(), decomposition_level as c_int, + output, + decomposition_lengths, + ) + }; + check_brainflow_exit_code(res)?; + Ok(wavelet_transform) +} + +pub fn perform_inverse_wavelet_transform(wavelet_transform: WaveletTransform) -> Result> { + let mut wavelet_transform = wavelet_transform; + let mut output = Vec::::with_capacity(wavelet_transform.original_data_len); + let wavelet = CString::new(wavelet_transform.wavelet)?; + let res = unsafe { + ffi::perform_inverse_wavelet_transform( + wavelet_transform.coefficients.as_mut_ptr() as *mut c_double, + wavelet_transform.original_data_len as c_int, + wavelet.as_ptr(), + wavelet_transform.decomposition_level as c_int, + wavelet_transform.decomposition_lengths.as_ptr() as *mut c_int, output.as_mut_ptr() as *mut c_double, - decomposition_lengths.as_mut_ptr() as *mut c_int, ) }; check_brainflow_exit_code(res)?; Ok(output) } + +pub fn perform_wavelet_denoising>( + data: &mut [f64], + wavelet: S, + decomposition_level: usize, +) -> Result<()> { + let wavelet = CString::new(wavelet.as_ref())?; + let res = unsafe { + ffi::perform_wavelet_denoising( + data.as_mut_ptr() as *mut c_double, + data.len() as c_int, + wavelet.as_ptr(), + decomposition_level as c_int, + ) + }; + check_brainflow_exit_code(res)?; + Ok(()) +} + +pub fn csp<'a, Data, Labels>(data: Data, labels: Labels) -> Result<(Array2, Array1)> +where + Data: AsArray<'a, f64, Ix3>, + Labels: AsArray<'a, f64, Ix1>, +{ + let data = data.into(); + let shape = data.shape(); + let n_epochs = shape[0]; + let n_channels = shape[1]; + let n_times = shape[2]; + let data: Vec<&f64> = data.iter().collect(); + + let labels = labels.into(); + let labels: Vec<&f64> = labels.iter().collect(); + + let mut output_filters = Vec::::with_capacity(n_channels * n_channels); + let mut output_eigenvalues = Vec::::with_capacity(n_channels); + + let res = unsafe { + ffi::get_csp( + data.as_ptr() as *const c_double, + labels.as_ptr() as *const c_double, + n_epochs as c_int, + n_channels as c_int, + n_times as c_int, + output_filters.as_mut_ptr() as *mut c_double, + output_eigenvalues.as_mut_ptr() as *mut c_double, + ) + }; + check_brainflow_exit_code(res)?; + + let output_filters = ArrayBase::from_vec(output_filters); + let output_filters = output_filters.into_shape((n_channels, n_channels)).unwrap(); + let output_eigenvalues = Array1::from(output_eigenvalues); + Ok((output_filters, output_eigenvalues)) +} + +pub fn get_csp<'a, Data, Labels>(data: Data, labels: Labels) -> Result<(Array2, Array1)> +where + Data: AsArray<'a, f64, Ix3>, + Labels: AsArray<'a, f64, Ix1>, +{ + csp(data, labels) +} + +pub fn window(window_function: WindowFunctions, window_len: usize) -> Result> { + let mut output = Vec::::with_capacity(window_len); + let res = unsafe { + ffi::get_window( + window_function as c_int, + window_len as c_int, + output.as_mut_ptr() as *mut c_double, + ) + }; + check_brainflow_exit_code(res)?; + Ok(output) +} + +pub fn get_window(window_function: WindowFunctions, window_len: usize) -> Result> { + window(window_function, window_len) +} + +pub fn perform_fft(data: &mut [f64], window_function: WindowFunctions) -> Result> { + let mut output_re = Vec::::with_capacity(data.len() / 2 + 1); + let mut output_im = Vec::::with_capacity(data.len() / 2 + 1); + let res = unsafe { + ffi::perform_fft( + data.as_mut_ptr() as *mut c_double, + data.len() as c_int, + window_function as c_int, + output_re.as_mut_ptr() as *mut c_double, + output_im.as_mut_ptr() as *mut c_double, + ) + }; + let output = output_re + .into_iter() + .zip(output_im) + .map(|(re, im)| Complex { re, im }) + .collect(); + check_brainflow_exit_code(res)?; + Ok(output) +} + +pub fn perform_ifft(data: &[Complex64], original_data_len: usize) -> Result> { + let mut restored_data = Vec::::with_capacity(original_data_len); + let (mut input_re, mut input_im): (Vec, Vec) = + data.iter().map(|d| (d.re, d.im)).unzip(); + let res = unsafe { + ffi::perform_ifft( + input_re.as_mut_ptr() as *mut c_double, + input_im.as_mut_ptr() as *mut c_double, + original_data_len as c_int, + restored_data.as_mut_ptr() as *mut c_double, + ) + }; + check_brainflow_exit_code(res)?; + Ok(restored_data) +} + +pub fn detrend(data: &mut [f64], detrend_operation: DetrendOperations) -> Result<()> { + let res = unsafe { + ffi::detrend( + data.as_mut_ptr() as *mut c_double, + data.len() as c_int, + detrend_operation as c_int, + ) + }; + Ok(check_brainflow_exit_code(res)?) +} + +pub fn psd( + data: &mut [f64], + sampling_rate: usize, + window_function: WindowFunctions, +) -> Result<(Vec, Vec)> { + let mut output_ampl = Vec::::with_capacity(data.len() / 2 + 1); + let mut output_freq = Vec::::with_capacity(data.len() / 2 + 1); + let res = unsafe { + ffi::get_psd( + data.as_mut_ptr() as *mut c_double, + data.len() as c_int, + sampling_rate as c_int, + window_function as c_int, + output_ampl.as_mut_ptr() as *mut c_double, + output_freq.as_mut_ptr() as *mut c_double, + ) + }; + check_brainflow_exit_code(res)?; + Ok((output_ampl, output_freq)) +} From 3272d5f5fe0507ba1664be5efe9d885b3a980132 Mon Sep 17 00:00:00 2001 From: Daniel Hahne Date: Tue, 28 Sep 2021 21:40:43 +0200 Subject: [PATCH 10/21] Finish impleemntation of board_shim, data_filter, and ml_model --- rust-package/brainflow/src/board_shim.rs | 1 - rust-package/brainflow/src/data_filter.rs | 198 +++++++++++++++++- rust-package/brainflow/src/ml_model.rs | 75 ++++++- .../src/ml_model/brainflow_model_param.rs | 46 ++++ 4 files changed, 307 insertions(+), 13 deletions(-) create mode 100644 rust-package/brainflow/src/ml_model/brainflow_model_param.rs diff --git a/rust-package/brainflow/src/board_shim.rs b/rust-package/brainflow/src/board_shim.rs index 3ee41f6f4..770e1f07c 100644 --- a/rust-package/brainflow/src/board_shim.rs +++ b/rust-package/brainflow/src/board_shim.rs @@ -23,7 +23,6 @@ pub struct BoardShim { impl BoardShim { pub fn new(board_id: BoardId, input_params: BrainFlowInputParams) -> Result { - dbg!(&input_params); let json_input_params = serde_json::to_string(&input_params)?; let json_input_params = CString::new(json_input_params)?; Ok(Self { diff --git a/rust-package/brainflow/src/data_filter.rs b/rust-package/brainflow/src/data_filter.rs index c8891787f..c04b8248a 100644 --- a/rust-package/brainflow/src/data_filter.rs +++ b/rust-package/brainflow/src/data_filter.rs @@ -1,12 +1,11 @@ +use ffi::{AggOperations, DetrendOperations, FilterTypes, LogLevels, NoiseTypes, WindowFunctions}; use getset::Getters; -use ndarray::{Array1, Array2, ArrayBase, AsArray, Ix1, Ix3}; +use ndarray::{Array1, Array2, ArrayBase, AsArray, Ix1, Ix2, Ix3}; use num::Complex; use num_complex::Complex64; use std::os::raw::c_int; use std::{ffi::CString, os::raw::c_double}; -use ffi::{AggOperations, DetrendOperations, FilterTypes, LogLevels, NoiseTypes, WindowFunctions}; - use crate::error::{BrainFlowError, Error}; use crate::{check_brainflow_exit_code, ffi, Result}; @@ -19,11 +18,11 @@ pub fn enable_data_logger() -> Result<()> { set_log_level(LogLevels::LEVEL_INFO) } -pub fn disable_board_logger() -> Result<()> { +pub fn disable_data_logger() -> Result<()> { set_log_level(LogLevels::LEVEL_OFF) } -pub fn enable_dev_board_logger() -> Result<()> { +pub fn enable_dev_data_logger() -> Result<()> { set_log_level(LogLevels::LEVEL_TRACE) } @@ -416,23 +415,200 @@ pub fn detrend(data: &mut [f64], detrend_operation: DetrendOperations) -> Result Ok(check_brainflow_exit_code(res)?) } +#[derive(Getters)] +#[getset(get = "pub")] +pub struct Psd { + amplitude: Vec, + frequency: Vec, +} + pub fn psd( data: &mut [f64], sampling_rate: usize, window_function: WindowFunctions, -) -> Result<(Vec, Vec)> { - let mut output_ampl = Vec::::with_capacity(data.len() / 2 + 1); - let mut output_freq = Vec::::with_capacity(data.len() / 2 + 1); +) -> Result { + let mut amplitude = Vec::::with_capacity(data.len() / 2 + 1); + let mut frequency = Vec::::with_capacity(data.len() / 2 + 1); let res = unsafe { ffi::get_psd( data.as_mut_ptr() as *mut c_double, data.len() as c_int, sampling_rate as c_int, window_function as c_int, - output_ampl.as_mut_ptr() as *mut c_double, - output_freq.as_mut_ptr() as *mut c_double, + amplitude.as_mut_ptr() as *mut c_double, + frequency.as_mut_ptr() as *mut c_double, + ) + }; + check_brainflow_exit_code(res)?; + Ok(Psd { + amplitude, + frequency, + }) +} + +pub fn get_psd( + data: &mut [f64], + sampling_rate: usize, + window_function: WindowFunctions, +) -> Result { + psd(data, sampling_rate, window_function) +} + +pub fn psd_welch( + data: &mut [f64], + nfft: usize, + overlap: usize, + sampling_rate: usize, + window_function: WindowFunctions, +) -> Result { + let mut amplitude = Vec::::with_capacity(nfft / 2 + 1); + let mut frequency = Vec::::with_capacity(nfft / 2 + 1); + let res = unsafe { + ffi::get_psd_welch( + data.as_mut_ptr() as *mut c_double, + data.len() as c_int, + nfft as c_int, + overlap as c_int, + sampling_rate as c_int, + window_function as c_int, + amplitude.as_mut_ptr() as *mut c_double, + frequency.as_mut_ptr() as *mut c_double, + ) + }; + check_brainflow_exit_code(res)?; + Ok(Psd { + amplitude, + frequency, + }) +} + +pub fn get_psd_welch( + data: &mut [f64], + nfft: usize, + overlap: usize, + sampling_rate: usize, + window_function: WindowFunctions, +) -> Result { + psd_welch(data, nfft, overlap, sampling_rate, window_function) +} + +pub fn avg_band_powers<'a, Data>( + data: Data, + sampling_rate: usize, + apply_filters: bool, +) -> Result<(Vec, Vec)> +where + Data: AsArray<'a, f64, Ix2>, +{ + let data = data.into(); + let shape = data.shape(); + let (cols, rows) = (shape[0], shape[1]); + + let mut avg_band_powers = Vec::with_capacity(5); + let mut stddev_band_powers = Vec::with_capacity(5); + let mut raw_data: Vec<&f64> = data.iter().collect(); + let res = unsafe { + ffi::get_avg_band_powers( + raw_data.as_mut_ptr() as *mut c_double, + rows as c_int, + cols as c_int, + sampling_rate as c_int, + apply_filters as c_int, + avg_band_powers.as_mut_ptr() as *mut c_double, + stddev_band_powers.as_mut_ptr() as *mut c_double, ) }; check_brainflow_exit_code(res)?; - Ok((output_ampl, output_freq)) + Ok((avg_band_powers, stddev_band_powers)) +} + +pub fn get_avg_band_powers<'a, Data>( + data: Data, + sampling_rate: usize, + apply_filters: bool, +) -> Result<(Vec, Vec)> +where + Data: AsArray<'a, f64, Ix2>, +{ + avg_band_powers(data, sampling_rate, apply_filters) +} + +pub fn band_power(psd: Psd, freq_start: f64, freq_end: f64) -> Result { + let mut band_power = 0.0; + let mut psd = psd; + let res = unsafe { + ffi::get_band_power( + psd.amplitude.as_mut_ptr() as *mut c_double, + psd.frequency.as_mut_ptr() as *mut c_double, + psd.amplitude.len() as c_int, + freq_start, + freq_end, + &mut band_power, + ) + }; + check_brainflow_exit_code(res)?; + Ok(band_power) +} + +pub fn get_band_power(psd: Psd, freq_start: f64, freq_end: f64) -> Result { + band_power(psd, freq_start, freq_end) +} + +pub fn nearest_power_of_two(value: usize) -> Result { + let mut output = 0; + let res = unsafe { ffi::get_nearest_power_of_two(value as c_int, &mut output) }; + check_brainflow_exit_code(res)?; + Ok(output as usize) +} + +pub fn get_nearest_power_of_two(value: usize) -> Result { + nearest_power_of_two(value) +} + +pub fn read_file>(file_name: S) -> Result> { + let file_name = CString::new(file_name.as_ref())?; + let mut num_elements = 0; + let res = unsafe { ffi::get_num_elements_in_file(file_name.as_ptr(), &mut num_elements) }; + check_brainflow_exit_code(res)?; + + let mut data = Vec::with_capacity(num_elements as usize); + let mut rows = 0; + let mut cols = 0; + let res = unsafe { + ffi::read_file( + data.as_mut_ptr() as *mut c_double, + &mut rows, + &mut cols, + file_name.as_ptr(), + num_elements as c_int, + ) + }; + check_brainflow_exit_code(res)?; + + let data = ArrayBase::from_vec(data); + let data = data.into_shape((cols as usize, rows as usize)).unwrap(); + Ok(data) +} + +pub fn write_file<'a, Data, S>(data: Data, file_name: S, file_mode: S) -> Result<()> +where + Data: AsArray<'a, f64, Ix2>, + S: AsRef, +{ + let file_name = CString::new(file_name.as_ref())?; + let file_mode = CString::new(file_mode.as_ref())?; + let data = data.into(); + let shape = data.shape(); + let (cols, rows) = (shape[0], shape[1]); + let mut data: Vec<&f64> = data.iter().collect(); + let res = unsafe { + ffi::write_file( + data.as_mut_ptr() as *mut c_double, + rows as c_int, + cols as c_int, + file_name.as_ptr(), + file_mode.as_ptr(), + ) + }; + Ok(check_brainflow_exit_code(res)?) } diff --git a/rust-package/brainflow/src/ml_model.rs b/rust-package/brainflow/src/ml_model.rs index 60dfb90f9..ed1201b0f 100644 --- a/rust-package/brainflow/src/ml_model.rs +++ b/rust-package/brainflow/src/ml_model.rs @@ -1 +1,74 @@ -use crate::ffi; +use std::{ + ffi::CString, + os::raw::{c_double, c_int}, +}; + +use crate::{check_brainflow_exit_code, ffi, Result}; + +mod brainflow_model_param; +pub use brainflow_model_param::{BrainFlowModelParams, BrainFlowModelParamsBuilder}; +use ffi::LogLevels; + +pub fn set_log_level(log_level: LogLevels) -> Result<()> { + let res = unsafe { ffi::set_log_level(log_level as c_int) }; + Ok(check_brainflow_exit_code(res)?) +} + +pub fn enable_ml_logger() -> Result<()> { + set_log_level(LogLevels::LEVEL_INFO) +} + +pub fn disable_ml_logger() -> Result<()> { + set_log_level(LogLevels::LEVEL_OFF) +} + +pub fn enable_dev_ml_logger() -> Result<()> { + set_log_level(LogLevels::LEVEL_TRACE) +} + +pub fn set_log_file>(log_file: S) -> Result<()> { + let log_file = log_file.as_ref(); + let log_file = CString::new(log_file)?; + let res = unsafe { ffi::set_log_file(log_file.as_ptr()) }; + Ok(check_brainflow_exit_code(res)?) +} + +pub struct MlModel { + model_params: BrainFlowModelParams, + json_model_params: CString, +} + +impl MlModel { + pub fn new(model_params: BrainFlowModelParams) -> Result { + let json_model_params = serde_json::to_string(&model_params)?; + let json_model_params = CString::new(json_model_params)?; + Ok(Self { + model_params, + json_model_params, + }) + } + + pub fn prepare(&self) -> Result<()> { + let res = unsafe { ffi::prepare(self.json_model_params.as_ptr()) }; + Ok(check_brainflow_exit_code(res)?) + } + + pub fn predict(&self, data: &mut [f64]) -> Result { + let mut output = 0.0; + let res = unsafe { + ffi::predict( + data.as_mut_ptr() as *mut c_double, + data.len() as c_int, + &mut output, + self.json_model_params.as_ptr(), + ) + }; + check_brainflow_exit_code(res)?; + Ok(output) + } + + pub fn release(&self) -> Result<()> { + let res = unsafe { ffi::release(self.json_model_params.as_ptr()) }; + Ok(check_brainflow_exit_code(res)?) + } +} diff --git a/rust-package/brainflow/src/ml_model/brainflow_model_param.rs b/rust-package/brainflow/src/ml_model/brainflow_model_param.rs new file mode 100644 index 000000000..ba9de12f2 --- /dev/null +++ b/rust-package/brainflow/src/ml_model/brainflow_model_param.rs @@ -0,0 +1,46 @@ +use getset::Getters; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Default, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, Getters)] +#[getset(get = "pub", set = "pub")] +pub struct BrainFlowModelParams { + metric: String, + classifier: String, + file: String, + other_info: String, +} + +#[derive(Default)] +pub struct BrainFlowModelParamsBuilder { + params: BrainFlowModelParams, +} + +impl BrainFlowModelParamsBuilder { + pub fn new() -> Self { + Default::default() + } + + pub fn metric>(mut self, metric: S) -> Self { + self.params.metric = metric.as_ref().to_string(); + self + } + + pub fn classifier>(mut self, classifier: S) -> Self { + self.params.classifier = classifier.as_ref().to_string(); + self + } + + pub fn file>(mut self, file: S) -> Self { + self.params.file = file.as_ref().to_string(); + self + } + + pub fn other_info>(mut self, other_info: S) -> Self { + self.params.other_info = other_info.as_ref().to_string(); + self + } + + pub fn build(self) -> BrainFlowModelParams { + self.params + } +} From bd5ec6a734f7ae5ad8920299fdfccd9f42f4c47a Mon Sep 17 00:00:00 2001 From: Daniel Hahne Date: Tue, 28 Sep 2021 22:04:43 +0200 Subject: [PATCH 11/21] Fix BrainFlowModelParams --- rust-package/brainflow/examples/cyton.rs | 8 ++++++++ .../brainflow/src/ml_model/brainflow_model_param.rs | 12 ++++++------ 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/rust-package/brainflow/examples/cyton.rs b/rust-package/brainflow/examples/cyton.rs index 1fcade165..4e9cdb9bb 100644 --- a/rust-package/brainflow/examples/cyton.rs +++ b/rust-package/brainflow/examples/cyton.rs @@ -1,8 +1,11 @@ use brainflow::board_shim::BoardShim; use brainflow::brainflow_input_params::BrainFlowInputParamsBuilder; +use brainflow::ml_model::{BrainFlowModelParamsBuilder, MlModel}; use brainflow::BoardId; fn main() { + brainflow::ml_model::enable_ml_logger().unwrap(); + brainflow::board_shim::enable_dev_board_logger().unwrap(); let params = BrainFlowInputParamsBuilder::default() .serial_port("/dev/ttyUSB0") .build(); @@ -16,4 +19,9 @@ fn main() { dbg!(brainflow::board_shim::eeg_channels(BoardId::CytonBoard).unwrap()); dbg!(board.is_prepared().unwrap()); + + let ml_params = BrainFlowModelParamsBuilder::default().build(); + let ml = MlModel::new(ml_params).unwrap(); + + ml.prepare().unwrap(); } diff --git a/rust-package/brainflow/src/ml_model/brainflow_model_param.rs b/rust-package/brainflow/src/ml_model/brainflow_model_param.rs index ba9de12f2..e469ff179 100644 --- a/rust-package/brainflow/src/ml_model/brainflow_model_param.rs +++ b/rust-package/brainflow/src/ml_model/brainflow_model_param.rs @@ -4,8 +4,8 @@ use serde::{Deserialize, Serialize}; #[derive(Debug, Default, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, Getters)] #[getset(get = "pub", set = "pub")] pub struct BrainFlowModelParams { - metric: String, - classifier: String, + metric: usize, + classifier: usize, file: String, other_info: String, } @@ -20,13 +20,13 @@ impl BrainFlowModelParamsBuilder { Default::default() } - pub fn metric>(mut self, metric: S) -> Self { - self.params.metric = metric.as_ref().to_string(); + pub fn metric(mut self, metric: usize) -> Self { + self.params.metric = metric; self } - pub fn classifier>(mut self, classifier: S) -> Self { - self.params.classifier = classifier.as_ref().to_string(); + pub fn classifier(mut self, classifier: usize) -> Self { + self.params.classifier = classifier; self } From bf3f2e27f44a17f205cf99b33d400dfcfed1596d Mon Sep 17 00:00:00 2001 From: Daniel Hahne Date: Thu, 30 Sep 2021 10:16:02 +0200 Subject: [PATCH 12/21] Dynamically load library for each module (board_controller, data_filter, ml_model) --- rust-package/brainflow-sys/Cargo.lock | 1 + rust-package/brainflow-sys/Cargo.toml | 3 + rust-package/brainflow-sys/build.rs | 103 ++- .../brainflow-sys/src/board_controller.rs | 789 ++++++++++++++++++ rust-package/brainflow-sys/src/constants.rs | 160 ++++ .../brainflow-sys/src/data_handler.rs | 755 +++++++++++++++++ rust-package/brainflow-sys/src/lib.rs | 634 +------------- rust-package/brainflow-sys/src/ml_model.rs | 107 +++ rust-package/brainflow/Cargo.toml | 1 + rust-package/brainflow/examples/cyton.rs | 2 +- rust-package/brainflow/src/board_shim.rs | 126 ++- rust-package/brainflow/src/data_filter.rs | 112 ++- rust-package/brainflow/src/lib.rs | 1 - rust-package/brainflow/src/ml_model.rs | 77 +- 14 files changed, 2104 insertions(+), 767 deletions(-) create mode 100644 rust-package/brainflow-sys/src/board_controller.rs create mode 100644 rust-package/brainflow-sys/src/constants.rs create mode 100644 rust-package/brainflow-sys/src/data_handler.rs create mode 100644 rust-package/brainflow-sys/src/ml_model.rs diff --git a/rust-package/brainflow-sys/Cargo.lock b/rust-package/brainflow-sys/Cargo.lock index 71575b7f4..9dec08561 100644 --- a/rust-package/brainflow-sys/Cargo.lock +++ b/rust-package/brainflow-sys/Cargo.lock @@ -78,6 +78,7 @@ version = "0.1.0" dependencies = [ "bindgen", "cmake", + "libloading", ] [[package]] diff --git a/rust-package/brainflow-sys/Cargo.toml b/rust-package/brainflow-sys/Cargo.toml index 16d474c89..d659257ed 100644 --- a/rust-package/brainflow-sys/Cargo.toml +++ b/rust-package/brainflow-sys/Cargo.toml @@ -16,3 +16,6 @@ build_bluetooth = [] [build-dependencies] bindgen = { version = "0.59.1", optional = true } cmake = "0.1" + +[dependencies] +libloading = "0.7.0" diff --git a/rust-package/brainflow-sys/build.rs b/rust-package/brainflow-sys/build.rs index 4a26bf2a0..99eab74be 100644 --- a/rust-package/brainflow-sys/build.rs +++ b/rust-package/brainflow-sys/build.rs @@ -4,7 +4,7 @@ use std::{env, path::PathBuf}; use std::{fmt::Display, path::Path}; #[cfg(feature = "generate_binding")] -fn generate_binding() { +fn generate_board_controller_binding() { const ALLOW_UNCONVENTIONALS: &'static str = "#![allow(non_camel_case_types)]\n"; let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); @@ -12,12 +12,84 @@ fn generate_binding() { let header_path = header_path.display(); let bindings = bindgen::Builder::default() - .header(format!("{}/brainflow_constants.h", &header_path)) .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("board_controller.rs"); + + bindings + .write_to_file(binding_target_path) + .expect("Could not write binding to `src/board_controller.rs`"); +} + +#[cfg(feature = "generate_binding")] +fn generate_data_handler_binding() { + const ALLOW_UNCONVENTIONALS: &'static str = "#![allow(non_camel_case_types)]\n"; + + let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); + let header_path = out_path.join("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("data_handler.rs"); + + bindings + .write_to_file(binding_target_path) + .expect("Could not write binding to `src/data_handler.rs`"); +} + +#[cfg(feature = "generate_binding")] +fn generate_ml_model_binding() { + const ALLOW_UNCONVENTIONALS: &'static str = "#![allow(non_camel_case_types)]\n"; + + let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); + let header_path = out_path.join("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("ml_model.rs"); + + bindings + .write_to_file(binding_target_path) + .expect("Could not write binding to `src/ml_model.rs`"); +} + +#[cfg(feature = "generate_binding")] +fn generate_constants_binding() { + const ALLOW_UNCONVENTIONALS: &'static str = "#![allow(non_camel_case_types)]\n"; + + let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); + let header_path = out_path.join("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++") @@ -29,11 +101,19 @@ fn generate_binding() { .generate() .expect("Unable to generate bindings"); - let binding_target_path = PathBuf::new().join("src").join("lib.rs"); + let binding_target_path = PathBuf::new().join("src").join("constants.rs"); bindings .write_to_file(binding_target_path) - .expect("Could not write binding to `src/lib.rs`"); + .expect("Could not write binding to `src/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 build() { @@ -72,25 +152,12 @@ fn build() { "OFF" }; - let brainflow_build_dir = cmake::Config::new(brainflow_path) + let _brainflow_build_dir = cmake::Config::new(brainflow_path) .define("USE_LIBFTDI", use_libftdi) .define("USE_OPENMP", use_openmp) .define("BUILD_OYMOTION_SDK", build_oymotion_sdk) .define("BUILD_BLUETOOTH", build_bluetooth) .build(); - link(brainflow_build_dir.display()) -} - -fn link(brainflow_build_dir: impl Display) { - println!("cargo:rustc-link-lib={}=Brainflow", "static"); - println!("cargo:rustc-link-lib={}=DSPFilters", "static"); - println!("cargo:rustc-link-lib={}=BoardController", "dylib"); - println!("cargo:rustc-link-lib={}=DataHandler", "dylib"); - println!("cargo:rustc-link-lib={}=BrainBitLib", "dylib"); - println!("cargo:rustc-link-lib={}=MLModule", "dylib"); - println!("cargo:rustc-link-lib={}=MuseLib", "dylib"); - println!("cargo:rustc-link-lib={}=stdc++", "dylib"); - println!("cargo:rustc-link-search=native={}/lib", brainflow_build_dir); } fn main() { diff --git a/rust-package/brainflow-sys/src/board_controller.rs b/rust-package/brainflow-sys/src/board_controller.rs new file mode 100644 index 000000000..9c84eca28 --- /dev/null +++ b/rust-package/brainflow-sys/src/board_controller.rs @@ -0,0 +1,789 @@ +/* automatically generated by rust-bindgen 0.59.1 */ + +#![allow(non_camel_case_types)] + + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct JNINativeInterface { + _unused: [u8; 0], +} +pub type JNIEnv = *const JNINativeInterface; +extern crate libloading; +pub struct BoardController { + __library: ::libloading::Library, + pub get_board_descr: Result< + unsafe extern "C" fn( + board_id: ::std::os::raw::c_int, + board_descr: *mut ::std::os::raw::c_char, + len: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int, + ::libloading::Error, + >, + pub get_sampling_rate: Result< + unsafe extern "C" fn( + board_id: ::std::os::raw::c_int, + sampling_rate: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int, + ::libloading::Error, + >, + pub get_package_num_channel: Result< + unsafe extern "C" fn( + board_id: ::std::os::raw::c_int, + package_num_channel: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int, + ::libloading::Error, + >, + pub get_timestamp_channel: Result< + unsafe extern "C" fn( + board_id: ::std::os::raw::c_int, + timestamp_channel: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int, + ::libloading::Error, + >, + pub get_marker_channel: Result< + unsafe extern "C" fn( + board_id: ::std::os::raw::c_int, + marker_channel: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int, + ::libloading::Error, + >, + pub get_battery_channel: Result< + unsafe extern "C" fn( + board_id: ::std::os::raw::c_int, + battery_channel: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int, + ::libloading::Error, + >, + pub get_num_rows: Result< + unsafe extern "C" fn( + board_id: ::std::os::raw::c_int, + num_rows: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int, + ::libloading::Error, + >, + pub get_eeg_names: Result< + unsafe extern "C" fn( + board_id: ::std::os::raw::c_int, + eeg_names: *mut ::std::os::raw::c_char, + len: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int, + ::libloading::Error, + >, + pub get_exg_channels: Result< + unsafe extern "C" fn( + board_id: ::std::os::raw::c_int, + exg_channels: *mut ::std::os::raw::c_int, + len: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int, + ::libloading::Error, + >, + pub get_eeg_channels: Result< + unsafe extern "C" fn( + board_id: ::std::os::raw::c_int, + eeg_channels: *mut ::std::os::raw::c_int, + len: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int, + ::libloading::Error, + >, + pub get_emg_channels: Result< + unsafe extern "C" fn( + board_id: ::std::os::raw::c_int, + emg_channels: *mut ::std::os::raw::c_int, + len: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int, + ::libloading::Error, + >, + pub get_ecg_channels: Result< + unsafe extern "C" fn( + board_id: ::std::os::raw::c_int, + ecg_channels: *mut ::std::os::raw::c_int, + len: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int, + ::libloading::Error, + >, + pub get_eog_channels: Result< + unsafe extern "C" fn( + board_id: ::std::os::raw::c_int, + eog_channels: *mut ::std::os::raw::c_int, + len: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int, + ::libloading::Error, + >, + pub get_ppg_channels: Result< + unsafe extern "C" fn( + board_id: ::std::os::raw::c_int, + ppg_channels: *mut ::std::os::raw::c_int, + len: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int, + ::libloading::Error, + >, + pub get_eda_channels: Result< + unsafe extern "C" fn( + board_id: ::std::os::raw::c_int, + eda_channels: *mut ::std::os::raw::c_int, + len: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int, + ::libloading::Error, + >, + pub get_accel_channels: Result< + unsafe extern "C" fn( + board_id: ::std::os::raw::c_int, + accel_channels: *mut ::std::os::raw::c_int, + len: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int, + ::libloading::Error, + >, + pub get_analog_channels: Result< + unsafe extern "C" fn( + board_id: ::std::os::raw::c_int, + analog_channels: *mut ::std::os::raw::c_int, + len: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int, + ::libloading::Error, + >, + pub get_gyro_channels: Result< + unsafe extern "C" fn( + board_id: ::std::os::raw::c_int, + gyro_channels: *mut ::std::os::raw::c_int, + len: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int, + ::libloading::Error, + >, + pub get_other_channels: Result< + unsafe extern "C" fn( + board_id: ::std::os::raw::c_int, + other_channels: *mut ::std::os::raw::c_int, + len: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int, + ::libloading::Error, + >, + pub get_temperature_channels: Result< + unsafe extern "C" fn( + board_id: ::std::os::raw::c_int, + temperature_channels: *mut ::std::os::raw::c_int, + len: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int, + ::libloading::Error, + >, + pub get_resistance_channels: Result< + unsafe extern "C" fn( + board_id: ::std::os::raw::c_int, + resistance_channels: *mut ::std::os::raw::c_int, + len: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int, + ::libloading::Error, + >, + pub get_device_name: Result< + unsafe extern "C" fn( + board_id: ::std::os::raw::c_int, + name: *mut ::std::os::raw::c_char, + len: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int, + ::libloading::Error, + >, + pub prepare_session: Result< + unsafe extern "C" fn( + board_id: ::std::os::raw::c_int, + json_brainflow_input_params: *const ::std::os::raw::c_char, + ) -> ::std::os::raw::c_int, + ::libloading::Error, + >, + pub start_stream: Result< + unsafe extern "C" fn( + buffer_size: ::std::os::raw::c_int, + streamer_params: *const ::std::os::raw::c_char, + board_id: ::std::os::raw::c_int, + json_brainflow_input_params: *const ::std::os::raw::c_char, + ) -> ::std::os::raw::c_int, + ::libloading::Error, + >, + pub stop_stream: Result< + unsafe extern "C" fn( + board_id: ::std::os::raw::c_int, + json_brainflow_input_params: *const ::std::os::raw::c_char, + ) -> ::std::os::raw::c_int, + ::libloading::Error, + >, + pub release_session: Result< + unsafe extern "C" fn( + board_id: ::std::os::raw::c_int, + json_brainflow_input_params: *const ::std::os::raw::c_char, + ) -> ::std::os::raw::c_int, + ::libloading::Error, + >, + pub get_current_board_data: Result< + unsafe extern "C" fn( + num_samples: ::std::os::raw::c_int, + data_buf: *mut f64, + returned_samples: *mut ::std::os::raw::c_int, + board_id: ::std::os::raw::c_int, + json_brainflow_input_params: *const ::std::os::raw::c_char, + ) -> ::std::os::raw::c_int, + ::libloading::Error, + >, + pub get_board_data_count: Result< + unsafe extern "C" fn( + result: *mut ::std::os::raw::c_int, + board_id: ::std::os::raw::c_int, + json_brainflow_input_params: *const ::std::os::raw::c_char, + ) -> ::std::os::raw::c_int, + ::libloading::Error, + >, + pub get_board_data: Result< + unsafe extern "C" fn( + data_count: ::std::os::raw::c_int, + data_buf: *mut f64, + board_id: ::std::os::raw::c_int, + json_brainflow_input_params: *const ::std::os::raw::c_char, + ) -> ::std::os::raw::c_int, + ::libloading::Error, + >, + pub config_board: Result< + unsafe extern "C" fn( + config: *mut ::std::os::raw::c_char, + response: *mut ::std::os::raw::c_char, + response_len: *mut ::std::os::raw::c_int, + board_id: ::std::os::raw::c_int, + json_brainflow_input_params: *const ::std::os::raw::c_char, + ) -> ::std::os::raw::c_int, + ::libloading::Error, + >, + pub is_prepared: Result< + unsafe extern "C" fn( + prepared: *mut ::std::os::raw::c_int, + board_id: ::std::os::raw::c_int, + json_brainflow_input_params: *const ::std::os::raw::c_char, + ) -> ::std::os::raw::c_int, + ::libloading::Error, + >, + pub insert_marker: Result< + unsafe extern "C" fn( + marker_value: f64, + board_id: ::std::os::raw::c_int, + json_brainflow_input_params: *const ::std::os::raw::c_char, + ) -> ::std::os::raw::c_int, + ::libloading::Error, + >, + pub set_log_level: Result< + unsafe extern "C" fn(log_level: ::std::os::raw::c_int) -> ::std::os::raw::c_int, + ::libloading::Error, + >, + pub set_log_file: Result< + unsafe extern "C" fn(log_file: *const ::std::os::raw::c_char) -> ::std::os::raw::c_int, + ::libloading::Error, + >, + pub log_message: Result< + unsafe extern "C" fn( + log_level: ::std::os::raw::c_int, + message: *mut ::std::os::raw::c_char, + ) -> ::std::os::raw::c_int, + ::libloading::Error, + >, + pub java_set_jnienv: Result< + unsafe extern "C" fn(java_jnienv: *mut JNIEnv) -> ::std::os::raw::c_int, + ::libloading::Error, + >, +} +impl BoardController { + pub unsafe fn new

(path: P) -> Result + where + P: AsRef<::std::ffi::OsStr>, + { + let library = ::libloading::Library::new(path)?; + Self::from_library(library) + } + pub unsafe fn from_library(library: L) -> Result + where + L: Into<::libloading::Library>, + { + let __library = library.into(); + let get_board_descr = __library.get(b"get_board_descr\0").map(|sym| *sym); + let get_sampling_rate = __library.get(b"get_sampling_rate\0").map(|sym| *sym); + let get_package_num_channel = __library.get(b"get_package_num_channel\0").map(|sym| *sym); + let get_timestamp_channel = __library.get(b"get_timestamp_channel\0").map(|sym| *sym); + let get_marker_channel = __library.get(b"get_marker_channel\0").map(|sym| *sym); + let get_battery_channel = __library.get(b"get_battery_channel\0").map(|sym| *sym); + let get_num_rows = __library.get(b"get_num_rows\0").map(|sym| *sym); + let get_eeg_names = __library.get(b"get_eeg_names\0").map(|sym| *sym); + let get_exg_channels = __library.get(b"get_exg_channels\0").map(|sym| *sym); + let get_eeg_channels = __library.get(b"get_eeg_channels\0").map(|sym| *sym); + let get_emg_channels = __library.get(b"get_emg_channels\0").map(|sym| *sym); + let get_ecg_channels = __library.get(b"get_ecg_channels\0").map(|sym| *sym); + let get_eog_channels = __library.get(b"get_eog_channels\0").map(|sym| *sym); + let get_ppg_channels = __library.get(b"get_ppg_channels\0").map(|sym| *sym); + let get_eda_channels = __library.get(b"get_eda_channels\0").map(|sym| *sym); + let get_accel_channels = __library.get(b"get_accel_channels\0").map(|sym| *sym); + let get_analog_channels = __library.get(b"get_analog_channels\0").map(|sym| *sym); + let get_gyro_channels = __library.get(b"get_gyro_channels\0").map(|sym| *sym); + let get_other_channels = __library.get(b"get_other_channels\0").map(|sym| *sym); + let get_temperature_channels = __library.get(b"get_temperature_channels\0").map(|sym| *sym); + let get_resistance_channels = __library.get(b"get_resistance_channels\0").map(|sym| *sym); + let get_device_name = __library.get(b"get_device_name\0").map(|sym| *sym); + let prepare_session = __library.get(b"prepare_session\0").map(|sym| *sym); + let start_stream = __library.get(b"start_stream\0").map(|sym| *sym); + let stop_stream = __library.get(b"stop_stream\0").map(|sym| *sym); + let release_session = __library.get(b"release_session\0").map(|sym| *sym); + let get_current_board_data = __library.get(b"get_current_board_data\0").map(|sym| *sym); + let get_board_data_count = __library.get(b"get_board_data_count\0").map(|sym| *sym); + let get_board_data = __library.get(b"get_board_data\0").map(|sym| *sym); + let config_board = __library.get(b"config_board\0").map(|sym| *sym); + let is_prepared = __library.get(b"is_prepared\0").map(|sym| *sym); + let insert_marker = __library.get(b"insert_marker\0").map(|sym| *sym); + let set_log_level = __library.get(b"set_log_level\0").map(|sym| *sym); + let set_log_file = __library.get(b"set_log_file\0").map(|sym| *sym); + let log_message = __library.get(b"log_message\0").map(|sym| *sym); + let java_set_jnienv = __library.get(b"java_set_jnienv\0").map(|sym| *sym); + Ok(BoardController { + __library, + get_board_descr, + get_sampling_rate, + get_package_num_channel, + get_timestamp_channel, + get_marker_channel, + get_battery_channel, + get_num_rows, + get_eeg_names, + get_exg_channels, + get_eeg_channels, + get_emg_channels, + get_ecg_channels, + get_eog_channels, + get_ppg_channels, + get_eda_channels, + get_accel_channels, + get_analog_channels, + get_gyro_channels, + get_other_channels, + get_temperature_channels, + get_resistance_channels, + get_device_name, + prepare_session, + start_stream, + stop_stream, + release_session, + get_current_board_data, + get_board_data_count, + get_board_data, + config_board, + is_prepared, + insert_marker, + set_log_level, + set_log_file, + log_message, + java_set_jnienv, + }) + } + pub unsafe fn get_board_descr( + &self, + board_id: ::std::os::raw::c_int, + board_descr: *mut ::std::os::raw::c_char, + len: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int { + (self + .get_board_descr + .as_ref() + .expect("Expected function, got error."))(board_id, board_descr, len) + } + pub unsafe fn get_sampling_rate( + &self, + board_id: ::std::os::raw::c_int, + sampling_rate: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int { + (self + .get_sampling_rate + .as_ref() + .expect("Expected function, got error."))(board_id, sampling_rate) + } + pub unsafe fn get_package_num_channel( + &self, + board_id: ::std::os::raw::c_int, + package_num_channel: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int { + (self + .get_package_num_channel + .as_ref() + .expect("Expected function, got error."))(board_id, package_num_channel) + } + pub unsafe fn get_timestamp_channel( + &self, + board_id: ::std::os::raw::c_int, + timestamp_channel: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int { + (self + .get_timestamp_channel + .as_ref() + .expect("Expected function, got error."))(board_id, timestamp_channel) + } + pub unsafe fn get_marker_channel( + &self, + board_id: ::std::os::raw::c_int, + marker_channel: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int { + (self + .get_marker_channel + .as_ref() + .expect("Expected function, got error."))(board_id, marker_channel) + } + pub unsafe fn get_battery_channel( + &self, + board_id: ::std::os::raw::c_int, + battery_channel: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int { + (self + .get_battery_channel + .as_ref() + .expect("Expected function, got error."))(board_id, battery_channel) + } + pub unsafe fn get_num_rows( + &self, + board_id: ::std::os::raw::c_int, + num_rows: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int { + (self + .get_num_rows + .as_ref() + .expect("Expected function, got error."))(board_id, num_rows) + } + pub unsafe fn get_eeg_names( + &self, + board_id: ::std::os::raw::c_int, + eeg_names: *mut ::std::os::raw::c_char, + len: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int { + (self + .get_eeg_names + .as_ref() + .expect("Expected function, got error."))(board_id, eeg_names, len) + } + pub unsafe fn get_exg_channels( + &self, + board_id: ::std::os::raw::c_int, + exg_channels: *mut ::std::os::raw::c_int, + len: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int { + (self + .get_exg_channels + .as_ref() + .expect("Expected function, got error."))(board_id, exg_channels, len) + } + pub unsafe fn get_eeg_channels( + &self, + board_id: ::std::os::raw::c_int, + eeg_channels: *mut ::std::os::raw::c_int, + len: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int { + (self + .get_eeg_channels + .as_ref() + .expect("Expected function, got error."))(board_id, eeg_channels, len) + } + pub unsafe fn get_emg_channels( + &self, + board_id: ::std::os::raw::c_int, + emg_channels: *mut ::std::os::raw::c_int, + len: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int { + (self + .get_emg_channels + .as_ref() + .expect("Expected function, got error."))(board_id, emg_channels, len) + } + pub unsafe fn get_ecg_channels( + &self, + board_id: ::std::os::raw::c_int, + ecg_channels: *mut ::std::os::raw::c_int, + len: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int { + (self + .get_ecg_channels + .as_ref() + .expect("Expected function, got error."))(board_id, ecg_channels, len) + } + pub unsafe fn get_eog_channels( + &self, + board_id: ::std::os::raw::c_int, + eog_channels: *mut ::std::os::raw::c_int, + len: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int { + (self + .get_eog_channels + .as_ref() + .expect("Expected function, got error."))(board_id, eog_channels, len) + } + pub unsafe fn get_ppg_channels( + &self, + board_id: ::std::os::raw::c_int, + ppg_channels: *mut ::std::os::raw::c_int, + len: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int { + (self + .get_ppg_channels + .as_ref() + .expect("Expected function, got error."))(board_id, ppg_channels, len) + } + pub unsafe fn get_eda_channels( + &self, + board_id: ::std::os::raw::c_int, + eda_channels: *mut ::std::os::raw::c_int, + len: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int { + (self + .get_eda_channels + .as_ref() + .expect("Expected function, got error."))(board_id, eda_channels, len) + } + pub unsafe fn get_accel_channels( + &self, + board_id: ::std::os::raw::c_int, + accel_channels: *mut ::std::os::raw::c_int, + len: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int { + (self + .get_accel_channels + .as_ref() + .expect("Expected function, got error."))(board_id, accel_channels, len) + } + pub unsafe fn get_analog_channels( + &self, + board_id: ::std::os::raw::c_int, + analog_channels: *mut ::std::os::raw::c_int, + len: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int { + (self + .get_analog_channels + .as_ref() + .expect("Expected function, got error."))(board_id, analog_channels, len) + } + pub unsafe fn get_gyro_channels( + &self, + board_id: ::std::os::raw::c_int, + gyro_channels: *mut ::std::os::raw::c_int, + len: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int { + (self + .get_gyro_channels + .as_ref() + .expect("Expected function, got error."))(board_id, gyro_channels, len) + } + pub unsafe fn get_other_channels( + &self, + board_id: ::std::os::raw::c_int, + other_channels: *mut ::std::os::raw::c_int, + len: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int { + (self + .get_other_channels + .as_ref() + .expect("Expected function, got error."))(board_id, other_channels, len) + } + pub unsafe fn get_temperature_channels( + &self, + board_id: ::std::os::raw::c_int, + temperature_channels: *mut ::std::os::raw::c_int, + len: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int { + (self + .get_temperature_channels + .as_ref() + .expect("Expected function, got error."))(board_id, temperature_channels, len) + } + pub unsafe fn get_resistance_channels( + &self, + board_id: ::std::os::raw::c_int, + resistance_channels: *mut ::std::os::raw::c_int, + len: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int { + (self + .get_resistance_channels + .as_ref() + .expect("Expected function, got error."))(board_id, resistance_channels, len) + } + pub unsafe fn get_device_name( + &self, + board_id: ::std::os::raw::c_int, + name: *mut ::std::os::raw::c_char, + len: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int { + (self + .get_device_name + .as_ref() + .expect("Expected function, got error."))(board_id, name, len) + } + pub unsafe fn prepare_session( + &self, + board_id: ::std::os::raw::c_int, + json_brainflow_input_params: *const ::std::os::raw::c_char, + ) -> ::std::os::raw::c_int { + (self + .prepare_session + .as_ref() + .expect("Expected function, got error."))(board_id, json_brainflow_input_params) + } + pub unsafe fn start_stream( + &self, + buffer_size: ::std::os::raw::c_int, + streamer_params: *const ::std::os::raw::c_char, + board_id: ::std::os::raw::c_int, + json_brainflow_input_params: *const ::std::os::raw::c_char, + ) -> ::std::os::raw::c_int { + (self + .start_stream + .as_ref() + .expect("Expected function, got error."))( + buffer_size, + streamer_params, + board_id, + json_brainflow_input_params, + ) + } + pub unsafe fn stop_stream( + &self, + board_id: ::std::os::raw::c_int, + json_brainflow_input_params: *const ::std::os::raw::c_char, + ) -> ::std::os::raw::c_int { + (self + .stop_stream + .as_ref() + .expect("Expected function, got error."))(board_id, json_brainflow_input_params) + } + pub unsafe fn release_session( + &self, + board_id: ::std::os::raw::c_int, + json_brainflow_input_params: *const ::std::os::raw::c_char, + ) -> ::std::os::raw::c_int { + (self + .release_session + .as_ref() + .expect("Expected function, got error."))(board_id, json_brainflow_input_params) + } + pub unsafe fn get_current_board_data( + &self, + num_samples: ::std::os::raw::c_int, + data_buf: *mut f64, + returned_samples: *mut ::std::os::raw::c_int, + board_id: ::std::os::raw::c_int, + json_brainflow_input_params: *const ::std::os::raw::c_char, + ) -> ::std::os::raw::c_int { + (self + .get_current_board_data + .as_ref() + .expect("Expected function, got error."))( + num_samples, + data_buf, + returned_samples, + board_id, + json_brainflow_input_params, + ) + } + pub unsafe fn get_board_data_count( + &self, + result: *mut ::std::os::raw::c_int, + board_id: ::std::os::raw::c_int, + json_brainflow_input_params: *const ::std::os::raw::c_char, + ) -> ::std::os::raw::c_int { + (self + .get_board_data_count + .as_ref() + .expect("Expected function, got error."))( + result, board_id, json_brainflow_input_params + ) + } + pub unsafe fn get_board_data( + &self, + data_count: ::std::os::raw::c_int, + data_buf: *mut f64, + board_id: ::std::os::raw::c_int, + json_brainflow_input_params: *const ::std::os::raw::c_char, + ) -> ::std::os::raw::c_int { + (self + .get_board_data + .as_ref() + .expect("Expected function, got error."))( + data_count, + data_buf, + board_id, + json_brainflow_input_params, + ) + } + pub unsafe fn config_board( + &self, + config: *mut ::std::os::raw::c_char, + response: *mut ::std::os::raw::c_char, + response_len: *mut ::std::os::raw::c_int, + board_id: ::std::os::raw::c_int, + json_brainflow_input_params: *const ::std::os::raw::c_char, + ) -> ::std::os::raw::c_int { + (self + .config_board + .as_ref() + .expect("Expected function, got error."))( + config, + response, + response_len, + board_id, + json_brainflow_input_params, + ) + } + pub unsafe fn is_prepared( + &self, + prepared: *mut ::std::os::raw::c_int, + board_id: ::std::os::raw::c_int, + json_brainflow_input_params: *const ::std::os::raw::c_char, + ) -> ::std::os::raw::c_int { + (self + .is_prepared + .as_ref() + .expect("Expected function, got error."))( + prepared, + board_id, + json_brainflow_input_params, + ) + } + pub unsafe fn insert_marker( + &self, + marker_value: f64, + board_id: ::std::os::raw::c_int, + json_brainflow_input_params: *const ::std::os::raw::c_char, + ) -> ::std::os::raw::c_int { + (self + .insert_marker + .as_ref() + .expect("Expected function, got error."))( + marker_value, + board_id, + json_brainflow_input_params, + ) + } + pub unsafe fn set_log_level(&self, log_level: ::std::os::raw::c_int) -> ::std::os::raw::c_int { + (self + .set_log_level + .as_ref() + .expect("Expected function, got error."))(log_level) + } + pub unsafe fn set_log_file( + &self, + log_file: *const ::std::os::raw::c_char, + ) -> ::std::os::raw::c_int { + (self + .set_log_file + .as_ref() + .expect("Expected function, got error."))(log_file) + } + pub unsafe fn log_message( + &self, + log_level: ::std::os::raw::c_int, + message: *mut ::std::os::raw::c_char, + ) -> ::std::os::raw::c_int { + (self + .log_message + .as_ref() + .expect("Expected function, got error."))(log_level, message) + } + pub unsafe fn java_set_jnienv(&self, java_jnienv: *mut JNIEnv) -> ::std::os::raw::c_int { + (self + .java_set_jnienv + .as_ref() + .expect("Expected function, got error."))(java_jnienv) + } +} diff --git a/rust-package/brainflow-sys/src/constants.rs b/rust-package/brainflow-sys/src/constants.rs new file mode 100644 index 000000000..cc5d5c0d0 --- /dev/null +++ b/rust-package/brainflow-sys/src/constants.rs @@ -0,0 +1,160 @@ +/* automatically generated by rust-bindgen 0.59.1 */ + +#![allow(non_camel_case_types)] + + +#[repr(i32)] +#[non_exhaustive] +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +pub enum BrainFlowExitCodes { + STATUS_OK = 0, + PORT_ALREADY_OPEN_ERROR = 1, + UNABLE_TO_OPEN_PORT_ERROR = 2, + SET_PORT_ERROR = 3, + BOARD_WRITE_ERROR = 4, + INCOMMING_MSG_ERROR = 5, + INITIAL_MSG_ERROR = 6, + BOARD_NOT_READY_ERROR = 7, + STREAM_ALREADY_RUN_ERROR = 8, + INVALID_BUFFER_SIZE_ERROR = 9, + STREAM_THREAD_ERROR = 10, + STREAM_THREAD_IS_NOT_RUNNING = 11, + EMPTY_BUFFER_ERROR = 12, + INVALID_ARGUMENTS_ERROR = 13, + UNSUPPORTED_BOARD_ERROR = 14, + BOARD_NOT_CREATED_ERROR = 15, + ANOTHER_BOARD_IS_CREATED_ERROR = 16, + GENERAL_ERROR = 17, + SYNC_TIMEOUT_ERROR = 18, + JSON_NOT_FOUND_ERROR = 19, + NO_SUCH_DATA_IN_JSON_ERROR = 20, + CLASSIFIER_IS_NOT_PREPARED_ERROR = 21, + ANOTHER_CLASSIFIER_IS_PREPARED_ERROR = 22, + UNSUPPORTED_CLASSIFIER_AND_METRIC_COMBINATION_ERROR = 23, +} +impl BoardIds { + pub const FIRST: BoardIds = BoardIds::PLAYBACK_FILE_BOARD; +} +impl BoardIds { + pub const LAST: BoardIds = BoardIds::ENOPHONE_BOARD; +} +#[repr(i32)] +#[non_exhaustive] +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +pub enum BoardIds { + PLAYBACK_FILE_BOARD = -3, + STREAMING_BOARD = -2, + SYNTHETIC_BOARD = -1, + CYTON_BOARD = 0, + GANGLION_BOARD = 1, + CYTON_DAISY_BOARD = 2, + GALEA_BOARD = 3, + GANGLION_WIFI_BOARD = 4, + CYTON_WIFI_BOARD = 5, + CYTON_DAISY_WIFI_BOARD = 6, + BRAINBIT_BOARD = 7, + UNICORN_BOARD = 8, + CALLIBRI_EEG_BOARD = 9, + CALLIBRI_EMG_BOARD = 10, + CALLIBRI_ECG_BOARD = 11, + FASCIA_BOARD = 12, + NOTION_1_BOARD = 13, + NOTION_2_BOARD = 14, + IRONBCI_BOARD = 15, + GFORCE_PRO_BOARD = 16, + FREEEEG32_BOARD = 17, + BRAINBIT_BLED_BOARD = 18, + GFORCE_DUAL_BOARD = 19, + GALEA_SERIAL_BOARD = 20, + MUSE_S_BLED_BOARD = 21, + MUSE_2_BLED_BOARD = 22, + CROWN_BOARD = 23, + ANT_NEURO_EE_410_BOARD = 24, + ANT_NEURO_EE_411_BOARD = 25, + ANT_NEURO_EE_430_BOARD = 26, + ANT_NEURO_EE_211_BOARD = 27, + ANT_NEURO_EE_212_BOARD = 28, + ANT_NEURO_EE_213_BOARD = 29, + ANT_NEURO_EE_214_BOARD = 30, + ANT_NEURO_EE_215_BOARD = 31, + ANT_NEURO_EE_221_BOARD = 32, + ANT_NEURO_EE_222_BOARD = 33, + ANT_NEURO_EE_223_BOARD = 34, + ANT_NEURO_EE_224_BOARD = 35, + ANT_NEURO_EE_225_BOARD = 36, + ENOPHONE_BOARD = 37, +} +#[repr(i32)] +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +pub enum IpProtocolType { + NONE = 0, + UDP = 1, + TCP = 2, +} +#[repr(i32)] +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +pub enum FilterTypes { + BUTTERWORTH = 0, + CHEBYSHEV_TYPE_1 = 1, + BESSEL = 2, +} +#[repr(i32)] +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +pub enum AggOperations { + MEAN = 0, + MEDIAN = 1, + EACH = 2, +} +#[repr(i32)] +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +pub enum WindowFunctions { + NO_WINDOW = 0, + HANNING = 1, + HAMMING = 2, + BLACKMAN_HARRIS = 3, +} +#[repr(i32)] +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +pub enum DetrendOperations { + NONE = 0, + CONSTANT = 1, + LINEAR = 2, +} +#[repr(i32)] +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +pub enum BrainFlowMetrics { + RELAXATION = 0, + CONCENTRATION = 1, +} +#[repr(i32)] +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +pub enum BrainFlowClassifiers { + REGRESSION = 0, + KNN = 1, + SVM = 2, + LDA = 3, +} +#[repr(i32)] +#[doc = " LogLevels enum to store all possible log levels"] +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +pub enum LogLevels { + LEVEL_TRACE = 0, + #[doc = " TRACE"] + LEVEL_DEBUG = 1, + #[doc = " DEBUG"] + LEVEL_INFO = 2, + #[doc = " INFO"] + LEVEL_WARN = 3, + #[doc = " WARN"] + LEVEL_ERROR = 4, + #[doc = " ERROR"] + LEVEL_CRITICAL = 5, + #[doc = " CRITICAL"] + LEVEL_OFF = 6, +} +#[repr(i32)] +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +pub enum NoiseTypes { + FIFTY = 0, + SIXTY = 1, +} diff --git a/rust-package/brainflow-sys/src/data_handler.rs b/rust-package/brainflow-sys/src/data_handler.rs new file mode 100644 index 000000000..b0a07d57c --- /dev/null +++ b/rust-package/brainflow-sys/src/data_handler.rs @@ -0,0 +1,755 @@ +/* automatically generated by rust-bindgen 0.59.1 */ + +#![allow(non_camel_case_types)] + + +extern crate libloading; +pub struct DataHandler { + __library: ::libloading::Library, + pub perform_lowpass: Result< + unsafe extern "C" fn( + data: *mut f64, + data_len: ::std::os::raw::c_int, + sampling_rate: ::std::os::raw::c_int, + cutoff: f64, + order: ::std::os::raw::c_int, + filter_type: ::std::os::raw::c_int, + ripple: f64, + ) -> ::std::os::raw::c_int, + ::libloading::Error, + >, + pub perform_highpass: Result< + unsafe extern "C" fn( + data: *mut f64, + data_len: ::std::os::raw::c_int, + sampling_rate: ::std::os::raw::c_int, + cutoff: f64, + order: ::std::os::raw::c_int, + filter_type: ::std::os::raw::c_int, + ripple: f64, + ) -> ::std::os::raw::c_int, + ::libloading::Error, + >, + pub perform_bandpass: Result< + unsafe extern "C" fn( + data: *mut f64, + data_len: ::std::os::raw::c_int, + sampling_rate: ::std::os::raw::c_int, + center_freq: f64, + band_width: f64, + order: ::std::os::raw::c_int, + filter_type: ::std::os::raw::c_int, + ripple: f64, + ) -> ::std::os::raw::c_int, + ::libloading::Error, + >, + pub perform_bandstop: Result< + unsafe extern "C" fn( + data: *mut f64, + data_len: ::std::os::raw::c_int, + sampling_rate: ::std::os::raw::c_int, + center_freq: f64, + band_width: f64, + order: ::std::os::raw::c_int, + filter_type: ::std::os::raw::c_int, + ripple: f64, + ) -> ::std::os::raw::c_int, + ::libloading::Error, + >, + pub remove_environmental_noise: Result< + unsafe extern "C" fn( + data: *mut f64, + data_len: ::std::os::raw::c_int, + sampling_rate: ::std::os::raw::c_int, + noise_type: ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int, + ::libloading::Error, + >, + pub perform_rolling_filter: Result< + unsafe extern "C" fn( + data: *mut f64, + data_len: ::std::os::raw::c_int, + period: ::std::os::raw::c_int, + agg_operation: ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int, + ::libloading::Error, + >, + pub perform_downsampling: Result< + unsafe extern "C" fn( + data: *mut f64, + data_len: ::std::os::raw::c_int, + period: ::std::os::raw::c_int, + agg_operation: ::std::os::raw::c_int, + output_data: *mut f64, + ) -> ::std::os::raw::c_int, + ::libloading::Error, + >, + pub perform_wavelet_transform: Result< + unsafe extern "C" fn( + data: *mut f64, + data_len: ::std::os::raw::c_int, + wavelet: *const ::std::os::raw::c_char, + decomposition_level: ::std::os::raw::c_int, + output_data: *mut f64, + decomposition_lengths: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int, + ::libloading::Error, + >, + pub perform_inverse_wavelet_transform: Result< + unsafe extern "C" fn( + wavelet_coeffs: *mut f64, + original_data_len: ::std::os::raw::c_int, + wavelet: *const ::std::os::raw::c_char, + decomposition_level: ::std::os::raw::c_int, + decomposition_lengths: *mut ::std::os::raw::c_int, + output_data: *mut f64, + ) -> ::std::os::raw::c_int, + ::libloading::Error, + >, + pub perform_wavelet_denoising: Result< + unsafe extern "C" fn( + data: *mut f64, + data_len: ::std::os::raw::c_int, + wavelet: *const ::std::os::raw::c_char, + decomposition_level: ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int, + ::libloading::Error, + >, + pub get_csp: Result< + unsafe extern "C" fn( + data: *const f64, + labels: *const f64, + n_epochs: ::std::os::raw::c_int, + n_channels: ::std::os::raw::c_int, + n_times: ::std::os::raw::c_int, + output_w: *mut f64, + output_d: *mut f64, + ) -> ::std::os::raw::c_int, + ::libloading::Error, + >, + pub get_window: Result< + unsafe extern "C" fn( + window_function: ::std::os::raw::c_int, + window_len: ::std::os::raw::c_int, + output_window: *mut f64, + ) -> ::std::os::raw::c_int, + ::libloading::Error, + >, + pub perform_fft: Result< + unsafe extern "C" fn( + data: *mut f64, + data_len: ::std::os::raw::c_int, + window_function: ::std::os::raw::c_int, + output_re: *mut f64, + output_im: *mut f64, + ) -> ::std::os::raw::c_int, + ::libloading::Error, + >, + pub perform_ifft: Result< + unsafe extern "C" fn( + input_re: *mut f64, + input_im: *mut f64, + data_len: ::std::os::raw::c_int, + restored_data: *mut f64, + ) -> ::std::os::raw::c_int, + ::libloading::Error, + >, + pub get_nearest_power_of_two: Result< + unsafe extern "C" fn( + value: ::std::os::raw::c_int, + output: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int, + ::libloading::Error, + >, + pub get_psd: Result< + unsafe extern "C" fn( + data: *mut f64, + data_len: ::std::os::raw::c_int, + sampling_rate: ::std::os::raw::c_int, + window_function: ::std::os::raw::c_int, + output_ampl: *mut f64, + output_freq: *mut f64, + ) -> ::std::os::raw::c_int, + ::libloading::Error, + >, + pub detrend: Result< + unsafe extern "C" fn( + data: *mut f64, + data_len: ::std::os::raw::c_int, + detrend_operation: ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int, + ::libloading::Error, + >, + pub get_psd_welch: Result< + unsafe extern "C" fn( + data: *mut f64, + data_len: ::std::os::raw::c_int, + nfft: ::std::os::raw::c_int, + overlap: ::std::os::raw::c_int, + sampling_rate: ::std::os::raw::c_int, + window_function: ::std::os::raw::c_int, + output_ampl: *mut f64, + output_freq: *mut f64, + ) -> ::std::os::raw::c_int, + ::libloading::Error, + >, + pub get_band_power: Result< + unsafe extern "C" fn( + ampl: *mut f64, + freq: *mut f64, + data_len: ::std::os::raw::c_int, + freq_start: f64, + freq_end: f64, + band_power: *mut f64, + ) -> ::std::os::raw::c_int, + ::libloading::Error, + >, + pub get_avg_band_powers: Result< + unsafe extern "C" fn( + raw_data: *mut f64, + rows: ::std::os::raw::c_int, + cols: ::std::os::raw::c_int, + sampling_rate: ::std::os::raw::c_int, + apply_filters: ::std::os::raw::c_int, + avg_band_powers: *mut f64, + stddev_band_powers: *mut f64, + ) -> ::std::os::raw::c_int, + ::libloading::Error, + >, + pub set_log_level: Result< + unsafe extern "C" fn(log_level: ::std::os::raw::c_int) -> ::std::os::raw::c_int, + ::libloading::Error, + >, + pub set_log_file: Result< + unsafe extern "C" fn(log_file: *const ::std::os::raw::c_char) -> ::std::os::raw::c_int, + ::libloading::Error, + >, + pub write_file: Result< + unsafe extern "C" fn( + data: *const f64, + num_rows: ::std::os::raw::c_int, + num_cols: ::std::os::raw::c_int, + file_name: *const ::std::os::raw::c_char, + file_mode: *const ::std::os::raw::c_char, + ) -> ::std::os::raw::c_int, + ::libloading::Error, + >, + pub read_file: Result< + unsafe extern "C" fn( + data: *mut f64, + num_rows: *mut ::std::os::raw::c_int, + num_cols: *mut ::std::os::raw::c_int, + file_name: *const ::std::os::raw::c_char, + num_elements: ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int, + ::libloading::Error, + >, + pub get_num_elements_in_file: Result< + unsafe extern "C" fn( + file_name: *const ::std::os::raw::c_char, + num_elements: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int, + ::libloading::Error, + >, +} +impl DataHandler { + pub unsafe fn new

(path: P) -> Result + where + P: AsRef<::std::ffi::OsStr>, + { + let library = ::libloading::Library::new(path)?; + Self::from_library(library) + } + pub unsafe fn from_library(library: L) -> Result + where + L: Into<::libloading::Library>, + { + let __library = library.into(); + let perform_lowpass = __library.get(b"perform_lowpass\0").map(|sym| *sym); + let perform_highpass = __library.get(b"perform_highpass\0").map(|sym| *sym); + let perform_bandpass = __library.get(b"perform_bandpass\0").map(|sym| *sym); + let perform_bandstop = __library.get(b"perform_bandstop\0").map(|sym| *sym); + let remove_environmental_noise = __library + .get(b"remove_environmental_noise\0") + .map(|sym| *sym); + let perform_rolling_filter = __library.get(b"perform_rolling_filter\0").map(|sym| *sym); + let perform_downsampling = __library.get(b"perform_downsampling\0").map(|sym| *sym); + let perform_wavelet_transform = __library + .get(b"perform_wavelet_transform\0") + .map(|sym| *sym); + let perform_inverse_wavelet_transform = __library + .get(b"perform_inverse_wavelet_transform\0") + .map(|sym| *sym); + let perform_wavelet_denoising = __library + .get(b"perform_wavelet_denoising\0") + .map(|sym| *sym); + let get_csp = __library.get(b"get_csp\0").map(|sym| *sym); + let get_window = __library.get(b"get_window\0").map(|sym| *sym); + let perform_fft = __library.get(b"perform_fft\0").map(|sym| *sym); + let perform_ifft = __library.get(b"perform_ifft\0").map(|sym| *sym); + let get_nearest_power_of_two = __library.get(b"get_nearest_power_of_two\0").map(|sym| *sym); + let get_psd = __library.get(b"get_psd\0").map(|sym| *sym); + let detrend = __library.get(b"detrend\0").map(|sym| *sym); + let get_psd_welch = __library.get(b"get_psd_welch\0").map(|sym| *sym); + let get_band_power = __library.get(b"get_band_power\0").map(|sym| *sym); + let get_avg_band_powers = __library.get(b"get_avg_band_powers\0").map(|sym| *sym); + let set_log_level = __library.get(b"set_log_level\0").map(|sym| *sym); + let set_log_file = __library.get(b"set_log_file\0").map(|sym| *sym); + let write_file = __library.get(b"write_file\0").map(|sym| *sym); + let read_file = __library.get(b"read_file\0").map(|sym| *sym); + let get_num_elements_in_file = __library.get(b"get_num_elements_in_file\0").map(|sym| *sym); + Ok(DataHandler { + __library, + perform_lowpass, + perform_highpass, + perform_bandpass, + perform_bandstop, + remove_environmental_noise, + perform_rolling_filter, + perform_downsampling, + perform_wavelet_transform, + perform_inverse_wavelet_transform, + perform_wavelet_denoising, + get_csp, + get_window, + perform_fft, + perform_ifft, + get_nearest_power_of_two, + get_psd, + detrend, + get_psd_welch, + get_band_power, + get_avg_band_powers, + set_log_level, + set_log_file, + write_file, + read_file, + get_num_elements_in_file, + }) + } + pub unsafe fn perform_lowpass( + &self, + data: *mut f64, + data_len: ::std::os::raw::c_int, + sampling_rate: ::std::os::raw::c_int, + cutoff: f64, + order: ::std::os::raw::c_int, + filter_type: ::std::os::raw::c_int, + ripple: f64, + ) -> ::std::os::raw::c_int { + (self + .perform_lowpass + .as_ref() + .expect("Expected function, got error."))( + data, + data_len, + sampling_rate, + cutoff, + order, + filter_type, + ripple, + ) + } + pub unsafe fn perform_highpass( + &self, + data: *mut f64, + data_len: ::std::os::raw::c_int, + sampling_rate: ::std::os::raw::c_int, + cutoff: f64, + order: ::std::os::raw::c_int, + filter_type: ::std::os::raw::c_int, + ripple: f64, + ) -> ::std::os::raw::c_int { + (self + .perform_highpass + .as_ref() + .expect("Expected function, got error."))( + data, + data_len, + sampling_rate, + cutoff, + order, + filter_type, + ripple, + ) + } + pub unsafe fn perform_bandpass( + &self, + data: *mut f64, + data_len: ::std::os::raw::c_int, + sampling_rate: ::std::os::raw::c_int, + center_freq: f64, + band_width: f64, + order: ::std::os::raw::c_int, + filter_type: ::std::os::raw::c_int, + ripple: f64, + ) -> ::std::os::raw::c_int { + (self + .perform_bandpass + .as_ref() + .expect("Expected function, got error."))( + data, + data_len, + sampling_rate, + center_freq, + band_width, + order, + filter_type, + ripple, + ) + } + pub unsafe fn perform_bandstop( + &self, + data: *mut f64, + data_len: ::std::os::raw::c_int, + sampling_rate: ::std::os::raw::c_int, + center_freq: f64, + band_width: f64, + order: ::std::os::raw::c_int, + filter_type: ::std::os::raw::c_int, + ripple: f64, + ) -> ::std::os::raw::c_int { + (self + .perform_bandstop + .as_ref() + .expect("Expected function, got error."))( + data, + data_len, + sampling_rate, + center_freq, + band_width, + order, + filter_type, + ripple, + ) + } + pub unsafe fn remove_environmental_noise( + &self, + data: *mut f64, + data_len: ::std::os::raw::c_int, + sampling_rate: ::std::os::raw::c_int, + noise_type: ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int { + (self + .remove_environmental_noise + .as_ref() + .expect("Expected function, got error."))( + data, data_len, sampling_rate, noise_type + ) + } + pub unsafe fn perform_rolling_filter( + &self, + data: *mut f64, + data_len: ::std::os::raw::c_int, + period: ::std::os::raw::c_int, + agg_operation: ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int { + (self + .perform_rolling_filter + .as_ref() + .expect("Expected function, got error."))(data, data_len, period, agg_operation) + } + pub unsafe fn perform_downsampling( + &self, + data: *mut f64, + data_len: ::std::os::raw::c_int, + period: ::std::os::raw::c_int, + agg_operation: ::std::os::raw::c_int, + output_data: *mut f64, + ) -> ::std::os::raw::c_int { + (self + .perform_downsampling + .as_ref() + .expect("Expected function, got error."))( + data, + data_len, + period, + agg_operation, + output_data, + ) + } + pub unsafe fn perform_wavelet_transform( + &self, + data: *mut f64, + data_len: ::std::os::raw::c_int, + wavelet: *const ::std::os::raw::c_char, + decomposition_level: ::std::os::raw::c_int, + output_data: *mut f64, + decomposition_lengths: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int { + (self + .perform_wavelet_transform + .as_ref() + .expect("Expected function, got error."))( + data, + data_len, + wavelet, + decomposition_level, + output_data, + decomposition_lengths, + ) + } + pub unsafe fn perform_inverse_wavelet_transform( + &self, + wavelet_coeffs: *mut f64, + original_data_len: ::std::os::raw::c_int, + wavelet: *const ::std::os::raw::c_char, + decomposition_level: ::std::os::raw::c_int, + decomposition_lengths: *mut ::std::os::raw::c_int, + output_data: *mut f64, + ) -> ::std::os::raw::c_int { + (self + .perform_inverse_wavelet_transform + .as_ref() + .expect("Expected function, got error."))( + wavelet_coeffs, + original_data_len, + wavelet, + decomposition_level, + decomposition_lengths, + output_data, + ) + } + pub unsafe fn perform_wavelet_denoising( + &self, + data: *mut f64, + data_len: ::std::os::raw::c_int, + wavelet: *const ::std::os::raw::c_char, + decomposition_level: ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int { + (self + .perform_wavelet_denoising + .as_ref() + .expect("Expected function, got error."))( + data, data_len, wavelet, decomposition_level + ) + } + pub unsafe fn get_csp( + &self, + data: *const f64, + labels: *const f64, + n_epochs: ::std::os::raw::c_int, + n_channels: ::std::os::raw::c_int, + n_times: ::std::os::raw::c_int, + output_w: *mut f64, + output_d: *mut f64, + ) -> ::std::os::raw::c_int { + (self + .get_csp + .as_ref() + .expect("Expected function, got error."))( + data, labels, n_epochs, n_channels, n_times, output_w, output_d, + ) + } + pub unsafe fn get_window( + &self, + window_function: ::std::os::raw::c_int, + window_len: ::std::os::raw::c_int, + output_window: *mut f64, + ) -> ::std::os::raw::c_int { + (self + .get_window + .as_ref() + .expect("Expected function, got error."))( + window_function, window_len, output_window + ) + } + pub unsafe fn perform_fft( + &self, + data: *mut f64, + data_len: ::std::os::raw::c_int, + window_function: ::std::os::raw::c_int, + output_re: *mut f64, + output_im: *mut f64, + ) -> ::std::os::raw::c_int { + (self + .perform_fft + .as_ref() + .expect("Expected function, got error."))( + data, + data_len, + window_function, + output_re, + output_im, + ) + } + pub unsafe fn perform_ifft( + &self, + input_re: *mut f64, + input_im: *mut f64, + data_len: ::std::os::raw::c_int, + restored_data: *mut f64, + ) -> ::std::os::raw::c_int { + (self + .perform_ifft + .as_ref() + .expect("Expected function, got error."))( + input_re, input_im, data_len, restored_data + ) + } + pub unsafe fn get_nearest_power_of_two( + &self, + value: ::std::os::raw::c_int, + output: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int { + (self + .get_nearest_power_of_two + .as_ref() + .expect("Expected function, got error."))(value, output) + } + pub unsafe fn get_psd( + &self, + data: *mut f64, + data_len: ::std::os::raw::c_int, + sampling_rate: ::std::os::raw::c_int, + window_function: ::std::os::raw::c_int, + output_ampl: *mut f64, + output_freq: *mut f64, + ) -> ::std::os::raw::c_int { + (self + .get_psd + .as_ref() + .expect("Expected function, got error."))( + data, + data_len, + sampling_rate, + window_function, + output_ampl, + output_freq, + ) + } + pub unsafe fn detrend( + &self, + data: *mut f64, + data_len: ::std::os::raw::c_int, + detrend_operation: ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int { + (self + .detrend + .as_ref() + .expect("Expected function, got error."))(data, data_len, detrend_operation) + } + pub unsafe fn get_psd_welch( + &self, + data: *mut f64, + data_len: ::std::os::raw::c_int, + nfft: ::std::os::raw::c_int, + overlap: ::std::os::raw::c_int, + sampling_rate: ::std::os::raw::c_int, + window_function: ::std::os::raw::c_int, + output_ampl: *mut f64, + output_freq: *mut f64, + ) -> ::std::os::raw::c_int { + (self + .get_psd_welch + .as_ref() + .expect("Expected function, got error."))( + data, + data_len, + nfft, + overlap, + sampling_rate, + window_function, + output_ampl, + output_freq, + ) + } + pub unsafe fn get_band_power( + &self, + ampl: *mut f64, + freq: *mut f64, + data_len: ::std::os::raw::c_int, + freq_start: f64, + freq_end: f64, + band_power: *mut f64, + ) -> ::std::os::raw::c_int { + (self + .get_band_power + .as_ref() + .expect("Expected function, got error."))( + ampl, freq, data_len, freq_start, freq_end, band_power, + ) + } + pub unsafe fn get_avg_band_powers( + &self, + raw_data: *mut f64, + rows: ::std::os::raw::c_int, + cols: ::std::os::raw::c_int, + sampling_rate: ::std::os::raw::c_int, + apply_filters: ::std::os::raw::c_int, + avg_band_powers: *mut f64, + stddev_band_powers: *mut f64, + ) -> ::std::os::raw::c_int { + (self + .get_avg_band_powers + .as_ref() + .expect("Expected function, got error."))( + raw_data, + rows, + cols, + sampling_rate, + apply_filters, + avg_band_powers, + stddev_band_powers, + ) + } + pub unsafe fn set_log_level(&self, log_level: ::std::os::raw::c_int) -> ::std::os::raw::c_int { + (self + .set_log_level + .as_ref() + .expect("Expected function, got error."))(log_level) + } + pub unsafe fn set_log_file( + &self, + log_file: *const ::std::os::raw::c_char, + ) -> ::std::os::raw::c_int { + (self + .set_log_file + .as_ref() + .expect("Expected function, got error."))(log_file) + } + pub unsafe fn write_file( + &self, + data: *const f64, + num_rows: ::std::os::raw::c_int, + num_cols: ::std::os::raw::c_int, + file_name: *const ::std::os::raw::c_char, + file_mode: *const ::std::os::raw::c_char, + ) -> ::std::os::raw::c_int { + (self + .write_file + .as_ref() + .expect("Expected function, got error."))( + data, num_rows, num_cols, file_name, file_mode, + ) + } + pub unsafe fn read_file( + &self, + data: *mut f64, + num_rows: *mut ::std::os::raw::c_int, + num_cols: *mut ::std::os::raw::c_int, + file_name: *const ::std::os::raw::c_char, + num_elements: ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int { + (self + .read_file + .as_ref() + .expect("Expected function, got error."))( + data, + num_rows, + num_cols, + file_name, + num_elements, + ) + } + pub unsafe fn get_num_elements_in_file( + &self, + file_name: *const ::std::os::raw::c_char, + num_elements: *mut ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int { + (self + .get_num_elements_in_file + .as_ref() + .expect("Expected function, got error."))(file_name, num_elements) + } +} diff --git a/rust-package/brainflow-sys/src/lib.rs b/rust-package/brainflow-sys/src/lib.rs index e8b699a62..0d7ac138b 100644 --- a/rust-package/brainflow-sys/src/lib.rs +++ b/rust-package/brainflow-sys/src/lib.rs @@ -1,630 +1,4 @@ -/* automatically generated by rust-bindgen 0.59.1 */ - -#![allow(non_camel_case_types)] - - -#[repr(i32)] -#[non_exhaustive] -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] -pub enum BrainFlowExitCodes { - STATUS_OK = 0, - PORT_ALREADY_OPEN_ERROR = 1, - UNABLE_TO_OPEN_PORT_ERROR = 2, - SET_PORT_ERROR = 3, - BOARD_WRITE_ERROR = 4, - INCOMMING_MSG_ERROR = 5, - INITIAL_MSG_ERROR = 6, - BOARD_NOT_READY_ERROR = 7, - STREAM_ALREADY_RUN_ERROR = 8, - INVALID_BUFFER_SIZE_ERROR = 9, - STREAM_THREAD_ERROR = 10, - STREAM_THREAD_IS_NOT_RUNNING = 11, - EMPTY_BUFFER_ERROR = 12, - INVALID_ARGUMENTS_ERROR = 13, - UNSUPPORTED_BOARD_ERROR = 14, - BOARD_NOT_CREATED_ERROR = 15, - ANOTHER_BOARD_IS_CREATED_ERROR = 16, - GENERAL_ERROR = 17, - SYNC_TIMEOUT_ERROR = 18, - JSON_NOT_FOUND_ERROR = 19, - NO_SUCH_DATA_IN_JSON_ERROR = 20, - CLASSIFIER_IS_NOT_PREPARED_ERROR = 21, - ANOTHER_CLASSIFIER_IS_PREPARED_ERROR = 22, - UNSUPPORTED_CLASSIFIER_AND_METRIC_COMBINATION_ERROR = 23, -} -impl BoardIds { - pub const FIRST: BoardIds = BoardIds::PLAYBACK_FILE_BOARD; -} -impl BoardIds { - pub const LAST: BoardIds = BoardIds::ENOPHONE_BOARD; -} -#[repr(i32)] -#[non_exhaustive] -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] -pub enum BoardIds { - PLAYBACK_FILE_BOARD = -3, - STREAMING_BOARD = -2, - SYNTHETIC_BOARD = -1, - CYTON_BOARD = 0, - GANGLION_BOARD = 1, - CYTON_DAISY_BOARD = 2, - GALEA_BOARD = 3, - GANGLION_WIFI_BOARD = 4, - CYTON_WIFI_BOARD = 5, - CYTON_DAISY_WIFI_BOARD = 6, - BRAINBIT_BOARD = 7, - UNICORN_BOARD = 8, - CALLIBRI_EEG_BOARD = 9, - CALLIBRI_EMG_BOARD = 10, - CALLIBRI_ECG_BOARD = 11, - FASCIA_BOARD = 12, - NOTION_1_BOARD = 13, - NOTION_2_BOARD = 14, - IRONBCI_BOARD = 15, - GFORCE_PRO_BOARD = 16, - FREEEEG32_BOARD = 17, - BRAINBIT_BLED_BOARD = 18, - GFORCE_DUAL_BOARD = 19, - GALEA_SERIAL_BOARD = 20, - MUSE_S_BLED_BOARD = 21, - MUSE_2_BLED_BOARD = 22, - CROWN_BOARD = 23, - ANT_NEURO_EE_410_BOARD = 24, - ANT_NEURO_EE_411_BOARD = 25, - ANT_NEURO_EE_430_BOARD = 26, - ANT_NEURO_EE_211_BOARD = 27, - ANT_NEURO_EE_212_BOARD = 28, - ANT_NEURO_EE_213_BOARD = 29, - ANT_NEURO_EE_214_BOARD = 30, - ANT_NEURO_EE_215_BOARD = 31, - ANT_NEURO_EE_221_BOARD = 32, - ANT_NEURO_EE_222_BOARD = 33, - ANT_NEURO_EE_223_BOARD = 34, - ANT_NEURO_EE_224_BOARD = 35, - ANT_NEURO_EE_225_BOARD = 36, - ENOPHONE_BOARD = 37, -} -#[repr(i32)] -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] -pub enum IpProtocolType { - NONE = 0, - UDP = 1, - TCP = 2, -} -#[repr(i32)] -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] -pub enum FilterTypes { - BUTTERWORTH = 0, - CHEBYSHEV_TYPE_1 = 1, - BESSEL = 2, -} -#[repr(i32)] -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] -pub enum AggOperations { - MEAN = 0, - MEDIAN = 1, - EACH = 2, -} -#[repr(i32)] -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] -pub enum WindowFunctions { - NO_WINDOW = 0, - HANNING = 1, - HAMMING = 2, - BLACKMAN_HARRIS = 3, -} -#[repr(i32)] -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] -pub enum DetrendOperations { - NONE = 0, - CONSTANT = 1, - LINEAR = 2, -} -#[repr(i32)] -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] -pub enum BrainFlowMetrics { - RELAXATION = 0, - CONCENTRATION = 1, -} -#[repr(i32)] -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] -pub enum BrainFlowClassifiers { - REGRESSION = 0, - KNN = 1, - SVM = 2, - LDA = 3, -} -#[repr(i32)] -#[doc = " LogLevels enum to store all possible log levels"] -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] -pub enum LogLevels { - LEVEL_TRACE = 0, - #[doc = " TRACE"] - LEVEL_DEBUG = 1, - #[doc = " DEBUG"] - LEVEL_INFO = 2, - #[doc = " INFO"] - LEVEL_WARN = 3, - #[doc = " WARN"] - LEVEL_ERROR = 4, - #[doc = " ERROR"] - LEVEL_CRITICAL = 5, - #[doc = " CRITICAL"] - LEVEL_OFF = 6, -} -#[repr(i32)] -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] -pub enum NoiseTypes { - FIFTY = 0, - SIXTY = 1, -} -extern "C" { - pub fn get_board_descr( - board_id: ::std::os::raw::c_int, - board_descr: *mut ::std::os::raw::c_char, - len: *mut ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn get_sampling_rate( - board_id: ::std::os::raw::c_int, - sampling_rate: *mut ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn get_package_num_channel( - board_id: ::std::os::raw::c_int, - package_num_channel: *mut ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn get_timestamp_channel( - board_id: ::std::os::raw::c_int, - timestamp_channel: *mut ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn get_marker_channel( - board_id: ::std::os::raw::c_int, - marker_channel: *mut ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn get_battery_channel( - board_id: ::std::os::raw::c_int, - battery_channel: *mut ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn get_num_rows( - board_id: ::std::os::raw::c_int, - num_rows: *mut ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn get_eeg_names( - board_id: ::std::os::raw::c_int, - eeg_names: *mut ::std::os::raw::c_char, - len: *mut ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn get_exg_channels( - board_id: ::std::os::raw::c_int, - exg_channels: *mut ::std::os::raw::c_int, - len: *mut ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn get_eeg_channels( - board_id: ::std::os::raw::c_int, - eeg_channels: *mut ::std::os::raw::c_int, - len: *mut ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn get_emg_channels( - board_id: ::std::os::raw::c_int, - emg_channels: *mut ::std::os::raw::c_int, - len: *mut ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn get_ecg_channels( - board_id: ::std::os::raw::c_int, - ecg_channels: *mut ::std::os::raw::c_int, - len: *mut ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn get_eog_channels( - board_id: ::std::os::raw::c_int, - eog_channels: *mut ::std::os::raw::c_int, - len: *mut ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn get_ppg_channels( - board_id: ::std::os::raw::c_int, - ppg_channels: *mut ::std::os::raw::c_int, - len: *mut ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn get_eda_channels( - board_id: ::std::os::raw::c_int, - eda_channels: *mut ::std::os::raw::c_int, - len: *mut ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn get_accel_channels( - board_id: ::std::os::raw::c_int, - accel_channels: *mut ::std::os::raw::c_int, - len: *mut ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn get_analog_channels( - board_id: ::std::os::raw::c_int, - analog_channels: *mut ::std::os::raw::c_int, - len: *mut ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn get_gyro_channels( - board_id: ::std::os::raw::c_int, - gyro_channels: *mut ::std::os::raw::c_int, - len: *mut ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn get_other_channels( - board_id: ::std::os::raw::c_int, - other_channels: *mut ::std::os::raw::c_int, - len: *mut ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn get_temperature_channels( - board_id: ::std::os::raw::c_int, - temperature_channels: *mut ::std::os::raw::c_int, - len: *mut ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn get_resistance_channels( - board_id: ::std::os::raw::c_int, - resistance_channels: *mut ::std::os::raw::c_int, - len: *mut ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn get_device_name( - board_id: ::std::os::raw::c_int, - name: *mut ::std::os::raw::c_char, - len: *mut ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn prepare_session( - board_id: ::std::os::raw::c_int, - json_brainflow_input_params: *const ::std::os::raw::c_char, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn start_stream( - buffer_size: ::std::os::raw::c_int, - streamer_params: *const ::std::os::raw::c_char, - board_id: ::std::os::raw::c_int, - json_brainflow_input_params: *const ::std::os::raw::c_char, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn stop_stream( - board_id: ::std::os::raw::c_int, - json_brainflow_input_params: *const ::std::os::raw::c_char, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn release_session( - board_id: ::std::os::raw::c_int, - json_brainflow_input_params: *const ::std::os::raw::c_char, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn get_current_board_data( - num_samples: ::std::os::raw::c_int, - data_buf: *mut f64, - returned_samples: *mut ::std::os::raw::c_int, - board_id: ::std::os::raw::c_int, - json_brainflow_input_params: *const ::std::os::raw::c_char, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn get_board_data_count( - result: *mut ::std::os::raw::c_int, - board_id: ::std::os::raw::c_int, - json_brainflow_input_params: *const ::std::os::raw::c_char, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn get_board_data( - data_count: ::std::os::raw::c_int, - data_buf: *mut f64, - board_id: ::std::os::raw::c_int, - json_brainflow_input_params: *const ::std::os::raw::c_char, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn config_board( - config: *mut ::std::os::raw::c_char, - response: *mut ::std::os::raw::c_char, - response_len: *mut ::std::os::raw::c_int, - board_id: ::std::os::raw::c_int, - json_brainflow_input_params: *const ::std::os::raw::c_char, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn is_prepared( - prepared: *mut ::std::os::raw::c_int, - board_id: ::std::os::raw::c_int, - json_brainflow_input_params: *const ::std::os::raw::c_char, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn insert_marker( - marker_value: f64, - board_id: ::std::os::raw::c_int, - json_brainflow_input_params: *const ::std::os::raw::c_char, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn set_log_level(log_level: ::std::os::raw::c_int) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn set_log_file(log_file: *const ::std::os::raw::c_char) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn log_message( - log_level: ::std::os::raw::c_int, - message: *mut ::std::os::raw::c_char, - ) -> ::std::os::raw::c_int; -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct JNINativeInterface { - _unused: [u8; 0], -} -pub type JNIEnv = *const JNINativeInterface; -extern "C" { - pub fn java_set_jnienv(java_jnienv: *mut JNIEnv) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn perform_lowpass( - data: *mut f64, - data_len: ::std::os::raw::c_int, - sampling_rate: ::std::os::raw::c_int, - cutoff: f64, - order: ::std::os::raw::c_int, - filter_type: ::std::os::raw::c_int, - ripple: f64, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn perform_highpass( - data: *mut f64, - data_len: ::std::os::raw::c_int, - sampling_rate: ::std::os::raw::c_int, - cutoff: f64, - order: ::std::os::raw::c_int, - filter_type: ::std::os::raw::c_int, - ripple: f64, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn perform_bandpass( - data: *mut f64, - data_len: ::std::os::raw::c_int, - sampling_rate: ::std::os::raw::c_int, - center_freq: f64, - band_width: f64, - order: ::std::os::raw::c_int, - filter_type: ::std::os::raw::c_int, - ripple: f64, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn perform_bandstop( - data: *mut f64, - data_len: ::std::os::raw::c_int, - sampling_rate: ::std::os::raw::c_int, - center_freq: f64, - band_width: f64, - order: ::std::os::raw::c_int, - filter_type: ::std::os::raw::c_int, - ripple: f64, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn remove_environmental_noise( - data: *mut f64, - data_len: ::std::os::raw::c_int, - sampling_rate: ::std::os::raw::c_int, - noise_type: ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn perform_rolling_filter( - data: *mut f64, - data_len: ::std::os::raw::c_int, - period: ::std::os::raw::c_int, - agg_operation: ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn perform_downsampling( - data: *mut f64, - data_len: ::std::os::raw::c_int, - period: ::std::os::raw::c_int, - agg_operation: ::std::os::raw::c_int, - output_data: *mut f64, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn perform_wavelet_transform( - data: *mut f64, - data_len: ::std::os::raw::c_int, - wavelet: *const ::std::os::raw::c_char, - decomposition_level: ::std::os::raw::c_int, - output_data: *mut f64, - decomposition_lengths: *mut ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn perform_inverse_wavelet_transform( - wavelet_coeffs: *mut f64, - original_data_len: ::std::os::raw::c_int, - wavelet: *const ::std::os::raw::c_char, - decomposition_level: ::std::os::raw::c_int, - decomposition_lengths: *mut ::std::os::raw::c_int, - output_data: *mut f64, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn perform_wavelet_denoising( - data: *mut f64, - data_len: ::std::os::raw::c_int, - wavelet: *const ::std::os::raw::c_char, - decomposition_level: ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn get_csp( - data: *const f64, - labels: *const f64, - n_epochs: ::std::os::raw::c_int, - n_channels: ::std::os::raw::c_int, - n_times: ::std::os::raw::c_int, - output_w: *mut f64, - output_d: *mut f64, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn get_window( - window_function: ::std::os::raw::c_int, - window_len: ::std::os::raw::c_int, - output_window: *mut f64, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn perform_fft( - data: *mut f64, - data_len: ::std::os::raw::c_int, - window_function: ::std::os::raw::c_int, - output_re: *mut f64, - output_im: *mut f64, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn perform_ifft( - input_re: *mut f64, - input_im: *mut f64, - data_len: ::std::os::raw::c_int, - restored_data: *mut f64, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn get_nearest_power_of_two( - value: ::std::os::raw::c_int, - output: *mut ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn get_psd( - data: *mut f64, - data_len: ::std::os::raw::c_int, - sampling_rate: ::std::os::raw::c_int, - window_function: ::std::os::raw::c_int, - output_ampl: *mut f64, - output_freq: *mut f64, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn detrend( - data: *mut f64, - data_len: ::std::os::raw::c_int, - detrend_operation: ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn get_psd_welch( - data: *mut f64, - data_len: ::std::os::raw::c_int, - nfft: ::std::os::raw::c_int, - overlap: ::std::os::raw::c_int, - sampling_rate: ::std::os::raw::c_int, - window_function: ::std::os::raw::c_int, - output_ampl: *mut f64, - output_freq: *mut f64, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn get_band_power( - ampl: *mut f64, - freq: *mut f64, - data_len: ::std::os::raw::c_int, - freq_start: f64, - freq_end: f64, - band_power: *mut f64, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn get_avg_band_powers( - raw_data: *mut f64, - rows: ::std::os::raw::c_int, - cols: ::std::os::raw::c_int, - sampling_rate: ::std::os::raw::c_int, - apply_filters: ::std::os::raw::c_int, - avg_band_powers: *mut f64, - stddev_band_powers: *mut f64, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn write_file( - data: *const f64, - num_rows: ::std::os::raw::c_int, - num_cols: ::std::os::raw::c_int, - file_name: *const ::std::os::raw::c_char, - file_mode: *const ::std::os::raw::c_char, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn read_file( - data: *mut f64, - num_rows: *mut ::std::os::raw::c_int, - num_cols: *mut ::std::os::raw::c_int, - file_name: *const ::std::os::raw::c_char, - num_elements: ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn get_num_elements_in_file( - file_name: *const ::std::os::raw::c_char, - num_elements: *mut ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn prepare(json_params: *const ::std::os::raw::c_char) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn predict( - data: *mut f64, - data_len: ::std::os::raw::c_int, - output: *mut f64, - json_params: *const ::std::os::raw::c_char, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn release(json_params: *const ::std::os::raw::c_char) -> ::std::os::raw::c_int; -} +pub mod board_controller; +pub mod constants; +pub mod data_handler; +pub mod ml_model; diff --git a/rust-package/brainflow-sys/src/ml_model.rs b/rust-package/brainflow-sys/src/ml_model.rs new file mode 100644 index 000000000..7f15dd434 --- /dev/null +++ b/rust-package/brainflow-sys/src/ml_model.rs @@ -0,0 +1,107 @@ +/* automatically generated by rust-bindgen 0.59.1 */ + +#![allow(non_camel_case_types)] + + +extern crate libloading; +pub struct MlModule { + __library: ::libloading::Library, + pub prepare: Result< + unsafe extern "C" fn(json_params: *const ::std::os::raw::c_char) -> ::std::os::raw::c_int, + ::libloading::Error, + >, + pub predict: Result< + unsafe extern "C" fn( + data: *mut f64, + data_len: ::std::os::raw::c_int, + output: *mut f64, + json_params: *const ::std::os::raw::c_char, + ) -> ::std::os::raw::c_int, + ::libloading::Error, + >, + pub release: Result< + unsafe extern "C" fn(json_params: *const ::std::os::raw::c_char) -> ::std::os::raw::c_int, + ::libloading::Error, + >, + pub set_log_level: Result< + unsafe extern "C" fn(log_level: ::std::os::raw::c_int) -> ::std::os::raw::c_int, + ::libloading::Error, + >, + pub set_log_file: Result< + unsafe extern "C" fn(log_file: *const ::std::os::raw::c_char) -> ::std::os::raw::c_int, + ::libloading::Error, + >, +} +impl MlModule { + pub unsafe fn new

(path: P) -> Result + where + P: AsRef<::std::ffi::OsStr>, + { + let library = ::libloading::Library::new(path)?; + Self::from_library(library) + } + pub unsafe fn from_library(library: L) -> Result + where + L: Into<::libloading::Library>, + { + let __library = library.into(); + let prepare = __library.get(b"prepare\0").map(|sym| *sym); + let predict = __library.get(b"predict\0").map(|sym| *sym); + let release = __library.get(b"release\0").map(|sym| *sym); + let set_log_level = __library.get(b"set_log_level\0").map(|sym| *sym); + let set_log_file = __library.get(b"set_log_file\0").map(|sym| *sym); + Ok(MlModule { + __library, + prepare, + predict, + release, + set_log_level, + set_log_file, + }) + } + pub unsafe fn prepare( + &self, + json_params: *const ::std::os::raw::c_char, + ) -> ::std::os::raw::c_int { + (self + .prepare + .as_ref() + .expect("Expected function, got error."))(json_params) + } + pub unsafe fn predict( + &self, + data: *mut f64, + data_len: ::std::os::raw::c_int, + output: *mut f64, + json_params: *const ::std::os::raw::c_char, + ) -> ::std::os::raw::c_int { + (self + .predict + .as_ref() + .expect("Expected function, got error."))(data, data_len, output, json_params) + } + pub unsafe fn release( + &self, + json_params: *const ::std::os::raw::c_char, + ) -> ::std::os::raw::c_int { + (self + .release + .as_ref() + .expect("Expected function, got error."))(json_params) + } + pub unsafe fn set_log_level(&self, log_level: ::std::os::raw::c_int) -> ::std::os::raw::c_int { + (self + .set_log_level + .as_ref() + .expect("Expected function, got error."))(log_level) + } + pub unsafe fn set_log_file( + &self, + log_file: *const ::std::os::raw::c_char, + ) -> ::std::os::raw::c_int { + (self + .set_log_file + .as_ref() + .expect("Expected function, got error."))(log_file) + } +} diff --git a/rust-package/brainflow/Cargo.toml b/rust-package/brainflow/Cargo.toml index dfc4fe600..a0393f29c 100644 --- a/rust-package/brainflow/Cargo.toml +++ b/rust-package/brainflow/Cargo.toml @@ -13,6 +13,7 @@ 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" diff --git a/rust-package/brainflow/examples/cyton.rs b/rust-package/brainflow/examples/cyton.rs index 4e9cdb9bb..b156905bb 100644 --- a/rust-package/brainflow/examples/cyton.rs +++ b/rust-package/brainflow/examples/cyton.rs @@ -4,8 +4,8 @@ use brainflow::ml_model::{BrainFlowModelParamsBuilder, MlModel}; use brainflow::BoardId; fn main() { - brainflow::ml_model::enable_ml_logger().unwrap(); brainflow::board_shim::enable_dev_board_logger().unwrap(); + brainflow::ml_model::enable_ml_logger().unwrap(); let params = BrainFlowInputParamsBuilder::default() .serial_port("/dev/ttyUSB0") .build(); diff --git a/rust-package/brainflow/src/board_shim.rs b/rust-package/brainflow/src/board_shim.rs index 770e1f07c..7a76e19eb 100644 --- a/rust-package/brainflow/src/board_shim.rs +++ b/rust-package/brainflow/src/board_shim.rs @@ -1,20 +1,32 @@ +use once_cell::sync::Lazy; use paste::paste; use std::{ ffi::CString, os::raw::{c_double, c_int}, + path::Path, + sync::Mutex, }; -use ffi::LogLevels; - use crate::{ brainflow_input_params::BrainFlowInputParams, check_brainflow_exit_code, error::{BrainFlowError, Error}, - ffi, BoardId, Result, + BoardId, Result, }; +use brainflow_sys::board_controller::BoardController; +use brainflow_sys::constants::LogLevels; + const MAX_CHANNELS: usize = 512; +pub static BOARD_CONTROLLER: Lazy> = Lazy::new(|| { + let lib_path = Path::new( + "../brainflow-sys/target/debug/build/brainflow-sys-7b10940f08b63c04/out/lib/libBoardController.so", + ); + let board_controller = unsafe { BoardController::new(lib_path).unwrap() }; + Mutex::new(board_controller) +}); + pub struct BoardShim { board_id: BoardId, input_params: BrainFlowInputParams, @@ -34,7 +46,7 @@ impl BoardShim { pub fn prepare_session(&self) -> Result<()> { let res = unsafe { - ffi::prepare_session( + BOARD_CONTROLLER.lock().unwrap().prepare_session( self.board_id as c_int, self.json_brainflow_input_params.as_ptr(), ) @@ -45,7 +57,7 @@ impl BoardShim { pub fn is_prepared(&self) -> Result { let mut prepared = 0; let res = unsafe { - ffi::is_prepared( + BOARD_CONTROLLER.lock().unwrap().is_prepared( &mut prepared, self.board_id as c_int, self.json_brainflow_input_params.as_ptr(), @@ -62,7 +74,7 @@ impl BoardShim { ) -> Result<()> { let streamer_params = CString::new(streamer_params.as_ref())?; let res = unsafe { - ffi::start_stream( + BOARD_CONTROLLER.lock().unwrap().start_stream( buffer_size as c_int, streamer_params.as_ptr(), self.board_id as c_int, @@ -74,7 +86,7 @@ impl BoardShim { pub fn stop_stream(&self) -> Result<()> { let res = unsafe { - ffi::stop_stream( + BOARD_CONTROLLER.lock().unwrap().stop_stream( self.board_id as c_int, self.json_brainflow_input_params.as_ptr(), ) @@ -84,7 +96,7 @@ impl BoardShim { pub fn release_session(&self) -> Result<()> { let res = unsafe { - ffi::release_session( + BOARD_CONTROLLER.lock().unwrap().release_session( self.board_id as c_int, self.json_brainflow_input_params.as_ptr(), ) @@ -95,7 +107,7 @@ impl BoardShim { pub fn board_data_count(&self) -> Result { let mut data_count = 0; let res = unsafe { - ffi::get_board_data_count( + BOARD_CONTROLLER.lock().unwrap().get_board_data_count( &mut data_count, self.board_id as c_int, self.json_brainflow_input_params.as_ptr(), @@ -118,7 +130,7 @@ impl BoardShim { }; let mut data_buf = Vec::with_capacity(num_samples * num_rows); let res = unsafe { - ffi::get_board_data( + BOARD_CONTROLLER.lock().unwrap().get_board_data( num_samples as c_int, data_buf.as_mut_ptr(), self.board_id as c_int, @@ -140,7 +152,7 @@ impl BoardShim { let mut data_buf = Vec::with_capacity(num_samples * num_rows); let mut len = 0; let res = unsafe { - ffi::get_current_board_data( + BOARD_CONTROLLER.lock().unwrap().get_current_board_data( num_samples as c_int, data_buf.as_mut_ptr(), &mut len, @@ -165,7 +177,7 @@ impl BoardShim { let response = response.into_raw(); let config = config.into_raw(); let (res, response) = unsafe { - let res = ffi::config_board( + let res = BOARD_CONTROLLER.lock().unwrap().config_board( config, response, &mut response_len, @@ -186,7 +198,7 @@ impl BoardShim { pub fn insert_marker(&self, value: f64) -> Result<()> { let res = unsafe { - ffi::insert_marker( + BOARD_CONTROLLER.lock().unwrap().insert_marker( value as c_double, self.board_id as c_int, self.json_brainflow_input_params.as_ptr(), @@ -206,9 +218,13 @@ impl BoardShim { }) } } - pub fn set_log_level(log_level: LogLevels) -> Result<()> { - let res = unsafe { ffi::set_log_level(log_level as c_int) }; + let res = unsafe { + BOARD_CONTROLLER + .lock() + .unwrap() + .set_log_level(log_level as c_int) + }; Ok(check_brainflow_exit_code(res)?) } @@ -227,15 +243,47 @@ pub fn enable_dev_board_logger() -> Result<()> { pub fn set_log_file>(log_file: S) -> Result<()> { let log_file = log_file.as_ref(); let log_file = CString::new(log_file)?; - let res = unsafe { ffi::set_log_file(log_file.as_ptr()) }; + let res = unsafe { + BOARD_CONTROLLER + .lock() + .unwrap() + .set_log_file(log_file.as_ptr()) + }; Ok(check_brainflow_exit_code(res)?) } +macro_rules! gen_fn { + ($fn_name:ident, $return_type:ident, $initial_value:literal) => { + paste! { + pub fn $fn_name( board_id: BoardId) -> Result<$return_type> { + let mut value = $initial_value; + let res = unsafe { BOARD_CONTROLLER.lock().unwrap().[](board_id as c_int, &mut value) }; + check_brainflow_exit_code(res)?; + Ok(value as $return_type) + } + + pub fn []( board_id: BoardId) -> Result<$return_type> { + $fn_name(board_id) + } + } + }; +} + +gen_fn!(sampling_rate, isize, -1); +gen_fn!(package_num_channel, isize, -1); +gen_fn!(timestamp_channel, isize, 0); +gen_fn!(marker_channel, isize, 0); +gen_fn!(battery_channel, isize, 0); +gen_fn!(num_rows, usize, 0); + pub fn log_message>(log_level: LogLevels, message: S) -> Result<()> { let message = message.as_ref(); let message = CString::new(message)?.into_raw(); let res = unsafe { - let res = ffi::log_message(log_level as c_int, message); + let res = BOARD_CONTROLLER + .lock() + .unwrap() + .log_message(log_level as c_int, message); let _ = CString::from_raw(message); res }; @@ -247,7 +295,11 @@ pub fn board_descr(board_id: BoardId) -> Result { let response = CString::new(Vec::with_capacity(16000))?; let response = response.into_raw(); let (res, response) = unsafe { - let res = ffi::get_board_descr(board_id as c_int, response, &mut response_len); + let res = BOARD_CONTROLLER.lock().unwrap().get_board_descr( + board_id as c_int, + response, + &mut response_len, + ); let response = CString::from_raw(response); (res, response) }; @@ -263,36 +315,16 @@ pub fn get_board_descr(board_id: BoardId) -> Result { board_descr(board_id) } -macro_rules! gen_fn { - ($fn_name:ident, $return_type:ident, $initial_value:literal) => { - paste! { - pub fn $fn_name(board_id: BoardId) -> Result<$return_type> { - let mut value = $initial_value; - let res = unsafe { ffi::[](board_id as c_int, &mut value) }; - check_brainflow_exit_code(res)?; - Ok(value as $return_type) - } - - pub fn [](board_id: BoardId) -> Result<$return_type> { - $fn_name(board_id) - } - } - }; -} - -gen_fn!(sampling_rate, isize, -1); -gen_fn!(package_num_channel, isize, -1); -gen_fn!(timestamp_channel, isize, 0); -gen_fn!(marker_channel, isize, 0); -gen_fn!(battery_channel, isize, 0); -gen_fn!(num_rows, usize, 0); - pub fn eeg_names(board_id: BoardId) -> Result> { let mut response_len = 0; let response = CString::new(Vec::with_capacity(16000))?; let response = response.into_raw(); let (res, response) = unsafe { - let res = ffi::get_eeg_names(board_id as c_int, response, &mut response_len); + let res = BOARD_CONTROLLER.lock().unwrap().get_eeg_names( + board_id as c_int, + response, + &mut response_len, + ); let response = CString::from_raw(response); (res, response) }; @@ -314,7 +346,11 @@ pub fn device_name(board_id: BoardId) -> Result { let response = CString::new(Vec::with_capacity(4096))?; let response = response.into_raw(); let (res, response) = unsafe { - let res = ffi::get_device_name(board_id as c_int, response, &mut response_len); + let res = BOARD_CONTROLLER.lock().unwrap().get_device_name( + board_id as c_int, + response, + &mut response_len, + ); let response = CString::from_raw(response); (res, response) }; @@ -333,7 +369,7 @@ macro_rules! gen_vec_fn { let mut channels: Vec = Vec::with_capacity(MAX_CHANNELS); let mut len = 0; let res = unsafe { - ffi::[]( + BOARD_CONTROLLER.lock().unwrap().[]( board_id as c_int, channels.as_mut_ptr() as *mut c_int, &mut len, diff --git a/rust-package/brainflow/src/data_filter.rs b/rust-package/brainflow/src/data_filter.rs index c04b8248a..da52dd72f 100644 --- a/rust-package/brainflow/src/data_filter.rs +++ b/rust-package/brainflow/src/data_filter.rs @@ -1,16 +1,36 @@ -use ffi::{AggOperations, DetrendOperations, FilterTypes, LogLevels, NoiseTypes, WindowFunctions}; use getset::Getters; use ndarray::{Array1, Array2, ArrayBase, AsArray, Ix1, Ix2, Ix3}; use num::Complex; use num_complex::Complex64; +use once_cell::sync::Lazy; use std::os::raw::c_int; +use std::path::Path; +use std::sync::Mutex; use std::{ffi::CString, os::raw::c_double}; use crate::error::{BrainFlowError, Error}; -use crate::{check_brainflow_exit_code, ffi, Result}; +use crate::{check_brainflow_exit_code, Result}; +use brainflow_sys::data_handler::DataHandler; + +pub static DATA_FILTER: Lazy> = Lazy::new(|| { + let lib_path = Path::new( + "../brainflow-sys/target/debug/build/brainflow-sys-7b10940f08b63c04/out/lib/libDataHandler.so", + ); + let data_filter = unsafe { DataHandler::new(lib_path).unwrap() }; + Mutex::new(data_filter) +}); + +use brainflow_sys::constants::{ + AggOperations, DetrendOperations, FilterTypes, LogLevels, NoiseTypes, WindowFunctions, +}; pub fn set_log_level(log_level: LogLevels) -> Result<()> { - let res = unsafe { ffi::set_log_level(log_level as c_int) }; + let res = unsafe { + DATA_FILTER + .lock() + .unwrap() + .set_log_level(log_level as c_int) + }; Ok(check_brainflow_exit_code(res)?) } @@ -29,18 +49,7 @@ pub fn enable_dev_data_logger() -> Result<()> { pub fn set_log_file>(log_file: S) -> Result<()> { let log_file = log_file.as_ref(); let log_file = CString::new(log_file)?; - let res = unsafe { ffi::set_log_file(log_file.as_ptr()) }; - Ok(check_brainflow_exit_code(res)?) -} - -pub fn log_message>(log_level: LogLevels, message: S) -> Result<()> { - let message = message.as_ref(); - let message = CString::new(message)?.into_raw(); - let res = unsafe { - let res = ffi::log_message(log_level as c_int, message); - let _ = CString::from_raw(message); - res - }; + let res = unsafe { DATA_FILTER.lock().unwrap().set_log_file(log_file.as_ptr()) }; Ok(check_brainflow_exit_code(res)?) } @@ -53,7 +62,7 @@ pub fn perform_lowpass( ripple: f64, ) -> Result<()> { let res = unsafe { - ffi::perform_lowpass( + DATA_FILTER.lock().unwrap().perform_lowpass( data.as_mut_ptr() as *mut c_double, data.len() as c_int, sampling_rate as c_int, @@ -76,7 +85,7 @@ pub fn perform_highpass( ripple: f64, ) -> Result<()> { let res = unsafe { - ffi::perform_highpass( + DATA_FILTER.lock().unwrap().perform_highpass( data.as_mut_ptr() as *mut c_double, data.len() as c_int, sampling_rate as c_int, @@ -100,7 +109,7 @@ pub fn perform_bandpass( ripple: f64, ) -> Result<()> { let res = unsafe { - ffi::perform_bandpass( + DATA_FILTER.lock().unwrap().perform_bandpass( data.as_mut_ptr() as *mut c_double, data.len() as c_int, sampling_rate as c_int, @@ -125,7 +134,7 @@ pub fn perform_bandstop( ripple: f64, ) -> Result<()> { let res = unsafe { - ffi::perform_bandstop( + DATA_FILTER.lock().unwrap().perform_bandstop( data.as_mut_ptr() as *mut c_double, data.len() as c_int, sampling_rate as c_int, @@ -146,7 +155,7 @@ pub fn remove_environmental_noise( noise_type: NoiseTypes, ) -> Result<()> { let res = unsafe { - ffi::remove_environmental_noise( + DATA_FILTER.lock().unwrap().remove_environmental_noise( data.as_mut_ptr() as *mut c_double, data.len() as c_int, sampling_rate as c_int, @@ -163,7 +172,7 @@ pub fn perform_rolling_filter( agg_operation: AggOperations, ) -> Result<()> { let res = unsafe { - ffi::perform_rolling_filter( + DATA_FILTER.lock().unwrap().perform_rolling_filter( data.as_mut_ptr() as *mut c_double, data.len() as c_int, period as c_int, @@ -184,7 +193,7 @@ pub fn perform_downsampling( } let mut output = Vec::::with_capacity(data.len() / period as usize); let res = unsafe { - ffi::perform_downsampling( + DATA_FILTER.lock().unwrap().perform_downsampling( data.as_mut_ptr() as *mut c_double, data.len() as c_int, period as c_int, @@ -256,7 +265,7 @@ pub fn perform_wavelet_transform>( let output = wavelet_transform.coefficients.as_mut_ptr() as *mut c_double; let decomposition_lengths = wavelet_transform.decomposition_lengths.as_mut_ptr() as *mut c_int; - ffi::perform_wavelet_transform( + DATA_FILTER.lock().unwrap().perform_wavelet_transform( data.as_mut_ptr() as *mut c_double, data.len() as c_int, wavelet.as_ptr(), @@ -274,14 +283,17 @@ pub fn perform_inverse_wavelet_transform(wavelet_transform: WaveletTransform) -> let mut output = Vec::::with_capacity(wavelet_transform.original_data_len); let wavelet = CString::new(wavelet_transform.wavelet)?; let res = unsafe { - ffi::perform_inverse_wavelet_transform( - wavelet_transform.coefficients.as_mut_ptr() as *mut c_double, - wavelet_transform.original_data_len as c_int, - wavelet.as_ptr(), - wavelet_transform.decomposition_level as c_int, - wavelet_transform.decomposition_lengths.as_ptr() as *mut c_int, - output.as_mut_ptr() as *mut c_double, - ) + DATA_FILTER + .lock() + .unwrap() + .perform_inverse_wavelet_transform( + wavelet_transform.coefficients.as_mut_ptr() as *mut c_double, + wavelet_transform.original_data_len as c_int, + wavelet.as_ptr(), + wavelet_transform.decomposition_level as c_int, + wavelet_transform.decomposition_lengths.as_ptr() as *mut c_int, + output.as_mut_ptr() as *mut c_double, + ) }; check_brainflow_exit_code(res)?; Ok(output) @@ -294,7 +306,7 @@ pub fn perform_wavelet_denoising>( ) -> Result<()> { let wavelet = CString::new(wavelet.as_ref())?; let res = unsafe { - ffi::perform_wavelet_denoising( + DATA_FILTER.lock().unwrap().perform_wavelet_denoising( data.as_mut_ptr() as *mut c_double, data.len() as c_int, wavelet.as_ptr(), @@ -324,7 +336,7 @@ where let mut output_eigenvalues = Vec::::with_capacity(n_channels); let res = unsafe { - ffi::get_csp( + DATA_FILTER.lock().unwrap().get_csp( data.as_ptr() as *const c_double, labels.as_ptr() as *const c_double, n_epochs as c_int, @@ -353,7 +365,7 @@ where pub fn window(window_function: WindowFunctions, window_len: usize) -> Result> { let mut output = Vec::::with_capacity(window_len); let res = unsafe { - ffi::get_window( + DATA_FILTER.lock().unwrap().get_window( window_function as c_int, window_len as c_int, output.as_mut_ptr() as *mut c_double, @@ -371,7 +383,7 @@ pub fn perform_fft(data: &mut [f64], window_function: WindowFunctions) -> Result let mut output_re = Vec::::with_capacity(data.len() / 2 + 1); let mut output_im = Vec::::with_capacity(data.len() / 2 + 1); let res = unsafe { - ffi::perform_fft( + DATA_FILTER.lock().unwrap().perform_fft( data.as_mut_ptr() as *mut c_double, data.len() as c_int, window_function as c_int, @@ -393,7 +405,7 @@ pub fn perform_ifft(data: &[Complex64], original_data_len: usize) -> Result, Vec) = data.iter().map(|d| (d.re, d.im)).unzip(); let res = unsafe { - ffi::perform_ifft( + DATA_FILTER.lock().unwrap().perform_ifft( input_re.as_mut_ptr() as *mut c_double, input_im.as_mut_ptr() as *mut c_double, original_data_len as c_int, @@ -406,7 +418,7 @@ pub fn perform_ifft(data: &[Complex64], original_data_len: usize) -> Result Result<()> { let res = unsafe { - ffi::detrend( + DATA_FILTER.lock().unwrap().detrend( data.as_mut_ptr() as *mut c_double, data.len() as c_int, detrend_operation as c_int, @@ -430,7 +442,7 @@ pub fn psd( let mut amplitude = Vec::::with_capacity(data.len() / 2 + 1); let mut frequency = Vec::::with_capacity(data.len() / 2 + 1); let res = unsafe { - ffi::get_psd( + DATA_FILTER.lock().unwrap().get_psd( data.as_mut_ptr() as *mut c_double, data.len() as c_int, sampling_rate as c_int, @@ -464,7 +476,7 @@ pub fn psd_welch( let mut amplitude = Vec::::with_capacity(nfft / 2 + 1); let mut frequency = Vec::::with_capacity(nfft / 2 + 1); let res = unsafe { - ffi::get_psd_welch( + DATA_FILTER.lock().unwrap().get_psd_welch( data.as_mut_ptr() as *mut c_double, data.len() as c_int, nfft as c_int, @@ -508,7 +520,7 @@ where let mut stddev_band_powers = Vec::with_capacity(5); let mut raw_data: Vec<&f64> = data.iter().collect(); let res = unsafe { - ffi::get_avg_band_powers( + DATA_FILTER.lock().unwrap().get_avg_band_powers( raw_data.as_mut_ptr() as *mut c_double, rows as c_int, cols as c_int, @@ -537,7 +549,7 @@ pub fn band_power(psd: Psd, freq_start: f64, freq_end: f64) -> Result { let mut band_power = 0.0; let mut psd = psd; let res = unsafe { - ffi::get_band_power( + DATA_FILTER.lock().unwrap().get_band_power( psd.amplitude.as_mut_ptr() as *mut c_double, psd.frequency.as_mut_ptr() as *mut c_double, psd.amplitude.len() as c_int, @@ -556,7 +568,12 @@ pub fn get_band_power(psd: Psd, freq_start: f64, freq_end: f64) -> Result { pub fn nearest_power_of_two(value: usize) -> Result { let mut output = 0; - let res = unsafe { ffi::get_nearest_power_of_two(value as c_int, &mut output) }; + let res = unsafe { + DATA_FILTER + .lock() + .unwrap() + .get_nearest_power_of_two(value as c_int, &mut output) + }; check_brainflow_exit_code(res)?; Ok(output as usize) } @@ -568,14 +585,19 @@ pub fn get_nearest_power_of_two(value: usize) -> Result { pub fn read_file>(file_name: S) -> Result> { let file_name = CString::new(file_name.as_ref())?; let mut num_elements = 0; - let res = unsafe { ffi::get_num_elements_in_file(file_name.as_ptr(), &mut num_elements) }; + let res = unsafe { + DATA_FILTER + .lock() + .unwrap() + .get_num_elements_in_file(file_name.as_ptr(), &mut num_elements) + }; check_brainflow_exit_code(res)?; let mut data = Vec::with_capacity(num_elements as usize); let mut rows = 0; let mut cols = 0; let res = unsafe { - ffi::read_file( + DATA_FILTER.lock().unwrap().read_file( data.as_mut_ptr() as *mut c_double, &mut rows, &mut cols, @@ -602,7 +624,7 @@ where let (cols, rows) = (shape[0], shape[1]); let mut data: Vec<&f64> = data.iter().collect(); let res = unsafe { - ffi::write_file( + DATA_FILTER.lock().unwrap().write_file( data.as_mut_ptr() as *mut c_double, rows as c_int, cols as c_int, diff --git a/rust-package/brainflow/src/lib.rs b/rust-package/brainflow/src/lib.rs index 7709b00a7..f34262525 100644 --- a/rust-package/brainflow/src/lib.rs +++ b/rust-package/brainflow/src/lib.rs @@ -2,7 +2,6 @@ extern crate num; #[macro_use] extern crate num_derive; -use brainflow_sys as ffi; use error::{BrainFlowError, Error}; mod board_id; diff --git a/rust-package/brainflow/src/ml_model.rs b/rust-package/brainflow/src/ml_model.rs index ed1201b0f..dcd53b3d1 100644 --- a/rust-package/brainflow/src/ml_model.rs +++ b/rust-package/brainflow/src/ml_model.rs @@ -1,37 +1,26 @@ use std::{ ffi::CString, os::raw::{c_double, c_int}, + path::Path, + sync::Mutex, }; -use crate::{check_brainflow_exit_code, ffi, Result}; +use crate::{check_brainflow_exit_code, Result}; mod brainflow_model_param; pub use brainflow_model_param::{BrainFlowModelParams, BrainFlowModelParamsBuilder}; -use ffi::LogLevels; -pub fn set_log_level(log_level: LogLevels) -> Result<()> { - let res = unsafe { ffi::set_log_level(log_level as c_int) }; - Ok(check_brainflow_exit_code(res)?) -} - -pub fn enable_ml_logger() -> Result<()> { - set_log_level(LogLevels::LEVEL_INFO) -} +use brainflow_sys::constants::LogLevels; +use brainflow_sys::ml_model::MlModule; +use once_cell::sync::Lazy; -pub fn disable_ml_logger() -> Result<()> { - set_log_level(LogLevels::LEVEL_OFF) -} - -pub fn enable_dev_ml_logger() -> Result<()> { - set_log_level(LogLevels::LEVEL_TRACE) -} - -pub fn set_log_file>(log_file: S) -> Result<()> { - let log_file = log_file.as_ref(); - let log_file = CString::new(log_file)?; - let res = unsafe { ffi::set_log_file(log_file.as_ptr()) }; - Ok(check_brainflow_exit_code(res)?) -} +pub static ML_MODULE: Lazy> = Lazy::new(|| { + let lib_path = Path::new( + "../brainflow-sys/target/debug/build/brainflow-sys-7b10940f08b63c04/out/lib/libMLModule.so", + ); + let ml_module = unsafe { MlModule::new(lib_path).unwrap() }; + Mutex::new(ml_module) +}); pub struct MlModel { model_params: BrainFlowModelParams, @@ -49,14 +38,19 @@ impl MlModel { } pub fn prepare(&self) -> Result<()> { - let res = unsafe { ffi::prepare(self.json_model_params.as_ptr()) }; + let res = unsafe { + ML_MODULE + .lock() + .unwrap() + .prepare(self.json_model_params.as_ptr()) + }; Ok(check_brainflow_exit_code(res)?) } pub fn predict(&self, data: &mut [f64]) -> Result { let mut output = 0.0; let res = unsafe { - ffi::predict( + ML_MODULE.lock().unwrap().predict( data.as_mut_ptr() as *mut c_double, data.len() as c_int, &mut output, @@ -68,7 +62,36 @@ impl MlModel { } pub fn release(&self) -> Result<()> { - let res = unsafe { ffi::release(self.json_model_params.as_ptr()) }; + let res = unsafe { + ML_MODULE + .lock() + .unwrap() + .release(self.json_model_params.as_ptr()) + }; Ok(check_brainflow_exit_code(res)?) } } + +pub fn set_log_level(log_level: LogLevels) -> Result<()> { + let res = unsafe { ML_MODULE.lock().unwrap().set_log_level(log_level as c_int) }; + Ok(check_brainflow_exit_code(res)?) +} + +pub fn enable_ml_logger() -> Result<()> { + set_log_level(LogLevels::LEVEL_INFO) +} + +pub fn disable_ml_logger() -> Result<()> { + set_log_level(LogLevels::LEVEL_OFF) +} + +pub fn enable_dev_ml_logger() -> Result<()> { + set_log_level(LogLevels::LEVEL_TRACE) +} + +pub fn set_log_file>(log_file: S) -> Result<()> { + let log_file = log_file.as_ref(); + let log_file = CString::new(log_file)?; + let res = unsafe { ML_MODULE.lock().unwrap().set_log_file(log_file.as_ptr()) }; + Ok(check_brainflow_exit_code(res)?) +} From ce206a002e9b907a5f28c9d537cc01bb2a648550 Mon Sep 17 00:00:00 2001 From: Daniel Hahne Date: Sat, 2 Oct 2021 09:24:26 +0200 Subject: [PATCH 13/21] Use brainflow's build system - Put -sys related code directly into brainflow - Remove submodule - Add rust-package/brainflow-sys/{lib,inc} to gitignore --- .gitignore | 2 + .gitmodules | 3 - rust-package/brainflow-sys/.gitignore | 20 - rust-package/brainflow-sys/Cargo.lock | 392 ------------------ rust-package/brainflow-sys/Cargo.toml | 21 - rust-package/brainflow-sys/README.md | 4 - rust-package/brainflow-sys/brainflow | 1 - rust-package/brainflow/Cargo.toml | 8 +- .../{brainflow-sys => brainflow}/build.rs | 84 +--- rust-package/brainflow/src/board_shim.rs | 26 +- rust-package/brainflow/src/data_filter.rs | 31 +- .../src/lib.rs => brainflow/src/ffi.rs} | 1 + .../src/ffi}/board_controller.rs | 1 - .../src => brainflow/src/ffi}/constants.rs | 1 - .../src => brainflow/src/ffi}/data_handler.rs | 1 - .../src => brainflow/src/ffi}/ml_model.rs | 1 - rust-package/brainflow/src/lib.rs | 1 + rust-package/brainflow/src/ml_model.rs | 26 +- src/board_controller/build.cmake | 8 + src/data_handler/build.cmake | 4 + src/ml/build.cmake | 10 +- 21 files changed, 117 insertions(+), 529 deletions(-) delete mode 100644 .gitmodules delete mode 100644 rust-package/brainflow-sys/.gitignore delete mode 100644 rust-package/brainflow-sys/Cargo.lock delete mode 100644 rust-package/brainflow-sys/Cargo.toml delete mode 100644 rust-package/brainflow-sys/README.md delete mode 160000 rust-package/brainflow-sys/brainflow rename rust-package/{brainflow-sys => brainflow}/build.rs (58%) rename rust-package/{brainflow-sys/src/lib.rs => brainflow/src/ffi.rs} (80%) rename rust-package/{brainflow-sys/src => brainflow/src/ffi}/board_controller.rs (99%) rename rust-package/{brainflow-sys/src => brainflow/src/ffi}/constants.rs (99%) rename rust-package/{brainflow-sys/src => brainflow/src/ffi}/data_handler.rs (99%) rename rust-package/{brainflow-sys/src => brainflow/src/ffi}/ml_model.rs (99%) diff --git a/.gitignore b/.gitignore index 0800e32c8..8662e0607 100644 --- a/.gitignore +++ b/.gitignore @@ -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 diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 3421f05f4..000000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "rust-package/brainflow-sys/brainflow"] - path = rust-package/brainflow-sys/brainflow - url = git@github.com:brainflow-dev/brainflow.git diff --git a/rust-package/brainflow-sys/.gitignore b/rust-package/brainflow-sys/.gitignore deleted file mode 100644 index 389159a37..000000000 --- a/rust-package/brainflow-sys/.gitignore +++ /dev/null @@ -1,20 +0,0 @@ -# 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 diff --git a/rust-package/brainflow-sys/Cargo.lock b/rust-package/brainflow-sys/Cargo.lock deleted file mode 100644 index 9dec08561..000000000 --- a/rust-package/brainflow-sys/Cargo.lock +++ /dev/null @@ -1,392 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "aho-corasick" -version = "0.7.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5" -dependencies = [ - "memchr", -] - -[[package]] -name = "ansi_term" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" -dependencies = [ - "winapi", -] - -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi", - "libc", - "winapi", -] - -[[package]] -name = "bindgen" -version = "0.59.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "453c49e5950bb0eb63bb3df640e31618846c89d5b7faa54040d76e98e0134375" -dependencies = [ - "bitflags", - "cexpr", - "clang-sys", - "clap", - "env_logger", - "lazy_static", - "lazycell", - "log", - "peeking_take_while", - "proc-macro2", - "quote", - "regex", - "rustc-hash", - "shlex", - "which", -] - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitvec" -version = "0.19.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8942c8d352ae1838c9dda0b0ca2ab657696ef2232a20147cf1b30ae1a9cb4321" -dependencies = [ - "funty", - "radium", - "tap", - "wyz", -] - -[[package]] -name = "brainflow-sys" -version = "0.1.0" -dependencies = [ - "bindgen", - "cmake", - "libloading", -] - -[[package]] -name = "cc" -version = "1.0.70" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d26a6ce4b6a484fa3edb70f7efa6fc430fd2b87285fe8b84304fd0936faa0dc0" - -[[package]] -name = "cexpr" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db507a7679252d2276ed0dd8113c6875ec56d3089f9225b2b42c30cc1f8e5c89" -dependencies = [ - "nom", -] - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "clang-sys" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10612c0ec0e0a1ff0e97980647cb058a6e7aedb913d01d009c406b8b7d0b26ee" -dependencies = [ - "glob", - "libc", - "libloading", -] - -[[package]] -name = "clap" -version = "2.33.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002" -dependencies = [ - "ansi_term", - "atty", - "bitflags", - "strsim", - "textwrap", - "unicode-width", - "vec_map", -] - -[[package]] -name = "cmake" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb6210b637171dfba4cda12e579ac6dc73f5165ad56133e5d72ef3131f320855" -dependencies = [ - "cc", -] - -[[package]] -name = "env_logger" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a19187fea3ac7e84da7dacf48de0c45d63c6a76f9490dae389aead16c243fce3" -dependencies = [ - "atty", - "humantime", - "log", - "regex", - "termcolor", -] - -[[package]] -name = "funty" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed34cd105917e91daa4da6b3728c47b068749d6a62c59811f06ed2ac71d9da7" - -[[package]] -name = "glob" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" - -[[package]] -name = "hermit-abi" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - -[[package]] -name = "humantime" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "lazycell" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" - -[[package]] -name = "libc" -version = "0.2.102" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2a5ac8f984bfcf3a823267e5fde638acc3325f6496633a5da6bb6eb2171e103" - -[[package]] -name = "libloading" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f84d96438c15fcd6c3f244c8fce01d1e2b9c6b5623e9c711dc9286d8fc92d6a" -dependencies = [ - "cfg-if", - "winapi", -] - -[[package]] -name = "log" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "memchr" -version = "2.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" - -[[package]] -name = "nom" -version = "6.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c5c51b9083a3c620fa67a2a635d1ce7d95b897e957d6b28ff9a5da960a103a6" -dependencies = [ - "bitvec", - "funty", - "memchr", - "version_check", -] - -[[package]] -name = "peeking_take_while" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" - -[[package]] -name = "proc-macro2" -version = "1.0.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9f5105d4fdaab20335ca9565e106a5d9b82b6219b5ba735731124ac6711d23d" -dependencies = [ - "unicode-xid", -] - -[[package]] -name = "quote" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "radium" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "941ba9d78d8e2f7ce474c015eea4d9c6d25b6a3327f9832ee29a4de27f91bbb8" - -[[package]] -name = "regex" -version = "1.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a26af418b574bd56588335b3a3659a65725d4e636eb1016c2f9e3b38c7cc759" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.6.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" - -[[package]] -name = "rustc-hash" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" - -[[package]] -name = "shlex" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3" - -[[package]] -name = "strsim" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" - -[[package]] -name = "tap" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" - -[[package]] -name = "termcolor" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "textwrap" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" -dependencies = [ - "unicode-width", -] - -[[package]] -name = "unicode-width" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" - -[[package]] -name = "unicode-xid" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" - -[[package]] -name = "vec_map" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" - -[[package]] -name = "version_check" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" - -[[package]] -name = "which" -version = "3.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d011071ae14a2f6671d0b74080ae0cd8ebf3a6f8c9589a2cd45f23126fe29724" -dependencies = [ - "libc", -] - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-util" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" -dependencies = [ - "winapi", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "wyz" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214" diff --git a/rust-package/brainflow-sys/Cargo.toml b/rust-package/brainflow-sys/Cargo.toml deleted file mode 100644 index d659257ed..000000000 --- a/rust-package/brainflow-sys/Cargo.toml +++ /dev/null @@ -1,21 +0,0 @@ -[package] -name = "brainflow-sys" -version = "0.1.0" -edition = "2018" -description = "FFI bindings to brainflow" -readme = "README.md" - -[features] -default = [] -generate_binding = ["bindgen"] -use_libftdi = [] -use_openmp = [] -build_oymotion_sdk = [] -build_bluetooth = [] - -[build-dependencies] -bindgen = { version = "0.59.1", optional = true } -cmake = "0.1" - -[dependencies] -libloading = "0.7.0" diff --git a/rust-package/brainflow-sys/README.md b/rust-package/brainflow-sys/README.md deleted file mode 100644 index 31a1afaa3..000000000 --- a/rust-package/brainflow-sys/README.md +++ /dev/null @@ -1,4 +0,0 @@ -# About -`brainflow-sys` is an FFI-Rust-binding to brainflow. - -Run with feature `generate_binging` to generate the actual binding src/lib.rs diff --git a/rust-package/brainflow-sys/brainflow b/rust-package/brainflow-sys/brainflow deleted file mode 160000 index d103874f7..000000000 --- a/rust-package/brainflow-sys/brainflow +++ /dev/null @@ -1 +0,0 @@ -Subproject commit d103874f7683c53e0cd1762a9729beadcba9a7a6 diff --git a/rust-package/brainflow/Cargo.toml b/rust-package/brainflow/Cargo.toml index a0393f29c..7376c7592 100644 --- a/rust-package/brainflow/Cargo.toml +++ b/rust-package/brainflow/Cargo.toml @@ -5,9 +5,12 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[features] +generate_binding = [] + [dependencies] -brainflow-sys = { path = "../brainflow-sys" } getset = "0.1.1" +libloading = "0.7.0" ndarray = "0.15.3" num = "0.4.0" num-complex = "0.4.0" @@ -18,3 +21,6 @@ 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" diff --git a/rust-package/brainflow-sys/build.rs b/rust-package/brainflow/build.rs similarity index 58% rename from rust-package/brainflow-sys/build.rs rename to rust-package/brainflow/build.rs index 99eab74be..35839a934 100644 --- a/rust-package/brainflow-sys/build.rs +++ b/rust-package/brainflow/build.rs @@ -1,14 +1,11 @@ #[cfg(feature = "generate_binding")] -use std::{env, path::PathBuf}; - -use std::{fmt::Display, path::Path}; +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 out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); - let header_path = out_path.join("inc"); + let header_path = PathBuf::from("inc"); let header_path = header_path.display(); let bindings = bindgen::Builder::default() @@ -22,19 +19,21 @@ fn generate_board_controller_binding() { .generate() .expect("Unable to generate bindings"); - let binding_target_path = PathBuf::new().join("src").join("board_controller.rs"); + 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/board_controller.rs`"); + .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 out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); - let header_path = out_path.join("inc"); + let header_path = PathBuf::from("inc"); let header_path = header_path.display(); let bindings = bindgen::Builder::default() @@ -47,19 +46,21 @@ fn generate_data_handler_binding() { .generate() .expect("Unable to generate bindings"); - let binding_target_path = PathBuf::new().join("src").join("data_handler.rs"); + 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/data_handler.rs`"); + .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 out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); - let header_path = out_path.join("inc"); + let header_path = PathBuf::from("inc"); let header_path = header_path.display(); let bindings = bindgen::Builder::default() @@ -72,19 +73,18 @@ fn generate_ml_model_binding() { .generate() .expect("Unable to generate bindings"); - let binding_target_path = PathBuf::new().join("src").join("ml_model.rs"); + 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/ml_model.rs`"); + .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 out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); - let header_path = out_path.join("inc"); + let header_path = PathBuf::from("inc"); let header_path = header_path.display(); let bindings = bindgen::Builder::default() @@ -101,11 +101,11 @@ fn generate_constants_binding() { .generate() .expect("Unable to generate bindings"); - let binding_target_path = PathBuf::new().join("src").join("constants.rs"); + 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/constants.rs`"); + .expect("Could not write binding to `src/ffi/constants.rs`"); } #[cfg(feature = "generate_binding")] @@ -116,53 +116,7 @@ fn generate_binding() { generate_constants_binding(); } -fn build() { - let brainflow_path = Path::new("brainflow"); - - println!( - "cargo:info=Brainflow source path used: {:?}.", - brainflow_path - .canonicalize() - .expect("Could not canonicalise to absolute path") - ); - - println!("cargo:info=Building Brainflow via CMake."); - - let use_libftdi = if cfg!(feature = "use_libfidi") { - "ON" - } else { - "OFF" - }; - - let use_openmp = if cfg!(feature = "use_openmp") { - "ON" - } else { - "OFF" - }; - - let build_oymotion_sdk = if cfg!(feature = "build_oymotion_sdk") { - "ON" - } else { - "OFF" - }; - - let build_bluetooth = if cfg!(feature = "build_bluetooth") { - "ON" - } else { - "OFF" - }; - - let _brainflow_build_dir = cmake::Config::new(brainflow_path) - .define("USE_LIBFTDI", use_libftdi) - .define("USE_OPENMP", use_openmp) - .define("BUILD_OYMOTION_SDK", build_oymotion_sdk) - .define("BUILD_BLUETOOTH", build_bluetooth) - .build(); -} - fn main() { - build(); - #[cfg(feature = "generate_binding")] generate_binding(); } diff --git a/rust-package/brainflow/src/board_shim.rs b/rust-package/brainflow/src/board_shim.rs index 7a76e19eb..4d429ae8a 100644 --- a/rust-package/brainflow/src/board_shim.rs +++ b/rust-package/brainflow/src/board_shim.rs @@ -14,15 +14,31 @@ use crate::{ BoardId, Result, }; -use brainflow_sys::board_controller::BoardController; -use brainflow_sys::constants::LogLevels; +use crate::ffi::board_controller::BoardController; +use crate::ffi::constants::LogLevels; const MAX_CHANNELS: usize = 512; +#[cfg(target_os = "windows")] pub static BOARD_CONTROLLER: Lazy> = Lazy::new(|| { - let lib_path = Path::new( - "../brainflow-sys/target/debug/build/brainflow-sys-7b10940f08b63c04/out/lib/libBoardController.so", - ); + #[cfg(target_pointer_width = "64")] + let lib_path = Path::new("lib\\libBoardController.dll"); + #[cfg(target_pointer_width = "32")] + let lib_path = Path::new("lib\\libBoardController32.dll"); + let board_controller = unsafe { BoardController::new(lib_path).unwrap() }; + Mutex::new(board_controller) +}); + +#[cfg(target_os = "macos")] +pub static BOARD_CONTROLLER: Lazy> = Lazy::new(|| { + let lib_path = Path::new("lib/libBoardController.dylib"); + let board_controller = unsafe { BoardController::new(lib_path).unwrap() }; + Mutex::new(board_controller) +}); + +#[cfg(target_os = "linux")] +pub static BOARD_CONTROLLER: Lazy> = Lazy::new(|| { + let lib_path = Path::new("lib/libBoardController.so"); let board_controller = unsafe { BoardController::new(lib_path).unwrap() }; Mutex::new(board_controller) }); diff --git a/rust-package/brainflow/src/data_filter.rs b/rust-package/brainflow/src/data_filter.rs index da52dd72f..6f4a5bb9c 100644 --- a/rust-package/brainflow/src/data_filter.rs +++ b/rust-package/brainflow/src/data_filter.rs @@ -9,20 +9,37 @@ use std::sync::Mutex; use std::{ffi::CString, os::raw::c_double}; use crate::error::{BrainFlowError, Error}; +use crate::ffi::{ + constants::{ + AggOperations, DetrendOperations, FilterTypes, LogLevels, NoiseTypes, WindowFunctions, + }, + data_handler::DataHandler, +}; use crate::{check_brainflow_exit_code, Result}; -use brainflow_sys::data_handler::DataHandler; +#[cfg(target_os = "windows")] pub static DATA_FILTER: Lazy> = Lazy::new(|| { - let lib_path = Path::new( - "../brainflow-sys/target/debug/build/brainflow-sys-7b10940f08b63c04/out/lib/libDataHandler.so", - ); + #[cfg(target_pointer_width = "64")] + let lib_path = Path::new("lib\\libDataHandler.dll"); + #[cfg(target_pointer_width = "32")] + let lib_path = Path::new("lib\\libDataHandler32.dll"); let data_filter = unsafe { DataHandler::new(lib_path).unwrap() }; Mutex::new(data_filter) }); -use brainflow_sys::constants::{ - AggOperations, DetrendOperations, FilterTypes, LogLevels, NoiseTypes, WindowFunctions, -}; +#[cfg(target_os = "macos")] +pub static DATA_FILTER: Lazy> = Lazy::new(|| { + let lib_path = Path::new("lib/libDataHandler.dylib"); + let data_filter = unsafe { DataHandler::new(lib_path).unwrap() }; + Mutex::new(data_filter) +}); + +#[cfg(target_os = "linux")] +pub static DATA_FILTER: Lazy> = Lazy::new(|| { + let lib_path = Path::new("lib/libDataHandler.so"); + let data_filter = unsafe { DataHandler::new(lib_path).unwrap() }; + Mutex::new(data_filter) +}); pub fn set_log_level(log_level: LogLevels) -> Result<()> { let res = unsafe { diff --git a/rust-package/brainflow-sys/src/lib.rs b/rust-package/brainflow/src/ffi.rs similarity index 80% rename from rust-package/brainflow-sys/src/lib.rs rename to rust-package/brainflow/src/ffi.rs index 0d7ac138b..7c6081ed6 100644 --- a/rust-package/brainflow-sys/src/lib.rs +++ b/rust-package/brainflow/src/ffi.rs @@ -1,3 +1,4 @@ +#![allow(dead_code)] pub mod board_controller; pub mod constants; pub mod data_handler; diff --git a/rust-package/brainflow-sys/src/board_controller.rs b/rust-package/brainflow/src/ffi/board_controller.rs similarity index 99% rename from rust-package/brainflow-sys/src/board_controller.rs rename to rust-package/brainflow/src/ffi/board_controller.rs index 9c84eca28..063022d4a 100644 --- a/rust-package/brainflow-sys/src/board_controller.rs +++ b/rust-package/brainflow/src/ffi/board_controller.rs @@ -2,7 +2,6 @@ #![allow(non_camel_case_types)] - #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct JNINativeInterface { diff --git a/rust-package/brainflow-sys/src/constants.rs b/rust-package/brainflow/src/ffi/constants.rs similarity index 99% rename from rust-package/brainflow-sys/src/constants.rs rename to rust-package/brainflow/src/ffi/constants.rs index cc5d5c0d0..2e5bad76e 100644 --- a/rust-package/brainflow-sys/src/constants.rs +++ b/rust-package/brainflow/src/ffi/constants.rs @@ -2,7 +2,6 @@ #![allow(non_camel_case_types)] - #[repr(i32)] #[non_exhaustive] #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] diff --git a/rust-package/brainflow-sys/src/data_handler.rs b/rust-package/brainflow/src/ffi/data_handler.rs similarity index 99% rename from rust-package/brainflow-sys/src/data_handler.rs rename to rust-package/brainflow/src/ffi/data_handler.rs index b0a07d57c..8a4f5edaa 100644 --- a/rust-package/brainflow-sys/src/data_handler.rs +++ b/rust-package/brainflow/src/ffi/data_handler.rs @@ -2,7 +2,6 @@ #![allow(non_camel_case_types)] - extern crate libloading; pub struct DataHandler { __library: ::libloading::Library, diff --git a/rust-package/brainflow-sys/src/ml_model.rs b/rust-package/brainflow/src/ffi/ml_model.rs similarity index 99% rename from rust-package/brainflow-sys/src/ml_model.rs rename to rust-package/brainflow/src/ffi/ml_model.rs index 7f15dd434..c4a0bc5c1 100644 --- a/rust-package/brainflow-sys/src/ml_model.rs +++ b/rust-package/brainflow/src/ffi/ml_model.rs @@ -2,7 +2,6 @@ #![allow(non_camel_case_types)] - extern crate libloading; pub struct MlModule { __library: ::libloading::Library, diff --git a/rust-package/brainflow/src/lib.rs b/rust-package/brainflow/src/lib.rs index f34262525..722e16356 100644 --- a/rust-package/brainflow/src/lib.rs +++ b/rust-package/brainflow/src/lib.rs @@ -9,6 +9,7 @@ pub mod board_shim; pub mod brainflow_input_params; pub mod data_filter; mod error; +mod ffi; pub mod ml_model; pub use board_id::BoardId; diff --git a/rust-package/brainflow/src/ml_model.rs b/rust-package/brainflow/src/ml_model.rs index dcd53b3d1..72fa27448 100644 --- a/rust-package/brainflow/src/ml_model.rs +++ b/rust-package/brainflow/src/ml_model.rs @@ -10,14 +10,30 @@ use crate::{check_brainflow_exit_code, Result}; mod brainflow_model_param; pub use brainflow_model_param::{BrainFlowModelParams, BrainFlowModelParamsBuilder}; -use brainflow_sys::constants::LogLevels; -use brainflow_sys::ml_model::MlModule; +use crate::ffi::constants::LogLevels; +use crate::ffi::ml_model::MlModule; use once_cell::sync::Lazy; +#[cfg(target_os = "windows")] pub static ML_MODULE: Lazy> = Lazy::new(|| { - let lib_path = Path::new( - "../brainflow-sys/target/debug/build/brainflow-sys-7b10940f08b63c04/out/lib/libMLModule.so", - ); + #[cfg(target_pointer_width = "64")] + let lib_path = Path::new("lib\\libMLModule.dll"); + #[cfg(target_pointer_width = "32")] + let lib_path = Path::new("lib\\libMLModule32.dll"); + let ml_module = unsafe { MlModule::new(lib_path).unwrap() }; + Mutex::new(ml_module) +}); + +#[cfg(target_os = "macos")] +pub static ML_MODULE: Lazy> = Lazy::new(|| { + let lib_path = Path::new("lib/libMLModule.dylib"); + let ml_module = unsafe { MlModule::new(lib_path).unwrap() }; + Mutex::new(ml_module) +}); + +#[cfg(target_os = "linux")] +pub static ML_MODULE: Lazy> = Lazy::new(|| { + let lib_path = Path::new("lib/libMLModule.so"); let ml_module = unsafe { MlModule::new(lib_path).unwrap() }; Mutex::new(ml_module) }); diff --git a/src/board_controller/build.cmake b/src/board_controller/build.cmake index 6316f14f7..3fd5b6ff0 100644 --- a/src/board_controller/build.cmake +++ b/src/board_controller/build.cmake @@ -161,6 +161,10 @@ if (MSVC) COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_HOME_DIRECTORY}/src/board_controller/inc/board_controller.h" "${CMAKE_HOME_DIRECTORY}/matlab-package/brainflow/inc/board_controller.h" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_HOME_DIRECTORY}/src/board_controller/inc/board_info_getter.h" "${CMAKE_HOME_DIRECTORY}/matlab-package/brainflow/inc/board_info_getter.h" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_HOME_DIRECTORY}/src/utils/inc/shared_export_matlab.h" "${CMAKE_HOME_DIRECTORY}/matlab-package/brainflow/inc/shared_export.h" + COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_HOME_DIRECTORY}/compiled/$/${BOARD_CONTROLLER_COMPILED_NAME}" "${CMAKE_HOME_DIRECTORY}/rust-package/brainflow/lib/${BOARD_CONTROLLER_COMPILED_NAME}" + COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_HOME_DIRECTORY}/src/board_controller/inc/board_controller.h" "${CMAKE_HOME_DIRECTORY}/rust-package/brainflow/inc/board_controller.h" + COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_HOME_DIRECTORY}/src/board_controller/inc/board_info_getter.h" "${CMAKE_HOME_DIRECTORY}/rust-package/brainflow/inc/board_info_getter.h" + COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_HOME_DIRECTORY}/src/utils/inc/brainflow_constants.h" "${CMAKE_HOME_DIRECTORY}/rust-package/brainflow/inc/brainflow_constants.h" ) endif (MSVC) if (UNIX AND NOT ANDROID) @@ -174,6 +178,10 @@ if (UNIX AND NOT ANDROID) COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_HOME_DIRECTORY}/src/utils/inc/shared_export_matlab.h" "${CMAKE_HOME_DIRECTORY}/matlab-package/brainflow/inc/shared_export.h" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_HOME_DIRECTORY}/src/utils/inc/brainflow_constants.h" "${CMAKE_HOME_DIRECTORY}/matlab-package/brainflow/inc/brainflow_constants.h" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_HOME_DIRECTORY}/compiled/${BOARD_CONTROLLER_COMPILED_NAME}" "${CMAKE_HOME_DIRECTORY}/matlab-package/brainflow/lib/${BOARD_CONTROLLER_COMPILED_NAME}" + COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_HOME_DIRECTORY}/compiled/${BOARD_CONTROLLER_COMPILED_NAME}" "${CMAKE_HOME_DIRECTORY}/rust-package/brainflow/lib/${BOARD_CONTROLLER_COMPILED_NAME}" + COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_HOME_DIRECTORY}/src/board_controller/inc/board_controller.h" "${CMAKE_HOME_DIRECTORY}/rust-package/brainflow/inc/board_controller.h" + COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_HOME_DIRECTORY}/src/board_controller/inc/board_info_getter.h" "${CMAKE_HOME_DIRECTORY}/rust-package/brainflow/inc/board_info_getter.h" + COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_HOME_DIRECTORY}/src/utils/inc/brainflow_constants.h" "${CMAKE_HOME_DIRECTORY}/rust-package/brainflow/inc/brainflow_constants.h" ) endif (UNIX AND NOT ANDROID) diff --git a/src/data_handler/build.cmake b/src/data_handler/build.cmake index f1447e0ad..e0462d74a 100644 --- a/src/data_handler/build.cmake +++ b/src/data_handler/build.cmake @@ -78,6 +78,8 @@ if (MSVC) COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_HOME_DIRECTORY}/compiled/$/${DATA_HANDLER_COMPILED_NAME}" "${CMAKE_HOME_DIRECTORY}/matlab-package/brainflow/lib/${DATA_HANDLER_COMPILED_NAME}" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_HOME_DIRECTORY}/src/data_handler/inc/data_handler.h" "${CMAKE_HOME_DIRECTORY}/matlab-package/brainflow/inc/data_handler.h" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_HOME_DIRECTORY}/src/utils/inc/shared_export_matlab.h" "${CMAKE_HOME_DIRECTORY}/matlab-package/brainflow/inc/shared_export.h" + COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_HOME_DIRECTORY}/compiled/$/${DATA_HANDLER_COMPILED_NAME}" "${CMAKE_HOME_DIRECTORY}/rust-package/brainflow/lib/${DATA_HANDLER_COMPILED_NAME}" + COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_HOME_DIRECTORY}/src/data_handler/inc/data_handler.h" "${CMAKE_HOME_DIRECTORY}/rust-package/brainflow/inc/data_handler.h" ) endif (MSVC) if (UNIX AND NOT ANDROID) @@ -89,6 +91,8 @@ if (UNIX AND NOT ANDROID) COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_HOME_DIRECTORY}/src/data_handler/inc/data_handler.h" "${CMAKE_HOME_DIRECTORY}/matlab-package/brainflow/inc/data_handler.h" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_HOME_DIRECTORY}/src/utils/inc/shared_export_matlab.h" "${CMAKE_HOME_DIRECTORY}/matlab-package/brainflow/inc/shared_export.h" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_HOME_DIRECTORY}/compiled/${DATA_HANDLER_COMPILED_NAME}" "${CMAKE_HOME_DIRECTORY}/matlab-package/brainflow/lib/${DATA_HANDLER_COMPILED_NAME}" + COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_HOME_DIRECTORY}/compiled/${DATA_HANDLER_COMPILED_NAME}" "${CMAKE_HOME_DIRECTORY}/rust-package/brainflow/lib/${DATA_HANDLER_COMPILED_NAME}" + COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_HOME_DIRECTORY}/src/data_handler/inc/data_handler.h" "${CMAKE_HOME_DIRECTORY}/rust-package/brainflow/inc/data_handler.h" ) endif (UNIX AND NOT ANDROID) if (ANDROID) diff --git a/src/ml/build.cmake b/src/ml/build.cmake index 829c8e220..f2f98be89 100644 --- a/src/ml/build.cmake +++ b/src/ml/build.cmake @@ -85,6 +85,10 @@ if (MSVC) COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_HOME_DIRECTORY}/src/ml/inc/ml_module.h" "${CMAKE_HOME_DIRECTORY}/matlab-package/brainflow/inc/ml_module.h" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_HOME_DIRECTORY}/src/utils/inc/shared_export_matlab.h" "${CMAKE_HOME_DIRECTORY}/matlab-package/brainflow/inc/shared_export.h" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_HOME_DIRECTORY}/src/ml/train/brainflow_svm.model" "${CMAKE_HOME_DIRECTORY}/matlab-package/brainflow/lib/brainflow_svm.model" + COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_HOME_DIRECTORY}/compiled/$/${ML_MODULE_COMPILED_NAME}" "${CMAKE_HOME_DIRECTORY}/rust-package/brainflow/lib/${ML_MODULE_COMPILED_NAME}" + COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_HOME_DIRECTORY}/src/ml/train/brainflow_svm.model" "${CMAKE_HOME_DIRECTORY}/rust-package/brainflow/lib/brainflow_svm.model" + COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_HOME_DIRECTORY}/src/ml/inc/ml_module.h" "${CMAKE_HOME_DIRECTORY}/rust-package/brainflow/inc/ml_module.h" + COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_HOME_DIRECTORY}/src/utils/inc/shared_export_matlab.h" "${CMAKE_HOME_DIRECTORY}/rust-package/brainflow/inc/shared_export.h" ) endif (MSVC) if (UNIX AND NOT ANDROID) @@ -100,6 +104,10 @@ if (UNIX AND NOT ANDROID) COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_HOME_DIRECTORY}/src/utils/inc/shared_export_matlab.h" "${CMAKE_HOME_DIRECTORY}/matlab-package/brainflow/inc/shared_export.h" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_HOME_DIRECTORY}/compiled/${ML_MODULE_COMPILED_NAME}" "${CMAKE_HOME_DIRECTORY}/matlab-package/brainflow/lib/${ML_MODULE_COMPILED_NAME}" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_HOME_DIRECTORY}/src/ml/train/brainflow_svm.model" "${CMAKE_HOME_DIRECTORY}/matlab-package/brainflow/lib/brainflow_svm.model" + COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_HOME_DIRECTORY}/compiled/${ML_MODULE_COMPILED_NAME}" "${CMAKE_HOME_DIRECTORY}/rust-package/brainflow/lib/${ML_MODULE_COMPILED_NAME}" + COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_HOME_DIRECTORY}/src/ml/inc/ml_module.h" "${CMAKE_HOME_DIRECTORY}/rust-package/brainflow/inc/ml_module.h" + COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_HOME_DIRECTORY}/src/ml/train/brainflow_svm.model" "${CMAKE_HOME_DIRECTORY}/rust-package/brainflow/lib/brainflow_svm.model" + COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${CMAKE_HOME_DIRECTORY}/src/utils/inc/shared_export_matlab.h" "${CMAKE_HOME_DIRECTORY}/rust-package/brainflow/inc/shared_export.h" ) endif (UNIX AND NOT ANDROID) if (ANDROID) @@ -128,4 +136,4 @@ install ( LIBRARY DESTINATION lib INCLUDES DESTINATION inc ARCHIVE DESTINATION lib -) \ No newline at end of file +) From 1cd652e2b788130fa947e47f859b153e3318d2de Mon Sep 17 00:00:00 2001 From: Daniel Hahne Date: Sun, 3 Oct 2021 10:12:28 +0200 Subject: [PATCH 14/21] Add documentation --- rust-package/brainflow/src/board_shim.rs | 149 +++++++++++++++--- .../brainflow/src/brainflow_input_params.rs | 10 ++ rust-package/brainflow/src/data_filter.rs | 40 +++++ rust-package/brainflow/src/lib.rs | 11 +- rust-package/brainflow/src/ml_model.rs | 17 +- .../src/ml_model/brainflow_model_param.rs | 8 + 6 files changed, 203 insertions(+), 32 deletions(-) diff --git a/rust-package/brainflow/src/board_shim.rs b/rust-package/brainflow/src/board_shim.rs index 4d429ae8a..92e6e612a 100644 --- a/rust-package/brainflow/src/board_shim.rs +++ b/rust-package/brainflow/src/board_shim.rs @@ -43,6 +43,7 @@ pub static BOARD_CONTROLLER: Lazy> = Lazy::new(|| { Mutex::new(board_controller) }); +/// BoardShim is a primary interface to all boards pub struct BoardShim { board_id: BoardId, input_params: BrainFlowInputParams, @@ -50,6 +51,7 @@ pub struct BoardShim { } impl BoardShim { + /// Creates a new [BoardShim]. pub fn new(board_id: BoardId, input_params: BrainFlowInputParams) -> Result { let json_input_params = serde_json::to_string(&input_params)?; let json_input_params = CString::new(json_input_params)?; @@ -59,7 +61,8 @@ impl BoardShim { json_brainflow_input_params: json_input_params, }) } - + /// Prepare streaming sesssion and initialize resources. + /// You need to call it before any other BoardShim object methods. pub fn prepare_session(&self) -> Result<()> { let res = unsafe { BOARD_CONTROLLER.lock().unwrap().prepare_session( @@ -70,6 +73,7 @@ impl BoardShim { Ok(check_brainflow_exit_code(res)?) } + /// Returns true if the session is ready. pub fn is_prepared(&self) -> Result { let mut prepared = 0; let res = unsafe { @@ -83,6 +87,7 @@ impl BoardShim { Ok(prepared > 0) } + /// Start streaming data, this methods stores data in ringbuffer. pub fn start_stream>( &self, buffer_size: usize, @@ -100,6 +105,7 @@ impl BoardShim { Ok(check_brainflow_exit_code(res)?) } + /// Stop streaming data. pub fn stop_stream(&self) -> Result<()> { let res = unsafe { BOARD_CONTROLLER.lock().unwrap().stop_stream( @@ -110,6 +116,7 @@ impl BoardShim { Ok(check_brainflow_exit_code(res)?) } + /// Release all resources. pub fn release_session(&self) -> Result<()> { let res = unsafe { BOARD_CONTROLLER.lock().unwrap().release_session( @@ -120,6 +127,7 @@ impl BoardShim { Ok(check_brainflow_exit_code(res)?) } + /// Get num of elements in ringbuffer. pub fn board_data_count(&self) -> Result { let mut data_count = 0; let res = unsafe { @@ -133,10 +141,12 @@ impl BoardShim { Ok(data_count as usize) } + /// Get num of elements in ringbuffer. pub fn get_board_data_count(&self) -> Result { self.board_data_count() } + /// Get board data and remove data from ringbuffer pub fn board_data(&self, n_data_points: Option) -> Result>> { let num_rows = num_rows(self.board_id)?; let num_samples = if let Some(n) = n_data_points { @@ -159,10 +169,12 @@ impl BoardShim { Ok(data_buf) } + /// Get board data and remove data from ringbuffer pub fn get_board_data(&self, n_data_points: Option) -> Result>> { self.board_data(n_data_points) } + /// Get specified amount of data or less if there is not enough data, doesnt remove data from ringbuffer. pub fn current_board_data(&self, num_samples: usize) -> Result>> { let num_rows = num_rows(self.board_id)?; let mut data_buf = Vec::with_capacity(num_samples * num_rows); @@ -182,10 +194,12 @@ impl BoardShim { Ok(data_buf) } + /// Get specified amount of data or less if there is not enough data, doesnt remove data from ringbuffer. pub fn get_current_board_data(&self, num_samples: usize) -> Result>> { self.current_board_data(num_samples) } + /// Use this method carefully and only if you understand what you are doing, do NOT use it to start or stop streaming pub fn config_board>(&self, config: S) -> Result { let config = CString::new(config.as_ref())?; let mut response_len = 0; @@ -212,6 +226,7 @@ impl BoardShim { .to_string()) } + /// Insert Marker to Data Stream. pub fn insert_marker(&self, value: f64) -> Result<()> { let res = unsafe { BOARD_CONTROLLER.lock().unwrap().insert_marker( @@ -223,6 +238,7 @@ impl BoardShim { Ok(check_brainflow_exit_code(res)?) } + /// Get's the actual board id, can be different than provided. pub fn board_id(&self) -> Result { Ok(match &self.board_id { BoardId::StreamingBoard | BoardId::PlaybackFileBoard => { @@ -234,6 +250,9 @@ impl BoardShim { }) } } + +/// Set BrainFlow log level, use it only if you want to write your own messages to BrainFlow logger, +/// otherwise use [enable_board_logger], [enable_dev_board_logger] or [disable_board_logger]. pub fn set_log_level(log_level: LogLevels) -> Result<()> { let res = unsafe { BOARD_CONTROLLER @@ -244,18 +263,22 @@ pub fn set_log_level(log_level: LogLevels) -> Result<()> { Ok(check_brainflow_exit_code(res)?) } +/// Enable BrainFlow board logger with level INFO, uses stderr for log messages by default. pub fn enable_board_logger() -> Result<()> { set_log_level(LogLevels::LEVEL_INFO) } +/// Disable BrainFlow board logger. pub fn disable_board_logger() -> Result<()> { set_log_level(LogLevels::LEVEL_OFF) } +/// Enable BrainFlow board logger with level TRACE, uses stderr for log messages by default. pub fn enable_dev_board_logger() -> Result<()> { set_log_level(LogLevels::LEVEL_TRACE) } +/// Redirect board logger from stderr to file, can be called any time. pub fn set_log_file>(log_file: S) -> Result<()> { let log_file = log_file.as_ref(); let log_file = CString::new(log_file)?; @@ -269,8 +292,9 @@ pub fn set_log_file>(log_file: S) -> Result<()> { } macro_rules! gen_fn { - ($fn_name:ident, $return_type:ident, $initial_value:literal) => { + ($fn_name:ident, $return_type:ident, $initial_value:literal, $doc:literal) => { paste! { + #[doc = $doc] pub fn $fn_name( board_id: BoardId) -> Result<$return_type> { let mut value = $initial_value; let res = unsafe { BOARD_CONTROLLER.lock().unwrap().[](board_id as c_int, &mut value) }; @@ -278,6 +302,7 @@ macro_rules! gen_fn { Ok(value as $return_type) } + #[doc = $doc] pub fn []( board_id: BoardId) -> Result<$return_type> { $fn_name(board_id) } @@ -285,13 +310,39 @@ macro_rules! gen_fn { }; } -gen_fn!(sampling_rate, isize, -1); -gen_fn!(package_num_channel, isize, -1); -gen_fn!(timestamp_channel, isize, 0); -gen_fn!(marker_channel, isize, 0); -gen_fn!(battery_channel, isize, 0); -gen_fn!(num_rows, usize, 0); - +gen_fn!(sampling_rate, isize, -1, "Write your own log message to BrainFlow logger, use it if you wanna have single logger for your own code and BrainFlow's code."); +gen_fn!( + package_num_channel, + isize, + -1, + "Get package num channel for a board." +); +gen_fn!( + timestamp_channel, + isize, + 0, + "Get timestamp channel in resulting data table for a board." +); +gen_fn!( + marker_channel, + isize, + 0, + "Get marker channel in resulting data table for a board." +); +gen_fn!( + battery_channel, + isize, + 0, + "Get battery channel for a board." +); +gen_fn!( + num_rows, + usize, + 0, + "Get number of rows in resulting data table for a board." +); + +/// Write your own log message to BrainFlow board logger, use it if you wanna have single logger for your own code and BrainFlow's code. pub fn log_message>(log_level: LogLevels, message: S) -> Result<()> { let message = message.as_ref(); let message = CString::new(message)?.into_raw(); @@ -306,6 +357,7 @@ pub fn log_message>(log_level: LogLevels, message: S) -> Result<() Ok(check_brainflow_exit_code(res)?) } +/// Get board description as json. pub fn board_descr(board_id: BoardId) -> Result { let mut response_len = 0; let response = CString::new(Vec::with_capacity(16000))?; @@ -327,10 +379,12 @@ pub fn board_descr(board_id: BoardId) -> Result { .to_string()) } +/// Get board description as json. pub fn get_board_descr(board_id: BoardId) -> Result { board_descr(board_id) } +/// Get names of EEG channels in 10-20 system if their location is fixed. pub fn eeg_names(board_id: BoardId) -> Result> { let mut response_len = 0; let response = CString::new(Vec::with_capacity(16000))?; @@ -352,11 +406,12 @@ pub fn eeg_names(board_id: BoardId) -> Result> { .map(|s| s.to_string()) .collect::>()) } - +/// Get names of EEG channels in 10-20 system if their location is fixed. pub fn get_eeg_names(board_id: BoardId) -> Result> { eeg_names(board_id) } +/// Get device name. pub fn device_name(board_id: BoardId) -> Result { let mut response_len = 0; let response = CString::new(Vec::with_capacity(4096))?; @@ -378,9 +433,15 @@ pub fn device_name(board_id: BoardId) -> Result { .to_string()) } +/// Get device name. +pub fn get_device_name(board_id: BoardId) -> Result { + device_name(board_id) +} + macro_rules! gen_vec_fn { - ($fn_name:ident) => { + ($fn_name:ident, $doc:literal) => { paste! { + #[doc = $doc] pub fn $fn_name(board_id: BoardId) -> Result> { let mut channels: Vec = Vec::with_capacity(MAX_CHANNELS); let mut len = 0; @@ -396,6 +457,7 @@ macro_rules! gen_vec_fn { Ok(channels) } + #[doc = $doc] pub fn [](board_id: BoardId) -> Result> { $fn_name(board_id) } @@ -403,16 +465,55 @@ macro_rules! gen_vec_fn { }; } -gen_vec_fn!(eeg_channels); -gen_vec_fn!(exg_channels); -gen_vec_fn!(emg_channels); -gen_vec_fn!(ecg_channels); -gen_vec_fn!(eog_channels); -gen_vec_fn!(eda_channels); -gen_vec_fn!(ppg_channels); -gen_vec_fn!(accel_channels); -gen_vec_fn!(gyro_channels); -gen_vec_fn!(analog_channels); -gen_vec_fn!(other_channels); -gen_vec_fn!(temperature_channels); -gen_vec_fn!(resistance_channels); +gen_vec_fn!( + eeg_channels, + "Get list of eeg channels in resulting data table for a board." +); +gen_vec_fn!( + exg_channels, + "Get list of exg channels in resulting data table for a board." +); +gen_vec_fn!( + emg_channels, + "Get list of emg channels in resulting data table for a board." +); +gen_vec_fn!( + ecg_channels, + "Get list of ecg channels in resulting data table for a board." +); +gen_vec_fn!( + eog_channels, + "Get list of eog channels in resulting data table for a board." +); +gen_vec_fn!( + eda_channels, + "Get list of eda channels in resulting data table for a board." +); +gen_vec_fn!( + ppg_channels, + "Get list of ppg channels in resulting data table for a board." +); +gen_vec_fn!( + accel_channels, + "Get list of accel channels in resulting data table for a board." +); +gen_vec_fn!( + gyro_channels, + "Get list of gyro channels in resulting data table for a board." +); +gen_vec_fn!( + analog_channels, + "Get list of analog channels in resulting data table for a board." +); +gen_vec_fn!( + other_channels, + "Get list of other channels in resulting data table for a board." +); +gen_vec_fn!( + temperature_channels, + "Get list of temperature channels in resulting data table for a board." +); +gen_vec_fn!( + resistance_channels, + "Get list of resistance channels in resulting data table for a board." +); diff --git a/rust-package/brainflow/src/brainflow_input_params.rs b/rust-package/brainflow/src/brainflow_input_params.rs index b5a48548c..5164cdf9d 100644 --- a/rust-package/brainflow/src/brainflow_input_params.rs +++ b/rust-package/brainflow/src/brainflow_input_params.rs @@ -1,6 +1,7 @@ use getset::Getters; use serde::{Deserialize, Serialize}; +/// Input parameters for [crate::board_shim::BoardShim]. #[derive(Debug, Default, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, Getters)] #[getset(get = "pub", set = "pub")] pub struct BrainFlowInputParams { @@ -15,41 +16,49 @@ pub struct BrainFlowInputParams { file: String, } +/// Builder for [BrainFlowInputParams]. #[derive(Default)] pub struct BrainFlowInputParamsBuilder { params: BrainFlowInputParams, } impl BrainFlowInputParamsBuilder { + /// Create a new builder. pub fn new() -> Self { Default::default() } + /// Serial port name is used for boards which reads data from serial port. pub fn serial_port>(mut self, port: S) -> Self { self.params.serial_port = port.as_ref().to_string(); self } + /// Mac address, for example, is used for bluetooth based boards. pub fn mac_address>(mut self, address: S) -> Self { self.params.mac_address = address.as_ref().to_string(); self } + /// IP address is used for boards which reads data from socket connection. pub fn ip_address>(mut self, address: S) -> Self { self.params.ip_address = address.as_ref().to_string(); self } + /// IP port for socket connection, for some boards where we know it in front you dont need this parameter. pub fn ip_port(mut self, port: usize) -> Self { self.params.ip_port = port; self } + /// IP protocol type from IpProtocolType enum. pub fn ip_protocol(mut self, protocol: i32) -> Self { self.params.ip_protocol = protocol; self } + /// Other info. pub fn other_info>(mut self, info: S) -> Self { self.params.other_info = info.as_ref().to_string(); self @@ -70,6 +79,7 @@ impl BrainFlowInputParamsBuilder { self } + /// Build BrainFlowInputParams with the given options. pub fn build(self) -> BrainFlowInputParams { self.params } diff --git a/rust-package/brainflow/src/data_filter.rs b/rust-package/brainflow/src/data_filter.rs index 6f4a5bb9c..b3b237595 100644 --- a/rust-package/brainflow/src/data_filter.rs +++ b/rust-package/brainflow/src/data_filter.rs @@ -41,6 +41,9 @@ pub static DATA_FILTER: Lazy> = Lazy::new(|| { Mutex::new(data_filter) }); +/// Set BrainFlow data logger log level. +/// Use it only if you want to write your own messages to BrainFlow logger. +/// Otherwise use [enable_data_logger], [enable_dev_data_logger] or [disable_data_logger]. pub fn set_log_level(log_level: LogLevels) -> Result<()> { let res = unsafe { DATA_FILTER @@ -51,18 +54,22 @@ pub fn set_log_level(log_level: LogLevels) -> Result<()> { Ok(check_brainflow_exit_code(res)?) } +/// Enable data logger with level INFO, uses stderr for log messages by default pub fn enable_data_logger() -> Result<()> { set_log_level(LogLevels::LEVEL_INFO) } +/// Disable data logger. pub fn disable_data_logger() -> Result<()> { set_log_level(LogLevels::LEVEL_OFF) } +/// Enable data logger with level TRACE, uses stderr for log messages by default. pub fn enable_dev_data_logger() -> Result<()> { set_log_level(LogLevels::LEVEL_TRACE) } +/// Redirect data logger from stderr to file, can be called any time. pub fn set_log_file>(log_file: S) -> Result<()> { let log_file = log_file.as_ref(); let log_file = CString::new(log_file)?; @@ -70,6 +77,7 @@ pub fn set_log_file>(log_file: S) -> Result<()> { Ok(check_brainflow_exit_code(res)?) } +/// Apply low pass filter to provided data. pub fn perform_lowpass( data: &mut [f64], sampling_rate: usize, @@ -93,6 +101,7 @@ pub fn perform_lowpass( Ok(()) } +/// Apply high pass filter to provided data. pub fn perform_highpass( data: &mut [f64], sampling_rate: usize, @@ -116,6 +125,7 @@ pub fn perform_highpass( Ok(()) } +/// Apply band pass filter to provided data. pub fn perform_bandpass( data: &mut [f64], sampling_rate: usize, @@ -141,6 +151,7 @@ pub fn perform_bandpass( Ok(()) } +/// Apply band stop filter to provided data. pub fn perform_bandstop( data: &mut [f64], sampling_rate: usize, @@ -166,6 +177,7 @@ pub fn perform_bandstop( Ok(()) } +/// Remove environmantal noise using notch filter. pub fn remove_environmental_noise( data: &mut [f64], sampling_rate: usize, @@ -183,6 +195,7 @@ pub fn remove_environmental_noise( Ok(()) } +/// Smooth data using moving average or median. pub fn perform_rolling_filter( data: &mut [f64], period: usize, @@ -200,6 +213,7 @@ pub fn perform_rolling_filter( Ok(()) } +/// Perform data downsampling, it doesnt apply lowpass filter for you, it just aggregates several data points. pub fn perform_downsampling( data: &mut [f64], period: usize, @@ -222,6 +236,7 @@ pub fn perform_downsampling( Ok(output) } +/// Data struct for output of wavelet transformations. #[derive(Getters)] #[getset(get = "pub")] pub struct WaveletTransform { @@ -248,6 +263,8 @@ impl WaveletTransform { } } + /// Create new WaveletTransform with coefficients. + /// This function can be used to create input data for [perform_inverse_wavelet_transform]. pub fn with_coefficients( coefficients: Vec, decomposition_level: usize, @@ -265,6 +282,7 @@ impl WaveletTransform { } } +/// Perform wavelet transform. pub fn perform_wavelet_transform>( data: &mut [f64], wavelet: S, @@ -295,6 +313,7 @@ pub fn perform_wavelet_transform>( Ok(wavelet_transform) } +/// Perform inverse wavelet transform. pub fn perform_inverse_wavelet_transform(wavelet_transform: WaveletTransform) -> Result> { let mut wavelet_transform = wavelet_transform; let mut output = Vec::::with_capacity(wavelet_transform.original_data_len); @@ -316,6 +335,7 @@ pub fn perform_inverse_wavelet_transform(wavelet_transform: WaveletTransform) -> Ok(output) } +/// Perform wavelet denoising. pub fn perform_wavelet_denoising>( data: &mut [f64], wavelet: S, @@ -334,6 +354,7 @@ pub fn perform_wavelet_denoising>( Ok(()) } +/// Calculate filters and the corresponding eigenvalues using the Common Spatial Patterns. pub fn csp<'a, Data, Labels>(data: Data, labels: Labels) -> Result<(Array2, Array1)> where Data: AsArray<'a, f64, Ix3>, @@ -371,6 +392,7 @@ where Ok((output_filters, output_eigenvalues)) } +/// Calculate filters and the corresponding eigenvalues using the Common Spatial Patterns. pub fn get_csp<'a, Data, Labels>(data: Data, labels: Labels) -> Result<(Array2, Array1)> where Data: AsArray<'a, f64, Ix3>, @@ -379,6 +401,7 @@ where csp(data, labels) } +/// Perform data windowing. pub fn window(window_function: WindowFunctions, window_len: usize) -> Result> { let mut output = Vec::::with_capacity(window_len); let res = unsafe { @@ -392,10 +415,12 @@ pub fn window(window_function: WindowFunctions, window_len: usize) -> Result Result> { window(window_function, window_len) } +/// Perform direct FFT. pub fn perform_fft(data: &mut [f64], window_function: WindowFunctions) -> Result> { let mut output_re = Vec::::with_capacity(data.len() / 2 + 1); let mut output_im = Vec::::with_capacity(data.len() / 2 + 1); @@ -417,6 +442,7 @@ pub fn perform_fft(data: &mut [f64], window_function: WindowFunctions) -> Result Ok(output) } +/// Perform inverse FFT. pub fn perform_ifft(data: &[Complex64], original_data_len: usize) -> Result> { let mut restored_data = Vec::::with_capacity(original_data_len); let (mut input_re, mut input_im): (Vec, Vec) = @@ -433,6 +459,7 @@ pub fn perform_ifft(data: &[Complex64], original_data_len: usize) -> Result Result<()> { let res = unsafe { DATA_FILTER.lock().unwrap().detrend( @@ -444,6 +471,7 @@ pub fn detrend(data: &mut [f64], detrend_operation: DetrendOperations) -> Result Ok(check_brainflow_exit_code(res)?) } +/// Data struct for output of PSD calculations. #[derive(Getters)] #[getset(get = "pub")] pub struct Psd { @@ -451,6 +479,7 @@ pub struct Psd { frequency: Vec, } +/// Calculate PSD. pub fn psd( data: &mut [f64], sampling_rate: usize, @@ -475,6 +504,7 @@ pub fn psd( }) } +/// Calculate PSD. pub fn get_psd( data: &mut [f64], sampling_rate: usize, @@ -483,6 +513,7 @@ pub fn get_psd( psd(data, sampling_rate, window_function) } +/// Calculate PSD using Welch method. pub fn psd_welch( data: &mut [f64], nfft: usize, @@ -511,6 +542,7 @@ pub fn psd_welch( }) } +/// Calculate PSD using Welch method. pub fn get_psd_welch( data: &mut [f64], nfft: usize, @@ -521,6 +553,7 @@ pub fn get_psd_welch( psd_welch(data, nfft, overlap, sampling_rate, window_function) } +/// Calculate avg and stddev of BandPowers across all channels, bands are 1-4,4-8,8-13,13-30,30-50. pub fn avg_band_powers<'a, Data>( data: Data, sampling_rate: usize, @@ -551,6 +584,7 @@ where Ok((avg_band_powers, stddev_band_powers)) } +/// Calculate avg and stddev of BandPowers across all channels, bands are 1-4,4-8,8-13,13-30,30-50. pub fn get_avg_band_powers<'a, Data>( data: Data, sampling_rate: usize, @@ -562,6 +596,7 @@ where avg_band_powers(data, sampling_rate, apply_filters) } +/// Calculate band power. pub fn band_power(psd: Psd, freq_start: f64, freq_end: f64) -> Result { let mut band_power = 0.0; let mut psd = psd; @@ -579,10 +614,12 @@ pub fn band_power(psd: Psd, freq_start: f64, freq_end: f64) -> Result { Ok(band_power) } +/// Calculate band power. pub fn get_band_power(psd: Psd, freq_start: f64, freq_end: f64) -> Result { band_power(psd, freq_start, freq_end) } +/// Calculate nearest power of two. pub fn nearest_power_of_two(value: usize) -> Result { let mut output = 0; let res = unsafe { @@ -595,10 +632,12 @@ pub fn nearest_power_of_two(value: usize) -> Result { Ok(output as usize) } +/// Calculate nearest power of two. pub fn get_nearest_power_of_two(value: usize) -> Result { nearest_power_of_two(value) } +/// Read data from file. pub fn read_file>(file_name: S) -> Result> { let file_name = CString::new(file_name.as_ref())?; let mut num_elements = 0; @@ -629,6 +668,7 @@ pub fn read_file>(file_name: S) -> Result> { Ok(data) } +/// Write data to file, in file data will be transposed. pub fn write_file<'a, Data, S>(data: Data, file_name: S, file_mode: S) -> Result<()> where Data: AsArray<'a, f64, Ix2>, diff --git a/rust-package/brainflow/src/lib.rs b/rust-package/brainflow/src/lib.rs index 722e16356..56d40ede0 100644 --- a/rust-package/brainflow/src/lib.rs +++ b/rust-package/brainflow/src/lib.rs @@ -5,20 +5,25 @@ extern crate num_derive; use error::{BrainFlowError, Error}; mod board_id; +/// The primary interface to all boards. pub mod board_shim; +/// Input parameters for [board_shim::BoardShim]. pub mod brainflow_input_params; + +/// Methods for signal processig. pub mod data_filter; mod error; mod ffi; +/// Used to calculate derivative metrics from raw data. pub mod ml_model; +/// Enum to store all supported Board Ids. pub use board_id::BoardId; type BrainFlowExitCode = i32; -pub fn check_brainflow_exit_code( - value: BrainFlowExitCode, -) -> std::result::Result<(), BrainFlowError> { +/// Convert the brainflow exit code to [BrainFlowError]. +fn check_brainflow_exit_code(value: BrainFlowExitCode) -> std::result::Result<(), BrainFlowError> { if value == 0 { Ok(()) } else { diff --git a/rust-package/brainflow/src/ml_model.rs b/rust-package/brainflow/src/ml_model.rs index 72fa27448..84bf268a0 100644 --- a/rust-package/brainflow/src/ml_model.rs +++ b/rust-package/brainflow/src/ml_model.rs @@ -39,20 +39,18 @@ pub static ML_MODULE: Lazy> = Lazy::new(|| { }); pub struct MlModel { - model_params: BrainFlowModelParams, json_model_params: CString, } impl MlModel { + /// Create a new MlModel. pub fn new(model_params: BrainFlowModelParams) -> Result { let json_model_params = serde_json::to_string(&model_params)?; let json_model_params = CString::new(json_model_params)?; - Ok(Self { - model_params, - json_model_params, - }) + Ok(Self { json_model_params }) } + /// Prepare classifier. pub fn prepare(&self) -> Result<()> { let res = unsafe { ML_MODULE @@ -63,6 +61,7 @@ impl MlModel { Ok(check_brainflow_exit_code(res)?) } + /// Calculate metric from data. pub fn predict(&self, data: &mut [f64]) -> Result { let mut output = 0.0; let res = unsafe { @@ -77,6 +76,7 @@ impl MlModel { Ok(output) } + /// Release classifier. pub fn release(&self) -> Result<()> { let res = unsafe { ML_MODULE @@ -88,23 +88,30 @@ impl MlModel { } } +/// Set BrainFlow ML log level. +/// Use it only if you want to write your own messages to BrainFlow logger. +/// Otherwise use [enable_ml_logger], [enable_dev_ml_logger], or [disable_ml_logger]. pub fn set_log_level(log_level: LogLevels) -> Result<()> { let res = unsafe { ML_MODULE.lock().unwrap().set_log_level(log_level as c_int) }; Ok(check_brainflow_exit_code(res)?) } +/// Enable ML logger with level INFO, uses stderr for log messages by default. pub fn enable_ml_logger() -> Result<()> { set_log_level(LogLevels::LEVEL_INFO) } +/// Disable BrainFlow ML logger. pub fn disable_ml_logger() -> Result<()> { set_log_level(LogLevels::LEVEL_OFF) } +/// Enable ML logger with level TRACE, uses stderr for log messages by default. pub fn enable_dev_ml_logger() -> Result<()> { set_log_level(LogLevels::LEVEL_TRACE) } +/// Redirect ML logger from stderr to file, can be called any time. pub fn set_log_file>(log_file: S) -> Result<()> { let log_file = log_file.as_ref(); let log_file = CString::new(log_file)?; diff --git a/rust-package/brainflow/src/ml_model/brainflow_model_param.rs b/rust-package/brainflow/src/ml_model/brainflow_model_param.rs index e469ff179..0ab7c30d0 100644 --- a/rust-package/brainflow/src/ml_model/brainflow_model_param.rs +++ b/rust-package/brainflow/src/ml_model/brainflow_model_param.rs @@ -1,6 +1,7 @@ use getset::Getters; use serde::{Deserialize, Serialize}; +/// Inputs parameters for MlModel. #[derive(Debug, Default, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, Getters)] #[getset(get = "pub", set = "pub")] pub struct BrainFlowModelParams { @@ -10,36 +11,43 @@ pub struct BrainFlowModelParams { other_info: String, } +/// Builder for [BrainFlowModelParams]. #[derive(Default)] pub struct BrainFlowModelParamsBuilder { params: BrainFlowModelParams, } impl BrainFlowModelParamsBuilder { + /// Create a new builder. pub fn new() -> Self { Default::default() } + /// Metric to calculate. pub fn metric(mut self, metric: usize) -> Self { self.params.metric = metric; self } + /// Classifier to use. pub fn classifier(mut self, classifier: usize) -> Self { self.params.classifier = classifier; self } + /// File to load model. pub fn file>(mut self, file: S) -> Self { self.params.file = file.as_ref().to_string(); self } + /// Other info. pub fn other_info>(mut self, other_info: S) -> Self { self.params.other_info = other_info.as_ref().to_string(); self } + /// Build BrainFlowModelParams with the given options. pub fn build(self) -> BrainFlowModelParams { self.params } From 2a7b6c20a63fefdf9b13355c66dbf74832caead6 Mon Sep 17 00:00:00 2001 From: Daniel Hahne Date: Sun, 3 Oct 2021 11:05:33 +0200 Subject: [PATCH 15/21] Add meta data to Cargo.toml and copy README.md from root --- rust-package/brainflow/Cargo.toml | 5 ++ rust-package/brainflow/README.md | 77 ++++++++++++++++++++++++++++++- 2 files changed, 80 insertions(+), 2 deletions(-) diff --git a/rust-package/brainflow/Cargo.toml b/rust-package/brainflow/Cargo.toml index 7376c7592..dfe2e0b74 100644 --- a/rust-package/brainflow/Cargo.toml +++ b/rust-package/brainflow/Cargo.toml @@ -1,7 +1,12 @@ [package] name = "brainflow" version = "0.1.0" +authors = ["Andrey Parfenov ", "Daniel Hahne "] 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" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/rust-package/brainflow/README.md b/rust-package/brainflow/README.md index c0c35553d..36e6534d5 100644 --- a/rust-package/brainflow/README.md +++ b/rust-package/brainflow/README.md @@ -1,2 +1,75 @@ -# About -`brainflow` is a Rust interface to https://brainflow.readthedocs.io . +

+ +
+ + GitHub all releases + + + PYPI + + + Nuget + +

+ +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) From 62d54ceb46fb79645b8f725e91ce4ed3e6f0b5a2 Mon Sep 17 00:00:00 2001 From: Daniel Hahne Date: Fri, 8 Oct 2021 18:43:53 +0200 Subject: [PATCH 16/21] Use only get_ version of functions --- rust-package/brainflow/examples/cyton.rs | 4 +- rust-package/brainflow/src/board_shim.rs | 83 ++++++----------------- rust-package/brainflow/src/data_filter.rs | 70 ++----------------- 3 files changed, 31 insertions(+), 126 deletions(-) diff --git a/rust-package/brainflow/examples/cyton.rs b/rust-package/brainflow/examples/cyton.rs index b156905bb..9c3337ad0 100644 --- a/rust-package/brainflow/examples/cyton.rs +++ b/rust-package/brainflow/examples/cyton.rs @@ -15,8 +15,8 @@ fn main() { board.prepare_session().unwrap(); - dbg!(brainflow::board_shim::eeg_names(BoardId::CytonBoard).unwrap()); - dbg!(brainflow::board_shim::eeg_channels(BoardId::CytonBoard).unwrap()); + dbg!(brainflow::board_shim::get_eeg_names(BoardId::CytonBoard).unwrap()); + dbg!(brainflow::board_shim::get_eeg_channels(BoardId::CytonBoard).unwrap()); dbg!(board.is_prepared().unwrap()); diff --git a/rust-package/brainflow/src/board_shim.rs b/rust-package/brainflow/src/board_shim.rs index 92e6e612a..940dee017 100644 --- a/rust-package/brainflow/src/board_shim.rs +++ b/rust-package/brainflow/src/board_shim.rs @@ -128,7 +128,7 @@ impl BoardShim { } /// Get num of elements in ringbuffer. - pub fn board_data_count(&self) -> Result { + pub fn get_board_data_count(&self) -> Result { let mut data_count = 0; let res = unsafe { BOARD_CONTROLLER.lock().unwrap().get_board_data_count( @@ -141,18 +141,13 @@ impl BoardShim { Ok(data_count as usize) } - /// Get num of elements in ringbuffer. - pub fn get_board_data_count(&self) -> Result { - self.board_data_count() - } - /// Get board data and remove data from ringbuffer - pub fn board_data(&self, n_data_points: Option) -> Result>> { - let num_rows = num_rows(self.board_id)?; + pub fn get_board_data(&self, n_data_points: Option) -> Result>> { + let num_rows = get_num_rows(self.board_id)?; let num_samples = if let Some(n) = n_data_points { - self.board_data_count()?.min(n) + self.get_board_data_count()?.min(n) } else { - self.board_data_count()? + self.get_board_data_count()? }; let mut data_buf = Vec::with_capacity(num_samples * num_rows); let res = unsafe { @@ -169,14 +164,9 @@ impl BoardShim { Ok(data_buf) } - /// Get board data and remove data from ringbuffer - pub fn get_board_data(&self, n_data_points: Option) -> Result>> { - self.board_data(n_data_points) - } - /// Get specified amount of data or less if there is not enough data, doesnt remove data from ringbuffer. - pub fn current_board_data(&self, num_samples: usize) -> Result>> { - let num_rows = num_rows(self.board_id)?; + pub fn get_current_board_data(&self, num_samples: usize) -> Result>> { + let num_rows = get_num_rows(self.board_id)?; let mut data_buf = Vec::with_capacity(num_samples * num_rows); let mut len = 0; let res = unsafe { @@ -194,11 +184,6 @@ impl BoardShim { Ok(data_buf) } - /// Get specified amount of data or less if there is not enough data, doesnt remove data from ringbuffer. - pub fn get_current_board_data(&self, num_samples: usize) -> Result>> { - self.current_board_data(num_samples) - } - /// Use this method carefully and only if you understand what you are doing, do NOT use it to start or stop streaming pub fn config_board>(&self, config: S) -> Result { let config = CString::new(config.as_ref())?; @@ -239,7 +224,7 @@ impl BoardShim { } /// Get's the actual board id, can be different than provided. - pub fn board_id(&self) -> Result { + pub fn get_board_id(&self) -> Result { Ok(match &self.board_id { BoardId::StreamingBoard | BoardId::PlaybackFileBoard => { let id = self.input_params.other_info().parse::().unwrap(); @@ -292,22 +277,17 @@ pub fn set_log_file>(log_file: S) -> Result<()> { } macro_rules! gen_fn { - ($fn_name:ident, $return_type:ident, $initial_value:literal, $doc:literal) => { - paste! { - #[doc = $doc] - pub fn $fn_name( board_id: BoardId) -> Result<$return_type> { - let mut value = $initial_value; - let res = unsafe { BOARD_CONTROLLER.lock().unwrap().[](board_id as c_int, &mut value) }; - check_brainflow_exit_code(res)?; - Ok(value as $return_type) - } - - #[doc = $doc] - pub fn []( board_id: BoardId) -> Result<$return_type> { - $fn_name(board_id) - } + ($fn_name:ident, $return_type:ident, $initial_value:literal, $doc:literal) => { + paste! { + #[doc = $doc] + pub fn []( board_id: BoardId) -> Result<$return_type> { + let mut value = $initial_value; + let res = unsafe { BOARD_CONTROLLER.lock().unwrap().[](board_id as c_int, &mut value) }; + check_brainflow_exit_code(res)?; + Ok(value as $return_type) } - }; + } + }; } gen_fn!(sampling_rate, isize, -1, "Write your own log message to BrainFlow logger, use it if you wanna have single logger for your own code and BrainFlow's code."); @@ -358,7 +338,7 @@ pub fn log_message>(log_level: LogLevels, message: S) -> Result<() } /// Get board description as json. -pub fn board_descr(board_id: BoardId) -> Result { +pub fn get_board_descr(board_id: BoardId) -> Result { let mut response_len = 0; let response = CString::new(Vec::with_capacity(16000))?; let response = response.into_raw(); @@ -379,13 +359,8 @@ pub fn board_descr(board_id: BoardId) -> Result { .to_string()) } -/// Get board description as json. -pub fn get_board_descr(board_id: BoardId) -> Result { - board_descr(board_id) -} - /// Get names of EEG channels in 10-20 system if their location is fixed. -pub fn eeg_names(board_id: BoardId) -> Result> { +pub fn get_eeg_names(board_id: BoardId) -> Result> { let mut response_len = 0; let response = CString::new(Vec::with_capacity(16000))?; let response = response.into_raw(); @@ -406,13 +381,9 @@ pub fn eeg_names(board_id: BoardId) -> Result> { .map(|s| s.to_string()) .collect::>()) } -/// Get names of EEG channels in 10-20 system if their location is fixed. -pub fn get_eeg_names(board_id: BoardId) -> Result> { - eeg_names(board_id) -} /// Get device name. -pub fn device_name(board_id: BoardId) -> Result { +pub fn get_device_name(board_id: BoardId) -> Result { let mut response_len = 0; let response = CString::new(Vec::with_capacity(4096))?; let response = response.into_raw(); @@ -433,16 +404,11 @@ pub fn device_name(board_id: BoardId) -> Result { .to_string()) } -/// Get device name. -pub fn get_device_name(board_id: BoardId) -> Result { - device_name(board_id) -} - macro_rules! gen_vec_fn { ($fn_name:ident, $doc:literal) => { paste! { #[doc = $doc] - pub fn $fn_name(board_id: BoardId) -> Result> { + pub fn [](board_id: BoardId) -> Result> { let mut channels: Vec = Vec::with_capacity(MAX_CHANNELS); let mut len = 0; let res = unsafe { @@ -456,11 +422,6 @@ macro_rules! gen_vec_fn { channels.resize(len as usize, 0); Ok(channels) } - - #[doc = $doc] - pub fn [](board_id: BoardId) -> Result> { - $fn_name(board_id) - } } }; } diff --git a/rust-package/brainflow/src/data_filter.rs b/rust-package/brainflow/src/data_filter.rs index b3b237595..4a532da02 100644 --- a/rust-package/brainflow/src/data_filter.rs +++ b/rust-package/brainflow/src/data_filter.rs @@ -355,7 +355,7 @@ pub fn perform_wavelet_denoising>( } /// Calculate filters and the corresponding eigenvalues using the Common Spatial Patterns. -pub fn csp<'a, Data, Labels>(data: Data, labels: Labels) -> Result<(Array2, Array1)> +pub fn get_csp<'a, Data, Labels>(data: Data, labels: Labels) -> Result<(Array2, Array1)> where Data: AsArray<'a, f64, Ix3>, Labels: AsArray<'a, f64, Ix1>, @@ -392,17 +392,8 @@ where Ok((output_filters, output_eigenvalues)) } -/// Calculate filters and the corresponding eigenvalues using the Common Spatial Patterns. -pub fn get_csp<'a, Data, Labels>(data: Data, labels: Labels) -> Result<(Array2, Array1)> -where - Data: AsArray<'a, f64, Ix3>, - Labels: AsArray<'a, f64, Ix1>, -{ - csp(data, labels) -} - /// Perform data windowing. -pub fn window(window_function: WindowFunctions, window_len: usize) -> Result> { +pub fn get_window(window_function: WindowFunctions, window_len: usize) -> Result> { let mut output = Vec::::with_capacity(window_len); let res = unsafe { DATA_FILTER.lock().unwrap().get_window( @@ -415,11 +406,6 @@ pub fn window(window_function: WindowFunctions, window_len: usize) -> Result Result> { - window(window_function, window_len) -} - /// Perform direct FFT. pub fn perform_fft(data: &mut [f64], window_function: WindowFunctions) -> Result> { let mut output_re = Vec::::with_capacity(data.len() / 2 + 1); @@ -480,7 +466,7 @@ pub struct Psd { } /// Calculate PSD. -pub fn psd( +pub fn get_psd( data: &mut [f64], sampling_rate: usize, window_function: WindowFunctions, @@ -504,17 +490,8 @@ pub fn psd( }) } -/// Calculate PSD. -pub fn get_psd( - data: &mut [f64], - sampling_rate: usize, - window_function: WindowFunctions, -) -> Result { - psd(data, sampling_rate, window_function) -} - /// Calculate PSD using Welch method. -pub fn psd_welch( +pub fn get_psd_welch( data: &mut [f64], nfft: usize, overlap: usize, @@ -542,19 +519,8 @@ pub fn psd_welch( }) } -/// Calculate PSD using Welch method. -pub fn get_psd_welch( - data: &mut [f64], - nfft: usize, - overlap: usize, - sampling_rate: usize, - window_function: WindowFunctions, -) -> Result { - psd_welch(data, nfft, overlap, sampling_rate, window_function) -} - /// Calculate avg and stddev of BandPowers across all channels, bands are 1-4,4-8,8-13,13-30,30-50. -pub fn avg_band_powers<'a, Data>( +pub fn get_avg_band_powers<'a, Data>( data: Data, sampling_rate: usize, apply_filters: bool, @@ -584,20 +550,8 @@ where Ok((avg_band_powers, stddev_band_powers)) } -/// Calculate avg and stddev of BandPowers across all channels, bands are 1-4,4-8,8-13,13-30,30-50. -pub fn get_avg_band_powers<'a, Data>( - data: Data, - sampling_rate: usize, - apply_filters: bool, -) -> Result<(Vec, Vec)> -where - Data: AsArray<'a, f64, Ix2>, -{ - avg_band_powers(data, sampling_rate, apply_filters) -} - /// Calculate band power. -pub fn band_power(psd: Psd, freq_start: f64, freq_end: f64) -> Result { +pub fn get_band_power(psd: Psd, freq_start: f64, freq_end: f64) -> Result { let mut band_power = 0.0; let mut psd = psd; let res = unsafe { @@ -614,13 +568,8 @@ pub fn band_power(psd: Psd, freq_start: f64, freq_end: f64) -> Result { Ok(band_power) } -/// Calculate band power. -pub fn get_band_power(psd: Psd, freq_start: f64, freq_end: f64) -> Result { - band_power(psd, freq_start, freq_end) -} - /// Calculate nearest power of two. -pub fn nearest_power_of_two(value: usize) -> Result { +pub fn get_nearest_power_of_two(value: usize) -> Result { let mut output = 0; let res = unsafe { DATA_FILTER @@ -632,11 +581,6 @@ pub fn nearest_power_of_two(value: usize) -> Result { Ok(output as usize) } -/// Calculate nearest power of two. -pub fn get_nearest_power_of_two(value: usize) -> Result { - nearest_power_of_two(value) -} - /// Read data from file. pub fn read_file>(file_name: S) -> Result> { let file_name = CString::new(file_name.as_ref())?; From 5a26e74e28dd3e7fedee8b3b163714632870bc9c Mon Sep 17 00:00:00 2001 From: Daniel Hahne Date: Fri, 8 Oct 2021 18:49:05 +0200 Subject: [PATCH 17/21] Add documentation meta data to Cargo.toml --- rust-package/brainflow/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/rust-package/brainflow/Cargo.toml b/rust-package/brainflow/Cargo.toml index dfe2e0b74..d269b6842 100644 --- a/rust-package/brainflow/Cargo.toml +++ b/rust-package/brainflow/Cargo.toml @@ -7,6 +7,7 @@ description = "BrainFlow is a library intended to obtain, parse and analyze EEG, 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 From e869e139b9904473c62b22218115ed9c9a009c43 Mon Sep 17 00:00:00 2001 From: Daniel Hahne Date: Fri, 8 Oct 2021 19:17:36 +0200 Subject: [PATCH 18/21] Add documentation to generate bindings. --- docs/BuildBrainFlow.rst | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/docs/BuildBrainFlow.rst b/docs/BuildBrainFlow.rst index f83e450e5..82f397493 100644 --- a/docs/BuildBrainFlow.rst +++ b/docs/BuildBrainFlow.rst @@ -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. From 4c48f460bc5e5a180172f2c91e1a71609dfa60b6 Mon Sep 17 00:00:00 2001 From: Daniel Hahne Date: Fri, 8 Oct 2021 20:00:41 +0200 Subject: [PATCH 19/21] Add automatic version replace mechanism to deploy.yml --- .github/workflows/deploy.yml | 6 ++++++ rust-package/brainflow/Cargo.toml | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index a6c695381..765f6cec4 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -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' diff --git a/rust-package/brainflow/Cargo.toml b/rust-package/brainflow/Cargo.toml index d269b6842..26bb8296f 100644 --- a/rust-package/brainflow/Cargo.toml +++ b/rust-package/brainflow/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "brainflow" -version = "0.1.0" +version = "0.0.0" authors = ["Andrey Parfenov ", "Daniel Hahne "] edition = "2018" description = "BrainFlow is a library intended to obtain, parse and analyze EEG, EMG, ECG, and other kinds of data from biosensors." From 963b15052ee587d979e6a3bff9265762992e7200 Mon Sep 17 00:00:00 2001 From: Daniel Hahne Date: Fri, 8 Oct 2021 21:33:09 +0200 Subject: [PATCH 20/21] Set lenght of vectors after they've been filled in foreign functions --- rust-package/brainflow/src/board_shim.rs | 26 ++++++++++++++--------- rust-package/brainflow/src/data_filter.rs | 22 ++++++++++++++++++- 2 files changed, 37 insertions(+), 11 deletions(-) diff --git a/rust-package/brainflow/src/board_shim.rs b/rust-package/brainflow/src/board_shim.rs index 940dee017..8ba3dd26a 100644 --- a/rust-package/brainflow/src/board_shim.rs +++ b/rust-package/brainflow/src/board_shim.rs @@ -2,9 +2,11 @@ use once_cell::sync::Lazy; use paste::paste; use std::{ ffi::CString, + mem, os::raw::{c_double, c_int}, path::Path, sync::Mutex, + vec, }; use crate::{ @@ -149,7 +151,9 @@ impl BoardShim { } else { self.get_board_data_count()? }; - let mut data_buf = Vec::with_capacity(num_samples * num_rows); + + let capacity = num_samples * num_rows; + let mut data_buf = Vec::with_capacity(capacity); let res = unsafe { BOARD_CONTROLLER.lock().unwrap().get_board_data( num_samples as c_int, @@ -160,28 +164,28 @@ impl BoardShim { }; check_brainflow_exit_code(res)?; - let data_buf = data_buf.chunks(num_samples).map(|d| d.to_vec()).collect(); - Ok(data_buf) + unsafe { data_buf.set_len(capacity) }; + Ok(data_buf.chunks(num_samples).map(|d| d.to_vec()).collect()) } /// Get specified amount of data or less if there is not enough data, doesnt remove data from ringbuffer. pub fn get_current_board_data(&self, num_samples: usize) -> Result>> { let num_rows = get_num_rows(self.board_id)?; - let mut data_buf = Vec::with_capacity(num_samples * num_rows); - let mut len = 0; + let capacity = num_samples * num_rows; + let mut data_buf = Vec::with_capacity(capacity); let res = unsafe { BOARD_CONTROLLER.lock().unwrap().get_current_board_data( num_samples as c_int, data_buf.as_mut_ptr(), - &mut len, + &mut 0, self.board_id as c_int, self.json_brainflow_input_params.as_ptr(), ) }; check_brainflow_exit_code(res)?; - let data_buf = data_buf.chunks(num_samples).map(|d| d.to_vec()).collect(); - Ok(data_buf) + unsafe { data_buf.set_len(capacity) }; + Ok(data_buf.chunks(num_samples).map(|d| d.to_vec()).collect()) } /// Use this method carefully and only if you understand what you are doing, do NOT use it to start or stop streaming @@ -410,16 +414,18 @@ macro_rules! gen_vec_fn { #[doc = $doc] pub fn [](board_id: BoardId) -> Result> { let mut channels: Vec = Vec::with_capacity(MAX_CHANNELS); + let channels_ptr = channels.as_mut_ptr(); let mut len = 0; let res = unsafe { + mem::forget(channels); BOARD_CONTROLLER.lock().unwrap().[]( board_id as c_int, - channels.as_mut_ptr() as *mut c_int, + channels_ptr as *mut c_int, &mut len, ) }; check_brainflow_exit_code(res)?; - channels.resize(len as usize, 0); + let channels: Vec = unsafe {Vec::from_raw_parts(channels_ptr, len as usize, MAX_CHANNELS)}; Ok(channels) } } diff --git a/rust-package/brainflow/src/data_filter.rs b/rust-package/brainflow/src/data_filter.rs index 4a532da02..5fabc6dbd 100644 --- a/rust-package/brainflow/src/data_filter.rs +++ b/rust-package/brainflow/src/data_filter.rs @@ -386,6 +386,9 @@ where }; check_brainflow_exit_code(res)?; + unsafe { output_filters.set_len(n_channels * n_channels) }; + unsafe { output_eigenvalues.set_len(n_channels) }; + let output_filters = ArrayBase::from_vec(output_filters); let output_filters = output_filters.into_shape((n_channels, n_channels)).unwrap(); let output_eigenvalues = Array1::from(output_eigenvalues); @@ -403,6 +406,8 @@ pub fn get_window(window_function: WindowFunctions, window_len: usize) -> Result ) }; check_brainflow_exit_code(res)?; + + unsafe { output.set_len(window_len) }; Ok(output) } @@ -419,12 +424,15 @@ pub fn perform_fft(data: &mut [f64], window_function: WindowFunctions) -> Result output_im.as_mut_ptr() as *mut c_double, ) }; + check_brainflow_exit_code(res)?; + + unsafe { output_re.set_len(data.len() / 2 + 1) }; + unsafe { output_im.set_len(data.len() / 2 + 1) }; let output = output_re .into_iter() .zip(output_im) .map(|(re, im)| Complex { re, im }) .collect(); - check_brainflow_exit_code(res)?; Ok(output) } @@ -442,6 +450,8 @@ pub fn perform_ifft(data: &[Complex64], original_data_len: usize) -> Result>(file_name: S) -> Result> { }; check_brainflow_exit_code(res)?; + unsafe { data.set_len(num_elements as usize) }; let data = ArrayBase::from_vec(data); let data = data.into_shape((cols as usize, rows as usize)).unwrap(); Ok(data) From 093f0d670c24c9da68cbd13a48963592c2337a50 Mon Sep 17 00:00:00 2001 From: Daniel Hahne Date: Fri, 8 Oct 2021 21:35:15 +0200 Subject: [PATCH 21/21] Update example to receive data. --- .../{cyton.rs => get_data_from_a_board.rs} | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) rename rust-package/brainflow/examples/{cyton.rs => get_data_from_a_board.rs} (56%) diff --git a/rust-package/brainflow/examples/cyton.rs b/rust-package/brainflow/examples/get_data_from_a_board.rs similarity index 56% rename from rust-package/brainflow/examples/cyton.rs rename to rust-package/brainflow/examples/get_data_from_a_board.rs index 9c3337ad0..d641e9ba7 100644 --- a/rust-package/brainflow/examples/cyton.rs +++ b/rust-package/brainflow/examples/get_data_from_a_board.rs @@ -1,6 +1,8 @@ +use std::thread; +use std::time::Duration; + use brainflow::board_shim::BoardShim; use brainflow::brainflow_input_params::BrainFlowInputParamsBuilder; -use brainflow::ml_model::{BrainFlowModelParamsBuilder, MlModel}; use brainflow::BoardId; fn main() { @@ -15,13 +17,13 @@ fn main() { board.prepare_session().unwrap(); - dbg!(brainflow::board_shim::get_eeg_names(BoardId::CytonBoard).unwrap()); - dbg!(brainflow::board_shim::get_eeg_channels(BoardId::CytonBoard).unwrap()); - - dbg!(board.is_prepared().unwrap()); + board.start_stream(20, "").unwrap(); + thread::sleep(Duration::from_secs(5)); + board.stop_stream().unwrap(); - let ml_params = BrainFlowModelParamsBuilder::default().build(); - let ml = MlModel::new(ml_params).unwrap(); + let cnt = dbg!(board.get_board_data_count().unwrap()); + let data = board.get_current_board_data(cnt).unwrap(); + board.release_session().unwrap(); - ml.prepare().unwrap(); + dbg!(data); }