Comparar commits

...

29 Commits

Autor SHA1 Mensagem Data
AJ Keller 483811b092 Update changelog.md 2017-04-03 13:26:07 -04:00
AJ Keller 54d223533a Update dependencies 2017-04-03 13:25:17 -04:00
AJ Keller a552248f21 Merge pull request #143 from octopicorn/patch-1
note about serialport node error
2017-03-23 23:55:24 -04:00
octopicorn 5013112b36 note about serialport node error 2017-03-23 20:40:59 -07:00
AJ Keller b65694575b Update changelog.md 2017-03-02 14:52:25 -05:00
AJ Keller e47128cc4a Merge pull request #140 from OpenBCI/development
Lab Streaming Layer example (#139)
2017-03-02 14:50:50 -05:00
AJ Keller 1a6029770f Merge pull request #141 from aj-ptw/impedance-csne
Impedance csne
2017-03-02 13:39:18 -05:00
AJ Keller a404703d2e Removed old functions for impedance - #28 2017-03-02 13:28:19 -05:00
AJ Keller f618dcd038 Linting well and added auto tests for new impedance stuff 2017-03-02 12:58:12 -05:00
AJ Keller 0f4cb8baf0 Merge branch 'development' of https://github.com/OpenBCI/OpenBCI_NodeJS into impedance-csne 2017-03-02 10:31:40 -05:00
AJ Keller 1ad709659b Removed functions that were removed in 1.5.0 2017-03-02 10:24:05 -05:00
AJ Keller b871bd159d Merge branch 'master' into development 2017-03-02 10:21:27 -05:00
Gabriel Ibagon 9d778b64f8 Lab Streaming Layer example (#139)
* working lab streaming layer example for Cyton

* working lab streaming layer example for Cyton

* working lab streaming layer example for Cyton

* readme formatting

* more readme formatting

* typo '-_-

* more detail in readme

* clarifying readme code

* more readme edits

* clarified main readme

* added sudo note
2017-02-17 12:14:13 -05:00
AJ Keller 95d6529e3a Fixes #28 - Impedance not working properly 2017-02-11 17:44:21 -08:00
AJ Keller 3f42be4df6 Merge pull request #136 from aj-ptw/fix-16-chan
Fix 16 chan
2017-01-04 00:01:04 -05:00
AJ Keller 2523f72059 Update readme for new functions and emitters 2017-01-03 23:30:59 -05:00
AJ Keller af9f08642e Fix #131 and add example for daisy with hardset 2017-01-03 23:17:40 -05:00
AJ Keller a2b4d73847 Bump minor version because of breaking changes 2017-01-03 22:45:33 -05:00
AJ Keller c2958f408e Add tests for new daisy code and Enh separated radio tests from main board test 2017-01-03 22:44:17 -05:00
AJ Keller 0dd0eceb46 Add: max channel support for simulator 2017-01-03 22:44:16 -05:00
AJ Keller 70a6165366 Merge pull request #135 from OpenBCI/development
Development
2017-01-02 12:22:49 -05:00
AJ Keller 2d7547ce79 Merge pull request #134 from aj-ptw/16-chan-bug
Addresses #131 - 16 channels not always working
2017-01-02 11:59:03 -05:00
AJ Keller de381a80de Addresses #131 - 16 channels not always working 2016-12-28 16:43:43 -05:00
AJ Keller 888be5d60f Merge pull request #132 from aj-ptw/add-exp-python
Remove simulator line from python example
2016-12-05 10:29:56 -05:00
AJ Keller 57e6d9f7c2 Remove simulator line from python example 2016-12-05 10:26:39 -05:00
AJ Keller fb3d722fc8 Update package.json 2016-12-02 02:34:29 -05:00
AJ Keller 2728617126 Update readme.md 2016-12-02 02:34:09 -05:00
AJ Keller dd7639829a Update readme.md 2016-12-02 02:33:27 -05:00
AJ Keller b11775ecde Update README.md 2016-12-02 02:16:56 -05:00
30 arquivos alterados com 2644 adições e 1249 exclusões
+1
Ver Arquivo
@@ -20,4 +20,5 @@ node_js:
install:
- npm install --all
script:
- npm run lint
- npm run test-cov
+72 -39
Ver Arquivo
@@ -14,6 +14,8 @@ We are proud to support all functionality of the OpenBCI 8 and 16 Channel boards
The purpose of this module is to **get connected** and **start streaming** as fast as possible.
Python researcher or developer? Check out how easy it is to [get access to the entire API in the Python example](examples/python)!
### Table of Contents:
---
@@ -37,6 +39,19 @@ The purpose of this module is to **get connected** and **start streaming** as fa
```
npm install openbci
```
#### serialport dependency
If you encounter this error when trying to run:
```
Error: The module '/path/to/your/project/node_modules/serialport/build/Release/serialport.node'
was compiled against a different Node.js version using
NODE_MODULE_VERSION 48. This version of Node.js requires
NODE_MODULE_VERSION 51. Please try re-compiling or re-installing
the module (for instance, using `npm rebuild` or`npm install`).
```
...the issue can be resolved by running:
```
npm rebuild --build-from-source
```
### <a name="tldr"></a> TL;DR:
Get connected and [start streaming right now with the example code](examples/getStreaming/getStreaming.js).
@@ -71,7 +86,9 @@ Want to know if the module really works? Check out some projects and organizatio
Still not satisfied it works?? Check out this [detailed report](http://s132342840.onlinehome.us/pushtheworld/files/voltageVerificationTestPlanAndResults.pdf) that scientifically validates the output voltages of this module.
How are you still doubting and not using this already? Fine, go look at some of the [700 **_automatic_** tests](https://codecov.io/gh/OpenBCI/OpenBCI_NodeJS) written for it!
How are you still doubting and not using this already? Fine, go look at some of the [800 **_automatic_** tests](https://codecov.io/gh/OpenBCI/OpenBCI_NodeJS) written for it!
Python researcher or developer? Check out how easy it is to [get access to the entire API in the Python example](examples/python)!
### <a name="general-overview"></a> General Overview:
@@ -84,6 +101,7 @@ Initializing the board:
var OpenBCIBoard = require('openbci');
var ourBoard = new OpenBCIBoard.OpenBCIBoard();
```
Go [checkout out the get streaming example](examples/getStreaming/getStreaming.js)!
For initializing with options, such as verbose print outs:
@@ -103,6 +121,16 @@ var ourBoard = new OpenBCIBoard({
});
```
Have a daisy?:
```js
var OpenBCIBoard = require('openbci').OpenBCIBoard;
var ourBoard = new OpenBCIBoard({
boardType: `daisy`,
hardSet: true
});
```
Go [checkout out the get streaming with daisy example](examples/getStreamingDaisy/getStreamingDaisy.js)!
Another useful way to start the simulator:
```js
var openBCIBoard = require('openbci');
@@ -126,7 +154,7 @@ var ourBoard = new OpenBCIBoard({
simulate: true
});
```
ps: go [checkout out the example](examples/debug/debug.js) to do it right now!
Go [checkout out the debug example](examples/debug/debug.js)!
'ready' event
------------
@@ -391,6 +419,7 @@ Board optional configurations.
* `daisy` - 8 Channel board with Daisy Module - 16 Channels
* `ganglion` - 4 Channel board
(NOTE: THIS IS IN-OP TIL RELEASE OF GANGLION BOARD 08/2016)
* `hardSet` {Boolean} - Recommended if using `daisy` board! For some reason, the `daisy` is sometimes not picked up by the module so you can set `hardSet` to true which will ensure the daisy is picked up. (Default `false`)
* `simulate` {Boolean} - Full functionality, just mock data. Must attach Daisy module by setting `simulatorDaisyModuleAttached` to `true` in order to get 16 channels. (Default `false`)
* `simulatorBoardFailure` {Boolean} - Simulates board communications failure. This occurs when the RFduino on the board is not polling the RFduino on the dongle. (Default `false`)
* `simulatorDaisyModuleAttached` {Boolean} - Simulates a daisy module being attached to the OpenBCI board. This is useful if you want to test how your application reacts to a user requesting 16 channels but there is no daisy module actually attached, or vice versa, where there is a daisy module attached and the user only wants to use 8 channels. (Default `false`)
@@ -510,6 +539,12 @@ Closes the serial port opened by [`.connect()`](#method-connect). Waits for sto
**_Returns_** a promise, fulfilled by a successful close of the serial port object, rejected otherwise.
### <a name="method-get-info"></a> .getInfo()
Get the core info object. It's the object that actually drives the parsing of data.
**_Returns_** Object - {{boardType: string, sampleRate: number, firmware: string, numberOfChannels: number, missedPackets: number}}
### <a name="method-get-settings-for-channel"></a> .getSettingsForChannel(channelNumber)
Gets the specified channelSettings register data from printRegisterSettings call.
@@ -522,6 +557,21 @@ A number specifying which channel you want to get data on. Only 1-8 at this time
**_Returns_** a promise, fulfilled if the command was sent to the board and the `.processBytes()` function is ready to reach for the specified channel.
### <a name="method-hard-set-board-type"></a> .hardSetBoardType(boardType)
Used to sync the module and board to `boardType`.
**Note: This has the potential to change the way data is parsed**
**_boardType_**
A String indicating the number of channels.
* `default` - Default board: Sample rate is `250Hz` and number of channels is `8`.
* `daisy` - Daisy board: Sample rate is `125Hz` and number of channels is `16`.
**_Returns_** a promise, fulfilled if both the board and module are the requested `boardType`, rejects otherwise.
### <a name="method-impedance-test-all-channels"></a> .impedanceTestAllChannels()
To apply test signals to the channels on the OpenBCI board used to test for impedance. This can take a little while to actually run (<8 seconds)!
@@ -711,6 +761,19 @@ Get the current number of channels available to use. (i.e. 8 or 16).
**_Returns_** a number, the total number of available channels.
### <a name="method-override-info-for-board-type"></a> .overrideInfoForBoardType(boardType)
Set the info property for board type.
**Note: This has the potential to change the way data is parsed**
**_boardType_**
A String indicating the number of channels.
* `default` - Default board: Sample rate is `250Hz` and number of channels is `8`.
* `daisy` - Daisy board: Sample rate is `125Hz` and number of channels is `16`.
### <a name="method-print-bytes-in"></a> .printBytesIn()
Prints the total number of bytes that were read in this session to the console.
@@ -1076,6 +1139,10 @@ Emitted when a packet (or packets) are dropped. Returns an array.
Emitted when there is an on the serial port.
### <a name="event-hard-set"></a> .on('hardSet', callback)
Emitted when the module detects the board is not configured as the options for the module intended and tries to save itself. i.e. when the `daisy` option is `true` and a soft reset message is parsed and the module determines that a daisy was not detected, the module will emit `hardSet` then send an attach daisy command to recover. Either `error` will be emitted if unable to attach or `ready` will be emitted if success.
### <a name="event-impedance-array"></a> .on('impedanceArray', callback)
Emitted when there is a new impedanceArray available. Returns an array.
@@ -1118,46 +1185,12 @@ The name of the simulator port.
### <a name="interfacing-with-other-tools-labstreaminglayer"></a> LabStreamingLayer
[LabStreamingLayer](https://github.com/sccn/labstreaminglayer) by SCCN is a stream management tool designed to time-synchronize multiple data streams, potentially from different sources, over a LAN network with millisecond accuracy (given configuration).
[LabStreamingLayer](https://github.com/sccn/labstreaminglayer) is a tool for streaming or recording time-series data. It can be used to interface with [Matlab](https://github.com/sccn/labstreaminglayer/tree/master/LSL/liblsl-Matlab), [Python](https://github.com/sccn/labstreaminglayer/tree/master/LSL/liblsl-Python), [Unity](https://github.com/xfleckx/LSL4Unity), and many other programs.
For example, a VR display device running a Unity simulation may, using the [LSL4Unity](https://github.com/xfleckx/LSL4Unity) library, emit string markers into LSL corresponding to events of interest (For the P300 ERP, this event would be the onset of an attended, unusual noise in a pattern of commonplace ones). The computer doing data collection via the OpenBCI_NodeJS library (potentially with 4ms accuracy) would then output into an LSL stream the EEG and AUX data. LSL can then synchronize the two clocks relative to each other before inputting into a different program or toolkit, like [BCILAB](https://github.com/sccn/BCILAB) for analysis to trigger responses in the Unity display.
To use LSL with the NodeJS SDK, go to our [labstreaminglayer example](https://github.com/OpenBCI/OpenBCI_NodeJS/tree/master/examples/labstreaminglayer), which contains code that is ready to start an LSL stream of OpenBCI data.
This requires OpenBCI_NodeJS exporting data into LSL. Currently, there does not exist a pre-built NodeJS module for LSL, though LSL comes with tools that could possibly allow creation of one. In the meantime, the simpler route is to use a concurrent python script (driven by NodeJS module [python-shell](https://www.npmjs.com/package/python-shell)) to handoff the data to LSL for you, like so:
Follow the directions in the [readme](https://github.com/OpenBCI/OpenBCI_NodeJS/blob/master/examples/labstreaminglayer/readme.md) to get started.
In your NodeJS code, before initializing/connecting to the OpenBCIBoard:
```js
// Construct LSL Handoff Python Shell
var PythonShell = require('python-shell');
var lsloutlet = new PythonShell('LslHandoff.py');
lsloutlet.on('message', function(message){
console.log('LslOutlet: ' + message);
});
console.log('Python Shell Created for LSLHandoff');
```
In your NodeJS code, when reading samples:
```js
st = sample.channelData.join(' ')
//getTime returns milliseconds since midnight 1970/01/01
var s = ''+ sample.timeStamp + ': '+ st
lsloutlet.send(s)
```
in LSLHandoff.py:
```py
from pylsl import StreamInfo, StreamOutlet
info = StreamInfo('OpenBCI_EEG', 'EEG', 8, 250, 'float32', '[RANDOM NUMBER HERE]')
outlet = StreamOutlet(info)
while True:
strSample = raw_input().split(': ',1)
sample = map(float, strSample[1].split(' '))
stamp = float(strSample[0])
outlet.push_sample(sample, stamp)
print('Pushed Sample At: ' + strSample[0])
```
AUX data would be done the same way in a separate LSL stream.
## <a name="developing"></a> Developing:
### <a name="developing-running"></a> Running:
+58
Ver Arquivo
@@ -1,3 +1,61 @@
# 1.5.2
### Dependency Package Updates
* `performance-now`: from `^0.2.0` to `2.1.0`
* `serialport` - from `4.0.1` to `4.0.7`
### Development Dependency Package Updates
* `bluebird`: from `3.4.6` to `3.5.0`
* `chai-as-promised`: from `^5.2.0` to `^6.0.0`
* `codecov`: from `^1.0.1` to `^2.1.0`
* `semistandard`: from `^9.0.0` to `^10.0.0`
* `sinon`: from `^1.17.2` to `^2.1.0`
* `snazzy`: from `^5.0.0` to `^6.0.0`
# 1.5.1
### New Features
* Add new example for Lab stream layer (#139) thanks @gabrielibagon
### Breaking changes
* Removed `impedanceCalculationForChannel()` and `impedanceCalculationForAllChannels` from `OpenBCISample.js`
### Bug Fixes
* Fixes #28- Impedance not working properly.
# 1.5.0
### New Features
* New simulator option `simulatorDaisyModuleCanBeAttached` - Boolean, deafults to true, allows the simulation of the a hot swapped daisy board or simulates a misinformed module.
* New `EventEmitter` - `hardSet` - for when the module detects the board is not configured as the options for the module intended and tries to save itself. i.e. when the `daisy` option is `true` and a soft reset message is parsed and the module determines that a daisy was not detected, the module will emit `hardSet` then send an attach daisy command to recover. Either `error` will be emitted if unable to attach or `ready` will be emitted if success.
* Add example for streaming with `daisy` and `hardSet`.
### Breaking changes
* `.setInfoForBoardType()` changed to `.overrideInfoForBoardType()` to elevate it's dangerous nature.
* `.setMaxChannels()` changed to `.hardSetBoardType()` and input changed from numerical to string: 8 and 16 to `default` and `daisy` respectively.
### Bug Fixes
* Fixes #131 - 16 chan not working by sending a channel command and parsing the return.
* Fixed bug where end of transmission characters would not be ejected from buffer.
### Enhancements
* Separated radio tests from main board test file.
# 1.4.4
### New Features
* Set max number of channels for the board to use with `.setMaxChannels()` see readme.md
* Set the core info object that drives the module with `.overrideInfoForBoardType()` see readme.md
* Get info for the core object that drives the module with `.getInfo()` see readme.md
### Work In Progress
* Bug where daisy would sometimes not be recognized which destroyed all data.
# 1.4.3
### New examples
* Add example of node to python
# 1.4.2
### New examples
+6 -7
Ver Arquivo
@@ -45,7 +45,6 @@ ourBoard.autoFindOpenBCIBoard().then(portName => {
*/
var readyFunc = () => {
// Get the sample rate after 'ready'
sampleRate = ourBoard.sampleRate();
if (stream) {
ourBoard.streamStart()
.catch(err => {
@@ -65,10 +64,10 @@ var sampleFunc = sample => {
ourBoard.on('ready', readyFunc);
ourBoard.on('sample', sampleFunc);
function exitHandler (options, err) {
if (options.cleanup) {
if (verbose) console.log('clean');
ourBoard.removeAllListeners();
/** Do additional clean up here */
}
if (err) console.log(err.stack);
@@ -81,14 +80,14 @@ function exitHandler (options, err) {
}
}
if (process.platform === "win32") {
const rl = require("readline").createInterface({
if (process.platform === 'win32') {
const rl = require('readline').createInterface({
input: process.stdin,
output: process.stdout
});
rl.on("SIGINT", function () {
process.emit("SIGINT");
rl.on('SIGINT', function () {
process.emit('SIGINT');
});
}
@@ -105,4 +104,4 @@ process.on('SIGINT', exitHandler.bind(null, {
// catches uncaught exceptions
process.on('uncaughtException', exitHandler.bind(null, {
exit: true
}));
}));
+1 -1
Ver Arquivo
@@ -13,6 +13,6 @@
"author": "AJ Keller",
"license": "MIT",
"dependencies": {
"openbci": "^1.4.1"
"openbci": "^1.5.0"
}
}
+10 -9
Ver Arquivo
@@ -27,12 +27,12 @@ ourBoard.autoFindOpenBCIBoard().then(portName => {
*/
ourBoard.connect(portName) // Port name is a serial port name, see `.listPorts()`
.then(() => {
ourBoard.on('ready',() => {
ourBoard.on('ready', () => {
ourBoard.streamStart();
ourBoard.on('sample',(sample) => {
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.");
for (let 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."
@@ -51,6 +51,7 @@ ourBoard.autoFindOpenBCIBoard().then(portName => {
function exitHandler (options, err) {
if (options.cleanup) {
if (verbose) console.log('clean');
ourBoard.removeAllListeners();
/** Do additional clean up here */
}
if (err) console.log(err.stack);
@@ -60,14 +61,14 @@ function exitHandler (options, err) {
}
}
if (process.platform === "win32") {
const rl = require("readline").createInterface({
if (process.platform === 'win32') {
const rl = require('readline').createInterface({
input: process.stdin,
output: process.stdout
});
rl.on("SIGINT", function () {
process.emit("SIGINT");
rl.on('SIGINT', function () {
process.emit('SIGINT');
});
}
@@ -84,4 +85,4 @@ process.on('SIGINT', exitHandler.bind(null, {
// catches uncaught exceptions
process.on('uncaughtException', exitHandler.bind(null, {
exit: true
}));
}));
+1 -1
Ver Arquivo
@@ -13,6 +13,6 @@
"author": "AJ Keller",
"license": "MIT",
"dependencies": {
"openbci": "^1.4.1"
"openbci": "^1.5.0"
}
}
@@ -0,0 +1,94 @@
/**
* 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({
boardType: 'daisy',
debug: debug,
hardSet: true,
verbose: verbose
});
ourBoard.on('error', (err) => {
console.log(err);
});
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.once('ready', () => {
ourBoard.streamStart();
ourBoard.on('sample', (sample) => {
/** Work with sample */
for (let 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 16: -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');
ourBoard.removeAllListeners();
/** 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-daisy",
"version": "1.0.0",
"description": "Get streaming with hard set daisy example",
"main": "getStreaming.js",
"scripts": {
"start": "node getStreamingDaisy.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [
"get"
],
"author": "AJ Keller",
"license": "MIT",
"dependencies": {
"openbci": "^1.5.0"
}
}
+142
Ver Arquivo
@@ -0,0 +1,142 @@
/**
* 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
});
var k = require('openbci').OpenBCIConstants;
let startedImpedance = false;
let iBuffer = [];
let count = 0;
const window = 50;
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) => {
if (startedImpedance === false) {
startedImpedance = true;
k.getImpedanceSetter(1, false, true)
.then((commands) => {
return ourBoard.write(commands);
})
.then(() => {
console.log('wrote commands to board');
})
.catch((err) => {
console.log('errr', err);
});
}
/** Work with sample */
const chan1ValInVolts = sample.channelData[0];
// const impedance = chan1ValInVolts / k.OBCILeadOffDriveInAmps;
// console.log(`impedance:\t${impedance} kOhms`);
iBuffer.push(chan1ValInVolts);
count++;
if (count >= window) {
let max = 0.0; // sumSquared
for (let i = 0; i < window; i++) {
if (iBuffer[i] > max) {
max = iBuffer[i];
}
// sumSquared += iBuffer[i] * iBuffer[i];
}
let min = 0.0;
for (let i = 0; i < window; i++) {
if (iBuffer[i] < min) {
min = iBuffer[i];
}
// sumSquared += iBuffer[i] * iBuffer[i];
}
const vP2P = max - min; // peak to peak
console.log(`impedance: \t${vP2P / 2 / k.OBCILeadOffDriveInAmps}`);
// console.log(`impedance: ${vRms/k.OBCILeadOffDriveInAmps}`);
// const mean_squared = sumSquared / window;
// const root_mean_squared = Math.sqrt(mean_squared);
// console.log(`impedance: ${root_mean_squared/k.OBCILeadOffDriveInAmps}`);
count = 0;
iBuffer = [];
}
// console.log(`uV:\t${chan1ValInVolts/(10*6)}\nimpedance:\t${impedance}`);
});
});
});
} 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 */
ourBoard.disconnect().catch(console.log);
ourBoard.removeAllListeners();
}
if (err) console.log(err.stack);
if (options.exit) {
if (verbose) console.log('exit');
ourBoard.streamStop()
.then(() => {
process.exit(0);
})
.catch((err) => {
console.log(err);
process.exit(0);
});
}
}
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 impedance example",
"main": "getStreaming.js",
"scripts": {
"start": "node impedance.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [
"get"
],
"author": "AJ Keller",
"license": "MIT",
"dependencies": {
"openbci": "^1.5.0"
}
}
+90
Ver Arquivo
@@ -0,0 +1,90 @@
import json
import sys
import numpy as np
import time
import zmq
from pylsl import StreamInfo, StreamOutlet
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_string(msg)
return
def recv(self):
"""
Checks the ZeroMQ for data
:return: str
String of data
"""
return self._socket.recv()
def initializeOutlet(interface):
"""
Initializes and returns an LSL outlet
:param interface: Interface
the Python interface to communicate with node
:return: StreamOutlet
returns a labstreaminglayer StreamOutlet
"""
numChans = None
while not numChans:
msg = interface.recv()
try:
dicty = json.loads(msg)
numChans = dicty.get('numChans')
sampleRate = dicty.get('sampleRate')
except ValueError as e:
print(e)
info = StreamInfo('OpenBCI_EEG', 'EEG', numChans, sampleRate, 'float32', 'myuid34234')
outlet = StreamOutlet(info)
print('init')
return outlet
def main(argv):
verbose = False
# Create a new python interface.
interface = Interface(verbose)
# Create a new labstreaminglayer outlet
outlet = initializeOutlet(interface);
# Stream incoming data to LSL
while True:
msg = interface.recv()
try:
dicty = json.loads(msg)
message = dicty.get('message')
data=message.get('channelData')
timeStamp = message.get('timeStamp')
outlet.push_sample(data,timeStamp)
except BaseException as e:
print(e)
if __name__ == '__main__':
main(sys.argv[1:])
+157
Ver Arquivo
@@ -0,0 +1,157 @@
/**
* 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 portPub = 'tcp://127.0.0.1:3004';
var zmq = require('zmq-prebuilt');
var socket = zmq.socket('pair');
var debug = false; // Pretty print any bytes in and out... it's amazing...
var verbose = true; // Adds verbosity to functions
var ourBoard = new OpenBCIBoard({
simulatorFirmwareVersion: 'v2',
debug: debug,
verbose: verbose
});
var timeSyncPossible = false;
var resyncPeriodMin = 1;
var secondsInMinute = 60;
var numChans = 8;
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'
numChans = ourBoard.numberOfChannels();
if (numChans === 16) {
ourBoard.overrideInfoForBoardType('daisy');
}
// 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();
sendToPython({'numChans': numChans, 'sampleRate': ourBoard.sampleRate()});
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
socket.bind(portPub, function (err) {
if (err) throw err;
console.log(`bound to ${portPub}`);
});
/**
* 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));
}
};
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
}));
+31
Ver Arquivo
@@ -0,0 +1,31 @@
{
"name": "labstreaminglayer",
"version": "1.0.0",
"description": "labstreaminglayer example",
"main": "index.js",
"scripts": {
"start": "concurrently --kill-others \"python handoff.py\" \"node index.js\"",
"start-node": "node index.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [
"python",
"openbci",
"node",
"labstreaminglayer",
"LSL"
],
"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"
}
}
+111
Ver Arquivo
@@ -0,0 +1,111 @@
# OpenBCI Node SDK to Lab Streaming Layer
## About
This code provides an example of how to stream OpenBCI data through the [lab streaming layer](https://github.com/sccn/labstreaminglayer) using the NodeJS SDK.
Follow the steps in this README to start streaming. The code is ready to run as-is, but can be modified and extended to customize how you are sending your data. This is designed to be used with the **OpenBCI Cyton** (for **Ganglion support**, see the [Ganglion Node SDK](https://github.com/OpenBCI/OpenBCI_NodeJS_Ganglion/tree/master/examples/labstreaminglayer)).
## Prerequisites
* [Python](https://www.python.org/downloads/)
* [ZeroMQ](http://zeromq.org/bindings:python)
```py
pip install pyzmq
```
* [Node.js LTS](https://nodejs.org/en/)
* [Lab Streaming Layer](https://github.com/sccn/labstreaminglayer)
```py
pip install pylsl
```
## Installation
First, install Python dependencies:
```bash
python setup.py install
```
Next, install NodeJS dependencies:
```bash
npm install
```
Note: depending on your computer settings, you may need to run as administrator or with `sudo`.
## Running
```
npm start
```
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
```
Note: depending on your computer settings, you may need to run as administrator or with `sudo`.
## Writing Lab Streaming Layer Code
If you would like to use lab streaming layer in a custom OpenBCI NodeJS application, you must include an instance of the OpenBCI NodeJS library and an instance of a Python interface. A basic example is shown below:
index.js
```js
var OpenBCIBoard = require('openbci').OpenBCIBoard;
var portPub = 'tcp://127.0.0.1:3004';
var zmq = require('zmq-prebuilt');
var socket = zmq.socket('pair');
var ourBoard = new OpenBCIBoard();
socket.bind(portPub);
ourBoard.autoFindOpenBCIBoard().then(portName => {
if (portName) {
ourBoard.connect(portName) // Port name is a serial port name, see `.listPorts()`
.then(() => {
ourBoard.on('ready',() => {
ourBoard.streamStart();
ourBoard.on('sample',(sample) => {
if (socket) {
socket.send(JSON.stringify({message: sample}));
}
}
});
});
});
} else {
console.log('Unable to auto find OpenBCI board');
}
});
/* Insert additional exit handlers and cleanup below*/
```
handoff.py
```python
import json
import zmq
from pylsl import StreamInfo, StreamOutlet
# Create ZMQ socket
context = zmq.Context()
_socket = context.socket(zmq.PAIR)
_socket.connect("tcp://localhost:3004")
# Create a new labstreaminglayer outlet
numChans = 8;
sampleRate = 250;
info = StreamInfo('OpenBCI_EEG', 'EEG', numChans, sampleRate, 'float32', 'openbci_12345')
outlet = StreamOutlet(info)
# Stream incoming data to LSL
while True:
msg = _socket.recv()
try:
dicty = json.loads(msg)
message = dicty.get('message')
data=message.get('channelData')
timeStamp = message.get('timeStamp')
outlet.push_sample(data,timeStamp)
except BaseException as e:
print(e)
```
## 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-labstreaminglayer',
version='0.0.1',
description='Labstreaminglayer with NodeJS',
url='',
author='AJ Keller',
author_email='pushtheworldllc@gmail.com',
license='MIT',
packages=find_packages(),
install_requires=['numpy', 'pyzmq','pylsl'],
zip_safe=False)
+13 -17
Ver Arquivo
@@ -10,21 +10,20 @@
* then `npm start`
*/
var OpenBCIBoard = require('openbci').OpenBCIBoard;
var port_pub = 'tcp://127.0.0.1:3004';
var portPub = 'tcp://127.0.0.1:3004';
var zmq = require('zmq-prebuilt');
var socket = zmq.socket('pair');
var simulate = true; // Sends synthetic data
var simulate = false; // 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,
simulate: simulate, // Uncomment to see how it works with simulator!
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;
@@ -40,9 +39,6 @@ ourBoard.autoFindOpenBCIBoard().then(portName => {
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();
@@ -54,7 +50,7 @@ ourBoard.autoFindOpenBCIBoard().then(portName => {
} else {
console.log('not able to time sync');
}
})
});
})
.catch(err => {
console.log(`connect: ${err}`);
@@ -98,9 +94,9 @@ ourBoard.on('sample', sampleFunc);
// ZMQ fun
socket.bind(port_pub, function (err) {
socket.bind(portPub, function (err) {
if (err) throw err;
console.log(`bound to ${port_pub}`);
console.log(`bound to ${portPub}`);
});
/**
@@ -117,9 +113,9 @@ var sendToPython = (interProcessObject, verbose) => {
}
};
var receiveFromPython = (raw_data) => {
var receiveFromPython = (rawData) => {
try {
let body = JSON.parse(raw_data); // five because `resp `
let body = JSON.parse(rawData); // five because `resp `
processInterfaceObject(body);
} catch (err) {
console.log('in -> ' + 'bad json');
@@ -185,14 +181,14 @@ function exitHandler (options, err) {
}
}
if (process.platform === "win32") {
const rl = require("readline").createInterface({
if (process.platform === 'win32') {
const rl = require('readline').createInterface({
input: process.stdin,
output: process.stdout
});
rl.on("SIGINT", function () {
process.emit("SIGINT");
rl.on('SIGINT', function () {
process.emit('SIGINT');
});
}
@@ -209,4 +205,4 @@ process.on('SIGINT', exitHandler.bind(null, {
// catches uncaught exceptions
process.on('uncaughtException', exitHandler.bind(null, {
exit: true
}));
}));
-1
Ver Arquivo
@@ -6,7 +6,6 @@
"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": [
+3 -6
Ver Arquivo
@@ -10,7 +10,8 @@ This module has every feature available on the OpenBCI Board.
* [Python 2.7](https://www.python.org/downloads/)
* [ZeroMQ](http://zeromq.org/bindings:python)
```python
```py
pip install pyzmq
```
* [Node.js LTS](https://nodejs.org/en/)
@@ -30,14 +31,10 @@ npm install
```
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!
Please PR if you have code to contribute!
+40
Ver Arquivo
@@ -10,6 +10,7 @@
var OpenBCIBoard = require('openbci').OpenBCIBoard;
var ourBoard = new OpenBCIBoard({});
var verbose = true; // Adds verbosity to functions
var sampleRate = 250; // Default to 250, ALWAYS verify with a call to `.sampleRate()` after 'ready' event!
var timeSyncPossible = false;
@@ -29,6 +30,7 @@ ourBoard.autoFindOpenBCIBoard().then(portName => {
});
} else {
/** Unable to auto find OpenBCI board */
console.log('Unable to auto find OpenBCI board');
}
});
@@ -86,3 +88,41 @@ var sampleFunc = sample => {
// 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');
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
}));
+220 -96
Ver Arquivo
@@ -20,9 +20,11 @@ function OpenBCIFactory () {
var _options = {
boardType: [k.OBCIBoardDefault, k.OBCIBoardDaisy, k.OBCIBoardGanglion],
baudRate: 115200,
hardSet: false,
simulate: false,
simulatorBoardFailure: false,
simulatorDaisyModuleAttached: false,
simulatorDaisyModuleCanBeAttached: true,
simulatorFirmwareVersion: [k.OBCIFirmwareV1, k.OBCIFirmwareV2],
simulatorFragmentation: [k.OBCISimulatorFragmentationNone, k.OBCISimulatorFragmentationRandom, k.OBCISimulatorFragmentationFullBuffers, k.OBCISimulatorFragmentationOneByOne],
simulatorLatencyTime: 16,
@@ -41,80 +43,88 @@ function OpenBCIFactory () {
};
/**
* @description The initialization method to call first, before any other method.
* @param options (optional) - Board optional configurations.
* - `baudRate` {Number} - Baud Rate, defaults to 115200. Manipulating this is allowed if
* firmware on board has been previously configured.
*
* - `boardType` {String} - Specifies type of OpenBCI board.
* 3 Possible Boards:
* `default` - 8 Channel OpenBCI board (Default)
* `daisy` - 8 Channel OpenBCI board with Daisy Module. Total of 16 channels.
* `ganglion` - 4 Channel board
* (NOTE: THIS IS IN-OP TIL RELEASE OF GANGLION BOARD 07/2016)
*
* - `simulate` {Boolean} - Full functionality, just mock data. Must attach Daisy module by setting
* `simulatorDaisyModuleAttached` to `true` in order to get 16 channels. (Default `false`)
*
* - `simulatorBoardFailure` {Boolean} - Simulates board communications failure. This occurs when the RFduino on
* the board is not polling the RFduino on the dongle. (Default `false`)
*
* - `simulatorDaisyModuleAttached` {Boolean} - Simulates a daisy module being attached to the OpenBCI board.
* This is useful if you want to test how your application reacts to a user requesting 16 channels
* but there is no daisy module actually attached, or vice versa, where there is a daisy module
* attached and the user only wants to use 8 channels. (Default `false`)
*
* - `simulatorFirmwareVersion` {String} - Allows simulator to be started with firmware version 2 features
* 2 Possible Options:
* `v1` - Firmware Version 1 (Default)
* `v2` - Firmware Version 2
*
* - `simulatorFragmentation` {String} - Specifies how to break packets to simulate fragmentation, which
* occurs commonly in real devices. It is recommended to test code with this enabled.
* 4 Possible Options:
* `none` - do not fragment packets; output complete chunks immediately when produced (Default)
* `random` - output random small chunks of data interspersed with full buffers
* `fullBuffers` - allow buffers to fill up until the latency timer has expired
* `oneByOne` - output each byte separately
*
* - `simulatorLatencyTime` {Number} - The time in milliseconds to wait before sending partially full buffers,
if `simulatorFragmentation` is specified. (Default `16`)
*
* - `simulatorBufferSize` {Number} - The size of a full buffer of data, if `simulatorFragmentation` is
* specified. (Default `4096`)
*
* - `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`)
*
* - `simulatorSerialPortFailure` {Boolean} - Simulates not being able to open a serial connection. Most likely
* due to a OpenBCI dongle not being plugged in.
*
* - `sntpTimeSync` - {Boolean} Syncs the module up with an SNTP time server and uses that as single source
* of truth instead of local computer time. If you are running experiements on your local
* computer, keep this `false`. (Default `false`)
*
* - `sntpTimeSyncHost` - {String} The ntp server to use, can be either sntp or ntp. (Defaults `pool.ntp.org`).
*
* - `sntpTimeSyncPort` - {Number} The port to access the ntp server. (Defaults `123`)
*
* - `verbose` {Boolean} - Print out useful debugging events. (Default `false`)
*
* - `debug` {Boolean} - Print out a raw dump of bytes sent and received. (Default `false`)
*
* @constructor
* @author AJ Keller (@pushtheworldllc)
*/
* @description The initialization method to call first, before any other method.
* @param options (optional) - Board optional configurations.
* - `baudRate` {Number} - Baud Rate, defaults to 115200. Manipulating this is allowed if
* firmware on board has been previously configured.
*
* - `boardType` {String} - Specifies type of OpenBCI board.
* 3 Possible Boards:
* `default` - 8 Channel OpenBCI board (Default)
* `daisy` - 8 Channel OpenBCI board with Daisy Module. Total of 16 channels.
* `ganglion` - 4 Channel board
* (NOTE: THIS IS IN-OP TIL RELEASE OF GANGLION BOARD 07/2016)
*
* - `hardSet` {Boolean} - Recommended if using `daisy` board! For some reason, the `daisy` is sometimes
* not picked up by the module so you can set `hardSet` to true which will ensure the daisy
* is picked up. (Default `false`)
*
* - `simulate` {Boolean} - Full functionality, just mock data. Must attach Daisy module by setting
* `simulatorDaisyModuleAttached` to `true` in order to get 16 channels. (Default `false`)
*
* - `simulatorBoardFailure` {Boolean} - Simulates board communications failure. This occurs when the RFduino on
* the board is not polling the RFduino on the dongle. (Default `false`)
*
* - `simulatorDaisyModuleAttached` {Boolean} - Simulates a daisy module being attached to the OpenBCI board.
* This is useful if you want to test how your application reacts to a user requesting 16 channels
* but there is no daisy module actually attached, or vice versa, where there is a daisy module
* attached and the user only wants to use 8 channels. (Default `false`)
*
* - `simulatorDaisyModuleCanBeAttached` {Boolean} - Allows the simulation of the a hot swapped daisy board.
* For example: You coule simulate if the board has only detected 8 channels and the user requested
* 16 channels. (Default `true`)
*
* - `simulatorFirmwareVersion` {String} - Allows simulator to be started with firmware version 2 features
* 2 Possible Options:
* `v1` - Firmware Version 1 (Default)
* `v2` - Firmware Version 2
*
* - `simulatorFragmentation` {String} - Specifies how to break packets to simulate fragmentation, which
* occurs commonly in real devices. It is recommended to test code with this enabled.
* 4 Possible Options:
* `none` - do not fragment packets; output complete chunks immediately when produced (Default)
* `random` - output random small chunks of data interspersed with full buffers
* `fullBuffers` - allow buffers to fill up until the latency timer has expired
* `oneByOne` - output each byte separately
*
* - `simulatorLatencyTime` {Number} - The time in milliseconds to wait before sending partially full buffers,
* if `simulatorFragmentation` is specified. (Default `16`)
*
* - `simulatorBufferSize` {Number} - The size of a full buffer of data, if `simulatorFragmentation` is
* specified. (Default `4096`)
*
* - `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`)
*
* - `simulatorSerialPortFailure` {Boolean} - Simulates not being able to open a serial connection. Most likely
* due to a OpenBCI dongle not being plugged in.
*
* - `sntpTimeSync` - {Boolean} Syncs the module up with an SNTP time server and uses that as single source
* of truth instead of local computer time. If you are running experiements on your local
* computer, keep this `false`. (Default `false`)
*
* - `sntpTimeSyncHost` - {String} The ntp server to use, can be either sntp or ntp. (Defaults `pool.ntp.org`).
*
* - `sntpTimeSyncPort` - {Number} The port to access the ntp server. (Defaults `123`)
*
* - `verbose` {Boolean} - Print out useful debugging events. (Default `false`)
*
* - `debug` {Boolean} - Print out a raw dump of bytes sent and received. (Default `false`)
*
* @constructor
* @author AJ Keller (@pushtheworldllc)
*/
function OpenBCIBoard (options) {
options = (typeof options !== 'function') && options || {};
var opts = {};
@@ -164,16 +174,7 @@ function OpenBCIFactory () {
this.buffer = null;
this.masterBuffer = masterBufferMaker();
// Objects
this.goertzelObject = openBCISample.goertzelNewObject(k.numberOfChannelsForBoardType(this.options.boardType));
this.impedanceTest = {
active: false,
isTestingPInput: false,
isTestingNInput: false,
onChannel: 0,
sampleNumber: 0,
continuousMode: false,
impedanceForChannel: 0
};
this.impedanceTest = openBCISample.impedanceTestObjDefault();
this.info = {
boardType: this.options.boardType,
sampleRate: k.OBCISampleRate125,
@@ -206,6 +207,7 @@ function OpenBCIFactory () {
this.timeOfPacketArrival = 0;
this.writeOutDelay = k.OBCIWriteIntervalDelayMSShort;
// Strings
this.portName = null;
// NTP
if (this.options.sntpTimeSync) {
@@ -254,6 +256,7 @@ function OpenBCIFactory () {
alpha: this.options.simulatorInjectAlpha,
boardFailure: this.options.simulatorBoardFailure,
daisy: this.options.simulatorDaisyModuleAttached,
daisyCanBeAttached: this.options.simulatorDaisyModuleCanBeAttached,
drift: this.options.simulatorInternalClockDrift,
firmwareVersion: this.options.simulatorFirmwareVersion,
fragmentation: this.options.simulatorFragmentation,
@@ -382,6 +385,14 @@ function OpenBCIFactory () {
* @description Checks if the board is currently sending samples.
* @returns {boolean} - True if streaming.
*/
OpenBCIBoard.prototype.isSimulating = function () {
return this.options.simulate;
};
/**
* @description Checks if the board is currently sending samples.
* @returns {boolean} - True if streaming.
*/
OpenBCIBoard.prototype.isStreaming = function () {
return this._streaming;
};
@@ -1012,6 +1023,103 @@ function OpenBCIFactory () {
});
};
/**
* Get the board type.
* @return boardType: string
*/
OpenBCIBoard.prototype.getBoardType = function () {
return this.info.boardType;
};
/**
* Get the core info object.
* @return {{boardType: string, sampleRate: number, firmware: string, numberOfChannels: number, missedPackets: number}}
*/
OpenBCIBoard.prototype.getInfo = function () {
return this.info;
};
/**
* Set the info property for board type.
* @param boardType {String}
* `default` or `daisy`. Defaults to `default`.
*/
OpenBCIBoard.prototype.overrideInfoForBoardType = function (boardType) {
switch (boardType) {
case k.OBCIBoardDaisy:
this.info.boardType = k.OBCIBoardDaisy;
this.info.numberOfChannels = k.OBCINumberOfChannelsDaisy;
this.info.sampleRate = k.OBCISampleRate125;
this.channelSettingsArray = k.channelSettingsArrayInit(k.OBCINumberOfChannelsDaisy);
this.impedanceArray = openBCISample.impedanceArray(k.OBCINumberOfChannelsDaisy);
break;
case k.OBCIBoardDefault:
default:
this.info.boardType = k.OBCIBoardDefault;
this.info.numberOfChannels = k.OBCINumberOfChannelsDefault;
this.info.sampleRate = k.OBCISampleRate250;
this.channelSettingsArray = k.channelSettingsArrayInit(k.OBCINumberOfChannelsDefault);
this.impedanceArray = openBCISample.impedanceArray(k.OBCINumberOfChannelsDefault);
break;
}
};
/**
* Used to sync the module and board to `boardType`
* @param boardType {String}
* Either `default` or `daisy`
* @return {Promise}
*/
OpenBCIBoard.prototype.hardSetBoardType = function (boardType) {
if (this.isStreaming()) return Promise.reject('Must not be streaming!');
return new Promise((resolve, reject) => {
const eotFunc = (data) => {
switch (data.slice(0, data.length - k.OBCIParseEOT.length).toString()) {
case k.OBCIChannelMaxNumber8SuccessDaisyRemoved:
this.overrideInfoForBoardType(k.OBCIBoardDefault);
resolve('daisy removed');
break;
case k.OBCIChannelMaxNumber16DaisyAlreadyAttached:
this.overrideInfoForBoardType(k.OBCIBoardDaisy);
resolve('daisy already attached');
break;
case k.OBCIChannelMaxNumber16DaisyAttached:
this.overrideInfoForBoardType(k.OBCIBoardDaisy);
resolve('daisy attached');
break;
case k.OBCIChannelMaxNumber16NoDaisyAttached:
this.overrideInfoForBoardType(k.OBCIBoardDefault);
reject('unable to attach daisy');
break;
case k.OBCIChannelMaxNumber8NoDaisyToRemove:
default:
this.overrideInfoForBoardType(k.OBCIBoardDefault);
resolve('no daisy to remove');
break;
}
};
if (boardType === k.OBCIBoardDefault) {
this.curParsingMode = k.OBCIParsingEOT;
this.once(k.OBCIEmitterEot, eotFunc);
this.write(k.OBCIChannelMaxNumber8)
.catch((err) => {
this.removeListener(k.OBCIEmitterEot, eotFunc);
reject(err);
});
} else if (boardType === k.OBCIBoardDaisy) {
this.curParsingMode = k.OBCIParsingEOT;
this.once(k.OBCIEmitterEot, eotFunc);
this.write(k.OBCIChannelMaxNumber16)
.catch((err) => {
this.removeListener(k.OBCIEmitterEot, eotFunc);
reject(err);
});
} else {
reject('invalid board type');
}
});
};
/**
* @description Sends a soft reset command to the board
* @returns {Promise}
@@ -1695,7 +1803,7 @@ function OpenBCIFactory () {
case k.OBCIParsingEOT:
if (openBCISample.doesBufferHaveEOT(data)) {
this.curParsingMode = k.OBCIParsingNormal;
this.emit('eot', data);
this.emit(k.OBCIEmitterEot, data);
this.buffer = openBCISample.stripToEOTBuffer(data);
} else {
this.buffer = data;
@@ -1705,9 +1813,29 @@ function OpenBCIFactory () {
// Does the buffer have an EOT in it?
if (openBCISample.doesBufferHaveEOT(data)) {
this._processParseBufferForReset(data);
this.curParsingMode = k.OBCIParsingNormal;
this.emit('ready');
this.buffer = openBCISample.stripToEOTBuffer(data);
if (this.options.hardSet) {
if (this.getBoardType() !== this.options.boardType) {
this.emit(k.OBCIEmitterHardSet);
this.hardSetBoardType(this.options.boardType)
.then(() => {
this.emit(k.OBCIEmitterReady);
})
.catch((err) => {
this.emit(k.OBCIEmitterError, err);
});
} else {
this.curParsingMode = k.OBCIParsingNormal;
this.emit(k.OBCIEmitterReady);
this.buffer = openBCISample.stripToEOTBuffer(data);
}
} else {
if (this.getBoardType() !== this.options.boardType && this.options.verbose) {
console.log(`Module detected ${this.getBoardType()} board type but you specified ${this.options.boardType}, use 'hardSet' to force the module to correct itself`);
}
this.curParsingMode = k.OBCIParsingNormal;
this.emit(k.OBCIEmitterReady);
this.buffer = openBCISample.stripToEOTBuffer(data);
}
} else {
this.buffer = data;
}
@@ -1807,13 +1935,9 @@ function OpenBCIFactory () {
*/
OpenBCIBoard.prototype._processParseBufferForReset = function (dataBuffer) {
if (openBCISample.countADSPresent(dataBuffer) === 2) {
this.info.boardType = k.OBCIBoardDaisy;
this.info.numberOfChannels = k.OBCINumberOfChannelsDaisy;
this.info.sampleRate = k.OBCISampleRate125;
this.overrideInfoForBoardType(k.OBCIBoardDaisy);
} else {
this.info.boardType = k.OBCIBoardDefault;
this.info.numberOfChannels = k.OBCINumberOfChannelsDefault;
this.info.sampleRate = k.OBCISampleRate250;
this.overrideInfoForBoardType(k.OBCIBoardDefault);
}
if (openBCISample.findV2Firmware(dataBuffer)) {
@@ -1882,13 +2006,13 @@ function OpenBCIFactory () {
if (this.impedanceTest.continuousMode) {
// console.log('running in continuous mode...')
// openBCISample.debugPrettyPrint(sampleObject)
impedanceArray = openBCISample.goertzelProcessSample(sampleObject, this.goertzelObject);
impedanceArray = openBCISample.impedanceCalculateArray(sampleObject, this.impedanceTest);
if (impedanceArray) {
this.emit('impedanceArray', impedanceArray);
}
} else if (this.impedanceTest.onChannel !== 0) {
// Only calculate impedance for one channel
impedanceArray = openBCISample.goertzelProcessSample(sampleObject, this.goertzelObject);
impedanceArray = openBCISample.impedanceCalculateArray(sampleObject, this.impedanceTest);
if (impedanceArray) {
this.impedanceTest.impedanceForChannel = impedanceArray[this.impedanceTest.onChannel - 1];
}
+14
Ver Arquivo
@@ -156,6 +156,11 @@ const obciMiscSoftReset = 'v';
/** 16 Channel Commands */
const obciChannelMaxNumber8 = 'c';
const obciChannelMaxNumber16 = 'C';
const obciChannelMaxNumber8NoDaisyToRemove = '';
const obciChannelMaxNumber8SuccessDaisyRemoved = 'daisy removed';
const obciChannelMaxNumber16DaisyAlreadyAttached = '16';
const obciChannelMaxNumber16DaisyAttached = 'daisy attached16';
const obciChannelMaxNumber16NoDaisyAttached = 'no daisy to attach!8';
/** 60Hz line filter */
const obciFilterDisable = 'g';
@@ -335,7 +340,9 @@ const obciRadioBaudRateFastStr = 'fast';
/** Emitters */
const obciEmitterClose = 'close';
const obciEmitterDroppedPacket = 'droppedPacket';
const obciEmitterEot = 'eot';
const obciEmitterError = 'error';
const obciEmitterHardSet = 'hardSet';
const obciEmitterImpedanceArray = 'impedanceArray';
const obciEmitterQuery = 'query';
const obciEmitterRawDataPacket = 'rawDataPacket';
@@ -724,6 +731,11 @@ module.exports = {
/** 16 Channel Commands */
OBCIChannelMaxNumber8: obciChannelMaxNumber8,
OBCIChannelMaxNumber16: obciChannelMaxNumber16,
OBCIChannelMaxNumber8NoDaisyToRemove: obciChannelMaxNumber8NoDaisyToRemove,
OBCIChannelMaxNumber8SuccessDaisyRemoved: obciChannelMaxNumber8SuccessDaisyRemoved,
OBCIChannelMaxNumber16DaisyAlreadyAttached: obciChannelMaxNumber16DaisyAlreadyAttached,
OBCIChannelMaxNumber16DaisyAttached: obciChannelMaxNumber16DaisyAttached,
OBCIChannelMaxNumber16NoDaisyAttached: obciChannelMaxNumber16NoDaisyAttached,
/** Filters */
OBCIFilterDisable: obciFilterDisable,
OBCIFilterEnable: obciFilterEnable,
@@ -894,7 +906,9 @@ module.exports = {
/** Emitters */
OBCIEmitterClose: obciEmitterClose,
OBCIEmitterDroppedPacket: obciEmitterDroppedPacket,
OBCIEmitterEot: obciEmitterEot,
OBCIEmitterError: obciEmitterError,
OBCIEmitterHardSet: obciEmitterHardSet,
OBCIEmitterImpedanceArray: obciEmitterImpedanceArray,
OBCIEmitterQuery: obciEmitterQuery,
OBCIEmitterRawDataPacket: obciEmitterRawDataPacket,
+42 -123
Ver Arquivo
@@ -13,14 +13,6 @@ const SCALE_FACTOR_ACCEL = 0.002 / Math.pow(2, 4);
const ACCEL_NUMBER_AXIS = 3;
// Default ADS1299 gains array
// For computing Goertzel Algorithm
// See: http://www.embedded.com/design/configurable-systems/4024443/The-Goertzel-Algorithm
// In the tutorial cited above, GOERTZEL_BLOCK_SIZE is referred to as N
const GOERTZEL_BLOCK_SIZE = 62;
const GOERTZEL_K_250 = Math.floor(0.5 + ((GOERTZEL_BLOCK_SIZE * k.OBCILeadOffFrequencyHz) / k.OBCISampleRate250));
const GOERTZEL_W_250 = ((2 * Math.PI) / GOERTZEL_BLOCK_SIZE) * GOERTZEL_K_250;
const GOERTZEL_COEFF_250 = 2 * Math.cos(GOERTZEL_W_250);
var sampleModule = {
/**
@@ -211,59 +203,6 @@ var sampleModule = {
},
floatTo3ByteBuffer,
floatTo2ByteBuffer,
/**
* @description Calculate the impedance for one channel only.
* @param sampleObject - Standard OpenBCI sample object
* @param channelNumber - Number, the channel you want to calculate impedance for.
* @returns {Promise} - Fulfilled with impedance value for the specified channel.
* @author AJ Keller
*/
impedanceCalculationForChannel: (sampleObject, channelNumber) => {
const sqrt2 = Math.sqrt(2);
return new Promise((resolve, reject) => {
if (sampleObject === undefined || sampleObject === null) reject('Sample Object cannot be null or undefined');
if (sampleObject.channelData === undefined || sampleObject.channelData === null) reject('Channel cannot be null or undefined');
if (channelNumber < 1 || channelNumber > k.OBCINumberOfChannelsDefault) reject('Channel number invalid.');
var index = channelNumber - 1;
if (sampleObject.channelData[index] < 0) {
sampleObject.channelData[index] *= -1;
}
var impedance = (sqrt2 * sampleObject.channelData[index]) / k.OBCILeadOffDriveInAmps;
// if (index === 0) console.log("Voltage: " + (sqrt2*sampleObject.channelData[index]) + " leadoff amps: " + k.OBCILeadOffDriveInAmps + " impedance: " + impedance)
resolve(impedance);
});
},
/**
* @description Calculate the impedance for all channels.
* @param sampleObject - Standard OpenBCI sample object
* @returns {Promise} - Fulfilled with impedances for the sample
* @author AJ Keller
*/
impedanceCalculationForAllChannels: sampleObject => {
const sqrt2 = Math.sqrt(2);
return new Promise((resolve, reject) => {
if (sampleObject === undefined || sampleObject === null) reject('Sample Object cannot be null or undefined');
if (sampleObject.channelData === undefined || sampleObject.channelData === null) reject('Channel cannot be null or undefined');
var sampleImpedances = [];
var numChannels = sampleObject.channelData.length;
for (var index = 0; index < numChannels; index++) {
if (sampleObject.channelData[index] < 0) {
sampleObject.channelData[index] *= -1;
}
var impedance = (sqrt2 * sampleObject.channelData[index]) / k.OBCILeadOffDriveInAmps;
sampleImpedances.push(impedance);
// if (index === 0) console.log("Voltage: " + (sqrt2*sampleObject.channelData[index]) + " leadoff amps: " + k.OBCILeadOffDriveInAmps + " impedance: " + impedance)
}
sampleObject.impedances = sampleImpedances;
resolve(sampleObject);
});
},
interpret16bitAsInt32: twoByteBuffer => {
var prefix = 0;
@@ -418,73 +357,53 @@ var sampleModule = {
scaleFactorAux: SCALE_FACTOR_ACCEL,
k,
/**
* @description Use the Goertzel algorithm to calculate impedances
* @param sample - a sample with channelData Array
* @param goertzelObj - An object that was created by a call to this.goertzelNewObject()
* @returns {Array} - Returns an array if finished computing
*/
goertzelProcessSample: (sample, goertzelObj) => {
// calculate the goertzel values for all channels
for (var i = 0; i < goertzelObj.numberOfChannels; i++) {
var q0 = GOERTZEL_COEFF_250 * goertzelObj.q1[i] - goertzelObj.q2[i] + sample.channelData[i];
goertzelObj.q2[i] = goertzelObj.q1[i];
goertzelObj.q1[i] = q0;
* Calculate the impedance
* @param sample {Object} - Standard sample
* @param impedanceTest {Object} - Impedance Object from openBCIBoard.js
* @return {null | Object} - Null if not enough samples have passed to calculate an accurate
*/
impedanceCalculateArray: (sample, impedanceTest) => {
impedanceTest.buffer.push(sample.channelData);
impedanceTest.count++;
// console.log('Q1: ' + goertzelObj.q1[i] + ' Q2: ' + goertzelObj.q2[i])
}
if (impedanceTest.count >= impedanceTest.window) {
let output = [];
for (let i = 0; i < sample.channelData.length; i++) {
let max = 0.0; // sumSquared
for (let j = 0; j < impedanceTest.window; j++) {
if (impedanceTest.buffer[i][j] > max) {
max = impedanceTest.buffer[i][j];
}
}
let min = 0.0;
for (let j = 0; j < impedanceTest.window; j++) {
if (impedanceTest.buffer[i][j] < min) {
min = impedanceTest.buffer[i][j];
}
}
const vP2P = max - min; // peak to peak
// Increment the index counter
goertzelObj.index++;
// Have we iterated more times then block size?
if (goertzelObj.index > GOERTZEL_BLOCK_SIZE) {
var impedanceArray = [];
for (var j = 0; j < goertzelObj.numberOfChannels; j++) {
// Calculate the magnitude of the voltage
// var q1SQRD = goertzelObj.q1[j] * goertzelObj.q1[j];
// var q2SQRD = goertzelObj.q2[j] * goertzelObj.q2[j];
// var lastPart = goertzelObj.q1[j] * goertzelObj.q2[j] * GOERTZEL_COEFF_250;
// console.log('Chan ' + j + ', Q1^2: ' + q1SQRD + ', Q2^2: ' + q2SQRD + ', Last Part: ' + lastPart)
var voltage = Math.sqrt((goertzelObj.q1[j] * goertzelObj.q1[j]) + (goertzelObj.q2[j] * goertzelObj.q2[j]) - goertzelObj.q1[j] * goertzelObj.q2[j] * GOERTZEL_COEFF_250);
// Calculate the impedance r = v/i
var impedance = voltage / k.OBCILeadOffDriveInAmps;
// Push the impedance into the final array
impedanceArray.push(impedance);
// Reset the goertzel variables to get ready for the next iteration
goertzelObj.q1[j] = 0;
goertzelObj.q2[j] = 0;
output.push(vP2P / 2 / k.OBCILeadOffDriveInAmps);
}
// Reset the goertzel index counter
goertzelObj.index = 0;
// Pass out the impedance array
return impedanceArray;
} else {
// This reject is really just for debugging
return;
impedanceTest.count = 0;
return output;
}
return null;
},
goertzelNewObject: numberOfChannels => {
// Object to help calculate the goertzel
var q1 = [];
var q2 = [];
for (var i = 0; i < numberOfChannels; i++) {
q1.push(0);
q2.push(0);
}
return {
q1: q1,
q2: q2,
index: 0,
numberOfChannels: numberOfChannels
};
impedanceTestObjDefault: (impedanceTestObj) => {
let newObj = impedanceTestObj || {};
newObj['active'] = false;
newObj['buffer'] = [];
newObj['count'] = 0;
newObj['isTestingPInput'] = false;
newObj['isTestingNInput'] = false;
newObj['onChannel'] = 0;
newObj['sampleNumber'] = 0;
newObj['continuousMode'] = false;
newObj['impedanceForChannel'] = 0;
newObj['window'] = 40;
return newObj;
},
GOERTZEL_BLOCK_SIZE,
samplePacket: sampleNumber => {
return new Buffer([0xA0, sampleNumberNormalize(sampleNumber), 0, 0, 1, 0, 0, 2, 0, 0, 3, 0, 0, 4, 0, 0, 5, 0, 0, 6, 0, 0, 7, 0, 0, 8, 0, 0, 0, 1, 0, 2, makeTailByteFromPacketType(k.OBCIStreamPacketStandardAccel)]);
},
@@ -1119,7 +1038,7 @@ function isSuccessInBuffer (dataBuffer) {
*/
function stripToEOTBuffer (dataBuffer) {
let indexOfEOT = dataBuffer.indexOf(k.OBCIParseEOT);
if (indexOfEOT > 0) {
if (indexOfEOT >= 0) {
indexOfEOT += k.OBCIParseEOT.length;
} else {
return dataBuffer;
+25
Ver Arquivo
@@ -15,6 +15,7 @@ function OpenBCISimulatorFactory () {
alpha: true,
boardFailure: false,
daisy: false,
daisyCanBeAttached: true,
drift: 0,
firmwareVersion: [k.OBCIFirmwareV1, k.OBCIFirmwareV2],
fragmentation: [k.OBCISimulatorFragmentationNone, k.OBCISimulatorFragmentationRandom, k.OBCISimulatorFragmentationFullBuffers, k.OBCISimulatorFragmentationOneByOne],
@@ -252,6 +253,30 @@ function OpenBCISimulatorFactory () {
}, 10);
}
break;
case k.OBCIChannelMaxNumber8:
if (this.options.daisy) {
this.options.daisy = false;
this._output(new Buffer(k.OBCIChannelMaxNumber8SuccessDaisyRemoved));
this._printEOT();
} else {
this._printEOT();
}
break;
case k.OBCIChannelMaxNumber16:
if (this.options.daisy) {
this._output(new Buffer(k.OBCIChannelMaxNumber16DaisyAlreadyAttached));
this._printEOT();
} else {
if (this.options.daisyCanBeAttached) {
this.options.daisy = true;
this._output(new Buffer(k.OBCIChannelMaxNumber16DaisyAttached));
this._printEOT();
} else {
this._output(new Buffer(k.OBCIChannelMaxNumber16NoDaisyAttached));
this._printEOT();
}
}
break;
default:
break;
}
+11 -9
Ver Arquivo
@@ -1,9 +1,10 @@
{
"name": "openbci",
"version": "1.4.2",
"version": "1.5.2",
"description": "The official Node.js SDK for the OpenBCI Biosensor Board.",
"main": "openBCIBoard",
"scripts": {
"lint": "semistandard | snazzy",
"start": "node index",
"test": "semistandard | snazzy && mocha test",
"test-cov": "istanbul cover ./node_modules/mocha/bin/_mocha -- -R spec && codecov"
@@ -18,8 +19,8 @@
"buffer-equal": "^1.0.0",
"gaussian": "^1.0.0",
"mathjs": "^3.3.0",
"performance-now": "^0.2.0",
"serialport": "4.0.1",
"performance-now": "^2.1.0",
"serialport": "4.0.7",
"sntp": "^2.0.0",
"streamsearch": "^0.1.2"
},
@@ -27,17 +28,18 @@
"test": "test"
},
"devDependencies": {
"bluebird": "3.4.6",
"bluebird": "3.5.0",
"chai": "^3.4.1",
"chai-as-promised": "^5.2.0",
"codecov": "^1.0.1",
"chai-as-promised": "^6.0.0",
"codecov": "^2.1.0",
"istanbul": "^0.4.4",
"mocha": "^3.0.2",
"sandboxed-module": "^2.0.3",
"semistandard": "^9.0.0",
"sinon": "^1.17.2",
"semistandard": "^10.0.0",
"sinon": "^2.1.0",
"sinon-as-promised": "^4.0.2",
"sinon-chai": "^2.8.0",
"snazzy": "^5.0.0"
"snazzy": "^6.0.0"
},
"repository": {
"type": "git",
+13
Ver Arquivo
@@ -443,6 +443,13 @@ describe('OpenBCIConstants', function () {
it('sets max of 16', function () {
assert.equal('C', k.OBCIChannelMaxNumber16);
});
it('has correct return messages', function () {
assert.equal('', k.OBCIChannelMaxNumber8NoDaisyToRemove);
assert.equal('daisy removed', k.OBCIChannelMaxNumber8SuccessDaisyRemoved);
assert.equal('16', k.OBCIChannelMaxNumber16DaisyAlreadyAttached);
assert.equal('daisy attached16', k.OBCIChannelMaxNumber16DaisyAttached);
assert.equal('no daisy to attach!8', k.OBCIChannelMaxNumber16NoDaisyAttached);
});
});
describe('On board filters', function () {
it('disable', function () {
@@ -1440,9 +1447,15 @@ describe('OpenBCIConstants', function () {
it('Event Emitter Dropped Packet', function () {
assert.equal('droppedPacket', k.OBCIEmitterDroppedPacket);
});
it('Event Emitter EOT', function () {
assert.equal('eot', k.OBCIEmitterEot);
});
it('Event Emitter Error', function () {
assert.equal('error', k.OBCIEmitterError);
});
it('Event Emitter Hard Set', function () {
assert.equal('hardSet', k.OBCIEmitterHardSet);
});
it('Event Emitter Impedance Array', function () {
assert.equal('impedanceArray', k.OBCIEmitterImpedanceArray);
});
+48 -37
Ver Arquivo
@@ -708,19 +708,6 @@ describe('openBCISample', function () {
assert(passed, 'a sample with accel data was produced');
});
});
describe('#impedanceCalculationForChannel', function () {
it('rejects when undefined sampleObject', function (done) {
var bad;
openBCISample.impedanceCalculationForChannel(bad, 1).should.be.rejected.and.notify(done);
});
it('rejects when undefined channel number', function (done) {
var bad;
openBCISample.impedanceCalculationForChannel('taco', bad).should.be.rejected.and.notify(done);
});
it('rejects when invalid channel number', function (done) {
openBCISample.impedanceCalculationForChannel('taco', 69).should.be.rejected.and.notify(done);
});
});
describe('#impedanceSummarize', function () {
var impedanceArray = [];
var numberOfChannels = 8;
@@ -1221,6 +1208,21 @@ $$$`);
}
expect(openBCISample.stripToEOTBuffer(buf).toString()).to.equal(buf.toString());
});
it('should slice the buffer after just eot $$$', function () {
let eotBuf = null;
let bufPost = null;
if (k.getVersionNumber(process.version) >= 6) {
// From introduced in node version 6.x.x
eotBuf = Buffer.from(k.OBCIParseEOT);
bufPost = Buffer.from('tacos');
} else {
eotBuf = new Buffer(k.OBCIParseEOT);
bufPost = new Buffer('tacos');
}
let totalBuf = Buffer.concat([eotBuf, bufPost]);
expect(openBCISample.stripToEOTBuffer(totalBuf).toString()).to.equal(bufPost.toString());
});
it('should slice the buffer after eot $$$', function () {
let bufPre = null;
let eotBuf = null;
@@ -1255,34 +1257,43 @@ $$$`);
expect(openBCISample.stripToEOTBuffer(totalBuf)).to.equal(null);
});
});
});
describe('#impedanceTestObjDefault', function () {
it('should give a new impedance object', function () {
const expectedImpedanceObj = {
active: false,
buffer: [],
count: 0,
isTestingPInput: false,
isTestingNInput: false,
onChannel: 0,
sampleNumber: 0,
continuousMode: false,
impedanceForChannel: 0,
window: 40
};
expect(openBCISample.impedanceTestObjDefault()).to.deep.equal(expectedImpedanceObj);
});
});
describe('#impedanceCalculateArray', function () {
const numberOfChannels = k.OBCINumberOfChannelsDefault;
const newRandomSample = openBCISample.randomSample(numberOfChannels, k.OBCISampleRate250, false, 'none');
describe('#goertzelProcessSample', function () {
var numberOfChannels = k.OBCINumberOfChannelsDefault;
var goertzelObj = openBCISample.goertzelNewObject(numberOfChannels);
var newRandomSample = openBCISample.randomSample(numberOfChannels, k.OBCISampleRate250);
afterEach(() => bluebirdChecks.noPendingPromises());
afterEach(() => bluebirdChecks.noPendingPromises());
it('produces an array of impedances', function (done) {
var passed = false;
for (var i = 0; i < openBCISample.GOERTZEL_BLOCK_SIZE + 1; i++) {
// console.log('Iteration ' + i)
var impedanceArray = openBCISample.goertzelProcessSample(newRandomSample(i), goertzelObj);
if (impedanceArray) {
// console.log('Impedance Array: ')
for (var j = 0; j < numberOfChannels; j++) {
console.log('Channel ' + (j + 1) + ': ' + impedanceArray[j].toFixed(8));
}
passed = true;
it('should not produce an array of impedances till window', function () {
const impTestObj = openBCISample.impedanceTestObjDefault();
for (let i = 0; i < impTestObj.window - 1; i++) {
expect(openBCISample.impedanceCalculateArray(newRandomSample(i), impTestObj)).to.equal(null);
}
}
setTimeout(() => {
if (passed) {
done();
} else {
done('Failed to produce impedance array within block size + 1');
expect(impTestObj.buffer.length).to.equal(impTestObj.window - 1);
});
it('should produce and array of impedances at window', function () {
const impTestObj = openBCISample.impedanceTestObjDefault();
let impedanceArray = null;
for (let i = 0; i < impTestObj.window; i++) {
impedanceArray = openBCISample.impedanceCalculateArray(newRandomSample(i), impTestObj);
}
expect(impedanceArray.length).to.equal(numberOfChannels);
});
});
});
+949
Ver Arquivo
@@ -0,0 +1,949 @@
'use strict';
var bluebirdChecks = require('./bluebirdChecks');
var sinon = require('sinon'); // eslint-disable-line no-unused-vars
var chai = require('chai');
var expect = chai.expect;
var should = chai.should(); // eslint-disable-line no-unused-vars
var openBCIBoard = require('../openBCIBoard');
var openBCISample = openBCIBoard.OpenBCISample;
var k = openBCISample.k;
var chaiAsPromised = require('chai-as-promised');
var sinonChai = require('sinon-chai');
chai.use(chaiAsPromised);
chai.use(sinonChai);
describe('openbci-radios', function () {
this.timeout(2000);
var ourBoard, masterPortName;
before(function (done) {
ourBoard = new openBCIBoard.OpenBCIBoard();
ourBoard.autoFindOpenBCIBoard()
.then(portName => {
ourBoard = null;
masterPortName = portName;
done();
})
.catch(() => {
ourBoard = null;
masterPortName = k.OBCISimulatorPortName;
done();
});
});
after(done => {
if (ourBoard) {
if (ourBoard['connected']) {
ourBoard.disconnect()
.then(() => {
done();
})
.catch(err => {
done(err);
});
} else {
done();
}
} else {
done();
}
});
describe('#radioChannelSet', function () {
afterEach(function (done) {
if (ourBoard.isConnected()) {
ourBoard.disconnect().then(() => {
done();
}).catch(() => done);
} else {
done();
}
});
afterEach(() => bluebirdChecks.noPendingPromises());
it('should not change the channel number if not connected', function (done) {
ourBoard = new openBCIBoard.OpenBCIBoard({
verbose: true,
simulate: true,
simulatorFirmwareVersion: 'v2'
});
ourBoard.radioChannelGet().should.be.rejected.and.notify(done);
});
it('should reject if streaming', function (done) {
ourBoard = new openBCIBoard.OpenBCIBoard({
verbose: true,
simulate: true,
simulatorFirmwareVersion: 'v2'
});
ourBoard.connect(k.OBCISimulatorPortName)
.then(() => {
ourBoard.once('ready', () => {
ourBoard.streamStart()
.then(() => {
ourBoard.radioChannelSet(1).then(() => {
done('should have rejected');
}).catch(() => {
done(); // Test pass
});
}).catch(err => done(err));
});
}).catch(err => done(err));
});
it('should reject if not firmware version 2', function (done) {
ourBoard = new openBCIBoard.OpenBCIBoard({
verbose: true,
simulate: true
});
ourBoard.connect(k.OBCISimulatorPortName)
.then(() => {
ourBoard.once('ready', () => {
ourBoard.radioChannelSet(1).should.be.rejected.and.notify(done);
});
}).catch(err => done(err));
});
it('should reject if a number is not sent as input', function (done) {
ourBoard = new openBCIBoard.OpenBCIBoard({
verbose: true,
simulate: true,
simulatorFirmwareVersion: 'v2'
});
ourBoard.connect(k.OBCISimulatorPortName)
.then(() => {
ourBoard.once('ready', () => {
ourBoard.radioChannelSet('1').should.be.rejected.and.notify(done);
});
}).catch(err => done(err));
});
it('should reject if no channel number is presented as arg', function (done) {
ourBoard = new openBCIBoard.OpenBCIBoard({
verbose: true,
simulate: true,
simulatorFirmwareVersion: 'v2'
});
ourBoard.connect(k.OBCISimulatorPortName)
.then(() => {
ourBoard.once('ready', () => {
ourBoard.radioChannelSet().should.be.rejected.and.notify(done);
});
}).catch(err => done(err));
});
it('should reject if the requested new channel number is lower than 0', function (done) {
ourBoard = new openBCIBoard.OpenBCIBoard({
verbose: true,
simulate: true,
simulatorFirmwareVersion: 'v2'
});
ourBoard.connect(k.OBCISimulatorPortName)
.then(() => {
ourBoard.once('ready', () => {
ourBoard.radioChannelSet(-1).should.be.rejected.and.notify(done);
});
}).catch(err => done(err));
});
it('should reject if the requested new channel number is higher than 25', function (done) {
ourBoard = new openBCIBoard.OpenBCIBoard({
verbose: true,
simulate: true,
simulatorFirmwareVersion: 'v2'
});
ourBoard.connect(k.OBCISimulatorPortName)
.then(() => {
ourBoard.once('ready', () => {
ourBoard.radioChannelSet(26).should.be.rejected.and.notify(done);
});
}).catch(err => done(err));
});
it('should not change the channel if the board is not communicating with the host', function (done) {
ourBoard = new openBCIBoard.OpenBCIBoard({
verbose: true,
simulate: true,
simulatorBoardFailure: true,
simulatorFirmwareVersion: 'v2'
});
ourBoard.connect(k.OBCISimulatorPortName)
.then(() => {
ourBoard.once('ready', () => {
ourBoard.radioChannelSet(1).should.be.rejected.and.notify(done);
});
}).catch(err => done(err));
});
it('should change the channel if connected, not steaming, and using firmware version 2+', function (done) {
var newChannelNumber = 2;
ourBoard = new openBCIBoard.OpenBCIBoard({
verbose: true,
simulate: true,
simulatorFirmwareVersion: 'v2'
});
ourBoard.connect(k.OBCISimulatorPortName)
.then(() => {
ourBoard.once('ready', () => {
ourBoard.radioChannelSet(newChannelNumber).then(channelNumber => {
expect(channelNumber).to.be.equal(newChannelNumber);
done();
}).catch(err => done(err));
});
}).catch(err => done(err));
});
});
describe('#radioChannelSetHostOverride', function () {
afterEach(function (done) {
if (ourBoard.isConnected()) {
ourBoard.disconnect().then(() => {
done();
}).catch(() => done);
} else {
done();
}
});
afterEach(() => bluebirdChecks.noPendingPromises());
it('should not change the channel number if not connected', function (done) {
ourBoard = new openBCIBoard.OpenBCIBoard({
verbose: true,
simulate: true,
simulatorFirmwareVersion: 'v2'
});
ourBoard.radioChannelSetHostOverride().should.be.rejected.and.notify(done);
});
it('should reject if streaming', function (done) {
ourBoard = new openBCIBoard.OpenBCIBoard({
verbose: true,
simulate: true,
simulatorFirmwareVersion: 'v2'
});
ourBoard.connect(k.OBCISimulatorPortName)
.then(() => {
ourBoard.once('ready', () => {
ourBoard.streamStart()
.then(() => {
ourBoard.radioChannelSetHostOverride(1).then(() => {
done('should have rejected');
}).catch(() => {
done(); // Test pass
});
}).catch(err => done(err));
});
}).catch(err => done(err));
});
it('should reject if a number is not sent as input', function (done) {
ourBoard = new openBCIBoard.OpenBCIBoard({
verbose: true,
simulate: true,
simulatorFirmwareVersion: 'v2'
});
ourBoard.connect(k.OBCISimulatorPortName)
.then(() => {
ourBoard.once('ready', () => {
ourBoard.radioChannelSetHostOverride('1').should.be.rejected.and.notify(done);
});
}).catch(err => done(err));
});
it('should reject if no channel number is presented as arg', function (done) {
ourBoard = new openBCIBoard.OpenBCIBoard({
verbose: true,
simulate: true,
simulatorFirmwareVersion: 'v2'
});
ourBoard.connect(k.OBCISimulatorPortName)
.then(() => {
ourBoard.once('ready', () => {
ourBoard.radioChannelSetHostOverride().should.be.rejected.and.notify(done);
});
}).catch(err => done(err));
});
it('should reject if the requested new channel number is lower than 0', function (done) {
ourBoard = new openBCIBoard.OpenBCIBoard({
verbose: true,
simulate: true,
simulatorFirmwareVersion: 'v2'
});
ourBoard.connect(k.OBCISimulatorPortName)
.then(() => {
ourBoard.once('ready', () => {
ourBoard.radioChannelSetHostOverride(-1).should.be.rejected.and.notify(done);
});
}).catch(err => done(err));
});
it('should reject if the requested new channel number is higher than 25', function (done) {
ourBoard = new openBCIBoard.OpenBCIBoard({
verbose: true,
simulate: true,
simulatorFirmwareVersion: 'v2'
});
ourBoard.connect(k.OBCISimulatorPortName)
.then(() => {
ourBoard.once('ready', () => {
ourBoard.radioChannelSetHostOverride(26).should.be.rejected.and.notify(done);
});
}).catch(err => done(err));
});
it('should change the channel if connected, not steaming, and using firmware version 2+', function (done) {
var newChannelNumber = 2;
ourBoard = new openBCIBoard.OpenBCIBoard({
verbose: true,
simulate: true,
simulatorFirmwareVersion: 'v2'
});
ourBoard.connect(k.OBCISimulatorPortName)
.then(() => {
ourBoard.once('ready', () => {
ourBoard.radioChannelSetHostOverride(newChannelNumber).then(channelNumber => {
expect(channelNumber).to.be.equal(newChannelNumber);
done();
}).catch(err => done(err));
});
}).catch(err => done(err));
});
});
describe('#radioChannelGet', function () {
afterEach(function (done) {
if (ourBoard.isConnected()) {
ourBoard.disconnect().then(() => {
done();
}).catch(() => done);
} else {
done();
}
});
afterEach(() => bluebirdChecks.noPendingPromises());
it('should not query if not connected', function (done) {
ourBoard = new openBCIBoard.OpenBCIBoard({
verbose: true,
simulate: true
});
ourBoard.radioChannelGet().should.be.rejected.and.notify(done);
});
it('should not query if streaming', function (done) {
ourBoard = new openBCIBoard.OpenBCIBoard({
verbose: true,
simulate: true
});
ourBoard.connect(k.OBCISimulatorPortName)
.then(() => {
ourBoard.once('ready', () => {
ourBoard.streamStart()
.then(() => {
ourBoard.radioChannelGet().then(() => {
done('should have rejected');
}).catch(() => {
done(); // Test pass
});
}).catch(err => done(err));
});
}).catch(err => done(err));
});
it('should not query if not firmware version 2', function (done) {
ourBoard = new openBCIBoard.OpenBCIBoard({
verbose: true,
simulate: true
});
ourBoard.connect(k.OBCISimulatorPortName)
.then(() => {
ourBoard.once('ready', () => {
ourBoard.radioChannelGet().should.be.rejected.and.notify(done);
});
}).catch(err => done(err));
});
it('should query if firmware version 2', function (done) {
ourBoard = new openBCIBoard.OpenBCIBoard({
verbose: true,
simulate: true,
simulatorFirmwareVersion: 'v2'
});
ourBoard.connect(k.OBCISimulatorPortName)
.then(() => {
ourBoard.once('ready', () => {
ourBoard.radioChannelGet().then(res => {
expect(res.channelNumber).to.be.within(k.OBCIRadioChannelMin, k.OBCIRadioChannelMax);
done();
}).catch(err => done(err));
});
}).catch(err => done(err));
});
it('should get message even if the board is not communicating with dongle', function (done) {
ourBoard = new openBCIBoard.OpenBCIBoard({
verbose: true,
simulate: true,
simulatorBoardFailure: true,
simulatorFirmwareVersion: 'v2'
});
ourBoard.connect(k.OBCISimulatorPortName)
.then(() => {
ourBoard.once('ready', () => {
ourBoard.radioChannelGet().should.be.rejected.and.notify(done);
});
}).catch(err => done(err));
});
});
describe('#radioPollTimeSet', function () {
afterEach(function (done) {
if (ourBoard.isConnected()) {
ourBoard.disconnect().then(() => {
done();
}).catch(() => done);
} else {
done();
}
});
afterEach(() => bluebirdChecks.noPendingPromises());
it('should not change the channel number if not connected', function (done) {
ourBoard = new openBCIBoard.OpenBCIBoard({
verbose: true,
simulate: true,
simulatorFirmwareVersion: 'v2'
});
ourBoard.radioPollTimeSet().should.be.rejected.and.notify(done);
});
it('should reject if streaming', function (done) {
ourBoard = new openBCIBoard.OpenBCIBoard({
verbose: true,
simulate: true,
simulatorFirmwareVersion: 'v2'
});
ourBoard.connect(k.OBCISimulatorPortName)
.then(() => {
ourBoard.once('ready', () => {
ourBoard.streamStart()
.then(() => {
ourBoard.radioPollTimeSet(1).then(() => {
done('should have rejected');
}).catch(() => {
done(); // Test pass
});
}).catch(err => done(err));
});
}).catch(err => done(err));
});
it('should reject if not firmware version 2', function (done) {
ourBoard = new openBCIBoard.OpenBCIBoard({
verbose: true,
simulate: true
});
ourBoard.connect(k.OBCISimulatorPortName)
.then(() => {
ourBoard.once('ready', () => {
ourBoard.radioPollTimeSet(1).should.be.rejected.and.notify(done);
});
}).catch(err => done(err));
});
it('should reject if a number is not sent as input', function (done) {
ourBoard = new openBCIBoard.OpenBCIBoard({
verbose: true,
simulate: true,
simulatorFirmwareVersion: 'v2'
});
ourBoard.connect(k.OBCISimulatorPortName)
.then(() => {
ourBoard.once('ready', () => {
ourBoard.radioPollTimeSet('1').should.be.rejected.and.notify(done);
});
}).catch(err => done(err));
});
it('should reject if no poll time is presented as arg', function (done) {
ourBoard = new openBCIBoard.OpenBCIBoard({
verbose: true,
simulate: true,
simulatorFirmwareVersion: 'v2'
});
ourBoard.connect(k.OBCISimulatorPortName)
.then(() => {
ourBoard.once('ready', () => {
ourBoard.radioPollTimeSet().should.be.rejected.and.notify(done);
});
}).catch(err => done(err));
});
it('should reject if the requested new poll time is lower than 0', function (done) {
ourBoard = new openBCIBoard.OpenBCIBoard({
verbose: true,
simulate: true,
simulatorFirmwareVersion: 'v2'
});
ourBoard.connect(k.OBCISimulatorPortName)
.then(() => {
ourBoard.once('ready', () => {
ourBoard.radioPollTimeSet(-1).should.be.rejected.and.notify(done);
});
}).catch(err => done(err));
});
it('should reject if the requested new poll time is higher than 255', function (done) {
ourBoard = new openBCIBoard.OpenBCIBoard({
verbose: true,
simulate: true,
simulatorFirmwareVersion: 'v2'
});
ourBoard.connect(k.OBCISimulatorPortName)
.then(() => {
ourBoard.once('ready', () => {
ourBoard.radioPollTimeSet(256).should.be.rejected.and.notify(done);
});
}).catch(err => done(err));
});
it('should not change the poll time if the board is not communicating with the host', function (done) {
ourBoard = new openBCIBoard.OpenBCIBoard({
verbose: true,
simulate: true,
simulatorBoardFailure: true,
simulatorFirmwareVersion: 'v2'
});
ourBoard.connect(k.OBCISimulatorPortName)
.then(() => {
ourBoard.once('ready', () => {
ourBoard.radioPollTimeSet(1).should.be.rejected.and.notify(done);
});
}).catch(err => done(err));
});
it('should change the poll time if connected, not steaming, and using firmware version 2+', function (done) {
var newPollTime = 69;
ourBoard = new openBCIBoard.OpenBCIBoard({
verbose: true,
simulate: true,
simulatorFirmwareVersion: 'v2'
});
ourBoard.connect(k.OBCISimulatorPortName)
.then(() => {
ourBoard.once('ready', () => {
ourBoard.radioPollTimeSet(newPollTime).then(() => {
done();
}).catch(err => {
done(err);
});
});
}).catch(err => done(err));
});
});
describe('#radioPollTimeGet', function () {
afterEach(function (done) {
if (ourBoard.isConnected()) {
ourBoard.disconnect().then(() => {
done();
}).catch(() => done);
} else {
done();
}
});
afterEach(() => bluebirdChecks.noPendingPromises());
it('should not query if not connected', function (done) {
ourBoard = new openBCIBoard.OpenBCIBoard({
verbose: true,
simulate: true
});
ourBoard.radioPollTimeGet().should.be.rejected.and.notify(done);
});
it('should not query if streaming', function (done) {
ourBoard = new openBCIBoard.OpenBCIBoard({
verbose: true,
simulate: true
});
ourBoard.connect(k.OBCISimulatorPortName)
.then(() => {
ourBoard.once('ready', () => {
ourBoard.streamStart()
.then(() => {
ourBoard.radioPollTimeGet().then(() => {
done('should have rejected');
}).catch(() => {
done(); // Test pass
});
}).catch(err => done(err));
});
}).catch(err => done(err));
});
it('should not query if not firmware version 2', function (done) {
ourBoard = new openBCIBoard.OpenBCIBoard({
verbose: true,
simulate: true
});
ourBoard.connect(k.OBCISimulatorPortName)
.then(() => {
ourBoard.once('ready', () => {
ourBoard.radioPollTimeGet().should.be.rejected.and.notify(done);
});
}).catch(err => done(err));
});
it('should query if firmware version 2', function (done) {
ourBoard = new openBCIBoard.OpenBCIBoard({
verbose: true,
simulate: true,
simulatorFirmwareVersion: 'v2'
});
ourBoard.connect(k.OBCISimulatorPortName)
.then(() => {
ourBoard.once('ready', () => {
ourBoard.radioPollTimeGet().then(pollTime => {
expect(pollTime).to.be.greaterThan(0);
done();
}).catch(err => done(err));
});
}).catch(err => done(err));
});
it('should get failure message if the board is not communicating with dongle', function (done) {
ourBoard = new openBCIBoard.OpenBCIBoard({
verbose: true,
simulate: true,
simulatorBoardFailure: true,
simulatorFirmwareVersion: 'v2'
});
ourBoard.connect(k.OBCISimulatorPortName)
.then(() => {
ourBoard.once('ready', () => {
ourBoard.radioPollTimeGet().should.be.rejected.and.notify(done);
});
}).catch(err => done(err));
});
});
describe('#radioBaudRateSet', function () {
afterEach(function (done) {
if (ourBoard.isConnected()) {
ourBoard.disconnect().then(() => {
done();
}).catch(() => done);
} else {
done();
}
});
afterEach(() => bluebirdChecks.noPendingPromises());
it('should not try to set baud rate if not connected', function (done) {
ourBoard = new openBCIBoard.OpenBCIBoard({
verbose: true,
simulate: true
});
ourBoard.radioBaudRateSet('default').should.be.rejected.and.notify(done);
});
it('should reject if no input', function (done) {
ourBoard = new openBCIBoard.OpenBCIBoard({
verbose: true,
simulate: true
});
ourBoard.radioBaudRateSet().should.be.rejected.and.notify(done);
});
it('should be rejected if input type incorrect', function (done) {
ourBoard = new openBCIBoard.OpenBCIBoard({
verbose: true,
simulate: true
});
ourBoard.radioBaudRateSet(1).should.be.rejected.and.notify(done);
});
it('should not try to change the baud rate if streaming', function (done) {
ourBoard = new openBCIBoard.OpenBCIBoard({
verbose: true,
simulate: true
});
ourBoard.connect(k.OBCISimulatorPortName)
.then(() => {
ourBoard.once('ready', () => {
ourBoard.streamStart()
.then(() => {
ourBoard.radioBaudRateSet('default').then(() => {
done('should have rejected');
}).catch(() => {
done(); // Test pass
});
}).catch(err => done(err));
});
}).catch(err => done(err));
});
it('should not try to change the baud rate if not firmware version 2', function (done) {
ourBoard = new openBCIBoard.OpenBCIBoard({
verbose: true,
simulate: true
});
ourBoard.connect(k.OBCISimulatorPortName)
.then(() => {
ourBoard.once('ready', () => {
ourBoard.radioBaudRateSet('default').should.be.rejected.and.notify(done);
});
}).catch(err => done(err));
});
it('should set the baud rate to default if firmware version 2', function (done) {
ourBoard = new openBCIBoard.OpenBCIBoard({
verbose: true,
simulate: true,
simulatorFirmwareVersion: 'v2'
});
ourBoard.connect(k.OBCISimulatorPortName)
.then(() => {
ourBoard.once('ready', () => {
ourBoard.radioBaudRateSet('default').then(baudrate => {
expect(baudrate).to.be.equal(115200);
done();
}).catch(err => done(err));
});
}).catch(err => done(err));
});
it('should set the baud rate to fast if firmware version 2', function (done) {
ourBoard = new openBCIBoard.OpenBCIBoard({
verbose: true,
simulate: true,
simulatorFirmwareVersion: 'v2'
});
ourBoard.connect(k.OBCISimulatorPortName)
.then(() => {
ourBoard.once('ready', () => {
ourBoard.radioBaudRateSet('fast').then(baudrate => {
expect(baudrate).to.be.equal(230400);
done();
}).catch(err => done(err));
});
}).catch(err => done(err));
});
});
describe('#radioSystemStatusGet', function () {
afterEach(function (done) {
if (ourBoard.isConnected()) {
ourBoard.disconnect().then(() => {
done();
}).catch(() => done);
} else {
done();
}
});
afterEach(() => bluebirdChecks.noPendingPromises());
it('should not get system status if not connected', function (done) {
ourBoard = new openBCIBoard.OpenBCIBoard({
verbose: true,
simulate: true
});
ourBoard.radioSystemStatusGet().should.be.rejected.and.notify(done);
});
it('should not get system status if streaming', function (done) {
ourBoard = new openBCIBoard.OpenBCIBoard({
verbose: true,
simulate: true
});
ourBoard.connect(k.OBCISimulatorPortName)
.then(() => {
ourBoard.once('ready', () => {
ourBoard.streamStart()
.then(() => {
ourBoard.radioSystemStatusGet().then(() => {
done('should have rejected');
}).catch(() => {
done(); // Test pass
});
}).catch(err => done(err));
});
}).catch(err => done(err));
});
it('should not get system status if not firmware version 2', function (done) {
ourBoard = new openBCIBoard.OpenBCIBoard({
verbose: true,
simulate: true
});
ourBoard.connect(k.OBCISimulatorPortName)
.then(() => {
ourBoard.once('ready', () => {
ourBoard.radioSystemStatusGet().should.be.rejected.and.notify(done);
});
}).catch(err => done(err));
});
it('should get up system status if firmware version 2', function (done) {
ourBoard = new openBCIBoard.OpenBCIBoard({
verbose: true,
simulate: true,
simulatorFirmwareVersion: 'v2'
});
ourBoard.connect(k.OBCISimulatorPortName)
.then(() => {
ourBoard.once('ready', () => {
ourBoard.radioSystemStatusGet().then(isUp => {
expect(isUp).to.be.true;
done();
}).catch(err => done(err));
});
}).catch(err => done(err));
});
it('should get down system status if firmware version 2', function (done) {
ourBoard = new openBCIBoard.OpenBCIBoard({
verbose: true,
simulate: true,
simulatorFirmwareVersion: 'v2',
simulatorBoardFailure: true
});
ourBoard.connect(k.OBCISimulatorPortName)
.then(() => {
ourBoard.once('ready', () => {
ourBoard.radioSystemStatusGet().then(isUp => {
expect(isUp).to.be.false;
done();
}).catch(err => done(err));
});
}).catch(err => done(err));
});
});
describe('#radioTests', function () {
this.timeout(0);
before(function (done) {
ourBoard = new openBCIBoard.OpenBCIBoard({
verbose: true,
simulatorFirmwareVersion: 'v2',
simulatorFragmentation: k.OBCISimulatorFragmentationRandom
});
ourBoard.connect(masterPortName).catch(err => done(err));
ourBoard.once('ready', () => {
done();
});
});
after(function (done) {
if (ourBoard.isConnected()) {
ourBoard.disconnect().then(() => {
done();
});
} else {
done();
}
});
after(() => bluebirdChecks.noPendingPromises());
it('should be able to get the channel number', function (done) {
// Don't test if not using v2
if (!ourBoard.usingVersionTwoFirmware()) return done();
// The channel number should be between 0 and 25. Those are hard limits.
ourBoard.radioChannelGet().then(res => {
expect(res.channelNumber).to.be.within(0, 25);
done();
}).catch(err => done(err));
});
it('should be able to set the channel to 1', function (done) {
// Don't test if not using v2
if (!ourBoard.usingVersionTwoFirmware()) return done();
ourBoard.radioChannelSet(1).then(channelNumber => {
expect(channelNumber).to.equal(1);
done();
}).catch(err => done(err));
});
it('should be able to set the channel to 2', function (done) {
// Don't test if not using v2
if (!ourBoard.usingVersionTwoFirmware()) return done();
ourBoard.radioChannelSet(2).then(channelNumber => {
expect(channelNumber).to.equal(2);
done();
}).catch(err => done(err));
});
it('should be able to set the channel to 25', function (done) {
// Don't test if not using v2
if (!ourBoard.usingVersionTwoFirmware()) return done();
ourBoard.radioChannelSet(25).then(channelNumber => {
expect(channelNumber).to.equal(25);
done();
}).catch(err => done(err));
});
it('should be able to set the channel to 5', function (done) {
// Don't test if not using v2
if (!ourBoard.usingVersionTwoFirmware()) return done();
ourBoard.radioChannelSet(5).then(channelNumber => {
expect(channelNumber).to.equal(5);
done();
}).catch(err => done(err));
});
it('should be able to override host channel number, verify system is down, set the host back and verify system is up', function (done) {
// Don't test if not using v2
if (!ourBoard.usingVersionTwoFirmware()) return done();
var systemChanNumber = 0;
var newChanNum = 0;
// var timey = Date.now()
// Get the current system channel
ourBoard.radioChannelGet()
.then(res => {
// Store it
systemChanNumber = res.channelNumber;
// console.log(`system channel number: ${res.channelNumber}`)
if (systemChanNumber === 25) {
newChanNum = 24;
} else {
newChanNum = systemChanNumber + 1;
}
// Call to change just the host
return ourBoard.radioChannelSetHostOverride(newChanNum);
})
.then(newChanNumActual => {
expect(newChanNumActual).to.equal(newChanNum);
// timey = Date.now()
// console.log(`new chan ${newChanNumActual} got`, timey, '0ms')
return new Promise((resolve, reject) => {
setTimeout(function () {
// console.log(`get status`, Date.now(), `${Date.now() - timey}ms`)
ourBoard.radioSystemStatusGet().then(isUp => {
// console.log('resolving', Date.now(), `${Date.now() - timey}ms`)
resolve(isUp);
})
.catch(err => {
reject(err);
});
}, 270); // Should be accurate after 270 seconds
});
})
.then(isUp => {
// console.log(`isUp test`, Date.now(), `${Date.now() - timey}ms`)
expect(isUp).to.be.false;
return ourBoard.radioChannelSetHostOverride(systemChanNumber); // Set back to good
})
.then(newChanNumActual => {
// Verify we set it back to normal
expect(newChanNumActual).to.equal(systemChanNumber);
return ourBoard.radioSystemStatusGet();
})
.then(isUp => {
expect(isUp).to.be.true;
done();
})
.catch(err => done(err));
});
it('should be able to get the poll time', function (done) {
// Don't test if not using v2
if (!ourBoard.usingVersionTwoFirmware()) return done();
ourBoard.radioPollTimeGet().should.eventually.be.greaterThan(0).and.notify(done);
});
it('should be able to set the poll time', function (done) {
// Don't test if not using v2
if (!ourBoard.usingVersionTwoFirmware()) return done();
ourBoard.radioPollTimeSet(80).should.become(80).and.notify(done);
});
it('should be able to change to default baud rate', function (done) {
// Don't test if not using v2
if (!ourBoard.usingVersionTwoFirmware()) return done();
ourBoard.radioBaudRateSet('default').should.become(115200).and.notify(done);
});
it('should be able to change to fast baud rate', function (done) {
// Don't test if not using v2
if (!ourBoard.usingVersionTwoFirmware()) return done();
ourBoard.radioBaudRateSet('fast').then(newBaudRate => {
expect(newBaudRate).to.equal(230400);
return ourBoard.radioBaudRateSet('default');
}).then(() => {
done();
}).catch(err => done(err));
});
it('should be able to set the system status', function (done) {
// Don't test if not using v2
if (!ourBoard.usingVersionTwoFirmware()) return done();
ourBoard.radioSystemStatusGet().then(isUp => {
expect(isUp).to.be.true;
done();
}).catch(err => done(err));
});
});
});
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
+59 -1
Ver Arquivo
@@ -32,6 +32,7 @@ describe('openBCISimulator', function () {
expect(simulator.options.alpha).to.be.true;
expect(simulator.options.boardFailure).to.be.false;
expect(simulator.options.daisy).to.be.false;
expect(simulator.options.daisyCanBeAttached).to.be.true;
expect(simulator.options.drift).to.equal(0);
expect(simulator.options.firmwareVersion).to.equal(k.OBCIFirmwareV1);
expect(simulator.options.lineNoise).to.equal(k.OBCISimulatorLineNoiseHz60);
@@ -272,12 +273,69 @@ describe('openBCISimulator', function () {
simulator.once('open', done);
});
afterEach(() => {
simulator.removeAllListeners('data');
simulator = null;
});
describe('set max channels', function () {
this.timeout(100);
it('should send nothing if no daisy attached', function (done) {
simulator.options.daisy = false;
simulator.on('data', function (data) {
expect(data.toString().match(k.OBCIParseEOT)).to.not.equal(null);
if (data.toString().match(k.OBCIParseEOT)) {
done();
}
});
simulator.write(k.OBCIChannelMaxNumber8);
});
it('should send daisy removed if daisy attached', function (done) {
simulator.options.daisy = true;
simulator.on('data', function (data) {
expect(data.toString().match(`daisy removed${k.OBCIParseEOT}`)).to.not.equal(null);
if (data.toString().match(k.OBCIParseEOT)) {
expect(simulator.options.daisy).to.equal(false);
done();
}
});
simulator.write(k.OBCIChannelMaxNumber8);
});
it('should send just 16 if daisy already attached', function (done) {
simulator.options.daisy = true;
simulator.on('data', function (data) {
expect(data.toString().match(`16${k.OBCIParseEOT}`)).to.not.equal(null);
if (data.toString().match(k.OBCIParseEOT)) {
done();
}
});
simulator.write(k.OBCIChannelMaxNumber16);
});
it('should send daisy attached if able to attach', function (done) {
simulator.options.daisy = false;
simulator.options.daisyCanBeAttached = true;
simulator.on('data', function (data) {
expect(data.toString().match(`daisy attached16`)).to.not.equal(null);
if (data.toString().match(k.OBCIParseEOT)) {
expect(simulator.options.daisy).to.equal(true);
done();
}
});
simulator.write(k.OBCIChannelMaxNumber16);
});
it('should send daisy attached if not able to attach', function (done) {
simulator.options.daisy = false;
simulator.options.daisyCanBeAttached = false;
simulator.on('data', function (data) {
expect(data.toString().match(`no daisy to attach!`)).to.not.equal(null);
if (data.toString().match(k.OBCIParseEOT)) {
done();
}
});
simulator.write(k.OBCIChannelMaxNumber16);
});
});
describe('reset', function () {
it('should be v2', function (done) {
simulator.on('data', function (data) {
console.log(data.toString());
expect(data.toString().match('v2')).to.not.equal(null);
done();
});