diff --git a/.travis.yml b/.travis.yml index 5bce7ed..39322e2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,24 +1,19 @@ language: node_js node_js: - - "4.0" - - "4.1" - - "4.2" - - "4.3" - - "4.4" - - "4.5" - - "4.6" - - "5.11.0" - - "6.0" - - "6.1" - - "6.2" - - "6.3" - - "6.4" - - "6.5" - - "6.6" - - "6.7" - - "6.8" + - "4.8.4" + - "6.11.1" + - "7.10.1" + - "8.1.4" +env: + - CXX=g++-4.8 +addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - g++-4.8 install: - npm install --all script: - - npm run lint - - npm run test-cov + - npm run test-lint + - npm run test-cov \ No newline at end of file diff --git a/changelog.md b/CHANGELOG.md similarity index 78% rename from changelog.md rename to CHANGELOG.md index bdc8776..ad88fb9 100644 --- a/changelog.md +++ b/CHANGELOG.md @@ -1,3 +1,110 @@ +# 3.0.0 + +This adds ganglion, wifi, and cyton support to the `openbci` main library. + +If you only need cyton over serial and so not want the additional support, please see [`openbci-cyton`](https://www.npmjs.com/package/openbci-cyton). + +# 2.2.1 + +### Enhancements + +* Bumped openbci-utilities to v0.2.0 for new accel data support + +# 2.2.0 + +### Bug Fixes + +* Calling sdStart and stop would change the writeOutDelay +* Timeout for v1 was set to 10 ms instead of 50 ms. +* Timeout for v2+ was set to 0 ms instead of 10 ms. + +# 2.1.4 + +### Enhancements + +* syncRegisterSettings now resolves channel setting object +* Bumped openbci-utilities to v0.1.5 + +# 2.1.3 + +### Enhancements + +* Can now sync the channel settings from the actual registers on the ADS! Call `.syncRegisterSettings()` +* Bumped openbci-utilities to v0.1.4 + +# 2.1.2 + +### Enhancements + +* Update openbci-utilities to v0.1.2 to patch for sendCounts. +* Disconnect did not disconnect from serial port if the device was not streaming. + +# 2.1.1 + +### Bug Fixes + +* Closes forgot parentheses in `getBoardType()` #152 (thanks @nateGeorge) + +### Enhancements + +* Add support for v3 cyton firmware. + +# 2.1.0 + +### Breaking changes + +* Significantly reduce the properties in `this.info` object to only have firmware version and number of missed packets. Code dependent on this.info should switch to using `numberOfChannels()`, and `getBoardType()` and `sampleRate()` for accurate board info! + +### Enhancements + +* Fixes for daisy with new board, specifically hardSet. + +# 2.0.1 + +### Bug Fixes + +* Debug bytes was set to always print in processBytes + +# 2.0.0 + +### New Features +* `index.js` file allows for ES6 destructing + +### Breaking Changes +* Change name of `OpenBCIBoard` to `Cyton` to follow new naming convention. + Simply change: + ```ecmascript 6 + const OpenBCIBoard = require('openbci').OpenBCIBoard; + const ourBoard = new OpenBCIBoard(); + ``` + ```ecmascript 6 + const Cyton = require('openbci').Cyton; + const ourBoard = new Cyton(); + ``` +* Major change to how board is initialized with removal of `factory` paradigm. +* New dependency called `openbci-utilities`. +* Rejections are errors with messages, so check err.message for info on message, don't expect string. + +### Bug Fixes +* Documentation error with `testSignal` function. + +### Enhancements +* Add more tests for public API functions. + +# 1.5.2 + +### Dependency Package Updates +* `performance-now`: from `^0.2.0` to `2.1.0` +* `serialport` - from `4.0.1` to `4.0.7` + +### Development Dependency Package Updates +* `bluebird`: from `3.4.6` to `3.5.0` +* `chai-as-promised`: from `^5.2.0` to `^6.0.0` +* `codecov`: from `^1.0.1` to `^2.1.0` +* `semistandard`: from `^9.0.0` to `^10.0.0` +* `sinon`: from `^1.17.2` to `^2.1.0` +* `snazzy`: from `^5.0.0` to `^6.0.0` + # 1.5.1 ### New Features @@ -52,7 +159,7 @@ ### Bug Fixes * Fixes bug where extra data after EOT (`$$$`) was dumped by preserving the poriton after the EOT for further decomposition. -* Fixes bug where any calls to channel set would actually break the openBCISample code as the channelSettingsArray contained an undefined. +* Fixes bug where any calls to channel set would actually break the openBCIUtilities code as the channelSettingsArray contained an undefined. * Writes promises resolve when they are actually sent over the serial port. # 1.4.0 @@ -198,7 +305,7 @@ The second major release for the OpenBCI Node.js SDK brings major changes, impro * NPM package is not called `openbci-sdk` anymore, now called `openbci` * Accelerometer data now goes into `.accelData` array instead of `.auxData` array. -* In openBCISample.js +* In openBCIUtilities.js * `parseRawPacket()` is now called `parseRawPacketStandard()` * `ready` event only triggered after soft reset. `eot` event emitted in all other conditions resulting in the board sending EOT ("$$$") * Must use camel case on the OpenBCISimulator object. @@ -276,7 +383,7 @@ The second major release for the OpenBCI Node.js SDK brings major changes, impro ### Bug Fixes * updates to README.me and comments to change ntp to sntp, because the two are similar, but not the same and we do not want to be misleading -* Extended [Stnp](https://www.npmjs.com/package/sntp) to main openBCIBoard.js +* Extended [Stnp](https://www.npmjs.com/package/sntp) to main openBCICyton.js * Add `.sntpNow()` function to get ntp time. # 0.3.1 diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100755 index 0000000..b0ab3a3 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,69 @@ +# OpenBCI NodeJS Code of Conduct + +## Purpose + +It is our hope that any one is able to contribute to OpenBCI NodeJS regardless of their background. Thus, we hope to provide a safe, welcoming, and warmly geeky environment for everybody, regardless of gender, sexual orientation, ability, ethnicity, socioeconomic status, and religion (or lack thereof). + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or +advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at [info@pushtheworld.us](mailto:info@pushtheworld.us). All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at [http://contributor-covenant.org/version/1/4][version] + +[homepage]: http://contributor-covenant.org +[version]: http://contributor-covenant.org/version/1/4/ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100755 index 0000000..9bc0265 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,27 @@ +# Contributing + +:tada::clinking_glasses: First off, thanks for taking the time to contribute! :tada::clinking_glasses: + +Contributions are always welcome, no matter how small. + +The following is a small set of guidelines for how to contribute to the project + +## Where to start + +### Code of Conduct +This project adheres to the Contributor Covenant [Code of Conduct](CODE_OF_CONDUCT.md). +By participating you are expected to adhere to these expectations. Please report unacceptable behaviour to [info@pushtheworld.us](mailto:info@pushtheworld.us) + +### Contributing on Github + +If you're new to Git and want to learn how to fork this repo, make your own additions, and include those additions in the master version of this project, check out this [great tutorial](http://blog.davidecoppola.com/2016/11/howto-contribute-to-open-source-project-on-github/). + +### Community + +This project is maintained by the [OpenBCI](www.openbci.com) and [NeuroTechX](www.neurotechx.com) community. Join the NeuroTechX Slack to check out our #devices channel, where discussions about OpenBCI takes place. + +## How can I contribute? + +If there's a feature you'd be interested in building, go ahead and we'll support you as much as we can. When you're finished submit a pull request to the master branch referencing the specific issue you addressed. + +If you find a bug, or have a suggestion on how to improve the project, just fill out a [Github issue](../../issues) diff --git a/README.md b/README.md index 0e4f94f..4e23f62 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,12 @@ +# OpenBCI NodeJS SDK + +

+ banner +

+

+ Provide a single source to program all OpenBCI biosensors in NodeJS +

+ [![Stories in Ready](https://badge.waffle.io/OpenBCI/OpenBCI_NodeJS.png?label=ready&title=Ready)](https://waffle.io/OpenBCI/OpenBCI_NodeJS) [![Join the chat at https://gitter.im/OpenBCI/OpenBCI_NodeJS](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/OpenBCI/OpenBCI_NodeJS?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Build Status](https://travis-ci.org/OpenBCI/OpenBCI_NodeJS.svg?branch=master)](https://travis-ci.org/OpenBCI/OpenBCI_NodeJS) @@ -6,1225 +15,129 @@ [![npm](https://img.shields.io/npm/dm/openbci.svg?maxAge=2592000)](http://npmjs.com/package/openbci) [![js-semistandard-style](https://img.shields.io/badge/code%20style-semistandard-brightgreen.svg?style=flat-square)](https://github.com/Flet/semistandard) -# OpenBCI Node.js SDK - -A Node.js module for OpenBCI ~ written with love by [Push The World!](http://www.pushtheworldllc.com) - -We are proud to support all functionality of the OpenBCI 8 and 16 Channel boards and are actively developing and maintaining this module. - -The purpose of this module is to **get connected** and **start streaming** as fast as possible. - -Python researcher or developer? Check out how easy it is to [get access to the entire API in the Python example](examples/python)! - -### Table of Contents: ---- - -1. [Installation](#install) -2. [TL;DR](#tldr) -3. [About](#About) -4. [General Overview](#general-overview) -5. [SDK Reference Guide](#sdk-reference-guide) - 1. [Constructor](#constructor) - 2. [Methods](#method) - 3. [Events](#event) - 4. [Constants](#constants) -6. [Interfacing With Other Tools](#interfacing-with-other-tools) -7. [Developing](#developing) -8. [Testing](#developing-testing) -9. [Contribute](#contribute) -10. [License](#license) -11. [Roadmap](#roadmap) - -### Installation: -``` -npm install openbci -``` -#### serialport dependency -If you encounter this error when trying to run: -``` -Error: The module '/path/to/your/project/node_modules/serialport/build/Release/serialport.node' -was compiled against a different Node.js version using -NODE_MODULE_VERSION 48. This version of Node.js requires -NODE_MODULE_VERSION 51. Please try re-compiling or re-installing -the module (for instance, using `npm rebuild` or`npm install`). -``` -...the issue can be resolved by running: -``` -npm rebuild --build-from-source -``` -### TL;DR: -Get connected and [start streaming right now with the example code](examples/getStreaming/getStreaming.js). - -```js -var OpenBCIBoard = require('openbci').OpenBCIBoard; -var ourBoard = new OpenBCIBoard(); -ourBoard.connect(portName) // Port name is a serial port name, see `.listPorts()` - .then(function() { - ourBoard.on('ready',function() { - ourBoard.streamStart(); - ourBoard.on('sample',function(sample) { - /** Work with sample */ - for (var i = 0; i < ourBoard.numberOfChannels(); i++) { - console.log("Channel " + (i + 1) + ": " + sample.channelData[i].toFixed(8) + " Volts."); - // prints to the console - // "Channel 1: 0.00001987 Volts." - // "Channel 2: 0.00002255 Volts." - // ... - // "Channel 8: -0.00001875 Volts." - } - }); - }); -}) -``` - -### About: -Want to know if the module really works? Check out some projects and organizations using it: - -* [_OpenEXP_](https://github.com/openexp/OpenEXP): an open-source desktop app for running experiments and collecting behavioral and physiological data. -* [_Thinker_](http://www.pushtheworldllc.com/#!thinker/uc1fn): a project building the world's first brainwave-word database. -* [_NeuroJS_](https://github.com/NeuroJS): a community dedicated to Neuroscience research using JavaScript, they have several great examples. - -Still not satisfied it works?? Check out this [detailed report](http://s132342840.onlinehome.us/pushtheworld/files/voltageVerificationTestPlanAndResults.pdf) that scientifically validates the output voltages of this module. - -How are you still doubting and not using this already? Fine, go look at some of the [800 **_automatic_** tests](https://codecov.io/gh/OpenBCI/OpenBCI_NodeJS) written for it! +## Welcome! -Python researcher or developer? Check out how easy it is to [get access to the entire API in the Python example](examples/python)! - -### General Overview: - -Initialization --------------- - -Initializing the board: - -```js -var OpenBCIBoard = require('openbci'); -var ourBoard = new OpenBCIBoard.OpenBCIBoard(); -``` -Go [checkout out the get streaming example](examples/getStreaming/getStreaming.js)! - -For initializing with options, such as verbose print outs: - -```js -var OpenBCIBoard = require('openbci').OpenBCIBoard; -var ourBoard = new OpenBCIBoard({ - verbose: true -}); -``` - -Or if you don't have a board and want to use synthetic data: - -```js -var OpenBCIBoard = require('openbci').OpenBCIBoard; -var ourBoard = new OpenBCIBoard({ - simulate: true -}); -``` - -Have a daisy?: -```js -var OpenBCIBoard = require('openbci').OpenBCIBoard; -var ourBoard = new OpenBCIBoard({ - boardType: `daisy`, - hardSet: true -}); -``` -Go [checkout out the get streaming with daisy example](examples/getStreamingDaisy/getStreamingDaisy.js)! - -Another useful way to start the simulator: -```js -var openBCIBoard = require('openbci'); -var k = openBCIBoard.OpenBCIConstants; -var ourBoard = openBCIBoard.OpenBCIBoard(); -ourBoard.connect(k.OBCISimulatorPortName) // This will set `simulate` to true - .then(function(boardSerial) { - ourBoard.on('ready',function() { - /** Start streaming, reading registers, what ever your heart desires */ - }); - }).catch(function(err) { - /** Handle connection errors */ - }); -``` - -To debug, it's amazing, do: - -```js -var OpenBCIBoard = require('openbci').OpenBCIBoard; -var ourBoard = new OpenBCIBoard({ - simulate: true -}); -``` -Go [checkout out the debug example](examples/debug/debug.js)! - -'ready' event ------------- - -You MUST wait for the 'ready' event to be emitted before streaming/talking with the board. The ready happens asynchronously -so installing the 'sample' listener and writing before the ready event might result in... nothing at all. - -```js -var OpenBCIBoard = require('openbci').OpenBCIBoard; -var ourBoard = new OpenBCIBoard(); -ourBoard.connect(portName).then(function(boardSerial) { - ourBoard.on('ready',function() { - /** Start streaming, reading registers, what ever your heart desires */ - }); -}).catch(function(err) { - /** Handle connection errors */ -}); -``` - -Sample properties: ------------------- -* `startByte` (`Number` should be `0xA0`) -* `sampleNumber` (a `Number` between 0-255) -* `channelData` (channel data indexed at 0 filled with floating point `Numbers` in Volts) -* `accelData` (`Array` with X, Y, Z accelerometer values when new data available) -* `auxData` (`Buffer` filled with either 2 bytes (if time synced) or 6 bytes (not time synced)) -* `stopByte` (`Number` should be `0xCx` where x is 0-15 in hex) -* `boardTime` (`Number` the raw board time) -* `timeStamp` (`Number` the `boardTime` plus the NTP calculated offset) - -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)`](#method-connect) with `portName` equal to [`'OpenBCISimulator'`](#constants-obcisimulatorportname). - -To get a ['sample'](#event-sample) event, you need to: -------------------------------------- -1. Call [`.connect(serialPortName)`](#method-connect) -2. Install the ['ready'](#event-ready) event emitter on resolved promise -3. In callback for ['ready'](#event-ready) emitter, call [`streamStart()`](#method-stream-start) -4. Install the ['sample'](#event-sample) event emitter -```js -var OpenBCIBoard = require('openbci').OpenBCIBoard; -var ourBoard = new OpenBCIBoard(); -ourBoard.connect(portName).then(function() { - ourBoard.on('ready',function() { - ourBoard.streamStart(); - ourBoard.on('sample',function(sample) { - /** Work with sample */ - }); - }); -}).catch(function(err) { - /** Handle connection errors */ -}); -``` -Close the connection with [`.streamStop()`](#method-stream-stop) and disconnect with [`.disconnect()`](#method-disconnect) -```js -var ourBoard = new require('openbci').OpenBCIBoard(); -ourBoard.streamStop().then(ourBoard.disconnect()); -``` - -Time Syncing ------------- -You must be using OpenBCI firmware version 2 in order to do time syncing. After you [`.connect()`](#method-connect) and send a [`.softReset()`](#method-soft-reset), you can call [`.usingVersionTwoFirmware()`](#method-using-version-two-firmware) to get a boolean response as to if you are using `v1` or `v2`. - -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! - -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! - -Using local computer time: -```js -var OpenBCIBoard = require('openbci').OpenBCIBoard, - ourBoard = new OpenBCIBoard({ - verbose:true - }); - -const resyncPeriodMin = 5; // re sync every five minutes -const secondsInMinute = 60; -var sampleRate = k.OBCISampleRate250; // Default to 250, ALWAYS verify with a call to `.sampleRate()` after 'ready' event! -var timeSyncPossible = false; - -// Call to connect -ourBoard.connect(portName).then(() => { - ourBoard.on('ready',() => { - // 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(); - - ourBoard.streamStart() - .then(() => { - /** Start streaming command sent to board. */ - }) - .catch(err => { - console.log(`stream start: ${err}`); - }) - }); - - // PTW recommends sample driven - ourBoard.on('sample',sample => { - // Resynchronize every every 5 minutes - if (sample._count % (sampleRate * resyncPeriodMin * secondsInMinute) === 0) { - ourBoard.syncClocksFull() - .then(syncObj => { - // Sync was successful - if (syncObj.valid) { - // Log the object to check it out! - console.log(`syncObj`,syncObj); - - // Sync was not successful - } else { - // Retry it - console.log(`Was not able to sync, please retry?`); - } - }); - } - - if (sample.timeStamp) { // true after the first sync - console.log(`NTP Time Stamp ${sample.timeStamp}`); - } - - }); -}) -.catch(err => { - console.log(`connect: ${err}`); -}); -``` - -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()`](#method-list-ports) 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 OpenBCIBoard = require('openbci').OpenBCIBoard; -var ourBoard = new 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*/ - } -}); -``` - -Note: [`.autoFindOpenBCIBoard()`](#method-auto-find-open-bci-board) will return the name of the Simulator if you instantiate with option `simulate: true`. - -Auto Test - (Using impedance to determine signal quality) ---------------------------------------------------------- -Measuring impedance is a vital tool in ensuring great data is collected. - -**_IMPORTANT!_** Measuring impedance takes time, so *only test what you must* - -Your OpenBCI board will have electrodes hooked up to either a P input, N input or in some cases both inputs. - -To test specific inputs of channels: - -1. Connect to board. -2. Start streaming. -3. Install the ['impedanceArray'](#event-impedance-array) event -4. Call [`.impedanceTestChannels()`](#method-impedance-test-channels) with your configuration array - -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 OpenBCIBoard = require('openbci').OpenBCIBoard; -var ourBoard = new OpenBCIBoard(); -ourBoard.connect(portName).then(function(boardSerial) { - ourBoard.on('ready',function() { - 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 */ -}); -``` - -But wait! What is this `impedanceArray`? An Array of Objects, for each object: -```js -[{ - channel: 1, - P: { - raw: -1, - text: 'init' - }, - N: { - raw: -1, - text: 'init' - } -}, -{ - // Continues for each channel up to the amount of channels on board (8 or 16) -},...]; -``` - -Where: - -* *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) - * *raw* is an impedance value resulting from the Goertzel algorithm. - * *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 run an impedance test on all inputs, one channel at a time: - -1. Connect to board -2. Start streaming -3. Install the ['impedanceArray'](#event-impedance-array) -4. Call [`.impedanceTestAllChannels()`](#method-impedance-test-all-channels) - -**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 OpenBCIBoard = require('openbci').OpenBCIBoard; -var ourBoard = new OpenBCIBoard(); -ourBoard.connect(portName).then(function(boardSerial) { - ourBoard.streamStart(); - ourBoard.on('impedanceArray', impedanceArray => { - /** Work with impedance */ - }); - ourBoard.impedanceTestAllChannels(); -} -``` +First and foremost, Welcome! :tada: Willkommen! :confetti_ball: Bienvenue! :balloon::balloon::balloon: -See Reference Guide for a complete list of impedance tests. +Thank you for visiting the OpenBCI NodeJS SDK repository. -# SDK Reference Guide: ---------------- -## Constructor: +This document (the README file) is a hub to give you some information about the project. Jump straight to one of the sections below, or just scroll down to find out more. -### OpenBCIBoard (options) +* [What are we doing? (And why?)](#what-are-we-doing) +* [Who are we?](#who-are-we) +* [What do we need?](#what-do-we-need) +* [How can you get involved?](#get-involved) +* [Get in touch](#contact-us) +* [Find out more](#find-out-more) +* [Understand the jargon](#glossary) -Create new instance of an OpenBCI board. +## What are we doing? -**_options (optional)_** +### The problem -Board optional configurations. +* There are a bunch of NodeJS repos for the Ganglion, Cyton and Wifi Shield +* Examples are spread out across all these NodeJS repos +* Some examples across NodeJS repos have the same code +* There is no common interface for these NodeJS repos +* NodeJS is a powerful tool for -* `baudRate` {Number} - Baud Rate, defaults to 115200. Manipulating this is allowed if firmware on board has been previously configured. -* `boardType` {String} - Specifies type of OpenBCI board (3 possible boards) - * `default` - 8 Channel OpenBCI board (Default) - * `daisy` - 8 Channel board with Daisy Module - 16 Channels - * `ganglion` - 4 Channel board - (NOTE: THIS IS IN-OP TIL RELEASE OF GANGLION BOARD 08/2016) -* `hardSet` {Boolean} - Recommended if using `daisy` board! For some reason, the `daisy` is sometimes not picked up by the module so you can set `hardSet` to true which will ensure the daisy is picked up. (Default `false`) -* `simulate` {Boolean} - Full functionality, just mock data. Must attach Daisy module by setting `simulatorDaisyModuleAttached` to `true` in order to get 16 channels. (Default `false`) -* `simulatorBoardFailure` {Boolean} - Simulates board communications failure. This occurs when the RFduino on the board is not polling the RFduino on the dongle. (Default `false`) -* `simulatorDaisyModuleAttached` {Boolean} - Simulates a daisy module being attached to the OpenBCI board. This is useful if you want to test how your application reacts to a user requesting 16 channels but there is no daisy module actually attached, or vice versa, where there is a daisy module attached and the user only wants to use 8 channels. (Default `false`) -* `simulatorFirmwareVersion` {String} - Allows the simulator to use firmware version 2 features. (2 Possible Options) - * `v1` - Firmware Version 1 (Default) - * `v2` - Firmware Version 2 -* `simulatorFragmentation` {String} - Specifies how to break packets to simulate fragmentation, which occurs commonly in real devices. It is recommended to test code with this enabled. (4 Possible Options) - * `none` - do not fragment packets; output complete chunks immediately when produced (Default) - * `random` - output random small chunks of data interspersed with full buffers - * `fullBuffers` - allow buffers to fill up until latency timer has expired - * `oneByOne` - output each byte separately -* `simulatorLatencyTime` {Number} - The time in milliseconds to wait before sending partially full buffers of data, if `simulatorFragmentation` is specified. (Default `16`) -* `simulatorBufferSize` {Number} - The size of a full buffer of data, if `simulatorFragmentation` is specified. (Default `4096`) -* `simulatorHasAccelerometer` - {Boolean} - Sets simulator to send packets with accelerometer data. (Default `true`) -* `simulatorInjectAlpha` - {Boolean} - Inject a 10Hz alpha wave in Channels 1 and 2 (Default `true`) -* `simulatorInjectLineNoise` {String} - Injects line noise on channels. (3 Possible Options) - * `60Hz` - 60Hz line noise (Default) [America] - * `50Hz` - 50Hz line noise [Europe] - * `none` - Do not inject line noise. -* `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`) -* `simulatorSerialPortFailure` {Boolean} - Simulates not being able to open a serial connection. Most likely due to a OpenBCI dongle not being plugged in. -* `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`) -* `sntpTimeSyncHost` - {String} The sntp server to use, can be either sntp or ntp (Defaults `pool.ntp.org`). -* `sntpTimeSyncPort` - {Number} The port to access the sntp server (Defaults `123`) -* `verbose` {Boolean} - Print out useful debugging events (Default `false`) -* `debug` {Boolean} - Print out a raw dump of bytes sent and received (Default `false`) +So, if even the very best developers want to use NodeJS with their OpenBCI boards, they are left scratching their heads with where to begin. integrate the current easy to use Cyton and Ganglion NodeJS drivers, they are still burdened by the limitations of the physical hardware on the OpenBCI system. -**Note, we have added support for either all lowercase OR camel case for the options, use whichever style you prefer.** +### The solution -## Methods: +The OpenBCI NodeJS SDK will: -### .autoFindOpenBCIBoard() +* Allow NodeJS users to import one module and use any board they choose +* Provide examples of using NodeJS to port data to other apps like python and lab streaming layer +* Provide a no low level device specific code to prevent the need to rewrite new examples for each board +* Provide examples of filtering and different functions to transform raw data +* Provide a common interface to all openbci boards to increase the speed at which new boards can be integrated -Automatically find an OpenBCI board. +Using this repo provides a building block for developing with NodeJS. The goal for the NodeJS library is to ***provide a single source to program all OpenBCI biosensors in NodeJS*** -**Note: This will always return an Array of `COM` ports on Windows** +## Who are we? -**_Returns_** a promise, fulfilled with a `portName` such as `/dev/tty.*` on Mac/Linux or `OpenBCISimulator` if `this.options.simulate === true`. +The founder of the OpenBCI NodeJS SDK is [AJ Keller][link_aj_keller]. If we look back in time, we see this library took shape when the [Cyton][link_shop_cyton] board was the only [OpenBCI][link_openbci] board around. Then the [Ganglion][link_shop_ganglion] came around which required it's own [nodejs libary][link_nodejs_ganglion]! When the [wifi shield][link_shop_wifi_shield] was in development, AJ created the [wifi nodejs driver][link_nodejs_wifi] which was had a lot of overlap with Cyton and Ganglion nodejs drivers. Therefore AJ pulled out the common code between all three NodeJS modules and created the [nodejs utilities][link_nodejs_utilities] which as of today is also available to use in the browser. -### .channelOff(channelNumber) +The contributors to these repos are people using NodeJS mainly for their data acquisition purposes. For example, the entire OpenBCI GUI is dependent on the NodeJS ecosystem to provide cross platform support. -Turn off a specified channel +## What do we need? -**_channelNumber_** +**You**! In whatever way you can help. -A number (1-16) specifying which channel you want to turn off. +We need expertise in programming, user experience, software sustainability, documentation and technical writing and project management. -**_Returns_** a promise, fulfilled if the command was sent to the write queue. +We'd love your feedback along the way. -### .channelOn(channelNumber) +Our primary goal is to provide a single source to program all OpenBCI biosensors in NodeJS, and we're excited to support the professional development of any and all of our contributors. If you're looking to learn to code, try out working collaboratively, or translate you skills to the digital domain, we're here to help. -Turn on a specified channel +## Get involved -**_channelNumber_** +If you think you can help in any of the areas listed above (and we bet you can) or in any of the many areas that we haven't yet thought of (and here we're *sure* you can) then please check out our [contributors' guidelines](CONTRIBUTING.md) and our [roadmap](ROADMAP.md). -A number (1-16) specifying which channel you want to turn on. +Please note that it's very important to us that we maintain a positive and supportive environment for everyone who wants to participate. When you join us we ask that you follow our [code of conduct](CODE_OF_CONDUCT.md) in all interactions both on and offline. -**_Returns_** a promise, fulfilled if the command was sent to the write queue. -### .channelSet(channelNumber,powerDown,gain,inputType,bias,srb2,srb1) +## Contact us -Send a channel setting command to the board. +If you want to report a problem or suggest an enhancement we'd love for you to [open an issue](../../issues) at this github repository because then we can get right on it. But you can also contact [AJ][link_aj_keller] by email (pushtheworldllc AT gmail DOT com) or on [twitter](https://twitter.com/aj-ptw). -**_channelNumber_** +You can also hang out, ask questions and share stories in the [OpenBCI NodeJS room](https://gitter.im/OpenBCI/OpenBCI_NodeJS?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) on Gitter. -Determines which channel to set. It's a 'Number' (1-16) +## Find out more -**_powerDown_** +You might be interested in: -Powers the channel up or down. It's a 'Bool' where `true` turns the channel off and `false` turns the channel on (default) +* Purchase a [Cyton][link_shop_cyton] | [Ganglion][link_shop_ganglion] | [WiFi Shield][link_shop_wifi_shield] from [OpenBCI][link_openbci] +* Get taught how to use OpenBCI devices by [Push The World][link_ptw] BCI Consulting -**_gain_** +And of course, you'll want to know our: -Sets the gain for the channel. It's a 'Number' that is either (1,2,4,6,8,12,24(default)) +* [Contributors' guidelines](CONTRIBUTING.md) +* [Roadmap](ROADMAP.md) -**_inputType_** +## Glossary -Selects the ADC channel input source. It's a 'String' that **MUST** be one of the following: "normal", "shorted", "biasMethod" , "mvdd" , "temp" , "testsig", "biasDrp", "biasDrn". +OpenBCI boards are commonly referred to as _biosensors_. A biosensor converts biological data into digital data. -**_bias_** - -Selects if the channel shall include the channel input in bias generation. It's a 'Bool' where `true` includes the channel in bias (default) or `false` it removes it from bias. - -**_srb2_** - -Select to connect (`true`) this channel's P input to the SRB2 pin. This closes a switch between P input and SRB2 for the given channel, and allows the P input to also remain connected to the ADC. It's a 'Bool' where `true` connects this input to SRB2 (default) or `false` which disconnect this input from SRB2. - -**_srb1_** - -Select to connect (`true`) all channels' N inputs to SRB1. This effects all pins, and disconnects all N inputs from the ADC. It's a 'Bool' where `true` connects all N inputs to SRB1 and `false` disconnects all N inputs from SRB1 (default). - -**_Returns_** a promise fulfilled if proper commands sent to the write queue, rejects on bad input or no board. - -**Example** -```js -ourBoard.channelSet(2,false,24,'normal',true,true,false); -// sends ['x','2','0','6','0','1','1','0','X'] to the command queue -``` - -### .connect(portName) - -The essential precursor method to be called initially to establish a serial connection to the OpenBCI board. - -**_portName_** - -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. - -### .debugSession() - -Calls all [`.printPacketsBad()`](#method-print-packets-bad), [`.printPacketsRead()`](#method-print-packets-read), [`.printBytesIn()`](#method-print-bytes-in) - -### .disconnect() - -Closes the serial port opened by [`.connect()`](#method-connect). Waits for stop streaming command to be sent if currently streaming. - -**_Returns_** a promise, fulfilled by a successful close of the serial port object, rejected otherwise. - -### .getInfo() - -Get the core info object. It's the object that actually drives the parsing of data. - -**_Returns_** Object - {{boardType: string, sampleRate: number, firmware: string, numberOfChannels: number, missedPackets: number}} - -### .getSettingsForChannel(channelNumber) - -Gets the specified channelSettings register data from printRegisterSettings call. - -**_channelNumber_** - -A number specifying which channel you want to get data on. Only 1-8 at this time. - -**Note, at this time this does not work for the daisy board** - -**_Returns_** a promise, fulfilled if the command was sent to the board and the `.processBytes()` function is ready to reach for the specified channel. - -### .hardSetBoardType(boardType) - -Used to sync the module and board to `boardType`. - -**Note: This has the potential to change the way data is parsed** +The [Ganglion][link_shop_ganglion] has 4 channels, meaning the Ganglion can take four simultaneous voltage readings. -**_boardType_** - -A String indicating the number of channels. - -* `default` - Default board: Sample rate is `250Hz` and number of channels is `8`. -* `daisy` - Daisy board: Sample rate is `125Hz` and number of channels is `16`. - -**_Returns_** a promise, fulfilled if both the board and module are the requested `boardType`, rejects otherwise. - -### .impedanceTestAllChannels() - -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)! - -Don't forget to install the ['impedanceArray'](#event-impedance-array) emitter to receive the impendances! - -**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!** - -**_Returns_** a promise upon completion of test. - -### .impedanceTestChannels(arrayOfCommands) - -**_arrayOfCommands_** - -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) - -Don't forget to install the `impedanceArray` emitter to receive the impendances! +The [Cyton][link_shop_cyton] has 8 channels and [Cyton with Daisy][link_shop_cyton_daisy] has 16 channels. -**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!** +Generally speaking, the Cyton records at a high quality with less noise. Noise is anything that is not signal. -**_Returns_** a promise upon completion of test. +## Thank you -### .impedanceTestChannel(channelNumber) +Thank you so much (Danke schön! Merci beaucoup!) for visiting the project and we do hope that you'll join us on this amazing journey to make programming with OpenBCI fun and easy. -Run a complete impedance test on a single channel, applying the test signal individually to P & N inputs. - -**_channelNumber_** - -A Number, specifies which channel you want to test. - -**_Returns_** a promise that resolves a single channel impedance object. - -**Example** -```js -var OpenBCIBoard = require('openbci').OpenBCIBoard; -var ourBoard = new 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: { - raw: 2394.45, - text: 'good' - }, - N: { - raw: 7694.45, - text: 'ok' - } -} -``` - -### .impedanceTestChannelInputP(channelNumber) - -Run impedance test on a single channel, applying the test signal only to P input. - -**_channelNumber_** - -A Number, specifies which channel you want to test. - -**_Returns_** a promise that resolves a single channel impedance object. - -**Example** -```js -var OpenBCIBoard = require('openbci').OpenBCIBoard; -var ourBoard = new 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: { - raw: 2394.45, - text: 'good' - }, - N: { - raw: -1, - text: 'init' - } -} +## Installation: ``` - -### .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 OpenBCIBoard = require('openbci').OpenBCIBoard; -var ourBoard = new 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: { - raw: -1, - text: 'init' - }, - N: { - raw: 7694.45, - text: 'ok' - } -} -``` - -### .impedanceTestContinuousStart() - -Sends command to turn on impedances for all channels and continuously calculate their impedances. - -**_Returns_** a promise, that fulfills when all the commands are sent to the internal write buffer - -### .impedanceTestContinuousStop() - -Sends command to turn off impedances for all channels and stop continuously calculate their impedances. - -**_Returns_** a promise, that fulfills when all the commands are sent to the internal write buffer - -### .isConnected() - -Checks if the driver is connected to a board. -**_Returns_** a boolean, true if connected - -### .isStreaming() - -Checks if the board is currently sending samples. -**_Returns_** a boolean, true if streaming - -### .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() - -Get the current number of channels available to use. (i.e. 8 or 16). - -**Note: This is dependent on if you configured the board correctly on setup options. Specifically as a daisy.** - -**_Returns_** a number, the total number of available channels. - -### .overrideInfoForBoardType(boardType) - -Set the info property for board type. - -**Note: This has the potential to change the way data is parsed** - -**_boardType_** - -A String indicating the number of channels. - -* `default` - Default board: Sample rate is `250Hz` and number of channels is `8`. -* `daisy` - Daisy board: Sample rate is `125Hz` and number of channels is `16`. - -### .printBytesIn() - -Prints the total number of bytes that were read in this session to the console. - -### .printPacketsBad() - -Prints the total number of packets that were not able to be read in this session to the console. - -### .printPacketsRead() - -Prints the total number of packets that were read in this session to the console. - -### .printRegisterSettings() - -Prints all register settings for the ADS1299 and the LIS3DH on the OpenBCI board. - -**_Returns_** a promise, fulfilled if the command was sent to the write queue. - -### .radioBaudRateSet(speed) - -Used to set the OpenBCI Host (Dongle) baud rate. With the RFduino configuration, the Dongle is the Host and the Board is the Device. Only the Device can initiate a communication between the two entities. There exists a detrimental error where if the Host is interrupted by the radio during a Serial write, then all hell breaks loose. So this is an effort to eliminate that problem by increasing the rate at which serial data is sent from the Host to the Serial driver. The rate can either be set to default or fast. Further the function should reject if currently streaming. Lastly and more important, if the board is not running the new firmware then this functionality does not exist and thus this method will reject. If the board is using firmware 2+ then this function should resolve the new baud rate after closing the current serial port and reopening one. - -**Note, this functionality requires OpenBCI Firmware Version 2.0** - -**_speed_** - -{String} - The baud rate that to switch to. Can be either `default` (115200) or `fast` (230400). - -**_Returns_** {Promise} - Resolves a {Number} that is the new baud rate, rejects on error. - -### .radioChannelGet() - -Used to query the OpenBCI system for it's radio channel number. The function will reject if not connected to the serial port of the dongle. Further the function should reject if currently streaming. Lastly and more important, if the board is not running the new firmware then this functionality does not exist and thus this method will reject. If the board is using firmware 2+ then this function should resolve an Object. See `returns` below. - -**Note, this functionality requires OpenBCI Firmware Version 2.0** - -**_Returns_** {Promise} - Resolve an object with keys `channelNumber` which is a Number and `err` which contains an error in the condition that there system is experiencing board communications failure. - -### .radioChannelSet(channelNumber) - -Used to set the system radio channel number. The function will reject if not connected to the serial port of the dongle. Further the function should reject if currently streaming. Lastly and more important, if the board is not running the new firmware then this functionality does not exist and thus this method will reject. If the board is using firmware 2+ then this function should resolve. - -**Note, this functionality requires OpenBCI Firmware Version 2.0** - -**_channelNumber_** - -{Number} - The channel number you want to set to, 1-25. - -**_Returns_** {Promise} - Resolves with the new channel number, rejects with err. - -### .radioChannelSetHostOverride(channelNumber) - -Used to set the ONLY the radio dongle Host channel number. This will fix your radio system if your dongle and board are not on the right channel and bring down your radio system if you take your dongle and board are not on the same channel. Use with caution! The function will reject if not connected to the serial port of the dongle. Further the function should reject if currently streaming. Lastly and more important, if the board is not running the new firmware then this functionality does not exist and thus this method will reject. If the board is using firmware 2+ then this function should resolve. - -**Note, this functionality requires OpenBCI Firmware Version 2.0** - -**_channelNumber_** - -{Number} - The channel number you want to set to, 1-25. - -**_Returns_** {Promise} - Resolves with the new channel number, rejects with err. - -### .radioPollTimeGet() - -Used to query the OpenBCI system for it's device's poll time. The function will reject if not connected to the serial port of the dongle. Further the function should reject if currently streaming. Lastly and more important, if the board is not running the new firmware then this functionality does not exist and thus this method will reject. If the board is using firmware 2+ then this function should resolve the poll time when fulfilled. It's important to note that if the board is not on, this function will always be rejected with a failure message. - -**Note, this functionality requires OpenBCI Firmware Version 2.0** - -**_Returns_** {Promise} - Resolves with the new poll time, rejects with err. - -### .radioPollTimeSet(pollTime) - -Used to set the OpenBCI poll time. With the RFduino configuration, the Dongle is the Host and the Board is the Device. Only the Device can initiate a communication between the two entities. Therefore this sets the interval at which the Device polls the Host for new information. Further the function should reject if currently streaming. Lastly and more important, if the board is not running the new firmware then this functionality does not exist and thus this method will reject. If the board is using firmware 2+ then this function should resolve. - -**Note, this functionality requires OpenBCI Firmware Version 2.0** - -**_pollTime_** - -{Number} - The poll time you want to set to, 0-255. - -**_Returns_** {Promise} - Resolves with the new channel number, rejects with err. - -### .radioSystemStatusGet() - -Used to ask the Host if it's radio system is up. This is useful to quickly determine if you are in fact ready to start trying to connect and such. The function will reject if not connected to the serial port of the dongle. Further the function should reject if currently streaming. Lastly and more important, if the board is not running the new firmware then this functionality does not exist and thus this method will reject. If the board is using firmware +v2.0.0 and the radios are both on the same channel and powered, then this will resolve true. - -**Note, this functionality requires OpenBCI Firmware Version 2.0** - -**_Returns_** {Promise} - Resolves true if both radios are powered and on the same channel; false otherwise. - -### .sampleRate() - -Get the current sample rate. - -**Note: This is dependent on if you configured the board correctly on setup options. Specifically as a daisy.** - -**_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()`](#method-connect) after. - -**Note, must be called after the constructor.** - -**_Returns_** a promise, fulfilled if able to enter simulate mode, reject if not. - -### .simulatorDisable() - -To leave simulate mode. - -**Note, must be called after the constructor.** - -**_Returns_** a promise, fulfilled if able to stop simulate mode, reject if not. - -### .sntp - -Extends the popular SNTP package on [npmjs](https://www.npmjs.com/package/sntp) - -### .sntpGetOffset() - -Stateful method for querying the current offset only when the last one is too old. (defaults to daily) - -**_Returns_** a promise with the time offset - -### .sntpStart() - -This starts the SNTP server and gets it to remain in sync with the SNTP server. - -**_Returns_** a promise if the module was able to sync with NTP server. - -### .sntpStop() - -Stops the SNTP from updating - -### .softReset() - -Sends a soft reset command to the board. - -**Note, this method must be sent to the board before you can start streaming. This triggers the initial 'ready' event emitter.** - -**_Returns_** a promise, fulfilled if the command was sent to the write queue. - -### .streamStart() - -Sends a start streaming command to the board. - -**Note, You must have called and fulfilled [`.connect()`](#method-connect) AND observed a `'ready'` emitter before calling this method.** - -**_Returns_** a promise, fulfilled if the command was sent to the write queue, rejected if unable. - -### .streamStop() - -Sends a stop streaming command to the board. - -**Note, You must have called and fulfilled [`.connect()`](#method-connect) AND observed a `'ready'` emitter before calling this method.** - -**_Returns_** a promise, fulfilled if the command was sent to the write queue, rejected if unable. - -### .syncClocks() - -Send the command to tell the board to start the syncing protocol. Must be connected, streaming and using version +2 firmware. - -**Note, this functionality requires OpenBCI Firmware Version 2.0** - -**_Returns_** {Promise} resolves if the command was sent to the write queue, rejects if unable. - -### .syncClocksFull() - -Send the command to tell the board to start the syncing protocol. Must be connected, streaming and using v2 firmware. Uses the `synced` event to ensure multiple syncs don't overlap. - -**Note, this functionality requires OpenBCI Firmware Version 2.0** - -**_Returns_** {Promise} resolves if `synced` event is emitted, rejects if not connected or using firmware v2. Resolves with a synced object: -```javascript -{ - boardTime: 0, // The time contained in the time sync set packet. - correctedTransmissionTime: false, // If the confirmation and the set packet arrive in the same serial flush we have big problem! This will be true in this case. See source code for full explanation. - timeSyncSent: 0, // The time the `<` was sent to the Dongle. - timeSyncSentConfirmation: 0, // The time the `<` was sent to the Board; It's really the time `,` was received from the Dongle. - timeSyncSetPacket: 0, // The time the set packet was received from the Board. - 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. -} -``` - -**Example** - -Syncing multiple times to base the offset of the average of the four syncs. - -```javascript -var OpenBCIBoard = require('openbci').OpenBCIBoard, - ourBoard = new OpenBCIBoard({ - verbose:true - }); - -var portName = /* INSERT PORT NAME HERE */; -var samples = []; // Array to store time synced samples into -var timeSyncActivated = false; - -ourBoard.connect(portName) - .then(() => { - ourBoard.on('ready',() => { - ourBoard.streamStart() - .then(() => { - /** Could also call `.syncClocksFull()` here */ - }) - .catch(err => { - console.log(`Error starting stream ${err}`); - }) - }); - ourBoard.on('sample',sample => { - /** If we are not synced, then do that! */ - if (timeSyncActivated === false) { - timeSyncActivated = true; - ourBoard.syncClocksFull() - .then(syncObj => { - if (syncObj.valid) { - console.log('1st sync done'); - } - return ourBoard.syncClocksFull(); - }) - .then(syncObj => { - if (syncObj.valid) { - console.log('2nd sync done'); - } - return ourBoard.syncClocksFull(); - }) - .then(syncObj => { - if (syncObj.valid) { - console.log('3rd sync done'); - } - return ourBoard.syncClocksFull(); - }) - .then(syncObj => { - if (syncObj.valid) { - console.log('4th sync done'); - - } - /* Do awesome time syncing stuff */ - }) - .catch(err => { - console.log(`sync err ${err}`); - }); - } - if (startLoggingSamples && sample.hasOwnProperty("timeStamp") && sample.hasOwnProperty("boardTime")) { - /** If you only want to log samples with time stamps */ - samples.push(sample); - } - }); - }) -.catch(err => { - console.log(`connect ${err}`); -}); - -``` - -### .testSignal(signal) - -Apply the internal test signal to all channels. - -**_signal_** - -A String indicating which test signal to apply - - * `dc` - Connect to DC signal - * `ground` - Connect to internal GND (VDD - VSS) - * `pulse1xFast` - Connect to test signal 1x Amplitude, fast pulse - * `pulse1xSlow` - Connect to test signal 1x Amplitude, slow pulse - * `pulse2xFast` - Connect to test signal 2x Amplitude, fast pulse - * `pulse2xFast` - Connect to test signal 2x Amplitude, slow pulse - * `none` - Reset to default - -**_Returns_** a promise, if the commands were sent to write buffer. - -### .time() - -Uses `._sntpNow()` time when sntpTimeSync specified `true` in options, or else Date.now() for time. - -**_Returns_** time since UNIX epoch in ms. - -### .usingVersionTwoFirmware() - -Convenience method to determine if you can use firmware v2.x.x capabilities. - -**Note, should be called after a [`.softReset()`](#method-soft-reset) because we can parse the output of that to determine if we are using firmware version 2.** - -**_Returns_** a boolean, true if using firmware version 2 or greater. - -### .write(dataToWrite) - -Send commands to the board. Due to the OpenBCI board firmware 1.0, a 10ms spacing **must** be observed between every command sent to the board. This method handles the timing and spacing between characters by adding characters to a global write queue and pulling from it every 10ms. If you are using firmware version +2.0 then you no spacing will be used. - -**_dataToWrite_** - -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, rejected if there were any problems. - -**Example** - -Sends a single character command to the board. -```js -// ourBoard has fulfilled the promise on .connect() and 'ready' has been observed previously -ourBoard.write('a'); -``` - -Sends an array of bytes -```js -// ourBoard has fulfilled the promise on .connect() and 'ready' has been observed previously -ourBoard.write(['x','0','1','0','0','0','0','0','0','X']); -``` - -Taking full advantage of the write queue. The following would be sent at t = 0, 10ms, 20ms, 30ms -```js -ourBoard.write('t'); -ourBoard.write('a'); -ourBoard.write('c'); -ourBoard.write('o'); -``` - -## Events: - -### .on('close', callback) - -Emitted when the serial connection to the board is closed. - -### .on('droppedPacket', callback) - -Emitted when a packet (or packets) are dropped. Returns an array. - -### .on('error', callback) - -Emitted when there is an on the serial port. - -### .on('hardSet', callback) - -Emitted when the module detects the board is not configured as the options for the module intended and tries to save itself. i.e. when the `daisy` option is `true` and a soft reset message is parsed and the module determines that a daisy was not detected, the module will emit `hardSet` then send an attach daisy command to recover. Either `error` will be emitted if unable to attach or `ready` will be emitted if success. - -### .on('impedanceArray', callback) - -Emitted when there is a new impedanceArray available. Returns an array. - -### .on('query', callback) - -Emitted resulting in a call to [`.getChannelSettings()`](#method-get-settings-for-channel) 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. - -### .on('synced', callback) - -Emitted when there is a new sample available. - -## Constants: - -To use the constants file simply: -```js -var openBCIBoard = require('openbci'); -var k = openBCIBoard.OpenBCIConstants; - -console.log(k.OBCISimulatorPortName); // prints OpenBCISimulator to the console. +npm install openbci ``` -### .OBCISimulatorPortName - -The name of the simulator port. - -## Interfacing With Other Tools: - -### LabStreamingLayer - -[LabStreamingLayer](https://github.com/sccn/labstreaminglayer) is a tool for streaming or recording time-series data. It can be used to interface with [Matlab](https://github.com/sccn/labstreaminglayer/tree/master/LSL/liblsl-Matlab), [Python](https://github.com/sccn/labstreaminglayer/tree/master/LSL/liblsl-Python), [Unity](https://github.com/xfleckx/LSL4Unity), and many other programs. - -To use LSL with the NodeJS SDK, go to our [labstreaminglayer example](https://github.com/OpenBCI/OpenBCI_NodeJS/tree/master/examples/labstreaminglayer), which contains code that is ready to start an LSL stream of OpenBCI data. - -Follow the directions in the [readme](https://github.com/OpenBCI/OpenBCI_NodeJS/blob/master/examples/labstreaminglayer/readme.md) to get started. - - ## Developing: ### Running: ``` -npm install -``` - -### Testing: - -``` -npm test +npm install --all ``` -## Contribute: - -1. Fork it! -2. Branch off of `development`: `git checkout development` -2. Create your feature branch: `git checkout -b my-new-feature` -3. Make changes -4. If adding a feature, please add test coverage. -5. Ensure tests all pass. (`npm test`) -6. Commit your changes: `git commit -m 'Add some feature'` -7. Push to the branch: `git push origin my-new-feature` -8. Submit a pull request. Make sure it is based off of the `development` branch when submitting! :D - ## License: MIT -## Roadmap: - -1. Ganglion integration (2.x) -2. Compatible with node streams (3.x) -3. Remove factory paradigm from main file (3.x) -5. ES6/ES7 total adoption (3.x) -4. Browser support (with browser serialport) (x.x) +[link_aj_keller]: https://github.com/aj-ptw +[link_shop_wifi_shield]: https://shop.openbci.com/collections/frontpage/products/wifi-shield?variant=44534009550 +[link_shop_ganglion]: https://shop.openbci.com/collections/frontpage/products/pre-order-ganglion-board +[link_shop_cyton]: https://shop.openbci.com/collections/frontpage/products/cyton-biosensing-board-8-channel +[link_shop_cyton_daisy]: https://shop.openbci.com/collections/frontpage/products/cyton-daisy-biosensing-boards-16-channel +[link_nodejs_cyton]: https://github.com/openbci/openbci_nodejs_cyton +[link_nodejs_ganglion]: https://github.com/openbci/openbci_nodejs_ganglion +[link_nodejs_wifi]: https://github.com/openbci/openbci_nodejs_wifi +[link_nodejs_utilities]: https://github.com/openbci/openbci_nodejs_utilities +[link_ptw]: https://www.pushtheworldllc.com +[link_openbci]: http://www.openbci.com +[link_mozwow]: http://mozillascience.github.io/working-open-workshop/index.html +[link_wifi_get_streaming]: examples/getStreaming/getStreaming.js +[link_openleaderscohort]: https://medium.com/@MozOpenLeaders +[link_mozsci]: https://science.mozilla.org diff --git a/ROADMAP.md b/ROADMAP.md new file mode 100755 index 0000000..8a57642 --- /dev/null +++ b/ROADMAP.md @@ -0,0 +1,14 @@ +# Roadmap + +## OpenBCI WiFi NodeJS + +Make programming with OpenBCI reliable, easy, research grade and fun! + +## Short term - what we're working on now + +- Add examples of data extraction +- Documentation + +## Medium term + +- Emotion detection diff --git a/examples/debug/debug.js b/examples/debug/debug.js index 822e185..9fa2ec3 100644 --- a/examples/debug/debug.js +++ b/examples/debug/debug.js @@ -10,12 +10,11 @@ * then `npm start` */ -var stream = true; -var debug = true; // Pretty print any bytes in and out... it's amazing... -var verbose = true; // Adds verbosity to functions -var OpenBCIBoard = require('openbci').OpenBCIBoard; - -var ourBoard = new OpenBCIBoard({ +const stream = true; +const debug = true; // Pretty print any bytes in and out... it's amazing... +const verbose = true; // Adds verbosity to functions +const Cyton = require('openbci').Cyton; +let ourBoard = new Cyton({ debug: debug, verbose: verbose }); diff --git a/examples/debug/package.json b/examples/debug/package.json index cfa64a9..04a4710 100644 --- a/examples/debug/package.json +++ b/examples/debug/package.json @@ -13,6 +13,6 @@ "author": "AJ Keller", "license": "MIT", "dependencies": { - "openbci": "^1.5.0" + "openbci": "^2.0.0" } } diff --git a/examples/getStreaming/getStreaming.js b/examples/getStreaming/getStreaming.js index 9d9f56f..424b012 100644 --- a/examples/getStreaming/getStreaming.js +++ b/examples/getStreaming/getStreaming.js @@ -9,11 +9,11 @@ * do `npm install` * then `npm start` */ -var debug = false; // Pretty print any bytes in and out... it's amazing... -var verbose = true; // Adds verbosity to functions +const debug = false; // Pretty print any bytes in and out... it's amazing... +const verbose = true; // Adds verbosity to functions -var OpenBCIBoard = require('openbci').OpenBCIBoard; -var ourBoard = new OpenBCIBoard({ +const Cyton = require('../../index').Cyton; +let ourBoard = new Cyton({ debug: debug, verbose: verbose }); @@ -28,7 +28,19 @@ ourBoard.autoFindOpenBCIBoard().then(portName => { ourBoard.connect(portName) // Port name is a serial port name, see `.listPorts()` .then(() => { ourBoard.on('ready', () => { - ourBoard.streamStart(); + ourBoard.syncRegisterSettings() + .then((cs) => { + return ourBoard.streamStart(); + }) + .catch((err) => { + console.log('err', err); + return ourBoard.streamStart(); + }) + .catch((err) => { + console.log('fatal err', err); + process.exit(0); + }); + ourBoard.on('sample', (sample) => { /** Work with sample */ for (let i = 0; i < ourBoard.numberOfChannels(); i++) { diff --git a/examples/getStreaming/package.json b/examples/getStreaming/package.json index 04f23df..68edb1b 100644 --- a/examples/getStreaming/package.json +++ b/examples/getStreaming/package.json @@ -13,6 +13,6 @@ "author": "AJ Keller", "license": "MIT", "dependencies": { - "openbci": "^1.5.0" + "openbci": "^2.0.0" } } diff --git a/examples/getStreamingDaisy/getStreamingDaisy.js b/examples/getStreamingDaisy/getStreamingDaisy.js index 0611534..ab3b446 100644 --- a/examples/getStreamingDaisy/getStreamingDaisy.js +++ b/examples/getStreamingDaisy/getStreamingDaisy.js @@ -9,11 +9,11 @@ * do `npm install` * then `npm start` */ -var debug = false; // Pretty print any bytes in and out... it's amazing... -var verbose = true; // Adds verbosity to functions +const debug = false; // Pretty print any bytes in and out... it's amazing... +const verbose = true; // Adds verbosity to functions -var OpenBCIBoard = require('openbci').OpenBCIBoard; -var ourBoard = new OpenBCIBoard({ +const Cyton = require('../../index').Cyton; +let ourBoard = new Cyton({ boardType: 'daisy', debug: debug, hardSet: true, diff --git a/examples/getStreamingDaisy/package.json b/examples/getStreamingDaisy/package.json index a84fa7a..f27ace9 100644 --- a/examples/getStreamingDaisy/package.json +++ b/examples/getStreamingDaisy/package.json @@ -13,6 +13,6 @@ "author": "AJ Keller", "license": "MIT", "dependencies": { - "openbci": "^1.5.0" + "openbci": "^2.0.0" } } diff --git a/examples/impedance/impedance.js b/examples/impedance/impedance.js index 137439d..d9c29ec 100644 --- a/examples/impedance/impedance.js +++ b/examples/impedance/impedance.js @@ -9,15 +9,16 @@ * do `npm install` * then `npm start` */ -var debug = false; // Pretty print any bytes in and out... it's amazing... -var verbose = true; // Adds verbosity to functions +const debug = false; // Pretty print any bytes in and out... it's amazing... +const verbose = true; // Adds verbosity to functions -var OpenBCIBoard = require('openbci').OpenBCIBoard; -var ourBoard = new OpenBCIBoard({ +const Cyton = require('openbci').Cyton; +let ourBoard = new Cyton({ debug: debug, verbose: verbose }); -var k = require('openbci').OpenBCIConstants; + +const k = require('openbci-utilities').Constants; let startedImpedance = false; let iBuffer = []; diff --git a/examples/impedance/package.json b/examples/impedance/package.json index 3b00667..58fffef 100644 --- a/examples/impedance/package.json +++ b/examples/impedance/package.json @@ -13,6 +13,7 @@ "author": "AJ Keller", "license": "MIT", "dependencies": { - "openbci": "^1.5.0" + "openbci": "^2.0.0", + "openbci-utilities": "0.0.9" } } diff --git a/examples/labstreaminglayer/index.js b/examples/labstreaminglayer/index.js index 719c75d..4fb2517 100644 --- a/examples/labstreaminglayer/index.js +++ b/examples/labstreaminglayer/index.js @@ -9,24 +9,24 @@ * do `npm install` * then `npm start` */ -var OpenBCIBoard = require('openbci').OpenBCIBoard; -var portPub = 'tcp://127.0.0.1:3004'; -var zmq = require('zmq-prebuilt'); -var socket = zmq.socket('pair'); -var debug = false; // Pretty print any bytes in and out... it's amazing... -var verbose = true; // Adds verbosity to functions - -var ourBoard = new OpenBCIBoard({ +const portPub = 'tcp://127.0.0.1:3004'; +const zmq = require('zmq-prebuilt'); +const socket = zmq.socket('pair'); +const debug = false; // Pretty print any bytes in and out... it's amazing... +const verbose = true; // Adds verbosity to functions + +const Cyton = require('openbci').Cyton; +let ourBoard = new Cyton({ simulatorFirmwareVersion: 'v2', debug: debug, verbose: verbose }); -var timeSyncPossible = false; -var resyncPeriodMin = 1; -var secondsInMinute = 60; -var numChans = 8; -var resyncPeriod = ourBoard.sampleRate() * resyncPeriodMin * secondsInMinute; +let timeSyncPossible = false; +let resyncPeriodMin = 1; +let secondsInMinute = 60; +let numChans = 8; +let resyncPeriod = ourBoard.sampleRate() * resyncPeriodMin * secondsInMinute; ourBoard.autoFindOpenBCIBoard().then(portName => { if (portName) { @@ -67,7 +67,7 @@ ourBoard.autoFindOpenBCIBoard().then(portName => { } }); -var sampleFunc = sample => { +const sampleFunc = sample => { if (sample._count % resyncPeriod === 0) { ourBoard.syncClocksFull() .then(syncObj => { @@ -107,9 +107,10 @@ socket.bind(portPub, function (err) { /** * Used to send a message to the Python process. * @param {Object} interProcessObject The standard inter-process object. + * @param {Boolean} verbose Should we do a verbose print out * @return {None} */ -var sendToPython = (interProcessObject, verbose) => { +const sendToPython = (interProcessObject, verbose) => { if (verbose) { console.log(`<- out ${JSON.stringify(interProcessObject)}`); } diff --git a/examples/labstreaminglayer/package.json b/examples/labstreaminglayer/package.json index 1aa759e..6d6d53d 100644 --- a/examples/labstreaminglayer/package.json +++ b/examples/labstreaminglayer/package.json @@ -18,7 +18,7 @@ "author": "AJ Keller", "license": "MIT", "dependencies": { - "openbci": "^1.4.2", + "openbci": "^2.0.0", "zmq-prebuilt": "^2.1.0" }, "devEngines": { diff --git a/examples/python/handoff.py b/examples/python/handoff.py index 7cc2a85..a095cfb 100644 --- a/examples/python/handoff.py +++ b/examples/python/handoff.py @@ -7,8 +7,8 @@ class Interface: def __init__(self, verbose=False): - context = zmq.Context() - self._socket = context.socket(zmq.PAIR) + self._context = zmq.Context() + self._socket = self._context.socket(zmq.PAIR) self._socket.connect("tcp://localhost:3004") self.verbose = verbose @@ -43,6 +43,13 @@ def recv(self): """ return self._socket.recv() + def close(self): + """ + Closes the zmq context + """ + self._backend.close() + self._context.term() + class RingBuffer(np.ndarray): """A multidimensional ring buffer.""" @@ -73,44 +80,49 @@ def main(argv): interface = Interface(verbose=verbose) # Signal buffer signal = RingBuffer(np.zeros((nb_chan + 1, 2500))) - - while True: - msg = interface.recv() - try: - dicty = json.loads(msg) - action = dicty.get('action') - command = dicty.get('command') - message = dicty.get('message') - - if command == 'sample': - if action == 'process': - # Do sample processing here - try: - if type(message) is not dict: - print "sample is not a dict", message - raise ValueError - # Get keys of sample - data = np.zeros(9) - - data[:-1] = message.get('channelData') - data[-1] = message.get('timeStamp') - - # Add data to end of ring buffer - signal.append(data) - - print message.get('sampleNumber') - except ValueError as e: - print e - elif command == 'status': - if action == 'active': - interface.send(json.dumps({ - 'action': 'alive', - 'command': 'status', - 'message': time.time() * 1000.0 - })) - - except BaseException as e: - print e + try: + while True: + msg = interface.recv() + print "woo" + try: + dicty = json.loads(msg) + action = dicty.get('action') + command = dicty.get('command') + message = dicty.get('message') + + if command == 'sample': + if action == 'process': + # Do sample processing here + try: + if type(message) is not dict: + print "sample is not a dict", message + raise ValueError + # Get keys of sample + data = np.zeros(nb_chan + 1) + + data[:-1] = message.get('channelData') + data[-1] = message.get('timeStamp') + + # Add data to end of ring buffer + signal.append(data) + + print message.get('sampleNumber') + except ValueError as e: + print e + elif command == 'status': + if action == 'active': + interface.send(json.dumps({ + 'action': 'alive', + 'command': 'status', + 'message': time.time() * 1000.0 + })) + except KeyboardInterrupt: + print "W: interrupt received, stopping" + print("Python ZMQ Link Clean Up") + interface.close() + raise ValueError("Peace") + except BaseException as e: + print e if __name__ == '__main__': diff --git a/examples/python/index.js b/examples/python/index.js index 80cd638..a96d7fd 100644 --- a/examples/python/index.js +++ b/examples/python/index.js @@ -1,3 +1,4 @@ +'use strict'; /** * This is an example from the readme.md * On windows you should run with PowerShell not git bash. @@ -9,76 +10,91 @@ * do `npm install` * then `npm start` */ -var OpenBCIBoard = require('openbci').OpenBCIBoard; -var portPub = 'tcp://127.0.0.1:3004'; -var zmq = require('zmq-prebuilt'); -var socket = zmq.socket('pair'); -var simulate = false; // Sends synthetic data -var debug = false; // Pretty print any bytes in and out... it's amazing... -var verbose = true; // Adds verbosity to functions - -var ourBoard = new OpenBCIBoard({ - simulate: simulate, // Uncomment to see how it works with simulator! - simulatorFirmwareVersion: 'v2', - debug: debug, - verbose: verbose -}); +const portPub = 'tcp://127.0.0.1:3004'; +const zmq = require('zeromq'); +const socket = zmq.socket('pair'); +const debug = false; // Pretty print any bytes in and out... it's amazing... +const verbose = true; // Adds verbosity to functions + +const kWirelessProtocolBluetooth = 'bluetooth'; // The dongle +const kWirelessProtocolWifi = 'wifi'; + +const curWirelessProtocol = kWirelessProtocolBluetooth; + +let cytonSerial, cytonWifi; +if (curWirelessProtocol === kWirelessProtocolBluetooth) { + const Cyton = require('openbci-cyton'); + const simulate = false; // Sends synthetic data + cytonSerial = new Cyton({ + simulate: simulate, // Uncomment to see how it works with simulator! + simulatorFirmwareVersion: 'v2', + debug: debug, + verbose: verbose + }); + + let timeSyncPossible = false; + + let resyncPeriodMin = 1; + let secondsInMinute = 60; + let resyncPeriod = cytonSerial.sampleRate() * resyncPeriodMin * secondsInMinute; + + cytonSerial.autoFindOpenBCIBoard().then(portName => { + if (portName) { + /** + * Connect to the board with portName + * i.e. ourBoard.connect(portName)..... + */ + // Call to connect + cytonSerial.connect(portName) + .then(() => { + cytonSerial.once('ready', () => { + // 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 = cytonSerial.usingAtLeastVersionTwoFirmware(); -var timeSyncPossible = false; -var resyncPeriodMin = 1; -var secondsInMinute = 60; -var resyncPeriod = ourBoard.sampleRate() * resyncPeriodMin * secondsInMinute; - -ourBoard.autoFindOpenBCIBoard().then(portName => { - if (portName) { - /** - * Connect to the board with portName - * i.e. ourBoard.connect(portName)..... - */ - // Call to connect - ourBoard.connect(portName) - .then(() => { - ourBoard.on('ready', () => { - // 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() + cytonSerial.streamStart() .catch(err => { console.log(`stream start: ${err}`); }); - } else { - console.log('not able to time sync'); - } + }); + }) + .catch(err => { + console.log(`connect: ${err}`); + process.exit(0); }); - }) - .catch(err => { - console.log(`connect: ${err}`); - }); - } else { - /** Unable to auto find OpenBCI board */ - console.log('Unable to auto find OpenBCI board'); - } -}); + } else { + /** Unable to auto find OpenBCI board */ + console.log('Unable to auto find OpenBCI board'); + process.exit(0); + } + }); + + const sampleFunc = sample => { + if (timeSyncPossible) { + if (sample._count % resyncPeriod === 0) { + cytonSerial.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!`); + } + }); + } -var sampleFunc = sample => { - if (sample._count % resyncPeriod === 0) { - ourBoard.syncClocksFull() - .then(syncObj => { - // Sync was successful - if (syncObj.valid) { - // Log the object to check it out! - console.log(`timeOffset`, syncObj.timeOffsetMaster); + 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}`); } else { - // Retry it - console.log(`Was not able to sync... retry!`); + sendToPython({ + action: 'process', + command: 'sample', + message: sample + }); } - }); - } - - 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}`); + } } else { sendToPython({ action: 'process', @@ -86,11 +102,44 @@ var sampleFunc = sample => { message: sample }); } - } -}; + }; + + // Subscribe to your functions + cytonSerial.on('sample', sampleFunc); +} else if (curWirelessProtocol === kWirelessProtocolWifi) { + const protocol = 'tcp'; // or 'udp' + + let Wifi = require('openbci-wifi'); + cytonWifi = new Wifi({ + debug: debug, + verbose: verbose, + sendCounts: false, + latency: 16667, + protocol: protocol, + burst: true + }); -// Subscribe to your functions -ourBoard.on('sample', sampleFunc); + const sampleFunc = (sample) => { + sendToPython({ + action: 'process', + command: 'sample', + message: sample + }); + }; + + cytonWifi.on('sample', sampleFunc); + + cytonWifi.searchToStream({ + streamStart: true, + sampleRate: 1000 + }) + .catch((err) => { + console.log(err); + process.exit(0); + }); +} else { + console.error(Error(`Selected wifi network ${curWirelessProtocol} is not support yet`)); +} // ZMQ fun @@ -104,7 +153,7 @@ socket.bind(portPub, function (err) { * @param {Object} interProcessObject The standard inter-process object. * @return {None} */ -var sendToPython = (interProcessObject, verbose) => { +const sendToPython = (interProcessObject, verbose) => { if (verbose) { console.log(`<- out ${JSON.stringify(interProcessObject)}`); } @@ -113,7 +162,7 @@ var sendToPython = (interProcessObject, verbose) => { } }; -var receiveFromPython = (rawData) => { +const receiveFromPython = (rawData) => { try { let body = JSON.parse(rawData); // five because `resp ` processInterfaceObject(body); @@ -124,7 +173,7 @@ var receiveFromPython = (rawData) => { socket.on('message', receiveFromPython); -var sendStatus = () => { +const sendStatus = () => { sendToPython({'action': 'active', 'message': 'ready', 'command': 'status'}, true); }; @@ -135,7 +184,7 @@ sendStatus(); * @param {String} body A stringify JSON object that shall be parsed. * @return {None} */ -var processInterfaceObject = (body) => { +const processInterfaceObject = (body) => { switch (body.command) { case 'status': processStatus(body); @@ -151,7 +200,7 @@ var processInterfaceObject = (body) => { * @param {Object} body * @return {None} */ -var processStatus = (body) => { +const processStatus = (body) => { switch (body.action) { case 'started': console.log(`python started @ ${body.message}ms`); @@ -173,11 +222,49 @@ function exitHandler (options, err) { if (options.cleanup) { if (verbose) console.log('clean'); /** Do additional clean up here */ + if (curWirelessProtocol === kWirelessProtocolBluetooth) { + if (cytonSerial) { + cytonSerial.removeAllListeners('sample'); + } + } else if (curWirelessProtocol === kWirelessProtocolWifi) { + if (cytonWifi) { + if (cytonWifi.isConnected()) cytonWifi.disconnect().catch(console.log); + cytonWifi.removeAllListeners('sample'); + cytonWifi.destroy(); + } + } } if (err) console.log(err.stack); if (options.exit) { if (verbose) console.log('exit'); - ourBoard.disconnect().catch(console.log); + if (curWirelessProtocol === kWirelessProtocolBluetooth) { + cytonSerial.disconnect() + .then(() => { + process.exit(0); + }) + .catch((err) => { + console.log(err); + process.exit(0); + }); + } else if (curWirelessProtocol === kWirelessProtocolWifi) { + if (cytonWifi.isStreaming()) { + let timmy = setTimeout(() => { + console.log("timeout"); + process.exit(0); + }, 1000); + cytonWifi.streamStop() + .then(() => { + console.log('stream stopped'); + if (timmy) clearTimeout(timmy); + process.exit(0); + }).catch((err) => { + console.log(err); + process.exit(0); + }); + } else { + process.exit(0); + } + } } } diff --git a/examples/python/package.json b/examples/python/package.json index 69ba1f3..0d5d6fa 100644 --- a/examples/python/package.json +++ b/examples/python/package.json @@ -1,11 +1,12 @@ { "name": "python", - "version": "1.0.0", + "version": "1.1.0", "description": "node to python example", "main": "index.js", "scripts": { "start": "concurrently --kill-others \"python handoff.py\" \"node index.js\"", "start-node": "node index.js", + "start-py": "python handoff.py", "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [ @@ -16,8 +17,9 @@ "author": "AJ Keller", "license": "MIT", "dependencies": { - "openbci": "^1.4.2", - "zmq-prebuilt": "^2.1.0" + "openbci-cyton": "^1.0.7", + "openbci-wifi": "^0.3.1", + "zeromq": "^4.6.0" }, "devEngines": { "node": "<=6.x", diff --git a/examples/timeSync/package.json b/examples/timeSync/package.json index fd06409..b1992e5 100644 --- a/examples/timeSync/package.json +++ b/examples/timeSync/package.json @@ -1,6 +1,6 @@ { "name": "timesync", - "version": "1.0.0", + "version": "1.1.0", "description": "Time sync example", "main": "timeSync.js", "scripts": { @@ -14,6 +14,6 @@ "author": "AJ Keller", "license": "MIT", "dependencies": { - "openbci": "^1.3.1" + "openbci": "^2.0.0" } } diff --git a/examples/timeSync/timeSync.js b/examples/timeSync/timeSync.js index 4bfbee0..1dbd6f1 100644 --- a/examples/timeSync/timeSync.js +++ b/examples/timeSync/timeSync.js @@ -6,14 +6,16 @@ * do `npm install` * then `npm start` */ +const verbose = true; // Adds verbosity to functions -var OpenBCIBoard = require('openbci').OpenBCIBoard; - -var ourBoard = new OpenBCIBoard({}); -var verbose = true; // Adds verbosity to functions +const Cyton = require('openbci').Cyton; +let ourBoard = new Cyton({ + simulatorFirmwareVersion: 'v2', + verbose: verbose +}); -var sampleRate = 250; // Default to 250, ALWAYS verify with a call to `.sampleRate()` after 'ready' event! -var timeSyncPossible = false; +let sampleRate = 250; // Default to 250, ALWAYS verify with a call to `.sampleRate()` after 'ready' event! +let timeSyncPossible = false; ourBoard.autoFindOpenBCIBoard().then(portName => { if (portName) { @@ -34,7 +36,7 @@ ourBoard.autoFindOpenBCIBoard().then(portName => { } }); -var readyFunc = () => { +const 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. @@ -50,14 +52,14 @@ var readyFunc = () => { } }; -var killFunc = () => { +const killFunc = () => { ourBoard.disconnect() .then(() => { process.kill(); }); }; -var sampleFunc = sample => { +const sampleFunc = sample => { // Resynchronize every every second if (sample._count % (sampleRate * 1) === 0) { ourBoard.syncClocksFull() diff --git a/images/openbci_large.png b/images/openbci_large.png new file mode 100644 index 0000000..fd3e7ee Binary files /dev/null and b/images/openbci_large.png differ diff --git a/index.js b/index.js new file mode 100644 index 0000000..ba8fe01 --- /dev/null +++ b/index.js @@ -0,0 +1,3 @@ +module.exports.Cyton = require('openbci-cyton'); +module.exports.Ganglion = require('openbci-ganglion'); +module.exports.Wifi = require('openbci-wifi'); diff --git a/openBCIBoard.js b/openBCIBoard.js deleted file mode 100644 index 58436ec..0000000 --- a/openBCIBoard.js +++ /dev/null @@ -1,2531 +0,0 @@ -'use strict'; -var EventEmitter = require('events').EventEmitter; -var util = require('util'); -var stream = require('stream'); -var SerialPort = require('serialport'); -var openBCISample = require('./openBCISample'); -var k = openBCISample.k; -var openBCISimulator = require('./openBCISimulator'); -var Sntp = require('sntp'); -var bufferEqual = require('buffer-equal'); -var math = require('mathjs'); - -/** -* @description SDK for OpenBCI Board {@link www.openbci.com} -* @module 'openbci-sdk' -*/ -function OpenBCIFactory () { - var factory = this; - - var _options = { - boardType: [k.OBCIBoardDefault, k.OBCIBoardDaisy, k.OBCIBoardGanglion], - baudRate: 115200, - hardSet: false, - simulate: false, - simulatorBoardFailure: false, - simulatorDaisyModuleAttached: false, - simulatorDaisyModuleCanBeAttached: true, - simulatorFirmwareVersion: [k.OBCIFirmwareV1, k.OBCIFirmwareV2], - simulatorFragmentation: [k.OBCISimulatorFragmentationNone, k.OBCISimulatorFragmentationRandom, k.OBCISimulatorFragmentationFullBuffers, k.OBCISimulatorFragmentationOneByOne], - simulatorLatencyTime: 16, - simulatorBufferSize: 4096, - simulatorHasAccelerometer: true, - simulatorInternalClockDrift: 0, - simulatorInjectAlpha: true, - simulatorInjectLineNoise: [k.OBCISimulatorLineNoiseHz60, k.OBCISimulatorLineNoiseHz50, k.OBCISimulatorLineNoiseNone], - simulatorSampleRate: 250, - simulatorSerialPortFailure: false, - sntpTimeSync: false, - sntpTimeSyncHost: 'pool.ntp.org', - sntpTimeSyncPort: 123, - verbose: false, - debug: false - }; - - /** - * @description The initialization method to call first, before any other method. - * @param options (optional) - Board optional configurations. - * - `baudRate` {Number} - Baud Rate, defaults to 115200. Manipulating this is allowed if - * firmware on board has been previously configured. - * - * - `boardType` {String} - Specifies type of OpenBCI board. - * 3 Possible Boards: - * `default` - 8 Channel OpenBCI board (Default) - * `daisy` - 8 Channel OpenBCI board with Daisy Module. Total of 16 channels. - * `ganglion` - 4 Channel board - * (NOTE: THIS IS IN-OP TIL RELEASE OF GANGLION BOARD 07/2016) - * - * - `hardSet` {Boolean} - Recommended if using `daisy` board! For some reason, the `daisy` is sometimes - * not picked up by the module so you can set `hardSet` to true which will ensure the daisy - * is picked up. (Default `false`) - * - * - `simulate` {Boolean} - Full functionality, just mock data. Must attach Daisy module by setting - * `simulatorDaisyModuleAttached` to `true` in order to get 16 channels. (Default `false`) - * - * - `simulatorBoardFailure` {Boolean} - Simulates board communications failure. This occurs when the RFduino on - * the board is not polling the RFduino on the dongle. (Default `false`) - * - * - `simulatorDaisyModuleAttached` {Boolean} - Simulates a daisy module being attached to the OpenBCI board. - * This is useful if you want to test how your application reacts to a user requesting 16 channels - * but there is no daisy module actually attached, or vice versa, where there is a daisy module - * attached and the user only wants to use 8 channels. (Default `false`) - * - * - `simulatorDaisyModuleCanBeAttached` {Boolean} - Allows the simulation of the a hot swapped daisy board. - * For example: You coule simulate if the board has only detected 8 channels and the user requested - * 16 channels. (Default `true`) - * - * - `simulatorFirmwareVersion` {String} - Allows simulator to be started with firmware version 2 features - * 2 Possible Options: - * `v1` - Firmware Version 1 (Default) - * `v2` - Firmware Version 2 - * - * - `simulatorFragmentation` {String} - Specifies how to break packets to simulate fragmentation, which - * occurs commonly in real devices. It is recommended to test code with this enabled. - * 4 Possible Options: - * `none` - do not fragment packets; output complete chunks immediately when produced (Default) - * `random` - output random small chunks of data interspersed with full buffers - * `fullBuffers` - allow buffers to fill up until the latency timer has expired - * `oneByOne` - output each byte separately - * - * - `simulatorLatencyTime` {Number} - The time in milliseconds to wait before sending partially full buffers, - * if `simulatorFragmentation` is specified. (Default `16`) - * - * - `simulatorBufferSize` {Number} - The size of a full buffer of data, if `simulatorFragmentation` is - * specified. (Default `4096`) - * - * - `simulatorHasAccelerometer` - {Boolean} - Sets simulator to send packets with accelerometer data. (Default `true`) - * - * - `simulatorInjectAlpha` - {Boolean} - Inject a 10Hz alpha wave in Channels 1 and 2 (Default `true`) - * - * - `simulatorInjectLineNoise` {String} - Injects line noise on channels. - * 3 Possible Options: - * `60Hz` - 60Hz line noise (Default) [America] - * `50Hz` - 50Hz line noise [Europe] - * `none` - Do not inject line noise. - * - * - `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`) - * - * - `simulatorSerialPortFailure` {Boolean} - Simulates not being able to open a serial connection. Most likely - * due to a OpenBCI dongle not being plugged in. - * - * - `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 experiements on your local - * computer, keep this `false`. (Default `false`) - * - * - `sntpTimeSyncHost` - {String} The ntp server to use, can be either sntp or ntp. (Defaults `pool.ntp.org`). - * - * - `sntpTimeSyncPort` - {Number} The port to access the ntp server. (Defaults `123`) - * - * - `verbose` {Boolean} - Print out useful debugging events. (Default `false`) - * - * - `debug` {Boolean} - Print out a raw dump of bytes sent and received. (Default `false`) - * - * @constructor - * @author AJ Keller (@pushtheworldllc) - */ - function OpenBCIBoard (options) { - options = (typeof options !== 'function') && options || {}; - var opts = {}; - - stream.Stream.call(this); - - /** Configuring Options */ - var o; - for (o in _options) { - var userOption = (o in options) ? o : o.toLowerCase(); - var userValue = options[userOption]; - delete options[userOption]; - - if (typeof _options[o] === 'object') { - // an array specifying a list of choices - // if the choice is not in the list, the first one is defaulted to - - if (_options[o].indexOf(userValue) !== -1) { - opts[o] = userValue; - } else { - opts[o] = _options[o][0]; - } - } else { - // anything else takes the user value if provided, otherwise is a default - - if (userValue !== undefined) { - opts[o] = userValue; - } else { - opts[o] = _options[o]; - } - } - } - - for (o in options) throw new Error('"' + o + '" is not a valid option'); - - // Set to global options object - this.options = opts; - - /** Properties (keep alphabetical) */ - // Arrays - this.accelArray = [0, 0, 0]; // X, Y, Z - this.channelSettingsArray = k.channelSettingsArrayInit(k.numberOfChannelsForBoardType(this.options.boardType)); - this.writeOutArray = []; - // Booleans - this._streaming = false; - // Buffers - this.buffer = null; - this.masterBuffer = masterBufferMaker(); - // Objects - this.impedanceTest = openBCISample.impedanceTestObjDefault(); - this.info = { - boardType: this.options.boardType, - sampleRate: k.OBCISampleRate125, - firmware: k.OBCIFirmwareV1, - numberOfChannels: k.OBCINumberOfChannelsDefault, - missedPackets: 0 - }; - if (this.options.boardType === k.OBCIBoardDefault) { - this.info.sampleRate = k.OBCISampleRate250; - } - - this._lowerChannelsSampleObject = null; - this.serial = null; - this.sync = { - curSyncObj: null, - eventEmitter: null, - objArray: [], - sntpActive: false, - timeOffsetMaster: 0, - timeOffsetAvg: 0, - timeOffsetArray: [] - }; - this.writer = null; - // Numbers - this.badPackets = 0; - this.curParsingMode = k.OBCIParsingReset; - this.impedanceArray = openBCISample.impedanceArray(k.numberOfChannelsForBoardType(this.options.boardType)); - this.previousSampleNumber = -1; - this.sampleCount = 0; - this.timeOfPacketArrival = 0; - this.writeOutDelay = k.OBCIWriteIntervalDelayMSShort; - // Strings - this.portName = null; - - // NTP - if (this.options.sntpTimeSync) { - // establishing ntp connection - this.sntpStart() - .catch(ignored => { - // try again once after a delay - return new Promise((resolve, reject) => { - setTimeout(resolve, 500); - }).then(() => this.sntpStart()); - }) - .then(() => { - if (this.options.verbose) console.log('SNTP: connected'); - }) - .catch(err => { - if (this.options.verbose) console.log(`Error [sntpStart] ${err}`); - this.emit('error', err); - }); - } - - // TODO: Add connect immediately functionality, suggest this to be the default... - } - - // This allows us to use the emitter class freely outside of the module - util.inherits(OpenBCIBoard, stream.Stream); - - /** - * @description The essential precursor method to be called initially to establish a - * serial connection to the OpenBCI board. - * @param portName - a string that contains the port name of the OpenBCIBoard. - * @returns {Promise} if the board was able to connect. - * @author AJ Keller (@pushtheworldllc) - */ - OpenBCIBoard.prototype.connect = function (portName) { - return new Promise((resolve, reject) => { - if (this.isConnected()) return reject('already connected!'); - - /* istanbul ignore else */ - if (this.options.simulate || portName === k.OBCISimulatorPortName) { - this.options.simulate = true; - // If we are simulating, set portName to fake name - this.portName = k.OBCISimulatorPortName; - if (this.options.verbose) console.log('using faux board ' + portName); - this.serial = new openBCISimulator.OpenBCISimulator(this.portName, { - accel: this.options.simulatorHasAccelerometer, - alpha: this.options.simulatorInjectAlpha, - boardFailure: this.options.simulatorBoardFailure, - daisy: this.options.simulatorDaisyModuleAttached, - daisyCanBeAttached: this.options.simulatorDaisyModuleCanBeAttached, - drift: this.options.simulatorInternalClockDrift, - firmwareVersion: this.options.simulatorFirmwareVersion, - fragmentation: this.options.simulatorFragmentation, - latencyTime: this.options.simulatorLatencyTime, - bufferSize: this.options.simulatorBufferSize, - lineNoise: this.options.simulatorInjectLineNoise, - sampleRate: this.options.simulatorSampleRate, - serialPortFailure: this.options.simulatorSerialPortFailure, - verbose: this.options.verbose - }); - } else { - this.portName = portName; - if (this.options.verbose) console.log('using real board ' + portName); - this.serial = new SerialPort(portName, { - baudRate: this.options.baudRate - }, (err) => { - if (err) reject(err); - }); - } - - if (this.options.verbose) console.log('Serial port connected'); - - this.serial.on('data', data => { - this._processBytes(data); - }); - this.serial.once('open', () => { - if (this.options.verbose) console.log('Serial port open'); - new Promise(resolve => { - // TODO: document why this 300 ms delay is needed - setTimeout(resolve, this.options.simulate ? 50 : 300); - }).then(() => { - if (this.options.verbose) console.log('Sending stop command, in case the device was left streaming...'); - return this.write(k.OBCIStreamStop); - }).then(() => { - return new Promise(resolve => this.serial.flush(resolve)); - }).then(() => { - // TODO: document why this 250 ms delay is needed - return new Promise(resolve => setTimeout(resolve, 250)); - }).then(() => { - if (this.options.verbose) console.log('Sending soft reset'); - // TODO: this promise chain resolves early because - // A. some legacy code (in tests) sets the ready handler after this resolves - // and - // B. other legacy code (in tests) needs the simulator to reply with segmented packets, never fragmented - // which is C. not implemented yet except in a manner such that replies occur in the write handler, - // resulting in the EOT arriving before this resolves - // Fix one or more of the above 3 situations, then move resolve() to the next block. - resolve(); - return this.softReset(); - }).then(() => { - if (this.options.verbose) console.log("Waiting for '$$$'"); - }); - }); - this.serial.once('close', () => { - if (this.options.verbose) console.log('Serial Port Closed'); - // 'close' is emitted in _disconnected() - this._disconnected('port closed'); - }); - this.serial.once('error', (err) => { - if (this.options.verbose) console.log('Serial Port Error'); - this.emit('error', err); - this._disconnected(err); - }); - }); - }; - - /** - * @description Called once when for any reason the serial port is no longer open. - * @private - */ - OpenBCIBoard.prototype._disconnected = function (err) { - this._streaming = false; - - clearTimeout(this.writer); - this.writer = null; - - this.serial.removeAllListeners(); - this.serial = null; - - this.emit('close'); - - while (this.writeOutArray.length > 0) { - var command = this.writeOutArray.pop(); - if (command.reject) command.reject(err); - } - }; - - /** - * @description Closes the serial port. Waits for stop streaming command to - * be sent if currently streaming. - * @returns {Promise} - fulfilled by a successful close of the serial port object, rejected otherwise. - * @author AJ Keller (@pushtheworldllc) - */ - OpenBCIBoard.prototype.disconnect = function () { - return Promise.resolve() - .then(() => { - if (this.isStreaming()) { - if (this.options.verbose) console.log('stop streaming'); - return this.streamStop(); - } - }) - .then(() => { - if (!this.isConnected()) { - return Promise.reject('no board connected'); - } else { - return new Promise((resolve, reject) => { - // serial emitting 'close' will call _disconnected - this.serial.close(() => { - resolve(); - }); - }); - } - }); - }; - - /** - * @description Checks if the driver is connected to a board. - * @returns {boolean} - True if connected. - */ - OpenBCIBoard.prototype.isConnected = function () { - if (!this.serial) return false; - return this.serial.isOpen(); - }; - - /** - * @description Checks if the board is currently sending samples. - * @returns {boolean} - True if streaming. - */ - OpenBCIBoard.prototype.isSimulating = function () { - return this.options.simulate; - }; - - /** - * @description Checks if the board is currently sending samples. - * @returns {boolean} - True if streaming. - */ - OpenBCIBoard.prototype.isStreaming = function () { - return this._streaming; - }; - - /** - * @description Sends a start streaming command to the board. - * @returns {Promise} indicating if the signal was able to be sent. - * Note: You must have successfully connected to an OpenBCI board using the connect - * method. Just because the signal was able to be sent to the board, does not - * mean the board will start streaming. - * @author AJ Keller (@pushtheworldllc) - */ - OpenBCIBoard.prototype.streamStart = function () { - return new Promise((resolve, reject) => { - if (this.isStreaming()) return reject('Error [.streamStart()]: Already streaming'); - this._streaming = true; - this._reset_ABANDONED(); // framework is incomplete but looks useful - this.write(k.OBCIStreamStart).then(resolve, reject); - }); - }; - - /** - * @description Sends a stop streaming command to the board. - * @returns {Promise} indicating if the signal was able to be sent. - * Note: You must have successfully connected to an OpenBCI board using the connect - * method. Just because the signal was able to be sent to the board, does not - * mean the board stopped streaming. - * @author AJ Keller (@pushtheworldllc) - */ - OpenBCIBoard.prototype.streamStop = function () { - return new Promise((resolve, reject) => { - if (!this.isStreaming()) return reject('Error [.streamStop()]: No stream to stop'); - this._streaming = false; - this.write(k.OBCIStreamStop).then(resolve, reject); - }); - }; - - /** - * @description To start simulating an open bci board - * Note: Must be called after the constructor - * @returns {Promise} - Fulfilled if able to enter simulate mode, reject if not. - * @author AJ Keller (@pushtheworldllc) - */ - OpenBCIBoard.prototype.simulatorEnable = function () { - return new Promise((resolve, reject) => { - if (this.options.simulate) return reject('Already simulating'); // Are we already in simulate mode? - if (this.isConnected()) { - this.disconnect() // disconnect first - .then(() => { - this.options.simulate = true; - resolve(); - }) - .catch(err => reject(err)); - } else { - this.options.simulate = true; - resolve(); - } - }); - }; - - /** - * @description To stop simulating an open bci board - * Note: Must be called after the constructor - * @returns {Promise} - Fulfilled if able to stop simulate mode, reject if not. - * @author AJ Keller (@pushtheworldllc) - */ - OpenBCIBoard.prototype.simulatorDisable = function () { - return new Promise((resolve, reject) => { - if (!this.options.simulate) return reject('Not simulating'); // Are we already not in simulate mode? - if (this.isConnected()) { - this.disconnect() - .then(() => { - this.options.simulate = false; - resolve(); - }) - .catch(err => reject(err)); - } else { - this.options.simulate = false; - resolve(); - } - }); - }; - - /** - * @description To be able to easily write to the board but ensure that we never send commands - * with less than a 10ms spacing between sends in early version boards. This uses - * an array and shifts off the entries until there are none left. - * @param dataToWrite - Either a single character or an Array of characters - * @returns {Promise} - * @author AJ Keller (@pushtheworldllc) - */ - OpenBCIBoard.prototype.write = function (dataToWrite) { - return new Promise((resolve, reject) => { - if (!this.isConnected()) { - reject('not connected'); - } else { - if (Array.isArray(dataToWrite)) { // Got an input array - var len = dataToWrite.length; - for (var i = 0; i < len; i++) { - this.writeOutArray.push({ cmd: dataToWrite[i], reject: reject }); - } - this.writeOutArray[this.writeOutArray.length - 1].resolve = resolve; - } else { - this.writeOutArray.push({ cmd: dataToWrite, reject: reject, resolve: resolve }); - } - - if (!this.writer) { // there is no writer started - var writerFunction = () => { - if (this.writeOutArray.length === 0) { - this.writer = null; - return; - } - - var command = this.writeOutArray.shift(); - var promise = this._writeAndDrain(command.cmd); - - promise.then(() => { - this.writer = setTimeout(writerFunction, this.writeOutDelay); - }, () => { - // write failed but more commands may be pending that need a result - writerFunction(); - }); - - if (command.reject) { - promise.catch(err => { - if (this.options.verbose) console.log('write failure: ' + err); - command.reject(err); - }); - } - if (command.resolve) promise.then(command.resolve); - }; - this.writer = setTimeout(writerFunction, this.writeOutDelay); - } - } - }); - }; - - /** - * @description Should be used to send data to the board - * @param data {Buffer} - The data to write out - * @returns {Promise} if signal was able to be sent - * @author AJ Keller (@pushtheworldllc) - */ - OpenBCIBoard.prototype._writeAndDrain = function (data) { - this._debugBytes('>>>', data); - - return new Promise((resolve, reject) => { - if (!this.isConnected()) return reject('Serial port not open'); - this.serial.write(data, (error) => { - if (error) { - console.log('Error [writeAndDrain]: ' + error); - reject(error); - } else { - this.serial.drain(function () { - resolve(); - }); - } - }); - }); - }; - - /** - * @description Automatically find an OpenBCI board. - * Note: This method is used for convenience and should be used when trying to - * connect to a board. If you find a case (i.e. a platform (linux, - * windows...) that this does not work, please open an issue and - * we will add support! - * @returns {Promise} - Fulfilled with portName, rejected when can't find the board. - * @author AJ Keller (@pushtheworldllc) - */ - OpenBCIBoard.prototype.autoFindOpenBCIBoard = function () { - var serialPatterns = [ - { // mac - comName: /usbserial-D/ - }, - { // linux - comName: /^\/dev\/ttyUSB/, - manufacturer: /^FTDI$/, - serialNumber: /^FTDI_FT231X_USB_UART/, - vendorId: /^0x0403$/, - productId: /^0x6015$/ - } - ]; - return new Promise((resolve, reject) => { - /* istanbul ignore else */ - if (this.options.simulate) { - this.portName = k.OBCISimulatorPortName; - if (this.options.verbose) console.log('auto found sim board'); - resolve(k.OBCISimulatorPortName); - } else { - SerialPort.list((err, ports) => { - if (err) { - if (this.options.verbose) console.log('serial port err'); - reject(err); - } - // This is one big if statement - if (ports.some(port => { - return serialPatterns.some(patterns => { - for (var attribute in patterns) { - if (!String(port[attribute]).match(patterns[attribute])) { - return false; - } - } - this.portName = port.comName; - return true; - }); - })) { - if (this.options.verbose) console.log('auto found board'); - resolve(this.portName); - } else { - if (this.options.verbose) console.log('could not find board'); - reject('Could not auto find board'); - } - }); - } - }); - }; - - /** - * @description Convenience method to determine if you can use firmware v2.x.x - * capabilities. - * @returns {boolean} - True if using firmware version 2 or greater. Should - * be called after a `.softReset()` because we can parse the output of that - * to determine if we are using firmware version 2. - * @author AJ Keller (@pushtheworldllc) - */ - OpenBCIBoard.prototype.usingVersionTwoFirmware = function () { - if (this.options.simulate) { - return this.options.simulatorFirmwareVersion === k.OBCIFirmwareV2; - } else { - return this.info.firmware === k.OBCIFirmwareV2; - } - }; - - /** - * @description Used to set the system radio channel number. The function will reject if not - * connected to the serial port of the dongle. Further the function should reject if currently streaming. - * Lastly and more important, if the board is not running the new firmware then this functionality does not - * exist and thus this method will reject. If the board is using firmware 2+ then this function should resolve. - * **Note**: This functionality requires OpenBCI Firmware Version 2.0 - * @param `channelNumber` {Number} - The channel number you want to set to, 1-25. - * @since 1.0.0 - * @returns {Promise} - Resolves with the new channel number, rejects with err. - * @author AJ Keller (@pushtheworldllc) - */ - OpenBCIBoard.prototype.radioChannelSet = function (channelNumber) { - var badCommsTimeout; - return new Promise((resolve, reject) => { - if (!this.isConnected()) return reject('Must be connected to Dongle. Pro tip: Call .connect()'); - if (this.isStreaming()) return reject("Don't query for the radio while streaming"); - if (!this.usingVersionTwoFirmware()) return reject('Must be using firmware version 2'); - if (channelNumber === undefined || channelNumber === null) return reject('Must input a new channel number to switch too!'); - if (!k.isNumber(channelNumber)) return reject('Must input type Number'); - if (channelNumber > k.OBCIRadioChannelMax) return reject(`New channel number must be less than ${k.OBCIRadioChannelMax}`); - if (channelNumber < k.OBCIRadioChannelMin) return reject(`New channel number must be greater than ${k.OBCIRadioChannelMin}`); - - // Set a timeout. Since poll times can be max of 255 seconds, we should set that as our timeout. This is - // important if the module was connected, not streaming and using the old firmware - badCommsTimeout = setTimeout(() => { - reject('Please make sure your dongle is using firmware v2'); - }, 1000); - - // Subscribe to the EOT event - this.once('eot', data => { - if (this.options.verbose) console.log(data.toString()); - // Remove the timeout! - clearTimeout(badCommsTimeout); - badCommsTimeout = null; - - if (openBCISample.isSuccessInBuffer(data)) { - resolve(data[data.length - 4]); - } else { - reject(`Error [radioChannelSet]: ${data}`); // The channel number is in the first byte - } - }); - - this.curParsingMode = k.OBCIParsingEOT; - - // Send the radio channel query command - this._writeAndDrain(new Buffer([k.OBCIRadioKey, k.OBCIRadioCmdChannelSet, channelNumber])).catch(reject); - }); - }; - - /** - * @description Used to set the ONLY the radio dongle Host channel number. This will fix your radio system if - * your dongle and board are not on the right channel and bring down your radio system if you take your - * dongle and board are not on the same channel. Use with caution! The function will reject if not - * connected to the serial port of the dongle. Further the function should reject if currently streaming. - * Lastly and more important, if the board is not running the new firmware then this functionality does not - * exist and thus this method will reject. If the board is using firmware 2+ then this function should resolve. - * **Note**: This functionality requires OpenBCI Firmware Version 2.0 - * @param `channelNumber` {Number} - The channel number you want to set to, 1-25. - * @since 1.0.0 - * @returns {Promise} - Resolves with the new channel number, rejects with err. - * @author AJ Keller (@pushtheworldllc) - */ - OpenBCIBoard.prototype.radioChannelSetHostOverride = function (channelNumber) { - var badCommsTimeout; - return new Promise((resolve, reject) => { - if (!this.isConnected()) return reject('Must be connected to Dongle. Pro tip: Call .connect()'); - if (this.isStreaming()) return reject("Don't query for the radio while streaming"); - if (channelNumber === undefined || channelNumber === null) return reject('Must input a new channel number to switch too!'); - if (!k.isNumber(channelNumber)) return reject('Must input type Number'); - if (channelNumber > k.OBCIRadioChannelMax) return reject(`New channel number must be less than ${k.OBCIRadioChannelMax}`); - if (channelNumber < k.OBCIRadioChannelMin) return reject(`New channel number must be greater than ${k.OBCIRadioChannelMin}`); - - // Set a timeout. Since poll times can be max of 255 seconds, we should set that as our timeout. This is - // important if the module was connected, not streaming and using the old firmware - badCommsTimeout = setTimeout(() => { - reject('Please make sure your dongle is using firmware v2'); - }, 1000); - - // Subscribe to the EOT event - this.once('eot', data => { - if (this.options.verbose) console.log(`${data.toString()}`); - // Remove the timeout! - clearTimeout(badCommsTimeout); - badCommsTimeout = null; - - if (openBCISample.isSuccessInBuffer(data)) { - resolve(data[data.length - 4]); - } else { - reject(`Error [radioChannelSet]: ${data}`); // The channel number is in the first byte - } - }); - - this.curParsingMode = k.OBCIParsingEOT; - - // Send the radio channel query command - this._writeAndDrain(new Buffer([k.OBCIRadioKey, k.OBCIRadioCmdChannelSetOverride, channelNumber])).catch(reject); - }); - }; - - /** - * @description Used to query the OpenBCI system for it's radio channel number. The function will reject if not - * connected to the serial port of the dongle. Further the function should reject if currently streaming. - * Lastly and more important, if the board is not running the new firmware then this functionality does not - * exist and thus this method will reject. If the board is using firmware 2+ then this function should resolve - * an Object. See `returns` below. - * **Note**: This functionality requires OpenBCI Firmware Version 2.0 - * @since 1.0.0 - * @returns {Promise} - Resolve an object with keys `channelNumber` which is a Number and `err` which contains an error in - * the condition that there system is experiencing board communications failure. - * @author AJ Keller (@pushtheworldllc) - */ - OpenBCIBoard.prototype.radioChannelGet = function () { - // The function to run on timeout - var badCommsTimeout; - - return new Promise((resolve, reject) => { - if (!this.isConnected()) return reject('Must be connected to Dongle. Pro tip: Call .connect()'); - if (this.isStreaming()) return reject("Don't query for the radio while streaming"); - if (!this.usingVersionTwoFirmware()) return reject('Must be using firmware v2'); - - // Set a timeout. Since poll times can be max of 255 seconds, we should set that as our timeout. This is - // important if the module was connected, not streaming and using the old firmware - badCommsTimeout = setTimeout(() => { - reject('Please make sure your dongle is plugged in and using firmware v2'); - }, 500); - - // Subscribe to the EOT event - this.once('eot', data => { - if (this.options.verbose) console.log(data.toString()); - // Remove the timeout! - clearTimeout(badCommsTimeout); - badCommsTimeout = null; - if (openBCISample.isSuccessInBuffer(data)) { - resolve({ - channelNumber: data[data.length - 4], - data: data - }); - } else { - reject(`Error [radioChannelGet]: ${data.toString()}`); - } - }); - - this.curParsingMode = k.OBCIParsingEOT; - - // Send the radio channel query command - this._writeAndDrain(new Buffer([k.OBCIRadioKey, k.OBCIRadioCmdChannelGet])).catch(reject); - }); - }; - - /** - * @description Used to query the OpenBCI system for it's device's poll time. The function will reject if not - * connected to the serial port of the dongle. Further the function should reject if currently streaming. - * Lastly and more important, if the board is not running the new firmware then this functionality does not - * exist and thus this method will reject. If the board is using firmware 2+ then this function should resolve - * the poll time when fulfilled. It's important to note that if the board is not on, this function will always - * be rejected with a failure message. - * **Note**: This functionality requires OpenBCI Firmware Version 2.0 - * @since 1.0.0 - * @returns {Promise} - Resolves with the poll time, rejects with an error message. - * @author AJ Keller (@pushtheworldllc) - */ - OpenBCIBoard.prototype.radioPollTimeGet = function () { - var badCommsTimeout; - return new Promise((resolve, reject) => { - if (!this.isConnected()) return reject('Must be connected to Dongle. Pro tip: Call .connect()'); - if (this.isStreaming()) return reject("Don't query for the poll time while streaming"); - if (!this.usingVersionTwoFirmware()) return reject('Must be using firmware v2'); - // Set a timeout. Since poll times can be max of 255 seconds, we should set that as our timeout. This is - // important if the module was connected, not streaming and using the old firmware - badCommsTimeout = setTimeout(() => { - reject('Please make sure your dongle is plugged in and using firmware v2'); - }, 1000); - - // Subscribe to the EOT event - this.once('eot', data => { - if (this.options.verbose) console.log(data.toString()); - // Remove the timeout! - clearTimeout(badCommsTimeout); - badCommsTimeout = null; - - if (openBCISample.isSuccessInBuffer(data)) { - var pollTime = data[data.length - 4]; - resolve(pollTime); - } else { - reject(`Error [radioPollTimeGet]: ${data}`); // The channel number is in the first byte - } - }); - - this.curParsingMode = k.OBCIParsingEOT; - - // Send the radio channel query command - this._writeAndDrain(new Buffer([k.OBCIRadioKey, k.OBCIRadioCmdPollTimeGet])).catch(reject); - }); - }; - - /** - * @description Used to set the OpenBCI poll time. With the RFduino configuration, the Dongle is the Host and the - * Board is the Device. Only the Device can initiate a communication between the two entities. Therefore this - * sets the interval at which the Device polls the Host for new information. Further the function should reject - * if currently streaming. Lastly and more important, if the board is not running the new firmware then this - * functionality does not exist and thus this method will reject. If the board is using firmware 2+ then this - * function should resolve. - * **Note**: This functionality requires OpenBCI Firmware Version 2.0 - * @param `pollTime` {Number} - The poll time you want to set for the system. 0-255 - * @since 1.0.0 - * @returns {Promise} - Resolves with new poll time, rejects with error message. - * @author AJ Keller (@pushtheworldllc) - */ - OpenBCIBoard.prototype.radioPollTimeSet = function (pollTime) { - var badCommsTimeout; - return new Promise((resolve, reject) => { - if (!this.isConnected()) return reject('Must be connected to Dongle. Pro tip: Call .connect()'); - if (this.isStreaming()) return reject("Don't change the poll time while streaming"); - if (!this.usingVersionTwoFirmware()) return reject('Must be using firmware v2'); - if (pollTime === undefined || pollTime === null) return reject('Must input a new poll time to switch too!'); - if (!k.isNumber(pollTime)) return reject('Must input type Number'); - if (pollTime > k.OBCIRadioPollTimeMax) return reject(`New polltime must be less than ${k.OBCIRadioPollTimeMax}`); - if (pollTime < k.OBCIRadioPollTimeMin) return reject(`New polltime must be greater than ${k.OBCIRadioPollTimeMin}`); - - // Set a timeout. Since poll times can be max of 255 seconds, we should set that as our timeout. This is - // important if the module was connected, not streaming and using the old firmware - badCommsTimeout = setTimeout(() => { - reject('Please make sure your dongle is plugged in and using firmware v2'); - }, 1000); - - // Subscribe to the EOT event - this.once('eot', data => { - if (this.options.verbose) console.log(data.toString()); - // Remove the timeout! - clearTimeout(badCommsTimeout); - badCommsTimeout = null; - - if (openBCISample.isSuccessInBuffer(data)) { - resolve(data[data.length - 4]); // Ditch the eot $$$ - } else { - reject(`Error [radioPollTimeSet]: ${data}`); // The channel number is in the first byte - } - }); - - this.curParsingMode = k.OBCIParsingEOT; - - // Send the radio channel query command - this._writeAndDrain(new Buffer([k.OBCIRadioKey, k.OBCIRadioCmdPollTimeSet, pollTime])).catch(reject); - }); - }; - - /** - * @description Used to set the OpenBCI Host (Dongle) baud rate. With the RFduino configuration, the Dongle is the - * Host and the Board is the Device. Only the Device can initiate a communication between the two entities. - * There exists a detrimental error where if the Host is interrupted by the radio during a Serial write, then - * all hell breaks loose. So this is an effort to eliminate that problem by increasing the rate at which serial - * data is sent from the Host to the Serial driver. The rate can either be set to default or fast. - * Further the function should reject if currently streaming. Lastly and more important, if the board is not - * running the new firmware then this functionality does not exist and thus this method will reject. - * If the board is using firmware 2+ then this function should resolve the new baud rate after closing the - * current serial port and reopening one. - * **Note**: This functionality requires OpenBCI Firmware Version 2.0 - * @since 1.0.0 - * @param speed {String} - The baud rate that to switch to. Can be either `default` (115200) or `fast` (230400) - * @returns {Promise} - Resolves a {Number} that is the new baud rate, rejects on error. - * @author AJ Keller (@pushtheworldllc) - */ - OpenBCIBoard.prototype.radioBaudRateSet = function (speed) { - var badCommsTimeout; - return new Promise((resolve, reject) => { - if (!this.isConnected()) return reject('Must be connected to Dongle. Pro tip: Call .connect()'); - if (this.isStreaming()) return reject("Don't change the baud rate while streaming"); - if (!this.usingVersionTwoFirmware()) return reject('Must be using firmware v2'); - if (!k.isString(speed)) return reject('Must input type String'); - // Set a timeout. Since poll times can be max of 255 seconds, we should set that as our timeout. This is - // important if the module was connected, not streaming and using the old firmware - badCommsTimeout = setTimeout(() => { - reject('Please make sure your dongle is plugged in and using firmware v2'); - }, 1000); - - // Subscribe to the EOT event - this.once('eot', data => { - if (this.options.verbose) console.log(data.toString()); - // Remove the timeout! - clearTimeout(badCommsTimeout); - badCommsTimeout = null; - var eotBuf = new Buffer('$$$'); - var newBaudRateBuf; - for (var i = data.length; i > 3; i--) { - if (bufferEqual(data.slice(i - 3, i), eotBuf)) { - newBaudRateBuf = data.slice(i - 9, i - 3); - break; - } - } - var newBaudRateNum = Number(newBaudRateBuf.toString()); - if (newBaudRateNum !== k.OBCIRadioBaudRateDefault && newBaudRateNum !== k.OBCIRadioBaudRateFast) { - return reject('Error parse mismatch, restart your system!'); - } - if (!this.isConnected()) { - reject('Lost connection to device during baud set'); - } else if (openBCISample.isSuccessInBuffer(data)) { - // Change the sample rate here - if (this.options.simulate === false) { - this.serial.update({baudRate: newBaudRateNum}, err => { - if (err) return reject(err); - else resolve(newBaudRateNum); - }); - } else { - resolve(newBaudRateNum); - } - } else { - reject(`Error [radioPollTimeGet]: ${data}`); // The channel number is in the first byte - } - }); - - this.curParsingMode = k.OBCIParsingEOT; - - // Send the radio channel query command - if (speed === k.OBCIRadioBaudRateFastStr) { - this._writeAndDrain(new Buffer([k.OBCIRadioKey, k.OBCIRadioCmdBaudRateSetFast])).catch(reject); - } else { - this._writeAndDrain(new Buffer([k.OBCIRadioKey, k.OBCIRadioCmdBaudRateSetDefault])).catch(reject); - } - }); - }; - - /** - * @description Used to ask the Host if it's radio system is up. This is useful to quickly determine if you are - * in fact ready to start trying to connect and such. The function will reject if not connected to the serial - * port of the dongle. Further the function should reject if currently streaming. - * Lastly and more important, if the board is not running the new firmware then this functionality does not - * exist and thus this method will reject. If the board is using firmware +v2.0.0 and the radios are both on the - * same channel and powered, then this will resolve true. - * **Note**: This functionality requires OpenBCI Firmware Version 2.0 - * @since 1.0.0 - * @returns {Promise} - Resolves true if both radios are powered and on the same channel; false otherwise. - * @author AJ Keller (@pushtheworldllc) - */ - OpenBCIBoard.prototype.radioSystemStatusGet = function () { - var badCommsTimeout; - return new Promise((resolve, reject) => { - if (!this.isConnected()) return reject('Must be connected to Dongle. Pro tip: Call .connect()'); - if (this.isStreaming()) return reject("Don't change the poll time while streaming"); - if (!this.usingVersionTwoFirmware()) return reject('Must be using firmware version 2'); - - // Set a timeout. Since poll times can be max of 255 seconds, we should set that as our timeout. This is - // important if the module was connected, not streaming and using the old firmware - badCommsTimeout = setTimeout(() => { - reject('Please make sure your dongle is plugged in and using firmware v2'); - }, 1000); - - // Subscribe to the EOT event - this.once('eot', data => { - // Remove the timeout! - clearTimeout(badCommsTimeout); - badCommsTimeout = null; - - if (this.options.verbose) console.log(data.toString()); - - if (openBCISample.isSuccessInBuffer(data)) { - resolve(true); - } else { - resolve(false); - } - }); - - this.curParsingMode = k.OBCIParsingEOT; - - // Send the radio channel query command - this._writeAndDrain(new Buffer([k.OBCIRadioKey, k.OBCIRadioCmdSystemStatus])).catch(reject); - }); - }; - - /** - * @description List available ports so the user can choose a device when not - * automatically found. - * Note: This method is used for convenience essentially just wrapping up - * serial port. - * @author Andy Heusser (@andyh616) - * @returns {Promise} - On fulfill will contain an array of Serial ports to use. - */ - OpenBCIBoard.prototype.listPorts = function () { - return new Promise((resolve, reject) => { - SerialPort.list((err, ports) => { - if (err) reject(err); - else { - ports.push({ - comName: k.OBCISimulatorPortName, - manufacturer: '', - serialNumber: '', - pnpId: '', - locationId: '', - vendorId: '', - productId: '' - }); - resolve(ports); - } - }); - }); - }; - - /** - * Get the board type. - * @return boardType: string - */ - OpenBCIBoard.prototype.getBoardType = function () { - return this.info.boardType; - }; - - /** - * Get the core info object. - * @return {{boardType: string, sampleRate: number, firmware: string, numberOfChannels: number, missedPackets: number}} - */ - OpenBCIBoard.prototype.getInfo = function () { - return this.info; - }; - - /** - * Set the info property for board type. - * @param boardType {String} - * `default` or `daisy`. Defaults to `default`. - */ - OpenBCIBoard.prototype.overrideInfoForBoardType = function (boardType) { - switch (boardType) { - case k.OBCIBoardDaisy: - this.info.boardType = k.OBCIBoardDaisy; - this.info.numberOfChannels = k.OBCINumberOfChannelsDaisy; - this.info.sampleRate = k.OBCISampleRate125; - this.channelSettingsArray = k.channelSettingsArrayInit(k.OBCINumberOfChannelsDaisy); - this.impedanceArray = openBCISample.impedanceArray(k.OBCINumberOfChannelsDaisy); - break; - case k.OBCIBoardDefault: - default: - this.info.boardType = k.OBCIBoardDefault; - this.info.numberOfChannels = k.OBCINumberOfChannelsDefault; - this.info.sampleRate = k.OBCISampleRate250; - this.channelSettingsArray = k.channelSettingsArrayInit(k.OBCINumberOfChannelsDefault); - this.impedanceArray = openBCISample.impedanceArray(k.OBCINumberOfChannelsDefault); - break; - } - }; - - /** - * Used to sync the module and board to `boardType` - * @param boardType {String} - * Either `default` or `daisy` - * @return {Promise} - */ - OpenBCIBoard.prototype.hardSetBoardType = function (boardType) { - if (this.isStreaming()) return Promise.reject('Must not be streaming!'); - return new Promise((resolve, reject) => { - const eotFunc = (data) => { - switch (data.slice(0, data.length - k.OBCIParseEOT.length).toString()) { - case k.OBCIChannelMaxNumber8SuccessDaisyRemoved: - this.overrideInfoForBoardType(k.OBCIBoardDefault); - resolve('daisy removed'); - break; - case k.OBCIChannelMaxNumber16DaisyAlreadyAttached: - this.overrideInfoForBoardType(k.OBCIBoardDaisy); - resolve('daisy already attached'); - break; - case k.OBCIChannelMaxNumber16DaisyAttached: - this.overrideInfoForBoardType(k.OBCIBoardDaisy); - resolve('daisy attached'); - break; - case k.OBCIChannelMaxNumber16NoDaisyAttached: - this.overrideInfoForBoardType(k.OBCIBoardDefault); - reject('unable to attach daisy'); - break; - case k.OBCIChannelMaxNumber8NoDaisyToRemove: - default: - this.overrideInfoForBoardType(k.OBCIBoardDefault); - resolve('no daisy to remove'); - break; - } - }; - if (boardType === k.OBCIBoardDefault) { - this.curParsingMode = k.OBCIParsingEOT; - this.once(k.OBCIEmitterEot, eotFunc); - this.write(k.OBCIChannelMaxNumber8) - .catch((err) => { - this.removeListener(k.OBCIEmitterEot, eotFunc); - reject(err); - }); - } else if (boardType === k.OBCIBoardDaisy) { - this.curParsingMode = k.OBCIParsingEOT; - this.once(k.OBCIEmitterEot, eotFunc); - this.write(k.OBCIChannelMaxNumber16) - .catch((err) => { - this.removeListener(k.OBCIEmitterEot, eotFunc); - reject(err); - }); - } else { - reject('invalid board type'); - } - }); - }; - - /** - * @description Sends a soft reset command to the board - * @returns {Promise} - * Note: The softReset command MUST be sent to the board before you can start - * streaming. - * @author AJ Keller (@pushtheworldllc) - */ - OpenBCIBoard.prototype.softReset = function () { - this.curParsingMode = k.OBCIParsingReset; - return this.write(k.OBCIMiscSoftReset); - }; - - /** - * @description To get the specified channelSettings register data from printRegisterSettings call - * @param channelNumber - a number - * @returns {Promise.|*} - * @author AJ Keller (@pushtheworldllc) - */ - // TODO: REDO THIS FUNCTION - OpenBCIBoard.prototype.getSettingsForChannel = function (channelNumber) { - return k.channelSettingsKeyForChannel(channelNumber).then((newSearchingBuffer) => { - // this.searchingBuf = newSearchingBuffer - return this.printRegisterSettings(); - }); - }; - - /** - * @description To print out the register settings to the console - * @returns {Promise.|*} - * @author AJ Keller (@pushtheworldllc) - */ - OpenBCIBoard.prototype.printRegisterSettings = function () { - return this.write(k.OBCIMiscQueryRegisterSettings).then(() => { - this.curParsingMode = k.OBCIParsingChannelSettings; - }); - }; - - /** - * @description Send a command to the board to turn a specified channel off - * @param channelNumber - * @returns {Promise.} - * @author AJ Keller (@pushtheworldllc) - */ - OpenBCIBoard.prototype.channelOff = function (channelNumber) { - return k.commandChannelOff(channelNumber).then((charCommand) => { - // console.log('sent command to turn channel ' + channelNumber + ' by sending command ' + charCommand) - return this.write(charCommand); - }); - }; - - /** - * @description Send a command to the board to turn a specified channel on - * @param channelNumber - * @returns {Promise.|*} - * @author AJ Keller (@pushtheworldllc) - */ - OpenBCIBoard.prototype.channelOn = function (channelNumber) { - return k.commandChannelOn(channelNumber).then((charCommand) => { - // console.log('sent command to turn channel ' + channelNumber + ' by sending command ' + charCommand) - return this.write(charCommand); - }); - }; - - /** - * @description To send a channel setting command to the board - * @param channelNumber - Number (1-16) - * @param powerDown - Bool (true -> OFF, false -> ON (default)) - * turns the channel on or off - * @param gain - Number (1,2,4,6,8,12,24(default)) - * sets the gain for the channel - * @param inputType - String (normal,shorted,biasMethod,mvdd,temp,testsig,biasDrp,biasDrn) - * selects the ADC channel input source - * @param bias - Bool (true -> Include in bias (default), false -> remove from bias) - * selects to include the channel input in bias generation - * @param srb2 - Bool (true -> Connect this input to SRB2 (default), - * false -> Disconnect this input from SRB2) - * Select to connect (true) this channel's P input to the SRB2 pin. This closes - * a switch between P input and SRB2 for the given channel, and allows the - * P input to also remain connected to the ADC. - * @param srb1 - Bool (true -> connect all N inputs to SRB1, - * false -> Disconnect all N inputs from SRB1 (default)) - * Select to connect (true) all channels' N inputs to SRB1. This effects all pins, - * and disconnects all N inputs from the ADC. - * @returns {Promise} resolves if sent, rejects on bad input or no board - * @author AJ Keller (@pushtheworldllc) - */ - OpenBCIBoard.prototype.channelSet = function (channelNumber, powerDown, gain, inputType, bias, srb2, srb1) { - var arrayOfCommands = []; - return new Promise((resolve, reject) => { - k.getChannelSetter(channelNumber, powerDown, gain, inputType, bias, srb2, srb1) - .then((val) => { - arrayOfCommands = val.commandArray; - this.channelSettingsArray[channelNumber - 1] = val.newChannelSettingsObject; - return this.write(arrayOfCommands); - }).then(resolve, reject); - }); - }; - - /** - * @description Apply the internal test signal to all channels - * @param signal - A string indicating which test signal to apply - * - `dc` - * - Connect to DC signal - * - `ground` - * - Connect to internal GND (VDD - VSS) - * - `pulse1xFast` - * - Connect to test signal 1x Amplitude, fast pulse - * - `pulse1xSlow` - * - Connect to test signal 1x Amplitude, slow pulse - * - `pulse2xFast` - * - Connect to test signal 2x Amplitude, fast pulse - * - `pulse2xFast` - * - Connect to test signal 2x Amplitude, slow pulse - * - `none` - * - Reset to default - * @returns {Promise} - * @author AJ Keller (@pushtheworldllc) - */ - OpenBCIBoard.prototype.testSignal = function (signal) { - return new Promise((resolve, reject) => { - k.getTestSignalCommand(signal) - .then(command => { - return this.write(command); - }) - .then(() => resolve()) - .catch(err => reject(err)); - }); - }; - - /** - * @description - Sends command to turn on impedances for all channels and continuously calculate their impedances - * @returns {Promise} - Fulfills when all the commands are sent to the internal write buffer - * @author AJ Keller (@pushtheworldllc) - */ - OpenBCIBoard.prototype.impedanceTestContinuousStart = function () { - return new Promise((resolve, reject) => { - if (this.impedanceTest.active) return reject('Error: test already active'); - if (this.impedanceTest.continuousMode) return reject('Error: Already in continuous impedance test mode!'); - - this.impedanceTest.active = true; - this.impedanceTest.continuousMode = true; - - var chain = Promise.resolve(); - for (var i = 0; i < this.numberOfChannels(); i++) { - chain = chain - .then(() => k.getImpedanceSetter(i + 1, false, true)) - .then((commandsArray) => this.write(commandsArray)); - } - chain.then(resolve, reject); - }); - }; - - /** - * @description - Sends command to turn off impedances for all channels and stop continuously calculate their impedances - * @returns {Promise} - Fulfills when all the commands are sent to the internal write buffer - * @author AJ Keller (@pushtheworldllc) - */ - OpenBCIBoard.prototype.impedanceTestContinuousStop = function () { - return new Promise((resolve, reject) => { - if (!this.impedanceTest.active) return reject('Error: no test active'); - if (!this.impedanceTest.continuousMode) return reject('Error: Not in continuous impedance test mode!'); - - this.impedanceTest.active = false; - this.impedanceTest.continuousMode = false; - - var chain = Promise.resolve(); - for (var i = 0; i < this.numberOfChannels(); i++) { - chain = chain - .then(() => k.getImpedanceSetter(i + 1, false, false)) - .then((commandsArray) => this.write(commandsArray)); - } - chain.then(resolve, reject); - }); - }; - - /** - * @description 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)! - * @returns {Promise} - Resovles when complete testing all the channels. - * @author AJ Keller (@pushtheworldllc) - */ - OpenBCIBoard.prototype.impedanceTestAllChannels = function () { - var upperLimit = k.OBCINumberOfChannelsDefault; - - /* istanbul ignore if */ - if (this.options.daisy) { - upperLimit = k.OBCINumberOfChannelsDaisy; - } - - if (!this.isStreaming()) return Promise.reject('Must be streaming!'); - - // Recursive function call - var completeChannelImpedanceTest = (channelNumber) => { - return new Promise((resolve, reject) => { - if (channelNumber > upperLimit) { // Base case! - this.emit('impedanceArray', this.impedanceArray); - this.impedanceTest.onChannel = 0; - resolve(); - } else { - if (this.options.verbose) console.log('\n\nImpedance Test for channel ' + channelNumber); - this.impedanceTestChannel(channelNumber) - .then(() => { - resolve(completeChannelImpedanceTest(channelNumber + 1)); - /* istanbul ignore next */ - }).catch(err => reject(err)); - } - }); - }; - - return completeChannelImpedanceTest(1); - }; - - /** - * @description To test specific input configurations of channels! - * @param arrayOfChannels - The array of configurations where: - * 'p' or 'P' is only test P input - * 'n' or 'N' is only test N input - * 'b' or 'B' is test both inputs (takes 66% longer to run) - * '-' to ignore channel - * EXAMPLE: - * For 8 channel board: ['-','N','n','p','P','-','b','b'] - * (Note: it doesn't matter if capitalized or not) - * @returns {Promise} - Fulfilled with a loaded impedance object. - * @author AJ Keller (@pushtheworldllc) - */ - OpenBCIBoard.prototype.impedanceTestChannels = function (arrayOfChannels) { - if (!Array.isArray(arrayOfChannels)) return Promise.reject('Input must be array of channels... See Docs!'); - if (!this.isStreaming()) return Promise.reject('Must be streaming!'); - // Check proper length of array - if (arrayOfChannels.length !== this.numberOfChannels()) return Promise.reject('Array length mismatch, should have ' + this.numberOfChannels() + ' but array has length ' + arrayOfChannels.length); - - // Recursive function call - var completeChannelImpedanceTest = (channelNumber) => { - return new Promise((resolve, reject) => { - if (channelNumber > arrayOfChannels.length) { // Base case! - this.emit('impedanceArray', this.impedanceArray); - this.impedanceTest.onChannel = 0; - resolve(); - } else { - if (this.options.verbose) console.log('\n\nImpedance Test for channel ' + channelNumber); - - var testCommand = arrayOfChannels[channelNumber - 1]; - - if (testCommand === 'p' || testCommand === 'P') { - this.impedanceTestChannelInputP(channelNumber).then(() => { - completeChannelImpedanceTest(channelNumber + 1).then(resolve, reject); - }).catch(err => reject(err)); - } else if (testCommand === 'n' || testCommand === 'N') { - this.impedanceTestChannelInputN(channelNumber).then(() => { - completeChannelImpedanceTest(channelNumber + 1).then(resolve, reject); - }).catch(err => reject(err)); - } else if (testCommand === 'b' || testCommand === 'B') { - this.impedanceTestChannel(channelNumber).then(() => { - completeChannelImpedanceTest(channelNumber + 1).then(resolve, reject); - }).catch(err => reject(err)); - } else { // skip ('-') condition - completeChannelImpedanceTest(channelNumber + 1).then(resolve, reject); - } - } - }); - }; - return completeChannelImpedanceTest(1); - }; - - /** - * @description Run a complete impedance test on a single channel, applying the test signal individually to P & N inputs. - * @param channelNumber - A Number, specifies which channel you want to test. - * @returns {Promise} - Fulfilled with a single channel impedance object. - * @author AJ Keller (@pushtheworldllc) - */ - OpenBCIBoard.prototype.impedanceTestChannel = function (channelNumber) { - this.impedanceArray[channelNumber - 1] = openBCISample.impedanceObject(channelNumber); - return new Promise((resolve, reject) => { - this._impedanceTestSetChannel(channelNumber, true, false) // Sends command for P input on channel number. - .then(channelNumber => { - return this._impedanceTestCalculateChannel(channelNumber, true, false); // Calculates for P input of channel number - }) - .then(channelNumber => { - return this._impedanceTestSetChannel(channelNumber, false, true); // Sends command for N input on channel number. - }) - .then(channelNumber => { - return this._impedanceTestCalculateChannel(channelNumber, false, true); // Calculates for N input of channel number - }) - .then(channelNumber => { - return this._impedanceTestSetChannel(channelNumber, false, false); // Sends command to stop applying test signal to P and N channel - }) - .then(channelNumber => { - return this._impedanceTestFinalizeChannel(channelNumber, true, true); // Finalize the impedances. - }) - .then((channelNumber) => resolve(this.impedanceArray[channelNumber - 1])) - .catch(err => reject(err)); - }); - }; - - /** - * @description Run impedance test on a single channel, applying the test signal only to P input. - * @param channelNumber - A Number, specifies which channel you want to test. - * @returns {Promise} - Fulfilled with a single channel impedance object. - * @author AJ Keller (@pushtheworldllc) - */ - OpenBCIBoard.prototype.impedanceTestChannelInputP = function (channelNumber) { - this.impedanceArray[channelNumber - 1] = openBCISample.impedanceObject(channelNumber); - return new Promise((resolve, reject) => { - this._impedanceTestSetChannel(channelNumber, true, false) // Sends command for P input on channel number. - .then(channelNumber => { - return this._impedanceTestCalculateChannel(channelNumber, true, false); // Calculates for P input of channel number - }) - .then(channelNumber => { - return this._impedanceTestSetChannel(channelNumber, false, false); // Sends command to stop applying test signal to P and N channel - }) - .then(channelNumber => { - return this._impedanceTestFinalizeChannel(channelNumber, true, false); // Finalize the impedances. - }) - .then((channelNumber) => resolve(this.impedanceArray[channelNumber - 1])) - .catch(err => reject(err)); - }); - }; - - /** - * @description Run impedance test on a single channel, applying the test signal to N input. - * @param channelNumber - A Number, specifies which channel you want to test. - * @returns {Promise} - Fulfilled with a single channel impedance object. - * @author AJ Keller (@pushtheworldllc) - */ - OpenBCIBoard.prototype.impedanceTestChannelInputN = function (channelNumber) { - this.impedanceArray[channelNumber - 1] = openBCISample.impedanceObject(channelNumber); - return new Promise((resolve, reject) => { - this._impedanceTestSetChannel(channelNumber, false, true) // Sends command for N input on channel number. - .then(channelNumber => { - return this._impedanceTestCalculateChannel(channelNumber, false, true); // Calculates for N input of channel number - }) - .then(channelNumber => { - return this._impedanceTestSetChannel(channelNumber, false, false); // Sends command to stop applying test signal to P and N channel - }) - .then(channelNumber => { - return this._impedanceTestFinalizeChannel(channelNumber, false, true); // Finalize the impedances. - }) - .then((channelNumber) => resolve(this.impedanceArray[channelNumber - 1])) - .catch(err => reject(err)); - }); - }; - - /* istanbul ignore next */ - /** - * @description To apply the impedance test signal to an input for any given channel - * @param channelNumber - Number - The channel you want to test. - * @param pInput - A bool true if you want to apply the test signal to the P input, false to not apply the test signal. - * @param nInput - A bool true if you want to apply the test signal to the N input, false to not apply the test signal. - * @returns {Promise} - With Number value of channel number - * @private - * @author AJ Keller (@pushtheworldllc) - */ - OpenBCIBoard.prototype._impedanceTestSetChannel = function (channelNumber, pInput, nInput) { - return new Promise((resolve, reject) => { - if (!this.isConnected()) return reject('Must be connected'); - - /* istanbul ignore if */ - if (this.options.verbose) { - if (pInput && !nInput) { - console.log('\tSending command to apply test signal to P input.'); - } else if (!pInput && nInput) { - console.log('\tSending command to apply test signal to N input.'); - } else if (pInput && nInput) { - console.log('\tSending command to apply test signal to P and N inputs.'); - } else { - console.log('\tSending command to stop applying test signal to both P and N inputs.'); - } - } - - if (!pInput && !nInput) { - this.impedanceTest.active = false; // Critical to changing the flow of `._processBytes()` - // this.writeOutDelay = k.OBCIWriteIntervalDelayMSShort - } else { - // this.writeOutDelay = k.OBCIWriteIntervalDelayMSLong - } - if (this.options.verbose) console.log('pInput: ' + pInput + ' nInput: ' + nInput); - // Get impedance settings to send the board - k.getImpedanceSetter(channelNumber, pInput, nInput).then((commandsArray) => { - return this.write(commandsArray); - }).then(() => { - /** - * If either pInput or nInput are true then we should start calculating impedance. Setting - * this.impedanceTest.active to true here allows us to route every sample for an impedance - * calculation instead of the normal sample output. - */ - if (pInput || nInput) this.impedanceTest.active = true; - resolve(channelNumber); - }, (err) => { - reject(err); - }); - }); - }; - - /** - * @description Calculates the impedance for a specified channel for a set time - * @param channelNumber - A Number, the channel number you want to test. - * @param pInput - A bool true if you want to calculate impedance on the P input, false to not calculate. - * @param nInput - A bool true if you want to calculate impedance on the N input, false to not calculate. - * @returns {Promise} - Resolves channelNumber as value on fulfill, rejects with error... - * @private - * @author AJ Keller (@pushtheworldllc) - */ - OpenBCIBoard.prototype._impedanceTestCalculateChannel = function (channelNumber, pInput, nInput) { - /* istanbul ignore if */ - if (this.options.verbose) { - if (pInput && !nInput) { - console.log('\tCalculating impedance for P input.'); - } else if (!pInput && nInput) { - console.log('\tCalculating impedance for N input.'); - } else if (pInput && nInput) { - console.log('\tCalculating impedance for P and N input.'); - } else { - console.log('\tNot calculating impedance for either P and N input.'); - } - } - return new Promise((resolve, reject) => { - if (channelNumber < 1 || channelNumber > this.numberOfChannels()) return reject('Invalid channel number'); - if (typeof pInput !== 'boolean') return reject("Invalid Input: 'pInput' must be of type Bool"); - if (typeof nInput !== 'boolean') return reject("Invalid Input: 'nInput' must be of type Bool"); - this.impedanceTest.onChannel = channelNumber; - this.impedanceTest.sampleNumber = 0; // Reset the sample number - this.impedanceTest.isTestingPInput = pInput; - this.impedanceTest.isTestingNInput = nInput; - // console.log(channelNumber + ' In calculate channel pInput: ' + pInput + ' this.impedanceTest.isTestingPInput: ' + this.impedanceTest.isTestingPInput) - // console.log(channelNumber + ' In calculate channel nInput: ' + nInput + ' this.impedanceTest.isTestingNInput: ' + this.impedanceTest.isTestingNInput) - setTimeout(() => { // Calculate for 250ms - this.impedanceTest.onChannel = 0; - /* istanbul ignore if */ - if (this.options.verbose) { - if (pInput && !nInput) { - console.log('\tDone calculating impedance for P input.'); - } else if (!pInput && nInput) { - console.log('\tDone calculating impedance for N input.'); - } else if (pInput && nInput) { - console.log('\tDone calculating impedance for P and N input.'); - } else { - console.log('\tNot calculating impedance for either P and N input.'); - } - } - if (pInput) this.impedanceArray[channelNumber - 1].P.raw = this.impedanceTest.impedanceForChannel; - if (nInput) this.impedanceArray[channelNumber - 1].N.raw = this.impedanceTest.impedanceForChannel; - resolve(channelNumber); - }, 400); - }); - }; - - /** - * @description Calculates average and gets textual value of impedance for a specified channel - * @param channelNumber - A Number, the channel number you want to finalize. - * @param pInput - A bool true if you want to finalize impedance on the P input, false to not finalize. - * @param nInput - A bool true if you want to finalize impedance on the N input, false to not finalize. - * @returns {Promise} - Resolves channelNumber as value on fulfill, rejects with error... - * @private - * @author AJ Keller (@pushtheworldllc) - */ - OpenBCIBoard.prototype._impedanceTestFinalizeChannel = function (channelNumber, pInput, nInput) { - /* istanbul ignore if */ - if (this.options.verbose) { - if (pInput && !nInput) { - console.log('\tFinalizing impedance for P input.'); - } else if (!pInput && nInput) { - console.log('\tFinalizing impedance for N input.'); - } else if (pInput && nInput) { - console.log('\tFinalizing impedance for P and N input.'); - } else { - console.log('\tNot Finalizing impedance for either P and N input.'); - } - } - return new Promise((resolve, reject) => { - if (channelNumber < 1 || channelNumber > this.numberOfChannels()) return reject('Invalid channel number'); - if (typeof pInput !== 'boolean') return reject("Invalid Input: 'pInput' must be of type Bool"); - if (typeof nInput !== 'boolean') return reject("Invalid Input: 'nInput' must be of type Bool"); - - if (pInput) openBCISample.impedanceSummarize(this.impedanceArray[channelNumber - 1].P); - if (nInput) openBCISample.impedanceSummarize(this.impedanceArray[channelNumber - 1].N); - - setTimeout(() => { - resolve(channelNumber); - }, 50); // Introduce a delay to allow for extra time in case of back to back tests - }); - }; - - /** - * @description Start logging to the SD card. If not streaming then `eot` event will be emitted with request - * response from the board. - * @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 when the command has been written. - * @private - * @author AJ Keller (@pushtheworldllc) - */ - OpenBCIBoard.prototype.sdStart = function (recordingDuration) { - return new Promise((resolve, reject) => { - if (!this.isConnected()) return 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.isStreaming()) { - this.curParsingMode = k.OBCIParsingEOT; - } - this.writeOutDelay = k.OBCIWriteIntervalDelayMSNone; - this.write(command).then(resolve, reject); - }) - .catch(err => reject(err)); - }); - }; - - /** - * @description Sends the stop SD logging command to the board. If not streaming then `eot` event will be emitted - * with request response from the board. - * @returns {Promise} - Resolves when written - * @author AJ Keller (@pushtheworldllc) - */ - OpenBCIBoard.prototype.sdStop = function () { - return new Promise((resolve, reject) => { - if (!this.isConnected()) return reject('Must be connected to the device'); - // If we are not streaming, then expect a confirmation message back from the board - if (!this.isStreaming()) { - this.curParsingMode = k.OBCIParsingEOT; - } - this.writeOutDelay = k.OBCIWriteIntervalDelayMSNone; - this.write(k.OBCISDLogStop).then(resolve, reject); - }); - }; - - /** - * @description Get the the current sample rate is. - * @returns {Number} The sample rate - * Note: This is dependent on if you configured the board correctly on setup options - * @author AJ Keller (@pushtheworldllc) - */ - OpenBCIBoard.prototype.sampleRate = function () { - if (this.options.simulate) { - return this.options.simulatorSampleRate; - } else { - if (this.info) { - return this.info.sampleRate; - } else { - switch (this.boardType) { - case k.OBCIBoardDaisy: - return k.OBCISampleRate125; - case k.OBCIBoardDefault: - default: - return k.OBCISampleRate250; - } - } - } - }; - - /** - * @description This function is used as a convenience method to determine how many - * channels the current board is using. - * @returns {Number} A number - * Note: This is dependent on if you configured the board correctly on setup options - * @author AJ Keller (@pushtheworldllc) - */ - OpenBCIBoard.prototype.numberOfChannels = function () { - if (this.info) { - return this.info.numberOfChannels; - } else { - switch (this.boardType) { - case k.OBCIBoardDaisy: - return k.OBCINumberOfChannelsDaisy; - case k.OBCIBoardDefault: - default: - return k.OBCINumberOfChannelsDefault; - } - } - }; - - /** - * @description Send the command to tell the board to start the syncing protocol. Must be connected, - * streaming and using at least version 2.0.0 firmware. - * **Note**: This functionality requires OpenBCI Firmware Version 2.0 - * @since 1.0.0 - * @returns {Promise} - Resolves if sent, rejects if not connected or using firmware verison +2. - * @author AJ Keller (@pushtheworldllc) - */ - OpenBCIBoard.prototype.syncClocks = function () { - return new Promise((resolve, reject) => { - if (!this.isConnected()) return reject('Must be connected to the device'); - if (!this.isStreaming()) return reject('Must be streaming to sync clocks'); - if (!this.usingVersionTwoFirmware()) return reject('Time sync not implemented on v1 firmware, please update to v2'); - this.sync.curSyncObj = openBCISample.newSyncObject(); - this.sync.curSyncObj.timeSyncSent = this.time(); - this.curParsingMode = k.OBCIParsingTimeSyncSent; - this._writeAndDrain(k.OBCISyncTimeSet).then(resolve, reject); - }); - }; - - /** - * @description Send the command to tell the board to start the syncing protocol. Must be connected, - * streaming and using at least version 2.0.0 firmware. Uses the `synced` event to ensure multiple syncs - * don't overlap. - * **Note**: This functionality requires OpenBCI Firmware Version 2.0 - * @since 1.1.0 - * @returns {Promise} - Resolves if `synced` event is emitted, rejects if not connected or using firmware v2. - * @author AJ Keller (@pushtheworldllc) - */ - OpenBCIBoard.prototype.syncClocksFull = function () { - return new Promise((resolve, reject) => { - if (!this.isConnected()) return reject('Must be connected to the device'); - if (!this.isStreaming()) return reject('Must be streaming to sync clocks'); - if (!this.usingVersionTwoFirmware()) return reject('Time sync not implemented on v1 firmware, please update to v2'); - var timeout = setTimeout(() => { - return reject('syncClocksFull timeout after 500ms with no sync'); - }, 500); // Should not take more than 1s to sync up - this.sync.eventEmitter = syncObj => { - clearTimeout(timeout); - return resolve(syncObj); - }; - this.once('synced', this.sync.eventEmitter); - this.sync.curSyncObj = openBCISample.newSyncObject(); - this.sync.curSyncObj.timeSyncSent = this.time(); - this.curParsingMode = k.OBCIParsingTimeSyncSent; - this._writeAndDrain(k.OBCISyncTimeSet) - .catch(err => { - clearTimeout(timeout); - return reject(err); - }); - }); - }; - - /** - * @description Output passed bytes on the console as a hexdump, if enabled - * @param prefix - label to show to the left of bytes - * @param data - bytes to output, a buffer or string - * @private - */ - OpenBCIBoard.prototype._debugBytes = function (prefix, data) { - if (!this.options.debug) return; - - if (typeof data === 'string') data = new Buffer(data); - - console.log('Debug bytes:'); - - for (var j = 0; j < data.length;) { - var hexPart = ''; - var ascPart = ''; - for (var end = Math.min(data.length, j + 16); j < end; ++j) { - var byt = data[j]; - - var hex = ('0' + byt.toString(16)).slice(-2); - hexPart += (((j & 0xf) === 0x8) ? ' ' : ' '); // puts an extra space 8 bytes in - hexPart += hex; - - var asc = (byt >= 0x20 && byt < 0x7f) ? String.fromCharCode(byt) : '.'; - ascPart += asc; - } - - // pad to fixed width for alignment - hexPart = (hexPart + ' ').substring(0, 3 * 17); - - console.log(prefix + ' ' + hexPart + '|' + ascPart + '|'); - } - }; - - /** - * @description Consider the '_processBytes' method to be the work horse of this - * entire framework. This method gets called any time there is new - * data coming in on the serial port. If you are familiar with the - * 'serialport' package, then every time data is emitted, this function - * gets sent the input data. The data comes in very fragmented, sometimes - * we get half of a packet, and sometimes we get 3 and 3/4 packets, so - * we will need to store what we don't read for next time. - * @param data - a buffer of unknown size - * @private - * @author AJ Keller (@pushtheworldllc) - */ - OpenBCIBoard.prototype._processBytes = function (data) { - this._debugBytes(this.curParsingMode + '<<', data); - - // Concat old buffer - var oldDataBuffer = null; - if (this.buffer) { - oldDataBuffer = this.buffer; - data = Buffer.concat([this.buffer, data], data.length + this.buffer.length); - } - - switch (this.curParsingMode) { - case k.OBCIParsingEOT: - if (openBCISample.doesBufferHaveEOT(data)) { - this.curParsingMode = k.OBCIParsingNormal; - this.emit(k.OBCIEmitterEot, data); - this.buffer = openBCISample.stripToEOTBuffer(data); - } else { - this.buffer = data; - } - break; - case k.OBCIParsingReset: - // Does the buffer have an EOT in it? - if (openBCISample.doesBufferHaveEOT(data)) { - this._processParseBufferForReset(data); - if (this.options.hardSet) { - if (this.getBoardType() !== this.options.boardType) { - this.emit(k.OBCIEmitterHardSet); - this.hardSetBoardType(this.options.boardType) - .then(() => { - this.emit(k.OBCIEmitterReady); - }) - .catch((err) => { - this.emit(k.OBCIEmitterError, err); - }); - } else { - this.curParsingMode = k.OBCIParsingNormal; - this.emit(k.OBCIEmitterReady); - this.buffer = openBCISample.stripToEOTBuffer(data); - } - } else { - if (this.getBoardType() !== this.options.boardType && this.options.verbose) { - console.log(`Module detected ${this.getBoardType()} board type but you specified ${this.options.boardType}, use 'hardSet' to force the module to correct itself`); - } - this.curParsingMode = k.OBCIParsingNormal; - this.emit(k.OBCIEmitterReady); - this.buffer = openBCISample.stripToEOTBuffer(data); - } - } else { - this.buffer = data; - } - break; - case k.OBCIParsingTimeSyncSent: - // If there is only one match - if (openBCISample.isTimeSyncSetConfirmationInBuffer(data)) { - if (this.options.verbose) console.log(`Found Time Sync Sent`); - this.sync.curSyncObj.timeSyncSentConfirmation = this.time(); - this.curParsingMode = k.OBCIParsingNormal; - } - this.buffer = this._processDataBuffer(data); - break; - case k.OBCIParsingNormal: - default: - this.buffer = this._processDataBuffer(data); - break; - } - - if (this.buffer && oldDataBuffer) { - if (bufferEqual(this.buffer, oldDataBuffer)) { - this.buffer = null; - } - } - }; - - /** - * @description Used to extract samples out of a buffer of unknown length - * @param dataBuffer {Buffer} - A buffer to parse for samples - * @returns {Buffer} - Any data that was not pulled out of the buffer - * @private - * @author AJ Keller (@pushtheworldllc) - */ - OpenBCIBoard.prototype._processDataBuffer = function (dataBuffer) { - if (!dataBuffer) return null; - var bytesToParse = dataBuffer.length; - // Exit if we have a buffer with less data than a packet - if (bytesToParse < k.OBCIPacketSize) return dataBuffer; - - var parsePosition = 0; - // Begin parseing - while (parsePosition <= bytesToParse - k.OBCIPacketSize) { - // Is the current byte a head byte that looks like 0xA0 - if (dataBuffer[parsePosition] === k.OBCIByteStart) { - // Now that we know the first is a head byte, let's see if the last one is a - // tail byte 0xCx where x is the set of numbers from 0-F (hex) - if (openBCISample.isStopByte(dataBuffer[parsePosition + k.OBCIPacketSize - 1])) { - /** We just qualified a raw packet */ - // This could be a time set packet! - this.timeOfPacketArrival = this.time(); - // Grab the raw packet, make a copy of it. - var rawPacket; - if (k.getVersionNumber(process.version) >= 6) { - // From introduced in node version 6.x.x - rawPacket = Buffer.from(dataBuffer.slice(parsePosition, parsePosition + k.OBCIPacketSize)); - } else { - rawPacket = new Buffer(dataBuffer.slice(parsePosition, parsePosition + k.OBCIPacketSize)); - } - - // Emit that buffer - this.emit('rawDataPacket', rawPacket); - // Submit the packet for processing - this._processQualifiedPacket(rawPacket); - // Overwrite the dataBuffer with a new buffer - var tempBuf; - if (parsePosition > 0) { - tempBuf = Buffer.concat([dataBuffer.slice(0, parsePosition), dataBuffer.slice(parsePosition + k.OBCIPacketSize)], dataBuffer.byteLength - k.OBCIPacketSize); - } else { - tempBuf = dataBuffer.slice(k.OBCIPacketSize); - } - if (tempBuf.length === 0) { - dataBuffer = null; - } else { - if (k.getVersionNumber(process.version) >= 6) { - dataBuffer = Buffer.from(tempBuf); - } else { - dataBuffer = new Buffer(tempBuf); - } - } - // Move the parse position up one packet - parsePosition = -1; - bytesToParse -= k.OBCIPacketSize; - } - } - parsePosition++; - } - - return dataBuffer; - }; - - /** - * @description Alters the global info object by parseing an incoming soft reset key - * @param dataBuffer {Buffer} - The soft reset data buffer - * @returns {Buffer} - If there is data left in the buffer, just it will be returned. - * @private - * @author AJ Keller (@pushtheworldllc) - */ - OpenBCIBoard.prototype._processParseBufferForReset = function (dataBuffer) { - if (openBCISample.countADSPresent(dataBuffer) === 2) { - this.overrideInfoForBoardType(k.OBCIBoardDaisy); - } else { - this.overrideInfoForBoardType(k.OBCIBoardDefault); - } - - if (openBCISample.findV2Firmware(dataBuffer)) { - this.info.firmware = k.OBCIFirmwareV2; - this.writeOutDelay = k.OBCIWriteIntervalDelayMSNone; - } else { - this.info.firmware = k.OBCIFirmwareV1; - this.writeOutDelay = k.OBCIWriteIntervalDelayMSShort; - } - }; - - /** - * @description Used to route qualified packets to their proper parsers - * @param rawDataPacketBuffer - * @private - * @author AJ Keller (@pushtheworldllc) - */ - OpenBCIBoard.prototype._processQualifiedPacket = function (rawDataPacketBuffer) { - if (!rawDataPacketBuffer) return; - if (rawDataPacketBuffer.byteLength !== k.OBCIPacketSize) return; - var missedPacketArray = openBCISample.droppedPacketCheck(this.previousSampleNumber, rawDataPacketBuffer[k.OBCIPacketPositionSampleNumber]); - if (missedPacketArray) { - this.emit(k.OBCIEmitterDroppedPacket, missedPacketArray); - } - this.previousSampleNumber = rawDataPacketBuffer[k.OBCIPacketPositionSampleNumber]; - var packetType = openBCISample.getRawPacketType(rawDataPacketBuffer[k.OBCIPacketPositionStopByte]); - switch (packetType) { - case k.OBCIStreamPacketStandardAccel: - this._processPacketStandardAccel(rawDataPacketBuffer); - break; - case k.OBCIStreamPacketStandardRawAux: - this._processPacketStandardRawAux(rawDataPacketBuffer); - break; - case k.OBCIStreamPacketUserDefinedType: - // Do nothing for User Defined Packets - break; - case k.OBCIStreamPacketAccelTimeSyncSet: - // Don't waste any time! - this._processPacketTimeSyncSet(rawDataPacketBuffer, this.timeOfPacketArrival); - this._processPacketTimeSyncedAccel(rawDataPacketBuffer); - break; - case k.OBCIStreamPacketAccelTimeSynced: - this._processPacketTimeSyncedAccel(rawDataPacketBuffer); - break; - case k.OBCIStreamPacketRawAuxTimeSyncSet: - this._processPacketTimeSyncSet(rawDataPacketBuffer, this.timeOfPacketArrival); - this._processPacketTimeSyncedRawAux(rawDataPacketBuffer); - break; - case k.OBCIStreamPacketRawAuxTimeSynced: - this._processPacketTimeSyncedRawAux(rawDataPacketBuffer); - break; - default: - // Don't do anything if the packet is not defined - break; - } - }; - - /** - * @description A method used to compute impedances. - * @param sampleObject - A sample object that follows the normal standards. - * @private - * @author AJ Keller (@pushtheworldllc) - */ - OpenBCIBoard.prototype._processImpedanceTest = function (sampleObject) { - var impedanceArray; - if (this.impedanceTest.continuousMode) { - // console.log('running in continuous mode...') - // openBCISample.debugPrettyPrint(sampleObject) - impedanceArray = openBCISample.impedanceCalculateArray(sampleObject, this.impedanceTest); - if (impedanceArray) { - this.emit('impedanceArray', impedanceArray); - } - } else if (this.impedanceTest.onChannel !== 0) { - // Only calculate impedance for one channel - impedanceArray = openBCISample.impedanceCalculateArray(sampleObject, this.impedanceTest); - if (impedanceArray) { - this.impedanceTest.impedanceForChannel = impedanceArray[this.impedanceTest.onChannel - 1]; - } - } - }; - - /** - * @description A method to parse a stream packet that has channel data and data in the aux channels that contains accel data. - * @param rawPacket - A 33byte data buffer from _processQualifiedPacket - * @private - * @author AJ Keller (@pushtheworldllc) - */ - OpenBCIBoard.prototype._processPacketStandardAccel = function (rawPacket) { - try { - let sample = openBCISample.parseRawPacketStandard(rawPacket, this.channelSettingsArray, true); - sample.rawPacket = rawPacket; - this._finalizeNewSample(sample); - } catch (err) { - this.badPackets++; - this.emit(k.OBCIEmitterDroppedPacket, [this.previousSampleNumber + 1]); - if (this.options.verbose) console.log(err); - } - }; - - /** - * @description A method to parse a stream packet that has channel data and data in the aux channels that should not be scaled. - * @param rawPacket - A 33byte data buffer from _processQualifiedPacket - * @private - * @author AJ Keller (@pushtheworldllc) - */ - OpenBCIBoard.prototype._processPacketStandardRawAux = function (rawPacket) { - try { - let sample = openBCISample.parseRawPacketStandard(rawPacket, this.channelSettingsArray, false); - sample.rawPacket = rawPacket; - this._finalizeNewSample(sample); - } catch (err) { - this.badPackets++; - this.emit(k.OBCIEmitterDroppedPacket, [this.previousSampleNumber + 1]); - if (this.options.verbose) console.log(err); - } - }; - - /** - * @description A method to parse a stream packet that does not have channel data or aux/accel data, just a timestamp - * @param rawPacket {Buffer} - A 33byte data buffer from _processQualifiedPacket - * @param timeOfPacketArrival {Number} - The time the packet arrived. - * @private - * @returns {Object} - A time sync object. - * @author AJ Keller (@pushtheworldllc) - */ - OpenBCIBoard.prototype._processPacketTimeSyncSet = function (rawPacket, timeOfPacketArrival) { - /** - * Helper function for creating a bad sync object - * @param err {object} - Can be any object - * @returns {{boardTime, correctedTransmissionTime, error, timeSyncSent, timeSyncSentConfirmation, timeSyncSetPacket, timeRoundTrip, timeTransmission, timeOffset, timeOffsetMaster, valid}|*} - */ - var getBadObject = (err) => { - var badObject = openBCISample.newSyncObject(); - badObject.timeOffsetMaster = this.sync.timeOffsetMaster; - // Create an error - badObject.error = err; - return badObject; - }; - - var syncObj = {}; - - if (this.sync.curSyncObj === null) { - if (this.options.verbose) console.log(k.OBCIErrorTimeSyncIsNull); - // Set the output to bad object - syncObj = getBadObject(k.OBCIErrorTimeSyncIsNull); - // Missed comma - } else if (this.curParsingMode === k.OBCIParsingTimeSyncSent) { - if (this.options.verbose) console.log(k.OBCIErrorTimeSyncNoComma); - // Set the output to bad object - syncObj = getBadObject(k.OBCIErrorTimeSyncNoComma); - } else { - try { - this.sync.curSyncObj.timeSyncSetPacket = timeOfPacketArrival; - if (this.options.verbose) console.log('Got time set packet from the board'); - let boardTime = openBCISample.getFromTimePacketTime(rawPacket); - this.sync.curSyncObj.boardTime = boardTime; - // if (this.options.verbose) { - // console.log(`Sent sync command at ${this.sync.curSyncObj.timeSyncSent} ms`) - // console.log(`Sent confirmation at ${this.sync.curSyncObj.timeSyncSentConfirmation} ms`) - // console.log(`Set packet arrived at ${this.sync.curSyncObj.timeSyncSetPacket} ms`) - // } - - // Calculate the time between sending the `<` to getting the set packet, call this the round trip length - this.sync.curSyncObj.timeRoundTrip = this.sync.curSyncObj.timeSyncSetPacket - this.sync.curSyncObj.timeSyncSent; - if (this.options.verbose) console.log(`Round trip time: ${this.sync.curSyncObj.timeRoundTrip} ms`); - - // If the sync sent conf and set packet arrive in different serial flushes - // ------------------------------------------ - // | | timeTransmission | < GOOD :) - // ------------------------------------------ - // ^ ^ ^ - // s s s - // e e e - // n n t packet - // t t confirmation - // - // Assume it's good... - this.sync.curSyncObj.timeTransmission = this.sync.curSyncObj.timeRoundTrip - (this.sync.curSyncObj.timeSyncSentConfirmation - this.sync.curSyncObj.timeSyncSent); - - // If the conf and the set packet arrive in the same serial flush we have big problem! - // ------------------------------------------ - // | | | < BAD :( - // ------------------------------------------ - // ^ ^ ^ - // s s s - // e e e - // n n t packet - // t t confirmation - if ((this.sync.curSyncObj.timeSyncSetPacket - this.sync.curSyncObj.timeSyncSentConfirmation) < k.OBCITimeSyncThresholdTransFailureMS) { - // Estimate that 75% of the time between sent and set packet was spent on the packet making its way from board to this point - this.sync.curSyncObj.timeTransmission = math.floor((this.sync.curSyncObj.timeSyncSetPacket - this.sync.curSyncObj.timeSyncSent) * k.OBCITimeSyncMultiplierWithSyncConf); - if (this.options.verbose) console.log(`Had to correct transmission time`); - this.sync.curSyncObj.correctedTransmissionTime = true; - } - - // Calculate the offset #finally - this.sync.curSyncObj.timeOffset = this.sync.curSyncObj.timeSyncSetPacket - this.sync.curSyncObj.timeTransmission - boardTime; - if (this.options.verbose) { - console.log(`Board offset time: ${this.sync.curSyncObj.timeOffset} ms`); - console.log(`Board time: ${boardTime}`); - } - - // Add to array - if (this.sync.timeOffsetArray.length >= k.OBCITimeSyncArraySize) { - // Shift the oldest one out of the array - this.sync.timeOffsetArray.shift(); - // Push the new value into the array - this.sync.timeOffsetArray.push(this.sync.curSyncObj.timeOffset); - } else { - // Push the new value into the array - this.sync.timeOffsetArray.push(this.sync.curSyncObj.timeOffset); - } - - // Calculate the master time offset that we use averaging to compute - if (this.sync.timeOffsetArray.length > 1) { - var sum = this.sync.timeOffsetArray.reduce(function (a, b) { return a + b; }); - this.sync.timeOffsetMaster = Math.floor(sum / this.sync.timeOffsetArray.length); - } else { - 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`); - } - - // Set the valid object to true - this.sync.curSyncObj.valid = true; - - // Make a byte by byte copy of event - syncObj = JSON.parse(JSON.stringify(this.sync.curSyncObj)); - - // Save obj to the global array - this.sync.objArray.push(syncObj); - } catch (err) { - // Log if verbose. - if (this.options.verbose) console.log(err.message); - syncObj = getBadObject(err); - } - } - // Fix the curParsingMode back to normal - this.curParsingMode = k.OBCIParsingNormal; - // Emit synced object - this.emit(k.OBCIEmitterSynced, syncObj); - // Set global to null - this.sync.curSyncObj = null; - // Return the object - return syncObj; - }; - - /** - * @description A method to parse a stream packet that contains channel data, a time stamp and event couple packets - * an accelerometer value. - * @param rawPacket - A 33byte data buffer from _processQualifiedPacket - * @private - * @author AJ Keller (@pushtheworldllc) - */ - OpenBCIBoard.prototype._processPacketTimeSyncedAccel = function (rawPacket) { - // if (this.sync.active === false) console.log('Need to sync with board...') - try { - let sample = openBCISample.parsePacketTimeSyncedAccel(rawPacket, this.channelSettingsArray, this.sync.timeOffsetMaster, this.accelArray); - sample.rawPacket = rawPacket; - this._finalizeNewSample(sample); - } catch (err) { - this.badPackets++; - this.emit(k.OBCIEmitterDroppedPacket, [this.previousSampleNumber + 1]); - if (this.options.verbose) console.log(err); - } - }; - - /** - * @description A method to parse a stream packet that contains channel data, a time stamp and two extra bytes that - * shall be emitted as a raw buffer and not scaled. - * @param rawPacket {Buffer} - A 33byte data buffer from _processQualifiedPacket - * @private - * @author AJ Keller (@pushtheworldllc) - */ - OpenBCIBoard.prototype._processPacketTimeSyncedRawAux = function (rawPacket) { - // if (this.sync.active === false) console.log('Need to sync with board...') - try { - let sample = openBCISample.parsePacketTimeSyncedRawAux(rawPacket, this.channelSettingsArray, this.sync.timeOffsetMaster); - sample.rawPacket = rawPacket; - this._finalizeNewSample(sample); - } catch (err) { - this.badPackets++; - this.emit(k.OBCIEmitterDroppedPacket, [this.previousSampleNumber + 1]); - if (this.options.verbose) console.log(err); - } - }; - - /** - * @description A method to emit samples through the EventEmitter channel `sample` or compute impedances if are - * being tested. - * @param sampleObject {Object} - A sample object that follows the normal standards. - * @private - * @author AJ Keller (@pushtheworldllc) - */ - OpenBCIBoard.prototype._finalizeNewSample = function (sampleObject) { - sampleObject._count = this.sampleCount++; - if (this.impedanceTest.active) { - this._processImpedanceTest(sampleObject); - } else { - // With the daisy board attached, lower channels (1-8) come in packets with odd sample numbers and upper - // channels (9-16) come in packets with even sample numbers - if (this.info.boardType === k.OBCIBoardDaisy) { - // Send the sample for downstream sample compaction - this._finalizeNewSampleForDaisy(sampleObject); - } else { - this.emit(k.OBCIEmitterSample, sampleObject); - } - } - }; - - /** - * @description This function is called every sample if the boardType is Daisy. The function stores odd sampleNumber - * sample objects to a private global variable called `._lowerChannelsSampleObject`. The method will emit a - * sample object only when the upper channels arrive in an even sampleNumber sample object. No sample will be - * emitted on an even sampleNumber if _lowerChannelsSampleObject is null and one will be added to the - * missedPacket counter. Further missedPacket will increase if two odd sampleNumber packets arrive in a row. - * @param sampleObject {Object} - The sample object to finalize - * @private - * @author AJ Keller (@pushtheworldllc) - */ - OpenBCIBoard.prototype._finalizeNewSampleForDaisy = function (sampleObject) { - if (openBCISample.isOdd(sampleObject.sampleNumber)) { - // Check for the skipped packet condition - if (this._lowerChannelsSampleObject) { - // The last packet was odd... missed the even packet - this.info.missedPackets++; - } - this._lowerChannelsSampleObject = sampleObject; - } else { - // Make sure there is an odd packet waiting to get merged with this packet - if (this._lowerChannelsSampleObject) { - // Merge these two samples - var mergedSample = openBCISample.makeDaisySampleObject(this._lowerChannelsSampleObject, sampleObject); - // Set the _lowerChannelsSampleObject object to null - this._lowerChannelsSampleObject = null; - // Emite the new merged sample - this.emit('sample', mergedSample); - } else { - // Missed the odd packet, i.e. two evens in a row - this.info.missedPackets++; - } - } - }; - - /** - * @description Reset the master buffer and reset the number of bad packets. - * @author AJ Keller (@pushtheworldllc) - */ - // TODO: nothing is using these constructs, but they look like good constructs. See contents of masterBufferMaker() - OpenBCIBoard.prototype._reset_ABANDONED = function () { - this.masterBuffer = masterBufferMaker(); - this.badPackets = 0; - }; - - /** - * @description Stateful method for querying the current offset only when the last - * one is too old. (defaults to daily) - * @returns {Promise} A promise with the time offset - * @author AJ Keller (@pushtheworldllc) - */ - OpenBCIBoard.prototype.sntpGetOffset = function () { - this.options.sntpTimeSync = true; - - if (!this.options.sntpTimeSync) return Promise.reject('sntp not enabled'); - - return new Promise((resolve, reject) => { - Sntp.offset({ - host: this.options.sntpTimeSyncHost, // Defaults to pool.ntp.org - port: this.options.sntpTimeSyncPort, // Defaults to 123 (NTP) - clockSyncRefresh: 30 * 60 * 1000, // Resync every 30 minutes - timeout: 500 // Assume packet has been lost after 500 milliseconds - }, function (err, offset) { - if (err) reject(err); - else resolve(offset); - }); - }); - }; - - /** - * @description Allows users to utilize all features of sntp if they want to... - */ - OpenBCIBoard.prototype.sntp = Sntp; - - /** - * @description This gets the time plus offset - * @private - */ - OpenBCIBoard.prototype._sntpNow = Sntp.now; - - /** - * @description This starts the SNTP server and gets it to remain in sync with the SNTP server - * @returns {Promise} - A promise if the module was able to sync with ntp server. - * @author AJ Keller (@pushtheworldllc) - */ - OpenBCIBoard.prototype.sntpStart = function (options) { - this.options.sntpTimeSync = true; - - // Sntp.start doesn't actually report errors (2016-10-29) - // so functionality is first detected via sntpGetOffset - return this.sntpGetOffset().then(() => { - return new Promise((resolve, reject) => { - Sntp.start({ - host: this.options.sntpTimeSyncHost, // Defaults to pool.ntp.org - port: this.options.sntpTimeSyncPort, // Defaults to 123 (NTP) - clockSyncRefresh: 30 * 60 * 1000, // Resync every 30 minutes - timeout: 500 // Assume packet has been lost after 500 milliseconds - }, () => { - this.sync.sntpActive = true; - this.emit('sntpTimeLock'); - resolve(); - }); - }); - }); - }; - - /** - * @description Stops the sntp from updating. - */ - OpenBCIBoard.prototype.sntpStop = function () { - Sntp.stop(); - this.options.sntpTimeSync = false; - this.sync.sntpActive = false; - }; - - /** - * @description Should use sntp time when sntpTimeSync specified in options, or else use Date.now() for time - * @returns {Number} - The time - * @author AJ Keller (@pushtheworldllc) - */ - OpenBCIBoard.prototype.time = function () { - if (this.options.sntpTimeSync) { - return this._sntpNow(); - } else { - return Date.now(); - } - }; - - /** - * @description This prints the total number of packets that were not able to be read - * @author AJ Keller (@pushtheworldllc) - */ - /* istanbul ignore next */ - OpenBCIBoard.prototype.printPacketsBad = function () { - if (this.badPackets > 1) { - console.log('Dropped a total of ' + this.badPackets + ' packets.'); - } else if (this.badPackets === 1) { - console.log('Dropped a total of 1 packet.'); - } else { - console.log('No packets dropped.'); - } - }; - - /** - * @description This prints the total bytes in - * @author AJ Keller (@pushtheworldllc) - */ - /* istanbul ignore next */ - OpenBCIBoard.prototype.printBytesIn = function () { - if (this.bytesIn > 1) { - console.log('Read in ' + this.bytesIn + ' bytes.'); - } else if (this.bytesIn === 1) { - console.log('Read one 1 packet in.'); - } else { - console.log('Read no packets.'); - } - }; - - /** - * @description This prints the total number of packets that have been read - * @author AJ Keller (@pushtheworldllc) - */ - /* istanbul ignore next */ - OpenBCIBoard.prototype.printPacketsRead = function () { - if (this.masterBuffer.packetsRead > 1) { - console.log('Read ' + this.masterBuffer.packetsRead + ' packets.'); - } else if (this.masterBuffer.packetsIn === 1) { - console.log('Read 1 packet.'); - } else { - console.log('No packets read.'); - } - }; - - /** - * @description Nice convenience method to print some session details - * @author AJ Keller (@pushtheworldllc) - */ - /* istanbul ignore next */ - OpenBCIBoard.prototype.debugSession = function () { - this.printBytesIn(); - this.printPacketsRead(); - this.printPacketsBad(); - }; - - /** - * @description To pretty print the info recieved on a Misc Register Query (printRegisterSettings) - * @param channelSettingsObj - */ - /* istanbul ignore next */ - OpenBCIBoard.prototype.debugPrintChannelSettings = function (channelSettingsObj) { - console.log('-- Channel Settings Object --'); - var powerState = 'OFF'; - if (channelSettingsObj.POWER_DOWN.toString().localeCompare('1')) { - powerState = 'ON'; - } - console.log('---- POWER STATE: ' + powerState); - console.log('-- END --'); - }; - - /** - * @description Quickly determine if a channel is on or off from a channelSettingObject. Most likely from a getChannelSettings call. - * @param channelSettingsObject - * @returns {boolean} - */ - OpenBCIBoard.prototype.channelIsOnFromChannelSettingsObject = function (channelSettingsObject) { - return channelSettingsObject.POWER_DOWN.toString().localeCompare('1') === 1; - }; - - // TODO: checkConnection (py: check_connection) - // TODO: reconnect (py: reconnect) - // TODO: testAuto - // TODO: getNbAUXChannels - // TODO: printIncomingText (py: print_incomming_text) - // TODO: warn - - factory.OpenBCIBoard = OpenBCIBoard; - factory.OpenBCIConstants = k; - factory.OpenBCISample = openBCISample; -} - -util.inherits(OpenBCIFactory, EventEmitter); - -module.exports = new OpenBCIFactory(); - -/** -* @description To parse a given channel given output from a print registers query -* @param rawChannelBuffer -* @example would be 'CH1SET 0x05, 0xFF, 1, 0, 0, 0, 0, 1, 0 -* @returns {Promise} -* @author AJ Keller (@pushtheworldllc) -*/ -// function getChannelSettingsObj (rawChannelBuffer) { -// return new Promise(function (resolve, reject) { -// if (rawChannelBuffer === undefined || rawChannelBuffer === null) { -// reject('Undefined or null channel buffer'); -// } -// -// var channelSettingsObject = { -// CHANNEL: '0', -// POWER_DOWN: '0', -// GAIN_SET: '0', -// INPUT_TYPE_SET: '0', -// BIAS_SET: '0', -// SRB2_SET: '0', -// SRB1_SET: '0' -// }; -// -// var bitsToSkip = 20; // CH1SET, 0x05, 0xE0 --> 20 bits -// var sizeOfData = rawChannelBuffer.byteLength; -// -// var objIndex = 0; -// for (var j = bitsToSkip; j < sizeOfData - 1; j += 3) { // every three bytes there is data -// switch (objIndex) { -// case 0: -// channelSettingsObject.POWER_DOWN = rawChannelBuffer.slice(j, j + 1).toString(); -// break; -// default: -// break; -// } -// -// objIndex++; -// } -// resolve(channelSettingsObject); -// }); -// } - -function masterBufferMaker () { - var masterBuf = new Buffer(k.OBCIMasterBufferSize); - masterBuf.fill(0); - return { // Buffer used to store bytes in and read packets from - buffer: masterBuf, - positionRead: 0, - positionWrite: 0, - packetsIn: 0, - packetsRead: 0, - looseBytes: 0 - }; -} diff --git a/openBCIConstants.js b/openBCIConstants.js deleted file mode 100644 index 3f83e29..0000000 --- a/openBCIConstants.js +++ /dev/null @@ -1,1212 +0,0 @@ -/** -* Created by ajk on 12/16/15. -* Purpose: This file folds all the constants for the -* OpenBCI Board -*/ -'use strict'; -/** Turning channels off */ -const obciChannelOff1 = '1'; -const obciChannelOff2 = '2'; -const obciChannelOff3 = '3'; -const obciChannelOff4 = '4'; -const obciChannelOff5 = '5'; -const obciChannelOff6 = '6'; -const obciChannelOff7 = '7'; -const obciChannelOff8 = '8'; -const obciChannelOff9 = 'q'; -const obciChannelOff10 = 'w'; -const obciChannelOff11 = 'e'; -const obciChannelOff12 = 'r'; -const obciChannelOff13 = 't'; -const obciChannelOff14 = 'y'; -const obciChannelOff15 = 'u'; -const obciChannelOff16 = 'i'; - -/** Turn channels on */ -const obciChannelOn1 = '!'; -const obciChannelOn2 = '@'; -const obciChannelOn3 = '#'; -const obciChannelOn4 = '$'; -const obciChannelOn5 = '%'; -const obciChannelOn6 = '^'; -const obciChannelOn7 = '&'; -const obciChannelOn8 = '*'; -const obciChannelOn9 = 'Q'; -const obciChannelOn10 = 'W'; -const obciChannelOn11 = 'E'; -const obciChannelOn12 = 'R'; -const obciChannelOn13 = 'T'; -const obciChannelOn14 = 'Y'; -const obciChannelOn15 = 'U'; -const obciChannelOn16 = 'I'; - -/** Test Signal Control Commands -* 1x - Voltage will be 1 * (VREFP - VREFN) / 2.4 mV -* 2x - Voltage will be 2 * (VREFP - VREFN) / 2.4 mV -*/ -const obciTestSignalConnectToDC = 'p'; -const obciTestSignalConnectToGround = '0'; -const obciTestSignalConnectToPulse1xFast = '='; -const obciTestSignalConnectToPulse1xSlow = '-'; -const obciTestSignalConnectToPulse2xFast = ']'; -const obciTestSignalConnectToPulse2xSlow = '['; - -/** Channel Setting Commands */ -const obciChannelCmdADCNormal = '0'; -const obciChannelCmdADCShorted = '1'; -const obciChannelCmdADCBiasDRP = '6'; -const obciChannelCmdADCBiasDRN = '7'; -const obciChannelCmdADCBiasMethod = '2'; -const obciChannelCmdADCMVDD = '3'; -const obciChannelCmdADCTemp = '4'; -const obciChannelCmdADCTestSig = '5'; -const obciChannelCmdBiasInclude = '1'; -const obciChannelCmdBiasRemove = '0'; -const obciChannelCmdChannel1 = '1'; -const obciChannelCmdChannel2 = '2'; -const obciChannelCmdChannel3 = '3'; -const obciChannelCmdChannel4 = '4'; -const obciChannelCmdChannel5 = '5'; -const obciChannelCmdChannel6 = '6'; -const obciChannelCmdChannel7 = '7'; -const obciChannelCmdChannel8 = '8'; -const obciChannelCmdChannel9 = 'Q'; -const obciChannelCmdChannel10 = 'W'; -const obciChannelCmdChannel11 = 'E'; -const obciChannelCmdChannel12 = 'R'; -const obciChannelCmdChannel13 = 'T'; -const obciChannelCmdChannel14 = 'Y'; -const obciChannelCmdChannel15 = 'U'; -const obciChannelCmdChannel16 = 'I'; -const obciChannelCmdGain1 = '0'; -const obciChannelCmdGain2 = '1'; -const obciChannelCmdGain4 = '2'; -const obciChannelCmdGain6 = '3'; -const obciChannelCmdGain8 = '4'; -const obciChannelCmdGain12 = '5'; -const obciChannelCmdGain24 = '6'; -const obciChannelCmdLatch = 'X'; -const obciChannelCmdPowerOff = '1'; -const obciChannelCmdPowerOn = '0'; -const obciChannelCmdSet = 'x'; -const obciChannelCmdSRB1Connect = '1'; -const obciChannelCmdSRB1Diconnect = '0'; -const obciChannelCmdSRB2Connect = '1'; -const obciChannelCmdSRB2Diconnect = '0'; - -/** Channel Setting Helper Strings */ -const obciStringADCNormal = 'normal'; -const obciStringADCShorted = 'shorted'; -const obciStringADCBiasMethod = 'biasMethod'; -const obciStringADCMvdd = 'mvdd'; -const obciStringADCTemp = 'temp'; -const obciStringADCTestSig = 'testSig'; -const obciStringADCBiasDrp = 'biasDrp'; -const obciStringADCBiasDrn = 'biasDrn'; - -/** Default Channel Settings */ -const obciChannelDefaultAllSet = 'd'; -const obciChannelDefaultAllGet = 'D'; - -/** LeadOff Impedance Commands */ -const obciChannelImpedanceLatch = 'Z'; -const obciChannelImpedanceSet = 'z'; -const obciChannelImpedanceTestSignalApplied = '1'; -const obciChannelImpedanceTestSignalAppliedNot = '0'; - -/** SD card Commands */ -const obciSDLogForHour1 = 'G'; -const obciSDLogForHour2 = 'H'; -const obciSDLogForHour4 = 'J'; -const obciSDLogForHour12 = 'K'; -const obciSDLogForHour24 = 'L'; -const obciSDLogForMin5 = 'A'; -const obciSDLogForMin15 = 'S'; -const obciSDLogForMin30 = 'F'; -const obciSDLogForSec14 = 'a'; -const obciSDLogStop = 'j'; - -/** SD Card String Commands */ -const obciStringSDHour1 = '1hour'; -const obciStringSDHour2 = '2hour'; -const obciStringSDHour4 = '4hour'; -const obciStringSDHour12 = '12hour'; -const obciStringSDHour24 = '24hour'; -const obciStringSDMin5 = '5min'; -const obciStringSDMin15 = '15min'; -const obciStringSDMin30 = '30min'; -const obciStringSDSec14 = '14sec'; - -/** Stream Data Commands */ -const obciStreamStart = 'b'; -const obciStreamStop = 's'; - -/** Miscellaneous */ -const obciMiscQueryRegisterSettings = '?'; -const obciMiscQueryRegisterSettingsChannel1 = 'CH1SET'; -const obciMiscQueryRegisterSettingsChannel2 = 'CH2SET'; -const obciMiscQueryRegisterSettingsChannel3 = 'CH3SET'; -const obciMiscQueryRegisterSettingsChannel4 = 'CH4SET'; -const obciMiscQueryRegisterSettingsChannel5 = 'CH5SET'; -const obciMiscQueryRegisterSettingsChannel6 = 'CH6SET'; -const obciMiscQueryRegisterSettingsChannel7 = 'CH7SET'; -const obciMiscQueryRegisterSettingsChannel8 = 'CH8SET'; -const obciMiscSoftReset = 'v'; - -/** 16 Channel Commands */ -const obciChannelMaxNumber8 = 'c'; -const obciChannelMaxNumber16 = 'C'; -const obciChannelMaxNumber8NoDaisyToRemove = ''; -const obciChannelMaxNumber8SuccessDaisyRemoved = 'daisy removed'; -const obciChannelMaxNumber16DaisyAlreadyAttached = '16'; -const obciChannelMaxNumber16DaisyAttached = 'daisy attached16'; -const obciChannelMaxNumber16NoDaisyAttached = 'no daisy to attach!8'; - -/** 60Hz line filter */ -const obciFilterDisable = 'g'; -const obciFilterEnable = 'f'; - -/** Triggers */ -const obciTrigger = '`'; - -/** Sync Clocks */ -const obciSyncTimeSet = '<'; -const obciSyncTimeSent = ','; - -/** Radio Key */ -const obciRadioKey = 0xF0; -/** Radio Commands */ -const obciRadioCmdChannelGet = 0x00; -const obciRadioCmdChannelSet = 0x01; -const obciRadioCmdChannelSetOverride = 0x02; -const obciRadioCmdPollTimeGet = 0x03; -const obciRadioCmdPollTimeSet = 0x04; -const obciRadioCmdBaudRateSetDefault = 0x05; -const obciRadioCmdBaudRateSetFast = 0x06; -const obciRadioCmdSystemStatus = 0x07; - -/** Possible number of channels */ -const obciNumberOfChannelsDaisy = 16; -const obciNumberOfChannelsDefault = 8; -const obciNumberOfChannelsGanglion = 4; - -/** Possible OpenBCI board types */ -const obciBoardDaisy = 'daisy'; -const obciBoardDefault = 'default'; -const obciBoardGanglion = 'ganglion'; - -/** Possible Simulator Line Noise injections */ -const obciSimulatorLineNoiseHz60 = '60Hz'; -const obciSimulatorLineNoiseHz50 = '50Hz'; -const obciSimulatorLineNoiseNone = 'none'; - -/** Possible Simulator Fragmentation modes */ -const obciSimulatorFragmentationRandom = 'random'; -const obciSimulatorFragmentationFullBuffers = 'fullBuffers'; -const obciSimulatorFragmentationOneByOne = 'oneByOne'; -const obciSimulatorFragmentationNone = 'none'; - -/** Possible Sample Rates */ -const obciSampleRate125 = 125; -const obciSampleRate250 = 250; - -/** Max sample number */ -const obciSampleNumberMax = 255; - -/** Packet Size */ -const obciPacketSize = 33; - -/** OpenBCI V3 Standard Packet Positions */ -/** -* 0:[startByte] | 1:[sampleNumber] | 2:[Channel-1.1] | 3:[Channel-1.2] | 4:[Channel-1.3] | 5:[Channel-2.1] | 6:[Channel-2.2] | 7:[Channel-2.3] | 8:[Channel-3.1] | 9:[Channel-3.2] | 10:[Channel-3.3] | 11:[Channel-4.1] | 12:[Channel-4.2] | 13:[Channel-4.3] | 14:[Channel-5.1] | 15:[Channel-5.2] | 16:[Channel-5.3] | 17:[Channel-6.1] | 18:[Channel-6.2] | 19:[Channel-6.3] | 20:[Channel-7.1] | 21:[Channel-7.2] | 22:[Channel-7.3] | 23:[Channel-8.1] | 24:[Channel-8.2] | 25:[Channel-8.3] | 26:[Aux-1.1] | 27:[Aux-1.2] | 28:[Aux-2.1] | 29:[Aux-2.2] | 30:[Aux-3.1] | 31:[Aux-3.2] | 32:StopByte -*/ -const obciPacketPositionChannelDataStart = 2; // 0:startByte | 1:sampleNumber | [2:4] | [5:7] | [8:10] | [11:13] | [14:16] | [17:19] | [21:23] | [24:26] -const obciPacketPositionChannelDataStop = 25; // 24 bytes for channel data -const obciPacketPositionSampleNumber = 1; -const obciPacketPositionStartByte = 0; // first byte -const obciPacketPositionStopByte = 32; // [32] -const obciPacketPositionStartAux = 26; // [26,27]:Aux 1 | [28,29]:Aux 2 | [30,31]:Aux 3 -const obciPacketPositionStopAux = 31; // - - - [30,31]:Aux 3 | 32: Stop byte -const obciPacketPositionTimeSyncAuxStart = 26; -const obciPacketPositionTimeSyncAuxStop = 28; -const obciPacketPositionTimeSyncTimeStart = 28; -const obciPacketPositionTimeSyncTimeStop = 32; - -/** Notable Bytes */ -const obciByteStart = 0xA0; -const obciByteStop = 0xC0; - -/** Errors */ -const errorInvalidByteLength = 'Invalid Packet Byte Length'; -const errorInvalidByteStart = 'Invalid Start Byte'; -const errorInvalidByteStop = 'Invalid Stop Byte'; -const errorTimeSyncIsNull = "'this.sync.curSyncObj' must not be null"; -const errorTimeSyncNoComma = 'Missed the time sync sent confirmation. Try sync again'; -const errorUndefinedOrNullInput = 'Undefined or Null Input'; - -/** Max Master Buffer Size */ -const obciMasterBufferSize = 4096; - -/** Impedance Calculation Variables */ -const obciLeadOffDriveInAmps = 0.000000006; -const obciLeadOffFrequencyHz = 31.5; - -/** Command send delay */ -const obciWriteIntervalDelayMSLong = 50; -const obciWriteIntervalDelayMSNone = 0; -const obciWriteIntervalDelayMSShort = 10; - -/** Impedance */ -const obciImpedanceTextBad = 'bad'; -const obciImpedanceTextNone = 'none'; -const obciImpedanceTextGood = 'good'; -const obciImpedanceTextInit = 'init'; -const obciImpedanceTextOk = 'ok'; - -const obciImpedanceThresholdGoodMin = 0; -const obciImpedanceThresholdGoodMax = 5000; -const obciImpedanceThresholdOkMin = 5001; -const obciImpedanceThresholdOkMax = 10000; -const obciImpedanceThresholdBadMin = 10001; -const obciImpedanceThresholdBadMax = 1000000; - -const obciImpedanceSeriesResistor = 2200; // There is a 2.2 k Ohm series resistor that must be subtracted - -/** Simulator */ -const obciSimulatorPortName = 'OpenBCISimulator'; - -/** -* Stream packet types/codes -*/ -const obciStreamPacketStandardAccel = 0; // 0000 -const obciStreamPacketStandardRawAux = 1; // 0001 -const obciStreamPacketUserDefinedType = 2; // 0010 -const obciStreamPacketAccelTimeSyncSet = 3; // 0011 -const obciStreamPacketAccelTimeSynced = 4; // 0100 -const obciStreamPacketRawAuxTimeSyncSet = 5; // 0101 -const obciStreamPacketRawAuxTimeSynced = 6; // 0110 - -/** Time from board */ -const obciStreamPacketTimeByteSize = 4; - -/** Time synced with accel packet */ -const obciAccelAxisX = 7; -const obciAccelAxisY = 8; -const obciAccelAxisZ = 9; - -/** Firmware version indicator */ -const obciFirmwareV1 = 'v1'; -const obciFirmwareV2 = 'v2'; - -/** Parse */ -const obciParseDaisy = 'Daisy'; -const obciParseFirmware = 'v2'; -const obciParseFailure = 'Failure'; -const obciParseEOT = '$$$'; -const obciParseSuccess = 'Success'; - -/** Used in parsing incoming serial data */ -const obciParsingChannelSettings = 2; -const obciParsingEOT = 4; -const obciParsingNormal = 3; -const obciParsingReset = 0; -const obciParsingTimeSyncSent = 1; - -/** Timeouts */ -const obciTimeoutProcessBytes = 500; // 0.5 seconds - -/** Simulator Board Configurations */ -const obciSimulatorRawAux = 'rawAux'; -const obciSimulatorStandard = 'standard'; - -/** OpenBCI Radio Limits */ -const obciRadioChannelMax = 25; -const obciRadioChannelMin = 1; -const obciRadioPollTimeMax = 255; -const obciRadioPollTimeMin = 0; - -/** Time sync stuff */ -const obciTimeSyncArraySize = 10; -const obciTimeSyncMultiplierWithSyncConf = 0.9; -const obciTimeSyncMultiplierWithoutSyncConf = 0.75; -const obciTimeSyncThresholdTransFailureMS = 10; // ms - -/** Baud Rates */ -const obciRadioBaudRateDefault = 115200; -const obciRadioBaudRateDefaultStr = 'default'; -const obciRadioBaudRateFast = 230400; -const obciRadioBaudRateFastStr = 'fast'; - -/** Emitters */ -const obciEmitterClose = 'close'; -const obciEmitterDroppedPacket = 'droppedPacket'; -const obciEmitterEot = 'eot'; -const obciEmitterError = 'error'; -const obciEmitterHardSet = 'hardSet'; -const obciEmitterImpedanceArray = 'impedanceArray'; -const obciEmitterQuery = 'query'; -const obciEmitterRawDataPacket = 'rawDataPacket'; -const obciEmitterReady = 'ready'; -const obciEmitterSample = 'sample'; -const obciEmitterSynced = 'synced'; - -module.exports = { - /** Turning channels off */ - OBCIChannelOff1: obciChannelOff1, - OBCIChannelOff2: obciChannelOff2, - OBCIChannelOff3: obciChannelOff3, - OBCIChannelOff4: obciChannelOff4, - OBCIChannelOff5: obciChannelOff5, - OBCIChannelOff6: obciChannelOff6, - OBCIChannelOff7: obciChannelOff7, - OBCIChannelOff8: obciChannelOff8, - OBCIChannelOff9: obciChannelOff9, - OBCIChannelOff10: obciChannelOff10, - OBCIChannelOff11: obciChannelOff11, - OBCIChannelOff12: obciChannelOff12, - OBCIChannelOff13: obciChannelOff13, - OBCIChannelOff14: obciChannelOff14, - OBCIChannelOff15: obciChannelOff15, - OBCIChannelOff16: obciChannelOff16, - /** - * Purpose: To get the proper command to turn a channel off - * @param channelNumber - A number (1-16) of the desired channel - * @returns {Promise} - */ - commandChannelOff: function (channelNumber) { - return new Promise(function (resolve, reject) { - switch (channelNumber) { - case 1: - resolve(obciChannelOff1); - break; - case 2: - resolve(obciChannelOff2); - break; - case 3: - resolve(obciChannelOff3); - break; - case 4: - resolve(obciChannelOff4); - break; - case 5: - resolve(obciChannelOff5); - break; - case 6: - resolve(obciChannelOff6); - break; - case 7: - resolve(obciChannelOff7); - break; - case 8: - resolve(obciChannelOff8); - break; - case 9: - resolve(obciChannelOff9); - break; - case 10: - resolve(obciChannelOff10); - break; - case 11: - resolve(obciChannelOff11); - break; - case 12: - resolve(obciChannelOff12); - break; - case 13: - resolve(obciChannelOff13); - break; - case 14: - resolve(obciChannelOff14); - break; - case 15: - resolve(obciChannelOff15); - break; - case 16: - resolve(obciChannelOff16); - break; - default: - reject('Error [commandChannelOff]: Invalid Channel Number'); - break; - } - }); - }, - /** Turning channels on */ - OBCIChannelOn1: obciChannelOn1, - OBCIChannelOn2: obciChannelOn2, - OBCIChannelOn3: obciChannelOn3, - OBCIChannelOn4: obciChannelOn4, - OBCIChannelOn5: obciChannelOn5, - OBCIChannelOn6: obciChannelOn6, - OBCIChannelOn7: obciChannelOn7, - OBCIChannelOn8: obciChannelOn8, - OBCIChannelOn9: obciChannelOn9, - OBCIChannelOn10: obciChannelOn10, - OBCIChannelOn11: obciChannelOn11, - OBCIChannelOn12: obciChannelOn12, - OBCIChannelOn13: obciChannelOn13, - OBCIChannelOn14: obciChannelOn14, - OBCIChannelOn15: obciChannelOn15, - OBCIChannelOn16: obciChannelOn16, - commandChannelOn: function (channelNumber) { - return new Promise(function (resolve, reject) { - switch (channelNumber) { - case 1: - resolve(obciChannelOn1); - break; - case 2: - resolve(obciChannelOn2); - break; - case 3: - resolve(obciChannelOn3); - break; - case 4: - resolve(obciChannelOn4); - break; - case 5: - resolve(obciChannelOn5); - break; - case 6: - resolve(obciChannelOn6); - break; - case 7: - resolve(obciChannelOn7); - break; - case 8: - resolve(obciChannelOn8); - break; - case 9: - resolve(obciChannelOn9); - break; - case 10: - resolve(obciChannelOn10); - break; - case 11: - resolve(obciChannelOn11); - break; - case 12: - resolve(obciChannelOn12); - break; - case 13: - resolve(obciChannelOn13); - break; - case 14: - resolve(obciChannelOn14); - break; - case 15: - resolve(obciChannelOn15); - break; - case 16: - resolve(obciChannelOn16); - break; - default: - reject('Error [commandChannelOn]: Invalid Channel Number'); - break; - } - }); - }, - /** Test Signal Control Commands */ - OBCITestSignalConnectToDC: obciTestSignalConnectToDC, - OBCITestSignalConnectToGround: obciTestSignalConnectToGround, - OBCITestSignalConnectToPulse1xFast: obciTestSignalConnectToPulse1xFast, - OBCITestSignalConnectToPulse1xSlow: obciTestSignalConnectToPulse1xSlow, - OBCITestSignalConnectToPulse2xFast: obciTestSignalConnectToPulse2xFast, - OBCITestSignalConnectToPulse2xSlow: obciTestSignalConnectToPulse2xSlow, - getTestSignalCommand: (signal) => { - return new Promise((resolve, reject) => { - switch (signal) { - case 'dc': - resolve(obciTestSignalConnectToDC); - break; - case 'ground': - resolve(obciTestSignalConnectToGround); - break; - case 'pulse1xFast': - resolve(obciTestSignalConnectToPulse1xFast); - break; - case 'pulse1xSlow': - resolve(obciTestSignalConnectToPulse1xSlow); - break; - case 'pulse2xFast': - resolve(obciTestSignalConnectToPulse2xFast); - break; - case 'pulse2xSlow': - resolve(obciTestSignalConnectToPulse2xSlow); - break; - case 'none': - resolve(obciChannelDefaultAllSet); - break; - default: - reject('Invalid selection! Check your spelling.'); - break; - } - }); - }, - /** Channel Setting Commands */ - OBCIChannelCmdADCNormal: obciChannelCmdADCNormal, - OBCIChannelCmdADCShorted: obciChannelCmdADCShorted, - OBCIChannelCmdADCBiasDRP: obciChannelCmdADCBiasDRP, - OBCIChannelCmdADCBiasDRN: obciChannelCmdADCBiasDRN, - OBCIChannelCmdADCBiasMethod: obciChannelCmdADCBiasMethod, - OBCIChannelCmdADCMVDD: obciChannelCmdADCMVDD, - OBCIChannelCmdADCTemp: obciChannelCmdADCTemp, - OBCIChannelCmdADCTestSig: obciChannelCmdADCTestSig, - OBCIChannelCmdBiasInclude: obciChannelCmdBiasInclude, - OBCIChannelCmdBiasRemove: obciChannelCmdBiasRemove, - OBCIChannelCmdChannel1: obciChannelCmdChannel1, - OBCIChannelCmdChannel2: obciChannelCmdChannel2, - OBCIChannelCmdChannel3: obciChannelCmdChannel3, - OBCIChannelCmdChannel4: obciChannelCmdChannel4, - OBCIChannelCmdChannel5: obciChannelCmdChannel5, - OBCIChannelCmdChannel6: obciChannelCmdChannel6, - OBCIChannelCmdChannel7: obciChannelCmdChannel7, - OBCIChannelCmdChannel8: obciChannelCmdChannel8, - OBCIChannelCmdChannel9: obciChannelCmdChannel9, - OBCIChannelCmdChannel10: obciChannelCmdChannel10, - OBCIChannelCmdChannel11: obciChannelCmdChannel11, - OBCIChannelCmdChannel12: obciChannelCmdChannel12, - OBCIChannelCmdChannel13: obciChannelCmdChannel13, - OBCIChannelCmdChannel14: obciChannelCmdChannel14, - OBCIChannelCmdChannel15: obciChannelCmdChannel15, - OBCIChannelCmdChannel16: obciChannelCmdChannel16, - commandChannelForCmd, - OBCIChannelCmdGain1: obciChannelCmdGain1, - OBCIChannelCmdGain2: obciChannelCmdGain2, - OBCIChannelCmdGain4: obciChannelCmdGain4, - OBCIChannelCmdGain6: obciChannelCmdGain6, - OBCIChannelCmdGain8: obciChannelCmdGain8, - OBCIChannelCmdGain12: obciChannelCmdGain12, - OBCIChannelCmdGain24: obciChannelCmdGain24, - commandForGain, - OBCIChannelCmdLatch: obciChannelCmdLatch, - OBCIChannelCmdPowerOff: obciChannelCmdPowerOff, - OBCIChannelCmdPowerOn: obciChannelCmdPowerOn, - OBCIChannelCmdSet: obciChannelCmdSet, - OBCIChannelCmdSRB1Connect: obciChannelCmdSRB1Connect, - OBCIChannelCmdSRB1Diconnect: obciChannelCmdSRB1Diconnect, - OBCIChannelCmdSRB2Connect: obciChannelCmdSRB2Connect, - OBCIChannelCmdSRB2Diconnect: obciChannelCmdSRB2Diconnect, - /** Channel Settings Object */ - channelSettingsObjectDefault, - channelSettingsArrayInit: (numberOfChannels) => { - var newChannelSettingsArray = []; - for (var i = 0; i < numberOfChannels; i++) { - newChannelSettingsArray.push(channelSettingsObjectDefault(i)); - } - return newChannelSettingsArray; - }, - /** Channel Setting Helper Strings */ - OBCIStringADCNormal: obciStringADCNormal, - OBCIStringADCShorted: obciStringADCShorted, - OBCIStringADCBiasMethod: obciStringADCBiasMethod, - OBCIStringADCMvdd: obciStringADCMvdd, - OBCIStringADCTemp: obciStringADCTemp, - OBCIStringADCTestSig: obciStringADCTestSig, - OBCIStringADCBiasDrp: obciStringADCBiasDrp, - OBCIStringADCBiasDrn: obciStringADCBiasDrn, - /** - * @description To convert a string like 'normal' to the correct command (i.e. '1') - * @param adcString - * @returns {Promise} - * @author AJ Keller (@pushtheworldllc) - */ - commandForADCString, - /** Default Channel Settings */ - OBCIChannelDefaultAllSet: obciChannelDefaultAllSet, - OBCIChannelDefaultAllGet: obciChannelDefaultAllGet, - /** LeadOff Impedance Commands */ - OBCIChannelImpedanceLatch: obciChannelImpedanceLatch, - OBCIChannelImpedanceSet: obciChannelImpedanceSet, - OBCIChannelImpedanceTestSignalApplied: obciChannelImpedanceTestSignalApplied, - OBCIChannelImpedanceTestSignalAppliedNot: obciChannelImpedanceTestSignalAppliedNot, - /** SD card Commands */ - OBCISDLogForHour1: obciSDLogForHour1, - OBCISDLogForHour2: obciSDLogForHour2, - OBCISDLogForHour4: obciSDLogForHour4, - OBCISDLogForHour12: obciSDLogForHour12, - OBCISDLogForHour24: obciSDLogForHour24, - OBCISDLogForMin5: obciSDLogForMin5, - OBCISDLogForMin15: obciSDLogForMin15, - OBCISDLogForMin30: obciSDLogForMin30, - OBCISDLogForSec14: obciSDLogForSec14, - OBCISDLogStop: obciSDLogStop, - /** SD Card String Commands */ - OBCIStringSDHour1: obciStringSDHour1, - OBCIStringSDHour2: obciStringSDHour2, - OBCIStringSDHour4: obciStringSDHour4, - OBCIStringSDHour12: obciStringSDHour12, - OBCIStringSDHour24: obciStringSDHour24, - OBCIStringSDMin5: obciStringSDMin5, - OBCIStringSDMin15: obciStringSDMin15, - OBCIStringSDMin30: obciStringSDMin30, - OBCIStringSDSec14: obciStringSDSec14, - /** - * @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 obciStringSDHour1: - resolve(obciSDLogForHour1); - break; - case obciStringSDHour2: - resolve(obciSDLogForHour2); - break; - case obciStringSDHour4: - resolve(obciSDLogForHour4); - break; - case obciStringSDHour12: - resolve(obciSDLogForHour12); - break; - case obciStringSDHour24: - resolve(obciSDLogForHour24); - break; - case obciStringSDMin5: - resolve(obciSDLogForMin5); - break; - case obciStringSDMin15: - resolve(obciSDLogForMin15); - break; - case obciStringSDMin30: - resolve(obciSDLogForMin30); - break; - case obciStringSDSec14: - resolve(obciSDLogForSec14); - break; - default: - reject(new Error(TypeError)); - break; - - } - }); - }, - /** Stream Data Commands */ - OBCIStreamStart: obciStreamStart, - OBCIStreamStop: obciStreamStop, - /** Miscellaneous */ - OBCIMiscQueryRegisterSettings: obciMiscQueryRegisterSettings, - OBCIMiscQueryRegisterSettingsChannel1: obciMiscQueryRegisterSettingsChannel1, - OBCIMiscQueryRegisterSettingsChannel2: obciMiscQueryRegisterSettingsChannel2, - OBCIMiscQueryRegisterSettingsChannel3: obciMiscQueryRegisterSettingsChannel3, - OBCIMiscQueryRegisterSettingsChannel4: obciMiscQueryRegisterSettingsChannel4, - OBCIMiscQueryRegisterSettingsChannel5: obciMiscQueryRegisterSettingsChannel5, - OBCIMiscQueryRegisterSettingsChannel6: obciMiscQueryRegisterSettingsChannel6, - OBCIMiscQueryRegisterSettingsChannel7: obciMiscQueryRegisterSettingsChannel7, - OBCIMiscQueryRegisterSettingsChannel8: obciMiscQueryRegisterSettingsChannel8, - channelSettingsKeyForChannel: channelNumber => { - return new Promise((resolve, reject) => { - switch (channelNumber) { - case 1: - resolve(new Buffer(obciMiscQueryRegisterSettingsChannel1)); - break; - case 2: - resolve(new Buffer(obciMiscQueryRegisterSettingsChannel2)); - break; - case 3: - resolve(new Buffer(obciMiscQueryRegisterSettingsChannel3)); - break; - case 4: - resolve(new Buffer(obciMiscQueryRegisterSettingsChannel4)); - break; - case 5: - resolve(new Buffer(obciMiscQueryRegisterSettingsChannel5)); - break; - case 6: - resolve(new Buffer(obciMiscQueryRegisterSettingsChannel6)); - break; - case 7: - resolve(new Buffer(obciMiscQueryRegisterSettingsChannel7)); - break; - case 8: - resolve(new Buffer(obciMiscQueryRegisterSettingsChannel8)); - break; - default: - reject('Invalid channel number'); - break; - } - }); - }, - OBCIMiscSoftReset: obciMiscSoftReset, - /** 16 Channel Commands */ - OBCIChannelMaxNumber8: obciChannelMaxNumber8, - OBCIChannelMaxNumber16: obciChannelMaxNumber16, - OBCIChannelMaxNumber8NoDaisyToRemove: obciChannelMaxNumber8NoDaisyToRemove, - OBCIChannelMaxNumber8SuccessDaisyRemoved: obciChannelMaxNumber8SuccessDaisyRemoved, - OBCIChannelMaxNumber16DaisyAlreadyAttached: obciChannelMaxNumber16DaisyAlreadyAttached, - OBCIChannelMaxNumber16DaisyAttached: obciChannelMaxNumber16DaisyAttached, - OBCIChannelMaxNumber16NoDaisyAttached: obciChannelMaxNumber16NoDaisyAttached, - /** Filters */ - OBCIFilterDisable: obciFilterDisable, - OBCIFilterEnable: obciFilterEnable, - /** Triggers */ - OBCITrigger: obciTrigger, - /** Possible number of channels */ - OBCINumberOfChannelsDaisy: obciNumberOfChannelsDaisy, - OBCINumberOfChannelsDefault: obciNumberOfChannelsDefault, - OBCINumberOfChannelsGanglion: obciNumberOfChannelsGanglion, - /** Possible OpenBCI board types */ - OBCIBoardDaisy: obciBoardDaisy, - OBCIBoardDefault: obciBoardDefault, - OBCIBoardGanglion: obciBoardGanglion, - numberOfChannelsForBoardType: boardType => { - switch (boardType) { - case obciBoardDaisy: - return obciNumberOfChannelsDaisy; - case obciBoardGanglion: - return obciNumberOfChannelsGanglion; - default: - return obciNumberOfChannelsDefault; - } - }, - /** Possible Sample Rates */ - OBCISampleRate125: obciSampleRate125, - OBCISampleRate250: obciSampleRate250, - /** Max sample number */ - OBCISampleNumberMax: obciSampleNumberMax, - /** Packet Size */ - OBCIPacketSize: obciPacketSize, - /** Notable Bytes */ - OBCIByteStart: obciByteStart, - OBCIByteStop: obciByteStop, - /** Errors */ - OBCIErrorInvalidByteLength: errorInvalidByteLength, - OBCIErrorInvalidByteStart: errorInvalidByteStart, - OBCIErrorInvalidByteStop: errorInvalidByteStop, - OBCIErrorTimeSyncIsNull: errorTimeSyncIsNull, - OBCIErrorTimeSyncNoComma: errorTimeSyncNoComma, - OBCIErrorUndefinedOrNullInput: errorUndefinedOrNullInput, - /** Max Master Buffer Size */ - OBCIMasterBufferSize: obciMasterBufferSize, - /** Impedance Calculation Variables */ - OBCILeadOffDriveInAmps: obciLeadOffDriveInAmps, - OBCILeadOffFrequencyHz: obciLeadOffFrequencyHz, - /** Channel Setter Maker */ - getChannelSetter: channelSetter, - /** Impedance Setter Maker */ - getImpedanceSetter: impedanceSetter, - /** Command send delay */ - OBCIWriteIntervalDelayMSLong: obciWriteIntervalDelayMSLong, - OBCIWriteIntervalDelayMSNone: obciWriteIntervalDelayMSNone, - OBCIWriteIntervalDelayMSShort: obciWriteIntervalDelayMSShort, - /** Sync Clocks */ - OBCISyncTimeSent: obciSyncTimeSent, - OBCISyncTimeSet: obciSyncTimeSet, - /** Radio Key */ - OBCIRadioKey: obciRadioKey, - /** Radio Commands */ - OBCIRadioCmdChannelGet: obciRadioCmdChannelGet, - OBCIRadioCmdChannelSet: obciRadioCmdChannelSet, - OBCIRadioCmdChannelSetOverride: obciRadioCmdChannelSetOverride, - OBCIRadioCmdPollTimeGet: obciRadioCmdPollTimeGet, - OBCIRadioCmdPollTimeSet: obciRadioCmdPollTimeSet, - OBCIRadioCmdBaudRateSetDefault: obciRadioCmdBaudRateSetDefault, - OBCIRadioCmdBaudRateSetFast: obciRadioCmdBaudRateSetFast, - OBCIRadioCmdSystemStatus: obciRadioCmdSystemStatus, - /** Impedance */ - OBCIImpedanceTextBad: obciImpedanceTextBad, - OBCIImpedanceTextGood: obciImpedanceTextGood, - OBCIImpedanceTextInit: obciImpedanceTextInit, - OBCIImpedanceTextOk: obciImpedanceTextOk, - OBCIImpedanceTextNone: obciImpedanceTextNone, - OBCIImpedanceThresholdBadMax: obciImpedanceThresholdBadMax, - OBCIImpedanceSeriesResistor: obciImpedanceSeriesResistor, - getTextForRawImpedance: (value) => { - if (value > obciImpedanceThresholdGoodMin && value < obciImpedanceThresholdGoodMax) { - return obciImpedanceTextGood; - } else if (value > obciImpedanceThresholdOkMin && value < obciImpedanceThresholdOkMax) { - return obciImpedanceTextOk; - } else if (value > obciImpedanceThresholdBadMin && value < obciImpedanceThresholdBadMax) { - return obciImpedanceTextBad; - } else { - return obciImpedanceTextNone; - } - }, - /** Simulator */ - OBCISimulatorPortName: obciSimulatorPortName, - /** - * Stream packet types/codes - */ - OBCIStreamPacketStandardAccel: obciStreamPacketStandardAccel, - OBCIStreamPacketStandardRawAux: obciStreamPacketStandardRawAux, - OBCIStreamPacketUserDefinedType: obciStreamPacketUserDefinedType, - OBCIStreamPacketAccelTimeSyncSet: obciStreamPacketAccelTimeSyncSet, - OBCIStreamPacketAccelTimeSynced: obciStreamPacketAccelTimeSynced, - OBCIStreamPacketRawAuxTimeSyncSet: obciStreamPacketRawAuxTimeSyncSet, - OBCIStreamPacketRawAuxTimeSynced: obciStreamPacketRawAuxTimeSynced, - /** fun funcs */ - isNumber, - isBoolean, - isString, - isUndefined, - isNull, - /** OpenBCI V3 Standard Packet Positions */ - OBCIPacketPositionStartByte: obciPacketPositionStartByte, - OBCIPacketPositionStopByte: obciPacketPositionStopByte, - OBCIPacketPositionStartAux: obciPacketPositionStartAux, - OBCIPacketPositionStopAux: obciPacketPositionStopAux, - OBCIPacketPositionChannelDataStart: obciPacketPositionChannelDataStart, - OBCIPacketPositionChannelDataStop: obciPacketPositionChannelDataStop, - OBCIPacketPositionSampleNumber: obciPacketPositionSampleNumber, - OBCIPacketPositionTimeSyncAuxStart: obciPacketPositionTimeSyncAuxStart, - OBCIPacketPositionTimeSyncAuxStop: obciPacketPositionTimeSyncAuxStop, - OBCIPacketPositionTimeSyncTimeStart: obciPacketPositionTimeSyncTimeStart, - OBCIPacketPositionTimeSyncTimeStop: obciPacketPositionTimeSyncTimeStop, - /** Possible Simulator Line Noise injections */ - OBCISimulatorLineNoiseHz60: obciSimulatorLineNoiseHz60, - OBCISimulatorLineNoiseHz50: obciSimulatorLineNoiseHz50, - OBCISimulatorLineNoiseNone: obciSimulatorLineNoiseNone, - /** Possible Simulator Fragmentation modes */ - OBCISimulatorFragmentationRandom: obciSimulatorFragmentationRandom, - OBCISimulatorFragmentationFullBuffers: obciSimulatorFragmentationFullBuffers, - OBCISimulatorFragmentationOneByOne: obciSimulatorFragmentationOneByOne, - OBCISimulatorFragmentationNone: obciSimulatorFragmentationNone, - /** Firmware version indicator */ - OBCIFirmwareV1: obciFirmwareV1, - OBCIFirmwareV2: obciFirmwareV2, - /** Time synced accel packet */ - OBCIAccelAxisX: obciAccelAxisX, - OBCIAccelAxisY: obciAccelAxisY, - OBCIAccelAxisZ: obciAccelAxisZ, - /** Time from board */ - OBCIStreamPacketTimeByteSize: obciStreamPacketTimeByteSize, - /** Parse */ - OBCIParseDaisy: obciParseDaisy, - OBCIParseFailure: obciParseFailure, - OBCIParseFirmware: obciParseFirmware, - OBCIParseEOT: obciParseEOT, - OBCIParseSuccess: obciParseSuccess, - /** Used in parsing incoming serial data */ - OBCIParsingChannelSettings: obciParsingChannelSettings, - OBCIParsingEOT: obciParsingEOT, - OBCIParsingNormal: obciParsingNormal, - OBCIParsingReset: obciParsingReset, - OBCIParsingTimeSyncSent: obciParsingTimeSyncSent, - /** Timeouts */ - OBCITimeoutProcessBytes: obciTimeoutProcessBytes, - /** Simulator Board Configurations */ - OBCISimulatorRawAux: obciSimulatorRawAux, - OBCISimulatorStandard: obciSimulatorStandard, - /** Radio Channel Limits */ - OBCIRadioChannelMax: obciRadioChannelMax, - OBCIRadioChannelMin: obciRadioChannelMin, - OBCIRadioPollTimeMax: obciRadioPollTimeMax, - OBCIRadioPollTimeMin: obciRadioPollTimeMin, - /** Time sync stuff */ - OBCITimeSyncArraySize: obciTimeSyncArraySize, - OBCITimeSyncMultiplierWithSyncConf: obciTimeSyncMultiplierWithSyncConf, - OBCITimeSyncMultiplierWithoutSyncConf: obciTimeSyncMultiplierWithoutSyncConf, - OBCITimeSyncThresholdTransFailureMS: obciTimeSyncThresholdTransFailureMS, - /** Baud Rates */ - OBCIRadioBaudRateDefault: obciRadioBaudRateDefault, - OBCIRadioBaudRateDefaultStr: obciRadioBaudRateDefaultStr, - OBCIRadioBaudRateFast: obciRadioBaudRateFast, - OBCIRadioBaudRateFastStr: obciRadioBaudRateFastStr, - getVersionNumber, - /** Emitters */ - OBCIEmitterClose: obciEmitterClose, - OBCIEmitterDroppedPacket: obciEmitterDroppedPacket, - OBCIEmitterEot: obciEmitterEot, - OBCIEmitterError: obciEmitterError, - OBCIEmitterHardSet: obciEmitterHardSet, - OBCIEmitterImpedanceArray: obciEmitterImpedanceArray, - OBCIEmitterQuery: obciEmitterQuery, - OBCIEmitterRawDataPacket: obciEmitterRawDataPacket, - OBCIEmitterReady: obciEmitterReady, - OBCIEmitterSample: obciEmitterSample, - OBCIEmitterSynced: obciEmitterSynced -}; - -/** -* @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. -* @param channelNumber - Number (1-16) -* @param powerDown - Bool (true -> OFF, false -> ON (default)) -* turns the channel on or off -* @param gain - Number (1,2,4,6,8,12,24(default)) -* sets the gain for the channel -* @param inputType - String (normal,shorted,biasMethod,mvdd,temp,testsig,biasDrp,biasDrn) -* selects the ADC channel input source -* @param bias - Bool (true -> Include in bias (default), false -> remove from bias) -* selects to include the channel input in bias generation -* @param srb2 - Bool (true -> Connect this input to SRB2 (default), -* false -> Disconnect this input from SRB2) -* Select to connect (true) this channel's P input to the SRB2 pin. This closes -* a switch between P input and SRB2 for the given channel, and allows the -* P input to also remain connected to the ADC. -* @param srb1 - Bool (true -> connect all N inputs to SRB1, -* false -> Disconnect all N inputs from SRB1 (default)) -* Select to connect (true) all channels' N inputs to SRB1. This effects all pins, -* and disconnects all N inputs from the ADC. -* @returns {Promise} resolves {commandArray: array of commands to be sent, - newChannelSettingsObject: an updated channel settings object - to be stored in openBCIBoard.channelSettingsArray}, - rejects on bad input or no board -*/ -function channelSetter (channelNumber, powerDown, gain, inputType, bias, srb2, srb1) { - // Used to store and assemble the commands - var cmdPowerDown, - cmdBias, - cmdSrb2, - cmdSrb1; - - return new Promise(function (resolve, reject) { - // Validate the input - 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(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) - .catch(err => reject(err)); - - // Set POWER_DOWN - cmdPowerDown = powerDown ? obciChannelCmdPowerOff : obciChannelCmdPowerOn; - - // Set Gain - var p2 = commandForGain(gain) - .catch(err => reject(err)); - - // Set ADC string - var p3 = commandForADCString(inputType) - .catch(err => reject(err)); - - // Set BIAS - cmdBias = bias ? obciChannelCmdBiasInclude : obciChannelCmdBiasRemove; - - // Set SRB2 - cmdSrb2 = srb2 ? obciChannelCmdSRB2Connect : obciChannelCmdSRB2Diconnect; - - // Set SRB1 - cmdSrb1 = srb1 ? obciChannelCmdSRB1Connect : obciChannelCmdSRB1Diconnect; - - var newChannelSettingsObject = { - channelNumber: channelNumber, - powerDown: powerDown, - gain: gain, - inputType: inputType, - bias: bias, - srb2: srb2, - srb1: srb1 - }; - - Promise.all([p1, p2, p3]).then(function (values) { - var outputArray = [ - obciChannelCmdSet, - values[0], - cmdPowerDown, - values[1], - values[2], - cmdBias, - cmdSrb2, - cmdSrb1, - obciChannelCmdLatch - ]; - resolve({commandArray: outputArray, newChannelSettingsObject: newChannelSettingsObject}); - }); - }); -} - -/** -* @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 -* @param nInputApplied - Bool (true -> Test Signal Applied, false -> Test Signal Not Applied (default)) -* applies the test signal to the N input -* @returns {Promise} - fulfilled will contain an array of comamnds -*/ -function impedanceSetter (channelNumber, pInputApplied, nInputApplied) { - var cmdNInputApplied, - cmdPInputApplied; - return new Promise((resolve, reject) => { - // validate inputs - if (!isNumber(channelNumber)) reject("channelNumber must be of type 'number' "); - if (!isBoolean(pInputApplied)) reject("pInputApplied must be of type 'boolean' "); - if (!isBoolean(nInputApplied)) reject("nInputApplied must be of type 'boolean' "); - - // Set pInputApplied - cmdPInputApplied = pInputApplied ? obciChannelImpedanceTestSignalApplied : obciChannelImpedanceTestSignalAppliedNot; - - // Set nInputApplied - cmdNInputApplied = nInputApplied ? obciChannelImpedanceTestSignalApplied : obciChannelImpedanceTestSignalAppliedNot; - - // Set Channel Number - commandChannelForCmd(channelNumber).then(command => { - var outputArray = [ - obciChannelImpedanceSet, - command, - cmdPInputApplied, - cmdNInputApplied, - obciChannelImpedanceLatch - ]; - // console.log(outputArray) - resolve(outputArray); - }).catch(err => reject(err)); - }); -} - -function isNumber (input) { - return (typeof input === 'number'); -} -function isBoolean (input) { - return (typeof input === 'boolean'); -} -function isString (input) { - return (typeof input === 'string'); -} -function isUndefined (input) { - return (typeof input === 'undefined'); -} -function isNull (input) { - return input === null; -} - -function commandForADCString (adcString) { - return new Promise(function (resolve, reject) { - switch (adcString) { - case obciStringADCNormal: - resolve(obciChannelCmdADCNormal); - break; - case obciStringADCShorted: - resolve(obciChannelCmdADCShorted); - break; - case obciStringADCBiasMethod: - resolve(obciChannelCmdADCBiasMethod); - break; - case obciStringADCMvdd: - resolve(obciChannelCmdADCMVDD); - break; - case obciStringADCTemp: - resolve(obciChannelCmdADCTemp); - break; - case obciStringADCTestSig: - resolve(obciChannelCmdADCTestSig); - break; - case obciStringADCBiasDrp: - resolve(obciChannelCmdADCBiasDRP); - break; - case obciStringADCBiasDrn: - resolve(obciChannelCmdADCBiasDRN); - break; - default: - reject('Invalid ADC string'); - break; - } - }); -} - -function commandForGain (gainSetting) { - return new Promise(function (resolve, reject) { - switch (gainSetting) { - case 1: - resolve(obciChannelCmdGain1); - break; - case 2: - resolve(obciChannelCmdGain2); - break; - case 4: - resolve(obciChannelCmdGain4); - break; - case 6: - resolve(obciChannelCmdGain6); - break; - case 8: - resolve(obciChannelCmdGain8); - break; - case 12: - resolve(obciChannelCmdGain12); - break; - case 24: - resolve(obciChannelCmdGain24); - break; - default: - reject('Invalid gain setting of ' + gainSetting + ' tisk tisk, gain must be (1,2,4,6,8,12,24)'); - break; - } - }); -} - -function commandChannelForCmd (channelNumber) { - return new Promise(function (resolve, reject) { - switch (channelNumber) { - case 1: - resolve(obciChannelCmdChannel1); - break; - case 2: - resolve(obciChannelCmdChannel2); - break; - case 3: - resolve(obciChannelCmdChannel3); - break; - case 4: - resolve(obciChannelCmdChannel4); - break; - case 5: - resolve(obciChannelCmdChannel5); - break; - case 6: - resolve(obciChannelCmdChannel6); - break; - case 7: - resolve(obciChannelCmdChannel7); - break; - case 8: - resolve(obciChannelCmdChannel8); - break; - case 9: - resolve(obciChannelCmdChannel9); - break; - case 10: - resolve(obciChannelCmdChannel10); - break; - case 11: - resolve(obciChannelCmdChannel11); - break; - case 12: - resolve(obciChannelCmdChannel12); - break; - case 13: - resolve(obciChannelCmdChannel13); - break; - case 14: - resolve(obciChannelCmdChannel14); - break; - case 15: - resolve(obciChannelCmdChannel15); - break; - case 16: - resolve(obciChannelCmdChannel16); - break; - default: - reject('Invalid channel number'); - break; - } - }); -} -function channelSettingsObjectDefault (channelNumber) { - return { - channelNumber: channelNumber, - powerDown: false, - gain: 24, - inputType: obciStringADCNormal, - bias: true, - srb2: true, - srb1: false - }; -} - -/** -* @description This function is used to extract the major version from a github -* version string. -* @returns {Number} The major version number -*/ -function getVersionNumber (versionStr) { - return Number(versionStr[1]); -} diff --git a/openBCISample.js b/openBCISample.js deleted file mode 100644 index 930bec6..0000000 --- a/openBCISample.js +++ /dev/null @@ -1,1196 +0,0 @@ -'use strict'; -var gaussian = require('gaussian'); -var k = require('./openBCIConstants'); -var StreamSearch = require('streamsearch'); - -/** Constants for interpreting the EEG data */ -// Reference voltage for ADC in ADS1299. -// Set by its hardware. -const ADS1299_VREF = 4.5; -// Scale factor for aux data -const SCALE_FACTOR_ACCEL = 0.002 / Math.pow(2, 4); -// X, Y, Z -const ACCEL_NUMBER_AXIS = 3; -// Default ADS1299 gains array - -var sampleModule = { - - /** - * @description This takes a 33 byte packet and converts it based on the last four bits. - * 0000 - Standard OpenBCI V3 Sample Packet - * @param dataBuf {Buffer} - A 33 byte buffer - * @param channelSettingsArray (optional) - An array of channel settings that is an Array that has shape similar to the one - * calling OpenBCIConstans.channelSettingsArrayInit(). The most important rule here is that it is - * Array of objects that have key-value pair {gain:NUMBER} - * @param convertAuxToAccel (optional) {Boolean} - Do you want to convert to g's? (Defaults to true)* - * @returns {Object} - A standard sample object. - */ - parseRawPacketStandard: (dataBuf, channelSettingsArray, convertAuxToAccel) => { - const defaultChannelSettingsArray = k.channelSettingsArrayInit(k.OBCINumberOfChannelsDefault); - - // channelSettingsArray is optional, defaults to CHANNEL_SETTINGS_ARRAY_DEFAULT - channelSettingsArray = channelSettingsArray || defaultChannelSettingsArray; - // By default convert to g's - if (convertAuxToAccel === undefined || convertAuxToAccel === null) convertAuxToAccel = true; - - // Check to make sure data is not null. - if (k.isUndefined(dataBuf) || k.isNull(dataBuf)) { - throw new Error(k.OBCIErrorUndefinedOrNullInput); - } - - // Check to make sure the buffer is the right size. - if (dataBuf.byteLength !== k.OBCIPacketSize) { - throw new Error(k.OBCIErrorInvalidByteLength); - } - - // Verify the correct stop byte. - if (dataBuf[0] !== k.OBCIByteStart) { - throw new Error(k.OBCIErrorInvalidByteStart); - } - - if (convertAuxToAccel) { - return parsePacketStandardAccel(dataBuf, channelSettingsArray); - } else { - return parsePacketStandardRawAux(dataBuf, channelSettingsArray); - } - }, - getRawPacketType, - getFromTimePacketAccel, - getFromTimePacketTime, - getFromTimePacketRawAux, - parsePacketTimeSyncedAccel, - parsePacketTimeSyncedRawAux, - /** - * @description Mainly used by the simulator to convert a randomly generated sample into a std OpenBCI V3 Packet - * @param sample - A sample object - * @returns {Buffer} - */ - convertSampleToPacketStandard: (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 = floatTo3ByteBuffer(sample.channelData[i]); - - threeByteBuffer.copy(packetBuffer, 2 + (i * 3)); - } - - for (var j = 0; j < 3; j++) { - var twoByteBuffer = floatTo2ByteBuffer(sample.auxData[j]); - - twoByteBuffer.copy(packetBuffer, (k.OBCIPacketSize - 1 - 6) + (i * 2)); - } - - // stop byte - packetBuffer[k.OBCIPacketSize - 1] = k.OBCIByteStop; - - return packetBuffer; - }, - /** - * @description Mainly used by the simulator to convert a randomly generated sample into a std OpenBCI V3 Packet - * @param sample - A sample object - * @param rawAux {Buffer} - A 6 byte long buffer to insert into raw buffer - * @returns {Buffer} - A 33 byte long buffer - */ - convertSampleToPacketRawAux: (sample, rawAux) => { - 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 = floatTo3ByteBuffer(sample.channelData[i]); - - threeByteBuffer.copy(packetBuffer, 2 + (i * 3)); - } - - // Write the raw aux bytes - rawAux.copy(packetBuffer, 26); - - // stop byte - packetBuffer[k.OBCIPacketSize - 1] = makeTailByteFromPacketType(k.OBCIStreamPacketStandardRawAux); - - return packetBuffer; - }, - /** - * @description Mainly used by the simulator to convert a randomly generated sample into an accel time sync set buffer - * @param sample {Buffer} - A sample object - * @param time {Number} - The time to inject into the sample. - * @returns {Buffer} - A time sync accel packet - */ - convertSampleToPacketAccelTimeSyncSet: (sample, time) => { - var buf = convertSampleToPacketAccelTimeSynced(sample, time); - buf[k.OBCIPacketPositionStopByte] = makeTailByteFromPacketType(k.OBCIStreamPacketAccelTimeSyncSet); - return buf; - }, - /** - * @description Mainly used by the simulator to convert a randomly generated sample into an accel time synced buffer - * @param sample {Buffer} - A sample object - * @param time {Number} - The time to inject into the sample. - * @returns {Buffer} - A time sync accel packet - */ - convertSampleToPacketAccelTimeSynced, - /** - * @description Mainly used by the simulator to convert a randomly generated sample into a raw aux time sync set packet - * @param sample {Buffer} - A sample object - * @param time {Number} - The time to inject into the sample. - * @param rawAux {Buffer} - 2 byte buffer to inject into sample - * @returns {Buffer} - A time sync raw aux packet - */ - convertSampleToPacketRawAuxTimeSyncSet: (sample, time, rawAux) => { - var buf = convertSampleToPacketRawAuxTimeSynced(sample, time, rawAux); - buf[k.OBCIPacketPositionStopByte] = makeTailByteFromPacketType(k.OBCIStreamPacketRawAuxTimeSyncSet); - return buf; - }, - convertSampleToPacketRawAuxTimeSynced, - debugPrettyPrint: (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 = 0; i < 8; i++) { - console.log('---- Channel Data ' + (i + 1) + ': ' + sample.channelData[i]); - } - if (sample.accelData) { - for (var j = 0; j < 3; j++) { - console.log('---- Accel Data ' + j + ': ' + sample.accelData[j]); - } - } - if (sample.auxData) { - console.log('---- Aux Data ' + sample.auxData); - } - console.log('---- Stop Byte: ' + sample.stopByte); - } - }, - samplePrintHeader: () => { - return ( - 'All voltages in Volts!' + - 'sampleNumber, channel1, channel2, channel3, channel4, channel5, channel6, channel7, channel8, aux1, aux2, aux3\n'); - }, - samplePrintLine: sample => { - return new Promise((resolve, reject) => { - if (sample === null || sample === undefined) reject('undefined sample'); - - resolve( - sample.sampleNumber + ',' + - sample.channelData[0].toFixed(8) + ',' + - sample.channelData[1].toFixed(8) + ',' + - sample.channelData[2].toFixed(8) + ',' + - sample.channelData[3].toFixed(8) + ',' + - sample.channelData[4].toFixed(8) + ',' + - sample.channelData[5].toFixed(8) + ',' + - sample.channelData[6].toFixed(8) + ',' + - sample.channelData[7].toFixed(8) + ',' + - sample.auxData[0].toFixed(8) + ',' + - sample.auxData[1].toFixed(8) + ',' + - sample.auxData[2].toFixed(8) + '\n' - ); - }); - }, - floatTo3ByteBuffer, - floatTo2ByteBuffer, - interpret16bitAsInt32: 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: threeByteBuffer => { - var prefix = 0; - - if (threeByteBuffer[0] > 127) { - // console.log('\t\tNegative number') - prefix = 255; - } - - return (prefix << 24) | (threeByteBuffer[0] << 16) | (threeByteBuffer[1] << 8) | threeByteBuffer[2]; - }, - impedanceArray: numberOfChannels => { - var impedanceArray = []; - for (var i = 0; i < numberOfChannels; i++) { - impedanceArray.push(newImpedanceObject(i + 1)); - } - return impedanceArray; - }, - impedanceObject: newImpedanceObject, - impedanceSummarize: singleInputObject => { - if (singleInputObject.raw > k.OBCIImpedanceThresholdBadMax) { // The case for no load (super high impedance) - singleInputObject.text = k.OBCIImpedanceTextNone; - } else { - singleInputObject.text = k.getTextForRawImpedance(singleInputObject.raw); // Get textual impedance - } - }, - newSample, - /** - * @description Create a configurable function to return samples for a simulator. This implements 1/f filtering injection to create more brain like data. - * @param numberOfChannels {Number} - The number of channels in the sample... either 8 or 16 - * @param sampleRateHz {Number} - The sample rate - * @param injectAlpha {Boolean} (optional) - True if you want to inject noise - * @param lineNoise {String} (optional) - A string that can be either: - * `60Hz` - 60Hz line noise (Default) (ex. __United States__) - * `50Hz` - 50Hz line noise (ex. __Europe__) - * `none` - Do not inject line noise. - * - * @returns {Function} - */ - randomSample: (numberOfChannels, sampleRateHz, injectAlpha, lineNoise) => { - const distribution = gaussian(0, 1); - const sineWaveFreqHz10 = 10; - const sineWaveFreqHz50 = 50; - const sineWaveFreqHz60 = 60; - const uVolts = 1000000; - - var sinePhaseRad = new Array(numberOfChannels + 1); // prevent index error with '+1' - 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 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); - - /** - * @description Use a 1/f filter - * @param previousSampleNumber {Number} - The previous sample number - */ - return previousSampleNumber => { - var sample = newSample(); - var whiteNoise; - for (var i = 0; i < numberOfChannels; i++) { // channels are 0 indexed - // This produces white noise - whiteNoise = distribution.ppf(Math.random()) * Math.sqrt(sampleRateHz / 2) / uVolts; - - switch (i) { - case 0: // Add 10Hz signal to channel 1... brainy - case 1: - if (injectAlpha) { - sinePhaseRad[i] += 2 * Math.PI * sineWaveFreqHz10 / sampleRateHz; - if (sinePhaseRad[i] > 2 * Math.PI) { - sinePhaseRad[i] -= 2 * Math.PI; - } - whiteNoise += (5 * Math.SQRT2 * Math.sin(sinePhaseRad[i])) / uVolts; - } - break; - default: - if (lineNoise === k.OBCISimulatorLineNoiseHz60) { - // If we're in murica we want to add 60Hz line noise - sinePhaseRad[i] += 2 * Math.PI * sineWaveFreqHz60 / sampleRateHz; - if (sinePhaseRad[i] > 2 * Math.PI) { - sinePhaseRad[i] -= 2 * Math.PI; - } - whiteNoise += (8 * Math.SQRT2 * Math.sin(sinePhaseRad[i])) / uVolts; - } else if (lineNoise === k.OBCISimulatorLineNoiseHz50) { - // add 50Hz line noise if we are not in america - sinePhaseRad[i] += 2 * Math.PI * sineWaveFreqHz50 / sampleRateHz; - if (sinePhaseRad[i] > 2 * Math.PI) { - sinePhaseRad[i] -= 2 * Math.PI; - } - whiteNoise += (8 * Math.SQRT2 * Math.sin(sinePhaseRad[i])) / uVolts; - } - } - /** - * See http://www.firstpr.com.au/dsp/pink-noise/ section "Filtering white noise to make it pink" - */ - b0[i] = 0.99765 * b0[i] + whiteNoise * 0.0990460; - b1[i] = 0.96300 * b1[i] + whiteNoise * 0.2965164; - b2[i] = 0.57000 * b2[i] + whiteNoise * 1.0526913; - sample.channelData[i] = b0[i] + b1[i] + b2[i] + whiteNoise * 0.1848; - } - if (previousSampleNumber === 255) { - sample.sampleNumber = 0; - } else { - sample.sampleNumber = previousSampleNumber + 1; - } - - /** - * 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 - sample.auxData = accelArray; - // Reset the counter - accelCounter = 0; - } else { - // Increment counter - accelCounter++; - // Store the default value - sample.auxData = auxData; - } - - return sample; - }; - }, - scaleFactorAux: SCALE_FACTOR_ACCEL, - k, - /** - * Calculate the impedance - * @param sample {Object} - Standard sample - * @param impedanceTest {Object} - Impedance Object from openBCIBoard.js - * @return {null | Object} - Null if not enough samples have passed to calculate an accurate - */ - impedanceCalculateArray: (sample, impedanceTest) => { - impedanceTest.buffer.push(sample.channelData); - impedanceTest.count++; - - if (impedanceTest.count >= impedanceTest.window) { - let output = []; - for (let i = 0; i < sample.channelData.length; i++) { - let max = 0.0; // sumSquared - for (let j = 0; j < impedanceTest.window; j++) { - if (impedanceTest.buffer[i][j] > max) { - max = impedanceTest.buffer[i][j]; - } - } - let min = 0.0; - for (let j = 0; j < impedanceTest.window; j++) { - if (impedanceTest.buffer[i][j] < min) { - min = impedanceTest.buffer[i][j]; - } - } - const vP2P = max - min; // peak to peak - - output.push(vP2P / 2 / k.OBCILeadOffDriveInAmps); - } - impedanceTest.count = 0; - return output; - } - return null; - }, - impedanceTestObjDefault: (impedanceTestObj) => { - let newObj = impedanceTestObj || {}; - newObj['active'] = false; - newObj['buffer'] = []; - newObj['count'] = 0; - newObj['isTestingPInput'] = false; - newObj['isTestingNInput'] = false; - newObj['onChannel'] = 0; - newObj['sampleNumber'] = 0; - newObj['continuousMode'] = false; - newObj['impedanceForChannel'] = 0; - newObj['window'] = 40; - return newObj; - }, - samplePacket: sampleNumber => { - return new Buffer([0xA0, sampleNumberNormalize(sampleNumber), 0, 0, 1, 0, 0, 2, 0, 0, 3, 0, 0, 4, 0, 0, 5, 0, 0, 6, 0, 0, 7, 0, 0, 8, 0, 0, 0, 1, 0, 2, makeTailByteFromPacketType(k.OBCIStreamPacketStandardAccel)]); - }, - samplePacketReal: sampleNumber => { - return new Buffer([0xA0, sampleNumberNormalize(sampleNumber), 0x8F, 0xF2, 0x40, 0x8F, 0xDF, 0xF4, 0x90, 0x2B, 0xB6, 0x8F, 0xBF, 0xBF, 0x7F, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0x94, 0x25, 0x34, 0x20, 0xB6, 0x7D, 0, 0xE0, 0, 0xE0, 0x0F, 0x70, makeTailByteFromPacketType(k.OBCIStreamPacketStandardAccel)]); - }, - samplePacketStandardRawAux: sampleNumber => { - return new Buffer([0xA0, sampleNumberNormalize(sampleNumber), 0, 0, 1, 0, 0, 2, 0, 0, 3, 0, 0, 4, 0, 0, 5, 0, 0, 6, 0, 0, 7, 0, 0, 8, 0, 1, 2, 3, 4, 5, makeTailByteFromPacketType(k.OBCIStreamPacketStandardRawAux)]); - }, - samplePacketAccelTimeSyncSet: sampleNumber => { - return new Buffer([0xA0, sampleNumberNormalize(sampleNumber), 0, 0, 1, 0, 0, 2, 0, 0, 3, 0, 0, 4, 0, 0, 5, 0, 0, 6, 0, 0, 7, 0, 0, 8, 0, 1, 0, 0, 0, 1, makeTailByteFromPacketType(k.OBCIStreamPacketAccelTimeSyncSet)]); - }, - samplePacketAccelTimeSynced: sampleNumber => { - return new Buffer([0xA0, sampleNumberNormalize(sampleNumber), 0, 0, 1, 0, 0, 2, 0, 0, 3, 0, 0, 4, 0, 0, 5, 0, 0, 6, 0, 0, 7, 0, 0, 8, 0, 1, 0, 0, 0, 1, makeTailByteFromPacketType(k.OBCIStreamPacketAccelTimeSynced)]); - }, - samplePacketRawAuxTimeSyncSet: sampleNumber => { - return new Buffer([0xA0, sampleNumberNormalize(sampleNumber), 0, 0, 1, 0, 0, 2, 0, 0, 3, 0, 0, 4, 0, 0, 5, 0, 0, 6, 0, 0, 7, 0, 0, 8, 0x00, 0x01, 0, 0, 0, 1, makeTailByteFromPacketType(k.OBCIStreamPacketRawAuxTimeSyncSet)]); - }, - samplePacketRawAuxTimeSynced: sampleNumber => { - return new Buffer([0xA0, sampleNumberNormalize(sampleNumber), 0, 0, 1, 0, 0, 2, 0, 0, 3, 0, 0, 4, 0, 0, 5, 0, 0, 6, 0, 0, 7, 0, 0, 8, 0x00, 0x01, 0, 0, 0, 1, makeTailByteFromPacketType(k.OBCIStreamPacketRawAuxTimeSynced)]); - }, - samplePacketUserDefined: () => { - return new Buffer([0xA0, 0x00, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, makeTailByteFromPacketType(k.OBCIStreamPacketUserDefinedType)]); - }, - makeDaisySampleObject, - getChannelDataArray, - isEven, - isOdd, - countADSPresent, - doesBufferHaveEOT, - findV2Firmware, - isFailureInBuffer, - isSuccessInBuffer, - isTimeSyncSetConfirmationInBuffer, - makeTailByteFromPacketType, - isStopByte, - newSyncObject, - stripToEOTBuffer, - /** - * @description Checks to make sure the previous sample number is one less - * then the new sample number. Takes into account sample numbers wrapping - * around at 255. - * @param `previousSampleNumber` {Number} - An integer number of the previous - * sample number. - * @param `newSampleNumber` {Number} - An integer number of the new sample - * number. - * @returns {Array} - Returns null if there is no dropped packets, otherwise, - * or on a missed packet, an array of their packet numbers is returned. - */ - droppedPacketCheck: (previousSampleNumber, newSampleNumber) => { - if (previousSampleNumber === k.OBCISampleNumberMax && newSampleNumber === 0) { - return null; - } - - if (newSampleNumber - previousSampleNumber === 1) { - return null; - } - - var missedPacketArray = []; - - if (previousSampleNumber > newSampleNumber) { - var numMised = k.OBCISampleNumberMax - previousSampleNumber; - for (var i = 0; i < numMised; i++) { - missedPacketArray.push(previousSampleNumber + i + 1); - } - previousSampleNumber = -1; - } - - for (var j = 1; j < (newSampleNumber - previousSampleNumber); j++) { - missedPacketArray.push(previousSampleNumber + j); - } - return missedPacketArray; - } -}; - -module.exports = sampleModule; - -function newImpedanceObject (channelNumber) { - return { - channel: channelNumber, - P: { - raw: -1, - text: k.OBCIImpedanceTextInit - }, - N: { - raw: -1, - text: k.OBCIImpedanceTextInit - } - }; -} - -function newSyncObject () { - return { - boardTime: 0, - correctedTransmissionTime: false, - error: null, - timeSyncSent: 0, - timeSyncSentConfirmation: 0, - timeSyncSetPacket: 0, - timeRoundTrip: 0, - timeTransmission: 0, - timeOffset: 0, - timeOffsetMaster: 0, - valid: false - }; -} - -/** -* @description This method parses a 33 byte OpenBCI V3 packet and converts to a sample object -* @param dataBuf - 33 byte packet that has bytes: -* 0:[startByte] | 1:[sampleNumber] | 2:[Channel-1.1] | 3:[Channel-1.2] | 4:[Channel-1.3] | 5:[Channel-2.1] | 6:[Channel-2.2] | 7:[Channel-2.3] | 8:[Channel-3.1] | 9:[Channel-3.2] | 10:[Channel-3.3] | 11:[Channel-4.1] | 12:[Channel-4.2] | 13:[Channel-4.3] | 14:[Channel-5.1] | 15:[Channel-5.2] | 16:[Channel-5.3] | 17:[Channel-6.1] | 18:[Channel-6.2] | 19:[Channel-6.3] | 20:[Channel-7.1] | 21:[Channel-7.2] | 22:[Channel-7.3] | 23:[Channel-8.1] | 24:[Channel-8.2] | 25:[Channel-8.3] | 26:[Aux-1.1] | 27:[Aux-1.2] | 28:[Aux-2.1] | 29:[Aux-2.2] | 30:[Aux-3.1] | 31:[Aux-3.2] | 32:StopByte -* @param channelSettingsArray {Array} - An array of channel settings that is an Array that has shape similar to the one -* calling OpenBCIConstans.channelSettingsArrayInit(). The most important rule here is that it is -* Array of objects that have key-value pair {gain:NUMBER} -* @returns {object} Sample. - * `sample` Object with: -* { -* channelData: {Array}, // of floats -* accelData: {Array}, // of floats of accel data -* sampleNumber: {Number} // The sample number -* } -*/ -function parsePacketStandardAccel (dataBuf, channelSettingsArray) { - var sampleObject = {}; - - sampleObject.accelData = getDataArrayAccel(dataBuf.slice(k.OBCIPacketPositionStartAux, k.OBCIPacketPositionStopAux + 1)); - - sampleObject.channelData = getChannelDataArray(dataBuf, channelSettingsArray); - - if (k.getVersionNumber(process.version) >= 6) { - // From introduced in node version 6.x.x - sampleObject.auxData = Buffer.from(dataBuf.slice(k.OBCIPacketPositionStartAux, k.OBCIPacketPositionStopAux + 1)); - } else { - sampleObject.auxData = new Buffer(dataBuf.slice(k.OBCIPacketPositionStartAux, k.OBCIPacketPositionStopAux + 1)); - } - // Get the sample number - sampleObject.sampleNumber = dataBuf[k.OBCIPacketPositionSampleNumber]; - // Get the start byte - sampleObject.startByte = dataBuf[0]; - // Get the stop byte - sampleObject.stopByte = dataBuf[k.OBCIPacketPositionStopByte]; - - return sampleObject; -} - -/** -* @description This method parses a 33 byte OpenBCI V3 packet and converts to a sample object -* @param dataBuf - 33 byte packet that has bytes: -* 0:[startByte] | 1:[sampleNumber] | 2:[Channel-1.1] | 3:[Channel-1.2] | 4:[Channel-1.3] | 5:[Channel-2.1] | 6:[Channel-2.2] | 7:[Channel-2.3] | 8:[Channel-3.1] | 9:[Channel-3.2] | 10:[Channel-3.3] | 11:[Channel-4.1] | 12:[Channel-4.2] | 13:[Channel-4.3] | 14:[Channel-5.1] | 15:[Channel-5.2] | 16:[Channel-5.3] | 17:[Channel-6.1] | 18:[Channel-6.2] | 19:[Channel-6.3] | 20:[Channel-7.1] | 21:[Channel-7.2] | 22:[Channel-7.3] | 23:[Channel-8.1] | 24:[Channel-8.2] | 25:[Channel-8.3] | 26:[Aux-1.1] | 27:[Aux-1.2] | 28:[Aux-2.1] | 29:[Aux-2.2] | 30:[Aux-3.1] | 31:[Aux-3.2] | 32:StopByte -* @param channelSettingsArray - An array of channel settings that is an Array that has shape similar to the one -* calling OpenBCIConstans.channelSettingsArrayInit(). The most important rule here is that it is -* Array of objects that have key-value pair {gain:NUMBER} -* @returns {Promise} - Fulfilled with a sample object that has form: -* { -* channelData: Array of floats -* auxData: 6 byte long buffer of raw aux data -* sampleNumber: a Number that is the sample -* } -*/ -function parsePacketStandardRawAux (dataBuf, channelSettingsArray) { - var sampleObject = {}; - - // Store the channel data - sampleObject.channelData = getChannelDataArray(dataBuf, channelSettingsArray); - - // Slice the buffer for the aux data - if (k.getVersionNumber(process.version) >= 6) { - // From introduced in node version 6.x.x - sampleObject.auxData = Buffer.from(dataBuf.slice(k.OBCIPacketPositionStartAux, k.OBCIPacketPositionStopAux + 1)); - } else { - sampleObject.auxData = new Buffer(dataBuf.slice(k.OBCIPacketPositionStartAux, k.OBCIPacketPositionStopAux + 1)); - } - // Get the sample number - sampleObject.sampleNumber = dataBuf[k.OBCIPacketPositionSampleNumber]; - // Get the start byte - sampleObject.startByte = dataBuf[0]; - // Get the stop byte - sampleObject.stopByte = dataBuf[k.OBCIPacketPositionStopByte]; - - return sampleObject; -} - -/** -* @description Grabs an accel value from a raw but time synced packet. Important that this utilizes the fact that: -* X axis data is sent with every sampleNumber % 10 === 0 -* Y axis data is sent with every sampleNumber % 10 === 1 -* Z axis data is sent with every sampleNumber % 10 === 2 -* @param dataBuf {Buffer} - The 33byte raw time synced accel packet -* @param channelSettingsArray {Array} - An array of channel settings that is an Array that has shape similar to the one -* calling OpenBCIConstans.channelSettingsArrayInit(). The most important rule here is that it is -* Array of objects that have key-value pair {gain:NUMBER} -* @param boardOffsetTime {Number} - The difference between board time and current time calculated with sync methods. -* @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. -* @returns {Object} - A sample object. NOTE: Only has accelData if this is a Z axis packet. -*/ -function parsePacketTimeSyncedAccel (dataBuf, channelSettingsArray, boardOffsetTime, accelArray) { - // Ths packet has 'A0','00'....,'AA','AA','FF','FF','FF','FF','C4' - // where the 'AA's form an accel 16bit num and 'FF's form a 32 bit time in ms - // The sample object we are going to build - var sampleObject = {}; - - // Get the sample number - sampleObject.sampleNumber = dataBuf[k.OBCIPacketPositionSampleNumber]; - // Get the start byte - sampleObject.startByte = dataBuf[0]; - // Get the stop byte - sampleObject.stopByte = dataBuf[k.OBCIPacketPositionStopByte]; - - // Get the board time - sampleObject.boardTime = getFromTimePacketTime(dataBuf); - sampleObject.timeStamp = sampleObject.boardTime + boardOffsetTime; - - // Extract the aux data - sampleObject.auxData = getFromTimePacketRawAux(dataBuf); - - // Grab the accelData only if `getFromTimePacketAccel` returns true. - if (getFromTimePacketAccel(dataBuf, accelArray)) { - sampleObject.accelData = accelArray; - } - - // Grab the channel data. - sampleObject.channelData = getChannelDataArray(dataBuf, channelSettingsArray); - - return sampleObject; -} - -/** -* @description Grabs an accel value from a raw but time synced packet. Important that this utilizes the fact that: -* X axis data is sent with every sampleNumber % 10 === 0 -* Y axis data is sent with every sampleNumber % 10 === 1 -* Z axis data is sent with every sampleNumber % 10 === 2 -* @param dataBuf {Buffer} - The 33byte raw time synced accel packet -* @param channelSettingsArray {Array} - An array of channel settings that is an Array that has shape similar to the one -* calling OpenBCIConstans.channelSettingsArrayInit(). The most important rule here is that it is -* Array of objects that have key-value pair {gain:NUMBER} -* @param boardOffsetTime {Number} - The difference between board time and current time calculated with sync methods. -* @returns {Object} - A sample object. NOTE: The aux data is placed in a 2 byte buffer -*/ -function parsePacketTimeSyncedRawAux (dataBuf, channelSettingsArray, boardOffsetTime) { - // Ths packet has 'A0','00'....,'AA','AA','FF','FF','FF','FF','C4' - // where the 'AA's form an accel 16bit num and 'FF's form a 32 bit time in ms - if (dataBuf.byteLength !== k.OBCIPacketSize) { - throw new Error(k.OBCIErrorInvalidByteLength); - } - - // The sample object we are going to build - var sampleObject = {}; - - // Get the sample number - sampleObject.sampleNumber = dataBuf[k.OBCIPacketPositionSampleNumber]; - // Get the start byte - sampleObject.startByte = dataBuf[0]; - // Get the stop byte - sampleObject.stopByte = dataBuf[k.OBCIPacketPositionStopByte]; - - // Get the board time - sampleObject.boardTime = getFromTimePacketTime(dataBuf); - sampleObject.timeStamp = sampleObject.boardTime + boardOffsetTime; - - // Extract the aux data - sampleObject.auxData = getFromTimePacketRawAux(dataBuf); - - // Grab the channel data. - sampleObject.channelData = getChannelDataArray(dataBuf, channelSettingsArray); - - return sampleObject; -} - -/** -* @description Extract a time from a time packet in ms. -* @param dataBuf - A raw packet with 33 bytes of data -* @returns {Number} - Board time in milli seconds -* @author AJ Keller (@pushtheworldllc) -*/ -function getFromTimePacketTime (dataBuf) { - // Ths packet has 'A0','00'....,'00','00','FF','FF','FF','FF','C3' where the 'FF's are times - const lastBytePosition = k.OBCIPacketSize - 1; // This is 33, but 0 indexed would be 32 minus 1 for the stop byte and another two for the aux channel or the - if (dataBuf.byteLength !== k.OBCIPacketSize) { - throw new Error(k.OBCIErrorInvalidByteLength); - } else { - // Grab the time from the packet - return dataBuf.readUInt32BE(lastBytePosition - k.OBCIStreamPacketTimeByteSize); - } -} - -/** -* @description Grabs an accel value from a raw but time synced packet. Important that this utilizes the fact that: -* X axis data is sent with every sampleNumber % 10 === 7 -* Y axis data is sent with every sampleNumber % 10 === 8 -* Z axis data is sent with every sampleNumber % 10 === 9 -* @param dataBuf {Buffer} - The 33byte raw time synced accel packet -* @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. -* @returns {boolean} - A boolean that is true only when the accel array is ready to be emitted... i.e. when this is a Z axis packet -*/ -function getFromTimePacketAccel (dataBuf, accelArray) { - const accelNumBytes = 2; - const lastBytePosition = k.OBCIPacketSize - 1 - k.OBCIStreamPacketTimeByteSize - accelNumBytes; // This is 33, but 0 indexed would be 32 minus - - if (dataBuf.byteLength !== k.OBCIPacketSize) { - throw new Error(k.OBCIErrorInvalidByteLength); - } - - var sampleNumber = dataBuf[k.OBCIPacketPositionSampleNumber]; - switch (sampleNumber % 10) { // The accelerometer is on a 25Hz sample rate, so every ten channel samples, we can get new data - case k.OBCIAccelAxisX: - accelArray[0] = sampleModule.interpret16bitAsInt32(dataBuf.slice(lastBytePosition, lastBytePosition + 2)) * SCALE_FACTOR_ACCEL; // slice is not inclusive on the right - return false; - case k.OBCIAccelAxisY: - accelArray[1] = sampleModule.interpret16bitAsInt32(dataBuf.slice(lastBytePosition, lastBytePosition + 2)) * SCALE_FACTOR_ACCEL; // slice is not inclusive on the right - return false; - case k.OBCIAccelAxisZ: - accelArray[2] = sampleModule.interpret16bitAsInt32(dataBuf.slice(lastBytePosition, lastBytePosition + 2)) * SCALE_FACTOR_ACCEL; // slice is not inclusive on the right - return true; - default: - return false; - } -} - -/** -* @description Grabs a raw aux value from a raw but time synced packet. -* @param dataBuf {Buffer} - The 33byte raw time synced raw aux packet -* @returns {Promise} - Fulfills a 2 byte buffer -*/ -function getFromTimePacketRawAux (dataBuf) { - if (dataBuf.byteLength !== k.OBCIPacketSize) { - throw new Error(k.OBCIErrorInvalidByteLength); - } - if (k.getVersionNumber(process.version) >= 6) { - return Buffer.from(dataBuf.slice(k.OBCIPacketPositionTimeSyncAuxStart, k.OBCIPacketPositionTimeSyncAuxStop)); - } else { - return new Buffer(dataBuf.slice(k.OBCIPacketPositionTimeSyncAuxStart, k.OBCIPacketPositionTimeSyncAuxStop)); - } -} - -/** -* @description Takes a buffer filled with 3 16 bit integers from an OpenBCI device and converts based on settings -* of the MPU, values are in ? -* @param dataBuf - Buffer that is 6 bytes long -* @returns {Array} - Array of floats 3 elements long -* @author AJ Keller (@pushtheworldllc) -*/ -function getDataArrayAccel (dataBuf) { - var accelData = []; - for (var i = 0; i < ACCEL_NUMBER_AXIS; i++) { - var index = i * 2; - accelData.push(sampleModule.interpret16bitAsInt32(dataBuf.slice(index, index + 2)) * SCALE_FACTOR_ACCEL); - } - return accelData; -} -/** -* @description Takes a buffer filled with 24 bit signed integers from an OpenBCI device with gain settings in -* channelSettingsArray[index].gain and converts based on settings of ADS1299... spits out an -* array of floats in VOLTS -* @param dataBuf {Buffer} - Buffer with 33 bit signed integers, number of elements is same as channelSettingsArray.length * 3 -* @param channelSettingsArray {Array} - The channel settings array, see OpenBCIConstants.channelSettingsArrayInit() for specs -* @returns {Array} - Array filled with floats for each channel's voltage in VOLTS -* @author AJ Keller (@pushtheworldllc) -*/ -function getChannelDataArray (dataBuf, channelSettingsArray) { - if (!Array.isArray(channelSettingsArray)) { - throw new Error('Error [getChannelDataArray]: Channel Settings must be an array!'); - } - var channelData = []; - // Grab the sample number from the buffer - var sampleNumber = dataBuf[k.OBCIPacketPositionSampleNumber]; - var daisy = channelSettingsArray.length > k.OBCINumberOfChannelsDefault; - - // Channel data arrays are always 8 long - for (var i = 0; i < k.OBCINumberOfChannelsDefault; i++) { - if (!channelSettingsArray[i].hasOwnProperty('gain')) { - throw new Error(`Error [getChannelDataArray]: Invalid channel settings object at index ${i}`); - } - if (!k.isNumber(channelSettingsArray[i].gain)) { - throw new Error('Error [getChannelDataArray]: Property gain of channelSettingsObject not or type Number'); - } - - var scaleFactor = 0; - if (isEven(sampleNumber) && daisy) { - scaleFactor = ADS1299_VREF / channelSettingsArray[i + k.OBCINumberOfChannelsDefault].gain / (Math.pow(2, 23) - 1); - } else { - scaleFactor = ADS1299_VREF / channelSettingsArray[i].gain / (Math.pow(2, 23) - 1); - } - // Convert the three byte signed integer and convert it - channelData.push(scaleFactor * sampleModule.interpret24bitAsInt32(dataBuf.slice((i * 3) + k.OBCIPacketPositionChannelDataStart, (i * 3) + k.OBCIPacketPositionChannelDataStart + 3))); - } - return channelData; -} - -function getRawPacketType (stopByte) { - return stopByte & 0xF; -} - -/** -* @description This method is useful for normalizing sample numbers for fake sample packets. This is intended to be -* useful for the simulator and automated testing. -* @param sampleNumber {Number} - The sample number you want to assign to the packet -* @returns {Number} - The normalized input `sampleNumber` between 0-255 -*/ -function sampleNumberNormalize (sampleNumber) { - if (sampleNumber || sampleNumber === 0) { - if (sampleNumber > 255) { - sampleNumber = 255; - } - } else { - sampleNumber = 0x45; - } - return sampleNumber; -} - -function newSample (sampleNumber) { - if (sampleNumber || sampleNumber === 0) { - if (sampleNumber > 255) { - sampleNumber = 255; - } - } else { - sampleNumber = 0; - } - return { - startByte: k.OBCIByteStart, - sampleNumber: sampleNumber, - channelData: [], - accelData: [], - auxData: null, - stopByte: k.OBCIByteStop, - boardTime: 0, - timeStamp: 0 - }; -} - -/** -* @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 -*/ -function floatTo3ByteBuffer (float) { - var intBuf = new Buffer(3); // 3 bytes for 24 bits - intBuf.fill(0); // Fill the buffer with 0s - - var temp = float / (ADS1299_VREF / 24 / (Math.pow(2, 23) - 1)); // 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 -*/ -function floatTo2ByteBuffer (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; -} - -/** -* @description Used to make one sample object from two sample objects. The sample number of the new daisy sample will -* be the upperSampleObject's sample number divded by 2. This allows us to preserve consecutive sample numbers that -* flip over at 127 instead of 255 for an 8 channel. The daisySampleObject will also have one `channelData` array -* with 16 elements inside it, with the lowerSampleObject in the lower indices and the upperSampleObject in the -* upper set of indices. The auxData from both channels shall be captured in an object called `auxData` which -* contains two arrays referenced by keys `lower` and `upper` for the `lowerSampleObject` and `upperSampleObject`, -* respectively. The timestamps shall be averaged and moved into an object called `timestamp`. Further, the -* un-averaged timestamps from the `lowerSampleObject` and `upperSampleObject` shall be placed into an object called -* `_timestamps` which shall contain two keys `lower` and `upper` which contain the original timestamps for their -* respective sampleObjects. -* @param lowerSampleObject {Object} - Lower 8 channels with odd sample number -* @param upperSampleObject {Object} - Upper 8 channels with even sample number -* @returns {Object} - The new merged daisy sample object -*/ -function makeDaisySampleObject (lowerSampleObject, upperSampleObject) { - var daisySampleObject = {}; - - daisySampleObject['channelData'] = lowerSampleObject.channelData.concat(upperSampleObject.channelData); - - daisySampleObject['sampleNumber'] = Math.floor(upperSampleObject.sampleNumber / 2); - - daisySampleObject['auxData'] = { - 'lower': lowerSampleObject.auxData, - 'upper': upperSampleObject.auxData - }; - - daisySampleObject['timestamp'] = (lowerSampleObject.timestamp + upperSampleObject.timestamp) / 2; - - daisySampleObject['_timestamps'] = { - 'lower': lowerSampleObject.timestamp, - 'upper': upperSampleObject.timestamp - }; - - if (lowerSampleObject.accelData) { - daisySampleObject['accelData'] = lowerSampleObject.accelData; - } else if (upperSampleObject.accelData) { - daisySampleObject['accelData'] = upperSampleObject.accelData; - } - - return daisySampleObject; -} - -/** -* @description Used to test a number to see if it is even -* @param a {Number} - The number to test -* @returns {boolean} - True if `a` is even -*/ -function isEven (a) { - return a % 2 === 0; -} -/** -* @description Used to test a number to see if it is odd -* @param a {Number} - The number to test -* @returns {boolean} - True if `a` is odd -*/ -function isOdd (a) { - return a % 2 === 1; -} - -/** -* @description Since we know exactly what this input will look like (See the hardware firmware) we can program this -* function with prior knowledge. -* @param dataBuffer {Buffer} - The buffer you want to parse. -* @return {Number} - The number of "ADS1299" present in the `dataBuffer` -*/ -function countADSPresent (dataBuffer) { - const s = new StreamSearch(new Buffer('ADS1299')); - - // Clear the buffer - s.reset(); - - // Push the new data buffer. This runs the search. - s.push(dataBuffer); - - // Check and see if there is a match - return s.matches; -} - -/** -* @description Searchs the buffer for a "$$$" or as we call an EOT -* @param dataBuffer - The buffer of some length to parse -* @returns {boolean} - True if the `$$$` was found. -*/ -// TODO: StreamSearch is optimized to search incoming chunks of data, streaming in, -// but a new search is constructed here with every call. This is not making use -// of StreamSearch's optimizations; the object should be preserved between chunks, -// and only fed the new data. TODO: also check other uses of StreamSearch -function doesBufferHaveEOT (dataBuffer) { - const s = new StreamSearch(new Buffer(k.OBCIParseEOT)); - - // Clear the buffer - s.reset(); - - // Push the new data buffer. This runs the search. - s.push(dataBuffer); - - // Check and see if there is a match - return s.matches >= 1; -} - -/** -* @description Used to parse a soft reset response to determine if the board is running the v2 firmware -* @param dataBuffer {Buffer} - The data to parse -* @returns {boolean} - True if `v2`is indeed found in the `dataBuffer` -*/ -function findV2Firmware (dataBuffer) { - const s = new StreamSearch(new Buffer(k.OBCIParseFirmware)); - - // Clear the buffer - s.reset(); - - // Push the new data buffer. This runs the search. - s.push(dataBuffer); - - // Check and see if there is a match - return s.matches >= 1; -} - -/** -* @description Used to parse a buffer for the word `Failure` that is acked back after private radio msg on failure -* @param dataBuffer {Buffer} - The buffer of some length to parse -* @returns {boolean} - True if `Failure` was found. -*/ -function isFailureInBuffer (dataBuffer) { - const s = new StreamSearch(new Buffer(k.OBCIParseFailure)); - - // Clear the buffer - s.reset(); - - // Push the new data buffer. This runs the search. - s.push(dataBuffer); - - // Check and see if there is a match - return s.matches >= 1; -} - -/** -* @description Used to parse a buffer for the word `Success` that is acked back after private radio msg on success -* @param dataBuffer {Buffer} - The buffer of some length to parse -* @returns {boolean} - True if `Success` was found. -*/ -function isSuccessInBuffer (dataBuffer) { - const s = new StreamSearch(new Buffer(k.OBCIParseSuccess)); - - // Clear the buffer - s.reset(); - - // Push the new data buffer. This runs the search. - s.push(dataBuffer); - - // Check and see if there is a match - return s.matches >= 1; -} - -/** - * @description Used to slice a buffer for the EOT '$$$'. - * @param dataBuffer {Buffer} - The buffer of some length to parse - * @returns {Buffer} - The remaining buffer. - */ -function stripToEOTBuffer (dataBuffer) { - let indexOfEOT = dataBuffer.indexOf(k.OBCIParseEOT); - if (indexOfEOT >= 0) { - indexOfEOT += k.OBCIParseEOT.length; - } else { - return dataBuffer; - } - - if (indexOfEOT < dataBuffer.byteLength) { - if (k.getVersionNumber(process.version) >= 6) { - // From introduced in node version 6.x.x - return Buffer.from(dataBuffer.slice(indexOfEOT)); - } else { - return new Buffer(dataBuffer.slice(indexOfEOT)); - } - } else { - return null; - } -} - -/** -* @description Used to parse a buffer for the `,` character that is acked back after a time sync request is sent -* @param dataBuffer {Buffer} - The buffer of some length to parse -* @returns {boolean} - True if the `,` was found. -*/ -function isTimeSyncSetConfirmationInBuffer (dataBuffer) { - if (dataBuffer) { - var bufferLength = dataBuffer.length; - switch (bufferLength) { - case 0: - return false; - case 1: - return dataBuffer[0] === k.OBCISyncTimeSent.charCodeAt(0); - case 2: - // HEAD Byte at End - if (dataBuffer[1] === k.OBCIByteStart) { - return dataBuffer[0] === k.OBCISyncTimeSent.charCodeAt(0); - // TAIL byte in front - } else if (isStopByte((dataBuffer[0]))) { - return dataBuffer[1] === k.OBCISyncTimeSent.charCodeAt(0); - } else { - return false; - } - default: - if (dataBuffer[0] === k.OBCISyncTimeSent.charCodeAt(0) && dataBuffer[1] === k.OBCIByteStart) { - return true; - } - for (var i = 1; i < bufferLength; i++) { - // The base case (last one) - // console.log(i) - if (i === (bufferLength - 1)) { - if (isStopByte((dataBuffer[i - 1]))) { - return dataBuffer[i] === k.OBCISyncTimeSent.charCodeAt(0); - } - } else { - // Wedged - if (isStopByte(dataBuffer[i - 1]) && dataBuffer[i + 1] === k.OBCIByteStart) { - return dataBuffer[i] === k.OBCISyncTimeSent.charCodeAt(0); - // TAIL byte in front - } - } - } - return false; - - } - } -} - -/** -* @description Mainly used by the simulator to convert a randomly generated sample into a std OpenBCI V3 Packet -* @param sample {Object} - A sample object -* @param time {Number} - The time to inject into the sample. -* @param rawAux {Buffer} - 2 byte buffer to inject into sample -* @returns {Buffer} - A time sync raw aux packet -*/ -function convertSampleToPacketRawAuxTimeSynced (sample, time, rawAux) { - 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 = floatTo3ByteBuffer(sample.channelData[i]); - - threeByteBuffer.copy(packetBuffer, 2 + (i * 3)); - } - - // Write the raw aux bytes - rawAux.copy(packetBuffer, 26); - - // Write the time - packetBuffer.writeInt32BE(time, 28); - - // stop byte - packetBuffer[k.OBCIPacketSize - 1] = makeTailByteFromPacketType(k.OBCIStreamPacketRawAuxTimeSynced); - - return packetBuffer; -} - -/** -* @description Mainly used by the simulator to convert a randomly generated sample into a std OpenBCI V3 Packet -* @param sample {Object} - A sample object -* @param time {Number} - The time to inject into the sample. -* @returns {Buffer} - A time sync accel packet -*/ -function convertSampleToPacketAccelTimeSynced (sample, time) { - 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 = floatTo3ByteBuffer(sample.channelData[i]); - - threeByteBuffer.copy(packetBuffer, 2 + (i * 3)); - } - - packetBuffer.writeInt32BE(time, 28); - - // stop byte - packetBuffer[k.OBCIPacketSize - 1] = makeTailByteFromPacketType(k.OBCIStreamPacketAccelTimeSynced); - - return packetBuffer; -} - -/** -* @description Converts a packet type {Number} into a OpenBCI stop byte -* @param type {Number} - The number to smash on to the stop byte. Must be 0-15, -* out of bounds input will result in a 0 -* @return {Number} - A properly formatted OpenBCI stop byte -*/ -function makeTailByteFromPacketType (type) { - if (type < 0 || type > 15) { - type = 0; - } - return k.OBCIByteStop | type; -} - -/** -* @description Used to check and see if a byte adheres to the stop byte structure of 0xCx where x is the set of -* numbers from 0-F in hex of 0-15 in decimal. -* @param byte {Number} - The number to test -* @returns {boolean} - True if `byte` follows the correct form -* @author AJ Keller (@pushtheworldllc) -*/ -function isStopByte (byte) { - return (byte & 0xF0) === k.OBCIByteStop; -} diff --git a/openBCISimulator.js b/openBCISimulator.js deleted file mode 100644 index 777e928..0000000 --- a/openBCISimulator.js +++ /dev/null @@ -1,488 +0,0 @@ -'use strict'; -var EventEmitter = require('events').EventEmitter; -var util = require('util'); -var stream = require('stream'); - -var openBCISample = require('./openBCISample'); -var k = openBCISample.k; -var now = require('performance-now'); - -function OpenBCISimulatorFactory () { - var factory = this; - - var _options = { - accel: true, - alpha: true, - boardFailure: false, - daisy: false, - daisyCanBeAttached: true, - drift: 0, - firmwareVersion: [k.OBCIFirmwareV1, k.OBCIFirmwareV2], - fragmentation: [k.OBCISimulatorFragmentationNone, k.OBCISimulatorFragmentationRandom, k.OBCISimulatorFragmentationFullBuffers, k.OBCISimulatorFragmentationOneByOne], - latencyTime: 16, - bufferSize: 4096, - lineNoise: [k.OBCISimulatorLineNoiseHz60, k.OBCISimulatorLineNoiseHz50, k.OBCISimulatorLineNoiseNone], - sampleRate: 250, - serialPortFailure: false, - verbose: false - }; - - function OpenBCISimulator (portName, options) { - options = (typeof options !== 'function') && options || {}; - var opts = {}; - - stream.Stream.call(this); - - /** Configuring Options */ - var o; - for (o in _options) { - var userValue = options[o]; - delete options[o]; - - if (typeof _options[o] === 'object') { - // an array specifying a list of choices - // if the choice is not in the list, the first one is defaulted to - - if (_options[o].indexOf(userValue) !== -1) { - opts[o] = userValue; - } else { - opts[o] = _options[o][0]; - } - } else { - // anything else takes the user value if provided, otherwise is a default - - if (userValue !== undefined) { - opts[o] = userValue; - } else { - opts[o] = _options[o]; - } - } - } - - for (o in options) throw new Error('"' + o + '" is not a valid option'); - - this.options = opts; - - // Bools - this.connected = false; - this.sd = { - active: false, - startTime: 0 - }; - this.streaming = false; - this.synced = false; - this.sendSyncSetPacket = false; - // Buffers - this.outputBuffer = new Buffer(this.options.bufferSize); - this.outputBuffered = 0; - // Numbers - this.channelNumber = 1; - this.hostChannelNumber = this.channelNumber; - this.pollTime = 80; - this.sampleNumber = -1; // So the first sample is 0 - // Objects - this.sampleGenerator = openBCISample.randomSample(k.OBCINumberOfChannelsDefault, this.options.sampleRate, this.options.alpha, this.options.lineNoise); - this.time = { - current: 0, - start: now(), - loop: null - }; - // Strings - this.portName = portName || k.OBCISimulatorPortName; - - // Call 'open' - if (this.options.verbose) console.log(`Port name: ${portName}`); - setTimeout(() => { - this.connected = true; - this.emit('open'); - }, 200); - } - - // This allows us to use the emitter class freely outside of the module - // TODO: upgrade from old-style streams to stream.Duplex or stream.Transform - util.inherits(OpenBCISimulator, stream.Stream); - - OpenBCISimulator.prototype.flush = function (callback) { - this.outputBuffered = 0; - - clearTimeout(this.outputLoopHandle); - this.outputLoopHandle = null; - - if (callback) callback(); - }; - - OpenBCISimulator.prototype.isOpen = function () { - return this.connected; - }; - - // output only size bytes of the output buffer - OpenBCISimulator.prototype._partialDrain = function (size) { - if (!this.connected) throw new Error('not connected'); - - if (size > this.outputBuffered) size = this.outputBuffered; - - // buffer is copied because presently openBCIBoard.js reuses it - var outBuffer = new Buffer(this.outputBuffer.slice(0, size)); - - this.outputBuffer.copy(this.outputBuffer, 0, size, this.outputBuffered); - this.outputBuffered -= size; - - this.emit('data', outBuffer); - }; - - // queue some data for output and send it out depending on options.fragmentation - OpenBCISimulator.prototype._output = function (dataBuffer) { - // drain full buffers until there is no overflow - while (this.outputBuffered + dataBuffer.length > this.outputBuffer.length) { - var len = dataBuffer.copy(this.outputBuffer, this.outputBuffered); - dataBuffer = dataBuffer.slice(len); - this.outputBuffered += len; - - this._partialDrain(this.outputBuffered); - this.flush(); - } - - dataBuffer.copy(this.outputBuffer, this.outputBuffered); - this.outputBuffered += dataBuffer.length; - - if (!this.outputLoopHandle) { - var latencyTime = this.options.latencyTime; - if (this.options.fragmentation === k.OBCISimulatorFragmentationOneByOne || - this.options.fragmentation === k.OBCISimulatorFragmentationNone) { - // no need to wait for latencyTime - // note that this is the only difference between 'none' and 'fullBuffers' - latencyTime = 0; - } - var outputLoop = () => { - var size; - switch (this.options.fragmentation) { - case k.OBCISimulatorFragmentationRandom: - if (Math.random() < 0.5) { - // randomly picked to send out a fragment - size = Math.ceil(Math.random() * Math.max(this.outputBuffered, 62)); - break; - } // else, randomly picked to send a complete buffer in next block - /* falls through */ - case k.OBCISimulatorFragmentationFullBuffers: - case k.OBCISimulatorFragmentationNone: - case false: - size = this.outputBuffered; - break; - case k.OBCISimulatorFragmentationOneByOne: - size = 1; - break; - } - this._partialDrain(size); - if (this.outputBuffered) { - this.outputLoopHandle = setTimeout(outputLoop, latencyTime); - } else { - this.outputLoopHandle = null; - } - }; - if (latencyTime === 0) { - outputLoop(); - } else { - this.outputLoopHandle = setTimeout(outputLoop, latencyTime); - } - } - }; - - OpenBCISimulator.prototype.write = function (data, callback) { - if (!this.connected) { - if (callback) callback('Not connected'); - else throw new Error('Not connected!'); - return; - } - - // TODO: this function assumes a type of Buffer for radio, and a type of String otherwise - // FIX THIS it makes it unusable outside the api code - switch (data[0]) { - case k.OBCIRadioKey: - this._processPrivateRadioMessage(data); - break; - 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.streaming = false; - this._output(new Buffer(`OpenBCI V3 Simulator On Board ADS1299 Device ID: 0x12345 ${this.options.daisy ? `On Daisy ADS1299 Device ID: 0xFFFFF\n` : ``} LIS3DH Device ID: 0x38422 ${this.options.firmwareVersion === k.OBCIFirmwareV2 ? `Firmware: v2.0.0\n` : ``}$$$`)); - 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._output(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._output(new Buffer(`Total Elapsed Time: ${now() - this.sd.startTime} ms`)); - this._output(new Buffer(`Max write time: ${Math.random() * 500} us`)); - this._output(new Buffer(`Min write time: ${Math.random() * 200} us`)); - this._output(new Buffer(`Overruns: 0`)); - this._printEOT(); - } else { - this._output(new Buffer('No open file to close\n')); - this._printEOT(); - } - } - this.SDLogActive = false; - break; - case k.OBCISyncTimeSet: - if (this.options.firmwareVersion === k.OBCIFirmwareV2) { - this.synced = true; - setTimeout(() => { - this._output(new Buffer(k.OBCISyncTimeSent)); - this._syncUp(); - }, 10); - } - break; - case k.OBCIChannelMaxNumber8: - if (this.options.daisy) { - this.options.daisy = false; - this._output(new Buffer(k.OBCIChannelMaxNumber8SuccessDaisyRemoved)); - this._printEOT(); - } else { - this._printEOT(); - } - break; - case k.OBCIChannelMaxNumber16: - if (this.options.daisy) { - this._output(new Buffer(k.OBCIChannelMaxNumber16DaisyAlreadyAttached)); - this._printEOT(); - } else { - if (this.options.daisyCanBeAttached) { - this.options.daisy = true; - this._output(new Buffer(k.OBCIChannelMaxNumber16DaisyAttached)); - this._printEOT(); - } else { - this._output(new Buffer(k.OBCIChannelMaxNumber16NoDaisyAttached)); - this._printEOT(); - } - } - break; - default: - break; - } - - /** Handle Callback */ - if (callback) { - callback(null, 'Success!'); - } - }; - - OpenBCISimulator.prototype.drain = function (callback) { - if (callback) callback(); - }; - - OpenBCISimulator.prototype.close = function (callback) { - if (this.connected) { - this.flush(); - - if (this.stream) clearInterval(this.stream); - - this.connected = false; - this.emit('close'); - if (callback) callback(); - } else { - if (callback) callback('not connected'); - } - }; - - OpenBCISimulator.prototype._startStream = function () { - var intervalInMS = 1000 / this.options.sampleRate; - - if (intervalInMS < 2) intervalInMS = 2; - - var getNewPacket = sampNumber => { - if (this.options.accel) { - if (this.synced) { - if (this.sendSyncSetPacket) { - this.sendSyncSetPacket = false; - return openBCISample.convertSampleToPacketAccelTimeSyncSet(this.sampleGenerator(sampNumber), now().toFixed(0)); - } else { - return openBCISample.convertSampleToPacketAccelTimeSynced(this.sampleGenerator(sampNumber), now().toFixed(0)); - } - } else { - return openBCISample.convertSampleToPacketStandard(this.sampleGenerator(sampNumber)); - } - } else { - if (this.synced) { - if (this.sendSyncSetPacket) { - this.sendSyncSetPacket = false; - return openBCISample.convertSampleToPacketRawAuxTimeSyncSet(this.sampleGenerator(sampNumber), now().toFixed(0), new Buffer([0, 0, 0, 0, 0, 0])); - } else { - return openBCISample.convertSampleToPacketRawAuxTimeSynced(this.sampleGenerator(sampNumber), now().toFixed(0), new Buffer([0, 0, 0, 0, 0, 0])); - } - } else { - return openBCISample.convertSampleToPacketRawAux(this.sampleGenerator(sampNumber), new Buffer([0, 0, 0, 0, 0, 0])); - } - } - }; - - this.stream = setInterval(() => { - this._output(getNewPacket(this.sampleNumber)); - this.sampleNumber++; - }, intervalInMS); - }; - - OpenBCISimulator.prototype._syncUp = function () { - setTimeout(() => { - this.sendSyncSetPacket = true; - }, 12); // 3 packets later - }; - - OpenBCISimulator.prototype._printEOT = function () { - this._output(new Buffer('$$$')); - }; - - OpenBCISimulator.prototype._printFailure = function () { - this._output(new Buffer('Failure: ')); - }; - - OpenBCISimulator.prototype._printSuccess = function () { - this._output(new Buffer('Success: ')); - }; - - OpenBCISimulator.prototype._printValidatedCommsTimeout = function () { - this._printFailure(); - this._output(new Buffer('Communications timeout - Device failed to poll Host')); - this._printEOT(); - }; - - OpenBCISimulator.prototype._processPrivateRadioMessage = function (dataBuffer) { - switch (dataBuffer[1]) { - case k.OBCIRadioCmdChannelGet: - if (this.options.firmwareVersion === k.OBCIFirmwareV2) { - if (!this.options.boardFailure) { - this._printSuccess(); - this._output(new Buffer(`Host and Device on Channel Number ${this.channelNumber}`)); - this._output(new Buffer([this.channelNumber])); - this._printEOT(); - } else if (!this.serialPortFailure) { - this._printFailure(); - this._output(new Buffer(`Host on Channel Number ${this.channelNumber}`)); - this._output(new Buffer([this.channelNumber])); - this._printEOT(); - } - } - break; - case k.OBCIRadioCmdChannelSet: - if (this.options.firmwareVersion === k.OBCIFirmwareV2) { - if (!this.options.boardFailure) { - if (dataBuffer[2] <= k.OBCIRadioChannelMax) { - this.channelNumber = dataBuffer[2]; - this.hostChannelNumber = this.channelNumber; - this._printSuccess(); - this._output(new Buffer(`Channel Number ${this.channelNumber}`)); - this._output(new Buffer([this.channelNumber])); - this._printEOT(); - } else { - this._printFailure(); - this._output(new Buffer('Verify channel number is less than 25')); - this._printEOT(); - } - } else if (!this.serialPortFailure) { - this._printValidatedCommsTimeout(); - } - } - break; - case k.OBCIRadioCmdChannelSetOverride: - if (this.options.firmwareVersion === k.OBCIFirmwareV2) { - if (dataBuffer[2] <= k.OBCIRadioChannelMax) { - if (dataBuffer[2] === this.channelNumber) { - this.options.boardFailure = false; - } else { - this.options.boardFailure = true; - } - this.hostChannelNumber = dataBuffer[2]; - this._printSuccess(); - this._output(new Buffer(`Host override - Channel Number ${this.hostChannelNumber}`)); - this._output(new Buffer([this.hostChannelNumber])); - this._printEOT(); - } else { - this._printFailure(); - this._output(new Buffer('Verify channel number is less than 25')); - this._printEOT(); - } - } - break; - case k.OBCIRadioCmdPollTimeGet: - if (this.options.firmwareVersion === k.OBCIFirmwareV2) { - if (!this.options.boardFailure) { - this._printSuccess(); - this._output(new Buffer(`Poll Time ${this.pollTime}`)); - this._output(new Buffer([this.pollTime])); - this._printEOT(); - } else { - this._printValidatedCommsTimeout(); - } - } - break; - case k.OBCIRadioCmdPollTimeSet: - if (this.options.firmwareVersion === k.OBCIFirmwareV2) { - if (!this.options.boardFailure) { - this.pollTime = dataBuffer[2]; - this._printSuccess(); - this._output(new Buffer(`Poll Time ${this.pollTime}`)); - this._output(new Buffer([this.pollTime])); - this._printEOT(); - } else { - this._printValidatedCommsTimeout(); - } - } - break; - case k.OBCIRadioCmdBaudRateSetDefault: - if (this.options.firmwareVersion === k.OBCIFirmwareV2) { - this._printSuccess(); - this._output(new Buffer('Switch your baud rate to 115200')); - this._output(new Buffer([0x24, 0x24, 0x24, 0xFF])); // The board really does this - } - break; - case k.OBCIRadioCmdBaudRateSetFast: - if (this.options.firmwareVersion === k.OBCIFirmwareV2) { - this._printSuccess(); - this._output(new Buffer('Switch your baud rate to 230400')); - this._output(new Buffer([0x24, 0x24, 0x24, 0xFF])); // The board really does this - } - break; - case k.OBCIRadioCmdSystemStatus: - if (this.options.firmwareVersion === k.OBCIFirmwareV2) { - if (!this.options.boardFailure) { - this._printSuccess(); - this._output(new Buffer('System is Up')); - this._printEOT(); - } else { - this._printFailure(); - this._output(new Buffer('System is Down')); - this._printEOT(); - } - } - break; - default: - break; - } - }; - - factory.OpenBCISimulator = OpenBCISimulator; -} - -util.inherits(OpenBCISimulatorFactory, EventEmitter); - -module.exports = new OpenBCISimulatorFactory(); diff --git a/package.json b/package.json index fbc0c90..4a4e726 100644 --- a/package.json +++ b/package.json @@ -1,13 +1,12 @@ { "name": "openbci", - "version": "1.5.1", - "description": "The official Node.js SDK for the OpenBCI Biosensor Board.", - "main": "openBCIBoard", + "version": "3.0.0", + "description": "The official Node.js SDK for the all OpenBCI Biosensor Boards.", + "main": "index.js", "scripts": { - "lint": "semistandard | snazzy", - "start": "node index", "test": "semistandard | snazzy && mocha test", - "test-cov": "istanbul cover ./node_modules/mocha/bin/_mocha -- -R spec && codecov" + "test-cov": "istanbul cover ./node_modules/mocha/bin/_mocha -- -R spec && codecov", + "test-lint": "semistandard | snazzy" }, "keywords": [ "openbci", @@ -16,31 +15,14 @@ "author": "AJ Keller (www.openbci.com)", "license": "MIT", "dependencies": { - "buffer-equal": "^1.0.0", - "gaussian": "^1.0.0", - "mathjs": "^3.3.0", - "performance-now": "^0.2.0", - "serialport": "4.0.1", - "sntp": "^2.0.0", - "streamsearch": "^0.1.2" + "openbci-cyton": "^1.0.7", + "openbci-ganglion": "^1.0.0", + "openbci-utilities": "^0.3.1", + "openbci-wifi": "^0.3.1" }, "directories": { "test": "test" }, - "devDependencies": { - "bluebird": "3.4.6", - "chai": "^3.4.1", - "chai-as-promised": "^5.2.0", - "codecov": "^1.0.1", - "istanbul": "^0.4.4", - "mocha": "^3.0.2", - "sandboxed-module": "^2.0.3", - "semistandard": "^9.0.0", - "sinon": "^1.17.2", - "sinon-as-promised": "^4.0.2", - "sinon-chai": "^2.8.0", - "snazzy": "^5.0.0" - }, "repository": { "type": "git", "url": "git+https://github.com/openbci/openbci_nodejs.git" @@ -55,6 +37,7 @@ "semistandard": { "globals": [ "describe", + "xdescribe", "context", "before", "beforeEach", diff --git a/test/OpenBCIConstants-test.js b/test/OpenBCIConstants-test.js deleted file mode 100644 index f51b2fa..0000000 --- a/test/OpenBCIConstants-test.js +++ /dev/null @@ -1,1478 +0,0 @@ -/** -* Created by ajk on 12/16/15. -*/ -'use strict'; -var bluebirdChecks = require('./bluebirdChecks'); -var assert = require('assert'); -var k = require('../openBCIConstants'); -var chai = require('chai'); -var expect = chai.expect; -var should = chai.should(); // eslint-disable-line no-unused-vars -var chaiAsPromised = require('chai-as-promised'); -chai.use(chaiAsPromised); - -describe('OpenBCIConstants', function () { - afterEach(() => bluebirdChecks.noPendingPromises()); - describe('Turning Channels Off', function () { - it('channel 1', function () { - assert.equal('1', k.OBCIChannelOff1); - }); - it('channel 2', function () { - assert.equal('2', k.OBCIChannelOff2); - }); - it('channel 3', function () { - assert.equal('3', k.OBCIChannelOff3); - }); - it('channel 4', function () { - assert.equal('4', k.OBCIChannelOff4); - }); - it('channel 5', function () { - assert.equal('5', k.OBCIChannelOff5); - }); - it('channel 6', function () { - assert.equal('6', k.OBCIChannelOff6); - }); - it('channel 7', function () { - assert.equal('7', k.OBCIChannelOff7); - }); - it('channel 8', function () { - assert.equal('8', k.OBCIChannelOff8); - }); - it('channel 9', function () { - assert.equal('q', k.OBCIChannelOff9); - }); - it('channel 10', function () { - assert.equal('w', k.OBCIChannelOff10); - }); - it('channel 11', function () { - assert.equal('e', k.OBCIChannelOff11); - }); - it('channel 12', function () { - assert.equal('r', k.OBCIChannelOff12); - }); - it('channel 13', function () { - assert.equal('t', k.OBCIChannelOff13); - }); - it('channel 14', function () { - assert.equal('y', k.OBCIChannelOff14); - }); - it('channel 15', function () { - assert.equal('u', k.OBCIChannelOff15); - }); - it('channel 16', function () { - assert.equal('i', k.OBCIChannelOff16); - }); - }); - describe('Turning Channels On', function () { - it('channel 1', function () { - assert.equal('!', k.OBCIChannelOn1); - }); - it('channel 2', function () { - assert.equal('@', k.OBCIChannelOn2); - }); - it('channel 3', function () { - assert.equal('#', k.OBCIChannelOn3); - }); - it('channel 4', function () { - assert.equal('$', k.OBCIChannelOn4); - }); - it('channel 5', function () { - assert.equal('%', k.OBCIChannelOn5); - }); - it('channel 6', function () { - assert.equal('^', k.OBCIChannelOn6); - }); - it('channel 7', function () { - assert.equal('&', k.OBCIChannelOn7); - }); - it('channel 8', function () { - assert.equal('*', k.OBCIChannelOn8); - }); - it('channel 9', function () { - assert.equal('Q', k.OBCIChannelOn9); - }); - it('channel 10', function () { - assert.equal('W', k.OBCIChannelOn10); - }); - it('channel 11', function () { - assert.equal('E', k.OBCIChannelOn11); - }); - it('channel 12', function () { - assert.equal('R', k.OBCIChannelOn12); - }); - it('channel 13', function () { - assert.equal('T', k.OBCIChannelOn13); - }); - it('channel 14', function () { - assert.equal('Y', k.OBCIChannelOn14); - }); - it('channel 15', function () { - assert.equal('U', k.OBCIChannelOn15); - }); - it('channel 16', function () { - assert.equal('I', k.OBCIChannelOn16); - }); - }); - describe('Test Signal Control Commands', function () { - it('Connect to DC', function () { - assert.equal('p', k.OBCITestSignalConnectToDC); - }); - it('Connect to Ground', function () { - assert.equal('0', k.OBCITestSignalConnectToGround); - }); - it('Connect to Pulse 1x Fast', function () { - assert.equal('=', k.OBCITestSignalConnectToPulse1xFast); - }); - it('Connect to Pulse 1x Slow', function () { - assert.equal('-', k.OBCITestSignalConnectToPulse1xSlow); - }); - it('Connect to Pulse 2x Fast', function () { - assert.equal(']', k.OBCITestSignalConnectToPulse2xFast); - }); - it('Connect to Pulse 2x Slow', function () { - assert.equal('[', k.OBCITestSignalConnectToPulse2xSlow); - }); - }); - describe('Channel Setting Commands', function () { - describe('Channel Selection', function () { - it('Channel 1', function () { - assert.equal('1', k.OBCIChannelCmdChannel1); - }); - it('Channel 2', function () { - assert.equal('2', k.OBCIChannelCmdChannel2); - }); - it('Channel 3', function () { - assert.equal('3', k.OBCIChannelCmdChannel3); - }); - it('Channel 4', function () { - assert.equal('4', k.OBCIChannelCmdChannel4); - }); - it('Channel 5', function () { - assert.equal('5', k.OBCIChannelCmdChannel5); - }); - it('Channel 6', function () { - assert.equal('6', k.OBCIChannelCmdChannel6); - }); - it('Channel 7', function () { - assert.equal('7', k.OBCIChannelCmdChannel7); - }); - it('Channel 8', function () { - assert.equal('8', k.OBCIChannelCmdChannel8); - }); - it('Channel 9', function () { - assert.equal('Q', k.OBCIChannelCmdChannel9); - }); - it('Channel 10', function () { - assert.equal('W', k.OBCIChannelCmdChannel10); - }); - it('Channel 11', function () { - assert.equal('E', k.OBCIChannelCmdChannel11); - }); - it('Channel 12', function () { - assert.equal('R', k.OBCIChannelCmdChannel12); - }); - it('Channel 13', function () { - assert.equal('T', k.OBCIChannelCmdChannel13); - }); - it('Channel 14', function () { - assert.equal('Y', k.OBCIChannelCmdChannel14); - }); - it('Channel 15', function () { - assert.equal('U', k.OBCIChannelCmdChannel15); - }); - it('Channel 16', function () { - assert.equal('I', k.OBCIChannelCmdChannel16); - }); - }); - describe('Power Down', function () { - it('OFF', function () { - assert.equal('1', k.OBCIChannelCmdPowerOff); - }); - it('ON', function () { - assert.equal('0', k.OBCIChannelCmdPowerOn); - }); - }); - describe('Gain Setting', function () { - it('1', function () { - assert.equal('0', k.OBCIChannelCmdGain1); - }); - it('2', function () { - assert.equal('1', k.OBCIChannelCmdGain2); - }); - it('4', function () { - assert.equal('2', k.OBCIChannelCmdGain4); - }); - it('6', function () { - assert.equal('3', k.OBCIChannelCmdGain6); - }); - it('8', function () { - assert.equal('4', k.OBCIChannelCmdGain8); - }); - it('12', function () { - assert.equal('5', k.OBCIChannelCmdGain12); - }); - it('24', function () { - assert.equal('6', k.OBCIChannelCmdGain24); - }); - }); - describe('ADC Channel Input Soruce', function () { - it('Normal', function () { - assert.equal('0', k.OBCIChannelCmdADCNormal); - }); - it('Shorted', function () { - assert.equal('1', k.OBCIChannelCmdADCShorted); - }); - it('Bias Method', function () { - assert.equal('2', k.OBCIChannelCmdADCBiasMethod); - }); - it('MVDD', function () { - assert.equal('3', k.OBCIChannelCmdADCMVDD); - }); - it('Temp', function () { - assert.equal('4', k.OBCIChannelCmdADCTemp); - }); - it('Test Signal', function () { - assert.equal('5', k.OBCIChannelCmdADCTestSig); - }); - it('Bias DRP', function () { - assert.equal('6', k.OBCIChannelCmdADCBiasDRP); - }); - it('Bias DRN', function () { - assert.equal('7', k.OBCIChannelCmdADCBiasDRN); - }); - }); - describe('Bias Set', function () { - it('Include in BIAS', function () { - assert.equal('1', k.OBCIChannelCmdBiasInclude); - }); - it('Remove from BIAS', function () { - assert.equal('0', k.OBCIChannelCmdBiasRemove); - }); - }); - describe('SRB2 Set', function () { - it('Disconnect this input from SRB2', function () { - assert.equal('0', k.OBCIChannelCmdSRB2Diconnect); - }); - it('Connect this input to the SRB2', function () { - assert.equal('1', k.OBCIChannelCmdSRB2Connect); - }); - }); - describe('SRB1 Set', function () { - it('Disconnect this input from SRB1', function () { - assert.equal('0', k.OBCIChannelCmdSRB1Diconnect); - }); - it('Connect this input to the SRB1', function () { - assert.equal('1', k.OBCIChannelCmdSRB1Connect); - }); - }); - it('Command to access channel settings', function () { - assert.equal('x', k.OBCIChannelCmdSet); - }); - it('Command to latch', function () { - assert.equal('X', k.OBCIChannelCmdLatch); - }); - }); - describe('Default Channel Settings', function () { - it('Set all channels to default', function () { - assert.equal('d', k.OBCIChannelDefaultAllSet); - }); - it('Get a report of the default settings card', function () { - assert.equal('D', k.OBCIChannelDefaultAllGet); - }); - }); - describe('LeadOff Impedance Commands', function () { - it('Command to access impedance settings', function () { - assert.equal('z', k.OBCIChannelImpedanceSet); - }); - it('Command to latch', function () { - assert.equal('Z', k.OBCIChannelImpedanceLatch); - }); - it('Test signal not applied', function () { - assert.equal('0', k.OBCIChannelImpedanceTestSignalAppliedNot); - }); - it('Test signal applied', function () { - assert.equal('1', k.OBCIChannelImpedanceTestSignalApplied); - }); - }); - describe('Time Sync Stuff', function () { - it('Can get proper array size', function () { - assert.equal(10, k.OBCITimeSyncArraySize); - }); - it('Get correct time sync with conf', function () { - assert.equal(0.9, k.OBCITimeSyncMultiplierWithSyncConf); - }); - it('Get correct time sync without conf', function () { - assert.equal(0.75, k.OBCITimeSyncMultiplierWithoutSyncConf); - }); - it('Get correct time sync transmission threshold', function () { - assert.equal(10, k.OBCITimeSyncThresholdTransFailureMS); - }); - }); - describe('SD card Commands', function () { - it('logs for 1 hour', function () { - assert.equal('G', k.OBCISDLogForHour1); - }); - it('logs for 2 hours', function () { - assert.equal('H', k.OBCISDLogForHour2); - }); - it('logs for 4 hours', function () { - assert.equal('J', k.OBCISDLogForHour4); - }); - it('logs for 12 hours', function () { - assert.equal('K', k.OBCISDLogForHour12); - }); - it('logs for 24 hours', function () { - assert.equal('L', k.OBCISDLogForHour24); - }); - it('logs for 5 minutes', function () { - assert.equal('A', k.OBCISDLogForMin5); - }); - it('logs for 15 minutes', function () { - assert.equal('S', k.OBCISDLogForMin15); - }); - it('logs for 30 minutes', function () { - assert.equal('F', k.OBCISDLogForMin30); - }); - it('logs for 14 seconds', function () { - assert.equal('a', k.OBCISDLogForSec14); - }); - it('stop logging and close the SD file', 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); - }); - it('stops', function () { - assert.equal('s', k.OBCIStreamStop); - }); - }); - describe('Miscellaneous', function () { - it('queries register settings', function () { - assert.equal('?', k.OBCIMiscQueryRegisterSettings); - }); - it('softly resets the board', function () { - assert.equal('v', k.OBCIMiscSoftReset); - }); - }); - describe('Max channel number commands', function () { - it('sets max of 8', function () { - assert.equal('c', k.OBCIChannelMaxNumber8); - }); - it('sets max of 16', function () { - assert.equal('C', k.OBCIChannelMaxNumber16); - }); - it('has correct return messages', function () { - assert.equal('', k.OBCIChannelMaxNumber8NoDaisyToRemove); - assert.equal('daisy removed', k.OBCIChannelMaxNumber8SuccessDaisyRemoved); - assert.equal('16', k.OBCIChannelMaxNumber16DaisyAlreadyAttached); - assert.equal('daisy attached16', k.OBCIChannelMaxNumber16DaisyAttached); - assert.equal('no daisy to attach!8', k.OBCIChannelMaxNumber16NoDaisyAttached); - }); - }); - describe('On board filters', function () { - it('disable', function () { - assert.equal('g', k.OBCIFilterDisable); - }); - it('enable', function () { - assert.equal('f', k.OBCIFilterEnable); - }); - }); - describe('Stream packet types/codes', function () { - it('Standard with Accel', function () { - assert.equal(0, k.OBCIStreamPacketStandardAccel); - }); - it('Standard with Raw Aux', function () { - assert.equal(1, k.OBCIStreamPacketStandardRawAux); - }); - it('User Defined Packet', function () { - assert.equal(2, k.OBCIStreamPacketUserDefinedType); - }); - it('Time Sync Set with accel', function () { - assert.equal(3, k.OBCIStreamPacketAccelTimeSyncSet); - }); - it('Time Synced with Accel', function () { - assert.equal(4, k.OBCIStreamPacketAccelTimeSynced); - }); - it('Time Sync set with Raw Aux', function () { - assert.equal(5, k.OBCIStreamPacketRawAuxTimeSyncSet); - }); - it('Time Synced with Raw Aux', function () { - assert.equal(6, k.OBCIStreamPacketRawAuxTimeSynced); - }); - }); - describe('Time synced with accel packet', function () { - it('X axis', function () { - assert.equal(7, k.OBCIAccelAxisX); - }); - it('Y axis', function () { - assert.equal(8, k.OBCIAccelAxisY); - }); - it('Z axis', function () { - assert.equal(9, k.OBCIAccelAxisZ); - }); - }); - describe('Time sync useful numbers', function () { - it('Time from the board is 4 bytes', function () { - assert.equal(4, k.OBCIStreamPacketTimeByteSize); - }); - }); - describe('should return the right command for each channel', function () { - it('Channel 1', function () { - var expectation = '1'; - var result = k.commandChannelForCmd(1); - return expect(result).to.eventually.equal(expectation); - }); - it('Channel 2', function () { - var expectation = '2'; - var result = k.commandChannelForCmd(2); - return expect(result).to.eventually.equal(expectation); - }); - it('Channel 3', function () { - var expectation = '3'; - var result = k.commandChannelForCmd(3); - return expect(result).to.eventually.equal(expectation); - }); - it('Channel 4', function () { - var expectation = '4'; - var result = k.commandChannelForCmd(4); - return expect(result).to.eventually.equal(expectation); - }); - it('Channel 5', function () { - var expectation = '5'; - var result = k.commandChannelForCmd(5); - return expect(result).to.eventually.equal(expectation); - }); - it('Channel 6', function () { - var expectation = '6'; - var result = k.commandChannelForCmd(6); - return expect(result).to.eventually.equal(expectation); - }); - it('Channel 7', function () { - var expectation = '7'; - var result = k.commandChannelForCmd(7); - return expect(result).to.eventually.equal(expectation); - }); - it('Channel 8', function () { - var expectation = '8'; - var result = k.commandChannelForCmd(8); - return expect(result).to.eventually.equal(expectation); - }); - it('Channel 9', function () { - var expectation = 'Q'; - var result = k.commandChannelForCmd(9); - return expect(result).to.eventually.equal(expectation); - }); - it('Channel 10', function () { - var expectation = 'W'; - var result = k.commandChannelForCmd(10); - return expect(result).to.eventually.equal(expectation); - }); - it('Channel 11', function () { - var expectation = 'E'; - var result = k.commandChannelForCmd(11); - return expect(result).to.eventually.equal(expectation); - }); - it('Channel 12', function () { - var expectation = 'R'; - var result = k.commandChannelForCmd(12); - return expect(result).to.eventually.equal(expectation); - }); - it('Channel 13', function () { - var expectation = 'T'; - var result = k.commandChannelForCmd(13); - return expect(result).to.eventually.equal(expectation); - }); - it('Channel 14', function () { - var expectation = 'Y'; - var result = k.commandChannelForCmd(14); - return expect(result).to.eventually.equal(expectation); - }); - it('Channel 15', function () { - var expectation = 'U'; - var result = k.commandChannelForCmd(15); - return expect(result).to.eventually.equal(expectation); - }); - it('Channel 16', function () { - var expectation = 'I'; - var result = k.commandChannelForCmd(16); - return expect(result).to.eventually.equal(expectation); - }); - it('Invalid channel request', function () { - var result = k.commandChannelForCmd(17); - return expect(result).to.be.rejected; - }); - }); - describe('should return correct channel off command for number', function () { - it('Channel 1', function () { - var expectation = '1'; - var result = k.commandChannelOff(1); - return expect(result).to.eventually.equal(expectation); - }); - it('Channel 2', function () { - var expectation = '2'; - var result = k.commandChannelOff(2); - return expect(result).to.eventually.equal(expectation); - }); - it('Channel 3', function () { - var expectation = '3'; - var result = k.commandChannelOff(3); - return expect(result).to.eventually.equal(expectation); - }); - it('Channel 4', function () { - var expectation = '4'; - var result = k.commandChannelOff(4); - return expect(result).to.eventually.equal(expectation); - }); - it('Channel 5', function () { - var expectation = '5'; - var result = k.commandChannelOff(5); - return expect(result).to.eventually.equal(expectation); - }); - it('Channel 6', function () { - var expectation = '6'; - var result = k.commandChannelOff(6); - return expect(result).to.eventually.equal(expectation); - }); - it('Channel 7', function () { - var expectation = '7'; - var result = k.commandChannelOff(7); - return expect(result).to.eventually.equal(expectation); - }); - it('Channel 8', function () { - var expectation = '8'; - var result = k.commandChannelOff(8); - return expect(result).to.eventually.equal(expectation); - }); - it('Channel 9', function () { - var expectation = 'q'; - var result = k.commandChannelOff(9); - return expect(result).to.eventually.equal(expectation); - }); - it('Channel 10', function () { - var expectation = 'w'; - var result = k.commandChannelOff(10); - return expect(result).to.eventually.equal(expectation); - }); - it('Channel 11', function () { - var expectation = 'e'; - var result = k.commandChannelOff(11); - return expect(result).to.eventually.equal(expectation); - }); - it('Channel 12', function () { - var expectation = 'r'; - var result = k.commandChannelOff(12); - return expect(result).to.eventually.equal(expectation); - }); - it('Channel 13', function () { - var expectation = 't'; - var result = k.commandChannelOff(13); - return expect(result).to.eventually.equal(expectation); - }); - it('Channel 14', function () { - var expectation = 'y'; - var result = k.commandChannelOff(14); - return expect(result).to.eventually.equal(expectation); - }); - it('Channel 15', function () { - var expectation = 'u'; - var result = k.commandChannelOff(15); - return expect(result).to.eventually.equal(expectation); - }); - it('Channel 16', function () { - var expectation = 'i'; - var result = k.commandChannelOff(16); - return expect(result).to.eventually.equal(expectation); - }); - it('Invalid channel request', function () { - var result = k.commandChannelOff(17); - return expect(result).to.be.rejected; - }); - }); - describe('should return correct channel on command for number', function () { - it('Channel 1', function () { - var expectation = '!'; - var result = k.commandChannelOn(1); - return expect(result).to.eventually.equal(expectation); - }); - it('Channel 2', function () { - var expectation = '@'; - var result = k.commandChannelOn(2); - return expect(result).to.eventually.equal(expectation); - }); - it('Channel 3', function () { - var expectation = '#'; - var result = k.commandChannelOn(3); - return expect(result).to.eventually.equal(expectation); - }); - it('Channel 4', function () { - var expectation = '$'; - var result = k.commandChannelOn(4); - return expect(result).to.eventually.equal(expectation); - }); - it('Channel 5', function () { - var expectation = '%'; - var result = k.commandChannelOn(5); - return expect(result).to.eventually.equal(expectation); - }); - it('Channel 6', function () { - var expectation = '^'; - var result = k.commandChannelOn(6); - return expect(result).to.eventually.equal(expectation); - }); - it('Channel 7', function () { - var expectation = '&'; - var result = k.commandChannelOn(7); - return expect(result).to.eventually.equal(expectation); - }); - it('Channel 8', function () { - var expectation = '*'; - var result = k.commandChannelOn(8); - return expect(result).to.eventually.equal(expectation); - }); - it('Channel 9', function () { - var expectation = 'Q'; - var result = k.commandChannelOn(9); - return expect(result).to.eventually.equal(expectation); - }); - it('Channel 10', function () { - var expectation = 'W'; - var result = k.commandChannelOn(10); - return expect(result).to.eventually.equal(expectation); - }); - it('Channel 11', function () { - var expectation = 'E'; - var result = k.commandChannelOn(11); - return expect(result).to.eventually.equal(expectation); - }); - it('Channel 12', function () { - var expectation = 'R'; - var result = k.commandChannelOn(12); - return expect(result).to.eventually.equal(expectation); - }); - it('Channel 13', function () { - var expectation = 'T'; - var result = k.commandChannelOn(13); - return expect(result).to.eventually.equal(expectation); - }); - it('Channel 14', function () { - var expectation = 'Y'; - var result = k.commandChannelOn(14); - return expect(result).to.eventually.equal(expectation); - }); - it('Channel 15', function () { - var expectation = 'U'; - var result = k.commandChannelOn(15); - return expect(result).to.eventually.equal(expectation); - }); - it('Channel 16', function () { - var expectation = 'I'; - var result = k.commandChannelOn(16); - return expect(result).to.eventually.equal(expectation); - }); - it('Invalid channel request', function () { - var result = k.commandChannelOn(17); - return expect(result).to.be.rejected; - }); - }); - describe('Number of channels', function () { - it('Daisy', function () { - assert.equal(16, k.OBCINumberOfChannelsDaisy); - }); - it('Default', function () { - assert.equal(8, k.OBCINumberOfChannelsDefault); - }); - it('Ganglion', function () { - assert.equal(4, k.OBCINumberOfChannelsGanglion); - }); - }); - describe('Possible Sample Rates', function () { - it('should be 125', function () { - assert.equal(125, k.OBCISampleRate125); - }); - it('should be 250', function () { - assert.equal(250, k.OBCISampleRate250); - }); - }); - describe('Max sample number', function () { - it('should be 255', function () { - assert.equal(255, k.OBCISampleNumberMax); - }); - }); - describe('Radio Channel Limits', function () { - it('should get the right channel number max', function () { - expect(k.OBCIRadioChannelMax).to.be.equal(25); - }); - it('should get the right channel number min', function () { - expect(k.OBCIRadioChannelMin).to.be.equal(1); - }); - it('should get the right poll time max', function () { - expect(k.OBCIRadioPollTimeMax).to.be.equal(255); - }); - it('should get the right poll time min', function () { - expect(k.OBCIRadioPollTimeMin).to.be.equal(0); - }); - }); - describe('#getChannelSetter', 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 (done) { - k.getChannelSetter(2, false, 24, 'normal', true, true, false).then(function (val) { - val.commandArray[1].should.equal('2'); - val.newChannelSettingsObject.channelNumber.should.equal(2); - val.newChannelSettingsObject.powerDown.should.equal(false); - val.newChannelSettingsObject.gain.should.equal(24); - val.newChannelSettingsObject.inputType.should.equal('normal'); - val.newChannelSettingsObject.bias.should.equal(true); - val.newChannelSettingsObject.srb2.should.equal(true); - val.newChannelSettingsObject.srb1.should.equal(false); - done(); - }).catch(function (err) { - done(err); - }); - }); - it('channel 5', function (done) { - k.getChannelSetter(5, false, 24, 'normal', true, true, false).then(function (val) { - val.commandArray[1].should.equal('5'); - val.newChannelSettingsObject.channelNumber.should.equal(5); - val.newChannelSettingsObject.powerDown.should.equal(false); - val.newChannelSettingsObject.gain.should.equal(24); - val.newChannelSettingsObject.inputType.should.equal('normal'); - val.newChannelSettingsObject.bias.should.equal(true); - val.newChannelSettingsObject.srb2.should.equal(true); - val.newChannelSettingsObject.srb1.should.equal(false); - done(); - }).catch(function (err) { - done(err); - }); - }); - it('channel 9', function (done) { - k.getChannelSetter(9, false, 24, 'normal', true, true, false).then(function (val) { - val.commandArray[1].should.equal('Q'); - val.newChannelSettingsObject.channelNumber.should.equal(9); - val.newChannelSettingsObject.powerDown.should.equal(false); - val.newChannelSettingsObject.gain.should.equal(24); - val.newChannelSettingsObject.inputType.should.equal('normal'); - val.newChannelSettingsObject.bias.should.equal(true); - val.newChannelSettingsObject.srb2.should.equal(true); - val.newChannelSettingsObject.srb1.should.equal(false); - done(); - }).catch(function (err) { - done(err); - }); - }); - it('channel 15', function (done) { - k.getChannelSetter(15, false, 24, 'normal', true, true, false).then(function (val) { - val.commandArray[1].should.equal('U'); - val.newChannelSettingsObject.channelNumber.should.equal(15); - val.newChannelSettingsObject.powerDown.should.equal(false); - val.newChannelSettingsObject.gain.should.equal(24); - val.newChannelSettingsObject.inputType.should.equal('normal'); - val.newChannelSettingsObject.bias.should.equal(true); - val.newChannelSettingsObject.srb2.should.equal(true); - val.newChannelSettingsObject.srb1.should.equal(false); - done(); - }).catch(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 (done) { - k.getChannelSetter('0', false, 24, 'normal', true, true, false).should.be.rejected.and.notify(done); - }); - }); - describe('power selection works', function () { - it('on', function (done) { - k.getChannelSetter(1, false, 24, 'normal', true, true, false).then(function (val) { - val.commandArray[2].should.equal('0'); - val.newChannelSettingsObject.channelNumber.should.equal(1); - val.newChannelSettingsObject.powerDown.should.equal(false); - val.newChannelSettingsObject.gain.should.equal(24); - val.newChannelSettingsObject.inputType.should.equal('normal'); - val.newChannelSettingsObject.bias.should.equal(true); - val.newChannelSettingsObject.srb2.should.equal(true); - val.newChannelSettingsObject.srb1.should.equal(false); - done(); - }).catch(function (err) { - done(err); - }); - }); - it('off', function (done) { - k.getChannelSetter(1, true, 24, 'normal', true, true, false).then(function (val) { - val.commandArray[2].should.equal('1'); - val.newChannelSettingsObject.channelNumber.should.equal(1); - val.newChannelSettingsObject.powerDown.should.equal(true); - val.newChannelSettingsObject.gain.should.equal(24); - val.newChannelSettingsObject.inputType.should.equal('normal'); - val.newChannelSettingsObject.bias.should.equal(true); - val.newChannelSettingsObject.srb2.should.equal(true); - val.newChannelSettingsObject.srb1.should.equal(false); - done(); - }).catch(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 (done) { - k.getChannelSetter(1, false, 1, 'normal', true, true, false).then(function (val) { - val.commandArray[3].should.equal('0'); - val.newChannelSettingsObject.channelNumber.should.equal(1); - val.newChannelSettingsObject.powerDown.should.equal(false); - val.newChannelSettingsObject.gain.should.equal(1); - val.newChannelSettingsObject.inputType.should.equal('normal'); - val.newChannelSettingsObject.bias.should.equal(true); - val.newChannelSettingsObject.srb2.should.equal(true); - val.newChannelSettingsObject.srb1.should.equal(false); - done(); - }).catch(function (err) { - done(err); - }); - }); - it('2x', function (done) { - k.getChannelSetter(1, false, 2, 'normal', true, true, false).then(function (val) { - val.commandArray[3].should.equal('1'); - val.newChannelSettingsObject.channelNumber.should.equal(1); - val.newChannelSettingsObject.powerDown.should.equal(false); - val.newChannelSettingsObject.gain.should.equal(2); - val.newChannelSettingsObject.inputType.should.equal('normal'); - val.newChannelSettingsObject.bias.should.equal(true); - val.newChannelSettingsObject.srb2.should.equal(true); - val.newChannelSettingsObject.srb1.should.equal(false); - done(); - }).catch(function (err) { - done(err); - }); - }); - it('4x', function (done) { - k.getChannelSetter(1, false, 4, 'normal', true, true, false).then(function (val) { - val.commandArray[3].should.equal('2'); - val.newChannelSettingsObject.channelNumber.should.equal(1); - val.newChannelSettingsObject.powerDown.should.equal(false); - val.newChannelSettingsObject.gain.should.equal(4); - val.newChannelSettingsObject.inputType.should.equal('normal'); - val.newChannelSettingsObject.bias.should.equal(true); - val.newChannelSettingsObject.srb2.should.equal(true); - val.newChannelSettingsObject.srb1.should.equal(false); - done(); - }).catch(function (err) { - done(err); - }); - }); - it('6x', function (done) { - k.getChannelSetter(1, false, 6, 'normal', true, true, false).then(function (val) { - val.commandArray[3].should.equal('3'); - val.newChannelSettingsObject.channelNumber.should.equal(1); - val.newChannelSettingsObject.powerDown.should.equal(false); - val.newChannelSettingsObject.gain.should.equal(6); - val.newChannelSettingsObject.inputType.should.equal('normal'); - val.newChannelSettingsObject.bias.should.equal(true); - val.newChannelSettingsObject.srb2.should.equal(true); - val.newChannelSettingsObject.srb1.should.equal(false); - done(); - }).catch(function (err) { - done(err); - }); - }); - it('8x', function (done) { - k.getChannelSetter(1, false, 8, 'normal', true, true, false).then(function (val) { - val.commandArray[3].should.equal('4'); - val.newChannelSettingsObject.channelNumber.should.equal(1); - val.newChannelSettingsObject.powerDown.should.equal(false); - val.newChannelSettingsObject.gain.should.equal(8); - val.newChannelSettingsObject.inputType.should.equal('normal'); - val.newChannelSettingsObject.bias.should.equal(true); - val.newChannelSettingsObject.srb2.should.equal(true); - val.newChannelSettingsObject.srb1.should.equal(false); - done(); - }).catch(function (err) { - done(err); - }); - }); - it('12x', function (done) { - k.getChannelSetter(1, false, 12, 'normal', true, true, false).then(function (val) { - val.commandArray[3].should.equal('5'); - val.newChannelSettingsObject.channelNumber.should.equal(1); - val.newChannelSettingsObject.powerDown.should.equal(false); - val.newChannelSettingsObject.gain.should.equal(12); - val.newChannelSettingsObject.inputType.should.equal('normal'); - val.newChannelSettingsObject.bias.should.equal(true); - val.newChannelSettingsObject.srb2.should.equal(true); - val.newChannelSettingsObject.srb1.should.equal(false); - done(); - }).catch(function (err) { - done(err); - }); - }); - it('24x', function (done) { - k.getChannelSetter(1, false, 24, 'normal', true, true, false).then(function (val) { - val.commandArray[3].should.equal('6'); - val.newChannelSettingsObject.channelNumber.should.equal(1); - val.newChannelSettingsObject.powerDown.should.equal(false); - val.newChannelSettingsObject.gain.should.equal(24); - val.newChannelSettingsObject.inputType.should.equal('normal'); - val.newChannelSettingsObject.bias.should.equal(true); - val.newChannelSettingsObject.srb2.should.equal(true); - val.newChannelSettingsObject.srb1.should.equal(false); - done(); - }).catch(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 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 (done) { - k.getChannelSetter(1, false, 24, 'normal', true, true, false).then(function (val) { - val.commandArray[4].should.equal('0'); - val.newChannelSettingsObject.channelNumber.should.equal(1); - val.newChannelSettingsObject.powerDown.should.equal(false); - val.newChannelSettingsObject.gain.should.equal(24); - val.newChannelSettingsObject.inputType.should.equal('normal'); - val.newChannelSettingsObject.bias.should.equal(true); - val.newChannelSettingsObject.srb2.should.equal(true); - val.newChannelSettingsObject.srb1.should.equal(false); - done(); - }).catch(function (err) { - done(err); - }); - }); - it('shorted', function (done) { - k.getChannelSetter(1, false, 24, 'shorted', true, true, false).then(function (val) { - val.commandArray[4].should.equal('1'); - val.newChannelSettingsObject.channelNumber.should.equal(1); - val.newChannelSettingsObject.powerDown.should.equal(false); - val.newChannelSettingsObject.gain.should.equal(24); - val.newChannelSettingsObject.inputType.should.equal('shorted'); - val.newChannelSettingsObject.bias.should.equal(true); - val.newChannelSettingsObject.srb2.should.equal(true); - val.newChannelSettingsObject.srb1.should.equal(false); - done(); - }).catch(function (err) { - done(err); - }); - }); - it('biasMethod', function (done) { - k.getChannelSetter(1, false, 24, 'biasMethod', true, true, false).then(function (val) { - val.commandArray[4].should.equal('2'); - val.newChannelSettingsObject.channelNumber.should.equal(1); - val.newChannelSettingsObject.powerDown.should.equal(false); - val.newChannelSettingsObject.gain.should.equal(24); - val.newChannelSettingsObject.inputType.should.equal('biasMethod'); - val.newChannelSettingsObject.bias.should.equal(true); - val.newChannelSettingsObject.srb2.should.equal(true); - val.newChannelSettingsObject.srb1.should.equal(false); - done(); - }).catch(function (err) { - done(err); - }); - }); - it('mvdd', function (done) { - k.getChannelSetter(1, false, 24, 'mvdd', true, true, false).then(function (val) { - val.commandArray[4].should.equal('3'); - val.newChannelSettingsObject.channelNumber.should.equal(1); - val.newChannelSettingsObject.powerDown.should.equal(false); - val.newChannelSettingsObject.gain.should.equal(24); - val.newChannelSettingsObject.inputType.should.equal('mvdd'); - val.newChannelSettingsObject.bias.should.equal(true); - val.newChannelSettingsObject.srb2.should.equal(true); - val.newChannelSettingsObject.srb1.should.equal(false); - done(); - }).catch(function (err) { - done(err); - }); - }); - it('temp', function (done) { - k.getChannelSetter(1, false, 24, 'temp', true, true, false).then(function (val) { - val.commandArray[4].should.equal('4'); - val.newChannelSettingsObject.channelNumber.should.equal(1); - val.newChannelSettingsObject.powerDown.should.equal(false); - val.newChannelSettingsObject.gain.should.equal(24); - val.newChannelSettingsObject.inputType.should.equal('temp'); - val.newChannelSettingsObject.bias.should.equal(true); - val.newChannelSettingsObject.srb2.should.equal(true); - val.newChannelSettingsObject.srb1.should.equal(false); - done(); - }).catch(function (err) { - done(err); - }); - }); - it('testsig', function (done) { - k.getChannelSetter(1, false, 24, 'testSig', true, true, false).then(function (val) { - val.commandArray[4].should.equal('5'); - val.newChannelSettingsObject.channelNumber.should.equal(1); - val.newChannelSettingsObject.powerDown.should.equal(false); - val.newChannelSettingsObject.gain.should.equal(24); - val.newChannelSettingsObject.inputType.should.equal('testSig'); - val.newChannelSettingsObject.bias.should.equal(true); - val.newChannelSettingsObject.srb2.should.equal(true); - val.newChannelSettingsObject.srb1.should.equal(false); - done(); - }).catch(function (err) { - done(err); - }); - }); - it('biasDrp', function (done) { - k.getChannelSetter(1, false, 24, 'biasDrp', true, true, false).then(function (val) { - val.commandArray[4].should.equal('6'); - val.newChannelSettingsObject.channelNumber.should.equal(1); - val.newChannelSettingsObject.powerDown.should.equal(false); - val.newChannelSettingsObject.gain.should.equal(24); - val.newChannelSettingsObject.inputType.should.equal('biasDrp'); - val.newChannelSettingsObject.bias.should.equal(true); - val.newChannelSettingsObject.srb2.should.equal(true); - val.newChannelSettingsObject.srb1.should.equal(false); - done(); - }).catch(function (err) { - done(err); - }); - }); - it('biasDrn', function (done) { - k.getChannelSetter(1, false, 24, 'biasDrn', true, true, false).then(function (val) { - val.commandArray[4].should.equal('7'); - val.newChannelSettingsObject.channelNumber.should.equal(1); - val.newChannelSettingsObject.powerDown.should.equal(false); - val.newChannelSettingsObject.gain.should.equal(24); - val.newChannelSettingsObject.inputType.should.equal('biasDrn'); - val.newChannelSettingsObject.bias.should.equal(true); - val.newChannelSettingsObject.srb2.should.equal(true); - val.newChannelSettingsObject.srb1.should.equal(false); - done(); - }).catch(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 (done) { - k.getChannelSetter(1, false, 24, 1, true, true, false).should.be.rejected.and.notify(done); - }); - }); - describe('bias selection works', function () { - it('Include', function (done) { - k.getChannelSetter(1, false, 24, 'normal', true, true, false).then(function (val) { - val.commandArray[5].should.equal('1'); - val.newChannelSettingsObject.channelNumber.should.equal(1); - val.newChannelSettingsObject.powerDown.should.equal(false); - val.newChannelSettingsObject.gain.should.equal(24); - val.newChannelSettingsObject.inputType.should.equal('normal'); - val.newChannelSettingsObject.bias.should.equal(true); - val.newChannelSettingsObject.srb2.should.equal(true); - val.newChannelSettingsObject.srb1.should.equal(false); - done(); - }).catch(function (err) { - done(err); - }); - }); - it('Remove', function (done) { - k.getChannelSetter(1, false, 24, 'normal', false, true, false).then(function (val) { - val.commandArray[5].should.equal('0'); - val.newChannelSettingsObject.channelNumber.should.equal(1); - val.newChannelSettingsObject.powerDown.should.equal(false); - val.newChannelSettingsObject.gain.should.equal(24); - val.newChannelSettingsObject.inputType.should.equal('normal'); - val.newChannelSettingsObject.bias.should.equal(false); - val.newChannelSettingsObject.srb2.should.equal(true); - val.newChannelSettingsObject.srb1.should.equal(false); - done(); - }).catch(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 (done) { - k.getChannelSetter(1, false, 24, 'normal', true, true, false).then(function (val) { - val.commandArray[6].should.equal('1'); - val.newChannelSettingsObject.channelNumber.should.equal(1); - val.newChannelSettingsObject.powerDown.should.equal(false); - val.newChannelSettingsObject.gain.should.equal(24); - val.newChannelSettingsObject.inputType.should.equal('normal'); - val.newChannelSettingsObject.bias.should.equal(true); - val.newChannelSettingsObject.srb2.should.equal(true); - val.newChannelSettingsObject.srb1.should.equal(false); - done(); - }).catch(function (err) { - done(err); - }); - }); - it('Disconnect', function (done) { - k.getChannelSetter(1, false, 24, 'normal', true, false, false).then(function (val) { - val.commandArray[6].should.equal('0'); - val.newChannelSettingsObject.channelNumber.should.equal(1); - val.newChannelSettingsObject.powerDown.should.equal(false); - val.newChannelSettingsObject.gain.should.equal(24); - val.newChannelSettingsObject.inputType.should.equal('normal'); - val.newChannelSettingsObject.bias.should.equal(true); - val.newChannelSettingsObject.srb2.should.equal(false); - val.newChannelSettingsObject.srb1.should.equal(false); - done(); - }).catch(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 (done) { - k.getChannelSetter(1, false, 24, 'normal', true, true, true).then(function (val) { - val.commandArray[7].should.equal('1'); - val.newChannelSettingsObject.channelNumber.should.equal(1); - val.newChannelSettingsObject.powerDown.should.equal(false); - val.newChannelSettingsObject.gain.should.equal(24); - val.newChannelSettingsObject.inputType.should.equal('normal'); - val.newChannelSettingsObject.bias.should.equal(true); - val.newChannelSettingsObject.srb2.should.equal(true); - val.newChannelSettingsObject.srb1.should.equal(true); - done(); - }).catch(function (err) { - done(err); - }); - }); - it('Disconnect', function (done) { - k.getChannelSetter(1, false, 24, 'normal', true, true, false).then(function (val) { - val.commandArray[7].should.equal('0'); - val.newChannelSettingsObject.channelNumber.should.equal(1); - val.newChannelSettingsObject.powerDown.should.equal(false); - val.newChannelSettingsObject.gain.should.equal(24); - val.newChannelSettingsObject.inputType.should.equal('normal'); - val.newChannelSettingsObject.bias.should.equal(true); - val.newChannelSettingsObject.srb2.should.equal(true); - val.newChannelSettingsObject.srb1.should.equal(false); - done(); - }).catch(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('#getTestSignalCommand', function () { - it('ground', function () { - var expectation = '0'; - var result = k.getTestSignalCommand('ground'); - return expect(result).to.eventually.equal(expectation); - }); - it('dc', function () { - var expectation = 'p'; - var result = k.getTestSignalCommand('dc'); - return expect(result).to.eventually.equal(expectation); - }); - it('Pulse 1x Fast', function () { - var expectation = '='; - var result = k.getTestSignalCommand('pulse1xFast'); - return expect(result).to.eventually.equal(expectation); - }); - it('Pulse 1x Slow', function () { - var expectation = '-'; - var result = k.getTestSignalCommand('pulse1xSlow'); - return expect(result).to.eventually.equal(expectation); - }); - it('Pulse 2x Fast', function () { - var expectation = ']'; - var result = k.getTestSignalCommand('pulse2xFast'); - return expect(result).to.eventually.equal(expectation); - }); - it('Pulse 2x Slow', function () { - var expectation = '['; - var result = k.getTestSignalCommand('pulse2xSlow'); - return expect(result).to.eventually.equal(expectation); - }); - it('none', function () { - var expectation = 'd'; - var result = k.getTestSignalCommand('none'); - return expect(result).to.eventually.equal(expectation); - }); - }); - describe('#getVersionNumber', function () { - it('should get the major version number from a github standard version string', () => { - var expectedVersion = 6; - var inputStringVersion = 'v6.0.0'; - - expect(k.getVersionNumber(inputStringVersion)).to.equal(expectedVersion); - }); - }); - describe('#getImpedanceSetter', function () { - describe('channel input selection works', function () { - it('channel 2', function (done) { - k.getImpedanceSetter(2, false, false).then(function (arrayOfCommands) { - arrayOfCommands[1].should.equal('2'); - done(); - }).catch(function (err) { - done(err); - }); - }); - it('channel 5', function (done) { - k.getImpedanceSetter(5, false, false).then(function (arrayOfCommands) { - arrayOfCommands[1].should.equal('5'); - done(); - }).catch(function (err) { - done(err); - }); - }); - it('channel 9', function (done) { - k.getImpedanceSetter(9, false, false).then(function (arrayOfCommands) { - arrayOfCommands[1].should.equal('Q'); - done(); - }).catch(function (err) { - done(err); - }); - }); - it('channel 15', function (done) { - k.getImpedanceSetter(15, false, false).then(function (arrayOfCommands) { - arrayOfCommands[1].should.equal('U'); - done(); - }).catch(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 (done) { - k.getImpedanceSetter('1', false, false).should.be.rejected.and.notify(done); - }); - }); - describe('P Input selection works', function () { - it('Test Signal Applied', function (done) { - k.getImpedanceSetter(1, true, false).then(function (arrayOfCommands) { - arrayOfCommands[2].should.equal('1'); - done(); - }).catch(function (err) { - done(err); - }); - }); - 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(); - }).catch(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 () { - it('Test Signal Applied', function (done) { - k.getImpedanceSetter(1, false, true).then(function (arrayOfCommands) { - arrayOfCommands[3].should.equal('1'); - done(); - }).catch(function (err) { - done(err); - }); - }); - it('Test Signal Not Applied', function (done) { - k.getImpedanceSetter(1, false, false).then(function (arrayOfCommands) { - arrayOfCommands[3].should.equal('0'); - done(); - }).catch(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 (done) { - k.getImpedanceSetter(1, true, true).then(function (arrayOfCommands) { - arrayOfCommands[0].should.equal('z'); - done(); - }).catch(function (err) { - done(err); - }); - }); - it('Latch', function (done) { - k.getImpedanceSetter(1, true, true).then(function (arrayOfCommands) { - arrayOfCommands[4].should.equal('Z'); - done(); - }).catch(function (err) { - done(err); - }); - }); - }); - }); - describe('fun funcs', function () { - describe('#isNumber', function () { - it('should return true for object of named type', function () { - expect(k.isNumber(1)).to.equal(true); - }); - it('should return false for not of named type', function () { - expect(k.isNumber('taco')).to.equal(false); - }); - }); - describe('#isBoolean', function () { - it('should return true for object of named type', function () { - expect(k.isBoolean(true)).to.equal(true); - }); - it('should return false for not of named type', function () { - expect(k.isBoolean('taco')).to.equal(false); - }); - }); - describe('#isString', function () { - it('should return true for object of named type', function () { - expect(k.isString('taco')).to.equal(true); - }); - it('should return false for not of named type', function () { - expect(k.isString(1)).to.equal(false); - }); - }); - describe('#isUndefined', function () { - it('should return true for object of named type', function () { - expect(k.isUndefined()).to.equal(true); - }); - it('should return false for not of named type', function () { - expect(k.isUndefined('im here')).to.equal(false); - }); - }); - describe('#isNull', function () { - it('should return true for object of named type', function () { - expect(k.isNull(null)).to.equal(true); - }); - it('should return false for not of named type', function () { - expect(k.isNull()).to.equal(false); - }); - it('should return false for not of named type', function () { - expect(k.isNull('taco')).to.equal(false); - }); - }); - }); - describe('Emitters', function () { - it('Event Emitter Close', function () { - assert.equal('close', k.OBCIEmitterClose); - }); - it('Event Emitter Dropped Packet', function () { - assert.equal('droppedPacket', k.OBCIEmitterDroppedPacket); - }); - it('Event Emitter EOT', function () { - assert.equal('eot', k.OBCIEmitterEot); - }); - it('Event Emitter Error', function () { - assert.equal('error', k.OBCIEmitterError); - }); - it('Event Emitter Hard Set', function () { - assert.equal('hardSet', k.OBCIEmitterHardSet); - }); - it('Event Emitter Impedance Array', function () { - assert.equal('impedanceArray', k.OBCIEmitterImpedanceArray); - }); - it('Event Emitter Query', function () { - assert.equal('query', k.OBCIEmitterQuery); - }); - it('Event Emitter Raw Data Packet', function () { - assert.equal('rawDataPacket', k.OBCIEmitterRawDataPacket); - }); - it('Event Emitter Ready', function () { - assert.equal('ready', k.OBCIEmitterReady); - }); - it('Event Emitter Sample', function () { - assert.equal('sample', k.OBCIEmitterSample); - }); - }); - describe('Errors', function () { - - }); -}); diff --git a/test/OpenBCISample-test.js b/test/OpenBCISample-test.js deleted file mode 100644 index 56f96bd..0000000 --- a/test/OpenBCISample-test.js +++ /dev/null @@ -1,1299 +0,0 @@ -/** -* Created by ajk on 12/15/15. -*/ -'use strict'; -var bluebirdChecks = require('./bluebirdChecks'); -var openBCISample = require('../openBCISample'); -var chai = require('chai'); -var expect = chai.expect; -var assert = chai.assert; -var should = chai.should(); // eslint-disable-line no-unused-vars - -var chaiAsPromised = require('chai-as-promised'); -var sinonChai = require('sinon-chai'); -chai.use(chaiAsPromised); -chai.use(sinonChai); -var bufferEqual = require('buffer-equal'); - -var k = openBCISample.k; - -const defaultChannelSettingsArray = k.channelSettingsArrayInit(k.OBCINumberOfChannelsDefault); - -var sampleBuf = openBCISample.samplePacket(); - -var accelArray; - -var channelScaleFactor = 4.5 / 24 / (Math.pow(2, 23) - 1); - -describe('openBCISample', function () { - beforeEach(function () { - accelArray = [0, 0, 0]; - }); - afterEach(() => bluebirdChecks.noPendingPromises()); - describe('#parseRawPacketStandard', function () { - this.timeout(4000); - it('should return the packet', function () { - expect(openBCISample.parseRawPacketStandard(sampleBuf)).to.not.be.null; - }); - it('should have the correct sample number', function () { - let sample = openBCISample.parseRawPacketStandard(sampleBuf); - - (sample.sampleNumber).should.equal(0x45); - }); - it('all the channels should have the same number value as their (index + 1) * scaleFactor', function () { - // sampleBuf has its channel number for each 3 byte integer. See line 20... - let sample = openBCISample.parseRawPacketStandard(sampleBuf); - - // So parse the sample we created and each value resulting from the channelData array should - // be its index + 1 (i.e. channel number) multiplied by the channel scale factor set by the - // ADS1299 for a gain of 24 (default) - sample.channelData.forEach((channelValue, index) => { - channelValue.should.equal(channelScaleFactor * (index + 1)); - }); - }); - it('gets the 6-byte raw aux buffer', function () { - let sample = openBCISample.parseRawPacketStandard(sampleBuf, defaultChannelSettingsArray, true); - Buffer.isBuffer(sample.auxData).should.be.equal(true); - }); - it('all the auxs should have the same number value as their index * scaleFactor', function () { - let sample = openBCISample.parseRawPacketStandard(sampleBuf); - - sample.accelData.forEach((accelValue, index) => { - accelValue.should.equal(openBCISample.scaleFactorAux * index); - }); - }); - it('check to see if negative numbers work on channel data', function () { - var temp = openBCISample.samplePacket(); - // console.log(temp) - var taco = new Buffer([0x81]); - taco.copy(temp, 2); - let sample = openBCISample.parseRawPacketStandard(temp); - assert.equal(sample.channelData[0], channelScaleFactor * -8323071, 'Negative numbers not working correctly'); - }); - it('check to see if negative numbers work on aux data', function () { - var temp = openBCISample.samplePacket(); - var taco = new Buffer([0x81]); - taco.copy(temp, 26); - let sample = openBCISample.parseRawPacketStandard(temp); - sample.accelData[0].should.be.approximately(-32512 * openBCISample.scaleFactorAux, 1); - }); - it('should work on 200 samples', function () { - var numberOfSamplesToTest = 200; - var samplesReceived = 0; - - for (var i = 0; i < numberOfSamplesToTest; i++) { - var temp = openBCISample.samplePacket(i); - // console.log(temp) - var taco = new Buffer([i]); - taco.copy(temp, 2); - let sample = openBCISample.parseRawPacketStandard(temp); - expect(sample.sampleNumber).to.equal(samplesReceived); - samplesReceived++; - } - }); - it('has the right sample number', function () { - var expectedSampleNumber = 0x45; - let sample = openBCISample.parseRawPacketStandard(sampleBuf); - sample.sampleNumber.should.equal(expectedSampleNumber); - }); - it('has the right stop byte', function () { - let sample = openBCISample.parseRawPacketStandard(sampleBuf); - sample.stopByte.should.equal(openBCISample.makeTailByteFromPacketType(k.OBCIStreamPacketStandardAccel)); - }); - it('has the right start byte', function () { - let sample = openBCISample.parseRawPacketStandard(sampleBuf); - sample.startByte.should.equal(0xA0); - }); - describe('#errorConditions', function () { - it('send non data buffer', function () { - expect(openBCISample.parseRawPacketStandard.bind(openBCISample, 1)).to.throw(k.OBCIErrorInvalidByteLength); - }); - it('bad start byte', function () { - var temp = openBCISample.samplePacket(); - temp[0] = 69; - expect(openBCISample.parseRawPacketStandard.bind(openBCISample, temp)).to.throw(k.OBCIErrorInvalidByteStart); - }); - it('wrong number of bytes', function () { - expect(openBCISample.parseRawPacketStandard.bind(openBCISample, new Buffer(5))).to.throw(k.OBCIErrorInvalidByteLength); - }); - it('undefined', function () { - expect(openBCISample.parseRawPacketStandard.bind(openBCISample)).to.throw(k.OBCIErrorUndefinedOrNullInput); - }); - }); - }); - describe('#parsePacketStandardRawAux', function () { - var packet; - it('gets 6-byte buffer', function () { - // Get a packet - // This packet has aux bytes with the same value as their index - packet = openBCISample.samplePacketStandardRawAux(0); - - let sample = openBCISample.parseRawPacketStandard(packet, defaultChannelSettingsArray, false); - Buffer.isBuffer(sample.auxData).should.equal(true); - }); - it('gets the correct 6-byte buffer', function () { - // Get a packet - // This packet has aux bytes with the same value as their index - packet = openBCISample.samplePacketStandardRawAux(0); - - let sample = openBCISample.parseRawPacketStandard(packet, defaultChannelSettingsArray, false); - for (var i = 0; i < 6; i++) { - sample.auxData[i].should.equal(i); - } - }); - it('all the channels should have the same number value as their (index + 1) * scaleFactor', function () { - packet = openBCISample.samplePacketStandardRawAux(0); - let sample = openBCISample.parseRawPacketStandard(packet, defaultChannelSettingsArray, false); - sample.channelData.forEach((channelValue, index) => { - channelValue.should.equal(channelScaleFactor * (index + 1)); - }); - }); - it('has the right sample number', function () { - var expectedSampleNumber = 69; - packet = openBCISample.samplePacketStandardRawAux(expectedSampleNumber); - let sample = openBCISample.parseRawPacketStandard(packet, defaultChannelSettingsArray, false); - sample.sampleNumber.should.equal(expectedSampleNumber); - }); - it('has the right stop byte', function () { - packet = openBCISample.samplePacketStandardRawAux(0); - let sample = openBCISample.parseRawPacketStandard(packet, defaultChannelSettingsArray, false); - sample.stopByte.should.equal(openBCISample.makeTailByteFromPacketType(k.OBCIStreamPacketStandardRawAux)); - }); - it('has the right start byte', function () { - packet = openBCISample.samplePacketStandardRawAux(0); - let sample = openBCISample.parseRawPacketStandard(packet, defaultChannelSettingsArray, false); - sample.startByte.should.equal(0xA0); - }); - describe('#errorConditions', function () { - it('send non data buffer', function () { - expect(openBCISample.parseRawPacketStandard.bind(openBCISample, 1)).to.throw(k.OBCIErrorInvalidByteLength); - }); - it('bad start byte', function () { - var temp = openBCISample.samplePacket(); - temp[0] = 69; - expect(openBCISample.parseRawPacketStandard.bind(openBCISample, temp, defaultChannelSettingsArray, false)).to.throw(k.OBCIErrorInvalidByteStart); - }); - it('wrong number of bytes', function () { - expect(openBCISample.parseRawPacketStandard.bind(openBCISample, new Buffer(5), defaultChannelSettingsArray, false)).to.throw(k.OBCIErrorInvalidByteLength); - }); - }); - }); - describe('#getFromTimePacketTime', function () { - it('should extract the proper time value from packet', function () { - let sampleWithTime = openBCISample.samplePacketAccelTimeSynced(0); - let time = openBCISample.getFromTimePacketTime(sampleWithTime); - time.should.equal(1); - }); - describe('#errorConditions', function () { - it('wrong number of bytes', function () { - expect(openBCISample.getFromTimePacketTime.bind(openBCISample, new Buffer(5))).to.throw(k.OBCIErrorInvalidByteLength); - }); - }); - }); - describe('#getFromTimePacketAccel', function () { - var packet; - - it('should emit and array if z axis i.e. sampleNumber % 10 === 9', function () { - // Make a packet with a sample number that represents z axis - packet = openBCISample.samplePacketAccelTimeSynced(9); - let isZAxis = openBCISample.getFromTimePacketAccel(packet, accelArray); - isZAxis.should.equal(true); - }); - it(`false if sample number is not sampleNumber % 10 === ${k.OBCIAccelAxisZ}`, function () { - // Make a packet that is anything but the z axis - packet = openBCISample.samplePacketAccelTimeSynced(k.OBCIAccelAxisX); - let isZAxis = openBCISample.getFromTimePacketAccel(packet, accelArray); - isZAxis.should.equal(false); - - packet = openBCISample.samplePacketAccelTimeSynced(k.OBCIAccelAxisY); - isZAxis = openBCISample.getFromTimePacketAccel(packet, accelArray); - isZAxis.should.equal(false); - - packet = openBCISample.samplePacketAccelTimeSynced(34); - isZAxis = openBCISample.getFromTimePacketAccel(packet, accelArray); - isZAxis.should.equal(false); - - packet = openBCISample.samplePacketAccelTimeSynced(100); - isZAxis = openBCISample.getFromTimePacketAccel(packet, accelArray); - isZAxis.should.equal(false); - }); - describe('#errorConditions', function () { - it('wrong number of bytes', function () { - expect(openBCISample.getFromTimePacketAccel.bind(openBCISample, new Buffer(5))).to.throw(k.OBCIErrorInvalidByteLength); - }); - }); - }); - describe('#parsePacketTimeSyncedAccel', function () { - // Global array (at least it's global in practice) to store accel data between packets - var packet1, packet2, packet3; - - it(`should only include accel data array on sampleNumber%10 === ${k.OBCIAccelAxisZ}`, function () { - // Generate three packets, packets only get one axis value per packet - // X axis data is sent with every sampleNumber % 10 === 7 - packet1 = openBCISample.samplePacketAccelTimeSynced(k.OBCIAccelAxisX); - // Y axis data is sent with every sampleNumber % 10 === 8 - packet2 = openBCISample.samplePacketAccelTimeSynced(k.OBCIAccelAxisY); - // Z axis data is sent with every sampleNumber % 10 === 9 - packet3 = openBCISample.samplePacketAccelTimeSynced(k.OBCIAccelAxisZ); - - let sample = openBCISample.parsePacketTimeSyncedAccel(packet1, defaultChannelSettingsArray, 0, accelArray); - sample.should.not.have.property('accelData'); - - sample = openBCISample.parsePacketTimeSyncedAccel(packet2, defaultChannelSettingsArray, 0, accelArray); - sample.should.not.have.property('accelData'); - - sample = openBCISample.parsePacketTimeSyncedAccel(packet3, defaultChannelSettingsArray, 0, accelArray); - sample.should.have.property('accelData'); - }); - it("should convert raw numbers into g's with scale factor", function () { - // Generate three packets, packets only get one axis value per packet - // X axis data is sent with every sampleNumber % 10 === 7 - packet1 = openBCISample.samplePacketAccelTimeSynced(k.OBCIAccelAxisX); - // Y axis data is sent with every sampleNumber % 10 === 8 - packet2 = openBCISample.samplePacketAccelTimeSynced(k.OBCIAccelAxisY); - // Z axis data is sent with every sampleNumber % 10 === 9 - packet3 = openBCISample.samplePacketAccelTimeSynced(k.OBCIAccelAxisZ); - - let sample = openBCISample.parsePacketTimeSyncedAccel(packet1, defaultChannelSettingsArray, 0, accelArray); - sample = openBCISample.parsePacketTimeSyncedAccel(packet2, defaultChannelSettingsArray, 0, accelArray); - sample = openBCISample.parsePacketTimeSyncedAccel(packet3, defaultChannelSettingsArray, 0, accelArray); - sample.accelData.forEach((accelValue, index) => { - accelValue.should.equal(openBCISample.scaleFactorAux); - }); - }); - it('all the channels should have the same number value as their (index + 1) * scaleFactor', function () { - packet1 = openBCISample.samplePacketAccelTimeSynced(0); - let sample = openBCISample.parsePacketTimeSyncedAccel(packet1, defaultChannelSettingsArray, 0, accelArray); // sampleBuf has its channel number for each 3 byte integer. See line 20... - sample.channelData.forEach((channelValue, index) => { - channelValue.should.equal(channelScaleFactor * (index + 1)); - }); - }); - it('has the right sample number', function () { - var expectedSampleNumber = 69; - packet1 = openBCISample.samplePacketAccelTimeSynced(expectedSampleNumber); - let sample = openBCISample.parsePacketTimeSyncedAccel(packet1, defaultChannelSettingsArray, 0, accelArray); // sampleBuf has its channel number for each 3 byte integer. See line 20... - sample.sampleNumber.should.equal(expectedSampleNumber); - }); - it('has the right stop byte', function () { - packet1 = openBCISample.samplePacketAccelTimeSynced(0); - let sample = openBCISample.parsePacketTimeSyncedAccel(packet1, defaultChannelSettingsArray, 0, accelArray); // sampleBuf has its channel number for each 3 byte integer. See line 20... - sample.stopByte.should.equal(openBCISample.makeTailByteFromPacketType(k.OBCIStreamPacketAccelTimeSynced)); - }); - it('has the right start byte', function () { - packet1 = openBCISample.samplePacketAccelTimeSynced(0); - let sample = openBCISample.parsePacketTimeSyncedAccel(packet1, defaultChannelSettingsArray, 0, accelArray); // sampleBuf has its channel number for each 3 byte integer. See line 20... - sample.startByte.should.equal(0xA0); - }); - describe('#errorConditions', function () { - it('wrong number of bytes', function () { - expect(openBCISample.parsePacketTimeSyncedAccel.bind(openBCISample, new Buffer(5), defaultChannelSettingsArray, 0, accelArray)).to.throw(k.OBCIErrorInvalidByteLength); - }); - }); - }); - describe('#getFromTimePacketRawAux', function () { - var packet; - it('should put the two aux bytes into a buffer', function () { - // Get a packet - packet = openBCISample.samplePacketRawAuxTimeSynced(0); - - let rawAuxBuffer = openBCISample.getFromTimePacketRawAux(packet); - Buffer.isBuffer(rawAuxBuffer).should.equal(true); - }); - describe('#errorConditions', function () { - it('wrong number of bytes', function () { - expect(openBCISample.getFromTimePacketRawAux.bind(openBCISample, new Buffer(5))).to.throw(k.OBCIErrorInvalidByteLength); - }); - }); - }); - describe('#parsePacketTimeSyncedRawAux', function () { - var packet; - it('should put the two aux bytes into a buffer', function () { - // Generate three packets, packets only get one axis value per packet - packet = openBCISample.samplePacketRawAuxTimeSynced(0); - - let sample = openBCISample.parsePacketTimeSyncedRawAux(packet, defaultChannelSettingsArray, 0); - sample.should.have.property('auxData'); - sample.auxData[0].should.equal(0); - sample.auxData[1].should.equal(1); - sample.auxData.byteLength.should.equal(2); - }); - it('all the channels should have the same number value as their (index + 1) * scaleFactor', function () { - packet = openBCISample.samplePacketRawAuxTimeSynced(0); - let sample = openBCISample.parsePacketTimeSyncedRawAux(packet, defaultChannelSettingsArray, 0); - sample.channelData.forEach((channelValue, index) => { - channelValue.should.equal(channelScaleFactor * (index + 1)); - }); - }); - it('has the right sample number', function () { - var expectedSampleNumber = 69; - packet = openBCISample.samplePacketRawAuxTimeSynced(expectedSampleNumber); - let sample = openBCISample.parsePacketTimeSyncedRawAux(packet, defaultChannelSettingsArray, 0); - sample.sampleNumber.should.equal(expectedSampleNumber); - }); - it('has the right stop byte', function () { - packet = openBCISample.samplePacketRawAuxTimeSynced(0); - let sample = openBCISample.parsePacketTimeSyncedRawAux(packet, defaultChannelSettingsArray, 0); - sample.stopByte.should.equal(openBCISample.makeTailByteFromPacketType(k.OBCIStreamPacketRawAuxTimeSynced)); - }); - it('has the right start byte', function () { - packet = openBCISample.samplePacketRawAuxTimeSynced(0); - let sample = openBCISample.parsePacketTimeSyncedRawAux(packet, defaultChannelSettingsArray, 0); - sample.startByte.should.equal(0xA0); - }); - describe('#errorConditions', function () { - it('wrong number of bytes', function () { - expect(openBCISample.parsePacketTimeSyncedRawAux.bind(openBCISample, new Buffer(5), defaultChannelSettingsArray, 0, accelArray)).to.throw(k.OBCIErrorInvalidByteLength); - }); - }); - }); - describe('#convertSampleToPacketStandard', function () { - var generateSample = openBCISample.randomSample(k.OBCINumberOfChannelsDefault, k.OBCISampleRate250); - - // get new sample - var newSample = generateSample(0); - - // try to convert to packet - var packetBuffer = openBCISample.convertSampleToPacketStandard(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 () { - let sample = openBCISample.parseRawPacketStandard(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 () { - let sample = openBCISample.parseRawPacketStandard(packetBuffer); - for (var i = 0; i < 3; i++) { - sample.accelData[i].should.be.approximately(newSample.auxData[i], 0.001); - } - }); - }); - describe('#convertSampleToPacketRawAux', function () { - var generateSample = openBCISample.randomSample(k.OBCINumberOfChannelsDefault, k.OBCISampleRate250); - - // get new sample - var newSample = generateSample(0); - - // Make a fake 6 byte buffer - var rawBuffer = new Buffer([0, 1, 2, 3, 4, 5]); - - // try to convert to packet - var packetBuffer = openBCISample.convertSampleToPacketRawAux(newSample, rawBuffer); - - 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(openBCISample.makeTailByteFromPacketType(k.OBCIStreamPacketStandardRawAux), '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 () { - let sample = openBCISample.parseRawPacketStandard(packetBuffer, defaultChannelSettingsArray, false); - for (var i = 0; i < k.OBCINumberOfChannelsDefault; i++) { - sample.channelData[i].should.be.approximately(newSample.channelData[i], 0.001); - } - }); - it('should get raw aux buffer', function () { - let sample = openBCISample.parseRawPacketStandard(packetBuffer, defaultChannelSettingsArray, false); - expect(sample.auxData).to.exist; - expect(bufferEqual(rawBuffer, sample.auxData)).to.be.true; - }); - }); - describe('#convertSampleToPacketAccelTimeSyncSet', function () { - var generateSample = openBCISample.randomSample(k.OBCINumberOfChannelsDefault, k.OBCISampleRate250); - - // get new sample - var newSample = generateSample(0); - - // Make a time - var time = 1010101; - - // Accel array - var accelArray = [0, 0, 0]; - - // Channel Settings - var channelSettingsArray = k.channelSettingsArrayInit(8); - - // try to convert to packet - var packetBuffer = openBCISample.convertSampleToPacketAccelTimeSyncSet(newSample, time); - - it('should have correct start byte', () => { - packetBuffer[0].should.equal(k.OBCIByteStart, 'confirming start byte'); - }); - it('should have correct stop byte', () => { - packetBuffer[k.OBCIPacketSize - 1].should.equal(openBCISample.makeTailByteFromPacketType(k.OBCIStreamPacketAccelTimeSyncSet), 'confirming stop byte'); - }); - it('should have correct sample number', () => { - packetBuffer[1].should.equal(1, 'confirming sample number is 1 more than 0'); - }); - it('should convert channel data to binary', function () { - let sample = openBCISample.parsePacketTimeSyncedAccel(packetBuffer, channelSettingsArray, 0, accelArray); - for (var i = 0; i < k.OBCINumberOfChannelsDefault; i++) { - sample.channelData[i].should.be.approximately(newSample.channelData[i], 0.001); - } - }); - it('should get board time', function () { - let sample = openBCISample.parsePacketTimeSyncedAccel(packetBuffer, channelSettingsArray, 0, accelArray); - expect(sample.boardTime).to.exist; - expect(sample.boardTime).to.equal(time); - }); - it('should get time stamp with offset', function () { - var timeOffset = 80; - let sample = openBCISample.parsePacketTimeSyncedAccel(packetBuffer, channelSettingsArray, timeOffset, accelArray); - expect(sample.timeStamp).to.exist; - expect(sample.timeStamp).to.equal(time + timeOffset); - }); - }); - describe('#convertSampleToPacketAccelTimeSynced', function () { - var generateSample = openBCISample.randomSample(k.OBCINumberOfChannelsDefault, k.OBCISampleRate250); - - // get new sample - var newSample = generateSample(0); - - // Make a time - var time = 1010101; - - // Accel array - var accelArray = [0, 0, 0]; - - // Channel Settings - var channelSettingsArray = k.channelSettingsArrayInit(8); - - // try to convert to packet - var packetBuffer = openBCISample.convertSampleToPacketAccelTimeSynced(newSample, time); - - it('should have correct start byte', () => { - packetBuffer[0].should.equal(k.OBCIByteStart, 'confirming start byte'); - }); - it('should have correct stop byte', () => { - packetBuffer[k.OBCIPacketSize - 1].should.equal(openBCISample.makeTailByteFromPacketType(k.OBCIStreamPacketAccelTimeSynced), 'confirming stop byte'); - }); - it('should have correct sample number', () => { - packetBuffer[1].should.equal(1, 'confirming sample number is 1 more than 0'); - }); - it('should convert channel data to binary', function () { - let sample = openBCISample.parsePacketTimeSyncedAccel(packetBuffer, channelSettingsArray, 0, accelArray); - for (var i = 0; i < k.OBCINumberOfChannelsDefault; i++) { - sample.channelData[i].should.be.approximately(newSample.channelData[i], 0.001); - } - }); - it('should get board time', function () { - let sample = openBCISample.parsePacketTimeSyncedAccel(packetBuffer, channelSettingsArray, 0, accelArray); - expect(sample.boardTime).to.exist; - expect(sample.boardTime).to.equal(time); - }); - it('should get time stamp with offset', function () { - var timeOffset = 80; - let sample = openBCISample.parsePacketTimeSyncedAccel(packetBuffer, channelSettingsArray, timeOffset, accelArray); - expect(sample.timeStamp).to.exist; - expect(sample.timeStamp).to.equal(time + timeOffset); - }); - }); - describe('#convertSampleToPacketRawAuxTimeSyncSet', function () { - var generateSample = openBCISample.randomSample(k.OBCINumberOfChannelsDefault, k.OBCISampleRate250); - - // get new sample - var newSample = generateSample(0); - - // Make a time - var time = 1010101; - - // Raw Aux - var rawAux = new Buffer([0, 1]); - - // Channel Settings - var channelSettingsArray = k.channelSettingsArrayInit(8); - - // try to convert to packet - var packetBuffer = openBCISample.convertSampleToPacketRawAuxTimeSyncSet(newSample, time, rawAux); - - it('should have correct start byte', () => { - packetBuffer[0].should.equal(k.OBCIByteStart, 'confirming start byte'); - }); - it('should have correct stop byte', () => { - packetBuffer[k.OBCIPacketSize - 1].should.equal(openBCISample.makeTailByteFromPacketType(k.OBCIStreamPacketRawAuxTimeSyncSet), 'confirming stop byte'); - }); - it('should have correct sample number', () => { - packetBuffer[1].should.equal(1, 'confirming sample number is 1 more than 0'); - }); - it('should convert channel data to binary', function () { - let sample = openBCISample.parsePacketTimeSyncedRawAux(packetBuffer, channelSettingsArray, 0); - for (var i = 0; i < k.OBCINumberOfChannelsDefault; i++) { - sample.channelData[i].should.be.approximately(newSample.channelData[i], 0.001); - } - }); - it('should get raw aux buffer', function () { - let sample = openBCISample.parsePacketTimeSyncedRawAux(packetBuffer, channelSettingsArray, 0); - expect(sample.auxData).to.exist; - expect(bufferEqual(rawAux, sample.auxData)).to.be.true; - }); - it('should get board time', function () { - let sample = openBCISample.parsePacketTimeSyncedRawAux(packetBuffer, channelSettingsArray, 0); - expect(sample.boardTime).to.exist; - expect(sample.boardTime).to.equal(time); - }); - it('should get time stamp with offset', function () { - var timeOffset = 80; - let sample = openBCISample.parsePacketTimeSyncedRawAux(packetBuffer, channelSettingsArray, timeOffset); - expect(sample.timeStamp).to.exist; - expect(sample.timeStamp).to.equal(time + timeOffset); - }); - }); - describe('#convertSampleToPacketRawAuxTimeSynced', function () { - var generateSample = openBCISample.randomSample(k.OBCINumberOfChannelsDefault, k.OBCISampleRate250); - - // get new sample - var newSample = generateSample(0); - - // Make a time - var time = 1010101; - - // Raw Aux - var rawAux = new Buffer([0, 1]); - - // Channel Settings - var channelSettingsArray = k.channelSettingsArrayInit(8); - - // try to convert to packet - var packetBuffer = openBCISample.convertSampleToPacketRawAuxTimeSynced(newSample, time, rawAux); - - it('should have correct start byte', () => { - packetBuffer[0].should.equal(k.OBCIByteStart, 'confirming start byte'); - }); - it('should have correct stop byte', () => { - packetBuffer[k.OBCIPacketSize - 1].should.equal(openBCISample.makeTailByteFromPacketType(k.OBCIStreamPacketRawAuxTimeSynced), 'confirming stop byte'); - }); - it('should have correct sample number', () => { - packetBuffer[1].should.equal(1, 'confirming sample number is 1 more than 0'); - }); - it('should convert channel data to binary', function () { - let sample = openBCISample.parsePacketTimeSyncedRawAux(packetBuffer, channelSettingsArray, 0); - for (var i = 0; i < k.OBCINumberOfChannelsDefault; i++) { - sample.channelData[i].should.be.approximately(newSample.channelData[i], 0.001); - } - }); - it('should get raw aux buffer', function () { - let sample = openBCISample.parsePacketTimeSyncedRawAux(packetBuffer, channelSettingsArray, 0); - expect(sample.auxData).to.exist; - expect(bufferEqual(rawAux, sample.auxData)).to.be.true; - }); - it('should get board time', function () { - let sample = openBCISample.parsePacketTimeSyncedRawAux(packetBuffer, channelSettingsArray, 0); - expect(sample.boardTime).to.exist; - expect(sample.boardTime).to.equal(time); - }); - it('should get time stamp with offset', function () { - var timeOffset = 80; - let sample = openBCISample.parsePacketTimeSyncedRawAux(packetBuffer, channelSettingsArray, timeOffset); - expect(sample.timeStamp).to.exist; - expect(sample.timeStamp).to.equal(time + timeOffset); - }); - }); - describe('#interpret24bitAsInt32', function () { - it('converts a small positive number', function () { - var buf1 = new Buffer([0x00, 0x06, 0x90]); // 0x000690 === 1680 - 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); - 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); - 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); - 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); - assert.equal(num, 1680); - }); - it('converts a large positive number', function () { - var buf1 = new Buffer([0x02, 0xC0]); // 0x02C0 === 704 - 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); - assert.equal(num, -1); - }); - it('converts a large negative number', function () { - var buf1 = new Buffer([0x81, 0xA1]); // 0x81A1 === -32351 - 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 * channelScaleFactor; - - 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 oldSampleNumber = 0; - var newSample = generateSample(oldSampleNumber); - 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(); - }); - }); - }); - 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('#impedanceSummarize', function () { - var impedanceArray = []; - var numberOfChannels = 8; - beforeEach(() => { - impedanceArray = openBCISample.impedanceArray(numberOfChannels); - }); - it('should find impedance good', function () { - impedanceArray[0].N.raw = 2201.84; - - openBCISample.impedanceSummarize(impedanceArray[0].N); - - impedanceArray[0].N.text.should.equal(k.OBCIImpedanceTextGood); // Check the text - }); - it('should find impedance ok', function () { - impedanceArray[0].N.raw = 5201.84; - - openBCISample.impedanceSummarize(impedanceArray[0].N); - - impedanceArray[0].N.text.should.equal(k.OBCIImpedanceTextOk); // Check the text - }); - it('should find impedance bad', function () { - impedanceArray[0].N.raw = 10201.84; - - openBCISample.impedanceSummarize(impedanceArray[0].N); - - impedanceArray[0].N.text.should.equal(k.OBCIImpedanceTextBad); // Check the text - }); - it('should find impedance none', function () { - impedanceArray[0].N.data = 44194179.09; // A huge number that would be seen if there was no electrode connected - - openBCISample.impedanceSummarize(impedanceArray[0].N); - - impedanceArray[0].N.text.should.equal(k.OBCIImpedanceTextNone); // Check the text - }); - }); - describe('#makeDaisySampleObject', function () { - var lowerSampleObject, upperSampleObject, daisySampleObject; - before(() => { - // Make the lower sample (channels 1-8) - lowerSampleObject = openBCISample.newSample(1); - lowerSampleObject.channelData = [1, 2, 3, 4, 5, 6, 7, 8]; - lowerSampleObject.auxData = [0, 1, 2]; - lowerSampleObject.timestamp = 4; - lowerSampleObject.accelData = [0.5, -0.5, 1]; - // Make the upper sample (channels 9-16) - upperSampleObject = openBCISample.newSample(2); - upperSampleObject.channelData = [9, 10, 11, 12, 13, 14, 15, 16]; - upperSampleObject.auxData = [3, 4, 5]; - upperSampleObject.timestamp = 8; - - // Call the function under test - daisySampleObject = openBCISample.makeDaisySampleObject(lowerSampleObject, upperSampleObject); - }); - it('should make a channelData array 16 elements long', function () { - daisySampleObject.channelData.length.should.equal(k.OBCINumberOfChannelsDaisy); - }); - it('should make a channelData array with lower array in front of upper array', function () { - for (var i = 0; i < 16; i++) { - expect(daisySampleObject.channelData[i]).to.equal(i + 1); - } - }); - it('should make the sample number equal to the second packet divided by two', function () { - daisySampleObject.sampleNumber.should.equal(upperSampleObject.sampleNumber / 2); - }); - it('should put the aux packets in an object', function () { - daisySampleObject.auxData.hasOwnProperty('lower').should.be.true; - daisySampleObject.auxData.hasOwnProperty('upper').should.be.true; - }); - it('should put the aux packets in an object in the right order', function () { - for (var i = 0; i < 3; i++) { - expect(daisySampleObject.auxData['lower'][i]).to.equal(i); - expect(daisySampleObject.auxData['upper'][i]).to.equal(i + 3); - } - }); - it('should average the two timestamps together', function () { - var expectedAverage = (upperSampleObject.timestamp + lowerSampleObject.timestamp) / 2; - daisySampleObject.timestamp.should.equal(expectedAverage); - }); - it('should place the old timestamps in an object', function () { - daisySampleObject._timestamps.lower.should.equal(lowerSampleObject.timestamp); - daisySampleObject._timestamps.upper.should.equal(upperSampleObject.timestamp); - }); - it('should store an accelerometer value if present', function () { - daisySampleObject.should.have.property('accelData'); - }); - }); - describe('#isEven', function () { - it('should return true for even number', function () { - openBCISample.isEven(2).should.be.true; - }); - it('should return false for odd number', function () { - openBCISample.isEven(1).should.be.false; - }); - }); - describe('#isOdd', function () { - it('should return true for odd number', function () { - openBCISample.isOdd(1).should.be.true; - }); - it('should return false for even number', function () { - openBCISample.isOdd(2).should.be.false; - }); - }); - describe('#getChannelDataArray', function () { - var sampleBuf, badChanArray; - beforeEach(() => { - sampleBuf = openBCISample.samplePacket(0); - }); - it('should multiply each channel by the proper scale value', function () { - var chanArr = k.channelSettingsArrayInit(k.OBCINumberOfChannelsDefault); // Not in daisy mode - var scaleFactor = 4.5 / 24 / (Math.pow(2, 23) - 1); - // Call the function under test - let valueArray = openBCISample.getChannelDataArray(sampleBuf, chanArr); - for (var j = 0; j < k.OBCINumberOfChannelsDefault; j++) { - console.log(`channel data ${j + 1}: ${valueArray[j]} : actual ${scaleFactor * (j + 1)}`); - expect(valueArray[j]).to.be.closeTo(scaleFactor * (j + 1), 0.0001); - } - }); - it('in daisy mode, on odd samples should use gains from index 0-7 of channel settings array', function () { - // Overwrite the default - sampleBuf = openBCISample.samplePacket(1); // even's are the daisy channels - // Make a 16 element long channel settings array - var chanArr = k.channelSettingsArrayInit(k.OBCINumberOfChannelsDaisy); - // Set the upper (8-15) of channel settings array. If the function under test uses the 1 gain, then the test - // will fail. - for (var i = k.OBCINumberOfChannelsDefault; i < k.OBCINumberOfChannelsDaisy; i++) { - chanArr[i].gain = 1; - } - var scaleFactor = 4.5 / 24 / (Math.pow(2, 23) - 1); - // Call the function under test - let valueArray = openBCISample.getChannelDataArray(sampleBuf, chanArr); - for (var j = 0; j < k.OBCINumberOfChannelsDefault; j++) { - // console.log(`channel data ${j + 1}: ${valueArray[j]} : actual ${scaleFactor * (j + 1)}`) - expect(valueArray[j]).to.be.closeTo(scaleFactor * (j + 1), 0.0001); - } - }); - it('in daisy mode, on even samples should use gains from index 8-15 of channel settings array', function () { - // Overwrite the default - sampleBuf = openBCISample.samplePacket(2); // even's are the daisy channels - // Make a 16 element long channel settings array - var chanArr = k.channelSettingsArrayInit(k.OBCINumberOfChannelsDaisy); - // Set the lower (0-7) of channel settings array. If the function under test uses the 1 gain, then the test - // will fail. - for (var i = 0; i < k.OBCINumberOfChannelsDefault; i++) { - chanArr[i].gain = 1; - } - // gain here is 24, the same as in the channel settings array - var scaleFactor = 4.5 / 24 / (Math.pow(2, 23) - 1); - // Call the function under test - let valueArray = openBCISample.getChannelDataArray(sampleBuf, chanArr); - for (var j = 0; j < k.OBCINumberOfChannelsDefault; j++) { - // console.log(`channel data ${j + 1}: ${valueArray[j]} : actual ${scaleFactor * (j + 1)}`) - expect(valueArray[j]).to.be.closeTo(scaleFactor * (j + 1), 0.0001); - } - }); - it('in default mode, should reject when empty channel setting array', function () { - badChanArray = new Array(k.OBCINumberOfChannelsDefault).fill(0); - expect(openBCISample.getChannelDataArray.bind(openBCISample, sampleBuf, badChanArray)).to.throw('Error [getChannelDataArray]: Invalid channel settings object at index 0'); - }); - it('in daisy mode, should reject when empty channel setting array', function () { - badChanArray = new Array(k.OBCINumberOfChannelsDaisy).fill(0); - expect(openBCISample.getChannelDataArray.bind(openBCISample, sampleBuf, badChanArray)).to.throw('Error [getChannelDataArray]: Invalid channel settings object at index 0'); - }); - it('in default mode, should reject if not numbers in gain position', function () { - badChanArray = []; - for (var i = 0; i < k.OBCINumberOfChannelsDefault; i++) { - badChanArray.push({ - gain: 'taco' - }); - } - expect(openBCISample.getChannelDataArray.bind(openBCISample, sampleBuf, badChanArray)).to.throw('Error [getChannelDataArray]: Property gain of channelSettingsObject not or type Number'); - }); - it('in daisy mode, should reject if not numbers in gain position', function () { - badChanArray = []; - for (var i = 0; i < k.OBCINumberOfChannelsDaisy; i++) { - badChanArray.push({ - gain: 'taco' - }); - } - expect(openBCISample.getChannelDataArray.bind(openBCISample, sampleBuf, badChanArray)).to.throw('Error [getChannelDataArray]: Property gain of channelSettingsObject not or type Number'); - }); - it('should reject when channelSettingsArray is not in fact an array', function () { - expect(openBCISample.getChannelDataArray.bind(openBCISample, sampleBuf, {})).to.throw('Error [getChannelDataArray]: Channel Settings must be an array!'); - }); - }); - describe('#countADSPresent', function () { - it('should not crash on small buff', function () { - var buf = new Buffer('AJ!'); - - openBCISample.countADSPresent(buf).should.equal(0); - }); - it('should not find any ADS1299 present', function () { - var buf = new Buffer('AJ Keller is an awesome programmer!\n I know right!'); - - openBCISample.countADSPresent(buf).should.equal(0); - }); - it('should find one ads present', function () { - var buf = new Buffer(`OpenBCI V3 Simulator -On Board ADS1299 Device ID: 0x12345 -LIS3DH Device ID: 0x38422$$$`); - - openBCISample.countADSPresent(buf).should.equal(1); - }); - it('should find two ads1299 present', function () { - var buf = new Buffer(`OpenBCI V3 Simulator -On Board ADS1299 Device ID: 0x12345 -On Daisy ADS1299 Device ID: 0xFFFFF -LIS3DH Device ID: 0x38422 -$$$`); - - openBCISample.countADSPresent(buf).should.equal(2); - }); - }); - describe('#doesBufferHaveEOT', function () { - it('should not crash on small buff', function () { - var buf = new Buffer('AJ!'); - - openBCISample.doesBufferHaveEOT(buf).should.equal(false); - }); - it('should not find any $$$', function () { - var buf = new Buffer(`OpenBCI V3 Simulator -On Board ADS1299 Device ID: 0x12345 -On Daisy ADS1299 Device ID: 0xFFFFF -LIS3DH Device ID: 0x38422 -Firmware: v2 -`); - - openBCISample.doesBufferHaveEOT(buf).should.equal(false); - - buf = Buffer.concat([buf, new Buffer(k.OBCIParseEOT)], buf.length + 3); - - openBCISample.doesBufferHaveEOT(buf).should.equal(true); - }); - it('should find a $$$', function () { - var buf = new Buffer(`OpenBCI V3 Simulator -On Board ADS1299 Device ID: 0x12345 -On Daisy ADS1299 Device ID: 0xFFFFF -LIS3DH Device ID: 0x38422 -Firmware: v2 -$$$`); - - openBCISample.doesBufferHaveEOT(buf).should.equal(true); - }); - }); - describe('#findV2Firmware', function () { - it('should not crash on small buff', function () { - var buf = new Buffer('AJ!'); - - openBCISample.findV2Firmware(buf).should.equal(false); - }); - it('should not find any v2', function () { - var buf = new Buffer('AJ Keller is an awesome programmer!\n I know right!'); - - openBCISample.findV2Firmware(buf).should.equal(false); - }); - it('should not find a v2', function () { - var buf = new Buffer(`OpenBCI V3 Simulator -On Board ADS1299 Device ID: 0x12345 -LIS3DH Device ID: 0x38422$$$`); - - openBCISample.findV2Firmware(buf).should.equal(false); - }); - it('should find a v2', function () { - var buf = new Buffer(`OpenBCI V3 Simulator -On Board ADS1299 Device ID: 0x12345 -On Daisy ADS1299 Device ID: 0xFFFFF -LIS3DH Device ID: 0x38422 -Firmware: v2 -$$$`); - - openBCISample.findV2Firmware(buf).should.equal(true); - }); - }); - describe('#isFailureInBuffer', function () { - it('should not crash on small buff', function () { - var buf = new Buffer('AJ!'); - - openBCISample.isFailureInBuffer(buf).should.equal(false); - }); - it('should not find any failure in a success message', function () { - var buf = new Buffer('Success: Poll time set$$$'); - - openBCISample.isFailureInBuffer(buf).should.equal(false); - }); - it('should find failure in a failure message', function () { - var buf = new Buffer('Failure: Could not change Dongle channel number$$$'); - - openBCISample.isFailureInBuffer(buf).should.equal(true); - }); - }); - describe('#isSuccessInBuffer', function () { - it('should not crash on small buff', function () { - var buf = new Buffer('AJ!'); - - openBCISample.isSuccessInBuffer(buf).should.equal(false); - }); - it('should not find any success in a failure message', function () { - var buf = new Buffer('Failure: Could not change Dongle channel number'); - - openBCISample.isSuccessInBuffer(buf).should.equal(false); - }); - it('should find success in a success message', function () { - var buf = new Buffer('Success: Poll time set$$$'); - - openBCISample.isSuccessInBuffer(buf).should.equal(true); - }); - }); - - describe('#isStopByte', function () { - it('should return true for a normal stop byte', () => { - expect(openBCISample.isStopByte(0xC0)).to.be.true; - }); - it('should return true for a good stop byte with a different end nibble', () => { - expect(openBCISample.isStopByte(0xCF)).to.be.true; - }); - it('should return false for a bad stop byte', () => { - expect(openBCISample.isStopByte(0xF0)).to.be.false; - }); - it('should return false for a bad stop byte', () => { - expect(openBCISample.isStopByte(0x00)).to.be.false; - }); - }); - - describe('#isTimeSyncSetConfirmationInBuffer', function () { - // Attn: 0x2C is ASCII for ',' - var comma = 0x2C; - it('should not find the character in a buffer without the character', function () { - openBCISample.isTimeSyncSetConfirmationInBuffer(openBCISample.samplePacket()).should.equal(false); - }); - it('should find with just 0x2C', function () { - var buffer = new Buffer([comma]); - expect(openBCISample.isTimeSyncSetConfirmationInBuffer(buffer), 'just comma').to.be.true; - }); - it('should find even at start of buffer', function () { - // Start of buffer - var buffer = new Buffer([comma, k.OBCIByteStart]); - expect(openBCISample.isTimeSyncSetConfirmationInBuffer(buffer), 'before packet').to.be.true; - }); - it('should find even at back of buffer', function () { - // Back of buffer - var buffer = new Buffer([0xC0, comma]); - expect(openBCISample.isTimeSyncSetConfirmationInBuffer(buffer), 'after packet').to.be.true; - }); - it('should find wedged beween two packets', function () { - // / wedged - var buffer = new Buffer([0xC0, comma, 0xA0]); - expect(openBCISample.isTimeSyncSetConfirmationInBuffer(buffer), 'wedged between packets').to.be.true; - }); - it('should not find if no comma present', function () { - // / wedged - var buffer = new Buffer([0x2D]); - expect(openBCISample.isTimeSyncSetConfirmationInBuffer(buffer), 'not comma').to.be.false; - }); - it('should not find if comma at the front of bad block', function () { - // Start of buffer - var buffer = new Buffer([comma, 0xCC]); - expect(openBCISample.isTimeSyncSetConfirmationInBuffer(buffer), 'front of buffer').to.be.false; - }); - it('should not find if comma at the back of bad block', function () { - // Back of buffer - var buffer = new Buffer([0xD3, comma]); - expect(openBCISample.isTimeSyncSetConfirmationInBuffer(buffer), 'end of buffer').to.be.false; - }); - it('should not find is not the comma', function () { - // Wedged - var buffer = new Buffer([comma, comma, comma]); - expect(openBCISample.isTimeSyncSetConfirmationInBuffer(buffer), 'strictly commas').to.be.false; - }); - it('should find the character in a buffer packed with samples', function () { - var buf1 = openBCISample.samplePacket(1); - var buf2 = openBCISample.samplePacket(2); - var buf3 = new Buffer([0x2C]); - var buf4 = openBCISample.samplePacket(3); - - var bufferLength = buf1.length + buf2.length + buf3.length + buf4.length; - /* eslint new-cap: ["error", { "properties": false }] */ - var buffer = new Buffer.concat([buf1, buf2, buf3, buf4], bufferLength); - expect(openBCISample.isTimeSyncSetConfirmationInBuffer(buffer)).to.be.true; - }); - it('should find the character in a buffer packed with samples with comma at end', function () { - var buf1 = openBCISample.samplePacket(1); - var buf2 = openBCISample.samplePacket(2); - var buf3 = openBCISample.samplePacket(3); - var buf4 = new Buffer([0x2C]); - - var bufferLength = buf1.length + buf2.length + buf3.length + buf4.length; - /* eslint new-cap: ["error", { "properties": false }] */ - var buffer = new Buffer.concat([buf1, buf2, buf3, buf4], bufferLength); - expect(openBCISample.isTimeSyncSetConfirmationInBuffer(buffer)).to.be.true; - }); - it('should not find the character in a buffer packed with samples', function () { - var buf1 = openBCISample.samplePacket(1); - var buf2 = openBCISample.samplePacket(2); - var buf3 = openBCISample.samplePacket(3); - - var bufferLength = buf1.length + buf2.length + buf3.length; - /* eslint new-cap: ["error", { "properties": false }] */ - var buffer = new Buffer.concat([buf1, buf2, buf3], bufferLength); - expect(openBCISample.isTimeSyncSetConfirmationInBuffer(buffer)).to.be.false; - }); - }); - describe('#makeTailByteFromPacketType', function () { - it('should convert 0 to 0xC0', function () { - expect(openBCISample.makeTailByteFromPacketType(0)).to.equal(0xC0); - }); - it('should convert 5 to 0xC5', function () { - expect(openBCISample.makeTailByteFromPacketType(5)).to.equal(0xC5); - }); - it('should convert 15 to 0xCF', function () { - expect(openBCISample.makeTailByteFromPacketType(15)).to.equal(0xCF); - }); - it('should convert 16 to 0xC0', function () { - expect(openBCISample.makeTailByteFromPacketType(16)).to.equal(0xC0); - }); - it('should convert 30 to 0xC0', function () { - expect(openBCISample.makeTailByteFromPacketType(30)).to.equal(0xC0); - }); - it('should convert -2 to 0xC0', function () { - expect(openBCISample.makeTailByteFromPacketType(-2)).to.equal(0xC0); - }); - }); - describe('#newSyncObject', function () { - var syncObj = openBCISample.newSyncObject(); - it('should have property timeSyncSent', function () { - expect(syncObj).to.have.property('timeSyncSent', 0); - }); - 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); - }); - it('should have property timeTransmission', function () { - expect(syncObj).to.have.property('timeTransmission', 0); - }); - it('should have property timeSyncSentConfirmation', function () { - expect(syncObj).to.have.property('timeSyncSentConfirmation', 0); - }); - it('should have property timeSyncSetPacket', function () { - expect(syncObj).to.have.property('timeSyncSetPacket', 0); - }); - it('should have property valid', function () { - expect(syncObj).to.have.property('valid', false); - }); - it('should have property correctedTransmissionTime', function () { - expect(syncObj).to.have.property('correctedTransmissionTime', false); - }); - it('should have property boardTime', function () { - expect(syncObj).to.have.property('boardTime', 0); - }); - it('should have property error', function () { - expect(syncObj).to.have.property('error', null); - }); - }); - describe('#droppedPacketCheck', function () { - it('should return an array of missed packet numbers', function () { - var previous = 0; - var current = previous + 2; - assert.sameMembers(openBCISample.droppedPacketCheck(previous, current), [1], 'dropped one packet'); - - previous = 0; - current = previous + 4; - assert.sameMembers(openBCISample.droppedPacketCheck(previous, current), [1, 2, 3], 'dropped three packets'); - - previous = 255; - current = 2; - assert.sameMembers(openBCISample.droppedPacketCheck(previous, current), [0, 1], 'dropped two packets on wrap edge!'); - - previous = 254; - current = 2; - assert.sameMembers(openBCISample.droppedPacketCheck(previous, current), [255, 0, 1], 'dropped three packets on wrap!'); - - previous = 250; - current = 1; - assert.sameMembers(openBCISample.droppedPacketCheck(previous, current), [251, 252, 253, 254, 255, 0], 'dropped a bunch of packets on wrap!'); - }); - it('should roll over when 255 was previous and current is 0', function () { - var previous = 255; - var current = 0; - expect(openBCISample.droppedPacketCheck(previous, current)).to.be.null; - }); - it('should return null when previous is one less then new sample number', function () { - var previous = 0; - var current = previous + 1; - expect(openBCISample.droppedPacketCheck(previous, current)).to.be.null; - }); - }); - describe('#stripToEOTBuffer', function () { - it('should return the buffer if no EOT', function () { - let buf = null; - if (k.getVersionNumber(process.version) >= 6) { - // From introduced in node version 6.x.x - buf = Buffer.from('tacos are delicious'); - } else { - buf = new Buffer('tacos are delicious'); - } - expect(openBCISample.stripToEOTBuffer(buf).toString()).to.equal(buf.toString()); - }); - it('should slice the buffer after just eot $$$', function () { - let eotBuf = null; - let bufPost = null; - if (k.getVersionNumber(process.version) >= 6) { - // From introduced in node version 6.x.x - eotBuf = Buffer.from(k.OBCIParseEOT); - bufPost = Buffer.from('tacos'); - } else { - eotBuf = new Buffer(k.OBCIParseEOT); - bufPost = new Buffer('tacos'); - } - - let totalBuf = Buffer.concat([eotBuf, bufPost]); - expect(openBCISample.stripToEOTBuffer(totalBuf).toString()).to.equal(bufPost.toString()); - }); - it('should slice the buffer after eot $$$', function () { - let bufPre = null; - let eotBuf = null; - let bufPost = null; - if (k.getVersionNumber(process.version) >= 6) { - // From introduced in node version 6.x.x - bufPre = Buffer.from('tacos are delicious'); - eotBuf = Buffer.from(k.OBCIParseEOT); - bufPost = Buffer.from('tacos'); - } else { - bufPre = new Buffer('tacos are delicious'); - eotBuf = new Buffer(k.OBCIParseEOT); - bufPost = new Buffer('tacos'); - } - - let totalBuf = Buffer.concat([bufPre, eotBuf, bufPost]); - expect(openBCISample.stripToEOTBuffer(totalBuf).toString()).to.equal(bufPost.toString()); - }); - it('should return null if nothing left', function () { - let bufPre = null; - let eotBuf = null; - if (k.getVersionNumber(process.version) >= 6) { - // From introduced in node version 6.x.x - bufPre = Buffer.from('tacos are delicious'); - eotBuf = Buffer.from(k.OBCIParseEOT); - } else { - bufPre = new Buffer('tacos are delicious'); - eotBuf = new Buffer(k.OBCIParseEOT); - } - - let totalBuf = Buffer.concat([bufPre, eotBuf]); - expect(openBCISample.stripToEOTBuffer(totalBuf)).to.equal(null); - }); - }); - describe('#impedanceTestObjDefault', function () { - it('should give a new impedance object', function () { - const expectedImpedanceObj = { - active: false, - buffer: [], - count: 0, - isTestingPInput: false, - isTestingNInput: false, - onChannel: 0, - sampleNumber: 0, - continuousMode: false, - impedanceForChannel: 0, - window: 40 - }; - expect(openBCISample.impedanceTestObjDefault()).to.deep.equal(expectedImpedanceObj); - }); - }); - describe('#impedanceCalculateArray', function () { - const numberOfChannels = k.OBCINumberOfChannelsDefault; - const newRandomSample = openBCISample.randomSample(numberOfChannels, k.OBCISampleRate250, false, 'none'); - - afterEach(() => bluebirdChecks.noPendingPromises()); - - it('should not produce an array of impedances till window', function () { - const impTestObj = openBCISample.impedanceTestObjDefault(); - for (let i = 0; i < impTestObj.window - 1; i++) { - expect(openBCISample.impedanceCalculateArray(newRandomSample(i), impTestObj)).to.equal(null); - } - expect(impTestObj.buffer.length).to.equal(impTestObj.window - 1); - }); - it('should produce and array of impedances at window', function () { - const impTestObj = openBCISample.impedanceTestObjDefault(); - let impedanceArray = null; - for (let i = 0; i < impTestObj.window; i++) { - impedanceArray = openBCISample.impedanceCalculateArray(newRandomSample(i), impTestObj); - } - expect(impedanceArray.length).to.equal(numberOfChannels); - }); - }); -}); diff --git a/test/bluebirdChecks.js b/test/bluebirdChecks.js deleted file mode 100644 index 2b792ac..0000000 --- a/test/bluebirdChecks.js +++ /dev/null @@ -1,142 +0,0 @@ -var timingEventsAsPromises = require('./timingEventsAsPromises'); -exports.BluebirdPromise = require('bluebird'); -exports.PromiseIgnored = global.Promise; - -// Enable bluebird for all promise usage during tests only -// Fails tests for issues bluebird finds -// Exports a function to list all promises (getPendingPromises) -// Exports a function to verify no promises pending within a timeout (noPendingPromises) - -exports.BluebirdPromise.config({ - // TODO: wForgottenReturn is disabled because timingEventsAsPromises triggers it; find a workaround - warnings: { wForgottenReturn: false }, - longStackTraces: true, - monitoring: true, - cancellation: true -}); - -// nextTick conveniently not instrumented by timingEventsAsPromises -exports.BluebirdPromise.setScheduler(process.nextTick); - -// unhandled rejections become test failures -process.on('unhandledRejection', (reason, promise) => { - if (!(reason instanceof Error)) { - reason = new Error('unhandled promise rejection: ' + reason); - } else { - reason.message = 'unhandled promise rejection: ' + reason.message; - } - process.nextTick(() => { throw reason; }); -}); - -// // warnings become test failures -// process.on('warning', (warning) => { -// var error = new Error(warning); -// process.nextTick(() => { throw error; }); -// }); - -// provide access to all currently pending promises -var pendingPromises = {}; -var promiseId = 0; -var nested = 0; - -function promiseCreationHandler (promise) { - // promise created already resolved; ignore - if (!promise.isPending()) return; - - // need to create another promise to get access to the extended stack trace - // nested detects if we are inside our own dummy promise - ++nested; - if (nested === 1) { - // not the dummy promise - promise.___id = ++promiseId; - // store promise details - var error = new Error('Promise ' + promise.___id + ' is still pending'); - var entry = { - promise: promise, - id: promise.___id, - error: error - }; - pendingPromises[promise.___id] = entry; - // extract stack trace by rejecting an error; bluebird fills in expanded stack - exports.BluebirdPromise.reject(error).catch(error => { - entry.error = error; - entry.stack = error.stack; - }); - } else { - promise.___nested = nested; - } - --nested; -} -process.on('promiseCreated', promiseCreationHandler); - -function promiseDoneHandler (promise) { - if (promise.___nested) return; - delete pendingPromises[promise.___id]; -} -process.on('promiseFulfilled', promiseDoneHandler); -process.on('promiseRejected', promiseDoneHandler); -process.on('promiseResolved', promiseDoneHandler); -process.on('promiseCancelled', promiseDoneHandler); - -exports.getPendingPromises = function () { - var ret = []; - for (var promise in pendingPromises) { - ret.push(pendingPromises[promise]); - } - return ret; -}; - -exports.noPendingPromises = function (milliseconds) { - if (!milliseconds) milliseconds = 0; - - return new exports.PromiseIgnored((resolve, reject) => { - function waited100 () { - var promises = exports.getPendingPromises(); - - if (promises.length === 0) { - return resolve(); - } - - if (milliseconds > 0) { - milliseconds -= 100; - return timingEventsAsPromises.setTimeoutIgnored(waited100, 100); - } - - // timed out, but promises remaining: cancel all - - console.log(promises.length + ' promises still pending'); - - promises.forEach(promise => { - promise.promise.cancel(); - }); - - // report one - reject(promises[0].error); - } - - timingEventsAsPromises.setTimeoutIgnored(waited100, 0); - }); -}; - -// now instrument the Promise object itself to always use a simplified version of bluebird -// bluebird is composed inside a bare-bones Promise object providing only the official calls - -global.Promise = function (handler) { - this._promise = new exports.BluebirdPromise(handler); -}; - -// compose class methods -['all', 'race', 'reject', 'resolve'].forEach(classMethod => { - global.Promise[classMethod] = function () { - return exports.BluebirdPromise[classMethod].apply(exports.BluebirdPromise, [].slice.call(arguments)); - }; - Object.defineProperty(global.Promise[classMethod], 'name', { value: 'Promise.' + classMethod }); -}); - -// compose object methods -['then', 'catch'].forEach(objectMethod => { - global.Promise.prototype[objectMethod] = function () { - return this._promise[objectMethod].apply(this._promise, [].slice.call(arguments)); - }; - Object.defineProperty(global.Promise.prototype[objectMethod], 'name', { value: 'Promise.' + objectMethod }); -}); diff --git a/test/openBCIBoard-Impedance-test.js b/test/openBCIBoard-Impedance-test.js deleted file mode 100644 index 54cfec8..0000000 --- a/test/openBCIBoard-Impedance-test.js +++ /dev/null @@ -1,608 +0,0 @@ -'use strict'; -var bluebirdChecks = require('./bluebirdChecks'); -var chai = require('chai'); -var should = chai.should(); // eslint-disable-line no-unused-vars -var openBCIBoard = require('../openBCIBoard'); -var openBCISample = openBCIBoard.OpenBCISample; -var k = openBCISample.k; - -var chaiAsPromised = require('chai-as-promised'); -var sinonChai = require('sinon-chai'); -chai.use(chaiAsPromised); -chai.use(sinonChai); - -describe('#impedanceTesting', function () { - var ourBoard; - this.timeout(20000); - - before(function (done) { - ourBoard = new openBCIBoard.OpenBCIBoard({ - verbose: true, - simulatorFragmentation: k.OBCISimulatorFragmentationRandom - }); - var useSim = () => { - return ourBoard.simulatorEnable().then(() => { - return ourBoard.connect(k.OBCISimulatorPortName); - }); - }; - ourBoard.autoFindOpenBCIBoard() - .then(portName => { - return ourBoard.connect(portName); - }) - .catch(() => { - return useSim(); - }) - .then(() => { - console.log('connected'); - }) - .catch(err => { - console.log('Error: ' + err); - }); - - ourBoard.once('ready', () => { - ourBoard.streamStart() - .then(() => { - setTimeout(() => { - done(); - }, 100); // give some time for the stream command to be sent - }) - .catch(err => { - console.log(err); - done(err); - }); - }); - }); - after(done => { - if (ourBoard.isConnected()) { - ourBoard.disconnect() - .then(() => { - done(); - }) - .catch(err => { - done(err); - }); - } else { - done(); - } - }); - after(() => bluebirdChecks.noPendingPromises()); - - describe('#impedanceTestAllChannels', function () { - var impedanceArray = []; - - before(function (done) { - ourBoard.once('impedanceArray', arr => { - impedanceArray = arr; - console.log(impedanceArray); - done(); - }); - ourBoard.impedanceTestAllChannels(); - }); - describe('#channel1', function () { - it('has valid channel number', function () { - impedanceArray[0].channel.should.be.equal(1); - }); - describe('#inputP', function () { - it('got raw impedance value', function () { - impedanceArray[0].P.should.have.property('raw').above(-1); - }); - it("text is not 'init'", function () { - impedanceArray[0].P.should.have.property('text').not.be.equal(k.OBCIImpedanceTextInit); - }); - }); - describe('#inputN', function () { - it('got raw impedance value', function () { - impedanceArray[0].N.should.have.property('raw').above(-1); - }); - it("text is not 'init'", function () { - impedanceArray[0].N.should.have.property('text').not.be.equal(k.OBCIImpedanceTextInit); - }); - }); - }); - describe('#channel2', function () { - it('has valid channel number', function () { - impedanceArray[1].channel.should.be.equal(2); - }); - describe('#inputP', function () { - it('got raw impedance value', function () { - impedanceArray[1].P.should.have.property('raw').above(-1); - }); - it("text is not 'init'", function () { - impedanceArray[1].P.should.have.property('text').not.be.equal(k.OBCIImpedanceTextInit); - }); - }); - describe('#inputN', function () { - it('got raw impedance value', function () { - impedanceArray[1].N.should.have.property('raw').above(-1); - }); - it("text is not 'init'", function () { - impedanceArray[1].N.should.have.property('text').not.be.equal(k.OBCIImpedanceTextInit); - }); - }); - }); - describe('#channel3', function () { - it('has valid channel number', function () { - impedanceArray[2].channel.should.be.equal(3); - }); - describe('#inputP', function () { - it('got raw impedance value', function () { - impedanceArray[2].P.should.have.property('raw').above(-1); - }); - it("text is not 'init'", function () { - impedanceArray[2].P.should.have.property('text').not.be.equal(k.OBCIImpedanceTextInit); - }); - }); - describe('#inputN', function () { - it('got raw impedance value', function () { - impedanceArray[2].N.should.have.property('raw').above(-1); - }); - it("text is not 'init'", function () { - impedanceArray[2].N.should.have.property('text').not.be.equal(k.OBCIImpedanceTextInit); - }); - }); - }); - describe('#channel4', function () { - it('has valid channel number', function () { - impedanceArray[3].channel.should.be.equal(4); - }); - describe('#inputP', function () { - it('got raw impedance value', function () { - impedanceArray[3].P.should.have.property('raw').above(-1); - }); - it("text is not 'init'", function () { - impedanceArray[3].P.should.have.property('text').not.be.equal(k.OBCIImpedanceTextInit); - }); - }); - describe('#inputN', function () { - it('got raw impedance value', function () { - impedanceArray[3].N.should.have.property('raw').above(-1); - }); - it("text is not 'init'", function () { - impedanceArray[3].N.should.have.property('text').not.be.equal(k.OBCIImpedanceTextInit); - }); - }); - }); - describe('#channel5', function () { - it('has valid channel number', function () { - impedanceArray[4].channel.should.be.equal(5); - }); - describe('#inputP', function () { - it('got raw impedance value', function () { - impedanceArray[4].P.should.have.property('raw').above(-1); - }); - it("text is not 'init'", function () { - impedanceArray[4].P.should.have.property('text').not.be.equal(k.OBCIImpedanceTextInit); - }); - }); - describe('#inputN', function () { - it('got raw impedance value', function () { - impedanceArray[4].N.should.have.property('raw').above(-1); - }); - it("text is not 'init'", function () { - impedanceArray[4].N.should.have.property('text').not.be.equal(k.OBCIImpedanceTextInit); - }); - }); - }); - describe('#channel6', function () { - it('has valid channel number', function () { - impedanceArray[5].channel.should.be.equal(6); - }); - describe('#inputP', function () { - it('got raw impedance value', function () { - impedanceArray[5].P.should.have.property('raw').above(-1); - }); - it("text is not 'init'", function () { - impedanceArray[5].P.should.have.property('text').not.be.equal(k.OBCIImpedanceTextInit); - }); - }); - describe('#inputN', function () { - it('got raw impedance value', function () { - impedanceArray[5].N.should.have.property('raw').above(-1); - }); - it("text is not 'init'", function () { - impedanceArray[5].N.should.have.property('text').not.be.equal(k.OBCIImpedanceTextInit); - }); - }); - }); - describe('#channel7', function () { - it('has valid channel number', function () { - impedanceArray[6].channel.should.be.equal(7); - }); - describe('#inputP', function () { - it('got raw impedance value', function () { - impedanceArray[6].P.should.have.property('raw').above(-1); - }); - it("text is not 'init'", function () { - impedanceArray[6].P.should.have.property('text').not.be.equal(k.OBCIImpedanceTextInit); - }); - }); - describe('#inputN', function () { - it('got raw impedance value', function () { - impedanceArray[6].N.should.have.property('raw').above(-1); - }); - it("text is not 'init'", function () { - impedanceArray[6].N.should.have.property('text').not.be.equal(k.OBCIImpedanceTextInit); - }); - }); - }); - describe('#channel8', function () { - it('has valid channel number', function () { - impedanceArray[7].channel.should.be.equal(8); - }); - describe('#inputP', function () { - it('got raw impedance value', function () { - impedanceArray[7].P.should.have.property('raw').above(-1); - }); - it("text is not 'init'", function () { - impedanceArray[7].P.should.have.property('text').not.be.equal(k.OBCIImpedanceTextInit); - }); - }); - describe('#inputN', function () { - it('got raw impedance value', function () { - impedanceArray[7].N.should.have.property('raw').above(-1); - }); - it("text is not 'init'", function () { - impedanceArray[7].N.should.have.property('text').not.be.equal(k.OBCIImpedanceTextInit); - }); - }); - }); - }); - describe('#impedanceTestChannelsRejects', function () { - it('rejects when it does not get an array', function (done) { - ourBoard.impedanceTestChannels('taco').should.be.rejected.and.notify(done); - }); - - it('rejects when it array length does not match number of channels', function (done) { - ourBoard.impedanceTestChannels(['-', 'N', 'n', 'p', 'P', 'p', 'b']).should.be.rejected.and.notify(done); - }); - }); - describe('#impedanceTestChannels', function () { - var impedanceArray = []; - - before(function (done) { - ourBoard.once('impedanceArray', arr => { - impedanceArray = arr; - done(); - }); - ourBoard.impedanceArray[0] = openBCISample.impedanceObject(1); - ourBoard.impedanceTestChannels(['-', 'N', 'n', 'p', 'P', 'p', 'b', 'B']).catch(err => done(err)); - }); - describe('#channel1', function () { - it('has valid channel number', function () { - impedanceArray[0].channel.should.be.equal(1); - }); - describe('#inputP', function () { - it('got raw impedance value', function () { - impedanceArray[0].P.should.have.property('raw').equal(-1); - }); - it("text is not 'init'", function () { - impedanceArray[0].P.should.have.property('text').equal(k.OBCIImpedanceTextInit); - }); - }); - describe('#inputN', function () { - it('got raw impedance value', function () { - impedanceArray[0].N.should.have.property('raw').equal(-1); - }); - it("text is not 'init'", function () { - impedanceArray[0].N.should.have.property('text').equal(k.OBCIImpedanceTextInit); - }); - }); - }); - describe('#channel2', function () { - it('has valid channel number', function () { - impedanceArray[1].channel.should.be.equal(2); - }); - describe('#inputP', function () { - it('got raw impedance value', function () { - impedanceArray[1].P.should.have.property('raw').equal(-1); - }); - it("text is not 'init'", function () { - impedanceArray[1].P.should.have.property('text').equal(k.OBCIImpedanceTextInit); - }); - }); - describe('#inputN', function () { - it('got raw impedance value', function () { - impedanceArray[1].N.should.have.property('raw').above(-1); - }); - it("text is not 'init'", function () { - impedanceArray[1].N.should.have.property('text').not.be.equal(k.OBCIImpedanceTextInit); - }); - }); - }); - describe('#channel3', function () { - it('has valid channel number', function () { - impedanceArray[2].channel.should.be.equal(3); - }); - describe('#inputP', function () { - it('got raw impedance value', function () { - impedanceArray[2].P.should.have.property('raw').equal(-1); - }); - it("text is not 'init'", function () { - impedanceArray[2].P.should.have.property('text').equal(k.OBCIImpedanceTextInit); - }); - }); - describe('#inputN', function () { - it('got raw impedance value', function () { - impedanceArray[2].N.should.have.property('raw').above(-1); - }); - it("text is not 'init'", function () { - impedanceArray[2].N.should.have.property('text').not.be.equal(k.OBCIImpedanceTextInit); - }); - }); - }); - describe('#channel4', function () { - it('has valid channel number', function () { - impedanceArray[3].channel.should.be.equal(4); - }); - describe('#inputP', function () { - it('got raw impedance value', function () { - impedanceArray[3].P.should.have.property('raw').above(-1); - }); - it("text is not 'init'", function () { - impedanceArray[3].P.should.have.property('text').not.be.equal(k.OBCIImpedanceTextInit); - }); - }); - describe('#inputN', function () { - it('got raw impedance value', function () { - impedanceArray[3].N.should.have.property('raw').equal(-1); - }); - it("text is not 'init'", function () { - impedanceArray[3].N.should.have.property('text').equal(k.OBCIImpedanceTextInit); - }); - }); - }); - describe('#channel5', function () { - it('has valid channel number', function () { - impedanceArray[4].channel.should.be.equal(5); - }); - describe('#inputP', function () { - it('got raw impedance value', function () { - impedanceArray[4].P.should.have.property('raw').above(-1); - }); - it("text is not 'init'", function () { - impedanceArray[4].P.should.have.property('text').not.be.equal(k.OBCIImpedanceTextInit); - }); - }); - describe('#inputN', function () { - it('got raw impedance value', function () { - impedanceArray[4].N.should.have.property('raw').equal(-1); - }); - it("text is not 'init'", function () { - impedanceArray[4].N.should.have.property('text').equal(k.OBCIImpedanceTextInit); - }); - }); - }); - describe('#channel6', function () { - it('has valid channel number', function () { - impedanceArray[5].channel.should.be.equal(6); - }); - describe('#inputP', function () { - it('got raw impedance value', function () { - impedanceArray[5].P.should.have.property('raw').above(-1); - }); - it("text is not 'init'", function () { - impedanceArray[5].P.should.have.property('text').not.be.equal(k.OBCIImpedanceTextInit); - }); - }); - describe('#inputN', function () { - it('got raw impedance value', function () { - impedanceArray[5].N.should.have.property('raw').equal(-1); - }); - it("text is not 'init'", function () { - impedanceArray[5].N.should.have.property('text').equal(k.OBCIImpedanceTextInit); - }); - }); - }); - describe('#channel7', function () { - it('has valid channel number', function () { - impedanceArray[6].channel.should.be.equal(7); - }); - describe('#inputP', function () { - it('got raw impedance value', function () { - impedanceArray[6].P.should.have.property('raw').above(-1); - }); - it("text is not 'init'", function () { - impedanceArray[6].P.should.have.property('text').not.be.equal(k.OBCIImpedanceTextInit); - }); - }); - describe('#inputN', function () { - it('got raw impedance value', function () { - impedanceArray[6].N.should.have.property('raw').above(-1); - }); - it("text is not 'init'", function () { - impedanceArray[6].N.should.have.property('text').not.be.equal(k.OBCIImpedanceTextInit); - }); - }); - }); - describe('#channel8', function () { - it('has valid channel number', function () { - impedanceArray[7].channel.should.be.equal(8); - }); - describe('#inputP', function () { - it('got raw impedance value', function () { - impedanceArray[7].P.should.have.property('raw').above(-1); - }); - it("text is not 'init'", function () { - impedanceArray[7].P.should.have.property('text').not.be.equal(k.OBCIImpedanceTextInit); - }); - }); - describe('#inputN', function () { - it('got raw impedance value', function () { - impedanceArray[7].N.should.have.property('raw').above(-1); - }); - it("text is not 'init'", function () { - impedanceArray[7].N.should.have.property('text').not.be.equal(k.OBCIImpedanceTextInit); - }); - }); - }); - }); - describe('#impedanceTestChannel', function () { - var impedanceObject = {}; - - before(function (done) { - ourBoard.impedanceTestChannel(1) - .then(impdObj => { - impedanceObject = impdObj; - done(); - }) - .catch(err => done(err)); - }); - describe('#channel1', function () { - it('has valid channel number', function () { - impedanceObject.channel.should.be.equal(1); - }); - describe('#inputP', function () { - it('got raw impedance value', function () { - impedanceObject.P.should.have.property('raw').above(-1); - }); - it("text is not 'init'", function () { - impedanceObject.P.should.have.property('text').not.be.equal(k.OBCIImpedanceTextInit); - }); - }); - describe('#inputN', function () { - it('got raw impedance value', function () { - impedanceObject.N.should.have.property('raw').above(-1); - }); - it("text is not 'init'", function () { - impedanceObject.N.should.have.property('text').not.be.equal(k.OBCIImpedanceTextInit); - }); - }); - }); - }); - describe('#impedanceTestChannelInputP', function () { - var impedanceObject = {}; - - before(function (done) { - ourBoard.impedanceTestChannelInputP(1) - .then(impdObj => { - impedanceObject = impdObj; - done(); - }) - .catch(err => done(err)); - }); - describe('#channel1', function () { - it('has valid channel number', function () { - impedanceObject.channel.should.be.equal(1); - }); - describe('#inputP', function () { - it('got raw impedance value', function () { - impedanceObject.P.should.have.property('raw').above(-1); - }); - it("text is not 'init'", function () { - impedanceObject.P.should.have.property('text').not.be.equal(k.OBCIImpedanceTextInit); - }); - }); - describe('#inputN', function () { - it('got raw impedance value', function () { - impedanceObject.N.should.have.property('raw').equal(-1); - }); - it("text is not 'init'", function () { - impedanceObject.N.should.have.property('text').equal(k.OBCIImpedanceTextInit); - }); - }); - }); - }); - describe('#impedanceTestChannelInputN', function () { - var impedanceObject = {}; - // wstream = fs.createWriteStream('hardwareVoltageOutputAll.txt') - - before(function (done) { - console.log('7'); - - ourBoard.on('sample', sample => { - // console.log('8') - // OpenBCISample.debugPrettyPrint(sample) - // good to start impedance testing.. - }); - - ourBoard.impedanceTestChannelInputN(1) - .then(impdObj => { - impedanceObject = impdObj; - setTimeout(() => { - done(); - }, 1000); - }) - .catch(err => done(err)); - }); - describe('#channel1', function () { - it('has valid channel number', function () { - impedanceObject.channel.should.be.equal(1); - }); - describe('#inputP', function () { - it('got raw impedance value', function () { - impedanceObject.P.should.have.property('raw').equal(-1); - }); - it("text is not 'init'", function () { - impedanceObject.P.should.have.property('text').equal(k.OBCIImpedanceTextInit); - }); - }); - describe('#inputN', function () { - it('got raw impedance value', function () { - impedanceObject.N.should.have.property('raw').above(-1); - }); - it("text is not 'init'", function () { - impedanceObject.N.should.have.property('text').not.be.equal(k.OBCIImpedanceTextInit); - }); - }); - }); - }); - describe('#impedanceTestContinuousStXX', function () { - before(function (done) { - ourBoard.impedanceTestContinuousStart() - .then(done).catch(err => done(err)); - }); - - after(function (done) { - ourBoard.impedanceTestContinuousStop() - .then(done); - }); - - it('prints 10 impedance arrays', function (done) { - var count = 1; - - var listener = impedanceArray => { - // console.log('\nImpedance Array: ' + count) - // console.log(impedanceArray) - count++; - if (count > 10) { - ourBoard.removeListener('impedanceArray', listener); - done(); - } - }; - ourBoard.on('impedanceArray', listener); - }); - }); - describe('#_impedanceTestSetChannel', function () { - it('reject with invalid channel', function (done) { - ourBoard._impedanceTestSetChannel(0, false, false).should.be.rejected.and.notify(done); - }); - }); - describe('#_impedanceTestCalculateChannel', function () { - it('reject with low invalid channel', function (done) { - ourBoard._impedanceTestCalculateChannel(0, false, false).should.be.rejected.and.notify(done); - }); - it('reject with high invalid channel', function (done) { - ourBoard._impedanceTestCalculateChannel(69, false, false).should.be.rejected.and.notify(done); - }); - it('reject with invalid data type pInput', function (done) { - ourBoard._impedanceTestCalculateChannel(1, 'taco', false).should.be.rejected.and.notify(done); - }); - it('reject with invalid data type nInput', function (done) { - ourBoard._impedanceTestCalculateChannel(1, false, 'taco').should.be.rejected.and.notify(done); - }); - }); - describe('#_impedanceTestFinalizeChannel', function () { - it('reject with low invalid channel', function (done) { - ourBoard._impedanceTestFinalizeChannel(0, false, false).should.be.rejected.and.notify(done); - }); - it('reject with high invalid channel', function (done) { - ourBoard._impedanceTestFinalizeChannel(69, false, false).should.be.rejected.and.notify(done); - }); - it('reject with invalid data type pInput', function (done) { - ourBoard._impedanceTestFinalizeChannel(1, 'taco', false).should.be.rejected.and.notify(done); - }); - it('reject with invalid data type nInput', function (done) { - ourBoard._impedanceTestFinalizeChannel(1, false, 'taco').should.be.rejected.and.notify(done); - }); - }); -}); diff --git a/test/openBCIBoard-radio-test.js b/test/openBCIBoard-radio-test.js deleted file mode 100644 index 5f5905d..0000000 --- a/test/openBCIBoard-radio-test.js +++ /dev/null @@ -1,949 +0,0 @@ -'use strict'; -var bluebirdChecks = require('./bluebirdChecks'); -var sinon = require('sinon'); // eslint-disable-line no-unused-vars -var chai = require('chai'); -var expect = chai.expect; -var should = chai.should(); // eslint-disable-line no-unused-vars -var openBCIBoard = require('../openBCIBoard'); -var openBCISample = openBCIBoard.OpenBCISample; -var k = openBCISample.k; -var chaiAsPromised = require('chai-as-promised'); -var sinonChai = require('sinon-chai'); - -chai.use(chaiAsPromised); -chai.use(sinonChai); - -describe('openbci-radios', function () { - this.timeout(2000); - var ourBoard, masterPortName; - - before(function (done) { - ourBoard = new openBCIBoard.OpenBCIBoard(); - ourBoard.autoFindOpenBCIBoard() - .then(portName => { - ourBoard = null; - masterPortName = portName; - done(); - }) - .catch(() => { - ourBoard = null; - masterPortName = k.OBCISimulatorPortName; - done(); - }); - }); - after(done => { - if (ourBoard) { - if (ourBoard['connected']) { - ourBoard.disconnect() - .then(() => { - done(); - }) - .catch(err => { - done(err); - }); - } else { - done(); - } - } else { - done(); - } - }); - - describe('#radioChannelSet', function () { - afterEach(function (done) { - if (ourBoard.isConnected()) { - ourBoard.disconnect().then(() => { - done(); - }).catch(() => done); - } else { - done(); - } - }); - afterEach(() => bluebirdChecks.noPendingPromises()); - - it('should not change the channel number if not connected', function (done) { - ourBoard = new openBCIBoard.OpenBCIBoard({ - verbose: true, - simulate: true, - simulatorFirmwareVersion: 'v2' - }); - ourBoard.radioChannelGet().should.be.rejected.and.notify(done); - }); - - it('should reject if streaming', function (done) { - ourBoard = new openBCIBoard.OpenBCIBoard({ - verbose: true, - simulate: true, - simulatorFirmwareVersion: 'v2' - }); - ourBoard.connect(k.OBCISimulatorPortName) - .then(() => { - ourBoard.once('ready', () => { - ourBoard.streamStart() - .then(() => { - ourBoard.radioChannelSet(1).then(() => { - done('should have rejected'); - }).catch(() => { - done(); // Test pass - }); - }).catch(err => done(err)); - }); - }).catch(err => done(err)); - }); - it('should reject if not firmware version 2', function (done) { - ourBoard = new openBCIBoard.OpenBCIBoard({ - verbose: true, - simulate: true - }); - ourBoard.connect(k.OBCISimulatorPortName) - .then(() => { - ourBoard.once('ready', () => { - ourBoard.radioChannelSet(1).should.be.rejected.and.notify(done); - }); - }).catch(err => done(err)); - }); - it('should reject if a number is not sent as input', function (done) { - ourBoard = new openBCIBoard.OpenBCIBoard({ - verbose: true, - simulate: true, - simulatorFirmwareVersion: 'v2' - }); - ourBoard.connect(k.OBCISimulatorPortName) - .then(() => { - ourBoard.once('ready', () => { - ourBoard.radioChannelSet('1').should.be.rejected.and.notify(done); - }); - }).catch(err => done(err)); - }); - - it('should reject if no channel number is presented as arg', function (done) { - ourBoard = new openBCIBoard.OpenBCIBoard({ - verbose: true, - simulate: true, - simulatorFirmwareVersion: 'v2' - }); - ourBoard.connect(k.OBCISimulatorPortName) - .then(() => { - ourBoard.once('ready', () => { - ourBoard.radioChannelSet().should.be.rejected.and.notify(done); - }); - }).catch(err => done(err)); - }); - - it('should reject if the requested new channel number is lower than 0', function (done) { - ourBoard = new openBCIBoard.OpenBCIBoard({ - verbose: true, - simulate: true, - simulatorFirmwareVersion: 'v2' - }); - ourBoard.connect(k.OBCISimulatorPortName) - .then(() => { - ourBoard.once('ready', () => { - ourBoard.radioChannelSet(-1).should.be.rejected.and.notify(done); - }); - }).catch(err => done(err)); - }); - - it('should reject if the requested new channel number is higher than 25', function (done) { - ourBoard = new openBCIBoard.OpenBCIBoard({ - verbose: true, - simulate: true, - simulatorFirmwareVersion: 'v2' - }); - ourBoard.connect(k.OBCISimulatorPortName) - .then(() => { - ourBoard.once('ready', () => { - ourBoard.radioChannelSet(26).should.be.rejected.and.notify(done); - }); - }).catch(err => done(err)); - }); - - it('should not change the channel if the board is not communicating with the host', function (done) { - ourBoard = new openBCIBoard.OpenBCIBoard({ - verbose: true, - simulate: true, - simulatorBoardFailure: true, - simulatorFirmwareVersion: 'v2' - }); - ourBoard.connect(k.OBCISimulatorPortName) - .then(() => { - ourBoard.once('ready', () => { - ourBoard.radioChannelSet(1).should.be.rejected.and.notify(done); - }); - }).catch(err => done(err)); - }); - - it('should change the channel if connected, not steaming, and using firmware version 2+', function (done) { - var newChannelNumber = 2; - ourBoard = new openBCIBoard.OpenBCIBoard({ - verbose: true, - simulate: true, - simulatorFirmwareVersion: 'v2' - }); - ourBoard.connect(k.OBCISimulatorPortName) - .then(() => { - ourBoard.once('ready', () => { - ourBoard.radioChannelSet(newChannelNumber).then(channelNumber => { - expect(channelNumber).to.be.equal(newChannelNumber); - done(); - }).catch(err => done(err)); - }); - }).catch(err => done(err)); - }); - }); - - describe('#radioChannelSetHostOverride', function () { - afterEach(function (done) { - if (ourBoard.isConnected()) { - ourBoard.disconnect().then(() => { - done(); - }).catch(() => done); - } else { - done(); - } - }); - afterEach(() => bluebirdChecks.noPendingPromises()); - it('should not change the channel number if not connected', function (done) { - ourBoard = new openBCIBoard.OpenBCIBoard({ - verbose: true, - simulate: true, - simulatorFirmwareVersion: 'v2' - }); - ourBoard.radioChannelSetHostOverride().should.be.rejected.and.notify(done); - }); - it('should reject if streaming', function (done) { - ourBoard = new openBCIBoard.OpenBCIBoard({ - verbose: true, - simulate: true, - simulatorFirmwareVersion: 'v2' - }); - ourBoard.connect(k.OBCISimulatorPortName) - .then(() => { - ourBoard.once('ready', () => { - ourBoard.streamStart() - .then(() => { - ourBoard.radioChannelSetHostOverride(1).then(() => { - done('should have rejected'); - }).catch(() => { - done(); // Test pass - }); - }).catch(err => done(err)); - }); - }).catch(err => done(err)); - }); - it('should reject if a number is not sent as input', function (done) { - ourBoard = new openBCIBoard.OpenBCIBoard({ - verbose: true, - simulate: true, - simulatorFirmwareVersion: 'v2' - }); - ourBoard.connect(k.OBCISimulatorPortName) - .then(() => { - ourBoard.once('ready', () => { - ourBoard.radioChannelSetHostOverride('1').should.be.rejected.and.notify(done); - }); - }).catch(err => done(err)); - }); - it('should reject if no channel number is presented as arg', function (done) { - ourBoard = new openBCIBoard.OpenBCIBoard({ - verbose: true, - simulate: true, - simulatorFirmwareVersion: 'v2' - }); - ourBoard.connect(k.OBCISimulatorPortName) - .then(() => { - ourBoard.once('ready', () => { - ourBoard.radioChannelSetHostOverride().should.be.rejected.and.notify(done); - }); - }).catch(err => done(err)); - }); - it('should reject if the requested new channel number is lower than 0', function (done) { - ourBoard = new openBCIBoard.OpenBCIBoard({ - verbose: true, - simulate: true, - simulatorFirmwareVersion: 'v2' - }); - ourBoard.connect(k.OBCISimulatorPortName) - .then(() => { - ourBoard.once('ready', () => { - ourBoard.radioChannelSetHostOverride(-1).should.be.rejected.and.notify(done); - }); - }).catch(err => done(err)); - }); - it('should reject if the requested new channel number is higher than 25', function (done) { - ourBoard = new openBCIBoard.OpenBCIBoard({ - verbose: true, - simulate: true, - simulatorFirmwareVersion: 'v2' - }); - ourBoard.connect(k.OBCISimulatorPortName) - .then(() => { - ourBoard.once('ready', () => { - ourBoard.radioChannelSetHostOverride(26).should.be.rejected.and.notify(done); - }); - }).catch(err => done(err)); - }); - it('should change the channel if connected, not steaming, and using firmware version 2+', function (done) { - var newChannelNumber = 2; - ourBoard = new openBCIBoard.OpenBCIBoard({ - verbose: true, - simulate: true, - simulatorFirmwareVersion: 'v2' - }); - ourBoard.connect(k.OBCISimulatorPortName) - .then(() => { - ourBoard.once('ready', () => { - ourBoard.radioChannelSetHostOverride(newChannelNumber).then(channelNumber => { - expect(channelNumber).to.be.equal(newChannelNumber); - done(); - }).catch(err => done(err)); - }); - }).catch(err => done(err)); - }); - }); - - describe('#radioChannelGet', function () { - afterEach(function (done) { - if (ourBoard.isConnected()) { - ourBoard.disconnect().then(() => { - done(); - }).catch(() => done); - } else { - done(); - } - }); - afterEach(() => bluebirdChecks.noPendingPromises()); - - it('should not query if not connected', function (done) { - ourBoard = new openBCIBoard.OpenBCIBoard({ - verbose: true, - simulate: true - }); - ourBoard.radioChannelGet().should.be.rejected.and.notify(done); - }); - it('should not query if streaming', function (done) { - ourBoard = new openBCIBoard.OpenBCIBoard({ - verbose: true, - simulate: true - }); - ourBoard.connect(k.OBCISimulatorPortName) - .then(() => { - ourBoard.once('ready', () => { - ourBoard.streamStart() - .then(() => { - ourBoard.radioChannelGet().then(() => { - done('should have rejected'); - }).catch(() => { - done(); // Test pass - }); - }).catch(err => done(err)); - }); - }).catch(err => done(err)); - }); - it('should not query if not firmware version 2', function (done) { - ourBoard = new openBCIBoard.OpenBCIBoard({ - verbose: true, - simulate: true - }); - ourBoard.connect(k.OBCISimulatorPortName) - .then(() => { - ourBoard.once('ready', () => { - ourBoard.radioChannelGet().should.be.rejected.and.notify(done); - }); - }).catch(err => done(err)); - }); - it('should query if firmware version 2', function (done) { - ourBoard = new openBCIBoard.OpenBCIBoard({ - verbose: true, - simulate: true, - simulatorFirmwareVersion: 'v2' - }); - ourBoard.connect(k.OBCISimulatorPortName) - .then(() => { - ourBoard.once('ready', () => { - ourBoard.radioChannelGet().then(res => { - expect(res.channelNumber).to.be.within(k.OBCIRadioChannelMin, k.OBCIRadioChannelMax); - done(); - }).catch(err => done(err)); - }); - }).catch(err => done(err)); - }); - it('should get message even if the board is not communicating with dongle', function (done) { - ourBoard = new openBCIBoard.OpenBCIBoard({ - verbose: true, - simulate: true, - simulatorBoardFailure: true, - simulatorFirmwareVersion: 'v2' - }); - ourBoard.connect(k.OBCISimulatorPortName) - .then(() => { - ourBoard.once('ready', () => { - ourBoard.radioChannelGet().should.be.rejected.and.notify(done); - }); - }).catch(err => done(err)); - }); - }); - - describe('#radioPollTimeSet', function () { - afterEach(function (done) { - if (ourBoard.isConnected()) { - ourBoard.disconnect().then(() => { - done(); - }).catch(() => done); - } else { - done(); - } - }); - afterEach(() => bluebirdChecks.noPendingPromises()); - it('should not change the channel number if not connected', function (done) { - ourBoard = new openBCIBoard.OpenBCIBoard({ - verbose: true, - simulate: true, - simulatorFirmwareVersion: 'v2' - }); - ourBoard.radioPollTimeSet().should.be.rejected.and.notify(done); - }); - - it('should reject if streaming', function (done) { - ourBoard = new openBCIBoard.OpenBCIBoard({ - verbose: true, - simulate: true, - simulatorFirmwareVersion: 'v2' - }); - ourBoard.connect(k.OBCISimulatorPortName) - .then(() => { - ourBoard.once('ready', () => { - ourBoard.streamStart() - .then(() => { - ourBoard.radioPollTimeSet(1).then(() => { - done('should have rejected'); - }).catch(() => { - done(); // Test pass - }); - }).catch(err => done(err)); - }); - }).catch(err => done(err)); - }); - - it('should reject if not firmware version 2', function (done) { - ourBoard = new openBCIBoard.OpenBCIBoard({ - verbose: true, - simulate: true - }); - ourBoard.connect(k.OBCISimulatorPortName) - .then(() => { - ourBoard.once('ready', () => { - ourBoard.radioPollTimeSet(1).should.be.rejected.and.notify(done); - }); - }).catch(err => done(err)); - }); - - it('should reject if a number is not sent as input', function (done) { - ourBoard = new openBCIBoard.OpenBCIBoard({ - verbose: true, - simulate: true, - simulatorFirmwareVersion: 'v2' - }); - ourBoard.connect(k.OBCISimulatorPortName) - .then(() => { - ourBoard.once('ready', () => { - ourBoard.radioPollTimeSet('1').should.be.rejected.and.notify(done); - }); - }).catch(err => done(err)); - }); - - it('should reject if no poll time is presented as arg', function (done) { - ourBoard = new openBCIBoard.OpenBCIBoard({ - verbose: true, - simulate: true, - simulatorFirmwareVersion: 'v2' - }); - ourBoard.connect(k.OBCISimulatorPortName) - .then(() => { - ourBoard.once('ready', () => { - ourBoard.radioPollTimeSet().should.be.rejected.and.notify(done); - }); - }).catch(err => done(err)); - }); - - it('should reject if the requested new poll time is lower than 0', function (done) { - ourBoard = new openBCIBoard.OpenBCIBoard({ - verbose: true, - simulate: true, - simulatorFirmwareVersion: 'v2' - }); - ourBoard.connect(k.OBCISimulatorPortName) - .then(() => { - ourBoard.once('ready', () => { - ourBoard.radioPollTimeSet(-1).should.be.rejected.and.notify(done); - }); - }).catch(err => done(err)); - }); - - it('should reject if the requested new poll time is higher than 255', function (done) { - ourBoard = new openBCIBoard.OpenBCIBoard({ - verbose: true, - simulate: true, - simulatorFirmwareVersion: 'v2' - }); - ourBoard.connect(k.OBCISimulatorPortName) - .then(() => { - ourBoard.once('ready', () => { - ourBoard.radioPollTimeSet(256).should.be.rejected.and.notify(done); - }); - }).catch(err => done(err)); - }); - - it('should not change the poll time if the board is not communicating with the host', function (done) { - ourBoard = new openBCIBoard.OpenBCIBoard({ - verbose: true, - simulate: true, - simulatorBoardFailure: true, - simulatorFirmwareVersion: 'v2' - }); - ourBoard.connect(k.OBCISimulatorPortName) - .then(() => { - ourBoard.once('ready', () => { - ourBoard.radioPollTimeSet(1).should.be.rejected.and.notify(done); - }); - }).catch(err => done(err)); - }); - - it('should change the poll time if connected, not steaming, and using firmware version 2+', function (done) { - var newPollTime = 69; - ourBoard = new openBCIBoard.OpenBCIBoard({ - verbose: true, - simulate: true, - simulatorFirmwareVersion: 'v2' - }); - ourBoard.connect(k.OBCISimulatorPortName) - .then(() => { - ourBoard.once('ready', () => { - ourBoard.radioPollTimeSet(newPollTime).then(() => { - done(); - }).catch(err => { - done(err); - }); - }); - }).catch(err => done(err)); - }); - }); - - describe('#radioPollTimeGet', function () { - afterEach(function (done) { - if (ourBoard.isConnected()) { - ourBoard.disconnect().then(() => { - done(); - }).catch(() => done); - } else { - done(); - } - }); - afterEach(() => bluebirdChecks.noPendingPromises()); - - it('should not query if not connected', function (done) { - ourBoard = new openBCIBoard.OpenBCIBoard({ - verbose: true, - simulate: true - }); - ourBoard.radioPollTimeGet().should.be.rejected.and.notify(done); - }); - it('should not query if streaming', function (done) { - ourBoard = new openBCIBoard.OpenBCIBoard({ - verbose: true, - simulate: true - }); - ourBoard.connect(k.OBCISimulatorPortName) - .then(() => { - ourBoard.once('ready', () => { - ourBoard.streamStart() - .then(() => { - ourBoard.radioPollTimeGet().then(() => { - done('should have rejected'); - }).catch(() => { - done(); // Test pass - }); - }).catch(err => done(err)); - }); - }).catch(err => done(err)); - }); - it('should not query if not firmware version 2', function (done) { - ourBoard = new openBCIBoard.OpenBCIBoard({ - verbose: true, - simulate: true - }); - ourBoard.connect(k.OBCISimulatorPortName) - .then(() => { - ourBoard.once('ready', () => { - ourBoard.radioPollTimeGet().should.be.rejected.and.notify(done); - }); - }).catch(err => done(err)); - }); - it('should query if firmware version 2', function (done) { - ourBoard = new openBCIBoard.OpenBCIBoard({ - verbose: true, - simulate: true, - simulatorFirmwareVersion: 'v2' - }); - ourBoard.connect(k.OBCISimulatorPortName) - .then(() => { - ourBoard.once('ready', () => { - ourBoard.radioPollTimeGet().then(pollTime => { - expect(pollTime).to.be.greaterThan(0); - done(); - }).catch(err => done(err)); - }); - }).catch(err => done(err)); - }); - it('should get failure message if the board is not communicating with dongle', function (done) { - ourBoard = new openBCIBoard.OpenBCIBoard({ - verbose: true, - simulate: true, - simulatorBoardFailure: true, - simulatorFirmwareVersion: 'v2' - }); - ourBoard.connect(k.OBCISimulatorPortName) - .then(() => { - ourBoard.once('ready', () => { - ourBoard.radioPollTimeGet().should.be.rejected.and.notify(done); - }); - }).catch(err => done(err)); - }); - }); - - describe('#radioBaudRateSet', function () { - afterEach(function (done) { - if (ourBoard.isConnected()) { - ourBoard.disconnect().then(() => { - done(); - }).catch(() => done); - } else { - done(); - } - }); - afterEach(() => bluebirdChecks.noPendingPromises()); - - it('should not try to set baud rate if not connected', function (done) { - ourBoard = new openBCIBoard.OpenBCIBoard({ - verbose: true, - simulate: true - }); - ourBoard.radioBaudRateSet('default').should.be.rejected.and.notify(done); - }); - it('should reject if no input', function (done) { - ourBoard = new openBCIBoard.OpenBCIBoard({ - verbose: true, - simulate: true - }); - ourBoard.radioBaudRateSet().should.be.rejected.and.notify(done); - }); - it('should be rejected if input type incorrect', function (done) { - ourBoard = new openBCIBoard.OpenBCIBoard({ - verbose: true, - simulate: true - }); - ourBoard.radioBaudRateSet(1).should.be.rejected.and.notify(done); - }); - it('should not try to change the baud rate if streaming', function (done) { - ourBoard = new openBCIBoard.OpenBCIBoard({ - verbose: true, - simulate: true - }); - ourBoard.connect(k.OBCISimulatorPortName) - .then(() => { - ourBoard.once('ready', () => { - ourBoard.streamStart() - .then(() => { - ourBoard.radioBaudRateSet('default').then(() => { - done('should have rejected'); - }).catch(() => { - done(); // Test pass - }); - }).catch(err => done(err)); - }); - }).catch(err => done(err)); - }); - it('should not try to change the baud rate if not firmware version 2', function (done) { - ourBoard = new openBCIBoard.OpenBCIBoard({ - verbose: true, - simulate: true - }); - ourBoard.connect(k.OBCISimulatorPortName) - .then(() => { - ourBoard.once('ready', () => { - ourBoard.radioBaudRateSet('default').should.be.rejected.and.notify(done); - }); - }).catch(err => done(err)); - }); - it('should set the baud rate to default if firmware version 2', function (done) { - ourBoard = new openBCIBoard.OpenBCIBoard({ - verbose: true, - simulate: true, - simulatorFirmwareVersion: 'v2' - }); - ourBoard.connect(k.OBCISimulatorPortName) - .then(() => { - ourBoard.once('ready', () => { - ourBoard.radioBaudRateSet('default').then(baudrate => { - expect(baudrate).to.be.equal(115200); - done(); - }).catch(err => done(err)); - }); - }).catch(err => done(err)); - }); - it('should set the baud rate to fast if firmware version 2', function (done) { - ourBoard = new openBCIBoard.OpenBCIBoard({ - verbose: true, - simulate: true, - simulatorFirmwareVersion: 'v2' - }); - ourBoard.connect(k.OBCISimulatorPortName) - .then(() => { - ourBoard.once('ready', () => { - ourBoard.radioBaudRateSet('fast').then(baudrate => { - expect(baudrate).to.be.equal(230400); - done(); - }).catch(err => done(err)); - }); - }).catch(err => done(err)); - }); - }); - - describe('#radioSystemStatusGet', function () { - afterEach(function (done) { - if (ourBoard.isConnected()) { - ourBoard.disconnect().then(() => { - done(); - }).catch(() => done); - } else { - done(); - } - }); - afterEach(() => bluebirdChecks.noPendingPromises()); - - it('should not get system status if not connected', function (done) { - ourBoard = new openBCIBoard.OpenBCIBoard({ - verbose: true, - simulate: true - }); - ourBoard.radioSystemStatusGet().should.be.rejected.and.notify(done); - }); - it('should not get system status if streaming', function (done) { - ourBoard = new openBCIBoard.OpenBCIBoard({ - verbose: true, - simulate: true - }); - ourBoard.connect(k.OBCISimulatorPortName) - .then(() => { - ourBoard.once('ready', () => { - ourBoard.streamStart() - .then(() => { - ourBoard.radioSystemStatusGet().then(() => { - done('should have rejected'); - }).catch(() => { - done(); // Test pass - }); - }).catch(err => done(err)); - }); - }).catch(err => done(err)); - }); - it('should not get system status if not firmware version 2', function (done) { - ourBoard = new openBCIBoard.OpenBCIBoard({ - verbose: true, - simulate: true - }); - ourBoard.connect(k.OBCISimulatorPortName) - .then(() => { - ourBoard.once('ready', () => { - ourBoard.radioSystemStatusGet().should.be.rejected.and.notify(done); - }); - }).catch(err => done(err)); - }); - it('should get up system status if firmware version 2', function (done) { - ourBoard = new openBCIBoard.OpenBCIBoard({ - verbose: true, - simulate: true, - simulatorFirmwareVersion: 'v2' - }); - ourBoard.connect(k.OBCISimulatorPortName) - .then(() => { - ourBoard.once('ready', () => { - ourBoard.radioSystemStatusGet().then(isUp => { - expect(isUp).to.be.true; - done(); - }).catch(err => done(err)); - }); - }).catch(err => done(err)); - }); - it('should get down system status if firmware version 2', function (done) { - ourBoard = new openBCIBoard.OpenBCIBoard({ - verbose: true, - simulate: true, - simulatorFirmwareVersion: 'v2', - simulatorBoardFailure: true - }); - ourBoard.connect(k.OBCISimulatorPortName) - .then(() => { - ourBoard.once('ready', () => { - ourBoard.radioSystemStatusGet().then(isUp => { - expect(isUp).to.be.false; - done(); - }).catch(err => done(err)); - }); - }).catch(err => done(err)); - }); - }); - - describe('#radioTests', function () { - this.timeout(0); - before(function (done) { - ourBoard = new openBCIBoard.OpenBCIBoard({ - verbose: true, - simulatorFirmwareVersion: 'v2', - simulatorFragmentation: k.OBCISimulatorFragmentationRandom - }); - ourBoard.connect(masterPortName).catch(err => done(err)); - - ourBoard.once('ready', () => { - done(); - }); - }); - after(function (done) { - if (ourBoard.isConnected()) { - ourBoard.disconnect().then(() => { - done(); - }); - } else { - done(); - } - }); - after(() => bluebirdChecks.noPendingPromises()); - it('should be able to get the channel number', function (done) { - // Don't test if not using v2 - if (!ourBoard.usingVersionTwoFirmware()) return done(); - // The channel number should be between 0 and 25. Those are hard limits. - ourBoard.radioChannelGet().then(res => { - expect(res.channelNumber).to.be.within(0, 25); - done(); - }).catch(err => done(err)); - }); - it('should be able to set the channel to 1', function (done) { - // Don't test if not using v2 - if (!ourBoard.usingVersionTwoFirmware()) return done(); - ourBoard.radioChannelSet(1).then(channelNumber => { - expect(channelNumber).to.equal(1); - done(); - }).catch(err => done(err)); - }); - it('should be able to set the channel to 2', function (done) { - // Don't test if not using v2 - if (!ourBoard.usingVersionTwoFirmware()) return done(); - ourBoard.radioChannelSet(2).then(channelNumber => { - expect(channelNumber).to.equal(2); - done(); - }).catch(err => done(err)); - }); - it('should be able to set the channel to 25', function (done) { - // Don't test if not using v2 - if (!ourBoard.usingVersionTwoFirmware()) return done(); - ourBoard.radioChannelSet(25).then(channelNumber => { - expect(channelNumber).to.equal(25); - done(); - }).catch(err => done(err)); - }); - it('should be able to set the channel to 5', function (done) { - // Don't test if not using v2 - if (!ourBoard.usingVersionTwoFirmware()) return done(); - ourBoard.radioChannelSet(5).then(channelNumber => { - expect(channelNumber).to.equal(5); - done(); - }).catch(err => done(err)); - }); - it('should be able to override host channel number, verify system is down, set the host back and verify system is up', function (done) { - // Don't test if not using v2 - if (!ourBoard.usingVersionTwoFirmware()) return done(); - var systemChanNumber = 0; - var newChanNum = 0; - // var timey = Date.now() - // Get the current system channel - ourBoard.radioChannelGet() - .then(res => { - // Store it - systemChanNumber = res.channelNumber; - // console.log(`system channel number: ${res.channelNumber}`) - if (systemChanNumber === 25) { - newChanNum = 24; - } else { - newChanNum = systemChanNumber + 1; - } - // Call to change just the host - return ourBoard.radioChannelSetHostOverride(newChanNum); - }) - .then(newChanNumActual => { - expect(newChanNumActual).to.equal(newChanNum); - // timey = Date.now() - // console.log(`new chan ${newChanNumActual} got`, timey, '0ms') - return new Promise((resolve, reject) => { - setTimeout(function () { - // console.log(`get status`, Date.now(), `${Date.now() - timey}ms`) - ourBoard.radioSystemStatusGet().then(isUp => { - // console.log('resolving', Date.now(), `${Date.now() - timey}ms`) - resolve(isUp); - }) - .catch(err => { - reject(err); - }); - }, 270); // Should be accurate after 270 seconds - }); - }) - .then(isUp => { - // console.log(`isUp test`, Date.now(), `${Date.now() - timey}ms`) - expect(isUp).to.be.false; - return ourBoard.radioChannelSetHostOverride(systemChanNumber); // Set back to good - }) - .then(newChanNumActual => { - // Verify we set it back to normal - expect(newChanNumActual).to.equal(systemChanNumber); - return ourBoard.radioSystemStatusGet(); - }) - .then(isUp => { - expect(isUp).to.be.true; - done(); - }) - .catch(err => done(err)); - }); - it('should be able to get the poll time', function (done) { - // Don't test if not using v2 - if (!ourBoard.usingVersionTwoFirmware()) return done(); - ourBoard.radioPollTimeGet().should.eventually.be.greaterThan(0).and.notify(done); - }); - it('should be able to set the poll time', function (done) { - // Don't test if not using v2 - if (!ourBoard.usingVersionTwoFirmware()) return done(); - ourBoard.radioPollTimeSet(80).should.become(80).and.notify(done); - }); - it('should be able to change to default baud rate', function (done) { - // Don't test if not using v2 - if (!ourBoard.usingVersionTwoFirmware()) return done(); - ourBoard.radioBaudRateSet('default').should.become(115200).and.notify(done); - }); - it('should be able to change to fast baud rate', function (done) { - // Don't test if not using v2 - if (!ourBoard.usingVersionTwoFirmware()) return done(); - ourBoard.radioBaudRateSet('fast').then(newBaudRate => { - expect(newBaudRate).to.equal(230400); - return ourBoard.radioBaudRateSet('default'); - }).then(() => { - done(); - }).catch(err => done(err)); - }); - it('should be able to set the system status', function (done) { - // Don't test if not using v2 - if (!ourBoard.usingVersionTwoFirmware()) return done(); - ourBoard.radioSystemStatusGet().then(isUp => { - expect(isUp).to.be.true; - done(); - }).catch(err => done(err)); - }); - }); -}); diff --git a/test/openBCIBoard-test.js b/test/openBCIBoard-test.js deleted file mode 100644 index 4cc06ac..0000000 --- a/test/openBCIBoard-test.js +++ /dev/null @@ -1,2835 +0,0 @@ -'use strict'; -var bluebirdChecks = require('./bluebirdChecks'); -var sinon = require('sinon'); -var chai = require('chai'); -var expect = chai.expect; -var should = chai.should(); // eslint-disable-line no-unused-vars -var openBCIBoard = require('../openBCIBoard'); -var openBCISample = openBCIBoard.OpenBCISample; -var k = openBCISample.k; -var chaiAsPromised = require('chai-as-promised'); -var sinonChai = require('sinon-chai'); -var bufferEqual = require('buffer-equal'); -var fs = require('fs'); -var math = require('mathjs'); - -chai.use(chaiAsPromised); -chai.use(sinonChai); - -describe('openbci-sdk', function () { - this.timeout(2000); - var ourBoard, masterPortName, realBoard, spy; - - before(function (done) { - ourBoard = new openBCIBoard.OpenBCIBoard(); - ourBoard.autoFindOpenBCIBoard() - .then(portName => { - ourBoard = null; - realBoard = true; - masterPortName = portName; - done(); - }) - .catch(() => { - ourBoard = null; - realBoard = false; - masterPortName = k.OBCISimulatorPortName; - done(); - }); - }); - after(done => { - if (ourBoard) { - if (ourBoard['connected']) { - ourBoard.disconnect() - .then(() => { - done(); - }) - .catch(err => { - done(err); - }); - } else { - done(); - } - } else { - done(); - } - }); - describe('#constructor', function () { - afterEach(() => { - ourBoard = null; - return bluebirdChecks.noPendingPromises(); - }); - it('constructs with require', function () { - var OpenBCIBoard = require('../openBCIBoard').OpenBCIBoard; - ourBoard = new OpenBCIBoard({ - verbose: true - }); - expect(ourBoard.numberOfChannels()).to.equal(8); - }); - it('constructs with the correct default options', () => { - var board = new openBCIBoard.OpenBCIBoard(); - expect(board.options.boardType).to.equal(k.OBCIBoardDefault); - expect(board.options.baudRate).to.equal(115200); - expect(board.options.hardSet).to.be.false; - expect(board.options.simulate).to.be.false; - expect(board.options.simulatorBoardFailure).to.be.false; - expect(board.options.simulatorDaisyModuleAttached).to.be.false; - expect(board.options.simulatorDaisyModuleCanBeAttached).to.be.true; - expect(board.options.simulatorFirmwareVersion).to.equal(k.OBCIFirmwareV1); - expect(board.options.simulatorHasAccelerometer).to.be.true; - expect(board.options.simulatorInternalClockDrift).to.equal(0); - expect(board.options.simulatorInjectAlpha).to.be.true; - expect(board.options.simulatorInjectLineNoise).to.equal(k.OBCISimulatorLineNoiseHz60); - expect(board.options.simulatorSampleRate).to.equal(k.OBCISampleRate250); - expect(board.options.simulatorSerialPortFailure).to.be.false; - expect(board.options.sntpTimeSync).to.be.false; - expect(board.options.sntpTimeSyncHost).to.equal('pool.ntp.org'); - expect(board.options.verbose).to.be.false; - expect(board.sampleRate()).to.equal(250); - expect(board.numberOfChannels()).to.equal(8); - expect(board.isConnected()).to.be.false; - expect(board.isStreaming()).to.be.false; - }); - it('should be able to set ganglion mode', () => { - var board = new openBCIBoard.OpenBCIBoard({ - boardType: 'ganglion' - }); - (board.options.boardType).should.equal('ganglion'); - }); - it('should be able to set set daisy mode', () => { - var ourBoard1 = new openBCIBoard.OpenBCIBoard({ - boardType: 'daisy' - }); - var ourBoard2 = new openBCIBoard.OpenBCIBoard({ - boardtype: 'daisy' - }); - (ourBoard1.options.boardType).should.equal('daisy'); - (ourBoard2.options.boardType).should.equal('daisy'); - it('should get value for daisy', () => { - ourBoard1.sampleRate().should.equal(125); - }); - it('should get value for daisy', () => { - ourBoard1.numberOfChannels().should.equal(16); - }); - }); - it('should be able to change baud rate', () => { - var ourBoard1 = new openBCIBoard.OpenBCIBoard({ - baudRate: 9600 - }); - (ourBoard1.options.baudRate).should.equal(9600); - var ourBoard2 = new openBCIBoard.OpenBCIBoard({ - baudrate: 9600 - }); - (ourBoard2.options.baudRate).should.equal(9600); - }); - it('should be able to enter simulate mode from the constructor', () => { - var board = new openBCIBoard.OpenBCIBoard({ - simulate: true - }); - expect(board.options.simulate).to.be.true; - }); - it('should be able to set the simulator to board failure mode', () => { - var ourBoard1 = new openBCIBoard.OpenBCIBoard({ - simulatorBoardFailure: true - }); - expect(ourBoard1.options.simulatorBoardFailure).to.be.true; - var ourBoard2 = new openBCIBoard.OpenBCIBoard({ - simulatorboardfailure: true - }); - expect(ourBoard2.options.simulatorBoardFailure).to.be.true; - }); - it('should be able to attach the daisy board in the simulator', () => { - var ourBoard1 = new openBCIBoard.OpenBCIBoard({ - simulatorDaisyModuleAttached: true - }); - expect(ourBoard1.options.simulatorDaisyModuleAttached).to.be.true; - // Verify multi case support - var ourBoard2 = new openBCIBoard.OpenBCIBoard({ - simulatordaisymoduleattached: true - }); - expect(ourBoard2.options.simulatorDaisyModuleAttached).to.be.true; - }); - it('should be able to start the simulator with firmware version 2', () => { - var ourBoard1 = new openBCIBoard.OpenBCIBoard({ - simulatorFirmwareVersion: 'v2' - }); - (ourBoard1.options.simulatorFirmwareVersion).should.equal(k.OBCIFirmwareV2); - // Verify multi case support - var ourBoard2 = new openBCIBoard.OpenBCIBoard({ - simulatorfirmwareversion: 'v2' - }); - (ourBoard2.options.simulatorFirmwareVersion).should.equal(k.OBCIFirmwareV2); - }); - it('should be able to put the simulator in raw aux mode', () => { - var ourBoard1 = new openBCIBoard.OpenBCIBoard({ - simulatorHasAccelerometer: false - }); - expect(ourBoard1.options.simulatorHasAccelerometer).to.be.false; - // Verify multi case support - var ourBoard2 = new openBCIBoard.OpenBCIBoard({ - simulatorhasaccelerometer: false - }); - expect(ourBoard2.options.simulatorHasAccelerometer).to.be.false; - }); - it('should be able to make the internal clock of the simulator run slow', () => { - var ourBoard1 = new openBCIBoard.OpenBCIBoard({ - simulatorInternalClockDrift: -1 - }); - expect(ourBoard1.options.simulatorInternalClockDrift).to.be.lessThan(0); - // Verify multi case support - var ourBoard2 = new openBCIBoard.OpenBCIBoard({ - simulatorinternalclockdrift: -1 - }); - expect(ourBoard2.options.simulatorInternalClockDrift).to.be.lessThan(0); - }); - it('should be able to make the internal clock of the simulator run fast', () => { - var ourBoard1 = new openBCIBoard.OpenBCIBoard({ - simulatorInternalClockDrift: 1 - }); - expect(ourBoard1.options.simulatorInternalClockDrift).to.be.greaterThan(0); - // Verify multi case support - var ourBoard2 = new openBCIBoard.OpenBCIBoard({ - simulatorinternalclockdrift: 1 - }); - expect(ourBoard2.options.simulatorInternalClockDrift).to.be.greaterThan(0); - }); - it('should be able to not inject alpha waves into the simulator', function () { - var ourBoard1 = new openBCIBoard.OpenBCIBoard({ - simulatorInjectAlpha: false - }); - expect(ourBoard1.options.simulatorInjectAlpha).to.be.false; - // Verify multi case support - var ourBoard2 = new openBCIBoard.OpenBCIBoard({ - simulatorinjectalpha: false - }); - expect(ourBoard2.options.simulatorInjectAlpha).to.be.false; - }); - it('can turn 50Hz line noise on', function () { - var ourBoard1 = new openBCIBoard.OpenBCIBoard({ - simulatorInjectLineNoise: '50Hz' - }); - expect(ourBoard1.options.simulatorInjectLineNoise).to.equal(k.OBCISimulatorLineNoiseHz50); - // Verify multi case support - var ourBoard2 = new openBCIBoard.OpenBCIBoard({ - simulatorinjectlinenoise: '50Hz' - }); - expect(ourBoard2.options.simulatorInjectLineNoise).to.equal(k.OBCISimulatorLineNoiseHz50); - }); - it('can turn no line noise on', function () { - ourBoard = new openBCIBoard.OpenBCIBoard({ - simulatorInjectLineNoise: 'none' - }); - (ourBoard.options.simulatorInjectLineNoise).should.equal(k.OBCISimulatorLineNoiseNone); - }); - it('defaults to 60Hz line noise when bad input', function () { - ourBoard = new openBCIBoard.OpenBCIBoard({ - simulatorInjectLineNoise: '20Hz' - }); - (ourBoard.options.simulatorInjectLineNoise).should.equal(k.OBCISimulatorLineNoiseHz60); - }); - 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('should be able to attach the daisy board in the simulator', () => { - var ourBoard1 = new openBCIBoard.OpenBCIBoard({ - simulatorSerialPortFailure: true - }); - expect(ourBoard1.options.simulatorSerialPortFailure).to.be.true; - // Verify multi case support - var ourBoard2 = new openBCIBoard.OpenBCIBoard({ - simulatorserialportfailure: true - }); - expect(ourBoard2.options.simulatorSerialPortFailure).to.be.true; - }); - it('should be able to enter sync mode', function () { - var ourBoard = new openBCIBoard.OpenBCIBoard({ - sntpTimeSync: true - }); - expect(ourBoard.options.sntpTimeSync).to.be.true; - - return new Promise((resolve, reject) => { - ourBoard.once('sntpTimeLock', resolve); - ourBoard.once('error', reject); - }).then(() => { - ourBoard.sntpStop(); - }, err => { - ourBoard.sntpStop(); - return Promise.reject(err); - }); - }); - it('should be able to change the ntp pool host', function () { - var expectedPoolName = 'time.apple.com'; - var ourBoard1 = new openBCIBoard.OpenBCIBoard({ - sntpTimeSyncHost: expectedPoolName - }); - expect(ourBoard1.options.sntpTimeSyncHost).to.equal(expectedPoolName); - // Verify multi case support - var ourBoard2 = new openBCIBoard.OpenBCIBoard({ - sntptimesynchost: expectedPoolName - }); - expect(ourBoard2.options.sntpTimeSyncHost).to.equal(expectedPoolName); - }); - it('should be able to change the ntp pool port', function () { - var expectedPortNumber = 73; - var ourBoard1 = new openBCIBoard.OpenBCIBoard({ - sntpTimeSyncPort: expectedPortNumber - }); - expect(ourBoard1.options.sntpTimeSyncPort).to.equal(expectedPortNumber); - // Verify multi case support - var ourBoard2 = new openBCIBoard.OpenBCIBoard({ - sntptimesyncport: expectedPortNumber - }); - expect(ourBoard2.options.sntpTimeSyncPort).to.equal(expectedPortNumber); - }); - it('should report when sntp fails', function (done) { - var ourBoard = new openBCIBoard.OpenBCIBoard({ - sntpTimeSync: true, - sntpTimeSyncHost: 'no\'where' - }); - ourBoard.once('error', () => { - done(); - }); - ourBoard.once('sntpTimeLock', () => { - ourBoard.sntpStop(); - done('got a time lock with nowhere'); - }); - }); - it('can enter verbose mode', function () { - ourBoard = new openBCIBoard.OpenBCIBoard({ - verbose: true - }); - (ourBoard.options.verbose).should.equal(true); - }); - it('should start in current stream state in the init mode', () => { - ourBoard = new openBCIBoard.OpenBCIBoard(); - - ourBoard.curParsingMode.should.equal(k.OBCIParsingReset); - }); - it('configures impedance testing variables correctly', function () { - ourBoard = new openBCIBoard.OpenBCIBoard(); - (ourBoard.impedanceTest.active).should.equal(false); - (ourBoard.impedanceTest.isTestingNInput).should.equal(false); - (ourBoard.impedanceTest.isTestingPInput).should.equal(false); - (ourBoard.impedanceTest.onChannel).should.equal(0); - (ourBoard.impedanceTest.sampleNumber).should.equal(0); - }); - it('configures sync object correctly', function () { - ourBoard = new openBCIBoard.OpenBCIBoard(); - expect(ourBoard.sync.curSyncObj).to.be.null; - expect(ourBoard.sync.eventEmitter).to.be.null; - expect(ourBoard.sync.objArray.length).to.equal(0); - (ourBoard.sync.sntpActive).should.equal(false); - (ourBoard.sync.timeOffsetMaster).should.equal(0); - (ourBoard.sync.timeOffsetAvg).should.equal(0); - expect(ourBoard.sync.timeOffsetArray.length).to.equal(0); - }); - it('configures impedance array with the correct amount of channels for default', function () { - ourBoard = new openBCIBoard.OpenBCIBoard(); - (ourBoard.impedanceArray.length).should.equal(8); - }); - it('configures impedance array with the correct amount of channels for daisy', function () { - ourBoard = new openBCIBoard.OpenBCIBoard({ - boardType: 'daisy' - }); - (ourBoard.impedanceArray.length).should.equal(16); - }); - it('configures impedance array with the correct amount of channels for ganglion', function () { - ourBoard = new openBCIBoard.OpenBCIBoard({ - boardType: 'ganglion' - }); - (ourBoard.impedanceArray.length).should.equal(4); - }); - it('should throw if passed an invalid option', function (done) { - try { - ourBoard = new openBCIBoard.OpenBCIBoard({ - foo: 'bar' - }); - done('did not throw'); - } catch (e) { done(); } - }); - }); - describe('#simulator', function () { - after(() => bluebirdChecks.noPendingPromises()); - it('can enable simulator after constructor', function (done) { - ourBoard = new openBCIBoard.OpenBCIBoard({ - verbose: true - }); - ourBoard.simulatorEnable().should.be.fulfilled.and.notify(done); - }); - it('should start sim and call disconnected', function (done) { - ourBoard = new openBCIBoard.OpenBCIBoard({ - verbose: true - }); - var disconnectStub = sinon.stub(ourBoard, 'disconnect').returns(Promise.resolve()); - var isConnectedStub = sinon.stub(ourBoard, 'isConnected').returns(true); - ourBoard.options.simulate.should.equal(false); - ourBoard.simulatorEnable().then(() => { - disconnectStub.should.have.been.calledOnce; - disconnectStub.restore(); - isConnectedStub.restore(); - ourBoard.options.simulate.should.equal(true); - done(); - }, done); - }); - it('should not enable the simulator if already simulating', function (done) { - ourBoard = new openBCIBoard.OpenBCIBoard({ - verbose: true, - simulate: true - }); - ourBoard.simulatorEnable().should.be.rejected.and.notify(done); - }); - it('can disable simulator', function (done) { - ourBoard = new openBCIBoard.OpenBCIBoard({ - verbose: true, - simulate: true - }); - ourBoard.simulatorDisable().should.be.fulfilled.and.notify(done); - }); - it('should not disable simulator if not in simulate mode', function (done) { - ourBoard = new openBCIBoard.OpenBCIBoard({ - verbose: true - }); - ourBoard.simulatorDisable().should.be.rejected.and.notify(done); - }); - it('should disable sim and call disconnected', function (done) { - ourBoard = new openBCIBoard.OpenBCIBoard({ - verbose: true, - simulate: true - }); - ourBoard.connect(k.OBCISimulatorPortName).catch(done); - ourBoard.on('ready', function () { - expect(ourBoard.isSimulating()).to.equal(true); - var disconnectSpy = sinon.spy(ourBoard, 'disconnect'); - ourBoard.options.simulate.should.equal(true); - ourBoard.simulatorDisable().then(() => { - disconnectSpy.should.have.been.calledOnce; - disconnectSpy.restore(); - ourBoard.options.simulate.should.equal(false); - done(); - }, done); - }); - }); - it('should be able to propagate constructor options to simulator', function (done) { - ourBoard = new openBCIBoard.OpenBCIBoard({ - verbose: true, - simulate: true, - simulatorBoardFailure: true, - simulatorDaisyModuleAttached: true, - simulatorDaisyModuleCanBeAttached: false, - simulatorFirmwareVersion: k.OBCIFirmwareV2, - simulatorHasAccelerometer: false, - simulatorInternalClockDrift: -1, - simulatorInjectAlpha: false, - simulatorFragmentation: k.OBCISimulatorFragmentationOneByOne, - simulatorLatencyTime: 314, - simulatorBufferSize: 2718, - simulatorInjectLineNoise: k.OBCISimulatorLineNoiseNone, - simulatorSampleRate: 16, - simulatorSerialPortFailure: true - }); - - ourBoard.connect(k.OBCISimulatorPortName) - .then(() => { - ourBoard.once('ready', () => { - var simOptions = ourBoard.serial.options; - expect(simOptions).to.be.an('object'); - expect(simOptions.accel).to.be.false; - expect(simOptions.alpha).to.be.false; - expect(simOptions.boardFailure).to.be.true; - expect(simOptions.daisy).to.be.true; - expect(simOptions.daisyCanBeAttached).to.be.false; - expect(simOptions.drift).to.be.below(0); - expect(simOptions.firmwareVersion).to.be.equal(k.OBCIFirmwareV2); - expect(simOptions.fragmentation).to.be.equal(k.OBCISimulatorFragmentationOneByOne); - expect(simOptions.latencyTime).to.be.equal(314); - expect(simOptions.bufferSize).to.be.equal(2718); - expect(simOptions.lineNoise).to.be.equal(k.OBCISimulatorLineNoiseNone); - expect(simOptions.sampleRate).to.be.equal(16); - expect(simOptions.serialPortFailure).to.be.true; - expect(simOptions.verbose).to.be.true; - ourBoard.disconnect().then(done).catch(done); - }); - }).catch(err => done(err)); - }); - it('should be able to set info for default board', function () { - ourBoard.info.boardType = 'burrito'; - ourBoard.info.sampleRate = 60; - ourBoard.info.numberOfChannels = 200; - ourBoard.overrideInfoForBoardType('default'); - expect(ourBoard.getInfo().boardType).to.be.equal(k.OBCIBoardDefault); - expect(ourBoard.getInfo().numberOfChannels).to.be.equal(k.OBCINumberOfChannelsDefault); - expect(ourBoard.getInfo().sampleRate).to.be.equal(k.OBCISampleRate250); - }); - it('should be able to set info for daisy board', function () { - ourBoard.info.boardType = 'burrito'; - ourBoard.info.sampleRate = 60; - ourBoard.info.numberOfChannels = 200; - ourBoard.overrideInfoForBoardType('daisy'); - expect(ourBoard.getInfo().boardType).to.be.equal(k.OBCIBoardDaisy); - expect(ourBoard.getInfo().numberOfChannels).to.be.equal(k.OBCINumberOfChannelsDaisy); - expect(ourBoard.getInfo().sampleRate).to.be.equal(k.OBCISampleRate125); - }); - it('should set info to default on bad input string', function () { - ourBoard.info.boardType = 'burrito'; - ourBoard.info.sampleRate = 60; - ourBoard.info.numberOfChannels = 200; - ourBoard.overrideInfoForBoardType('taco'); - expect(ourBoard.getInfo().boardType).to.be.equal(k.OBCIBoardDefault); - expect(ourBoard.getInfo().numberOfChannels).to.be.equal(k.OBCINumberOfChannelsDefault); - expect(ourBoard.getInfo().sampleRate).to.be.equal(k.OBCISampleRate250); - }); - }); - describe('#debug', function () { - before(function (done) { - ourBoard = new openBCIBoard.OpenBCIBoard({ - debug: true - }); - ourBoard.connect(k.OBCISimulatorPortName).catch(done); - ourBoard.once('ready', () => { - sinon.spy(console, 'log'); - done(); - }); - }); - after(function (done) { - console.log.restore(); - ourBoard.disconnect().then(done, done); - }); - after(() => bluebirdChecks.noPendingPromises()); - it('outputs a packet when written', done => { - console.log.reset(); - ourBoard.write(k.OBCIStreamStop).catch(done); - setTimeout(() => { - console.log.should.have.been.calledWithMatch(k.OBCIStreamStop); - done(); - }, 20); - }); - it('outputs a packet when received', done => { - console.log.reset(); - ourBoard.sdStop().catch(done); - ourBoard.once('eot', () => { - console.log.should.have.been.calledWithMatch('$'); - done(); - }); - }); - }); - describe('#boardTests', function () { - this.timeout(3000); - before(function () { - ourBoard = new openBCIBoard.OpenBCIBoard({ - simulate: !realBoard, - verbose: false, - simulatorFragmentation: k.OBCISimulatorFragmentationRandom - }); - spy = sinon.spy(ourBoard, '_writeAndDrain'); - }); - after(function (done) { - if (ourBoard.isConnected()) { - ourBoard.disconnect().then(() => { - done(); - }); - } else { - done(); - } - }); - after(() => bluebirdChecks.noPendingPromises()); - afterEach(function () { - if (spy) spy.reset(); - }); - describe('#connect/disconnect/streamStart/streamStop', function () { - it('rejects if already disconnected', function () { - return ourBoard.disconnect().should.be.rejected; - }); - it('rejects if already connected', function (done) { - ourBoard.connect(masterPortName).catch(err => done(err)); - - ourBoard.once('ready', () => { - ourBoard.connect(masterPortName).should.be.rejected - .then(() => ourBoard.disconnect()) - .should.notify(done); - }); - }); - it('gets the ready signal from the board and sends a stop streaming command before disconnecting', function (done) { - // spy = sinon.spy(ourBoard,"_writeAndDrain") - - ourBoard.connect(masterPortName).catch(err => done(err)); - - ourBoard.once('ready', function () { - ourBoard.streamStart().catch(err => done(err)); // start streaming - - ourBoard.once('sample', (sample) => { // wait till we get a sample - ourBoard.disconnect().then(() => { // call disconnect - // console.log('Device is streaming: ' + ourBoard.isStreaming() ? 'true' : 'false') - setTimeout(() => { - spy.should.have.been.calledWithMatch(k.OBCIStreamStop); - var conditionalTimeout = realBoard ? 300 : 0; - setTimeout(() => { - done(); - }, conditionalTimeout); - }, 4 * k.OBCIWriteIntervalDelayMSShort); // give plenty of time - }).catch(err => done(err)); - }); - }); - }); - it('rawDataPacket is emitted', function (done) { - ourBoard.connect(masterPortName).catch(err => done(err)); - // for the ready signal test - ourBoard.once('ready', function () { - ourBoard.streamStart().catch(err => done(err)); // start streaming - - ourBoard.once('rawDataPacket', (rawDataPacket) => { // wait till we get a raw data packet - ourBoard.disconnect().then(() => { // call disconnect - done(); - }).catch(err => done(err)); - }); - }); - }); - it('daisy not attached in soft reset, daisy requested by user in options, module tries to attach and is successful', function (done) { - if (ourBoard.isSimulating()) { - // Turn hardSet on - ourBoard.options.hardSet = true; - // Set the options to daisy boardType - ourBoard.options.boardType = k.OBCIBoardDaisy; - // The simulator does not have a daisy - ourBoard.options.simulatorDaisyModuleAttached = false; - // The simulator is able to attach daisy - ourBoard.options.simulatorDaisyModuleCanBeAttached = true; - const failTestWithErr = (err) => { - ourBoard.options.hardSet = false; - ourBoard.disconnect().then(() => { // call disconnect - done(err); - }).catch(() => { - done(err); - }); - }; - const hardSetFuncOnTime = () => { - // Verify the module is still default - expect(ourBoard.getBoardType()).to.equal(k.OBCIBoardDefault); - // Remove the premature ready function because it won't fire - ourBoard.removeListener('ready', readyFuncPreMature); - // If the board was able to attach the daisy - ourBoard.once('ready', readyFuncSuccess); - // If the board was unable to attach the daisy. - ourBoard.once('error', errorFuncTestFailure); // should not happen - }; - const errorFuncTestFailure = () => { - ourBoard.removeListener('ready', readyFuncSuccess); - failTestWithErr('failed to attach daisy, should emit error'); - }; - const readyFuncPreMature = () => { - ourBoard.removeListener('hardSet', hardSetFuncOnTime); - failTestWithErr('the board should not have been ready yet'); - }; - const readyFuncSuccess = () => { - // Verify the module is still default - expect(ourBoard.getBoardType()).to.equal(k.OBCIBoardDaisy); - // Remove because it won't fire - ourBoard.removeListener('error', errorFuncTestFailure); - ourBoard.options.hardSet = false; - ourBoard.disconnect().then(() => { // call disconnect - done(); - }).catch(() => { - done(); - }); - }; - - ourBoard.once('ready', readyFuncPreMature); - ourBoard.once('hardSet', hardSetFuncOnTime); - ourBoard.connect(masterPortName).catch(err => done(err)); - } else { - done(); - } - }); - it('daisy not attached in soft reset, daisy requested by user in options, module tries to attach and fails', function (done) { - if (ourBoard.isSimulating()) { - // Turn hardSet on - ourBoard.options.hardSet = true; - // Set the options to daisy boardType - ourBoard.options.boardType = k.OBCIBoardDaisy; - // The simulator does NOT have a daisy - ourBoard.options.simulatorDaisyModuleAttached = false; - // The simulator is NOT able to attach daisy - ourBoard.options.simulatorDaisyModuleCanBeAttached = false; - const failTestWithErr = (err) => { - ourBoard.options.hardSet = false; - ourBoard.disconnect().then(() => { // call disconnect - done(err); - }).catch(() => { - done(err); - }); - }; - const hardSetFuncOnTime = () => { - // Verify the module is still default - expect(ourBoard.getBoardType()).to.equal(k.OBCIBoardDefault); - // Remove the premature ready function because it won't fire - ourBoard.removeListener('ready', readyFuncPreMature); - // If the board was able to attach the daisy - ourBoard.once('ready', readyFuncTestFailure); - // If the board was unable to attach the daisy. - ourBoard.once('error', errorFuncTestSuccess); // should not happen - }; - const errorFuncTestSuccess = () => { - // Verify the module is still default - expect(ourBoard.getBoardType()).to.equal(k.OBCIBoardDefault); - ourBoard.options.hardSet = false; - ourBoard.disconnect().then(() => { // call disconnect - ourBoard.removeListener('ready', readyFuncTestFailure); - done(); - }).catch(() => { - ourBoard.removeListener('ready', readyFuncTestFailure); - done(); - }); - }; - const readyFuncPreMature = () => { - ourBoard.removeListener('hardSet', hardSetFuncOnTime); - failTestWithErr('the board should not have been ready yet'); - }; - const readyFuncTestFailure = () => { - failTestWithErr('failed to attach daisy when requested, ready should not be emitted'); - }; - - ourBoard.once('ready', readyFuncPreMature); - ourBoard.once('hardSet', hardSetFuncOnTime); - ourBoard.connect(masterPortName).catch(err => done(err)); - } else { - done(); - } - }); - it('daisy attached in soft reset, default board (not daisy) requested by user in options, module tries to remove and succeeds', function (done) { - if (ourBoard.isSimulating()) { - // Turn hardSet on - ourBoard.options.hardSet = true; - // Set the options to daisy boardType - ourBoard.options.boardType = k.OBCIBoardDefault; - // The simulator has a daisy attached - ourBoard.options.simulatorDaisyModuleAttached = true; - - const failTestWithErr = (err) => { - ourBoard.options.hardSet = false; - ourBoard.disconnect().then(() => { // call disconnect - done(err); - }).catch(() => { - done(err); - }); - }; - const hardSetFuncOnTime = () => { - // Verify the module is set to daisy mode - expect(ourBoard.getBoardType()).to.equal(k.OBCIBoardDaisy); - // Remove the premature ready function because it won't fire - ourBoard.removeListener('ready', readyFuncPreMature); - // If the board was able to remove the daisy - ourBoard.once('ready', readyFuncSuccess); // intended - // If the board was unable to remove the daisy. - ourBoard.once('error', errorFuncTestFailure); // should not happen - }; - const errorFuncTestFailure = () => { - ourBoard.removeListener('ready', readyFuncSuccess); - failTestWithErr('failed to attach daisy, should emit error'); - }; - const readyFuncPreMature = () => { - ourBoard.removeListener('hardSet', hardSetFuncOnTime); - failTestWithErr('the board should not have been ready yet'); - }; - const readyFuncSuccess = () => { - // Verify the module switched to default type - expect(ourBoard.getBoardType()).to.equal(k.OBCIBoardDefault); - // Remove because it won't fire - ourBoard.removeListener('error', errorFuncTestFailure); - ourBoard.options.hardSet = false; - ourBoard.disconnect().then(() => { // call disconnect - done(); - }).catch(() => { - done(); - }); - }; - - ourBoard.once('ready', readyFuncPreMature); - ourBoard.once('hardSet', hardSetFuncOnTime); - ourBoard.connect(masterPortName).catch(err => done(err)); - } else { - done(); - } - }); - it('daisy attached in soft reset, daisy requested by user in options, module is successful', function (done) { - if (ourBoard.isSimulating()) { - // Turn hardSet on - ourBoard.options.hardSet = true; - // Set the options to daisy boardType - ourBoard.options.boardType = k.OBCIBoardDaisy; - // The simulator does have a daisy - ourBoard.options.simulatorDaisyModuleAttached = true; - // The simulator is able to attach daisy - ourBoard.options.simulatorDaisyModuleCanBeAttached = true; - const failTestWithErr = (err) => { - ourBoard.options.hardSet = false; - ourBoard.disconnect().then(() => { // call disconnect - done(err); - }).catch(() => { - done(err); - }); - }; - var hardSetFuncFailure = () => { - ourBoard.removeListener('ready', readyFuncSuccess); - ourBoard.removeListener('hardSet', hardSetFuncFailure); - failTestWithErr('should not hardSet'); - }; - var errorFuncTestFailure = () => { - ourBoard.removeListener('ready', readyFuncSuccess); - ourBoard.removeListener('hardSet', hardSetFuncFailure); - failTestWithErr('should not error'); - }; - var readyFuncSuccess = () => { - ourBoard.removeListener('error', errorFuncTestFailure); - ourBoard.removeListener('hardSet', hardSetFuncFailure); - // Verify the module is still default - expect(ourBoard.getBoardType()).to.equal(k.OBCIBoardDaisy); - ourBoard.options.hardSet = false; - ourBoard.disconnect().then(() => { // call disconnect - done(); - }).catch(() => { - done(); - }); - }; - - ourBoard.once('error', errorFuncTestFailure); - ourBoard.once('ready', readyFuncSuccess); - ourBoard.once('hardSet', hardSetFuncFailure); - ourBoard.connect(masterPortName).catch(err => done(err)); - } else { - done(); - } - }); - it('no daisy attached in soft reset, default requested by user in options, module is successful', function (done) { - if (ourBoard.isSimulating()) { - // Turn hardSet on - ourBoard.options.hardSet = true; - // Set the options to default boardType - ourBoard.options.boardType = k.OBCIBoardDefault; - // The simulator does not have a daisy - ourBoard.options.simulatorDaisyModuleAttached = false; - // The simulator is able to attach daisy - ourBoard.options.simulatorDaisyModuleCanBeAttached = false; - const failTestWithErr = (err) => { - ourBoard.options.hardSet = false; - ourBoard.disconnect().then(() => { // call disconnect - done(err); - }).catch(() => { - done(err); - }); - }; - var hardSetFuncFailure = () => { - ourBoard.removeListener('ready', readyFuncSuccess); - ourBoard.removeListener('hardSet', hardSetFuncFailure); - failTestWithErr('should not hard set'); - }; - var errorFuncTestFailure = () => { - ourBoard.removeListener('ready', readyFuncSuccess); - ourBoard.removeListener('hardSet', hardSetFuncFailure); - failTestWithErr('should not emit error'); - }; - var readyFuncSuccess = () => { - ourBoard.removeListener('error', errorFuncTestFailure); - ourBoard.removeListener('hardSet', hardSetFuncFailure); - // Verify the module is still default - expect(ourBoard.getBoardType()).to.equal(k.OBCIBoardDefault); - ourBoard.options.hardSet = false; - ourBoard.disconnect().then(() => { // call disconnect - done(); - }).catch(() => { - done(); - }); - }; - - ourBoard.once('error', errorFuncTestFailure); - ourBoard.once('ready', readyFuncSuccess); - ourBoard.once('hardSet', hardSetFuncFailure); - ourBoard.connect(masterPortName).catch(err => done(err)); - } else { - done(); - } - }); - }); - describe('#connected', function () { - beforeEach(function (done) { - ourBoard.connect(masterPortName).catch(done); - - ourBoard.once('ready', done); - }); - afterEach(function (done) { - if (ourBoard.isConnected()) { - ourBoard.disconnect().then(done, () => done()); - } else { - done(); - } - }); - it('is connected after connection', function () { - expect(ourBoard.isConnected()).to.be.true; - }); - it('is no longer connected after clean disconnection', function (done) { - ourBoard.disconnect().then(() => { - expect(ourBoard.isConnected()).to.be.false; - done(); - }, done); - }); - it('is no longer connected if stream closes itself', function (done) { - ourBoard.serial.close(() => { - expect(ourBoard.isConnected()).to.be.false; - done(); - }); - }); - it('is no longer connected after a stream error', function () { - var errorDamper = () => true; - ourBoard.on('error', errorDamper); - ourBoard.serial.emit('error', new Error('test error')); - expect(ourBoard.isConnected()).to.be.false; - ourBoard.removeListener('error', errorDamper); - }); - }); - describe('#write', function () { - beforeEach(function (done) { - ourBoard.connect(masterPortName).catch(done); - - ourBoard.once('ready', done); - }); - afterEach(function (done) { - if (ourBoard.isConnected()) { - ourBoard.disconnect().then(done, done); - } else { - done(); - } - }); - it('rejects after clean disconnection', function (done) { - ourBoard.disconnect().then(() => { - ourBoard.write(k.OBCIMiscSoftReset).should.be.rejected.and.notify(done); - }, done); - }); - it('rejects if stream closes itself', function (done) { - ourBoard.serial.close(() => { - ourBoard.write(k.OBCIMiscSoftReset).should.be.rejected.and.notify(done); - }); - }); - it('rejects after a stream error', function (done) { - var errorDamper = () => true; - ourBoard.on('error', errorDamper); - ourBoard.serial.emit('error', new Error('test error')); - ourBoard.write(k.OBCIMiscSoftReset).should.be.rejected.and.notify(done); - ourBoard.removeListener('error', errorDamper); - }); - it('does not allow data to be sent after clean disconnection', function (done) { - var writeSpy1 = sinon.spy(ourBoard.serial, 'write'); - var byteToWrite = k.OBCISDLogStop; - var writeWhileConnected = function () { - ourBoard.write(byteToWrite).then(() => { - if (ourBoard.isConnected()) { - writeSpy1.reset(); - writeWhileConnected(); - } else { - done('wrote when not connected'); - } - }, err => { - if (ourBoard.isConnected()) { - done(err); - } else { - process.nextTick(() => { - ourBoard.connect(masterPortName).catch(done); - var writeSpy2 = sinon.spy(ourBoard.serial, 'write'); - ourBoard.once('ready', () => { - writeSpy2.should.equal(ourBoard.serial.write); - writeSpy1.should.have.not.been.called; - writeSpy2.should.have.not.been.calledWith(byteToWrite); - writeSpy1.restore(); - writeSpy2.restore(); - done(); - }); - }); - } - }); - }; - writeWhileConnected(); - ourBoard.disconnect().catch(done); - }); - it('disconnects immediately, rejecting all buffered writes', function () { - var writeSpy = sinon.spy(ourBoard.serial, 'write'); - return Promise.all([ - ourBoard.write(k.OBCISDLogStop).should.have.been.rejected, - ourBoard.write(k.OBCISDLogStop).should.have.been.rejected, - ourBoard.write(k.OBCISDLogStop).should.have.been.rejected, - ourBoard.write(k.OBCISDLogStop).should.have.been.rejected, - ourBoard.disconnect() - ]).then(() => { - writeSpy.should.have.not.been.called; - writeSpy.restore(); - }); - }); - }); - describe('#listPorts', function () { - it('returns a list of ports', function (done) { - ourBoard.listPorts().then(ports => { - if (ports.some(port => { - if (port.comName === masterPortName) { - return true; - } - })) { - done(); - } else { - done(); - } - }); - }); - }); - describe('#sdStart', function () { - before(function (done) { - ourBoard.connect(k.OBCISimulatorPortName) - .then(() => { - ourBoard.once('ready', done); - }) - .catch(err => done(err)); - }); - afterEach(function (done) { - ourBoard.sdStop() - .catch(done); - ourBoard.once('eot', () => { - 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('eot', () => { - done(); - }); - }); - it('can start 5 minutes of logging with sd', function (done) { - ourBoard.sdStart('5min') - .catch(err => done(err)); - ourBoard.once('eot', () => { - done(); - }); - }); - it('can start 15 minutes of logging with sd', function (done) { - ourBoard.sdStart('15min') - .catch(err => done(err)); - ourBoard.once('eot', () => { - done(); - }); - }); - it('can start 30 minutes of logging with sd', function (done) { - ourBoard.sdStart('30min') - .catch(err => done(err)); - ourBoard.once('eot', () => { - done(); - }); - }); - it('can start 1 hour of logging with sd', function (done) { - ourBoard.sdStart('1hour') - .catch(err => done(err)); - ourBoard.once('eot', () => { - done(); - }); - }); - it('can start 2 hours of logging with sd', function (done) { - ourBoard.sdStart('2hour') - .catch(err => done(err)); - ourBoard.once('eot', () => { - done(); - }); - }); - it('can start 4 hours of logging with sd', function (done) { - ourBoard.sdStart('4hour') - .catch(err => done(err)); - ourBoard.once('eot', () => { - done(); - }); - }); - it('can start 12 hours of logging with sd', function (done) { - ourBoard.sdStart('12hour') - .catch(err => done(err)); - ourBoard.once('eot', () => { - done(); - }); - }); - it('can start 24 hours of logging with sd', function (done) { - ourBoard.sdStart('24hour') - .catch(done); - ourBoard.once('eot', () => { - done(); - }); - }); - }); - describe('#sdStop', function () { - before(function (done) { - ourBoard.connect(k.OBCISimulatorPortName).catch(err => done(err)); - ourBoard.once('ready', done); - }); - it('can stop logging with sd', function (done) { - // console.log('yoyoyo') - ourBoard.sdStop().catch(err => done(err)); - ourBoard.once('eot', () => { - // check here in case write was delayed - spy.should.have.been.calledWith('j'); - done(); - }); - }); - }); - describe('#setBoardType', function () { - before(function (done) { - if (!ourBoard.isConnected()) { - ourBoard.connect(masterPortName) - .then(done) - .catch(done); - } else { - done(); - } - }); - after(function (done) { - ourBoard.disconnect() - .then(done) - .catch(done); - }); - it('should resolve for setting max channels to 8 when already 8', function (done) { - if (ourBoard.isSimulating()) { - ourBoard.serial.options.daisy = false; - ourBoard.hardSetBoardType('default') - .then((res) => { - expect(res).to.equal('no daisy to remove'); - expect(ourBoard.getBoardType()).to.equal(k.OBCIBoardDefault); - done(); - }).catch(done); - } else { - done(); - } - }); - it('should resolve for setting max channels to 8', function (done) { - if (ourBoard.isSimulating()) { - ourBoard.serial.options.daisy = true; - ourBoard.hardSetBoardType('default') - .then((res) => { - expect(res).to.equal('daisy removed'); - expect(ourBoard.getBoardType()).to.equal(k.OBCIBoardDefault); - done(); - }).catch(done); - } else { - done(); - } - }); - it('should resolve for setting max channels to 16 if daisy already attached', function (done) { - if (ourBoard.isSimulating()) { - ourBoard.serial.options.daisy = true; - ourBoard.hardSetBoardType('daisy') - .then((res) => { - expect(res).to.equal('daisy already attached'); - expect(ourBoard.getBoardType()).to.equal(k.OBCIBoardDaisy); - done(); - }).catch(done); - } else { - done(); - } - }); - it('should resolve for setting max channels to 16 if daisy able to be attached', function (done) { - if (ourBoard.isSimulating()) { - ourBoard.serial.options.daisy = false; - ourBoard.serial.options.daisyCanBeAttached = true; - ourBoard.hardSetBoardType('daisy') - .then((res) => { - expect(res).to.equal('daisy attached'); - expect(ourBoard.getBoardType()).to.equal(k.OBCIBoardDaisy); - done(); - }).catch(done); - } else { - done(); - } - }); - it('should reject when setting max channels to 16 if daisy not able to be attached', function (done) { - if (ourBoard.isSimulating()) { - ourBoard.serial.options.daisy = false; - ourBoard.serial.options.daisyCanBeAttached = false; - ourBoard.hardSetBoardType('daisy') - .then(done) - .catch((err) => { - expect(err).to.equal('unable to attach daisy'); - expect(ourBoard.getBoardType()).to.equal(k.OBCIBoardDefault); - done(); - }); - } else { - done(); - } - }); - it('should not write a command if invalid channel number', function (done) { - ourBoard.hardSetBoardType(0).should.be.rejected.and.notify(done); - }); - }); - describe('#channelOff', function () { - before(function (done) { - if (!ourBoard.isConnected()) { - ourBoard.connect(masterPortName) - .then(done) - .catch(err => done(err)); - } else { - done(); - } - }); - - it('should call the write function with proper command for channel 1', function (done) { - ourBoard.channelOff(1).then(() => { - setTimeout(() => { - spy.should.have.been.calledWith(k.OBCIChannelOff1); - done(); - }, 5 * k.OBCIWriteIntervalDelayMSShort); - }); - }); - it('should call the write function with proper command for channel 16', function (done) { - // spy = sinon.spy(ourBoard,"_writeAndDrain") - - ourBoard.channelOff(16).then(() => { - setTimeout(() => { - spy.should.have.been.calledWith(k.OBCIChannelOff16); - done(); - }, 5 * k.OBCIWriteIntervalDelayMSShort); - }); - }); - it('should reject with invalid channel', function (done) { - ourBoard.channelOff(0).should.be.rejected.and.notify(done); - }); - it('should turn the realBoard channel off', function (done) { - ourBoard.channelOff(1).then(() => { - setTimeout(() => { - spy.should.have.been.calledWith(k.OBCIChannelOff1); - done(); - }, 5 * k.OBCIWriteIntervalDelayMSShort); - }); - }); - }); - describe('#channelOn', function () { - before(function (done) { - if (!ourBoard.isConnected()) { - ourBoard.connect(masterPortName) - .then(done) - .catch(err => done(err)); - } else { - done(); - } - }); - - it('should call the write function with proper command for channel 2', function (done) { - ourBoard.channelOn(2).then(() => { - setTimeout(() => { - spy.should.have.been.calledWith(k.OBCIChannelOn2); - done(); - }, 5 * k.OBCIWriteIntervalDelayMSShort); - }); - }); - it('should call the write function with proper command for channel 16', function (done) { - ourBoard.channelOn(16).then(() => { - setTimeout(() => { - spy.should.have.been.calledWith(k.OBCIChannelOn16); - done(); - }, 5 * k.OBCIWriteIntervalDelayMSShort); - }); - }); - it('should reject with invalid channel', function (done) { - ourBoard.channelOn(0).should.be.rejected.and.notify(done); - }); - }); - describe('#channelSet', function () { - this.timeout(6000); - before(function (done) { - if (!ourBoard.isConnected()) { - ourBoard.connect(masterPortName) - .then(done) - .catch(err => done(err)); - } else { - done(); - } - }); - it('should call the writeAndDrain function array of commands 9 times', function (done) { - setTimeout(() => { - spy.reset(); - ourBoard.channelSet(1, true, 24, 'normal', true, true, true) - .then(() => { - setTimeout(() => { - spy.callCount.should.equal(9); - done(); - }, 15 * k.OBCIWriteIntervalDelayMSShort); - }) - .catch(err => done(err)); - }, 10 * k.OBCIWriteIntervalDelayMSShort); // give some time for writer to finish - }); - - it('should be rejected', function (done) { - ourBoard.channelSet(1, true, 24, 'normal', 'taco', true, true).should.be.rejected.and.notify(done); - }); - }); - - describe('#impedanceTest Not Connected Rejects ', function () { - it('rejects all channeles when not streaming', function (done) { - ourBoard.impedanceTestAllChannels().should.be.rejected.and.notify(done); - }); - it('rejects array channels when not streaming', function (done) { - ourBoard.impedanceTestChannels(['-', 'N', 'n', 'p', 'P', '-', 'b', 'b']).should.be.rejected.and.notify(done); - }); - }); - describe('#impedancePrivates', function () { - describe('disconnected', function () { - before(function (done) { - if (ourBoard.isConnected()) { - ourBoard.disconnect() - .then(done) - .catch(err => done(err)); - } else { - done(); - } - }); - describe('#_impedanceTestSetChannel', function () { - it('should reject because not connected', function (done) { - ourBoard._impedanceTestSetChannel(0, false, false).should.be.rejected.and.notify(done); - }); - }); - }); - }); - }); - - /** - * Test the function that parses an incoming data buffer for packets - */ - describe('#_processDataBuffer', function () { - var _processQualifiedPacketSpy; - before(() => { - ourBoard = new openBCIBoard.OpenBCIBoard({ - verbose: true - }); - _processQualifiedPacketSpy = sinon.spy(ourBoard, '_processQualifiedPacket'); - }); - after(() => { - ourBoard = null; - return bluebirdChecks.noPendingPromises(); - }); - - it('should do nothing when empty buffer inserted', () => { - var buffer = null; - - // Test the function - buffer = ourBoard._processDataBuffer(buffer); - - expect(buffer).to.be.null; - }); - it('should return an unaltered buffer if there is less than a packets worth of data in it', () => { - var expectedString = 'AJ'; - var buffer = new Buffer(expectedString); - - // Reset the spy if it exists - if (_processQualifiedPacketSpy) _processQualifiedPacketSpy.reset(); - - // Test the function - buffer = ourBoard._processDataBuffer(buffer); - - // Convert the buffer to a string and ensure that it equals the expected string - buffer.toString().should.equal(expectedString); - - // Make sure that the spy was not infact called. - _processQualifiedPacketSpy.should.not.have.been.called; - }); - it('should identify a packet', () => { - var buffer = openBCISample.samplePacketReal(0); - - // Reset the spy if it exists - if (_processQualifiedPacketSpy) _processQualifiedPacketSpy.reset(); - - // Call the function under test - buffer = ourBoard._processDataBuffer(buffer); - - // Ensure that we extracted only one buffer - _processQualifiedPacketSpy.should.have.been.calledOnce; - - // The buffer should not have anything in it any more - expect(buffer).to.be.null; - }); - it('should extract a buffer and preserve the remaining data in the buffer', () => { - var expectedString = 'AJ'; - var extraBuffer = new Buffer(expectedString); - // declare the big buffer - var buffer = new Buffer(k.OBCIPacketSize + extraBuffer.length); - // Fill that new big buffer with buffers - openBCISample.samplePacketReal(0).copy(buffer, 0); - extraBuffer.copy(buffer, k.OBCIPacketSize); - // Reset the spy if it exists - if (_processQualifiedPacketSpy) _processQualifiedPacketSpy.reset(); - // Call the function under test - buffer = ourBoard._processDataBuffer(buffer); - // Ensure that we extracted only one buffer - _processQualifiedPacketSpy.should.have.been.called; - // The buffer should have the epxected number of bytes left - buffer.length.should.equal(expectedString.length); - // Convert the buffer to a string and ensure that it equals the expected string - buffer.toString().should.equal(expectedString); - }); - - it('should be able to extract multiple packets from a single buffer', () => { - // We are going to extract multiple buffers - var expectedNumberOfBuffers = 3; - // declare the big buffer - var buffer = new Buffer(k.OBCIPacketSize * expectedNumberOfBuffers); - // Fill that new big buffer with buffers - openBCISample.samplePacketReal(0).copy(buffer, 0); - openBCISample.samplePacketReal(1).copy(buffer, k.OBCIPacketSize); - openBCISample.samplePacketReal(2).copy(buffer, k.OBCIPacketSize * 2); - // Reset the spy if it exists - if (_processQualifiedPacketSpy) _processQualifiedPacketSpy.reset(); - // Call the function under test - buffer = ourBoard._processDataBuffer(buffer); - // Ensure that we extracted only one buffer - _processQualifiedPacketSpy.should.have.been.calledThrice; - // The buffer should not have anything in it any more - expect(buffer).to.be.null; - }); - - it('should be able to get multiple packets and keep extra data on the end', () => { - var expectedString = 'AJ'; - var extraBuffer = new Buffer(expectedString); - // We are going to extract multiple buffers - var expectedNumberOfBuffers = 2; - // declare the big buffer - var buffer = new Buffer(k.OBCIPacketSize * expectedNumberOfBuffers + extraBuffer.length); - // Fill that new big buffer with buffers - openBCISample.samplePacketReal(0).copy(buffer, 0); - openBCISample.samplePacketReal(1).copy(buffer, k.OBCIPacketSize); - extraBuffer.copy(buffer, k.OBCIPacketSize * 2); - // Reset the spy if it exists - if (_processQualifiedPacketSpy) _processQualifiedPacketSpy.reset(); - // Call the function under test - buffer = ourBoard._processDataBuffer(buffer); - // Ensure that we extracted only one buffer - _processQualifiedPacketSpy.should.have.been.calledTwice; - // The buffer should not have anything in it any more - buffer.length.should.equal(extraBuffer.length); - }); - - it('should be able to get multiple packets with junk in the middle', () => { - var expectedString = ','; - var extraBuffer = new Buffer(expectedString); - // We are going to extract multiple buffers - var expectedNumberOfBuffers = 2; - // declare the big buffer - var buffer = new Buffer(k.OBCIPacketSize * expectedNumberOfBuffers + extraBuffer.length); - // Fill that new big buffer with buffers - openBCISample.samplePacketReal(0).copy(buffer, 0); - extraBuffer.copy(buffer, k.OBCIPacketSize); - openBCISample.samplePacketReal(1).copy(buffer, k.OBCIPacketSize + extraBuffer.byteLength); - - // Reset the spy if it exists - if (_processQualifiedPacketSpy) _processQualifiedPacketSpy.reset(); - // Call the function under test - buffer = ourBoard._processDataBuffer(buffer); - // Ensure that we extracted only one buffer - _processQualifiedPacketSpy.should.have.been.calledTwice; - // The buffer should not have anything in it any more - bufferEqual(extraBuffer, buffer).should.be.true; - buffer.length.should.equal(extraBuffer.length); - }); - - it('should be able to get multiple packets with junk in the middle and end', () => { - var expectedString = ','; - var extraBuffer = new Buffer(expectedString); - // We are going to extract multiple buffers - var expectedNumberOfBuffers = 2; - // declare the big buffer - var buffer = new Buffer(k.OBCIPacketSize * expectedNumberOfBuffers + extraBuffer.length * 2); - // Fill that new big buffer with buffers - openBCISample.samplePacketReal(0).copy(buffer, 0); - extraBuffer.copy(buffer, k.OBCIPacketSize); - openBCISample.samplePacketReal(1).copy(buffer, k.OBCIPacketSize + extraBuffer.byteLength); - extraBuffer.copy(buffer, k.OBCIPacketSize * 2 + extraBuffer.byteLength); - // Reset the spy if it exists - if (_processQualifiedPacketSpy) _processQualifiedPacketSpy.reset(); - // Call the function under test - buffer = ourBoard._processDataBuffer(buffer); - // Ensure that we extracted only one buffer - _processQualifiedPacketSpy.should.have.been.calledTwice; - // The buffer should not have anything in it any more - bufferEqual(Buffer.concat([extraBuffer, extraBuffer], 2), buffer).should.be.true; - buffer.length.should.equal(extraBuffer.length * 2); - }); - }); - - /** - * Test the function that routes raw packets for processing - */ - describe('#_processQualifiedPacket', function () { - var ourBoard; - var funcSpyTimeSyncSet, funcSpyTimeSyncedAccel, funcSpyTimeSyncedRawAux, funcSpyStandardRawAux, funcSpyStandardAccel; - - before(function () { - ourBoard = new openBCIBoard.OpenBCIBoard({ - verbose: true - }); - // Put watchers on all functions - funcSpyStandardAccel = sinon.spy(ourBoard, '_processPacketStandardAccel'); - funcSpyStandardRawAux = sinon.spy(ourBoard, '_processPacketStandardRawAux'); - funcSpyTimeSyncSet = sinon.spy(ourBoard, '_processPacketTimeSyncSet'); - funcSpyTimeSyncedAccel = sinon.spy(ourBoard, '_processPacketTimeSyncedAccel'); - funcSpyTimeSyncedRawAux = sinon.spy(ourBoard, '_processPacketTimeSyncedRawAux'); - }); - beforeEach(function () { - funcSpyStandardAccel.reset(); - funcSpyStandardRawAux.reset(); - funcSpyTimeSyncSet.reset(); - funcSpyTimeSyncedAccel.reset(); - funcSpyTimeSyncedRawAux.reset(); - - ourBoard.sync.curSyncObj = openBCISample.newSyncObject(); - }); - after(function () { - // ourBoard = null - }); - after(() => bluebirdChecks.noPendingPromises()); - - it('should process a standard packet', function () { - var buffer = openBCISample.samplePacket(0); - - // Call the function under test - ourBoard._processQualifiedPacket(buffer); - - // Ensure that we extracted only one buffer - funcSpyStandardAccel.should.have.been.calledOnce; - }); - it('should process a standard packet with raw aux', function () { - var buffer = openBCISample.samplePacketStandardRawAux(0); - - // Call the function under test - ourBoard._processQualifiedPacket(buffer); - - // Ensure that we extracted only one buffer - funcSpyStandardRawAux.should.have.been.calledOnce; - }); - it('should call nothing for a user defined packet type ', function () { - var buffer = openBCISample.samplePacketUserDefined(); - - // Call the function under test - ourBoard._processQualifiedPacket(buffer); - - // Nothing should be called - funcSpyStandardAccel.should.not.have.been.called; - funcSpyStandardRawAux.should.not.have.been.called; - funcSpyTimeSyncSet.should.not.have.been.called; - funcSpyTimeSyncedAccel.should.not.have.been.called; - funcSpyTimeSyncedRawAux.should.not.have.been.called; - }); - it('should process a time sync set packet with accel', function () { - var buffer = openBCISample.samplePacketAccelTimeSyncSet(); - - // Call the function under test - ourBoard._processQualifiedPacket(buffer); - - // We should call to sync up - funcSpyTimeSyncSet.should.have.been.calledOnce; - funcSpyTimeSyncSet.should.have.been.calledWith(buffer); - // we should call to get a packet - funcSpyTimeSyncedAccel.should.have.been.calledOnce; - funcSpyTimeSyncedAccel.should.have.been.calledWith(buffer); - }); - it('should process a time synced packet with accel', function () { - var buffer = openBCISample.samplePacketAccelTimeSynced(0); - - // Call the function under test - ourBoard._processQualifiedPacket(buffer); - - // Ensure that we extracted only one buffer - funcSpyTimeSyncedAccel.should.have.been.calledOnce; - }); - it('should process a time sync set packet with raw aux', function () { - var buffer = openBCISample.samplePacketRawAuxTimeSyncSet(0); - - // Call the function under test - ourBoard._processQualifiedPacket(buffer); - - // We should call to sync up - funcSpyTimeSyncSet.should.have.been.calledOnce; - funcSpyTimeSyncSet.should.have.been.calledWith(buffer); - // we should call to get a packet - funcSpyTimeSyncedRawAux.should.have.been.calledOnce; - funcSpyTimeSyncedRawAux.should.have.been.calledWith(buffer); - }); - it('should process a time synced packet with raw aux', function () { - var buffer = openBCISample.samplePacketRawAuxTimeSynced(0); - - // Call the function under test - ourBoard._processQualifiedPacket(buffer); - - // Ensure that we extracted only one buffer - funcSpyTimeSyncedRawAux.should.have.been.calledOnce; - }); - it('should not identify any packet', function () { - var buffer = openBCISample.samplePacket(0); - - // Set the stop byte to some number not yet defined - buffer[k.OBCIPacketPositionStopByte] = 0xCF; - - // Call the function under test - ourBoard._processDataBuffer(buffer); - - // Nothing should be called - funcSpyStandardAccel.should.not.have.been.called; - funcSpyStandardRawAux.should.not.have.been.called; - funcSpyTimeSyncSet.should.not.have.been.called; - funcSpyTimeSyncedAccel.should.not.have.been.called; - funcSpyTimeSyncedRawAux.should.not.have.been.called; - }); - it('should emit a dropped packet on dropped packet', function (done) { - // Set to default state - ourBoard.previousSampleNumber = -1; - var sampleNumber0 = openBCISample.samplePacket(0); - ourBoard.once('droppedPacket', () => { - done(); - }); - var sampleNumber2 = openBCISample.samplePacket(2); - // Call the function under test - ourBoard._processDataBuffer(sampleNumber0); - ourBoard._processDataBuffer(sampleNumber2); - }); - it('should emit a dropped packet on dropped packet with edge', function (done) { - // Set to default state - var count = 0; - ourBoard.previousSampleNumber = 253; - var buf1 = openBCISample.samplePacket(254); - var countFunc = arr => { - count++; - }; - ourBoard.on('droppedPacket', countFunc); - var buf2 = openBCISample.samplePacket(0); - var buf3 = openBCISample.samplePacket(1); - // Call the function under test - ourBoard._processDataBuffer(buf1); - ourBoard._processDataBuffer(buf2); - ourBoard._processDataBuffer(buf3); - setTimeout(() => { - ourBoard.removeListener('droppedPacket', countFunc); - expect(count).to.equal(1); - done(); - }, 10); - }); - }); - - describe('#_processPacketTimeSyncSet', function () { - var timeSyncSetPacket; - var ourBoard; - before(() => { - ourBoard = new openBCIBoard.OpenBCIBoard({ - verbose: false - }); - }); - beforeEach(() => { - timeSyncSetPacket = openBCISample.samplePacketRawAuxTimeSyncSet(); - ourBoard.sync.timeOffsetArray = []; - }); - afterEach(() => { - ourBoard.sync.curSyncObj = null; - }); - after(() => bluebirdChecks.noPendingPromises()); - it('should emit and return bad object if no sync in progress', function () { - var timeSetPacketArrived = ourBoard.time(); - var expectedTimeSyncOffsetMaster = 72; - ourBoard.sync.timeOffsetMaster = expectedTimeSyncOffsetMaster; - ourBoard.curParsingMode = k.OBCIParsingTimeSyncSent; - ourBoard.once('synced', (syncObj) => { - expect(syncObj).to.have.property('valid', false); - expect(syncObj).to.have.property('error', k.OBCIErrorTimeSyncIsNull); - expect(syncObj).to.have.property('timeOffsetMaster', expectedTimeSyncOffsetMaster); - }); - let syncObject = ourBoard._processPacketTimeSyncSet(timeSyncSetPacket, timeSetPacketArrived); - expect(ourBoard.curParsingMode).to.equal(k.OBCIParsingNormal); - expect(syncObject).to.have.property('valid', false); - expect(syncObject).to.have.property('error', k.OBCIErrorTimeSyncIsNull); - expect(syncObject).to.have.property('timeOffsetMaster', expectedTimeSyncOffsetMaster); - }); - it('should emit and return bad synced object if no sent confirmation found', function () { - var timeSetPacketArrived = ourBoard.time(); - var expectedTimeSyncOffsetMaster = 72; - ourBoard.once('synced', (syncObj) => { - expect(syncObj).to.have.property('valid', false); - expect(syncObj).to.have.property('error', k.OBCIErrorTimeSyncNoComma); - expect(syncObj).to.have.property('timeOffsetMaster', expectedTimeSyncOffsetMaster); - }); - ourBoard.sync.timeOffsetMaster = expectedTimeSyncOffsetMaster; - ourBoard.curParsingMode = k.OBCIParsingTimeSyncSent; - ourBoard.sync.curSyncObj = openBCISample.newSyncObject(); - let syncObject = ourBoard._processPacketTimeSyncSet(timeSyncSetPacket, timeSetPacketArrived); - expect(ourBoard.curParsingMode).to.equal(k.OBCIParsingNormal); - expect(syncObject).to.have.property('valid', false); - expect(syncObject).to.have.property('error', k.OBCIErrorTimeSyncNoComma); - expect(syncObject).to.have.property('timeOffsetMaster', expectedTimeSyncOffsetMaster); - }); - it('should emit and return bad synced object with invalid raw packet', function () { - var timeSetPacketArrived = ourBoard.time(); - var expectedTimeSyncOffsetMaster = 72; - var badPacket; - if (k.getVersionNumber(process.version) >= 6) { - // from introduced in node version 6.x.x - badPacket = Buffer.from(timeSyncSetPacket.slice(0, 30)); - } else { - badPacket = new Buffer(timeSyncSetPacket.slice(0, 30)); - } - ourBoard.sync.curSyncObj = openBCISample.newSyncObject(); - ourBoard.sync.timeOffsetMaster = expectedTimeSyncOffsetMaster; - ourBoard.once('synced', (syncObj) => { - expect(syncObj).to.have.property('valid', false); - expect(syncObj.error).to.have.property('message', k.OBCIErrorInvalidByteLength); - expect(syncObj).to.have.property('timeOffsetMaster', expectedTimeSyncOffsetMaster); - }); - let syncObject = ourBoard._processPacketTimeSyncSet(badPacket, timeSetPacketArrived); - expect(ourBoard.curParsingMode).to.equal(k.OBCIParsingNormal); - expect(syncObject).to.have.property('valid', false); - expect(syncObject.error).to.have.property('message', k.OBCIErrorInvalidByteLength); - expect(syncObject).to.have.property('timeOffsetMaster', expectedTimeSyncOffsetMaster); - }); - it('should calculate round trip time as the difference between time sent and time set packet arrived', function (done) { - var timeSetPacketArrived = ourBoard.time(); - var expectedRoundTripTime = 20; // ms - ourBoard.curParsingMode = k.OBCIParsingNormal; // indicates the sent conf was found - // Make a new object! - ourBoard.sync.curSyncObj = openBCISample.newSyncObject(); - // Set the sent time - ourBoard.sync.curSyncObj.timeSyncSent = timeSetPacketArrived - expectedRoundTripTime; - - ourBoard.once('synced', obj => { - expect(obj.timeRoundTrip).to.equal(expectedRoundTripTime); - done(); - }); - ourBoard._processPacketTimeSyncSet(timeSyncSetPacket, timeSetPacketArrived); - }); - it('should calculate transmission time as the difference between round trip time and (sentConf - sent) when set arrived - sent conf is larger than threshold', function (done) { - var timeSetPacketArrived = ourBoard.time(); - var expectedRoundTripTime = 20; // ms - var expectedTimeTillSentConf = expectedRoundTripTime - k.OBCITimeSyncThresholdTransFailureMS - 1; // 9 ms - // Setup - ourBoard.curParsingMode = k.OBCIParsingNormal; // indicates the sent conf was found - // Make a new object! - ourBoard.sync.curSyncObj = openBCISample.newSyncObject(); - // Set the sent time - ourBoard.sync.curSyncObj.timeSyncSent = timeSetPacketArrived - expectedRoundTripTime; - ourBoard.sync.curSyncObj.timeSyncSentConfirmation = ourBoard.sync.curSyncObj.timeSyncSent + expectedTimeTillSentConf; - - ourBoard.once('synced', obj => { - expect(obj.timeTransmission).to.equal(obj.timeRoundTrip - (obj.timeSyncSentConfirmation - obj.timeSyncSent)); - done(); - }); - ourBoard._processPacketTimeSyncSet(timeSyncSetPacket, timeSetPacketArrived); - }); - it('should calculate transmission time as a percentage of round trip time when set arrived - sent conf is smaller than threshold', function (done) { - var timeSetPacketArrived = ourBoard.time(); - var expectedRoundTripTime = 20; // ms - var expectedTimeTillSentConf = expectedRoundTripTime - k.OBCITimeSyncThresholdTransFailureMS + 1; // 11 ms - // Setup - ourBoard.curParsingMode = k.OBCIParsingNormal; // indicates the sent conf was found - // Make a new object! - ourBoard.sync.curSyncObj = openBCISample.newSyncObject(); - // Set the sent time - ourBoard.sync.curSyncObj.timeSyncSent = timeSetPacketArrived - expectedRoundTripTime; - ourBoard.sync.curSyncObj.timeSyncSentConfirmation = ourBoard.sync.curSyncObj.timeSyncSent + expectedTimeTillSentConf; - - ourBoard.once('synced', obj => { - expect(obj.timeTransmission).to.equal(obj.timeRoundTrip * k.OBCITimeSyncMultiplierWithSyncConf); - done(); - }); - ourBoard._processPacketTimeSyncSet(timeSyncSetPacket, timeSetPacketArrived); - }); - it('should calculate offset time as a time packet arrived - transmission time - board time', function (done) { - var timeSetPacketArrived = ourBoard.time(); - var expectedRoundTripTime = 20; // ms - var expectedTimeTillSentConf = expectedRoundTripTime - k.OBCITimeSyncThresholdTransFailureMS - 2; // 8 ms - // Set the board time - var boardTime = 5000; - timeSyncSetPacket.writeInt32BE(boardTime, k.OBCIPacketPositionTimeSyncTimeStart); - - // Setup - ourBoard.curParsingMode = k.OBCIParsingNormal; // indicates the sent conf was found - // Make a new object! - ourBoard.sync.curSyncObj = openBCISample.newSyncObject(); - // Set the sent time - ourBoard.sync.curSyncObj.timeSyncSent = timeSetPacketArrived - expectedRoundTripTime; - ourBoard.sync.curSyncObj.timeSyncSentConfirmation = ourBoard.sync.curSyncObj.timeSyncSent + expectedTimeTillSentConf; - - var expectedTransmissionTime = expectedRoundTripTime - (ourBoard.sync.curSyncObj.timeSyncSentConfirmation - ourBoard.sync.curSyncObj.timeSyncSent); - - var expectedTimeOffset = timeSetPacketArrived - expectedTransmissionTime - boardTime; - - ourBoard.once('synced', obj => { - expect(obj.timeOffset, 'object timeOffset').to.equal(expectedTimeOffset); - expect(ourBoard.sync.timeOffsetMaster, 'master time offset').to.equal(expectedTimeOffset); - done(); - }); - ourBoard._processPacketTimeSyncSet(timeSyncSetPacket, timeSetPacketArrived); - }); - it('should calculate offset time as an average of previous offset times', function (done) { - var timeSetPacketArrived = ourBoard.time(); - var expectedRoundTripTime = 20; // ms - var expectedTimeTillSentConf = expectedRoundTripTime - k.OBCITimeSyncThresholdTransFailureMS - 2; // 8 ms - // Set the board time - var boardTime = 5000; - timeSyncSetPacket.writeInt32BE(boardTime, k.OBCIPacketPositionTimeSyncTimeStart); - - // Setup - ourBoard.curParsingMode = k.OBCIParsingNormal; // indicates the sent conf was found - // Make a new object! - ourBoard.sync.curSyncObj = openBCISample.newSyncObject(); - // Set the sent time - ourBoard.sync.curSyncObj.timeSyncSent = timeSetPacketArrived - expectedRoundTripTime; - ourBoard.sync.curSyncObj.timeSyncSentConfirmation = ourBoard.sync.curSyncObj.timeSyncSent + expectedTimeTillSentConf; - - var expectedTransmissionTime = expectedRoundTripTime - (ourBoard.sync.curSyncObj.timeSyncSentConfirmation - ourBoard.sync.curSyncObj.timeSyncSent); - - var expectedTimeOffset = timeSetPacketArrived - expectedTransmissionTime - boardTime; - - var dif1 = 3; - ourBoard.sync.timeOffsetArray.push(expectedTimeOffset + dif1); - var dif2 = 1; - ourBoard.sync.timeOffsetArray.push(expectedTimeOffset + dif2); - - ourBoard.once('synced', obj => { - expect(obj.timeOffset, 'object timeOffset').to.equal(expectedTimeOffset); - - var expectedMasterTimeoffset = math.floor((obj.timeOffset + (obj.timeOffset + dif1) + (obj.timeOffset + dif2)) / 3); - expect(ourBoard.sync.timeOffsetMaster, 'master time offset').to.equal(expectedMasterTimeoffset); - done(); - }); - ourBoard._processPacketTimeSyncSet(timeSyncSetPacket, timeSetPacketArrived); - }); - }); - - describe('#_processPacket Errors', function () { - var ourBoard; - before(() => { - ourBoard = new openBCIBoard.OpenBCIBoard({ - verbose: false - }); - }); - beforeEach(() => { - ourBoard.badPackets = 0; - ourBoard.previousSampleNumber = 0; - }); - afterEach(() => { - ourBoard.sync.curSyncObj = null; - }); - after(() => bluebirdChecks.noPendingPromises()); - it('_processPacketStandardAccel', function () { - ourBoard.once('droppedPacket', (droppedPacketArray) => { - expect(droppedPacketArray[0]).to.equal(1); - }); - ourBoard._processPacketStandardAccel(new Buffer(5)); - expect(ourBoard.badPackets).to.equal(1); - }); - it('_processPacketStandardRawAux', function () { - ourBoard.once('droppedPacket', (droppedPacketArray) => { - expect(droppedPacketArray[0]).to.equal(1); - }); - ourBoard._processPacketStandardRawAux(new Buffer(5)); - expect(ourBoard.badPackets).to.equal(1); - }); - it('_processPacketTimeSyncedAccel', function () { - ourBoard.once('droppedPacket', (droppedPacketArray) => { - expect(droppedPacketArray[0]).to.equal(1); - }); - ourBoard._processPacketTimeSyncedAccel(new Buffer(5)); - expect(ourBoard.badPackets).to.equal(1); - }); - it('_processPacketTimeSyncedRawAux', function () { - ourBoard.once('droppedPacket', (droppedPacketArray) => { - expect(droppedPacketArray[0]).to.equal(1); - }); - ourBoard._processPacketTimeSyncedRawAux(new Buffer(5)); - expect(ourBoard.badPackets).to.equal(1); - }); - }); - describe('#time', function () { - after(() => bluebirdChecks.noPendingPromises()); - it('should use sntp time when sntpTimeSync specified in options', function (done) { - var board = new openBCIBoard.OpenBCIBoard({ - verbose: true, - sntpTimeSync: true - }); - board.on('sntpTimeLock', function () { - var funcSpySntpNow = sinon.spy(board, '_sntpNow'); - board.time(); - funcSpySntpNow.should.have.been.calledOnce; - funcSpySntpNow.restore(); - board.sntpStop(); - done(); - }); - }); - it('should use Date.now() for time when sntpTimeSync is not specified in options', function () { - var board = new openBCIBoard.OpenBCIBoard({ - verbose: true - }); - var funcSpySntpNow = sinon.spy(board, '_sntpNow'); - - board.time(); - - funcSpySntpNow.should.not.have.been.called; - - funcSpySntpNow.reset(); - - funcSpySntpNow = null; - }); - it('should emit sntpTimeLock event after sycned with ntp server', function (done) { - var board = new openBCIBoard.OpenBCIBoard({ - verbose: true, - sntpTimeSync: true - }); - - board.once('sntpTimeLock', () => { - board.sntpStop(); - done(); - }); - }); - }); - describe('#sntpStart', function () { - after(() => bluebirdChecks.noPendingPromises()); - it('should be able to start ntp server', () => { - var board = new openBCIBoard.OpenBCIBoard(); - expect(board.sntp.isLive()).to.be.false; - return Promise.all([ - board.sntpStart() - .then(() => { - expect(board.sntp.isLive()).to.be.true; - }), - new Promise(resolve => { - board.once('sntpTimeLock', resolve); - }) - ]).then(() => { - board.sntpStop(); - }); - }); - }); - describe('#sntpStop', function () { - this.timeout(5000); - var board; - before(done => { - board = new openBCIBoard.OpenBCIBoard({ - sntpTimeSync: true - }); - board.once('sntpTimeLock', () => { - done(); - }); - }); - after(() => { - board.sntpStop(); - }); - after(() => bluebirdChecks.noPendingPromises()); - it('should be able to stop the ntp server and set the globals correctly', function () { - // Verify the before condition is correct - expect(board.options.sntpTimeSync).to.be.true; - expect(board.sync.sntpActive).to.be.true; - expect(board.sntp.isLive()).to.be.true; - - // Call the function under test - board.sntpStop(); - - // Ensure the globals were set off - expect(board.options.sntpTimeSync).to.be.false; - expect(board.sync.sntpActive).to.be.false; - expect(board.sntp.isLive()).to.be.false; - }); - }); - describe('#sntpGetOffset', function () { - after(() => bluebirdChecks.noPendingPromises()); - it('should get the sntp offset', function (done) { - var board = new openBCIBoard.OpenBCIBoard({ - sntpTimeSync: true - }); - board.once('sntpTimeLock', () => { - board.sntpGetOffset().then(offset => { - board.sntpStop(); - done(); - }, done); - }); - }); - }); - describe('#_processParseBufferForReset', function () { - var ourBoard; - - before(() => { - ourBoard = new openBCIBoard.OpenBCIBoard({ - verbose: true - }); - }); - beforeEach(() => { - ourBoard.info = { - boardType: 'burrito', - sampleRate: 60, - firmware: 'taco', - numberOfChannels: 200 - }; - }); - - after(() => { - ourBoard = null; - }); - after(() => bluebirdChecks.noPendingPromises()); - - it('should recognize firmware version 1 with no daisy', () => { - var buf = new Buffer(`OpenBCI V3 Simulator -On Board ADS1299 Device ID: 0x12345 -LIS3DH Device ID: 0x38422$$$`); - - ourBoard._processParseBufferForReset(buf); - - ourBoard.info.firmware.should.equal(k.OBCIFirmwareV1); - ourBoard.info.boardType.should.equal(k.OBCIBoardDefault); - ourBoard.info.sampleRate.should.equal(k.OBCISampleRate250); - ourBoard.info.numberOfChannels.should.equal(k.OBCINumberOfChannelsDefault); - }); - it('should recognize firmware version 1 with daisy', () => { - var buf = new Buffer(`OpenBCI V3 Simulator -On Board ADS1299 Device ID: 0x12345 -On Daisy ADS1299 Device ID: 0xFFFFF -LIS3DH Device ID: 0x38422 -$$$`); - - ourBoard._processParseBufferForReset(buf); - - ourBoard.info.firmware.should.equal(k.OBCIFirmwareV1); - ourBoard.info.boardType.should.equal(k.OBCIBoardDaisy); - ourBoard.info.sampleRate.should.equal(k.OBCISampleRate125); - ourBoard.info.numberOfChannels.should.equal(k.OBCINumberOfChannelsDaisy); - }); - it('should recognize firmware version 2 with no daisy', () => { - var buf = new Buffer(`OpenBCI V3 Simulator -On Board ADS1299 Device ID: 0x12345 -LIS3DH Device ID: 0x38422 -Firmware: v2 -$$$`); - - ourBoard._processParseBufferForReset(buf); - - ourBoard.info.firmware.should.equal(k.OBCIFirmwareV2); - ourBoard.info.boardType.should.equal(k.OBCIBoardDefault); - ourBoard.info.sampleRate.should.equal(k.OBCISampleRate250); - ourBoard.info.numberOfChannels.should.equal(k.OBCINumberOfChannelsDefault); - }); - it('should recognize firmware version 2 with daisy', () => { - var buf = new Buffer(`OpenBCI V3 Simulator -On Board ADS1299 Device ID: 0x12345 -On Daisy ADS1299 Device ID: 0xFFFFF -LIS3DH Device ID: 0x38422 -Firmware: v2 -$$$`); - - ourBoard._processParseBufferForReset(buf); - - ourBoard.info.firmware.should.equal(k.OBCIFirmwareV2); - ourBoard.info.boardType.should.equal(k.OBCIBoardDaisy); - ourBoard.info.sampleRate.should.equal(k.OBCISampleRate125); - ourBoard.info.numberOfChannels.should.equal(k.OBCINumberOfChannelsDaisy); - }); - }); - - describe('#_processBytes', function () { - before(() => { - ourBoard = new openBCIBoard.OpenBCIBoard({ - verbose: true - }); - }); - beforeEach(() => { - ourBoard.sync.curSyncObj = openBCISample.newSyncObject(); - }); - afterEach(() => { - ourBoard.buffer = null; - }); - after(() => bluebirdChecks.noPendingPromises()); - - describe('#OBCIParsingReset', function () { - var _processParseBufferForResetSpy; - before(() => { - _processParseBufferForResetSpy = sinon.spy(ourBoard, '_processParseBufferForReset'); - }); - beforeEach(() => { - _processParseBufferForResetSpy.reset(); - }); - it('should wait till EOT ($$$) before starting parse', function () { - var buf1 = new Buffer(`OpenBCI V3 Simulator -On Board ADS1299 Device ID: 0x12345 -`); - var buf2 = new Buffer(`LIS3DH Device ID: `); - var buf3 = new Buffer(`0x38422 -$$$`); - - // Fake a soft reset send - ourBoard.curParsingMode = k.OBCIParsingReset; - - // Send the first buffer - ourBoard._processBytes(buf1); - // Verify the parse function was not called - _processParseBufferForResetSpy.should.not.have.been.called; - // Verify the global buffer has the first buf in it - bufferEqual(ourBoard.buffer, buf1); - // Send another buffer without EOT - ourBoard._processBytes(buf2); - // Verify the parse function was not called - _processParseBufferForResetSpy.should.not.have.been.called; - // Verify the global buffer has the first and second buf in it - bufferEqual(ourBoard.buffer, Buffer.concat([buf1, buf2])); - // Send another buffer without EOT - ourBoard._processBytes(buf3); - // Verify the parse function was called - _processParseBufferForResetSpy.should.have.been.calledOnce; - // Verify the global buffer is empty - expect(ourBoard.buffer).to.be.null; - }); - }); - - describe('#OBCIParsingTimeSyncSent', function () { - // var spy - before(() => { - // spy = sinon.spy(ourBoard.openBCISample,"isTimeSyncSetConfirmationInBuffer") - }); - beforeEach(() => { - ourBoard.curParsingMode = k.OBCIParsingTimeSyncSent; - ourBoard.sync.curSyncObj = openBCISample.newSyncObject(); - // spy.reset() - }); - it('should call to find the time sync set character in the buffer', function () { - // Verify the log event is called - var buf = new Buffer(','); - // Call the processBytes function - ourBoard._processBytes(buf); - // Verify the function was called - expect(ourBoard.curParsingMode).to.equal(k.OBCIParsingNormal); - - let emitted = false; - // Listen for the sample event - ourBoard.once('sample', () => { - emitted = true; - }); - // Make a new buffer - var buf1 = openBCISample.samplePacketReal(1); - // Send the buffer in - ourBoard._processBytes(buf1); - expect(ourBoard.buffer).to.be.null; - expect(emitted).to.be.true; - }); - it('should clear the buffer after a time sync set packet', function () { - let emitted = false; - // Verify the log event is called - var buf = new Buffer(','); - // Call the processBytes function - ourBoard._processBytes(buf); - // Verify the function was called - expect(ourBoard.curParsingMode).to.equal(k.OBCIParsingNormal); - - // Listen for the sample event - ourBoard.once('synced', () => { - // Verify the buffer is cleared - emitted = true; - }); - // Make a new buffer - var buf1 = openBCISample.samplePacketAccelTimeSyncSet(1); - // Send the buffer in - ourBoard._processBytes(buf1); - expect(ourBoard.buffer).to.be.null; - expect(emitted).to.be.true; - }); - it('should call to find the time sync set character in the buffer after packet', function () { - var buf1 = openBCISample.samplePacket(); - var buf2 = new Buffer(','); - - // Call the processBytes function - ourBoard._processBytes(Buffer.concat([buf1, buf2], buf1.length + 1)); - // Verify the function was called - expect(ourBoard.curParsingMode).to.equal(k.OBCIParsingNormal); - // Verify the buffer is empty - // expect(ourBoard.buffer).to.be.null - // ourBoard.buffer.length.should.equal(0) - }); - it('should find time sync and emit two samples', function (done) { - var buf1 = openBCISample.samplePacket(250); - var buf2 = new Buffer([0x2C]); - var buf3 = openBCISample.samplePacket(251); - - var inputBuf = Buffer.concat([buf1, buf2, buf3], buf1.byteLength + 1 + buf3.byteLength); - - var sampleCounter = 0; - - var newSample = sample => { - // console.log(`sample ${JSON.stringify(sample)}`) - if (sampleCounter === 0) { - sample.sampleNumber.should.equal(250); - } else if (sampleCounter === 1) { - sample.sampleNumber.should.equal(251); - // bufferEqual(buf1, buffer).should.be.true - // ourBoard.buffer.length.should.equal(buf1.length) - ourBoard.removeListener('sample', newSample); - expect(ourBoard.curParsingMode).to.equal(k.OBCIParsingNormal); - done(); - } - sampleCounter++; - }; - - ourBoard.on('sample', newSample); - - // Call the processBytes function - ourBoard._processBytes(inputBuf); - }); - it('should not find the packet if in packet', () => { - var buf1 = openBCISample.samplePacket(250); - buf1[4] = 0x2C; // Inject a false packet - var buf2 = openBCISample.samplePacket(251); - - // Call the processBytes function - ourBoard._processBytes(Buffer.concat([buf1, buf2], buf1.length + buf2.length)); - // Verify the time sync set was NOT called - expect(ourBoard.curParsingMode).to.equal(k.OBCIParsingTimeSyncSent); - }); - }); - - describe('#OBCIParsingNormal', function () { - before(() => { - ourBoard.curParsingMode = k.OBCIParsingNormal; - }); - it('should emit a sample when inserted', function (done) { - var expectedSampleNumber = 0; - var buf1 = openBCISample.samplePacketReal(expectedSampleNumber); - - // Declare the event emitter prior to calling function - ourBoard.once('sample', sample => { - sample.sampleNumber.should.equal(expectedSampleNumber); - }); - - // Now call the function which should call the "sample" event - ourBoard._processBytes(buf1); - expect(ourBoard.buffer).to.be.null; - done(); - }); - it('should get three packets even if one was sent in the last data emit', function () { - var expectedSampleNumber = 0; - var buf1 = openBCISample.samplePacketReal(expectedSampleNumber); - var buf2 = openBCISample.samplePacketReal(expectedSampleNumber + 1); - var buf3 = openBCISample.samplePacketReal(expectedSampleNumber + 2); - // Pretend that half of buf1 got sent in the first serial flush - // and that the last half of it will arrive a lil later - var splitPoint = 15; - if (k.getVersionNumber(process.version) >= 6) { - // from introduced in node version 6.x.x - ourBoard.buffer = Buffer.from(buf1.slice(0, splitPoint)); - } else { - ourBoard.buffer = new Buffer(buf1.slice(0, splitPoint)); - } - var dataBuf = Buffer.concat([buf1.slice(splitPoint), buf2, buf3]); - - var sampleCounter = 0; - var newSample = sample => { - if (sampleCounter === expectedSampleNumber) { - expect(sample.sampleNumber).to.equal(expectedSampleNumber); - } else if (sampleCounter === expectedSampleNumber + 1) { - expect(sample.sampleNumber).to.equal(expectedSampleNumber + 1); - } else if (sampleCounter === expectedSampleNumber + 2) { - expect(sample.sampleNumber).to.equal(expectedSampleNumber + 2); - ourBoard.removeListener('sample', newSample); - } - sampleCounter++; - }; - ourBoard.on('sample', newSample); - // Now call the function which should call the "sample" event - ourBoard._processBytes(dataBuf); - expect(ourBoard.buffer).to.be.null; - }); - it('should keep extra data in the buffer', function () { - var expectedSampleNumber = 0; - var buf1 = openBCISample.samplePacketReal(expectedSampleNumber); - var buf2 = openBCISample.samplePacketReal(expectedSampleNumber + 1); - var buf3 = openBCISample.samplePacketReal(expectedSampleNumber + 2); - // Pretend that half of buf1 got sent in the first serial flush - // and that the last half of it will arrive a lil later - var splitPoint = 15; - - ourBoard['buffer'] = null; - var bufFirstHalf, bufLastHalf; - if (k.getVersionNumber(process.version) >= 6) { - // from introduced in node version 6.x.x - bufFirstHalf = Buffer.from(buf3.slice(0, splitPoint)); - bufLastHalf = Buffer.from(buf3.slice(splitPoint)); - } else { - bufFirstHalf = new Buffer(buf3.slice(0, splitPoint)); - bufLastHalf = new Buffer(buf3.slice(splitPoint)); - } - - var sampleCounter = 0; - var newSample = sample => { - if (sampleCounter === expectedSampleNumber) { - expect(sample.sampleNumber).to.equal(expectedSampleNumber); - } else if (sampleCounter === expectedSampleNumber + 1) { - expect(sample.sampleNumber).to.equal(expectedSampleNumber + 1); - } else if (sampleCounter === expectedSampleNumber + 2) { - expect(sample.sampleNumber).to.equal(expectedSampleNumber + 2); - ourBoard.removeListener('sample', newSample); - } - sampleCounter++; - }; - ourBoard.on('sample', newSample); - // Now call the function which should call the "sample" event - ourBoard._processBytes(Buffer.concat([buf1, buf2, bufFirstHalf])); - // Now verify there is data still in the global buffer by calling _processBytes on the last half - ourBoard._processBytes(bufLastHalf); - expect(ourBoard.buffer).to.be.null; - }); - it('should throw out old data if it is incomplete and add to badPackets count', function () { - // Some how this packet go messed up and lodged in... This is the worst case, that the buffer has - // an incomplete packet. - ourBoard.buffer = new Buffer([0xA0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xC0]); - - // New buffer incoming - var expectedSampleNumber = 1; - var buf1 = openBCISample.samplePacketReal(expectedSampleNumber); - var buf2 = openBCISample.samplePacketReal(expectedSampleNumber + 1); - var buf3 = openBCISample.samplePacketReal(expectedSampleNumber + 2); - - // New data incoming! - var dataBuf = Buffer.concat([buf1, buf2, buf3]); - - var sampleCounter = expectedSampleNumber; - var newSample = sample => { - if (sampleCounter === expectedSampleNumber) { - expect(sample.sampleNumber).to.equal(expectedSampleNumber); - } else if (sampleCounter === expectedSampleNumber + 1) { - expect(sample.sampleNumber).to.equal(expectedSampleNumber + 1); - } else if (sampleCounter === expectedSampleNumber + 2) { - expect(sample.sampleNumber).to.equal(expectedSampleNumber + 2); - ourBoard.removeListener('sample', newSample); - } - sampleCounter++; - }; - ourBoard.on('sample', newSample); - // Now call the function which should call the "sample" event - ourBoard._processBytes(dataBuf); - // Verify that the old data was rejected - expect(ourBoard.buffer).to.be.null; - }); - }); - - describe('#OBCIParsingEOT', function () { - beforeEach(() => { - ourBoard.curParsingMode = k.OBCIParsingEOT; - }); - it("should emit the 'eot' event", function (done) { - var buf = new Buffer('Tacos are amazing af$$$'); - - var eotEvent = data => { - expect(bufferEqual(data, buf)).to.be.true; - ourBoard.curParsingMode.should.be.equal(k.OBCIParsingNormal); - done(); - }; - - ourBoard.once('eot', eotEvent); - - ourBoard._processBytes(buf); - }); - it("should emit the 'eot' event even if stuff comes in two serial flushes", function (done) { - var buf1 = new Buffer('Tacos are '); - var buf2 = new Buffer('amazing af$$$'); - - var eotEvent = data => { - bufferEqual(data, Buffer.concat([buf1, buf2], buf1.length + buf2.length)).should.be.true; - ourBoard.curParsingMode.should.be.equal(k.OBCIParsingNormal); - done(); - }; - - ourBoard.once('eot', eotEvent); - - ourBoard._processBytes(buf1); - ourBoard._processBytes(buf2); - }); - }); - }); - - describe('#_finalizeNewSampleForDaisy', function () { - var ourBoard, randomSampleGenerator, sampleEvent, failTimeout; - before(() => { - ourBoard = new openBCIBoard.OpenBCIBoard({ - verbose: true - }); - randomSampleGenerator = openBCISample.randomSample(k.OBCINumberOfChannelsDefault, k.OBCISampleRate250, false, 'none'); - }); - beforeEach(() => { - // Clear the global var - ourBoard._lowerChannelsSampleObject = null; - ourBoard.info.missedPackets = 0; - }); - afterEach(() => { - if (sampleEvent) { - ourBoard.removeListener('sample', sampleEvent); - sampleEvent = null; - } - if (failTimeout) { - clearTimeout(failTimeout); - failTimeout = null; - } - }); - after(() => bluebirdChecks.noPendingPromises()); - it('should store the sample to a global variable for next time', () => { - var oddSample = randomSampleGenerator(0); // Previous was 0, so the next one will be 1 (odd) - - // Call the function under test - ourBoard._finalizeNewSampleForDaisy(oddSample); - - // Check to make sure the variable is stored - expect(ourBoard._lowerChannelsSampleObject).to.equal(oddSample); - }); - it('should emit a sample on even sample if odd was before', function (done) { - var oddSample = randomSampleGenerator(0); // Previous was 0, so the next one will be 1 (odd) - var evenSample = randomSampleGenerator(1); // Previous was 1, so the next one will be 2 (even) - - // The function to be called when sample event is fired - var sampleEvent = (sample) => { - // test pass here - done(); - }; - - // Subscribe to the sample event - ourBoard.once('sample', sampleEvent); - - // Call the function under test twice - ourBoard._finalizeNewSampleForDaisy(oddSample); - ourBoard._finalizeNewSampleForDaisy(evenSample); - - // Set a timeout to end the function, after giving enough time for the sample to be emitted if were going to - // be - failTimeout = setTimeout(() => { - // Fail condition - done("didn't emit a sample"); - }, 5); // 5ms should be plenty of time - }); - it('should not emit a sample if there is no lower sample object and this is an even sample number', function (done) { - var evenSample = randomSampleGenerator(1); // Previous was 1, so the next one will be 2 (even) - - // The function to be called when sample event is fired - sampleEvent = (sample) => { - // test fail condition - done('emitted a sample'); - }; - - console.log('_lowerChannelsSampleObject', ourBoard._lowerChannelsSampleObject); - - // Subscribe to the sample event - ourBoard.once('sample', sampleEvent); - - // Call the function under test - ourBoard._finalizeNewSampleForDaisy(evenSample); - - // Set a timeout to end the function, after giving enough time for the sample to be emitted if were going to - // be - failTimeout = setTimeout(() => { - // This is the condition where an odd was skipped so need to keep track of this as a missed packet - expect(ourBoard.info.missedPackets).to.equal(1); - done(); // Test pass here - }, 5); // 5ms should be plenty of time - }); - it('should not emit a sample if back to back odd samples', function (done) { - var oddSample1 = randomSampleGenerator(0); // Previous was 0, so the next one will be 1 (odd) - var oddSample2 = randomSampleGenerator(2); // Previous was 0, so the next one will be 1 (odd) - - // The function to be called when sample event is fired - sampleEvent = (sample) => { - // test fail condition - done('emitted a sample'); - }; - - // Subscribe to the sample event - ourBoard.once('sample', sampleEvent); - - // Call the function under test twice - ourBoard._finalizeNewSampleForDaisy(oddSample1); - ourBoard._finalizeNewSampleForDaisy(oddSample2); - - // Set a timeout to end the function, after giving enough time for the sample to be emitted if were going to - // be - failTimeout = setTimeout(() => { - // This is the condition where an even was skipped so need to keep track of this as a missed packet - expect(ourBoard.info.missedPackets).to.equal(1); - ourBoard.removeListener('sample', sampleEvent); - done(); // Test pass here - }, 5); // 5ms should be plenty of time - }); - }); - - describe('#usingVersionTwoFirmware', function () { - after(() => bluebirdChecks.noPendingPromises()); - it('should return true if firmware is version 2', () => { - ourBoard = new openBCIBoard.OpenBCIBoard(); - ourBoard.info.firmware = 'v2'; - - expect(ourBoard.usingVersionTwoFirmware()).to.be.true; - }); - it('should return false if not firmware version 2', () => { - ourBoard = new openBCIBoard.OpenBCIBoard(); - - expect(ourBoard.usingVersionTwoFirmware()).to.be.false; - }); - }); - - describe('#hardwareValidation', function () { - this.timeout(20000); // long timeout for pleanty of stream time :) - var runHardwareValidation = true; - var wstream; - var board; - before(function (done) { - if (masterPortName === k.OBCISimulatorPortName) { - runHardwareValidation = false; - } - if (runHardwareValidation) { - board = new openBCIBoard.OpenBCIBoard({ - verbose: true, - simulatorFragmentation: k.OBCISimulatorFragmentationRandom - }); - // Use the line below to output the - wstream = fs.createWriteStream('hardwareVoltageOutputAll.txt'); - - board.connect(masterPortName) - .catch(err => done(err)); - - board.once('ready', () => { - done(); - }); - } else { - done(); - } - }); - after(function () { - if (runHardwareValidation) { - board.disconnect(); - } - }); - after(() => bluebirdChecks.noPendingPromises()); - it('test all output signals', function (done) { - if (runHardwareValidation) { - board.streamStart() - .then(() => { - console.log('Started stream'); - console.log('--------'); - }) - .catch(err => done(err)); - - setTimeout(() => { - console.log('*-------'); - board.testSignal('pulse1xSlow'); - }, 3000); - setTimeout(() => { - console.log('**------'); - board.testSignal('pulse2xSlow'); - }, 5000); - setTimeout(() => { - console.log('***-----'); - board.testSignal('pulse1xFast'); - }, 7000); - setTimeout(() => { - console.log('****----'); - board.testSignal('pulse2xFast'); - }, 9000); - setTimeout(() => { - console.log('*****---'); - board.testSignal('none'); - }, 11000); - setTimeout(() => { - console.log('******--'); - board.testSignal('pulse1xSlow'); - }, 13000); - setTimeout(() => { - console.log('*******-'); - board.testSignal('none'); - }, 15000); - - board.on('sample', sample => { - openBCISample.samplePrintLine(sample) - .then(line => { - wstream.write(line); - }); - }); - // This stops the test - setTimeout(() => { - console.log('********'); - done(); - }, 19000); - } else { - done(); - } - }); - }); -}); - -describe('#daisy', function () { - var ourBoard; - this.timeout(4000); - before(function (done) { - ourBoard = new openBCIBoard.OpenBCIBoard({ - verbose: true, - simulatorFirmwareVersion: 'v2', - simulatorDaisyModuleAttached: true, - simulatorFragmentation: k.OBCISimulatorFragmentationRandom - }); - - var useSim = () => { - ourBoard.simulatorEnable() - .then(() => { - console.log(`has daisy module: ${ourBoard.options.simulatorDaisyModuleAttached}`); - return ourBoard.connect(k.OBCISimulatorPortName); - }) - .then(() => { - return ourBoard.softReset(); - }) - .catch(err => console.log(err)); - }; - ourBoard.autoFindOpenBCIBoard() - .then(portName => { - return setTimeout(() => { - console.log('Issuing connect'); - ourBoard.connect(portName); - }, 500); - }) - .catch(() => { - useSim(); - }) - .then(() => { - // console.log('connected') - }) - .catch(err => { - console.log('Error: ' + err); - }); - - ourBoard.once('ready', () => { - done(); - }); - }); - after(function (done) { - if (ourBoard.isConnected()) { - ourBoard.disconnect().then(() => { - done(); - }).catch(() => done); - } else { - done(); - } - }); - after(() => bluebirdChecks.noPendingPromises()); - it('can get samples with channel array of length 16 if daisy', function (done) { - var numberOfSamples = 130; - var sampleCount = 0; - - if (ourBoard.info.boardType !== k.OBCIBoardDaisy) { - return done(); - } - var samp = sample => { - expect(sample.channelData.length).to.equal(k.OBCINumberOfChannelsDaisy); - if (sampleCount <= numberOfSamples) { - sampleCount++; - } else { - ourBoard.disconnect() - .then(() => { - done(); - }); - ourBoard.removeListener('sample', samp); - } - }; - ourBoard.on('sample', samp); - ourBoard.streamStart() - .catch(err => { - done(err); - }); - // Attached the emitted - }); -}); - -describe('#syncWhileStreaming', function () { - var ourBoard; - this.timeout(4000); - before(function (done) { - ourBoard = new openBCIBoard.OpenBCIBoard({ - verbose: true, - simulatorFirmwareVersion: 'v2', - simulatorFragmentation: k.OBCISimulatorFragmentationRandom - }); - var useSim = () => { - ourBoard.simulatorEnable() - .then(() => { - console.log(`sim firmware version: ${ourBoard.options.simulatorFirmwareVersion}`); - return ourBoard.connect(k.OBCISimulatorPortName); - }) - .then(() => { - return ourBoard.softReset(); - }) - .catch(err => console.log(err)); - }; - ourBoard.autoFindOpenBCIBoard() - .then(portName => { - return setTimeout(() => { - console.log('Issuing connect'); - ourBoard.connect(portName); - }, 500); - }) - .catch(() => { - useSim(); - }) - .then(() => { - // console.log('connected') - }) - .catch(err => { - console.log('Error: ' + err); - }); - - ourBoard.once('ready', () => { - ourBoard.streamStart() - .then(() => { - done(); - }) - .catch(err => { - done(err); - }); - }); - }); - after(function (done) { - if (ourBoard.isConnected()) { - ourBoard.disconnect().then(() => { - done(); - }).catch(() => done); - } else { - done(); - } - }); - after(() => bluebirdChecks.noPendingPromises()); - afterEach(() => { - this.buffer = null; - }); - describe('#syncClocks', function () { - this.timeout(4000); - it('can sync while streaming', done => { - var syncAfterSamples = 50; - var notSynced = true; - var syncFunc = obj => { - ourBoard.removeListener('sample', samp); - done(); - }; - var samp = sample => { - if (sample.sampleNumber >= syncAfterSamples && notSynced) { - notSynced = false; - // Call the first one - ourBoard.syncClocks() - .catch(() => { - ourBoard.removeListener('sample', samp); - ourBoard.removeListener('synced', syncFunc); - done(); - }); - } - }; - ourBoard.on('sample', samp); - ourBoard.once('synced', syncFunc); - }); - }); - describe('#syncClocksFull', function () { - this.timeout(4000); - it('can run a full clock sync', done => { - var notSynced = true; - var sampleFun = sample => { - if (notSynced) { - notSynced = false; - // Call the first one - ourBoard.syncClocksFull() - .then(syncObj => { - if (syncObj.valid) { - ourBoard.removeListener('sample', sampleFun); - done(); - } else { - ourBoard.removeListener('sample', sampleFun); - done('Not able to sync'); - } - }).catch(() => { - ourBoard.removeListener('sample', sampleFun); - done(); - }); - } - }; - ourBoard.on('sample', sampleFun); - }); - }); -}); - -describe('#syncErrors', function () { - var ourBoard; - this.timeout(4000); - before(function (done) { - ourBoard = new openBCIBoard.OpenBCIBoard({ - verbose: true, - simulatorFirmwareVersion: 'v2' - }); - var useSim = () => { - ourBoard.simulatorEnable() - .then(() => { - return ourBoard.connect(k.OBCISimulatorPortName); - }) - .then(() => { - return ourBoard.softReset(); - }) - .catch(err => console.log(err)); - }; - ourBoard.autoFindOpenBCIBoard() - .then(portName => { - return setTimeout(() => { - console.log('Issuing connect'); - ourBoard.connect(portName); - }, 500); - }) - .catch(() => { - useSim(); - }) - .then(() => { - // console.log('connected'); - }) - .catch(err => { - console.log('Error: ' + err); - }); - - ourBoard.once('ready', () => { - done(); - }); - }); - after(function (done) { - if (ourBoard.isConnected()) { - ourBoard.disconnect().then(() => { - done(); - }).catch(() => done); - } else { - done(); - } - }); - after(() => bluebirdChecks.noPendingPromises()); - afterEach(() => { - this.buffer = null; - }); - describe('#syncClocksFull', function () { - it('should reject syncClocksFull request because of timeout', done => { - var notSynced = true; - var sampleFun = sample => { - if (notSynced) { - notSynced = false; - // Call the first one - ourBoard.syncClocksFull() - .then(syncObj => { - done('Should not be able to sync'); - }).catch(() => { - ourBoard.removeListener('sample', sampleFun); - done(); - }); - ourBoard.streamStop(); - } - }; - ourBoard.streamStart() - .catch((err) => { - ourBoard.removeListener('sample', sampleFun); - done(`could not start time sync with err: ${err}`); - }); - ourBoard.on('sample', sampleFun); - }); - }); -}); diff --git a/test/openBCISimulator-test.js b/test/openBCISimulator-test.js deleted file mode 100644 index faf52d0..0000000 --- a/test/openBCISimulator-test.js +++ /dev/null @@ -1,894 +0,0 @@ -'use strict'; -var bluebirdChecks = require('./bluebirdChecks'); -var bufferEqual = require('buffer-equal'); -var chai = require('chai'); -var chaiAsPromised = require(`chai-as-promised`); -var expect = chai.expect; -var should = chai.should(); // eslint-disable-line no-unused-vars -var openBCISimulator = require('../openBCISimulator'); -var openBCISample = require('../openBCISample'); -var k = openBCISample.k; - -chai.use(chaiAsPromised); - -describe('openBCISimulator', function () { - this.timeout(4000); - var portName = k.OBCISimulatorPortName; - afterEach(() => bluebirdChecks.noPendingPromises(200)); - describe('#constructor', function () { - var simulator; - afterEach(() => { - simulator = null; - }); - after(done => { - setTimeout(() => { - // Since there is a conditional timeout, it's important to wait to start the next test till this ends for sure - done(); - }, 200); // The same amount of time in the simulator - }); - it('constructs with the correct default options', function () { - simulator = new openBCISimulator.OpenBCISimulator(); - expect(simulator.options.accel).to.be.true; - expect(simulator.options.alpha).to.be.true; - expect(simulator.options.boardFailure).to.be.false; - expect(simulator.options.daisy).to.be.false; - expect(simulator.options.daisyCanBeAttached).to.be.true; - expect(simulator.options.drift).to.equal(0); - expect(simulator.options.firmwareVersion).to.equal(k.OBCIFirmwareV1); - expect(simulator.options.lineNoise).to.equal(k.OBCISimulatorLineNoiseHz60); - expect(simulator.options.sampleRate).to.equal(k.OBCISampleRate250); - expect(simulator.options.serialPortFailure).to.be.false; - expect(simulator.options.verbose).to.be.false; - expect(simulator.options.fragmentation).to.equal(k.OBCISimulatorFragmentationNone); - expect(simulator.options.latencyTime).to.equal(16); - expect(simulator.options.bufferSize).to.equal(4096); - }); - it('should be able to get into daisy mode', function () { - simulator = new openBCISimulator.OpenBCISimulator(portName, { - daisy: true - }); - expect(simulator.options.daisy).to.be.true; - }); - it('should set the correct sample rate in daisy mode, if no sampleRate is provided', function () { - simulator = new openBCISimulator.OpenBCISimulator(portName, { - daisy: true - }); - expect(simulator.options.sampleRate).to.equal(250); // produce samples at same rate - }); - it('should use provided sample rate even if daisy is true', function () { - simulator = new openBCISimulator.OpenBCISimulator(portName, { - daisy: true, - sampleRate: 20 - }); - expect(simulator.options.daisy).to.be.true; - expect(simulator.options.sampleRate).to.equal(20); - }); - it('should be able to put into firmware version 2', function () { - simulator = new openBCISimulator.OpenBCISimulator(portName, { - firmwareVersion: 'v2' - }); - expect(simulator.options.firmwareVersion).to.equal(k.OBCIFirmwareV2); - }); - it('should be able to simulate board failure', function () { - simulator = new openBCISimulator.OpenBCISimulator(portName, { - boardFailure: true - }); - expect(simulator.options.boardFailure).to.be.true; - }); - it('should be able to simulate serial port failure', function () { - simulator = new openBCISimulator.OpenBCISimulator(portName, { - serialPortFailure: true - }); - expect(simulator.options.serialPortFailure).to.be.true; - }); - it('can turn 50Hz line noise on', function () { - simulator = new openBCISimulator.OpenBCISimulator(portName, { - lineNoise: '50Hz' - }); - (simulator.options.lineNoise).should.equal(k.OBCISimulatorLineNoiseHz50); - }); - it('can turn no line noise on', function () { - simulator = new openBCISimulator.OpenBCISimulator(portName, { - lineNoise: 'none' - }); - (simulator.options.lineNoise).should.equal(k.OBCISimulatorLineNoiseNone); - }); - it('should not inject alpha if desired', function () { - simulator = new openBCISimulator.OpenBCISimulator(portName, { - alpha: false - }); - expect(simulator.options.alpha).to.be.false; - }); - it('should be able to not use the accel', function () { - simulator = new openBCISimulator.OpenBCISimulator(portName, { - accel: false - }); - expect(simulator.options.accel).to.be.false; - }); - it('should be able to set positive drift', function () { - simulator = new openBCISimulator.OpenBCISimulator(portName, { - drift: 1 - }); - expect(simulator.options.drift).to.be.greaterThan(0); - }); - it('should be able to set negative drift', function () { - simulator = new openBCISimulator.OpenBCISimulator(portName, { - drift: -1 - }); - expect(simulator.options.drift).to.be.lessThan(0); - }); - it('should throw if passed an invalid option', function (done) { - try { - simulator = new openBCISimulator.OpenBCISimulator(portName, { - foo: 'bar' - }); - done('did not throw'); - } catch (e) { done(); } - }); - }); - describe('#write', function () { - it('should refuse to write when not connected', function (done) { - var simulator = new openBCISimulator.OpenBCISimulator(k.OBCISimulatorPortName); - try { - simulator.write('q'); - done('did not throw on disconnected write'); - } catch (e) { - simulator.write('q', err => { - if (err) { - done(); - } else { - done('did not provide error on disconnected write'); - } - }); - } - }); - }); - describe('#close', function () { - it('should provide an error closing when already closed', function (done) { - var simulator = new openBCISimulator.OpenBCISimulator(k.OBCISimulatorPortName); - simulator.close(err => { - if (err) { - done(); - } else { - done('closed successfully but had no time to open'); - } - }); - }); - }); - describe(`_startStream`, function () { - it('should return a packet with sample data in it', function (done) { - var simulator = new openBCISimulator.OpenBCISimulator(k.OBCISimulatorPortName); - var sampleCounter = 0; - var sampleTestSize = 5; - - var newDataFunc = data => { - if (sampleCounter > sampleTestSize) { - simulator.write(k.OBCIStreamStop); - simulator.removeListener('data', newDataFunc); - let sample = openBCISample.parseRawPacketStandard(data, k.channelSettingsArrayInit(k.OBCINumberOfChannelsDefault), true); - expect(sample.channelData).to.not.all.equal(0); - done(); - simulator = null; - } else { - sampleCounter++; - } - }; - simulator.on('data', newDataFunc); - simulator.once('open', () => simulator._startStream()); - }); - it('should return a sync set packet with accel', function (done) { - var simulator = new openBCISimulator.OpenBCISimulator(k.OBCISimulatorPortName); - var sampleCounter = 0; - var sampleTestSize = 5; - - var newDataFunc = data => { - if (sampleCounter === 0) { - // Ensure everything is switched on for this test - simulator.options.accel = true; - simulator.synced = true; - simulator.sendSyncSetPacket = true; - expect(data[k.OBCIPacketPositionStopByte]).to.equal(openBCISample.makeTailByteFromPacketType(k.OBCIStreamPacketStandardAccel)); - } else if (sampleCounter === 1) { - // Now this data should be the time sync up packet - expect(data[k.OBCIPacketPositionStopByte]).to.equal(openBCISample.makeTailByteFromPacketType(k.OBCIStreamPacketAccelTimeSyncSet)); - // Expect flag to be down - expect(simulator.sendSyncSetPacket).to.be.false; - } else if (sampleCounter >= sampleTestSize) { - simulator.write(k.OBCIStreamStop); - simulator.removeListener('data', newDataFunc); - simulator = null; - done(); - } else { - // Now this data should be the time sync up packet - expect(data[k.OBCIPacketPositionStopByte]).to.equal(openBCISample.makeTailByteFromPacketType(k.OBCIStreamPacketAccelTimeSynced)); - } - sampleCounter++; - }; - - simulator.on('data', newDataFunc); - simulator.once('open', () => simulator.write(k.OBCIStreamStart)); - }); - it('should return a sync set packet with raw aux', function (done) { - var simulator = new openBCISimulator.OpenBCISimulator(k.OBCISimulatorPortName, { - accel: false - }); - var sampleCounter = 0; - var sampleTestSize = 5; - - var newDataFunc = data => { - if (sampleCounter === 0) { - // Ensure everything is switched on for this test - simulator.synced = true; - simulator.sendSyncSetPacket = true; - expect(data[k.OBCIPacketPositionStopByte]).to.equal(openBCISample.makeTailByteFromPacketType(k.OBCIStreamPacketStandardRawAux)); - } else if (sampleCounter === 1) { - // Now this data should be the time sync up packet - expect(data[k.OBCIPacketPositionStopByte]).to.equal(openBCISample.makeTailByteFromPacketType(k.OBCIStreamPacketRawAuxTimeSyncSet)); - // Expect flag to be down - expect(simulator.sendSyncSetPacket).to.be.false; - } else if (sampleCounter >= sampleTestSize) { - simulator.write(k.OBCIStreamStop); - simulator.removeListener('data', newDataFunc); - simulator = null; - done(); - } else { - // Now this data should be the time sync up packet - expect(data[k.OBCIPacketPositionStopByte]).to.equal(openBCISample.makeTailByteFromPacketType(k.OBCIStreamPacketRawAuxTimeSynced)); - } - sampleCounter++; - }; - - simulator.on('data', newDataFunc); - simulator.once('open', () => simulator.write(k.OBCIStreamStart)); - }); - }); - describe(`firmwareVersion1`, function () { - var simulator; - beforeEach((done) => { - simulator = new openBCISimulator.OpenBCISimulator(k.OBCISimulatorPortName, { - firmwareVersion: 'v1' - }); - simulator.once('open', done); - }); - afterEach(() => { - simulator = null; - }); - describe('reset', function () { - it('should not be v2', function (done) { - simulator.on('data', function (data) { - console.log(data.toString()); - expect(data.toString().match('v2')).to.equal(null); - done(); - }); - simulator.write(k.OBCIMiscSoftReset); - }); - }); - }); - describe(`firmwareVersion2`, function () { - var simulator; - beforeEach((done) => { - simulator = new openBCISimulator.OpenBCISimulator(k.OBCISimulatorPortName, { - firmwareVersion: 'v2' - }); - simulator.once('open', done); - }); - afterEach(() => { - simulator.removeAllListeners('data'); - simulator = null; - }); - describe('set max channels', function () { - this.timeout(100); - it('should send nothing if no daisy attached', function (done) { - simulator.options.daisy = false; - simulator.on('data', function (data) { - expect(data.toString().match(k.OBCIParseEOT)).to.not.equal(null); - if (data.toString().match(k.OBCIParseEOT)) { - done(); - } - }); - simulator.write(k.OBCIChannelMaxNumber8); - }); - it('should send daisy removed if daisy attached', function (done) { - simulator.options.daisy = true; - simulator.on('data', function (data) { - expect(data.toString().match(`daisy removed${k.OBCIParseEOT}`)).to.not.equal(null); - if (data.toString().match(k.OBCIParseEOT)) { - expect(simulator.options.daisy).to.equal(false); - done(); - } - }); - simulator.write(k.OBCIChannelMaxNumber8); - }); - it('should send just 16 if daisy already attached', function (done) { - simulator.options.daisy = true; - simulator.on('data', function (data) { - expect(data.toString().match(`16${k.OBCIParseEOT}`)).to.not.equal(null); - if (data.toString().match(k.OBCIParseEOT)) { - done(); - } - }); - simulator.write(k.OBCIChannelMaxNumber16); - }); - it('should send daisy attached if able to attach', function (done) { - simulator.options.daisy = false; - simulator.options.daisyCanBeAttached = true; - simulator.on('data', function (data) { - expect(data.toString().match(`daisy attached16`)).to.not.equal(null); - if (data.toString().match(k.OBCIParseEOT)) { - expect(simulator.options.daisy).to.equal(true); - done(); - } - }); - simulator.write(k.OBCIChannelMaxNumber16); - }); - it('should send daisy attached if not able to attach', function (done) { - simulator.options.daisy = false; - simulator.options.daisyCanBeAttached = false; - simulator.on('data', function (data) { - expect(data.toString().match(`no daisy to attach!`)).to.not.equal(null); - if (data.toString().match(k.OBCIParseEOT)) { - done(); - } - }); - simulator.write(k.OBCIChannelMaxNumber16); - }); - }); - describe('reset', function () { - it('should be v2', function (done) { - simulator.on('data', function (data) { - expect(data.toString().match('v2')).to.not.equal(null); - done(); - }); - simulator.write(k.OBCIMiscSoftReset); - }); - }); - describe('_processPrivateRadioMessage', function () { - describe('OBCIRadioCmdChannelGet', function () { - it('should emit success if firmware version 2', done => { - simulator.channelNumber = 0; - var buf = new Buffer(0); - var dataEmit = data => { - buf = Buffer.concat([buf, data]); - if (openBCISample.doesBufferHaveEOT(buf)) { - expect(openBCISample.isSuccessInBuffer(buf)).to.be.true; - expect(openBCISample.isFailureInBuffer(buf)).to.be.false; - expect(buf[buf.length - 4]).to.equal(0); - simulator.removeListener('data', dataEmit); - done(); - } - }; - - simulator.on('data', dataEmit); - - simulator._processPrivateRadioMessage(new Buffer([k.OBCIRadioKey, k.OBCIRadioCmdChannelGet])); - }); - it('should emit failure if board failure and host channel number', done => { - // Turn board failure mode - simulator.options.boardFailure = true; - simulator.channelNumber = 9; - var buf = new Buffer(0); - var dataEmit = data => { - buf = Buffer.concat([buf, data]); - if (openBCISample.doesBufferHaveEOT(buf)) { - expect(openBCISample.isSuccessInBuffer(buf)).to.be.false; - expect(openBCISample.isFailureInBuffer(buf)).to.be.true; - expect(buf[buf.length - 4]).to.equal(9); - simulator.removeListener('data', dataEmit); - done(); - } - }; - - simulator.on('data', dataEmit); - - simulator._processPrivateRadioMessage(new Buffer([k.OBCIRadioKey, k.OBCIRadioCmdChannelGet])); - }); - }); - describe('OBCIRadioCmdChannelSet', function () { - it('should set the channel number if in bounds', done => { - var newChanNum = 20; - var buf = new Buffer(0); - var dataEmit = data => { - buf = Buffer.concat([buf, data]); - if (openBCISample.doesBufferHaveEOT(buf)) { - expect(openBCISample.isSuccessInBuffer(buf)).to.be.true; - expect(openBCISample.isFailureInBuffer(buf)).to.be.false; - expect(buf[buf.length - 4]).to.equal(newChanNum); - expect(simulator.channelNumber).to.equal(newChanNum); - expect(simulator.hostChannelNumber).to.equal(newChanNum); - simulator.removeListener('data', dataEmit); - done(); - } - }; - - simulator.on('data', dataEmit); - - simulator._processPrivateRadioMessage(new Buffer([k.OBCIRadioKey, k.OBCIRadioCmdChannelSet, newChanNum])); - }); - it('should not set the channel number if out of bounds', done => { - var newChanNum = 26; - var buf = new Buffer(0); - var dataEmit = data => { - buf = Buffer.concat([buf, data]); - if (openBCISample.doesBufferHaveEOT(buf)) { - expect(openBCISample.isSuccessInBuffer(buf)).to.be.false; - expect(openBCISample.isFailureInBuffer(buf)).to.be.true; - simulator.removeListener('data', dataEmit); - done(); - } - }; - - simulator.on('data', dataEmit); - - simulator._processPrivateRadioMessage(new Buffer([k.OBCIRadioKey, k.OBCIRadioCmdChannelSet, newChanNum])); - }); - it('should emit failure if board failure', done => { - // Turn board failure mode - simulator.options.boardFailure = true; - var buf = new Buffer(0); - var dataEmit = data => { - buf = Buffer.concat([buf, data]); - if (openBCISample.doesBufferHaveEOT(buf)) { - expect(openBCISample.isSuccessInBuffer(buf)).to.be.false; - expect(openBCISample.isFailureInBuffer(buf)).to.be.true; - simulator.removeListener('data', dataEmit); - done(); - } - }; - - simulator.on('data', dataEmit); - simulator._processPrivateRadioMessage(new Buffer([k.OBCIRadioKey, k.OBCIRadioCmdChannelSet, 7])); - }); - }); - describe('OBCIRadioCmdChannelSetOverride', function () { - it('should change just the hosts channel number and not the systems channel number and force a board comms failure', done => { - var systemChannelNumber = 0; - var newHostChannelNumber = 1; - simulator.channelNumber = systemChannelNumber; - var buf = new Buffer(0); - var dataEmit = data => { - buf = Buffer.concat([buf, data]); - if (openBCISample.doesBufferHaveEOT(buf)) { - expect(openBCISample.isSuccessInBuffer(buf)).to.be.true; - expect(openBCISample.isFailureInBuffer(buf)).to.be.false; - expect(buf[buf.length - 4]).to.equal(newHostChannelNumber); - expect(simulator.options.boardFailure).to.be.true; - expect(simulator.channelNumber).to.equal(systemChannelNumber); - expect(simulator.hostChannelNumber).to.equal(newHostChannelNumber); - simulator.removeListener('data', dataEmit); - done(); - } - }; - - simulator.on('data', dataEmit); - - simulator._processPrivateRadioMessage(new Buffer([k.OBCIRadioKey, k.OBCIRadioCmdChannelSetOverride, newHostChannelNumber])); - }); - it('should change just the hosts channel number and not the systems channel number and fix a board failure', done => { - var systemChannelNumber = 0; - var oldHostChannelNumber = 1; - simulator.channelNumber = systemChannelNumber; - simulator.hostChannelNumber = oldHostChannelNumber; - var buf = new Buffer(0); - var dataEmit = data => { - buf = Buffer.concat([buf, data]); - if (openBCISample.doesBufferHaveEOT(buf)) { - expect(openBCISample.isSuccessInBuffer(buf)).to.be.true; - expect(openBCISample.isFailureInBuffer(buf)).to.be.false; - expect(buf[buf.length - 4]).to.equal(systemChannelNumber); - expect(simulator.options.boardFailure).to.be.false; - expect(simulator.channelNumber).to.equal(systemChannelNumber); - expect(simulator.hostChannelNumber).to.equal(systemChannelNumber); - simulator.removeListener('data', dataEmit); - done(); - } - }; - - simulator.on('data', dataEmit); - - simulator._processPrivateRadioMessage(new Buffer([k.OBCIRadioKey, k.OBCIRadioCmdChannelSetOverride, systemChannelNumber])); - }); - it('should not set the channel number if out of bounds', done => { - var newChanNum = 26; - var buf = new Buffer(0); - var dataEmit = data => { - buf = Buffer.concat([buf, data]); - if (openBCISample.doesBufferHaveEOT(buf)) { - expect(openBCISample.isSuccessInBuffer(buf)).to.be.false; - expect(openBCISample.isFailureInBuffer(buf)).to.be.true; - simulator.removeListener('data', dataEmit); - done(); - } - }; - - simulator.on('data', dataEmit); - - simulator._processPrivateRadioMessage(new Buffer([k.OBCIRadioKey, k.OBCIRadioCmdChannelSetOverride, newChanNum])); - }); - }); - describe('OBCIRadioCmdPollTimeGet', function () { - it('should emit success if firmware version 2 with poll time', done => { - var expectedPollTime = 80; - simulator.pollTime = expectedPollTime; - var buf = new Buffer(0); - var dataEmit = data => { - buf = Buffer.concat([buf, data]); - if (openBCISample.doesBufferHaveEOT(buf)) { - expect(openBCISample.isSuccessInBuffer(buf)).to.be.true; - expect(openBCISample.isFailureInBuffer(buf)).to.be.false; - expect(buf[buf.length - 4]).to.equal(expectedPollTime); - simulator.removeListener('data', dataEmit); - done(); - } - }; - - simulator.on('data', dataEmit); - - simulator._processPrivateRadioMessage(new Buffer([k.OBCIRadioKey, k.OBCIRadioCmdPollTimeGet])); - }); - it('should emit failure if board failure', done => { - // Turn board failure mode - simulator.options.boardFailure = true; - var buf = new Buffer(0); - var dataEmit = data => { - buf = Buffer.concat([buf, data]); - if (openBCISample.doesBufferHaveEOT(buf)) { - expect(openBCISample.isSuccessInBuffer(buf)).to.be.false; - expect(openBCISample.isFailureInBuffer(buf)).to.be.true; - simulator.removeListener('data', dataEmit); - done(); - } - }; - - simulator.on('data', dataEmit); - - simulator._processPrivateRadioMessage(new Buffer([k.OBCIRadioKey, k.OBCIRadioCmdPollTimeGet])); - }); - }); - describe('OBCIRadioCmdPollTimeSet', function () { - it('should set the poll time if in bounds', done => { - var newPollTime = 20; - var buf = new Buffer(0); - var dataEmit = data => { - buf = Buffer.concat([buf, data]); - if (openBCISample.doesBufferHaveEOT(buf)) { - expect(openBCISample.isSuccessInBuffer(buf)).to.be.true; - expect(openBCISample.isFailureInBuffer(buf)).to.be.false; - expect(buf[buf.length - 4]).to.equal(newPollTime); - simulator.removeListener('data', dataEmit); - done(); - } - }; - - simulator.on('data', dataEmit); - - simulator._processPrivateRadioMessage(new Buffer([k.OBCIRadioKey, k.OBCIRadioCmdPollTimeSet, newPollTime])); - }); - it('should emit failure if board failure', done => { - // Turn board failure mode - simulator.options.boardFailure = true; - var buf = new Buffer(0); - var dataEmit = data => { - buf = Buffer.concat([buf, data]); - if (openBCISample.doesBufferHaveEOT(buf)) { - expect(openBCISample.isSuccessInBuffer(buf)).to.be.false; - expect(openBCISample.isFailureInBuffer(buf)).to.be.true; - simulator.removeListener('data', dataEmit); - done(); - } - }; - - simulator.on('data', dataEmit); - simulator._processPrivateRadioMessage(new Buffer([k.OBCIRadioKey, k.OBCIRadioCmdPollTimeSet, 7])); - }); - }); - describe('OBCIRadioCmdBaudRateSetDefault', function () { - it('should emit success if firmware version 2 with proper baud rate', done => { - var buf = new Buffer(0); - var dataEmit = data => { - buf = Buffer.concat([buf, data]); - if (openBCISample.doesBufferHaveEOT(buf)) { - expect(openBCISample.isSuccessInBuffer(buf)).to.be.true; - expect(openBCISample.isFailureInBuffer(buf)).to.be.false; - var eotBuf = new Buffer('$$$'); - var newBaudRateBuf; - for (var i = buf.length; i > 3; i--) { - if (bufferEqual(buf.slice(i - 3, i), eotBuf)) { - newBaudRateBuf = buf.slice(i - 9, i - 3); - break; - } - } - var newBaudRateNum = Number(newBaudRateBuf.toString()); - expect(newBaudRateNum).to.equal(k.OBCIRadioBaudRateDefault); - simulator.removeListener('data', dataEmit); - done(); - } - }; - - simulator.on('data', dataEmit); - - simulator._processPrivateRadioMessage(new Buffer([k.OBCIRadioKey, k.OBCIRadioCmdBaudRateSetDefault])); - }); - it('should emit success if board failure', done => { - // Turn board failure mode - simulator.options.boardFailure = true; - var buf = new Buffer(0); - var dataEmit = data => { - buf = Buffer.concat([buf, data]); - if (openBCISample.doesBufferHaveEOT(buf)) { - expect(openBCISample.isSuccessInBuffer(buf)).to.be.true; - expect(openBCISample.isFailureInBuffer(buf)).to.be.false; - simulator.removeListener('data', dataEmit); - done(); - } - }; - - simulator.on('data', dataEmit); - - simulator._processPrivateRadioMessage(new Buffer([k.OBCIRadioKey, k.OBCIRadioCmdBaudRateSetDefault])); - }); - }); - describe('OBCIRadioCmdBaudRateSetFast', function () { - it('should emit success if firmware version 2 with proper baud rate', done => { - var buf = new Buffer(0); - var dataEmit = data => { - buf = Buffer.concat([buf, data]); - if (openBCISample.doesBufferHaveEOT(buf)) { - expect(openBCISample.isSuccessInBuffer(buf)).to.be.true; - expect(openBCISample.isFailureInBuffer(buf)).to.be.false; - var eotBuf = new Buffer(`$$$`); - var newBaudRateBuf; - for (var i = buf.length; i > 3; i--) { - if (bufferEqual(buf.slice(i - 3, i), eotBuf)) { - newBaudRateBuf = buf.slice(i - 9, i - 3); - break; - } - } - var newBaudRateNum = Number(newBaudRateBuf.toString()); - expect(newBaudRateNum).to.equal(k.OBCIRadioBaudRateFast); - simulator.removeListener('data', dataEmit); - done(); - } - }; - - simulator.on('data', dataEmit); - - simulator._processPrivateRadioMessage(new Buffer([k.OBCIRadioKey, k.OBCIRadioCmdBaudRateSetFast])); - }); - it('should emit success if board failure', done => { - // Turn board failure mode - simulator.options.boardFailure = true; - var buf = new Buffer(0); - var dataEmit = data => { - buf = Buffer.concat([buf, data]); - if (openBCISample.doesBufferHaveEOT(buf)) { - expect(openBCISample.isSuccessInBuffer(buf)).to.be.true; - expect(openBCISample.isFailureInBuffer(buf)).to.be.false; - simulator.removeListener('data', dataEmit); - done(); - } - }; - - simulator.on('data', dataEmit); - - simulator._processPrivateRadioMessage(new Buffer([k.OBCIRadioKey, k.OBCIRadioCmdBaudRateSetFast])); - }); - }); - describe('OBCIRadioCmdSystemStatus', function () { - it('should emit success if firmware version 2', done => { - var buf = new Buffer(0); - var dataEmit = data => { - buf = Buffer.concat([buf, data]); - if (openBCISample.doesBufferHaveEOT(buf)) { - expect(openBCISample.isSuccessInBuffer(buf)).to.be.true; - expect(openBCISample.isFailureInBuffer(buf)).to.be.false; - simulator.removeListener('data', dataEmit); - done(); - } - }; - - simulator.on('data', dataEmit); - - simulator._processPrivateRadioMessage(new Buffer([k.OBCIRadioKey, k.OBCIRadioCmdSystemStatus])); - }); - it('should emit failure if board failure', done => { - // Turn board failure mode - simulator.options.boardFailure = true; - var buf = new Buffer(0); - var dataEmit = data => { - buf = Buffer.concat([buf, data]); - if (openBCISample.doesBufferHaveEOT(buf)) { - expect(openBCISample.isSuccessInBuffer(buf)).to.be.false; - expect(openBCISample.isFailureInBuffer(buf)).to.be.true; - simulator.removeListener('data', dataEmit); - done(); - } - }; - - simulator.on('data', dataEmit); - - simulator._processPrivateRadioMessage(new Buffer([k.OBCIRadioKey, k.OBCIRadioCmdSystemStatus])); - }); - }); - }); - }); - describe('fragmentation', function () { - var simulator; - afterEach(done => { - simulator.removeAllListeners(); - simulator.write(k.OBCIStreamStop); - simulator.close(done); - }); - it('Should accumulate packets if set to FullBuffers', function (done) { - var bufferSize = 64; - simulator = new openBCISimulator.OpenBCISimulator(portName, { - fragmentation: k.OBCISimulatorFragmentationFullBuffers, - bufferSize: bufferSize, - latencyTime: 1000 - }); - simulator.once('data', function (buffer) { - expect(buffer.length).to.equal(bufferSize); - done(); - }); - simulator.once('open', () => simulator.write(k.OBCIStreamStart)); - }); - it('Should emit partial packets after latencyTime', function (done) { - var bufferSize = 4096; - simulator = new openBCISimulator.OpenBCISimulator(portName, { - fragmentation: k.OBCISimulatorFragmentationFullBuffers, - bufferSize: 4096, - latencyTime: 0 - }); - simulator.once('data', function (buffer) { - expect(buffer.length).to.be.lessThan(bufferSize); - done(); - }); - simulator.once('open', () => simulator.write(k.OBCIStreamStart)); - }); - it('Should emit single bytes if set to OneByOne', function (done) { - simulator = new openBCISimulator.OpenBCISimulator(portName, { - fragmentation: k.OBCISimulatorFragmentationOneByOne - }); - var counter = 0; - simulator.on('data', function (buffer) { - expect(buffer.length).to.equal(1); - ++counter; - - if (counter === 5) done(); - }); - simulator.once('open', () => simulator.write(k.OBCIStreamStart)); - }); - it('should properly split packets, retaining valid packets', function (done) { - simulator = new openBCISimulator.OpenBCISimulator(portName, { - fragmentation: k.OBCISimulatorFragmentationRandom - }); - var buffer = new Buffer(0); - var counter = 0; - simulator.on('data', function (data) { - buffer = Buffer.concat([buffer, data], buffer.length + data.length); - if (buffer.length >= 33) { - openBCISample.parseRawPacketStandard(buffer.slice(0, 33)); - buffer = buffer.slice(33); - ++counter; - if (counter === 5) done(); - } - }); - simulator.once('open', () => simulator.write(k.OBCIStreamStart)); - }); - }); - describe(`boardFailure`, function () {}); - - describe(`#sync`, function () { - this.timeout(2000); - var simulator; - beforeEach(function (done) { - simulator = new openBCISimulator.OpenBCISimulator(portName, { - firmwareVersion: 'v2' - }); - simulator.once('open', () => { - done(); - }); - }); - afterEach(function () { - simulator = null; - }); - it(`should emit the time sync sent command`, function (done) { - simulator.once('data', data => { - expect(openBCISample.isTimeSyncSetConfirmationInBuffer(data)).to.be.true; - done(); - }); - simulator.write(k.OBCISyncTimeSet, (err, msg) => { - if (err) { - done(err); - } - }); - }); - it(`should set synced to true`, function (done) { - simulator.synced = false; - var newData = data => { - expect(simulator.synced).to.be.true; - simulator.removeListener('data', newData); - done(); - }; - - simulator.on('data', data => { - newData(data); - }); - - simulator.write(k.OBCISyncTimeSet, (err, msg) => { - if (err) { - done(err); - } - }); - }); - it(`should emit a time sync set packet followed by a time synced accel packet after sync up call`, function (done) { - simulator.synced = false; - var emitCounter = 0; - var maxPacketsBetweenSetPacket = 5; - var newData = data => { - if (emitCounter === 0) { // the time sync packet is emitted here - // Make a call to start streaming - simulator.write(k.OBCIStreamStart, err => { - if (err) done(err); - }); - } else if (emitCounter < maxPacketsBetweenSetPacket) { - if (openBCISample.getRawPacketType(data[k.OBCIPacketPositionStopByte]) === k.OBCIStreamPacketAccelTimeSyncSet) { - simulator.removeListener('data', newData); - simulator.write(k.OBCIStreamStop, err => { - if (err) done(err); - done(); - }); - } else { - expect(openBCISample.getRawPacketType(data[k.OBCIPacketPositionStopByte])).to.equal(k.OBCIStreamPacketAccelTimeSynced); - } - } else { - done(`Failed to get set packet in time`); - } - emitCounter++; - }; - - simulator.on('data', newData); - - simulator.write(k.OBCISyncTimeSet, (err, msg) => { - if (err) { - done(err); - } - }); - }); - it(`should emit a time sync set raw aux, then time synced raw aux packet after sync up call`, function (done) { - simulator.synced = false; - simulator.options.accel = false; - var emitCounter = 0; - var maxPacketsBetweenSetPacket = 5; - var newData = data => { - if (emitCounter === 0) { // the time sync packet is emitted here - // Make a call to start streaming - simulator.write(k.OBCIStreamStart, err => { - if (err) done(err); - }); - } else if (emitCounter < maxPacketsBetweenSetPacket) { - if (openBCISample.getRawPacketType(data[k.OBCIPacketPositionStopByte]) === k.OBCIStreamPacketRawAuxTimeSyncSet) { - simulator.removeListener('data', newData); - simulator.write(k.OBCIStreamStop, err => { - if (err) done(err); - done(); - }); - } else { - expect(openBCISample.getRawPacketType(data[k.OBCIPacketPositionStopByte])).to.equal(k.OBCIStreamPacketRawAuxTimeSynced); - } - } else { - done(`Failed to get set packet in time`); - } - - emitCounter++; - }; - - simulator.on('data', newData); - - simulator.write(k.OBCISyncTimeSet, (err, msg) => { - if (err) { - done(err); - } - }); - }); - }); -}); diff --git a/test/timingEventsAsPromises.js b/test/timingEventsAsPromises.js deleted file mode 100644 index 8ab0c88..0000000 --- a/test/timingEventsAsPromises.js +++ /dev/null @@ -1,108 +0,0 @@ -// Converts timing events to use promises, to gain bluebird's checks - -function instrumentTimingEvents (module, type) { - // replaces module[type] with a function that does the same thing but uses a promise - // assumes the first argument will be to a callback function - - // if this a setSomething function with a clearSomething partner, the partner will also be instrumented - var setName = type; - var clearName = null; - if (type.substring(0, 3) === 'set') { - clearName = 'clear' + type.substring(3); - } - - if (!module[setName]) return; - - // store original functions - var originalSet = module[setName]; - var originalClear = module[clearName]; - exports[setName + 'Ignored'] = originalSet; - - // dictionary to store promise details for each call - var events = {}; - - // setAsPromise() is the brunt of the function. It replaces the previous global function, - // and sets up a promise to resolve when the callback is called - var eventCount = 0; - var setAsPromise = function (callback) { - var args = [].slice.call(arguments); - - var eventNum = ++eventCount; - var eventHandle; - - if (setAsPromise._ignoreCount > 0) { - --setAsPromise._ignoreCount; - - return originalSet.apply(this, args); - } - - // actual callback is replaced by promise resolve - args[0] = function () { - if (!events[eventNum]) throw new Error(setName + ' ' + eventNum + ' disappeared'); - events[eventNum].resolve([].slice.call(arguments)); - }; - - eventHandle = originalSet.apply(this, args) || eventNum; - - // this portion is a function so that setInterval may be handled via recursion - function dispatch () { - var handlerDetails = { handle: eventHandle }; - - var promise = new Promise((resolve, reject) => { - handlerDetails.resolve = resolve; - handlerDetails.reject = reject; - }); - - handlerDetails.promise = promise; - events[eventNum] = handlerDetails; - - promise.then(function (argumentArray) { - if (type !== 'setInterval') { - delete events[eventNum]; - } else { - dispatch(); - } - - // call original handler - callback.apply(this, argumentArray); - }, () => { - originalClear(eventHandle); - delete events[eventNum]; - }); - - return promise; - } - - dispatch(); - - return eventNum; - }; - - // actually replace functions with instrumented ones - setAsPromise._ignoreCount = 0; - module[setName] = setAsPromise; - Object.defineProperty(setAsPromise, 'name', { value: setName + 'AsPromise' }); - - if (clearName) { - module[clearName] = (eventNum) => { - if (!events[eventNum]) { - originalClear(eventNum); - } else { - events[eventNum].reject(new Error('cleared')); - } - }; - Object.defineProperty(module[clearName], 'name', { value: clearName + 'AsPromise' }); - } -} - -instrumentTimingEvents(global, 'setTimeout'); -instrumentTimingEvents(global, 'setInterval'); -instrumentTimingEvents(global, 'setImmediate'); -// // Possible TODO: nextTick needs some exceptions included to prevent infinite recursion -// instrumentTimingEvents(process, 'nextTick'); - -// the next call to the passed function should not be promisified -// may be queued multiple times -exports.ignoreOnce = (ignored) => { - ignored._ignoreCount ++; -};