From 5a5f2b1697dddfe4d169f3ff83c1ff3746b6ed50 Mon Sep 17 00:00:00 2001
From: Aaron Cuevas Lopez <aacuelo@teleco.upv.es>
Date: Fri, 23 Jan 2015 03:31:30 +0100
Subject: [PATCH] Add proper support for RHD2164

---
 .../Processors/DataThreads/RHD2000Editor.cpp  |   8 +-
 .../Processors/DataThreads/RHD2000Thread.cpp  | 315 +++++++++++-------
 Source/Processors/DataThreads/RHD2000Thread.h |  39 ++-
 3 files changed, 235 insertions(+), 127 deletions(-)

diff --git a/Source/Processors/DataThreads/RHD2000Editor.cpp b/Source/Processors/DataThreads/RHD2000Editor.cpp
index b2c3fea9d..8769ec79e 100644
--- a/Source/Processors/DataThreads/RHD2000Editor.cpp
+++ b/Source/Processors/DataThreads/RHD2000Editor.cpp
@@ -1199,7 +1199,7 @@ void HeadstageOptionsInterface::checkEnabledState()
 
     if (board->isHeadstageEnabled(hsNumber1))
     {
-        channelsOnHs1 = 32;
+		channelsOnHs1 = board->getChannelsInHeadstage(hsNumber1);
         hsButton1->setLabel(String(channelsOnHs1));
         hsButton1->setEnabledState(true);
     }
@@ -1212,7 +1212,7 @@ void HeadstageOptionsInterface::checkEnabledState()
 
     if (board->isHeadstageEnabled(hsNumber2))
     {
-        channelsOnHs2 = 32;
+        channelsOnHs2 = board->getChannelsInHeadstage(hsNumber2);
         hsButton2->setLabel(String(channelsOnHs2));
         hsButton2->setEnabledState(true);
     }
@@ -1230,7 +1230,7 @@ void HeadstageOptionsInterface::checkEnabledState()
 void HeadstageOptionsInterface::buttonClicked(Button* button)
 {
 
-    if (!(editor->acquisitionIsActive) && board->foundInputSource())
+  /*  if (!(editor->acquisitionIsActive) && board->foundInputSource())
     {
 
         //std::cout << "Acquisition is not active" << std::endl;
@@ -1265,7 +1265,7 @@ void HeadstageOptionsInterface::buttonClicked(Button* button)
 
 
         editor->getEditorViewport()->makeEditorVisible(editor, false, true);
-    }
+    }*/
 
 }
 
diff --git a/Source/Processors/DataThreads/RHD2000Thread.cpp b/Source/Processors/DataThreads/RHD2000Thread.cpp
index 8ebb1cc23..de8fe09d4 100644
--- a/Source/Processors/DataThreads/RHD2000Thread.cpp
+++ b/Source/Processors/DataThreads/RHD2000Thread.cpp
@@ -81,6 +81,10 @@ RHD2000Thread::RHD2000Thread(SourceNode* sn) : DataThread(sn),
     cableLengthPortA(0.914f), cableLengthPortB(0.914f), cableLengthPortC(0.914f), cableLengthPortD(0.914f), // default is 3 feet (0.914 m),
     audioOutputL(-1), audioOutputR(-1) ,numberingScheme(1)
 {
+
+	for (int i=0; i < MAX_NUM_HEADSTAGES; i++)
+		headstagesArray.add(new RHDHeadstage(static_cast<Rhd2000EvalBoard::BoardDataSource>(i)));
+
     evalBoard = new Rhd2000EvalBoard;
     dataBlock = new Rhd2000DataBlock(1);
     dataBuffer = new DataBuffer(2, 10000); // start with 2 channels and automatically resize
@@ -408,9 +412,13 @@ void RHD2000Thread::scanPorts()
     {
         return;
     }
+
+	//Clear previous known streams
+	enabledStreams.clear();
+
     // Scan SPI ports
 
-    int delay, stream, id;
+    int delay, hs, id;
 	int register59Value;
     //int numChannelsOnPort[4] = {0, 0, 0, 0};
     Rhd2000EvalBoard::BoardDataSource initStreamPorts[8] =
@@ -438,6 +446,7 @@ void RHD2000Thread::scanPorts()
     };
 
     chipId.insertMultiple(0,-1,8);
