Skip to content

Commit 7e6830d

Browse files
committed
Optimize data acquisition loop
1 parent 85fc6f4 commit 7e6830d

8 files changed

Lines changed: 164 additions & 21 deletions

File tree

Builds/VisualStudio2013/open-ephys.sln

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,7 @@ Global
3232
GlobalSection(SolutionProperties) = preSolution
3333
HideSolutionNode = FALSE
3434
EndGlobalSection
35+
GlobalSection(Performance) = preSolution
36+
HasPerformanceSessions = true
37+
EndGlobalSection
3538
EndGlobal

Builds/VisualStudio2013/open-ephys.vcxproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,7 @@
208208
<AdditionalLibraryDirectories>../../Resources/windows-libs/HDF5/lib/x64;../../Resources/windows-libs/ZeroMQ/lib_x64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
209209
<LargeAddressAware>true</LargeAddressAware>
210210
<AdditionalDependencies>setupapi.lib;opengl32.lib;glu32.lib;hdf5.lib;hdf5_cpp.lib;libzmq-v120-mt-4_0_4.lib;%(AdditionalDependencies)</AdditionalDependencies>
211+
<Profile>true</Profile>
211212
</Link>
212213
<Bscmake>
213214
<SuppressStartupBanner>true</SuppressStartupBanner>
0 Bytes
Binary file not shown.

Source/Processors/DataThreads/RHD2000Thread.cpp

Lines changed: 102 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@
4747
#define DEBUG_EMULATE_HEADSTAGES 8
4848
#define DEBUG_EMULATE_64CH
4949

50+
#define INIT_STEP ( evalBoard->isUSB3() ? 256 : 60)
51+
5052
// Allocates memory for a 3-D array of doubles.
5153
void allocateDoubleArray3D(std::vector<std::vector<std::vector<double> > >& array3D,
5254
int xSize, int ySize, int zSize)
@@ -88,6 +90,8 @@ RHD2000Thread::RHD2000Thread(SourceNode* sn) : DataThread(sn),
8890
newScan(true), ledsEnabled(true)
8991
{
9092
impedanceThread = new RHDImpedanceMeasure(this);
93+
memset(auxBuffer, 0, sizeof(auxBuffer));
94+
memset(auxSamples, 0, sizeof(auxSamples));
9195

9296
for (int i=0; i < MAX_NUM_HEADSTAGES; i++)
9397
headstagesArray.add(new RHDHeadstage(static_cast<Rhd2000EvalBoard::BoardDataSource>(i)));
@@ -389,7 +393,7 @@ void RHD2000Thread::initializeBoard()
389393

390394
// Since our longest command sequence is 60 commands, run the SPI interface for
391395
// 60 samples (64 for usb3 power-of two needs)
392-
evalBoard->setMaxTimeStep(64);
396+
evalBoard->setMaxTimeStep(INIT_STEP);
393397
evalBoard->setContinuousRunMode(false);
394398

395399
// Start SPI interface
@@ -405,8 +409,7 @@ void RHD2000Thread::initializeBoard()
405409
// need to do anything with this, since it was only used for ADC calibration
406410
ScopedPointer<Rhd2000DataBlock> dataBlock = new Rhd2000DataBlock(evalBoard->getNumEnabledDataStreams(), evalBoard->isUSB3());
407411

408-
evalBoard->readDataBlock(dataBlock, 64);
409-
412+
evalBoard->readDataBlock(dataBlock, INIT_STEP);
410413
// Now that ADC calibration has been performed, we switch to the command sequence
411414
// that does not execute ADC calibration.
412415
evalBoard->selectAuxCommandBank(Rhd2000EvalBoard::PortA, Rhd2000EvalBoard::AuxCmd3,
@@ -508,7 +511,7 @@ void RHD2000Thread::scanPorts()
508511

509512
// Since our longest command sequence is 60 commands, we run the SPI
510513
// interface for 60 samples. (64 for usb3 power-of two needs)
511-
evalBoard->setMaxTimeStep(64);
514+
evalBoard->setMaxTimeStep(INIT_STEP);
512515
evalBoard->setContinuousRunMode(false);
513516

514517
ScopedPointer<Rhd2000DataBlock> dataBlock =
@@ -545,7 +548,7 @@ void RHD2000Thread::scanPorts()
545548
;
546549
}
547550
// Read the resulting single data block from the USB interface.
548-
evalBoard->readDataBlock(dataBlock, 64);
551+
evalBoard->readDataBlock(dataBlock, INIT_STEP);
549552

550553
// Read the Intan chip ID number from each RHD2000 chip found.
551554
// Record delay settings that yield good communication with the chip.
@@ -1413,12 +1416,14 @@ bool RHD2000Thread::startAcquisition()
14131416
std::cout << "Flushing FIFO." << std::endl;
14141417
evalBoard->flush();
14151418
evalBoard->setContinuousRunMode(true);
1419+
evalBoard->printFIFOmetrics();
14161420
evalBoard->run();
1421+
evalBoard->printFIFOmetrics();
14171422
}
14181423

