Skip to content

Commit 3dc48f8

Browse files
author
AJ Keller
authoredJul 14, 2017
Merge pull request #5 from aj-ptw/master
Fix packet parsing issues
2 parents a6525d5 + 406fadc commit 3dc48f8

7 files changed

+274
-121
lines changed
 

Diff for: ‎.travis.yml

+1
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,5 @@ node_js:
77
install:
88
- npm install --all
99
script:
10+
- npm run test-lint
1011
- npm run test-cov

Diff for: ‎changelog.md

+21
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,24 @@
1+
# 0.0.8
2+
3+
### New Features
4+
5+
* Sample object now has property `valid` of type `boolean`, `false` when error parseing packet, `true` otherwise. On `false` there will be another property called `error` of type `string` which contains an error message.
6+
7+
# 0.0.7
8+
9+
### Continuous Integration
10+
11+
* Add `npm run test-lint` to add linting to travis.yml
12+
13+
### Bug Fixes
14+
15+
* Last sample number was confusing to use with `transformRawDataPacketsToSample`
16+
17+
### New Features
18+
19+
* In openBCIUtilities.js add function `transformRawDataPacketToSample` to parse a single raw data packet
20+
* In openBCIConstants.js add function `rawDataToSampleObjectDefault(numChannels)` which should be used by drivers to create the object that is passed through each call to `transformRawDataPacketsToSample`
21+
122
# 0.0.6
223

324
### Bug Fixes

Diff for: ‎openBCIConstants.js

+25-4
Original file line numberDiff line numberDiff line change
@@ -486,11 +486,11 @@ const obciNobleEmitterStateChange = 'stateChange';
486486
const obciNobleStatePoweredOn = 'poweredOn';
487487

488488
/** Protocols */
489-
const obciProtocolBLE = "ble";
490-
const obciProtocolSerial = "serial";
491-
const obciProtocolWifi = "wifi";
489+
const obciProtocolBLE = 'ble';
490+
const obciProtocolSerial = 'serial';
491+
const obciProtocolWifi = 'wifi';
492492

