Skip to content

Commit 176414f

Browse files
committed
Send MSBs instead of using delta compression
1 parent 4e19bd3 commit 176414f

3 files changed

Lines changed: 135 additions & 140 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@
22
.DS_Store
33
.metadata/
44
RemoteSystemsTempFiles/
5+
.vscode/

OpenBCI_Ganglion_Library.cpp

Lines changed: 121 additions & 132 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ void OpenBCI_Ganglion::initialize() {
4848
Serial.begin(115200);
4949
} else {
5050
Serial.begin(9600);
51-
SimbleeBLE.advertisementData = "Ganglion 1";
51+
SimbleeBLE.advertisementData = "Ganglion";
5252
SimbleeBLE.begin();
5353
SimbleeBLE.txPowerLevel = +4;
5454
}
@@ -60,14 +60,14 @@ void OpenBCI_Ganglion::initialize() {
6060
void OpenBCI_Ganglion::makeUniqueId() {
6161
uint64_t id = getDeviceId();
6262
String stringy = String(getDeviceIdLow(), HEX);
63-
advdata[11] = (uint8_t)stringy.charAt(0);
64-
advdata[12] = (uint8_t)stringy.charAt(1);
65-
advdata[13] = (uint8_t)stringy.charAt(2);
66-
advdata[14] = (uint8_t)stringy.charAt(3);
63+
advdata[16] = (uint8_t)stringy.charAt(0);
64+
advdata[17] = (uint8_t)stringy.charAt(1);
65+
advdata[18] = (uint8_t)stringy.charAt(2);
66+
advdata[19] = (uint8_t)stringy.charAt(3);
6767
SimbleeBLE.manufacturerName = "openbci.com";
6868
SimbleeBLE.modelNumber = "Ganglion";
6969
SimbleeBLE.hardwareRevision = "1.0.1";
70-
SimbleeBLE.softwareRevision = "2.0.1";
70+
SimbleeBLE.softwareRevision = "3.0.0";
7171
}
7272

7373
void OpenBCI_Ganglion::blinkLED() {
@@ -149,7 +149,10 @@ boolean OpenBCI_Ganglion::startRunning(void) {
149149

150150
void OpenBCI_Ganglion::processData() {
151151
MCP_dataReady = false;
152-
if(sampleCounter >= 201){ sampleCounter = 0; }
152+
if(sampleCounter > 200){
153+
sampleCounter = 0;
154+
ringBufferLevel = 0;
155+
}
153156
if (wifi.present && wifi.tx) {
154157
if (useAccel){
155158
wifi.storeByteBufTx(PCKT_END | PACKET_TYPE_ACCEL);
@@ -171,25 +174,19 @@ void OpenBCI_Ganglion::processData() {
171174
return;
172175
}
173176

174-
if (sampleCounter == 0) {
175-
buildRawPacket(); // assemble raw packet on sampleCounter roll-over
176-
sendRawPacket(); // send raw sample packet
177+
if(useAccel == true){
178+
if(accelOnEdge == true){
179+
accelOnEdge = false;
180+
if(sampleCounter%2 == 0){ compressData19(); return; }
181+
}
182+
compressData18(); // compress deltas and send on even samples
177183
} else {
178-
if(useAccel == true){
179-
if(accelOnEdge == true){
180-
accelOnEdge = false;
181-
if(sampleCounter%2 == 0){ compressData19(); return; }
182-
}
183-
compressData18(); // compress deltas and send on even samples
184-
} else {
185-
if(accelOffEdge == true){
186-
accelOffEdge = false;
187-
if(sampleCounter%2 == 0){ compressData18(); return; }
188-
}
189-
compressData19(); // compress deltas and send on even samples
184+
if(accelOffEdge == true){
185+
accelOffEdge = false;
186+
if(sampleCounter%2 == 0){ compressData18(); return; }
190187
}
188+
compressData19(); // compress deltas and send on even samples
191189
}
192-
193190
}
194191

195192
boolean OpenBCI_Ganglion::stopRunning(void) {
@@ -202,8 +199,6 @@ boolean OpenBCI_Ganglion::stopRunning(void) {
202199
return is_running;
203200
}
204201

205-
206-
207202
int OpenBCI_Ganglion::changeChannelState_maintainRunningState(int chan, int start) {
208203
boolean was_running_when_called = is_running;
209204
//must stop running to turn channel on/off
@@ -252,76 +247,57 @@ void OpenBCI_Ganglion::incrementSyntheticChannelData() {
252247
}
253248
}
254249

255-
void OpenBCI_Ganglion::buildRawPacket() {
256-
int byteCounter = 0;
257-
ringBufferLevel = 0;
258-
for (int i = 0; i < 4; i++) {
259-
for (int j = 16; j >= 0; j -= 8) { // fill the raw data array for streaming
260-
compression_ring[ringBufferLevel][byteCounter] = ((channelData[i] >> j) & 0xFF);
261-
byteCounter++;
262-
}
263-
lastChannelData[i] = channelData[i]; // keep track of the previous value
264-
}
265-
}
266-
267-
268-
void OpenBCI_Ganglion::sendRawPacket() {
269-
radioBuffer[0] = ringBufferLevel;
270-
for (int i = 0; i < 12; i++) {
271-
radioBuffer[i + 1] = compression_ring[ringBufferLevel][i];
250+
/*
251+
Send two samples in one packet by truncating the data to the MSBs.
252+
Each sample is a signed 24 bit integer, but is stored in a 32 bit integer.
253+
This means that only the 32nd (sign) and 1st-23rd bits have data.
254+
Truncate the 24 bit integer to 18 bits by removing the 6 LSBs.
255+
Move the sign bit to the new LSB place.
256+
Now the sample is in bits 1-18 where the first bit is the sign bit.
257+
Align the 2 samples x 4 channel x 18 bit samples into 18 bytes.
258+
*/
259+
void OpenBCI_Ganglion::compressData18()
260+
{
261+
bool even = (sampleCounter % 2) == 0;
262+
for (int i = 0; i < 4; i++)
263+
{
264+
bitWrite(channelData[i], 6, (bitRead(channelData[i], 31))); // Store the sign bit in bit 6
265+
channelData[i] = channelData[i] >> 6; // Then align the data to bits 1-18
272266
}
273-
for (char c = 0; c < 7; c++) {
274-
radioBuffer[c + 13] = c + 'A'; // padding
267+
if (even)
268+
{
269+
// Pack even samples first
270+
compression_ring[ringBufferLevel][0] = ((channelData[0] & 0x0003FC00) >> 10);
271+
compression_ring[ringBufferLevel][1] = ((channelData[0] & 0x000003FC) >> 2);
272+
compression_ring[ringBufferLevel][2] = ((channelData[0] & 0x00000003) << 6);
273+
compression_ring[ringBufferLevel][2] |= ((channelData[1] & 0x0003F000) >> 12);
274+
compression_ring[ringBufferLevel][3] = ((channelData[1] & 0x00000FF0) >> 4);
275+
compression_ring[ringBufferLevel][4] = ((channelData[1] & 0x0000000F) << 4);
276+
compression_ring[ringBufferLevel][4] |= ((channelData[2] & 0x0003C000) >> 14);
277+
compression_ring[ringBufferLevel][5] = ((channelData[2] & 0x00003FC0) >> 6);
278+
compression_ring[ringBufferLevel][6] = ((channelData[2] & 0x0000003F) << 2);
279+
compression_ring[ringBufferLevel][6] |= ((channelData[3] & 0x00030000) >> 16);
280+
compression_ring[ringBufferLevel][7] = ((channelData[3] & 0x0000FF00) >> 8);
281+
compression_ring[ringBufferLevel][8] = ((channelData[3] & 0x000000FF));
275282
}
276-
ringBufferLevel++;
283+
else
284+
{
285+
// Pack odd samples second
286+
compression_ring[ringBufferLevel][9] = ((channelData[0] & 0x0003FC00) >> 10);
287+
compression_ring[ringBufferLevel][10] = ((channelData[0] & 0x000003FC) >> 2);
288+
compression_ring[ringBufferLevel][11] = ((channelData[0] & 0x00000003) << 6);
289+
compression_ring[ringBufferLevel][11] |= ((channelData[1] & 0x0003F000) >> 12);
290+
compression_ring[ringBufferLevel][12] = ((channelData[1] & 0x00000FF0) >> 4);
291+
compression_ring[ringBufferLevel][13] = ((channelData[1] & 0x0000000F) << 4);
292+
compression_ring[ringBufferLevel][13] |= ((channelData[2] & 0x0003C000) >> 14);
293+
compression_ring[ringBufferLevel][14] = ((channelData[2] & 0x00003FC0) >> 6);
294+
compression_ring[ringBufferLevel][15] = ((channelData[2] & 0x0000003F) << 2);
295+
compression_ring[ringBufferLevel][16] |= ((channelData[3] & 0x00030000) >> 16);
296+
compression_ring[ringBufferLevel][16] = ((channelData[3] & 0x0000FF00) >> 8);
297+
compression_ring[ringBufferLevel][17] = ((channelData[3] & 0x000000FF));
277298

278-
if (BLEconnected) {
279-
SimbleeBLE.send(radioBuffer, 20);
280-
}
281-
}
282-
/*
283-
send two samples in one packet by compressing the data
284-
first, take the delta between the current sample and the last sample
285-
then, retain the sign of the delta by moving it to bit 0
286-
then, only send the LSBs
287-
this function crams the data into a BLE packet
288-
*/
289-
void OpenBCI_Ganglion::compressData18() {
290-
int deltas[4];
291-
int even = sampleCounter % 2;
292-
for (int i = 0; i < 4; i++) {
293-
deltas[i] = lastChannelData[i] - channelData[i]; // subtract new from old
294-
lastChannelData[i] = channelData[i]; // keep track of the previous value
295-
bitWrite(deltas[i], 0, (bitRead(deltas[i], 31))); // store the sign bit in bit0
296-
}
297-
if (even == 1) { // pack odd samples first
298-
compression_ring[ringBufferLevel][0] = ((deltas[0] & 0x0003FC00) >> 10);
299-
compression_ring[ringBufferLevel][1] = ((deltas[0] & 0x000003FC) >> 2);
300-
compression_ring[ringBufferLevel][2] = ((deltas[0] & 0x00000003) << 6);
301-
compression_ring[ringBufferLevel][2] |= ((deltas[1] & 0x0003F000) >> 12);
302-
compression_ring[ringBufferLevel][3] = ((deltas[1] & 0x00000FF0) >> 4);
303-
compression_ring[ringBufferLevel][4] = ((deltas[1] & 0x0000000F) << 4);
304-
compression_ring[ringBufferLevel][4] |= ((deltas[2] & 0x0003C000) >> 14);
305-
compression_ring[ringBufferLevel][5] = ((deltas[2] & 0x00003FC0) >> 6);
306-
compression_ring[ringBufferLevel][6] = ((deltas[2] & 0x0000003F) << 2);
307-
compression_ring[ringBufferLevel][6] |= ((deltas[3] & 0x00030000) >> 16);
308-
compression_ring[ringBufferLevel][7] = ((deltas[3] & 0x0000FF00) >> 8);
309-
compression_ring[ringBufferLevel][8] = (deltas[3] & 0x000000FF);
310-
} else { // pack even samples second
311-
compression_ring[ringBufferLevel][9] = ((deltas[0] & 0x0003FC00) >> 10);
312-
compression_ring[ringBufferLevel][10] = ((deltas[0] & 0x000003FC) >> 2);
313-
compression_ring[ringBufferLevel][11] = ((deltas[0] & 0x00000003) << 6);
314-
compression_ring[ringBufferLevel][11] |= ((deltas[1] & 0x0003F000) >> 12);
315-
compression_ring[ringBufferLevel][12] = ((deltas[1] & 0x00000FF0) >> 4);
316-
compression_ring[ringBufferLevel][13] = ((deltas[1] & 0x0000000F) << 4);
317-
compression_ring[ringBufferLevel][13] |= ((deltas[2] & 0x0003C000) >> 14);
318-
compression_ring[ringBufferLevel][14] = ((deltas[2] & 0x00003FC0) >> 6);
319-
compression_ring[ringBufferLevel][15] = ((deltas[2] & 0x0000003F) << 2);
320-
compression_ring[ringBufferLevel][15] |= ((deltas[3] & 0x00030000) >> 16);
321-
compression_ring[ringBufferLevel][16] = ((deltas[3] & 0x0000FF00) >> 8);
322-
compression_ring[ringBufferLevel][17] = (deltas[3] & 0x000000FF);
323-
324-
sendCompressedPacket18(); // send on the even packet
299+
// Send on the even packet
300+
sendCompressedPacket18();
325301
}
326302
}
327303

@@ -346,49 +322,62 @@ void OpenBCI_Ganglion::sendCompressedPacket18() {
346322
}
347323

348324

349-
void OpenBCI_Ganglion::compressData19() {
350-
int deltas[4];
351-
int even = sampleCounter % 2;
352-
for (int i = 0; i < 4; i++) {
353-
deltas[i] = lastChannelData[i] - channelData[i]; // subtract new from old
354-
lastChannelData[i] = channelData[i]; // keep track of the previous value
355-
bitWrite(deltas[i], 0, (bitRead(deltas[i], 31))); // store the sign bit in bit0
356-
}
357-
if (even == 1) { // pack odd samples first
358-
compression_ring[ringBufferLevel][0] = ((deltas[0] & 0x0007F800) >> 11);
359-
compression_ring[ringBufferLevel][1] = ((deltas[0] & 0x000007F8) >> 3);
360-
compression_ring[ringBufferLevel][2] = ((deltas[0] & 0x00000007) << 5);
361-
compression_ring[ringBufferLevel][2] |= ((deltas[1] & 0x0007C000) >> 14);
362-
compression_ring[ringBufferLevel][3] = ((deltas[1] & 0x00003FC0) >> 6);
363-
compression_ring[ringBufferLevel][4] = ((deltas[1] & 0x0000003F) << 2);
364-
compression_ring[ringBufferLevel][4] |= ((deltas[2] & 0x00060000) >> 17);
365-
compression_ring[ringBufferLevel][5] = ((deltas[2] & 0x0001FE00) >> 9);
366-
compression_ring[ringBufferLevel][6] = ((deltas[2] & 0x000001FE) >> 1);
367-
compression_ring[ringBufferLevel][7] = ((deltas[2] & 00000001) << 7);
368-
compression_ring[ringBufferLevel][7] |= ((deltas[3] & 0x0007F000) >> 12);
369-
compression_ring[ringBufferLevel][8] = ((deltas[3] & 0x00000FF0) >> 4);
370-
compression_ring[ringBufferLevel][9] = ((deltas[3] & 0x0000000F) << 4);
371-
} else { // pack even samples second
372-
compression_ring[ringBufferLevel][9] |= ((deltas[0] & 0x00078000) >> 15);
373-
compression_ring[ringBufferLevel][10] = ((deltas[0] & 0x00007F80) >> 7);
374-
compression_ring[ringBufferLevel][11] = ((deltas[0] & 0x0000007F) << 1);
375-
compression_ring[ringBufferLevel][11] |= ((deltas[1] & 0x00040000) >> 18);
376-
compression_ring[ringBufferLevel][12] = ((deltas[1] & 0x0003FC00) >> 10);
377-
compression_ring[ringBufferLevel][13] = ((deltas[1] & 0x000003FC) >> 2);
378-
compression_ring[ringBufferLevel][14] = ((deltas[1] & 0x00000003) << 6);
379-
compression_ring[ringBufferLevel][14] |= ((deltas[2] & 0x0007E000) >> 13);
380-
compression_ring[ringBufferLevel][15] = ((deltas[2] & 0x00001FE0) >> 5);
381-
compression_ring[ringBufferLevel][16] = ((deltas[2] & 0x0000001F) << 3);
382-
compression_ring[ringBufferLevel][16] |= ((deltas[3] & 0x00070000) >> 16);
383-
compression_ring[ringBufferLevel][17] = ((deltas[3] & 0x0000FF00) >> 8);
384-
compression_ring[ringBufferLevel][18] = (deltas[3] & 0x000000FF);
385-
386-
sendCompressedPacket19(); // send on the even packet
325+
/*
326+
Send two samples in one packet by truncating the data to the MSBs.
327+
Each sample is a signed 24 bit integer, but is stored in a 32 bit integer.
328+
This means that only the 32nd (sign) and 1st-23rd bits have data.
329+
Truncate the 24 bit integer to 19 bits by removing the 5 LSBs.
330+
Move the sign bit to the new LSB place.
331+
Now the sample is in bits 1-19 where the first bit is the sign bit.
332+
Align the 2 samples x 4 channel x 19 bit samples into 19 bytes.
333+
*/
334+
void OpenBCI_Ganglion::compressData19()
335+
{
336+
bool even = (sampleCounter % 2) == 0;
337+
for (int i = 0; i < 4; i++)
338+
{
339+
bitWrite(channelData[i], 5, (bitRead(channelData[i], 31))); // Store the sign bit in bit 5
340+
channelData[i] = channelData[i] >> 5; // Then align the data to bits 1-19
341+
}
342+
if (even)
343+
{
344+
// Pack even samples first
345+
compression_ring[ringBufferLevel][0] = ((channelData[0] & 0x0007F800) >> 11);
346+
compression_ring[ringBufferLevel][1] = ((channelData[0] & 0x000007F8) >> 3);
347+
compression_ring[ringBufferLevel][2] = ((channelData[0] & 0x00000007) << 5);
348+
compression_ring[ringBufferLevel][2] |= ((channelData[1] & 0x0007C000) >> 14);
349+
compression_ring[ringBufferLevel][3] = ((channelData[1] & 0x00003FC0) >> 6);
350+
compression_ring[ringBufferLevel][4] = ((channelData[1] & 0x0000003F) << 2);
351+
compression_ring[ringBufferLevel][4] |= ((channelData[2] & 0x00060000) >> 17);
352+
compression_ring[ringBufferLevel][5] = ((channelData[2] & 0x0001FE00) >> 9);
353+
compression_ring[ringBufferLevel][6] = ((channelData[2] & 0x000001FE) >> 1);
354+
compression_ring[ringBufferLevel][7] = ((channelData[2] & 0x00000001) << 7);
355+
compression_ring[ringBufferLevel][7] |= ((channelData[3] & 0x0007F000) >> 12);
356+
compression_ring[ringBufferLevel][8] = ((channelData[3] & 0x00000FF0) >> 4);
357+
compression_ring[ringBufferLevel][9] = ((channelData[3] & 0x0000000F) << 4);
358+
}
359+
else
360+
{
361+
// Pack odd samples second
362+
compression_ring[ringBufferLevel][9] |= ((channelData[0] & 0x00078000) >> 15);
363+
compression_ring[ringBufferLevel][10] = ((channelData[0] & 0x00007F80) >> 7);
364+
compression_ring[ringBufferLevel][11] = ((channelData[0] & 0x0000007F) << 1);
365+
compression_ring[ringBufferLevel][11] |= ((channelData[1] & 0x00040000) >> 18);
366+
compression_ring[ringBufferLevel][12] = ((channelData[1] & 0x0003FC00) >> 10);
367+
compression_ring[ringBufferLevel][13] = ((channelData[1] & 0x000003FC) >> 2);
368+
compression_ring[ringBufferLevel][14] = ((channelData[1] & 0x00000003) << 6);
369+
compression_ring[ringBufferLevel][14] |= ((channelData[2] & 0x0007E000) >> 13);
370+
compression_ring[ringBufferLevel][15] = ((channelData[2] & 0x00001FE0) >> 5);
371+
compression_ring[ringBufferLevel][16] = ((channelData[2] & 0x0000001F) << 3);
372+
compression_ring[ringBufferLevel][16] |= ((channelData[3] & 0x00070000) >> 16);
373+
compression_ring[ringBufferLevel][17] = ((channelData[3] & 0x0000FF00) >> 8);
374+
compression_ring[ringBufferLevel][18] = ((channelData[3] & 0x000000FF));
375+
376+
// Send on the even packet
377+
sendCompressedPacket19();
387378
}
388379
}
389380

390-
391-
392381
void OpenBCI_Ganglion::sendCompressedPacket19() {
393382
radioBuffer[0] = ringBufferLevel + 100;
394383
for (int i = 0; i < 19; i++) {

OpenBCI_Ganglion_Library.h

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -123,9 +123,9 @@ class OpenBCI_Ganglion {
123123

124124
boolean settingSampleRate = false;
125125

126-
uint8_t advdata[15] =
126+
uint8_t advdata[21] =
127127
{
128-
14, // length // 0
128+
20, // length // 0
129129
0x09, // complete local name type // 1
130130
0x47, // 'G' // 2
131131
0x61, // 'a' // 3
@@ -135,11 +135,17 @@ class OpenBCI_Ganglion {
135135
0x69, // 'i' // 7
136136
0x6F, // 'o' // 8
137137
0x6E, // 'n' // 9
138-
0x2D, // '-' // 10
139-
0x54, // 'T' // 11
140-
0x41, // 'A' // 12
141-
0x43, // 'C' // 13
142-
0x4f, // 'O' // 14
138+
0x20, // ' ' // 10
139+
0x31, // '1' // 11
140+
0x2E, // '.' // 12
141+
0x33, // '3' // 13
142+
0x20, // ' ' // 14
143+
0x28, // '(' // 15
144+
0x54, // 'T' // 16
145+
0x41, // 'A' // 17
146+
0x43, // 'C' // 18
147+
0x4f, // 'O' // 19
148+
0x29, // ')' // 20
143149
};
144150

145151
// int LED_delayTime = 300;
@@ -177,7 +183,6 @@ class OpenBCI_Ganglion {
177183
byte compression_ring[RING_SIZE][MAX_BYTES_PER_PACKET];
178184
int ringBufferLevel = 0; // const int compressionMask = 0xFFFFFFF8;
179185
int channelData[4]; // holds channel data
180-
int lastChannelData[4]; // holds last channel data
181186
byte rawChannelData[24];
182187
volatile byte sampleCounter = 0xFF; // sample counter, for real
183188
volatile boolean MCP_dataReady = false;

0 commit comments

Comments
 (0)