14191424
blockSize = dataBlock->calculateDataBlockSizeInWords(evalBoard->getNumEnabledDataStreams(), evalBoard->isUSB3());
14201425
std::cout << "Expecting blocksize of " << blockSize << " for " << evalBoard->getNumEnabledDataStreams() << " streams" << std::endl;
1421-
1426+
evalBoard->printFIFOmetrics();
14221427
startThread();
14231428

14241429

@@ -1481,19 +1486,102 @@ bool RHD2000Thread::stopAcquisition()
14811486
bool RHD2000Thread::updateBuffer()
14821487
{
14831488
int chOffset;
1489+
unsigned char* bufferPtr;
14841490
//cout << "Number of 16-bit words in FIFO: " << evalBoard->numWordsInFifo() << endl;
14851491
//cout << "Block size: " << blockSize << endl;
1486-
1487-
bool return_code;
1492+
14881493
//std::cout << "Current number of words: " << evalBoard->numWordsInFifo() << " for " << blockSize << std::endl;
1489-
if (evalBoard->numWordsInFifo() >= 189440)
1494+
if (evalBoard->isUSB3() || evalBoard->numWordsInFifo() >= blockSize)
14901495
{
1491-
return_code = evalBoard->readDataBlock(dataBlock);
1496+
bool return_code;
1497+
1498+
return_code = evalBoard->readRawDataBlock(&bufferPtr);
14921499

1493-
for (int samp = 0; samp < dataBlock->getSamplesPerDataBlock(evalBoard->isUSB3()); samp++)
1500+
int index = 0;
1501+
int auxIndex, chanIndex;
1502+
int numStreams = enabledStreams.size();
1503+
int nSamps = Rhd2000DataBlock::getSamplesPerDataBlock(evalBoard->isUSB3());
1504+
1505+
evalBoard->printFIFOmetrics();
1506+
for (int samp = 0; samp < nSamps; samp++)
14941507
{
14951508
int channel = -1;
14961509

1510+
if (!Rhd2000DataBlock::checkUsbHeader(bufferPtr, index))
1511+
{
1512+
cerr << "Error in Rhd2000EvalBoard::readDataBlock: Incorrect header." << endl;
1513+
break;
1514+
}
1515+
1516+
index += 8;
1517+
timestamp = Rhd2000DataBlock::convertUsbTimeStamp(bufferPtr,index);
1518+
index += 4;
1519+
auxIndex = index;
1520+
//skip the aux channels
1521+
index += numStreams * 6;
1522+
// do the neural data channels first
1523+
for (int dataStream = 0; dataStream < numStreams; dataStream++)
1524+
{
1525+
int nChans = numChannelsPerDataStream[dataStream];
1526+
chanIndex = index + 2*dataStream;
1527+
if ((chipId[dataStream] == CHIP_ID_RHD2132) && (nChans == 16)) //RHD2132 16ch. headstage
1528+
{
1529+
chanIndex += 2 * RHD2132_16CH_OFFSET*numStreams;
1530+
}
1531+
for (int chan = 0; chan < nChans; chan++)
1532+
{
1533+
channel++;
1534+
thisSample[channel] = float(Rhd2000DataBlock::convertUsbWord(bufferPtr, index) - 32768)*0.195f;
1535+
chanIndex += 2*numStreams;
1536+
}
1537+
}
1538+
index += 64 * numStreams;
1539+
//now we can do the aux channels
1540+
auxIndex += 2*numStreams;
1541+
for (int dataStream = 0; dataStream < numStreams; dataStream++)
1542+
{
1543+
if (chipId[dataStream] != CHIP_ID_RHD2164_B)
1544+
{
1545+
int auxNum = (samp+3) % 4;
1546+
if (auxNum < 3)
1547+
{
1548+
auxSamples[dataStream][auxNum] = float(Rhd2000DataBlock::convertUsbWord(bufferPtr, auxIndex) - 32768)*0.0000374;
1549+
}
1550+
for (int chan = 0; chan < 3; chan++)
1551+
{
1552+
channel++;
1553+
if (auxNum == 3)
1554+
{
1555+
auxBuffer[channel] = auxSamples[dataStream][chan];
1556+
}
1557+
thisSample[channel] = auxBuffer[channel];
1558+
}
1559+
}
1560+
auxIndex += 2;
1561+
1562+
}
1563+
index += 2 * numStreams;
1564+
if (acquireAdcChannels)
1565+
{
1566+
for (int adcChan = 0; adcChan < 8; ++adcChan)
1567+
{
1568+
1569+
channel++;
1570+
// ADC waveform units = volts
1571+
thisSample[channel] =
1572+
//0.000050354 * float(dataBlock->boardAdcData[adcChan][samp]);
1573+
0.00015258789 * float(Rhd2000DataBlock::convertUsbWord(bufferPtr, index)) - 5 - 0.4096; // account for +/-5V input range and DC offset
1574+
index += 2;
1575+
}
1576+
}
1577+
else
1578+
{
1579+
index += 16;
1580+
}
1581+
eventCode = Rhd2000DataBlock::convertUsbWord(bufferPtr, index);
1582+
index += 4;
1583+
dataBuffer->addToBuffer(thisSample, &timestamp, &eventCode, 1);
1584+
#if 0
14971585
// do the neural data channels first
14981586
for (int dataStream = 0; dataStream < enabledStreams.size(); dataStream++)
14991587
{
@@ -1584,14 +1672,13 @@ bool RHD2000Thread::updateBuffer()
15841672
timestamp = dataBlock->timeStamp[samp];
15851673
//timestamp = timestamp;
15861674
eventCode = dataBlock->ttlIn[samp];
1587-
15881675
dataBuffer->addToBuffer(thisSample, &timestamp, &eventCode, 1);
1589-
1676+
#endif
15901677
}
15911678

15921679
}
15931680

1594-
1681+
15951682
if (dacOutputShouldChange)
15961683
{
15971684
std::cout << "DAC" << std::endl;
@@ -1624,8 +1711,7 @@ bool RHD2000Thread::updateBuffer()
16241711

16251712
dacOutputShouldChange = false;
16261713
}
1627-
1628-
1714+
16291715
return true;
16301716

16311717
}

Source/Processors/DataThreads/RHD2000Thread.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ class RHD2000Thread : public DataThread, public Timer
149149

150150
float thisSample[MAX_NUM_CHANNELS];
151151
float auxBuffer[MAX_NUM_CHANNELS]; // aux inputs are only sampled every 4th sample, so use this to buffer the samples so they can be handles just like the regular neural channels later
152+
float auxSamples[MAX_NUM_DATA_STREAMS_USB3][3];
152153

153154
unsigned int blockSize;
154155

Source/Processors/DataThreads/rhythm-api/rhd2000datablock.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
#define RHD2000DATABLOCK_H
2323

2424
#define SAMPLES_PER_DATA_BLOCK_USB2 300 //modified by Open-ephys
25-
#define SAMPLES_PER_DATA_BLOCK_USB3 320
25+
#define SAMPLES_PER_DATA_BLOCK_USB3 256
2626
#define SAMPLES_PER_DATA_BLOCK(usb3) (usb3 ? SAMPLES_PER_DATA_BLOCK_USB3 : SAMPLES_PER_DATA_BLOCK_USB2)
2727
#define MAX_SAMPLES_PER_DATA_BLOCK (SAMPLES_PER_DATA_BLOCK_USB3 > SAMPLES_PER_DATA_BLOCK_USB2 ? SAMPLES_PER_DATA_BLOCK_USB3 : SAMPLES_PER_DATA_BLOCK_USB2)
2828
#define RHD2000_HEADER_MAGIC_NUMBER 0xc691199927021942
@@ -49,6 +49,10 @@ class Rhd2000DataBlock
4949
void print(int stream) const;
5050
void write(ofstream &saveOut, int numDataStreams) const;
5151

52+
static inline bool checkUsbHeader(unsigned char usbBuffer[], int index);
53+
static inline unsigned int convertUsbTimeStamp(unsigned char usbBuffer[], int index);
54+
static inline int convertUsbWord(unsigned char usbBuffer[], int index);
55+
5256
private:
5357
void allocateIntArray3D(vector<vector<vector<int> > > &array3D, int xSize, int ySize, int zSize);
5458
void allocateIntArray2D(vector<vector<int> > &array2D, int xSize, int ySize);
@@ -57,9 +61,7 @@ class Rhd2000DataBlock
5761

5862
void writeWordLittleEndian(ofstream &outputStream, int dataWord) const;
5963

60-
bool checkUsbHeader(unsigned char usbBuffer[], int index);
61-
unsigned int convertUsbTimeStamp(unsigned char usbBuffer[], int index);
62-
int convertUsbWord(unsigned char usbBuffer[], int index);
64+
6365
const unsigned int samplesPerBlock;
6466
bool usb3;
6567
};

