BrainAccess Core C API Usage Example

// This is the main file for a Bluetooth EEG system application, connection
// example. It includes necessary headers, defines sleep functions, and
// initializes variables.

#include "bacore.h"
#include "eeg_manager.h"
#include <stdio.h>
#include <string.h>

#ifdef _WIN32
#include <windows.h> // Windows-specific sleep function
#define sleep_ms(x) Sleep(x)
#else
#include <unistd.h>                    // POSIX (Linux/Unix) sleep function
#define sleep_ms(x) usleep((x) * 1000) // usleep takes microseconds
#endif

#define DEVICE_NAME    "BA MINI 000"
#define CHANNELS_COUNT 8
ba_eeg_manager* manager1;
ba_error compatibility;

void ota_update_callback(void* data, const size_t size, const size_t sent)
{
        printf("update: %zu / %zu\n", size, sent);
}

static void chunk_callback(const void* const* data, size_t size, void* user_data)
{
        // Get the data for the sample number and channels
        const size_t* eeg_data_sample_number = (const size_t*)data[ba_eeg_manager_get_channel_index(manager1, BA_EEG_CHANNEL_ID_SAMPLE_NUMBER)];
        const double* eeg_data_channel_0 = (const double*)data[ba_eeg_manager_get_channel_index(manager1, BA_EEG_CHANNEL_ID_ELECTRODE_MEASUREMENT + 0)];
        const double* eeg_data_channel_1 = (const double*)data[ba_eeg_manager_get_channel_index(manager1, BA_EEG_CHANNEL_ID_ELECTRODE_MEASUREMENT + 1)];
        const double* eeg_data_channel_2 = (const double*)data[ba_eeg_manager_get_channel_index(manager1, BA_EEG_CHANNEL_ID_ELECTRODE_MEASUREMENT + 2)];
        const double* eeg_data_channel_3 = (const double*)data[ba_eeg_manager_get_channel_index(manager1, BA_EEG_CHANNEL_ID_ELECTRODE_MEASUREMENT + 3)];
        const double* eeg_data_channel_4 = (const double*)data[ba_eeg_manager_get_channel_index(manager1, BA_EEG_CHANNEL_ID_ELECTRODE_MEASUREMENT + 4)];
        const double* eeg_data_channel_5 = (const double*)data[ba_eeg_manager_get_channel_index(manager1, BA_EEG_CHANNEL_ID_ELECTRODE_MEASUREMENT + 5)];
        const double* eeg_data_channel_6 = (const double*)data[ba_eeg_manager_get_channel_index(manager1, BA_EEG_CHANNEL_ID_ELECTRODE_MEASUREMENT + 6)];
        const uint8_t* is_streaming = (const uint8_t*)data[ba_eeg_manager_get_channel_index(manager1, BA_EEG_CHANNEL_ID_STREAMING)];

        for (size_t i = 0; i < size; ++i)
        {
                // Process the data directly without storing it in a structure
//              printf("[%zu] %f - %f - %f - %f || %d\n", eeg_data_sample_number[i], eeg_data_channel_0[i], eeg_data_channel_1[i], eeg_data_channel_2[i], eeg_data_channel_3[i], is_streaming[i]);
        }
//      printf("\n");
}

// Callback function for handling disconnection events.
// This function is called when the connection to the device is lost.
// It prints a message indicating the disconnection event.
void disconnect_callback(void* data)
{
        printf("Disconnectedd\n");
}

// Function to scan for available Bluetooth EEG devices and initialize the
// system.
ba_init_error scan_devices()
{
        // Initialize the status variable to hold the result of the initialization
        ba_init_error status = BA_INIT_ERROR_OK;
        const ba_version* curr_version = ba_core_get_version();
        printf("Core current version : %d.%d.%d\n", curr_version->major, curr_version->minor, curr_version->patch);

        // Initialize the Bluetooth EEG system using the defined version
        status |= ba_core_init();

        // Check if the initialization was successful
        if (status != BA_INIT_ERROR_OK)
        {
                // Print an error message if the initialization failed
                printf("Core init Error: %d\n", status);
                return status;
        }

        // Scan for available Bluetooth EEG devices
        status |= ba_core_scan(0);

        // Check if no devices were found after the first scan
        if (ba_core_device_count() == 0)
        {
                // Keep scanning for devices until at least one is found
                for (int i = 0; i < 5; i++)
                {
                        // Print the number of scan attempts
                        printf("Found devices count: %d\n", ba_core_device_count());

                        // Scan for available devices again
                        status |= ba_core_scan(0);
                        if (ba_core_device_count() != 0)
                        {
                                break;
                        }
                }
        }

        // Print a message indicating the end of the scanning process
        printf("Search: \n");

        // Check if no devices were found after scanning
        if (ba_core_device_count() == 0)
        {
                // Print a message indicating that no devices were found
                printf("0 Devices were found\n");

                // Close the Bluetooth EEG system
                ba_core_close();

                // Return an error code indicating that no devices were found
                status |= BA_INIT_ERROR_NOT_FOUND;
        }
        return status;
}

