BrainBit for developers Subscribe for updates Visit website

Tutorial

System requirements

OS: macOS Catalina

Software: Xcode 12

IOS minimal version: 12.0

Framework: neurosdk.framework-1.7.6.1

Dependencies: libc++.tbd, CoreBluetooth.framework

Beginning of work

Creating a simple project

Unpack the downloaded zip file with the framework.

Create an empty project “Application”.

 

Create a frameworks folder in the directory with the project file and put the folder in it neurosdk.framework

 

Add framework to the project.

To do this, go to Project settings - General - Frameworks, Libraries, and Embedded Content - click on “+”

 

A window opens in which we click Add Other… - Add Files...

 

Select the path to neurosdk.framework, click Open

 

Thus, we have added neurosdk.framework to the project.

 

Next, add dependencies.

To do this, also go to Project settings - General - Frameworks, Libraries, and Embedded Content - and click on the "+"

In the window that appears, in the search bar, find CoreBluetooth.framework and press the button “Add”

 

We also add libc ++.tbd

 

As a result, in the Frameworks, Libraries, and Embedded Content section, we see the following picture:

 

The required dependencies have been added to the project.

Further, in Info.plist for the correct operation of the SDK, you need to add the NSBluetoothAlwaysUsageDescription key.

Device search example

First of all to find nearby devices you need to create global variable of NTDeviceEnumerator.

 

    
let scanner = NTDeviceEnumerator(deviceType: .TypeBrainbit)
    

 

 

You can specify which type of device you're looking for by deviceType (TypeBrainbit, TypeCallibri,TypeAny). Instance of NTDeviceEnumerator has subscribeFoundDevice event will hit when a new device appears.

Note:    Make sure your instance lifetime is enough to find a new device. For example your enumerator variable is a private field of the class.

Warn:   Searching for device only when object NTDeviceEnumerator exists in memory.

 

    
scanner.subscribeFoundDevice { (deviceInfo) in
    self.device = NTDevice(enumerator: self.scanner, deviceInfo: deviceInfo)
}
    

 

 

Here we insert closure and if new device will be detected you received NTDeviceInfo.

Note: Remember to create new NTDevice you new NTDeviceInfo and NTDeviceEnumerator.

Warn: All subscribers are run in separate thread. Be careful when call ui-based code.

Connecting the device

To receive data from the device and to send commands to it first you need to connect to it.

 

    
device?.connect()
    

 

 

You could read the device state to check whether it is connected or not. You also could subscribe subscribeParameterChanged event to receive notifications when the device goes out of range.

 

    
device?.subscribeParameterChanged(subscriber: { (param) in
    if(param == .state) {
        let state = device.state()
        if( state == .connected) {
              print("Connected")
        } else {
              print("Disconnected")
         }
      }
})
    

 

 

Working with channels

Create channels

Take EEG channels as an example.

 

    
var eegChannels: [String: NTEegChannel?] = [:]
    

 

 

Create channels with their names (T3, T4, O1, O2). To do this, call getChannelInfoArray from NTDeviceTraits to get the channelInfo array, and element-by-element initialize NTEegChannel with device parameters and each channelInfo

 

    
do {
            try NTDeviceTraits.hasChannels(withType: device, channelType: .signal)
            NTDeviceTraits.getChannelInfoArray(withType: device, channelType: .signal, error: nil).forEach {
                eegChannels[$0.name] = NTEegChannel(device: device, channelInfo: $0)
            }
            print("initEegChannels succeeded")
            
        }
        catch let err as NSError{
            print("initEegChannels failed")
        }
    

 

 

Retrieving data

First of all, for EEG channels, you need to execute the startSignal command.

 

    
self.device?.execute(command: .startSignal)
    

 

 

Then you need to subscribe to each of the four channels (subscribeLengthChanged) and then read the data (readData)

 

    
self.eegChannels.forEach { (channelName, channel) in
            channel?.subscribeLengthChanged(subscribe: { (length) in
                   let newdata = channel?.readData(offset: length-1, length: 1).first
                })
        }
    

The newdata variables in this example are the desired channel values.

 

Finishing work with channels

 

At the end of working with channels, you need to unsubscribe from them (by passing nil to subscribeLengthChanged).

    
self.eegChannels.forEach{ (_, channel) in
            channel?.subscribeLengthChanged(subscribe: nil)
        }
    

And send the stopSignal command to the device.

    
self.device?.execute(command: .stopSignal)