From 4f4a9a3fff8333f0d643f7f40288f37d7a784500 Mon Sep 17 00:00:00 2001 From: Andrey Parfenov Date: Mon, 25 Dec 2023 20:01:53 +0100 Subject: [PATCH] add config_board_with_bytes method which is not recommended to use Signed-off-by: Andrey Parfenov --- cpp_package/src/board_shim.cpp | 9 ++++++++ cpp_package/src/inc/board_shim.h | 2 ++ .../brainflow/board_controller_library.cs | 17 +++++++++++++++ .../brainflow/brainflow/board_shim.cs | 13 ++++++++++++ .../src/main/java/brainflow/BoardShim.java | 14 +++++++++++++ julia_package/brainflow/src/board_shim.jl | 5 +++++ matlab_package/brainflow/BoardShim.m | 8 +++++++ nodejs_package/brainflow/board_shim.ts | 11 ++++++++++ nodejs_package/brainflow/functions.types.ts | 8 +++++++ python_package/brainflow/board_shim.py | 21 ++++++++++++++++++- .../examples/tests/config_board_with_bytes.py | 19 +++++++++++++++++ rust_package/brainflow/src/board_shim.rs | 13 ++++++++++++ .../brainflow/src/ffi/board_controller.rs | 8 +++++++ src/board_controller/board_controller.cpp | 19 +++++++++++++++++ src/board_controller/inc/board.h | 7 +++++++ src/board_controller/inc/board_controller.h | 2 ++ src/board_controller/inc/synthetic_board.h | 1 + src/board_controller/synthetic_board.cpp | 11 ++++++++++ 18 files changed, 187 insertions(+), 1 deletion(-) create mode 100644 python_package/examples/tests/config_board_with_bytes.py diff --git a/cpp_package/src/board_shim.cpp b/cpp_package/src/board_shim.cpp index 0fd07073e..3ec1fc74c 100644 --- a/cpp_package/src/board_shim.cpp +++ b/cpp_package/src/board_shim.cpp @@ -244,6 +244,15 @@ std::string BoardShim::config_board (std::string config) return resp; } +void BoardShim::config_board_with_bytes (const char *bytes, int len) +{ + int res = ::config_board_with_bytes (bytes, len, board_id, serialized_params.c_str ()); + if (res != (int)BrainFlowExitCodes::STATUS_OK) + { + throw BrainFlowException ("failed to config board with bytes", res); + } +} + void BoardShim::insert_marker (double value, int preset) { int res = ::insert_marker (value, preset, board_id, serialized_params.c_str ()); diff --git a/cpp_package/src/inc/board_shim.h b/cpp_package/src/inc/board_shim.h index cb48edaf9..d5c2f0881 100644 --- a/cpp_package/src/inc/board_shim.h +++ b/cpp_package/src/inc/board_shim.h @@ -263,6 +263,8 @@ class BoardShim BrainFlowArray get_board_data (int num_datapoints, int preset); /// send string to a board, use it carefully and only if you understand what you are doing std::string config_board (std::string config); + /// send raw bytes to a board, not implemented for majority of devices, not recommended to use + void config_board_with_bytes (const char *bytes, int len); /// insert marker in data stream void insert_marker (double value, int preset = (int)BrainFlowPresets::DEFAULT_PRESET); }; diff --git a/csharp_package/brainflow/brainflow/board_controller_library.cs b/csharp_package/brainflow/brainflow/board_controller_library.cs index ec7e10604..2419f9ba1 100644 --- a/csharp_package/brainflow/brainflow/board_controller_library.cs +++ b/csharp_package/brainflow/brainflow/board_controller_library.cs @@ -143,6 +143,8 @@ public static class BoardControllerLibrary64 [DllImport ("BoardController", SetLastError = true, CallingConvention = CallingConvention.Cdecl)] public static extern int config_board (string config, byte[] response, int[] len, int board_id, string input_json); [DllImport ("BoardController", SetLastError = true, CallingConvention = CallingConvention.Cdecl)] + public static extern int config_board_with_bytes (byte[] bytes, int len, int board_id, string input_json); + [DllImport ("BoardController", SetLastError = true, CallingConvention = CallingConvention.Cdecl)] public static extern int set_log_file_board_controller (string log_file); [DllImport ("BoardController", SetLastError = true, CallingConvention = CallingConvention.Cdecl)] public static extern int get_sampling_rate (int board_id, int preset, int[] sampling_rate); @@ -231,6 +233,8 @@ public static class BoardControllerLibrary32 [DllImport ("BoardController32", SetLastError = true, CallingConvention = CallingConvention.Cdecl)] public static extern int config_board (string config, byte[] response, int[] len, int board_id, string input_json); [DllImport ("BoardController32", SetLastError = true, CallingConvention = CallingConvention.Cdecl)] + public static extern int config_board_with_bytes (byte[] bytes, int len, int board_id, string input_json); + [DllImport ("BoardController32", SetLastError = true, CallingConvention = CallingConvention.Cdecl)] public static extern int set_log_file_board_controller (string log_file); [DllImport ("BoardController32", SetLastError = true, CallingConvention = CallingConvention.Cdecl)] public static extern int get_sampling_rate (int board_id, int preset, int[] sampling_rate); @@ -456,6 +460,19 @@ public static int config_board (string config, byte[] str, int[] len, int board_ return (int)BrainFlowExitCodes.GENERAL_ERROR; } + public static int config_board_with_bytes (byte[] bytes, int len, int board_id, string input_json) + { + switch (PlatformHelper.get_library_environment ()) + { + case LibraryEnvironment.x64: + return BoardControllerLibrary64.config_board_with_bytes (bytes, len, board_id, input_json); + case LibraryEnvironment.x86: + return BoardControllerLibrary32.config_board_with_bytes (bytes, len, board_id, input_json); + } + + return (int)BrainFlowExitCodes.GENERAL_ERROR; + } + public static int add_streamer (string streamer, int preset, int board_id, string input_json) { switch (PlatformHelper.get_library_environment ()) diff --git a/csharp_package/brainflow/brainflow/board_shim.cs b/csharp_package/brainflow/brainflow/board_shim.cs index f714c9bf9..24211f8f3 100644 --- a/csharp_package/brainflow/brainflow/board_shim.cs +++ b/csharp_package/brainflow/brainflow/board_shim.cs @@ -725,6 +725,19 @@ public string config_board (string config) string response = System.Text.Encoding.UTF8.GetString (str, 0, len[0]); return response; } + + /// + /// send raw bytes to device, dont use it + /// + /// + public void config_board_with_bytes (byte[] bytes) + { + int res = BoardControllerLibrary.config_board_with_bytes (bytes, bytes.Length, board_id, input_json); + if (res != (int)BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res); + } + } /// /// add streamer diff --git a/java_package/brainflow/src/main/java/brainflow/BoardShim.java b/java_package/brainflow/src/main/java/brainflow/BoardShim.java index 064c6acb0..7603178ae 100644 --- a/java_package/brainflow/src/main/java/brainflow/BoardShim.java +++ b/java_package/brainflow/src/main/java/brainflow/BoardShim.java @@ -25,6 +25,8 @@ private interface DllInterface extends Library int config_board (String config, byte[] names, int[] len, int board_id, String params); + int config_board_with_bytes (byte[] bytes, int len, int board_id, String params); + int add_streamer (String streamer, int preset, int board_id, String params); int delete_streamer (String streamer, int preset, int board_id, String params); @@ -1417,6 +1419,18 @@ public String config_board (String config) throws BrainFlowError return resp; } + /** + * send string to a board, dont use it + */ + public void config_board_with_bytes (byte[] bytes) throws BrainFlowError + { + int ec = instance.config_board_with_bytes (bytes, bytes.length, board_id, input_json); + if (ec != BrainFlowExitCode.STATUS_OK.get_code ()) + { + throw new BrainFlowError ("Error in config_board", ec); + } + } + /** * start streaming thread, store data in internal ringbuffer and stream them * from brainflow at the same time diff --git a/julia_package/brainflow/src/board_shim.jl b/julia_package/brainflow/src/board_shim.jl index 195f83661..dc3cd1b7f 100644 --- a/julia_package/brainflow/src/board_shim.jl +++ b/julia_package/brainflow/src/board_shim.jl @@ -287,6 +287,11 @@ end return sub_string end +@brainflow_rethrow function config_board_with_bytes(bytes::Vector{Cuchar}, len::Integer, board_shim::BoardShim) + ccall((:config_board_with_bytes, BOARD_CONTROLLER_INTERFACE), Cint, (Ptr{UInt8}, Cint, Cint, Ptr{UInt8}), + bytes, len, board_shim.board_id, board_shim.input_json) +end + @brainflow_rethrow function get_board_data(num_samples::Integer, board_shim::BoardShim, preset::PresetType=Integer(DEFAULT_PRESET)) data_size = get_board_data_count(board_shim, preset) if num_samples < 0 diff --git a/matlab_package/brainflow/BoardShim.m b/matlab_package/brainflow/BoardShim.m index 288968563..248e2aba3 100644 --- a/matlab_package/brainflow/BoardShim.m +++ b/matlab_package/brainflow/BoardShim.m @@ -385,6 +385,14 @@ function prepare_session(obj) [exit_code, tmp, response] = calllib(lib_name, task_name, config, blanks(4096), 4096, obj.board_id, obj.input_params_json); BoardShim.check_ec(exit_code, task_name); end + + function config_board_with_bytes(obj, bytes) + % send bytes to the board, do not use it + task_name = 'config_board_with_bytes'; + lib_name = BoardShim.load_lib(); + exit_code = calllib(lib_name, task_name, bytes, size(bytes, 2), obj.board_id, obj.input_params_json); + BoardShim.check_ec(exit_code, task_name); + end function add_streamer(obj, streamer, preset) % add streamer diff --git a/nodejs_package/brainflow/board_shim.ts b/nodejs_package/brainflow/board_shim.ts index 309e9f2ad..37447b1dc 100644 --- a/nodejs_package/brainflow/board_shim.ts +++ b/nodejs_package/brainflow/board_shim.ts @@ -68,6 +68,7 @@ class BoardControllerDLL extends BoardControllerFunctions this.prepareSession = this.lib.func(CLike.prepare_session); this.startStream = this.lib.func(CLike.start_stream); this.configBoard = this.lib.func(CLike.config_board); + this.configBoardWithBytes = this.lib.func(CLike.config_board_with_bytes); this.getBoardDataCount = this.lib.func(CLike.get_board_data_count); this.getBoardData = this.lib.func(CLike.get_board_data); this.getCurrentBoardData = this.lib.func(CLike.get_current_board_data); @@ -285,6 +286,16 @@ export class BoardShim return out[0].substring(0, len[0]); } + public configBoardWithBytes(config: string, len: number): void + { + const res = BoardControllerDLL.getInstance().configBoardWithBytes( + config, len, this.boardId, this.inputJson); + if (res !== BrainFlowExitCodes.STATUS_OK) + { + throw new BrainFlowError (res, 'Could not config board with bytes'); + } + } + public getBoardDataCount(preset = BrainFlowPresets.DEFAULT_PRESET): number { const dataSize = [0]; diff --git a/nodejs_package/brainflow/functions.types.ts b/nodejs_package/brainflow/functions.types.ts index 9bdefd98c..7d171cc1d 100644 --- a/nodejs_package/brainflow/functions.types.ts +++ b/nodejs_package/brainflow/functions.types.ts @@ -33,6 +33,8 @@ export enum BoardControllerCLikeFunctions { 'int add_streamer (const char *streamer, int preset, int board_id, const char *json_brainflow_input_params)', config_board = 'int config_board (const char *config, _Inout_ char *response, _Inout_ int *resp_len, int board_id, const char *json_brainflow_input_params)', + config_board_with_bytes = + 'int config_board_with_bytes (const char *bytes, int len, int board_id, const char *json_brainflow_input_params)', delete_streamer = 'int delete_streamer (const char *streamer, int preset, int board_id, const char *json_brainflow_input_params)', insert_marker = @@ -139,6 +141,12 @@ export class BoardControllerFunctions boardId: BoardIds, inputJson: string, ) => BrainFlowExitCodes; + configBoardWithBytes!: ( + config: string, + len: number, + boardId: BoardIds, + inputJson: string, + ) => BrainFlowExitCodes; getBoardDataCount!: ( preset: BrainFlowPresets, dataSize: number[], diff --git a/python_package/brainflow/board_shim.py b/python_package/brainflow/board_shim.py index a1ebb6e19..73603bb2e 100644 --- a/python_package/brainflow/board_shim.py +++ b/python_package/brainflow/board_shim.py @@ -313,6 +313,15 @@ def __init__(self): ctypes.c_char_p ] + self.config_board_with_bytes = self.lib.config_board_with_bytes + self.config_board_with_bytes.restype = ctypes.c_int + self.config_board_with_bytes.argtypes = [ + ndpointer(ctypes.c_ubyte), + ctypes.c_int, + ctypes.c_int, + ctypes.c_char_p + ] + self.get_sampling_rate = self.lib.get_sampling_rate self.get_sampling_rate.restype = ctypes.c_int self.get_sampling_rate.argtypes = [ @@ -1360,7 +1369,7 @@ def get_board_data(self, num_samples=None, preset: int = BrainFlowPresets.DEFAUL return data_arr.reshape(package_length, data_size) - def config_board(self, config) -> None: + def config_board(self, config) -> str: """Use this method carefully and only if you understand what you are doing, do NOT use it to start or stop streaming :param config: string to send to a board @@ -1380,3 +1389,13 @@ def config_board(self, config) -> None: if res != BrainFlowExitCodes.STATUS_OK.value: raise BrainFlowError('unable to config board', res) return string.tobytes().decode('utf-8')[0:string_len[0]] + + def config_board_with_bytes(self, bytes_to_send) -> None: + """Use this method carefully and only if you understand what you are doing + + :param bytes_to_send: bytes to send + :type config: ndarray astype(numpy.ubyte) + """ + res = BoardControllerDLL.get_instance().config_board_with_bytes(bytes_to_send, len(bytes_to_send), self.board_id, self.input_json) + if res != BrainFlowExitCodes.STATUS_OK.value: + raise BrainFlowError('unable to config board', res) diff --git a/python_package/examples/tests/config_board_with_bytes.py b/python_package/examples/tests/config_board_with_bytes.py new file mode 100644 index 000000000..2bcb48d7d --- /dev/null +++ b/python_package/examples/tests/config_board_with_bytes.py @@ -0,0 +1,19 @@ +import numpy + +from brainflow.board_shim import BoardShim, BrainFlowInputParams, BoardIds + + +def main(): + BoardShim.enable_dev_board_logger() + + params = BrainFlowInputParams() + board = BoardShim(BoardIds.SYNTHETIC_BOARD, params) + board.prepare_session() + config = numpy.zeros(4).astype(numpy.ubyte) + config[1] = 3 + board.config_board_with_bytes(config) + board.release_session() + + +if __name__ == "__main__": + main() diff --git a/rust_package/brainflow/src/board_shim.rs b/rust_package/brainflow/src/board_shim.rs index e4b599760..9abf1dec3 100644 --- a/rust_package/brainflow/src/board_shim.rs +++ b/rust_package/brainflow/src/board_shim.rs @@ -240,6 +240,19 @@ impl BoardShim { .to_string()) } + /// Use this method carefully and only if you understand what you are doing. + pub fn config_board_with_bytes(&self, bytes: Vec) -> Result<()> { + let res = unsafe { + board_controller::config_board_with_bytes( + bytes.as_ptr(), + bytes.len() as c_int, + self.board_id as c_int, + self.json_brainflow_input_params.as_ptr(), + ) + }; + Ok(check_brainflow_exit_code(res)?) + } + /// Insert Marker to Data Stream. pub fn insert_marker(&self, value: f64, preset: BrainFlowPresets) -> Result<()> { let res = unsafe { diff --git a/rust_package/brainflow/src/ffi/board_controller.rs b/rust_package/brainflow/src/ffi/board_controller.rs index eea61650e..2d854f4ec 100644 --- a/rust_package/brainflow/src/ffi/board_controller.rs +++ b/rust_package/brainflow/src/ffi/board_controller.rs @@ -258,6 +258,14 @@ extern "C" { json_brainflow_input_params: *const ::std::os::raw::c_char, ) -> ::std::os::raw::c_int; } +extern "C" { + pub fn config_board_with_bytes( + bytes: *const ::std::os::raw::c_char, + len: ::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, diff --git a/src/board_controller/board_controller.cpp b/src/board_controller/board_controller.cpp index 535f55aae..b9436135a 100644 --- a/src/board_controller/board_controller.cpp +++ b/src/board_controller/board_controller.cpp @@ -476,6 +476,25 @@ int config_board (const char *config, char *response, int *response_len, int boa return res; } +int config_board_with_bytes ( + const char *bytes, int len, int board_id, const char *json_brainflow_input_params) +{ + std::lock_guard lock (mutex); + if ((bytes == NULL) || (len < 1)) + { + return (int)BrainFlowExitCodes::INVALID_ARGUMENTS_ERROR; + } + + std::pair key; + int res = check_board_session (board_id, json_brainflow_input_params, key, false); + if (res != (int)BrainFlowExitCodes::STATUS_OK) + { + return res; + } + auto board_it = boards.find (key); + return board_it->second->config_board_with_bytes (bytes, len); +} + int add_streamer ( const char *streamer, int preset, int board_id, const char *json_brainflow_input_params) { diff --git a/src/board_controller/inc/board.h b/src/board_controller/inc/board.h index f3fb4a498..29e66c21b 100644 --- a/src/board_controller/inc/board.h +++ b/src/board_controller/inc/board.h @@ -54,6 +54,13 @@ class Board virtual int release_session () = 0; virtual int config_board (std::string config, std::string &response) = 0; + // some devices may implement it but there is no requirement to have this method and we do not + // recommend anybody to use it + virtual int config_board_with_bytes (const char *bytes, int len) + { + return (int)BrainFlowExitCodes::UNSUPPORTED_BOARD_ERROR; + } + int get_current_board_data ( int num_samples, int preset, double *data_buf, int *returned_samples); int get_board_data_count (int preset, int *result); diff --git a/src/board_controller/inc/board_controller.h b/src/board_controller/inc/board_controller.h index 0ebcec79b..d909a9df8 100644 --- a/src/board_controller/inc/board_controller.h +++ b/src/board_controller/inc/board_controller.h @@ -24,6 +24,8 @@ extern "C" double *data_buf, int board_id, const char *json_brainflow_input_params); SHARED_EXPORT int CALLING_CONVENTION config_board (const char *config, char *response, int *response_len, int board_id, const char *json_brainflow_input_params); + SHARED_EXPORT int CALLING_CONVENTION config_board_with_bytes ( + const char *bytes, int len, int board_id, const char *json_brainflow_input_params); SHARED_EXPORT int CALLING_CONVENTION is_prepared ( int *prepared, int board_id, const char *json_brainflow_input_params); SHARED_EXPORT int CALLING_CONVENTION insert_marker ( diff --git a/src/board_controller/inc/synthetic_board.h b/src/board_controller/inc/synthetic_board.h index f79eb4d18..3af3d30e4 100644 --- a/src/board_controller/inc/synthetic_board.h +++ b/src/board_controller/inc/synthetic_board.h @@ -26,4 +26,5 @@ class SyntheticBoard : public Board int stop_stream (); int release_session (); int config_board (std::string config, std::string &response); + int config_board_with_bytes (const char *bytes, int len); }; diff --git a/src/board_controller/synthetic_board.cpp b/src/board_controller/synthetic_board.cpp index a5f6783ed..09be30a02 100644 --- a/src/board_controller/synthetic_board.cpp +++ b/src/board_controller/synthetic_board.cpp @@ -258,3 +258,14 @@ int SyntheticBoard::config_board (std::string config, std::string &response) response = "Config:" + config; return (int)BrainFlowExitCodes::STATUS_OK; } + +// if you use this board as a reference, more likely you dont need to implement this method +int SyntheticBoard::config_board_with_bytes (const char *bytes, int len) +{ + safe_logger (spdlog::level::info, "config_board_with_bytes for len: {}", len); + for (int i = 0; i < len; i++) + { + safe_logger (spdlog::level::trace, "byte: {} value: {}", i, (int)bytes[i]); + } + return (int)BrainFlowExitCodes::STATUS_OK; +}