+	Array<int> tmpChipId(chipId);
 
 	setSampleRate(Rhd2000EvalBoard::SampleRate30000Hz, true); // set to 30 kHz temporarily
 
@@ -517,28 +526,28 @@ void RHD2000Thread::scanPorts()
 
         // Read the Intan chip ID number from each RHD2000 chip found.
         // Record delay settings that yield good communication with the chip.
-        for (stream = 0; stream < MAX_NUM_DATA_STREAMS; ++stream)//MAX_NUM_DATA_STREAMS; ++stream)
+        for (hs = 0; hs < MAX_NUM_HEADSTAGES; ++hs)//MAX_NUM_DATA_STREAMS; ++stream)
         {
             // std::cout << "Stream number " << stream << ", delay = " << delay << std::endl;
 
-			id = deviceId(dataBlock, stream, register59Value);
+			id = deviceId(dataBlock, hs, register59Value);
 
 			if (id == CHIP_ID_RHD2132 || id == CHIP_ID_RHD2216 ||
                 (id == CHIP_ID_RHD2164 && register59Value == REGISTER_59_MISO_A))
             {
                 //  std::cout << "Device ID found: " << id << std::endl;
 
-                sumGoodDelays.set(stream,sumGoodDelays[stream] + 1);
+                sumGoodDelays.set(hs,sumGoodDelays[hs] + 1);
 
-                if (indexFirstGoodDelay[stream] == -1)
+                if (indexFirstGoodDelay[hs] == -1)
                 {
-                    indexFirstGoodDelay.set(stream, delay);
-                    chipId.set(stream,id);
+                    indexFirstGoodDelay.set(hs, delay);
+                    tmpChipId.set(hs,id);
                 }
-                else if (indexSecondGoodDelay[stream] == -1)
+                else if (indexSecondGoodDelay[hs] == -1)
                 {
-                    indexSecondGoodDelay.set(stream,delay);
-                    chipId.set(stream,id);
+                    indexSecondGoodDelay.set(hs,delay);
+                    tmpChipId.set(hs,id);
                 }
             }
         }
