From fe2abac07bc362d896f0b4b75c2d056c8882f6d2 Mon Sep 17 00:00:00 2001 From: AJ Keller Date: Thu, 29 Sep 2016 00:23:33 -0400 Subject: [PATCH] Add example for time syncing --- README.md | 1 + changelog.md | 6 +++ examples/timeSync/package.json | 19 +++++++ examples/timeSync/timeSync.js | 93 ++++++++++++++++++++++++++++++++++ openBCIBoard.js | 2 + openBCISample.js | 1 + package.json | 2 +- test/OpenBCISample-test.js | 3 ++ 8 files changed, 126 insertions(+), 1 deletion(-) create mode 100644 examples/timeSync/package.json create mode 100644 examples/timeSync/timeSync.js diff --git a/README.md b/README.md index e1a3170..5ff8af8 100644 --- a/README.md +++ b/README.md @@ -895,6 +895,7 @@ Send the command to tell the board to start the syncing protocol. Must be connec timeRoundTrip: 0, // Simply timeSyncSetPacket - timeSyncSent. timeTransmission: 0, // Estimated time it took for time sync set packet to be sent from Board to Driver. timeOffset: 0, // The map (or translation) from boardTime to module time. + timeOffsetMaster: 0, // The map (or translation) from boardTime to module time averaged over time syncs. valid: false // If there was an error in the process, valid will be false and no time sync was done. It's important to resolve this so we can perform multiple promise syncs as show in the example below. } ``` diff --git a/changelog.md b/changelog.md index dc30503..2565487 100644 --- a/changelog.md +++ b/changelog.md @@ -1,3 +1,9 @@ +# 1.3.2 + +### Enhancements + +* Added master time offset `timeOffsetMaster` to `syncObj` which is a running average across sync attempts. + # 1.3.1 ### Bug Fixes diff --git a/examples/timeSync/package.json b/examples/timeSync/package.json new file mode 100644 index 0000000..fd06409 --- /dev/null +++ b/examples/timeSync/package.json @@ -0,0 +1,19 @@ +{ + "name": "timesync", + "version": "1.0.0", + "description": "Time sync example", + "main": "timeSync.js", + "scripts": { + "start": "node timeSync.js", + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [ + "time", + "sync" + ], + "author": "AJ Keller", + "license": "MIT", + "dependencies": { + "openbci": "^1.3.1" + } +} diff --git a/examples/timeSync/timeSync.js b/examples/timeSync/timeSync.js new file mode 100644 index 0000000..b04a184 --- /dev/null +++ b/examples/timeSync/timeSync.js @@ -0,0 +1,93 @@ +/** +* This is an example of time syncing every second for one minute. Used with a +* real board. +* To run: +* change directory to this file `cd examples/timeSync` +* do `npm install` +* then `npm start` +*/ + +var OpenBCIBoard = require('openbci').OpenBCIBoard; + +var ourBoard = new OpenBCIBoard({}); + +const resyncPeriodMin = 5; // re sync every five minutes +const secondsInMinute = 60; +var sampleRate = 250; // Default to 250, ALWAYS verify with a call to `.sampleRate()` after 'ready' event! +var timeSyncPossible = false; + +ourBoard.autoFindOpenBCIBoard().then(portName => { + if(portName) { + /** + * Connect to the board with portName + * i.e. ourBoard.connect(portName)..... + */ + // Call to connect + ourBoard.connect(portName).then(() => { + console.log(`connected`); + + }) + .catch(err => { + console.log(`connect: ${err}`); + }); + } else { + /**Unable to auto find OpenBCI board*/ + } +}); + +var readyFunc = () => { + // Get the sample rate after 'ready' + sampleRate = ourBoard.sampleRate(); + // Find out if you can even time sync, you must be using v2 and this is only accurate after a `.softReset()` call which is called internally on `.connect()`. We parse the `.softReset()` response for the presence of firmware version 2 properties. + timeSyncPossible = ourBoard.usingVersionTwoFirmware(); + + if (timeSyncPossible) { + ourBoard.streamStart() + .catch(err => { + console.log(`stream start: ${err}`); + }); + } else { + killFunc(); + } + +} + +var killFunc = () => { + ourBoard.disconnect() + .then(() => { + process.kill(); + }); +} + +var sampleFunc = sample => { + // Resynchronize every every second + if (sample._count % (sampleRate * 1) === 0) { + ourBoard.syncClocksFull() + .then(syncObj => { + // Sync was successful + if (syncObj.valid) { + // Log the object to check it out! + console.log(`timeOffset`,syncObj.timeOffsetMaster); + } else { + // Retry it + console.log(`Was not able to sync... retry!`); + } + }); + } + + if (sample.timeStamp) { // true after the first successful sync + if (sample.timeStamp < 10 * 60 * 60 * 1000) { // Less than 10 hours + console.log(`Bad time sync ${sample.timeStamp}`); + } + } + + // Stop after one minute + if (sample._count > sampleRate * 60) { + killFunc(); + } + +} + +// Subscribe to your functions +ourBoard.on('ready',readyFunc); +ourBoard.on('sample',sampleFunc); diff --git a/openBCIBoard.js b/openBCIBoard.js index 4acc373..0d7f37b 100644 --- a/openBCIBoard.js +++ b/openBCIBoard.js @@ -1933,6 +1933,8 @@ function OpenBCIFactory() { this.sync.timeOffsetMaster = this.sync.curSyncObj.timeOffset; } + this.sync.curSyncObj.timeOffsetMaster = this.sync.timeOffsetMaster; + if (this.options.verbose) { console.log(`Master offset ${this.sync.timeOffsetMaster} ms`); } diff --git a/openBCISample.js b/openBCISample.js index 9c03ff1..9e4eaf5 100644 --- a/openBCISample.js +++ b/openBCISample.js @@ -586,6 +586,7 @@ function newSyncObject() { timeRoundTrip: 0, timeTransmission: 0, timeOffset: 0, + timeOffsetMaster: 0, valid: false } } diff --git a/package.json b/package.json index 06aa8c3..a19cf39 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "openbci", - "version": "1.3.1", + "version": "1.3.2", "description": "The official Node.js SDK for the OpenBCI Biosensor Board.", "main": "openBCIBoard", "scripts": { diff --git a/test/OpenBCISample-test.js b/test/OpenBCISample-test.js index c76f8cf..ba19d6b 100644 --- a/test/OpenBCISample-test.js +++ b/test/OpenBCISample-test.js @@ -1352,6 +1352,9 @@ describe('openBCISample',function() { it("should have property timeOffset",function() { expect(syncObj).to.have.property("timeOffset",0); }); + it("should have property timeOffsetMaster",function() { + expect(syncObj).to.have.property("timeOffsetMaster",0); + }); it("should have property timeRoundTrip",function() { expect(syncObj).to.have.property("timeRoundTrip",0); });