Comparar commits
14 Commits
| Autor | SHA1 | Data | |
|---|---|---|---|
| 70a6165366 | |||
| 2d7547ce79 | |||
| de381a80de | |||
| 888be5d60f | |||
| 57e6d9f7c2 | |||
| fb3d722fc8 | |||
| 2728617126 | |||
| dd7639829a | |||
| b11775ecde | |||
| f96cdd94ec | |||
| 4ce630dc4c | |||
| 8557444c55 | |||
| c2c75fe9d8 | |||
| 13d4f57003 |
+48
-1
@@ -14,6 +14,8 @@ We are proud to support all functionality of the OpenBCI 8 and 16 Channel boards
|
||||
|
||||
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:
|
||||
---
|
||||
|
||||
@@ -38,7 +40,7 @@ The purpose of this module is to **get connected** and **start streaming** as fa
|
||||
npm install openbci
|
||||
```
|
||||
### <a name="tldr"></a> TL;DR:
|
||||
Get connected and start streaming right now
|
||||
Get connected and [start streaming right now with the example code](examples/getStreaming/getStreaming.js).
|
||||
|
||||
```js
|
||||
var OpenBCIBoard = require('openbci').OpenBCIBoard;
|
||||
@@ -73,6 +75,8 @@ Still not satisfied it works?? Check out this [detailed report](http://s13234284
|
||||
|
||||
How are you still doubting and not using this already? Fine, go look at some of the [700 **_automatic_** tests](https://codecov.io/gh/OpenBCI/OpenBCI_NodeJS) written for it!
|
||||
|
||||
Python researcher or developer? Check out how easy it is to [get access to the entire API in the Python example](examples/python)!
|
||||
|
||||
### <a name="general-overview"></a> General Overview:
|
||||
|
||||
Initialization
|
||||
@@ -118,6 +122,15 @@ ourBoard.connect(k.OBCISimulatorPortName) // This will set `simulate` to true
|
||||
});
|
||||
```
|
||||
|
||||
To debug, it's amazing, do:
|
||||
|
||||
```js
|
||||
var OpenBCIBoard = require('openbci').OpenBCIBoard;
|
||||
var ourBoard = new OpenBCIBoard({
|
||||
simulate: true
|
||||
});
|
||||
```
|
||||
ps: go [checkout out the example](examples/debug/debug.js) to do it right now!
|
||||
|
||||
'ready' event
|
||||
------------
|
||||
@@ -501,6 +514,12 @@ Closes the serial port opened by [`.connect()`](#method-connect). Waits for sto
|
||||
|
||||
**_Returns_** a promise, fulfilled by a successful close of the serial port object, rejected otherwise.
|
||||
|
||||
### <a name="method-get-info"></a> .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}}
|
||||
|
||||
### <a name="method-get-settings-for-channel"></a> .getSettingsForChannel(channelNumber)
|
||||
|
||||
Gets the specified channelSettings register data from printRegisterSettings call.
|
||||
@@ -828,6 +847,34 @@ Stop logging to the SD card and close any open file. If you are not streaming wh
|
||||
|
||||
**_Returns_** resolves if the command was added to the write queue.
|
||||
|
||||
### <a name="method-set-info-for-board-type"></a> .setInfoForBoardType(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`.
|
||||
|
||||
**_Returns_** a promise, fulfilled if the command was sent to the write queue. Rejects if input is not `8` or `16`.
|
||||
|
||||
### <a name="method-set-max-channels"></a> .setMaxChannels(numberOfChannels)
|
||||
|
||||
Sends a command to the board to set the max channels. If you have a daisy attached, calling this function will re-sniff for the daisy ADS and attempt to use it.
|
||||
|
||||
**_numberOfChannels_**
|
||||
|
||||
A Number indicating the number of channels.
|
||||
|
||||
* `8` - Default number of channels.
|
||||
* `16` - Daisy number of channels.
|
||||
|
||||
**_Returns_** a promise, fulfilled if the command was sent to the write queue. Rejects if input is not `8` or `16`.
|
||||
|
||||
### <a name="method-simulator-enable"></a> .simulatorEnable()
|
||||
|
||||
To enter simulate mode. Must call [`.connect()`](#method-connect) after.
|
||||
|
||||
@@ -1,3 +1,24 @@
|
||||
# 1.4.4
|
||||
|
||||
### New Features
|
||||
* Set max number of channels for the board to use with `.setMaxChannels()` see readme.md
|
||||
* Set the core info object that drives the module with `.setInfoForBoardType()` see readme.md
|
||||
* Get info for the core obhect that drives the module with `.getInfo()` see readme.md
|
||||
|
||||
### Work In Progress
|
||||
* Bug where daisy would sometimes not be recognized which destroyed all data.
|
||||
|
||||
# 1.4.3
|
||||
|
||||
### New examples
|
||||
* Add example of node to python
|
||||
|
||||
# 1.4.2
|
||||
|
||||
### New examples
|
||||
* Add example of debug
|
||||
* Add example of get streaming
|
||||
|
||||
# 1.4.1
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
/**
|
||||
* This is an example of debugging the board. Thanks to Karl @baffo32
|
||||
* On windows you should run with PowerShell not git bash.
|
||||
* Install
|
||||
* [nodejs](https://nodejs.org/en/)
|
||||
*
|
||||
* To run:
|
||||
* change directory to this file `cd examples/debug`
|
||||
* do `npm install`
|
||||
* 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({
|
||||
debug: debug,
|
||||
verbose: verbose
|
||||
});
|
||||
|
||||
ourBoard.autoFindOpenBCIBoard().then(portName => {
|
||||
if (portName) {
|
||||
/**
|
||||
* Connect to the board with portName
|
||||
* Only works if one board is plugged in
|
||||
* i.e. ourBoard.connect(portName).....
|
||||
*/
|
||||
// Call to connect
|
||||
ourBoard.connect(portName).then(() => {
|
||||
console.log(`connected`);
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(`connect: ${err}`);
|
||||
});
|
||||
} else {
|
||||
/** Unable to auto find OpenBCI board */
|
||||
console.log('Unable to auto find OpenBCI board');
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* The board is ready to start streaming after the ready function is fired.
|
||||
*/
|
||||
var readyFunc = () => {
|
||||
// Get the sample rate after 'ready'
|
||||
sampleRate = ourBoard.sampleRate();
|
||||
if (stream) {
|
||||
ourBoard.streamStart()
|
||||
.catch(err => {
|
||||
console.log(`stream start: ${err}`);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
var sampleFunc = sample => {
|
||||
/**
|
||||
* Checkout the README.md for all other API functions.
|
||||
* We support every feature.
|
||||
* */
|
||||
};
|
||||
|
||||
// Subscribe to your functions
|
||||
ourBoard.on('ready', readyFunc);
|
||||
ourBoard.on('sample', sampleFunc);
|
||||
|
||||
|
||||
function exitHandler (options, err) {
|
||||
if (options.cleanup) {
|
||||
if (verbose) console.log('clean');
|
||||
/** Do additional clean up here */
|
||||
}
|
||||
if (err) console.log(err.stack);
|
||||
if (options.exit) {
|
||||
if (verbose) console.log('exit');
|
||||
if (stream) {
|
||||
ourBoard.streamStop().catch(console.log);
|
||||
}
|
||||
ourBoard.disconnect().catch(console.log);
|
||||
}
|
||||
}
|
||||
|
||||
if (process.platform === "win32") {
|
||||
const rl = require("readline").createInterface({
|
||||
input: process.stdin,
|
||||
output: process.stdout
|
||||
});
|
||||
|
||||
rl.on("SIGINT", function () {
|
||||
process.emit("SIGINT");
|
||||
});
|
||||
}
|
||||
|
||||
// do something when app is closing
|
||||
process.on('exit', exitHandler.bind(null, {
|
||||
cleanup: true
|
||||
}));
|
||||
|
||||
// catches ctrl+c event
|
||||
process.on('SIGINT', exitHandler.bind(null, {
|
||||
exit: true
|
||||
}));
|
||||
|
||||
// catches uncaught exceptions
|
||||
process.on('uncaughtException', exitHandler.bind(null, {
|
||||
exit: true
|
||||
}));
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"name": "debug",
|
||||
"version": "1.0.0",
|
||||
"description": "Debug example",
|
||||
"main": "debug.js",
|
||||
"scripts": {
|
||||
"start": "node debug.js",
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"keywords": [
|
||||
"debug"
|
||||
],
|
||||
"author": "AJ Keller",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"openbci": "^1.4.1"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
/**
|
||||
* This is an example from the readme.md
|
||||
* On windows you should run with PowerShell not git bash.
|
||||
* Install
|
||||
* [nodejs](https://nodejs.org/en/)
|
||||
*
|
||||
* To run:
|
||||
* change directory to this file `cd examples/debug`
|
||||
* 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
|
||||
|
||||
var OpenBCIBoard = require('openbci').OpenBCIBoard;
|
||||
var ourBoard = new OpenBCIBoard({
|
||||
debug: debug,
|
||||
verbose: verbose
|
||||
});
|
||||
|
||||
ourBoard.autoFindOpenBCIBoard().then(portName => {
|
||||
if (portName) {
|
||||
/**
|
||||
* Connect to the board with portName
|
||||
* Only works if one board is plugged in
|
||||
* i.e. ourBoard.connect(portName).....
|
||||
*/
|
||||
ourBoard.connect(portName) // Port name is a serial port name, see `.listPorts()`
|
||||
.then(() => {
|
||||
ourBoard.on('ready',() => {
|
||||
ourBoard.streamStart();
|
||||
ourBoard.on('sample',(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."
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
} else {
|
||||
/** Unable to auto find OpenBCI board */
|
||||
console.log('Unable to auto find OpenBCI board');
|
||||
}
|
||||
});
|
||||
|
||||
function exitHandler (options, err) {
|
||||
if (options.cleanup) {
|
||||
if (verbose) console.log('clean');
|
||||
/** Do additional clean up here */
|
||||
}
|
||||
if (err) console.log(err.stack);
|
||||
if (options.exit) {
|
||||
if (verbose) console.log('exit');
|
||||
ourBoard.disconnect().catch(console.log);
|
||||
}
|
||||
}
|
||||
|
||||
if (process.platform === "win32") {
|
||||
const rl = require("readline").createInterface({
|
||||
input: process.stdin,
|
||||
output: process.stdout
|
||||
});
|
||||
|
||||
rl.on("SIGINT", function () {
|
||||
process.emit("SIGINT");
|
||||
});
|
||||
}
|
||||
|
||||
// do something when app is closing
|
||||
process.on('exit', exitHandler.bind(null, {
|
||||
cleanup: true
|
||||
}));
|
||||
|
||||
// catches ctrl+c event
|
||||
process.on('SIGINT', exitHandler.bind(null, {
|
||||
exit: true
|
||||
}));
|
||||
|
||||
// catches uncaught exceptions
|
||||
process.on('uncaughtException', exitHandler.bind(null, {
|
||||
exit: true
|
||||
}));
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"name": "get-streaming",
|
||||
"version": "1.0.0",
|
||||
"description": "Get streaming example",
|
||||
"main": "getStreaming.js",
|
||||
"scripts": {
|
||||
"start": "node getStreaming.js",
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"keywords": [
|
||||
"get"
|
||||
],
|
||||
"author": "AJ Keller",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"openbci": "^1.4.1"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
import json
|
||||
import sys
|
||||
import numpy as np
|
||||
import time
|
||||
import zmq
|
||||
|
||||
|
||||
class Interface:
|
||||
def __init__(self, verbose=False):
|
||||
context = zmq.Context()
|
||||
self._socket = context.socket(zmq.PAIR)
|
||||
self._socket.connect("tcp://localhost:3004")
|
||||
|
||||
self.verbose = verbose
|
||||
|
||||
if self.verbose:
|
||||
print "Client Ready!"
|
||||
|
||||
# Send a quick message to tell node process we are up and running
|
||||
self.send(json.dumps({
|
||||
'action': 'started',
|
||||
'command': 'status',
|
||||
'message': time.time()*1000.0
|
||||
}))
|
||||
|
||||
def send(self, msg):
|
||||
"""
|
||||
Sends a message to TCP server
|
||||
:param msg: str
|
||||
A string to send to node TCP server, could be a JSON dumps...
|
||||
:return: None
|
||||
"""
|
||||
if self.verbose:
|
||||
print '<- out ' + msg
|
||||
self._socket.send(msg)
|
||||
return
|
||||
|
||||
def recv(self):
|
||||
"""
|
||||
Checks the ZeroMQ for data
|
||||
:return: str
|
||||
String of data
|
||||
"""
|
||||
return self._socket.recv()
|
||||
|
||||
|
||||
class RingBuffer(np.ndarray):
|
||||
"""A multidimensional ring buffer."""
|
||||
|
||||
def __new__(cls, input_array):
|
||||
obj = np.asarray(input_array).view(cls)
|
||||
return obj
|
||||
|
||||
def __array_finalize__(self, obj):
|
||||
if obj is None:
|
||||
return
|
||||
|
||||
def __array_wrap__(self, out_arr, context=None):
|
||||
return np.ndarray.__array_wrap__(self, out_arr, context)
|
||||
|
||||
def append(self, x):
|
||||
"""Adds element x to the ring buffer."""
|
||||
x = np.asarray(x)
|
||||
self[:, :-1] = self[:, 1:]
|
||||
self[:, -1] = x
|
||||
|
||||
|
||||
def main(argv):
|
||||
nb_chan = 8
|
||||
verbose = True
|
||||
|
||||
# Create a new python interface.
|
||||
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
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main(sys.argv[1:])
|
||||
@@ -0,0 +1,212 @@
|
||||
/**
|
||||
* This is an example from the readme.md
|
||||
* On windows you should run with PowerShell not git bash.
|
||||
* Install
|
||||
* [nodejs](https://nodejs.org/en/)
|
||||
*
|
||||
* To run:
|
||||
* change directory to this file `cd examples/debug`
|
||||
* do `npm install`
|
||||
* then `npm start`
|
||||
*/
|
||||
var OpenBCIBoard = require('openbci').OpenBCIBoard;
|
||||
var port_pub = 'tcp://127.0.0.1:3004';
|
||||
var zmq = require('zmq-prebuilt');
|
||||
var socket = zmq.socket('pair');
|
||||
var simulate = true; // 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
|
||||
});
|
||||
|
||||
var sampleRate = 250; // Default to 250, ALWAYS verify with a call to `.sampleRate()` after 'ready' event!
|
||||
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', () => {
|
||||
|
||||
// Get the sample rate after 'ready'
|
||||
sampleRate = ourBoard.sampleRate();
|
||||
// Find out if you can even time sync, you must be using v2 and this is only accurate after a `.softReset()` call which is called internally on `.connect()`. We parse the `.softReset()` response for the presence of firmware version 2 properties.
|
||||
timeSyncPossible = ourBoard.usingVersionTwoFirmware();
|
||||
|
||||
if (timeSyncPossible) {
|
||||
ourBoard.streamStart()
|
||||
.catch(err => {
|
||||
console.log(`stream start: ${err}`);
|
||||
});
|
||||
} else {
|
||||
console.log('not able to time sync');
|
||||
}
|
||||
})
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(`connect: ${err}`);
|
||||
});
|
||||
} else {
|
||||
/** Unable to auto find OpenBCI board */
|
||||
console.log('Unable to auto find OpenBCI board');
|
||||
}
|
||||
});
|
||||
|
||||
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);
|
||||
} else {
|
||||
// Retry it
|
||||
console.log(`Was not able to sync... retry!`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (sample.timeStamp) { // true after the first successful sync
|
||||
if (sample.timeStamp < 10 * 60 * 60 * 1000) { // Less than 10 hours
|
||||
console.log(`Bad time sync ${sample.timeStamp}`);
|
||||
} else {
|
||||
sendToPython({
|
||||
action: 'process',
|
||||
command: 'sample',
|
||||
message: sample
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Subscribe to your functions
|
||||
ourBoard.on('sample', sampleFunc);
|
||||
|
||||
// ZMQ fun
|
||||
|
||||
socket.bind(port_pub, function (err) {
|
||||
if (err) throw err;
|
||||
console.log(`bound to ${port_pub}`);
|
||||
});
|
||||
|
||||
/**
|
||||
* Used to send a message to the Python process.
|
||||
* @param {Object} interProcessObject The standard inter-process object.
|
||||
* @return {None}
|
||||
*/
|
||||
var sendToPython = (interProcessObject, verbose) => {
|
||||
if (verbose) {
|
||||
console.log(`<- out ${JSON.stringify(interProcessObject)}`);
|
||||
}
|
||||
if (socket) {
|
||||
socket.send(JSON.stringify(interProcessObject));
|
||||
}
|
||||
};
|
||||
|
||||
var receiveFromPython = (raw_data) => {
|
||||
try {
|
||||
let body = JSON.parse(raw_data); // five because `resp `
|
||||
processInterfaceObject(body);
|
||||
} catch (err) {
|
||||
console.log('in -> ' + 'bad json');
|
||||
}
|
||||
};
|
||||
|
||||
socket.on('message', receiveFromPython);
|
||||
|
||||
var sendStatus = () => {
|
||||
sendToPython({'action': 'active', 'message': 'ready', 'command': 'status'}, true);
|
||||
};
|
||||
|
||||
sendStatus();
|
||||
|
||||
/**
|
||||
* Process an incoming message
|
||||
* @param {String} body A stringify JSON object that shall be parsed.
|
||||
* @return {None}
|
||||
*/
|
||||
var processInterfaceObject = (body) => {
|
||||
switch (body.command) {
|
||||
case 'status':
|
||||
processStatus(body);
|
||||
break;
|
||||
default:
|
||||
unrecognizedCommand(body);
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Used to process a status related command from TCP IPC.
|
||||
* @param {Object} body
|
||||
* @return {None}
|
||||
*/
|
||||
var processStatus = (body) => {
|
||||
switch (body.action) {
|
||||
case 'started':
|
||||
console.log(`python started @ ${body.message}ms`);
|
||||
break;
|
||||
case 'alive':
|
||||
console.log(`python duplex communication test completed @ ${body.message}ms`);
|
||||
break;
|
||||
default:
|
||||
unrecognizedCommand(body);
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
function unrecognizedCommand (body) {
|
||||
console.log(`unrecognizedCommand ${body}`);
|
||||
}
|
||||
|
||||
function exitHandler (options, err) {
|
||||
if (options.cleanup) {
|
||||
if (verbose) console.log('clean');
|
||||
/** Do additional clean up here */
|
||||
}
|
||||
if (err) console.log(err.stack);
|
||||
if (options.exit) {
|
||||
if (verbose) console.log('exit');
|
||||
ourBoard.disconnect().catch(console.log);
|
||||
}
|
||||
}
|
||||
|
||||
if (process.platform === "win32") {
|
||||
const rl = require("readline").createInterface({
|
||||
input: process.stdin,
|
||||
output: process.stdout
|
||||
});
|
||||
|
||||
rl.on("SIGINT", function () {
|
||||
process.emit("SIGINT");
|
||||
});
|
||||
}
|
||||
|
||||
// do something when app is closing
|
||||
process.on('exit', exitHandler.bind(null, {
|
||||
cleanup: true
|
||||
}));
|
||||
|
||||
// catches ctrl+c event
|
||||
process.on('SIGINT', exitHandler.bind(null, {
|
||||
exit: true
|
||||
}));
|
||||
|
||||
// catches uncaught exceptions
|
||||
process.on('uncaughtException', exitHandler.bind(null, {
|
||||
exit: true
|
||||
}));
|
||||
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"name": "python",
|
||||
"version": "1.0.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",
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"keywords": [
|
||||
"python",
|
||||
"openbci",
|
||||
"node"
|
||||
],
|
||||
"author": "AJ Keller",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"openbci": "^1.4.2",
|
||||
"zmq-prebuilt": "^2.1.0"
|
||||
},
|
||||
"devEngines": {
|
||||
"node": "<=6.x",
|
||||
"npm": ">=3.x"
|
||||
},
|
||||
"devDependencies": {
|
||||
"concurrently": "^3.1.0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
# OpenBCI Node SDK to Python
|
||||
|
||||
## About
|
||||
|
||||
Written to end the struggles of python researchers and developers. ~ written with love by [Push The World!](http://www.pushtheworldllc.com)
|
||||
|
||||
This module has every feature available on the OpenBCI Board.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
* [Python 2.7](https://www.python.org/downloads/)
|
||||
* [ZeroMQ](http://zeromq.org/bindings:python)
|
||||
|
||||
```py
|
||||
pip install pyzmq
|
||||
```
|
||||
* [Node.js LTS](https://nodejs.org/en/)
|
||||
|
||||
|
||||
## Installation
|
||||
For Python 2.7 do:
|
||||
```bash
|
||||
python setup.py install
|
||||
```
|
||||
For Node:
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
## Running
|
||||
```
|
||||
npm start
|
||||
```
|
||||
For running just the node, for example if you were running the python in a separate ide and debugging, it's useful.
|
||||
```python
|
||||
npm run start-node
|
||||
```
|
||||
|
||||
## Contributing
|
||||
Please PR if you have code to contribute!
|
||||
@@ -0,0 +1,12 @@
|
||||
from setuptools import setup, find_packages
|
||||
|
||||
setup(name='openbci-node-python',
|
||||
version='0.0.1',
|
||||
description='Node to Python the right way',
|
||||
url='',
|
||||
author='AJ Keller',
|
||||
author_email='pushtheworldllc@gmail.com',
|
||||
license='MIT',
|
||||
packages=find_packages(),
|
||||
install_requires=['numpy', 'pyzmq'],
|
||||
zip_safe=False)
|
||||
@@ -29,6 +29,7 @@ ourBoard.autoFindOpenBCIBoard().then(portName => {
|
||||
});
|
||||
} else {
|
||||
/** Unable to auto find OpenBCI board */
|
||||
console.log('Unable to auto find OpenBCI board');
|
||||
}
|
||||
});
|
||||
|
||||
@@ -86,3 +87,41 @@ var sampleFunc = sample => {
|
||||
// Subscribe to your functions
|
||||
ourBoard.on('ready', readyFunc);
|
||||
ourBoard.on('sample', sampleFunc);
|
||||
|
||||
function exitHandler (options, err) {
|
||||
if (options.cleanup) {
|
||||
if (verbose) console.log('clean');
|
||||
/** Do additional clean up here */
|
||||
}
|
||||
if (err) console.log(err.stack);
|
||||
if (options.exit) {
|
||||
if (verbose) console.log('exit');
|
||||
ourBoard.disconnect().catch(console.log);
|
||||
}
|
||||
}
|
||||
|
||||
if (process.platform === "win32") {
|
||||
const rl = require("readline").createInterface({
|
||||
input: process.stdin,
|
||||
output: process.stdout
|
||||
});
|
||||
|
||||
rl.on("SIGINT", function () {
|
||||
process.emit("SIGINT");
|
||||
});
|
||||
}
|
||||
|
||||
// do something when app is closing
|
||||
process.on('exit', exitHandler.bind(null, {
|
||||
cleanup: true
|
||||
}));
|
||||
|
||||
// catches ctrl+c event
|
||||
process.on('SIGINT', exitHandler.bind(null, {
|
||||
exit: true
|
||||
}));
|
||||
|
||||
// catches uncaught exceptions
|
||||
process.on('uncaughtException', exitHandler.bind(null, {
|
||||
exit: true
|
||||
}));
|
||||
+49
-6
@@ -1012,6 +1012,53 @@ function OpenBCIFactory () {
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 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.setInfoForBoardType = function(boardType) {
|
||||
switch (boardType) {
|
||||
case k.OBCIBoardDaisy:
|
||||
this.info.boardType = k.OBCIBoardDaisy;
|
||||
this.info.numberOfChannels = k.OBCINumberOfChannelsDaisy;
|
||||
this.info.sampleRate = k.OBCISampleRate125;
|
||||
break;
|
||||
case k.OBCIBoardDefault:
|
||||
default:
|
||||
this.info.boardType = k.OBCIBoardDefault;
|
||||
this.info.numberOfChannels = k.OBCINumberOfChannelsDefault;
|
||||
this.info.sampleRate = k.OBCISampleRate250;
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Used to set the max number of channels on the Cyton board.
|
||||
* @param numberOfChannels {number}
|
||||
* Either 8 or 16
|
||||
* @return {Promise}
|
||||
*/
|
||||
OpenBCIBoard.prototype.setMaxChannels = function (numberOfChannels) {
|
||||
if (numberOfChannels === k.OBCINumberOfChannelsDefault) {
|
||||
this.curParsingMode = k.OBCIParsingEOT;
|
||||
return this.write(k.OBCIChannelMaxNumber8);
|
||||
} else if (numberOfChannels === k.OBCINumberOfChannelsDaisy) {
|
||||
this.curParsingMode = k.OBCIParsingEOT;
|
||||
return this.write(k.OBCIChannelMaxNumber16);
|
||||
} else {
|
||||
return Promise.reject('invalid number of channels');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @description Sends a soft reset command to the board
|
||||
* @returns {Promise}
|
||||
@@ -1807,13 +1854,9 @@ function OpenBCIFactory () {
|
||||
*/
|
||||
OpenBCIBoard.prototype._processParseBufferForReset = function (dataBuffer) {
|
||||
if (openBCISample.countADSPresent(dataBuffer) === 2) {
|
||||
this.info.boardType = k.OBCIBoardDaisy;
|
||||
this.info.numberOfChannels = k.OBCINumberOfChannelsDaisy;
|
||||
this.info.sampleRate = k.OBCISampleRate125;
|
||||
this.setInfoForBoardType(k.OBCIBoardDaisy);
|
||||
} else {
|
||||
this.info.boardType = k.OBCIBoardDefault;
|
||||
this.info.numberOfChannels = k.OBCINumberOfChannelsDefault;
|
||||
this.info.sampleRate = k.OBCISampleRate250;
|
||||
this.setInfoForBoardType(k.OBCIBoardDefault);
|
||||
}
|
||||
|
||||
if (openBCISample.findV2Firmware(dataBuffer)) {
|
||||
|
||||
+2
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "openbci",
|
||||
"version": "1.4.1",
|
||||
"version": "1.4.4",
|
||||
"description": "The official Node.js SDK for the OpenBCI Biosensor Board.",
|
||||
"main": "openBCIBoard",
|
||||
"scripts": {
|
||||
@@ -36,6 +36,7 @@
|
||||
"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"
|
||||
},
|
||||
|
||||
@@ -9,6 +9,7 @@ var openBCISample = openBCIBoard.OpenBCISample;
|
||||
var k = openBCISample.k;
|
||||
var chaiAsPromised = require('chai-as-promised');
|
||||
var sinonChai = require('sinon-chai');
|
||||
var sinonAsPromised = require('sinon-as-promised')(bluebirdChecks.BluebirdPromise);
|
||||
var bufferEqual = require('buffer-equal');
|
||||
var fs = require('fs');
|
||||
var math = require('mathjs');
|
||||
@@ -451,6 +452,34 @@ describe('openbci-sdk', function () {
|
||||
});
|
||||
}).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.setInfoForBoardType('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.setInfoForBoardType('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.setInfoForBoardType('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) {
|
||||
@@ -664,7 +693,7 @@ describe('openbci-sdk', function () {
|
||||
ourBoard.write(k.OBCISDLogStop).should.have.been.rejected,
|
||||
ourBoard.write(k.OBCISDLogStop).should.have.been.rejected,
|
||||
ourBoard.disconnect()
|
||||
]).then(() => {+
|
||||
]).then(() => {
|
||||
writeSpy.should.have.not.been.called;
|
||||
writeSpy.restore();
|
||||
});
|
||||
@@ -785,6 +814,38 @@ describe('openbci-sdk', function () {
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('#setMaxChannels', function () {
|
||||
before(function (done) {
|
||||
if (!ourBoard.isConnected()) {
|
||||
ourBoard.connect(masterPortName)
|
||||
.then(done)
|
||||
.catch(err => done(err));
|
||||
} else {
|
||||
done();
|
||||
}
|
||||
});
|
||||
it('should write the command to set channels to 8', function (done) {
|
||||
ourBoard.setMaxChannels(8)
|
||||
.then(() => {
|
||||
setTimeout(() => {
|
||||
spy.should.have.been.calledWith(k.OBCIChannelMaxNumber8);
|
||||
done();
|
||||
}, 5 * k.OBCIWriteIntervalDelayMSShort);
|
||||
}).catch(done);
|
||||
});
|
||||
it('should write the command to set channels to 16', function (done) {
|
||||
ourBoard.setMaxChannels(16)
|
||||
.then(() => {
|
||||
setTimeout(() => {
|
||||
spy.should.have.been.calledWith(k.OBCIChannelMaxNumber16);
|
||||
done();
|
||||
}, 5 * k.OBCIWriteIntervalDelayMSShort);
|
||||
}).catch(done);
|
||||
});
|
||||
it('should not write a command if invalid channel number', function (done) {
|
||||
ourBoard.setMaxChannels(0).should.be.rejected.and.notify(done);
|
||||
});
|
||||
});
|
||||
// bad
|
||||
describe('#channelOff', function () {
|
||||
before(function (done) {
|
||||
|
||||
Referência em uma Nova Issue
Bloquear um usuário