diff --git a/Source/Devices/Neuropixels1e.cpp b/Source/Devices/Neuropixels1e.cpp index d7c7a8e..549dcf6 100644 --- a/Source/Devices/Neuropixels1e.cpp +++ b/Source/Devices/Neuropixels1e.cpp @@ -135,6 +135,8 @@ int Neuropixels1e::configureDevice() LOGD ("Probe SN: ", probeMetadata.getProbeSerialNumber()); + settings[0]->connected = probeMetadata.getProbeSerialNumber() != 0; + return ONI_ESUCCESS; } diff --git a/Source/Devices/Neuropixels1f.cpp b/Source/Devices/Neuropixels1f.cpp index 0f65f93..b3bd082 100644 --- a/Source/Devices/Neuropixels1f.cpp +++ b/Source/Devices/Neuropixels1f.cpp @@ -127,6 +127,8 @@ int Neuropixels1f::configureDevice() LOGD ("Probe SN: ", probeMetadata.getProbeSerialNumber()); + settings[0]->connected = probeMetadata.getProbeSerialNumber() != 0; + // Enable device streaming rc = deviceContext->writeRegister (deviceIdx, 0x8000, 1); if (rc != ONI_ESUCCESS) diff --git a/Source/Devices/Neuropixels2e.cpp b/Source/Devices/Neuropixels2e.cpp index 0c62ace..4b4b54a 100644 --- a/Source/Devices/Neuropixels2e.cpp +++ b/Source/Devices/Neuropixels2e.cpp @@ -316,18 +316,22 @@ int Neuropixels2e::configureDevice() LOGD ("Probe A SN: ", probeMetadata[0].getProbeSerialNumber()); LOGD ("Probe B SN: ", probeMetadata[1].getProbeSerialNumber()); - if (probeMetadata[0].getProbeSerialNumber() == 0 && probeMetadata[1].getProbeSerialNumber() == 0) - { - m_numProbes = 0; - throw error_str ("No probes were found connected at address " + std::to_string (getDeviceIdx())); - } - else if (probeMetadata[0].getProbeSerialNumber() != 0 && probeMetadata[1].getProbeSerialNumber() != 0) + m_numProbes = 0; + + for(int i = 0; i < NumberOfProbes; i++) { - m_numProbes = 2; + if (probeMetadata[i].getProbeSerialNumber() != 0) + { + settings[i]->connected = true; + m_numProbes++; + } + else + settings[i]->connected = false; } - else + + if (m_numProbes == 0) { - m_numProbes = 1; + throw error_str ("No probes were found connected at address " + std::to_string (getDeviceIdx())); } streamInfos.clear(); @@ -342,9 +346,9 @@ int Neuropixels2e::configureDevice() bool Neuropixels2e::updateSettings() { - for (int i = 0; i < 2; i++) + for (int i = 0; i < NumberOfProbes; i++) { - if (probeMetadata[i].getProbeSerialNumber() != 0) + if (settings[i]->connected) { if (! NeuropixelsProbeMetadata::validateProbeTypeAndPartNumber (settings[i]->probeType, probeMetadata[i])) { @@ -416,7 +420,7 @@ bool Neuropixels2e::updateSettings() for (int i = 0; i < NumberOfProbes; i++) { - if (probeMetadata[i].getProbeSerialNumber() != 0) + if (settings[i]->connected) { selectProbe (serializer.get(), i == 0 ? ProbeASelected : ProbeBSelected); writeConfiguration (settings[i].get()); @@ -554,7 +558,7 @@ void Neuropixels2e::addSourceBuffers (OwnedArray& sourceBuffers) if (m_numProbes == 1) { sourceBuffers.add (new DataBuffer (streamInfos.getFirst().getNumChannels(), (int) streamInfos.getFirst().getSampleRate() * bufferSizeInSeconds)); - auto bufferIndex = probeMetadata[0].getProbeSerialNumber() != 0 ? 0 : 1; + auto bufferIndex = settings[0]->connected ? 0 : 1; amplifierBuffer[bufferIndex] = sourceBuffers.getLast(); } else diff --git a/Source/NeuropixelsComponents.h b/Source/NeuropixelsComponents.h index f663375..1625d12 100644 --- a/Source/NeuropixelsComponents.h +++ b/Source/NeuropixelsComponents.h @@ -287,6 +287,7 @@ struct ProbeSettings lfpGainIndex = newSettings->lfpGainIndex; referenceIndex = newSettings->referenceIndex; apFilterState = newSettings->apFilterState; + connected = newSettings->connected; selectedBank = newSettings->selectedBank; selectedShank = newSettings->selectedShank; @@ -344,6 +345,7 @@ struct ProbeSettings int lfpGainIndex = 0; int referenceIndex = 0; bool apFilterState = false; + bool connected = false; std::vector selectedBank; std::vector selectedShank; @@ -562,4 +564,67 @@ static class NeuropixelsV1 return baseConfigs; } }; + +static class NeuropixelsHelpers +{ +public: + /** Set all channel metadata, starting with the last (most recently added) channel and working backwards over all selected electrodes */ + static void setChannelMetadata (OwnedArray* continuousChannels, const std::vector>& probeSettings) + { + ContinuousChannel** channels = continuousChannels->end(); + channels--; + + for (auto it = probeSettings.rbegin(); it != probeSettings.rend(); it++) + { + ProbeSettings* probeSetting = it->get(); + + if (! probeSetting->connected) + continue; + + for (int i = probeSetting->numberOfChannels - 1; i >= 0; i--) + { + auto channel = *channels--; + + int globalIndex = probeSetting->selectedElectrode[i]; + int shankIndex = probeSetting->electrodeMetadata[globalIndex].shank; + + float xpos = probeSetting->electrodeMetadata[globalIndex].xpos; + float ypos = probeSetting->electrodeMetadata[globalIndex].ypos; + + // NB: Depth must be a unique value for compatibility with legacy LFP viewer channel sorting algorithm + float depth = ypos + (float)shankIndex * 10000.0f + xpos * 0.001f; + + channel->position.x = xpos; + channel->position.y = depth; + + channel->group.name = "Shank " + String (shankIndex + 1); + channel->group.number = shankIndex; + + // NB: Add real Y position as a metadata descriptor + MetadataDescriptor yposDescriptor (MetadataDescriptor::MetadataType::FLOAT, + 1, + "ypos", + "Channel y-position (relative to shank tip)", + "channel.ypos"); + + MetadataValue yposValue (MetadataDescriptor::MetadataType::FLOAT, 1); + yposValue.setValue (ypos); + + channel->addMetadata (yposDescriptor, yposValue); + + // NB: Add electrode index as metadata + MetadataDescriptor selectedElectrodeDescriptor (MetadataDescriptor::MetadataType::UINT16, + 1, + "electrode_index", + "Electrode index for this channel", + "neuropixels.electrode_index"); + + MetadataValue selectedElectrodeValue (MetadataDescriptor::MetadataType::UINT16, 1); + selectedElectrodeValue.setValue ((uint16) globalIndex); + + channel->addMetadata (selectedElectrodeDescriptor, selectedElectrodeValue); + } + } + } +}; } // namespace OnixSourcePlugin diff --git a/Source/OnixSource.cpp b/Source/OnixSource.cpp index 4f9118f..4401042 100644 --- a/Source/OnixSource.cpp +++ b/Source/OnixSource.cpp @@ -836,6 +836,8 @@ void OnixSource::updateSettings (OwnedArray* continuousChanne deviceInfos->add (device); addIndividualStreams (source->streamInfos, dataStreams, deviceInfos, continuousChannels); + + NeuropixelsHelpers::setChannelMetadata (continuousChannels, std::static_pointer_cast (source)->settings); } else if (type == OnixDeviceType::BNO || type == OnixDeviceType::POLLEDBNO) { @@ -885,6 +887,8 @@ void OnixSource::updateSettings (OwnedArray* continuousChanne deviceInfos->add (device); addIndividualStreams (source->streamInfos, dataStreams, deviceInfos, continuousChannels); + + NeuropixelsHelpers::setChannelMetadata (continuousChannels, std::static_pointer_cast (source)->settings); } else if (type == OnixDeviceType::MEMORYMONITOR) { @@ -979,6 +983,8 @@ void OnixSource::updateSettings (OwnedArray* continuousChanne deviceInfos->add (device); addIndividualStreams (source->streamInfos, dataStreams, deviceInfos, continuousChannels); + + NeuropixelsHelpers::setChannelMetadata (continuousChannels, std::static_pointer_cast (source)->settings); } else if (type == OnixDeviceType::OUTPUTCLOCK) { diff --git a/Source/UI/NeuropixelsV1Interface.cpp b/Source/UI/NeuropixelsV1Interface.cpp index e124afa..a3184f3 100644 --- a/Source/UI/NeuropixelsV1Interface.cpp +++ b/Source/UI/NeuropixelsV1Interface.cpp @@ -925,6 +925,8 @@ void NeuropixelsV1Interface::selectElectrodes (std::vector electrodes) { std::static_pointer_cast (device)->settings[0]->selectElectrodes (electrodes); + CoreServices::updateSignalChain (editor); + repaint(); } diff --git a/Source/UI/NeuropixelsV2eProbeInterface.cpp b/Source/UI/NeuropixelsV2eProbeInterface.cpp index edf256a..1ab7690 100644 --- a/Source/UI/NeuropixelsV2eProbeInterface.cpp +++ b/Source/UI/NeuropixelsV2eProbeInterface.cpp @@ -682,6 +682,8 @@ void NeuropixelsV2eProbeInterface::selectElectrodes (std::vector electrodes { std::static_pointer_cast (device)->settings[probeIndex]->selectElectrodes (electrodes); + CoreServices::updateSignalChain (editor); + repaint(); }