Skip to content

Commit 97d5b3a

Browse files
author
AJ Keller
authored
Merge pull request #15 from aj-ptw/development
Development
2 parents a60f4ef + b82fc27 commit 97d5b3a

File tree

4 files changed

+168
-16
lines changed

4 files changed

+168
-16
lines changed

changelog.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
# 0.2.1
2+
3+
### Bug Fixes
4+
5+
* Accel data with counts did not work for cyton with daisy. Also fixed up some test errors with the effected functions.
6+
7+
### New Features
8+
9+
* Add features for `openbci-ganglion`
10+
111
# 0.2.0
212

313
### New Feature

openBCIUtilities.js

Lines changed: 52 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ let utilitiesModule = {
141141
},
142142
transformRawDataPacketToSample,
143143
transformRawDataPacketsToSample,
144+
convertGanglionArrayToBuffer,
144145
getRawPacketType,
145146
getFromTimePacketAccel,
146147
getFromTimePacketTime,
@@ -382,6 +383,7 @@ let utilitiesModule = {
382383
}
383384
},
384385
newSample,
386+
newSampleNoScale,
385387
/**
386388
* @description Create a configurable function to return samples for a simulator. This implements 1/f filtering injection to create more brain like data.
387389
* @param numberOfChannels {Number} - The number of channels in the sample... either 8 or 16
@@ -1041,6 +1043,18 @@ function transformRawDataPacketToSample (o) {
10411043
return sample;
10421044
}
10431045

1046+
/**
1047+
* Used to convert a ganglions decompressed back into a buffer
1048+
* @param arr {Array} - An array of four numbers
1049+
* @param data {Buffer} - A buffer to store into
1050+
*/
1051+
function convertGanglionArrayToBuffer (arr, data) {
1052+
for (let i = 0; i < k.OBCINumberOfChannelsGanglion; i++) {
1053+
data.writeInt16BE(arr[i] >> 8, (i * 3));
1054+
data.writeInt8(arr[i] & 255, (i * 3) + 2);
1055+
}
1056+
}
1057+
10441058
/**
10451059
* @description This function takes a raw data buffer of 4 3-byte signed integers for ganglion
10461060
* @param o {Object} - The input object
@@ -1643,6 +1657,26 @@ function newSample (sampleNumber) {
16431657
};
16441658
}
16451659

1660+
function newSampleNoScale (sampleNumber) {
1661+
if (sampleNumber || sampleNumber === 0) {
1662+
if (sampleNumber > 255) {
1663+
sampleNumber = 255;
1664+
}
1665+
} else {
1666+
sampleNumber = 0;
1667+
}
1668+
return {
1669+
startByte: k.OBCIByteStart,
1670+
sampleNumber: sampleNumber,
1671+
channelDataCounts: [],
1672+
accelDataCounts: [],
1673+
auxData: null,
1674+
stopByte: k.OBCIByteStop,
1675+
boardTime: 0,
1676+
timestamp: 0
1677+
};
1678+
}
1679+
16461680
/**
16471681
* @description Convert float number into three byte buffer. This is the opposite of .interpret24bitAsInt32()
16481682
* @param float - The number you want to convert
@@ -1705,34 +1739,42 @@ function makeDaisySampleObject (lowerSampleObject, upperSampleObject) {
17051739
let daisySampleObject = {};
17061740

17071741
if (lowerSampleObject.hasOwnProperty('channelData')) {
1708-
daisySampleObject['channelData'] = lowerSampleObject.channelData.concat(upperSampleObject.channelData);
1742+
daisySampleObject.channelData = lowerSampleObject.channelData.concat(upperSampleObject.channelData);
17091743
}
17101744

17111745
if (lowerSampleObject.hasOwnProperty('channelDataCounts')) {
1712-
daisySampleObject['channelDataCounts'] = lowerSampleObject.channelDataCounts.concat(upperSampleObject.channelDataCounts);
1746+
daisySampleObject.channelDataCounts = lowerSampleObject.channelDataCounts.concat(upperSampleObject.channelDataCounts);
17131747
}
17141748

1715-
daisySampleObject['sampleNumber'] = Math.floor(upperSampleObject.sampleNumber / 2);
1749+
daisySampleObject.sampleNumber = Math.floor(upperSampleObject.sampleNumber / 2);
17161750

1717-
daisySampleObject['auxData'] = {
1751+
daisySampleObject.auxData = {
17181752
'lower': lowerSampleObject.auxData,
17191753
'upper': upperSampleObject.auxData
17201754
};
17211755

1722-
daisySampleObject['timestamp'] = (lowerSampleObject.timestamp + upperSampleObject.timestamp) / 2;
1756+
daisySampleObject.timestamp = (lowerSampleObject.timestamp + upperSampleObject.timestamp) / 2;
17231757

17241758
daisySampleObject['_timestamps'] = {
17251759
'lower': lowerSampleObject.timestamp,
17261760
'upper': upperSampleObject.timestamp
17271761
};
17281762

1729-
if (lowerSampleObject.accelData) {
1730-
daisySampleObject['accelData'] = lowerSampleObject.accelData;
1731-
} else if (upperSampleObject.accelData) {
1732-
daisySampleObject['accelData'] = upperSampleObject.accelData;
1763+
if (lowerSampleObject.hasOwnProperty('accelData')) {
1764+
if (lowerSampleObject.accelData[0] > 0 || lowerSampleObject.accelData[1] > 0 || lowerSampleObject.accelData[2] > 0) {
1765+
daisySampleObject.accelData = lowerSampleObject.accelData;
1766+
} else {
1767+
daisySampleObject.accelData = upperSampleObject.accelData;
1768+
}
1769+
} else if (lowerSampleObject.hasOwnProperty('accelDataCounts')) {
1770+
if (lowerSampleObject.accelDataCounts[0] > 0 || lowerSampleObject.accelDataCounts[1] > 0 || lowerSampleObject.accelDataCounts[2] > 0) {
1771+
daisySampleObject.accelDataCounts = lowerSampleObject.accelDataCounts;
1772+
} else {
1773+
daisySampleObject.accelDataCounts = upperSampleObject.accelDataCounts;
1774+
}
17331775
}
17341776

1735-
daisySampleObject['valid'] = true;
1777+
daisySampleObject.valid = true;
17361778

17371779
return daisySampleObject;
17381780
}

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "openbci-utilities",
3-
"version": "0.2.0",
3+
"version": "0.2.1",
44
"description": "The official utility package of Node.js SDK for the OpenBCI Biosensor Boards.",
55
"main": "index.js",
66
"scripts": {

test/openBCIUtilities-test.js

Lines changed: 105 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,83 @@ describe('openBCIUtilities', function () {
3737
accelArray = [0, 0, 0];
3838
});
3939
afterEach(() => bluebirdChecks.noPendingPromises());
40+
describe('#convertGanglionArrayToBuffer', function () {
41+
it('should fill the packet with values from data', function () {
42+
const numChannels = k.numberOfChannelsForBoardType(k.OBCIBoardGanglion);
43+
let arr = [0, 1, 2, 3];
44+
let rawDataPacket = k.rawDataToSampleObjectDefault(numChannels).rawDataPacket;
45+
rawDataPacket.fill(0); // fill with zeros
46+
let data = Buffer.alloc(k.OBCIPacketSizeBLERaw);
47+
openBCIUtilities.convertGanglionArrayToBuffer(arr, data);
48+
const sampleNumber = 23;
49+
openBCIUtilities.ganglionFillRawDataPacket({
50+
data,
51+
rawDataPacket,
52+
sampleNumber
53+
});
54+
expect(bufferEqual(rawDataPacket.slice(2, 2 + k.OBCIPacketSizeBLERaw), data), `expected ${data.toString('hex')} but got ${rawDataPacket.slice(2, 2 + k.OBCIPacketSizeBLERaw).toString('hex')}`).to.be.true();
55+
expect(rawDataPacket[k.OBCIPacketPositionSampleNumber]).to.equal(sampleNumber);
56+
expect(rawDataPacket[k.OBCIPacketPositionStartByte]).to.equal(k.OBCIByteStart);
57+
expect(rawDataPacket[k.OBCIPacketPositionStopByte]).to.equal(k.OBCIStreamPacketStandardRawAux);
58+
});
59+
describe('#errorConditions', function () {
60+
it('send undefined data buffer', function () {
61+
expect(openBCIUtilities.ganglionFillRawDataPacket.bind(openBCIUtilities, {
62+
rawDataPacket: Buffer.alloc(k.OBCIPacketSize),
63+
sampleNumber: 0
64+
})).to.throw(k.OBCIErrorUndefinedOrNullInput);
65+
});
66+
it('send null data buffer', function () {
67+
expect(openBCIUtilities.ganglionFillRawDataPacket.bind(openBCIUtilities, {
68+
data: null,
69+
rawDataPacket: Buffer.alloc(k.OBCIPacketSize),
70+
sampleNumber: 0
71+
})).to.throw(k.OBCIErrorUndefinedOrNullInput);
72+
});
73+
it('send undefined rawDataPacket buffer', function () {
74+
expect(openBCIUtilities.ganglionFillRawDataPacket.bind(openBCIUtilities, {
75+
data: Buffer.alloc(k.OBCIPacketSizeBLERaw),
76+
sampleNumber: 0
77+
})).to.throw(k.OBCIErrorUndefinedOrNullInput);
78+
});
79+
it('send null rawDataPacket buffer', function () {
80+
expect(openBCIUtilities.ganglionFillRawDataPacket.bind(openBCIUtilities, {
81+
data: Buffer.alloc(k.OBCIPacketSizeBLERaw),
82+
rawDataPacket: null,
83+
sampleNumber: 0
84+
})).to.throw(k.OBCIErrorUndefinedOrNullInput);
85+
});
86+
it('no sample number', function () {
87+
expect(openBCIUtilities.ganglionFillRawDataPacket.bind(openBCIUtilities, {
88+
data: Buffer.alloc(k.OBCIPacketSizeBLERaw),
89+
rawDataPacket: Buffer.alloc(k.OBCIPacketSize)
90+
})).to.throw(k.OBCIErrorUndefinedOrNullInput);
91+
});
92+
it('wrong number of bytes rawDataPacket', function () {
93+
expect(openBCIUtilities.ganglionFillRawDataPacket.bind(openBCIUtilities, {
94+
data: Buffer.alloc(k.OBCIPacketSizeBLERaw),
95+
rawDataPacket: Buffer.alloc(5),
96+
sampleNumber: 0
97+
})).to.throw(k.OBCIErrorInvalidByteLength);
98+
});
99+
it('wrong number of bytes data', function () {
100+
expect(openBCIUtilities.ganglionFillRawDataPacket.bind(openBCIUtilities, {
101+
data: Buffer.alloc(5),
102+
rawDataPacket: Buffer.alloc(k.OBCIPacketSize),
103+
sampleNumber: 0
104+
})).to.throw(k.OBCIErrorInvalidByteLength);
105+
});
106+
it('undefined', function () {
107+
expect(openBCIUtilities.ganglionFillRawDataPacket.bind(openBCIUtilities)).to.throw(k.OBCIErrorUndefinedOrNullInput);
108+
expect(openBCIUtilities.ganglionFillRawDataPacket.bind(openBCIUtilities), {
109+
rawDataPacket: Buffer.alloc(k.OBCIPacketSize)
110+
}).to.throw(k.OBCIErrorUndefinedOrNullInput);
111+
expect(openBCIUtilities.ganglionFillRawDataPacket.bind(openBCIUtilities), {
112+
data: Buffer.alloc(k.OBCIPacketSizeBLERaw)
113+
}).to.throw(k.OBCIErrorUndefinedOrNullInput);
114+
});
115+
});
116+
});
40117
describe('#ganglionFillRawDataPacket', function () {
41118
it('should fill the packet with values from data', function () {
42119
const numChannels = k.numberOfChannelsForBoardType(k.OBCIBoardGanglion);
@@ -1444,24 +1521,26 @@ describe('openBCIUtilities', function () {
14441521
lowerSampleObject = openBCIUtilities.newSample(1);
14451522
lowerSampleObject.channelData = [1, 2, 3, 4, 5, 6, 7, 8];
14461523
lowerSampleObject.auxData = [0, 1, 2];
1524+
lowerSampleObject.accelData = [0, 0, 0];
14471525
lowerSampleObject.timestamp = 4;
1448-
lowerSampleObject.accelData = [0.5, -0.5, 1];
14491526
// Make the upper sample (channels 9-16)
14501527
upperSampleObject = openBCIUtilities.newSample(2);
14511528
upperSampleObject.channelData = [9, 10, 11, 12, 13, 14, 15, 16];
14521529
upperSampleObject.auxData = [3, 4, 5];
1530+
upperSampleObject.accelData = [0, 1, 2];
14531531
upperSampleObject.timestamp = 8;
14541532

14551533
daisySampleObject = openBCIUtilities.makeDaisySampleObject(lowerSampleObject, upperSampleObject);
14561534

1457-
lowerSampleObjectNoScale = openBCIUtilities.newSample(1);
1535+
lowerSampleObjectNoScale = openBCIUtilities.newSampleNoScale(1);
14581536
lowerSampleObjectNoScale.channelDataCounts = [1, 2, 3, 4, 5, 6, 7, 8];
1537+
lowerSampleObjectNoScale.accelDataCounts = [0, 0, 0];
14591538
lowerSampleObjectNoScale.auxData = [0, 1, 2];
14601539
lowerSampleObjectNoScale.timestamp = 4;
1461-
lowerSampleObjectNoScale.accelData = [0.5, -0.5, 1];
14621540
// Make the upper sample (channels 9-16)
1463-
upperSampleObjectNoScale = openBCIUtilities.newSample(2);
1541+
upperSampleObjectNoScale = openBCIUtilities.newSampleNoScale(2);
14641542
upperSampleObjectNoScale.channelDataCounts = [9, 10, 11, 12, 13, 14, 15, 16];
1543+
upperSampleObjectNoScale.accelDataCounts = [0, 1, 2];
14651544
upperSampleObjectNoScale.auxData = [3, 4, 5];
14661545
upperSampleObjectNoScale.timestamp = 8;
14671546

@@ -1513,7 +1592,28 @@ describe('openBCIUtilities', function () {
15131592
});
15141593
it('should store an accelerometer value if present', function () {
15151594
expect(daisySampleObject).to.have.property('accelData');
1516-
expect(daisySampleObjectNoScale).to.have.property('accelData');
1595+
expect(daisySampleObject.accelData).to.deep.equal([0, 1, 2]);
1596+
expect(daisySampleObjectNoScale).to.have.property('accelDataCounts');
1597+
expect(daisySampleObjectNoScale.accelDataCounts).to.deep.equal([0, 1, 2]);
1598+
});
1599+
it('should work for all accel cases to extract the non-zero values', function () {
1600+
let lowerSample = openBCIUtilities.newSample(1);
1601+
lowerSample.accelData = [0, 1, 2];
1602+
let upperSample = openBCIUtilities.newSample(2);
1603+
upperSample.accelData = [0, 0, 0];
1604+
1605+
let lowerSampleNoScale = openBCIUtilities.newSampleNoScale(1);
1606+
lowerSampleNoScale.accelDataCounts = [0, 1, 2];
1607+
let upperSampleNoScale = openBCIUtilities.newSampleNoScale(2);
1608+
upperSampleNoScale.accelDataCounts = [0, 0, 0];
1609+
1610+
// Call the function under test
1611+
let daisySample = openBCIUtilities.makeDaisySampleObject(lowerSample, upperSample);
1612+
let daisySampleNoScale = openBCIUtilities.makeDaisySampleObject(lowerSampleNoScale, upperSampleNoScale);
1613+
expect(daisySample).to.have.property('accelData');
1614+
expect(daisySample.accelData).to.deep.equal([0, 1, 2]);
1615+
expect(daisySampleNoScale).to.have.property('accelDataCounts');
1616+
expect(daisySampleNoScale.accelDataCounts).to.deep.equal([0, 1, 2]);
15171617
});
15181618
});
15191619
describe('#makeDaisySampleObjectWifi', function () {

0 commit comments

Comments
 (0)