diff --git a/Resources/Bitfiles/rhd2000_1.41.bit b/Resources/Bitfiles/rhd2000_1.41.bit new file mode 100644 index 0000000000000000000000000000000000000000..b1e354d4bfd2c8525341d03d9ff13aaf3d3f14d9 Binary files /dev/null and b/Resources/Bitfiles/rhd2000_1.41.bit differ diff --git a/Source/Processors/DataThreads/RHD2000Editor.cpp b/Source/Processors/DataThreads/RHD2000Editor.cpp index b2c3fea9d80b0b74b06c037976b4d81b0e91b643..a5b9321846b374749050a672f87fe34f7f0402a3 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,11 +1230,11 @@ 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; - if (button == hsButton1) + if ((button == hsButton1) && (board->getChannelsInHeadstage(hsNumber1))) { if (channelsOnHs1 == 32) channelsOnHs1 = 16; @@ -1246,11 +1246,11 @@ void HeadstageOptionsInterface::buttonClicked(Button* button) hsButton1->setLabel(String(channelsOnHs1)); board->setNumChannels(hsNumber1, channelsOnHs1); - // board->updateChannelNames(); + board->updateChannelNames(); editor->updateSettings(); } - else if (button == hsButton2) + else if ((button == hsButton2) && (board->getChannelsInHeadstage(hsNumber2))) { if (channelsOnHs2 == 32) channelsOnHs2 = 16; @@ -1259,7 +1259,7 @@ void HeadstageOptionsInterface::buttonClicked(Button* button) hsButton2->setLabel(String(channelsOnHs2)); board->setNumChannels(hsNumber2, channelsOnHs2); - // board->updateChannelNames(); + board->updateChannelNames(); editor->updateSettings(); } diff --git a/Source/Processors/DataThreads/RHD2000Thread.cpp b/Source/Processors/DataThreads/RHD2000Thread.cpp index 6a6fb639228eaafb1caa84b3fab3518a3db8ca45..bbc9ecaae67fe82c7bd185aba427f0341c0f7050 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 @@ -135,9 +139,11 @@ RHD2000Thread::RHD2000Thread(SourceNode* sn) : DataThread(sn), dacChannelsToUpdate[k] = true; dacStream[k] = 0; setDACthreshold(k, 65534); + dacChannels[k] = -1; + dacThresholds[k] = 0; } - evalBoard->getDacInformation(dacChannels,dacThresholds); + // evalBoard->getDacInformation(dacChannels,dacThresholds); //sn->setDefaultNamingScheme(numberingScheme); //setDefaultChannelNamesAndType(); @@ -189,17 +195,18 @@ void RHD2000Thread::setDACchannel(int dacOutput, int stream, int channel) dacStream[dacOutput] = stream; dacChannelsToUpdate[dacOutput] = true; dacOutputShouldChange = true; - evalBoard->updateDacAssignment(dacOutput, stream,channel); // doesn't really change anything, but keep things in sync... + // evalBoard->updateDacAssignment(dacOutput, channel); // doesn't really change anything, but keep things in sync... } Array<int> RHD2000Thread::getDACchannels() { - Array<int> dacChannels; + Array<int> dacChannelsArray; + //dacChannelsArray.addArray(dacChannels,8); for (int k=0; k<8; k++) - { - dacChannels.add(evalBoard->gecDacDataChannel(k)); + { + dacChannelsArray.add(dacChannels[k]); } - return dacChannels; + return dacChannelsArray; } bool RHD2000Thread::openBoard(String pathToLibrary) @@ -346,6 +353,12 @@ void RHD2000Thread::initializeBoard() // - clears the ttlOut // - disables all DACs and sets gain to 0 + setSampleRate(Rhd2000EvalBoard::SampleRate30000Hz); + evalBoard->setCableLengthMeters(Rhd2000EvalBoard::PortA, cableLengthPortA); + evalBoard->setCableLengthMeters(Rhd2000EvalBoard::PortB, cableLengthPortB); + evalBoard->setCableLengthMeters(Rhd2000EvalBoard::PortC, cableLengthPortC); + evalBoard->setCableLengthMeters(Rhd2000EvalBoard::PortD, cableLengthPortD); + // Select RAM Bank 0 for AuxCmd3 initially, so the ADC is calibrated. evalBoard->selectAuxCommandBank(Rhd2000EvalBoard::PortA, Rhd2000EvalBoard::AuxCmd3, 0); evalBoard->selectAuxCommandBank(Rhd2000EvalBoard::PortB, Rhd2000EvalBoard::AuxCmd3, 0); @@ -368,10 +381,10 @@ void RHD2000Thread::initializeBoard() // Read the resulting single data block from the USB interface. We don't // need to do anything with this, since it was only used for ADC calibration - Rhd2000DataBlock* dataBlock = new Rhd2000DataBlock(evalBoard->getNumEnabledDataStreams()); + ScopedPointer<Rhd2000DataBlock> dataBlock = new Rhd2000DataBlock(evalBoard->getNumEnabledDataStreams()); - // evalBoard->readDataBlock(dataBlock); + evalBoard->readDataBlock(dataBlock); // Now that ADC calibration has been performed, we switch to the command sequence // that does not execute ADC calibration. @@ -385,9 +398,9 @@ void RHD2000Thread::initializeBoard() fastSettleEnabled ? 2 : 1); - updateRegisters(); + //updateRegisters(); - // Let's turn one LED on to indicate that the board is now connected + // Let's turn one LED on to indicate that the board is now connected int ledArray[8] = {1, 0, 0, 0, 0, 0, 0, 0}; evalBoard->setLedDisplay(ledArray); @@ -399,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] = @@ -429,8 +446,9 @@ void RHD2000Thread::scanPorts() }; chipId.insertMultiple(0,-1,8); + Array<int> tmpChipId(chipId); - setSampleRate(16, true); // set to 30 kHz temporarily + setSampleRate(Rhd2000EvalBoard::SampleRate30000Hz, true); // set to 30 kHz temporarily // Enable all data streams, and set sources to cover one or two chips // on Ports A-D. @@ -508,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 || + 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); } } } @@ -545,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); @@ -557,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++,tmpChipId[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 @@ -591,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]); } } @@ -622,39 +647,33 @@ void RHD2000Thread::scanPorts() evalBoard->estimateCableLengthMeters(max(optimumDelay[6],optimumDelay[7])); setSampleRate(savedSampleRateIndex); // restore saved sample rate - - updateRegisters(); + //updateRegisters(); } int RHD2000Thread::deviceId(Rhd2000DataBlock* dataBlock, int stream, int ®ister59Value) { bool intanChipPresent; - // First, check ROM registers 32-36 to verify that they hold 'INTAN'. + // First, check ROM registers 32-36 to verify that they hold 'INTAN', and + // the initial chip name ROM registers 24-26 that hold 'RHD'. // This is just used to verify that we are getting good data over the SPI // communication channel. - // std::cout << dataBlock->auxiliaryData[stream][2][32] << " "; - // std::cout << dataBlock->auxiliaryData[stream][2][33] << " "; - // std::cout << dataBlock->auxiliaryData[stream][2][34] << " "; - // std::cout << dataBlock->auxiliaryData[stream][2][35] << " "; - // std::cout << dataBlock->auxiliaryData[stream][2][36] << std::endl; - - intanChipPresent = (dataBlock->auxiliaryData[stream][2][32] == 73 && // I = 73 - dataBlock->auxiliaryData[stream][2][33] == 78 && // N = 78 - dataBlock->auxiliaryData[stream][2][34] == 84 && // T = 84 - dataBlock->auxiliaryData[stream][2][35] == 65 && // A = 65 - dataBlock->auxiliaryData[stream][2][36] == 78); // N = 78 - - // If the SPI communication is bad, return -1. Otherwise, return the Intan + intanChipPresent = ((char) dataBlock->auxiliaryData[stream][2][32] == 'I' && + (char) dataBlock->auxiliaryData[stream][2][33] == 'N' && + (char) dataBlock->auxiliaryData[stream][2][34] == 'T' && + (char) dataBlock->auxiliaryData[stream][2][35] == 'A' && + (char) dataBlock->auxiliaryData[stream][2][36] == 'N' && + (char) dataBlock->auxiliaryData[stream][2][24] == 'R' && + (char) dataBlock->auxiliaryData[stream][2][25] == 'H' && + (char) dataBlock->auxiliaryData[stream][2][26] == 'D'); + + // If the SPI communication is bad, return -1. Otherwise, return the Intan // chip ID number stored in ROM regstier 63. - if (!intanChipPresent) - { - register59Value = -1; + if (!intanChipPresent) { + register59Value = -1; return -1; - } - else - { - register59Value = dataBlock->auxiliaryData[stream][2][23]; // Register 59 + } else { + register59Value = dataBlock->auxiliaryData[stream][2][23]; // Register 59 return dataBlock->auxiliaryData[stream][2][19]; // chip ID (Register 63) } } @@ -668,8 +687,19 @@ bool RHD2000Thread::isAcquisitionActive() void RHD2000Thread::setNumChannels(int hsNum, int numChannels) { - if (numChannelsPerDataStream[hsNum] > 0) - numChannelsPerDataStream.set(hsNum, numChannels); + if (headstagesArray[hsNum]->getNumChannels() == 32) + { + if (numChannels < headstagesArray[hsNum]->getNumChannels()) + headstagesArray[hsNum]->setHalfChannels(true); + else + headstagesArray[hsNum]->setHalfChannels(false); + numChannelsPerDataStream.set(hsNum, numChannels); + } +} + +int RHD2000Thread::getHeadstageChannels(int hsNum) +{ + return headstagesArray[hsNum]->getNumChannels(); } @@ -833,11 +863,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); @@ -864,16 +894,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); @@ -892,7 +922,7 @@ void RHD2000Thread::setDefaultChannelNamesAndType() } stream.add(i); - originalChannelNumber.add(numChannelsPerDataStream[i]+k); + originalChannelNumber.add(headstagesArray[i]->getNumChannels()+k); } } } @@ -905,7 +935,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); @@ -916,7 +946,7 @@ void RHD2000Thread::setDefaultChannelNamesAndType() gains.add(getAdcBitVolts(k)); } - stream.add(MAX_NUM_DATA_STREAMS); + stream.add(MAX_NUM_HEADSTAGES); originalChannelNumber.add(k); } @@ -932,12 +962,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]->getNumActiveChannels(); } } @@ -951,9 +981,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; } @@ -1086,45 +1116,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); - dataBuffer->resize(getNumChannels(), 10000); + return true; +} - 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) @@ -1277,6 +1344,8 @@ void RHD2000Thread::setSampleRate(int sampleRateIndex, bool isTemporary) evalBoard->setCableLengthMeters(Rhd2000EvalBoard::PortC, cableLengthPortC); evalBoard->setCableLengthMeters(Rhd2000EvalBoard::PortD, cableLengthPortD); + updateRegisters(); + } void RHD2000Thread::updateRegisters() @@ -1294,10 +1363,12 @@ void RHD2000Thread::updateRegisters() int commandSequenceLength; vector<int> commandList; - // Create a command list for the AuxCmd1 slot. This command sequence will create a 250 Hz, - // zero-amplitude sine wave (i.e., a flatline). We will change this when we want to perform - // impedance testing. - commandSequenceLength = chipRegisters.createCommandListZcheckDac(commandList, 250.0, 0.0); + // Create a command list for the AuxCmd1 slot. This command sequence will continuously + // update Register 3, which controls the auxiliary digital output pin on each RHD2000 chip. + // In concert with the v1.4 Rhythm FPGA code, this permits real-time control of the digital + // output pin on chips on each SPI port. + chipRegisters.setDigOutLow(); // Take auxiliary output out of HiZ mode. + commandSequenceLength = chipRegisters.createCommandListUpdateDigOut(commandList); evalBoard->uploadCommandList(commandList, Rhd2000EvalBoard::AuxCmd1, 0); evalBoard->selectAuxCommandLength(Rhd2000EvalBoard::AuxCmd1, 0, commandSequenceLength - 1); evalBoard->selectAuxCommandBank(Rhd2000EvalBoard::PortA, Rhd2000EvalBoard::AuxCmd1, 0); @@ -1490,82 +1561,74 @@ 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 (chipId[dataStream] != CHIP_ID_RHD2164_B) //Channel B of 2164 shouldn't be copied + { + 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[dataStream][1][samp + 0] - 45000.0f); + // constant offset keeps the values visible in the LFP Viewer - channel++; - thisSample[channel] = 0.0374 * - float(dataBlock->auxiliaryData[streamNumber][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[dataStream][1][samp + 1] - 45000.0f); + // constant offset keeps the values visible in the LFP Viewer - channel++; - thisSample[channel] = 0.0374 * - float(dataBlock->auxiliaryData[streamNumber][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[dataStream][1][samp + 2] - 45000.0f); + // constant offset keeps the values visible in the LFP Viewer - channel++; - thisSample[channel] = 0.0374 * - float(dataBlock->auxiliaryData[streamNumber][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]; + } + } } @@ -1607,7 +1670,8 @@ bool RHD2000Thread::updateBuffer() evalBoard->enableDac(k, true); evalBoard->selectDacDataStream(k, dacStream[k]); evalBoard->selectDacDataChannel(k, dacChannels[k]); - evalBoard->setDacThresholdVoltage(k, (int) dacThresholds[k]); + evalBoard->setDacThreshold(k, (int)abs((dacThresholds[k]/0.195) + 32768),dacThresholds[k] >= 0); + // evalBoard->setDacThresholdVoltage(k, (int) dacThresholds[k]); } else { @@ -1617,8 +1681,8 @@ bool RHD2000Thread::updateBuffer() } evalBoard->setTtlMode(ttlMode); - evalBoard->setFastSettleByTTL(fastTTLSettleEnabled); - evalBoard->setFastSettleByTTLchannel(fastSettleTTLChannel); + evalBoard->enableExternalFastSettle(fastTTLSettleEnabled); + evalBoard->setExternalFastSettleChannel(fastSettleTTLChannel); evalBoard->setDacHighpassFilter(desiredDAChpf); evalBoard->enableDacHighpassFilter(desiredDAChpfState); @@ -1872,8 +1936,7 @@ void RHD2000Thread::runImpedanceTest(Array<int>& streams, Array<int>& channels, evalBoard->uploadCommandList(commandList, Rhd2000EvalBoard::AuxCmd1, 1); evalBoard->selectAuxCommandLength(Rhd2000EvalBoard::AuxCmd1, 0, commandSequenceLength - 1); - bool fastSettleMode = evalBoard->getExternalFastSettle(); - if (fastSettleMode) + if (fastTTLSettleEnabled) { evalBoard->enableExternalFastSettle(false); } @@ -2118,8 +2181,59 @@ void RHD2000Thread::runImpedanceTest(Array<int>& streams, Array<int>& channels, evalBoard->selectAuxCommandBank(Rhd2000EvalBoard::PortD, Rhd2000EvalBoard::AuxCmd3, fastSettleEnabled ? 2 : 1); - if (fastSettleMode) + if (fastTTLSettleEnabled) { evalBoard->enableExternalFastSettle(true); } } + + +RHDHeadstage::RHDHeadstage(Rhd2000EvalBoard::BoardDataSource stream) : +numStreams(0), channelsPerStream(32), dataStream(stream), halfChannels(false) +{ +} + +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; +} + +void RHDHeadstage::setHalfChannels(bool half) +{ + halfChannels = half; +} + +int RHDHeadstage::getNumActiveChannels() +{ + return (int)(getNumChannels() / (halfChannels ? 2 : 1)); +} + +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 6eb6c031de3f59ef9346261b51a5ad3efed7e173..9a5bd3cf6109c122c74bb1664d5167c81423f2c9 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); @@ -120,8 +117,15 @@ public: void setDefaultNamingScheme(int scheme); String getChannelName(ChannelType t, int str, int ch); + void setNumChannels(int hsNum, int nChannels); + int getHeadstageChannels(int hsNum); private: + + bool enableHeadstage(int hsNum, bool enabled, int nStr = 1, int strChans = 32); + void updateBoardStreams(); + void setCableLength(int hsNum, float length); + void setDefaultChannelNamesAndType(); bool channelModified(ChannelType t, int str, int k, String &oldName, float &oldGain, int &index); @@ -130,7 +134,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 +191,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 +209,25 @@ 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(); + void setHalfChannels(bool half); //mainly used for de 16ch rhd2132 board + int getNumActiveChannels(); + Rhd2000EvalBoard::BoardDataSource getDataStream(int index); + bool isPlugged(); +private: + Rhd2000EvalBoard::BoardDataSource dataStream; + int numStreams; + int channelsPerStream; + bool halfChannels; + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(RHDHeadstage); +}; + #endif // __RHD2000THREAD_H_2C4CBD67__ diff --git a/Source/Processors/DataThreads/rhythm-api/rhd2000datablock.cpp b/Source/Processors/DataThreads/rhythm-api/rhd2000datablock.cpp index d22a4ba36a9b557c50e5843ce5514714d7f21493..030ae354444ed4cee688ae4129605c285bdb6bb1 100755 --- a/Source/Processors/DataThreads/rhythm-api/rhd2000datablock.cpp +++ b/Source/Processors/DataThreads/rhythm-api/rhd2000datablock.cpp @@ -3,9 +3,9 @@ // // Intan Technoloies RHD2000 Rhythm Interface API // Rhd2000DataBlock Class -// Version 1.0 (14 January 2013) +// Version 1.4 (26 February 2014) // -// Copyright (c) 2013 Intan Technologies LLC +// Copyright (c) 2013-2014 Intan Technologies LLC // // This software is provided 'as-is', without any express or implied warranty. // In no event will the authors be held liable for any damages arising from the @@ -42,19 +42,19 @@ Rhd2000DataBlock::Rhd2000DataBlock(int numDataStreams) } // Allocates memory for a 1-D array of integers. -void Rhd2000DataBlock::allocateIntArray1D(vector<int>& array1D, int xSize) +void Rhd2000DataBlock::allocateIntArray1D(vector<int> &array1D, int xSize) { array1D.resize(xSize); } // Allocates memory for a 1-D array of unsigned integers. -void Rhd2000DataBlock::allocateUIntArray1D(vector<unsigned int>& array1D, int xSize) +void Rhd2000DataBlock::allocateUIntArray1D(vector<unsigned int> &array1D, int xSize) { array1D.resize(xSize); } // Allocates memory for a 2-D array of integers. -void Rhd2000DataBlock::allocateIntArray2D(vector<vector<int> >& array2D, int xSize, int ySize) +void Rhd2000DataBlock::allocateIntArray2D(vector<vector<int> > & array2D, int xSize, int ySize) { int i; @@ -64,17 +64,15 @@ void Rhd2000DataBlock::allocateIntArray2D(vector<vector<int> >& array2D, int xSi } // Allocates memory for a 3-D array of integers. -void Rhd2000DataBlock::allocateIntArray3D(vector<vector<vector<int> > >& array3D, int xSize, int ySize, int zSize) +void Rhd2000DataBlock::allocateIntArray3D(vector<vector<vector<int> > > &array3D, int xSize, int ySize, int zSize) { int i, j; array3D.resize(xSize); - for (i = 0; i < xSize; ++i) - { + for (i = 0; i < xSize; ++i) { array3D[i].resize(ySize); - for (j = 0; j < ySize; ++j) - { + for (j = 0; j < ySize; ++j) { array3D[i][j].resize(zSize); } } @@ -144,31 +142,25 @@ void Rhd2000DataBlock::fillFromUsbBuffer(unsigned char usbBuffer[], int blockInd int index, t, channel, stream, i; index = blockIndex * 2 * calculateDataBlockSizeInWords(numDataStreams); - for (t = 0; t < SAMPLES_PER_DATA_BLOCK; ++t) - { - if (!checkUsbHeader(usbBuffer, index)) - { - //cerr << "Error in Rhd2000EvalBoard::readDataBlock: Incorrect header." << endl; + for (t = 0; t < SAMPLES_PER_DATA_BLOCK; ++t) { + if (!checkUsbHeader(usbBuffer, index)) { + // cerr << "Error in Rhd2000EvalBoard::readDataBlock: Incorrect header." << endl; } index += 8; timeStamp[t] = convertUsbTimeStamp(usbBuffer, index); index += 4; // Read auxiliary results - for (channel = 0; channel < 3; ++channel) - { - for (stream = 0; stream < numDataStreams; ++stream) - { + for (channel = 0; channel < 3; ++channel) { + for (stream = 0; stream < numDataStreams; ++stream) { auxiliaryData[stream][channel][t] = convertUsbWord(usbBuffer, index); index += 2; } } // Read amplifier channels - for (channel = 0; channel < 32; ++channel) - { - for (stream = 0; stream < numDataStreams; ++stream) - { + for (channel = 0; channel < 32; ++channel) { + for (stream = 0; stream < numDataStreams; ++stream) { amplifierData[stream][channel][t] = convertUsbWord(usbBuffer, index); index += 2; } @@ -178,8 +170,7 @@ void Rhd2000DataBlock::fillFromUsbBuffer(unsigned char usbBuffer[], int blockInd index += 2 * numDataStreams; // Read from AD5662 ADCs - for (i = 0; i < 8; ++i) - { + for (i = 0; i < 8; ++i) { boardAdcData[i][t] = convertUsbWord(usbBuffer, index); index += 2; } @@ -203,25 +194,24 @@ void Rhd2000DataBlock::print(int stream) const cout << "RHD 2000 Data Block contents:" << endl; cout << " ROM contents:" << endl; cout << " Chip Name: " << - (char) auxiliaryData[stream][2][24] << - (char) auxiliaryData[stream][2][25] << - (char) auxiliaryData[stream][2][26] << - (char) auxiliaryData[stream][2][27] << - (char) auxiliaryData[stream][2][28] << - (char) auxiliaryData[stream][2][29] << - (char) auxiliaryData[stream][2][30] << - (char) auxiliaryData[stream][2][31] << endl; + (char) auxiliaryData[stream][2][24] << + (char) auxiliaryData[stream][2][25] << + (char) auxiliaryData[stream][2][26] << + (char) auxiliaryData[stream][2][27] << + (char) auxiliaryData[stream][2][28] << + (char) auxiliaryData[stream][2][29] << + (char) auxiliaryData[stream][2][30] << + (char) auxiliaryData[stream][2][31] << endl; cout << " Company Name:" << - (char) auxiliaryData[stream][2][32] << - (char) auxiliaryData[stream][2][33] << - (char) auxiliaryData[stream][2][34] << - (char) auxiliaryData[stream][2][35] << - (char) auxiliaryData[stream][2][36] << endl; + (char) auxiliaryData[stream][2][32] << + (char) auxiliaryData[stream][2][33] << + (char) auxiliaryData[stream][2][34] << + (char) auxiliaryData[stream][2][35] << + (char) auxiliaryData[stream][2][36] << endl; cout << " Intan Chip ID: " << auxiliaryData[stream][2][19] << endl; cout << " Number of Amps: " << auxiliaryData[stream][2][20] << endl; cout << " Unipolar/Bipolar Amps: "; - switch (auxiliaryData[stream][2][21]) - { + switch (auxiliaryData[stream][2][21]) { case 0: cout << "bipolar"; break; @@ -246,7 +236,7 @@ void Rhd2000DataBlock::print(int stream) const cout << " MUX bias: " << ((auxiliaryData[stream][2][RamOffset + 2] & 0x3f) >> 0) << endl; cout << " MUX load: " << ((auxiliaryData[stream][2][RamOffset + 3] & 0xe0) >> 5) << endl; cout << " tempS2, tempS1: " << ((auxiliaryData[stream][2][RamOffset + 3] & 0x10) >> 4) << "," << - ((auxiliaryData[stream][2][RamOffset + 3] & 0x08) >> 3) << endl; + ((auxiliaryData[stream][2][RamOffset + 3] & 0x08) >> 3) << endl; cout << " tempen: " << ((auxiliaryData[stream][2][RamOffset + 3] & 0x04) >> 2) << endl; cout << " digout HiZ: " << ((auxiliaryData[stream][2][RamOffset + 3] & 0x02) >> 1) << endl; cout << " digout: " << ((auxiliaryData[stream][2][RamOffset + 3] & 0x01) >> 0) << endl; @@ -285,45 +275,45 @@ void Rhd2000DataBlock::print(int stream) const cout << fixed << setprecision(2); cout << " RH1 DAC1, DAC2: " << rH1Dac1 << " " << rH1Dac2 << " = " << (rH1 / 1000) << - " kOhm" << endl; + " kOhm" << endl; cout << " RH2 DAC1, DAC2: " << rH2Dac1 << " " << rH2Dac2 << " = " << (rH2 / 1000) << - " kOhm" << endl; + " kOhm" << endl; cout << " RL DAC1, DAC2, DAC3: " << rLDac1 << " " << rLDac2 << " " << rLDac3 << " = " << - (rL / 1000) << " kOhm" << endl; + (rL / 1000) << " kOhm" << endl; cout << " amp power[31:0]: " << - ((auxiliaryData[stream][2][RamOffset + 17] & 0x80) >> 7) << - ((auxiliaryData[stream][2][RamOffset + 17] & 0x40) >> 6) << - ((auxiliaryData[stream][2][RamOffset + 17] & 0x20) >> 5) << - ((auxiliaryData[stream][2][RamOffset + 17] & 0x10) >> 4) << - ((auxiliaryData[stream][2][RamOffset + 17] & 0x08) >> 3) << - ((auxiliaryData[stream][2][RamOffset + 17] & 0x04) >> 2) << - ((auxiliaryData[stream][2][RamOffset + 17] & 0x02) >> 1) << - ((auxiliaryData[stream][2][RamOffset + 17] & 0x01) >> 0) << " " << - ((auxiliaryData[stream][2][RamOffset + 16] & 0x80) >> 7) << - ((auxiliaryData[stream][2][RamOffset + 16] & 0x40) >> 6) << - ((auxiliaryData[stream][2][RamOffset + 16] & 0x20) >> 5) << - ((auxiliaryData[stream][2][RamOffset + 16] & 0x10) >> 4) << - ((auxiliaryData[stream][2][RamOffset + 16] & 0x08) >> 3) << - ((auxiliaryData[stream][2][RamOffset + 16] & 0x04) >> 2) << - ((auxiliaryData[stream][2][RamOffset + 16] & 0x02) >> 1) << - ((auxiliaryData[stream][2][RamOffset + 16] & 0x01) >> 0) << " " << - ((auxiliaryData[stream][2][RamOffset + 15] & 0x80) >> 7) << - ((auxiliaryData[stream][2][RamOffset + 15] & 0x40) >> 6) << - ((auxiliaryData[stream][2][RamOffset + 15] & 0x20) >> 5) << - ((auxiliaryData[stream][2][RamOffset + 15] & 0x10) >> 4) << - ((auxiliaryData[stream][2][RamOffset + 15] & 0x08) >> 3) << - ((auxiliaryData[stream][2][RamOffset + 15] & 0x04) >> 2) << - ((auxiliaryData[stream][2][RamOffset + 15] & 0x02) >> 1) << - ((auxiliaryData[stream][2][RamOffset + 15] & 0x01) >> 0) << " " << - ((auxiliaryData[stream][2][RamOffset + 14] & 0x80) >> 7) << - ((auxiliaryData[stream][2][RamOffset + 14] & 0x40) >> 6) << - ((auxiliaryData[stream][2][RamOffset + 14] & 0x20) >> 5) << - ((auxiliaryData[stream][2][RamOffset + 14] & 0x10) >> 4) << - ((auxiliaryData[stream][2][RamOffset + 14] & 0x08) >> 3) << - ((auxiliaryData[stream][2][RamOffset + 14] & 0x04) >> 2) << - ((auxiliaryData[stream][2][RamOffset + 14] & 0x02) >> 1) << - ((auxiliaryData[stream][2][RamOffset + 14] & 0x01) >> 0) << endl; + ((auxiliaryData[stream][2][RamOffset + 17] & 0x80) >> 7) << + ((auxiliaryData[stream][2][RamOffset + 17] & 0x40) >> 6) << + ((auxiliaryData[stream][2][RamOffset + 17] & 0x20) >> 5) << + ((auxiliaryData[stream][2][RamOffset + 17] & 0x10) >> 4) << + ((auxiliaryData[stream][2][RamOffset + 17] & 0x08) >> 3) << + ((auxiliaryData[stream][2][RamOffset + 17] & 0x04) >> 2) << + ((auxiliaryData[stream][2][RamOffset + 17] & 0x02) >> 1) << + ((auxiliaryData[stream][2][RamOffset + 17] & 0x01) >> 0) << " " << + ((auxiliaryData[stream][2][RamOffset + 16] & 0x80) >> 7) << + ((auxiliaryData[stream][2][RamOffset + 16] & 0x40) >> 6) << + ((auxiliaryData[stream][2][RamOffset + 16] & 0x20) >> 5) << + ((auxiliaryData[stream][2][RamOffset + 16] & 0x10) >> 4) << + ((auxiliaryData[stream][2][RamOffset + 16] & 0x08) >> 3) << + ((auxiliaryData[stream][2][RamOffset + 16] & 0x04) >> 2) << + ((auxiliaryData[stream][2][RamOffset + 16] & 0x02) >> 1) << + ((auxiliaryData[stream][2][RamOffset + 16] & 0x01) >> 0) << " " << + ((auxiliaryData[stream][2][RamOffset + 15] & 0x80) >> 7) << + ((auxiliaryData[stream][2][RamOffset + 15] & 0x40) >> 6) << + ((auxiliaryData[stream][2][RamOffset + 15] & 0x20) >> 5) << + ((auxiliaryData[stream][2][RamOffset + 15] & 0x10) >> 4) << + ((auxiliaryData[stream][2][RamOffset + 15] & 0x08) >> 3) << + ((auxiliaryData[stream][2][RamOffset + 15] & 0x04) >> 2) << + ((auxiliaryData[stream][2][RamOffset + 15] & 0x02) >> 1) << + ((auxiliaryData[stream][2][RamOffset + 15] & 0x01) >> 0) << " " << + ((auxiliaryData[stream][2][RamOffset + 14] & 0x80) >> 7) << + ((auxiliaryData[stream][2][RamOffset + 14] & 0x40) >> 6) << + ((auxiliaryData[stream][2][RamOffset + 14] & 0x20) >> 5) << + ((auxiliaryData[stream][2][RamOffset + 14] & 0x10) >> 4) << + ((auxiliaryData[stream][2][RamOffset + 14] & 0x08) >> 3) << + ((auxiliaryData[stream][2][RamOffset + 14] & 0x04) >> 2) << + ((auxiliaryData[stream][2][RamOffset + 14] & 0x02) >> 1) << + ((auxiliaryData[stream][2][RamOffset + 14] & 0x01) >> 0) << endl; cout << endl; @@ -338,7 +328,7 @@ void Rhd2000DataBlock::print(int stream) const cout << setprecision(1); cout << " Temperature sensor (only one reading): " << tempUnitsC << " C (" << - tempUnitsF << " F)" << endl; + tempUnitsF << " F)" << endl; cout << setprecision(2); cout << " Supply voltage sensor : " << vddSense << " V" << endl; @@ -354,7 +344,7 @@ void Rhd2000DataBlock::print(int stream) const // the processor running the operating system. // // (See "Endianness" article in Wikipedia for more information.) -void Rhd2000DataBlock::writeWordLittleEndian(ofstream& outputStream, int dataWord) const +void Rhd2000DataBlock::writeWordLittleEndian(ofstream &outputStream, int dataWord) const { unsigned short msb, lsb; @@ -366,29 +356,23 @@ void Rhd2000DataBlock::writeWordLittleEndian(ofstream& outputStream, int dataWor } // Write contents of data block to a binary output stream (saveOut) in little endian format. -void Rhd2000DataBlock::write(ofstream& saveOut, int numDataStreams) const +void Rhd2000DataBlock::write(ofstream &saveOut, int numDataStreams) const { int t, channel, stream, i; - for (t = 0; t < SAMPLES_PER_DATA_BLOCK; ++t) - { + for (t = 0; t < SAMPLES_PER_DATA_BLOCK; ++t) { writeWordLittleEndian(saveOut, timeStamp[t]); - for (channel = 0; channel < 32; ++channel) - { - for (stream = 0; stream < numDataStreams; ++stream) - { + for (channel = 0; channel < 32; ++channel) { + for (stream = 0; stream < numDataStreams; ++stream) { writeWordLittleEndian(saveOut, amplifierData[stream][channel][t]); } } - for (channel = 0; channel < 3; ++channel) - { - for (stream = 0; stream < numDataStreams; ++stream) - { + for (channel = 0; channel < 3; ++channel) { + for (stream = 0; stream < numDataStreams; ++stream) { writeWordLittleEndian(saveOut, auxiliaryData[stream][channel][t]); } } - for (i = 0; i < 8; ++i) - { + for (i = 0; i < 8; ++i) { writeWordLittleEndian(saveOut, boardAdcData[i][t]); } writeWordLittleEndian(saveOut, ttlIn[t]); diff --git a/Source/Processors/DataThreads/rhythm-api/rhd2000datablock.h b/Source/Processors/DataThreads/rhythm-api/rhd2000datablock.h index 121d43e92d9b67016f7009ef7350fb216eaec76a..4cf6705d5e95795ca0e53ca2c9e1754f1c1970b8 100755 --- a/Source/Processors/DataThreads/rhythm-api/rhd2000datablock.h +++ b/Source/Processors/DataThreads/rhythm-api/rhd2000datablock.h @@ -3,8 +3,9 @@ // // Intan Technoloies RHD2000 Rhythm Interface API // Rhd2000DataBlock Class Header File +// Version 1.4 (26 February 2014) // -// Copyright (c) 2013 Intan Technologies LLC +// Copyright (c) 2013-2014 Intan Technologies LLC // // This software is provided 'as-is', without any express or implied warranty. // In no event will the authors be held liable for any damages arising from the @@ -20,7 +21,7 @@ #ifndef RHD2000DATABLOCK_H #define RHD2000DATABLOCK_H -#define SAMPLES_PER_DATA_BLOCK 300 +#define SAMPLES_PER_DATA_BLOCK 300 //modified by Open-ephys #define RHD2000_HEADER_MAGIC_NUMBER 0xc691199927021942 using namespace std; @@ -43,15 +44,15 @@ public: static unsigned int getSamplesPerDataBlock(); void fillFromUsbBuffer(unsigned char usbBuffer[], int blockIndex, int numDataStreams); void print(int stream) const; - void write(ofstream& saveOut, int numDataStreams) const; + void write(ofstream &saveOut, int numDataStreams) const; private: - void allocateIntArray3D(vector<vector<vector<int> > >& array3D, int xSize, int ySize, int zSize); - void allocateIntArray2D(vector<vector<int> >& array2D, int xSize, int ySize); - void allocateIntArray1D(vector<int>& array1D, int xSize); - void allocateUIntArray1D(vector<unsigned int>& array1D, int xSize); + void allocateIntArray3D(vector<vector<vector<int> > > &array3D, int xSize, int ySize, int zSize); + void allocateIntArray2D(vector<vector<int> > &array2D, int xSize, int ySize); + void allocateIntArray1D(vector<int> &array1D, int xSize); + void allocateUIntArray1D(vector<unsigned int> &array1D, int xSize); - void writeWordLittleEndian(ofstream& outputStream, int dataWord) const; + void writeWordLittleEndian(ofstream &outputStream, int dataWord) const; bool checkUsbHeader(unsigned char usbBuffer[], int index); unsigned int convertUsbTimeStamp(unsigned char usbBuffer[], int index); diff --git a/Source/Processors/DataThreads/rhythm-api/rhd2000evalboard.cpp b/Source/Processors/DataThreads/rhythm-api/rhd2000evalboard.cpp index 5d7452ca6e47647683b6d3b2715e28d8e1e6a9bd..4cf3735cacc3c5bffd3289f2e5c47c5b83f9a64b 100755 --- a/Source/Processors/DataThreads/rhythm-api/rhd2000evalboard.cpp +++ b/Source/Processors/DataThreads/rhythm-api/rhd2000evalboard.cpp @@ -3,9 +3,9 @@ // // Intan Technoloies RHD2000 Rhythm Interface API // Rhd2000EvalBoard Class -// Version 1.0 (14 January 2013) +// Version 1.4 (26 February 2014) // -// Copyright (c) 2013 Intan Technologies LLC +// Copyright (c) 2013-2014 Intan Technologies LLC // // This software is provided 'as-is', without any express or implied warranty. // In no event will the authors be held liable for any damages arising from the @@ -23,7 +23,7 @@ #include <fstream> #include <vector> #include <queue> -#include <math.h> +#include <cmath> #include "rhd2000evalboard.h" #include "rhd2000datablock.h" @@ -39,33 +39,21 @@ using namespace std; Rhd2000EvalBoard::Rhd2000EvalBoard() { int i; - fast_settle_enabled = false; sampleRate = SampleRate30000Hz; // Rhythm FPGA boots up with 30.0 kS/s/channel sampling rate numDataStreams = 0; - dev = 0; //nullptr; + dev = 0; - for (i = 0; i < MAX_NUM_DATA_STREAMS; ++i) - { + for (i = 0; i < MAX_NUM_DATA_STREAMS; ++i) { dataStreamEnabled[i] = 0; } - dacChannelAssignment = new int[8]; - dacStreamAssignment = new int[8]; - dacChannelThreshold = new float[8]; - for (int k=0;k<8;k++) - { - dacStreamAssignment[k] = -1; - dacChannelAssignment[k] = -1; - dacChannelThreshold[k] =0; - } + + cableDelay.resize(4, -1); } -//Destructor: Deletes the device to avoid memory leak +//Destructor: Deletes the device to avoid memory leak in Open ephys Rhd2000EvalBoard::~Rhd2000EvalBoard() { if (dev != 0) delete dev; - delete dacChannelAssignment; - delete dacChannelThreshold; - delete dacStreamAssignment; } // Find an Opal Kelly XEM6010-LX45 board attached to a USB port and open it. @@ -76,47 +64,40 @@ int Rhd2000EvalBoard::open(const char* libname) string serialNumber = ""; int i, nDevices; - cout << "---- Intan Technologies ---- Rhythm RHD2000 Controller v1.0 ----" << endl << endl; - if (okFrontPanelDLL_LoadLib(libname) == false) - { + cout << "---- Intan Technologies ---- Rhythm RHD2000 Controller v1.41 ----" << endl << endl; + if (okFrontPanelDLL_LoadLib(NULL) == false) { cerr << "FrontPanel DLL could not be loaded. " << - "Make sure this DLL is in the application start directory." << endl; + "Make sure this DLL is in the application start directory." << endl; return -1; } okFrontPanelDLL_GetVersion(dll_date, dll_time); cout << endl << "FrontPanel DLL loaded. Built: " << dll_date << " " << dll_time << endl; - if (dev != 0) delete dev; //Avoid memory leaks if open is called twice. - dev = new okCFrontPanel; cout << endl << "Scanning USB for Opal Kelly devices..." << endl << endl; nDevices = dev->GetDeviceCount(); cout << "Found " << nDevices << " Opal Kelly device" << ((nDevices == 1) ? "" : "s") << - " connected:" << endl; - for (i = 0; i < nDevices; ++i) - { + " connected:" << endl; + for (i = 0; i < nDevices; ++i) { cout << " Device #" << i + 1 << ": Opal Kelly " << - opalKellyModelName(dev->GetDeviceListModel(i)).c_str() << - " with serial number " << dev->GetDeviceListSerial(i).c_str() << endl; + opalKellyModelName(dev->GetDeviceListModel(i)).c_str() << + " with serial number " << dev->GetDeviceListSerial(i).c_str() << endl; } cout << endl; // Find first device in list of type XEM6010LX45. - for (i = 0; i < nDevices; ++i) - { - if (dev->GetDeviceListModel(i) == OK_PRODUCT_XEM6010LX45) - { + for (i = 0; i < nDevices; ++i) { + if (dev->GetDeviceListModel(i) == OK_PRODUCT_XEM6010LX45) { serialNumber = dev->GetDeviceListSerial(i); break; } } // Attempt to open device. - if (dev->OpenBySerial(serialNumber) != okCFrontPanel::NoError) - { + if (dev->OpenBySerial(serialNumber) != okCFrontPanel::NoError) { delete dev; - dev = 0; //nullptr; + dev = 0; cerr << "Device could not be opened. Is one connected?" << endl; return -2; } @@ -127,7 +108,7 @@ int Rhd2000EvalBoard::open(const char* libname) // Get some general information about the XEM. cout << "FPGA system clock: " << getSystemClockFreq() << " MHz" << endl; // Should indicate 100 MHz cout << "Opal Kelly device firmware version: " << dev->GetDeviceMajorVersion() << "." << - dev->GetDeviceMinorVersion() << endl; + dev->GetDeviceMinorVersion() << endl; cout << "Opal Kelly device serial number: " << dev->GetSerialNumber().c_str() << endl; cout << "Opal Kelly device ID string: " << dev->GetDeviceID().c_str() << endl << endl; @@ -139,8 +120,7 @@ bool Rhd2000EvalBoard::uploadFpgaBitfile(string filename) { okCFrontPanel::ErrorCode errorCode = dev->ConfigureFPGA(filename); - switch (errorCode) - { + switch (errorCode) { case okCFrontPanel::NoError: break; case okCFrontPanel::DeviceNotOpen: @@ -170,11 +150,10 @@ bool Rhd2000EvalBoard::uploadFpgaBitfile(string filename) } // Check for Opal Kelly FrontPanel support in the FPGA configuration. - if (dev->IsFrontPanelEnabled() == false) - { + if (dev->IsFrontPanelEnabled() == false) { cerr << "Opal Kelly FrontPanel support is not enabled in this FPGA configuration." << endl; delete dev; - dev = 0; //nullptr; + dev = 0; return(false); } @@ -183,26 +162,17 @@ bool Rhd2000EvalBoard::uploadFpgaBitfile(string filename) boardId = dev->GetWireOutValue(WireOutBoardId); boardVersion = dev->GetWireOutValue(WireOutBoardVersion); - if (boardId != RHYTHM_BOARD_ID) - { + if (boardId != RHYTHM_BOARD_ID) { cerr << "FPGA configuration does not support Rhythm. Incorrect board ID: " << boardId << endl; return(false); - } - else - { + } else { cout << "Rhythm configuration file successfully loaded. Rhythm version number: " << - boardVersion << endl << endl; + boardVersion << endl << endl; } return(true); } -// Uses the Opal Kelly library to reset the FPGA -void Rhd2000EvalBoard::resetFpga() -{ - dev->ResetFPGA(); -} - // Reads system clock frequency from Opal Kelly board (in MHz). Should be 100 MHz for normal // Rhythm operation. double Rhd2000EvalBoard::getSystemClockFreq() const @@ -256,8 +226,7 @@ void Rhd2000EvalBoard::initialize() setDataSource(7, PortD2); enableDataStream(0, true); // start with only one data stream enabled - for (i = 1; i < MAX_NUM_DATA_STREAMS; i++) - { + for (i = 1; i < MAX_NUM_DATA_STREAMS; i++) { enableDataStream(i, false); } @@ -288,14 +257,12 @@ void Rhd2000EvalBoard::initialize() selectDacDataChannel(6, 0); selectDacDataChannel(7, 0); - setDacManual(DacManual1, 32768); // midrange value = 0 V - setDacManual(DacManual2, 32768); // midrange value = 0 V + setDacManual(32768); // midrange value = 0 V setDacGain(0); setAudioNoiseSuppress(0); - setTtlMode(0); // If 1 then Digital outputs 0-7 are DAC comparators; 8-15 under manual control - // by default, set to 0 (all are under manual control). + setTtlMode(1); // Digital outputs 0-7 are DAC comparators; 8-15 under manual control setDacThreshold(0, 32768, true); setDacThreshold(1, 32768, true); @@ -305,6 +272,18 @@ void Rhd2000EvalBoard::initialize() setDacThreshold(5, 32768, true); setDacThreshold(6, 32768, true); setDacThreshold(7, 32768, true); + + enableExternalFastSettle(false); + setExternalFastSettleChannel(0); + + enableExternalDigOut(PortA, false); + enableExternalDigOut(PortB, false); + enableExternalDigOut(PortC, false); + enableExternalDigOut(PortD, false); + setExternalDigOutChannel(PortA, 0); + setExternalDigOutChannel(PortB, 0); + setExternalDigOutChannel(PortC, 0); + setExternalDigOutChannel(PortD, 0); } // Set the per-channel sampling rate of the RHD2000 chips connected to the FPGA. @@ -365,78 +344,77 @@ bool Rhd2000EvalBoard::setSampleRate(AmplifierSampleRate newSampleRate) unsigned long M, D; - switch (newSampleRate) - { - case SampleRate1000Hz: - M = 7; - D = 125; - break; - case SampleRate1250Hz: - M = 7; - D = 100; - break; - case SampleRate1500Hz: - M = 21; - D = 250; - break; - case SampleRate2000Hz: - M = 14; - D = 125; - break; - case SampleRate2500Hz: - M = 35; - D = 250; - break; - case SampleRate3000Hz: - M = 21; - D = 125; - break; - case SampleRate3333Hz: - M = 14; - D = 75; - break; - case SampleRate4000Hz: - M = 28; - D = 125; - break; - case SampleRate5000Hz: - M = 7; - D = 25; - break; - case SampleRate6250Hz: - M = 7; - D = 20; - break; - case SampleRate8000Hz: - M = 112; - D = 250; - break; - case SampleRate10000Hz: - M = 14; - D = 25; - break; - case SampleRate12500Hz: - M = 7; - D = 10; - break; - case SampleRate15000Hz: - M = 21; - D = 25; - break; - case SampleRate20000Hz: - M = 28; - D = 25; - break; - case SampleRate25000Hz: - M = 35; - D = 25; - break; - case SampleRate30000Hz: - M = 42; - D = 25; - break; - default: - return(false); + switch (newSampleRate) { + case SampleRate1000Hz: + M = 7; + D = 125; + break; + case SampleRate1250Hz: + M = 7; + D = 100; + break; + case SampleRate1500Hz: + M = 21; + D = 250; + break; + case SampleRate2000Hz: + M = 14; + D = 125; + break; + case SampleRate2500Hz: + M = 35; + D = 250; + break; + case SampleRate3000Hz: + M = 21; + D = 125; + break; + case SampleRate3333Hz: + M = 14; + D = 75; + break; + case SampleRate4000Hz: + M = 28; + D = 125; + break; + case SampleRate5000Hz: + M = 7; + D = 25; + break; + case SampleRate6250Hz: + M = 7; + D = 20; + break; + case SampleRate8000Hz: + M = 112; + D = 250; + break; + case SampleRate10000Hz: + M = 14; + D = 25; + break; + case SampleRate12500Hz: + M = 7; + D = 10; + break; + case SampleRate15000Hz: + M = 21; + D = 25; + break; + case SampleRate20000Hz: + M = 28; + D = 25; + break; + case SampleRate25000Hz: + M = 35; + D = 25; + break; + case SampleRate30000Hz: + M = 42; + D = 25; + break; + default: + return(false); } sampleRate = newSampleRate; @@ -458,61 +436,60 @@ bool Rhd2000EvalBoard::setSampleRate(AmplifierSampleRate newSampleRate) // Returns the current per-channel sampling rate (in Hz) as a floating-point number. double Rhd2000EvalBoard::getSampleRate() const { - switch (sampleRate) - { - case SampleRate1000Hz: - return 1000.0; - break; - case SampleRate1250Hz: - return 1250.0; - break; - case SampleRate1500Hz: - return 1500.0; - break; - case SampleRate2000Hz: - return 2000.0; - break; - case SampleRate2500Hz: - return 2500.0; - break; - case SampleRate3000Hz: - return 3000.0; - break; - case SampleRate3333Hz: - return (10000.0 / 3.0); - break; - case SampleRate4000Hz: - return 4000.0; - break; - case SampleRate5000Hz: - return 5000.0; - break; - case SampleRate6250Hz: - return 6250.0; - break; - case SampleRate8000Hz: - return 8000.0; - break; - case SampleRate10000Hz: - return 10000.0; - break; - case SampleRate12500Hz: - return 12500.0; - break; - case SampleRate15000Hz: - return 15000.0; - break; - case SampleRate20000Hz: - return 20000.0; - break; - case SampleRate25000Hz: - return 25000.0; - break; - case SampleRate30000Hz: - return 30000.0; - break; - default: - return -1.0; + switch (sampleRate) { + case SampleRate1000Hz: + return 1000.0; + break; + case SampleRate1250Hz: + return 1250.0; + break; + case SampleRate1500Hz: + return 1500.0; + break; + case SampleRate2000Hz: + return 2000.0; + break; + case SampleRate2500Hz: + return 2500.0; + break; + case SampleRate3000Hz: + return 3000.0; + break; + case SampleRate3333Hz: + return (10000.0 / 3.0); + break; + case SampleRate4000Hz: + return 4000.0; + break; + case SampleRate5000Hz: + return 5000.0; + break; + case SampleRate6250Hz: + return 6250.0; + break; + case SampleRate8000Hz: + return 8000.0; + break; + case SampleRate10000Hz: + return 10000.0; + break; + case SampleRate12500Hz: + return 12500.0; + break; + case SampleRate15000Hz: + return 15000.0; + break; + case SampleRate20000Hz: + return 20000.0; + break; + case SampleRate25000Hz: + return 25000.0; + break; + case SampleRate30000Hz: + return 30000.0; + break; + default: + return -1.0; } } @@ -528,41 +505,27 @@ void Rhd2000EvalBoard::printCommandList(const vector<int> &commandList) const int cmd, channel, reg, data; cout << endl; - for (i = 0; i < commandList.size(); ++i) - { + for (i = 0; i < commandList.size(); ++i) { cmd = commandList[i]; - if (cmd < 0 || cmd > 0xffff) - { + if (cmd < 0 || cmd > 0xffff) { cout << " command[" << i << "] = INVALID COMMAND: " << cmd << endl; - } - else if ((cmd & 0xc000) == 0x0000) - { + } else if ((cmd & 0xc000) == 0x0000) { channel = (cmd & 0x3f00) >> 8; cout << " command[" << i << "] = CONVERT(" << channel << ")" << endl; - } - else if ((cmd & 0xc000) == 0xc000) - { + } else if ((cmd & 0xc000) == 0xc000) { reg = (cmd & 0x3f00) >> 8; cout << " command[" << i << "] = READ(" << reg << ")" << endl; - } - else if ((cmd & 0xc000) == 0x8000) - { + } else if ((cmd & 0xc000) == 0x8000) { reg = (cmd & 0x3f00) >> 8; data = (cmd & 0x00ff); cout << " command[" << i << "] = WRITE(" << reg << ","; cout << hex << uppercase << internal << setfill('0') << setw(2) << data << nouppercase << dec; cout << ")" << endl; - } - else if (cmd == 0x5500) - { + } else if (cmd == 0x5500) { cout << " command[" << i << "] = CALIBRATE" << endl; - } - else if (cmd == 0x6a00) - { + } else if (cmd == 0x6a00) { cout << " command[" << i << "] = CLEAR" << endl; - } - else - { + } else { cout << " command[" << i << "] = INVALID COMMAND: "; cout << hex << uppercase << internal << setfill('0') << setw(4) << cmd << nouppercase << dec; cout << endl; @@ -577,26 +540,22 @@ void Rhd2000EvalBoard::uploadCommandList(const vector<int> &commandList, AuxCmdS { unsigned int i; - if (auxCommandSlot != AuxCmd1 && auxCommandSlot != AuxCmd2 && auxCommandSlot != AuxCmd3) - { + if (auxCommandSlot != AuxCmd1 && auxCommandSlot != AuxCmd2 && auxCommandSlot != AuxCmd3) { cerr << "Error in Rhd2000EvalBoard::uploadCommandList: auxCommandSlot out of range." << endl; return; } - if (bank < 0 || bank > 15) - { + if (bank < 0 || bank > 15) { cerr << "Error in Rhd2000EvalBoard::uploadCommandList: bank out of range." << endl; return; } - for (i = 0; i < commandList.size(); ++i) - { + for (i = 0; i < commandList.size(); ++i) { dev->SetWireInValue(WireInCmdRamData, commandList[i]); dev->SetWireInValue(WireInCmdRamAddr, i); dev->SetWireInValue(WireInCmdRamBank, bank); dev->UpdateWireIns(); - switch (auxCommandSlot) - { + switch (auxCommandSlot) { case AuxCmd1: dev->ActivateTriggerIn(TrigInRamWrite, 0); break; @@ -616,44 +575,40 @@ void Rhd2000EvalBoard::selectAuxCommandBank(BoardPort port, AuxCmdSlot auxComman { int bitShift; - if (auxCommandSlot != AuxCmd1 && auxCommandSlot != AuxCmd2 && auxCommandSlot != AuxCmd3) - { + if (auxCommandSlot != AuxCmd1 && auxCommandSlot != AuxCmd2 && auxCommandSlot != AuxCmd3) { cerr << "Error in Rhd2000EvalBoard::selectAuxCommandBank: auxCommandSlot out of range." << endl; return; } - if (bank < 0 || bank > 15) - { + if (bank < 0 || bank > 15) { cerr << "Error in Rhd2000EvalBoard::selectAuxCommandBank: bank out of range." << endl; return; } - switch (port) - { - case PortA: - bitShift = 0; - break; - case PortB: - bitShift = 4; - break; - case PortC: - bitShift = 8; - break; - case PortD: - bitShift = 12; - break; - } - - switch (auxCommandSlot) - { - case AuxCmd1: - dev->SetWireInValue(WireInAuxCmdBank1, bank << bitShift, 0x000f << bitShift); - break; - case AuxCmd2: - dev->SetWireInValue(WireInAuxCmdBank2, bank << bitShift, 0x000f << bitShift); - break; - case AuxCmd3: - dev->SetWireInValue(WireInAuxCmdBank3, bank << bitShift, 0x000f << bitShift); - break; + switch (port) { + case PortA: + bitShift = 0; + break; + case PortB: + bitShift = 4; + break; + case PortC: + bitShift = 8; + break; + case PortD: + bitShift = 12; + break; + } + + switch (auxCommandSlot) { + case AuxCmd1: + dev->SetWireInValue(WireInAuxCmdBank1, bank << bitShift, 0x000f << bitShift); + break; + case AuxCmd2: + dev->SetWireInValue(WireInAuxCmdBank2, bank << bitShift, 0x000f << bitShift); + break; + case AuxCmd3: + dev->SetWireInValue(WireInAuxCmdBank3, bank << bitShift, 0x000f << bitShift); + break; } dev->UpdateWireIns(); } @@ -662,38 +617,34 @@ void Rhd2000EvalBoard::selectAuxCommandBank(BoardPort port, AuxCmdSlot auxComman // auxiliary command slot (AuxCmd1, AuxCmd2, or AuxCmd3). void Rhd2000EvalBoard::selectAuxCommandLength(AuxCmdSlot auxCommandSlot, int loopIndex, int endIndex) { - if (auxCommandSlot != AuxCmd1 && auxCommandSlot != AuxCmd2 && auxCommandSlot != AuxCmd3) - { + if (auxCommandSlot != AuxCmd1 && auxCommandSlot != AuxCmd2 && auxCommandSlot != AuxCmd3) { cerr << "Error in Rhd2000EvalBoard::selectAuxCommandLength: auxCommandSlot out of range." << endl; return; } - if (loopIndex < 0 || loopIndex > 1023) - { + if (loopIndex < 0 || loopIndex > 1023) { cerr << "Error in Rhd2000EvalBoard::selectAuxCommandLength: loopIndex out of range." << endl; return; } - if (endIndex < 0 || endIndex > 1023) - { + if (endIndex < 0 || endIndex > 1023) { cerr << "Error in Rhd2000EvalBoard::selectAuxCommandLength: endIndex out of range." << endl; return; } - switch (auxCommandSlot) - { - case AuxCmd1: - dev->SetWireInValue(WireInAuxCmdLoop1, loopIndex); - dev->SetWireInValue(WireInAuxCmdLength1, endIndex); - break; - case AuxCmd2: - dev->SetWireInValue(WireInAuxCmdLoop2, loopIndex); - dev->SetWireInValue(WireInAuxCmdLength2, endIndex); - break; - case AuxCmd3: - dev->SetWireInValue(WireInAuxCmdLoop3, loopIndex); - dev->SetWireInValue(WireInAuxCmdLength3, endIndex); - break; + switch (auxCommandSlot) { + case AuxCmd1: + dev->SetWireInValue(WireInAuxCmdLoop1, loopIndex); + dev->SetWireInValue(WireInAuxCmdLength1, endIndex); + break; + case AuxCmd2: + dev->SetWireInValue(WireInAuxCmdLoop2, loopIndex); + dev->SetWireInValue(WireInAuxCmdLength2, endIndex); + break; + case AuxCmd3: + dev->SetWireInValue(WireInAuxCmdLoop3, loopIndex); + dev->SetWireInValue(WireInAuxCmdLength3, endIndex); + break; } dev->UpdateWireIns(); } @@ -712,12 +663,9 @@ void Rhd2000EvalBoard::resetBoard() // maxTimeStep is reached (if continuousMode == false). void Rhd2000EvalBoard::setContinuousRunMode(bool continuousMode) { - if (continuousMode) - { + if (continuousMode) { dev->SetWireInValue(WireInResetRun, 0x02, 0x02); - } - else - { + } else { dev->SetWireInValue(WireInResetRun, 0x00, 0x02); } dev->UpdateWireIns(); @@ -750,12 +698,9 @@ bool Rhd2000EvalBoard::isRunning() const dev->UpdateWireOuts(); value = dev->GetWireOutValue(WireOutSpiRunning); - if ((value & 0x01) == 0) - { + if ((value & 0x01) == 0) { return false; - } - else - { + } else { return true; } } @@ -784,26 +729,32 @@ void Rhd2000EvalBoard::setCableDelay(BoardPort port, int delay) { int bitShift; - if (delay < 0 || delay > 15) - { - cerr << "Error in Rhd2000EvalBoard::setCableDelay: delay out of range." << endl; - return; - } - - switch (port) - { - case PortA: - bitShift = 0; - break; - case PortB: - bitShift = 4; - break; - case PortC: - bitShift = 8; - break; - case PortD: - bitShift = 12; - break; + if (delay < 0 || delay > 15) { + cerr << "Warning in Rhd2000EvalBoard::setCableDelay: delay out of range: " << delay << endl; + } + + if (delay < 0) delay = 0; + if (delay > 15) delay = 15; + + switch (port) { + case PortA: + bitShift = 0; + cableDelay[0] = delay; + break; + case PortB: + bitShift = 4; + cableDelay[1] = delay; + break; + case PortC: + bitShift = 8; + cableDelay[2] = delay; + break; + case PortD: + bitShift = 12; + cableDelay[3] = delay; + break; + default: + cerr << "Error in RHD2000EvalBoard::setCableDelay: unknown port." << endl; } dev->SetWireInValue(WireInMisoDelay, delay << bitShift, 0x000f << bitShift); @@ -822,17 +773,15 @@ void Rhd2000EvalBoard::setCableLengthMeters(BoardPort port, double lengthInMeter const double xilinxLvdsOutputDelay = 1.9e-9; // 1.9 ns Xilinx LVDS output pin delay const double xilinxLvdsInputDelay = 1.4e-9; // 1.4 ns Xilinx LVDS input pin delay const double rhd2000Delay = 9.0e-9; // 9.0 ns RHD2000 SCLK-to-MISO delay - const double misoSettleTime = 10.0e-9; // 10.0 ns delay after MISO changes, before we sample it + const double misoSettleTime = 6.7e-9; // 6.7 ns delay after MISO changes, before we sample it tStep = 1.0 / (2800.0 * getSampleRate()); // data clock that samples MISO has a rate 35 x 80 = 2800x higher than the sampling rate - cableVelocity = 0.67 * speedOfLight; // propogation velocity on cable is rougly 2/3 the speed of light + // cableVelocity = 0.67 * speedOfLight; // propogation velocity on cable: version 1.3 and earlier + cableVelocity = 0.555 * speedOfLight; // propogation velocity on cable: version 1.4 improvement based on cable measurements distance = 2.0 * lengthInMeters; // round trip distance data must travel on cable - timeDelay = distance / cableVelocity + xilinxLvdsOutputDelay + rhd2000Delay + xilinxLvdsInputDelay + misoSettleTime; - - delay = (int) ceil(timeDelay / tStep); + timeDelay = (distance / cableVelocity) + xilinxLvdsOutputDelay + rhd2000Delay + xilinxLvdsInputDelay + misoSettleTime; - // cout << "Total delay = " << (1e9 * timeDelay) << " ns" << endl; - // cout << "setCableLength: setting delay to " << delay << endl; + delay = (int) floor(((timeDelay / tStep) + 1.0) + 0.5); if (delay < 1) delay = 1; // delay of zero is too short (due to I/O delays), even for zero-length cables @@ -854,11 +803,14 @@ double Rhd2000EvalBoard::estimateCableLengthMeters(int delay) const const double xilinxLvdsOutputDelay = 1.9e-9; // 1.9 ns Xilinx LVDS output pin delay const double xilinxLvdsInputDelay = 1.4e-9; // 1.4 ns Xilinx LVDS input pin delay const double rhd2000Delay = 9.0e-9; // 9.0 ns RHD2000 SCLK-to-MISO delay + const double misoSettleTime = 6.7e-9; // 6.7 ns delay after MISO changes, before we sample it tStep = 1.0 / (2800.0 * getSampleRate()); // data clock that samples MISO has a rate 35 x 80 = 2800x higher than the sampling rate - cableVelocity = 0.67 * speedOfLight; // propogation velocity on cable is rougly 2/3 the speed of light + // cableVelocity = 0.67 * speedOfLight; // propogation velocity on cable: version 1.3 and earlier + cableVelocity = 0.555 * speedOfLight; // propogation velocity on cable: version 1.4 improvement based on cable measurements - distance = cableVelocity * (delay * tStep - (xilinxLvdsOutputDelay + rhd2000Delay + xilinxLvdsInputDelay)); + // distance = cableVelocity * (delay * tStep - (xilinxLvdsOutputDelay + rhd2000Delay + xilinxLvdsInputDelay)); // version 1.3 and earlier + distance = cableVelocity * ((((double) delay) - 1.0) * tStep - (xilinxLvdsOutputDelay + rhd2000Delay + xilinxLvdsInputDelay + misoSettleTime)); // version 1.4 improvement if (distance < 0.0) distance = 0.0; return (distance / 2.0); @@ -884,83 +836,67 @@ void Rhd2000EvalBoard::setDataSource(int stream, BoardDataSource dataSource) int bitShift; OkEndPoint endPoint; - if (stream < 0 || stream > 7) - { + if (stream < 0 || stream > 7) { cerr << "Error in Rhd2000EvalBoard::setDataSource: stream out of range." << endl; return; } - switch (stream) - { - case 0: - endPoint = WireInDataStreamSel1234; - bitShift = 0; - break; - case 1: - endPoint = WireInDataStreamSel1234; - bitShift = 4; - break; - case 2: - endPoint = WireInDataStreamSel1234; - bitShift = 8; - break; - case 3: - endPoint = WireInDataStreamSel1234; - bitShift = 12; - break; - case 4: - endPoint = WireInDataStreamSel5678; - bitShift = 0; - break; - case 5: - endPoint = WireInDataStreamSel5678; - bitShift = 4; - break; - case 6: - endPoint = WireInDataStreamSel5678; - bitShift = 8; - break; - case 7: - endPoint = WireInDataStreamSel5678; - bitShift = 12; - break; + switch (stream) { + case 0: + endPoint = WireInDataStreamSel1234; + bitShift = 0; + break; + case 1: + endPoint = WireInDataStreamSel1234; + bitShift = 4; + break; + case 2: + endPoint = WireInDataStreamSel1234; + bitShift = 8; + break; + case 3: + endPoint = WireInDataStreamSel1234; + bitShift = 12; + break; + case 4: + endPoint = WireInDataStreamSel5678; + bitShift = 0; + break; + case 5: + endPoint = WireInDataStreamSel5678; + bitShift = 4; + break; + case 6: + endPoint = WireInDataStreamSel5678; + bitShift = 8; + break; + case 7: + endPoint = WireInDataStreamSel5678; + bitShift = 12; + break; } dev->SetWireInValue(endPoint, dataSource << bitShift, 0x000f << bitShift); dev->UpdateWireIns(); } -bool Rhd2000EvalBoard::isStreamEnabled(int streamIndex) -{ - if (streamIndex < 0 || streamIndex > (MAX_NUM_DATA_STREAMS - 1)) - return false; - - return dataStreamEnabled[streamIndex]; -} - // Enable or disable one of the eight available USB data streams (0-7). void Rhd2000EvalBoard::enableDataStream(int stream, bool enabled) { - if (stream < 0 || stream > (MAX_NUM_DATA_STREAMS - 1)) - { + if (stream < 0 || stream > (MAX_NUM_DATA_STREAMS - 1)) { cerr << "Error in Rhd2000EvalBoard::setDataSource: stream out of range." << endl; return; } - if (enabled) - { - if (dataStreamEnabled[stream] == 0) - { + if (enabled) { + if (dataStreamEnabled[stream] == 0) { dev->SetWireInValue(WireInDataStreamEn, 0x0001 << stream, 0x0001 << stream); dev->UpdateWireIns(); dataStreamEnabled[stream] = 1; ++numDataStreams; } - } - else - { - if (dataStreamEnabled[stream] == 1) - { + } else { + if (dataStreamEnabled[stream] == 1) { dev->SetWireInValue(WireInDataStreamEn, 0x0000 << stream, 0x0001 << stream); dev->UpdateWireIns(); dataStreamEnabled[stream] = 0; @@ -988,8 +924,7 @@ void Rhd2000EvalBoard::setTtlOut(int ttlOutArray[]) int i, ttlOut; ttlOut = 0; - for (i = 0; i < 16; ++i) - { + for (i = 0; i < 16; ++i) { if (ttlOutArray[i] > 0) ttlOut += 1 << i; } @@ -1005,31 +940,22 @@ void Rhd2000EvalBoard::getTtlIn(int ttlInArray[]) dev->UpdateWireOuts(); ttlIn = dev->GetWireOutValue(WireOutTtlIn); - for (i = 0; i < 16; ++i) - { + for (i = 0; i < 16; ++i) { ttlInArray[i] = 0; if ((ttlIn & (1 << i)) > 0) ttlInArray[i] = 1; } } -void Rhd2000EvalBoard::setDacManual(DacManual dac, int value) +// Set manual value for DACs. +void Rhd2000EvalBoard::setDacManual(int value) { - if (value < 0 || value > 65535) - { + if (value < 0 || value > 65535) { cerr << "Error in Rhd2000EvalBoard::setDacManual: value out of range." << endl; return; } - switch (dac) - { - case DacManual1: - dev->SetWireInValue(WireInDacManual1, value); - break; - case DacManual2: - dev->SetWireInValue(WireInDacManual2, value); - break; - } + dev->SetWireInValue(WireInDacManual, value); dev->UpdateWireIns(); } @@ -1039,8 +965,7 @@ void Rhd2000EvalBoard::setLedDisplay(int ledArray[]) int i, ledOut; ledOut = 0; - for (i = 0; i < 8; ++i) - { + for (i = 0; i < 8; ++i) { if (ledArray[i] > 0) ledOut += 1 << i; } @@ -1051,38 +976,36 @@ void Rhd2000EvalBoard::setLedDisplay(int ledArray[]) // Enable or disable AD5662 DAC channel (0-7) void Rhd2000EvalBoard::enableDac(int dacChannel, bool enabled) { - if (dacChannel < 0 || dacChannel > 7) - { + if (dacChannel < 0 || dacChannel > 7) { cerr << "Error in Rhd2000EvalBoard::enableDac: dacChannel out of range." << endl; return; } - switch (dacChannel) - { - case 0: - dev->SetWireInValue(WireInDacSource1, (enabled ? 0x0200 : 0x0000), 0x0200); - break; - case 1: - dev->SetWireInValue(WireInDacSource2, (enabled ? 0x0200 : 0x0000), 0x0200); - break; - case 2: - dev->SetWireInValue(WireInDacSource3, (enabled ? 0x0200 : 0x0000), 0x0200); - break; - case 3: - dev->SetWireInValue(WireInDacSource4, (enabled ? 0x0200 : 0x0000), 0x0200); - break; - case 4: - dev->SetWireInValue(WireInDacSource5, (enabled ? 0x0200 : 0x0000), 0x0200); - break; - case 5: - dev->SetWireInValue(WireInDacSource6, (enabled ? 0x0200 : 0x0000), 0x0200); - break; - case 6: - dev->SetWireInValue(WireInDacSource7, (enabled ? 0x0200 : 0x0000), 0x0200); - break; - case 7: - dev->SetWireInValue(WireInDacSource8, (enabled ? 0x0200 : 0x0000), 0x0200); - break; + switch (dacChannel) { + case 0: + dev->SetWireInValue(WireInDacSource1, (enabled ? 0x0200 : 0x0000), 0x0200); + break; + case 1: + dev->SetWireInValue(WireInDacSource2, (enabled ? 0x0200 : 0x0000), 0x0200); + break; + case 2: + dev->SetWireInValue(WireInDacSource3, (enabled ? 0x0200 : 0x0000), 0x0200); + break; + case 3: + dev->SetWireInValue(WireInDacSource4, (enabled ? 0x0200 : 0x0000), 0x0200); + break; + case 4: + dev->SetWireInValue(WireInDacSource5, (enabled ? 0x0200 : 0x0000), 0x0200); + break; + case 5: + dev->SetWireInValue(WireInDacSource6, (enabled ? 0x0200 : 0x0000), 0x0200); + break; + case 6: + dev->SetWireInValue(WireInDacSource7, (enabled ? 0x0200 : 0x0000), 0x0200); + break; + case 7: + dev->SetWireInValue(WireInDacSource8, (enabled ? 0x0200 : 0x0000), 0x0200); + break; } dev->UpdateWireIns(); } @@ -1090,8 +1013,7 @@ void Rhd2000EvalBoard::enableDac(int dacChannel, bool enabled) // Set the gain level of all eight DAC channels to 2^gain (gain = 0-7). void Rhd2000EvalBoard::setDacGain(int gain) { - if (gain < 0 || gain > 7) - { + if (gain < 0 || gain > 7) { cerr << "Error in Rhd2000EvalBoard::setDacGain: gain out of range." << endl; return; } @@ -1104,8 +1026,7 @@ void Rhd2000EvalBoard::setDacGain(int gain) // +16*noiseSuppress and -16*noiseSuppress LSBs. (noiseSuppress = 0-127). void Rhd2000EvalBoard::setAudioNoiseSuppress(int noiseSuppress) { - if (noiseSuppress < 0 || noiseSuppress > 127) - { + if (noiseSuppress < 0 || noiseSuppress > 127) { cerr << "Error in Rhd2000EvalBoard::setAudioNoiseSuppress: noiseSuppress out of range." << endl; return; } @@ -1114,160 +1035,169 @@ void Rhd2000EvalBoard::setAudioNoiseSuppress(int noiseSuppress) dev->UpdateWireIns(); } -// Assign a particular data stream (0-7) to a DAC channel (0-7). +// Assign a particular data stream (0-7) to a DAC channel (0-7). Setting stream +// to 8 selects DacManual1 value; setting stream to 9 selects DacManual2 value. void Rhd2000EvalBoard::selectDacDataStream(int dacChannel, int stream) { - if (dacChannel < 0 || dacChannel > 7) - { + if (dacChannel < 0 || dacChannel > 7) { cerr << "Error in Rhd2000EvalBoard::selectDacDataStream: dacChannel out of range." << endl; return; } - if (stream < 0 || stream > 9) - { + if (stream < 0 || stream > 9) { cerr << "Error in Rhd2000EvalBoard::selectDacDataStream: stream out of range." << endl; return; } - dacStreamAssignment[dacChannel] = stream; - switch (dacChannel) - { - case 0: - dev->SetWireInValue(WireInDacSource1, stream << 5, 0x01e0); - break; - case 1: - dev->SetWireInValue(WireInDacSource2, stream << 5, 0x01e0); - break; - case 2: - dev->SetWireInValue(WireInDacSource3, stream << 5, 0x01e0); - break; - case 3: - dev->SetWireInValue(WireInDacSource4, stream << 5, 0x01e0); - break; - case 4: - dev->SetWireInValue(WireInDacSource5, stream << 5, 0x01e0); - break; - case 5: - dev->SetWireInValue(WireInDacSource6, stream << 5, 0x01e0); - break; - case 6: - dev->SetWireInValue(WireInDacSource7, stream << 5, 0x01e0); - break; - case 7: - dev->SetWireInValue(WireInDacSource8, stream << 5, 0x01e0); - break; + + switch (dacChannel) { + case 0: + dev->SetWireInValue(WireInDacSource1, stream << 5, 0x01e0); + break; + case 1: + dev->SetWireInValue(WireInDacSource2, stream << 5, 0x01e0); + break; + case 2: + dev->SetWireInValue(WireInDacSource3, stream << 5, 0x01e0); + break; + case 3: + dev->SetWireInValue(WireInDacSource4, stream << 5, 0x01e0); + break; + case 4: + dev->SetWireInValue(WireInDacSource5, stream << 5, 0x01e0); + break; + case 5: + dev->SetWireInValue(WireInDacSource6, stream << 5, 0x01e0); + break; + case 6: + dev->SetWireInValue(WireInDacSource7, stream << 5, 0x01e0); + break; + case 7: + dev->SetWireInValue(WireInDacSource8, stream << 5, 0x01e0); + break; } dev->UpdateWireIns(); } -void Rhd2000EvalBoard::setFastSettleByTTL(bool state) - +// Assign a particular amplifier channel (0-31) to a DAC channel (0-7). +void Rhd2000EvalBoard::selectDacDataChannel(int dacChannel, int dataChannel) { - dev->SetWireInValue(WireInResetRun, (state ? 0x10 : 0x00), 0x10); - dev->UpdateWireIns(); -} + if (dacChannel < 0 || dacChannel > 7) { + cerr << "Error in Rhd2000EvalBoard::selectDacDataChannel: dacChannel out of range." << endl; + return; + } -void Rhd2000EvalBoard::setFastSettleByTTLchannel(int channel) -{ - if (channel < 0 || channel > 7) - { - cerr << "Error in Rhd2000EvalBoard::setFastSettleByTTLchannel: channel out of range." << endl; + if (dataChannel < 0 || dataChannel > 31) { + cerr << "Error in Rhd2000EvalBoard::selectDacDataChannel: dataChannel out of range." << endl; return; } -// the WireInTTLSettleChannel is also used by DAC, so keep the values of 10 used bits - // and shift the channel value 10 bits to the left - dev->SetWireInValue(WireInTTLSettleChannel, channel << 10, 0x3c00); + + switch (dacChannel) { + case 0: + dev->SetWireInValue(WireInDacSource1, dataChannel << 0, 0x001f); + break; + case 1: + dev->SetWireInValue(WireInDacSource2, dataChannel << 0, 0x001f); + break; + case 2: + dev->SetWireInValue(WireInDacSource3, dataChannel << 0, 0x001f); + break; + case 3: + dev->SetWireInValue(WireInDacSource4, dataChannel << 0, 0x001f); + break; + case 4: + dev->SetWireInValue(WireInDacSource5, dataChannel << 0, 0x001f); + break; + case 5: + dev->SetWireInValue(WireInDacSource6, dataChannel << 0, 0x001f); + break; + case 6: + dev->SetWireInValue(WireInDacSource7, dataChannel << 0, 0x001f); + break; + case 7: + dev->SetWireInValue(WireInDacSource8, dataChannel << 0, 0x001f); + break; + } dev->UpdateWireIns(); } - - // Enable external triggering of amplifier hardware 'fast settle' function (blanking). -// If external triggering is enabled, this fast settling of amplifiers on all connected +// If external triggering is enabled, the fast settling of amplifiers on all connected // chips will be controlled in real time via one of the 16 TTL inputs. void Rhd2000EvalBoard::enableExternalFastSettle(bool enable) { - fast_settle_enabled = enable; dev->SetWireInValue(WireInMultiUse, enable ? 1 : 0); dev->UpdateWireIns(); dev->ActivateTriggerIn(TrigInExtFastSettle, 0); } -bool Rhd2000EvalBoard::getExternalFastSettle() -{ - return fast_settle_enabled; -} // Select which of the TTL inputs 0-15 is used to perform a hardware 'fast settle' (blanking) -// of the amplifiers if external triggering of fast settling -// is enabled. +// of the amplifiers if external triggering of fast settling is enabled. void Rhd2000EvalBoard::setExternalFastSettleChannel(int channel) { if (channel < 0 || channel > 15) { cerr << "Error in Rhd2000EvalBoard::setExternalFastSettleChannel: channel out of range." << endl; return; } + dev->SetWireInValue(WireInMultiUse, channel); dev->UpdateWireIns(); dev->ActivateTriggerIn(TrigInExtFastSettle, 1); } -int Rhd2000EvalBoard::gecDacDataChannel(int dacChannel) +// Enable external control of RHD2000 auxiliary digital output pin (auxout). +// If external control is enabled, the digital output of all chips connected to a +// selected SPI port will be controlled in real time via one of the 16 TTL inputs. +void Rhd2000EvalBoard::enableExternalDigOut(BoardPort port, bool enable) { - if (dacChannel < 0 || dacChannel > 7) - return -1; - return dacChannelAssignment[dacChannel]; -} + dev->SetWireInValue(WireInMultiUse, enable ? 1 : 0); + dev->UpdateWireIns(); -void Rhd2000EvalBoard::updateDacAssignment(int dacChannel, int stream, int channel) -{ - dacStreamAssignment[dacChannel] = stream; - dacChannelAssignment[dacChannel] = channel; - //selectDacDataStream + switch (port) { + case PortA: + dev->ActivateTriggerIn(TrigInExtDigOut, 0); + break; + case PortB: + dev->ActivateTriggerIn(TrigInExtDigOut, 1); + break; + case PortC: + dev->ActivateTriggerIn(TrigInExtDigOut, 2); + break; + case PortD: + dev->ActivateTriggerIn(TrigInExtDigOut, 3); + break; + default: + cerr << "Error in Rhd2000EvalBoard::enableExternalDigOut: port out of range." << endl; + } } -// Assign a particular amplifier channel (0-31) to a DAC channel (0-7). -void Rhd2000EvalBoard::selectDacDataChannel(int dacChannel, int dataChannel) +// Select which of the TTL inputs 0-15 is used to control the auxiliary digital output +// pin of the chips connected to a particular SPI port, if external control of auxout is enabled. +void Rhd2000EvalBoard::setExternalDigOutChannel(BoardPort port, int channel) { - if (dacChannel < 0 || dacChannel > 7) - { - cerr << "Error in Rhd2000EvalBoard::selectDacDataChannel: dacChannel out of range." << endl; + if (channel < 0 || channel > 15) { + cerr << "Error in Rhd2000EvalBoard::setExternalDigOutChannel: channel out of range." << endl; return; } - if (dataChannel < 0 || dataChannel > 31) - { - cerr << "Error in Rhd2000EvalBoard::selectDacDataChannel: dataChannel out of range." << endl; - return; - } - dacChannelAssignment[dacChannel] = dataChannel; + dev->SetWireInValue(WireInMultiUse, channel); + dev->UpdateWireIns(); - switch (dacChannel) - { - case 0: - dev->SetWireInValue(WireInDacSource1, dataChannel << 0, 0x001f); - break; - case 1: - dev->SetWireInValue(WireInDacSource2, dataChannel << 0, 0x001f); - break; - case 2: - dev->SetWireInValue(WireInDacSource3, dataChannel << 0, 0x001f); - break; - case 3: - dev->SetWireInValue(WireInDacSource4, dataChannel << 0, 0x001f); - break; - case 4: - dev->SetWireInValue(WireInDacSource5, dataChannel << 0, 0x001f); - break; - case 5: - dev->SetWireInValue(WireInDacSource6, dataChannel << 0, 0x001f); - break; - case 6: - dev->SetWireInValue(WireInDacSource7, dataChannel << 0, 0x001f); - break; - case 7: - dev->SetWireInValue(WireInDacSource8, dataChannel << 0, 0x001f); - break; + switch (port) { + case PortA: + dev->ActivateTriggerIn(TrigInExtDigOut, 4); + break; + case PortB: + dev->ActivateTriggerIn(TrigInExtDigOut, 5); + break; + case PortC: + dev->ActivateTriggerIn(TrigInExtDigOut, 6); + break; + case PortD: + dev->ActivateTriggerIn(TrigInExtDigOut, 7); + break; + default: + cerr << "Error in Rhd2000EvalBoard::setExternalDigOutChannel: port out of range." << endl; } - dev->UpdateWireIns(); } // Enable optional FPGA-implemented digital high-pass filters associated with DAC outputs @@ -1316,28 +1246,7 @@ void Rhd2000EvalBoard::setDacHighpassFilter(double cutoff) // in the range of 0 to 65535, where the 'zero' level is 32768. // If trigPolarity is true, voltages equaling or rising above the threshold produce a high TTL output. // If trigPolarity is false, voltages equaling or falling below the threshold produce a high TTL output. -// -// To convert threshold in voltage to this range, use the following: -// int threshLevel = ((double) threshold / 0.195) + 32768; -// evalBoard->setDacThreshold(0, threshLevel, threshold >= 0); - -void Rhd2000EvalBoard::setDacThresholdVoltage(int dacChannel, float voltage_threshold) -{ - int threshLevel = (voltage_threshold / 0.195) + 32768; - setDacThreshold(dacChannel, abs(threshLevel), voltage_threshold >= 0); - -} - -void Rhd2000EvalBoard::getDacInformation(int *ch, float *th) -{ - for (int k=0;k<8;k++) - { - ch[k] = dacChannelAssignment[k]; - th[k] = dacChannelThreshold[k]; - } -} - -void Rhd2000EvalBoard::setDacThreshold(int dacChannel, int threshold, bool trigPolarityPositive) +void Rhd2000EvalBoard::setDacThreshold(int dacChannel, int threshold, bool trigPolarity) { if (dacChannel < 0 || dacChannel > 7) { cerr << "Error in Rhd2000EvalBoard::setDacThreshold: dacChannel out of range." << endl; @@ -1348,7 +1257,6 @@ void Rhd2000EvalBoard::setDacThreshold(int dacChannel, int threshold, bool trigP cerr << "Error in Rhd2000EvalBoard::setDacThreshold: threshold out of range." << endl; return; } - dacChannelThreshold[dacChannel] = trigPolarityPositive? -(float)(threshold-32768)*0.195 : (float)(threshold-32768)*0.195; // Set threshold level. dev->SetWireInValue(WireInMultiUse, threshold); @@ -1356,7 +1264,7 @@ void Rhd2000EvalBoard::setDacThreshold(int dacChannel, int threshold, bool trigP dev->ActivateTriggerIn(TrigInDacThresh, dacChannel); // Set threshold polarity. - dev->SetWireInValue(WireInMultiUse, (trigPolarityPositive ? 1 : 0)); + dev->SetWireInValue(WireInMultiUse, (trigPolarity ? 1 : 0)); dev->UpdateWireIns(); dev->ActivateTriggerIn(TrigInDacThresh, dacChannel + 8); } @@ -1402,28 +1310,25 @@ bool Rhd2000EvalBoard::isDataClockLocked() const // data acquisition has been stopped.) void Rhd2000EvalBoard::flush() { - while (numWordsInFifo() >= USB_BUFFER_SIZE / 2) - { + while (numWordsInFifo() >= USB_BUFFER_SIZE / 2) { dev->ReadFromPipeOut(PipeOutData, USB_BUFFER_SIZE, usbBuffer); } - while (numWordsInFifo() > 0) - { + while (numWordsInFifo() > 0) { dev->ReadFromPipeOut(PipeOutData, 2 * numWordsInFifo(), usbBuffer); } } // Read data block from the USB interface, if one is available. Returns true if data block // was available. -bool Rhd2000EvalBoard::readDataBlock(Rhd2000DataBlock* dataBlock) +bool Rhd2000EvalBoard::readDataBlock(Rhd2000DataBlock *dataBlock) { unsigned int numBytesToRead; numBytesToRead = 2 * dataBlock->calculateDataBlockSizeInWords(numDataStreams); - if (numBytesToRead > USB_BUFFER_SIZE) - { + if (numBytesToRead > USB_BUFFER_SIZE) { cerr << "Error in Rhd2000EvalBoard::readDataBlock: USB buffer size exceeded. " << - "Increase value of USB_BUFFER_SIZE." << endl; + "Increase value of USB_BUFFER_SIZE." << endl; return false; } @@ -1440,7 +1345,7 @@ bool Rhd2000EvalBoard::readDataBlocks(int numBlocks, queue<Rhd2000DataBlock> &da { unsigned int numWordsToRead, numBytesToRead; int i; - Rhd2000DataBlock* dataBlock; + Rhd2000DataBlock *dataBlock; numWordsToRead = numBlocks * dataBlock->calculateDataBlockSizeInWords(numDataStreams); @@ -1449,22 +1354,18 @@ bool Rhd2000EvalBoard::readDataBlocks(int numBlocks, queue<Rhd2000DataBlock> &da numBytesToRead = 2 * numWordsToRead; - if (numBytesToRead > USB_BUFFER_SIZE) - { + if (numBytesToRead > USB_BUFFER_SIZE) { cerr << "Error in Rhd2000EvalBoard::readDataBlocks: USB buffer size exceeded. " << - "Increase value of USB_BUFFER_SIZE." << endl; + "Increase value of USB_BUFFER_SIZE." << endl; return false; } dev->ReadFromPipeOut(PipeOutData, numBytesToRead, usbBuffer); dataBlock = new Rhd2000DataBlock(numDataStreams); - for (i = 0; i < numBlocks; ++i) - { - // dataBlock = new Rhd2000DataBlock(numDataStreams); + for (i = 0; i < numBlocks; ++i) { dataBlock->fillFromUsbBuffer(usbBuffer, i, numDataStreams); dataQueue.push(*dataBlock); - // delete dataBlock; } delete dataBlock; @@ -1473,12 +1374,11 @@ bool Rhd2000EvalBoard::readDataBlocks(int numBlocks, queue<Rhd2000DataBlock> &da // Writes the contents of a data block queue (dataQueue) to a binary output stream (saveOut). // Returns the number of data blocks written. -int Rhd2000EvalBoard::queueToFile(queue<Rhd2000DataBlock> &dataQueue, ofstream& saveOut) +int Rhd2000EvalBoard::queueToFile(queue<Rhd2000DataBlock> &dataQueue, ofstream &saveOut) { int count = 0; - while (!dataQueue.empty()) - { + while (!dataQueue.empty()) { dataQueue.front().write(saveOut, getNumEnabledDataStreams()); dataQueue.pop(); ++count; @@ -1490,69 +1390,68 @@ int Rhd2000EvalBoard::queueToFile(queue<Rhd2000DataBlock> &dataQueue, ofstream& // Return name of Opal Kelly board based on model code. string Rhd2000EvalBoard::opalKellyModelName(int model) const { - switch (model) - { - case OK_PRODUCT_XEM3001V1: - return("XEM3001V1"); - case OK_PRODUCT_XEM3001V2: - return("XEM3001V2"); - case OK_PRODUCT_XEM3010: - return("XEM3010"); - case OK_PRODUCT_XEM3005: - return("XEM3005"); - case OK_PRODUCT_XEM3001CL: - return("XEM3001CL"); - case OK_PRODUCT_XEM3020: - return("XEM3020"); - case OK_PRODUCT_XEM3050: - return("XEM3050"); - case OK_PRODUCT_XEM9002: - return("XEM9002"); - case OK_PRODUCT_XEM3001RB: - return("XEM3001RB"); - case OK_PRODUCT_XEM5010: - return("XEM5010"); - case OK_PRODUCT_XEM6110LX45: - return("XEM6110LX45"); - case OK_PRODUCT_XEM6001: - return("XEM6001"); - case OK_PRODUCT_XEM6010LX45: - return("XEM6010LX45"); - case OK_PRODUCT_XEM6010LX150: - return("XEM6010LX150"); - case OK_PRODUCT_XEM6110LX150: - return("XEM6110LX150"); - case OK_PRODUCT_XEM6006LX9: - return("XEM6006LX9"); - case OK_PRODUCT_XEM6006LX16: - return("XEM6006LX16"); - case OK_PRODUCT_XEM6006LX25: - return("XEM6006LX25"); - case OK_PRODUCT_XEM5010LX110: - return("XEM5010LX110"); - case OK_PRODUCT_ZEM4310: - return("ZEM4310"); - case OK_PRODUCT_XEM6310LX45: - return("XEM6310LX45"); - case OK_PRODUCT_XEM6310LX150: - return("XEM6310LX150"); - case OK_PRODUCT_XEM6110V2LX45: - return("XEM6110V2LX45"); - case OK_PRODUCT_XEM6110V2LX150: - return("XEM6110V2LX150"); - case OK_PRODUCT_XEM6002LX9: - return("XEM6002LX9"); - case OK_PRODUCT_XEM6310MTLX45: - return("XEM6310MTLX45"); - case OK_PRODUCT_XEM6320LX130T: - return("XEM6320LX130T"); - default: - return("UNKNOWN"); + switch (model) { + case OK_PRODUCT_XEM3001V1: + return("XEM3001V1"); + case OK_PRODUCT_XEM3001V2: + return("XEM3001V2"); + case OK_PRODUCT_XEM3010: + return("XEM3010"); + case OK_PRODUCT_XEM3005: + return("XEM3005"); + case OK_PRODUCT_XEM3001CL: + return("XEM3001CL"); + case OK_PRODUCT_XEM3020: + return("XEM3020"); + case OK_PRODUCT_XEM3050: + return("XEM3050"); + case OK_PRODUCT_XEM9002: + return("XEM9002"); + case OK_PRODUCT_XEM3001RB: + return("XEM3001RB"); + case OK_PRODUCT_XEM5010: + return("XEM5010"); + case OK_PRODUCT_XEM6110LX45: + return("XEM6110LX45"); + case OK_PRODUCT_XEM6001: + return("XEM6001"); + case OK_PRODUCT_XEM6010LX45: + return("XEM6010LX45"); + case OK_PRODUCT_XEM6010LX150: + return("XEM6010LX150"); + case OK_PRODUCT_XEM6110LX150: + return("XEM6110LX150"); + case OK_PRODUCT_XEM6006LX9: + return("XEM6006LX9"); + case OK_PRODUCT_XEM6006LX16: + return("XEM6006LX16"); + case OK_PRODUCT_XEM6006LX25: + return("XEM6006LX25"); + case OK_PRODUCT_XEM5010LX110: + return("XEM5010LX110"); + case OK_PRODUCT_ZEM4310: + return("ZEM4310"); + case OK_PRODUCT_XEM6310LX45: + return("XEM6310LX45"); + case OK_PRODUCT_XEM6310LX150: + return("XEM6310LX150"); + case OK_PRODUCT_XEM6110V2LX45: + return("XEM6110V2LX45"); + case OK_PRODUCT_XEM6110V2LX150: + return("XEM6110V2LX150"); + case OK_PRODUCT_XEM6002LX9: + return("XEM6002LX9"); + case OK_PRODUCT_XEM6310MTLX45: + return("XEM6310MTLX45"); + case OK_PRODUCT_XEM6320LX130T: + return("XEM6320LX130T"); + default: + return("UNKNOWN"); } } // Return 4-bit "board mode" input. -int Rhd2000EvalBoard::getBoardMode() +int Rhd2000EvalBoard::getBoardMode() const { int mode; @@ -1564,3 +1463,45 @@ int Rhd2000EvalBoard::getBoardMode() return mode; } +// Return FPGA cable delay for selected SPI port. +int Rhd2000EvalBoard::getCableDelay(BoardPort port) const +{ + switch (port) { + case PortA: + return cableDelay[0]; + case PortB: + return cableDelay[1]; + case PortC: + return cableDelay[2]; + case PortD: + return cableDelay[3]; + default: + cerr << "Error in RHD2000EvalBoard::getCableDelay: unknown port." << endl; + return -1; + } +} + +// Return FPGA cable delays for all SPI ports. +void Rhd2000EvalBoard::getCableDelay(vector<int> &delays) const +{ + if (delays.size() != 4) { + delays.resize(4); + } + for (int i = 0; i < 4; ++i) { + delays[i] = cableDelay[i]; + } +} + +// Uses the Opal Kelly library to reset the FPGA +void Rhd2000EvalBoard::resetFpga() +{ + dev->ResetFPGA(); +} + +bool Rhd2000EvalBoard::isStreamEnabled(int streamIndex) +{ + if (streamIndex < 0 || streamIndex > (MAX_NUM_DATA_STREAMS - 1)) + return false; + + return dataStreamEnabled[streamIndex]; +} diff --git a/Source/Processors/DataThreads/rhythm-api/rhd2000evalboard.h b/Source/Processors/DataThreads/rhythm-api/rhd2000evalboard.h index 3d670a18fbb935f0b736cafbc2b0769ef14ca8ab..a3238db0baf931549ddebd027ea044e3a270a456 100755 --- a/Source/Processors/DataThreads/rhythm-api/rhd2000evalboard.h +++ b/Source/Processors/DataThreads/rhythm-api/rhd2000evalboard.h @@ -3,9 +3,9 @@ // // Intan Technoloies RHD2000 Rhythm Interface API // Rhd2000EvalBoard Class Header File -// Version 1.0 (14 January 2013) +// Version 1.4 (26 February 2014) // -// Copyright (c) 2013 Intan Technologies LLC +// Copyright (c) 2013-2014 Intan Technologies LLC // // This software is provided 'as-is', without any express or implied warranty. // In no event will the authors be held liable for any damages arising from the @@ -38,14 +38,13 @@ class Rhd2000EvalBoard public: Rhd2000EvalBoard(); - ~Rhd2000EvalBoard(); + ~Rhd2000EvalBoard(); - int open(const char* libname); + int open(const char* libname); //patched to allow selecting path to dll bool uploadFpgaBitfile(string filename); void initialize(); - enum AmplifierSampleRate - { + enum AmplifierSampleRate { SampleRate1000Hz, SampleRate1250Hz, SampleRate1500Hz, @@ -69,15 +68,13 @@ public: double getSampleRate() const; AmplifierSampleRate getSampleRateEnum() const; - enum AuxCmdSlot - { + enum AuxCmdSlot { AuxCmd1, AuxCmd2, AuxCmd3 }; - enum BoardPort - { + enum BoardPort { PortA, PortB, PortC, @@ -89,10 +86,6 @@ public: void selectAuxCommandBank(BoardPort port, AuxCmdSlot auxCommandSlot, int bank); void selectAuxCommandLength(AuxCmdSlot auxCommandSlot, int loopIndex, int endIndex); - void runImpedance(); - bool getExternalFastSettle(); - - void resetBoard(); void setContinuousRunMode(bool continuousMode); void setMaxTimeStep(unsigned int maxTimeStep); @@ -100,22 +93,16 @@ public: bool isRunning() const; unsigned int numWordsInFifo() const; static unsigned int fifoCapacityInWords(); - void setDacThresholdVoltage(int dacChannel, float voltage_threshold); - void setDacThreshold(int dacChannel, int threshold, bool trigPolarity); - void enableDacHighpassFilter(bool enable); - void setDacHighpassFilter(double cutoff); + void setCableDelay(BoardPort port, int delay); void setCableLengthMeters(BoardPort port, double lengthInMeters); void setCableLengthFeet(BoardPort port, double lengthInFeet); double estimateCableLengthMeters(int delay) const; double estimateCableLengthFeet(int delay) const; - void setTtlMode(int mode); + void setDspSettle(bool enabled); - int getBoardMode(); - void getDacInformation(int *ch, float *th); - enum BoardDataSource - { + enum BoardDataSource { PortA1 = 0, PortA2 = 1, PortB1 = 2, @@ -136,20 +123,13 @@ public: void setDataSource(int stream, BoardDataSource dataSource); void enableDataStream(int stream, bool enabled); - bool isStreamEnabled(int streamIndex); int getNumEnabledDataStreams() const; void clearTtlOut(); void setTtlOut(int ttlOutArray[]); void getTtlIn(int ttlInArray[]); - enum DacManual - { - DacManual1, - DacManual2 - }; - - void setDacManual(DacManual dac, int value); + void setDacManual(int value); void setLedDisplay(int ledArray[]); @@ -158,37 +138,39 @@ public: void setAudioNoiseSuppress(int noiseSuppress); void selectDacDataStream(int dacChannel, int stream); void selectDacDataChannel(int dacChannel, int dataChannel); - - int gecDacDataChannel(int dacChannel); - void updateDacAssignment(int dacChannel, int stream, int channel); void enableExternalFastSettle(bool enable); void setExternalFastSettleChannel(int channel); - void setFastSettleByTTL(bool state); - void setFastSettleByTTLchannel(int channel); + void enableExternalDigOut(BoardPort port, bool enable); + void setExternalDigOutChannel(BoardPort port, int channel); + void enableDacHighpassFilter(bool enable); + void setDacHighpassFilter(double cutoff); + void setDacThreshold(int dacChannel, int threshold, bool trigPolarity); + void setTtlMode(int mode); void flush(); - bool readDataBlock(Rhd2000DataBlock* dataBlock); + bool readDataBlock(Rhd2000DataBlock *dataBlock); bool readDataBlocks(int numBlocks, queue<Rhd2000DataBlock> &dataQueue); - int queueToFile(queue<Rhd2000DataBlock> &dataQueue, std::ofstream& saveOut); + int queueToFile(queue<Rhd2000DataBlock> &dataQueue, std::ofstream &saveOut); + int getBoardMode() const; + int getCableDelay(BoardPort port) const; + void getCableDelay(vector<int> &delays) const; - void resetFpga(); + //Additions by open-ephys + void resetFpga(); + bool isStreamEnabled(int streamIndex); private: - okCFrontPanel* dev; + okCFrontPanel *dev; AmplifierSampleRate sampleRate; int numDataStreams; // total number of data streams currently enabled int dataStreamEnabled[MAX_NUM_DATA_STREAMS]; // 0 (disabled) or 1 (enabled) - int *dacChannelAssignment; - int *dacStreamAssignment; - float *dacChannelThreshold; - bool fast_settle_enabled; + vector<int> cableDelay; // Buffer for reading bytes from USB interface unsigned char usbBuffer[USB_BUFFER_SIZE]; // Opal Kelly module USB interface endpoint addresses - enum OkEndPoint - { + enum OkEndPoint { WireInResetRun = 0x00, WireInMaxTimeStepLsb = 0x01, WireInMaxTimeStepMsb = 0x02, @@ -219,18 +201,16 @@ private: WireInDacSource6 = 0x1b, WireInDacSource7 = 0x1c, WireInDacSource8 = 0x1d, - WireInDacManual1 = 0x1e, - WireInDacManual2 = 0x1f, - WireInMultiUse = 0x1f, + WireInDacManual = 0x1e, + WireInMultiUse = 0x1f, - WireInTTLSettleChannel = 0x16, TrigInDcmProg = 0x40, TrigInSpiStart = 0x41, TrigInRamWrite = 0x42, TrigInDacThresh = 0x43, TrigInDacHpf = 0x44, TrigInExtFastSettle = 0x45, - + TrigInExtDigOut = 0x46, WireOutNumWordsLsb = 0x20, WireOutNumWordsMsb = 0x21, @@ -249,6 +229,7 @@ private: bool isDcmProgDone() const; bool isDataClockLocked() const; + }; #endif // RHD2000EVALBOARD_H diff --git a/Source/Processors/DataThreads/rhythm-api/rhd2000registers.cpp b/Source/Processors/DataThreads/rhythm-api/rhd2000registers.cpp index 3fe9e2aa6ad861140b86296c2ed4b5a3b139500d..e2857da04086d095adfe0537d2ca5e813eb74811 100755 --- a/Source/Processors/DataThreads/rhythm-api/rhd2000registers.cpp +++ b/Source/Processors/DataThreads/rhythm-api/rhd2000registers.cpp @@ -3,9 +3,9 @@ // // Intan Technoloies RHD2000 Rhythm Interface API // Rhd2000Registers Class -// Version 1.0 (14 January 2013) +// Version 1.4 (26 February 2014) // -// Copyright (c) 2013 Intan Technologies LLC +// Copyright (c) 2013-2014 Intan Technologies LLC // // This software is provided 'as-is', without any express or implied warranty. // In no event will the authors be held liable for any damages arising from the @@ -20,10 +20,9 @@ #include <iostream> #include <iomanip> -#include <math.h> +#include <cmath> #include <vector> #include <queue> -#include <cmath> #include "rhd2000registers.h" @@ -38,41 +37,41 @@ using namespace std; // Constructor. Set RHD2000 register variables to default values. Rhd2000Registers::Rhd2000Registers(double sampleRate) { - aPwr.resize(32); + aPwr.resize(64); defineSampleRate(sampleRate); // Set default values for all register settings adcReferenceBw = 3; // ADC reference generator bandwidth (0 [highest BW] - 3 [lowest BW]); - // always set to 3 + // always set to 3 setFastSettle(false); // amplifier fast settle (off = normal operation) ampVrefEnable = 1; // enable amplifier voltage references (0 = power down; 1 = enable); - // 1 = normal operation + // 1 = normal operation adcComparatorBias = 3; // ADC comparator preamp bias current (0 [lowest] - 3 [highest], only - // valid for comparator select = 2,3); always set to 3 + // valid for comparator select = 2,3); always set to 3 adcComparatorSelect = 2; // ADC comparator select; always set to 2 vddSenseEnable = 1; // supply voltage sensor enable (0 = disable; 1 = enable) // adcBufferBias = 32; // ADC reference buffer bias current (0 [highest current] - 63 [lowest current]); - // This value should be set according to ADC sampling rate; set in setSampleRate() + // This value should be set according to ADC sampling rate; set in setSampleRate() // muxBias = 40; // ADC input MUX bias current (0 [highest current] - 63 [lowest current]); - // This value should be set according to ADC sampling rate; set in setSampleRate() + // This value should be set according to ADC sampling rate; set in setSampleRate() // muxLoad = 0; // MUX capacitance load at ADC input (0 [min CL] - 7 [max CL]); LSB = 3 pF - // Set in setSampleRate() + // Set in setSampleRate() tempS1 = 0; // temperature sensor S1 (0-1); 0 = power saving mode when temperature sensor is - // not in use + // not in use tempS2 = 0; // temperature sensor S2 (0-1); 0 = power saving mode when temperature sensor is - // not in use + // not in use tempEn = 0; // temperature sensor enable (0 = disable; 1 = enable) setDigOutHiZ(); // auxiliary digital output state weakMiso = 1; // weak MISO (0 = MISO line is HiZ when CS is inactive; 1 = MISO line is weakly - // driven when CS is inactive) + // driven when CS is inactive) twosComp = 0; // two's complement ADC results (0 = unsigned offset representation; 1 = signed - // representation) + // representation) absMode = 0; // absolute value mode (0 = normal output; 1 = output passed through abs(x) function) enableDsp(true); // DSP offset removal enable/disable setDspCutoffFreq(1.0); // DSP offset removal HPF cutoff freqeuncy @@ -82,10 +81,10 @@ Rhd2000Registers::Rhd2000Registers(double sampleRate) setZcheckScale(ZcheckCs100fF); // impedance testing scale factor (100 fF, 1.0 pF, or 10.0 pF) zcheckConnAll = 0; // impedance testing connect all (0 = normal operation; 1 = connect all electrodes together) setZcheckPolarity(ZcheckPositiveInput); // impedance testing polarity select (RHD2216 only) (0 = test positive inputs; - // 1 = test negative inputs) + // 1 = test negative inputs) enableZcheck(false); // impedance testing enable/disable - setZcheckChannel(0); // impedance testing amplifier select (0-63, but MSB is ignored, so 0-31 in practice) + setZcheckChannel(0); // impedance testing amplifier select (0-63) offChipRH1 = 0; // bandwidth resistor RH1 on/off chip (0 = on chip; 1 = off chip) offChipRH2 = 0; // bandwidth resistor RH2 on/off chip (0 = on chip; 1 = off chip) @@ -108,48 +107,31 @@ void Rhd2000Registers::defineSampleRate(double newSampleRate) muxLoad = 0; - if (sampleRate < 3334.0) - { + if (sampleRate < 3334.0) { muxBias = 40; adcBufferBias = 32; - } - else if (sampleRate < 4001.0) - { + } else if (sampleRate < 4001.0) { muxBias = 40; adcBufferBias = 16; - } - else if (sampleRate < 5001.0) - { + } else if (sampleRate < 5001.0) { muxBias = 40; adcBufferBias = 8; - } - else if (sampleRate < 6251.0) - { + } else if (sampleRate < 6251.0) { muxBias = 32; adcBufferBias = 8; - } - else if (sampleRate < 8001.0) - { + } else if (sampleRate < 8001.0) { muxBias = 26; adcBufferBias = 8; - } - else if (sampleRate < 10001.0) - { + } else if (sampleRate < 10001.0) { muxBias = 18; adcBufferBias = 4; - } - else if (sampleRate < 12501.0) - { + } else if (sampleRate < 12501.0) { muxBias = 16; adcBufferBias = 3; - } - else if (sampleRate < 15001.0) - { + } else if (sampleRate < 15001.0) { muxBias = 7; adcBufferBias = 3; - } - else - { + } else { muxBias = 4; adcBufferBias = 2; } @@ -220,8 +202,7 @@ double Rhd2000Registers::setDspCutoffFreq(double newDspCutoffFreq) logNewDspCutoffFreq = log10(newDspCutoffFreq); // Generate table of all possible DSP cutoff frequencies - for (n = 1; n < 16; ++n) - { + for (n = 1; n < 16; ++n) { x = pow(2.0, (double) n); fCutoff[n] = sampleRate * log(x / (x - 1.0)) / (2*Pi); logFCutoff[n] = log10(fCutoff[n]); @@ -229,21 +210,14 @@ double Rhd2000Registers::setDspCutoffFreq(double newDspCutoffFreq) } // Now find the closest value to the requested cutoff frequency (on a logarithmic scale) - if (newDspCutoffFreq > fCutoff[1]) - { + if (newDspCutoffFreq > fCutoff[1]) { dspCutoffFreq = 1; - } - else if (newDspCutoffFreq < fCutoff[15]) - { + } else if (newDspCutoffFreq < fCutoff[15]) { dspCutoffFreq = 15; - } - else - { + } else { minLogDiff = 10000000.0; - for (n = 1; n < 16; ++n) - { - if (abs(logNewDspCutoffFreq - logFCutoff[n]) < minLogDiff) - { + for (n = 1; n < 16; ++n) { + if (abs(logNewDspCutoffFreq - logFCutoff[n]) < minLogDiff) { minLogDiff = abs(logNewDspCutoffFreq - logFCutoff[n]); dspCutoffFreq = n; } @@ -281,8 +255,7 @@ void Rhd2000Registers::setZcheckDacPower(bool enabled) // (ZcheckCs100fF, ZcheckCs1pF, or Zcheck10pF). void Rhd2000Registers::setZcheckScale(ZcheckCs scale) { - switch (scale) - { + switch (scale) { case ZcheckCs100fF: zcheckScale = 0x00; // Cs = 0.1 pF break; @@ -299,26 +272,22 @@ void Rhd2000Registers::setZcheckScale(ZcheckCs scale) // on the variable polarity (ZcheckPositiveInput or ZcheckNegativeInput) void Rhd2000Registers::setZcheckPolarity(ZcheckPolarity polarity) { - switch (polarity) - { + switch (polarity) { case ZcheckPositiveInput: zcheckSelPol = 0; break; - case ZcheckNegativeInput: + case ZcheckNegativeInput: zcheckSelPol = 1; break; } } -// Select the amplifier channel (0-31) for impedance testing. +// Select the amplifier channel (0-63) for impedance testing. int Rhd2000Registers::setZcheckChannel(int channel) { - if (channel < 0 || channel > 31) - { + if (channel < 0 || channel > 63) { return -1; - } - else - { + } else { zcheckSelect = channel; return zcheckSelect; } @@ -327,8 +296,7 @@ int Rhd2000Registers::setZcheckChannel(int channel) // Power up or down selected amplifier on chip void Rhd2000Registers::setAmpPowered(int channel, bool powered) { - if (channel >= 0 && channel <= 31) - { + if (channel >= 0 && channel <= 63) { aPwr[channel] = (powered ? 1 : 0); } } @@ -336,8 +304,7 @@ void Rhd2000Registers::setAmpPowered(int channel, bool powered) // Power up all amplifiers on chip void Rhd2000Registers::powerUpAllAmps() { - for (int channel = 0; channel < 32; ++channel) - { + for (int channel = 0; channel < 64; ++channel) { aPwr[channel] = 1; } } @@ -345,8 +312,7 @@ void Rhd2000Registers::powerUpAllAmps() // Power down all amplifiers on chip void Rhd2000Registers::powerDownAllAmps() { - for (int channel = 0; channel < 32; ++channel) - { + for (int channel = 0; channel < 64; ++channel) { aPwr[channel] = 0; } } @@ -358,72 +324,87 @@ int Rhd2000Registers::getRegisterValue(int reg) const int regout; const int zcheckDac = 128; // midrange - switch (reg) - { - case 0: - regout = (adcReferenceBw << 6) + (ampFastSettle << 5) + (ampVrefEnable << 4) + - (adcComparatorBias << 2) + adcComparatorSelect; - break; - case 1: - regout = (vddSenseEnable << 6) + adcBufferBias; - break; - case 2: - regout = muxBias; - break; - case 3: - regout = (muxLoad << 5) + (tempS2 << 4) + (tempS1 << 3) + (tempEn << 2) + - (digOutHiZ << 1) + digOut; - break; - case 4: - regout = (weakMiso << 7) + (twosComp << 6) + (absMode << 5) + (dspEn << 4) + - dspCutoffFreq; - break; - case 5: - regout = (zcheckDacPower << 6) + (zcheckLoad << 5) + (zcheckScale << 3) + - (zcheckConnAll << 2) + (zcheckSelPol << 1) + zcheckEn; - break; - case 6: - regout = zcheckDac; - break; - case 7: - regout = zcheckSelect; - break; - case 8: - regout = (offChipRH1 << 7) + rH1Dac1; - break; - case 9: - regout = (adcAux1En << 7) + rH1Dac2; - break; - case 10: - regout = (offChipRH2 << 7) + rH2Dac1; - break; - case 11: - regout = (adcAux2En << 7) + rH2Dac2; - break; - case 12: - regout = (offChipRL << 7) + rLDac1; - break; - case 13: - regout = (adcAux3En << 7) + (rLDac3 << 6) + rLDac2; - break; - case 14: - regout = (aPwr[7] << 7) + (aPwr[6] << 6) + (aPwr[5] << 5) + (aPwr[4] << 4) + - (aPwr[3] << 3) + (aPwr[2] << 2) + (aPwr[1] << 1) + aPwr[0]; - break; - case 15: - regout = (aPwr[15] << 7) + (aPwr[14] << 6) + (aPwr[13] << 5) + (aPwr[12] << 4) + - (aPwr[11] << 3) + (aPwr[10] << 2) + (aPwr[9] << 1) + aPwr[0]; - break; - case 16: - regout = (aPwr[23] << 7) + (aPwr[22] << 6) + (aPwr[21] << 5) + (aPwr[20] << 4) + - (aPwr[19] << 3) + (aPwr[18] << 2) + (aPwr[17] << 1) + aPwr[16]; - break; - case 17: - regout = (aPwr[31] << 7) + (aPwr[30] << 6) + (aPwr[29] << 5) + (aPwr[28] << 4) + - (aPwr[27] << 3) + (aPwr[26] << 2) + (aPwr[25] << 1) + aPwr[24]; - break; - default: - regout = -1; + switch (reg) { + case 0: + regout = (adcReferenceBw << 6) + (ampFastSettle << 5) + (ampVrefEnable << 4) + + (adcComparatorBias << 2) + adcComparatorSelect; + break; + case 1: + regout = (vddSenseEnable << 6) + adcBufferBias; + break; + case 2: + regout = muxBias; + break; + case 3: + regout = (muxLoad << 5) + (tempS2 << 4) + (tempS1 << 3) + (tempEn << 2) + + (digOutHiZ << 1) + digOut; + break; + case 4: + regout = (weakMiso << 7) + (twosComp << 6) + (absMode << 5) + (dspEn << 4) + + dspCutoffFreq; + break; + case 5: + regout = (zcheckDacPower << 6) + (zcheckLoad << 5) + (zcheckScale << 3) + + (zcheckConnAll << 2) + (zcheckSelPol << 1) + zcheckEn; + break; + case 6: + regout = zcheckDac; + break; + case 7: + regout = zcheckSelect; + break; + case 8: + regout = (offChipRH1 << 7) + rH1Dac1; + break; + case 9: + regout = (adcAux1En << 7) + rH1Dac2; + break; + case 10: + regout = (offChipRH2 << 7) + rH2Dac1; + break; + case 11: + regout = (adcAux2En << 7) + rH2Dac2; + break; + case 12: + regout = (offChipRL << 7) + rLDac1; + break; + case 13: + regout = (adcAux3En << 7) + (rLDac3 << 6) + rLDac2; + break; + case 14: + regout = (aPwr[7] << 7) + (aPwr[6] << 6) + (aPwr[5] << 5) + (aPwr[4] << 4) + + (aPwr[3] << 3) + (aPwr[2] << 2) + (aPwr[1] << 1) + aPwr[0]; + break; + case 15: + regout = (aPwr[15] << 7) + (aPwr[14] << 6) + (aPwr[13] << 5) + (aPwr[12] << 4) + + (aPwr[11] << 3) + (aPwr[10] << 2) + (aPwr[9] << 1) + aPwr[0]; + break; + case 16: + regout = (aPwr[23] << 7) + (aPwr[22] << 6) + (aPwr[21] << 5) + (aPwr[20] << 4) + + (aPwr[19] << 3) + (aPwr[18] << 2) + (aPwr[17] << 1) + aPwr[16]; + break; + case 17: + regout = (aPwr[31] << 7) + (aPwr[30] << 6) + (aPwr[29] << 5) + (aPwr[28] << 4) + + (aPwr[27] << 3) + (aPwr[26] << 2) + (aPwr[25] << 1) + aPwr[24]; + break; + case 18: + regout = (aPwr[39] << 7) + (aPwr[38] << 6) + (aPwr[37] << 5) + (aPwr[36] << 4) + + (aPwr[35] << 3) + (aPwr[34] << 2) + (aPwr[33] << 1) + aPwr[32]; + break; + case 19: + regout = (aPwr[47] << 7) + (aPwr[46] << 6) + (aPwr[45] << 5) + (aPwr[44] << 4) + + (aPwr[43] << 3) + (aPwr[42] << 2) + (aPwr[41] << 1) + aPwr[40]; + break; + case 20: + regout = (aPwr[55] << 7) + (aPwr[54] << 6) + (aPwr[53] << 5) + (aPwr[52] << 4) + + (aPwr[51] << 3) + (aPwr[50] << 2) + (aPwr[49] << 1) + aPwr[48]; + break; + case 21: + regout = (aPwr[63] << 7) + (aPwr[62] << 6) + (aPwr[61] << 5) + (aPwr[60] << 4) + + (aPwr[59] << 3) + (aPwr[58] << 2) + (aPwr[57] << 1) + aPwr[56]; + break; + default: + regout = -1; } return regout; } @@ -452,13 +433,10 @@ double Rhd2000Registers::rLFromLowerBandwidth(double lowerBandwidth) const { double log10f = log10(lowerBandwidth); - if (lowerBandwidth < 4.0) - { + if (lowerBandwidth < 4.0) { return 1.0061 * pow(10.0, (4.9391 - 1.2088 * log10f + 0.5698 * log10f * log10f + 0.1442 * log10f * log10f * log10f)); - } - else - { + } else { return 1.0061 * pow(10.0, (4.7351 - 0.5916 * log10f + 0.08482 * log10f * log10f)); } } @@ -496,19 +474,15 @@ double Rhd2000Registers::lowerBandwidthFromRL(double rL) const double a, b, c; // Quadratic fit below is invalid for values of RL less than 5.1 kOhm - if (rL < 5100.0) - { + if (rL < 5100.0) { rL = 5100.0; } - if (rL < 30000.0) - { + if (rL < 30000.0) { a = 0.08482; b = -0.5916; c = 4.7351 - log10(rL/1.0061); - } - else - { + } else { a = 0.3303; b = -1.2100; c = 4.9873 - log10(rL/1.0061); @@ -539,8 +513,7 @@ double Rhd2000Registers::setUpperBandwidth(double upperBandwidth) int i; // Upper bandwidths higher than 30 kHz don't work well with the RHD2000 amplifiers - if (upperBandwidth > 30000.0) - { + if (upperBandwidth > 30000.0) { upperBandwidth = 30000.0; } @@ -550,19 +523,15 @@ double Rhd2000Registers::setUpperBandwidth(double upperBandwidth) rH1Dac2 = 0; rH1Actual = RH1Base; - for (i = 0; i < RH1Dac2Steps; ++i) - { - if (rH1Actual < rH1Target - (RH1Dac2Unit - RH1Dac1Unit / 2)) - { + for (i = 0; i < RH1Dac2Steps; ++i) { + if (rH1Actual < rH1Target - (RH1Dac2Unit - RH1Dac1Unit / 2)) { rH1Actual += RH1Dac2Unit; ++rH1Dac2; } } - for (i = 0; i < RH1Dac1Steps; ++i) - { - if (rH1Actual < rH1Target - (RH1Dac1Unit / 2)) - { + for (i = 0; i < RH1Dac1Steps; ++i) { + if (rH1Actual < rH1Target - (RH1Dac1Unit / 2)) { rH1Actual += RH1Dac1Unit; ++rH1Dac1; } @@ -574,19 +543,15 @@ double Rhd2000Registers::setUpperBandwidth(double upperBandwidth) rH2Dac2 = 0; rH2Actual = RH2Base; - for (i = 0; i < RH2Dac2Steps; ++i) - { - if (rH2Actual < rH2Target - (RH2Dac2Unit - RH2Dac1Unit / 2)) - { + for (i = 0; i < RH2Dac2Steps; ++i) { + if (rH2Actual < rH2Target - (RH2Dac2Unit - RH2Dac1Unit / 2)) { rH2Actual += RH2Dac2Unit; ++rH2Dac2; } } - for (i = 0; i < RH2Dac1Steps; ++i) - { - if (rH2Actual < rH2Target - (RH2Dac1Unit / 2)) - { + for (i = 0; i < RH2Dac1Steps; ++i) { + if (rH2Actual < rH2Target - (RH2Dac1Unit / 2)) { rH2Actual += RH2Dac1Unit; ++rH2Dac1; } @@ -643,8 +608,7 @@ double Rhd2000Registers::setLowerBandwidth(double lowerBandwidth) int i; // Lower bandwidths higher than 1.5 kHz don't work well with the RHD2000 amplifiers - if (lowerBandwidth > 1500.0) - { + if (lowerBandwidth > 1500.0) { lowerBandwidth = 1500.0; } @@ -655,25 +619,20 @@ double Rhd2000Registers::setLowerBandwidth(double lowerBandwidth) rLDac3 = 0; rLActual = RLBase; - if (lowerBandwidth < 0.15) - { + if (lowerBandwidth < 0.15) { rLActual += RLDac3Unit; ++rLDac3; } - for (i = 0; i < RLDac2Steps; ++i) - { - if (rLActual < rLTarget - (RLDac2Unit - RLDac1Unit / 2)) - { + for (i = 0; i < RLDac2Steps; ++i) { + if (rLActual < rLTarget - (RLDac2Unit - RLDac1Unit / 2)) { rLActual += RLDac2Unit; ++rLDac2; } } - for (i = 0; i < RLDac1Steps; ++i) - { - if (rLActual < rLTarget - (RLDac1Unit / 2)) - { + for (i = 0; i < RLDac1Steps; ++i) { + if (rLActual < rLTarget - (RLDac1Unit / 2)) { rLActual += RLDac1Unit; ++rLDac1; } @@ -706,8 +665,7 @@ double Rhd2000Registers::setLowerBandwidth(double lowerBandwidth) // Return a 16-bit MOSI command (CALIBRATE or CLEAR) int Rhd2000Registers::createRhd2000Command(Rhd2000CommandType commandType) { - switch (commandType) - { + switch (commandType) { case Rhd2000CommandCalibrate: return 0x5500; // 0101010100000000 break; @@ -715,8 +673,8 @@ int Rhd2000Registers::createRhd2000Command(Rhd2000CommandType commandType) return 0x6a00; // 0110101000000000 break; default: - cerr << "Error in Rhd2000Registers::createRhd2000Command: " << - "Only 'Calibrate' or 'Clear Calibration' commands take zero arguments." << endl; + cerr << "Error in Rhd2000Registers::createRhd2000Command: " << + "Only 'Calibrate' or 'Clear Calibration' commands take zero arguments." << endl; return -1; } } @@ -724,30 +682,27 @@ int Rhd2000Registers::createRhd2000Command(Rhd2000CommandType commandType) // Return a 16-bit MOSI command (CONVERT or READ) int Rhd2000Registers::createRhd2000Command(Rhd2000CommandType commandType, int arg1) { - switch (commandType) - { + switch (commandType) { case Rhd2000CommandConvert: - if (arg1 < 0 || arg1 > 63) - { + if (arg1 < 0 || arg1 > 63) { cerr << "Error in Rhd2000Registers::createRhd2000Command: " << - "Channel number out of range." << endl; + "Channel number out of range." << endl; return -1; } return 0x0000 + (arg1 << 8); // 00cccccc0000000h; if the command is 'Convert', - // arg1 is the channel number + // arg1 is the channel number case Rhd2000CommandRegRead: - if (arg1 < 0 || arg1 > 63) - { + if (arg1 < 0 || arg1 > 63) { cerr << "Error in Rhd2000Registers::createRhd2000Command: " << - "Register address out of range." << endl; + "Register address out of range." << endl; return -1; } return 0xc000 + (arg1 << 8); // 11rrrrrr00000000; if the command is 'Register Read', - // arg1 is the register address + // arg1 is the register address break; default: cerr << "Error in Rhd2000Registers::createRhd2000Command: " << - "Only 'Convert' and 'Register Read' commands take one argument." << endl; + "Only 'Convert' and 'Register Read' commands take one argument." << endl; return -1; } } @@ -755,35 +710,33 @@ int Rhd2000Registers::createRhd2000Command(Rhd2000CommandType commandType, int a // Return a 16-bit MOSI command (WRITE) int Rhd2000Registers::createRhd2000Command(Rhd2000CommandType commandType, int arg1, int arg2) { - switch (commandType) - { + switch (commandType) { case Rhd2000CommandRegWrite: - if (arg1 < 0 || arg1 > 63) - { + if (arg1 < 0 || arg1 > 63) { cerr << "Error in Rhd2000Registers::createRhd2000Command: " << - "Register address out of range." << endl; + "Register address out of range." << endl; return -1; } - if (arg2 < 0 || arg2 > 255) - { + if (arg2 < 0 || arg2 > 255) { cerr << "Error in Rhd2000Registers::createRhd2000Command: " << - "Register data out of range." << endl; + "Register data out of range." << endl; return -1; } return 0x8000 + (arg1 << 8) + arg2; // 10rrrrrrdddddddd; if the command is 'Register Write', - // arg1 is the register address and arg1 is the data + // arg1 is the register address and arg1 is the data break; default: cerr << "Error in Rhd2000Registers::createRhd2000Command: " << - "Only 'Register Write' commands take two arguments." << endl; + "Only 'Register Write' commands take two arguments." << endl; return -1; } } + // Create a list of 60 commands to program most RAM registers on a RHD2000 chip, read those values // back to confirm programming, read ROM registers, and (if calibrate == true) run ADC calibration. // Returns the length of the command list. -int Rhd2000Registers::createCommandListRegisterConfig(vector<int>& commandList, bool calibrate) +int Rhd2000Registers::createCommandListRegisterConfig(vector<int> &commandList, bool calibrate) { commandList.clear(); // if command list already exists, erase it and start a new one @@ -792,17 +745,17 @@ int Rhd2000Registers::createCommandListRegisterConfig(vector<int>& commandList, commandList.push_back(createRhd2000Command(Rhd2000CommandRegRead, 63)); // Program RAM registers - commandList.push_back(createRhd2000Command(Rhd2000CommandRegWrite, 0, getRegisterValue(0))); - commandList.push_back(createRhd2000Command(Rhd2000CommandRegWrite, 1, getRegisterValue(1))); - commandList.push_back(createRhd2000Command(Rhd2000CommandRegWrite, 2, getRegisterValue(2))); + commandList.push_back(createRhd2000Command(Rhd2000CommandRegWrite, 0, getRegisterValue( 0))); + commandList.push_back(createRhd2000Command(Rhd2000CommandRegWrite, 1, getRegisterValue( 1))); + commandList.push_back(createRhd2000Command(Rhd2000CommandRegWrite, 2, getRegisterValue( 2))); // Don't program Register 3 (MUX Load, Temperature Sensor, and Auxiliary Digital Output); // control temperature sensor in another command stream - commandList.push_back(createRhd2000Command(Rhd2000CommandRegWrite, 4, getRegisterValue(4))); - commandList.push_back(createRhd2000Command(Rhd2000CommandRegWrite, 5, getRegisterValue(5))); + commandList.push_back(createRhd2000Command(Rhd2000CommandRegWrite, 4, getRegisterValue( 4))); + commandList.push_back(createRhd2000Command(Rhd2000CommandRegWrite, 5, getRegisterValue( 5))); // Don't program Register 6 (Impedance Check DAC) here; create DAC waveform in another command stream - commandList.push_back(createRhd2000Command(Rhd2000CommandRegWrite, 7, getRegisterValue(7))); - commandList.push_back(createRhd2000Command(Rhd2000CommandRegWrite, 8, getRegisterValue(8))); - commandList.push_back(createRhd2000Command(Rhd2000CommandRegWrite, 9, getRegisterValue(9))); + commandList.push_back(createRhd2000Command(Rhd2000CommandRegWrite, 7, getRegisterValue( 7))); + commandList.push_back(createRhd2000Command(Rhd2000CommandRegWrite, 8, getRegisterValue( 8))); + commandList.push_back(createRhd2000Command(Rhd2000CommandRegWrite, 9, getRegisterValue( 9))); commandList.push_back(createRhd2000Command(Rhd2000CommandRegWrite, 10, getRegisterValue(10))); commandList.push_back(createRhd2000Command(Rhd2000CommandRegWrite, 11, getRegisterValue(11))); commandList.push_back(createRhd2000Command(Rhd2000CommandRegWrite, 12, getRegisterValue(12))); @@ -857,20 +810,21 @@ int Rhd2000Registers::createCommandListRegisterConfig(vector<int>& commandList, commandList.push_back(createRhd2000Command(Rhd2000CommandRegRead, 17)); // Optionally, run ADC calibration (should only be run once after board is plugged in) - if (calibrate) - { + if (calibrate) { commandList.push_back(createRhd2000Command(Rhd2000CommandCalibrate)); - } - else - { + } else { commandList.push_back(createRhd2000Command(Rhd2000CommandRegRead, 63)); } - // End with a few dummy commands - commandList.push_back(createRhd2000Command(Rhd2000CommandRegRead, 63)); - commandList.push_back(createRhd2000Command(Rhd2000CommandRegRead, 63)); - commandList.push_back(createRhd2000Command(Rhd2000CommandRegRead, 63)); - commandList.push_back(createRhd2000Command(Rhd2000CommandRegRead, 63)); + // Added in Version 1.2: + // Program amplifier 31-63 power up/down registers in case a RHD2164 is connected + // Note: We don't read these registers back, since they are only 'visible' on MISO B. + commandList.push_back(createRhd2000Command(Rhd2000CommandRegWrite, 18, getRegisterValue(18))); + commandList.push_back(createRhd2000Command(Rhd2000CommandRegWrite, 19, getRegisterValue(19))); + commandList.push_back(createRhd2000Command(Rhd2000CommandRegWrite, 20, getRegisterValue(20))); + commandList.push_back(createRhd2000Command(Rhd2000CommandRegWrite, 21, getRegisterValue(21))); + + // End with a dummy command commandList.push_back(createRhd2000Command(Rhd2000CommandRegRead, 63)); @@ -888,7 +842,7 @@ int Rhd2000Registers::createCommandListRegisterConfig(vector<int>& commandList, // different RAM banks, and the appropriate command list selected at the right time. // // Returns the length of the command list. -int Rhd2000Registers::createCommandListTempSensor(vector<int>& commandList) +int Rhd2000Registers::createCommandListTempSensor(vector<int> &commandList) { int i; @@ -939,8 +893,7 @@ int Rhd2000Registers::createCommandListTempSensor(vector<int>& commandList) commandList.push_back(createRhd2000Command(Rhd2000CommandConvert, 34)); // sample AuxIn3 commandList.push_back(createRhd2000Command(Rhd2000CommandConvert, 48)); // sample Supply Voltage Sensor - for (i = 0; i < 8; ++i) - { + for (i = 0; i < 8; ++i) { commandList.push_back(createRhd2000Command(Rhd2000CommandConvert, 32)); // sample AuxIn1 commandList.push_back(createRhd2000Command(Rhd2000CommandConvert, 33)); // sample AuxIn2 commandList.push_back(createRhd2000Command(Rhd2000CommandConvert, 34)); // sample AuxIn3 @@ -950,11 +903,80 @@ int Rhd2000Registers::createCommandListTempSensor(vector<int>& commandList) return commandList.size(); } +// Create a list of 60 commands to update Register 3 (controlling the auxiliary digital ouput +// pin) every sampling period. +// +// Since this command list consists of writing to Register 3, it also sets the state of the +// on-chip temperature sensor. The temperature sensor settings are therefore changed throughout +// this command list to coordinate with the 60-command list generated by createCommandListTempSensor(). +// +// Returns the length of the command list. +int Rhd2000Registers::createCommandListUpdateDigOut(vector<int> &commandList) +{ + int i; + + commandList.clear(); // if command list already exists, erase it and start a new one + + tempEn = 1; + + commandList.push_back(createRhd2000Command(Rhd2000CommandRegWrite, 3, getRegisterValue(3))); + commandList.push_back(createRhd2000Command(Rhd2000CommandRegWrite, 3, getRegisterValue(3))); + commandList.push_back(createRhd2000Command(Rhd2000CommandRegWrite, 3, getRegisterValue(3))); + tempS1 = tempEn; + tempS2 = 0; + commandList.push_back(createRhd2000Command(Rhd2000CommandRegWrite, 3, getRegisterValue(3))); + + commandList.push_back(createRhd2000Command(Rhd2000CommandRegWrite, 3, getRegisterValue(3))); + commandList.push_back(createRhd2000Command(Rhd2000CommandRegWrite, 3, getRegisterValue(3))); + commandList.push_back(createRhd2000Command(Rhd2000CommandRegWrite, 3, getRegisterValue(3))); + tempS1 = tempEn; + tempS2 = tempEn; + commandList.push_back(createRhd2000Command(Rhd2000CommandRegWrite, 3, getRegisterValue(3))); + + commandList.push_back(createRhd2000Command(Rhd2000CommandRegWrite, 3, getRegisterValue(3))); + commandList.push_back(createRhd2000Command(Rhd2000CommandRegWrite, 3, getRegisterValue(3))); + commandList.push_back(createRhd2000Command(Rhd2000CommandRegWrite, 3, getRegisterValue(3))); + commandList.push_back(createRhd2000Command(Rhd2000CommandRegWrite, 3, getRegisterValue(3))); + + commandList.push_back(createRhd2000Command(Rhd2000CommandRegWrite, 3, getRegisterValue(3))); + commandList.push_back(createRhd2000Command(Rhd2000CommandRegWrite, 3, getRegisterValue(3))); + commandList.push_back(createRhd2000Command(Rhd2000CommandRegWrite, 3, getRegisterValue(3))); + tempS1 = 0; + tempS2 = tempEn; + commandList.push_back(createRhd2000Command(Rhd2000CommandRegWrite, 3, getRegisterValue(3))); + + commandList.push_back(createRhd2000Command(Rhd2000CommandRegWrite, 3, getRegisterValue(3))); + commandList.push_back(createRhd2000Command(Rhd2000CommandRegWrite, 3, getRegisterValue(3))); + commandList.push_back(createRhd2000Command(Rhd2000CommandRegWrite, 3, getRegisterValue(3))); + commandList.push_back(createRhd2000Command(Rhd2000CommandRegWrite, 3, getRegisterValue(3))); + + commandList.push_back(createRhd2000Command(Rhd2000CommandRegWrite, 3, getRegisterValue(3))); + commandList.push_back(createRhd2000Command(Rhd2000CommandRegWrite, 3, getRegisterValue(3))); + commandList.push_back(createRhd2000Command(Rhd2000CommandRegWrite, 3, getRegisterValue(3))); + tempS1 = 0; + tempS2 = 0; + commandList.push_back(createRhd2000Command(Rhd2000CommandRegWrite, 3, getRegisterValue(3))); + + commandList.push_back(createRhd2000Command(Rhd2000CommandRegWrite, 3, getRegisterValue(3))); + commandList.push_back(createRhd2000Command(Rhd2000CommandRegWrite, 3, getRegisterValue(3))); + commandList.push_back(createRhd2000Command(Rhd2000CommandRegWrite, 3, getRegisterValue(3))); + commandList.push_back(createRhd2000Command(Rhd2000CommandRegWrite, 3, getRegisterValue(3))); + + for (i = 0; i < 8; ++i) { + commandList.push_back(createRhd2000Command(Rhd2000CommandRegWrite, 3, getRegisterValue(3))); + commandList.push_back(createRhd2000Command(Rhd2000CommandRegWrite, 3, getRegisterValue(3))); + commandList.push_back(createRhd2000Command(Rhd2000CommandRegWrite, 3, getRegisterValue(3))); + commandList.push_back(createRhd2000Command(Rhd2000CommandRegWrite, 3, getRegisterValue(3))); + } + + return commandList.size(); +} + // Create a list of up to 1024 commands to generate a sine wave of particular frequency (in Hz) and // amplitude (in DAC steps, 0-128) using the on-chip impedance testing voltage DAC. If frequency is set to zero, // a DC baseline waveform is created. // Returns the length of the command list. -int Rhd2000Registers::createCommandListZcheckDac(vector<int>& commandList, double frequency, double amplitude) +int Rhd2000Registers::createCommandListZcheckDac(vector<int> &commandList, double frequency, double amplitude) { int i, period, value; double t; @@ -962,49 +984,34 @@ int Rhd2000Registers::createCommandListZcheckDac(vector<int>& commandList, doubl commandList.clear(); // if command list already exists, erase it and start a new one - if (amplitude < 0.0 || amplitude > 128.0) - { + if (amplitude < 0.0 || amplitude > 128.0) { cerr << "Error in Rhd2000Registers::createCommandListZcheckDac: Amplitude out of range." << endl; return -1; } - if (frequency < 0.0) - { + if (frequency < 0.0) { cerr << "Error in Rhd2000Registers::createCommandListZcheckDac: Negative frequency not allowed." << endl; return -1; - } - else if (frequency > sampleRate / 4.0) - { + } else if (frequency > sampleRate / 4.0) { cerr << "Error in Rhd2000Registers::createCommandListZcheckDac: " << - "Frequency too high relative to sampling rate." << endl; + "Frequency too high relative to sampling rate." << endl; return -1; } - if (frequency == 0.0) - { - for (i = 0; i < MaxCommandLength; ++i) - { + if (frequency == 0.0) { + for (i = 0; i < MaxCommandLength; ++i) { commandList.push_back(createRhd2000Command(Rhd2000CommandRegWrite, 6, 128)); } - } - else - { + } else { period = (int) floor(sampleRate / frequency + 0.5); - if (period > MaxCommandLength) - { + if (period > MaxCommandLength) { cerr << "Error in Rhd2000Registers::createCommandListZcheckDac: Frequency too low." << endl; return -1; - } - else - { + } else { t = 0.0; - for (i = 0; i < period; ++i) - { + for (i = 0; i < period; ++i) { value = (int) floor(amplitude * sin(2 * Pi * frequency * t) + 128.0 + 0.5); - if (value < 0) - { + if (value < 0) { value = 0; - } - else if (value > 255) - { + } else if (value > 255) { value = 255; } commandList.push_back(createRhd2000Command(Rhd2000CommandRegWrite, 6, value)); diff --git a/Source/Processors/DataThreads/rhythm-api/rhd2000registers.h b/Source/Processors/DataThreads/rhythm-api/rhd2000registers.h index 74ee25e89bc8b6f698150193fe1c5672200db81d..992f2b68de38b5f9ec4bfdaddda6f030f5fb0beb 100755 --- a/Source/Processors/DataThreads/rhythm-api/rhd2000registers.h +++ b/Source/Processors/DataThreads/rhythm-api/rhd2000registers.h @@ -3,9 +3,9 @@ // // Intan Technoloies RHD2000 Rhythm Interface API // Rhd2000Registers Class Header File -// Version 1.0 (14 January 2013) +// Version 1.4 (26 February 2014) // -// Copyright (c) 2013 Intan Technologies LLC +// Copyright (c) 2013-2014 Intan Technologies LLC // // This software is provided 'as-is', without any express or implied warranty. // In no event will the authors be held liable for any damages arising from the @@ -49,15 +49,13 @@ public: void enableZcheck(bool enabled); void setZcheckDacPower(bool enabled); - enum ZcheckCs - { + enum ZcheckCs { ZcheckCs100fF, ZcheckCs1pF, ZcheckCs10pF }; - enum ZcheckPolarity - { + enum ZcheckPolarity { ZcheckPositiveInput, ZcheckNegativeInput }; @@ -75,12 +73,12 @@ public: double setUpperBandwidth(double upperBandwidth); double setLowerBandwidth(double lowerBandwidth); - int createCommandListRegisterConfig(vector<int>& commandList, bool calibrate); - int createCommandListTempSensor(vector<int>& commandList); - int createCommandListZcheckDac(vector<int>& commandList, double frequency, double amplitude); + int createCommandListRegisterConfig(vector<int> &commandList, bool calibrate); + int createCommandListTempSensor(vector<int> &commandList); + int createCommandListUpdateDigOut(vector<int> &commandList); + int createCommandListZcheckDac(vector<int> &commandList, double frequency, double amplitude); - enum Rhd2000CommandType - { + enum Rhd2000CommandType { Rhd2000CommandConvert, Rhd2000CommandCalibrate, Rhd2000CommandCalClear,