Source/Processors/DataThreads/rhythm-api/rhd2000evalboard.cpp

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include "rhd2000datablock.h"
3030

3131
#include "okFrontPanelDLL.h"
32+
#include <Windows.h>
3233

3334
using namespace std;
3435

@@ -685,6 +686,10 @@ void Rhd2000EvalBoard::resetBoard()
685686
dev->UpdateWireIns();
686687
dev->ActivateTriggerIn(TrigInOpenEphys, 16);
687688
cout << "Blocksize set to " << USB3_BLOCK_SIZE << endl;
689+
dev->SetWireInValue(WireInMultiUse, DDR_BLOCK_SIZE);
690+
dev->UpdateWireIns();
691+
dev->ActivateTriggerIn(TrigInOpenEphys, 17);
692+
cout << "DDR burst set to " << DDR_BLOCK_SIZE << endl;
688693
}
689694
}
690695

@@ -720,6 +725,7 @@ void Rhd2000EvalBoard::run()
720725
{
721726
dev->UpdateWireOuts();
722727
std::cout << "Block size: " << dev->GetWireOutValue(0x26) << std::endl;
728+
std::cout << "Burst len: " << dev->GetWireOutValue(0x27) << std::endl;
723729
dev->ActivateTriggerIn(TrigInSpiStart, 0);
724730
}
725731

