Skip to content

Commit

Permalink
add support for emotibit (#579)
Browse files Browse the repository at this point in the history
* add support for emotibit

Signed-off-by: Andrey Parfenov <a1994ndrey@gmail.com>
  • Loading branch information
Andrey1994 committed Dec 1, 2022
1 parent c23e07b commit cfd95e7
Show file tree
Hide file tree
Showing 34 changed files with 1,721 additions and 16 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/run_android.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
os: [ubuntu-latest]

env:
ANDROID_NDK_VERSION: 21.4.7075529
ANDROID_NDK_VERSION: 25.1.8937393

steps:
- name: Clone Repository
Expand Down Expand Up @@ -45,7 +45,7 @@ jobs:
for ABI in arm64-v8a armeabi-v7a x86 x86_64; do
mkdir $GITHUB_WORKSPACE/libftdi/build-$ABI
cd $GITHUB_WORKSPACE/libftdi/build-$ABI
cmake -G Ninja -DCMAKE_TOOLCHAIN_FILE=${ANDROID_HOME}/ndk/${ANDROID_NDK_VERSION}/build/cmake/android.toolchain.cmake -DANDROID_ABI=$ABI -DCMAKE_BUILD_TYPE=Release -DANDROID_NATIVE_API_LEVEL=android-19 -DEXAMPLES=OFF -DFTDI_EEPROM=OFF -DLIBUSB_LIBRARIES=$GITHUB_WORKSPACE/libusb/android/libs/$ABI/libusb1.0.so -DLIBUSB_INCLUDE_DIR=$GITHUB_WORKSPACE/libusb/libusb -DCMAKE_INSTALL_PREFIX=$GITHUB_WORKSPACE/install-$ABI ..
cmake -G Ninja -DCMAKE_TOOLCHAIN_FILE=${ANDROID_HOME}/ndk/${ANDROID_NDK_VERSION}/build/cmake/android.toolchain.cmake -DANDROID_ABI=$ABI -DCMAKE_BUILD_TYPE=Release -DANDROID_NATIVE_API_LEVEL=android-24 -DEXAMPLES=OFF -DFTDI_EEPROM=OFF -DLIBUSB_LIBRARIES=$GITHUB_WORKSPACE/libusb/android/libs/$ABI/libusb1.0.so -DLIBUSB_INCLUDE_DIR=$GITHUB_WORKSPACE/libusb/libusb -DCMAKE_INSTALL_PREFIX=$GITHUB_WORKSPACE/install-$ABI ..
ninja
ninja install
done
Expand All @@ -54,7 +54,7 @@ jobs:
for ABI in arm64-v8a armeabi-v7a x86 x86_64; do
mkdir $GITHUB_WORKSPACE/build-$ABI
cd $GITHUB_WORKSPACE/build-$ABI
cmake -G Ninja -DCMAKE_TOOLCHAIN_FILE=${ANDROID_HOME}/ndk/${ANDROID_NDK_VERSION}/build/cmake/android.toolchain.cmake -DANDROID_ABI=$ABI -DCMAKE_BUILD_TYPE=Release -DANDROID_NATIVE_API_LEVEL=android-19 -DCMAKE_FIND_ROOT_PATH=$GITHUB_WORKSPACE/install-$ABI -DUSE_LIBFTDI=ON ..
cmake -G Ninja -DCMAKE_TOOLCHAIN_FILE=${ANDROID_HOME}/ndk/${ANDROID_NDK_VERSION}/build/cmake/android.toolchain.cmake -DANDROID_ABI=$ABI -DCMAKE_BUILD_TYPE=Release -DANDROID_NATIVE_API_LEVEL=android-24 -DCMAKE_FIND_ROOT_PATH=$GITHUB_WORKSPACE/install-$ABI -DUSE_LIBFTDI=ON ..
ninja
done
- name: Prepare Zip
Expand Down
12 changes: 12 additions & 0 deletions cpp_package/src/board_shim.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -557,6 +557,18 @@ std::vector<int> BoardShim::get_resistance_channels (int board_id, int preset)
return std::vector<int> (channels, channels + len);
}

