Skip to content

Commit 8cafa3f

Browse files
author
AJ Keller
committed
ADD SD Card Support Functions
1 parent c267cca commit 8cafa3f

File tree

9 files changed

+368
-17
lines changed

9 files changed

+368
-17
lines changed

README.md

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,7 @@ Board optional configurations.
290290
* `simulatorSampleRate` - The sample rate to use for the simulator (Default is `250`)
291291
* `simulatorAlpha` - {Boolean} - Inject and 10Hz alpha wave in Channels 1 and 2 (Default `true`)
292292
* `simulatorLineNoise` - Injects line noise on channels.
293-
* `60Hz` - 60Hz line noise (Default) (ex. __Unite States__)
293+
* `60Hz` - 60Hz line noise (Default) (ex. __United States__)
294294
* `50Hz` - 50Hz line noise (ex. __Europe__)
295295
* `None` - Do not inject line noise.
296296
* `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.
599599
600600
**_Returns_** a number, the current sample rate.
601601
602+
### .sdStart(recordingDuration)
603+
604+
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 `$$$`.
605+
606+
**_recordingDuration_**
607+
608+
The duration you want to log SD information for. Opens a new SD file to write into. Limited to:
609+
610+
* `14sec` - 14 seconds
611+
* `5min` - 5 minutes
612+
* `15min` - 15 minutes
613+
* `30min` - 30 minutes
614+
* `1hour` - 1 hour
615+
* `2hour` - 2 hour
616+
* `4hour` - 4 hour
617+
* `12hour` - 12 hour
618+
* `24hour` - 24 hour
619+
620+
**Note: You must have the proper type of SD card inserted into the board for logging to work.**
621+
622+
**_Returns_** resolves if the command was added to the write queue.
623+
624+
### .sdStop(recordingDuration)
625+
626+
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.
627+
628+
**_Returns_** resolves if the command was added to the write queue.
629+
602630
### .simulatorEnable()
603631
604632
To enter simulate mode. Must call `.connect()` after.

changelog.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,14 @@
1-
# 0.3.3
1+
# 0.3.5
2+
3+
### New Features
4+
5+
* SD card support! Now logging to an SD card is easier than ever.
6+
7+
### Bug Fixes
8+
9+
* Sample rate does not return correct sample rate for custom rate on simulator. #58
10+
11+
# 0.3.4
212

313
### New Features
414

openBCIBoard.js

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -987,17 +987,63 @@ function OpenBCIFactory() {
987987
});
988988
};
989989

990+
/**
991+
* @description Start logging to the SD card.
992+
* @param recordingDuration {String} - The duration you want to log SD information for. Limited to:
993+
* '14sec', '5min', '15min', '30min', '1hour', '2hour', '4hour', '12hour', '24hour'
994+
* @returns {Promise} - Resolves if the command was added to write queue.
995+
* @author AJ Keller (@pushtheworldllc)
996+
*/
997+
OpenBCIBoard.prototype.sdStart = function(recordingDuration) {
998+
return new Promise((resolve,reject) => {
999+
if (!this.connected) reject('Must be connected to the device');
1000+
k.sdSettingForString(recordingDuration)
1001+
.then(command => {
1002+
// If we are not streaming, then expect a confirmation message back from the board
1003+
if (!this.streaming) {
1004+
this.isLookingForKeyInBuffer = true;
1005+
this.searchingBuf = this.searchBuffers.miscStop;
1006+
}
1007+
this.writeOutDelay = k.OBCIWriteIntervalDelayMSNone;
1008+
return this.write(command);
1009+
})
1010+
.catch(err => reject(err));
1011+
});
1012+
1013+
};
1014+
1015+
/**
1016+
* @description Sends the stop SD logging command to the board.
1017+
* @returns {Promise}
1018+
*/
1019+
OpenBCIBoard.prototype.sdStop = function() {
1020+
return new Promise((resolve,reject) => {
1021+
if (!this.connected) reject('Must be connected to the device');
1022+
// If we are not streaming, then expect a confirmation message back from the board
1023+
if (!this.streaming) {
1024+
this.isLookingForKeyInBuffer = true;
1025+
this.searchingBuf = this.searchBuffers.miscStop;
1026+
}
1027+
this.writeOutDelay = k.OBCIWriteIntervalDelayMSNone;
1028+
return this.write(k.OBCISDLogStop);
1029+
});
1030+
};
1031+
9901032
/**
9911033
* @description Get the the current sample rate is.
9921034
* @returns {Number} The sample rate
9931035
* Note: This is dependent on if you configured the board correctly on setup options
9941036
* @author AJ Keller (@pushtheworldllc)
9951037
*/
9961038
OpenBCIBoard.prototype.sampleRate = function() {
997-
if(this.options.boardType === k.OBCIBoardDaisy) {
998-
return k.OBCISampleRate125;
1039+
if (this.options.simulate) {
1040+
return this.options.simulatorSampleRate;
9991041
} else {
1000-
return k.OBCISampleRate250;
1042+
if(this.options.boardType === k.OBCIBoardDaisy) {
1043+
return k.OBCISampleRate125;
1044+
} else {
1045+
return k.OBCISampleRate250;
1046+
}
10011047
}
10021048
};
10031049

openBCIConstants.js

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,17 @@ const kOBCISDLogForMin30 = 'F';
126126
const kOBCISDLogForSec14 = 'a';
127127
const kOBCISDLogStop = 'j';
128128

129+
/** SD Card String Commands */
130+
const kOBCIStringSDHour1 = '1hour';
131+
const kOBCIStringSDHour2 = '2hour';
132+
const kOBCIStringSDHour4 = '4hour';
133+
const kOBCIStringSDHour12 = '12hour';
134+
const kOBCIStringSDHour24 = '24hour';
135+
const kOBCIStringSDMin5 = '5min';
136+
const kOBCIStringSDMin15 = '15min';
137+
const kOBCIStringSDMin30 = '30min';
138+
const kOBCIStringSDSec14 = '14sec';
139+
129140
/** Stream Data Commands */
130141
const kOBCIStreamStart = 'b';
131142
const kOBCIStreamStop = 's';
@@ -519,6 +530,58 @@ module.exports = {
519530
OBCISDLogForMin30:kOBCISDLogForMin30,
520531
OBCISDLogForSec14:kOBCISDLogForSec14,
521532
OBCISDLogStop:kOBCISDLogStop,
533+
/** SD Card String Commands */
534+
OBCIStringSDHour1:kOBCIStringSDHour1,
535+
OBCIStringSDHour2:kOBCIStringSDHour2,
536+
OBCIStringSDHour4:kOBCIStringSDHour4,
537+
OBCIStringSDHour12:kOBCIStringSDHour12,
538+
OBCIStringSDHour24:kOBCIStringSDHour24,
539+
OBCIStringSDMin5:kOBCIStringSDMin5,
540+
OBCIStringSDMin15:kOBCIStringSDMin15,
541+
OBCIStringSDMin30:kOBCIStringSDMin30,
542+
OBCIStringSDSec14:kOBCIStringSDSec14,
543+
/**
544+
* @description Converts a sd string into the proper setting.
545+
* @param stringCommand {String} - The length of time you want to record to the SD for.
546+
* @returns {Promise} The command to send to the Board, returns an error on improper `stringCommand`
547+
*/
548+
sdSettingForString: (stringCommand) => {
549+
return new Promise((resolve,reject) => {
550+
switch (stringCommand) {
551+
case kOBCIStringSDHour1:
552+
resolve(kOBCISDLogForHour1);
553+
break;
554+
case kOBCIStringSDHour2:
555+
resolve(kOBCISDLogForHour2);
556+
break;
557+
case kOBCIStringSDHour4:
558+
resolve(kOBCISDLogForHour4);
559+
break;
560+
case kOBCIStringSDHour12:
561+
resolve(kOBCISDLogForHour12);
562+
break;
563+
case kOBCIStringSDHour24:
564+
resolve(kOBCISDLogForHour24);
565+
break;
566+
case kOBCIStringSDMin5:
567+
resolve(kOBCISDLogForMin5);
568+
break;
569+
case kOBCIStringSDMin15:
570+
resolve(kOBCISDLogForMin15);
571+
break;
572+
case kOBCIStringSDMin30:
573+
resolve(kOBCISDLogForMin30);
574+
break;
575+
case kOBCIStringSDSec14:
576+
resolve(kOBCISDLogForSec14);
577+
break;
578+
default:
579+
reject(new Error(TypeError));
580+
break;
581+
582+
}
583+
});
584+
},
522585
/** Stream Data Commands */
523586
OBCIStreamStart:kOBCIStreamStart,
524587
OBCIStreamStop:kOBCIStreamStop,

openBCISample.js

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -297,15 +297,12 @@ var sampleModule = {
297297

298298
var auxData = [0,0,0];
299299

300-
// Init arrays to hold coefficients for each channel
301-
var b0 = new Array(numberOfChannels);
302-
var b1 = new Array(numberOfChannels);
303-
var b2 = new Array(numberOfChannels);
300+
// Init arrays to hold coefficients for each channel and init to 0
301+
// This gives the 1/f filter memory on each iteration
302+
var b0 = new Array(numberOfChannels).fill(0);
303+
var b1 = new Array(numberOfChannels).fill(0);
304+
var b2 = new Array(numberOfChannels).fill(0);
304305

305-
// Init coefficients to 0
306-
b0.fill(0);
307-
b1.fill(0);
308-
b2.fill(0);
309306

310307
return function(previousSampleNumber) {
311308
var newSample = self.newSample();
@@ -315,7 +312,7 @@ var sampleModule = {
315312
whiteNoise = distribution.ppf(Math.random()) * Math.sqrt(sampleRateHz/2)/uVolts;
316313

317314
switch (i) {
318-
case 0: // Add 10Hz signal to channel 1... briany
315+
case 0: // Add 10Hz signal to channel 1... brainy
319316
case 1:
320317
if (injectAlpha) {
321318
sinePhaseRad[i] += 2 * Math.PI * sineWaveFreqHz10 / sampleRateHz;

openBCISimulator.js

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,11 @@ function OpenBCISimulatorFactory() {
4141

4242
// Bools
4343
this.connected = false;
44+
this.sd = {
45+
active:false,
46+
startTime: 0
47+
};
48+
this.streaming = false;
4449
// Buffers
4550
this.buffer = new Buffer(500);
4651
// Numbers
@@ -87,13 +92,45 @@ function OpenBCISimulatorFactory() {
8792
switch (data[0]) {
8893
case k.OBCIStreamStart:
8994
if (!this.stream) this._startStream();
95+
this.streaming = true;
9096
break;
9197
case k.OBCIStreamStop:
9298
if (this.stream) clearInterval(this.stream); // Stops the stream
99+
this.streaming = false;
93100
break;
94101
case k.OBCIMiscSoftReset:
95102
if (this.stream) clearInterval(this.stream);
96-
this.emit('data', new Buffer('OpenBCI Board Simulator\nPush The World V-0.2\n$$$'));
103+
this.streaming = false;
104+
this.emit('data', new Buffer('OpenBCI Board Simulator\nPush The World\nFirmware: v2$$$'));
105+
break;
106+
case k.OBCISDLogForHour1:
107+
case k.OBCISDLogForHour2:
108+
case k.OBCISDLogForHour4:
109+
case k.OBCISDLogForHour12:
110+
case k.OBCISDLogForHour24:
111+
case k.OBCISDLogForMin5:
112+
case k.OBCISDLogForMin15:
113+
case k.OBCISDLogForMin30:
114+
case k.OBCISDLogForSec14:
115+
// If we are not streaming, then do verbose output
116+
if (!this.streaming) {
117+
this.emit('data', new Buffer('Wiring is correct and a card is present.\nCorresponding SD file OBCI_69.TXT\n$$$'));
118+
}
119+
this.sd.active = true;
120+
this.sd.startTime = now();
121+
break;
122+
case k.OBCISDLogStop:
123+
if (!this.streaming) {
124+
if (this.SDLogActive) {
125+
this.emit('data', new Buffer('Total Elapsed Time: ' + (now() - this.sd.startTime) + ' ms\n'));
126+
this.emit('data', new Buffer('Max write time: ' + (Math.random()*500) + ' us\n'));
127+
this.emit('data', new Buffer('Min write time: ' + (Math.random()*200) + ' us\n'));
128+
this.emit('data', new Buffer('Overruns: 0\n$$$'));
129+
} else {
130+
this.emit('data', new Buffer('No open file to close\n$$$'));
131+
}
132+
}
133+
this.SDLogActive = false;
97134
break;
98135
case k.OBCISyncClockStart:
99136
setTimeout(() => {

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "openbci-sdk",
3-
"version": "0.3.4",
4-
"description": "A fully NodeJS based API for the OpenBCI board connecting to the hardware directly over serial",
3+
"version": "0.3.5",
4+
"description": "The official Node.js SDK for the OpenBCI Biosensor Board.",
55
"main": "openBCIBoard",
66
"scripts": {
77
"start": "node index",

test/OpenBCIConstants-test.js

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,86 @@ describe('OpenBCIConstants', function() {
323323
assert.equal('j', k.OBCISDLogStop);
324324
});
325325
});
326+
describe('SD card string Commands',function() {
327+
it('logs for 1 hour', function() {
328+
assert.equal('1hour', k.OBCIStringSDHour1);
329+
});
330+
it('logs for 2 hours', function() {
331+
assert.equal('2hour', k.OBCIStringSDHour2);
332+
});
333+
it('logs for 4 hours', function() {
334+
assert.equal('4hour', k.OBCIStringSDHour4);
335+
});
336+
it('logs for 12 hours', function() {
337+
assert.equal('12hour', k.OBCIStringSDHour12);
338+
});
339+
it('logs for 24 hours', function() {
340+
assert.equal('24hour', k.OBCIStringSDHour24);
341+
});
342+
it('logs for 5 minutes', function() {
343+
assert.equal('5min', k.OBCIStringSDMin5);
344+
});
345+
it('logs for 15 minutes', function() {
346+
assert.equal('15min', k.OBCIStringSDMin15);
347+
});
348+
it('logs for 30 minutes', function() {
349+
assert.equal('30min', k.OBCIStringSDMin30);
350+
});
351+
it('logs for 14 seconds', function() {
352+
assert.equal('14sec', k.OBCIStringSDSec14);
353+
});
354+
});
355+
describe('#sdSettingForString',function() {
356+
it('correct command for 1 hour', function() {
357+
var expectation = k.OBCISDLogForHour1;
358+
var result = k.sdSettingForString('1hour');
359+
return expect(result).to.eventually.equal(expectation);
360+
});
361+
it('correct command for 2 hour', function() {
362+
var expectation = k.OBCISDLogForHour2;
363+
var result = k.sdSettingForString('2hour');
364+
return expect(result).to.eventually.equal(expectation);
365+
});
366+
it('correct command for 4 hour', function() {
367+
var expectation = k.OBCISDLogForHour4;
368+
var result = k.sdSettingForString('4hour');
369+
return expect(result).to.eventually.equal(expectation);
370+
});
371+
it('correct command for 12 hour', function() {
372+
var expectation = k.OBCISDLogForHour12;
373+
var result = k.sdSettingForString('12hour');
374+
return expect(result).to.eventually.equal(expectation);
375+
});
376+
it('correct command for 24 hour', function() {
377+
var expectation = k.OBCISDLogForHour24;
378+
var result = k.sdSettingForString('24hour');
379+
return expect(result).to.eventually.equal(expectation);
380+
});
381+
it('correct command for 5 min', function() {
382+
var expectation = k.OBCISDLogForMin5;
383+
var result = k.sdSettingForString('5min');
384+
return expect(result).to.eventually.equal(expectation);
385+
});
386+
it('correct command for 15 min', function() {
387+
var expectation = k.OBCISDLogForMin15;
388+
var result = k.sdSettingForString('15min');
389+
return expect(result).to.eventually.equal(expectation);
390+
});
391+
it('correct command for 30 min', function() {
392+
var expectation = k.OBCISDLogForMin30;
393+
var result = k.sdSettingForString('30min');
394+
return expect(result).to.eventually.equal(expectation);
395+
});
396+
it('correct command for 14 seconds', function() {
397+
var expectation = k.OBCISDLogForSec14;
398+
var result = k.sdSettingForString('14sec');
399+
return expect(result).to.eventually.equal(expectation);
400+
});
401+
it('Invalid command request', function() {
402+
var result = k.sdSettingForString('taco');
403+
return expect(result).to.be.rejected;
404+
});
405+
});
326406
describe('Stream Data Commands',function() {
327407
it('starts',function () {
328408
assert.equal('b', k.OBCIStreamStart);

0 commit comments

Comments
 (0)