@@ -1392,6 +1398,7 @@ void Rhd2000EvalBoard::flush()
13921398
while (numWordsInFifo() > 0) {
13931399
dev->ReadFromBlockPipeOut(PipeOutData, USB3_BLOCK_SIZE, USB3_BLOCK_SIZE *max(2 * numWordsInFifo() / USB3_BLOCK_SIZE, (unsigned int)1), usbBuffer);
13941400
cout << "Flush phase B: " << numWordsInFifo() << endl;
1401+
printFIFOmetrics();
13951402
}
13961403
dev->SetWireInValue(WireInResetRun, 0, 1 << 16);
13971404
dev->UpdateWireIns();
@@ -1426,6 +1433,7 @@ bool Rhd2000EvalBoard::readDataBlock(Rhd2000DataBlock *dataBlock, int nSamples)
14261433
{
14271434
//std::cout << "usb3 read : " << numBytesToRead << " in " << USB3_BLOCK_SIZE << " blocks" << std::endl;
14281435
res = dev->ReadFromBlockPipeOut(PipeOutData, USB3_BLOCK_SIZE, numBytesToRead, usbBuffer);
1436+
14291437
}
14301438
else
14311439
{
@@ -1441,6 +1449,39 @@ bool Rhd2000EvalBoard::readDataBlock(Rhd2000DataBlock *dataBlock, int nSamples)
14411449
return true;
14421450
}
14431451

