Skip to content
Snippets Groups Projects
Commit 216d11fc authored by Aaron Cuevas Lopez's avatar Aaron Cuevas Lopez
Browse files

Move impedance testing to its own thread

parent 31526ea3
No related branches found
No related tags found
No related merge requests found
......@@ -541,6 +541,9 @@ RHD2000Editor::RHD2000Editor(GenericProcessor* parentNode,
measureWhenRecording = false;
saveImpedances = false;
impedanceData = new ImpedanceData();
impedanceData->valid = false;
// add headstage-specific controls (currently just an enable/disable button)
for (int i = 0; i < 4; i++)
{
......@@ -689,14 +692,18 @@ void RHD2000Editor::scanPorts()
void RHD2000Editor::measureImpedance()
{
Array<int> stream, channel;
Array<float> magnitude, phase;
board->runImpedanceTest(stream,channel,magnitude,phase);
impedanceData->valid = false;
board->runImpedanceTest(impedanceData);
}
void RHD2000Editor::handleAsyncUpdate()
{
if (!impedanceData->valid)
return;
if (canvas == nullptr)
VisualizerEditor::canvas = createNewCanvas();
// update components...
canvas->updateImpedance(stream,channel,magnitude,phase);
canvas->updateImpedance(impedanceData->streams, impedanceData->channels, impedanceData->magnitudes, impedanceData->phases);
if (saveImpedances)
{
getProcessorGraph()->getRecordNode()->createNewDirectory();
......@@ -711,14 +718,14 @@ void RHD2000Editor::measureImpedance()
XmlDocument doc(file);
ScopedPointer<XmlElement> xml = new XmlElement("CHANNEL_IMPEDANCES");
for (int i = 0; i < channel.size(); i++)
for (int i = 0; i < impedanceData->channels.size(); i++)
{
XmlElement* chan = new XmlElement("CHANNEL");
chan->setAttribute("name",board->getChannelName(i));
chan->setAttribute("stream",stream[i]);
chan->setAttribute("channel_number",channel[i]);
chan->setAttribute("magnitude",magnitude[i]);
chan->setAttribute("phase",phase[i]);
chan->setAttribute("stream", impedanceData->streams[i]);
chan->setAttribute("channel_number", impedanceData->channels[i]);
chan->setAttribute("magnitude", impedanceData->magnitudes[i]);
chan->setAttribute("phase", impedanceData->phases[i]);
xml->addChildElement(chan);
}
xml->writeToFile(file,String::empty);
......
......@@ -38,6 +38,7 @@ class AudioInterface;
class RHD2000Thread;
class UtilityButton;
struct ImpedanceData;
/**
......@@ -157,7 +158,7 @@ public:
ScopedPointer<FPGAchannelList> channelList;
};
class RHD2000Editor : public VisualizerEditor, public ComboBox::Listener
class RHD2000Editor : public VisualizerEditor, public ComboBox::Listener, public AsyncUpdater
{
public:
......@@ -184,6 +185,8 @@ public:
bool getSaveImpedance();
bool getAutoMeasureImpedance();
void handleAsyncUpdate();
private:
OwnedArray<HeadstageOptionsInterface> headstageOptionsInterfaces;
......@@ -208,6 +211,9 @@ private:
RHD2000Thread* board;
FPGAcanvas* canvas;
ScopedPointer<ImpedanceData> impedanceData;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(RHD2000Editor);
};
......
......@@ -22,6 +22,7 @@
*/
#include "RHD2000Thread.h"
#include "RHD2000Editor.h"
#include "../SourceNode/SourceNode.h"
#if defined(_WIN32)
......@@ -82,6 +83,7 @@ RHD2000Thread::RHD2000Thread(SourceNode* sn) : DataThread(sn),
audioOutputL(-1), audioOutputR(-1) ,numberingScheme(1),
newScan(true)
{
impedanceThread = new RHDImpedanceMeasure(this);
for (int i=0; i < MAX_NUM_HEADSTAGES; i++)
headstagesArray.add(new RHDHeadstage(static_cast<Rhd2000EvalBoard::BoardDataSource>(i)));
......@@ -427,6 +429,7 @@ void RHD2000Thread::scanPorts()
return;
}
impedanceThread->stopThreadSafely();
//Clear previous known streams
enabledStreams.clear();
......@@ -930,7 +933,7 @@ float RHD2000Thread::getAdcBitVolts(int chan)
double RHD2000Thread::setUpperBandwidth(double upper)
{
impedanceThread->stopThreadSafely();
desiredUpperBandwidth = upper;
updateRegisters();
......@@ -941,6 +944,7 @@ double RHD2000Thread::setUpperBandwidth(double upper)
double RHD2000Thread::setLowerBandwidth(double lower)
{
impedanceThread->stopThreadSafely();
desiredLowerBandwidth = lower;
updateRegisters();
......@@ -950,7 +954,7 @@ double RHD2000Thread::setLowerBandwidth(double lower)
double RHD2000Thread::setDspCutoffFreq(double freq)
{
impedanceThread->stopThreadSafely();
desiredDspCutoffFreq = freq;
updateRegisters();
......@@ -966,6 +970,7 @@ double RHD2000Thread::getDspCutoffFreq()
void RHD2000Thread::setDSPOffset(bool state)
{
impedanceThread->stopThreadSafely();
dspEnabled = state;
updateRegisters();
}
......@@ -1130,7 +1135,7 @@ void RHD2000Thread::enableAdcs(bool t)
void RHD2000Thread::setSampleRate(int sampleRateIndex, bool isTemporary)
{
impedanceThread->stopThreadSafely();
if (!isTemporary)
{
savedSampleRateIndex = sampleRateIndex;
......@@ -1360,7 +1365,7 @@ void RHD2000Thread::setCableLength(int hsNum, float length)
bool RHD2000Thread::startAcquisition()
{
impedanceThread->waitSafely();
dataBlock = new Rhd2000DataBlock(evalBoard->getNumEnabledDataStreams());
std::cout << "Expecting " << getNumChannels() << " channels." << std::endl;
......@@ -1690,6 +1695,13 @@ int RHD2000Thread::getHeadstageChannel(int& hs, int ch)
return -1;
}
void RHD2000Thread::runImpedanceTest(ImpedanceData* data)
{
impedanceThread->stopThreadSafely();
impedanceThread->prepareData(data);
impedanceThread->startThread();
}
RHDHeadstage::RHDHeadstage(Rhd2000EvalBoard::BoardDataSource stream) :
numStreams(0), channelsPerStream(32), dataStream(stream), halfChannels(false)
......@@ -1744,7 +1756,7 @@ bool RHDHeadstage::isPlugged()
/***********************************/
/* Below is code for impedance measurements */
RHDImpedanceMeasure::RHDImpedanceMeasure(RHD2000Thread* b, ImpedanceData* d) : Thread(""), data(d), board(b)
RHDImpedanceMeasure::RHDImpedanceMeasure(RHD2000Thread* b) : Thread(""), data(nullptr), board(b)
{
// to perform electrode impedance measurements at very low frequencies.
const int maxNumBlocks = 120;
......@@ -1752,7 +1764,40 @@ RHDImpedanceMeasure::RHDImpedanceMeasure(RHD2000Thread* b, ImpedanceData* d) : T
allocateDoubleArray3D(amplifierPreFilter, numStreams, 32, SAMPLES_PER_DATA_BLOCK * maxNumBlocks);
}
RHDImpedanceMeasure::~RHDImpedanceMeasure()
{
stopThreadSafely();
}
void RHDImpedanceMeasure::stopThreadSafely()
{
if (isThreadRunning())
{
sendActionMessage("Impedance measure in progress. Stopping it.");
if (!stopThread(3000)) //wait three seconds max for it to exit gracefully
{
std::cerr << "ERROR: Impedance measurement thread did not exit. Force killed it. This might led to crashes." << std::endl;
}
}
}
void RHDImpedanceMeasure::waitSafely()
{
if (!waitForThreadToExit(120000)) //two minutes should be enough for completing a scan
{
sendActionMessage("Impedance measurement took too much. Aborting.");
if (!stopThread(3000)) //wait three seconds max for it to exit gracefully
{
std::cerr << "ERROR: Impedance measurement thread did not exit. Force killed it. This might led to crashes." << std::endl;
}
}
}
void RHDImpedanceMeasure::prepareData(ImpedanceData* d)
{
addActionListener(board->sn->getMessageCenter());
data = d;
}
// Update electrode impedance measurement frequency, after checking that
......@@ -1955,6 +2000,20 @@ void RHDImpedanceMeasure::empiricalResistanceCorrection(double& impedanceMagnitu
}
void RHDImpedanceMeasure::run()
{
RHD2000Editor* ed;
ed = (RHD2000Editor*)board->sn->editor.get();
if (data == nullptr)
return;
runImpedanceMeasurement();
restoreFPGA();
ed->triggerAsyncUpdate();
data = nullptr;
}
#define CHECK_EXIT if (threadShouldExit()) return
void RHDImpedanceMeasure::runImpedanceMeasurement()
{
int commandSequenceLength, stream, channel, capRange;
double cSeries;
......@@ -1967,7 +2026,7 @@ void RHDImpedanceMeasure::run()
Array<int> enabledStreams;
for (stream = 0; stream < MAX_NUM_DATA_STREAMS; ++stream)
{
CHECK_EXIT;
if (board->evalBoard->isStreamEnabled(stream))
{
enabledStreams.add(stream);
......@@ -1987,6 +2046,7 @@ void RHDImpedanceMeasure::run()
}
// Create a command list for the AuxCmd1 slot.
commandSequenceLength = board->chipRegisters.createCommandListZcheckDac(commandList, actualImpedanceFreq, 128.0);
CHECK_EXIT;
board->evalBoard->uploadCommandList(commandList, Rhd2000EvalBoard::AuxCmd1, 1);
board->evalBoard->selectAuxCommandLength(Rhd2000EvalBoard::AuxCmd1,
0, commandSequenceLength - 1);
......@@ -1994,7 +2054,7 @@ void RHDImpedanceMeasure::run()
{
board->evalBoard->enableExternalFastSettle(false);
}
CHECK_EXIT;
board->evalBoard->selectAuxCommandBank(Rhd2000EvalBoard::PortA,
Rhd2000EvalBoard::AuxCmd1, 1);
board->evalBoard->selectAuxCommandBank(Rhd2000EvalBoard::PortB,
......@@ -2011,12 +2071,14 @@ void RHDImpedanceMeasure::run()
int numBlocks = ceil((numPeriods + 2.0) * period / 60.0); // + 2 periods to give time to settle initially
if (numBlocks < 2) numBlocks = 2; // need first block for command to switch channels to take effect.
CHECK_EXIT;
board->actualDspCutoffFreq = board->chipRegisters.setDspCutoffFreq(board->desiredDspCutoffFreq);
board->actualLowerBandwidth = board->chipRegisters.setLowerBandwidth(board->desiredLowerBandwidth);
board->actualUpperBandwidth = board->chipRegisters.setUpperBandwidth(board->desiredUpperBandwidth);
board->chipRegisters.enableDsp(board->dspEnabled);
board->chipRegisters.enableZcheck(true);
commandSequenceLength = board->chipRegisters.createCommandListRegisterConfig(commandList, false);
CHECK_EXIT;
// Upload version with no ADC calibration to AuxCmd3 RAM Bank 1.
board->evalBoard->uploadCommandList(commandList, Rhd2000EvalBoard::AuxCmd3, 3);
board->evalBoard->selectAuxCommandLength(Rhd2000EvalBoard::AuxCmd3, 0, commandSequenceLength - 1);
......@@ -2025,6 +2087,7 @@ void RHDImpedanceMeasure::run()
board->evalBoard->selectAuxCommandBank(Rhd2000EvalBoard::PortC, Rhd2000EvalBoard::AuxCmd3, 3);
board->evalBoard->selectAuxCommandBank(Rhd2000EvalBoard::PortD, Rhd2000EvalBoard::AuxCmd3, 3);
CHECK_EXIT;
board->evalBoard->setContinuousRunMode(false);
board->evalBoard->setMaxTimeStep(SAMPLES_PER_DATA_BLOCK * numBlocks);
......@@ -2066,7 +2129,6 @@ void RHDImpedanceMeasure::run()
for (capRange = 0; capRange < 3; ++capRange)
{
switch (capRange)
{
case 0:
......@@ -2089,6 +2151,7 @@ void RHDImpedanceMeasure::run()
// Check all 32 channels across all active data streams.
for (channel = 0; channel < 32; ++channel)
{
CHECK_EXIT;
cout << "running impedance on channel " << channel << endl;
board->chipRegisters.setZcheckChannel(channel);
......@@ -2119,6 +2182,7 @@ void RHDImpedanceMeasure::run()
// and repeat the previous steps.
if (rhd2164ChipPresent)
{
CHECK_EXIT;
board->chipRegisters.setZcheckChannel(channel + 32); // address channels 32-63
commandSequenceLength =
board->chipRegisters.createCommandListRegisterConfig(commandList, false);
......@@ -2214,7 +2278,12 @@ void RHDImpedanceMeasure::run()
}
}
}
data->valid = true;
}
void RHDImpedanceMeasure::restoreFPGA()
{
board->evalBoard->setContinuousRunMode(false);
board->evalBoard->setMaxTimeStep(0);
board->evalBoard->flush();
......
......@@ -52,6 +52,7 @@ struct ImpedanceData
Array<int> channels;
Array<float> magnitudes;
Array<float> phases;
bool valid;
};
/**
......@@ -123,6 +124,8 @@ public:
/*Gets the headstage relative channel index from the absolute channel index*/
int getHeadstageChannel(int& hs, int ch);
void runImpedanceTest(ImpedanceData* data);
private:
bool enableHeadstage(int hsNum, bool enabled, int nStr = 1, int strChans = 32);
......@@ -196,6 +199,7 @@ private:
int numberingScheme ;
Array<float> adcBitVolts;
bool newScan;
ScopedPointer<RHDImpedanceMeasure> impedanceThread;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(RHD2000Thread);
};
......@@ -221,12 +225,18 @@ private:
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(RHDHeadstage);
};
class RHDImpedanceMeasure : public Thread
class RHDImpedanceMeasure : public Thread, public ActionBroadcaster
{
public:
RHDImpedanceMeasure(RHD2000Thread* b, ImpedanceData* d);
RHDImpedanceMeasure(RHD2000Thread* b);
~RHDImpedanceMeasure();
void prepareData(ImpedanceData* d);
void stopThreadSafely();
void waitSafely();
void run();
private:
void runImpedanceMeasurement();
void restoreFPGA();
void measureComplexAmplitude(std::vector<std::vector<std::vector<double>>>& measuredMagnitude,
std::vector<std::vector<std::vector<double>>>& measuredPhase,
int capIndex, int stream, int chipChannel, int numBlocks,
......@@ -246,6 +256,8 @@ private:
ImpedanceData* data;
RHD2000Thread* board;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(RHDImpedanceMeasure);
};
#endif // __RHD2000THREAD_H_2C4CBD67__
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment