From 5e9029f1bbe015f4d9a232654db573e2f367fa9e Mon Sep 17 00:00:00 2001 From: Andrey Parfenov Date: Sat, 23 Aug 2025 19:07:18 +0200 Subject: [PATCH] Add support for Muse S Anthena device Signed-off-by: Andrey Parfenov --- .../brainflow/board_controller_library.cs | 1 + .../src/main/java/brainflow/BoardIds.java | 3 +- julia_package/brainflow/src/board_shim.jl | 1 + matlab_package/brainflow/BoardIds.m | 1 + nodejs_package/brainflow/brainflow.types.ts | 3 +- python_package/brainflow/board_shim.py | 1 + src/board_controller/board_controller.cpp | 4 + src/board_controller/brainflow_boards.cpp | 26 +- src/board_controller/build.cmake | 1 + src/board_controller/muse/inc/muse_anthena.h | 44 ++ .../muse/inc/muse_anthena_constants.h | 13 + src/board_controller/muse/muse.cpp | 8 +- src/board_controller/muse/muse_anthena.cpp | 424 ++++++++++++++++++ src/utils/inc/brainflow_constants.h | 3 +- 14 files changed, 528 insertions(+), 5 deletions(-) create mode 100644 src/board_controller/muse/inc/muse_anthena.h create mode 100644 src/board_controller/muse/inc/muse_anthena_constants.h create mode 100644 src/board_controller/muse/muse_anthena.cpp diff --git a/csharp_package/brainflow/brainflow/board_controller_library.cs b/csharp_package/brainflow/brainflow/board_controller_library.cs index 10a910621..ff62deaf8 100644 --- a/csharp_package/brainflow/brainflow/board_controller_library.cs +++ b/csharp_package/brainflow/brainflow/board_controller_library.cs @@ -124,6 +124,7 @@ public enum BoardIds SYNCHRONI_UNO_1_CHANNELS_BOARD = 62, OB3000_24_CHANNELS_BOARD = 63, BIOLISTENER_BOARD = 64, + MUSE_S_ANTHENA_BOARD = 65 }; diff --git a/java_package/brainflow/src/main/java/brainflow/BoardIds.java b/java_package/brainflow/src/main/java/brainflow/BoardIds.java index 487d8fc5a..c672ca971 100644 --- a/java_package/brainflow/src/main/java/brainflow/BoardIds.java +++ b/java_package/brainflow/src/main/java/brainflow/BoardIds.java @@ -73,7 +73,8 @@ public enum BoardIds SYNCHRONI_PENTO_8_CHANNELS_BOARD(61), SYNCHRONI_UNO_1_CHANNELS_BOARD(62), OB3000_24_CHANNELS_BOARD(63), - BIOLISTENER_BOARD(64); + BIOLISTENER_BOARD(64), + MUSE_S_ANTHENA_BOARD(65); 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 3e7086093..ccc32ebd1 100644 --- a/julia_package/brainflow/src/board_shim.jl +++ b/julia_package/brainflow/src/board_shim.jl @@ -69,6 +69,7 @@ export BrainFlowInputParams SYNCHRONI_UNO_1_CHANNELS_BOARD = 62 OB3000_24_CHANNELS_BOARD = 63 BIOLISTENER_BOARD = 64 + MUSE_S_ANTHENA_BOARD = 65 end diff --git a/matlab_package/brainflow/BoardIds.m b/matlab_package/brainflow/BoardIds.m index cc242952d..04305b712 100644 --- a/matlab_package/brainflow/BoardIds.m +++ b/matlab_package/brainflow/BoardIds.m @@ -67,5 +67,6 @@ SYNCHRONI_UNO_1_CHANNELS_BOARD(62) OB3000_24_CHANNELS_BOARD(63) BIOLISTENER_BOARD(64) + MUSE_S_ANTHENA_BOARD(65) end end \ No newline at end of file diff --git a/nodejs_package/brainflow/brainflow.types.ts b/nodejs_package/brainflow/brainflow.types.ts index f55f10187..77c70dda8 100644 --- a/nodejs_package/brainflow/brainflow.types.ts +++ b/nodejs_package/brainflow/brainflow.types.ts @@ -76,7 +76,8 @@ export enum BoardIds { SYNCHRONI_PENTO_8_CHANNELS_BOARD = 61, SYNCHRONI_UNO_1_CHANNELS_BOARD = 62, OB3000_24_CHANNELS_BOARD = 63, - BIOLISTENER_BOARD = 64 + BIOLISTENER_BOARD = 64, + MUSE_S_ANTHENA_BOARD = 65 } export enum IpProtocolTypes { diff --git a/python_package/brainflow/board_shim.py b/python_package/brainflow/board_shim.py index 0f98d001f..0a20b16c9 100644 --- a/python_package/brainflow/board_shim.py +++ b/python_package/brainflow/board_shim.py @@ -82,6 +82,7 @@ class BoardIds(enum.IntEnum): SYNCHRONI_UNO_1_CHANNELS_BOARD = 62 #: OB3000_24_CHANNELS_BOARD = 63 #: BIOLISTENER_BOARD = 64 #: + MUSE_S_ANTHENA_BOARD = 65 #: class IpProtocolTypes(enum.IntEnum): diff --git a/src/board_controller/board_controller.cpp b/src/board_controller/board_controller.cpp index 3cab800f5..6c491dd5d 100644 --- a/src/board_controller/board_controller.cpp +++ b/src/board_controller/board_controller.cpp @@ -49,6 +49,7 @@ #include "json.hpp" #include "knight.h" #include "muse.h" +#include "muse_anthena.h" #include "muse_bled.h" #include "notion_osc.h" #include "ntl_wifi.h" @@ -237,6 +238,9 @@ int prepare_session (int board_id, const char *json_brainflow_input_params) case BoardIds::MUSE_S_BOARD: board = std::shared_ptr (new Muse (board_id, params)); break; + case BoardIds::MUSE_S_ANTHENA_BOARD: + board = std::shared_ptr (new MuseAnthena (board_id, params)); + break; case BoardIds::BRAINALIVE_BOARD: board = std::shared_ptr (new BrainAlive (params)); break; diff --git a/src/board_controller/brainflow_boards.cpp b/src/board_controller/brainflow_boards.cpp index e3f0a5657..0e787468e 100644 --- a/src/board_controller/brainflow_boards.cpp +++ b/src/board_controller/brainflow_boards.cpp @@ -82,7 +82,8 @@ BrainFlowBoards::BrainFlowBoards() {"61", json::object()}, {"62", json::object()}, {"63", json::object()}, - {"64", json::object()} + {"64", json::object()}, + {"65", json::object()} } }}; @@ -1221,6 +1222,29 @@ BrainFlowBoards::BrainFlowBoards() {"battery_channel", 8}, {"other_channels", {9, 10}} }; + brainflow_boards_json["boards"]["65"]["default"] = + { + {"name", "MuseAnthena"}, + {"sampling_rate", 256}, + {"timestamp_channel", 6}, + {"marker_channel", 7}, + {"package_num_channel", 0}, + {"num_rows", 8}, + {"eeg_channels", {1, 2, 3, 4}}, + {"eeg_names", "TP9,AF7,AF8,TP10"}, + {"other_channels", {5}} + }; + brainflow_boards_json["boards"]["65"]["auxiliary"] = + { + {"name", "MuseAnthenaAux"}, + {"sampling_rate", 52}, + {"timestamp_channel", 7}, + {"marker_channel", 8}, + {"package_num_channel", 0}, + {"num_rows", 9}, + {"accel_channels", {1, 2, 3}}, + {"gyro_channels", {4, 5, 6}} + }; } BrainFlowBoards boards_struct; diff --git a/src/board_controller/build.cmake b/src/board_controller/build.cmake index 5239cb2d6..998b70543 100644 --- a/src/board_controller/build.cmake +++ b/src/board_controller/build.cmake @@ -80,6 +80,7 @@ SET (BOARD_CONTROLLER_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/board_controller/enophone/enophone.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/board_controller/ble_lib_board.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/board_controller/muse/muse.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/board_controller/muse/muse_anthena.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/board_controller/brainalive/brainalive.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/board_controller/emotibit/emotibit.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/board_controller/ntl/ntl_wifi.cpp diff --git a/src/board_controller/muse/inc/muse_anthena.h b/src/board_controller/muse/inc/muse_anthena.h new file mode 100644 index 000000000..fc0eeebd8 --- /dev/null +++ b/src/board_controller/muse/inc/muse_anthena.h @@ -0,0 +1,44 @@ +#pragma once + +#include +#include +#include +#include + +#include "ble_lib_board.h" + + +class MuseAnthena : public BLELibBoard +{ + +protected: + volatile simpleble_adapter_t muse_adapter; + volatile simpleble_peripheral_t muse_peripheral; + bool initialized; + bool is_streaming; + std::mutex m; + std::condition_variable cv; + std::vector> notified_characteristics; + std::pair control_characteristics; + + std::string bytes_to_string (const uint8_t *data, size_t size); + +public: + MuseAnthena (int board_id, struct BrainFlowInputParams params); + ~MuseAnthena (); + + int prepare_session (); + int start_stream (int buffer_size, const char *streamer_params); + int stop_stream (); + int release_session (); + int config_board (std::string config, std::string &response); + int config_board (std::string config); + + void adapter_on_scan_found (simpleble_adapter_t adapter, simpleble_peripheral_t peripheral); + void peripheral_on_eeg (simpleble_peripheral_t peripheral, simpleble_uuid_t service, + simpleble_uuid_t characteristic, const uint8_t *data, size_t size); + void peripheral_on_aux (simpleble_peripheral_t peripheral, simpleble_uuid_t service, + simpleble_uuid_t characteristic, const uint8_t *data, size_t size); + void peripheral_on_status (simpleble_peripheral_t peripheral, simpleble_uuid_t service, + simpleble_uuid_t characteristic, const uint8_t *data, size_t size); +}; diff --git a/src/board_controller/muse/inc/muse_anthena_constants.h b/src/board_controller/muse/inc/muse_anthena_constants.h new file mode 100644 index 000000000..e4517ef2d --- /dev/null +++ b/src/board_controller/muse/inc/muse_anthena_constants.h @@ -0,0 +1,13 @@ +#pragma once + + +// info about services and chars +#define MUSE_ANTHENA_SERVICE_UUID 0xFE8D + +#define MUSE_ANTHENA_GATT_ATTR_STREAM_TOGGLE "273e0001-4c4d-454d-96be-f03bac821358" +#define MUSE_ANTHENA_GATT_EEG "273e0013-4c4d-454d-96be-f03bac821358" +#define MUSE_ANTHENA_GATT_AUX "273e0014-4c4d-454d-96be-f03bac821358" + +// info for equations +#define MUSE_ANTHENA_ACCELEROMETER_SCALE_FACTOR 0.0000610352 +#define MUSE_ANTHENA_GYRO_SCALE_FACTOR 0.007476 diff --git a/src/board_controller/muse/muse.cpp b/src/board_controller/muse/muse.cpp index 97741313e..390bbf5ff 100644 --- a/src/board_controller/muse/muse.cpp +++ b/src/board_controller/muse/muse.cpp @@ -558,8 +558,14 @@ int Muse::config_board (std::string config) { return (int)BrainFlowExitCodes::BOARD_NOT_CREATED_ERROR; } - uint8_t command[16]; + constexpr int max_size = 16; + uint8_t command[max_size]; size_t len = config.size (); + if (len + 2 >= max_size) + { + safe_logger (spdlog::level::err, "Invalid command, max size is {}", max_size); + return (int)BrainFlowExitCodes::INVALID_ARGUMENTS_ERROR; + } command[0] = (uint8_t)len + 1; for (size_t i = 0; i < len; i++) { diff --git a/src/board_controller/muse/muse_anthena.cpp b/src/board_controller/muse/muse_anthena.cpp new file mode 100644 index 000000000..9dcc09930 --- /dev/null +++ b/src/board_controller/muse/muse_anthena.cpp @@ -0,0 +1,424 @@ +#include "muse_anthena.h" + +#include +#include +#include + +#include "custom_cast.h" +#include "muse_anthena_constants.h" +#include "timestamp.h" + + +void anthena_adapter_on_scan_found ( + simpleble_adapter_t adapter, simpleble_peripheral_t peripheral, void *board) +{ + ((MuseAnthena *)(board))->adapter_on_scan_found (adapter, peripheral); +} + +void anthena_peripheral_on_eeg (simpleble_peripheral_t peripheral, simpleble_uuid_t service, + simpleble_uuid_t characteristic, const uint8_t *data, size_t size, void *board) +{ + ((MuseAnthena *)(board))->peripheral_on_eeg (peripheral, service, characteristic, data, size); +} + +void anthena_peripheral_on_aux (simpleble_peripheral_t peripheral, simpleble_uuid_t service, + simpleble_uuid_t characteristic, const uint8_t *data, size_t size, void *board) +{ + ((MuseAnthena *)(board))->peripheral_on_aux (peripheral, service, characteristic, data, size); +} + +MuseAnthena::MuseAnthena (int board_id, struct BrainFlowInputParams params) + : BLELibBoard (board_id, params) +{ + initialized = false; + muse_adapter = NULL; + muse_peripheral = NULL; + is_streaming = false; +} + +MuseAnthena::~MuseAnthena () +{ + skip_logs = true; + release_session (); +} + +int MuseAnthena::prepare_session () +{ + if (initialized) + { + safe_logger (spdlog::level::info, "Session is already prepared"); + return (int)BrainFlowExitCodes::STATUS_OK; + } + if (params.timeout < 1) + { + params.timeout = 6; + } + safe_logger (spdlog::level::info, "Use timeout for discovery: {}", params.timeout); + if (!init_dll_loader ()) + { + safe_logger (spdlog::level::err, "Failed to init dll_loader"); + return (int)BrainFlowExitCodes::GENERAL_ERROR; + } + size_t adapter_count = simpleble_adapter_get_count (); + if (adapter_count == 0) + { + safe_logger (spdlog::level::err, "No BLE adapters found"); + return (int)BrainFlowExitCodes::UNABLE_TO_OPEN_PORT_ERROR; + } + + safe_logger (spdlog::level::info, "found {} BLE adapter(s)", adapter_count); + + muse_adapter = simpleble_adapter_get_handle (0); + if (muse_adapter == NULL) + { + safe_logger (spdlog::level::err, "Adapter is NULL"); + return (int)BrainFlowExitCodes::UNABLE_TO_OPEN_PORT_ERROR; + } + + simpleble_adapter_set_callback_on_scan_found ( + muse_adapter, ::anthena_adapter_on_scan_found, (void *)this); + + if (!simpleble_adapter_is_bluetooth_enabled ()) + { + safe_logger (spdlog::level::warn, "Probably bluetooth is disabled."); + // dont throw an exception because of this + // https://github.com/OpenBluetoothToolbox/SimpleBLE/issues/115 + } + + simpleble_adapter_scan_start (muse_adapter); + int res = (int)BrainFlowExitCodes::STATUS_OK; + std::unique_lock lk (m); + auto sec = std::chrono::seconds (1); + if (cv.wait_for (lk, params.timeout * sec, [this] { return this->muse_peripheral != NULL; })) + { + safe_logger (spdlog::level::info, "Found MuseAnthena device"); + } + else + { + safe_logger (spdlog::level::err, "Failed to find MuseAnthena Device"); + res = (int)BrainFlowExitCodes::BOARD_NOT_READY_ERROR; + } + simpleble_adapter_scan_stop (muse_adapter); + if (res == (int)BrainFlowExitCodes::STATUS_OK) + { + // for safety + for (int i = 0; i < 3; i++) + { + if (simpleble_peripheral_connect (muse_peripheral) == SIMPLEBLE_SUCCESS) + { + safe_logger (spdlog::level::info, "Connected to MuseAnthena Device"); + res = (int)BrainFlowExitCodes::STATUS_OK; + break; + } + else + { + safe_logger ( + spdlog::level::warn, "Failed to connect to MuseAnthena Device: {}/3", i); + res = (int)BrainFlowExitCodes::BOARD_NOT_READY_ERROR; +#ifdef _WIN32 + Sleep (1000); +#else + sleep (1); +#endif + } + } + } + +// https://github.com/OpenBluetoothToolbox/SimpleBLE/issues/26#issuecomment-955606799 +#ifdef _WIN32 + Sleep (1000); +#else + sleep (1); +#endif + + bool control_characteristics_found = false; + + if (res == (int)BrainFlowExitCodes::STATUS_OK) + { + size_t services_count = simpleble_peripheral_services_count (muse_peripheral); + for (size_t i = 0; i < services_count; i++) + { + simpleble_service_t service; + if (simpleble_peripheral_services_get (muse_peripheral, i, &service) != + SIMPLEBLE_SUCCESS) + { + safe_logger (spdlog::level::err, "failed to get service"); + res = (int)BrainFlowExitCodes::BOARD_NOT_READY_ERROR; + } + + safe_logger (spdlog::level::trace, "found servce {}", service.uuid.value); + for (size_t j = 0; j < service.characteristic_count; j++) + { + safe_logger (spdlog::level::trace, "found characteristic {}", + service.characteristics[j].uuid.value); + + // control characteristic + if (strcmp (service.characteristics[j].uuid.value, + MUSE_ANTHENA_GATT_ATTR_STREAM_TOGGLE) == 0) + { + control_characteristics = std::pair ( + service.uuid, service.characteristics[j].uuid); + control_characteristics_found = true; + safe_logger (spdlog::level::info, "found control characteristic"); + } + + // eeg characteristic + if (strcmp (service.characteristics[j].uuid.value, MUSE_ANTHENA_GATT_EEG) == 0) + { + if (simpleble_peripheral_notify (muse_peripheral, service.uuid, + service.characteristics[j].uuid, ::anthena_peripheral_on_eeg, + (void *)this) == SIMPLEBLE_SUCCESS) + { + notified_characteristics.push_back ( + std::pair ( + service.uuid, service.characteristics[j].uuid)); + } + else + { + safe_logger (spdlog::level::err, "Failed to notify for {} {}", + service.uuid.value, service.characteristics[j].uuid.value); + res = (int)BrainFlowExitCodes::GENERAL_ERROR; + } + } + + // aux characteristic(acce, gyro, etc) + if (strcmp (service.characteristics[j].uuid.value, MUSE_ANTHENA_GATT_AUX) == 0) + { + if (simpleble_peripheral_notify (muse_peripheral, service.uuid, + service.characteristics[j].uuid, ::anthena_peripheral_on_aux, + (void *)this) == SIMPLEBLE_SUCCESS) + { + notified_characteristics.push_back ( + std::pair ( + service.uuid, service.characteristics[j].uuid)); + } + else + { + safe_logger (spdlog::level::err, "Failed to notify for {} {}", + service.uuid.value, service.characteristics[j].uuid.value); + res = (int)BrainFlowExitCodes::GENERAL_ERROR; + } + } + } + } + } + + if (res == (int)BrainFlowExitCodes::STATUS_OK) + { + initialized = true; + // used to be v1 for old muse devices + res = config_board ("v4"); + } + if (res == (int)BrainFlowExitCodes::STATUS_OK) + { + // p21 - eeg only + res = config_board ("p21"); + } + else + { + release_session (); + } + + return res; +} + +int MuseAnthena::start_stream (int buffer_size, const char *streamer_params) +{ + if (!initialized) + { + return (int)BrainFlowExitCodes::BOARD_NOT_CREATED_ERROR; + } + + int res = prepare_for_acquisition (buffer_size, streamer_params); + if (res == (int)BrainFlowExitCodes::STATUS_OK) + { + res = config_board ("dc001"); + } + if (res == (int)BrainFlowExitCodes::STATUS_OK) + { + is_streaming = true; + } + + return res; +} + +int MuseAnthena::stop_stream () +{ + if (muse_peripheral == NULL) + { + return (int)BrainFlowExitCodes::BOARD_NOT_CREATED_ERROR; + } + int res = (int)BrainFlowExitCodes::STATUS_OK; + if (is_streaming) + { + res = config_board ("h"); + } + else + { + res = (int)BrainFlowExitCodes::STREAM_ALREADY_RUN_ERROR; + } + is_streaming = false; + return res; +} + +int MuseAnthena::release_session () +{ + if (initialized) + { + // repeat it multiple times, failure here may lead to a crash + for (int i = 0; i < 2; i++) + { + stop_stream (); + // need to wait for notifications to stop triggered before unsubscribing, otherwise + // macos fails inside simpleble with timeout +#ifdef _WIN32 + Sleep (2000); +#else + sleep (2); +#endif + for (auto notified : notified_characteristics) + { + if (simpleble_peripheral_unsubscribe ( + muse_peripheral, notified.first, notified.second) != SIMPLEBLE_SUCCESS) + { + safe_logger (spdlog::level::err, "failed to unsubscribe for {} {}", + notified.first.value, notified.second.value); + } + } + } + free_packages (); + initialized = false; + } + if (muse_peripheral != NULL) + { + bool is_connected = false; + if (simpleble_peripheral_is_connected (muse_peripheral, &is_connected) == SIMPLEBLE_SUCCESS) + { + if (is_connected) + { + simpleble_peripheral_disconnect (muse_peripheral); + } + } + simpleble_peripheral_release_handle (muse_peripheral); + muse_peripheral = NULL; + } + if (muse_adapter != NULL) + { + simpleble_adapter_release_handle (muse_adapter); + muse_adapter = NULL; + } + + return (int)BrainFlowExitCodes::STATUS_OK; +} + +int MuseAnthena::config_board (std::string config, std::string &response) +{ + return config_board (config); +} + +int MuseAnthena::config_board (std::string config) +{ + if (!initialized) + { + return (int)BrainFlowExitCodes::BOARD_NOT_CREATED_ERROR; + } + constexpr int max_size = 16; + uint8_t command[max_size]; + size_t len = config.size (); + if (len + 2 >= max_size) + { + safe_logger (spdlog::level::err, "Invalid command, max size is {}", max_size); + return (int)BrainFlowExitCodes::INVALID_ARGUMENTS_ERROR; + } + command[0] = (uint8_t)len + 1; + for (size_t i = 0; i < len; i++) + { + command[i + 1] = uint8_t (config[i]); + } + command[len + 1] = 10; + safe_logger (spdlog::level::trace, "Command to send: {}", bytes_to_string (command, len + 2)); + if (simpleble_peripheral_write_command (muse_peripheral, control_characteristics.first, + control_characteristics.second, command, len + 2) != SIMPLEBLE_SUCCESS) + { + safe_logger (spdlog::level::err, "failed to send command {} to device", config.c_str ()); + return (int)BrainFlowExitCodes::BOARD_WRITE_ERROR; + } + return (int)BrainFlowExitCodes::STATUS_OK; +} + +void MuseAnthena::adapter_on_scan_found ( + simpleble_adapter_t adapter, simpleble_peripheral_t peripheral) +{ + char *peripheral_identified = simpleble_peripheral_identifier (peripheral); + char *peripheral_address = simpleble_peripheral_address (peripheral); + bool found = false; + if (!params.mac_address.empty ()) + { + if (strcmp (peripheral_address, params.mac_address.c_str ()) == 0) + { + found = true; + } + } + else + { + if (!params.serial_number.empty ()) + { + if (strcmp (peripheral_identified, params.serial_number.c_str ()) == 0) + { + found = true; + } + } + else + { + if (strncmp (peripheral_identified, "MuseS", 4) == 0) + { + found = true; + } + } + } + + safe_logger (spdlog::level::trace, "address {}", peripheral_address); + simpleble_free (peripheral_address); + safe_logger (spdlog::level::trace, "identifier {}", peripheral_identified); + simpleble_free (peripheral_identified); + + if (found) + { + { + std::lock_guard lk (m); + muse_peripheral = peripheral; + } + cv.notify_one (); + } + else + { + simpleble_peripheral_release_handle (peripheral); + } +} + +void MuseAnthena::peripheral_on_eeg (simpleble_peripheral_t peripheral, simpleble_uuid_t service, + simpleble_uuid_t characteristic, const uint8_t *data, size_t size) +{ + safe_logger (spdlog::level::trace, "EEG packet: {}", bytes_to_string (data, size)); + // TODO parse it and fill default preset +} + +void MuseAnthena::peripheral_on_aux (simpleble_peripheral_t peripheral, simpleble_uuid_t service, + simpleble_uuid_t characteristic, const uint8_t *data, size_t size) +{ + safe_logger (spdlog::level::trace, "AUX packet: {}", bytes_to_string (data, size)); + // TODO parse it and fill aux preset +} + + +std::string MuseAnthena::bytes_to_string (const uint8_t *data, size_t size) +{ + std::ostringstream oss; + for (size_t i = 0; i < size; i++) + { + if (i > 0) + oss << " "; + oss << static_cast (data[i]); + } + return oss.str (); +} \ No newline at end of file diff --git a/src/utils/inc/brainflow_constants.h b/src/utils/inc/brainflow_constants.h index 021bbca7e..44d508b41 100644 --- a/src/utils/inc/brainflow_constants.h +++ b/src/utils/inc/brainflow_constants.h @@ -96,9 +96,10 @@ enum class BoardIds : int SYNCHRONI_UNO_1_CHANNELS_BOARD = 62, OB3000_24_CHANNELS_BOARD = 63, BIOLISTENER_BOARD = 64, + MUSE_S_ANTHENA_BOARD = 65, // use it to iterate FIRST = PLAYBACK_FILE_BOARD, - LAST = BIOLISTENER_BOARD + LAST = MUSE_S_ANTHENA_BOARD }; enum class IpProtocolTypes : int