Narnia's Psychedelic Mushrooms
    Wondering what’s next for npm?Check out our public roadmap! »

    @openbci/ganglion

    2.0.0 • Public • Published

    Join the chat at https://gitter.im/OpenBCI/OpenBCI_NodeJS Build Status codecov Dependency Status npm

    OpenBCI Node.js Ganglion SDK

    A Node.js module for OpenBCI.

    We are proud to support all functionality of the Ganglion (4 channel).

    The purpose of this module is to get connected and start streaming as fast as possible.

    Table of Contents:


    1. TL;DR
    2. Prerequisites
    3. Installation
    4. Ganglion
    5. General Overview
    6. SDK Reference Guide
    7. Interfacing With Other Tools
    8. Developing
    9. Testing
    10. Contribute
    11. License
    12. Roadmap

    TL;DR:

    Get connected and start streaming right now

    const Ganglion = require("openbci-ganglion");
    const ganglion = new Ganglion();
    ganglion.once("ganglionFound", peripheral => {
      // Stop searching for BLE devices once a ganglion is found.
      ganglion.searchStop();
      ganglion.on("sample", sample => {
        /** Work with sample */
        console.log(sample.sampleNumber);
        for (let i = 0; i < ganglion.numberOfChannels(); i++) {
          console.log(
            "Channel " +
              (+ 1) +
              "" +
              sample.channelData[i].toFixed(8) +
              " Volts."
          );
        }
      });
      ganglion.once("ready", () => {
        ganglion.streamStart();
      });
      ganglion.connect(peripheral);
    });
    // Start scanning for BLE devices
    ganglion.searchStart();

    Prerequisites:

    Please ensure Python 2.7 is installed for all OS.

    macOS

    Linux

    • Kernel version 3.6 or above
    • libbluetooth-dev
    • libudev-dev

    Running without sudo

    In order to stream data on Linux without root/sudo access, you may need to give the node binary privileges to start and stop BLE advertising.

    sudo setcap cap_net_raw+eip $(eval readlink -f `which node`)

    Note: this command requires setcap to be installed. Install it with the libcap2-bin package.

    sudo apt-get install libcap2-bin

    Windows 8+

    See @don's set up guide on Bluetooth LE with Node.js and Noble on Windows.

    Installation:

    Install from npm:

    npm install @openbci/ganglion
    

    About:

    The Ganglion driver used by OpenBCI's Processing GUI and Electron Hub.

    Check out the automatic tests written for it!

    General Overview:

    Initialization

    Initializing the board:

    const Ganglion = require("openbci-ganglion");
    const ganglion = new Ganglion();

    For initializing with options, such as verbose print outs:

    const Ganglion = require("openbci-ganglion");
    const ourBoard = new Ganglion({
      verbose: true
    });

    For initializing with callback, such as to catch errors on noble startup:

    const Ganglion = require("openbci-ganglion");
    const ourBoard = new Ganglion(error => {
      if (error) {
        console.log("error", error);
      } else {
        console.log("no error");
      }
    });

    For initializing with options and callback, such as verbose and to catch errors on noble startup:

    const Ganglion = require("openbci-ganglion");
    const ourBoard = new Ganglion(
      {
        verbose: true
      },
      error => {
        if (error) {
          console.log("error", error);
        } else {
          console.log("no error");
        }
      }
    );

    'ready' event

    You MUST wait for the 'ready' event to be emitted before streaming/talking with the board. The ready happens asynchronously so installing the 'sample' listener and writing before the ready event might result in... nothing at all.

    const Ganglion = require("openbci-ganglion");
    const ourBoard = new Ganglion();
    ourBoard
      .connect(portName)
      .then(function(boardSerial) {
        ourBoard.on("ready", function() {
          /** Start streaming, reading registers, what ever your heart desires  */
        });
      })
      .catch(function(err) {
        /** Handle connection errors */
      });

    Sample properties:

    • sampleNumber (a Number between 0-255)
    • channelData (channel data indexed at 0 filled with floating point Numbers in Volts)
    • accelData (Array with X, Y, Z accelerometer values when new data available)
    • timeStamp (Number the boardTime plus the NTP calculated offset)

    The power of this module is in using the sample emitter, to be provided with samples to do with as you wish.

    To get a 'sample' event, you need to:

    1. Call .connect(localName | peripheral)
    2. Install the 'ready' event emitter on resolved promise
    3. In callback for 'ready' emitter, call streamStart()
    4. Install the 'sample' event emitter
    const Ganglion = require("openbci-ganglion");
    const ourBoard = new Ganglion();
    ourBoard
      .connect(localName)
      .then(function() {
        ourBoard.on("ready", function() {
          ourBoard.streamStart();
          ourBoard.on("sample", function(sample) {
            /** Work with sample */
          });
        });
      })
      .catch(function(err) {
        /** Handle connection errors */
      });

    Close the connection with .streamStop() and disconnect with .disconnect()

    const Ganglion = require("openbci-ganglion");
    const ourBoard = new Ganglion();
    ourBoard.streamStop().then(ourBoard.disconnect());

    See Reference Guide for a complete list of impedance tests.

    SDK Reference Guide:


    Classes

    Ganglion

    Typedefs

    InitializationObject : Object

    Board optional configurations.

    BLED112AttributeValue : Object
    BLED112AttributeWrite : Object
    BLEDConnection : Object
    BLED112FindInformationFound : Object
    BLED112GapConnectDirect : Object
    BLED112GroupService : Object
    BLED112ParseRawAttributeValue : Object
    BLED112ParseRawHeadTail : Object
    BLED112ParseRawWord : Object
    BLED112Peripheral : Object
    BLED112RspGroupType : Object

    Ganglion

    Kind: global class
    Author: AJ Keller (@pushtheworldllc)

    new Ganglion(options, callback)

    The initialization method to call first, before any other method.

    Param Type Description
    options InitializationObject (optional) - Board optional configurations.
    callback function (optional) - A callback function used to determine if the noble module was able to be started. This can be very useful on Windows when there is no compatible BLE device found.

    ganglion.options : InitializationObject

    Kind: instance property of Ganglion

    ganglion._accelArray

    Private Properties (keep alphabetical)

    Kind: instance property of Ganglion

    ganglion._bled112WriteCharacteristic : BLED112FindInformationFound

    Kind: instance property of Ganglion

    ganglion.buffer

    Public Properties (keep alphabetical)

    Kind: instance property of Ganglion

    ganglion.accelStart() ⇒ Promise

    Used to enable the accelerometer. Will result in accelerometer packets arriving 10 times a second. Note that the accelerometer is enabled by default.

    Kind: instance method of Ganglion

    ganglion.accelStop() ⇒ Promise

    Used to disable the accelerometer. Prevents accelerometer data packets from arriving.

    Kind: instance method of Ganglion

    ganglion.autoReconnect()

    Used to start a scan if power is on. Useful if a connection is dropped.

    Kind: instance method of Ganglion

    ganglion.channelOff(channelNumber) ⇒ Promise.<T>

    Send a command to the board to turn a specified channel off

    Kind: instance method of Ganglion
    Author: AJ Keller (@pushtheworldllc)

    Param
    channelNumber

    ganglion.channelOn(channelNumber) ⇒ Promise.<T> | *

    Send a command to the board to turn a specified channel on

    Kind: instance method of Ganglion
    Author: AJ Keller (@pushtheworldllc)

    Param
    channelNumber

    ganglion.cleanupEmitters()

    Used to clean up emitters

    Kind: instance method of Ganglion

    ganglion.connect(id) ⇒ Promise

    The essential precursor method to be called initially to establish a ble connection to the OpenBCI ganglion board.

    Kind: instance method of Ganglion
    Returns: Promise - If the board was able to connect.
    Author: AJ Keller (@pushtheworldllc)

    Param Type Description
    id String | Object a string local name or peripheral object

    ganglion.destroyNoble()

    Destroys the noble!

    Kind: instance method of Ganglion

    ganglion.destroyBLED112()

    Destroys the noble!

    Kind: instance method of Ganglion

    ganglion.destroyMultiPacketBuffer()

    Destroys the multi packet buffer.

    Kind: instance method of Ganglion

    ganglion.disconnect(stopStreaming) ⇒ Promise

    Closes the connection to the board. Waits for stop streaming command to be sent if currently streaming.

    Kind: instance method of Ganglion
    Returns: Promise - - fulfilled by a successful close, rejected otherwise.
    Author: AJ Keller (@pushtheworldllc)

    Param Type Description
    stopStreaming Boolean (optional) - True if you want to stop streaming before disconnecting.

    ganglion.getLocalName() ⇒ null | String

    Return the local name of the attached Ganglion device.

    Kind: instance method of Ganglion

    ganglion.getMutliPacketBuffer() ⇒ null | Buffer

    Get's the multi packet buffer.

    Kind: instance method of Ganglion
    Returns: null | Buffer - - Can be null if no multi packets received.

    ganglion.impedanceStart() ⇒ global.Promise | Promise

    Call to start testing impedance.

    Kind: instance method of Ganglion

    ganglion.impedanceStop() ⇒ global.Promise | Promise

    Call to stop testing impedance.

    Kind: instance method of Ganglion

    ganglion.initDriver() ⇒ Promise.<any>

    Initialize the drivers

    Kind: instance method of Ganglion

    ganglion.isConnected() ⇒ boolean

    Checks if the driver is connected to a board.

    Kind: instance method of Ganglion
    Returns: boolean - - True if connected.

    ganglion.isNobleReady() ⇒ boolean

    Checks if bluetooth is powered on.

    Kind: instance method of Ganglion
    Returns: boolean - - True if bluetooth is powered on.

    ganglion.isSearching() ⇒ boolean

    Checks if noble is currently scanning.

    Kind: instance method of Ganglion
    Returns: boolean - - True if streaming.

    ganglion.isStreaming() ⇒ boolean

    Checks if the board is currently sending samples.

    Kind: instance method of Ganglion
    Returns: boolean - - True if streaming.

    ganglion.numberOfChannels() ⇒ Number

    This function is used as a convenience method to determine how many channels the current board is using.

    Kind: instance method of Ganglion
    Returns: Number - A number Note: This is dependent on if you configured the board correctly on setup options
    Author: AJ Keller (@pushtheworldllc)

    ganglion.printRegisterSettings() ⇒ Promise.<T> | *

    To print out the register settings to the console

    Kind: instance method of Ganglion
    Author: AJ Keller (@pushtheworldllc)

    ganglion.sampleRate() ⇒ Number

    Get the the current sample rate is.

    Kind: instance method of Ganglion
    Returns: Number - The sample rate Note: This is dependent on if you configured the board correctly on setup options

    ganglion.searchStart(`maxSearchTime`) ⇒ Promise

    List available peripherals so the user can choose a device when not automatically found.

    Kind: instance method of Ganglion
    Returns: Promise - - If scan was started

    Param Type Description
    maxSearchTime Number The amount of time to spend searching. (Default is 20 seconds)

    ganglion.searchStop() ⇒ global.Promise | Promise

    Called to end a search.

    Kind: instance method of Ganglion

    ganglion.softReset() ⇒ Promise

    Sends a soft reset command to the board

    Kind: instance method of Ganglion
    Returns: Promise - - Fulfilled if the command was sent to board.
    Author: AJ Keller (@pushtheworldllc)

    ganglion.streamStart() ⇒ Promise

    Sends a start streaming command to the board.

    Kind: instance method of Ganglion
    Returns: Promise - indicating if the signal was able to be sent. Note: You must have successfully connected to an OpenBCI board using the connect method. Just because the signal was able to be sent to the board, does not mean the board will start streaming.
    Author: AJ Keller (@pushtheworldllc)

    ganglion.streamStop() ⇒ Promise

    Sends a stop streaming command to the board.

    Kind: instance method of Ganglion
    Returns: Promise - indicating if the signal was able to be sent. Note: You must have successfully connected to an OpenBCI board using the connect method. Just because the signal was able to be sent to the board, does not mean the board stopped streaming.
    Author: AJ Keller (@pushtheworldllc)

    ganglion.syntheticEnable() ⇒ Promise

    Puts the board in synthetic data generation mode. Must call streamStart still.

    Kind: instance method of Ganglion
    Returns: Promise - indicating if the signal was able to be sent.
    Author: AJ Keller (@pushtheworldllc)

    ganglion.syntheticDisable() ⇒ Promise

    Takes the board out of synthetic data generation mode. Must call streamStart still.

    Kind: instance method of Ganglion
    Returns: Promise - - fulfilled if the command was sent.
    Author: AJ Keller (@pushtheworldllc)

    ganglion.write(data) ⇒ Promise

    Used to send data to the board.

    Kind: instance method of Ganglion
    Returns: Promise - - fulfilled if command was able to be sent
    Author: AJ Keller (@pushtheworldllc)

    Param Type Description
    data Array | Buffer | Number | String The data to write out

    Example

    Sends a single character command to the board.

    // ourBoard has fulfilled the promise on .connect() and 'ready' has been observed previously
    ourBoard.write("a");

    Sends an array of bytes

    // ourBoard has fulfilled the promise on .connect() and 'ready' has been observed previously
    ourBoard.write(["x", "0", "1", "0", "0", "0", "0", "0", "0", "X"]);

    Call crazy? Go for it...

    ourBoard.write("t");
    ourBoard.write("a");
    ourBoard.write("c");
    ourBoard.write("o");

    ganglion._bled112WriteAndDrain(data) ⇒ Promise

    Should be used to send data to the board

    Kind: instance method of Ganglion
    Returns: Promise - if signal was able to be sent
    Author: AJ Keller (@pushtheworldllc)

    Param Type Description
    data Buffer | Buffer2 The data to write out

    Ganglion~o

    Configuring Options

    Kind: inner property of Ganglion

    kOBCIBLED112ParsingConnectDirect

    Used in parsing incoming serial data

    Kind: global constant

    InitializationObject : Object

    Board optional configurations.

    Kind: global typedef
    Properties

    Name Type Description
    bled112 Boolean Whether to use bled112 as bluetooth driver or default to first available. (Default false)
    debug Boolean Print out a raw dump of bytes sent and received. (Default false)
    driverAutoInit Boolean Used to auto start either noble or the bled112 drivers (Default true)
    nobleAutoStart Boolean Automatically initialize noble. Subscribes to blue tooth state changes and such. (Default true)
    nobleScanOnPowerOn Boolean Start scanning for Ganglion BLE devices as soon as power turns on. (Default true)
    sendCounts Boolean Send integer raw counts instead of scaled floats. (Default false)
    simulate Boolean (IN-OP) Full functionality, just mock data. (Default false)
    simulatorBoardFailure Boolean (IN-OP) Simulates board communications failure. This occurs when the RFduino on the board is not polling the RFduino on the dongle. (Default false)
    simulatorHasAccelerometer Boolean Sets simulator to send packets with accelerometer data. (Default true)
    simulatorInjectAlpha Boolean Inject a 10Hz alpha wave in Channels 1 and 2 (Default true)
    simulatorInjectLineNoise String Injects line noise on channels. 3 Possible Options: 60Hz - 60Hz line noise (Default) [America] 50Hz - 50Hz line noise [Europe] none - Do not inject line noise.
    simulatorSampleRate Number The sample rate to use for the simulator. Simulator will set to 125 if simulatorDaisyModuleAttached is set true. However, setting this option overrides that setting and this sample rate will be used. (Default is 250)
    Boolean Print out useful debugging events. (Default false)

    BLED112AttributeValue : Object

    Kind: global typedef
    Properties

    Name Type Description
    characteristicHandle Number
    characteristicHandleRaw Buffer The string of the advertisement data, not the full ad data
    connection Number The connection the info is from
    type Number The type, where 0x01 is data?
    value Buffer The value from device

    BLED112AttributeWrite : Object

    Kind: global typedef
    Properties

    Name Type Description
    characteristicHandleRaw Buffer Buffer of length 2 for the service number in the att database
    connection Number Which connection is being used
    value String | Buffer The value to send to the device

    BLEDConnection : Object

    Kind: global typedef
    Properties

    Name Type
    addressType Number
    bonding Number
    connection Number
    connectionInterval Number
    flags Number
    latency Number
    sender Buffer
    timeout Number

    BLED112FindInformationFound : Object

    Kind: global typedef
    Properties

    Name Type Description
    characteristicHandle Number
    characteristicHandleRaw Buffer The string of the advertisement data, not the full ad data
    connection Number The entire end of ad data
    type Number The type, where 0x02 is short uuid and 0x10 is long, it's hex for length
    uuid Buffer

    BLED112GapConnectDirect : Object

    Kind: global typedef
    Properties

    Name Type
    connection Number
    result Buffer

    BLED112GroupService : Object

    Kind: global typedef
    Properties

    Name Type
    connection number
    end number
    endRaw Buffer
    start number
    startRaw Buffer
    uuid Buffer

    BLED112ParseRawAttributeValue : Object

    Kind: global typedef
    Properties

    Name Type Description
    buffer Buffer | Buffer2 The raw data buffer to parse
    ignore Number The position to ignore in the word
    length Number The length of raw you want to extract
    lengthPosition Number The position of the byte that stores the length of the value
    verify Object
    verify.comparePosition Number The value to compare with position
    verify.difference Number The difference between position and comparePostion
    verify.ignore Number The difference between position and comparePostion
    verify.position Number The position of the verification byte
    word Buffer | Buffer2 The 4 byte word to search for, ignore byte in postion 1

    BLED112ParseRawHeadTail : Object

    Kind: global typedef
    Properties

    Name Type Description
    buffer Buffer | Buffer2 The raw data buffer to parse
    head Number The head byte to search for
    length Number The length of raw you want to extract
    tail Number The tail byte to search for

    BLED112ParseRawWord : Object

    Kind: global typedef
    Properties

    Name Type Description
    buffer Buffer | Buffer2 The raw data buffer to parse
    length Number The length of raw you want to extract
    verify Object
    verify.position Number The position of the verification byte
    verify.value Number The value of the verification byte
    word Buffer | Buffer2 The 4 byte word to search for

    BLED112Peripheral : Object

    Kind: global typedef
    Properties

    Name Type Description
    addressType Number
    advertisement Object
    advertisement.localName String Same as advertisementDataString but mimics what noble outputs
    advertisementDataString String The string of the advertisement data, not the full ad data
    advertisementDataRaw Buffer | Buffer2 The entire end of ad data
    bond Number
    packetType Number -
    rssi Number The RSSI which stands for receive signal strength indicator and is in db so it's negative, and lower the better.
    sender Buffer | Buffer2 The mac address

    BLED112RspGroupType : Object

    Kind: global typedef
    Properties

    Name Type
    connection Number
    result Buffer

    Events:

    .on('accelerometer', callback)

    Emitted when the module receives accelerometer data.

    Returns an object with properties:

    accelData {Array}

    Array of floats for each dimension in g's.

    NOTE: Only present if sendCounts is true.

    accelDataCounts {Array}

    Array of integers for each dimension in counts.

    NOTE: Only present if sendCounts is false.

    Example (if sendCounts is false):

    {
      "accelData": [0.0, 0.0, 0.0, 0.0]
    }

    Example (if sendCounts is true):

    {
      "accelDataCounts": [0, 0, 0, 0]
    }

    .on('droppedPacket', callback)

    Emitted when a packet (or packets) are dropped. Returns an array.

    .on('error', callback)

    Emitted when there is an on the serial port.

    .on('impedance', callback)

    Emitted when there is a new impedance available.

    Returns an object with properties:

    channelNumber {Number}

    The channel number: 1, 2, 3, 4 respectively and 0 for reference.

    impedanceValue {Number}

    The impedance in ohms.

    Example:

    {
      "channelNumber": 0,
      "impedanceValue": 0
    }

    .on('rawDataPacket', callback)

    Emitted when there is a new raw data packet available.

    .on('ready', callback)

    Emitted when the board is in a ready to start streaming state.

    .on('sample', callback)

    Emitted when there is a new sample available.

    Returns an object with properties:

    channelData {Array}

    Array of floats for each channel in volts..

    NOTE: Only present if sendCounts is true.

    channelDataCounts {Array}

    Array of integers for each channel in counts.

    NOTE: Only present if sendCounts is false.

    sampleNumber {Number}

    The sample number. Only goes up to 254.

    timeStamp {Number}

    The time the sample is packed up. Not accurate for ERP.

    Example (if sendCounts is false):

    {
      "channelData": [0.0, 0.0, 0.0, 0.0],
      "sampleNumber": 0,
      "timeStamp": 0
    }

    Example (if sendCounts is true):

    {
      "channelDataCounts": [0, 0, 0, 0],
      "sampleNumber": 0,
      "timeStamp": 0
    }

    .on('scanStart', callback)

    Emitted when a noble scan is started.

    .on('scanStop', callback)

    Emitted when a noble scan is stopped.

    Interfacing With Other Tools:

    LabStreamingLayer

    LabStreamingLayer is a tool for streaming or recording time-series data. It can be used to interface with Matlab, Python, Unity, and many other programs.

    To use LSL with the NodeJS SDK, go to our labstreaminglayer example, which contains code that is ready to start an LSL stream of OpenBCI data.

    Follow the directions in the readme to get started.

    Developing:

    Running:

    npm install
    

    Testing:

    npm test
    

    Contribute:

    1. Fork it!
    2. Branch off of development: git checkout development
    3. Create your feature branch: git checkout -b my-new-feature
    4. Make changes
    5. If adding a feature, please add test coverage.
    6. Ensure tests all pass. (npm test)
    7. Commit your changes: git commit -m 'Add some feature'
    8. Push to the branch: git push origin my-new-feature
    9. Submit a pull request. Make sure it is based off of the development branch when submitting! :D

    License:

    MIT

    Install

    npm i @openbci/ganglion

    DownloadsWeekly Downloads

    0

    Version

    2.0.0

    License

    MIT

    Unpacked Size

    168 kB

    Total Files

    16

    Last publish

    Collaborators

    • avatar
    • avatar
    • avatar
    • avatar