Skip to content

Commit 6cf5e99

Browse files
author
AJ Keller
authored
Merge pull request #72 from pushtheworldllc/dev
Update time synced accel packets
2 parents 9bd1121 + 6cbf99e commit 6cf5e99

File tree

8 files changed

+55
-43
lines changed

8 files changed

+55
-43
lines changed

README.md

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ Time Syncing
162162
------------
163163
You must be using OpenBCI firmware version 2 in order to do time syncing. After you `.connect()` and send a `.softReset()`, you can call `.usingVersionTwoFirmware()` to get a boolean response as to if you are using `v1` or `v2`.
164164

165-
Now using firmware `v2`, the fun begins! We synchronize the Board's clock with the module's time. In firmware `v2` we leverage samples with time stamps and different time stamps and unique new features to calculate a time sync strategy. Time syncing has been verified to +/- 4ms and a test report is on the way. We are still working on the synchronize of this module and an NTP server, this is an open call for any NTP experts out there! With a global NTP server you could use several different devices and all sync to the same time server. That way you can really do some serious cloud computing!
165+
Now using firmware `v2`, the fun begins! We synchronize the Board's clock with the module's time. In firmware `v2` we leverage samples with time stamps and _ACKs_ from the Dongle to form a time synchronization strategy. Time syncing has been verified to +/- 4ms and a test report is on the way. We are still working on the synchronize of this module and an NTP server, this is an open call for any NTP experts out there! With a global NTP server you could use several different devices and all sync to the same time server. That way you can really do some serious cloud computing!
166166

167167
Keep your resync interval above 50ms. While it's important to resync every couple minutes due to drifting of clocks, please do not try to sync without getting the last sync event! We can only support one sync operation at a time!
168168

