Comparar commits
3 Commits
| Autor | SHA1 | Data | |
|---|---|---|---|
| 8f24aa55b7 | |||
| 92242c87b2 | |||
| 655513e757 |
@@ -36,3 +36,7 @@ myOutput.txt
|
||||
|
||||
# Local npm builds for testing end in .tgz
|
||||
*.tgz
|
||||
|
||||
# For git
|
||||
*.orig
|
||||
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- "4.0"
|
||||
install:
|
||||
- npm install --all
|
||||
script:
|
||||
- npm run test-cov
|
||||
|
||||
+301
-107
@@ -1,6 +1,7 @@
|
||||
[](https://waffle.io/OpenBCI/openbci-js-sdk)
|
||||
[](https://gitter.im/OpenBCI/openbci-js-sdk?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
[](https://travis-ci.org/OpenBCI/openbci-js-sdk)
|
||||
[](https://codecov.io/github/OpenBCI/openbci-js-sdk?branch=master)
|
||||
|
||||
# openbci-sdk
|
||||
|
||||
@@ -26,6 +27,34 @@ var ourBoard = require('openbci-sdk').OpenBCIBoard({
|
||||
});
|
||||
```
|
||||
|
||||
Or if you don't have a board and want to use synthetic data:
|
||||
|
||||
```js
|
||||
var ourBoard = require('openbci-sdk').OpenBCIBoard({
|
||||
simulate: true
|
||||
});
|
||||
```
|
||||
|
||||
Auto-finding boards
|
||||
-------------------
|
||||
You must have the OpenBCI board connected to the PC before trying to automatically find it.
|
||||
|
||||
If a port is not automatically found, then call `.listPorts()` to get a list of all serial ports this would be a good place to present a drop down picker list to the user, so they may manually select the serial port name.
|
||||
|
||||
```js
|
||||
var ourBoard = new require('openbci-sdk').OpenBCIBoard();
|
||||
ourBoard.autoFindOpenBCIBoard().then(portName => {
|
||||
if(portName) {
|
||||
/**
|
||||
* Connect to the board with portName
|
||||
* i.e. ourBoard.connect(portName).....
|
||||
*/
|
||||
} else {
|
||||
/**Unable to auto find OpenBCI board*/
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
'ready' event
|
||||
------------
|
||||
|
||||
@@ -47,12 +76,14 @@ Sample properties:
|
||||
------------------
|
||||
* `startByte` (`Number` should be `0xA0`)
|
||||
* `sampleNumber` (a `Number` between 0-255)
|
||||
* `channelData` (channel data indexed starting at 1 [1,2,3,4,5,6,7,8] filled with floating point `Numbers`)
|
||||
* `channelData` (channel data indexed at 0 filled with floating point `Numbers` in Volts)
|
||||
* `auxData` (aux data indexed starting at 0 [0,1,2] filled with floating point `Numbers`)
|
||||
* `stopByte` (`Number` should be `0xC0`)
|
||||
|
||||
The power of this module is in using the sample emitter, to be provided with samples to do with as you wish.
|
||||
|
||||
You can also start the simulator by sending `.connect(portName)` with `portName` equal to `'/dev/tty.openBCISimulator'`.
|
||||
|
||||
To get a 'sample' event, you need to:
|
||||
-------------------------------------
|
||||
1. Call `.connect(serialPortName)`
|
||||
@@ -78,103 +109,103 @@ var ourBoard = new require('openbci-sdk').OpenBCIBoard();
|
||||
ourBoard.streamStop().then(ourBoard.disconnect());
|
||||
```
|
||||
|
||||
To start the simulator test samples:
|
||||
----------
|
||||
1. Call `.simulatorStart()`
|
||||
2. In callback for 'ready' emitter, call `streamStart()`
|
||||
3. Install the 'sample' event emitter
|
||||
```js
|
||||
var ourBoard = new require('openbci-sdk').OpenBCIBoard();
|
||||
ourBoard.simulatorStart().then(function() {
|
||||
ourBoard.on('sample',function(sample) {
|
||||
/** Work with sample */
|
||||
});
|
||||
}).catch(function(err) {
|
||||
console.log('Error [simulator]: ' + err);
|
||||
});
|
||||
```
|
||||
To stop the simulator:
|
||||
```js
|
||||
ourBoard.simulatorStop()
|
||||
```
|
||||
|
||||
Impedance (signal quality)
|
||||
--------------------------
|
||||
Auto Test - (Using impedance to determine signal quality)
|
||||
---------------------------------------------------------
|
||||
Measuring impedance is a vital tool in ensuring great data is collected.
|
||||
|
||||
* **Good** impedance is < 5k Ohms
|
||||
* **Ok** impedance is 5 to 10k Ohms
|
||||
* **Bad** impedance is > 10k Ohms
|
||||
**_IMPORTANT!_** Measuring impedance takes time, so *only test what you must*
|
||||
|
||||
To test for impedance we must apply a known test signal to which either the P, N, or both channels and then apply a little math.
|
||||
Your OpenBCI board will have electrodes hooked up to either a P input, N input or in some cases both inputs.
|
||||
|
||||
When you start measuring for electrode impedance's, a new additional property called `impedanceArray` (indexed 1,2,3,4,5,6,7,8), can be found on the sample object from the emitted by 'sample'.
|
||||
To test specific inputs of channels:
|
||||
|
||||
**Note: You must be streaming in order to measure impedance's. Takes up to 2 seconds to start measuring impedances.**
|
||||
1. Connect to board.
|
||||
2. Start streaming.
|
||||
3. Install the 'impedanceArray' emitter
|
||||
4. Call `.impedanceTestChannels()` with your configuration array
|
||||
|
||||
To start measuring all channels impedance's:
|
||||
A configuration array looks like, for an 8 channel board, `['-','N','n','p','P','-','b','b']`
|
||||
|
||||
Where there are the same number of elements as channels and each element can be either:
|
||||
|
||||
* `p` or `P` (only test P input)
|
||||
* `n` or `N` (only test N input)
|
||||
* `b` or `B` (test both inputs) (takes 66% longer to run then previous two `p` or `n`)
|
||||
* `-` (ignore channel)
|
||||
|
||||
Without further ado, here is an example:
|
||||
```js
|
||||
var ourBoard = new require('openbci-sdk').OpenBCIBoard();
|
||||
ourBoard.connect(portName).then(function(boardSerial) {
|
||||
ourBoard.on('ready',function() {
|
||||
ourBoard.impedanceTestStartAll().then(() => {
|
||||
ourBoard.streamStart();
|
||||
});
|
||||
ourBoard.on('sample',function(sample) {
|
||||
/** Do normal Sample actions */
|
||||
if(sample.impedanceArray) {
|
||||
/** Work with impedance array */
|
||||
}
|
||||
ourBoard.streamStart();
|
||||
ourBoard.once('impedanceArray', impedanceArray => {
|
||||
/** Work with impedance Array */
|
||||
});
|
||||
ourBoard.impedanceTestChannels(['n','N','n','p','P','p','b','B']).catch(err => console.log(err));
|
||||
});
|
||||
}).catch(function(err) {
|
||||
/** Handle connection errors */
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
To stop measuring impedance's:
|
||||
But wait! What is this `impedanceArray`? An Array of Objects, for each object:
|
||||
```js
|
||||
ourBoard.impedanceTestStopAll();
|
||||
[{
|
||||
channel: 1,
|
||||
P: {
|
||||
data: [],
|
||||
average: -1,
|
||||
text: 'init'
|
||||
},
|
||||
N: {
|
||||
data: [],
|
||||
average: -1,
|
||||
text: 'init'
|
||||
}
|
||||
},
|
||||
{
|
||||
// Continues for each channel up to the amount of channels on board (8 or 16)
|
||||
},...];
|
||||
```
|
||||
|
||||
To apply the test signal to a specific input of a specific channel (i.e. Channel 2 test signal applied to P input and not N input):
|
||||
```js
|
||||
ourBoard.impedanceTestStartChannel(2,true,false);
|
||||
```
|
||||
Where:
|
||||
|
||||
To stop applying the test signal to a specific channel (i.e. Stop applying signal to channel 2):
|
||||
```js
|
||||
ourBoard.impedanceTestStopChannel(2);
|
||||
```
|
||||
* *channel* is the channel number (`impedanceArray[0]` is channel 1, `impedanceArray[6]` is channel 7)
|
||||
* *P* is the P input data (Note: P is capitalized)
|
||||
* *data* is an array of raw impedances values that were recorded over 250ms
|
||||
* *average* is an average impedance value taken from `data` array. To get this value we remove outliers from the `data` array and average the cleaned data.
|
||||
* *text* is a text interpretation of the `average`
|
||||
* **Good** impedance is < 5k Ohms
|
||||
* **Ok** impedance is 5 to 10k Ohms
|
||||
* **Bad** impedance is > 10k Ohms
|
||||
* **None** impedance is > 1M Ohms
|
||||
* *N* is the N input data (Note: N is capitalized) (see above for what N object consists of)
|
||||
|
||||
To stop calculating impedance's every time there is a new sample:
|
||||
```js
|
||||
ourBoard.impedanceTestCalculatingStop();
|
||||
```
|
||||
You would call `.impedanceTestCalculatingStop()` if you were measuring the impedance for a specified channel. You do NOT need to call `.impedanceTestCalculatingStop()` after calling `.impedanceTestStopAll()` because it is called for you.
|
||||
To run an impedance test on all imputs:
|
||||
|
||||
Auto-finding boards
|
||||
-------------------
|
||||
You must have the OpenBCI board connected to the PC before trying to automatically find it.
|
||||
1. Connect to board
|
||||
2. Start streaming
|
||||
3. Install the 'impedanceObject'
|
||||
4. Call `.impedanceTestAllChannels()`
|
||||
|
||||
If a port is not automatically found, then a list of ports will be returned, this would be a
|
||||
good place to present a drop down picker list to the user, so they may manually select the
|
||||
serial port name.
|
||||
**Note: Takes up to 5 seconds to start measuring impedances. There is an unknown number of samples taken. Not always 60!**
|
||||
|
||||
For example:
|
||||
|
||||
```js
|
||||
var ourBoard = new require('openbci-sdk').OpenBCIBoard();
|
||||
ourBoard.autoFindOpenBCIBoard().then((value) => {
|
||||
if(Array.isArray(value)) {
|
||||
/**Unable to auto find OpenBCI board*/
|
||||
} else {
|
||||
/**
|
||||
* Connect to the board with portName
|
||||
* i.e. ourBoard.connect(portName).....
|
||||
*/
|
||||
}
|
||||
});
|
||||
ourBoard.connect(portName).then(function(boardSerial) {
|
||||
ourBoard.streamStart();
|
||||
ourBoard.on('impedanceArray', impedanceArray => {
|
||||
/** Work with impedance */
|
||||
});
|
||||
ourBoard.impedanceTestAllChannels();
|
||||
}
|
||||
```
|
||||
|
||||
See Reference Guide for a complete list of impedance tests.
|
||||
|
||||
Reference Guide
|
||||
---------------
|
||||
## Methods
|
||||
@@ -187,9 +218,16 @@ Create new instance of an OpenBCI board.
|
||||
|
||||
Board optional configurations.
|
||||
|
||||
* `boardType` Specifies type of OpenBCI board (3 possible boards)
|
||||
* `default` - 8 Channel OpenBCI board (Default)
|
||||
* `daisy` - 8 Channel board with Daisy Module
|
||||
(NOTE: THIS IS IN-OP AT THIS TIME DUE TO NO ACCESS TO ACCESSORY BOARD)
|
||||
* `ganglion` - 4 Channel board
|
||||
(NOTE: THIS IS IN-OP TIL RELEASE OF GANGLION BOARD 07/2016)
|
||||
* `baudRate` Baud Rate, defaults to 115200. Manipulating this is allowed if firmware on board has been previously configured.
|
||||
* `daisy` Daisy chain board is connected to the OpenBCI board. (NOTE: THIS IS IN-OP AT THIS TIME DUE TO NO ACCESS TO ACCESSORY BOARD)
|
||||
* `verbose` To output more messages to the command line.
|
||||
* `simulate` Full functionality, just synthetic data.
|
||||
* `simulatorSampleRate` - The sample rate to use for the simulator (Default is `250`)
|
||||
|
||||
**Note, we have added support for either all lowercase OR camelcase of the options, use whichever style you prefer.**
|
||||
|
||||
@@ -199,7 +237,7 @@ Automatically find an OpenBCI board.
|
||||
|
||||
**Note: This will always return an Array of `COM` ports on Windows**
|
||||
|
||||
**_Returns_** a promise, fulfilled with a `portName` such as `/dev/tty.*` on Mac/Linux or an 'Array' of all the serial ports.
|
||||
**_Returns_** a promise, fulfilled with a `portName` such as `/dev/tty.*` on Mac/Linux.
|
||||
|
||||
### .channelOff(channelNumber)
|
||||
|
||||
@@ -269,7 +307,7 @@ The essential precursor method to be called initially to establish a serial conn
|
||||
|
||||
The system path of the OpenBCI board serial port to open. For example, `/dev/tty` on Mac/Linux or `COM1` on Windows.
|
||||
|
||||
**_Returns_** a promise, fulfilled by a successful serial connection to the board, containing the serial port object that was opened. The promise will be rejected at any time if the serial port has an 'error' or 'close' event emitted.
|
||||
**_Returns_** a promise, fulfilled by a successful serial connection to the board The promise will be rejected at any time if the serial port has an 'error' or 'close' event emitted.
|
||||
|
||||
### .debugSession()
|
||||
|
||||
@@ -293,49 +331,167 @@ 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.
|
||||
|
||||
### .impedanceTestStartAll()
|
||||
### .impedanceTestAllChannels()
|
||||
|
||||
To apply test signals to all the channels and all inputs on an OpenBCI board.
|
||||
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)!
|
||||
|
||||
**Note, you must be connected in order to set the test commands. Also this method can take up to 2 seconds to send all commands!**
|
||||
Don't forget to install the `impedanceArray` emitter to receive the impendances!
|
||||
|
||||
**_Returns_** a promise, fulfilled once all the commands are sent to the board.
|
||||
**Note, you must be connected in order to set the test commands. Also this method can take up to 5 seconds to send all commands!**
|
||||
|
||||
### .impedanceTestStopAll()
|
||||
**_Returns_** a promise upon completion of test.
|
||||
|
||||
To stop applying test signals to all the channels and inputs on an OpenBCI board.
|
||||
### .impedanceTestChannels(arrayOfCommands)
|
||||
|
||||
**Note, you must be connected in order to set the test commands. Also this method can take up to 2 seconds to send all commands!**
|
||||
**_arrayOfCommands_**
|
||||
|
||||
**_Returns_** a promise, fulfilled once all the commands are sent to the board.
|
||||
The array of configurations where there are the same number of elements as channels and each element can be either:
|
||||
|
||||
* `p` or `P` (only test P input)
|
||||
* `n` or `N` (only test N input)
|
||||
* `b` or `B` (test both inputs) (takes 66% longer to run then previous two `p` or `n`)
|
||||
* `-` (ignore channel)
|
||||
|
||||
### .impedanceTestStartChannel(channelNumber,pInput,nInput)
|
||||
Don't forget to install the `impedanceArray` emitter to receive the impendances!
|
||||
|
||||
To apply the impedance test signal to an input for any given channel.
|
||||
**Note, you must be connected in order to set the test commands. Also this method can take up to 5 seconds to send all commands!**
|
||||
|
||||
**_channelNumber_**
|
||||
**_Returns_** a promise upon completion of test.
|
||||
|
||||
A number specifying which channel you want to get apply the test signal to. Only 1-8 at this time.
|
||||
### .impedanceTestChannel(channelNumber)
|
||||
|
||||
**_pInput_**
|
||||
Run a complete impedance test on a single channel, applying the test signal individually to P & N inputs.
|
||||
|
||||
A bool true if you want to apply the test signal to the P input, false to not apply the test signal.
|
||||
**_channelNumber_**
|
||||
|
||||
**_nInput_**
|
||||
A Number, specifies which channel you want to test.
|
||||
|
||||
A bool true if you want to apply the test signal to the N input, false to not apply the test signal.
|
||||
**_Returns_** a promise that resolves a single channel impedance object.
|
||||
|
||||
### .impedanceTestCalculatingStart()
|
||||
Example:
|
||||
```js
|
||||
var ourBoard = new require('openbci-sdk').OpenBCIBoard();
|
||||
ourBoard.connect(portName).then(function(boardSerial) {
|
||||
ourBoard.on('ready',function() {
|
||||
ourBoard.streamStart();
|
||||
ourBoard.impedanceTestChannel(1)
|
||||
.then(impedanceObject => {
|
||||
/** Do something with impedanceObject! */
|
||||
})
|
||||
.catch(err => console.log(err));
|
||||
});
|
||||
}).catch(function(err) {
|
||||
/** Handle connection errors */
|
||||
});
|
||||
```
|
||||
Where an impedance for this method call would look like:
|
||||
```js
|
||||
{
|
||||
channel: 1,
|
||||
P: {
|
||||
data: [3456.324,2204.5,...],
|
||||
average: 2394.45,
|
||||
text: 'good'
|
||||
},
|
||||
N: {
|
||||
data: [5436.324,9404.5,...],
|
||||
average: 7694.45,
|
||||
text: 'ok'
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
To start calculating impedance's every time there is a new sample.
|
||||
### .impedanceTestChannelInputP(channelNumber)
|
||||
|
||||
**Note, this is automatically called by `.impedanceTestStartAll()` and `.impedanceTestStartChannel()`**
|
||||
Run impedance test on a single channel, applying the test signal only to P input.
|
||||
|
||||
### .impedanceTestCalculatingStop()
|
||||
**_channelNumber_**
|
||||
|
||||
To stop calculating impedance's every time there is a new sample.
|
||||
A Number, specifies which channel you want to test.
|
||||
|
||||
**Note, this is automatically called by `.impedanceTestStopAll()`**
|
||||
**_Returns_** a promise that resolves a single channel impedance object.
|
||||
|
||||
Example:
|
||||
```js
|
||||
var ourBoard = new require('openbci-sdk').OpenBCIBoard();
|
||||
ourBoard.connect(portName).then(function(boardSerial) {
|
||||
ourBoard.on('ready',function() {
|
||||
ourBoard.streamStart();
|
||||
ourBoard.impedanceTestChannelInputP(1)
|
||||
.then(impedanceObject => {
|
||||
/** Do something with impedanceObject! */
|
||||
})
|
||||
.catch(err => console.log(err));
|
||||
});
|
||||
}).catch(function(err) {
|
||||
/** Handle connection errors */
|
||||
});
|
||||
```
|
||||
Where an impedance for this method call would look like:
|
||||
```js
|
||||
{
|
||||
channel: 1,
|
||||
P: {
|
||||
data: [3456.324,2204.5,...],
|
||||
average: 2394.45,
|
||||
text: 'good'
|
||||
},
|
||||
N: {
|
||||
data: [],
|
||||
average: -1,
|
||||
text: 'init'
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### .impedanceTestChannelInputN(channelNumber)
|
||||
|
||||
Run impedance test on a single channel, applying the test signal only to N input.
|
||||
|
||||
**_channelNumber_**
|
||||
|
||||
A Number, specifies which channel you want to test.
|
||||
|
||||
**_Returns_** a promise that resolves a single channel impedance object.
|
||||
|
||||
Example:
|
||||
```js
|
||||
var ourBoard = new require('openbci-sdk').OpenBCIBoard();
|
||||
ourBoard.connect(portName).then(function(boardSerial) {
|
||||
ourBoard.on('ready',function() {
|
||||
ourBoard.streamStart();
|
||||
ourBoard.impedanceTestChannelInputN(1)
|
||||
.then(impedanceObject => {
|
||||
/** Do something with impedanceObject! */
|
||||
})
|
||||
.catch(err => console.log(err));
|
||||
});
|
||||
}).catch(function(err) {
|
||||
/** Handle connection errors */
|
||||
});
|
||||
```
|
||||
Where an impedance for this method call would look like:
|
||||
```js
|
||||
{
|
||||
channel: 1,
|
||||
P: {
|
||||
data: [],
|
||||
average: -1,
|
||||
text: 'init'
|
||||
},
|
||||
N: {
|
||||
data: [5436.324,9404.5,...],
|
||||
average: 7694.45,
|
||||
text: 'ok'
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### .listPorts()
|
||||
|
||||
List available ports so the user can choose a device when not automatically found.
|
||||
|
||||
**_Returns_** a promise, fulfilled with a list of available serial ports.
|
||||
|
||||
### .numberOfChannels()
|
||||
|
||||
@@ -373,19 +529,19 @@ Get the current sample rate.
|
||||
|
||||
### .simulatorStart()
|
||||
|
||||
To start simulating an OpenBCI board.
|
||||
To enter simulate mode. Must call `.connect()` after.
|
||||
|
||||
**Note, must be called after the constructor.**
|
||||
|
||||
**_Returns_** a promise, if the simulator was able to start.
|
||||
**_Returns_** a promise, fulfilled if able to enter simulate mode, reject if not.
|
||||
|
||||
### .simulatorStop()
|
||||
|
||||
To stop simulating an OpenBCI board.
|
||||
To leave simulate mode.
|
||||
|
||||
**Note, must be called after the constructor.**
|
||||
|
||||
**_Returns_** a promise, if the simulator was able to stop.
|
||||
**_Returns_** a promise, fulfilled if able to stop simulate mode, reject if not.
|
||||
|
||||
### .softReset()
|
||||
|
||||
@@ -401,7 +557,7 @@ Sends a start streaming command to the board.
|
||||
|
||||
**Note, You must have called and fulfilled `.connect()` AND observed a `'ready'` emitter before calling this method.**
|
||||
|
||||
**_Returns_** a promise, fulfilled if the command was sent to the write queue.
|
||||
**_Returns_** a promise, fulfilled if the command was sent to the write queue, rejected if unable.
|
||||
|
||||
### .streamStop()
|
||||
|
||||
@@ -409,7 +565,7 @@ Sends a stop streaming command to the board.
|
||||
|
||||
**Note, You must have called and fulfilled `.connect()` AND observed a `'ready'` emitter before calling this method.**
|
||||
|
||||
**_Returns_** a promise, fulfilled if the command was sent to the write queue.
|
||||
**_Returns_** a promise, fulfilled if the command was sent to the write queue, rejected if unable.
|
||||
|
||||
### .write(data)
|
||||
|
||||
@@ -419,7 +575,7 @@ Send commands to the board. Due to the OpenBCI board firmware, a 10ms spacing **
|
||||
|
||||
Either a single character or an Array of characters
|
||||
|
||||
**_Returns_** a promise, fulfilled if the board has been connected and `dataToWrite` has been added to the write queue
|
||||
**_Returns_** a promise, fulfilled if the board has been connected and `dataToWrite` has been added to the write queue, rejected if there were any problems.
|
||||
|
||||
**Example**
|
||||
|
||||
@@ -445,27 +601,65 @@ ourBoard.write('o');
|
||||
|
||||
## Events
|
||||
|
||||
### .on('close', callback)
|
||||
|
||||
Emitted when the serial connection to the board is closed.
|
||||
|
||||
### .on('error', callback)
|
||||
|
||||
Emitted when there is an on the serial port.
|
||||
|
||||
### .on('impedanceArray', callback)
|
||||
|
||||
Emitted when there is a new impedanceArray available.
|
||||
|
||||
### .on('query', callback)
|
||||
|
||||
Emitted resulting in a call to `.getChannelSettings()` with the channelSettingsObject
|
||||
|
||||
### .on('rawDataPacket', callback)
|
||||
|
||||
Emitted when there is a new raw data packet available.
|
||||
|
||||
### .on('ready', callback)
|
||||
|
||||
Emitted when the board is in a ready to start streaming state.
|
||||
|
||||
### .on('sample', callback)
|
||||
|
||||
Emitted when there is a new sample available.
|
||||
Emitted when there is a new sample available.
|
||||
|
||||
## Properties
|
||||
|
||||
### connected
|
||||
|
||||
A bool, true if connected to an OpenBCI board, false if not.
|
||||
|
||||
### streaming
|
||||
|
||||
A bool, true if streaming data from an OpenBCI board, false if not.
|
||||
|
||||
## Dev Notes
|
||||
Running
|
||||
-------
|
||||
1. Plug usb module into serial port
|
||||
1. Turn OpenBCI device on
|
||||
1. Type `npm start` into the terminal in the project directory
|
||||
1. `npm install -D`
|
||||
2. Plug usb module into serial port
|
||||
3. Turn OpenBCI device on
|
||||
4. Type `npm start` into the terminal in the project directory
|
||||
|
||||
Testing
|
||||
-------
|
||||
```
|
||||
npm test
|
||||
```
|
||||
```
|
||||
|
||||
## Contribute to the library
|
||||
1. Fork it!
|
||||
2. Create your feature branch: `git checkout -b my-new-feature`
|
||||
3. Make changes and ensure tests all pass. (`npm test`)
|
||||
4. Commit your changes: `git commit -m 'Add some feature'`
|
||||
5. Push to the branch: `git push origin my-new-feature`
|
||||
6. Submit a pull request :D
|
||||
|
||||
## License
|
||||
MIT
|
||||
Arquivo binário não exibido.
+605
-359
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+77
-11
@@ -155,6 +155,11 @@ const kOBCINumberOfChannelsDaisy = 16;
|
||||
const kOBCINumberOfChannelsDefault = 8;
|
||||
const kOBCINumberOfChannelsGanglion = 4;
|
||||
|
||||
/** Possible OpenBCI board types */
|
||||
const kOBCIBoardDaisy = 'daisy';
|
||||
const kOBCIBoardDefault = 'default';
|
||||
const kOBCIBoardGanglion = 'ganglion';
|
||||
|
||||
/** Possible Sample Rates*/
|
||||
const kOBCISampleRate125 = 125;
|
||||
const kOBCISampleRate250 = 250;
|
||||
@@ -179,7 +184,28 @@ const kOBCIMasterBufferSize = kOBCIPacketSize * 100;
|
||||
const kOBCILeadOffDriveInAmps = 0.000000006;
|
||||
|
||||
/** Command send delay */
|
||||
const kOBCIWriteIntervalDelayMS = 10;
|
||||
const kOBCIWriteIntervalDelayMSLong = 50;
|
||||
const kOBCIWriteIntervalDelayMSNone = 0;
|
||||
const kOBCIWriteIntervalDelayMSShort = 10;
|
||||
|
||||
/** Impedance */
|
||||
const kOBCIImpedanceTextBad = 'bad';
|
||||
const kOBCIImpedanceTextNone = 'none';
|
||||
const kOBCIImpedanceTextGood = 'good';
|
||||
const kOBCIImpedanceTextInit = 'init';
|
||||
const kOBCIImpedanceTextOk = 'ok';
|
||||
|
||||
const kOBCIImpedanceThresholdGoodMin = 0;
|
||||
const kOBCIImpedanceThresholdGoodMax = 5000;
|
||||
const kOBCIImpedanceThresholdOkMin = 5001;
|
||||
const kOBCIImpedanceThresholdOkMax = 10000;
|
||||
const kOBCIImpedanceThresholdBadMin = 10001;
|
||||
const kOBCIImpedanceThresholdBadMax = 1000000;
|
||||
|
||||
const kOBCIImpedanceSeriesResistor = 2200; // There is a 2.2 k Ohm series resistor that must be subtracted
|
||||
|
||||
/** Simulator */
|
||||
const kOBCISimulatorPortName = '/dev/tty.openBCISimulator';
|
||||
|
||||
module.exports = {
|
||||
/** Turning channels off */
|
||||
@@ -396,10 +422,10 @@ module.exports = {
|
||||
OBCIStringADCBiasDrp:kOBCIStringADCBiasDrp,
|
||||
OBCIStringADCBiasDrn:kOBCIStringADCBiasDrn,
|
||||
/**
|
||||
* Purpose: To convert a string like 'normal' to the correct command (i.e. '1')
|
||||
* @description To convert a string like 'normal' to the correct command (i.e. '1')
|
||||
* @param adcString
|
||||
* @returns {Promise}
|
||||
* Author: AJ Keller (@pushtheworldllc)
|
||||
* @author AJ Keller (@pushtheworldllc)
|
||||
*/
|
||||
commandForADCString:commandForADCString,
|
||||
/** Default Channel Settings */
|
||||
@@ -480,6 +506,20 @@ module.exports = {
|
||||
OBCINumberOfChannelsDaisy:kOBCINumberOfChannelsDaisy,
|
||||
OBCINumberOfChannelsDefault:kOBCINumberOfChannelsDefault,
|
||||
OBCINumberOfChannelsGanglion:kOBCINumberOfChannelsGanglion,
|
||||
/** Possible OpenBCI board types */
|
||||
OBCIBoardDaisy:kOBCIBoardDaisy,
|
||||
OBCIBoardDefault:kOBCIBoardDefault,
|
||||
OBCIBoardGanglion:kOBCIBoardGanglion,
|
||||
numberOfChannelsForBoardType: boardType => {
|
||||
switch (boardType) {
|
||||
case kOBCIBoardDaisy:
|
||||
return kOBCINumberOfChannelsDaisy;
|
||||
case kOBCIBoardGanglion:
|
||||
return kOBCINumberOfChannelsGanglion;
|
||||
default:
|
||||
return kOBCINumberOfChannelsDefault;
|
||||
}
|
||||
},
|
||||
/** Possible Sample Rates */
|
||||
OBCISampleRate125:kOBCISampleRate125,
|
||||
OBCISampleRate250:kOBCISampleRate250,
|
||||
@@ -502,11 +542,34 @@ module.exports = {
|
||||
/** Impedance Setter Maker */
|
||||
getImpedanceSetter:impedanceSetter,
|
||||
/** Command send delay */
|
||||
OBCIWriteIntervalDelayMS:kOBCIWriteIntervalDelayMS
|
||||
OBCIWriteIntervalDelayMSLong:kOBCIWriteIntervalDelayMSLong,
|
||||
OBCIWriteIntervalDelayMSNone:kOBCIWriteIntervalDelayMSNone,
|
||||
OBCIWriteIntervalDelayMSShort:kOBCIWriteIntervalDelayMSShort,
|
||||
/** Impedance */
|
||||
OBCIImpedanceTextBad:kOBCIImpedanceTextBad,
|
||||
OBCIImpedanceTextGood:kOBCIImpedanceTextGood,
|
||||
OBCIImpedanceTextInit:kOBCIImpedanceTextInit,
|
||||
OBCIImpedanceTextOk:kOBCIImpedanceTextOk,
|
||||
OBCIImpedanceTextNone:kOBCIImpedanceTextNone,
|
||||
OBCIImpedanceThresholdBadMax:kOBCIImpedanceThresholdBadMax,
|
||||
OBCIImpedanceSeriesResistor:kOBCIImpedanceSeriesResistor,
|
||||
getTextForRawImpedance: (value) => {
|
||||
if (value > kOBCIImpedanceThresholdGoodMin && value < kOBCIImpedanceThresholdGoodMax) {
|
||||
return kOBCIImpedanceTextGood;
|
||||
} else if (value > kOBCIImpedanceThresholdOkMin && value < kOBCIImpedanceThresholdOkMax) {
|
||||
return kOBCIImpedanceTextOk;
|
||||
} else if (value > kOBCIImpedanceThresholdBadMin && value < kOBCIImpedanceThresholdBadMax) {
|
||||
return kOBCIImpedanceTextBad;
|
||||
} else {
|
||||
return kOBCIImpedanceTextNone;
|
||||
}
|
||||
},
|
||||
/** Simulator */
|
||||
OBCISimulatorPortName:kOBCISimulatorPortName
|
||||
};
|
||||
|
||||
/**
|
||||
* Purpose: To add a usability abstraction layer above channel setting commands. Due to the
|
||||
* @description To add a usability abstraction layer above channel setting commands. Due to the
|
||||
* extensive and highly specific nature of the channel setting command chain, this
|
||||
* will take several different human readable inputs and merge to one array filled
|
||||
* with the correct commands, prime for sending directly to the write command.
|
||||
@@ -543,22 +606,25 @@ function channelSetter(channelNumber,powerDown,gain,inputType,bias,srb2,srb1) {
|
||||
if (!isNumber(channelNumber)) reject('channelNumber must be of type \'number\' ');
|
||||
if (!isBoolean(powerDown)) reject('powerDown must be of type \'boolean\' ');
|
||||
if (!isNumber(gain)) reject('gain must be of type \'number\' ');
|
||||
if (!isString(inputTdype)) reject('inputType must be of type \'string\' ');
|
||||
if (!isString(inputType)) reject('inputType must be of type \'string\' ');
|
||||
if (!isBoolean(bias)) reject('bias must be of type \'boolean\' ');
|
||||
if (!isBoolean(srb2)) reject('srb1 must be of type \'boolean\' ');
|
||||
if (!isBoolean(srb1)) reject('srb2 must be of type \'boolean\' ');
|
||||
|
||||
// Set Channel Number
|
||||
var p1 = commandChannelForCmd(channelNumber);
|
||||
var p1 = commandChannelForCmd(channelNumber)
|
||||
.catch(err => reject(err));
|
||||
|
||||
// Set POWER_DOWN
|
||||
cmdPowerDown = powerDown ? kOBCIChannelCmdPowerOff : kOBCIChannelCmdPowerOn;
|
||||
|
||||
// Set Gain
|
||||
var p2 = commandForGain(gain);
|
||||
var p2 = commandForGain(gain)
|
||||
.catch(err => reject(err));
|
||||
|
||||
// Set ADC string
|
||||
var p3 = commandForADCString(inputType);
|
||||
var p3 = commandForADCString(inputType)
|
||||
.catch(err => reject(err));
|
||||
|
||||
// Set BIAS
|
||||
cmdBias = bias ? kOBCIChannelCmdBiasInclude : kOBCIChannelCmdBiasRemove;
|
||||
@@ -588,7 +654,7 @@ function channelSetter(channelNumber,powerDown,gain,inputType,bias,srb2,srb1) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Purpose: To build the array of commands to send to the board to measure impedance
|
||||
* @description To build the array of commands to send to the board to measure impedance
|
||||
* @param channelNumber
|
||||
* @param pInputApplied - Bool (true -> Test Signal Applied, false -> Test Signal Not Applied (default))
|
||||
* applies the test signal to the P input
|
||||
@@ -622,7 +688,7 @@ function impedanceSetter(channelNumber,pInputApplied,nInputApplied) {
|
||||
];
|
||||
//console.log(outputArray);
|
||||
resolve(outputArray);
|
||||
});
|
||||
}).catch(err => reject(err));;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
+144
-31
@@ -1,5 +1,8 @@
|
||||
'use strict';
|
||||
var gaussian = require('gaussian');
|
||||
var outliers = require('outliers');
|
||||
var stats = require('scientific-statistics');
|
||||
|
||||
/** Constants for interpreting the EEG data */
|
||||
// Reference voltage for ADC in ADS1299.
|
||||
// Set by its hardware.
|
||||
@@ -12,8 +15,8 @@ const SCALE_FACTOR_ACCEL = 0.002 / Math.pow(2,4);
|
||||
// Scale factor for channelData
|
||||
const SCALE_FACTOR_CHANNEL = ADS1299_VREF / ADS1299_GAIN / (Math.pow(2,23) - 1);
|
||||
|
||||
var k = require('./openBCIConstants');
|
||||
|
||||
var k = require('./openBCIConstants');
|
||||
|
||||
module.exports = {
|
||||
convertPacketToSample: function (dataBuf) {
|
||||
@@ -24,30 +27,26 @@ module.exports = {
|
||||
var numberOfBytes = dataBuf.byteLength;
|
||||
var scaleData = true;
|
||||
|
||||
if (numberOfBytes != k.OBCIPacketSize) return;
|
||||
if (dataBuf[0] != k.OBCIByteStart) return;
|
||||
if (dataBuf[32] != k.OBCIByteStop) return;
|
||||
if (numberOfBytes != k.OBCIPacketSize) return;
|
||||
|
||||
var channelData = function () {
|
||||
var out = {};
|
||||
var count = 1;
|
||||
var out = [];
|
||||
var count = 0;
|
||||
for (var i = 2; i <= numberOfBytes - 10; i += 3) {
|
||||
//console.log('\tDataBuf is is: ' + dataBuf.slice(i, i + 3).toString('hex'));
|
||||
//var newNumber = self.interpret24bitAsInt32(dataBuf.slice(i, i + 3));
|
||||
//out[count] = newNumber * SCALE_FACTOR_CHANNEL;
|
||||
out[count] = scaleData ? self.interpret24bitAsInt32(dataBuf.slice(i, i + 3)) * SCALE_FACTOR_CHANNEL : self.interpret24bitAsInt32(dataBuf.slice(i, i + 3));
|
||||
//console.log("in" + dataBuf.slice(i,i+3));
|
||||
//console.log(out[count]);
|
||||
var number = self.interpret24bitAsInt32(dataBuf.slice(i, i + 3));
|
||||
out.push(number * SCALE_FACTOR_CHANNEL);
|
||||
count++;
|
||||
}
|
||||
return out;
|
||||
};
|
||||
|
||||
var auxData = function () {
|
||||
var out = {};
|
||||
var out = [];
|
||||
var count = 0;
|
||||
for (var i = numberOfBytes - 7; i < numberOfBytes - 1; i += 2) {
|
||||
out[count] = scaleData ? self.interpret16bitAsInt32(dataBuf.slice(i, i + 2)) * SCALE_FACTOR_ACCEL : self.interpret16bitAsInt32(dataBuf.slice(i, i + 2));
|
||||
out.push(scaleData ? self.interpret16bitAsInt32(dataBuf.slice(i, i + 2)) * SCALE_FACTOR_ACCEL : self.interpret16bitAsInt32(dataBuf.slice(i, i + 2)));
|
||||
count++;
|
||||
}
|
||||
return out;
|
||||
@@ -61,16 +60,45 @@ module.exports = {
|
||||
stopByte: dataBuf[numberOfBytes - 1] // byte
|
||||
}
|
||||
},
|
||||
debugPrettyPrint: function(sample) {
|
||||
convertSampleToPacket: function(sample) {
|
||||
var packetBuffer = new Buffer(k.OBCIPacketSize);
|
||||
packetBuffer.fill(0);
|
||||
|
||||
// start byte
|
||||
packetBuffer[0] = k.OBCIByteStart;
|
||||
|
||||
// sample number
|
||||
packetBuffer[1] = sample.sampleNumber;
|
||||
|
||||
// channel data
|
||||
for (var i = 0; i < k.OBCINumberOfChannelsDefault; i++) {
|
||||
var threeByteBuffer = this.floatTo3ByteBuffer(sample.channelData[i]);
|
||||
|
||||
threeByteBuffer.copy(packetBuffer, 2 + (i * 3));
|
||||
}
|
||||
|
||||
for (var j = 0; j < 3; j++) {
|
||||
var twoByteBuffer = this.floatTo2ByteBuffer(sample.auxData[j]);
|
||||
|
||||
twoByteBuffer.copy(packetBuffer, (k.OBCIPacketSize - 1 - 6) + (i * 2));
|
||||
}
|
||||
|
||||
|
||||
// stop byte
|
||||
packetBuffer[k.OBCIPacketSize - 1] = k.OBCIByteStop;
|
||||
|
||||
return packetBuffer;
|
||||
},
|
||||
|
||||
debugPrettyPrint: function(sample) {
|
||||
if(sample === null || sample === undefined) {
|
||||
console.log('== Sample is undefined ==');
|
||||
} else {
|
||||
console.log('-- Sample --');
|
||||
console.log('---- Start Byte: ' + sample.startByte);
|
||||
console.log('---- Sample Number: ' + sample.sampleNumber);
|
||||
for(var i = 1; i <= 8; i++) {
|
||||
console.log('---- Channel Data ' + i + ': ' + sample.channelData[i]);
|
||||
for(var i = 0; i < 8; i++) {
|
||||
console.log('---- Channel Data ' + (i + 1) + ': ' + sample.channelData[i]);
|
||||
}
|
||||
for(var j = 0; j < 3; j++) {
|
||||
console.log('---- Aux Data ' + j + ': ' + sample.auxData[j]);
|
||||
@@ -78,20 +106,80 @@ module.exports = {
|
||||
console.log('---- Stop Byte: ' + sample.stopByte);
|
||||
}
|
||||
},
|
||||
impedanceCalculation: function(sampleObject) {
|
||||
/**
|
||||
* @description Convert float number into three byte buffer. This is the opposite of .interpret24bitAsInt32()
|
||||
* @param float - The number you want to convert
|
||||
* @returns {Buffer} - 3-byte buffer containing the float
|
||||
*/
|
||||
floatTo3ByteBuffer: function(float) {
|
||||
var intBuf = new Buffer(3); // 3 bytes for 24 bits
|
||||
intBuf.fill(0); // Fill the buffer with 0s
|
||||
|
||||
var temp = float / SCALE_FACTOR_CHANNEL; // Convert to counts
|
||||
|
||||
temp = Math.floor(temp); // Truncate counts number
|
||||
|
||||
// Move into buffer
|
||||
intBuf[2] = temp & 255;
|
||||
intBuf[1] = (temp & (255 << 8)) >> 8;
|
||||
intBuf[0] = (temp & (255 << 16)) >> 16;
|
||||
|
||||
return intBuf;
|
||||
},
|
||||
/**
|
||||
* @description Convert float number into three byte buffer. This is the opposite of .interpret24bitAsInt32()
|
||||
* @param float - The number you want to convert
|
||||
* @returns {Buffer} - 3-byte buffer containing the float
|
||||
*/
|
||||
floatTo2ByteBuffer: function(float) {
|
||||
var intBuf = new Buffer(2); // 2 bytes for 16 bits
|
||||
intBuf.fill(0); // Fill the buffer with 0s
|
||||
|
||||
var temp = float / SCALE_FACTOR_ACCEL; // Convert to counts
|
||||
|
||||
temp = Math.floor(temp); // Truncate counts number
|
||||
|
||||
//console.log('Num: ' + temp);
|
||||
|
||||
// Move into buffer
|
||||
intBuf[1] = temp & 255;
|
||||
intBuf[0] = (temp & (255 << 8)) >> 8;
|
||||
|
||||
return intBuf;
|
||||
},
|
||||
/**
|
||||
* Purpose: 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} - Fullfilled with impedance vaule for the specified channel.
|
||||
* Author: AJ Keller
|
||||
*/
|
||||
impedanceCalculationForChannel: function(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 impedanceArray = [];
|
||||
for (var i = 1; i <= k.OBCINumberOfChannelsDefault; i++) {
|
||||
impedanceArray[i] = (sqrt2 * sampleObject.channelData[i]) / k.OBCILeadOffDriveInAmps;
|
||||
var index = channelNumber - 1;
|
||||
|
||||
if (sampleObject.channelData[index] < 0) {
|
||||
sampleObject.channelData[index] *= -1;
|
||||
}
|
||||
sampleObject.impedanceArray = impedanceArray;
|
||||
resolve(sampleObject);
|
||||
var impedance = (sqrt2 * sampleObject.channelData[index]) / k.OBCILeadOffDriveInAmps;
|
||||
resolve(impedance);
|
||||
});
|
||||
},
|
||||
interpret16bitAsInt32: function(twoByteBuffer) {
|
||||
var prefix = 0;
|
||||
|
||||
if(twoByteBuffer[0] > 127) {
|
||||
//console.log('\t\tNegative number');
|
||||
prefix = 65535; // 0xFFFF
|
||||
}
|
||||
|
||||
return (prefix << 16) | (twoByteBuffer[0] << 8) | twoByteBuffer[1];
|
||||
},
|
||||
interpret24bitAsInt32: function(threeByteBuffer) {
|
||||
var prefix = 0;
|
||||
|
||||
@@ -103,15 +191,24 @@ module.exports = {
|
||||
return (prefix << 24 ) | (threeByteBuffer[0] << 16) | (threeByteBuffer[1] << 8) | threeByteBuffer[2];
|
||||
|
||||
},
|
||||
interpret16bitAsInt32: function(twoByteBuffer) {
|
||||
var prefix = 0;
|
||||
|
||||
if(twoByteBuffer[0] > 127) {
|
||||
//console.log('\t\tNegative number');
|
||||
prefix = 65535; // 0xFFFF
|
||||
impedanceArray: (numberOfChannels) => {
|
||||
var impedanceArray = [];
|
||||
for (var i = 0; i < numberOfChannels; i++) {
|
||||
impedanceArray.push(newImpedanceObject(i+1));
|
||||
}
|
||||
return impedanceArray;
|
||||
},
|
||||
impedanceObject: newImpedanceObject,
|
||||
impedanceSummarize: (singleInputObject) => {
|
||||
var median = stats.median(singleInputObject.data);
|
||||
if (median > k.OBCIImpedanceThresholdBadMax) { // The case for no load (super high impedance)
|
||||
singleInputObject.average = median;
|
||||
singleInputObject.text = k.OBCIImpedanceTextNone;
|
||||
} else {
|
||||
var cleanedData = singleInputObject.data.filter(outliers()); // Remove outliers
|
||||
singleInputObject.average = stats.mean(cleanedData); // Get average numerical impedance
|
||||
singleInputObject.text = k.getTextForRawImpedance(singleInputObject.average); // Get textual impedance
|
||||
}
|
||||
|
||||
return (prefix << 16) | (twoByteBuffer[0] << 8) | twoByteBuffer[1];
|
||||
},
|
||||
newSample: function() {
|
||||
return {
|
||||
@@ -142,7 +239,7 @@ module.exports = {
|
||||
|
||||
//console.log('New Sample: ' + JSON.stringify(newSample));
|
||||
|
||||
for(var i = 1; i <= numberOfChannels; i++) { //channels are 1 indexed
|
||||
for(var i = 0; i < numberOfChannels; i++) { //channels are 0 indexed
|
||||
newSample.channelData[i] = distribution.ppf(Math.random())*Math.sqrt(sampleRateHz/2)/uVolts;
|
||||
|
||||
switch (i) {
|
||||
@@ -186,4 +283,20 @@ module.exports = {
|
||||
scaleFactorAux: SCALE_FACTOR_ACCEL,
|
||||
scaleFactorChannel: SCALE_FACTOR_CHANNEL,
|
||||
k:k
|
||||
};
|
||||
};
|
||||
|
||||
function newImpedanceObject(channelNumber) {
|
||||
return {
|
||||
channel: channelNumber,
|
||||
P: {
|
||||
data: [],
|
||||
average: -1,
|
||||
text: k.OBCIImpedanceTextInit
|
||||
},
|
||||
N: {
|
||||
data: [],
|
||||
average: -1,
|
||||
text: k.OBCIImpedanceTextInit
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
'use strict';
|
||||
|
||||
var EventEmitter = require('events').EventEmitter;
|
||||
var util = require('util');
|
||||
var stream = require('stream');
|
||||
|
||||
var openBCISample = require('./openBCISample');
|
||||
var k = openBCISample.k;
|
||||
|
||||
|
||||
function OpenBCISimulatorFactory() {
|
||||
var factory = this;
|
||||
|
||||
|
||||
|
||||
var _options = {
|
||||
samplerate: 250,
|
||||
daisy: false,
|
||||
verbose: false
|
||||
};
|
||||
|
||||
|
||||
|
||||
function OpenBCISimulator(portName, options) {
|
||||
options = (typeof options !== 'function') && options || {};
|
||||
var opts = {};
|
||||
|
||||
stream.Stream.call(this);
|
||||
|
||||
/** Configuring Options */
|
||||
opts.sampleRate = options.sampleRate || options.samplerate || _options.samplerate;
|
||||
opts.daisy = options.daisy || _options.daisy;
|
||||
opts.verbose = options.verbose || _options.verbose;
|
||||
|
||||
this.options = opts;
|
||||
|
||||
// Bools
|
||||
this.connected = false;
|
||||
// Buffers
|
||||
this.buffer = new Buffer(500);
|
||||
// Numbers
|
||||
this.sampleNumber = -1; // So the first sample is 0
|
||||
// Strings
|
||||
this.portName = portName || k.OBCISimulatorPortName;
|
||||
|
||||
// Call 'open'
|
||||
setTimeout(() => {
|
||||
console.log('Port name: ' + portName);
|
||||
if (portName === k.OBCISimulatorPortName) {
|
||||
this.emit('open');
|
||||
this.connected = true;
|
||||
} else {
|
||||
var err = new Error('Serialport not open.');
|
||||
this.emit('error',err);
|
||||
}
|
||||
}, 200);
|
||||
|
||||
}
|
||||
|
||||
// This allows us to use the emitter class freely outside of the module
|
||||
util.inherits(OpenBCISimulator, stream.Stream);
|
||||
|
||||
OpenBCISimulator.prototype.flush = function() {
|
||||
this.buffer.fill(0);
|
||||
//if (this.options.verbose) console.log('flushed');
|
||||
};
|
||||
|
||||
OpenBCISimulator.prototype.write = function(data,callback) {
|
||||
if (data[0] === k.OBCIStreamStart) {
|
||||
if (!this.stream) this._startStream();
|
||||
} else if (data[0] === k.OBCIStreamStop) {
|
||||
if (this.stream) clearInterval(this.stream); // Stops the stream
|
||||
} else if (data[0] === k.OBCIMiscSoftReset) {
|
||||
if (this.stream) clearInterval(this.stream);
|
||||
this.emit('data', new Buffer('OpenBCI Board Simulator\nPush The World V-0.2\n$$$'));
|
||||
}
|
||||
|
||||
/** Handle Callback */
|
||||
if (this.connected) {
|
||||
callback(null,'Success!');
|
||||
}
|
||||
};
|
||||
|
||||
OpenBCISimulator.prototype.drain = function(callback) {
|
||||
callback();
|
||||
//if (this.options.verbose) console.log('drain');
|
||||
};
|
||||
|
||||
OpenBCISimulator.prototype.close = function(callback) {
|
||||
if (this.connected) {
|
||||
this.emit('close');
|
||||
}
|
||||
this.connected = false;
|
||||
//if (this.options.verbose) console.log('close');
|
||||
callback();
|
||||
};
|
||||
|
||||
OpenBCISimulator.prototype._startStream = function() {
|
||||
var intervalInMS = 1000 / this.options.sampleRate;
|
||||
|
||||
if (intervalInMS < 2) intervalInMS = 2;
|
||||
|
||||
var generateSample = openBCISample.randomSample(k.OBCINumberOfChannelsDefault, k.OBCISampleRate250);
|
||||
|
||||
var getNewPacket = sampNumber => {
|
||||
return openBCISample.convertSampleToPacket(generateSample(sampNumber));
|
||||
};
|
||||
|
||||
this.stream = setInterval(() => {
|
||||
this.emit('data', getNewPacket(this.sampleNumber));
|
||||
this.sampleNumber++;
|
||||
}, intervalInMS);
|
||||
};
|
||||
|
||||
factory.OpenBCISimulator = OpenBCISimulator;
|
||||
|
||||
}
|
||||
|
||||
util.inherits(OpenBCISimulatorFactory, EventEmitter);
|
||||
|
||||
module.exports = new OpenBCISimulatorFactory();
|
||||
+9
-3
@@ -1,11 +1,12 @@
|
||||
{
|
||||
"name": "openbci-sdk",
|
||||
"version": "0.1.9",
|
||||
"version": "0.2.0",
|
||||
"description": "A fully NodeJS based API for the OpenBCI board connecting to the hardware directly over serial",
|
||||
"main": "openBCIBoard",
|
||||
"scripts": {
|
||||
"start": "node index",
|
||||
"test": "mocha test"
|
||||
"test": "mocha test",
|
||||
"test-cov": "istanbul cover ./node_modules/mocha/bin/_mocha -- -R spec && codecov"
|
||||
},
|
||||
"keywords": [
|
||||
"openbci",
|
||||
@@ -15,6 +16,9 @@
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"gaussian": "^1.0.0",
|
||||
"istanbul": "^0.4.2",
|
||||
"outliers": "0.0.3",
|
||||
"scientific-statistics": "^0.2.7",
|
||||
"serialport": "^2.0.2"
|
||||
},
|
||||
"directories": {
|
||||
@@ -23,9 +27,11 @@
|
||||
"devDependencies": {
|
||||
"chai": "^3.4.1",
|
||||
"chai-as-promised": "^5.2.0",
|
||||
"codecov": "^1.0.1",
|
||||
"mocha": "^2.3.4",
|
||||
"sandboxed-module": "^2.0.3",
|
||||
"sinon": "^1.17.2"
|
||||
"sinon": "^1.17.2",
|
||||
"sinon-chai": "^2.8.0"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
+84
-139
@@ -636,7 +636,7 @@ describe('OpenBCIConstants', function() {
|
||||
//'channel 1, power on, gain 24, inputType normal, bias include, srb2 connect, srb1 dissconnect'
|
||||
describe('channel input selection works', function() {
|
||||
//this.timeout(5000);
|
||||
it('channel 2', function() {
|
||||
it('channel 2', function(done) {
|
||||
k.getChannelSetter(2,false,24,'normal',true,true,false).then(function(arrayOfCommands) {
|
||||
arrayOfCommands[1].should.equal('2');
|
||||
done();
|
||||
@@ -644,7 +644,7 @@ describe('OpenBCIConstants', function() {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
it('channel 5', function() {
|
||||
it('channel 5', function(done) {
|
||||
k.getChannelSetter(5,false,24,'normal',true,true,false).then(function(arrayOfCommands) {
|
||||
arrayOfCommands[1].should.equal('5');
|
||||
done();
|
||||
@@ -652,7 +652,7 @@ describe('OpenBCIConstants', function() {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
it('channel 9', function() {
|
||||
it('channel 9', function(done) {
|
||||
k.getChannelSetter(9,false,24,'normal',true,true,false).then(function(arrayOfCommands) {
|
||||
arrayOfCommands[1].should.equal('Q');
|
||||
done();
|
||||
@@ -660,7 +660,7 @@ describe('OpenBCIConstants', function() {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
it('channel 15', function() {
|
||||
it('channel 15', function(done) {
|
||||
k.getChannelSetter(15,false,24,'normal',true,true,false).then(function(arrayOfCommands) {
|
||||
arrayOfCommands[1].should.equal('U');
|
||||
done();
|
||||
@@ -668,23 +668,15 @@ describe('OpenBCIConstants', function() {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
it('Invalid channel selection', function() {
|
||||
k.getChannelSetter(0,false,24,'normal',true,true,false).then(function(arrayOfCommands) {
|
||||
done('Should have rejected promise');
|
||||
}, function(err) {
|
||||
done(err);
|
||||
});
|
||||
it('Invalid channel selection', function(done) {
|
||||
k.getChannelSetter(0,false,24,'normal',true,true,false).should.be.rejected.and.notify(done);
|
||||
});
|
||||
it('Invalid type', function() {
|
||||
k.getChannelSetter('0',false,24,'normal',true,true,false).then(function(arrayOfCommands) {
|
||||
done('Should have rejected promise');
|
||||
}, function(err) {
|
||||
done(err);
|
||||
});
|
||||
it('Invalid type', function(done) {
|
||||
k.getChannelSetter('0',false,24,'normal',true,true,false).should.be.rejected.and.notify(done);
|
||||
});
|
||||
});
|
||||
describe('power selection works', function() {
|
||||
it('on', function() {
|
||||
it('on', function(done) {
|
||||
k.getChannelSetter(1,false,24,'normal',true,true,false).then(function(arrayOfCommands) {
|
||||
arrayOfCommands[2].should.equal('0');
|
||||
done();
|
||||
@@ -692,7 +684,7 @@ describe('OpenBCIConstants', function() {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
it('off', function() {
|
||||
it('off', function(done) {
|
||||
k.getChannelSetter(1,true,24,'normal',true,true,false).then(function(arrayOfCommands) {
|
||||
arrayOfCommands[2].should.equal('1');
|
||||
done();
|
||||
@@ -700,16 +692,12 @@ describe('OpenBCIConstants', function() {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
it('Invalid type', function() {
|
||||
k.getChannelSetter(1,'taco',24,'normal',true,true,false).then(function(arrayOfCommands) {
|
||||
done('Should have rejected promise');
|
||||
}, function(err) {
|
||||
done(err);
|
||||
});
|
||||
it('Invalid type', function(done) {
|
||||
k.getChannelSetter(1,'taco',24,'normal',true,true,false).should.be.rejected.and.notify(done);
|
||||
});
|
||||
});
|
||||
describe('gain selection works', function() {
|
||||
it('1x', function() {
|
||||
it('1x', function(done) {
|
||||
k.getChannelSetter(1,false,1,'normal',true,true,false).then(function(arrayOfCommands) {
|
||||
arrayOfCommands[3].should.equal('0');
|
||||
done();
|
||||
@@ -717,7 +705,7 @@ describe('OpenBCIConstants', function() {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
it('2x', function() {
|
||||
it('2x', function(done) {
|
||||
k.getChannelSetter(1,false,2,'normal',true,true,false).then(function(arrayOfCommands) {
|
||||
arrayOfCommands[3].should.equal('1');
|
||||
done();
|
||||
@@ -725,63 +713,55 @@ describe('OpenBCIConstants', function() {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
it('4x', function() {
|
||||
it('4x', function(done) {
|
||||
k.getChannelSetter(1,false,4,'normal',true,true,false).then(function(arrayOfCommands) {
|
||||
arrayOfCommands[3].should.equal('2');
|
||||
done();
|
||||
}, function(err) {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
it('6x', function(done) {
|
||||
k.getChannelSetter(1,false,6,'normal',true,true,false).then(function(arrayOfCommands) {
|
||||
arrayOfCommands[3].should.equal('3');
|
||||
done();
|
||||
}, function(err) {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
it('6x', function() {
|
||||
k.getChannelSetter(1,false,6,'normal',true,true,false).then(function(arrayOfCommands) {
|
||||
it('8x', function(done) {
|
||||
k.getChannelSetter(1,false,8,'normal',true,true,false).then(function(arrayOfCommands) {
|
||||
arrayOfCommands[3].should.equal('4');
|
||||
done();
|
||||
}, function(err) {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
it('8x', function() {
|
||||
k.getChannelSetter(1,false,8,'normal',true,true,false).then(function(arrayOfCommands) {
|
||||
it('12x', function(done) {
|
||||
k.getChannelSetter(1,false,12,'normal',true,true,false).then(function(arrayOfCommands) {
|
||||
arrayOfCommands[3].should.equal('5');
|
||||
done();
|
||||
}, function(err) {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
it('12x', function() {
|
||||
k.getChannelSetter(1,false,12,'normal',true,true,false).then(function(arrayOfCommands) {
|
||||
it('24x', function(done) {
|
||||
k.getChannelSetter(1,false,24,'normal',true,true,false).then(function(arrayOfCommands) {
|
||||
arrayOfCommands[3].should.equal('6');
|
||||
done();
|
||||
}, function(err) {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
it('24x', function() {
|
||||
k.getChannelSetter(1,false,24,'normal',true,true,false).then(function(arrayOfCommands) {
|
||||
arrayOfCommands[3].should.equal('7');
|
||||
done();
|
||||
}, function(err) {
|
||||
done(err);
|
||||
});
|
||||
it('Invalid type', function(done) {
|
||||
k.getChannelSetter(1,false,'24','normal',true,true,false).should.be.rejected.and.notify(done);
|
||||
});
|
||||
it('Invalid type', function() {
|
||||
k.getChannelSetter(1,false,'24','normal',true,true,false).then(function(arrayOfCommands) {
|
||||
done('Should have rejected promise');
|
||||
}, function(err) {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
it('Invalid gain setting', function() {
|
||||
k.getChannelSetter(1,false,5,'normal',true,true,false).then(function(arrayOfCommands) {
|
||||
done('Should have rejected promise');
|
||||
}, function(err) {
|
||||
done(err);
|
||||
});
|
||||
it('Invalid gain setting', function(done) {
|
||||
k.getChannelSetter(1,false,5,'normal',true,true,false).should.be.rejected.and.notify(done);
|
||||
});
|
||||
});
|
||||
describe('input type', function() {
|
||||
it('normal', function() {
|
||||
it('normal', function(done) {
|
||||
k.getChannelSetter(1,false,24,'normal',true,true,false).then(function(arrayOfCommands) {
|
||||
arrayOfCommands[4].should.equal('0');
|
||||
done();
|
||||
@@ -789,7 +769,7 @@ describe('OpenBCIConstants', function() {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
it('shorted', function() {
|
||||
it('shorted', function(done) {
|
||||
k.getChannelSetter(1,false,24,'shorted',true,true,false).then(function(arrayOfCommands) {
|
||||
arrayOfCommands[4].should.equal('1');
|
||||
done();
|
||||
@@ -797,7 +777,7 @@ describe('OpenBCIConstants', function() {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
it('biasMethod', function() {
|
||||
it('biasMethod', function(done) {
|
||||
k.getChannelSetter(1,false,24,'biasMethod',true,true,false).then(function(arrayOfCommands) {
|
||||
arrayOfCommands[4].should.equal('2');
|
||||
done();
|
||||
@@ -805,7 +785,7 @@ describe('OpenBCIConstants', function() {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
it('mvdd', function() {
|
||||
it('mvdd', function(done) {
|
||||
k.getChannelSetter(1,false,24,'mvdd',true,true,false).then(function(arrayOfCommands) {
|
||||
arrayOfCommands[4].should.equal('3');
|
||||
done();
|
||||
@@ -813,7 +793,7 @@ describe('OpenBCIConstants', function() {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
it('temp', function() {
|
||||
it('temp', function(done) {
|
||||
k.getChannelSetter(1,false,24,'temp',true,true,false).then(function(arrayOfCommands) {
|
||||
arrayOfCommands[4].should.equal('4');
|
||||
done();
|
||||
@@ -821,15 +801,15 @@ describe('OpenBCIConstants', function() {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
it('testsig', function() {
|
||||
k.getChannelSetter(1,false,24,'testsig',true,true,false).then(function(arrayOfCommands) {
|
||||
it('testsig', function(done) {
|
||||
k.getChannelSetter(1,false,24,'testSig',true,true,false).then(function(arrayOfCommands) {
|
||||
arrayOfCommands[4].should.equal('5');
|
||||
done();
|
||||
}, function(err) {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
it('biasDrp', function() {
|
||||
it('biasDrp', function(done) {
|
||||
k.getChannelSetter(1,false,24,'biasDrp',true,true,false).then(function(arrayOfCommands) {
|
||||
arrayOfCommands[4].should.equal('6');
|
||||
done();
|
||||
@@ -837,7 +817,7 @@ describe('OpenBCIConstants', function() {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
it('biasDrn', function() {
|
||||
it('biasDrn', function(done) {
|
||||
k.getChannelSetter(1,false,24,'biasDrn',true,true,false).then(function(arrayOfCommands) {
|
||||
arrayOfCommands[4].should.equal('7');
|
||||
done();
|
||||
@@ -845,23 +825,15 @@ describe('OpenBCIConstants', function() {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
it('Invalid setting', function() {
|
||||
k.getChannelSetter(1,false,24,'taco',true,true,false).then(function(arrayOfCommands) {
|
||||
done('Should have rejected promise');
|
||||
}, function(err) {
|
||||
done(err);
|
||||
});
|
||||
it('Invalid setting', function(done) {
|
||||
k.getChannelSetter(1,false,24,'taco',true,true,false).should.be.rejected.and.notify(done);
|
||||
});
|
||||
it('Invalid type', function() {
|
||||
k.getChannelSetter(1,false,24,1,true,true,false).then(function(arrayOfCommands) {
|
||||
done('Should have rejected promise');
|
||||
}, function(err) {
|
||||
done(err);
|
||||
});
|
||||
it('Invalid type', function(done) {
|
||||
k.getChannelSetter(1,false,24,1,true,true,false).should.be.rejected.and.notify(done);
|
||||
});
|
||||
});
|
||||
describe('bias selection works', function() {
|
||||
it('Include', function() {
|
||||
it('Include', function(done) {
|
||||
k.getChannelSetter(1,false,24,'normal',true,true,false).then(function(arrayOfCommands) {
|
||||
arrayOfCommands[5].should.equal('1');
|
||||
done();
|
||||
@@ -869,7 +841,7 @@ describe('OpenBCIConstants', function() {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
it('Remove', function() {
|
||||
it('Remove', function(done) {
|
||||
k.getChannelSetter(1,false,24,'normal',false,true,false).then(function(arrayOfCommands) {
|
||||
arrayOfCommands[5].should.equal('0');
|
||||
done();
|
||||
@@ -877,16 +849,12 @@ describe('OpenBCIConstants', function() {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
it('Invalid type', function() {
|
||||
k.getChannelSetter(1,false,24,'normal','taco',true,false).then(function(arrayOfCommands) {
|
||||
done('Should have rejected promise');
|
||||
}, function(err) {
|
||||
done(err);
|
||||
});
|
||||
it('Invalid type', function(done) {
|
||||
k.getChannelSetter(1,false,24,'normal','taco',true,false).should.be.rejected.and.notify(done);
|
||||
});
|
||||
});
|
||||
describe('SRB2 selection works', function() {
|
||||
it('Connect', function() {
|
||||
it('Connect', function(done) {
|
||||
k.getChannelSetter(1,false,24,'normal',true,true,false).then(function(arrayOfCommands) {
|
||||
arrayOfCommands[6].should.equal('1');
|
||||
done();
|
||||
@@ -894,7 +862,7 @@ describe('OpenBCIConstants', function() {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
it('Disconnect', function() {
|
||||
it('Disconnect', function(done) {
|
||||
k.getChannelSetter(1,false,24,'normal',true,false,false).then(function(arrayOfCommands) {
|
||||
arrayOfCommands[6].should.equal('0');
|
||||
done();
|
||||
@@ -902,16 +870,12 @@ describe('OpenBCIConstants', function() {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
it('Invalid type', function() {
|
||||
k.getChannelSetter(1,false,24,'normal',true,'taco',false).then(function(arrayOfCommands) {
|
||||
done('Should have rejected promise');
|
||||
}, function(err) {
|
||||
done(err);
|
||||
});
|
||||
it('Invalid type', function(done) {
|
||||
k.getChannelSetter(1,false,24,'normal',true,'taco',false).should.be.rejected.and.notify(done);
|
||||
});
|
||||
});
|
||||
describe('SRB1 selection works', function() {
|
||||
it('Connect', function() {
|
||||
it('Connect', function(done) {
|
||||
k.getChannelSetter(1,false,24,'normal',true,true,true).then(function(arrayOfCommands) {
|
||||
arrayOfCommands[7].should.equal('1');
|
||||
done();
|
||||
@@ -919,7 +883,7 @@ describe('OpenBCIConstants', function() {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
it('Disconnect', function() {
|
||||
it('Disconnect', function(done) {
|
||||
k.getChannelSetter(1,false,24,'normal',true,true,false).then(function(arrayOfCommands) {
|
||||
arrayOfCommands[7].should.equal('0');
|
||||
done();
|
||||
@@ -927,18 +891,14 @@ describe('OpenBCIConstants', function() {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
it('Invalid type', function() {
|
||||
k.getChannelSetter(1,false,24,'normal',true,true,'taco').then(function(arrayOfCommands) {
|
||||
done('Should have rejected promise');
|
||||
}, function(err) {
|
||||
done(err);
|
||||
});
|
||||
it('Invalid type', function(done) {
|
||||
k.getChannelSetter(1, false, 24, 'normal', true, true, 'taco').should.be.rejected.and.notify(done);
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('#getChannelSetter', function() {
|
||||
describe('#getImpedanceSetter', function() {
|
||||
describe('channel input selection works', function () {
|
||||
it('channel 2', function () {
|
||||
it('channel 2', function (done) {
|
||||
k.getImpedanceSetter(2, false, false).then(function (arrayOfCommands) {
|
||||
arrayOfCommands[1].should.equal('2');
|
||||
done();
|
||||
@@ -946,7 +906,7 @@ describe('OpenBCIConstants', function() {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
it('channel 5', function () {
|
||||
it('channel 5', function (done) {
|
||||
k.getImpedanceSetter(5, false, false).then(function (arrayOfCommands) {
|
||||
arrayOfCommands[1].should.equal('5');
|
||||
done();
|
||||
@@ -954,7 +914,7 @@ describe('OpenBCIConstants', function() {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
it('channel 9', function () {
|
||||
it('channel 9', function (done) {
|
||||
k.getImpedanceSetter(9, false, false).then(function (arrayOfCommands) {
|
||||
arrayOfCommands[1].should.equal('Q');
|
||||
done();
|
||||
@@ -962,7 +922,7 @@ describe('OpenBCIConstants', function() {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
it('channel 15', function () {
|
||||
it('channel 15', function (done) {
|
||||
k.getImpedanceSetter(15, false, false).then(function (arrayOfCommands) {
|
||||
arrayOfCommands[1].should.equal('U');
|
||||
done();
|
||||
@@ -970,82 +930,67 @@ describe('OpenBCIConstants', function() {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
it('Invalid channel selection', function () {
|
||||
k.getImpedanceSetter(0, false, false).then(function (arrayOfCommands) {
|
||||
done('Should have rejected promise');
|
||||
}, function (err) {
|
||||
done(err);
|
||||
});
|
||||
it('Invalid channel selection', function (done) {
|
||||
k.getImpedanceSetter(0, false, false).should.be.rejected.and.notify(done);
|
||||
});
|
||||
it('Invalid type', function () {
|
||||
k.getImpedanceSetter('1', false, false).then(function (arrayOfCommands) {
|
||||
done('Should have rejected promise');
|
||||
}, function (err) {
|
||||
done(err);
|
||||
});
|
||||
it('Invalid type', function (done) {
|
||||
k.getImpedanceSetter('1', false, false).should.be.rejected.and.notify(done);
|
||||
});
|
||||
});
|
||||
describe('P Input selection works', function() {
|
||||
describe('P Input selection works', function(done) {
|
||||
it('Test Signal Applied', function() {
|
||||
k.getImpedanceSetter(0, true, false).then(function (arrayOfCommands) {
|
||||
k.getImpedanceSetter(1, true, false).then(function (arrayOfCommands) {
|
||||
arrayOfCommands[2].should.equal('1');
|
||||
done();
|
||||
}, function(err) {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
it('Test Signal Not Applied', function() {
|
||||
k.getImpedanceSetter(0, false, false).then(function (arrayOfCommands) {
|
||||
it('Test Signal Not Applied', function(done) {
|
||||
k.getImpedanceSetter(1, false, false).then(function (arrayOfCommands) {
|
||||
console.log('\n\n\narray: ' + arrayOfCommands + '\n\n\n');
|
||||
arrayOfCommands[2].should.equal('0');
|
||||
done();
|
||||
}, function(err) {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
it('Invalid type', function() {
|
||||
k.getImpedanceSetter(0, 'taco', false).then(function (arrayOfCommands) {
|
||||
done('Should have rejected promise');
|
||||
}, function(err) {
|
||||
done(err);
|
||||
});
|
||||
it('Invalid type', function(done) {
|
||||
k.getImpedanceSetter(1, 'taco', false).should.be.rejected.and.notify(done);
|
||||
});
|
||||
});
|
||||
describe('N Input selection works', function() {
|
||||
describe('N Input selection works', function(done) {
|
||||
it('Test Signal Applied', function() {
|
||||
k.getImpedanceSetter(0, true, false).then(function (arrayOfCommands) {
|
||||
k.getImpedanceSetter(1, true, false).then(function (arrayOfCommands) {
|
||||
arrayOfCommands[3].should.equal('1');
|
||||
done();
|
||||
}, function(err) {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
it('Test Signal Not Applied', function() {
|
||||
k.getImpedanceSetter(0, false, false).then(function (arrayOfCommands) {
|
||||
it('Test Signal Not Applied', function(done) {
|
||||
k.getImpedanceSetter(1, false, false).then(function (arrayOfCommands) {
|
||||
arrayOfCommands[3].should.equal('0');
|
||||
done();
|
||||
}, function(err) {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
it('Invalid type', function() {
|
||||
k.getImpedanceSetter(0, false, 'taco').then(function (arrayOfCommands) {
|
||||
done('Should have rejected promise');
|
||||
}, function(err) {
|
||||
done(err);
|
||||
});
|
||||
it('Invalid type', function(done) {
|
||||
k.getImpedanceSetter(1, false, 'taco').should.be.rejected.and.notify(done);
|
||||
});
|
||||
});
|
||||
describe('Prefix and postfix commands work', function() {
|
||||
it('Set', function() {
|
||||
k.getImpedanceSetter(0, true, true).then(function (arrayOfCommands) {
|
||||
it('Set', function(done) {
|
||||
k.getImpedanceSetter(1, true, true).then(function (arrayOfCommands) {
|
||||
arrayOfCommands[0].should.equal('z');
|
||||
done();
|
||||
}, function(err) {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
it('Latch', function() {
|
||||
k.getImpedanceSetter(0, true, true).then(function (arrayOfCommands) {
|
||||
it('Latch', function(done) {
|
||||
k.getImpedanceSetter(1, true, true).then(function (arrayOfCommands) {
|
||||
arrayOfCommands[4].should.equal('Z');
|
||||
done();
|
||||
}, function(err) {
|
||||
|
||||
+233
-34
@@ -2,13 +2,18 @@
|
||||
* Created by ajk on 12/15/15.
|
||||
*/
|
||||
var assert = require('assert');
|
||||
var OpenBCISample = require('../openBCISample');
|
||||
var chai = require('chai')
|
||||
, expect = chai.expect
|
||||
, should = chai.should();
|
||||
var chaiAsPromised = require("chai-as-promised");
|
||||
var openBCISample = require('../openBCISample');
|
||||
var sinon = require('sinon');
|
||||
var chai = require('chai'),
|
||||
should = chai.should(),
|
||||
openBCIBoard = require('../openBCIBoard');
|
||||
|
||||
var k = OpenBCISample.k;
|
||||
var chaiAsPromised = require("chai-as-promised");
|
||||
var sinonChai = require("sinon-chai");
|
||||
chai.use(chaiAsPromised);
|
||||
chai.use(sinonChai);
|
||||
|
||||
var k = openBCISample.k;
|
||||
|
||||
var samplePacket = function () {
|
||||
var byteSample = 0x45;
|
||||
@@ -24,30 +29,31 @@ var sampleBuf = samplePacket();
|
||||
|
||||
|
||||
|
||||
describe('OpenBCISample',function() {
|
||||
describe('openBCISample',function() {
|
||||
describe('#convertPacketToSample', function() {
|
||||
it('should have the correct start byte', function() {
|
||||
var sample = OpenBCISample.convertPacketToSample(sampleBuf);
|
||||
var sample = openBCISample.convertPacketToSample(sampleBuf);
|
||||
assert.equal(k.OBCIByteStart,sample.startByte);
|
||||
});
|
||||
it('should have the correct stop byte', function() {
|
||||
var sample = OpenBCISample.convertPacketToSample(sampleBuf);
|
||||
var sample = openBCISample.convertPacketToSample(sampleBuf);
|
||||
assert.equal(k.OBCIByteStop,sample.stopByte);
|
||||
});
|
||||
it('should have the correct sample number', function() {
|
||||
var sample = OpenBCISample.convertPacketToSample(sampleBuf);
|
||||
var sample = openBCISample.convertPacketToSample(sampleBuf);
|
||||
assert.equal(0x45,sample.sampleNumber);
|
||||
});
|
||||
it('all the channels should have the same number value as their index * scaleFactor', function() {
|
||||
var sample = OpenBCISample.convertPacketToSample(sampleBuf);
|
||||
for(var i = 1;i <= 8;i++) {
|
||||
assert.equal(sample.channelData[i],OpenBCISample.scaleFactorChannel * i);
|
||||
it('all the channels should have the same number value as their (index + 1) * scaleFactor', function() {
|
||||
var sample = openBCISample.convertPacketToSample(sampleBuf);
|
||||
for(var i = 0;i < k.OBCINumberOfChannelsDefault;i++) {
|
||||
//console.log(openBCISample.scaleFactorChannel * i);
|
||||
assert.equal(sample.channelData[i],openBCISample.scaleFactorChannel * (i+1));
|
||||
}
|
||||
});
|
||||
it('all the auxs should have the same number value as their index * scaleFactor', function() {
|
||||
var sample = OpenBCISample.convertPacketToSample(sampleBuf);
|
||||
var sample = openBCISample.convertPacketToSample(sampleBuf);
|
||||
for(var i = 0;i < 3;i++) {
|
||||
assert.equal(sample.auxData[i],OpenBCISample.scaleFactorAux * i);
|
||||
assert.equal(sample.auxData[i],openBCISample.scaleFactorAux * i);
|
||||
}
|
||||
});
|
||||
it('check to see if negative numbers work on channel data',function() {
|
||||
@@ -55,9 +61,8 @@ describe('OpenBCISample',function() {
|
||||
//console.log(temp);
|
||||
var taco = new Buffer([0x81]);
|
||||
taco.copy(temp,2);
|
||||
//console.log(temp);
|
||||
var sample = OpenBCISample.convertPacketToSample(sampleBuf);
|
||||
assert(sample.channelData[1], -8323071 * OpenBCISample.scaleFactorChannel);
|
||||
var sample = openBCISample.convertPacketToSample(temp);
|
||||
sample.channelData[0].should.be.approximately(-8323071 * openBCISample.scaleFactorChannel, 0.001);
|
||||
|
||||
});
|
||||
it('check to see if negative numbers work on aux data',function() {
|
||||
@@ -66,63 +71,257 @@ describe('OpenBCISample',function() {
|
||||
var taco = new Buffer([0x81]);
|
||||
taco.copy(temp,26);
|
||||
//console.log(temp);
|
||||
var sample = OpenBCISample.convertPacketToSample(temp);
|
||||
//OpenBCISample.debugPrettyPrint(sample);
|
||||
assert.equal(sample.auxData[0],-32512 * OpenBCISample.scaleFactorAux);
|
||||
var sample = openBCISample.convertPacketToSample(temp);
|
||||
//openBCISample.debugPrettyPrint(sample);
|
||||
sample.auxData[0].should.be.approximately(-32512 * openBCISample.scaleFactorAux,1);
|
||||
|
||||
});
|
||||
describe('#errorConditions', function() {
|
||||
it('send non data buffer', function() {
|
||||
var sample = openBCISample.convertPacketToSample(1);
|
||||
assert.equal(undefined,sample);
|
||||
});
|
||||
it('bad start byte', function() {
|
||||
var temp = samplePacket();
|
||||
temp[0] = 69;
|
||||
var sample = openBCISample.convertPacketToSample(temp);
|
||||
assert.equal(undefined,sample);
|
||||
});
|
||||
it('bad stop byte', function() {
|
||||
var temp = samplePacket();
|
||||
temp[32] = 69;
|
||||
var sample = openBCISample.convertPacketToSample(temp);
|
||||
assert.equal(undefined,sample);
|
||||
});
|
||||
it('wrong number of bytes', function() {
|
||||
var sample = openBCISample.convertPacketToSample(new Buffer(5));
|
||||
assert.equal(undefined,sample);
|
||||
});
|
||||
it('undefined', function() {
|
||||
var sample = openBCISample.convertPacketToSample();
|
||||
assert.equal(undefined,sample);
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('#convertSampleToPacket', function() {
|
||||
var generateSample = openBCISample.randomSample(k.OBCINumberOfChannelsDefault, k.OBCISampleRate250);
|
||||
|
||||
// get new sample
|
||||
var newSample = generateSample(0);
|
||||
|
||||
// try to convert to packet
|
||||
var packetBuffer = openBCISample.convertSampleToPacket(newSample);
|
||||
|
||||
it('should have correct start byte', function() {
|
||||
packetBuffer[0].should.equal(k.OBCIByteStart,'confirming start byte');
|
||||
});
|
||||
it('should have correct stop byte', function() {
|
||||
packetBuffer[k.OBCIPacketSize - 1].should.equal(k.OBCIByteStop,'confirming stop byte');
|
||||
});
|
||||
it('should have correct sample number', function() {
|
||||
packetBuffer[1].should.equal(1,'confirming sample number is 1 more than 0');
|
||||
});
|
||||
it('should convert channel data to binary', function() {
|
||||
var sample = openBCISample.convertPacketToSample(packetBuffer);
|
||||
for(var i = 0; i < k.OBCINumberOfChannelsDefault; i++) {
|
||||
sample.channelData[i].should.be.approximately(newSample.channelData[i],0.001);
|
||||
}
|
||||
});
|
||||
it('should convert aux data to binary', function() {
|
||||
var sample = openBCISample.convertPacketToSample(packetBuffer);
|
||||
for(var i = 0; i < 3; i++) {
|
||||
sample.auxData[i].should.be.approximately(newSample.auxData[i],0.001);
|
||||
}
|
||||
});
|
||||
});
|
||||
describe('#interpret24bitAsInt32', function() {
|
||||
it('converts a small positive number', function() {
|
||||
var buf1 = new Buffer([0x00,0x06,0x90]); // 0x000690 === 1680
|
||||
var num = OpenBCISample.interpret24bitAsInt32(buf1);
|
||||
var num = openBCISample.interpret24bitAsInt32(buf1);
|
||||
assert.equal(num,1680);
|
||||
});
|
||||
it('converts a large positive number', function() {
|
||||
var buf1 = new Buffer([0x02,0xC0,0x01]); // 0x02C001 === 180225
|
||||
var num = OpenBCISample.interpret24bitAsInt32(buf1);
|
||||
var num = openBCISample.interpret24bitAsInt32(buf1);
|
||||
assert.equal(num,180225);
|
||||
});
|
||||
it('converts a small negative number', function() {
|
||||
var buf1 = new Buffer([0xFF,0xFF,0xFF]); // 0xFFFFFF === -1
|
||||
var num = OpenBCISample.interpret24bitAsInt32(buf1);
|
||||
assert.equal(num,-1);
|
||||
var num = openBCISample.interpret24bitAsInt32(buf1);
|
||||
num.should.be.approximately(-1,1);
|
||||
});
|
||||
it('converts a large negative number', function() {
|
||||
var buf1 = new Buffer([0x81,0xA1,0x01]); // 0x81A101 === -8281855
|
||||
var num = OpenBCISample.interpret24bitAsInt32(buf1);
|
||||
assert.equal(num,-8281855);
|
||||
var num = openBCISample.interpret24bitAsInt32(buf1);
|
||||
num.should.be.approximately(-8281855,1);
|
||||
});
|
||||
});
|
||||
describe('#interpret16bitAsInt32', function() {
|
||||
it('converts a small positive number', function() {
|
||||
var buf1 = new Buffer([0x06,0x90]); // 0x0690 === 1680
|
||||
var num = OpenBCISample.interpret16bitAsInt32(buf1);
|
||||
var num = openBCISample.interpret16bitAsInt32(buf1);
|
||||
assert.equal(num,1680);
|
||||
});
|
||||
it('converts a large positive number', function() {
|
||||
var buf1 = new Buffer([0x02,0xC0]); // 0x02C0 === 704
|
||||
var num = OpenBCISample.interpret16bitAsInt32(buf1);
|
||||
var num = openBCISample.interpret16bitAsInt32(buf1);
|
||||
assert.equal(num,704);
|
||||
});
|
||||
it('converts a small negative number', function() {
|
||||
var buf1 = new Buffer([0xFF,0xFF]); // 0xFFFF === -1
|
||||
var num = OpenBCISample.interpret16bitAsInt32(buf1);
|
||||
var num = openBCISample.interpret16bitAsInt32(buf1);
|
||||
assert.equal(num,-1);
|
||||
});
|
||||
it('converts a large negative number', function() {
|
||||
var buf1 = new Buffer([0x81,0xA1]); // 0x81A1 === -32351
|
||||
var num = OpenBCISample.interpret16bitAsInt32(buf1);
|
||||
var num = openBCISample.interpret16bitAsInt32(buf1);
|
||||
assert.equal(num,-32351);
|
||||
});
|
||||
});
|
||||
describe('#floatTo3ByteBuffer', function() {
|
||||
it('converts random floats to a 3-byte buffer', function() {
|
||||
var generateSample = openBCISample.randomSample(k.OBCINumberOfChannelsDefault, k.OBCISampleRate250);
|
||||
var newSample = generateSample(0);
|
||||
|
||||
for (var i = 0; i < k.OBCINumberOfChannelsDefault; i++) {
|
||||
var buff = openBCISample.floatTo3ByteBuffer(newSample.channelData[i]);
|
||||
|
||||
var num = openBCISample.interpret24bitAsInt32(buff);
|
||||
|
||||
num = num * openBCISample.scaleFactorChannel;
|
||||
|
||||
num.should.be.approximately(newSample.channelData[i],0.00002);
|
||||
}
|
||||
});
|
||||
});
|
||||
describe('#floatTo2ByteBuffer', function() {
|
||||
it('converts random floats to a 2-byte buffer', function() {
|
||||
var auxData = [0.001,1,-0.00892];
|
||||
|
||||
for (var i = 0; i < 3 ; i++) {
|
||||
var buff = openBCISample.floatTo2ByteBuffer(auxData[i]);
|
||||
|
||||
var num = openBCISample.interpret16bitAsInt32(buff);
|
||||
|
||||
num = num * openBCISample.scaleFactorAux;
|
||||
|
||||
num.should.be.approximately(auxData[i],0.001);
|
||||
}
|
||||
});
|
||||
});
|
||||
describe('#randomSample', function() {
|
||||
it('should generate a random sample',function() {
|
||||
var generateSample = OpenBCISample.randomSample(k.OBCINumberOfChannelsDefault, k.OBCISampleRate250);
|
||||
var generateSample = openBCISample.randomSample(k.OBCINumberOfChannelsDefault, k.OBCISampleRate250);
|
||||
var oldSampleNumber = 0;
|
||||
var newSample = generateSample(oldSampleNumber);
|
||||
console.log(JSON.stringify(newSample));
|
||||
assert(newSample.sampleNumber,oldSampleNumber+1);
|
||||
describe('#debugPrettyPrint',function() {
|
||||
it('works with a good sample',function() {
|
||||
openBCISample.debugPrettyPrint(newSample);
|
||||
});
|
||||
it('does not with a undefined sample',function() {
|
||||
openBCISample.debugPrettyPrint();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
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) {
|
||||
var bad;
|
||||
openBCISample.impedanceCalculationForChannel('taco',69).should.be.rejected.and.notify(done);
|
||||
});
|
||||
});
|
||||
describe('#impedanceSummarize', function() {
|
||||
var impedanceArray = [];
|
||||
var numberOfChannels = 8;
|
||||
beforeEach(() => {
|
||||
impedanceArray = openBCISample.impedanceArray(numberOfChannels);
|
||||
});
|
||||
it('should find impedance good', function() {
|
||||
impedanceArray[0].data = [5201.84, 7583.14, 2067.17, 0, 4132.37, 3189.33, 0, 3010.21, 7720.12, 4095.69, 0, 2730.19];
|
||||
|
||||
openBCISample.impedanceSummarize(impedanceArray[0]);
|
||||
|
||||
var sum = 0;
|
||||
var arrLen = impedanceArray[0].data.length;
|
||||
for (var i = 0; i < arrLen; i++) {
|
||||
sum += impedanceArray[0].data[i];
|
||||
}
|
||||
var avg = sum / arrLen;
|
||||
|
||||
impedanceArray[0].average.should.be.approximately(avg,10); // Check the average
|
||||
impedanceArray[0].text.should.equal(k.OBCIImpedanceTextGood); // Check the text
|
||||
});
|
||||
it('should find impedance ok', function() {
|
||||
impedanceArray[0].data = [5201.84, 7583.14, 6067.17, 4305.43, 4132.37, 9189.33, 6925.34, 5010.21, 7720.12, 6095.69, 8730.19];
|
||||
|
||||
openBCISample.impedanceSummarize(impedanceArray[0]);
|
||||
|
||||
var sum = 0;
|
||||
var arrLen = impedanceArray[0].data.length;
|
||||
for (var i = 0; i < arrLen; i++) {
|
||||
sum += impedanceArray[0].data[i];
|
||||
}
|
||||
var avg = sum / arrLen;
|
||||
|
||||
impedanceArray[0].average.should.be.approximately(avg,10); // Check the average
|
||||
impedanceArray[0].text.should.equal(k.OBCIImpedanceTextOk); // Check the text
|
||||
});
|
||||
it('should find impedance bad', function() {
|
||||
impedanceArray[0].data = [10201.84, 12583.14, 16067.17, 14305.43, 14132.37, 13189.33, 16925.34, 15010.21, 17720.12, 16095.69, 18730.19];
|
||||
|
||||
openBCISample.impedanceSummarize(impedanceArray[0]);
|
||||
|
||||
var sum = 0;
|
||||
var arrLen = impedanceArray[0].data.length;
|
||||
for (var i = 0; i < arrLen; i++) {
|
||||
sum += impedanceArray[0].data[i];
|
||||
}
|
||||
var avg = sum / arrLen;
|
||||
|
||||
impedanceArray[0].average.should.be.approximately(avg,10); // Check the average
|
||||
impedanceArray[0].text.should.equal(k.OBCIImpedanceTextBad); // Check the text
|
||||
});
|
||||
it('should find impedance none', function() {
|
||||
impedanceArray[0].data = [44194179.09, 44194179.09, 44194179.09, 44194179.09, 44194179.09, 44194179.09, 44194179.09, 44194179.09, 44194179.09, 44194179.09, 44194179.09];
|
||||
|
||||
openBCISample.impedanceSummarize(impedanceArray[0]);
|
||||
|
||||
var sum = 0;
|
||||
var arrLen = impedanceArray[0].data.length;
|
||||
for (var i = 0; i < arrLen; i++) {
|
||||
sum += impedanceArray[0].data[i];
|
||||
}
|
||||
var avg = sum / arrLen;
|
||||
|
||||
impedanceArray[0].average.should.be.approximately(avg,10); // Check the average
|
||||
impedanceArray[0].text.should.equal(k.OBCIImpedanceTextNone); // Check the text
|
||||
});
|
||||
it('should remove outliers from data and find good impedance', function() {
|
||||
impedanceArray[0].data = [5201.84, 7583.14, 1112067.17, 0, 4132.37, 3189.33, 0, 1113010.21, 7720.12, 4095.69, 0, 2730.19];
|
||||
|
||||
openBCISample.impedanceSummarize(impedanceArray[0]);
|
||||
|
||||
var cleanedData = [5201.84, 7583.14, 0, 4132.37, 3189.33, 0, 7720.12, 4095.69, 0, 2730.19];
|
||||
|
||||
var sum = 0;
|
||||
var arrLen = cleanedData.length;
|
||||
for (var i = 0; i < arrLen; i++) {
|
||||
sum += cleanedData[i];
|
||||
}
|
||||
var avg = sum / arrLen;
|
||||
|
||||
impedanceArray[0].average.should.be.approximately(avg,10); // Check the average
|
||||
impedanceArray[0].text.should.equal(k.OBCIImpedanceTextGood); // Check the text
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
+1120
-117
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
@@ -12,8 +12,8 @@ var Hardware = function () {
|
||||
// write: this.write.bind(this),
|
||||
// softReset: this.softReset.bind(this),
|
||||
// autoFindOpenBCIBoard: this.autoFindOpenBCIBoard.bind(this),
|
||||
// simulatorStart: this.simulatorStart.bind(this),
|
||||
// simulatorStop: this.simulatorStop.bind(this)
|
||||
// simulatorEnable: this.simulatorEnable.bind(this),
|
||||
// simulatorDisable: this.simulatorDisable.bind(this)
|
||||
//};
|
||||
};
|
||||
|
||||
@@ -75,7 +75,7 @@ Hardware.prototype.streamStop = function () {
|
||||
});
|
||||
};
|
||||
|
||||
Hardware.prototype.simulatorStart = function () {
|
||||
Hardware.prototype.simulatorEnable = function () {
|
||||
return new Promise((resolve,reject) => {
|
||||
if(!this.bciBoard) reject('Board does not exist - call hardware.createBoard() first');
|
||||
|
||||
@@ -84,7 +84,7 @@ Hardware.prototype.simulatorStart = function () {
|
||||
});
|
||||
};
|
||||
|
||||
Hardware.prototype.simulatorStop = function () {
|
||||
Hardware.prototype.simulatorDisable = function () {
|
||||
return new Promise((resolve,reject) => {
|
||||
if(!this.bciBoard) reject('Board does not exist - call hardware.createBoard() first');
|
||||
|
||||
|
||||
Referência em uma Nova Issue
Bloquear um usuário