std::vector<int> BoardShim::get_magnetometer_channels (int board_id, int preset)
{
int channels[MAX_CHANNELS];
int len = 0;
int res = ::get_magnetometer_channels (board_id, preset, channels, &len);
if (res != (int)BrainFlowExitCodes::STATUS_OK)
{
throw BrainFlowException ("failed to get board info", res);
}
return std::vector<int> (channels, channels + len);
}

std::string BoardShim::get_version ()
{
char version[64];
Expand Down
7 changes: 7 additions & 0 deletions cpp_package/src/inc/board_shim.h
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,13 @@ class BoardShim
*/
static std::vector<int> get_resistance_channels (
int board_id, int preset = (int)BrainFlowPresets::DEFAULT_PRESET);
/**
* get row indices which hold magnetometer data
* @param board_id board id of your device
* @throw BrainFlowException If this board has no such data exit code is UNSUPPORTED_BOARD_ERROR
*/
static std::vector<int> get_magnetometer_channels (
int board_id, int preset = (int)BrainFlowPresets::DEFAULT_PRESET);
/// release all currently prepared session
static void release_all_sessions ();
/// get brainflow version
Expand Down
28 changes: 27 additions & 1 deletion csharp_package/brainflow/brainflow/board_controller_library.cs
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,8 @@ public enum BoardIds
PIEEG_BOARD = 43,
EXPLORE_4_CHAN_BOARD = 44,
EXPLORE_8_CHAN_BOARD = 45,
GANGLION_NATIVE_BOARD = 46
GANGLION_NATIVE_BOARD = 46,
EMOTIBIT_BOARD = 47
};


Expand Down Expand Up @@ -180,6 +181,8 @@ public static class BoardControllerLibrary64
[DllImport ("BoardController.dll", SetLastError = true, CallingConvention = CallingConvention.Cdecl)]
public static extern int get_resistance_channels (int board_id, int preset, int[] channels, int[] len);
[DllImport ("BoardController.dll", SetLastError = true, CallingConvention = CallingConvention.Cdecl)]
public static extern int get_magnetometer_channels (int board_id, int preset, int[] channels, int[] len);
[DllImport ("BoardController.dll", SetLastError = true, CallingConvention = CallingConvention.Cdecl)]
public static extern int get_exg_channels (int board_id, int preset, int[] channels, int[] len);
[DllImport ("BoardController.dll", SetLastError = true, CallingConvention = CallingConvention.Cdecl)]
public static extern int get_device_name (int board_id, int preset, byte[] name, int[] len);
Expand Down Expand Up @@ -281,6 +284,8 @@ public static class BoardControllerLibrary32
public static extern int add_streamer (string streamer, int preset, int board_id, string input_json);
[DllImport ("BoardController32.dll", SetLastError = true, CallingConvention = CallingConvention.Cdecl)]
public static extern int delete_streamer (string streamer, int preset, int board_id, string input_json);
[DllImport ("BoardController32.dll", SetLastError = true, CallingConvention = CallingConvention.Cdecl)]
public static extern int get_magnetometer_channels (int board_id, int preset, int[] channels, int[] len);
}

public static class BoardControllerLibraryLinux
Expand Down Expand Up @@ -365,6 +370,8 @@ public static class BoardControllerLibraryLinux
public static extern int add_streamer (string streamer, int preset, int board_id, string input_json);
[DllImport ("libBoardController.so", SetLastError = true, CallingConvention = CallingConvention.Cdecl)]
public static extern int delete_streamer (string streamer, int preset, int board_id, string input_json);
[DllImport ("libBoardController.so", SetLastError = true, CallingConvention = CallingConvention.Cdecl)]
public static extern int get_magnetometer_channels (int board_id, int preset, int[] channels, int[] len);
}

public static class BoardControllerLibraryMac
Expand Down Expand Up @@ -449,6 +456,8 @@ public static class BoardControllerLibraryMac
public static extern int add_streamer (string streamer, int preset, int board_id, string input_json);
[DllImport ("libBoardController.dylib", SetLastError = true, CallingConvention = CallingConvention.Cdecl)]
public static extern int delete_streamer (string streamer, int preset, int board_id, string input_json);
[DllImport ("libBoardController.dylib", SetLastError = true, CallingConvention = CallingConvention.Cdecl)]
public static extern int get_magnetometer_channels (int board_id, int preset, int[] channels, int[] len);
}

