OS: Windows 10 1803
Bluetooth v4.2
Software: any c/c++ IDE, c11 compiler
CMake: v3.14 and higher
You can get the SDK here. This is an archive that includes the following folders:
To work you need "include" and "windows".
The example will use CMake and VS 2019.
Open VS2019. Select "Continue without code". Next go to:
And open the created directory.
Next, you need to configure the project. To do this, open the CMakeLists.txt file and add the following lines:
cmake_minimum_required(VERSION 3.14)
Means the minimum required version CMake - 3.14
project(BrainBitDemo LANGUAGES C)
Project name - BrainBitDemo, which uses C language
add_executable(BrainBitDemo main.c)
An .exe file will be created from the main.c source code
Adding the SDK to the assembly:
target_include_directories(BrainBitDemo PRIVATE include)
The project includes the header files from the include folder. The PRIVATE annotation means they won't be copied to the output folder.
find_library(SDK_LIB NAMES neurosdk-x64d PATHS windows)
Search for the neurosdk-x64d.lib library in the windows folder and save the found path to SDK_LIB. Required for linking .exe and .dll files.
target_link_libraries(BrainBitDemo PRIVATE ${SDK_LIB})
Adding the found library to the project.
find_file(SDK_DLL NAMES neurosdk-x64d.dll PATHS windows)
Search for neurosdk-x64d.dll in the windows folder and save the found path in SDK_LIB.
add_custom_command(TARGET BrainBitDemo POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy ${SDK_DLL} $<TARGET_FILE_DIR:BrainBitDemo>)
Adds neurosdk-x64d.dll to the output directory after build.
Add an empty function to main.c main().
Create project cache:
You can build a project :-)
To start working with the device, you need to search for and connect the device.
The DeviceEnumerator class searches for devices throughout its existence. To find a device of a particular type, the DeviceType enumeration is used.
DeviceEnumerator* enumerator = create_device_enumerator(DeviceTypeBrainbit);
After completing the search (and connection), be sure to delete the instance DeviceEnumerator.
enumerator_delete(enumerator);
To receive search results, you need to create a listener for this event and a function for processing the results, and then subscribe to the event of changing the list of found devices.
DeviceListListener listListener;
int resultCode = enumerator_set_device_list_changed_callback(enumerator, &on_device_list_changed, &listListener, 0);
It is imperative to unsubscribe from this event as soon as the desired device is found.
enumerator_unsubscribe_device_list_changed(listListener);
You can get a list of found devices using the function:
DeviceInfoArray deviceInfoArray;
int resultCode = enumerator_get_device_list(enumerator, &deviceInfoArray);
free_DeviceInfoArray(deviceInfoArray);
Next, you need to create an instance of the Device class and connect to the device:
Device* device = create_Device(enumerator, deviceInfoArray.info_array[0]);
int resultCode = device_connect(device);
Device signal channel
Channel creation
ChannelInfoArray deviceChannels;
device_available_channels(device, &deviceChannels);
SignalDoubleChannel* T3Signal = NULL;
SignalDoubleChannel* T4Signal = NULL;
SignalDoubleChannel* O1Signal = NULL;
SignalDoubleChannel* O2Signal = NULL;
for (size_t i = 0; i < deviceChannels.info_count; ++i) {
if (deviceChannels.info_array[i].type == ChannelTypeSignal) {
if (strcmp(deviceChannels.info_array[i].name, "T3") == 0) {
T3Signal = create_SignalDoubleChannel_info(device, deviceChannels.info_array[i]);
} else if (strcmp(deviceChannels.info_array[i].name, "T4") == 0) {
T4Signal = create_SignalDoubleChannel_info(device, deviceChannels.info_array[i]);
} else if (strcmp(deviceChannels.info_array[i].name, "O1") == 0) {
O1Signal = create_SignalDoubleChannel_info(device, deviceChannels.info_array[i]);
} else if (strcmp(deviceChannels.info_array[i].name, "O2") == 0) {
O2Signal = create_SignalDoubleChannel_info(device, deviceChannels.info_array[i]);
}
}
}
free_ChannelInfoArray(deviceChannels);
Subscribing to an event of receiving new data in a channel and processing it is similar to a battery channel. The second parameter of the constructor is required in order to establish from which lead to remove the signal (T3, T4, O1, O2). The indicated signaling channels can be obtained from the device class.
Receiving data
void data_signal_channel_callback(AnyChannel* channel, size_t length, void* channelDataOut) {
size_t signalLength = 0;
do
{
AnyChannel_get_total_length(channel, &signalLength);
} while (signalLength < SIGNAL_SAMPLES_COUNT);
double signalBuffer[SIGNAL_SAMPLES_COUNT];
DoubleChannel_read_data(channel, 0, SIGNAL_SAMPLES_COUNT, signalBuffer, SIGNAL_SAMPLES_COUNT, &signalLength);
}
LengthListenerHandle signalListener = NULL;
AnyChannel_add_length_callback((AnyChannel*)signal, data_signal_channel_callback, &signalListener, 0);
For data channels other than the battery channel, it is necessary to execute the command to start receiving data, for example, for the signal channel and its derivatives:
device_execute(device, CommandStartSignal);
If you do not need to receive data from the device, then it is recommended to stop the process of transferring this data (to save battery power of the device and phone), for the signal channel and its derivatives it is:
device_execute(device, CommandStopSignal);