From cd19ddc925bac77c17b6dd7e33c4a28f49b96de8 Mon Sep 17 00:00:00 2001 From: bparks13 Date: Fri, 3 Oct 2025 14:56:54 -0400 Subject: [PATCH 1/3] Refactor ProbeSettings to allow settings with different numbers of electrodes --- Source/Devices/Neuropixels1.cpp | 15 +---- Source/Devices/Neuropixels1.h | 4 +- Source/Devices/Neuropixels1e.cpp | 2 +- Source/Devices/Neuropixels1f.cpp | 2 +- Source/Devices/Neuropixels2e.cpp | 41 ++++++------- Source/Devices/Neuropixels2e.h | 10 ++-- Source/Formats/ProbeInterface.h | 25 +------- Source/NeuropixelsComponents.h | 70 ++++++++++++---------- Source/UI/NeuropixelsV1Interface.cpp | 6 +- Source/UI/NeuropixelsV1Interface.h | 4 +- Source/UI/NeuropixelsV1ProbeBrowser.h | 4 +- Source/UI/NeuropixelsV2eProbeBrowser.h | 4 +- Source/UI/NeuropixelsV2eProbeInterface.cpp | 14 ++++- Source/UI/NeuropixelsV2eProbeInterface.h | 6 +- Source/UI/ProbeBrowser.h | 7 +-- 15 files changed, 100 insertions(+), 114 deletions(-) diff --git a/Source/Devices/Neuropixels1.cpp b/Source/Devices/Neuropixels1.cpp index 9a17df5..7522c11 100644 --- a/Source/Devices/Neuropixels1.cpp +++ b/Source/Devices/Neuropixels1.cpp @@ -47,7 +47,7 @@ Neuropixels1::Neuropixels1 (std::string name, std::string hubName, OnixDeviceTyp { } -void Neuropixels1::setSettings (ProbeSettings* settings_, int index) +void Neuropixels1::setSettings (ProbeSettings* settings_, int index) { if (index >= settings.size()) { @@ -169,9 +169,9 @@ void Neuropixels1::updateLfpOffsets (std::array& samples, } } -void Neuropixels1::defineMetadata (ProbeSettings* settings) +void Neuropixels1::defineMetadata (ProbeSettings* settings, ProbeType probeType) { - settings->probeType = ProbeType::NPX_V1; + settings->probeType = probeType; settings->probeMetadata.name = "Neuropixels 1.0"; std::vector> shankOutline { @@ -200,13 +200,6 @@ void Neuropixels1::defineMetadata (ProbeSettingsprobeMetadata.num_adcs = 32; // NB: Is this right for 1.0e? settings->probeMetadata.adc_bits = 10; // NB: Is this right for 1.0e? - settings->availableBanks = { - Bank::A, - Bank::B, - Bank::C, - Bank::NONE // disconnected - }; - Array xpositions = { 27.0f, 59.0f, 11.0f, 43.0f }; for (int i = 0; i < numberOfElectrodes; i++) @@ -296,8 +289,6 @@ void Neuropixels1::defineMetadata (ProbeSettingselectrodeConfigurationIndex = (int32_t) ElectrodeConfiguration::BankA; auto selection = selectElectrodeConfiguration (settings->electrodeConfigurationIndex); settings->selectElectrodes (selection); - - settings->isValid = true; } uint64_t Neuropixels1::getProbeSerialNumber (int index) diff --git a/Source/Devices/Neuropixels1.h b/Source/Devices/Neuropixels1.h index df950eb..022e38c 100644 --- a/Source/Devices/Neuropixels1.h +++ b/Source/Devices/Neuropixels1.h @@ -47,12 +47,12 @@ class Neuropixels1 : public INeuropixel* settings) override; + void defineMetadata (ProbeSettings* settings, ProbeType probeType) override; /** Select a preset electrode configuration, based on the index of the given enum */ std::vector selectElectrodeConfiguration (int electrodeConfigurationIndex) override; - void setSettings (ProbeSettings* settings_, int index = 0) override; + void setSettings (ProbeSettings* settings_, int index = 0) override; uint64_t getProbeSerialNumber (int index = 0) override; std::string getProbePartNumber (int index = 0) override; diff --git a/Source/Devices/Neuropixels1e.cpp b/Source/Devices/Neuropixels1e.cpp index 9a8251d..309f76d 100644 --- a/Source/Devices/Neuropixels1e.cpp +++ b/Source/Devices/Neuropixels1e.cpp @@ -107,7 +107,7 @@ Neuropixels1e::Neuropixels1e (std::string name, std::string hubName, const oni_d "lfp"); streamInfos.add (lfpStream); - defineMetadata (settings[0].get()); + defineMetadata (settings[0].get(), ProbeType::NPX_V1); adcCalibrationFilePath = "None"; gainCalibrationFilePath = "None"; diff --git a/Source/Devices/Neuropixels1f.cpp b/Source/Devices/Neuropixels1f.cpp index 1463c5f..6216d1f 100644 --- a/Source/Devices/Neuropixels1f.cpp +++ b/Source/Devices/Neuropixels1f.cpp @@ -95,7 +95,7 @@ Neuropixels1f::Neuropixels1f (std::string name, std::string hubName, const oni_d "lfp"); streamInfos.add (lfpStream); - defineMetadata (settings[0].get()); + defineMetadata (settings[0].get(), ProbeType::NPX_V1); adcCalibrationFilePath = "None"; gainCalibrationFilePath = "None"; diff --git a/Source/Devices/Neuropixels2e.cpp b/Source/Devices/Neuropixels2e.cpp index d14679c..dfc956c 100644 --- a/Source/Devices/Neuropixels2e.cpp +++ b/Source/Devices/Neuropixels2e.cpp @@ -27,14 +27,14 @@ using namespace OnixSourcePlugin; Neuropixels2e::Neuropixels2e (std::string name, std::string hubName, const oni_dev_idx_t deviceIdx_, std::shared_ptr ctx_) : OnixDevice (name, hubName, Neuropixels2e::getDeviceType(), deviceIdx_, ctx_, true), I2CRegisterContext (ProbeI2CAddress, deviceIdx_, ctx_), - INeuropixel (NeuropixelsV2eValues::numberOfSettings, NeuropixelsV2eValues::numberOfShanks) + INeuropixel (NeuropixelsV2eValues::numberOfSettings, NeuropixelsV2eValues::quadShankCount) { frameCount.fill (0); sampleNumber.fill (0); for (int i = 0; i < NeuropixelsV2eValues::numberOfSettings; i++) { - defineMetadata (settings[i].get()); + defineMetadata (settings[i].get(), ProbeType::NPX_V2_QUAD_SHANK); } for (int i = 0; i < NumberOfProbes; i++) @@ -592,7 +592,7 @@ void Neuropixels2e::processFrames() } } -void Neuropixels2e::writeConfiguration (ProbeSettings* settings) +void Neuropixels2e::writeConfiguration (ProbeSettings* settings) { auto baseBits = makeBaseBits (getReference (settings->referenceIndex)); writeShiftRegister (SR_CHAIN5, baseBits[0]); @@ -710,7 +710,7 @@ Neuropixels2e::BaseBitsArray Neuropixels2e::makeBaseBits (NeuropixelsV2Reference return baseBits; } -Neuropixels2e::ShankBitsArray Neuropixels2e::makeShankBits (NeuropixelsV2Reference reference, std::array channelMap) +Neuropixels2e::ShankBitsArray Neuropixels2e::makeShankBits (NeuropixelsV2Reference reference, std::vector channelMap) { ShankBitsArray shankBits; @@ -760,7 +760,7 @@ Neuropixels2e::ShankBitsArray Neuropixels2e::makeShankBits (NeuropixelsV2Referen return shankBits; } -void Neuropixels2e::setSettings (ProbeSettings* settings_, int index) +void Neuropixels2e::setSettings (ProbeSettings* settings_, int index) { if (index >= settings.size()) { @@ -771,12 +771,13 @@ void Neuropixels2e::setSettings (ProbeSettingsupdateProbeSettings (settings_); } -void Neuropixels2e::defineMetadata (ProbeSettings* settings) +void Neuropixels2e::defineMetadata (ProbeSettings* settings, ProbeType probeType) { - auto shankCount = NeuropixelsV2eValues::numberOfShanks; + settings->probeType = probeType; - settings->probeType = ProbeType::NPX_V2; - settings->probeMetadata.name = "Neuropixels 2.0e" + (shankCount == 1) ? " - Single Shank" : " - Quad Shank"; + auto shankCount = probeType == ProbeType::NPX_V2_QUAD_SHANK ? NeuropixelsV2eValues::quadShankCount : NeuropixelsV2eValues::singleShankCount; + + settings->probeMetadata.name = "Neuropixels 2.0e" + (probeType == ProbeType::NPX_V2_QUAD_SHANK) ? " - Single Shank" : " - Quad Shank"; constexpr float shankTipY = 0.0f; constexpr float shankBaseY = 155.0f; @@ -787,8 +788,8 @@ void Neuropixels2e::defineMetadata (ProbeSettings> probeContour { - { 0, probeLengthY }, - { 0, shankLengthY }, + {0, probeLengthY}, + {0, shankLengthY}, }; for (int i = 0; i < shankCount; i++) @@ -805,11 +806,11 @@ void Neuropixels2e::defineMetadata (ProbeSettings { 0.0f, probeLengthY }); std::vector> shankOutline { - { 27, 31 }, - { 27, 514 }, - { 27 + 5, 522 }, - { 27 + 10, 514 }, - { 27 + 10, 31 } + { 27, 31}, + { 27, 514}, + { 27 + 5, 522}, + {27 + 10, 514}, + {27 + 10, 31} }; settings->probeMetadata.shank_count = shankCount; @@ -821,14 +822,6 @@ void Neuropixels2e::defineMetadata (ProbeSettingsprobeMetadata.num_adcs = 24; settings->probeMetadata.adc_bits = 12; - settings->availableBanks = { - Bank::A, - Bank::B, - Bank::C, - Bank::D, - Bank::NONE // disconnected - }; - for (int i = 0; i < settings->probeMetadata.electrodes_per_shank * settings->probeMetadata.shank_count; i++) { ElectrodeMetadata metadata; diff --git a/Source/Devices/Neuropixels2e.h b/Source/Devices/Neuropixels2e.h index 3137aac..9db252a 100644 --- a/Source/Devices/Neuropixels2e.h +++ b/Source/Devices/Neuropixels2e.h @@ -46,7 +46,7 @@ enum class NeuropixelsV2Status : uint32_t /* Configures and streams data from a Neuropixels 2.0e device (aka a configured raw deserializer) */ -class Neuropixels2e : public INeuropixel, +class Neuropixels2e : public INeuropixel, public OnixDevice, public I2CRegisterContext { @@ -76,7 +76,7 @@ class Neuropixels2e : public INeuropixel, 4>; BaseBitsArray static makeBaseBits (NeuropixelsV2Reference reference); - ShankBitsArray static makeShankBits (NeuropixelsV2Reference reference, std::array channelMap); + ShankBitsArray static makeShankBits (NeuropixelsV2Reference reference, std::vector channelMap); template void writeShiftRegister (uint32_t srAddress, std::bitset bits); @@ -91,8 +91,8 @@ class Neuropixels2e : public INeuropixel*) override; - void setSettings (ProbeSettings* settings_, int index) override; + void defineMetadata (ProbeSettings* settings, ProbeType probeType) override; + void setSettings (ProbeSettings* settings_, int index) override; static OnixDeviceType getDeviceType(); private: @@ -120,7 +120,7 @@ class Neuropixels2e : public INeuropixel*); + void writeConfiguration (ProbeSettings*); void selectElectrodesInRange (std::vector& selection, int startIndex, int numberOfElectrodes); void selectElectrodesAcrossShanks (std::vector& selection, int startIndex, int numberOfElectrodes); diff --git a/Source/Formats/ProbeInterface.h b/Source/Formats/ProbeInterface.h index ef85ba2..55bb912 100644 --- a/Source/Formats/ProbeInterface.h +++ b/Source/Formats/ProbeInterface.h @@ -37,8 +37,7 @@ class ProbeInterfaceJson return File (recordingDirectory.getFullPathName() + File::getSeparatorString() + String (name) + String (ProbeInterfaceJson::FileExtension)); } - template - static bool writeProbeSettingsToJson (File& file, ProbeSettings* settings) + static bool writeProbeSettingsToJson (File& file, ProbeSettings* settings) { DynamicObject output; @@ -88,8 +87,7 @@ class ProbeInterfaceJson DynamicObject::Ptr probe = new DynamicObject(); DynamicObject::Ptr annotations = new DynamicObject(); annotations->setProperty (Identifier ("manufacturer"), "imec"); - auto probeName = getProbeName (settings->probeType); - annotations->setProperty (Identifier ("name"), String (probeName)); + annotations->setProperty (Identifier ("name"), String (settings->probeMetadata.name)); probe->setProperty (Identifier ("ndim"), 2); probe->setProperty (Identifier ("si_units"), "um"); @@ -127,8 +125,7 @@ class ProbeInterfaceJson return true; } - template - static bool readProbeSettingsFromJson (File& file, ProbeSettings* settings) + static bool readProbeSettingsFromJson (File& file, ProbeSettings* settings) { auto json = JSON::parse (file); @@ -290,7 +287,6 @@ class ProbeInterfaceJson settings->electrodeMetadata[ch].shank = int (shank_ids->getReference (ch)); } - settings->clearElectrodeSelection(); std::vector selectedChannels {}; for (int ch = 0; ch < device_channel_indices->size(); ch++) @@ -311,20 +307,5 @@ class ProbeInterfaceJson return true; } - - static std::string getProbeName (ProbeType type) - { - switch (type) - { - case OnixSourcePlugin::ProbeType::NONE: - return ""; - case OnixSourcePlugin::ProbeType::NPX_V1: - return "Neuropixels 1.0"; - case OnixSourcePlugin::ProbeType::NPX_V2: - return "Neuropixels 2.0"; - default: - return ""; - } - } }; } // namespace OnixSourcePlugin diff --git a/Source/NeuropixelsComponents.h b/Source/NeuropixelsComponents.h index 71ebb79..08e355b 100644 --- a/Source/NeuropixelsComponents.h +++ b/Source/NeuropixelsComponents.h @@ -35,7 +35,8 @@ enum class ProbeType { NONE = 1, NPX_V1, - NPX_V2, + NPX_V2_SINGLE_SHANK, + NPX_V2_QUAD_SHANK, }; enum class Bank @@ -231,21 +232,40 @@ struct NeuropixelsV2eValues { static constexpr int numberOfChannels = 384; static constexpr int electrodesPerShank = 1280; - static constexpr int numberOfShanks = 4; - static constexpr int numberOfElectrodes = numberOfShanks * electrodesPerShank; + static constexpr int quadShankCount = 4; + static constexpr int numberOfQuadShankElectrodes = electrodesPerShank * quadShankCount; + static constexpr int singleShankCount = 1; + static constexpr int numberOfSingleShankElectrodes = electrodesPerShank; static constexpr int numberOfSettings = 2; }; -template struct ProbeSettings { + ProbeSettings (int numChannels, int numElectrodes, ProbeType type) : numberOfChannels (numChannels), numberOfElectrodes (numElectrodes) + { + selectedBank = std::vector(numChannels, Bank::A); + selectedShank = std::vector (numChannels, 0); + selectedElectrode = std::vector (numChannels); + + for (int i = 0; i < numChannels; i++) + { + selectedElectrode[i] = i; + } + + electrodeMetadata = std::vector (numElectrodes); + + probeType = type; + } + + const int numberOfChannels; + const int numberOfElectrodes; + void updateProbeSettings (ProbeSettings* newSettings) { availableElectrodeConfigurations = newSettings->availableElectrodeConfigurations; availableApGains = newSettings->availableApGains; availableLfpGains = newSettings->availableLfpGains; availableReferences = newSettings->availableReferences; - availableBanks = newSettings->availableBanks; electrodeConfigurationIndex = newSettings->electrodeConfigurationIndex; apGainIndex = newSettings->apGainIndex; @@ -263,13 +283,6 @@ struct ProbeSettings probeMetadata = newSettings->probeMetadata; }; - void clearElectrodeSelection() - { - selectedBank.fill (Bank::A); - selectedShank.fill (0); - selectedElectrode.fill (-1); - } - void selectElectrodes (std::vector electrodes) { for (int i = 0; i < electrodes.size(); i++) @@ -310,24 +323,21 @@ struct ProbeSettings Array availableApGains; // Available AP gain values for each channel (if any) Array availableLfpGains; // Available LFP gain values for each channel (if any) Array availableReferences; // reference types - Array availableBanks; // bank inds - int electrodeConfigurationIndex; - int apGainIndex; - int lfpGainIndex; - int referenceIndex; - bool apFilterState; + int electrodeConfigurationIndex = 0; + int apGainIndex = 0; + int lfpGainIndex = 0; + int referenceIndex = 0; + bool apFilterState = false; - std::array selectedBank; - std::array selectedShank; - std::array selectedElectrode; - std::array electrodeMetadata; + std::vector selectedBank; + std::vector selectedShank; + std::vector selectedElectrode; + std::vector electrodeMetadata; - ProbeType probeType; + ProbeType probeType = ProbeType::NONE; ProbeMetadata probeMetadata; - - bool isValid = false; }; template @@ -356,7 +366,7 @@ class INeuropixel { for (int i = 0; i < numSettings; i++) { - settings.emplace_back (std::make_unique>()); + settings.emplace_back (std::make_unique (ch, e, ProbeType::NONE)); } } @@ -364,10 +374,10 @@ class INeuropixel static const int numberOfElectrodes = e; const int numberOfShanks; - std::vector>> settings; + std::vector> settings; - virtual void setSettings (ProbeSettings* settings_, int index) = 0; - virtual void defineMetadata (ProbeSettings* settings) = 0; + virtual void setSettings (ProbeSettings* settings_, int index) = 0; + virtual void defineMetadata (ProbeSettings* settings, ProbeType probeType) = 0; virtual uint64_t getProbeSerialNumber (int index) = 0; virtual std::string getProbePartNumber (int index) = 0; virtual std::string getFlexPartNumber (int index) = 0; @@ -412,7 +422,7 @@ using ConfigBitsArray = std::array, 2>; static class NeuropixelsV1 { public: - ShankBitset static makeShankBits (NeuropixelsV1Reference reference, std::array channelMap) + ShankBitset static makeShankBits (NeuropixelsV1Reference reference, std::vector channelMap) { constexpr int shankBitExt1 = 965; constexpr int shankBitExt2 = 2; diff --git a/Source/UI/NeuropixelsV1Interface.cpp b/Source/UI/NeuropixelsV1Interface.cpp index 50b6e86..e124afa 100644 --- a/Source/UI/NeuropixelsV1Interface.cpp +++ b/Source/UI/NeuropixelsV1Interface.cpp @@ -1016,7 +1016,7 @@ void NeuropixelsV1Interface::drawLegend() } } -bool NeuropixelsV1Interface::applyProbeSettings (ProbeSettings* p) +bool NeuropixelsV1Interface::applyProbeSettings (ProbeSettings* p) { auto npx = std::static_pointer_cast (device); @@ -1090,6 +1090,8 @@ void NeuropixelsV1Interface::saveParameters (XmlElement* xml) xmlNode->setAttribute ("flexPartNumber", npx->getFlexPartNumber()); xmlNode->setAttribute ("flexVersion", npx->getFlexVersion()); + xmlNode->setAttribute ("probeType", (int) settings->probeType); + xmlNode->setAttribute ("isEnabled", bool (device->isEnabled())); xmlNode->setAttribute ("searchForCalibrationFiles", searchForCalibrationFilesButton->getToggleState()); @@ -1162,6 +1164,8 @@ void NeuropixelsV1Interface::loadParameters (XmlElement* xml) LOGC ("Different serial numbers found. Current serial number is " + std::to_string (npx->getProbeSerialNumber()) + ", while the saved serial number is " + std::to_string (xmlNode->getIntAttribute ("probeSerialNumber")) + ". Updating settings..."); } + settings->probeType = (ProbeType) xmlNode->getIntAttribute ("probeType", (int) ProbeType::NPX_V1); + npx->setEnabled (xmlNode->getBoolAttribute ("isEnabled")); searchForCalibrationFilesButton->setToggleState (xmlNode->getBoolAttribute ("searchForCalibrationFiles", false), sendNotification); diff --git a/Source/UI/NeuropixelsV1Interface.h b/Source/UI/NeuropixelsV1Interface.h index 8446be3..f65420a 100644 --- a/Source/UI/NeuropixelsV1Interface.h +++ b/Source/UI/NeuropixelsV1Interface.h @@ -45,7 +45,7 @@ class NeuropixelsV1Interface : public SettingsInterface, public TextEditor::Listener { public: - friend class ProbeBrowser; + friend class ProbeBrowser; NeuropixelsV1Interface (std::shared_ptr d, OnixSourceEditor* e, OnixSourceCanvas* c); @@ -59,7 +59,7 @@ class NeuropixelsV1Interface : public SettingsInterface, void updateInfoString() override; void updateSettings() override; - bool applyProbeSettings (ProbeSettings* p); + bool applyProbeSettings (ProbeSettings* p); void selectElectrodes (std::vector electrodes); diff --git a/Source/UI/NeuropixelsV1ProbeBrowser.h b/Source/UI/NeuropixelsV1ProbeBrowser.h index be64aff..d8a850a 100644 --- a/Source/UI/NeuropixelsV1ProbeBrowser.h +++ b/Source/UI/NeuropixelsV1ProbeBrowser.h @@ -28,7 +28,7 @@ namespace OnixSourcePlugin { -class NeuropixelsV1ProbeBrowser : public ProbeBrowser +class NeuropixelsV1ProbeBrowser : public ProbeBrowser { public: NeuropixelsV1ProbeBrowser (SettingsInterface* parent_, int probeIndex_) : ProbeBrowser (parent_, probeIndex_) @@ -36,7 +36,7 @@ class NeuropixelsV1ProbeBrowser : public ProbeBrowser* getSettings() override + ProbeSettings* getSettings() override { if (parent->getDevice()->getDeviceType() == OnixDeviceType::NEUROPIXELSV1E) return std::static_pointer_cast (parent->getDevice())->settings[0].get(); diff --git a/Source/UI/NeuropixelsV2eProbeBrowser.h b/Source/UI/NeuropixelsV2eProbeBrowser.h index df3adfc..0028880 100644 --- a/Source/UI/NeuropixelsV2eProbeBrowser.h +++ b/Source/UI/NeuropixelsV2eProbeBrowser.h @@ -27,7 +27,7 @@ namespace OnixSourcePlugin { -class NeuropixelsV2eProbeBrowser : public ProbeBrowser +class NeuropixelsV2eProbeBrowser : public ProbeBrowser { public: NeuropixelsV2eProbeBrowser (SettingsInterface* parent_, int probeIndex_) : ProbeBrowser (parent_, probeIndex_) @@ -35,7 +35,7 @@ class NeuropixelsV2eProbeBrowser : public ProbeBrowser* getSettings() override + ProbeSettings* getSettings() override { return std::static_pointer_cast (parent->getDevice())->settings[probeIndex].get(); } diff --git a/Source/UI/NeuropixelsV2eProbeInterface.cpp b/Source/UI/NeuropixelsV2eProbeInterface.cpp index 30ac8d6..5f795ba 100644 --- a/Source/UI/NeuropixelsV2eProbeInterface.cpp +++ b/Source/UI/NeuropixelsV2eProbeInterface.cpp @@ -436,7 +436,9 @@ void NeuropixelsV2eProbeInterface::buttonClicked (Button* button) if (fileChooser.browseForFileToOpen()) { - if (ProbeInterfaceJson::readProbeSettingsFromJson (fileChooser.getResult(), npx->settings[probeIndex].get())) + auto settings = npx->settings[probeIndex].get(); + + if (ProbeInterfaceJson::readProbeSettingsFromJson (fileChooser.getResult(), settings)) { applyProbeSettings (npx->settings[probeIndex].get()); checkForExistingChannelPreset(); @@ -451,7 +453,9 @@ void NeuropixelsV2eProbeInterface::buttonClicked (Button* button) { try { - ProbeInterfaceJson::writeProbeSettingsToJson (fileChooser.getResult(), npx->settings[probeIndex].get()); + auto settings = npx->settings[probeIndex].get(); + + ProbeInterfaceJson::writeProbeSettingsToJson (fileChooser.getResult(), settings); } catch (const error_str& e) { @@ -691,7 +695,7 @@ void NeuropixelsV2eProbeInterface::updateSettings() gainCorrectionFile->setText (npx->getGainCorrectionFile (probeIndex) == "None" ? "" : npx->getGainCorrectionFile (probeIndex), dontSendNotification); } -bool NeuropixelsV2eProbeInterface::applyProbeSettings (ProbeSettings* p) +bool NeuropixelsV2eProbeInterface::applyProbeSettings (ProbeSettings* p) { if (electrodeConfigurationComboBox != 0) electrodeConfigurationComboBox->setSelectedId (p->electrodeConfigurationIndex + 2, dontSendNotification); @@ -756,6 +760,8 @@ void NeuropixelsV2eProbeInterface::saveParameters (XmlElement* xml) xmlNode->setAttribute ("flexPartNumber", npx->getFlexPartNumber (probeIndex)); xmlNode->setAttribute ("flexVersion", npx->getFlexVersion (probeIndex)); + xmlNode->setAttribute ("probeType", (int) settings->probeType); + xmlNode->setAttribute ("searchForCorrectionFiles", searchForCorrectionFilesButton->getToggleState()); xmlNode->setAttribute ("gainCorrectionFolder", gainCorrectionFolder->getText()); @@ -811,6 +817,8 @@ void NeuropixelsV2eProbeInterface::loadParameters (XmlElement* xml) LOGC ("Different serial numbers found. Current serial number is " + std::to_string (npx->getProbeSerialNumber (probeIndex)) + ", while the saved serial number is " + std::to_string (xmlNode->getIntAttribute ("probeSerialNumber")) + ". Updating settings..."); } + settings->probeType = (ProbeType) xmlNode->getIntAttribute ("probeType", (int) ProbeType::NPX_V2_QUAD_SHANK); + searchForCorrectionFilesButton->setToggleState (xmlNode->getBoolAttribute ("searchForCorrectionFiles", false), sendNotification); gainCorrectionFolder->setText (xmlNode->getStringAttribute ("gainCorrectionFolder", "")); diff --git a/Source/UI/NeuropixelsV2eProbeInterface.h b/Source/UI/NeuropixelsV2eProbeInterface.h index 2722692..967a7b9 100644 --- a/Source/UI/NeuropixelsV2eProbeInterface.h +++ b/Source/UI/NeuropixelsV2eProbeInterface.h @@ -45,7 +45,7 @@ class NeuropixelsV2eProbeInterface : public SettingsInterface, public TextEditor::Listener { public: - friend class ProbeBrowser; + friend class ProbeBrowser; friend class NeuropixelsV2eInterface; NeuropixelsV2eProbeInterface (std::shared_ptr d, int ind, OnixSourceEditor* e, OnixSourceCanvas* c); @@ -60,7 +60,7 @@ class NeuropixelsV2eProbeInterface : public SettingsInterface, void updateInfoString() override; void updateSettings() override; - bool applyProbeSettings (ProbeSettings* p); + bool applyProbeSettings (ProbeSettings* p); void setReference (int index); void selectElectrodes (std::vector electrodes); @@ -104,7 +104,7 @@ class NeuropixelsV2eProbeInterface : public SettingsInterface, std::unique_ptr loadJsonButton; std::unique_ptr saveJsonButton; - std::unique_ptr> probeBrowser; + std::unique_ptr probeBrowser; std::unique_ptr enableViewComponent; std::unique_ptr referenceViewComponent; diff --git a/Source/UI/ProbeBrowser.h b/Source/UI/ProbeBrowser.h index 59ac71b..bce7b18 100644 --- a/Source/UI/ProbeBrowser.h +++ b/Source/UI/ProbeBrowser.h @@ -28,7 +28,6 @@ namespace OnixSourcePlugin { -template class ProbeBrowser : public Component, public Timer { @@ -560,12 +559,12 @@ class ProbeBrowser : public Component, } } - int getZoomHeight() + int getZoomHeight() const { return zoomHeight; } - int getZoomOffset() + int getZoomOffset() const { return zoomOffset; } @@ -586,7 +585,7 @@ class ProbeBrowser : public Component, int probeIndex; - virtual ProbeSettings* getSettings() { return nullptr; } + virtual ProbeSettings* getSettings() { return nullptr; } private: const int leftEdgeOffset = 220; From 1fa9e88037cbbda21e4d38d12d82d0c4f7d96d33 Mon Sep 17 00:00:00 2001 From: bparks13 Date: Fri, 3 Oct 2025 17:15:32 -0400 Subject: [PATCH 2/3] Before acquisition, check if the probe type and probe part number match - Confirms if the selected probe type is the same as the connected hardware. Used to confirm if a probe is connected that is not implemented (such as the 1.0 UHD probe), or to confirm that the correct probe is selected (2.0 single- or quad-shank probes) --- Source/Devices/Neuropixels1.cpp | 34 ++++++++++++++------- Source/Devices/Neuropixels1.h | 2 ++ Source/Devices/Neuropixels1e.cpp | 3 ++ Source/Devices/Neuropixels1f.cpp | 3 ++ Source/Devices/Neuropixels2e.cpp | 6 ++++ Source/Devices/NeuropixelsProbeMetadata.cpp | 33 ++++++++++++++++++++ Source/Devices/NeuropixelsProbeMetadata.h | 3 ++ Source/NeuropixelsComponents.h | 21 +++++++++++-- 8 files changed, 91 insertions(+), 14 deletions(-) diff --git a/Source/Devices/Neuropixels1.cpp b/Source/Devices/Neuropixels1.cpp index 7522c11..4d17c14 100644 --- a/Source/Devices/Neuropixels1.cpp +++ b/Source/Devices/Neuropixels1.cpp @@ -175,20 +175,20 @@ void Neuropixels1::defineMetadata (ProbeSettings* settings, ProbeType probeType) settings->probeMetadata.name = "Neuropixels 1.0"; std::vector> shankOutline { - { 27, 31 }, - { 27, 514 }, - { 27 + 5, 522 }, - { 27 + 10, 514 }, - { 27 + 10, 31 } + { 27, 31}, + { 27, 514}, + { 27 + 5, 522}, + {27 + 10, 514}, + {27 + 10, 31} }; std::vector> probeContour { - { 0, 155 }, - { 35, 0 }, - { 70, 155 }, - { 70, 9770 }, - { 0, 9770 }, - { 0, 155 } + { 0, 155}, + {35, 0}, + {70, 155}, + {70, 9770}, + { 0, 9770}, + { 0, 155} }; settings->probeMetadata.shank_count = 1; @@ -520,3 +520,15 @@ void Neuropixels1::setGainCalibrationFilePath (std::string filepath) { gainCalibrationFilePath = filepath; } + +bool Neuropixels1::validateProbeTypeAndPartNumber () +{ + if (! NeuropixelsProbeMetadata::validateProbeTypeAndPartNumber (settings[0]->probeType, probeMetadata.getProbePartNumber())) + { + Onix1::showWarningMessageBoxAsync ("Probe Type / Number Mismatch", "The selected probe type is " + ProbeTypeString.at (settings[0]->probeType) + ", but the probe part number is " + probeMetadata.getProbePartNumber() + "."); + return false; + } + + return true; +} + diff --git a/Source/Devices/Neuropixels1.h b/Source/Devices/Neuropixels1.h index 022e38c..476f1ca 100644 --- a/Source/Devices/Neuropixels1.h +++ b/Source/Devices/Neuropixels1.h @@ -133,6 +133,8 @@ class Neuropixels1 : public INeuropixel&, int64); void updateApOffsets (std::array&, int64); + bool validateProbeTypeAndPartNumber (); + enum class ElectrodeConfiguration : int32_t { BankA = 0, diff --git a/Source/Devices/Neuropixels1e.cpp b/Source/Devices/Neuropixels1e.cpp index 309f76d..725df62 100644 --- a/Source/Devices/Neuropixels1e.cpp +++ b/Source/Devices/Neuropixels1e.cpp @@ -197,6 +197,9 @@ void Neuropixels1e::resetProbe() bool Neuropixels1e::updateSettings() { + if (! validateProbeTypeAndPartNumber()) + return false; + auto updater = NeuropixelsV1eBackgroundUpdater (this); return updater.updateSettings() && adcValues.size() == NeuropixelsV1Values::AdcCount; diff --git a/Source/Devices/Neuropixels1f.cpp b/Source/Devices/Neuropixels1f.cpp index 6216d1f..0f65f93 100644 --- a/Source/Devices/Neuropixels1f.cpp +++ b/Source/Devices/Neuropixels1f.cpp @@ -153,6 +153,9 @@ int Neuropixels1f::configureDevice() bool Neuropixels1f::updateSettings() { + if (! validateProbeTypeAndPartNumber()) + return false; + auto updater = NeuropixelsV1fBackgroundUpdater (this); return updater.updateSettings() && adcValues.size() == NeuropixelsV1Values::AdcCount; diff --git a/Source/Devices/Neuropixels2e.cpp b/Source/Devices/Neuropixels2e.cpp index dfc956c..a5b388e 100644 --- a/Source/Devices/Neuropixels2e.cpp +++ b/Source/Devices/Neuropixels2e.cpp @@ -342,6 +342,12 @@ bool Neuropixels2e::updateSettings() { if (probeMetadata[i].getProbeSerialNumber() != 0) { + if (! NeuropixelsProbeMetadata::validateProbeTypeAndPartNumber (settings[i]->probeType, probeMetadata[i].getProbePartNumber())) + { + Onix1::showWarningMessageBoxAsync ("Probe Type / Number Mismatch", "The selected probe type is " + ProbeTypeString.at (settings[i]->probeType) + ", but the probe part number is " + probeMetadata[i].getProbePartNumber() + "."); + return false; + } + if (gainCorrectionFilePath[i] == "None" || gainCorrectionFilePath[i] == "") { Onix1::showWarningMessageBoxAsync ("Missing File", "Missing gain correction file for probe " + std::to_string (probeMetadata[i].getProbeSerialNumber())); diff --git a/Source/Devices/NeuropixelsProbeMetadata.cpp b/Source/Devices/NeuropixelsProbeMetadata.cpp index 13a66ab..3053ae3 100644 --- a/Source/Devices/NeuropixelsProbeMetadata.cpp +++ b/Source/Devices/NeuropixelsProbeMetadata.cpp @@ -86,6 +86,39 @@ NeuropixelsProbeMetadata::NeuropixelsProbeMetadata(I2CRegisterContext* flex, Oni } } +bool NeuropixelsProbeMetadata::validateProbeTypeAndPartNumber (ProbeType probeType, std::string partNumber) +{ + if (probeType == ProbeType::NONE) + return false; + + else if (probeType == ProbeType::NPX_V1) + { + if (partNumber == "PRB_1_4_0480_1" || partNumber == "PRB_1_4_0480_1_C" || partNumber == "PRB_1_2_0480_2") + return true; + + else + return false; + } + else if (probeType == ProbeType::NPX_V2_SINGLE_SHANK) + { + if (partNumber == "NP2003" || partNumber == "NP2004") + return true; + + else + return false; + } + else if (probeType == ProbeType::NPX_V2_QUAD_SHANK) + { + if (partNumber == "NP2013" || partNumber == "NP2014") + return true; + + else + return false; + } + else + return false; +} + const uint64_t NeuropixelsProbeMetadata::getProbeSerialNumber() const { return probeSerialNumber; diff --git a/Source/Devices/NeuropixelsProbeMetadata.h b/Source/Devices/NeuropixelsProbeMetadata.h index fe7873a..dec3b75 100644 --- a/Source/Devices/NeuropixelsProbeMetadata.h +++ b/Source/Devices/NeuropixelsProbeMetadata.h @@ -23,6 +23,7 @@ #pragma once #include "../I2CRegisterContext.h" +#include "../NeuropixelsComponents.h" #include "../OnixDevice.h" namespace OnixSourcePlugin @@ -38,6 +39,8 @@ namespace OnixSourcePlugin const std::string getFlexPartNumber() const; const std::string getFlexVersion() const; + static bool validateProbeTypeAndPartNumber (ProbeType probeType, std::string partNumber); + private: OnixDeviceType deviceType = OnixDeviceType::UNKNOWN; diff --git a/Source/NeuropixelsComponents.h b/Source/NeuropixelsComponents.h index 08e355b..a76ea2c 100644 --- a/Source/NeuropixelsComponents.h +++ b/Source/NeuropixelsComponents.h @@ -39,6 +39,13 @@ enum class ProbeType NPX_V2_QUAD_SHANK, }; +const std::map ProbeTypeString = { + { ProbeType::NONE, "None"}, + { ProbeType::NPX_V1, "Neuropixels 1.0"}, + {ProbeType::NPX_V2_SINGLE_SHANK, "Neuropixels 2.0 - single shank"}, + { ProbeType::NPX_V2_QUAD_SHANK, "Neuropixels 2.0 - multishank"}, +}; + enum class Bank { NONE = -1, @@ -212,7 +219,14 @@ struct NeuropixelsV1Adc const int threshold; NeuropixelsV1Adc (int compP_ = 16, int compN_ = 16, int slope_ = 0, int coarse_ = 0, int fine_ = 0, int cfix_ = 0, int offset_ = 0, int threshold_ = 512) - : compP (compP_), compN (compN_), slope (slope_), coarse (coarse_), fine (fine_), cfix (cfix_), offset (offset_), threshold (threshold_) + : compP (compP_), + compN (compN_), + slope (slope_), + coarse (coarse_), + fine (fine_), + cfix (cfix_), + offset (offset_), + threshold (threshold_) { } }; @@ -241,9 +255,10 @@ struct NeuropixelsV2eValues struct ProbeSettings { - ProbeSettings (int numChannels, int numElectrodes, ProbeType type) : numberOfChannels (numChannels), numberOfElectrodes (numElectrodes) + ProbeSettings (int numChannels, int numElectrodes, ProbeType type) : numberOfChannels (numChannels), + numberOfElectrodes (numElectrodes) { - selectedBank = std::vector(numChannels, Bank::A); + selectedBank = std::vector (numChannels, Bank::A); selectedShank = std::vector (numChannels, 0); selectedElectrode = std::vector (numChannels); From 53a90f8aff710a38f880f14eb4239e716d1c316d Mon Sep 17 00:00:00 2001 From: bparks13 Date: Mon, 6 Oct 2025 17:09:54 -0400 Subject: [PATCH 3/3] Add Neuropixels 2.0 single-shank - Add drop-down menu for NPX 2.0e devices to switch between quad- and single-shank probes --- Source/Devices/Neuropixels1.cpp | 72 +-- Source/Devices/Neuropixels1.h | 2 +- Source/Devices/Neuropixels2e.cpp | 26 +- Source/Devices/Neuropixels2e.h | 2 +- Source/Devices/NeuropixelsProbeMetadata.cpp | 287 +++++----- Source/Devices/NeuropixelsProbeMetadata.h | 119 ++-- Source/NeuropixelsComponents.h | 2 +- Source/UI/NeuropixelsV2eProbeInterface.cpp | 600 +++++++++++--------- Source/UI/NeuropixelsV2eProbeInterface.h | 12 + 9 files changed, 617 insertions(+), 505 deletions(-) diff --git a/Source/Devices/Neuropixels1.cpp b/Source/Devices/Neuropixels1.cpp index 4d17c14..ffd3078 100644 --- a/Source/Devices/Neuropixels1.cpp +++ b/Source/Devices/Neuropixels1.cpp @@ -58,47 +58,55 @@ void Neuropixels1::setSettings (ProbeSettings* settings_, int index) settings[index]->updateProbeSettings (settings_); } -std::vector Neuropixels1::selectElectrodeConfiguration (int electrodeConfigurationIndex) +std::vector Neuropixels1::selectElectrodeConfiguration (int electrodeConfigurationIndex, ProbeType probeType) { std::vector selection; - if (electrodeConfigurationIndex == (int32_t) ElectrodeConfiguration::BankA) + if (probeType == ProbeType::NPX_V1) { - for (int i = 0; i < 384; i++) - selection.emplace_back (i); - } - else if (electrodeConfigurationIndex == (int32_t) ElectrodeConfiguration::BankB) - { - for (int i = 384; i < 768; i++) - selection.emplace_back (i); - } - else if (electrodeConfigurationIndex == (int32_t) ElectrodeConfiguration::BankC) - { - for (int i = 576; i < 960; i++) - selection.emplace_back (i); - } - else if (electrodeConfigurationIndex == (int32_t) ElectrodeConfiguration::SingleColumn) - { - for (int i = 0; i < 384; i += 2) - selection.emplace_back (i); - - for (int i = 385; i < 768; i += 2) - selection.emplace_back (i); - } - else if (electrodeConfigurationIndex == (int32_t) ElectrodeConfiguration::Tetrodes) - { - for (int i = 0; i < 384; i += 8) + if (electrodeConfigurationIndex == (int32_t) ElectrodeConfiguration::BankA) { - for (int j = 0; j < 4; j++) - selection.emplace_back (i + j); + for (int i = 0; i < 384; i++) + selection.emplace_back (i); } + else if (electrodeConfigurationIndex == (int32_t) ElectrodeConfiguration::BankB) + { + for (int i = 384; i < 768; i++) + selection.emplace_back (i); + } + else if (electrodeConfigurationIndex == (int32_t) ElectrodeConfiguration::BankC) + { + for (int i = 576; i < 960; i++) + selection.emplace_back (i); + } + else if (electrodeConfigurationIndex == (int32_t) ElectrodeConfiguration::SingleColumn) + { + for (int i = 0; i < 384; i += 2) + selection.emplace_back (i); - for (int i = 388; i < 768; i += 8) + for (int i = 385; i < 768; i += 2) + selection.emplace_back (i); + } + else if (electrodeConfigurationIndex == (int32_t) ElectrodeConfiguration::Tetrodes) { - for (int j = 0; j < 4; j++) - selection.emplace_back (i + j); + for (int i = 0; i < 384; i += 8) + { + for (int j = 0; j < 4; j++) + selection.emplace_back (i + j); + } + + for (int i = 388; i < 768; i += 8) + { + for (int j = 0; j < 4; j++) + selection.emplace_back (i + j); + } } } + else + { + LOGE ("Invalid probe type given for a Neuropixels 2.0 device: ", ProbeTypeString.at (probeType)); + return selection; + } assert (selection.size() == numberOfChannels && "Invalid number of selected channels."); @@ -521,7 +529,7 @@ void Neuropixels1::setGainCalibrationFilePath (std::string filepath) gainCalibrationFilePath = filepath; } -bool Neuropixels1::validateProbeTypeAndPartNumber () +bool Neuropixels1::validateProbeTypeAndPartNumber() { if (! NeuropixelsProbeMetadata::validateProbeTypeAndPartNumber (settings[0]->probeType, probeMetadata.getProbePartNumber())) { diff --git a/Source/Devices/Neuropixels1.h b/Source/Devices/Neuropixels1.h index 476f1ca..a8166d1 100644 --- a/Source/Devices/Neuropixels1.h +++ b/Source/Devices/Neuropixels1.h @@ -50,7 +50,7 @@ class Neuropixels1 : public INeuropixel selectElectrodeConfiguration (int electrodeConfigurationIndex) override; + std::vector selectElectrodeConfiguration (int electrodeConfigurationIndex, ProbeType probeType = ProbeType::NPX_V1) override; void setSettings (ProbeSettings* settings_, int index = 0) override; diff --git a/Source/Devices/Neuropixels2e.cpp b/Source/Devices/Neuropixels2e.cpp index a5b388e..c48ad1f 100644 --- a/Source/Devices/Neuropixels2e.cpp +++ b/Source/Devices/Neuropixels2e.cpp @@ -98,13 +98,11 @@ void Neuropixels2e::selectElectrodesAcrossShanks (std::vector& selection, i } } -std::vector Neuropixels2e::selectElectrodeConfiguration (int electrodeConfigurationIndex) +std::vector Neuropixels2e::selectElectrodeConfiguration (int electrodeConfigurationIndex, ProbeType probeType) { - static int numberOfElectrodesAcrossShanks = 96; - std::vector selection; - if (numberOfShanks == 1) + if (probeType == ProbeType::NPX_V2_SINGLE_SHANK) { if (electrodeConfigurationIndex == (int32_t) ElectrodeConfigurationSingleShank::BankA) { @@ -124,8 +122,10 @@ std::vector Neuropixels2e::selectElectrodeConfiguration (int electrodeConfi selectElectrodesInRange (selection, bankDOffset, numberOfChannels); } } - else if (numberOfShanks == 4) + else if (probeType == ProbeType::NPX_V2_QUAD_SHANK) { + static int numberOfElectrodesAcrossShanks = 96; + if (electrodeConfigurationIndex == (int32_t) ElectrodeConfigurationQuadShank::Shank1BankA) { selectElectrodesInRange (selection, 0, numberOfChannels); @@ -227,6 +227,10 @@ std::vector Neuropixels2e::selectElectrodeConfiguration (int electrodeConfi selectElectrodesAcrossShanks (selection, numberOfElectrodesAcrossShanks * 12, numberOfElectrodesAcrossShanks); } } + else + { + LOGE ("Invalid probe type given for a Neuropixels 2.0 device: ", ProbeTypeString.at(probeType)); + } return selection; } @@ -344,7 +348,7 @@ bool Neuropixels2e::updateSettings() { if (! NeuropixelsProbeMetadata::validateProbeTypeAndPartNumber (settings[i]->probeType, probeMetadata[i].getProbePartNumber())) { - Onix1::showWarningMessageBoxAsync ("Probe Type / Number Mismatch", "The selected probe type is " + ProbeTypeString.at (settings[i]->probeType) + ", but the probe part number is " + probeMetadata[i].getProbePartNumber() + "."); + Onix1::showWarningMessageBoxAsync ("Probe Type Mismatch", "The selected probe type is '" + ProbeTypeString.at (settings[i]->probeType) + "', but the connected probe is '" + NeuropixelsProbeMetadata::getProbeTypeString (probeMetadata[i].getProbePartNumber()) + "'. Please select the correct probe type to match the connected probe."); return false; } @@ -1092,14 +1096,18 @@ void Neuropixels2e::defineMetadata (ProbeSettings* settings, ProbeType probeType settings->apFilterState = false; settings->electrodeConfigurationIndex = (int32_t) ElectrodeConfigurationSingleShank::BankA; - auto selection = selectElectrodeConfiguration (settings->electrodeConfigurationIndex); + auto selection = selectElectrodeConfiguration (settings->electrodeConfigurationIndex, probeType); settings->selectElectrodes (selection); settings->availableReferences.add ("Ext"); - settings->availableReferences.add ("Tip1"); - if (shankCount == 4) + if (probeType == ProbeType::NPX_V2_SINGLE_SHANK) + { + settings->availableReferences.add ("Tip"); + } + else if (probeType == ProbeType::NPX_V2_QUAD_SHANK) { + settings->availableReferences.add ("Tip1"); settings->availableReferences.add ("Tip2"); settings->availableReferences.add ("Tip3"); settings->availableReferences.add ("Tip4"); diff --git a/Source/Devices/Neuropixels2e.h b/Source/Devices/Neuropixels2e.h index 9db252a..66531ee 100644 --- a/Source/Devices/Neuropixels2e.h +++ b/Source/Devices/Neuropixels2e.h @@ -86,7 +86,7 @@ class Neuropixels2e : public INeuropixel selectElectrodeConfiguration (int electrodeConfigurationIndex) override; + std::vector selectElectrodeConfiguration (int electrodeConfigurationIndex, ProbeType probeType) override; uint64_t getProbeSerialNumber (int index) override; std::string getProbePartNumber (int index) override; std::string getFlexPartNumber (int index) override; diff --git a/Source/Devices/NeuropixelsProbeMetadata.cpp b/Source/Devices/NeuropixelsProbeMetadata.cpp index 3053ae3..5aa821f 100644 --- a/Source/Devices/NeuropixelsProbeMetadata.cpp +++ b/Source/Devices/NeuropixelsProbeMetadata.cpp @@ -1,22 +1,22 @@ /* - ------------------------------------------------------------------ + ------------------------------------------------------------------ - Copyright (C) Open Ephys + Copyright (C) Open Ephys - ------------------------------------------------------------------ + ------------------------------------------------------------------ - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. - You should have received a copy of the GNU General Public License - along with this program. If not, see . + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ @@ -24,66 +24,66 @@ using namespace OnixSourcePlugin; -NeuropixelsProbeMetadata::NeuropixelsProbeMetadata(I2CRegisterContext* flex, OnixDeviceType type) - : deviceType(type) +NeuropixelsProbeMetadata::NeuropixelsProbeMetadata (I2CRegisterContext* flex, OnixDeviceType type) + : deviceType (type) { - if (flex == nullptr) - { - throw error_str("Flex is not initialized when trying to read Neuropixels probe metadata."); - } - - if (deviceType != OnixDeviceType::NEUROPIXELSV1E - && deviceType != OnixDeviceType::NEUROPIXELSV1F - && deviceType != OnixDeviceType::NEUROPIXELSV2E) - { - throw error_str("Invalid device type given. Expected the type to be a Neuropixels device."); - } - - try - { - std::vector probeSnBytes; - int rc = flex->readBytes(getProbeSerialNumberOffset(), sizeof(probeSerialNumber), probeSnBytes); - if (rc != ONI_ESUCCESS) - throw error_t(rc); - - for (int i = 0; i < probeSnBytes.size(); i++) - { - if (probeSnBytes[i] <= 0xFF) - { - probeSerialNumber |= (((uint64_t)probeSnBytes[i]) << (i * 8)); - } - } - - const int partNumberLength = 20; - - rc = flex->readString(getProbePartNumberOffset(), partNumberLength, probePartNumber); - if (rc != ONI_ESUCCESS) - throw error_t(rc); - - rc = flex->readString(getFlexPartNumberOffset(), partNumberLength, flexPartNumber); - if (rc != ONI_ESUCCESS) - throw error_t(rc); - - oni_reg_val_t version, revision; - - rc = flex->ReadByte(getFlexVersionOffset(), &version); - if (rc != ONI_ESUCCESS) - throw error_t(rc); - - rc = flex->ReadByte(getFlexRevisionOffset(), &revision); - if (rc != ONI_ESUCCESS) - throw error_t(rc); - - flexVersion = std::to_string(version) + "." + std::to_string(revision); - } - catch (const error_t e) - { - if (e.num() == ONI_EREADFAILURE) - return; - - Onix1::showWarningMessageBoxAsync("Error Reading Probe Metadata", - "Encountered an error while trying to read probe metadata: " + std::string(e.what())); - } + if (flex == nullptr) + { + throw error_str ("Flex is not initialized when trying to read Neuropixels probe metadata."); + } + + if (deviceType != OnixDeviceType::NEUROPIXELSV1E + && deviceType != OnixDeviceType::NEUROPIXELSV1F + && deviceType != OnixDeviceType::NEUROPIXELSV2E) + { + throw error_str ("Invalid device type given. Expected the type to be a Neuropixels device."); + } + + try + { + std::vector probeSnBytes; + int rc = flex->readBytes (getProbeSerialNumberOffset(), sizeof (probeSerialNumber), probeSnBytes); + if (rc != ONI_ESUCCESS) + throw error_t (rc); + + for (int i = 0; i < probeSnBytes.size(); i++) + { + if (probeSnBytes[i] <= 0xFF) + { + probeSerialNumber |= (((uint64_t) probeSnBytes[i]) << (i * 8)); + } + } + + const int partNumberLength = 20; + + rc = flex->readString (getProbePartNumberOffset(), partNumberLength, probePartNumber); + if (rc != ONI_ESUCCESS) + throw error_t (rc); + + rc = flex->readString (getFlexPartNumberOffset(), partNumberLength, flexPartNumber); + if (rc != ONI_ESUCCESS) + throw error_t (rc); + + oni_reg_val_t version, revision; + + rc = flex->ReadByte (getFlexVersionOffset(), &version); + if (rc != ONI_ESUCCESS) + throw error_t (rc); + + rc = flex->ReadByte (getFlexRevisionOffset(), &revision); + if (rc != ONI_ESUCCESS) + throw error_t (rc); + + flexVersion = std::to_string (version) + "." + std::to_string (revision); + } + catch (const error_t e) + { + if (e.num() == ONI_EREADFAILURE) + return; + + Onix1::showWarningMessageBoxAsync ("Error Reading Probe Metadata", + "Encountered an error while trying to read probe metadata: " + std::string (e.what())); + } } bool NeuropixelsProbeMetadata::validateProbeTypeAndPartNumber (ProbeType probeType, std::string partNumber) @@ -119,102 +119,117 @@ bool NeuropixelsProbeMetadata::validateProbeTypeAndPartNumber (ProbeType probeTy return false; } +std::string NeuropixelsProbeMetadata::getProbeTypeString(std::string partNumber) +{ + if (partNumber == "PRB_1_4_0480_1" || partNumber == "PRB_1_4_0480_1_C" || partNumber == "PRB_1_2_0480_2") + return ProbeTypeString.at (ProbeType::NPX_V1); + + else if (partNumber == "NP2003" || partNumber == "NP2004") + return ProbeTypeString.at (ProbeType::NPX_V2_SINGLE_SHANK); + + else if (partNumber == "NP2013" || partNumber == "NP2014") + return ProbeTypeString.at (ProbeType::NPX_V2_QUAD_SHANK); + + else + return "Invalid part number"; +} + const uint64_t NeuropixelsProbeMetadata::getProbeSerialNumber() const { - return probeSerialNumber; + return probeSerialNumber; } const std::string NeuropixelsProbeMetadata::getProbePartNumber() const { - return probePartNumber; + return probePartNumber; } const std::string NeuropixelsProbeMetadata::getFlexPartNumber() const { - return flexPartNumber; + return flexPartNumber; } const std::string NeuropixelsProbeMetadata::getFlexVersion() const { - return flexVersion; + return flexVersion; } uint32_t NeuropixelsProbeMetadata::getProbeSerialNumberOffset() const { - switch (deviceType) - { - case OnixDeviceType::NEUROPIXELSV1E: - case OnixDeviceType::NEUROPIXELSV1F: - return (uint32_t)NeuropixelsV1Offset::PROBE_SN; - - case OnixDeviceType::NEUROPIXELSV2E: - return (uint32_t)NeuropixelsV2Offset::PROBE_SN; - - default: - throw error_str("Invalid device type found in Neuropixels Probe Metadata. Expected a Neuropixels device type."); - } + switch (deviceType) + { + case OnixDeviceType::NEUROPIXELSV1E: + case OnixDeviceType::NEUROPIXELSV1F: + return (uint32_t) NeuropixelsV1Offset::PROBE_SN; + + case OnixDeviceType::NEUROPIXELSV2E: + return (uint32_t) NeuropixelsV2Offset::PROBE_SN; + + default: + throw error_str ("Invalid device type found in Neuropixels Probe Metadata. Expected a Neuropixels device type."); + } } uint32_t NeuropixelsProbeMetadata::getProbePartNumberOffset() const { - switch (deviceType) - { - case OnixDeviceType::NEUROPIXELSV1E: - case OnixDeviceType::NEUROPIXELSV1F: - return (uint32_t)NeuropixelsV1Offset::PROBE_PN; - - case OnixDeviceType::NEUROPIXELSV2E: - return (uint32_t)NeuropixelsV2Offset::PROBE_PN; - - default: - throw error_str("Invalid device type found in Neuropixels Probe Metadata. Expected a Neuropixels device type."); - } + switch (deviceType) + { + case OnixDeviceType::NEUROPIXELSV1E: + case OnixDeviceType::NEUROPIXELSV1F: + return (uint32_t) NeuropixelsV1Offset::PROBE_PN; + + case OnixDeviceType::NEUROPIXELSV2E: + return (uint32_t) NeuropixelsV2Offset::PROBE_PN; + + default: + throw error_str ("Invalid device type found in Neuropixels Probe Metadata. Expected a Neuropixels device type."); + } } uint32_t NeuropixelsProbeMetadata::getFlexPartNumberOffset() const { - switch (deviceType) - { - case OnixDeviceType::NEUROPIXELSV1E: - case OnixDeviceType::NEUROPIXELSV1F: - return (uint32_t)NeuropixelsV1Offset::FLEX_PN; - - case OnixDeviceType::NEUROPIXELSV2E: - return (uint32_t)NeuropixelsV2Offset::FLEX_PN; - - default: - throw error_str("Invalid device type found in Neuropixels Probe Metadata. Expected a Neuropixels device type."); - } + switch (deviceType) + { + case OnixDeviceType::NEUROPIXELSV1E: + case OnixDeviceType::NEUROPIXELSV1F: + return (uint32_t) NeuropixelsV1Offset::FLEX_PN; + + case OnixDeviceType::NEUROPIXELSV2E: + return (uint32_t) NeuropixelsV2Offset::FLEX_PN; + + default: + throw error_str ("Invalid device type found in Neuropixels Probe Metadata. Expected a Neuropixels device type."); + } } uint32_t NeuropixelsProbeMetadata::getFlexVersionOffset() const { - switch (deviceType) - { - case OnixDeviceType::NEUROPIXELSV1E: - case OnixDeviceType::NEUROPIXELSV1F: - return (uint32_t)NeuropixelsV1Offset::FLEX_VERSION; - - case OnixDeviceType::NEUROPIXELSV2E: - return (uint32_t)NeuropixelsV2Offset::FLEX_VERSION; - - default: - throw error_str("Invalid device type found in Neuropixels Probe Metadata. Expected a Neuropixels device type."); - } + switch (deviceType) + { + case OnixDeviceType::NEUROPIXELSV1E: + case OnixDeviceType::NEUROPIXELSV1F: + return (uint32_t) NeuropixelsV1Offset::FLEX_VERSION; + + case OnixDeviceType::NEUROPIXELSV2E: + return (uint32_t) NeuropixelsV2Offset::FLEX_VERSION; + + default: + throw error_str ("Invalid device type found in Neuropixels Probe Metadata. Expected a Neuropixels device type."); + } } uint32_t NeuropixelsProbeMetadata::getFlexRevisionOffset() const { - switch (deviceType) - { - case OnixDeviceType::NEUROPIXELSV1E: - case OnixDeviceType::NEUROPIXELSV1F: - return (uint32_t)NeuropixelsV1Offset::FLEX_REVISION; - - case OnixDeviceType::NEUROPIXELSV2E: - return (uint32_t)NeuropixelsV2Offset::FLEX_REVISION; - - default: - throw error_str("Invalid device type found in Neuropixels Probe Metadata. Expected a Neuropixels device type."); - } + switch (deviceType) + { + case OnixDeviceType::NEUROPIXELSV1E: + case OnixDeviceType::NEUROPIXELSV1F: + return (uint32_t) NeuropixelsV1Offset::FLEX_REVISION; + + case OnixDeviceType::NEUROPIXELSV2E: + return (uint32_t) NeuropixelsV2Offset::FLEX_REVISION; + + default: + throw error_str ("Invalid device type found in Neuropixels Probe Metadata. Expected a Neuropixels device type."); + } } diff --git a/Source/Devices/NeuropixelsProbeMetadata.h b/Source/Devices/NeuropixelsProbeMetadata.h index dec3b75..2486f18 100644 --- a/Source/Devices/NeuropixelsProbeMetadata.h +++ b/Source/Devices/NeuropixelsProbeMetadata.h @@ -1,22 +1,22 @@ /* - ------------------------------------------------------------------ + ------------------------------------------------------------------ - Copyright (C) Open Ephys + Copyright (C) Open Ephys - ------------------------------------------------------------------ + ------------------------------------------------------------------ - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. - You should have received a copy of the GNU General Public License - along with this program. If not, see . + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ @@ -28,49 +28,50 @@ namespace OnixSourcePlugin { - class NeuropixelsProbeMetadata - { - public: - NeuropixelsProbeMetadata() = default; - NeuropixelsProbeMetadata(I2CRegisterContext* flex, OnixDeviceType type); - - const uint64_t getProbeSerialNumber() const; - const std::string getProbePartNumber() const; - const std::string getFlexPartNumber() const; - const std::string getFlexVersion() const; - - static bool validateProbeTypeAndPartNumber (ProbeType probeType, std::string partNumber); - - private: - OnixDeviceType deviceType = OnixDeviceType::UNKNOWN; - - std::string probePartNumber = ""; - uint64_t probeSerialNumber = 0ull; - std::string flexPartNumber = ""; - std::string flexVersion = ""; - - uint32_t getProbeSerialNumberOffset() const; - uint32_t getProbePartNumberOffset() const; - uint32_t getFlexPartNumberOffset() const; - uint32_t getFlexVersionOffset() const; - uint32_t getFlexRevisionOffset() const; - - enum class NeuropixelsV1Offset : uint32_t - { - PROBE_SN = 0, - FLEX_VERSION = 10, - FLEX_REVISION = 11, - FLEX_PN = 20, - PROBE_PN = 40, - }; - - enum class NeuropixelsV2Offset : uint32_t - { - PROBE_SN = 0x00, - FLEX_VERSION = 0x10, - FLEX_REVISION = 0x11, - FLEX_PN = 0x20, - PROBE_PN = 0x40, - }; - }; -} +class NeuropixelsProbeMetadata +{ +public: + NeuropixelsProbeMetadata() = default; + NeuropixelsProbeMetadata (I2CRegisterContext* flex, OnixDeviceType type); + + const uint64_t getProbeSerialNumber() const; + const std::string getProbePartNumber() const; + const std::string getFlexPartNumber() const; + const std::string getFlexVersion() const; + + static bool validateProbeTypeAndPartNumber (ProbeType probeType, std::string partNumber); + static std::string getProbeTypeString (std::string partNumber); + +private: + OnixDeviceType deviceType = OnixDeviceType::UNKNOWN; + + std::string probePartNumber = ""; + uint64_t probeSerialNumber = 0ull; + std::string flexPartNumber = ""; + std::string flexVersion = ""; + + uint32_t getProbeSerialNumberOffset() const; + uint32_t getProbePartNumberOffset() const; + uint32_t getFlexPartNumberOffset() const; + uint32_t getFlexVersionOffset() const; + uint32_t getFlexRevisionOffset() const; + + enum class NeuropixelsV1Offset : uint32_t + { + PROBE_SN = 0, + FLEX_VERSION = 10, + FLEX_REVISION = 11, + FLEX_PN = 20, + PROBE_PN = 40, + }; + + enum class NeuropixelsV2Offset : uint32_t + { + PROBE_SN = 0x00, + FLEX_VERSION = 0x10, + FLEX_REVISION = 0x11, + FLEX_PN = 0x20, + PROBE_PN = 0x40, + }; +}; +} // namespace OnixSourcePlugin diff --git a/Source/NeuropixelsComponents.h b/Source/NeuropixelsComponents.h index a76ea2c..f663375 100644 --- a/Source/NeuropixelsComponents.h +++ b/Source/NeuropixelsComponents.h @@ -397,7 +397,7 @@ class INeuropixel virtual std::string getProbePartNumber (int index) = 0; virtual std::string getFlexPartNumber (int index) = 0; virtual std::string getFlexVersion (int index) = 0; - virtual std::vector selectElectrodeConfiguration (int electrodeConfigurationIndex) = 0; + virtual std::vector selectElectrodeConfiguration (int electrodeConfigurationIndex, ProbeType probeType) = 0; bool saveProbeInterfaceFile (File recordingDirectory, std::string streamName, int probeIndex = 0) { diff --git a/Source/UI/NeuropixelsV2eProbeInterface.cpp b/Source/UI/NeuropixelsV2eProbeInterface.cpp index 5f795ba..edf256a 100644 --- a/Source/UI/NeuropixelsV2eProbeInterface.cpp +++ b/Source/UI/NeuropixelsV2eProbeInterface.cpp @@ -36,284 +36,286 @@ NeuropixelsV2eProbeInterface::NeuropixelsV2eProbeInterface (std::shared_ptr (device)->settings[probeIndex].get(); - - type = SettingsInterface::Type::PROBE_SETTINGS_INTERFACE; - - mode = VisualizationMode::ENABLE_VIEW; - - probeBrowser = std::make_unique (this, probeIndex); - probeBrowser->setBounds (0, 0, 600, 600); - addAndMakeVisible (probeBrowser.get()); - - int currentHeight = 55; - - FontOptions fontName = FontOptions ("Fira Code", "Medium", 30.0f); - FontOptions fontRegularButton = FontOptions ("Fira Code", "Regular", 12.0f); - FontOptions fontRegularLabel = FontOptions ("Fira Code", "Regular", 13.0f); - - deviceLabel = std::make_unique