@@ -376,10 +376,10 @@ Board optional configurations.
376376
* `None` - Do not inject line noise.
377377
* `simulatorSampleRate` {Number} - The sample rate to use for the simulator. Simulator will set to 125 if `simulatorDaisyModuleAttached` is set `true`. However, setting this option overrides that setting and this sample rate will be used. (Default is `250`)
378378
* `simulatorSerialPortFailure` {Boolean} - Simulates not being able to open a serial connection. Most likely due to a OpenBCI dongle not being plugged in.
379-
* `sntpTimeSync` - {Boolean} Syncs the module up with an SNTP time server and uses that as single source of truth instead of local computer time. (Default `true`)
379+
* `sntpTimeSync` - {Boolean} Syncs the module up with an SNTP time server and uses that as single source of truth instead of local computer time. If you are running experiments on your local computer, keep this `false`. (Default `false`)
380380
* `sntpTimeSyncHost` - {String} The sntp server to use, can be either sntp or ntp (Defaults `pool.ntp.org`).
381381
* `sntpTimeSyncPort` - {Number} The port to access the sntp server (Defaults `123`)
382-
* `verbose` {Boolean} - Print out useful debugging events
382+
* `verbose` {Boolean} - Print out useful debugging events (Default `false`)
383383
384384
**Note, we have added support for either all lowercase OR camel case for the options, use whichever style you prefer.**
385385
@@ -879,6 +879,8 @@ Send the command to tell the board to start the syncing protocol. Must be connec
879879
880880
**Example**
881881
882+
Syncing multiple times to base the offset of the average of the four syncs.
883+
882884
```javascript
883885
var OpenBCIBoard = require('openbci').OpenBCIBoard,
884886
ourBoard = new OpenBCIBoard({
@@ -1068,7 +1070,7 @@ The name of the simulator port.
10681070
10691071
### LabStreamingLayer
10701072
1071-
[LabStreamingLayer](https://github.com/sccn/labstreaminglayer) by SCCN is a stream management tool designed to time-synchronize multiple data streams, potentially from different sources, over a LAN network with millisecond accuracy (given configuration).
1073+
[LabStreamingLayer](https://github.com/sccn/labstreaminglayer) by SCCN is a stream management tool designed to time-synchronize multiple data streams, potentially from different sources, over a LAN network with millisecond accuracy (given configuration).
10721074
10731075
For example, a VR display device running a Unity simulation may, using the [LSL4Unity](https://github.com/xfleckx/LSL4Unity) library, emit string markers into LSL corresponding to events of interest (For the P300 ERP, this event would be the onset of an attended, unusual noise in a pattern of commonplace ones). The computer doing data collection via the OpenBCI_NodeJS library (potentially with 4ms accuracy) would then output into an LSL stream the EEG and AUX data. LSL can then synchronize the two clocks relative to each other before inputting into a different program or toolkit, like [BCILAB](https://github.com/sccn/BCILAB) for analysis to trigger responses in the Unity display.
10741076

changelog.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
# 1.2.0
2+
3+
### New Features
4+
5+
* Add tutorial/sample code for interfacing the module with lab streaming layer.
6+
7+
### Breaking Changes
8+
9+
* Fixed time synced accel to work OpenBCI_32bit_Library release candidate 5 and newer.
10+
111
# 1.1.0
212

313
### New Features

openBCIBoard.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ var EventEmitter = require('events').EventEmitter,
77
openBCISample = require('./openBCISample'),
88
k = openBCISample.k,
99
openBCISimulator = require('./openBCISimulator'),
10-
now = require("performance-now"),
10+
now = require('performance-now'),
1111
Sntp = require('sntp'),
1212
StreamSearch = require('streamsearch'),
1313
bufferEqual = require('buffer-equal'),
@@ -1525,7 +1525,7 @@ function OpenBCIFactory() {
15251525

15261526
/**
15271527
* @description Send the command to tell the board to start the syncing protocol. Must be connected,
1528-
* streaming and using version +2 firmware.
1528+
* streaming and using at least version 2.0.0 firmware.
15291529
* **Note**: This functionality requires OpenBCI Firmware Version 2.0
15301530
* @since 1.0.0
15311531
* @returns {Promise} - Resolves if sent, rejects if not connected or using firmware verison +2.
@@ -1546,7 +1546,7 @@ function OpenBCIFactory() {
15461546

15471547
/**
15481548
* @description Send the command to tell the board to start the syncing protocol. Must be connected,
1549-
* streaming and using version +2 firmware. Uses the `synced` event to ensure multiple syncs
1549+
* streaming and using at least version 2.0.0 firmware. Uses the `synced` event to ensure multiple syncs
15501550
* don't overlap.
15511551
* **Note**: This functionality requires OpenBCI Firmware Version 2.0
15521552
* @since 1.1.0
@@ -1889,7 +1889,7 @@ function OpenBCIFactory() {
18891889
// n n t packet
18901890
// t t confirmation
18911891
if ((this.sync.curSyncObj.timeSyncSetPacket - this.sync.curSyncObj.timeSyncSentConfirmation) < k.OBCITimeSyncThresholdTransFailureMS) {
1892-
// Estimate that 75% of the time between sent and set packet was spent on the packet making it's way from board to this point
1892+
// Estimate that 75% of the time between sent and set packet was spent on the packet making its way from board to this point
18931893
this.sync.curSyncObj.timeTransmission = math.floor((this.sync.curSyncObj.timeSyncSetPacket - this.sync.curSyncObj.timeSyncSent) * k.OBCITimeSyncMultiplierWithSyncConf);
18941894
if (this.options.verbose) console.log(`Had to correct transmission time`);
18951895
this.sync.curSyncObj.correctedTransmissionTime = true;

openBCIConstants.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -275,9 +275,9 @@ const OBCIStreamPacketRawAuxTimeSynced = 6; // 0110
275275
const OBCIStreamPacketTimeByteSize = 4;
276276

277277
/** Time synced with accel packet */
278-
const OBCIAccelAxisX = 0;
279-
const OBCIAccelAxisY = 1;
280-
const OBCIAccelAxisZ = 2;
278+
const OBCIAccelAxisX = 7;
279+
const OBCIAccelAxisY = 8;
280+
const OBCIAccelAxisZ = 9;
281281

282282
/** Firmware version indicator */
283283
const OBCIFirmwareV1 = 'v1';

openBCISample.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -776,9 +776,9 @@ function getFromTimePacketTime(dataBuf) {
776776

777777
/**
778778
* @description Grabs an accel value from a raw but time synced packet. Important that this utilizes the fact that:
779-
* X axis data is sent with every sampleNumber % 10 === 0
780-
* Y axis data is sent with every sampleNumber % 10 === 1
781-
* Z axis data is sent with every sampleNumber % 10 === 2
779+
* X axis data is sent with every sampleNumber % 10 === 7
780+
* Y axis data is sent with every sampleNumber % 10 === 8
781+
* Z axis data is sent with every sampleNumber % 10 === 9
782782
* @param dataBuf {Buffer} - The 33byte raw time synced accel packet
783783
* @param accelArray {Array} - A 3 element array that allows us to have inter packet memory of x and y axis data and emit only on the z axis packets.
784784
* @returns {Promise} - Fulfills with a boolean that is true only when the accel array is ready to be emitted... i.e. when this is a Z axis packet
@@ -791,15 +791,15 @@ function getFromTimePacketAccel(dataBuf, accelArray) {
791791
var sampleNumber = dataBuf[k.OBCIPacketPositionSampleNumber];
792792
switch (sampleNumber % 10) { // The accelerometer is on a 25Hz sample rate, so every ten channel samples, we can get new data
793793
case k.OBCIAccelAxisX:
794-
accelArray[k.OBCIAccelAxisX] = sampleModule.interpret16bitAsInt32(dataBuf.slice(lastBytePosition, lastBytePosition + 2)) * SCALE_FACTOR_ACCEL; // slice is not inclusive on the right
794+
accelArray[0] = sampleModule.interpret16bitAsInt32(dataBuf.slice(lastBytePosition, lastBytePosition + 2)) * SCALE_FACTOR_ACCEL; // slice is not inclusive on the right
795795
resolve(false);
796796
break;
797797
case k.OBCIAccelAxisY:
798-
accelArray[k.OBCIAccelAxisY] = sampleModule.interpret16bitAsInt32(dataBuf.slice(lastBytePosition, lastBytePosition + 2)) * SCALE_FACTOR_ACCEL; // slice is not inclusive on the right
798+
accelArray[1] = sampleModule.interpret16bitAsInt32(dataBuf.slice(lastBytePosition, lastBytePosition + 2)) * SCALE_FACTOR_ACCEL; // slice is not inclusive on the right
799799
resolve(false);
800800
break;
801801
case k.OBCIAccelAxisZ:
802-
accelArray[k.OBCIAccelAxisZ] = sampleModule.interpret16bitAsInt32(dataBuf.slice(lastBytePosition, lastBytePosition + 2)) * SCALE_FACTOR_ACCEL; // slice is not inclusive on the right
802+
accelArray[2] = sampleModule.interpret16bitAsInt32(dataBuf.slice(lastBytePosition, lastBytePosition + 2)) * SCALE_FACTOR_ACCEL; // slice is not inclusive on the right
803803
resolve(true);
804804
break;
805805
default:

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "openbci",
3-
"version": "1.1.0",
3+
"version": "1.2.0",
44
"description": "The official Node.js SDK for the OpenBCI Biosensor Board.",
55
"main": "openBCIBoard",
66
"scripts": {

test/OpenBCIConstants-test.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -474,13 +474,13 @@ describe('OpenBCIConstants', function() {
474474
});
475475
describe('Time synced with accel packet',function() {
476476
it('X axis',function () {
477-
assert.equal(0, k.OBCIAccelAxisX);
477+
assert.equal(7, k.OBCIAccelAxisX);
478478
});
479479
it('Y axis',function () {
480-
assert.equal(1, k.OBCIAccelAxisY);
480+
assert.equal(8, k.OBCIAccelAxisY);
481481
});
482482
it('Z axis',function () {
483-
assert.equal(2, k.OBCIAccelAxisZ);
483+
assert.equal(9, k.OBCIAccelAxisZ);
484484
});
485485
});
486486
describe('Time sync useful numbers',function() {

test/OpenBCISample-test.js

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -259,9 +259,9 @@ describe('openBCISample',function() {
259259
describe('#getFromTimePacketAccel',function() {
260260
var packet;
261261

262-
it('should emit and array if z axis i.e. sampleNumber % 10 === 2', function(done) {
262+
it('should emit and array if z axis i.e. sampleNumber % 10 === 9', function(done) {
263263
// Make a packet with a sample number that represents z axis
264-
packet = openBCISample.samplePacketAccelTimeSynced(2);
264+
packet = openBCISample.samplePacketAccelTimeSynced(9);
265265
openBCISample.getFromTimePacketAccel(packet,accelArray)
266266
.then(isZAxis => {
267267
// accel array ready
@@ -272,19 +272,19 @@ describe('openBCISample',function() {
272272
done(err);
273273
})
274274
});
275-
it('false if sample number is not sampleNumber % 10 === 2', function(done) {
275+
it(`false if sample number is not sampleNumber % 10 === ${k.OBCIAccelAxisZ}`, function(done) {
276276
// Make a packet that is anything but the z axis
277-
packet = openBCISample.samplePacketAccelTimeSynced(0);
277+
packet = openBCISample.samplePacketAccelTimeSynced(k.OBCIAccelAxisX);
278278
openBCISample.getFromTimePacketAccel(packet,accelArray)
279279
.then(isZAxis => {
280-
// Accel array not ready for sampleNumber % 10 === 0
280+
// Accel array not ready for sampleNumber % 10 === 7
281281
isZAxis.should.equal(false);
282282

283-
packet = openBCISample.samplePacketAccelTimeSynced(1);
283+
packet = openBCISample.samplePacketAccelTimeSynced(k.OBCIAccelAxisY);
284284
return openBCISample.getFromTimePacketAccel(packet,accelArray);
285285
})
286286
.then(isZAxis => {
287-
// Accel array not ready for sampleNumber % 10 === 1
287+
// Accel array not ready for sampleNumber % 10 === 8
288288
isZAxis.should.equal(false);
289289

290290
packet = openBCISample.samplePacketAccelTimeSynced(34);
@@ -294,11 +294,11 @@ describe('openBCISample',function() {
294294
// Accel array not ready for sampleNumber % 10 === 4
295295
isZAxis.should.equal(false);
296296

297-
packet = openBCISample.samplePacketAccelTimeSynced(99);
297+
packet = openBCISample.samplePacketAccelTimeSynced(100);
298298
return openBCISample.getFromTimePacketAccel(packet,accelArray);
299299
})
300300
.then(isZAxis => {
301-
// Accel array not ready for sampleNumber % 10 === 9
301+
// Accel array not ready for sampleNumber % 10 === 0
302302
isZAxis.should.equal(false);
303303
done();
304304
})
@@ -316,14 +316,14 @@ describe('openBCISample',function() {
316316
// Global array (at least it's global in practice) to store accel data between packets
317317
var packet1, packet2, packet3;
318318

319-
it('should only include accel data array on sampleNumber%10 === 2', function(done) {
319+
it(`should only include accel data array on sampleNumber%10 === ${k.OBCIAccelAxisZ}`, function(done) {
320320
// Generate three packets, packets only get one axis value per packet
321-
// X axis data is sent with every sampleNumber % 10 === 0
322-
packet1 = openBCISample.samplePacketAccelTimeSynced(0);
323-
// Y axis data is sent with every sampleNumber % 10 === 1
324-
packet2 = openBCISample.samplePacketAccelTimeSynced(1);
325-
// Z axis data is sent with every sampleNumber % 10 === 2
326-
packet3 = openBCISample.samplePacketAccelTimeSynced(2);
321+
// X axis data is sent with every sampleNumber % 10 === 7
322+
packet1 = openBCISample.samplePacketAccelTimeSynced(k.OBCIAccelAxisX);
323+
// Y axis data is sent with every sampleNumber % 10 === 8
324+
packet2 = openBCISample.samplePacketAccelTimeSynced(k.OBCIAccelAxisY);
325+
// Z axis data is sent with every sampleNumber % 10 === 9
326+
packet3 = openBCISample.samplePacketAccelTimeSynced(k.OBCIAccelAxisZ);
327327

328328
openBCISample.parsePacketTimeSyncedAccel(packet1,defaultChannelSettingsArray,0,accelArray)
329329
.then(sampleObject => {
@@ -342,12 +342,12 @@ describe('openBCISample',function() {
342342
});
343343
it('should convert raw numbers into g\'s with scale factor',function(done) {
344344
// Generate three packets, packets only get one axis value per packet
345-
// X axis data is sent with every sampleNumber % 10 === 0
346-
packet1 = openBCISample.samplePacketAccelTimeSynced(0);
347-
// Y axis data is sent with every sampleNumber % 10 === 1
348-
packet2 = openBCISample.samplePacketAccelTimeSynced(1);
349-
// Z axis data is sent with every sampleNumber % 10 === 2
350-
packet3 = openBCISample.samplePacketAccelTimeSynced(2);
345+
// X axis data is sent with every sampleNumber % 10 === 7
346+
packet1 = openBCISample.samplePacketAccelTimeSynced(k.OBCIAccelAxisX);
347+
// Y axis data is sent with every sampleNumber % 10 === 8
348+
packet2 = openBCISample.samplePacketAccelTimeSynced(k.OBCIAccelAxisY);
349+
// Z axis data is sent with every sampleNumber % 10 === 9
350+
packet3 = openBCISample.samplePacketAccelTimeSynced(k.OBCIAccelAxisZ);
351351

352352
openBCISample.parsePacketTimeSyncedAccel(packet1,defaultChannelSettingsArray,0,accelArray)
353353
.then(() => {

0 commit comments

Comments
 (0)