// Function to connect to the Bluetooth EEG device and perform EEG operations
ba_init_error connect_ble(ba_eeg_manager** const manager, const char* device_name)
{
        ba_init_error status = BA_INIT_ERROR_OK;

        // Print the number of available devices
        printf("devices found: %d\n", ba_core_device_count());

        // Get the name of the first device
        char name[20];

        // Find the device with the name "BA MINI 002"
        int device = -1;
        for (int i = 0; i < ba_core_device_count(); ++i)
        {
                ba_core_device_get_name(name, i);
                if (strcmp(name, device_name) == 0)
                {
                        device = i;
                        printf("Device found!!!!!!!\n");
                }
        }

        // If the device is not found, return -1
        if (device < 0)
        {
                return -1;
        }

        // Define the callback function for handling disconnection events
        ba_callback_disconnect disconnect_cb = disconnect_callback;
        // Set the callback function for handling disconnection events
        ba_eeg_manager_set_callback_disconnect(*manager, disconnect_cb, NULL);
        // Connect to the selected device

        compatibility = ba_eeg_manager_connect(*manager, device, NULL, NULL);
        printf("Connected\n");
        printf("device info: %zu\n", ba_eeg_manager_get_device_info(manager)->serial_number);
        if (compatibility == BA_ERROR_CONNECTION)
        {
                return status;
        }
        const ba_battery_info info = ba_eeg_manager_get_battery_info(*manager);
        printf("battery level: %d | is charger connected: %d | is charging: %d \n", info.level, info.is_charger_connected, info.is_charging);

        // Return the status of the initialization
        return status;
}

void start_stream_ble(ba_eeg_manager** const manager, const int channels)
{
        //               Enable and set the gain for all electrode channels
        for (int i = 0; i < channels; ++i)
        {
                ba_eeg_manager_set_channel_enabled(*manager, BA_EEG_CHANNEL_ID_ELECTRODE_CONTACT + i, true);
                ba_eeg_manager_set_channel_enabled(*manager, BA_EEG_CHANNEL_ID_ELECTRODE_MEASUREMENT + i, true);
                ba_eeg_manager_set_channel_gain(*manager, BA_EEG_CHANNEL_ID_ELECTRODE_MEASUREMENT + i, BA_GAIN_MODE_X8);
        }

        ba_eeg_manager_set_channel_enabled(*manager, BA_EEG_CHANNEL_ID_SAMPLE_NUMBER, true);
        ba_eeg_manager_set_channel_enabled(*manager, BA_EEG_CHANNEL_ID_STREAMING, true);
        // Set the impedance measurement mode to off

        //       Load the configuration
        //      ba_eeg_manager_load_config(*manager, NULL, NULL);

        // Define the callback function for handling EEG data chunks
        ba_callback_chunk my_callback = chunk_callback;

        // Set the callback function for handling EEG data chunks
        ba_eeg_manager_set_callback_chunk(*manager, my_callback, *manager);

        // Start the EEG data streaming
        //      if (compatibility == BA_ERROR_OK)
        //      {
        ba_eeg_manager_start_stream(*manager, NULL, NULL);
        //      }
        printf("stream_start\n");
}

// Function to stop the Bluetooth EEG system and disconnect from the device
void disconnect_ble(ba_eeg_manager** const manager)
{
        // Free the EEG manager instance
        ba_eeg_manager_free(*manager);
}

// Main function to run the Bluetooth EEG system application
int main()
{
        scan_devices();
        printf("scanned....\n");
        sleep_ms(5000);
        //      sleep(5);
        manager1 = ba_eeg_manager_new();

        uint8_t status = connect_ble(&manager1, DEVICE_NAME);

        printf("is_conn: %d", ba_eeg_manager_is_connected(manager1));
        //              if (status != BA_ERROR_OK || compatibility == BA_ERROR_CONNECTION)
        //              {
        //                      //              sleep_ms(10000);
        //
        //                      printf("Error connecting to device: %d(%d)\n", status,
        //      compatibility);                 return status;
        //              }
        //      uint8_t ret =
        //              ba_eeg_manager_start_update(manager1, ota_update_callback, NULL);
        //      // Get the battery information
        //
        //      printf("Update returned: %d", ret);

        start_stream_ble(&manager1, CHANNELS_COUNT);
        // Stop the EEG data streaming
        for (int j = 0; j < 30; ++j)
        {
                uint8_t ret = ba_eeg_manager_annotate(manager1, "j");
                printf("%d - returned: %d\n", j, ret);
                sleep(1);
        }
        printf("annotations finished\n");
        size_t annotation_size;
        ba_annotation* annot;
        int prev = 0;
        ba_eeg_manager_get_annotations(manager1, &annot, &annotation_size);
        printf("annotations: %zu\n", annotation_size);
        for (size_t i = 0; i < annotation_size; i++)
        {
                printf("Annotation: %s   (%zu)  (%d)\n", annot[i].annotation, annot[i].timestamp, annot[i].timestamp - prev);
                prev = annot[i].timestamp;
        }
        ba_eeg_manager_stop_stream(manager1, NULL, NULL);
        printf("stream_stop\n");
        ba_eeg_manager_disconnect(&manager1);

        sleep_ms(4000);

        disconnect_ble(&manager1);
        sleep_ms(3000);

        // Close the Bluetooth EEG system
        ba_core_close();
        return 0;
}