@@ -554,7 +563,7 @@ void RHD2000Thread::scanPorts()
 #if DEBUG_EMULATE_HEADSTAGES > 0
 	for (int nd = 0; nd < MAX_NUM_DATA_STREAMS; ++nd)
 	{
-		if ((nd < DEBUG_EMULATE_HEADSTAGES) &&(chipId[0] > 0))
+		if ((nd < DEBUG_EMULATE_HEADSTAGES) &&(tmpChipId[0] > 0))
 		{
 			evalBoard->setDataSource(nd,initStreamPorts[0]);
 			enableHeadstage(nd,true);
@@ -566,29 +575,36 @@ void RHD2000Thread::scanPorts()
 	}
 #else
 	// Now, disable data streams where we did not find chips present.
-    for (stream = 0; stream < MAX_NUM_DATA_STREAMS; ++stream)
+	int chipIdx = 0;
+	for (hs = 0; hs < MAX_NUM_HEADSTAGES; ++hs)
     {
-        if (chipId[stream] > 0)
+		if ((tmpChipId[hs] > 0) && (enabledStreams.size() < MAX_NUM_DATA_STREAMS))
         {
+			chipId.set(chipIdx++,chipId[hs]);
             //std::cout << "Enabling headstage on stream " << stream << std::endl;
-            if (chipId[stream] == CHIP_ID_RHD2164) //RHD2164
+            if (tmpChipId[hs] == CHIP_ID_RHD2164) //RHD2164
             {
-                //We just add it like a second headstage, allowing only one RHD2164 per channel
-                //This would need to change
-                evalBoard->setDataSource(stream+1,initStreamDdrPorts[stream]);
-                enableHeadstage(stream,true);
-                enableHeadstage(stream+1,true);
-                chipId.set(stream+1,CHIP_ID_RHD2164_B);
-                stream++;
+				if (enabledStreams.size() < MAX_NUM_DATA_STREAMS - 1)
+				{
+					enableHeadstage(hs,true,2,32);
+					chipId.set(chipIdx++,CHIP_ID_RHD2164_B);
+				}
+				else //just one stream left
+				{
+					enableHeadstage(hs,true,1,32);
+				}
             }
             else
-                enableHeadstage(stream, true);
+			{
+                enableHeadstage(hs, true,1,tmpChipId[hs] == 1 ? 32:16);
+			}
         }
         else
         {
-            enableHeadstage(stream, false);
+            enableHeadstage(hs, false);
         }
     }
+	updateBoardStreams();
 #endif
 
 
@@ -600,15 +616,15 @@ void RHD2000Thread::scanPorts()
     Array<int> optimumDelay;
     optimumDelay.insertMultiple(0,0,8);
 
-    for (stream = 0; stream < MAX_NUM_DATA_STREAMS; ++stream)
+	for (hs = 0; hs < MAX_NUM_HEADSTAGES; ++hs)
     {
-        if (sumGoodDelays[stream] == 1 || sumGoodDelays[stream] == 2)
+        if (sumGoodDelays[hs] == 1 || sumGoodDelays[hs] == 2)
         {
-            optimumDelay.set(stream,indexFirstGoodDelay[stream]);
+            optimumDelay.set(hs,indexFirstGoodDelay[hs]);
         }
-        else if (sumGoodDelays[stream] > 2)
+        else if (sumGoodDelays[hs] > 2)
         {
-            optimumDelay.set(stream,indexSecondGoodDelay[stream]);
+            optimumDelay.set(hs,indexSecondGoodDelay[hs]);
         }
     }
 
@@ -669,11 +685,11 @@ bool RHD2000Thread::isAcquisitionActive()
     return isTransmitting;
 }
 
-void RHD2000Thread::setNumChannels(int hsNum, int numChannels)
+/*void RHD2000Thread::setNumChannels(int hsNum, int numChannels)
 {
     if (numChannelsPerDataStream[hsNum] > 0)
         numChannelsPerDataStream.set(hsNum, numChannels);
-}
+}*/
 
 
 void RHD2000Thread::getEventChannelNames(StringArray& Names)
@@ -836,11 +852,11 @@ void RHD2000Thread::setDefaultChannelNamesAndType()
     stream_prefix.add("D1");
     stream_prefix.add("D2");
 
