Comparar commits

...

23 Commits

Autor SHA1 Mensagem Data
AJ Keller f96cdd94ec Merge pull request #130 from aj-ptw/add-exp-python
Add exp python
2016-12-02 02:14:51 -05:00
AJ Keller 4ce630dc4c Add: Python example 2016-12-02 02:14:08 -05:00
AJ Keller 8557444c55 1.4.2 2016-12-02 00:25:07 -05:00
AJ Keller c2c75fe9d8 Merge pull request #129 from aj-ptw/add-exp-debug
Add debug and get streaming examples
2016-12-02 00:23:26 -05:00
AJ Keller 13d4f57003 Add debug and get streaming examples 2016-12-02 00:23:02 -05:00
AJ Keller b9d0a466f8 Update changelog.md 2016-11-16 01:41:53 -05:00
AJ Keller 4428040a06 Merge pull request #123 from OpenBCI/development
1.4.1
2016-11-16 01:40:52 -05:00
AJ Keller f7e5c4988e Merge pull request #124 from baffo32/1.4.0-writes-resolve-promises
Write Promises Resolve When Write Completes
2016-11-09 23:56:24 -05:00
Karl Semich d4799dd45a Improve coverage 2016-11-09 19:54:09 +00:00
AJ Keller 212db205f2 Merge pull request #125 from baffo32/no-parallel-sntp
Refrain from testing sntp in parallel
2016-11-09 14:29:03 -05:00
Karl Semich 47b2df5802 openBCIBoard.js: make use of write promises 2016-11-09 18:59:34 +00:00
Karl Semich d06b6101e3 Resolve write promises when writes complete. Fixes #91 2016-11-09 18:58:17 +00:00
Karl Semich eb0510be6f Refrain from testing sntp in parallel 2016-11-09 18:48:37 +00:00
AJ Keller c696d4f5ca Update changelog.md 2016-11-08 02:37:17 -05:00
AJ Keller 677517715a Merge pull request #122 from khwilson/fix-typos-in-readme
Some fixes to typos in the README
2016-11-08 02:35:33 -05:00
AJ Keller 600b1b2b28 Merge pull request #121 from khwilson/fix-channelSet-so-promise-only-resolves-one-value
Bugfix: channelSet always fails due to bad resolve()
2016-11-07 16:38:00 -05:00
Kevin Wilson 32d011d1f9 Bugfix: channelSet always fails due to bad resolve()
The `resolve` function of a Promise takes *exactly one* argument.
All further arguments are ignored. Thus, the newChannelSettingsObject
that was being returned by the channelSet Promise was ignored and
the corresponding value in openBCIBoard was always undefined.

Thus, any calls to channel set would actually break the openBCISample
code as the channelSettingsArray contained an `undefined`.