public static class BoardControllerLibrary
Expand Down Expand Up @@ -1117,6 +1126,23 @@ public static int get_resistance_channels (int board_id, int preset, int[] chann
return (int)BrainFlowExitCodes.GENERAL_ERROR;
}

public static int get_magnetometer_channels (int board_id, int preset, int[] channels, int[] len)
{
switch (PlatformHelper.get_library_environment ())
{
case LibraryEnvironment.x64:
return BoardControllerLibrary64.get_magnetometer_channels (board_id, preset, channels, len);
case LibraryEnvironment.x86:
return BoardControllerLibrary32.get_magnetometer_channels (board_id, preset, channels, len);
case LibraryEnvironment.Linux:
return BoardControllerLibraryLinux.get_magnetometer_channels (board_id, preset, channels, len);
case LibraryEnvironment.MacOS:
return BoardControllerLibraryMac.get_magnetometer_channels (board_id, preset, channels, len);
}

return (int)BrainFlowExitCodes.GENERAL_ERROR;
}

public static int release_all_sessions ()
{
switch (PlatformHelper.get_library_environment ())
Expand Down
24 changes: 24 additions & 0 deletions csharp_package/brainflow/brainflow/board_shim.cs
Original file line number Diff line number Diff line change
Expand Up @@ -580,6 +580,30 @@ public static int[] get_resistance_channels (int board_id, int preset = (int)Bra
return result;
}

/// <summary>
/// get magnetometer channels for this board
/// </summary>
/// <param name="board_id"></param>
/// <param name="preset">preset for device</param>
/// <returns>array of row nums</returns>
/// <exception cref="BrainFlowException">If this board has no such data exit code is UNSUPPORTED_BOARD_ERROR</exception>
public static int[] get_magnetometer_channels (int board_id, int preset = (int)BrainFlowPresets.DEFAULT_PRESET)
{
int[] len = new int[1];
int[] channels = new int[512];
int res = BoardControllerLibrary.get_magnetometer_channels (board_id, preset, channels, len);
if (res != (int)BrainFlowExitCodes.STATUS_OK)
{
throw new BrainFlowError (res);
}
int[] result = new int[len[0]];
for (int i = 0; i < len[0]; i++)
{
result[i] = channels[i];
}
return result;
}

/// <summary>
/// set log level, logger is disabled by default
/// </summary>
Expand Down
13 changes: 9 additions & 4 deletions docs/BuildBrainFlow.rst
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,11 @@ Now you can use BrainFlow SDK in your Android application!

Note: Android Studio inline compiler may show red errors but it should be compiled fine with Gradle. To fix inline compiler you can use *File > Sync Project with Gradle Files* or click at *File > Invalidate Cache/Restart > Invalidate and Restart*

Prebuild libraries for *jniLibs.zip* are complied using:

- Android NDK 25.1.8937393
- *-DANDROID_NATIVE_API_LEVEL=android-24*

.. compound::

For some API calls you need to provide additional permissions via manifest file of your application ::
Expand Down Expand Up @@ -268,13 +273,13 @@ Compilation instructions:

# to prepare project(choose ABIs which you need)
# for arm64-v8a
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=arm64-v8a ..
cmake -G Ninja -DCMAKE_TOOLCHAIN_FILE=D:\workspace\android-ndk-r25b\build\cmake\android.toolchain.cmake -DANDROID_NATIVE_API_LEVEL=android-24 -DANDROID_ABI=arm64-v8a ..
# for armeabi-v7a
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=armeabi-v7a ..
cmake -G Ninja -DCMAKE_TOOLCHAIN_FILE=D:\workspace\android-ndk-r25b\build\cmake\android.toolchain.cmake -DANDROID_NATIVE_API_LEVEL=android-24 -DANDROID_ABI=armeabi-v7a ..
# for x86_64
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_64 ..
cmake -G Ninja -DCMAKE_TOOLCHAIN_FILE=D:\workspace\android-ndk-r25b\build\cmake\android.toolchain.cmake -DANDROID_NATIVE_API_LEVEL=android-24 -DANDROID_ABI=x86_64 ..
# 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 ..
cmake -G Ninja -DCMAKE_TOOLCHAIN_FILE=D:\workspace\android-ndk-r25b\build\cmake\android.toolchain.cmake -DANDROID_NATIVE_API_LEVEL=android-24 -DANDROID_ABI=x86 ..

# to build(should be run for each ABI from previous step**
cmake --build . --target install --config Release -j 2 --parallel 2
37 changes: 37 additions & 0 deletions docs/SupportedBoards.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1203,3 +1203,40 @@ 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

EmotiBit
---------

EmotiBit board
~~~~~~~~~~~~~~~

.. image:: https://live.staticflickr.com/65535/52519313192_7869efa2f5.jpg
:width: 500px
:height: 281px

`EmotiBit Website <https://www.emotibit.com/>`_

To create such board you need to specify the following board ID and fields of BrainFlowInputParams object:

- :code:`BoardIds.EMOTIBIT_BOARD`
- *optional:* :code:`ip_address`, you can provide *broadcast* ip address of the network with EmotiBit device, e.g. 192.168.178.255. If not provided BrainFlow will try to autodiscover the network and it may take a little longer.

Initialization Example:

.. code-block:: python
params = BrainFlowInputParams()
board = BoardShim(BoardIds.EMOTIBIT_BOARD, params)
Supported platforms:

- Windows
- MacOS
- Linux
- Devices like Raspberry Pi

Available :ref:`presets-label`:

- :code:`BrainFlowPresets.DEFAULT_PRESET`, it contains accelerometer, gyroscope and magnetometer data
- :code:`BrainFlowPresets.AUXILIARY_PRESET`, it contains PPG data
- :code:`BrainFlowPresets.ANCILLARY_PRESET`, it contains EDA and temperature data
3 changes: 2 additions & 1 deletion java_package/brainflow/src/main/java/brainflow/BoardIds.java
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ public enum BoardIds
PIEEG_BOARD (43),
EXPLORE_4_CHAN_BOARD (44),
EXPLORE_8_CHAN_BOARD (45),
GANGLION_NATIVE_BOARD (46);
GANGLION_NATIVE_BOARD (46),
EMOTIBIT_BOARD (47);

private final int board_id;
private static final Map<Integer, BoardIds> bi_map = new HashMap<Integer, BoardIds> ();
Expand Down
46 changes: 46 additions & 0 deletions java_package/brainflow/src/main/java/brainflow/BoardShim.java
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ int get_current_board_data (int num_samples, int preset, double[] data_buf, int[

int get_resistance_channels (int board_id, int preset, int[] channels, int[] len);

int get_magnetometer_channels (int board_id, int preset, int[] channels, int[] len);

int get_temperature_channels (int board_id, int preset, int[] temperature_channels, int[] len);

int release_all_sessions ();
Expand Down Expand Up @@ -852,6 +854,50 @@ public static int[] get_temperature_channels (BoardIds board_id) throws BrainFlo
return get_temperature_channels (board_id.get_code ());
}

/**
* get row indices in returned by get_board_data() 2d array which contain
* magnetometer data
*/
public static int[] get_magnetometer_channels (int board_id, BrainFlowPresets preset) throws BrainFlowError
{
int[] len = new int[1];
int[] channels = new int[512];
int ec = instance.get_magnetometer_channels (board_id, preset.get_code (), channels, len);
if (ec != BrainFlowExitCode.STATUS_OK.get_code ())
{
throw new BrainFlowError ("Error in board info getter", ec);
}

return Arrays.copyOfRange (channels, 0, len[0]);
}

/**
* get row indices in returned by get_board_data() 2d array which contain
* magnetometer data
*/
public static int[] get_magnetometer_channels (int board_id) throws BrainFlowError
{
return get_magnetometer_channels (board_id, BrainFlowPresets.DEFAULT_PRESET);
}

/**
* get row indices in returned by get_board_data() 2d array which contain
* magnetometer data
*/
public static int[] get_magnetometer_channels (BoardIds board_id, BrainFlowPresets preset) throws BrainFlowError
{
return get_magnetometer_channels (board_id.get_code (), preset);
}

/**
* get row indices in returned by get_board_data() 2d array which contain
* magnetometer data
*/
public static int[] get_magnetometer_channels (BoardIds board_id) throws BrainFlowError
{
return get_magnetometer_channels (board_id.get_code ());
}

/**
* get row indices in returned by get_board_data() 2d array which contain
* resistance data
Expand Down
2 changes: 2 additions & 0 deletions julia_package/brainflow/src/board_shim.jl
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ export BrainFlowInputParams
EXPLORE_4_CHAN_BOARD = 44
EXPLORE_8_CHAN_BOARD = 45
GANGLION_NATIVE_BOARD = 46
EMOTIBIT_BOARD = 47

end

Expand Down Expand Up @@ -189,6 +190,7 @@ channel_function_names = (
:get_other_channels,
:get_temperature_channels,
:get_resistance_channels,
:get_magnetometer_channels,
)

# generating the channels functions
Expand Down
1 change: 1 addition & 0 deletions matlab_package/brainflow/BoardIds.m
Original file line number Diff line number Diff line change
Expand Up @@ -51,5 +51,6 @@
EXPLORE_4_CHAN_BOARD(44)
EXPLORE_8_CHAN_BOARD(45)
GANGLION_NATIVE_BOARD(46)
EMOTIBIT_BOARD(47)
end
end
11 changes: 11 additions & 0 deletions matlab_package/brainflow/BoardShim.m
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,17 @@ function log_message(log_level, message)
resistance_channels = data.Value(1,1:num_channels.Value) + 1;
end

function magnetometer_channels = get_magnetometer_channels(board_id, preset)
% get magnetometer channels for provided board id
task_name = 'get_magnetometer_channels';
lib_name = BoardShim.load_lib();
num_channels = libpointer('int32Ptr', 0);
data = libpointer('int32Ptr', zeros(1, 512));
exit_code = calllib(lib_name, task_name, board_id, preset, data, num_channels);
BoardShim.check_ec(exit_code, task_name);
magnetometer_channels = data.Value(1,1:num_channels.Value) + 1;
end

end

methods
Expand Down
32 changes: 32 additions & 0 deletions python_package/brainflow/board_shim.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ class BoardIds(enum.IntEnum):
EXPLORE_4_CHAN_BOARD = 44 #:
EXPLORE_8_CHAN_BOARD = 45 #:
GANGLION_NATIVE_BOARD = 46 #:
EMOTIBIT_BOARD = 47 #:


class IpProtocolTypes(enum.IntEnum):
Expand Down Expand Up @@ -516,6 +517,15 @@ def __init__(self):
ndpointer(ctypes.c_int32)
]

self.get_magnetometer_channels = self.lib.get_magnetometer_channels
self.get_magnetometer_channels.restype = ctypes.c_int
self.get_magnetometer_channels.argtypes = [
ctypes.c_int,
ctypes.c_int,
ndpointer(ctypes.c_int32),
ndpointer(ctypes.c_int32)
]


class BoardShim(object):
"""BoardShim class is a primary interface to all boards
Expand Down Expand Up @@ -1096,6 +1106,28 @@ def get_resistance_channels(cls, board_id: int, preset: int = BrainFlowPresets.D
result = resistance_channels.tolist()[0:num_channels[0]]
return result

@classmethod
def get_magnetometer_channels(cls, board_id: int, preset: int = BrainFlowPresets.DEFAULT_PRESET) -> List[int]:
"""get list of magnetometer channels in resulting data table for a board
:param board_id: Board Id
:type board_id: int
:param preset: preset
:type preset: int
:return: list of magnetometer channels in returned numpy array
:rtype: List[int]
:raises BrainFlowError: If this board has no such data exit code is UNSUPPORTED_BOARD_ERROR
"""

num_channels = numpy.zeros(1).astype(numpy.int32)
magnetometer_channels = numpy.zeros(512).astype(numpy.int32)

res = BoardControllerDLL.get_instance().get_magnetometer_channels(board_id, preset, magnetometer_channels, num_channels)
if res != BrainFlowExitCodes.STATUS_OK.value:
raise BrainFlowError('unable to request info about this board', res)
result = magnetometer_channels.tolist()[0:num_channels[0]]
return result

@classmethod
def release_all_sessions(cls) -> None:
"""release all prepared sessions"""
Expand Down

0 comments on commit cfd95e7

Please sign in to comment.