-    for (int i = 0; i < MAX_NUM_DATA_STREAMS; i++)
+    for (int i = 0; i < MAX_NUM_HEADSTAGES; i++)
     {
-        if (numChannelsPerDataStream[i] > 0)
+		if (headstagesArray[i]->isPlugged())
         {
-            for (int k = 0; k < numChannelsPerDataStream[i]; k++)
+			for (int k = 0; k < headstagesArray[i]->getNumChannels(); k++)
             {
                 type.add(HEADSTAGE_CHANNEL);
 
@@ -867,16 +883,16 @@ void RHD2000Thread::setDefaultChannelNamesAndType()
         }
     }
 	//Aux channels
-	for (int i = 0; i < MAX_NUM_DATA_STREAMS; i++)
+	for (int i = 0; i < MAX_NUM_HEADSTAGES; i++)
     {	
-    	if (numChannelsPerDataStream[i] > 0)
+    	if (headstagesArray[i]->isPlugged())
         {
 			for (int k = 0; k < 3; k++)
 		        {
 
 		            type.add(AUX_CHANNEL);
 
-		            if (channelModified(AUX_CHANNEL,i,numChannelsPerDataStream[i]+k, oldName,oldGain, dummy))
+		            if (channelModified(AUX_CHANNEL,i,headstagesArray[i]->getNumChannels()+k, oldName,oldGain, dummy))
 		            {
 		                Names.add(oldName);
 		                gains.add(oldGain);
@@ -895,7 +911,7 @@ void RHD2000Thread::setDefaultChannelNamesAndType()
 		            }
 
 		            stream.add(i);
-		            originalChannelNumber.add(numChannelsPerDataStream[i]+k);
+		            originalChannelNumber.add(headstagesArray[i]->getNumChannels()+k);
 		        }
 		 }
 	}
@@ -908,7 +924,7 @@ void RHD2000Thread::setDefaultChannelNamesAndType()
             channelNumber++;
             type.add(ADC_CHANNEL);
 
-			if (channelModified(ADC_CHANNEL,MAX_NUM_DATA_STREAMS,k, oldName,oldGain,dummy))
+			if (channelModified(ADC_CHANNEL,MAX_NUM_HEADSTAGES,k, oldName,oldGain,dummy))
             {
                 Names.add(oldName);
                 gains.add(oldGain);
@@ -919,7 +935,7 @@ void RHD2000Thread::setDefaultChannelNamesAndType()
                 gains.add(getAdcBitVolts(k));
             }
             
-            stream.add(MAX_NUM_DATA_STREAMS);
+            stream.add(MAX_NUM_HEADSTAGES);
             originalChannelNumber.add(k);
 
         }