This fixes the bug.
2016-11-07 15:44:30 -05:00
Kevin Wilson ee6c50294c Some fixes to typos in the README
Contributing should be off of the `development` branch, `SNTP` misspelled,
and a broken link to the `Testing` section.
2016-11-07 15:44:08 -05:00
AJ Keller 34be4c9fe3 Update changelog.md 2016-11-02 21:53:37 -04:00
AJ Keller 57dc399742 Merge pull request #118 from baffo32/1.4.0-bugtests
Fragmented and Buffered Samples (#115)
2016-11-02 21:41:44 -04:00
Karl Semich 5d989f6ea4 lint fixes 2016-11-03 00:29:32 +00:00
AJ Keller 2eebde6053 Add strip to EOT function and tests. 2016-11-03 00:29:32 +00:00
AJ Keller f7f8517c28 Update verison number to 1.4.1 2016-11-01 15:43:23 -04:00
20 arquivos alterados com 1154 adições e 225 exclusões
+14 -4
Ver Arquivo
@@ -28,7 +28,7 @@ The purpose of this module is to **get connected** and **start streaming** as fa
4. [Constants](#constants)
6. [Interfacing With Other Tools](#interfacing-with-other-tools)
7. [Developing](#developing)
8. [Testing](#testing)
8. [Testing](#developing-testing)
9. [Contribute](#contribute)
10. [License](#license)
11. [Roadmap](#roadmap)
@@ -38,7 +38,7 @@ The purpose of this module is to **get connected** and **start streaming** as fa
npm install openbci
```
### <a name="tldr"></a> TL;DR:
Get connected and start streaming right now
Get connected and [start streaming right now with the example code](examples/getStreaming/getStreaming.js).
```js
var OpenBCIBoard = require('openbci').OpenBCIBoard;
@@ -118,6 +118,15 @@ ourBoard.connect(k.OBCISimulatorPortName) // This will set `simulate` to true
});
```
To debug, it's amazing, do:
```js
var OpenBCIBoard = require('openbci').OpenBCIBoard;
var ourBoard = new OpenBCIBoard({
simulate: true
});
```
ps: go [checkout out the example](examples/debug/debug.js) to do it right now!
'ready' event
------------
@@ -846,7 +855,7 @@ To leave simulate mode.
### <a name="method-sntp"></a> .sntp
Extends the popular STNP package on [npmjs](https://www.npmjs.com/package/sntp)
Extends the popular SNTP package on [npmjs](https://www.npmjs.com/package/sntp)
### <a name="method-sntp-get-offset"></a> .sntpGetOffset()
@@ -1166,13 +1175,14 @@ npm test
## <a name="contribute"></a> Contribute:
1. Fork it!
2. Branch off of `development`: `git checkout development`
2. Create your feature branch: `git checkout -b my-new-feature`
3. Make changes
4. If adding a feature, please add test coverage.
5. Ensure tests all pass. (`npm test`)
6. Commit your changes: `git commit -m 'Add some feature'`
7. Push to the branch: `git push origin my-new-feature`
8. Submit a pull request :D
8. Submit a pull request. Make sure it is based off of the `development` branch when submitting! :D
## <a name="license"></a> License:
+14
Ver Arquivo
@@ -1,3 +1,16 @@
# 1.4.2
### New examples
* Add example of debug
* Add example of get streaming
# 1.4.1
### Bug Fixes
* Fixes bug where extra data after EOT (`$$$`) was dumped by preserving the poriton after the EOT for further decomposition.
* Fixes bug where any calls to channel set would actually break the openBCISample code as the channelSettingsArray contained an undefined.
* Writes promises resolve when they are actually sent over the serial port.
# 1.4.0
### New Features
@@ -22,6 +35,7 @@
* The `.streaming` property has been removed, replaced by `.isStreaming()`. Removed from docs.
* An error event will be emitted if sntp fails to initialize on construction
* The simulator will no longer communicate when disconnected
* Promises returned by writes will now only resolve after the write has been sent
### Bug Fixes
+108
Ver Arquivo
@@ -0,0 +1,108 @@
/**
* This is an example of debugging the board. Thanks to Karl @baffo32
* On windows you should run with PowerShell not git bash.
* Install
* [nodejs](https://nodejs.org/en/)
*
* To run:
* change directory to this file `cd examples/debug`
* do `npm install`
* then `npm start`
*/
var stream = true;
var debug = true; // Pretty print any bytes in and out... it's amazing...
var verbose = true; // Adds verbosity to functions
var OpenBCIBoard = require('openbci').OpenBCIBoard;
var ourBoard = new OpenBCIBoard({
debug: debug,
verbose: verbose
});
ourBoard.autoFindOpenBCIBoard().then(portName => {
if (portName) {
/**
* Connect to the board with portName
* Only works if one board is plugged in
* i.e. ourBoard.connect(portName).....
*/
// Call to connect
ourBoard.connect(portName).then(() => {
console.log(`connected`);
})
.catch(err => {
console.log(`connect: ${err}`);
});
} else {
/** Unable to auto find OpenBCI board */
console.log('Unable to auto find OpenBCI board');
}
});
/**
* The board is ready to start streaming after the ready function is fired.
*/
var readyFunc = () => {
// Get the sample rate after 'ready'
sampleRate = ourBoard.sampleRate();
if (stream) {
ourBoard.streamStart()
.catch(err => {
console.log(`stream start: ${err}`);
});
}
};
var sampleFunc = sample => {
/**
* Checkout the README.md for all other API functions.
* We support every feature.
* */
};
// Subscribe to your functions
ourBoard.on('ready', readyFunc);
ourBoard.on('sample', sampleFunc);
function exitHandler (options, err) {
if (options.cleanup) {
if (verbose) console.log('clean');
/** Do additional clean up here */
}
if (err) console.log(err.stack);
if (options.exit) {
if (verbose) console.log('exit');
if (stream) {
ourBoard.streamStop().catch(console.log);
}
ourBoard.disconnect().catch(console.log);
}
}
if (process.platform === "win32") {
const rl = require("readline").createInterface({
input: process.stdin,
output: process.stdout
});
rl.on("SIGINT", function () {
process.emit("SIGINT");
});
}
// do something when app is closing
process.on('exit', exitHandler.bind(null, {
cleanup: true
}));
// catches ctrl+c event
process.on('SIGINT', exitHandler.bind(null, {
exit: true
}));
// catches uncaught exceptions
process.on('uncaughtException', exitHandler.bind(null, {
exit: true
}));
+18
Ver Arquivo
@@ -0,0 +1,18 @@
{
"name": "debug",
"version": "1.0.0",
"description": "Debug example",
"main": "debug.js",
"scripts": {
"start": "node debug.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [
"debug"
],
"author": "AJ Keller",
"license": "MIT",
"dependencies": {
"openbci": "^1.4.1"
}
}
+87
Ver Arquivo
@@ -0,0 +1,87 @@
/**
* This is an example from the readme.md
* On windows you should run with PowerShell not git bash.
* Install
* [nodejs](https://nodejs.org/en/)
*
* To run:
* change directory to this file `cd examples/debug`
* do `npm install`
* then `npm start`
*/
var debug = false; // Pretty print any bytes in and out... it's amazing...
var verbose = true; // Adds verbosity to functions
var OpenBCIBoard = require('openbci').OpenBCIBoard;
var ourBoard = new OpenBCIBoard({
debug: debug,
verbose: verbose
});
ourBoard.autoFindOpenBCIBoard().then(portName => {
if (portName) {
/**
* Connect to the board with portName
* Only works if one board is plugged in
* i.e. ourBoard.connect(portName).....
*/
ourBoard.connect(portName) // Port name is a serial port name, see `.listPorts()`
.then(() => {
ourBoard.on('ready',() => {
ourBoard.streamStart();
ourBoard.on('sample',(sample) => {
/** Work with sample */
for (var i = 0; i < ourBoard.numberOfChannels(); i++) {
console.log("Channel " + (i + 1) + ": " + sample.channelData[i].toFixed(8) + " Volts.");
// prints to the console
// "Channel 1: 0.00001987 Volts."
// "Channel 2: 0.00002255 Volts."
// ...
// "Channel 8: -0.00001875 Volts."
}
});
});
});
} else {
/** Unable to auto find OpenBCI board */
console.log('Unable to auto find OpenBCI board');
}
});
function exitHandler (options, err) {
if (options.cleanup) {
if (verbose) console.log('clean');
/** Do additional clean up here */
}
if (err) console.log(err.stack);
if (options.exit) {
if (verbose) console.log('exit');
ourBoard.disconnect().catch(console.log);
}
}
if (process.platform === "win32") {
const rl = require("readline").createInterface({
input: process.stdin,
output: process.stdout
});
rl.on("SIGINT", function () {
process.emit("SIGINT");
});
}
// do something when app is closing
process.on('exit', exitHandler.bind(null, {
cleanup: true
}));
// catches ctrl+c event
process.on('SIGINT', exitHandler.bind(null, {
exit: true
}));
// catches uncaught exceptions
process.on('uncaughtException', exitHandler.bind(null, {
exit: true
}));
+18
Ver Arquivo
@@ -0,0 +1,18 @@
{
"name": "get-streaming",
"version": "1.0.0",
"description": "Get streaming example",
"main": "getStreaming.js",
"scripts": {
"start": "node getStreaming.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [
"get"
],
"author": "AJ Keller",
"license": "MIT",
"dependencies": {
"openbci": "^1.4.1"
}
}
+117
Ver Arquivo
@@ -0,0 +1,117 @@
import json
import sys
import numpy as np
import time
import zmq
class Interface:
def __init__(self, verbose=False):
context = zmq.Context()
self._socket = context.socket(zmq.PAIR)
self._socket.connect("tcp://localhost:3004")
self.verbose = verbose
if self.verbose:
print "Client Ready!"
# Send a quick message to tell node process we are up and running
self.send(json.dumps({
'action': 'started',
'command': 'status',
'message': time.time()*1000.0
}))
def send(self, msg):
"""
Sends a message to TCP server
:param msg: str
A string to send to node TCP server, could be a JSON dumps...
:return: None
"""
if self.verbose:
print '<- out ' + msg
self._socket.send(msg)
return
def recv(self):
"""
Checks the ZeroMQ for data
:return: str
String of data
"""
return self._socket.recv()
class RingBuffer(np.ndarray):
"""A multidimensional ring buffer."""
def __new__(cls, input_array):
obj = np.asarray(input_array).view(cls)
return obj
def __array_finalize__(self, obj):
if obj is None:
return
def __array_wrap__(self, out_arr, context=None):
return np.ndarray.__array_wrap__(self, out_arr, context)
def append(self, x):
"""Adds element x to the ring buffer."""
x = np.asarray(x)
self[:, :-1] = self[:, 1:]
self[:, -1] = x
def main(argv):
nb_chan = 8
verbose = True
# Create a new python interface.
interface = Interface(verbose=verbose)
# Signal buffer
signal = RingBuffer(np.zeros((nb_chan + 1, 2500)))
while True:
msg = interface.recv()
try:
dicty = json.loads(msg)
action = dicty.get('action')
command = dicty.get('command')
message = dicty.get('message')
if command == 'sample':
if action == 'process':
# Do sample processing here
try:
if type(message) is not dict:
print "sample is not a dict", message
raise ValueError
# Get keys of sample
data = np.zeros(9)
data[:-1] = message.get('channelData')
data[-1] = message.get('timeStamp')
# Add data to end of ring buffer
signal.append(data)
print message.get('sampleNumber')
except ValueError as e:
print e
elif command == 'status':
if action == 'active':
interface.send(json.dumps({
'action': 'alive',
'command': 'status',
'message': time.time() * 1000.0
}))
except BaseException as e:
print e
if __name__ == '__main__':
main(sys.argv[1:])
+212
Ver Arquivo
@@ -0,0 +1,212 @@
/**
* This is an example from the readme.md
* On windows you should run with PowerShell not git bash.
* Install
* [nodejs](https://nodejs.org/en/)
*
* To run:
* change directory to this file `cd examples/debug`
* do `npm install`
* then `npm start`
*/
var OpenBCIBoard = require('openbci').OpenBCIBoard;
var port_pub = 'tcp://127.0.0.1:3004';
var zmq = require('zmq-prebuilt');
var socket = zmq.socket('pair');
var simulate = true; // Sends synthetic data
var debug = false; // Pretty print any bytes in and out... it's amazing...
var verbose = true; // Adds verbosity to functions
var ourBoard = new OpenBCIBoard({
simulate: simulate,
simulatorFirmwareVersion: 'v2',
debug: debug,
verbose: verbose
});
var sampleRate = 250; // Default to 250, ALWAYS verify with a call to `.sampleRate()` after 'ready' event!
var timeSyncPossible = false;
var resyncPeriodMin = 1;
var secondsInMinute = 60;
var resyncPeriod = ourBoard.sampleRate() * resyncPeriodMin * secondsInMinute;
ourBoard.autoFindOpenBCIBoard().then(portName => {
if (portName) {
/**
* Connect to the board with portName
* i.e. ourBoard.connect(portName).....
*/
// Call to connect
ourBoard.connect(portName)
.then(() => {
ourBoard.on('ready', () => {
// Get the sample rate after 'ready'
sampleRate = ourBoard.sampleRate();
// Find out if you can even time sync, you must be using v2 and this is only accurate after a `.softReset()` call which is called internally on `.connect()`. We parse the `.softReset()` response for the presence of firmware version 2 properties.
timeSyncPossible = ourBoard.usingVersionTwoFirmware();
if (timeSyncPossible) {
ourBoard.streamStart()
.catch(err => {
console.log(`stream start: ${err}`);
});
} else {
console.log('not able to time sync');
}
})
})
.catch(err => {
console.log(`connect: ${err}`);
});
} else {
/** Unable to auto find OpenBCI board */
console.log('Unable to auto find OpenBCI board');
}
});
var sampleFunc = sample => {
if (sample._count % resyncPeriod === 0) {
ourBoard.syncClocksFull()
.then(syncObj => {
// Sync was successful
if (syncObj.valid) {
// Log the object to check it out!
console.log(`timeOffset`, syncObj.timeOffsetMaster);
} else {
// Retry it
console.log(`Was not able to sync... retry!`);
}
});
}
if (sample.timeStamp) { // true after the first successful sync
if (sample.timeStamp < 10 * 60 * 60 * 1000) { // Less than 10 hours
console.log(`Bad time sync ${sample.timeStamp}`);
} else {
sendToPython({
action: 'process',
command: 'sample',
message: sample
});
}
}
};
// Subscribe to your functions
ourBoard.on('sample', sampleFunc);
// ZMQ fun
socket.bind(port_pub, function (err) {
if (err) throw err;
console.log(`bound to ${port_pub}`);
});
/**
* Used to send a message to the Python process.
* @param {Object} interProcessObject The standard inter-process object.
* @return {None}
*/
var sendToPython = (interProcessObject, verbose) => {
if (verbose) {
console.log(`<- out ${JSON.stringify(interProcessObject)}`);
}
if (socket) {
socket.send(JSON.stringify(interProcessObject));
}
};
var receiveFromPython = (raw_data) => {
try {
let body = JSON.parse(raw_data); // five because `resp `
processInterfaceObject(body);
} catch (err) {
console.log('in -> ' + 'bad json');
}
};
socket.on('message', receiveFromPython);
var sendStatus = () => {
sendToPython({'action': 'active', 'message': 'ready', 'command': 'status'}, true);
};
sendStatus();
/**
* Process an incoming message
* @param {String} body A stringify JSON object that shall be parsed.
* @return {None}
*/
var processInterfaceObject = (body) => {
switch (body.command) {
case 'status':
processStatus(body);
break;
default:
unrecognizedCommand(body);
break;
}
};
/**
* Used to process a status related command from TCP IPC.
* @param {Object} body
* @return {None}
*/
var processStatus = (body) => {
switch (body.action) {
case 'started':
console.log(`python started @ ${body.message}ms`);
break;
case 'alive':
console.log(`python duplex communication test completed @ ${body.message}ms`);
break;
default:
unrecognizedCommand(body);
break;
}
};
function unrecognizedCommand (body) {
console.log(`unrecognizedCommand ${body}`);
}
function exitHandler (options, err) {
if (options.cleanup) {
if (verbose) console.log('clean');
/** Do additional clean up here */
}
if (err) console.log(err.stack);
if (options.exit) {
if (verbose) console.log('exit');
ourBoard.disconnect().catch(console.log);
}
}
if (process.platform === "win32") {
const rl = require("readline").createInterface({
input: process.stdin,
output: process.stdout
});
rl.on("SIGINT", function () {
process.emit("SIGINT");
});
}
// do something when app is closing
process.on('exit', exitHandler.bind(null, {
cleanup: true
}));
// catches ctrl+c event
process.on('SIGINT', exitHandler.bind(null, {
exit: true
}));
// catches uncaught exceptions
process.on('uncaughtException', exitHandler.bind(null, {
exit: true
}));
+30
Ver Arquivo
@@ -0,0 +1,30 @@
{
"name": "python",
"version": "1.0.0",
"description": "node to python example",
"main": "index.js",
"scripts": {
"start": "concurrently --kill-others \"python handoff.py\" \"node index.js\"",
"start-node": "node index.js",
"start-verbose": "concurrently --kill-others \"python handoff.py -v\" \"node index.js\"",
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [
"python",
"openbci",
"node"
],
"author": "AJ Keller",
"license": "MIT",
"dependencies": {
"openbci": "^1.4.2",
"zmq-prebuilt": "^2.1.0"
},
"devEngines": {
"node": "<=6.x",
"npm": ">=3.x"
},
"devDependencies": {
"concurrently": "^3.1.0"
}
}
+43
Ver Arquivo
@@ -0,0 +1,43 @@
# OpenBCI Node SDK to Python
## About
Written to end the struggles of python researchers and developers. ~ written with love by [Push The World!](http://www.pushtheworldllc.com)
This module has every feature available on the OpenBCI Board.
## Prerequisites
* [Python 2.7](https://www.python.org/downloads/)
* [ZeroMQ](http://zeromq.org/bindings:python)
```python
pip install pyzmq
```
* [Node.js LTS](https://nodejs.org/en/)
## Installation
For Python 2.7 do:
```bash
python setup.py install
```
For Node:
```bash
npm install
```
## Running
```
npm start
```
Verbose:
```
npm run start-verbose
```
For running just the node, for example if you were running the python in a separate ide and debugging, it's useful.
```python
npm run start-node
```
## Contributing
Please PR if you have code to contribute!
+12
Ver Arquivo
@@ -0,0 +1,12 @@
from setuptools import setup, find_packages
setup(name='openbci-node-python',
version='0.0.1',
description='Node to Python the right way',
url='',
author='AJ Keller',
author_email='pushtheworldllc@gmail.com',
license='MIT',
packages=find_packages(),
install_requires=['numpy', 'pyzmq'],
zip_safe=False)
+124 -119
Ver Arquivo
@@ -157,7 +157,7 @@ function OpenBCIFactory () {
// Arrays
this.accelArray = [0, 0, 0]; // X, Y, Z
this.channelSettingsArray = k.channelSettingsArrayInit(k.numberOfChannelsForBoardType(this.options.boardType));
this.writeOutArray = new Array(100);
this.writeOutArray = [];
// Booleans
this._streaming = false;
// Buffers
@@ -200,7 +200,6 @@ function OpenBCIFactory () {
// Numbers
this.badPackets = 0;
this.curParsingMode = k.OBCIParsingReset;
this.commandsToWrite = 0;
this.impedanceArray = openBCISample.impedanceArray(k.numberOfChannelsForBoardType(this.options.boardType));
this.previousSampleNumber = -1;
this.sampleCount = 0;
@@ -281,29 +280,42 @@ function OpenBCIFactory () {
this._processBytes(data);
});
this.serial.once('open', () => {
var timeoutLength = this.options.simulate ? 50 : 300;
if (this.options.verbose) console.log('Serial port open');
setTimeout(() => {
new Promise(resolve => {
// TODO: document why this 300 ms delay is needed
setTimeout(resolve, this.options.simulate ? 50 : 300);
}).then(() => {
if (this.options.verbose) console.log('Sending stop command, in case the device was left streaming...');
this.write(k.OBCIStreamStop);
if (this.serial) this.serial.flush();
}, timeoutLength);
setTimeout(() => {
return this.write(k.OBCIStreamStop);
}).then(() => {
return new Promise(resolve => this.serial.flush(resolve));
}).then(() => {
// TODO: document why this 250 ms delay is needed
return new Promise(resolve => setTimeout(resolve, 250));
}).then(() => {
if (this.options.verbose) console.log('Sending soft reset');
this.softReset();
// TODO: this promise chain resolves early because
// A. some legacy code (in tests) sets the ready handler after this resolves
// and
// B. other legacy code (in tests) needs the simulator to reply with segmented packets, never fragmented
// which is C. not implemented yet except in a manner such that replies occur in the write handler,
// resulting in the EOT arriving before this resolves
// Fix one or more of the above 3 situations, then move resolve() to the next block.
resolve();
return this.softReset();
}).then(() => {
if (this.options.verbose) console.log("Waiting for '$$$'");
}, timeoutLength + 250);
});
});
this.serial.once('close', () => {
if (this.options.verbose) console.log('Serial Port Closed');
// 'close' is emitted in _disconnected()
this._disconnected();
this._disconnected('port closed');
});
this.serial.once('error', (err) => {
if (this.options.verbose) console.log('Serial Port Error');
this.emit('error', err);
this._disconnected();
this._disconnected(err);
});
});
};
@@ -312,10 +324,9 @@ function OpenBCIFactory () {
* @description Called once when for any reason the serial port is no longer open.
* @private
*/
OpenBCIBoard.prototype._disconnected = function () {
OpenBCIBoard.prototype._disconnected = function (err) {
this._streaming = false;
this.commandsToWrite = 0;
clearTimeout(this.writer);
this.writer = null;
@@ -323,6 +334,11 @@ function OpenBCIFactory () {
this.serial = null;
this.emit('close');
while (this.writeOutArray.length > 0) {
var command = this.writeOutArray.pop();
if (command.reject) command.reject(err);
}
};
/**
@@ -332,9 +348,6 @@ function OpenBCIFactory () {
* @author AJ Keller (@pushtheworldllc)
*/
OpenBCIBoard.prototype.disconnect = function () {
if (!this.isConnected()) return Promise.reject('no board connected');
// no need for timeout here; streamStop already performs a delay
return Promise.resolve()
.then(() => {
if (this.isStreaming()) {
@@ -343,12 +356,16 @@ function OpenBCIFactory () {
}
})
.then(() => {
return new Promise((resolve, reject) => {
// serial emitting 'close' will call _disconnected
this.serial.close(() => {
resolve();
if (!this.isConnected()) {
return Promise.reject('no board connected');
} else {
return new Promise((resolve, reject) => {
// serial emitting 'close' will call _disconnected
this.serial.close(() => {
resolve();
});
});
});
}
});
};
@@ -382,13 +399,7 @@ function OpenBCIFactory () {
if (this.isStreaming()) return reject('Error [.streamStart()]: Already streaming');
this._streaming = true;
this._reset_ABANDONED(); // framework is incomplete but looks useful
this.write(k.OBCIStreamStart)
.then(() => {
setTimeout(() => {
resolve();
}, 10); // allow time for command to get sent
})
.catch(err => reject(err));
this.write(k.OBCIStreamStart).then(resolve, reject);
});
};
@@ -404,13 +415,7 @@ function OpenBCIFactory () {
return new Promise((resolve, reject) => {
if (!this.isStreaming()) return reject('Error [.streamStop()]: No stream to stop');
this._streaming = false;
this.write(k.OBCIStreamStop)
.then(() => {
setTimeout(() => {
resolve();
}, 10); // allow time for command to get sent
})
.catch(err => reject(err));
this.write(k.OBCIStreamStop).then(resolve, reject);
});
};
@@ -462,50 +467,55 @@ function OpenBCIFactory () {
/**
* @description To be able to easily write to the board but ensure that we never send commands
* with less than a 10ms spacing between sends. This uses an array and pops off
* the entries until there are none left.
* with less than a 10ms spacing between sends in early version boards. This uses
* an array and shifts off the entries until there are none left.
* @param dataToWrite - Either a single character or an Array of characters
* @returns {Promise}
* @author AJ Keller (@pushtheworldllc)
*/
OpenBCIBoard.prototype.write = function (dataToWrite) {
var writerFunction = () => {
/* istanbul ignore else */
if (this.commandsToWrite > 0) {
var command = this.writeOutArray.shift();
this.commandsToWrite--;
if (this.commandsToWrite === 0) {
this.writer = null;
return new Promise((resolve, reject) => {
if (!this.isConnected()) {
reject('not connected');
} else {
if (Array.isArray(dataToWrite)) { // Got an input array
var len = dataToWrite.length;
for (var i = 0; i < len; i++) {
this.writeOutArray.push({ cmd: dataToWrite[i], reject: reject });
}
this.writeOutArray[this.writeOutArray.length - 1].resolve = resolve;
} else {
this.writeOutArray.push({ cmd: dataToWrite, reject: reject, resolve: resolve });
}
if (!this.writer) { // there is no writer started
var writerFunction = () => {
if (this.writeOutArray.length === 0) {
this.writer = null;
return;
}
var command = this.writeOutArray.shift();
var promise = this._writeAndDrain(command.cmd);
promise.then(() => {
this.writer = setTimeout(writerFunction, this.writeOutDelay);
}, () => {
// write failed but more commands may be pending that need a result
writerFunction();
});
if (command.reject) {
promise.catch(err => {
if (this.options.verbose) console.log('write failure: ' + err);
command.reject(err);
});
}
if (command.resolve) promise.then(command.resolve);
};
this.writer = setTimeout(writerFunction, this.writeOutDelay);
}
this._writeAndDrain(command)
.catch(err => {
/* istanbul ignore if */
if (this.options.verbose) console.log('write failure: ' + err);
});
} else {
if (this.options.verbose) console.log('Big problem! Writer started with no commands to write');
}
};
return new Promise((resolve, reject) => {
// console.log('write method called')
if (!this.isConnected()) return reject('not connected');
if (Array.isArray(dataToWrite)) { // Got an input array
var len = dataToWrite.length;
for (var i = 0; i < len; i++) {
this.writeOutArray[this.commandsToWrite] = dataToWrite[i];
this.commandsToWrite++;
}
} else {
this.writeOutArray[this.commandsToWrite] = dataToWrite;
this.commandsToWrite++;
}
if (this.writer === null || this.writer === undefined) { // there is no writer started
this.writer = setTimeout(writerFunction, this.writeOutDelay);
}
resolve();
});
};
@@ -651,7 +661,7 @@ function OpenBCIFactory () {
this.curParsingMode = k.OBCIParsingEOT;
// Send the radio channel query command
this._writeAndDrain(new Buffer([k.OBCIRadioKey, k.OBCIRadioCmdChannelSet, channelNumber]));
this._writeAndDrain(new Buffer([k.OBCIRadioKey, k.OBCIRadioCmdChannelSet, channelNumber])).catch(reject);
});
};
@@ -701,7 +711,7 @@ function OpenBCIFactory () {
this.curParsingMode = k.OBCIParsingEOT;
// Send the radio channel query command
this._writeAndDrain(new Buffer([k.OBCIRadioKey, k.OBCIRadioCmdChannelSetOverride, channelNumber]));
this._writeAndDrain(new Buffer([k.OBCIRadioKey, k.OBCIRadioCmdChannelSetOverride, channelNumber])).catch(reject);
});
};
@@ -751,7 +761,7 @@ function OpenBCIFactory () {
this.curParsingMode = k.OBCIParsingEOT;
// Send the radio channel query command
this._writeAndDrain(new Buffer([k.OBCIRadioKey, k.OBCIRadioCmdChannelGet]));
this._writeAndDrain(new Buffer([k.OBCIRadioKey, k.OBCIRadioCmdChannelGet])).catch(reject);
});
};
@@ -797,7 +807,7 @@ function OpenBCIFactory () {
this.curParsingMode = k.OBCIParsingEOT;
// Send the radio channel query command
this._writeAndDrain(new Buffer([k.OBCIRadioKey, k.OBCIRadioCmdPollTimeGet]));
this._writeAndDrain(new Buffer([k.OBCIRadioKey, k.OBCIRadioCmdPollTimeGet])).catch(reject);
});
};
@@ -848,7 +858,7 @@ function OpenBCIFactory () {
this.curParsingMode = k.OBCIParsingEOT;
// Send the radio channel query command
this._writeAndDrain(new Buffer([k.OBCIRadioKey, k.OBCIRadioCmdPollTimeSet, pollTime]));
this._writeAndDrain(new Buffer([k.OBCIRadioKey, k.OBCIRadioCmdPollTimeSet, pollTime])).catch(reject);
});
};
@@ -920,9 +930,9 @@ function OpenBCIFactory () {
// Send the radio channel query command
if (speed === k.OBCIRadioBaudRateFastStr) {
this._writeAndDrain(new Buffer([k.OBCIRadioKey, k.OBCIRadioCmdBaudRateSetFast]));
this._writeAndDrain(new Buffer([k.OBCIRadioKey, k.OBCIRadioCmdBaudRateSetFast])).catch(reject);
} else {
this._writeAndDrain(new Buffer([k.OBCIRadioKey, k.OBCIRadioCmdBaudRateSetDefault]));
this._writeAndDrain(new Buffer([k.OBCIRadioKey, k.OBCIRadioCmdBaudRateSetDefault])).catch(reject);
}
});
};
@@ -970,7 +980,7 @@ function OpenBCIFactory () {
this.curParsingMode = k.OBCIParsingEOT;
// Send the radio channel query command
this._writeAndDrain(new Buffer([k.OBCIRadioKey, k.OBCIRadioCmdSystemStatus]));
this._writeAndDrain(new Buffer([k.OBCIRadioKey, k.OBCIRadioCmdSystemStatus])).catch(reject);
});
};
@@ -1092,13 +1102,11 @@ function OpenBCIFactory () {
var arrayOfCommands = [];
return new Promise((resolve, reject) => {
k.getChannelSetter(channelNumber, powerDown, gain, inputType, bias, srb2, srb1)
.then((arr, newChannelSettingObject) => {
arrayOfCommands = arr;
this.channelSettingsArray[channelNumber - 1] = newChannelSettingObject;
resolve(this.write(arrayOfCommands));
}, function (err) {
reject(err);
});
.then((val) => {
arrayOfCommands = val.commandArray;
this.channelSettingsArray[channelNumber - 1] = val.newChannelSettingsObject;
return this.write(arrayOfCommands);
}).then(resolve, reject);
});
};
@@ -1146,12 +1154,13 @@ function OpenBCIFactory () {
this.impedanceTest.active = true;
this.impedanceTest.continuousMode = true;
var chain = Promise.resolve();
for (var i = 0; i < this.numberOfChannels(); i++) {
k.getImpedanceSetter(i + 1, false, true).then((commandsArray) => {
this.write(commandsArray);
});
chain = chain
.then(() => k.getImpedanceSetter(i + 1, false, true))
.then((commandsArray) => this.write(commandsArray));
}
resolve();
chain.then(resolve, reject);
});
};
@@ -1168,12 +1177,13 @@ function OpenBCIFactory () {
this.impedanceTest.active = false;
this.impedanceTest.continuousMode = false;
var chain = Promise.resolve();
for (var i = 0; i < this.numberOfChannels(); i++) {
k.getImpedanceSetter(i + 1, false, false).then((commandsArray) => {
this.write(commandsArray);
});
chain = chain
.then(() => k.getImpedanceSetter(i + 1, false, false))
.then((commandsArray) => this.write(commandsArray));
}
resolve();
chain.then(resolve, reject);
});
};
@@ -1358,8 +1368,6 @@ function OpenBCIFactory () {
return new Promise((resolve, reject) => {
if (!this.isConnected()) return reject('Must be connected');
var delayInMS = 0;
/* istanbul ignore if */
if (this.options.verbose) {
if (pInput && !nInput) {
@@ -1382,18 +1390,15 @@ function OpenBCIFactory () {
if (this.options.verbose) console.log('pInput: ' + pInput + ' nInput: ' + nInput);
// Get impedance settings to send the board
k.getImpedanceSetter(channelNumber, pInput, nInput).then((commandsArray) => {
this.write(commandsArray);
// delayInMS += commandsArray.length * k.OBCIWriteIntervalDelayMSLong
delayInMS += this.commandsToWrite * k.OBCIWriteIntervalDelayMSShort; // Account for commands waiting to be sent in the write buffer
setTimeout(() => {
/**
* If either pInput or nInput are true then we should start calculating impedance. Setting
* this.impedanceTest.active to true here allows us to route every sample for an impedance
* calculation instead of the normal sample output.
*/
if (pInput || nInput) this.impedanceTest.active = true;
resolve(channelNumber);
}, delayInMS); // Prevents emitting .impedanceArray before all setting commands have been applied
return this.write(commandsArray);
}).then(() => {
/**
* If either pInput or nInput are true then we should start calculating impedance. Setting
* this.impedanceTest.active to true here allows us to route every sample for an impedance
* calculation instead of the normal sample output.
*/
if (pInput || nInput) this.impedanceTest.active = true;
resolve(channelNumber);
}, (err) => {
reject(err);
});
@@ -1494,7 +1499,7 @@ function OpenBCIFactory () {
* response from the board.
* @param recordingDuration {String} - The duration you want to log SD information for. Limited to:
* '14sec', '5min', '15min', '30min', '1hour', '2hour', '4hour', '12hour', '24hour'
* @returns {Promise} - Resolves if the command was added to write queue.
* @returns {Promise} - Resolves when the command has been written.
* @private
* @author AJ Keller (@pushtheworldllc)
*/
@@ -1517,7 +1522,7 @@ function OpenBCIFactory () {
/**
* @description Sends the stop SD logging command to the board. If not streaming then `eot` event will be emitted
* with request response from the board.
* @returns {Promise} - Resovles if added to the write queue
* @returns {Promise} - Resolves when written
* @author AJ Keller (@pushtheworldllc)
*/
OpenBCIBoard.prototype.sdStop = function () {
@@ -1593,8 +1598,7 @@ function OpenBCIFactory () {
this.sync.curSyncObj = openBCISample.newSyncObject();
this.sync.curSyncObj.timeSyncSent = this.time();
this.curParsingMode = k.OBCIParsingTimeSyncSent;
this._writeAndDrain(k.OBCISyncTimeSet);
resolve();
this._writeAndDrain(k.OBCISyncTimeSet).then(resolve, reject);
});
};
@@ -1692,7 +1696,7 @@ function OpenBCIFactory () {
if (openBCISample.doesBufferHaveEOT(data)) {
this.curParsingMode = k.OBCIParsingNormal;
this.emit('eot', data);
this.buffer = null;
this.buffer = openBCISample.stripToEOTBuffer(data);
} else {
this.buffer = data;
}
@@ -1702,8 +1706,8 @@ function OpenBCIFactory () {
if (openBCISample.doesBufferHaveEOT(data)) {
this._processParseBufferForReset(data);
this.curParsingMode = k.OBCIParsingNormal;
this.buffer = null;
this.emit('ready');
this.buffer = openBCISample.stripToEOTBuffer(data);
} else {
this.buffer = data;
}
@@ -1795,11 +1799,12 @@ function OpenBCIFactory () {
};
/**
* @description Alters the global info object by parseing an incoming soft reset key
* @param dataBuffer {Buffer} - The soft reset data buffer
* @private
* @author AJ Keller (@pushtheworldllc)
*/
* @description Alters the global info object by parseing an incoming soft reset key
* @param dataBuffer {Buffer} - The soft reset data buffer
* @returns {Buffer} - If there is data left in the buffer, just it will be returned.
* @private
* @author AJ Keller (@pushtheworldllc)
*/
OpenBCIBoard.prototype._processParseBufferForReset = function (dataBuffer) {
if (openBCISample.countADSPresent(dataBuffer) === 2) {
this.info.boardType = k.OBCIBoardDaisy;
+5 -3
Ver Arquivo
@@ -926,7 +926,10 @@ module.exports = {
* false -> Disconnect all N inputs from SRB1 (default))
* Select to connect (true) all channels' N inputs to SRB1. This effects all pins,
* and disconnects all N inputs from the ADC.
* @returns {Promise} resolves array of commands to be sent, rejects on bad input or no board
* @returns {Promise} resolves {commandArray: array of commands to be sent,
newChannelSettingsObject: an updated channel settings object
to be stored in openBCIBoard.channelSettingsArray},
rejects on bad input or no board
*/
function channelSetter (channelNumber, powerDown, gain, inputType, bias, srb2, srb1) {
// Used to store and assemble the commands
@@ -991,8 +994,7 @@ function channelSetter (channelNumber, powerDown, gain, inputType, bias, srb2, s
cmdSrb1,
obciChannelCmdLatch
];
// console.log(outputArray)
resolve(outputArray, newChannelSettingsObject);
resolve({commandArray: outputArray, newChannelSettingsObject: newChannelSettingsObject});
});
});
}
+26
Ver Arquivo
@@ -522,6 +522,7 @@ var sampleModule = {
makeTailByteFromPacketType,
isStopByte,
newSyncObject,
stripToEOTBuffer,
/**
* @description Checks to make sure the previous sample number is one less
* then the new sample number. Takes into account sample numbers wrapping
@@ -1111,6 +1112,31 @@ function isSuccessInBuffer (dataBuffer) {
return s.matches >= 1;
}
/**
* @description Used to slice a buffer for the EOT '$$$'.
* @param dataBuffer {Buffer} - The buffer of some length to parse
* @returns {Buffer} - The remaining buffer.
*/
function stripToEOTBuffer (dataBuffer) {
let indexOfEOT = dataBuffer.indexOf(k.OBCIParseEOT);
if (indexOfEOT > 0) {
indexOfEOT += k.OBCIParseEOT.length;
} else {
return dataBuffer;
}
if (indexOfEOT < dataBuffer.byteLength) {
if (k.getVersionNumber(process.version) >= 6) {
// From introduced in node version 6.x.x
return Buffer.from(dataBuffer.slice(indexOfEOT));
} else {
return new Buffer(dataBuffer.slice(indexOfEOT));
}
} else {
return null;
}
}
/**
* @description Used to parse a buffer for the `,` character that is acked back after a time sync request is sent
* @param dataBuffer {Buffer} - The buffer of some length to parse
+3 -1
Ver Arquivo
@@ -101,11 +101,13 @@ function OpenBCISimulatorFactory () {
// TODO: upgrade from old-style streams to stream.Duplex or stream.Transform
util.inherits(OpenBCISimulator, stream.Stream);
OpenBCISimulator.prototype.flush = function () {
OpenBCISimulator.prototype.flush = function (callback) {
this.outputBuffered = 0;
clearTimeout(this.outputLoopHandle);
this.outputLoopHandle = null;
if (callback) callback();
};
OpenBCISimulator.prototype.isOpen = function () {
+1 -1
Ver Arquivo
@@ -1,6 +1,6 @@
{
"name": "openbci",
"version": "1.4.0",
"version": "1.4.2",
"description": "The official Node.js SDK for the OpenBCI Biosensor Board.",
"main": "openBCIBoard",
"scripts": {
+243 -54
Ver Arquivo
@@ -792,32 +792,60 @@ describe('OpenBCIConstants', function () {
describe('channel input selection works', function () {
// this.timeout(5000)
it('channel 2', function (done) {
k.getChannelSetter(2, false, 24, 'normal', true, true, false).then(function (arrayOfCommands) {
arrayOfCommands[1].should.equal('2');
k.getChannelSetter(2, false, 24, 'normal', true, true, false).then(function (val) {
val.commandArray[1].should.equal('2');
val.newChannelSettingsObject.channelNumber.should.equal(2);
val.newChannelSettingsObject.powerDown.should.equal(false);
val.newChannelSettingsObject.gain.should.equal(24);
val.newChannelSettingsObject.inputType.should.equal('normal');
val.newChannelSettingsObject.bias.should.equal(true);
val.newChannelSettingsObject.srb2.should.equal(true);
val.newChannelSettingsObject.srb1.should.equal(false);
done();
}).catch(function (err) {
done(err);
});
});
it('channel 5', function (done) {
k.getChannelSetter(5, false, 24, 'normal', true, true, false).then(function (arrayOfCommands) {
arrayOfCommands[1].should.equal('5');
k.getChannelSetter(5, false, 24, 'normal', true, true, false).then(function (val) {
val.commandArray[1].should.equal('5');
val.newChannelSettingsObject.channelNumber.should.equal(5);
val.newChannelSettingsObject.powerDown.should.equal(false);
val.newChannelSettingsObject.gain.should.equal(24);
val.newChannelSettingsObject.inputType.should.equal('normal');
val.newChannelSettingsObject.bias.should.equal(true);
val.newChannelSettingsObject.srb2.should.equal(true);
val.newChannelSettingsObject.srb1.should.equal(false);
done();
}).catch(function (err) {
done(err);
});
});
it('channel 9', function (done) {
k.getChannelSetter(9, false, 24, 'normal', true, true, false).then(function (arrayOfCommands) {
arrayOfCommands[1].should.equal('Q');
k.getChannelSetter(9, false, 24, 'normal', true, true, false).then(function (val) {
val.commandArray[1].should.equal('Q');
val.newChannelSettingsObject.channelNumber.should.equal(9);
val.newChannelSettingsObject.powerDown.should.equal(false);
val.newChannelSettingsObject.gain.should.equal(24);
val.newChannelSettingsObject.inputType.should.equal('normal');
val.newChannelSettingsObject.bias.should.equal(true);
val.newChannelSettingsObject.srb2.should.equal(true);
val.newChannelSettingsObject.srb1.should.equal(false);
done();
}).catch(function (err) {
done(err);
});
});
it('channel 15', function (done) {
k.getChannelSetter(15, false, 24, 'normal', true, true, false).then(function (arrayOfCommands) {
arrayOfCommands[1].should.equal('U');
k.getChannelSetter(15, false, 24, 'normal', true, true, false).then(function (val) {
val.commandArray[1].should.equal('U');
val.newChannelSettingsObject.channelNumber.should.equal(15);
val.newChannelSettingsObject.powerDown.should.equal(false);
val.newChannelSettingsObject.gain.should.equal(24);
val.newChannelSettingsObject.inputType.should.equal('normal');
val.newChannelSettingsObject.bias.should.equal(true);
val.newChannelSettingsObject.srb2.should.equal(true);
val.newChannelSettingsObject.srb1.should.equal(false);
done();
}).catch(function (err) {
done(err);
@@ -832,16 +860,30 @@ describe('OpenBCIConstants', function () {
});
describe('power selection works', function () {
it('on', function (done) {
k.getChannelSetter(1, false, 24, 'normal', true, true, false).then(function (arrayOfCommands) {
arrayOfCommands[2].should.equal('0');
k.getChannelSetter(1, false, 24, 'normal', true, true, false).then(function (val) {
val.commandArray[2].should.equal('0');
val.newChannelSettingsObject.channelNumber.should.equal(1);
val.newChannelSettingsObject.powerDown.should.equal(false);
val.newChannelSettingsObject.gain.should.equal(24);
val.newChannelSettingsObject.inputType.should.equal('normal');
val.newChannelSettingsObject.bias.should.equal(true);
val.newChannelSettingsObject.srb2.should.equal(true);
val.newChannelSettingsObject.srb1.should.equal(false);
done();
}).catch(function (err) {
done(err);
});
});
it('off', function (done) {
k.getChannelSetter(1, true, 24, 'normal', true, true, false).then(function (arrayOfCommands) {
arrayOfCommands[2].should.equal('1');
k.getChannelSetter(1, true, 24, 'normal', true, true, false).then(function (val) {
val.commandArray[2].should.equal('1');
val.newChannelSettingsObject.channelNumber.should.equal(1);
val.newChannelSettingsObject.powerDown.should.equal(true);
val.newChannelSettingsObject.gain.should.equal(24);
val.newChannelSettingsObject.inputType.should.equal('normal');
val.newChannelSettingsObject.bias.should.equal(true);
val.newChannelSettingsObject.srb2.should.equal(true);
val.newChannelSettingsObject.srb1.should.equal(false);
done();
}).catch(function (err) {
done(err);
@@ -853,56 +895,105 @@ describe('OpenBCIConstants', function () {
});
describe('gain selection works', function () {
it('1x', function (done) {
k.getChannelSetter(1, false, 1, 'normal', true, true, false).then(function (arrayOfCommands) {
arrayOfCommands[3].should.equal('0');
k.getChannelSetter(1, false, 1, 'normal', true, true, false).then(function (val) {
val.commandArray[3].should.equal('0');
val.newChannelSettingsObject.channelNumber.should.equal(1);
val.newChannelSettingsObject.powerDown.should.equal(false);
val.newChannelSettingsObject.gain.should.equal(1);
val.newChannelSettingsObject.inputType.should.equal('normal');
val.newChannelSettingsObject.bias.should.equal(true);
val.newChannelSettingsObject.srb2.should.equal(true);
val.newChannelSettingsObject.srb1.should.equal(false);
done();
}).catch(function (err) {
done(err);
});
});
it('2x', function (done) {
k.getChannelSetter(1, false, 2, 'normal', true, true, false).then(function (arrayOfCommands) {
arrayOfCommands[3].should.equal('1');
k.getChannelSetter(1, false, 2, 'normal', true, true, false).then(function (val) {
val.commandArray[3].should.equal('1');
val.newChannelSettingsObject.channelNumber.should.equal(1);
val.newChannelSettingsObject.powerDown.should.equal(false);
val.newChannelSettingsObject.gain.should.equal(2);
val.newChannelSettingsObject.inputType.should.equal('normal');
val.newChannelSettingsObject.bias.should.equal(true);
val.newChannelSettingsObject.srb2.should.equal(true);
val.newChannelSettingsObject.srb1.should.equal(false);
done();
}).catch(function (err) {
done(err);
});
});
it('4x', function (done) {
k.getChannelSetter(1, false, 4, 'normal', true, true, false).then(function (arrayOfCommands) {
arrayOfCommands[3].should.equal('2');
k.getChannelSetter(1, false, 4, 'normal', true, true, false).then(function (val) {
val.commandArray[3].should.equal('2');
val.newChannelSettingsObject.channelNumber.should.equal(1);
val.newChannelSettingsObject.powerDown.should.equal(false);
val.newChannelSettingsObject.gain.should.equal(4);
val.newChannelSettingsObject.inputType.should.equal('normal');
val.newChannelSettingsObject.bias.should.equal(true);
val.newChannelSettingsObject.srb2.should.equal(true);
val.newChannelSettingsObject.srb1.should.equal(false);
done();
}).catch(function (err) {
done(err);
});
});
it('6x', function (done) {
k.getChannelSetter(1, false, 6, 'normal', true, true, false).then(function (arrayOfCommands) {
arrayOfCommands[3].should.equal('3');
k.getChannelSetter(1, false, 6, 'normal', true, true, false).then(function (val) {
val.commandArray[3].should.equal('3');
val.newChannelSettingsObject.channelNumber.should.equal(1);
val.newChannelSettingsObject.powerDown.should.equal(false);
val.newChannelSettingsObject.gain.should.equal(6);
val.newChannelSettingsObject.inputType.should.equal('normal');
val.newChannelSettingsObject.bias.should.equal(true);
val.newChannelSettingsObject.srb2.should.equal(true);
val.newChannelSettingsObject.srb1.should.equal(false);
done();
}).catch(function (err) {
done(err);
});
});
it('8x', function (done) {
k.getChannelSetter(1, false, 8, 'normal', true, true, false).then(function (arrayOfCommands) {
arrayOfCommands[3].should.equal('4');
k.getChannelSetter(1, false, 8, 'normal', true, true, false).then(function (val) {
val.commandArray[3].should.equal('4');
val.newChannelSettingsObject.channelNumber.should.equal(1);
val.newChannelSettingsObject.powerDown.should.equal(false);
val.newChannelSettingsObject.gain.should.equal(8);
val.newChannelSettingsObject.inputType.should.equal('normal');
val.newChannelSettingsObject.bias.should.equal(true);
val.newChannelSettingsObject.srb2.should.equal(true);
val.newChannelSettingsObject.srb1.should.equal(false);
done();
}).catch(function (err) {
done(err);
});
});
it('12x', function (done) {
k.getChannelSetter(1, false, 12, 'normal', true, true, false).then(function (arrayOfCommands) {
arrayOfCommands[3].should.equal('5');
k.getChannelSetter(1, false, 12, 'normal', true, true, false).then(function (val) {
val.commandArray[3].should.equal('5');
val.newChannelSettingsObject.channelNumber.should.equal(1);
val.newChannelSettingsObject.powerDown.should.equal(false);
val.newChannelSettingsObject.gain.should.equal(12);
val.newChannelSettingsObject.inputType.should.equal('normal');
val.newChannelSettingsObject.bias.should.equal(true);
val.newChannelSettingsObject.srb2.should.equal(true);
val.newChannelSettingsObject.srb1.should.equal(false);
done();
}).catch(function (err) {
done(err);
});
});
it('24x', function (done) {
k.getChannelSetter(1, false, 24, 'normal', true, true, false).then(function (arrayOfCommands) {
arrayOfCommands[3].should.equal('6');
k.getChannelSetter(1, false, 24, 'normal', true, true, false).then(function (val) {
val.commandArray[3].should.equal('6');
val.newChannelSettingsObject.channelNumber.should.equal(1);
val.newChannelSettingsObject.powerDown.should.equal(false);
val.newChannelSettingsObject.gain.should.equal(24);
val.newChannelSettingsObject.inputType.should.equal('normal');
val.newChannelSettingsObject.bias.should.equal(true);
val.newChannelSettingsObject.srb2.should.equal(true);
val.newChannelSettingsObject.srb1.should.equal(false);
done();
}).catch(function (err) {
done(err);
@@ -917,64 +1008,120 @@ describe('OpenBCIConstants', function () {
});
describe('input type', function () {
it('normal', function (done) {
k.getChannelSetter(1, false, 24, 'normal', true, true, false).then(function (arrayOfCommands) {
arrayOfCommands[4].should.equal('0');
k.getChannelSetter(1, false, 24, 'normal', true, true, false).then(function (val) {
val.commandArray[4].should.equal('0');
val.newChannelSettingsObject.channelNumber.should.equal(1);
val.newChannelSettingsObject.powerDown.should.equal(false);
val.newChannelSettingsObject.gain.should.equal(24);
val.newChannelSettingsObject.inputType.should.equal('normal');
val.newChannelSettingsObject.bias.should.equal(true);
val.newChannelSettingsObject.srb2.should.equal(true);
val.newChannelSettingsObject.srb1.should.equal(false);
done();
}).catch(function (err) {
done(err);
});
});
it('shorted', function (done) {
k.getChannelSetter(1, false, 24, 'shorted', true, true, false).then(function (arrayOfCommands) {
arrayOfCommands[4].should.equal('1');
k.getChannelSetter(1, false, 24, 'shorted', true, true, false).then(function (val) {
val.commandArray[4].should.equal('1');
val.newChannelSettingsObject.channelNumber.should.equal(1);
val.newChannelSettingsObject.powerDown.should.equal(false);
val.newChannelSettingsObject.gain.should.equal(24);
val.newChannelSettingsObject.inputType.should.equal('shorted');
val.newChannelSettingsObject.bias.should.equal(true);
val.newChannelSettingsObject.srb2.should.equal(true);
val.newChannelSettingsObject.srb1.should.equal(false);
done();
}).catch(function (err) {
done(err);
});
});
it('biasMethod', function (done) {
k.getChannelSetter(1, false, 24, 'biasMethod', true, true, false).then(function (arrayOfCommands) {
arrayOfCommands[4].should.equal('2');
k.getChannelSetter(1, false, 24, 'biasMethod', true, true, false).then(function (val) {
val.commandArray[4].should.equal('2');
val.newChannelSettingsObject.channelNumber.should.equal(1);
val.newChannelSettingsObject.powerDown.should.equal(false);
val.newChannelSettingsObject.gain.should.equal(24);
val.newChannelSettingsObject.inputType.should.equal('biasMethod');
val.newChannelSettingsObject.bias.should.equal(true);
val.newChannelSettingsObject.srb2.should.equal(true);
val.newChannelSettingsObject.srb1.should.equal(false);
done();
}).catch(function (err) {
done(err);
});
});
it('mvdd', function (done) {
k.getChannelSetter(1, false, 24, 'mvdd', true, true, false).then(function (arrayOfCommands) {
arrayOfCommands[4].should.equal('3');
k.getChannelSetter(1, false, 24, 'mvdd', true, true, false).then(function (val) {
val.commandArray[4].should.equal('3');
val.newChannelSettingsObject.channelNumber.should.equal(1);
val.newChannelSettingsObject.powerDown.should.equal(false);
val.newChannelSettingsObject.gain.should.equal(24);
val.newChannelSettingsObject.inputType.should.equal('mvdd');
val.newChannelSettingsObject.bias.should.equal(true);
val.newChannelSettingsObject.srb2.should.equal(true);
val.newChannelSettingsObject.srb1.should.equal(false);
done();
}).catch(function (err) {
done(err);
});
});
it('temp', function (done) {
k.getChannelSetter(1, false, 24, 'temp', true, true, false).then(function (arrayOfCommands) {
arrayOfCommands[4].should.equal('4');
k.getChannelSetter(1, false, 24, 'temp', true, true, false).then(function (val) {
val.commandArray[4].should.equal('4');
val.newChannelSettingsObject.channelNumber.should.equal(1);
val.newChannelSettingsObject.powerDown.should.equal(false);
val.newChannelSettingsObject.gain.should.equal(24);
val.newChannelSettingsObject.inputType.should.equal('temp');
val.newChannelSettingsObject.bias.should.equal(true);
val.newChannelSettingsObject.srb2.should.equal(true);
val.newChannelSettingsObject.srb1.should.equal(false);
done();
}).catch(function (err) {
done(err);
});
});
it('testsig', function (done) {
k.getChannelSetter(1, false, 24, 'testSig', true, true, false).then(function (arrayOfCommands) {
arrayOfCommands[4].should.equal('5');
k.getChannelSetter(1, false, 24, 'testSig', true, true, false).then(function (val) {
val.commandArray[4].should.equal('5');
val.newChannelSettingsObject.channelNumber.should.equal(1);
val.newChannelSettingsObject.powerDown.should.equal(false);
val.newChannelSettingsObject.gain.should.equal(24);
val.newChannelSettingsObject.inputType.should.equal('testSig');
val.newChannelSettingsObject.bias.should.equal(true);
val.newChannelSettingsObject.srb2.should.equal(true);
val.newChannelSettingsObject.srb1.should.equal(false);
done();
}).catch(function (err) {
done(err);
});
});
it('biasDrp', function (done) {
k.getChannelSetter(1, false, 24, 'biasDrp', true, true, false).then(function (arrayOfCommands) {
arrayOfCommands[4].should.equal('6');
k.getChannelSetter(1, false, 24, 'biasDrp', true, true, false).then(function (val) {
val.commandArray[4].should.equal('6');
val.newChannelSettingsObject.channelNumber.should.equal(1);
val.newChannelSettingsObject.powerDown.should.equal(false);
val.newChannelSettingsObject.gain.should.equal(24);
val.newChannelSettingsObject.inputType.should.equal('biasDrp');
val.newChannelSettingsObject.bias.should.equal(true);
val.newChannelSettingsObject.srb2.should.equal(true);
val.newChannelSettingsObject.srb1.should.equal(false);
done();
}).catch(function (err) {
done(err);
});
});
it('biasDrn', function (done) {
k.getChannelSetter(1, false, 24, 'biasDrn', true, true, false).then(function (arrayOfCommands) {
arrayOfCommands[4].should.equal('7');
k.getChannelSetter(1, false, 24, 'biasDrn', true, true, false).then(function (val) {
val.commandArray[4].should.equal('7');
val.newChannelSettingsObject.channelNumber.should.equal(1);
val.newChannelSettingsObject.powerDown.should.equal(false);
val.newChannelSettingsObject.gain.should.equal(24);
val.newChannelSettingsObject.inputType.should.equal('biasDrn');
val.newChannelSettingsObject.bias.should.equal(true);
val.newChannelSettingsObject.srb2.should.equal(true);
val.newChannelSettingsObject.srb1.should.equal(false);
done();
}).catch(function (err) {
done(err);
@@ -989,16 +1136,30 @@ describe('OpenBCIConstants', function () {
});
describe('bias selection works', function () {
it('Include', function (done) {
k.getChannelSetter(1, false, 24, 'normal', true, true, false).then(function (arrayOfCommands) {
arrayOfCommands[5].should.equal('1');
k.getChannelSetter(1, false, 24, 'normal', true, true, false).then(function (val) {
val.commandArray[5].should.equal('1');
val.newChannelSettingsObject.channelNumber.should.equal(1);
val.newChannelSettingsObject.powerDown.should.equal(false);
val.newChannelSettingsObject.gain.should.equal(24);
val.newChannelSettingsObject.inputType.should.equal('normal');
val.newChannelSettingsObject.bias.should.equal(true);
val.newChannelSettingsObject.srb2.should.equal(true);
val.newChannelSettingsObject.srb1.should.equal(false);
done();
}).catch(function (err) {
done(err);
});
});
it('Remove', function (done) {
k.getChannelSetter(1, false, 24, 'normal', false, true, false).then(function (arrayOfCommands) {
arrayOfCommands[5].should.equal('0');
k.getChannelSetter(1, false, 24, 'normal', false, true, false).then(function (val) {
val.commandArray[5].should.equal('0');
val.newChannelSettingsObject.channelNumber.should.equal(1);
val.newChannelSettingsObject.powerDown.should.equal(false);
val.newChannelSettingsObject.gain.should.equal(24);
val.newChannelSettingsObject.inputType.should.equal('normal');
val.newChannelSettingsObject.bias.should.equal(false);
val.newChannelSettingsObject.srb2.should.equal(true);
val.newChannelSettingsObject.srb1.should.equal(false);
done();
}).catch(function (err) {
done(err);
@@ -1010,16 +1171,30 @@ describe('OpenBCIConstants', function () {
});
describe('SRB2 selection works', function () {
it('Connect', function (done) {
k.getChannelSetter(1, false, 24, 'normal', true, true, false).then(function (arrayOfCommands) {
arrayOfCommands[6].should.equal('1');
k.getChannelSetter(1, false, 24, 'normal', true, true, false).then(function (val) {
val.commandArray[6].should.equal('1');
val.newChannelSettingsObject.channelNumber.should.equal(1);
val.newChannelSettingsObject.powerDown.should.equal(false);
val.newChannelSettingsObject.gain.should.equal(24);
val.newChannelSettingsObject.inputType.should.equal('normal');
val.newChannelSettingsObject.bias.should.equal(true);
val.newChannelSettingsObject.srb2.should.equal(true);
val.newChannelSettingsObject.srb1.should.equal(false);
done();
}).catch(function (err) {
done(err);
});
});
it('Disconnect', function (done) {
k.getChannelSetter(1, false, 24, 'normal', true, false, false).then(function (arrayOfCommands) {
arrayOfCommands[6].should.equal('0');
k.getChannelSetter(1, false, 24, 'normal', true, false, false).then(function (val) {
val.commandArray[6].should.equal('0');
val.newChannelSettingsObject.channelNumber.should.equal(1);
val.newChannelSettingsObject.powerDown.should.equal(false);
val.newChannelSettingsObject.gain.should.equal(24);
val.newChannelSettingsObject.inputType.should.equal('normal');
val.newChannelSettingsObject.bias.should.equal(true);
val.newChannelSettingsObject.srb2.should.equal(false);
val.newChannelSettingsObject.srb1.should.equal(false);
done();
}).catch(function (err) {
done(err);
@@ -1031,16 +1206,30 @@ describe('OpenBCIConstants', function () {
});
describe('SRB1 selection works', function () {
it('Connect', function (done) {
k.getChannelSetter(1, false, 24, 'normal', true, true, true).then(function (arrayOfCommands) {
arrayOfCommands[7].should.equal('1');
k.getChannelSetter(1, false, 24, 'normal', true, true, true).then(function (val) {
val.commandArray[7].should.equal('1');
val.newChannelSettingsObject.channelNumber.should.equal(1);
val.newChannelSettingsObject.powerDown.should.equal(false);
val.newChannelSettingsObject.gain.should.equal(24);
val.newChannelSettingsObject.inputType.should.equal('normal');
val.newChannelSettingsObject.bias.should.equal(true);
val.newChannelSettingsObject.srb2.should.equal(true);
val.newChannelSettingsObject.srb1.should.equal(true);
done();
}).catch(function (err) {
done(err);
});
});
it('Disconnect', function (done) {
k.getChannelSetter(1, false, 24, 'normal', true, true, false).then(function (arrayOfCommands) {
arrayOfCommands[7].should.equal('0');
k.getChannelSetter(1, false, 24, 'normal', true, true, false).then(function (val) {
val.commandArray[7].should.equal('0');
val.newChannelSettingsObject.channelNumber.should.equal(1);
val.newChannelSettingsObject.powerDown.should.equal(false);
val.newChannelSettingsObject.gain.should.equal(24);
val.newChannelSettingsObject.inputType.should.equal('normal');
val.newChannelSettingsObject.bias.should.equal(true);
val.newChannelSettingsObject.srb2.should.equal(true);
val.newChannelSettingsObject.srb1.should.equal(false);
done();
}).catch(function (err) {
done(err);
+45
Ver Arquivo
@@ -1210,6 +1210,51 @@ $$$`);
expect(openBCISample.droppedPacketCheck(previous, current)).to.be.null;
});
});
describe('#stripToEOTBuffer', function () {
it('should return the buffer if no EOT', function () {
let buf = null;
if (k.getVersionNumber(process.version) >= 6) {
// From introduced in node version 6.x.x
buf = Buffer.from('tacos are delicious');
} else {
buf = new Buffer('tacos are delicious');
}
expect(openBCISample.stripToEOTBuffer(buf).toString()).to.equal(buf.toString());
});
it('should slice the buffer after eot $$$', function () {
let bufPre = null;
let eotBuf = null;
let bufPost = null;
if (k.getVersionNumber(process.version) >= 6) {
// From introduced in node version 6.x.x
bufPre = Buffer.from('tacos are delicious');
eotBuf = Buffer.from(k.OBCIParseEOT);
bufPost = Buffer.from('tacos');
} else {
bufPre = new Buffer('tacos are delicious');
eotBuf = new Buffer(k.OBCIParseEOT);
bufPost = new Buffer('tacos');
}
let totalBuf = Buffer.concat([bufPre, eotBuf, bufPost]);
expect(openBCISample.stripToEOTBuffer(totalBuf).toString()).to.equal(bufPost.toString());
});
it('should return null if nothing left', function () {
let bufPre = null;
let eotBuf = null;
if (k.getVersionNumber(process.version) >= 6) {
// From introduced in node version 6.x.x
bufPre = Buffer.from('tacos are delicious');
eotBuf = Buffer.from(k.OBCIParseEOT);
} else {
bufPre = new Buffer('tacos are delicious');
eotBuf = new Buffer(k.OBCIParseEOT);
}
let totalBuf = Buffer.concat([bufPre, eotBuf]);
expect(openBCISample.stripToEOTBuffer(totalBuf)).to.equal(null);
});
});
});
describe('#goertzelProcessSample', function () {
+33 -42
Ver Arquivo
@@ -245,34 +245,18 @@ describe('openbci-sdk', function () {
expect(ourBoard2.options.simulatorSerialPortFailure).to.be.true;
});
it('should be able to enter sync mode', function () {
var ourBoard1, ourBoard2;
ourBoard1 = new openBCIBoard.OpenBCIBoard({
var ourBoard = new openBCIBoard.OpenBCIBoard({
sntpTimeSync: true
});
expect(ourBoard1.options.sntpTimeSync).to.be.true;
expect(ourBoard.options.sntpTimeSync).to.be.true;
// Verify multi case support
ourBoard2 = new openBCIBoard.OpenBCIBoard({
sntptimesync: true
});
expect(ourBoard2.options.sntpTimeSync).to.be.true;
return Promise.all([
new Promise((resolve, reject) => {
ourBoard1.once('sntpTimeLock', resolve);
ourBoard1.once('error', reject);
}),
new Promise((resolve, reject) => {
ourBoard2.once('sntpTimeLock', resolve);
ourBoard2.once('error', reject);
})
]).then(() => {
ourBoard1.sntpStop();
ourBoard2.sntpStop();
return new Promise((resolve, reject) => {
ourBoard.once('sntpTimeLock', resolve);
ourBoard.once('error', reject);
}).then(() => {
ourBoard.sntpStop();
}, err => {
ourBoard1.sntpStop();
ourBoard2.sntpStop();
ourBoard.sntpStop();
return Promise.reject(err);
});
});
@@ -525,6 +509,9 @@ describe('openbci-sdk', function () {
if (spy) spy.reset();
});
describe('#connect/disconnect/streamStart/streamStop', function () {
it('rejects if already disconnected', function () {
return ourBoard.disconnect().should.be.rejected;
});
it('rejects if already connected', function (done) {
ourBoard.connect(masterPortName).catch(err => done(err));
@@ -614,7 +601,7 @@ describe('openbci-sdk', function () {
});
afterEach(function (done) {
if (ourBoard.isConnected()) {
ourBoard.disconnect().then(done, () => done());
ourBoard.disconnect().then(done, done);
} else {
done();
}
@@ -640,12 +627,10 @@ describe('openbci-sdk', function () {
var writeSpy1 = sinon.spy(ourBoard.serial, 'write');
var byteToWrite = k.OBCISDLogStop;
var writeWhileConnected = function () {
var commands = [];
while (commands.length < 4) commands.push(byteToWrite);
ourBoard.write(commands).then(() => {
ourBoard.write(byteToWrite).then(() => {
if (ourBoard.isConnected()) {
writeSpy1.reset();
setTimeout(writeWhileConnected, 10 * (commands.length - 1));
writeWhileConnected();
} else {
done('wrote when not connected');
}
@@ -653,15 +638,17 @@ describe('openbci-sdk', function () {
if (ourBoard.isConnected()) {
done(err);
} else {
ourBoard.connect(masterPortName).catch(done);
var writeSpy2 = sinon.spy(ourBoard.serial, 'write');
ourBoard.once('ready', () => {
writeSpy2.should.equal(ourBoard.serial.write);
writeSpy1.should.have.not.been.called;
writeSpy2.should.have.not.been.calledWith(byteToWrite);
writeSpy1.restore();
writeSpy2.restore();
done();
process.nextTick(() => {
ourBoard.connect(masterPortName).catch(done);
var writeSpy2 = sinon.spy(ourBoard.serial, 'write');
ourBoard.once('ready', () => {
writeSpy2.should.equal(ourBoard.serial.write);
writeSpy1.should.have.not.been.called;
writeSpy2.should.have.not.been.calledWith(byteToWrite);
writeSpy1.restore();
writeSpy2.restore();
done();
});
});
}
});
@@ -669,13 +656,17 @@ describe('openbci-sdk', function () {
writeWhileConnected();
ourBoard.disconnect().catch(done);
});
it('disconnects immediately without performing buffered writes', function (done) {
it('disconnects immediately, rejecting all buffered writes', function () {
var writeSpy = sinon.spy(ourBoard.serial, 'write');
ourBoard.write(k.OBCISDLogStop);
ourBoard.disconnect().then(() => {
return Promise.all([
ourBoard.write(k.OBCISDLogStop).should.have.been.rejected,
ourBoard.write(k.OBCISDLogStop).should.have.been.rejected,
ourBoard.write(k.OBCISDLogStop).should.have.been.rejected,
ourBoard.write(k.OBCISDLogStop).should.have.been.rejected,
ourBoard.disconnect()
]).then(() => {+
writeSpy.should.have.not.been.called;
writeSpy.restore();
done();
});
});
});
+1 -1
Ver Arquivo
@@ -667,7 +667,7 @@ describe('openBCISimulator', function () {
bufferSize: bufferSize,
latencyTime: 1000
});
simulator.on('data', function (buffer) {
simulator.once('data', function (buffer) {
expect(buffer.length).to.equal(bufferSize);
done();
});