493-
module.exports = {
493+
const constantsModule = {
494494
/** Turning channels off */
495495
OBCIChannelOff1: obciChannelOff1,
496496
OBCIChannelOff2: obciChannelOff2,
@@ -1178,11 +1178,13 @@ module.exports = {
11781178
commandSampleRateForCmdCyton,
11791179
commandSampleRateForCmdGanglion,
11801180
commandBoardModeForMode,
1181+
rawDataToSampleObjectDefault,
11811182
/** Protocols */
11821183
OBCIProtocolBLE: obciProtocolBLE,
11831184
OBCIProtocolSerial: obciProtocolSerial,
11841185
OBCIProtocolWifi: obciProtocolWifi
11851186
};
1187+
module.exports = constantsModule;
11861188

11871189
/**
11881190
* @description To add a usability abstraction layer above channel setting commands. Due to the
@@ -1528,6 +1530,25 @@ function channelSettingsObjectDefault (channelNumber) {
15281530
};
15291531
}
15301532

1533+
/**
1534+
* @description RawDataToSample default object creation
1535+
* @param numChannels {Number} - The number of channels
1536+
* @returns {RawDataToSample} - A new object
1537+
*/
1538+
function rawDataToSampleObjectDefault (numChannels) {
1539+
if (_.isUndefined(numChannels)) numChannels = obciNumberOfChannelsDefault;
1540+
return {
1541+
accelArray: [0, 0, 0],
1542+
channelSettings: constantsModule.channelSettingsArrayInit(numChannels),
1543+
lastSampleNumber: 0,
1544+
rawDataPacket: Buffer.alloc(33),
1545+
rawDataPackets: [],
1546+
scale: true,
1547+
timeOffset: 0,
1548+
verbose: false
1549+
};
1550+
}
1551+
15311552
/**
15321553
* Get's the command for sample rate Cyton
15331554
* @param sampleRate {Number} - The desired sample rate

Diff for: ‎openBCIUtilities.js

+76-54
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,17 @@ var utilitiesModule = {
2828
* @property {Array} channelData The extracted channel data
2929
* @property {Buffer} rawDataPacket The raw data packet
3030
*/
31+
/**
32+
* @typedef {Object} RawDataToSample
33+
* @property {Array} rawDataPackets - An array of rawDataPackets
34+
* @property {Buffer} rawDataPacket - A single raw data packet
35+
* @property {Array} channelSettings - The channel settings array
36+
* @property {Number} timeOffset (optional) for non time stamp use cases i.e. 0xC0 or 0xC1 (default and raw aux)
37+
* @property {Array} accelArray (optional) for non time stamp use cases
38+
* @property {Boolean} verbose (optional) for verbose output
39+
* @property {Number} lastSampleNumber (optional) - The last sample number
40+
* @property {Boolean} scale (optional) Default `true`. A gain of 24 for Cyton will be used and 51 for ganglion by default.
41+
*/
3142
/**
3243
* @description Used to extract samples out of a buffer of unknown length
3344
* @param dataBuffer {Buffer} - A buffer to parse for samples
@@ -107,6 +118,7 @@ var utilitiesModule = {
107118
};
108119
},
109120

121+
transformRawDataPacketToSample,
110122
transformRawDataPacketsToSample,
111123
getRawPacketType,
112124
getFromTimePacketAccel,
@@ -879,71 +891,71 @@ function newSyncObject () {
879891

880892
/**
881893
* @description Used transform raw data packets into fully qualified packets
882-
* @param o {Object}
883-
* @param o.rawDataPackets {Array} - An array of rawDataPackets
884-
* @param o.channelSettings {Array}
885-
* @param o.timeOffset {Number} (optional) for non time stamp use cases i.e. 0xC0 or 0xC1 (default and raw aux)
886-
* @param o.accelArray {Array} (optional) for non time stamp use cases
887-
* @param o.verbose {Boolean} (optional) for verbose output
888-
* @param o.scale {Boolean} (optional) Default `true`. A gain of 24 for Cyton will be used and 51 for ganglion by default.
894+
* @param o {RawDataToSample} - Used to hold data and configuration settings
889895
* @return {Array} samples An array of {Sample}
890896
* @author AJ Keller (@pushtheworldllc)
891897
*/
892898
function transformRawDataPacketsToSample (o) {
893899
let samples = [];
894900
for (let i = 0; i < o.rawDataPackets.length; i++) {
895-
const rawDataPacket = o.rawDataPackets[i];
896-
const packetType = getRawPacketType(rawDataPacket[k.OBCIPacketPositionStopByte]);
897-
let sample;
898-
try {
899-
switch (packetType) {
900-
case k.OBCIStreamPacketStandardAccel:
901-
sample = utilitiesModule.parsePacketStandardAccel({
902-
rawDataPacket,
903-
channelSettings: o.channelSettings,
904-
scale: o.scale
905-
});
906-
break;
907-
case k.OBCIStreamPacketStandardRawAux:
908-
sample = utilitiesModule.parsePacketStandardRawAux({
909-
rawDataPacket,
910-
channelSettings: o.channelSettings,
911-
scale: o.scale
912-
});
913-
break;
914-
case k.OBCIStreamPacketAccelTimeSyncSet:
915-
case k.OBCIStreamPacketAccelTimeSynced:
916-
sample = utilitiesModule.parsePacketTimeSyncedAccel({
917-
rawDataPacket,
918-
channelSettings: o.channelSettings,
919-
timeOffset: o.timeOffset,
920-
accelArray: o.accelArray
921-
});
922-
break;
923-
case k.OBCIStreamPacketRawAuxTimeSyncSet:
924-
case k.OBCIStreamPacketRawAuxTimeSynced:
925-
sample = utilitiesModule.parsePacketTimeSyncedRawAux({
926-
rawDataPacket,
927-
channelSettings: o.channelSettings,
928-
timeOffset: o.timeOffset
929-
});
930-
break;
931-
default:
932-
// Don't do anything if the packet is not defined
933-
break;
934-
}
935-
samples.push(sample);
936-
} catch (err) {
937-
samples.push({
938-
rawDataPacket
939-
});
940-
if (o.verbose) console.log(err);
901+
o.rawDataPacket = o.rawDataPackets[i];
902+
const sample = transformRawDataPacketToSample(o);
903+
samples.push(sample);
904+
if (sample.hasOwnProperty('sampleNumber')) {
905+
o['lastSampleNumber'] = sample.sampleNumber;
906+
} else {
907+
o['lastSampleNumber'] = o.rawDataPacket[k.OBCIPacketPositionSampleNumber];
941908
}
942909
}
943-
944910
return samples;
945911
}
946912

913+
/**
914+
* @description Used transform raw data packets into fully qualified packets
915+
* @param o {RawDataToSample} - Used to hold data and configuration settings
916+
* @return {Array} samples An array of {Sample}
917+
* @author AJ Keller (@pushtheworldllc)
918+
*/
919+
function transformRawDataPacketToSample (o) {
920+
let sample;
921+
try {
922+
const packetType = getRawPacketType(o.rawDataPacket[k.OBCIPacketPositionStopByte]);
923+
switch (packetType) {
924+
case k.OBCIStreamPacketStandardAccel:
925+
sample = utilitiesModule.parsePacketStandardAccel(o);
926+
break;
927+
case k.OBCIStreamPacketStandardRawAux:
928+
sample = utilitiesModule.parsePacketStandardRawAux(o);
929+
break;
930+
case k.OBCIStreamPacketAccelTimeSyncSet:
931+
case k.OBCIStreamPacketAccelTimeSynced:
932+
sample = utilitiesModule.parsePacketTimeSyncedAccel(o);
933+
break;
934+
case k.OBCIStreamPacketRawAuxTimeSyncSet:
935+
case k.OBCIStreamPacketRawAuxTimeSynced:
936+
sample = utilitiesModule.parsePacketTimeSyncedRawAux(o);
937+
break;
938+
default:
939+
// Don't do anything if the packet is not defined
940+
sample = {
941+
error: `bad stop byte ${o.rawDataPacket.slice(32, 33).toString('hex')}`,
942+
valid: false,
943+
rawDataPacket: o.rawDataPacket
944+
};
945+
if (o.verbose) console.log(sample.error);
946+
break;
947+
}
948+
} catch (err) {
949+
sample = {
950+
error: err,
951+
valid: false,
952+
rawDataPacket: o.rawDataPacket
953+
};
954+
if (o.verbose) console.log(err);
955+
}
956+
return sample;
957+
}
958+
947959
/**
948960
* @description This method parses a 33 byte OpenBCI V3 packet and converts to a sample object
949961
* @param o {Object} - The input object
@@ -952,6 +964,7 @@ function transformRawDataPacketsToSample (o) {
952964
* calling k.channelSettingsArrayInit(). The most important rule here is that it is
953965
* Array of objects that have key-value pair {gain:NUMBER}
954966
* @param o.scale {Boolean} - Do you want to scale the results? Default true
967+
* @param o.lastSampleNumber {Number} - The last sample number
955968
* @returns {Sample} - A sample object. NOTE: Only has accelData if this is a Z axis packet.
956969
*/
957970
function parsePacketStandardAccel (o) {
@@ -982,6 +995,8 @@ function parsePacketStandardAccel (o) {
982995
// Get the stop byte
983996
sampleObject.stopByte = o.rawDataPacket[k.OBCIPacketPositionStopByte];
984997

998+
sampleObject.valid = true;
999+
9851000
return sampleObject;
9861001
}
9871002

@@ -993,6 +1008,7 @@ function parsePacketStandardAccel (o) {
9931008
* calling k.channelSettingsArrayInit(). The most important rule here is that it is
9941009
* Array of objects that have key-value pair {gain:NUMBER}
9951010
* @param o.scale {Boolean} - Do you want to scale the results? Default is true
1011+
* @param o.lastSampleNumber {Number} - The last sample number
9961012
* @returns {Sample} - A sample object. NOTE: Only has accelData if this is a Z axis packet.
9971013
*/
9981014
function parsePacketStandardRawAux (o) {
@@ -1024,6 +1040,8 @@ function parsePacketStandardRawAux (o) {
10241040
// Get the stop byte
10251041
sampleObject.stopByte = o.rawDataPacket[k.OBCIPacketPositionStopByte];
10261042

1043+
sampleObject.valid = true;
1044+
10271045
return sampleObject;
10281046
}
10291047

@@ -1078,6 +1096,8 @@ function parsePacketTimeSyncedAccel (o) {
10781096
if (o.scale) sampleObject.channelData = getChannelDataArray(o);
10791097
else sampleObject.channelDataCounts = getChannelDataArrayNoScale(o.rawDataPacket);
10801098

1099+
sampleObject.valid = true;
1100+
10811101
return sampleObject;
10821102
}
10831103

@@ -1125,6 +1145,8 @@ function parsePacketTimeSyncedRawAux (o) {
11251145
if (o.scale) sampleObject.channelData = getChannelDataArray(o);
11261146
else sampleObject.channelDataCounts = getChannelDataArrayNoScale(o.rawDataPacket);
11271147

1148+
sampleObject.valid = true;
1149+
11281150
return sampleObject;
11291151
}
11301152

Diff for: ‎package.json

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
{
22
"name": "openbci-utilities",
3-
"version": "0.0.6",
3+
"version": "0.0.8",
44
"description": "The official utility package of Node.js SDK for the OpenBCI Biosensor Boards.",
55
"main": "index.js",
66
"scripts": {
7-
"test": "semistandard | snazzy && mocha test",
7+
"test": "mocha test",
8+
"test-lint": "semistandard | snazzy",
89
"test-cov": "istanbul cover ./node_modules/mocha/bin/_mocha -- -R spec && codecov"
910
},
1011
"keywords": [

Diff for: ‎test/openBCIConstants-test.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -969,16 +969,16 @@ describe('OpenBCIConstants', function () {
969969
});
970970
describe('Board Types', function () {
971971
it('should get right name for chan daisy', function () {
972-
expect(k.OBCIBoardDaisy).to.equal("daisy");
972+
expect(k.OBCIBoardDaisy).to.equal('daisy');
973973
});
974974
it('should get right name for chan cyton', function () {
975-
expect(k.OBCIBoardCyton).to.equal("cyton");
975+
expect(k.OBCIBoardCyton).to.equal('cyton');
976976
});
977977
it('should get right name for chan ganglion', function () {
978-
expect(k.OBCIBoardGanglion).to.equal("ganglion");
978+
expect(k.OBCIBoardGanglion).to.equal('ganglion');
979979
});
980980
it('should get right name for chan none', function () {
981-
expect(k.OBCIBoardNone).to.equal("none");
981+
expect(k.OBCIBoardNone).to.equal('none');
982982
});
983983
});
984984
describe('numberOfChannelsForBoardTypes', function () {

0 commit comments

Comments
 (0)
Please sign in to comment.