diff --git a/csharp_package/brainflow/brainflow/board_controller_library.cs b/csharp_package/brainflow/brainflow/board_controller_library.cs
index b2cf103cd..64be6691b 100644
--- a/csharp_package/brainflow/brainflow/board_controller_library.cs
+++ b/csharp_package/brainflow/brainflow/board_controller_library.cs
@@ -104,7 +104,9 @@ public enum BoardIds
BRAINALIVE_BOARD = 40,
MUSE_2016_BOARD = 41,
MUSE_2016_BLED_BOARD = 42,
- PIEEG_BOARD = 43
+ PIEEG_BOARD = 43,
+ EXPLORE_4_CHAN_BOARD = 44,
+ EXPLORE_8_CHAN_BOARD = 45
};
diff --git a/docs/SupportedBoards.rst b/docs/SupportedBoards.rst
index c752b4428..090caea45 100644
--- a/docs/SupportedBoards.rst
+++ b/docs/SupportedBoards.rst
@@ -32,6 +32,7 @@ Supported platforms:
- Windows >= 8.1
- Linux
- MacOS
+- Devices like Raspberry Pi
By default it generates new timestamps and stops at the end of the file. You can override it using commands:
@@ -79,6 +80,8 @@ Supported platforms:
- Windows >= 8.1
- Linux
- MacOS
+- Devices like Raspberry Pi
+- Android
In methods like:
@@ -110,6 +113,7 @@ Supported platforms:
- Windows >= 8.1
- Linux
- MacOS
+- Devices like Raspberry Pi
- Android
OpenBCI
@@ -144,6 +148,7 @@ Supported platforms:
- Windows >= 8.1
- Linux
- MacOS
+- Devices like Raspberry Pi
**On MacOS there are two serial ports for each device: /dev/tty..... and /dev/cu..... You HAVE to specify /dev/cu.....**
@@ -179,6 +184,7 @@ Supported platforms:
- Windows >= 8.1
- Linux
- MacOS
+- Devices like Raspberry Pi
**On MacOS there are two serial ports for each device: /dev/tty..... and /dev/cu..... You HAVE to specify /dev/cu.....**
@@ -201,6 +207,7 @@ Supported platforms:
- Windows >= 8.1
- Linux
- MacOS
+- Devices like Raspberry Pi
**On MacOS there are two serial ports for each device: /dev/tty..... and /dev/cu..... You HAVE to specify /dev/cu.....**
@@ -254,6 +261,7 @@ Supported platforms:
- Windows >= 8.1
- Linux
- MacOS
+- Devices like Raspberry Pi
- Android
CytonDaisy with WIFI Shield
@@ -279,6 +287,7 @@ Supported platforms:
- Windows >= 8.1
- Linux
- MacOS
+- Devices like Raspberry Pi
- Android
NeuroMD
@@ -430,6 +439,7 @@ Supported platforms:
- Windows
- Linux
- MacOS
+- Devices like Raspberry Pi
*Note: On Windows you may need to disable firewall to allow broadcast messages.*
@@ -455,6 +465,7 @@ Supported platforms:
- Windows
- Linux
- MacOS
+- Devices like Raspberry Pi
*Note: On Windows you may need to disable firewall to allow broadcast messages.*
@@ -479,6 +490,7 @@ Supported platforms:
- Windows
- Linux
- MacOS
+- Devices like Raspberry Pi
*Note: On Windows you may need to disable firewall to allow broadcast messages.*
@@ -554,6 +566,7 @@ Supported platforms:
- Windows
- Linux
- MacOS
+- Devices like Raspberry Pi
Muse
------
@@ -822,6 +835,10 @@ Supported platforms:
- Windows
- Linux
+Available commands:
+
+- Set sampling rate: :code:`board.config_board("sampling_rate:500")`, for available values check docs from Ant Neuro.
+
For more information about Ant Neuro boards please refer to their User Manual.
@@ -852,6 +869,7 @@ Supported platforms:
- Windows
- Linux
- MacOS
+- Devices like Raspberry Pi
Steps to find MAC address:
@@ -898,3 +916,95 @@ Supported platforms:
- MacOS 10.15+
- Linux, compilation from source code probably will be needed
- Devices like Raspberry Pi
+
+
+Mentalab
+---------
+
+.. csv-table:: Required inputs
+ :header: "Board", "Board Id", "serial_port", "mac_address", "ip_address", "ip_port", "ip_protocol", "other_info", "timeout", "serial_number", "file", "preset", "master_board"
+
+ "Explore4Channels", "BoardIds.EXPLORE_4_CHAN_BOARD (44)", "-", "Optional: MAC adress", "-", "-", "-", "-", "-", "-", "-", "-", "-"
+ "Explore8Channels", "BoardIds.EXPLORE_8_CHAN_BOARD (45)", "-", "Optional: MAC adress", "-", "-", "-", "-", "-", "-", "-", "-", "-"
+
+Explore 4 Channels Board
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. image:: https://live.staticflickr.com/65535/52349031632_51bc8ea56c.jpg"
+ :width: 500px
+ :height: 334px
+
+`Mentalab website `_
+
+To choose this board in BoardShim constructor please specify:
+
+- board_id: 44
+- Optional: mac address field of BrainFlowInputParams structure
+
+Supported platforms:
+
+- Windows
+- Linux
+- MacOS
+- Devices like Raspberry Pi
+
+**On Linux in order to compile and use it you may need to install :code:`libbluetooth-dev` for Debian like systems and :code:`bluez-libs-devel` for Fedora like.**
+
+Available :ref:`presets-label`:
+
+- *BrainFlowPresets.DEFAULT_PRESET* contains EEG data
+- *BrainFlowPresets.AUXILIARY_PRESET* contains Gyro and Accel data
+- *BrainFlowPresets.ANCILLARY_PRESET* contains battery and temperature data
+
+Steps to find MAC address:
+
+- On Windows: open device manager, navigate to explore device, click properties and select Bluetooth Address
+- On Linux: install bluez-utils and run :code:`bluetoothctl paired-devices`
+- On MacOS: run :code:`system_profiler SPBluetoothDataType`
+
+Steps to connect:
+
+- Enable device and Pair it with your laptop using bluetooth settings
+- Ensure that blue LED is blinking before calling :code:`board.prepare_session()`
+- If you see green LED probably you need to reboot a devce
+
+Explore 8 Channels Board
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. image:: https://live.staticflickr.com/65535/52349031632_51bc8ea56c.jpg"
+ :width: 500px
+ :height: 334px
+
+`Mentalab website `_
+
+To choose this board in BoardShim constructor please specify:
+
+- board_id: 44
+- Optional: mac address field of BrainFlowInputParams structure
+
+Supported platforms:
+
+- Windows
+- Linux
+- MacOS
+- Devices like Raspberry Pi
+
+**On Linux in order to compile and use it you may need to install :code:`libbluetooth-dev` for Debian like systems and :code:`bluez-libs-devel` for Fedora like.**
+
+Available :ref:`presets-label`:
+
+- *BrainFlowPresets.DEFAULT_PRESET* contains EEG data
+- *BrainFlowPresets.AUXILIARY_PRESET* contains Gyro and Accel data
+- *BrainFlowPresets.ANCILLARY_PRESET* contains battery and temperature data
+
+Steps to find MAC address:
+
+- On Windows: open device manager, navigate to explore device, click properties and select Bluetooth Address
+- On Linux: install bluez-utils and run :code:`bluetoothctl paired-devices`
+- On MacOS: run :code:`system_profiler SPBluetoothDataType`
+
+Steps to connect:
+
+- Enable device and Pair it with your laptop using bluetooth settings
+- Ensure that blue LED is blinking before calling :code:`board.prepare_session()`
+- If you see green LED probably you need to reboot a devce
diff --git a/java_package/brainflow/src/main/java/brainflow/BoardIds.java b/java_package/brainflow/src/main/java/brainflow/BoardIds.java
index 0e7ecad96..a523e9050 100644
--- a/java_package/brainflow/src/main/java/brainflow/BoardIds.java
+++ b/java_package/brainflow/src/main/java/brainflow/BoardIds.java
@@ -54,7 +54,9 @@ public enum BoardIds
BRAINALIVE_BOARD (40),
MUSE_2016_BOARD (41),
MUSE_2016_BLED_BOARD (42),
- PIEEG_BOARD (43);
+ PIEEG_BOARD (43),
+ EXPLORE_4_CHAN_BOARD (44),
+ EXPLORE_8_CHAN_BOARD (45);
private final int board_id;
private static final Map bi_map = new HashMap ();
diff --git a/julia_package/brainflow/src/board_shim.jl b/julia_package/brainflow/src/board_shim.jl
index 49bcb264f..1d7464685 100644
--- a/julia_package/brainflow/src/board_shim.jl
+++ b/julia_package/brainflow/src/board_shim.jl
@@ -50,6 +50,8 @@ export BrainFlowInputParams
MUSE_2016_BOARD = 41
MUSE_2016_BLED_BOARD = 42
PIEEG_BOARD = 43
+ EXPLORE_4_CHAN_BOARD = 44
+ EXPLORE_8_CHAN_BOARD = 45
end
diff --git a/matlab_package/brainflow/BoardIds.m b/matlab_package/brainflow/BoardIds.m
index 0e010ec68..eec6e9de1 100644
--- a/matlab_package/brainflow/BoardIds.m
+++ b/matlab_package/brainflow/BoardIds.m
@@ -48,5 +48,7 @@
MUSE_2016_BOARD (41)
MUSE_2016_BLED_BOARD (42)
PIEEG_BOARD (43)
+ EXPLORE_4_CHAN_BOARD (44)
+ EXPLORE_8_CHAN_BOARD (45)
end
end
\ No newline at end of file
diff --git a/python_package/brainflow/board_shim.py b/python_package/brainflow/board_shim.py
index 1a223dd0c..1a8f537bb 100644
--- a/python_package/brainflow/board_shim.py
+++ b/python_package/brainflow/board_shim.py
@@ -64,6 +64,8 @@ class BoardIds(enum.IntEnum):
MUSE_2016_BOARD = 41 #:
MUSE_2016_BLED_BOARD = 42 #:
PIEEG_BOARD = 43 #:
+ EXPLORE_4_CHAN_BOARD = 44 #:
+ EXPLORE_8_CHAN_BOARD = 45 #:
class IpProtocolTypes(enum.IntEnum):
diff --git a/python_package/examples/tests/explore.py b/python_package/examples/tests/explore.py
new file mode 100644
index 000000000..8d11d125d
--- /dev/null
+++ b/python_package/examples/tests/explore.py
@@ -0,0 +1,38 @@
+import argparse
+import time
+
+from brainflow.board_shim import BoardShim, BrainFlowInputParams, BrainFlowPresets, BoardIds
+from brainflow.data_filter import DataFilter
+
+
+def main():
+ BoardShim.enable_dev_board_logger()
+ parser = argparse.ArgumentParser()
+ parser.add_argument('--mac-address', type=str, help='mac address', required=False, default='')
+ args = parser.parse_args()
+
+ params = BrainFlowInputParams()
+ params.mac_address = args.mac_address
+ board = BoardShim(BoardIds.EXPLORE_4_CHAN_BOARD, params)
+ board.prepare_session()
+ board.start_stream()
+ # important: for explore device config board has to be after start stream
+ # board.config_board('sampling_rate:500')
+ # board.config_board('test_signal:1') # 1 is a bitmask represented as int not channel num
+ time.sleep(20)
+ data_eeg = board.get_board_data(preset=BrainFlowPresets.DEFAULT_PRESET)
+ data_orn = board.get_board_data(preset=BrainFlowPresets.AUXILIARY_PRESET)
+ data_env = board.get_board_data(preset=BrainFlowPresets.ANCILLARY_PRESET)
+ board.stop_stream()
+ board.release_session()
+
+ print(data_eeg)
+ print(data_orn)
+ print(data_env)
+ DataFilter.write_file(data_eeg, 'data_eeg.csv', 'w')
+ DataFilter.write_file(data_orn, 'data_orn.csv', 'w')
+ DataFilter.write_file(data_env, 'data_env.csv', 'w')
+
+
+if __name__ == "__main__":
+ main()
diff --git a/rust_package/brainflow/src/ffi/constants.rs b/rust_package/brainflow/src/ffi/constants.rs
index 6aa2c3d94..d771f50f4 100644
--- a/rust_package/brainflow/src/ffi/constants.rs
+++ b/rust_package/brainflow/src/ffi/constants.rs
@@ -32,7 +32,7 @@ impl BoardIds {
pub const FIRST: BoardIds = BoardIds::PlaybackFileBoard;
}
impl BoardIds {
- pub const LAST: BoardIds = BoardIds::PieegBoard;
+ pub const LAST: BoardIds = BoardIds::Explore8ChanBoard;
}
#[repr(i32)]
#[derive(FromPrimitive, ToPrimitive, Debug, Copy, Clone, Hash, PartialEq, Eq)]
@@ -84,6 +84,8 @@ pub enum BoardIds {
Muse2016Board = 41,
Muse2016BledBoard = 42,
PieegBoard = 43,
+ Explore4ChanBoard = 44,
+ Explore8ChanBoard = 45,
}
#[repr(i32)]
#[derive(FromPrimitive, ToPrimitive, Debug, Copy, Clone, Hash, PartialEq, Eq)]
diff --git a/src/board_controller/board_controller.cpp b/src/board_controller/board_controller.cpp
index 61ce49d5d..ea763ac6d 100644
--- a/src/board_controller/board_controller.cpp
+++ b/src/board_controller/board_controller.cpp
@@ -32,6 +32,7 @@
#include "cyton_daisy_wifi.h"
#include "cyton_wifi.h"
#include "enophone.h"
+#include "explore.h"
#include "freeeeg32.h"
#include "galea.h"
#include "galea_serial.h"
@@ -241,6 +242,12 @@ int prepare_session (int board_id, const char *json_brainflow_input_params)
case BoardIds::PIEEG_BOARD:
board = std::shared_ptr (new PiEEG (params));
break;
+ case BoardIds::EXPLORE_4_CHAN_BOARD:
+ board = std::shared_ptr (new Explore (board_id, params));
+ break;
+ case BoardIds::EXPLORE_8_CHAN_BOARD:
+ board = std::shared_ptr (new Explore (board_id, params));
+ break;
default:
return (int)BrainFlowExitCodes::UNSUPPORTED_BOARD_ERROR;
}
diff --git a/src/board_controller/brainflow_boards.cpp b/src/board_controller/brainflow_boards.cpp
index 1f552d9ac..578128e5f 100644
--- a/src/board_controller/brainflow_boards.cpp
+++ b/src/board_controller/brainflow_boards.cpp
@@ -63,7 +63,9 @@ BrainFlowBoards::BrainFlowBoards()
{"40", json::object()},
{"41", json::object()},
{"42", json::object()},
- {"43", json::object()}
+ {"43", json::object()},
+ {"44", json::object()},
+ {"45", json::object()}
}
}};
@@ -768,6 +770,80 @@ BrainFlowBoards::BrainFlowBoards()
{"emg_channels", {1, 2, 3, 4, 5, 6, 7, 8}},
{"ecg_channels", {1, 2, 3, 4, 5, 6, 7, 8}}
};
+ brainflow_boards_json["boards"]["44"]["default"] =
+ {
+ {"name", "Explore4Channels"},
+ {"sampling_rate", 250},
+ {"timestamp_channel", 6},
+ {"marker_channel", 7},
+ {"package_num_channel", 0},
+ {"num_rows", 8},
+ {"eeg_channels", {1, 2, 3, 4}},
+ {"emg_channels", {1, 2, 3, 4}},
+ {"ecg_channels", {1, 2, 3, 4}},
+ {"other_channels", {5}} // data status
+ };
+ brainflow_boards_json["boards"]["44"]["auxiliary"] =
+ {
+ {"name", "Explore4Channels"},
+ {"sampling_rate", 20},
+ {"timestamp_channel", 10},
+ {"marker_channel", 11},
+ {"package_num_channel", 0},
+ {"num_rows", 12},
+ {"accel_channels", {1, 2, 3}},
+ {"gyro_channels", {4, 5, 6}},
+ {"other_channels", {7, 8, 9}}
+ };
+ brainflow_boards_json["boards"]["44"]["ancillary"] =
+ {
+ {"name", "Explore4Channels"},
+ {"sampling_rate", 1},
+ {"timestamp_channel", 4},
+ {"marker_channel", 5},
+ {"package_num_channel", 0},
+ {"num_rows", 6},
+ {"temperature_channels", {1}},
+ {"battery_channel", 2},
+ {"other_channels", {3}}
+ };
+ brainflow_boards_json["boards"]["45"]["default"] =
+ {
+ {"name", "Explore8Channels"},
+ {"sampling_rate", 250},
+ {"timestamp_channel", 10},
+ {"marker_channel", 11},
+ {"package_num_channel", 0},
+ {"num_rows", 12},
+ {"eeg_channels", {1, 2, 3, 4, 5, 6, 7, 8}},
+ {"emg_channels", {1, 2, 3, 4, 5, 6, 7, 8}},
+ {"ecg_channels", {1, 2, 3, 4, 5, 6, 7, 8}},
+ {"other_channels", {9}} // data status
+ };
+ brainflow_boards_json["boards"]["45"]["auxiliary"] =
+ {
+ {"name", "Explore8Channels"},
+ {"sampling_rate", 20},
+ {"timestamp_channel", 10},
+ {"marker_channel", 11},
+ {"package_num_channel", 0},
+ {"num_rows", 12},
+ {"accel_channels", {1, 2, 3}},
+ {"gyro_channels", {4, 5, 6}},
+ {"other_channels", {7, 8, 9}}
+ };
+ brainflow_boards_json["boards"]["45"]["ancillary"] =
+ {
+ {"name", "Explore8Channels"},
+ {"sampling_rate", 1},
+ {"timestamp_channel", 4},
+ {"marker_channel", 5},
+ {"package_num_channel", 0},
+ {"num_rows", 6},
+ {"temperature_channels", {1}},
+ {"battery_channel", 2},
+ {"other_channels", {3}}
+ };
}
BrainFlowBoards boards_struct;
\ No newline at end of file
diff --git a/src/board_controller/bt_lib_board.cpp b/src/board_controller/bt_lib_board.cpp
index ec6afac81..93e117193 100644
--- a/src/board_controller/bt_lib_board.cpp
+++ b/src/board_controller/bt_lib_board.cpp
@@ -68,9 +68,8 @@ int BTLibBoard::prepare_session ()
if (params.ip_port <= 0)
{
params.ip_port = 1;
- safe_logger (spdlog::level::warn, "Port for Bluetooth is not provided, default is: {}",
- params.ip_port);
}
+ safe_logger (spdlog::level::info, "Use bluetooth port: {}", params.ip_port);
if ((params.mac_address.empty ()) && (return_res == (int)BrainFlowExitCodes::STATUS_OK))
{
safe_logger (
@@ -125,7 +124,13 @@ int BTLibBoard::release_session ()
int BTLibBoard::config_board (std::string config, std::string &response)
{
- return bluetooth_write_data (config.c_str (), (int)strlen (config.c_str ()));
+ int res = bluetooth_write_data (config.c_str (), (int)strlen (config.c_str ()));
+ if (res != (int)strlen (config.c_str ()))
+ {
+ safe_logger (spdlog::level::err, "failed to config device, res: {}", res);
+ return (int)BrainFlowExitCodes::BOARD_WRITE_ERROR;
+ }
+ return (int)BrainFlowExitCodes::STATUS_OK;
}
int BTLibBoard::bluetooth_open_device ()
@@ -179,12 +184,7 @@ int BTLibBoard::bluetooth_write_data (const char *command, int len)
int res = func_config (
const_cast (command), len, const_cast (params.mac_address.c_str ()));
- if (res != (int)SocketBluetoothReturnCodes::STATUS_OK)
- {
- safe_logger (spdlog::level::err, "failed to config board: {}", res);
- return (int)BrainFlowExitCodes::BOARD_NOT_READY_ERROR;
- }
- return (int)BrainFlowExitCodes::STATUS_OK;
+ return res;
}
int BTLibBoard::bluetooth_get_data (char *data, int len)
@@ -193,7 +193,7 @@ int BTLibBoard::bluetooth_get_data (char *data, int len)
(int (*) (char *, int, char *))dll_loader->get_address ("bluetooth_get_data");
if (func_get == NULL)
{
- safe_logger (spdlog::level::err, "failed to get function address for bluetooth_write_data");
+ safe_logger (spdlog::level::err, "failed to get function address for bluetooth_get_data");
return (int)BrainFlowExitCodes::GENERAL_ERROR;
}
diff --git a/src/board_controller/build.cmake b/src/board_controller/build.cmake
index cc06c7966..5e423e008 100644
--- a/src/board_controller/build.cmake
+++ b/src/board_controller/build.cmake
@@ -65,6 +65,7 @@ SET (BOARD_CONTROLLER_SRC
${CMAKE_HOME_DIRECTORY}/src/board_controller/neuromd/callibri_ecg.cpp
${CMAKE_HOME_DIRECTORY}/src/board_controller/neuromd/callibri_emg.cpp
${CMAKE_HOME_DIRECTORY}/src/board_controller/neurosity/notion_osc.cpp
+ ${CMAKE_HOME_DIRECTORY}/src/board_controller/mentalab/explore.cpp
${CMAKE_HOME_DIRECTORY}/src/board_controller/oymotion/gforce_pro.cpp
${CMAKE_HOME_DIRECTORY}/src/board_controller/oymotion/gforce_dual.cpp
${CMAKE_HOME_DIRECTORY}/src/board_controller/hackerbci/ironbci.cpp
@@ -130,6 +131,7 @@ target_include_directories (
${CMAKE_HOME_DIRECTORY}/src/board_controller/enophone/inc
${CMAKE_HOME_DIRECTORY}/third_party/SimpleBLE/include
${CMAKE_HOME_DIRECTORY}/src/board_controller/brainalive/inc
+ ${CMAKE_HOME_DIRECTORY}/src/board_controller/mentalab/inc
)
target_compile_definitions(${BOARD_CONTROLLER_NAME} PRIVATE NOMINMAX BRAINFLOW_VERSION=${BRAINFLOW_VERSION})
diff --git a/src/board_controller/enophone/enophone.cpp b/src/board_controller/enophone/enophone.cpp
index 1f7633ad8..437ff5235 100644
--- a/src/board_controller/enophone/enophone.cpp
+++ b/src/board_controller/enophone/enophone.cpp
@@ -20,11 +20,20 @@ Enophone::~Enophone ()
release_session ();
}
+int Enophone::prepare_session ()
+{
+ if (params.ip_port <= 0)
+ {
+ params.ip_port = 1; // default for enophone
+ }
+ return BTLibBoard::prepare_session ();
+}
+
int Enophone::start_stream (int buffer_size, const char *streamer_params)
{
if (!initialized)
{
- safe_logger (spdlog::level::err, "You need to call prepare_session before config_board");
+ safe_logger (spdlog::level::err, "You need to call prepare_session before start_stream");
return (int)BrainFlowExitCodes::BOARD_NOT_CREATED_ERROR;
}
if (keep_alive)
diff --git a/src/board_controller/enophone/inc/enophone.h b/src/board_controller/enophone/inc/enophone.h
index bbf575bb3..c9eb3fca7 100644
--- a/src/board_controller/enophone/inc/enophone.h
+++ b/src/board_controller/enophone/inc/enophone.h
@@ -25,6 +25,7 @@ class Enophone : public BTLibBoard
Enophone (struct BrainFlowInputParams params);
~Enophone ();
+ int prepare_session ();
int start_stream (int buffer_size, const char *streamer_params);
int stop_stream ();
int release_session ();
diff --git a/src/board_controller/mentalab/explore.cpp b/src/board_controller/mentalab/explore.cpp
new file mode 100644
index 000000000..8289c428c
--- /dev/null
+++ b/src/board_controller/mentalab/explore.cpp
@@ -0,0 +1,495 @@
+#include
+#include
+
+#include "explore.h"
+
+#include "custom_cast.h"
+#include "get_dll_dir.h"
+#include "timestamp.h"
+
+Explore::Explore (int board_id, struct BrainFlowInputParams params) : BTLibBoard (board_id, params)
+{
+ keep_alive = false;
+ last_eeg_timestamp = -1;
+ state = (int)BrainFlowExitCodes::SYNC_TIMEOUT_ERROR;
+}
+
+Explore::~Explore ()
+{
+ skip_logs = true;
+ release_session ();
+}
+
+int Explore::prepare_session ()
+{
+ if (params.ip_port <= 0)
+ {
+ params.ip_port = 5; // default for explore
+ }
+ return BTLibBoard::prepare_session ();
+}
+
+int Explore::config_board (std::string config, std::string &response)
+{
+ bool prefix_found = false;
+ constexpr int command_len = 14;
+ unsigned char command[command_len];
+ memset (command, 0, command_len);
+ // pid
+ command[0] = 0xA0;
+ // payload len
+ command[2] = 10;
+ command[3] = 0;
+ // timestamp, doesnt really matter since we dont use it and it's wrong even in explorepy, it
+ // gets upper part from unix timestamp and this part does not change
+ command[4] = 0x17;
+ command[5] = 0x15;
+ command[6] = 0xEC;
+ command[7] = 0x1E;
+ // fletcher
+ command[10] = 0xAF;
+ command[11] = 0xBE;
+ command[12] = 0xAD;
+ command[13] = 0xDE;
+
+ std::string sps_prefix = "sampling_rate:";
+ if (config.find (sps_prefix) != std::string::npos)
+ {
+ prefix_found = true;
+ int new_sampling_rate = 0;
+ std::string value = config.substr (sps_prefix.size ());
+ try
+ {
+ new_sampling_rate = std::stoi (value);
+ }
+ catch (...)
+ {
+ safe_logger (spdlog::level::err, "format is '{}value'", sps_prefix.c_str ());
+ return (int)BrainFlowExitCodes::INVALID_ARGUMENTS_ERROR;
+ }
+ if ((new_sampling_rate != 250) && (new_sampling_rate != 500) && (new_sampling_rate != 1000))
+ {
+ safe_logger (spdlog::level::err,
+ "invalid sampling rate provided, possible values are 250, 500, 1000");
+ return (int)BrainFlowExitCodes::INVALID_ARGUMENTS_ERROR;
+ }
+ command[8] = 0xA1; // op code
+ if (new_sampling_rate == 250)
+ command[9] = 0x01;
+ if (new_sampling_rate == 500)
+ command[9] = 0x02;
+ if (new_sampling_rate == 1000)
+ command[9] = 0x03;
+ }
+ std::string test_sig_prefix = "test_signal:";
+ if (config.find (test_sig_prefix) != std::string::npos)
+ {
+ prefix_found = true;
+ int mask = 0;
+ std::string value = config.substr (test_sig_prefix.size ());
+ try
+ {
+ mask = std::stoi (value);
+ }
+ catch (...)
+ {
+ safe_logger (spdlog::level::err, "format is '{}value'", test_sig_prefix.c_str ());
+ return (int)BrainFlowExitCodes::INVALID_ARGUMENTS_ERROR;
+ }
+ if ((mask < 0) || (mask > 255))
+ {
+ safe_logger (spdlog::level::err, "invalid mask provided, should be between 1 and 255");
+ return (int)BrainFlowExitCodes::INVALID_ARGUMENTS_ERROR;
+ }
+ command[8] = 0xAA; // op code
+ command[9] = (unsigned char)mask;
+ }
+
+ // todo, it changes package format, also need to change parsing somehow
+ /*
+ std::string chan_prefix = "channels:";
+ if (config.find (chan_prefix) != std::string::npos)
+ {
+ prefix_found = true;
+ int mask = 0;
+ std::string value = config.substr (chan_prefix.size ());
+ try
+ {
+ mask = std::stoi (value);
+ }
+ catch (...)
+ {
+ safe_logger (spdlog::level::err, "format is '{}value'", chan_prefix.c_str ());
+ return (int)BrainFlowExitCodes::INVALID_ARGUMENTS_ERROR;
+ }
+ if ((mask < 0) || (mask > 255))
+ {
+ safe_logger (spdlog::level::err, "invalid mask provided, should be between 1 and 255");
+ return (int)BrainFlowExitCodes::INVALID_ARGUMENTS_ERROR;
+ }
+ command[8] = 0xA2; // op code
+ command[9] = (unsigned char)mask;
+ }
+ */
+
+ if (!prefix_found)
+ {
+ safe_logger (spdlog::level::err,
+ "invalid config format, supported formats are sampling_rate:value and "
+ "test_signal:value");
+ return (int)BrainFlowExitCodes::INVALID_ARGUMENTS_ERROR;
+ }
+
+ std::string command_str = "";
+ for (int i = 0; i < command_len; i++)
+ command_str += std::to_string (command[i]) + " ";
+ safe_logger (spdlog::level::info, "sending command {} to device", command_str.c_str ());
+
+ int res = bluetooth_write_data ((char *)command, command_len);
+ if (res != command_len)
+ {
+ safe_logger (spdlog::level::err, "failed to config device, res: {}", res);
+ return (int)BrainFlowExitCodes::BOARD_WRITE_ERROR;
+ }
+ return (int)BrainFlowExitCodes::STATUS_OK;
+}
+
+int Explore::start_stream (int buffer_size, const char *streamer_params)
+{
+ if (!initialized)
+ {
+ safe_logger (spdlog::level::err, "You need to call prepare_session before start_stream");
+ return (int)BrainFlowExitCodes::BOARD_NOT_CREATED_ERROR;
+ }
+ if (keep_alive)
+ {
+ safe_logger (spdlog::level::err, "Streaming thread already running");
+ return (int)BrainFlowExitCodes::STREAM_ALREADY_RUN_ERROR;
+ }
+
+ int res = prepare_for_acquisition (buffer_size, streamer_params);
+ if (res != (int)BrainFlowExitCodes::STATUS_OK)
+ {
+ return res;
+ }
+
+ res = bluetooth_open_device ();
+ if (res != (int)BrainFlowExitCodes::STATUS_OK)
+ {
+ return res;
+ }
+
+ keep_alive = true;
+ streaming_thread = std::thread ([this] { this->read_thread (); });
+ // wait for the 1st package received
+ std::unique_lock lk (this->m);
+ auto sec = std::chrono::seconds (1);
+ int num_secs = 7;
+ if (cv.wait_for (lk, num_secs * sec,
+ [this] { return this->state != (int)BrainFlowExitCodes::SYNC_TIMEOUT_ERROR; }))
+ {
+ return state;
+ }
+ else
+ {
+ safe_logger (spdlog::level::err, "no data received in {} sec, stopping thread", num_secs);
+ stop_stream ();
+ return (int)BrainFlowExitCodes::BOARD_NOT_READY_ERROR;
+ }
+}
+
+int Explore::stop_stream ()
+{
+ if (keep_alive)
+ {
+ keep_alive = false;
+ streaming_thread.join ();
+ state = (int)BrainFlowExitCodes::SYNC_TIMEOUT_ERROR;
+ last_eeg_timestamp = -1.0;
+ return bluetooth_close_device ();
+ }
+ else
+ {
+ return (int)BrainFlowExitCodes::STREAM_THREAD_IS_NOT_RUNNING;
+ }
+}
+
+int Explore::release_session ()
+{
+ if (initialized)
+ {
+ stop_stream ();
+ free_packages ();
+ }
+ return BTLibBoard::release_session ();
+}
+
+void Explore::read_thread ()
+{
+ // exg data
+ int num_exg_rows = board_descr["default"]["num_rows"];
+ double *package_exg = new double[num_exg_rows];
+ memset (package_exg, 0, sizeof (double) * num_exg_rows);
+ // orientation data
+ int num_aux_rows = board_descr["auxiliary"]["num_rows"];
+ double *package_aux = new double[num_aux_rows];
+ memset (package_aux, 0, sizeof (double) * num_aux_rows);
+ // env data
+ int num_anc_rows = board_descr["ancillary"]["num_rows"];
+ double *package_anc = new double[num_anc_rows];
+ memset (package_anc, 0, sizeof (double) * num_anc_rows);
+
+ unsigned char payload_buffer[UINT16_MAX];
+
+ while (keep_alive)
+ {
+ struct ExploreHeader header;
+ int res = bluetooth_get_data ((char *)&header, sizeof (header));
+ if (res < 0)
+ {
+ safe_logger (spdlog::level::err, "error reading data from bluetooth");
+ }
+ if (res != 8)
+ {
+ continue;
+ }
+ // notify main thread that 1st byte received
+ if (state != (int)BrainFlowExitCodes::STATUS_OK)
+ {
+ {
+ std::lock_guard lk (m);
+ state = (int)BrainFlowExitCodes::STATUS_OK;
+ }
+ cv.notify_one ();
+ safe_logger (spdlog::level::debug, "received first package");
+ }
+ res = 0;
+ // safe_logger (spdlog::level::trace, "header pid counter size timestamp: {} {} {} {}",
+ // header.pid, header.counter, header.payload_size, header.timestamp);
+
+ header.payload_size -= 4; // its because of timestamp which moved to header from the package
+ if (header.payload_size < 1)
+ {
+ safe_logger (spdlog::level::err, "negative size for payload");
+ continue;
+ }
+
+ while ((res != header.payload_size) && (keep_alive))
+ {
+ res = bluetooth_get_data ((char *)payload_buffer, header.payload_size);
+ }
+ if (!keep_alive)
+ {
+ break;
+ }
+
+ switch (header.pid)
+ {
+ case 0x0d:
+ parse_orientation_data (&header, package_aux, payload_buffer);
+ break;
+ case 0x90: // eeg94
+ parse_eeg_data (&header, package_exg, payload_buffer, 2.4, 33);
+ break;
+ case 0xD0: // eeg94r
+ parse_eeg_data (&header, package_exg, payload_buffer, 2.4, 33);
+ break;
+ case 0x92: // eeg98
+ parse_eeg_data (&header, package_exg, payload_buffer, 2.4, 16);
+ break;
+ case 0xD2: // eeg98r
+ parse_eeg_data (&header, package_exg, payload_buffer, 2.4, 16);
+ break;
+ case 0x3e: // eeg99
+ parse_eeg_data (&header, package_exg, payload_buffer, 4.5, 16);
+ break;
+ case 0x1e: // eeg99s
+ parse_eeg_data (&header, package_exg, payload_buffer, 4.5, 16);
+ break;
+ case 0x13: // env
+ parse_env_data (&header, package_anc, payload_buffer);
+ break;
+ default:
+ safe_logger (spdlog::level::trace, "received header: {}", header.pid);
+ break;
+ }
+ }
+ delete[] package_anc;
+ delete[] package_exg;
+ delete[] package_aux;
+}
+
+std::string Explore::get_name_selector ()
+{
+ return "Explore";
+}
+
+void Explore::parse_orientation_data (
+ const ExploreHeader *header, double *package, unsigned char *payload)
+{
+ int payload_size = header->payload_size;
+ if ((payload[payload_size - 4] != 0xAF) || (payload[payload_size - 3] != 0xBE) ||
+ (payload[payload_size - 2] != 0xAD) || (payload[payload_size - 1] != 0xDE))
+ {
+ safe_logger (spdlog::level::warn, "checksum failed, {} {} {} {}", payload[payload_size - 4],
+ payload[payload_size - 3], payload[payload_size - 2], payload[payload_size - 1]);
+ return;
+ }
+ payload_size = payload_size - 4;
+
+ std::vector accel_channels = board_descr["auxiliary"]["accel_channels"];
+ std::vector gyro_channels = board_descr["auxiliary"]["gyro_channels"];
+ std::vector other_channels = board_descr["auxiliary"]["other_channels"];
+
+ if (payload_size % 2 != 0) // 2 is int16
+ {
+ safe_logger (spdlog::level::warn, "Invalid payload size for Orn package: {}");
+ return;
+ }
+ int num_datapoints = payload_size / 2;
+
+ for (int i = 0; i < num_datapoints; i++)
+ {
+ double data = (double)cast_16bit_to_int32_swap_order ((unsigned char *)(payload + 2 * i));
+ if (i < 3)
+ {
+ package[accel_channels[i]] = 0.061 * data;
+ }
+ else if (i < 6)
+ {
+ package[gyro_channels[i - 3]] = 8.750 * data;
+ }
+ else
+ {
+ if (i == 6)
+ {
+ data *= -1; // no idea why, copypaste, maybe bug in fw
+ }
+ package[other_channels[i - 6]] = 1.52 * data;
+ }
+ }
+ package[board_descr["auxiliary"]["timestamp_channel"].get ()] = get_timestamp ();
+ package[board_descr["auxiliary"]["package_num_channel"].get ()] = header->counter;
+ push_package (package, (int)BrainFlowPresets::AUXILIARY_PRESET);
+}
+
+void Explore::parse_eeg_data (const ExploreHeader *header, double *package, unsigned char *payload,
+ double vref, int n_packages)
+{
+ int payload_size = header->payload_size;
+ if ((payload[payload_size - 4] != 0xAF) || (payload[payload_size - 3] != 0xBE) ||
+ (payload[payload_size - 2] != 0xAD) || (payload[payload_size - 1] != 0xDE))
+ {
+ safe_logger (spdlog::level::warn, "checksum failed, {} {} {} {}", payload[payload_size - 4],
+ payload[payload_size - 3], payload[payload_size - 2], payload[payload_size - 1]);
+ return;
+ }
+ double current_timestamp = get_timestamp ();
+ payload_size = payload_size - 4;
+ std::vector eeg_channels = board_descr["default"]["eeg_channels"];
+ if ((payload_size % n_packages != 0) || (payload_size % 3 != 0)) // 3 is int24 format
+ {
+ safe_logger (spdlog::level::warn,
+ "Invalid payload size for EEG package: {}, n_packages: {}", payload_size, n_packages);
+ return;
+ }
+ if (payload_size % (eeg_channels.size () + 1) != 0) // 1 for data status, maybe its reference
+ {
+ safe_logger (spdlog::level::warn, "Invalid payload size for num_eeg_channels: {}, {}",
+ payload_size, eeg_channels.size ());
+ return;
+ }
+
+ int num_datapoints = payload_size / 3;
+ // convert to uV
+ std::vector data;
+ for (int i = 0; i < num_datapoints; i++)
+ {
+ double datapoint =
+ (double)cast_24bit_to_int32_swap_order ((unsigned char *)(payload + i * 3));
+ data.push_back (datapoint);
+ }
+ int num_total_channels = (int)eeg_channels.size () + 1;
+ int other_channel = board_descr["default"]["other_channels"][0];
+ // submit packages
+ if (last_eeg_timestamp > 0.0)
+ {
+ double step = (current_timestamp - last_eeg_timestamp) / n_packages;
+ for (int i = 0; i < n_packages; i++)
+ {
+ for (int j = 0; j < num_total_channels; j++)
+ {
+ if (j == 0)
+ {
+ package[other_channel] = data[i * num_total_channels + j];
+ }
+ else
+ {
+ double gain = 1.E-6 * (pow (2, 23) - 1) * 6.0;
+ package[eeg_channels[j - 1]] = data[i * num_total_channels + j] * vref / gain;
+ }
+ }
+ package[board_descr["default"]["timestamp_channel"].get ()] = last_eeg_timestamp +
+ step * (i + 1); // todo improve timestamps, use data from device
+ package[board_descr["default"]["package_num_channel"].get ()] = header->counter;
+ push_package (package, (int)BrainFlowPresets::DEFAULT_PRESET);
+ }
+ }
+ last_eeg_timestamp = current_timestamp;
+}
+
+void Explore::parse_env_data (const ExploreHeader *header, double *package, unsigned char *payload)
+{
+ int payload_size = header->payload_size;
+ if ((payload[payload_size - 4] != 0xAF) || (payload[payload_size - 3] != 0xBE) ||
+ (payload[payload_size - 2] != 0xAD) || (payload[payload_size - 1] != 0xDE))
+ {
+ safe_logger (spdlog::level::warn, "checksum failed, {} {} {} {}", payload[payload_size - 4],
+ payload[payload_size - 3], payload[payload_size - 2], payload[payload_size - 1]);
+ return;
+ }
+ payload_size = payload_size - 4;
+ if (payload_size < 5)
+ {
+ safe_logger (spdlog::level::warn, "invalid size for env package: {}", payload_size);
+ return;
+ }
+ int temperature_channel = board_descr["ancillary"]["temperature_channels"][0];
+ int battery_channel = board_descr["ancillary"]["battery_channel"];
+ int other_channel = board_descr["ancillary"]["other_channels"][0];
+
+ uint16_t battery_raw = 0;
+ memcpy (&battery_raw, payload + 3, 2);
+ double battery = (16.8 / 6.8) * (1.8 / 2457) * battery_raw;
+ package[temperature_channel] = (double)payload[0];
+ package[battery_channel] = get_battery_percentage (battery);
+ uint16_t light_raw = 0;
+ memcpy (&light_raw, payload + 1, 2);
+ package[other_channel] = (1000.0 / 4095.0) * light_raw;
+ package[board_descr["ancillary"]["timestamp_channel"].get ()] = get_timestamp ();
+ package[board_descr["ancillary"]["package_num_channel"].get ()] = header->counter;
+ push_package (package, (int)BrainFlowPresets::ANCILLARY_PRESET);
+}
+
+double Explore::get_battery_percentage (double battery)
+{
+ double percentage = 0.0;
+ if (battery < 3.1)
+ percentage = 1;
+ else if (battery < 3.5)
+ percentage = 1 + (battery - 3.1) / .4 * 10;
+ else if (battery < 3.8)
+ percentage = 10 + (battery - 3.5) / .3 * 40;
+ else if (battery < 3.9)
+ percentage = 40 + (battery - 3.8) / .1 * 20;
+ else if (battery < 4.)
+ percentage = 60 + (battery - 3.9) / .1 * 15;
+ else if (battery < 4.1)
+ percentage = 75 + (battery - 4.) / .1 * 15;
+ else if (battery < 4.2)
+ percentage = 90 + (battery - 4.1) / .1 * 10;
+ else if (battery > 4.2)
+ percentage = 100;
+
+ return percentage;
+}
\ No newline at end of file
diff --git a/src/board_controller/mentalab/inc/explore.h b/src/board_controller/mentalab/inc/explore.h
new file mode 100644
index 000000000..f12cb44bf
--- /dev/null
+++ b/src/board_controller/mentalab/inc/explore.h
@@ -0,0 +1,58 @@
+#pragma once
+
+#include
+#include
+#include
+#include
+
+#include "bt_lib_board.h"
+
+
+#pragma pack(push, 1)
+struct ExploreHeader
+{
+ unsigned char pid;
+ unsigned char counter;
+ uint16_t payload_size;
+ uint32_t timestamp;
+
+ ExploreHeader ()
+ {
+ pid = 0;
+ payload_size = 0;
+ counter = 0;
+ timestamp = 0;
+ }
+};
+#pragma pack(pop)
+
+class Explore : public BTLibBoard
+{
+
+protected:
+ volatile bool keep_alive;
+ volatile int state;
+ std::thread streaming_thread;
+ std::mutex m;
+ std::condition_variable cv;
+ double last_eeg_timestamp;
+
+ void read_thread ();
+ std::string get_name_selector ();
+ void parse_eeg_data (const ExploreHeader *header, double *package, unsigned char *payload,
+ double vref, int n_packages);
+ void parse_orientation_data (
+ const ExploreHeader *header, double *package, unsigned char *payload);
+ void parse_env_data (const ExploreHeader *header, double *package, unsigned char *payload);
+ double get_battery_percentage (double battery);
+
+public:
+ Explore (int board_id, struct BrainFlowInputParams params);
+ ~Explore ();
+
+ int prepare_session ();
+ int config_board (std::string config, std::string &response);
+ int start_stream (int buffer_size, const char *streamer_params);
+ int stop_stream ();
+ int release_session ();
+};
diff --git a/src/tests/utils/bluetooth/bluetooth_functions_unittest.cpp b/src/tests/utils/bluetooth/bluetooth_functions_unittest.cpp
index bc4a51fbd..0c4010228 100644
--- a/src/tests/utils/bluetooth/bluetooth_functions_unittest.cpp
+++ b/src/tests/utils/bluetooth/bluetooth_functions_unittest.cpp
@@ -88,20 +88,6 @@ TEST (BluetoothTest, CloseDevice_AddressNull_ParameterErrorReturned)
EXPECT_EQ (result, (int)SocketBluetoothReturnCodes::PARAMETER_ERROR);
}
-TEST (BluetoothTest, GetData_AllRequestedBytesAvailable_NumberOfRequestedBytesReturned)
-{
- char mac[] = BRAINFLOW_TEST_BLUETOOTH_VALID_MAC;
- bluetooth_open_device (BRAINFLOW_TEST_BLUETOOTH_ALL_BYTES_AVAILABLE_PORT, mac);
-
- char buffer[BRAINFLOW_TEST_BLUETOOTH_EXPECTED_BYTES] {0};
- int n_bytes = bluetooth_get_data (buffer, BRAINFLOW_TEST_BLUETOOTH_EXPECTED_BYTES, mac);
-
- EXPECT_EQ (n_bytes, BRAINFLOW_TEST_BLUETOOTH_EXPECTED_BYTES);
- EXPECT_THAT (buffer, Each (BRAINFLOW_TEST_BLUETOOTH_DATA_CHAR));
-
- bluetooth_close_device (mac);
-}
-
TEST (BluetoothTest, GetData_SomeRequestedBytesAvailable_NumberBytesReadReturned)
{
char mac[] = BRAINFLOW_TEST_BLUETOOTH_VALID_MAC;
@@ -110,11 +96,7 @@ TEST (BluetoothTest, GetData_SomeRequestedBytesAvailable_NumberBytesReadReturned
char buffer[BRAINFLOW_TEST_BLUETOOTH_EXPECTED_BYTES] {0};
int n_bytes = bluetooth_get_data (buffer, BRAINFLOW_TEST_BLUETOOTH_EXPECTED_BYTES, mac);
- EXPECT_GT (n_bytes, 0);
- EXPECT_LT (n_bytes, BRAINFLOW_TEST_BLUETOOTH_EXPECTED_BYTES);
-
- EXPECT_THAT (buffer, Contains (BRAINFLOW_TEST_BLUETOOTH_DATA_CHAR).Times (n_bytes));
-
+ EXPECT_EQ (n_bytes, 0);
bluetooth_close_device (mac);
}
diff --git a/src/tests/utils/bluetooth/socket_bluetooth_test.cpp b/src/tests/utils/bluetooth/socket_bluetooth_test.cpp
index 90725cbb1..83e2b1024 100644
--- a/src/tests/utils/bluetooth/socket_bluetooth_test.cpp
+++ b/src/tests/utils/bluetooth/socket_bluetooth_test.cpp
@@ -38,28 +38,27 @@ int SocketBluetooth::recv (char *data, int size)
return 0;
}
- int n_bytes = bytes_available ();
-
- // Fill the data buffer
- for (auto i = 0; i < n_bytes; i++)
- {
- data[i] = BRAINFLOW_TEST_BLUETOOTH_DATA_CHAR;
- }
-
- return n_bytes;
-}
-
-int SocketBluetooth::bytes_available ()
-{
+ int n_bytes = 0;
switch (port)
{
case BRAINFLOW_TEST_BLUETOOTH_ALL_BYTES_AVAILABLE_PORT:
- return BRAINFLOW_TEST_BLUETOOTH_EXPECTED_BYTES;
+ n_bytes = BRAINFLOW_TEST_BLUETOOTH_EXPECTED_BYTES;
case BRAINFLOW_TEST_BLUETOOTH_SOME_BYTES_AVAILABLE_PORT:
- return BRAINFLOW_TEST_BLUETOOTH_EXPECTED_BYTES / 2;
+ n_bytes = BRAINFLOW_TEST_BLUETOOTH_EXPECTED_BYTES / 2;
default:
- return 0;
+ n_bytes = 0;
+ }
+
+ if (n_bytes >= size)
+ {
+ for (auto i = 0; i < size; i++)
+ {
+ data[i] = BRAINFLOW_TEST_BLUETOOTH_DATA_CHAR;
+ }
+ return size;
}
+
+ return 0;
}
int SocketBluetooth::close ()
diff --git a/src/utils/bluetooth/inc/socket_bluetooth.h b/src/utils/bluetooth/inc/socket_bluetooth.h
index 22bc5395e..2e95d7df6 100644
--- a/src/utils/bluetooth/inc/socket_bluetooth.h
+++ b/src/utils/bluetooth/inc/socket_bluetooth.h
@@ -15,9 +15,9 @@
#ifdef __APPLE__
#include "pipe.h"
-#include
#endif
+#include
#include
#include
#include
@@ -37,7 +37,10 @@ class SocketBluetooth
int connect ();
int send (const char *data, int size);
int recv (char *data, int size);
- int bytes_available ();
+ int bytes_available ()
+ {
+ return (int)temp_buffer.size ();
+ }
int close ();
static std::pair discover (char *device_selector);
@@ -45,12 +48,13 @@ class SocketBluetooth
private:
std::string mac_addr;
int port;
+ std::queue temp_buffer;
#ifdef _WIN32
SOCKET socket_bt;
#elif defined(__linux__)
int socket_bt;
+ int rep[2];
#elif defined(__APPLE__)
pipe_consumer_t *consumer;
- std::queue temp_buffer;
#endif
};
diff --git a/src/utils/bluetooth/socket_bluetooth_linux.cpp b/src/utils/bluetooth/socket_bluetooth_linux.cpp
index 9550b1d2b..9ab10ff95 100644
--- a/src/utils/bluetooth/socket_bluetooth_linux.cpp
+++ b/src/utils/bluetooth/socket_bluetooth_linux.cpp
@@ -23,10 +23,18 @@ SocketBluetooth::SocketBluetooth (std::string mac_addr, int port)
this->mac_addr = mac_addr;
this->port = port;
socket_bt = -1;
+ rep[0] = -1;
+ rep[1] = -1;
}
int SocketBluetooth::connect ()
{
+ if (pipe (rep) == -1)
+ {
+ return (int)SocketBluetoothReturnCodes::OS_SPECIFIC_ERROR;
+ }
+ int flags = fcntl (rep[0], F_GETFL, 0);
+ fcntl (rep[0], F_SETFL, flags | O_NONBLOCK);
struct sockaddr_rc addr;
memset (&addr, 0, sizeof (addr));
@@ -63,40 +71,34 @@ int SocketBluetooth::recv (char *data, int size)
{
return -1;
}
- // waiting for exact amount of bytes
- int e = bytes_available ();
- if (e < size)
- {
- return 0;
- }
fd_set set;
FD_ZERO (&set);
FD_SET (socket_bt, &set);
+ FD_SET (rep[0], &set);
+ int nfds = (socket_bt > rep[0]) ? socket_bt : rep[0];
- int res = -1;
- struct timeval timeout;
- timeout.tv_sec = 0;
- timeout.tv_usec = 0;
- if (select (socket_bt + 1, &set, NULL, NULL, &timeout) >= 0)
+ if (pselect (nfds + 1, &set, NULL, NULL, NULL, NULL) >= 0)
{
if (FD_ISSET (socket_bt, &set))
{
- res = ::recv (socket_bt, data, size, 0);
+ int res = ::recv (socket_bt, data, size, 0);
+ for (int i = 0; i < res; i++)
+ {
+ temp_buffer.push (data[i]);
+ }
}
}
- return res;
-}
-
-int SocketBluetooth::bytes_available ()
-{
- if (socket_bt < 0)
+ if ((int)temp_buffer.size () < size)
{
- return -1;
+ return 0;
+ }
+ for (int i = 0; i < size; i++)
+ {
+ data[i] = temp_buffer.front ();
+ temp_buffer.pop ();
}
- int count;
- ioctl (socket_bt, FIONREAD, &count);
- return count;
+ return size;
}
int SocketBluetooth::close ()
diff --git a/src/utils/bluetooth/socket_bluetooth_macos.mm b/src/utils/bluetooth/socket_bluetooth_macos.mm
index 041a98882..fb0539d86 100644
--- a/src/utils/bluetooth/socket_bluetooth_macos.mm
+++ b/src/utils/bluetooth/socket_bluetooth_macos.mm
@@ -104,11 +104,6 @@
return res;
}
-int SocketBluetooth::bytes_available ()
-{
- return 0;
-}
-
std::pair SocketBluetooth::discover (char *selector)
{
// somehow it leads to connection reset and audio stops, todo - fix, dont use autodiscovery on macos
diff --git a/src/utils/bluetooth/socket_bluetooth_win.cpp b/src/utils/bluetooth/socket_bluetooth_win.cpp
index d747ff7c4..4f86756c1 100644
--- a/src/utils/bluetooth/socket_bluetooth_win.cpp
+++ b/src/utils/bluetooth/socket_bluetooth_win.cpp
@@ -93,38 +93,32 @@ int SocketBluetooth::recv (char *data, int size)
{
return -1;
}
- // waiting for exact amount of bytes
- int e = bytes_available ();
- if (e < size)
- {
- return 0;
- }
fd_set set;
FD_ZERO (&set);
FD_SET (socket_bt, &set);
- int res = -1;
-
timeval timeout {0, 0};
if (select (1, &set, nullptr, nullptr, &timeout) >= 0)
{
if (FD_ISSET (socket_bt, &set))
{
- res = ::recv (socket_bt, data, size, 0);
+ int res = ::recv (socket_bt, data, size, 0);
+ for (int i = 0; i < res; i++)
+ {
+ temp_buffer.push (data[i]);
+ }
}
}
- return res;
-}
-
-int SocketBluetooth::bytes_available ()
-{
- if (socket_bt == INVALID_SOCKET)
+ if ((int)temp_buffer.size () < size)
{
- return -1;
+ return 0;
+ }
+ for (int i = 0; i < size; i++)
+ {
+ data[i] = temp_buffer.front ();
+ temp_buffer.pop ();
}
- u_long count;
- ioctlsocket (socket_bt, FIONREAD, &count);
- return count;
+ return size;
}
int SocketBluetooth::close ()
diff --git a/src/utils/inc/brainflow_constants.h b/src/utils/inc/brainflow_constants.h
index b6e96c1b2..e809fdd8e 100644
--- a/src/utils/inc/brainflow_constants.h
+++ b/src/utils/inc/brainflow_constants.h
@@ -77,9 +77,11 @@ enum class BoardIds : int
MUSE_2016_BOARD = 41,
MUSE_2016_BLED_BOARD = 42,
PIEEG_BOARD = 43,
+ EXPLORE_4_CHAN_BOARD = 44,
+ EXPLORE_8_CHAN_BOARD = 45,
// use it to iterate
FIRST = PLAYBACK_FILE_BOARD,
- LAST = PIEEG_BOARD
+ LAST = EXPLORE_8_CHAN_BOARD
};
enum class IpProtocolTypes : int
diff --git a/src/utils/inc/custom_cast.h b/src/utils/inc/custom_cast.h
index 38459d437..28d82c8de 100644
--- a/src/utils/inc/custom_cast.h
+++ b/src/utils/inc/custom_cast.h
@@ -19,6 +19,15 @@ inline int32_t cast_24bit_to_int32 (unsigned char *byte_array)
return (prefix << 24) | (byte_array[0] << 16) | (byte_array[1] << 8) | byte_array[2];
}
+inline int32_t cast_24bit_to_int32_swap_order (unsigned char *byte_array)
+{
+ unsigned char swapped[3];
+ swapped[0] = byte_array[2];
+ swapped[1] = byte_array[1];
+ swapped[2] = byte_array[0];
+ return cast_24bit_to_int32 (swapped);
+}
+
inline int32_t cast_16bit_to_int32 (unsigned char *byte_array)
{
int prefix = 0;
@@ -29,6 +38,14 @@ inline int32_t cast_16bit_to_int32 (unsigned char *byte_array)
return (prefix << 16) | (byte_array[0] << 8) | byte_array[1];
}
+inline int32_t cast_16bit_to_int32_swap_order (unsigned char *byte_array)
+{
+ unsigned char swapped[2];
+ swapped[0] = byte_array[1];
+ swapped[1] = byte_array[0];
+ return cast_16bit_to_int32 (swapped);
+}
+
inline void uchar_to_bits (unsigned char c, unsigned char *bits)
{
for (int i = sizeof (unsigned char) * 8; i; c >>= 1)
@@ -93,4 +110,4 @@ inline int32_t swap_endians (int32_t value)
rightmost_byte <<= 0;
result = (leftmost_byte | left_middle_byle | right_middle_byte | rightmost_byte);
return result;
-}
\ No newline at end of file
+}