1452+
bool Rhd2000EvalBoard::readRawDataBlock(unsigned char** bufferPtr, int nSamples)
1453+
{
1454+
unsigned int numBytesToRead;
1455+
long res;
1456+
1457+
numBytesToRead = 2 * Rhd2000DataBlock::calculateDataBlockSizeInWords(numDataStreams, usb3, nSamples);
1458+
1459+
if (numBytesToRead > USB_BUFFER_SIZE) {
1460+
cerr << "Error in Rhd2000EvalBoard::readDataBlock: USB buffer size exceeded. " <<
1461+
"Increase value of USB_BUFFER_SIZE." << endl;
1462+
*bufferPtr = nullptr;
1463+
return false;
1464+
}
1465+
1466+
if (usb3)
1467+
{
1468+
//std::cout << "usb3 read : " << numBytesToRead << " in " << USB3_BLOCK_SIZE << " blocks" << std::endl;
1469+
res = dev->ReadFromBlockPipeOut(PipeOutData, USB3_BLOCK_SIZE, numBytesToRead, usbBuffer);
1470+
1471+
}
1472+
else
1473+
{
1474+
//std::cout << "usb2 read: " << numBytesToRead << std::endl;
1475+
res = dev->ReadFromPipeOut(PipeOutData, numBytesToRead, usbBuffer);
1476+
}
1477+
if (res == ok_Timeout)
1478+
{
1479+
cerr << "CRITICAL: Timeout on pipe read. Check block and buffer sizes." << endl;
1480+
}
1481+
*bufferPtr = usbBuffer;
1482+
return true;
1483+
}
1484+
14441485
// Reads a certain number of USB data blocks, if the specified number is available, and appends them
14451486
// to queue. Returns true if data blocks were available.
14461487
bool Rhd2000EvalBoard::readDataBlocks(int numBlocks, queue<Rhd2000DataBlock> &dataQueue)
@@ -1618,4 +1659,10 @@ void Rhd2000EvalBoard::enableBoardLeds(bool enable)
16181659
bool Rhd2000EvalBoard::isUSB3()
16191660
{
16201661
return usb3;
1662+
}
1663+
1664+
void Rhd2000EvalBoard::printFIFOmetrics()
1665+
{
1666+
dev->UpdateWireOuts();
1667+
std::cout << "In FIFO: " << dev->GetWireOutValue(0x28) << " DDR: " << dev->GetWireOutValue(0x2a) << " Out FIFO: " << dev->GetWireOutValue(0x29) << std::endl;
16211668
}

Source/Processors/DataThreads/rhythm-api/rhd2000evalboard.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@
3030

3131
#define MAX_NUM_DATA_STREAMS(u3) ( u3 ? MAX_NUM_DATA_STREAMS_USB3 : MAX_NUM_DATA_STREAMS_USB2 )
3232

33-
#define USB3_BLOCK_SIZE 256
33+
#define USB3_BLOCK_SIZE 2048
34+
#define DDR_BLOCK_SIZE 32
3435

3536
#include <queue>
3637

@@ -166,6 +167,8 @@ class Rhd2000EvalBoard
166167
bool isStreamEnabled(int streamIndex);
167168
void enableBoardLeds(bool enable);
168169
bool isUSB3();
170+
void printFIFOmetrics();
171+
bool readRawDataBlock(unsigned char** bufferPtr, int nSamples = -1);
169172

170173
private:
171174
okCFrontPanel *dev;

0 commit comments

Comments
 (0)