Comparar commits

..

12 Commits

Autor SHA1 Mensagem Data
AJ Keller ee66c49ff0 Update changelog.md
Forgot to update change log on merge
2016-06-21 21:21:14 -04:00
Andy Heusser abfb37a38e Merge pull request #65 from pushtheworldllc/dev-serialport-upgrade
Dev serialport upgrade
2016-06-21 17:14:40 -04:00
AJ Keller 48be1a01db ENH add more travis versions 2016-06-21 07:36:50 -04:00
AJ Keller 8bbc011ead ENH bump serialport to 3.0.0 2016-06-21 07:33:38 -04:00
Teon L Brooks cc839b3b32 Merge pull request #62 from pushtheworldllc/dev-sim-accel
Add accel data to simulator closes #61
2016-06-10 00:04:22 -04:00
AJ Keller e2cd5d1dd7 Add accel data to simulator closes #61 2016-06-09 21:44:22 -04:00
AJ Keller 682074dff7 Update README.md 2016-06-02 22:34:45 -04:00
AJ Keller 0af11eabe5 Update README.md 2016-06-02 22:34:05 -04:00
AJ Keller 31eea736dd Merge pull request #60 from pushtheworldllc/dev
ADD SD card support functions
2016-06-02 22:16:31 -04:00
AJ Keller 8cafa3f7ff ADD SD Card Support Functions 2016-06-02 22:12:17 -04:00
AJ Keller 971787720e Merge pull request #57 from pushtheworldllc/bug-ci-fail
Removed auto test dependent on ntp with travis fail
2016-05-01 12:31:22 -04:00
AJ Keller c267cca924 Removed auto test dependent on ntp with travis fail 2016-05-01 12:28:01 -04:00
11 arquivos alterados com 438 adições e 23 exclusões
+5
Ver Arquivo
@@ -1,7 +1,12 @@
language: node_js
node_js:
- "4.0"
- "4.1"
- "4.2"
- "5.11.0"
- "6.0"
- "6.1"
- "6.2"
install:
- npm install --all
script:
+31 -3
Ver Arquivo
@@ -3,7 +3,7 @@
[![Build Status](https://travis-ci.org/OpenBCI/openbci-js-sdk.svg?branch=master)](https://travis-ci.org/OpenBCI/openbci-js-sdk)
[![codecov.io](https://codecov.io/github/OpenBCI/openbci-js-sdk/coverage.svg?branch=master)](https://codecov.io/github/OpenBCI/openbci-js-sdk?branch=master)
# openbci-sdk
# OpenBCI Node.js SDK
A Node.js module for OpenBCI ~ written with love by [Push The World!](http://www.pushtheworldllc.com)
@@ -290,7 +290,7 @@ Board optional configurations.
* `simulatorSampleRate` - The sample rate to use for the simulator (Default is `250`)
* `simulatorAlpha` - {Boolean} - Inject and 10Hz alpha wave in Channels 1 and 2 (Default `true`)
* `simulatorLineNoise` - Injects line noise on channels.
* `60Hz` - 60Hz line noise (Default) (ex. __Unite States__)
* `60Hz` - 60Hz line noise (Default) (ex. __United States__)
* `50Hz` - 50Hz line noise (ex. __Europe__)
* `None` - Do not inject line noise.
* `sntp` - Syncs the module up with an SNTP time server. Syncs the board on startup with the SNTP time. Adds a time stamp to the AUX channels. NOTE: (NOT FULLY IMPLEMENTED) [DO NOT USE]
@@ -599,6 +599,34 @@ Get the current sample rate.
**_Returns_** a number, the current sample rate.
### .sdStart(recordingDuration)
Start logging to the SD card. If you are not streaming when you send this command, then you should expect to get a success or failure message followed by and end of transmission `$$$`.
**_recordingDuration_**
The duration you want to log SD information for. Opens a new SD file to write into. Limited to:
* `14sec` - 14 seconds
* `5min` - 5 minutes
* `15min` - 15 minutes
* `30min` - 30 minutes
* `1hour` - 1 hour
* `2hour` - 2 hour
* `4hour` - 4 hour
* `12hour` - 12 hour
* `24hour` - 24 hour
**Note: You must have the proper type of SD card inserted into the board for logging to work.**
**_Returns_** resolves if the command was added to the write queue.
### .sdStop()
Stop logging to the SD card and close any open file. If you are not streaming when you send this command, then you should expect to get a success or failure message followed by and end of transmission `$$$`. The success message contains a lot of useful information about what happened when writing to the SD card.
**_Returns_** resolves if the command was added to the write queue.
### .simulatorEnable()
To enter simulate mode. Must call `.connect()` after.
@@ -798,4 +826,4 @@ npm test
6. Submit a pull request :D
## License
MIT
MIT
+24 -2
Ver Arquivo
@@ -1,4 +1,26 @@
# 0.3.3
# 0.3.7
### New Features
* Upgrade dependencies
* Update Travis
# 0.3.6
### New Features
* Simulator now has accelerometer data
# 0.3.5
### New Features
* SD card support! Now logging to an SD card is easier than ever.
### Bug Fixes
* Sample rate does not return correct sample rate for custom rate on simulator. #58
# 0.3.4
### New Features
@@ -65,4 +87,4 @@
### Github Issues Addressed
* #25, #26, #27, #29, #30, #31, #33, #34
* #25, #26, #27, #29, #30, #31, #33, #34
+49 -3
Ver Arquivo
@@ -987,6 +987,48 @@ function OpenBCIFactory() {
});
};
/**
* @description Start logging to the SD card.
* @param recordingDuration {String} - The duration you want to log SD information for. Limited to:
* '14sec', '5min', '15min', '30min', '1hour', '2hour', '4hour', '12hour', '24hour'
* @returns {Promise} - Resolves if the command was added to write queue.
* @author AJ Keller (@pushtheworldllc)
*/
OpenBCIBoard.prototype.sdStart = function(recordingDuration) {
return new Promise((resolve,reject) => {
if (!this.connected) reject('Must be connected to the device');
k.sdSettingForString(recordingDuration)
.then(command => {
// If we are not streaming, then expect a confirmation message back from the board
if (!this.streaming) {
this.isLookingForKeyInBuffer = true;
this.searchingBuf = this.searchBuffers.miscStop;
}
this.writeOutDelay = k.OBCIWriteIntervalDelayMSNone;
return this.write(command);
})
.catch(err => reject(err));
});
};
/**
* @description Sends the stop SD logging command to the board.
* @returns {Promise}
*/
OpenBCIBoard.prototype.sdStop = function() {
return new Promise((resolve,reject) => {
if (!this.connected) reject('Must be connected to the device');
// If we are not streaming, then expect a confirmation message back from the board
if (!this.streaming) {
this.isLookingForKeyInBuffer = true;
this.searchingBuf = this.searchBuffers.miscStop;
}
this.writeOutDelay = k.OBCIWriteIntervalDelayMSNone;
return this.write(k.OBCISDLogStop);
});
};
/**
* @description Get the the current sample rate is.
* @returns {Number} The sample rate
@@ -994,10 +1036,14 @@ function OpenBCIFactory() {
* @author AJ Keller (@pushtheworldllc)
*/
OpenBCIBoard.prototype.sampleRate = function() {
if(this.options.boardType === k.OBCIBoardDaisy) {
return k.OBCISampleRate125;
if (this.options.simulate) {
return this.options.simulatorSampleRate;
} else {
return k.OBCISampleRate250;
if(this.options.boardType === k.OBCIBoardDaisy) {
return k.OBCISampleRate125;
} else {
return k.OBCISampleRate250;
}
}
};
+63
Ver Arquivo
@@ -126,6 +126,17 @@ const kOBCISDLogForMin30 = 'F';
const kOBCISDLogForSec14 = 'a';
const kOBCISDLogStop = 'j';
/** SD Card String Commands */
const kOBCIStringSDHour1 = '1hour';
const kOBCIStringSDHour2 = '2hour';
const kOBCIStringSDHour4 = '4hour';
const kOBCIStringSDHour12 = '12hour';
const kOBCIStringSDHour24 = '24hour';
const kOBCIStringSDMin5 = '5min';
const kOBCIStringSDMin15 = '15min';
const kOBCIStringSDMin30 = '30min';
const kOBCIStringSDSec14 = '14sec';
/** Stream Data Commands */
const kOBCIStreamStart = 'b';
const kOBCIStreamStop = 's';
@@ -519,6 +530,58 @@ module.exports = {
OBCISDLogForMin30:kOBCISDLogForMin30,
OBCISDLogForSec14:kOBCISDLogForSec14,
OBCISDLogStop:kOBCISDLogStop,
/** SD Card String Commands */
OBCIStringSDHour1:kOBCIStringSDHour1,
OBCIStringSDHour2:kOBCIStringSDHour2,
OBCIStringSDHour4:kOBCIStringSDHour4,
OBCIStringSDHour12:kOBCIStringSDHour12,
OBCIStringSDHour24:kOBCIStringSDHour24,
OBCIStringSDMin5:kOBCIStringSDMin5,
OBCIStringSDMin15:kOBCIStringSDMin15,
OBCIStringSDMin30:kOBCIStringSDMin30,
OBCIStringSDSec14:kOBCIStringSDSec14,
/**
* @description Converts a sd string into the proper setting.
* @param stringCommand {String} - The length of time you want to record to the SD for.
* @returns {Promise} The command to send to the Board, returns an error on improper `stringCommand`
*/
sdSettingForString: (stringCommand) => {
return new Promise((resolve,reject) => {
switch (stringCommand) {
case kOBCIStringSDHour1:
resolve(kOBCISDLogForHour1);
break;
case kOBCIStringSDHour2:
resolve(kOBCISDLogForHour2);
break;
case kOBCIStringSDHour4:
resolve(kOBCISDLogForHour4);
break;
case kOBCIStringSDHour12:
resolve(kOBCISDLogForHour12);
break;
case kOBCIStringSDHour24:
resolve(kOBCISDLogForHour24);
break;
case kOBCIStringSDMin5:
resolve(kOBCISDLogForMin5);
break;
case kOBCIStringSDMin15:
resolve(kOBCISDLogForMin15);
break;
case kOBCIStringSDMin30:
resolve(kOBCISDLogForMin30);
break;
case kOBCIStringSDSec14:
resolve(kOBCISDLogForSec14);
break;
default:
reject(new Error(TypeError));
break;
}
});
},
/** Stream Data Commands */
OBCIStreamStart:kOBCIStreamStart,
OBCIStreamStop:kOBCIStreamStop,
+35 -10
Ver Arquivo
@@ -296,16 +296,17 @@ var sampleModule = {
sinePhaseRad.fill(0);
var auxData = [0,0,0];
var accelCounter = 0;
// With 250Hz, every 10 samples, with 125Hz, every 5...
var samplesPerAccelRate = Math.floor(sampleRateHz / 25); // best to make this an integer
if (samplesPerAccelRate < 1) samplesPerAccelRate = 1;
// Init arrays to hold coefficients for each channel
var b0 = new Array(numberOfChannels);
var b1 = new Array(numberOfChannels);
var b2 = new Array(numberOfChannels);
// Init arrays to hold coefficients for each channel and init to 0
// This gives the 1/f filter memory on each iteration
var b0 = new Array(numberOfChannels).fill(0);
var b1 = new Array(numberOfChannels).fill(0);
var b2 = new Array(numberOfChannels).fill(0);
// Init coefficients to 0
b0.fill(0);
b1.fill(0);
b2.fill(0);
return function(previousSampleNumber) {
var newSample = self.newSample();
@@ -315,7 +316,7 @@ var sampleModule = {
whiteNoise = distribution.ppf(Math.random()) * Math.sqrt(sampleRateHz/2)/uVolts;
switch (i) {
case 0: // Add 10Hz signal to channel 1... briany
case 0: // Add 10Hz signal to channel 1... brainy
case 1:
if (injectAlpha) {
sinePhaseRad[i] += 2 * Math.PI * sineWaveFreqHz10 / sampleRateHz;
@@ -355,7 +356,31 @@ var sampleModule = {
} else {
newSample.sampleNumber = previousSampleNumber + 1;
}
newSample.auxData = auxData;
/**
* Sample rate of accelerometer is 25Hz... when the accelCounter hits the relative sample rate of the accel
* we will output a new accel value. The approach will be to consider that Z should be about 1 and X and Y
* should be somewhere around 0.
*/
if (accelCounter == samplesPerAccelRate) {
// Initialize a new array
var accelArray = [0,0,0];
// Calculate X
accelArray[0] = (Math.random() * 0.1 * (Math.random() > 0.5 ? -1 : 1));
// Calculate Y
accelArray[1] = (Math.random() * 0.1 * (Math.random() > 0.5 ? -1 : 1));
// Calculate Z, this is around 1
accelArray[2] = 1 - ((Math.random() * 0.4) * (Math.random() > 0.5 ? -1 : 1));
// Store the newly calculated value
newSample.auxData = accelArray;
// Reset the counter
accelCounter = 0;
} else {
// Increment counter
accelCounter++;
// Store the default value
newSample.auxData = auxData;
}
return newSample;
};
+38 -1
Ver Arquivo
@@ -41,6 +41,11 @@ function OpenBCISimulatorFactory() {
// Bools
this.connected = false;
this.sd = {
active:false,
startTime: 0
};
this.streaming = false;
// Buffers
this.buffer = new Buffer(500);
// Numbers
@@ -87,13 +92,45 @@ function OpenBCISimulatorFactory() {
switch (data[0]) {
case k.OBCIStreamStart:
if (!this.stream) this._startStream();
this.streaming = true;
break;
case k.OBCIStreamStop:
if (this.stream) clearInterval(this.stream); // Stops the stream
this.streaming = false;
break;
case k.OBCIMiscSoftReset:
if (this.stream) clearInterval(this.stream);
this.emit('data', new Buffer('OpenBCI Board Simulator\nPush The World V-0.2\n$$$'));
this.streaming = false;
this.emit('data', new Buffer('OpenBCI Board Simulator\nPush The World\nFirmware: v2$$$'));
break;
case k.OBCISDLogForHour1:
case k.OBCISDLogForHour2:
case k.OBCISDLogForHour4:
case k.OBCISDLogForHour12:
case k.OBCISDLogForHour24:
case k.OBCISDLogForMin5:
case k.OBCISDLogForMin15:
case k.OBCISDLogForMin30:
case k.OBCISDLogForSec14:
// If we are not streaming, then do verbose output
if (!this.streaming) {
this.emit('data', new Buffer('Wiring is correct and a card is present.\nCorresponding SD file OBCI_69.TXT\n$$$'));
}
this.sd.active = true;
this.sd.startTime = now();
break;
case k.OBCISDLogStop:
if (!this.streaming) {
if (this.SDLogActive) {
this.emit('data', new Buffer('Total Elapsed Time: ' + (now() - this.sd.startTime) + ' ms\n'));
this.emit('data', new Buffer('Max write time: ' + (Math.random()*500) + ' us\n'));
this.emit('data', new Buffer('Min write time: ' + (Math.random()*200) + ' us\n'));
this.emit('data', new Buffer('Overruns: 0\n$$$'));
} else {
this.emit('data', new Buffer('No open file to close\n$$$'));
}
}
this.SDLogActive = false;
break;
case k.OBCISyncClockStart:
setTimeout(() => {
+4 -3
Ver Arquivo
@@ -1,7 +1,7 @@
{
"name": "openbci-sdk",
"version": "0.3.4",
"description": "A fully NodeJS based API for the OpenBCI board connecting to the hardware directly over serial",
"version": "0.3.7",
"description": "The official Node.js SDK for the OpenBCI Biosensor Board.",
"main": "openBCIBoard",
"scripts": {
"start": "node index",
@@ -18,7 +18,8 @@
"gaussian": "^1.0.0",
"istanbul": "^0.4.2",
"performance-now": "^0.2.0",
"serialport": "~2.1.0",
"scientific-statistics": "^0.2.7",
"serialport": "3.1.2",
"sntp": "^2.0.0"
},
"directories": {
+80
Ver Arquivo
@@ -323,6 +323,86 @@ describe('OpenBCIConstants', function() {
assert.equal('j', k.OBCISDLogStop);
});
});
describe('SD card string Commands',function() {
it('logs for 1 hour', function() {
assert.equal('1hour', k.OBCIStringSDHour1);
});
it('logs for 2 hours', function() {
assert.equal('2hour', k.OBCIStringSDHour2);
});
it('logs for 4 hours', function() {
assert.equal('4hour', k.OBCIStringSDHour4);
});
it('logs for 12 hours', function() {
assert.equal('12hour', k.OBCIStringSDHour12);
});
it('logs for 24 hours', function() {
assert.equal('24hour', k.OBCIStringSDHour24);
});
it('logs for 5 minutes', function() {
assert.equal('5min', k.OBCIStringSDMin5);
});
it('logs for 15 minutes', function() {
assert.equal('15min', k.OBCIStringSDMin15);
});
it('logs for 30 minutes', function() {
assert.equal('30min', k.OBCIStringSDMin30);
});
it('logs for 14 seconds', function() {
assert.equal('14sec', k.OBCIStringSDSec14);
});
});
describe('#sdSettingForString',function() {
it('correct command for 1 hour', function() {
var expectation = k.OBCISDLogForHour1;
var result = k.sdSettingForString('1hour');
return expect(result).to.eventually.equal(expectation);
});
it('correct command for 2 hour', function() {
var expectation = k.OBCISDLogForHour2;
var result = k.sdSettingForString('2hour');
return expect(result).to.eventually.equal(expectation);
});
it('correct command for 4 hour', function() {
var expectation = k.OBCISDLogForHour4;
var result = k.sdSettingForString('4hour');
return expect(result).to.eventually.equal(expectation);
});
it('correct command for 12 hour', function() {
var expectation = k.OBCISDLogForHour12;
var result = k.sdSettingForString('12hour');
return expect(result).to.eventually.equal(expectation);
});
it('correct command for 24 hour', function() {
var expectation = k.OBCISDLogForHour24;
var result = k.sdSettingForString('24hour');
return expect(result).to.eventually.equal(expectation);
});
it('correct command for 5 min', function() {
var expectation = k.OBCISDLogForMin5;
var result = k.sdSettingForString('5min');
return expect(result).to.eventually.equal(expectation);
});
it('correct command for 15 min', function() {
var expectation = k.OBCISDLogForMin15;
var result = k.sdSettingForString('15min');
return expect(result).to.eventually.equal(expectation);
});
it('correct command for 30 min', function() {
var expectation = k.OBCISDLogForMin30;
var result = k.sdSettingForString('30min');
return expect(result).to.eventually.equal(expectation);
});
it('correct command for 14 seconds', function() {
var expectation = k.OBCISDLogForSec14;
var result = k.sdSettingForString('14sec');
return expect(result).to.eventually.equal(expectation);
});
it('Invalid command request', function() {
var result = k.sdSettingForString('taco');
return expect(result).to.be.rejected;
});
});
describe('Stream Data Commands',function() {
it('starts',function () {
assert.equal('b', k.OBCIStreamStart);
+17
Ver Arquivo
@@ -242,6 +242,23 @@ describe('openBCISample',function() {
});
});
});
it('should generate a sample with accel data every 25Hz',function() {
var generateSample = openBCISample.randomSample(k.OBCINumberOfChannelsDefault, k.OBCISampleRate250);
var newSample = generateSample(0);
var passed = false;
// Should get one non-zero auxData array (on the 10th sample)
for (var i = 0; i < 10; i++) {
newSample = generateSample(newSample.sampleNumber);
if (newSample.auxData[0] !== 0 || newSample.auxData[1] !== 0 || newSample.auxData[2] !== 0) {
passed = true;
newSample.auxData[0].should.be.approximately(0,0.1);
newSample.auxData[1].should.be.approximately(0,0.1);
newSample.auxData[2].should.be.approximately(1,0.4);
}
}
assert(passed,"a sample with accel data was produced");
});
});
describe('#impedanceCalculationForChannel', function() {
+92 -1
Ver Arquivo
@@ -104,6 +104,15 @@ describe('openbci-sdk',function() {
});
(ourBoard.options.simulate).should.equal(true);
});
it('can enter simulate mode with different sample rate', function() {
ourBoard = new openBCIBoard.OpenBCIBoard({
simulate: true,
simulatorSampleRate: 69
});
(ourBoard.options.simulate).should.equal(true);
(ourBoard.options.simulatorSampleRate).should.equal(69);
(ourBoard.sampleRate()).should.equal(69);
});
it('can turn 50Hz line noise on', function() {
ourBoard = new openBCIBoard.OpenBCIBoard({
simulatorLineNoise: '50Hz'
@@ -315,6 +324,87 @@ describe('openbci-sdk',function() {
});
})
});
describe('#sdStart',function() {
before(function(done) {
ourBoard.connect(masterPortName)
.then(() => {
ourBoard.once('ready',done);
})
.catch(err => done(err));
});
afterEach(function(done) {
ourBoard.sdStop()
.catch(done);
ourBoard.once('ready',done);
});
after(function(done) {
ourBoard.disconnect()
.then(done)
.catch(err => done(err));
});
it('can start 14 seconds of logging with sd',function(done) {
ourBoard.sdStart('14sec')
.catch(err => done(err));
ourBoard.once('ready',done);
});
it('can start 5 minutes of logging with sd',function(done) {
ourBoard.sdStart('5min')
.catch(err => done(err));
ourBoard.once('ready',done);
});
it('can start 15 minutes of logging with sd',function(done) {
ourBoard.sdStart('15min')
.catch(err => done(err));
ourBoard.once('ready',done);
});
it('can start 30 minutes of logging with sd',function(done) {
ourBoard.sdStart('30min')
.catch(err => done(err));
ourBoard.once('ready',done);
});
it('can start 1 hour of logging with sd',function(done) {
ourBoard.sdStart('1hour')
.catch(err => done(err));
ourBoard.once('ready',done);
});
it('can start 2 hours of logging with sd',function(done) {
ourBoard.sdStart('2hour')
.catch(err => done(err));
ourBoard.once('ready',done);
});
it('can start 4 hours of logging with sd',function(done) {
ourBoard.sdStart('4hour')
.catch(err => done(err));
ourBoard.once('ready',done);
});
it('can start 12 hours of logging with sd',function(done) {
ourBoard.sdStart('12hour')
.catch(err => done(err));
ourBoard.once('ready',done);
});
it('can start 24 hours of logging with sd',function(done) {
ourBoard.sdStart('24hour')
.catch(done);
ourBoard.once('ready',done);
});
});
describe('#sdStop',function() {
before(function(done) {
ourBoard.connect(masterPortName).catch(err => done(err));
ourBoard.once('ready',done);
});
it('can stop logging with sd',function(done) {
console.log('yoyoyo');
ourBoard.sdStop()
.then(() => {
console.log('taco');
spy.should.have.been.calledWith('j');
})
.catch(err => done(err));
ourBoard.once('ready',done);
});
});
// bad
describe('#channelOff', function () {
before(function(done) {
@@ -1139,7 +1229,8 @@ describe('#impedanceTesting', function() {
});
});
describe('#sync', function() {
// Need a better test
xdescribe('#sync', function() {
var ourBoard;
this.timeout(5000);
before(function (done) {