@@ -935,12 +951,12 @@ int RHD2000Thread::getNumChannels()
 int RHD2000Thread::getNumHeadstageOutputs()
 {
     numChannels = 0;
-    for (int i = 0; i < MAX_NUM_DATA_STREAMS; i++)
+	for (int i = 0; i < MAX_NUM_HEADSTAGES; i++)
     {
 
-        if (numChannelsPerDataStream[i] > 0)
+		if (headstagesArray[i]->isPlugged())
         {
-            numChannels += numChannelsPerDataStream[i];
+			numChannels += headstagesArray[i]->getNumChannels();
         }
     }
 
@@ -954,9 +970,9 @@ int RHD2000Thread::getNumAuxOutputs()
 {
     int numAuxOutputs = 0;
 
-    for (int i = 0; i < MAX_NUM_DATA_STREAMS; i++)
+	for (int i = 0; i < MAX_NUM_HEADSTAGES; i++)
     {
-        if (numChannelsPerDataStream[i] > 0)
+        if (headstagesArray[i]->isPlugged() > 0)
         {
             numAuxOutputs += 3;
         }
@@ -1089,45 +1105,82 @@ bool RHD2000Thread::foundInputSource()
 
 }
 
-bool RHD2000Thread::enableHeadstage(int hsNum, bool enabled)
+bool RHD2000Thread::enableHeadstage(int hsNum, bool enabled, int nStr, int strChans)
 {
 
-    evalBoard->enableDataStream(hsNum, enabled);
+ /*   evalBoard->enableDataStream(hsNum, enabled);*/
 
-    if (enabled)
-    {
-        numChannelsPerDataStream.set(hsNum, 32);
-    }
-    else
-    {
-        numChannelsPerDataStream.set(hsNum, 0);
-    }
+	if (enabled)
+	{
+		headstagesArray[hsNum]->setNumStreams(nStr);
+		headstagesArray[hsNum]->setChannelsPerStream(strChans);
+		enabledStreams.add(headstagesArray[hsNum]->getDataStream(0));
+		numChannelsPerDataStream.add(strChans);
+		if (nStr > 1)
+		{
+			enabledStreams.add(headstagesArray[hsNum]->getDataStream(1));
+			numChannelsPerDataStream.add(strChans);
+		}
+	}
+	else
+	{
+		int idx = enabledStreams.indexOf(headstagesArray[hsNum]->getDataStream(0));
+		if (idx >= 0)
+		{
+			enabledStreams.remove(idx);
+			numChannelsPerDataStream.remove(idx);
+		}
+		if (headstagesArray[hsNum]->getNumStreams() > 1)
+		{
+			idx = enabledStreams.indexOf(headstagesArray[hsNum]->getDataStream(1));
+			if (idx >= 0)
+			{
+				enabledStreams.remove(idx);
+				numChannelsPerDataStream.remove(idx);
+			}
+		}
+		headstagesArray[hsNum]->setNumStreams(0);
+	}
 
-    std::cout << "Enabled channels: ";
+	/*    
+	std::cout << "Enabled channels: ";
 
     for (int i = 0; i < MAX_NUM_DATA_STREAMS; i++)
     {
         std::cout << numChannelsPerDataStream[i] << " ";
-    }
+    }*/
 
-    std:: cout << std::endl;
+	dataBuffer->resize(getNumChannels(), 10000);
 
+	return true;
+}
 
-    dataBuffer->resize(getNumChannels(), 10000);
-
-    return true;
+void RHD2000Thread::updateBoardStreams()
+{
+	for (int i=0; i <  MAX_NUM_DATA_STREAMS; i++)
+	{
+		if (i < enabledStreams.size())
+		{
+			evalBoard->enableDataStream(i,true);
+			evalBoard->setDataSource(i,enabledStreams[i]);
+		}
+		else
+		{
+			evalBoard->enableDataStream(i,false);
+		}
+	}
 }
 
 bool RHD2000Thread::isHeadstageEnabled(int hsNum)
 {
 
-    if (numChannelsPerDataStream[hsNum] > 0)
-    {
-        return true;
-    }
+	return headstagesArray[hsNum]->isPlugged();
 
-    return false;
+}
 
+int RHD2000Thread::getChannelsInHeadstage(int hsNum)
+{
+	return headstagesArray[hsNum]->getNumChannels();
 }
 
 void RHD2000Thread::assignAudioOut(int dacChannel, int dataChannel)
@@ -1497,82 +1550,73 @@ bool RHD2000Thread::updateBuffer()
 
         for (int samp = 0; samp < dataBlock->getSamplesPerDataBlock(); samp++)
         {
-            int streamNumber = -1;
             int channel = -1;
 
             // do the neural data channels first
-            for (int dataStream = 0; dataStream < MAX_NUM_DATA_STREAMS; dataStream++)
-            {
-                if (numChannelsPerDataStream[dataStream] > 0)
-                {
-                    streamNumber++;
+			for (int dataStream = 0; dataStream < enabledStreams.size(); dataStream++)
+			{
 
-                    for (int chan = 0; chan < numChannelsPerDataStream[dataStream]; chan++)
-                    {
+				for (int chan = 0; chan < numChannelsPerDataStream[dataStream]; chan++)
+				{
 
-                        //  std::cout << "reading sample stream " << streamNumber << " chan " << chan << " sample "<< samp << std::endl;
+					//  std::cout << "reading sample stream " << streamNumber << " chan " << chan << " sample "<< samp << std::endl;
 
-                        channel++;
+					channel++;
 
-                        int value = dataBlock->amplifierData[streamNumber][chan][samp];
+					int value = dataBlock->amplifierData[dataStream][chan][samp];
 
-                        thisSample[channel] = float(value-32768)*0.195f;
-                    }
+					thisSample[channel] = float(value-32768)*0.195f;
+				}
 
-                }
 
-            }
+			}
 
-            streamNumber = -1;
 
             // then do the Intan AUX channels
-            for (int dataStream = 0; dataStream < MAX_NUM_DATA_STREAMS; dataStream++)
+			for (int dataStream = 0; dataStream < enabledStreams.size(); dataStream++)
             {
-                if (numChannelsPerDataStream[dataStream] > 0)
-                {
-                    streamNumber++;
 
-                    if (samp % 4 == 1)   // every 4th sample should have auxiliary input data
-                    {
+				if (samp % 4 == 1)   // every 4th sample should have auxiliary input data
+				{
 
-                        // std::cout << "reading sample stream " << streamNumber << " aux ADCs " << std::endl;
+					// std::cout << "reading sample stream " << streamNumber << " aux ADCs " << std::endl;
 
-                        channel++;
-                        thisSample[channel] = 0.0374 *
-                                              float(dataBlock->auxiliaryData[streamNumber][1][samp+0] - 45000.0f) ;
-                        // constant offset keeps the values visible in the LFP Viewer
+					channel++;
+					thisSample[channel] = 0.0374 *
+						float(dataBlock->auxiliaryData[dataStream][1][samp+0] - 45000.0f) ;
+					// constant offset keeps the values visible in the LFP Viewer
 
-                        auxBuffer[channel] = thisSample[channel];
+					auxBuffer[channel] = thisSample[channel];
 
-                        channel++;
-                        thisSample[channel] = 0.0374 *
-                                              float(dataBlock->auxiliaryData[streamNumber][1][samp+1] - 45000.0f) ;
-                        // constant offset keeps the values visible in the LFP Viewer
+					channel++;
+					thisSample[channel] = 0.0374 *
+						float(dataBlock->auxiliaryData[dataStream][1][samp+1] - 45000.0f) ;
+					// constant offset keeps the values visible in the LFP Viewer
 
-                        auxBuffer[channel] = thisSample[channel];
+					auxBuffer[channel] = thisSample[channel];
 
 
-                        channel++;
-                        thisSample[channel] = 0.0374 *
-                                              float(dataBlock->auxiliaryData[streamNumber][1][samp+2] - 45000.0f) ;
-                        // constant offset keeps the values visible in the LFP Viewer
+					channel++;
+					thisSample[channel] = 0.0374 *
+						float(dataBlock->auxiliaryData[dataStream][1][samp+2] - 45000.0f) ;
+					// constant offset keeps the values visible in the LFP Viewer
 
-                        auxBuffer[channel] = thisSample[channel];
+					auxBuffer[channel] = thisSample[channel];
 
-                    }
-                    else    // repeat last values from buffer
-                    {
+				}
+				else    // repeat last values from buffer
+				{
 
-                        //std::cout << "reading sample stream " << streamNumber << " aux ADCs " << std::endl;
+					//std::cout << "reading sample stream " << streamNumber << " aux ADCs " << std::endl;
+
+					channel++;
+					thisSample[channel] = auxBuffer[channel];
+					channel++;
+					thisSample[channel] = auxBuffer[channel];
+					channel++;
+					thisSample[channel] = auxBuffer[channel];
+				}
 
-                        channel++;
-                        thisSample[channel] = auxBuffer[channel];
-                        channel++;
-                        thisSample[channel] = auxBuffer[channel];
-                        channel++;
-                        thisSample[channel] = auxBuffer[channel];
-                    }
-                }
 
             }
 
@@ -2130,3 +2174,44 @@ void RHD2000Thread::runImpedanceTest(Array<int>& streams, Array<int>& channels,
         evalBoard->enableExternalFastSettle(true);
     }
 }
+
+
+RHDHeadstage::RHDHeadstage(Rhd2000EvalBoard::BoardDataSource stream) : 
+	numStreams(0), channelsPerStream(32), dataStream(stream)
+{
+}
+
+RHDHeadstage::~RHDHeadstage()
+{
+}
+
+void RHDHeadstage::setNumStreams(int num)
+{
+	numStreams = num;
+}
+
+void RHDHeadstage::setChannelsPerStream(int nchan)
+{
+	channelsPerStream = nchan;
+}
+
+int RHDHeadstage::getNumChannels()
+{
+	return channelsPerStream*numStreams;
+}
+
+int RHDHeadstage::getNumStreams()
+{
+	return numStreams;
+}
+
+Rhd2000EvalBoard::BoardDataSource RHDHeadstage::getDataStream(int index)
+{
+	if (index < 0 || index > 1) index = 0;
+	return static_cast<Rhd2000EvalBoard::BoardDataSource>(dataStream+MAX_NUM_HEADSTAGES*index);
+}
+
+bool RHDHeadstage::isPlugged()
+{
+	return (numStreams > 0);
+}
\ No newline at end of file
diff --git a/Source/Processors/DataThreads/RHD2000Thread.h b/Source/Processors/DataThreads/RHD2000Thread.h
index 6eb6c031d..70a5edc96 100644
--- a/Source/Processors/DataThreads/RHD2000Thread.h
+++ b/Source/Processors/DataThreads/RHD2000Thread.h
@@ -40,9 +40,10 @@
 #include "../GenericProcessor/GenericProcessor.h"
 
 #define MAX_NUM_DATA_STREAMS 8
+#define MAX_NUM_HEADSTAGES 8
 
 class SourceNode;
-
+class RHDHeadstage;
 /**
 
   Communicates with the RHD2000 Evaluation Board from Intan Technologies
@@ -68,12 +69,8 @@ public:
     float getBitVolts(Channel* chan);
     float getAdcBitVolts(int channelNum);
 
-    // for internal use:
-    bool isHeadstageEnabled(int hsNum);
-
-    bool enableHeadstage(int hsNum, bool enabled);
-    void setCableLength(int hsNum, float length);
-    void setNumChannels(int hsNum, int nChannels);
+	bool isHeadstageEnabled(int hsNum);
+	int getChannelsInHeadstage(int hsNum);
 
     void setSampleRate(int index, bool temporary = false);
 
@@ -122,6 +119,12 @@ public:
 	String getChannelName(ChannelType t, int str, int ch);
 
 private:
+
+    bool enableHeadstage(int hsNum, bool enabled, int nStr = 1, int strChans = 32);
+	void updateBoardStreams();
+    void setCableLength(int hsNum, float length);
+ //   void setNumChannels(int hsNum, int nChannels);
+
     void setDefaultChannelNamesAndType();
     bool channelModified(ChannelType t, int str, int k, String &oldName, float &oldGain, int &index);
 
@@ -130,7 +133,6 @@ private:
     Rhd2000DataBlock* dataBlock;
 
     std::vector<std::vector<std::vector<double>>> amplifierPreFilter;
-    Array<int> numChannelsPerDataStream;
     void factorOutParallelCapacitance(double &impedanceMagnitude, double &impedancePhase,
                                               double frequency, double parasiticCapacitance);
     void empiricalResistanceCorrection(double &impedanceMagnitude, double &impedancePhase,
@@ -188,6 +190,9 @@ private:
     float *dacThresholds;
     bool *dacChannelsToUpdate;
     Array<int> chipId;
+	OwnedArray<RHDHeadstage> headstagesArray;
+	Array<Rhd2000EvalBoard::BoardDataSource> enabledStreams;
+	Array<int> numChannelsPerDataStream;
 
     // used for data stream names...
     int numberingScheme ;
@@ -203,4 +208,22 @@ private:
     JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(RHD2000Thread);
 };
 
+class RHDHeadstage
+{
+public:
+	RHDHeadstage(Rhd2000EvalBoard::BoardDataSource stream);
+	~RHDHeadstage();
+	void setNumStreams(int num);
+	void setChannelsPerStream(int nchan);
+	int getNumChannels();
+	int getNumStreams();
+	Rhd2000EvalBoard::BoardDataSource getDataStream(int index);
+	bool isPlugged();
+private:
+	Rhd2000EvalBoard::BoardDataSource dataStream;
+	int numStreams;
+	int channelsPerStream;
+	JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(RHDHeadstage);
+};
+
 #endif  // __RHD2000THREAD_H_2C4CBD67__
-- 
GitLab