diff --git a/.clang-format b/.clang-format
new file mode 100644
index 0000000..43cdbfe
--- /dev/null
+++ b/.clang-format
@@ -0,0 +1,60 @@
+# Note: Uses clang-format v17
+---
+Language: Cpp
+# BasedOnStyle: JUCE (Custom)
+AccessModifierOffset: -4
+AlignAfterOpenBracket: Align
+AlignArrayOfStructures: Right
+AlignConsecutiveAssignments: false
+AlignConsecutiveDeclarations: false
+AlignEscapedNewlines: Left
+AlignOperands: Align
+AlignTrailingComments: false
+AllowAllParametersOfDeclarationOnNextLine: false
+AllowShortBlocksOnASingleLine: Never
+AllowShortCaseLabelsOnASingleLine: false
+AllowShortFunctionsOnASingleLine: All
+AllowShortIfStatementsOnASingleLine: Never
+AllowShortLoopsOnASingleLine: false
+AlwaysBreakAfterDefinitionReturnType: None
+AlwaysBreakAfterReturnType: None
+AlwaysBreakBeforeMultilineStrings: false
+AlwaysBreakTemplateDeclarations: Yes
+BinPackArguments: false
+BinPackParameters: false
+BreakBeforeBinaryOperators: NonAssignment
+BreakBeforeBraces: Allman
+BreakBeforeTernaryOperators: true
+BreakConstructorInitializers: BeforeColon
+BreakInheritanceList : BeforeColon
+BreakStringLiterals: false
+ColumnLimit: 0
+ConstructorInitializerIndentWidth: 4
+ContinuationIndentWidth: 4
+Cpp11BracedListStyle: false
+DerivePointerAlignment: false
+DisableFormat: false
+IndentCaseLabels: true
+IndentWidth: 4
+IndentWrappedFunctionNames: true
+KeepEmptyLinesAtEOF: true
+KeepEmptyLinesAtTheStartOfBlocks: false
+MaxEmptyLinesToKeep: 1
+NamespaceIndentation: Inner
+PackConstructorInitializers: CurrentLine
+PointerAlignment: Left
+ReflowComments: true
+SortIncludes: true
+SpaceAfterCStyleCast: true
+SpaceAfterLogicalNot: true
+SpaceBeforeAssignmentOperators: true
+SpaceBeforeCpp11BracedList: true
+SpaceBeforeInheritanceColon: true
+SpaceBeforeParens: NonEmptyParentheses
+SpaceInEmptyParentheses: false
+SpacesInAngles: Never
+SpacesInParens: Never
+SpacesInContainerLiterals: true
+Standard: "c++17"
+TabWidth: 4
+UseTab: Never
\ No newline at end of file
diff --git a/Source/Devices/AnalogIO.cpp b/Source/Devices/AnalogIO.cpp
index c59d7e0..5c0cc0d 100644
--- a/Source/Devices/AnalogIO.cpp
+++ b/Source/Devices/AnalogIO.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,235 +24,238 @@
using namespace OnixSourcePlugin;
-AnalogIO::AnalogIO(std::string name, std::string hubName, const oni_dev_idx_t deviceIdx_, std::shared_ptr oni_ctx)
- : OnixDevice(name, hubName, AnalogIO::getDeviceType(), deviceIdx_, oni_ctx)
+AnalogIO::AnalogIO (std::string name, std::string hubName, const oni_dev_idx_t deviceIdx_, std::shared_ptr oni_ctx)
+ : OnixDevice (name, hubName, AnalogIO::getDeviceType(), deviceIdx_, oni_ctx)
{
- StreamInfo analogInputStream = StreamInfo(
- OnixDevice::createStreamName({ getHubName(), name, "AnalogInput" }),
- "Analog Input data",
- getStreamIdentifier(),
- numChannels,
- getSampleRate(),
- "AnalogInput",
- ContinuousChannel::Type::ADC,
- getVoltsPerDivision(AnalogIOVoltageRange::TenVolts), // NB: +/- 10 Volts
- "V",
- {},
- { "input" });
- streamInfos.add(analogInputStream);
-
- for (int i = 0; i < numFrames; i++)
- eventCodes[i] = 0;
-
- for (int i = 0; i < numChannels; i++)
- {
- channelDirection[i] = AnalogIODirection::Input;
- channelVoltageRange[i] = AnalogIOVoltageRange::TenVolts;
- }
-
- dataType = AnalogIODataType::Volts;
+ StreamInfo analogInputStream = StreamInfo (
+ OnixDevice::createStreamName ({ getHubName(), name, "AnalogInput" }),
+ "Analog Input data",
+ getStreamIdentifier(),
+ numChannels,
+ getSampleRate(),
+ "AnalogInput",
+ ContinuousChannel::Type::ADC,
+ getVoltsPerDivision (AnalogIOVoltageRange::TenVolts), // NB: +/- 10 Volts
+ "V",
+ {},
+ { "input" });
+ streamInfos.add (analogInputStream);
+
+ for (int i = 0; i < numFrames; i++)
+ eventCodes[i] = 0;
+
+ for (int i = 0; i < numChannels; i++)
+ {
+ channelDirection[i] = AnalogIODirection::Input;
+ channelVoltageRange[i] = AnalogIOVoltageRange::TenVolts;
+ }
+
+ dataType = AnalogIODataType::Volts;
}
int AnalogIO::getSampleRate()
{
- return std::floor(AnalogIOFrequencyHz / framesToAverage);
+ return std::floor (AnalogIOFrequencyHz / framesToAverage);
}
OnixDeviceType AnalogIO::getDeviceType()
{
- return OnixDeviceType::ANALOGIO;
+ return OnixDeviceType::ANALOGIO;
}
int AnalogIO::configureDevice()
{
- if (deviceContext == nullptr || !deviceContext->isInitialized())
- throw error_str("Device context is not initialized properly for " + getName());
+ if (deviceContext == nullptr || ! deviceContext->isInitialized())
+ throw error_str ("Device context is not initialized properly for " + getName());
- return deviceContext->writeRegister(deviceIdx, (uint32_t)AnalogIORegisters::ENABLE, (oni_reg_val_t)(isEnabled() ? 1 : 0));
+ return deviceContext->writeRegister (deviceIdx, (uint32_t) AnalogIORegisters::ENABLE, (oni_reg_val_t) (isEnabled() ? 1 : 0));
}
bool AnalogIO::updateSettings()
{
- int rc = 0;
+ int rc = 0;
- for (int i = 0; i < numChannels; i++)
- {
- rc = deviceContext->writeRegister(deviceIdx, (oni_reg_addr_t)AnalogIORegisters::CH00_IN_RANGE + i, (oni_reg_val_t)channelVoltageRange[i]);
- if (rc != ONI_ESUCCESS) return false;
- }
+ for (int i = 0; i < numChannels; i++)
+ {
+ rc = deviceContext->writeRegister (deviceIdx, (oni_reg_addr_t) AnalogIORegisters::CH00_IN_RANGE + i, (oni_reg_val_t) channelVoltageRange[i]);
+ if (rc != ONI_ESUCCESS)
+ return false;
+ }
- uint32_t ioReg = 0;
+ uint32_t ioReg = 0;
- for (int i = 0; i < numChannels; i++)
- {
- ioReg = (ioReg & ~((uint32_t)1 << i)) | ((uint32_t)(channelDirection[i]) << i);
- }
+ for (int i = 0; i < numChannels; i++)
+ {
+ ioReg = (ioReg & ~((uint32_t) 1 << i)) | ((uint32_t) (channelDirection[i]) << i);
+ }
- rc = deviceContext->writeRegister(deviceIdx, (oni_reg_addr_t)AnalogIORegisters::CHDIR, ioReg);
- if (rc != ONI_ESUCCESS) return false;
+ rc = deviceContext->writeRegister (deviceIdx, (oni_reg_addr_t) AnalogIORegisters::CHDIR, ioReg);
+ if (rc != ONI_ESUCCESS)
+ return false;
- for (int i = 0; i < numChannels; i++)
- {
- voltsPerDivision[i] = getVoltsPerDivision(channelVoltageRange[i]);
- }
+ for (int i = 0; i < numChannels; i++)
+ {
+ voltsPerDivision[i] = getVoltsPerDivision (channelVoltageRange[i]);
+ }
- return true;
+ return true;
}
-float AnalogIO::getVoltsPerDivision(AnalogIOVoltageRange voltageRange)
+float AnalogIO::getVoltsPerDivision (AnalogIOVoltageRange voltageRange)
{
- switch (voltageRange)
- {
- case AnalogIOVoltageRange::TenVolts:
- return 20.0f / numberOfDivisions;
- case AnalogIOVoltageRange::TwoPointFiveVolts:
- return 5.0f / numberOfDivisions;
- case AnalogIOVoltageRange::FiveVolts:
- return 10.0f / numberOfDivisions;
- default:
- return 0.0f;
- }
+ switch (voltageRange)
+ {
+ case AnalogIOVoltageRange::TenVolts:
+ return 20.0f / numberOfDivisions;
+ case AnalogIOVoltageRange::TwoPointFiveVolts:
+ return 5.0f / numberOfDivisions;
+ case AnalogIOVoltageRange::FiveVolts:
+ return 10.0f / numberOfDivisions;
+ default:
+ return 0.0f;
+ }
}
-AnalogIODirection AnalogIO::getChannelDirection(int channelNumber)
+AnalogIODirection AnalogIO::getChannelDirection (int channelNumber)
{
- if (channelNumber > numChannels || channelNumber < 0)
- {
- LOGE("Channel number must be between 0 and " + std::to_string(channelNumber));
- return AnalogIODirection::Input;
- }
+ if (channelNumber > numChannels || channelNumber < 0)
+ {
+ LOGE ("Channel number must be between 0 and " + std::to_string (channelNumber));
+ return AnalogIODirection::Input;
+ }
- return channelDirection[channelNumber];
+ return channelDirection[channelNumber];
}
-std::string AnalogIO::getChannelDirection(AnalogIODirection direction)
+std::string AnalogIO::getChannelDirection (AnalogIODirection direction)
{
- switch (direction)
- {
- case AnalogIODirection::Input:
- return "Input";
- case AnalogIODirection::Output:
- return "Output";
- default:
- return "";
- }
+ switch (direction)
+ {
+ case AnalogIODirection::Input:
+ return "Input";
+ case AnalogIODirection::Output:
+ return "Output";
+ default:
+ return "";
+ }
}
-void AnalogIO::setChannelDirection(int channelNumber, AnalogIODirection direction)
+void AnalogIO::setChannelDirection (int channelNumber, AnalogIODirection direction)
{
- if (channelNumber > numChannels || channelNumber < 0)
- {
- LOGE("Channel number must be between 0 and " + std::to_string(channelNumber));
- return;
- }
+ if (channelNumber > numChannels || channelNumber < 0)
+ {
+ LOGE ("Channel number must be between 0 and " + std::to_string (channelNumber));
+ return;
+ }
- channelDirection[channelNumber] = direction;
+ channelDirection[channelNumber] = direction;
}
-AnalogIOVoltageRange AnalogIO::getChannelVoltageRange(int channelNumber)
+AnalogIOVoltageRange AnalogIO::getChannelVoltageRange (int channelNumber)
{
- if (channelNumber > numChannels || channelNumber < 0)
- {
- LOGE("Channel number must be between 0 and " + std::to_string(channelNumber));
- return AnalogIOVoltageRange::FiveVolts;
- }
+ if (channelNumber > numChannels || channelNumber < 0)
+ {
+ LOGE ("Channel number must be between 0 and " + std::to_string (channelNumber));
+ return AnalogIOVoltageRange::FiveVolts;
+ }
- return channelVoltageRange[channelNumber];
+ return channelVoltageRange[channelNumber];
}
-void AnalogIO::setChannelVoltageRange(int channelNumber, AnalogIOVoltageRange direction)
+void AnalogIO::setChannelVoltageRange (int channelNumber, AnalogIOVoltageRange direction)
{
- if (channelNumber > numChannels || channelNumber < 0)
- {
- LOGE("Channel number must be between 0 and " + std::to_string(channelNumber));
- return;
- }
+ if (channelNumber > numChannels || channelNumber < 0)
+ {
+ LOGE ("Channel number must be between 0 and " + std::to_string (channelNumber));
+ return;
+ }
- channelVoltageRange[channelNumber] = direction;
+ channelVoltageRange[channelNumber] = direction;
}
AnalogIODataType AnalogIO::getDataType() const
{
- return dataType;
+ return dataType;
}
-void AnalogIO::setDataType(AnalogIODataType type)
+void AnalogIO::setDataType (AnalogIODataType type)
{
- dataType = type;
+ dataType = type;
}
void AnalogIO::startAcquisition()
{
- currentFrame = 0;
- currentAverageFrame = 0;
- sampleNumber = 0;
+ currentFrame = 0;
+ currentAverageFrame = 0;
+ sampleNumber = 0;
- analogInputSamples.fill(0);
+ analogInputSamples.fill (0);
}
int AnalogIO::getNumberOfFrames()
{
- return frameQueue.size_approx();
+ return frameQueue.size_approx();
}
-void AnalogIO::addSourceBuffers(OwnedArray& sourceBuffers)
+void AnalogIO::addSourceBuffers (OwnedArray& sourceBuffers)
{
- sourceBuffers.add(new DataBuffer(streamInfos.getFirst().getNumChannels(), (int)streamInfos.getFirst().getSampleRate() * bufferSizeInSeconds));
- analogInputBuffer = sourceBuffers.getLast();
+ sourceBuffers.add (new DataBuffer (streamInfos.getFirst().getNumChannels(), (int) streamInfos.getFirst().getSampleRate() * bufferSizeInSeconds));
+ analogInputBuffer = sourceBuffers.getLast();
}
-void AnalogIO::processFrame(uint64_t eventWord)
+void AnalogIO::processFrame (uint64_t eventWord)
{
- oni_frame_t* frame;
- if (!frameQueue.try_dequeue(frame)) { //NB: This method should never be called unless a frame is sure to be there
- jassertfalse;
- }
+ oni_frame_t* frame;
+ if (! frameQueue.try_dequeue (frame))
+ { // NB: This method should never be called unless a frame is sure to be there
+ jassertfalse;
+ }
- int16_t* dataPtr = (int16_t*)frame->data;
+ int16_t* dataPtr = (int16_t*) frame->data;
- int dataOffset = 4;
+ int dataOffset = 4;
- for (size_t i = 0; i < numChannels; i++)
- {
- if (dataType == AnalogIODataType::S16)
- analogInputSamples[currentFrame + i * numFrames] += *(dataPtr + dataOffset + i);
- else
- analogInputSamples[currentFrame + i * numFrames] += *(dataPtr + dataOffset + i) * voltsPerDivision[i];
- }
+ for (size_t i = 0; i < numChannels; i++)
+ {
+ if (dataType == AnalogIODataType::S16)
+ analogInputSamples[currentFrame + i * numFrames] += *(dataPtr + dataOffset + i);
+ else
+ analogInputSamples[currentFrame + i * numFrames] += *(dataPtr + dataOffset + i) * voltsPerDivision[i];
+ }
- currentAverageFrame++;
+ currentAverageFrame++;
- if (currentAverageFrame >= framesToAverage)
- {
- for (size_t i = 0; i < numChannels; i++)
- {
- analogInputSamples[currentFrame + i * numFrames] /= framesToAverage;
- }
+ if (currentAverageFrame >= framesToAverage)
+ {
+ for (size_t i = 0; i < numChannels; i++)
+ {
+ analogInputSamples[currentFrame + i * numFrames] /= framesToAverage;
+ }
- currentAverageFrame = 0;
+ currentAverageFrame = 0;
- timestamps[currentFrame] = deviceContext->convertTimestampToSeconds(frame->time);
- sampleNumbers[currentFrame] = sampleNumber++;
- eventCodes[currentFrame] = eventWord;
+ timestamps[currentFrame] = deviceContext->convertTimestampToSeconds (frame->time);
+ sampleNumbers[currentFrame] = sampleNumber++;
+ eventCodes[currentFrame] = eventWord;
- currentFrame++;
- }
+ currentFrame++;
+ }
- oni_destroy_frame(frame);
+ oni_destroy_frame (frame);
- if (currentFrame >= numFrames)
- {
- analogInputBuffer->addToBuffer(analogInputSamples.data(), sampleNumbers, timestamps, eventCodes, numFrames);
+ if (currentFrame >= numFrames)
+ {
+ analogInputBuffer->addToBuffer (analogInputSamples.data(), sampleNumbers, timestamps, eventCodes, numFrames);
- analogInputSamples.fill(0);
- currentFrame = 0;
- }
+ analogInputSamples.fill (0);
+ currentFrame = 0;
+ }
}
void AnalogIO::processFrames()
{
- while (frameQueue.peek() != nullptr)
- {
- processFrame();
- }
+ while (frameQueue.peek() != nullptr)
+ {
+ processFrame();
+ }
}
diff --git a/Source/Devices/AnalogIO.h b/Source/Devices/AnalogIO.h
index b395a0b..f6bc15b 100644
--- a/Source/Devices/AnalogIO.h
+++ b/Source/Devices/AnalogIO.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 .
*/
@@ -26,107 +26,106 @@
namespace OnixSourcePlugin
{
- enum class AnalogIORegisters : uint32_t
- {
- ENABLE = 0,
- CHDIR = 1,
- CH00_IN_RANGE = 2,
- CH01_IN_RANGE = 3,
- CH02_IN_RANGE = 4,
- CH03_IN_RANGE = 5,
- CH04_IN_RANGE = 6,
- CH05_IN_RANGE = 7,
- CH06_IN_RANGE = 8,
- CH07_IN_RANGE = 9,
- CH08_IN_RANGE = 10,
- CH09_IN_RANGE = 11,
- CH10_IN_RANGE = 12,
- CH11_IN_RANGE = 13,
- };
-
- enum class AnalogIOVoltageRange : uint32_t
- {
- TenVolts = 0,
- TwoPointFiveVolts = 1,
- FiveVolts = 2
- };
-
- enum class AnalogIODirection : uint32_t
- {
- Input = 0,
- Output = 1
- };
-
- enum class AnalogIODataType : uint32_t
- {
- S16 = 0,
- Volts = 1
- };
-
- /*
- Configures and streams data from an AnalogIO device on a Breakout Board
- */
- class AnalogIO : public OnixDevice
- {
- public:
- AnalogIO(std::string name, std::string hubName, const oni_dev_idx_t, std::shared_ptr oni_ctx);
-
- int configureDevice() override;
- bool updateSettings() override;
- void startAcquisition() override;
- void addSourceBuffers(OwnedArray& sourceBuffers) override;
- void processFrames() override;
-
- void processFrame(uint64_t eventWord = 0);
-
- AnalogIODirection getChannelDirection(int channelNumber);
- static std::string getChannelDirection(AnalogIODirection direction);
- void setChannelDirection(int channelNumber, AnalogIODirection direction);
-
- AnalogIOVoltageRange getChannelVoltageRange(int channelNumber);
- void setChannelVoltageRange(int channelNumber, AnalogIOVoltageRange direction);
-
- AnalogIODataType getDataType() const;
- void setDataType(AnalogIODataType type);
-
- static OnixDeviceType getDeviceType();
-
- static int getSampleRate();
-
- int getNumberOfFrames();
-
- private:
-
- DataBuffer* analogInputBuffer = nullptr;
-
- static constexpr int AnalogIOFrequencyHz = 100000;
- static constexpr int framesToAverage = 4; // NB: Downsampling from 100 kHz to 25 kHz
-
- static constexpr int numFrames = 25;
- static constexpr int numChannels = 12;
-
- static constexpr int numberOfDivisions = 1 << 16;
- static constexpr int dacMidScale = 1 << 15;
-
- std::array channelDirection;
- std::array channelVoltageRange;
-
- AnalogIODataType dataType = AnalogIODataType::Volts;
-
- unsigned short currentFrame = 0;
- unsigned short currentAverageFrame = 0;
- int sampleNumber = 0;
-
- std::array analogInputSamples;
-
- double timestamps[numFrames];
- int64 sampleNumbers[numFrames];
- uint64 eventCodes[numFrames];
-
- std::array voltsPerDivision;
-
- static float getVoltsPerDivision(AnalogIOVoltageRange voltageRange);
-
- JUCE_LEAK_DETECTOR(AnalogIO);
- };
-}
+enum class AnalogIORegisters : uint32_t
+{
+ ENABLE = 0,
+ CHDIR = 1,
+ CH00_IN_RANGE = 2,
+ CH01_IN_RANGE = 3,
+ CH02_IN_RANGE = 4,
+ CH03_IN_RANGE = 5,
+ CH04_IN_RANGE = 6,
+ CH05_IN_RANGE = 7,
+ CH06_IN_RANGE = 8,
+ CH07_IN_RANGE = 9,
+ CH08_IN_RANGE = 10,
+ CH09_IN_RANGE = 11,
+ CH10_IN_RANGE = 12,
+ CH11_IN_RANGE = 13,
+};
+
+enum class AnalogIOVoltageRange : uint32_t
+{
+ TenVolts = 0,
+ TwoPointFiveVolts = 1,
+ FiveVolts = 2
+};
+
+enum class AnalogIODirection : uint32_t
+{
+ Input = 0,
+ Output = 1
+};
+
+enum class AnalogIODataType : uint32_t
+{
+ S16 = 0,
+ Volts = 1
+};
+
+/*
+ Configures and streams data from an AnalogIO device on a Breakout Board
+*/
+class AnalogIO : public OnixDevice
+{
+public:
+ AnalogIO (std::string name, std::string hubName, const oni_dev_idx_t, std::shared_ptr oni_ctx);
+
+ int configureDevice() override;
+ bool updateSettings() override;
+ void startAcquisition() override;
+ void addSourceBuffers (OwnedArray& sourceBuffers) override;
+ void processFrames() override;
+
+ void processFrame (uint64_t eventWord = 0);
+
+ AnalogIODirection getChannelDirection (int channelNumber);
+ static std::string getChannelDirection (AnalogIODirection direction);
+ void setChannelDirection (int channelNumber, AnalogIODirection direction);
+
+ AnalogIOVoltageRange getChannelVoltageRange (int channelNumber);
+ void setChannelVoltageRange (int channelNumber, AnalogIOVoltageRange direction);
+
+ AnalogIODataType getDataType() const;
+ void setDataType (AnalogIODataType type);
+
+ static OnixDeviceType getDeviceType();
+
+ static int getSampleRate();
+
+ int getNumberOfFrames();
+
+private:
+ DataBuffer* analogInputBuffer = nullptr;
+
+ static constexpr int AnalogIOFrequencyHz = 100000;
+ static constexpr int framesToAverage = 4; // NB: Downsampling from 100 kHz to 25 kHz
+
+ static constexpr int numFrames = 25;
+ static constexpr int numChannels = 12;
+
+ static constexpr int numberOfDivisions = 1 << 16;
+ static constexpr int dacMidScale = 1 << 15;
+
+ std::array channelDirection;
+ std::array channelVoltageRange;
+
+ AnalogIODataType dataType = AnalogIODataType::Volts;
+
+ unsigned short currentFrame = 0;
+ unsigned short currentAverageFrame = 0;
+ int sampleNumber = 0;
+
+ std::array analogInputSamples;
+
+ double timestamps[numFrames];
+ int64 sampleNumbers[numFrames];
+ uint64 eventCodes[numFrames];
+
+ std::array voltsPerDivision;
+
+ static float getVoltsPerDivision (AnalogIOVoltageRange voltageRange);
+
+ JUCE_LEAK_DETECTOR (AnalogIO);
+};
+} // namespace OnixSourcePlugin
diff --git a/Source/Devices/Bno055.cpp b/Source/Devices/Bno055.cpp
index 21fac20..14547ef 100644
--- a/Source/Devices/Bno055.cpp
+++ b/Source/Devices/Bno055.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,209 +24,203 @@
using namespace OnixSourcePlugin;
-Bno055::Bno055(std::string name, std::string hubName, const oni_dev_idx_t deviceIdx_, std::shared_ptr ctx)
- : OnixDevice(name, hubName, Bno055::getDeviceType(), deviceIdx_, ctx)
+Bno055::Bno055 (std::string name, std::string hubName, const oni_dev_idx_t deviceIdx_, std::shared_ptr ctx)
+ : OnixDevice (name, hubName, Bno055::getDeviceType(), deviceIdx_, ctx)
{
- auto streamIdentifier = getStreamIdentifier();
-
- std::string port = getPortName(deviceIdx);
- StreamInfo eulerAngleStream = StreamInfo(
- OnixDevice::createStreamName({ port, getHubName(), getName(), "Euler" }),
- "Bosch Bno055 9-axis inertial measurement unit (IMU) Euler angle",
- streamIdentifier,
- 3,
- sampleRate,
- "Eul",
- ContinuousChannel::Type::AUX,
- eulerAngleScale,
- "Degrees",
- { "Y", "R", "P" },
- "euler",
- { "y", "r", "p" }
- );
- streamInfos.add(eulerAngleStream);
-
- StreamInfo quaternionStream = StreamInfo(
- OnixDevice::createStreamName({ port, getHubName(), getName(), "Quaternion" }),
- "Bosch Bno055 9-axis inertial measurement unit (IMU) Quaternion",
- streamIdentifier,
- 4,
- sampleRate,
- "Quat",
- ContinuousChannel::Type::AUX,
- quaternionScale,
- "u", // NB: Quaternion data is unitless by definition
- { "W", "X", "Y", "Z" },
- "quaternion",
- { "w", "x", "y", "z" }
- );
- streamInfos.add(quaternionStream);
-
- StreamInfo accelerationStream = StreamInfo(
- OnixDevice::createStreamName({ port, getHubName(), getName(), "Acceleration" }),
- "Bosch Bno055 9-axis inertial measurement unit (IMU) Acceleration",
- streamIdentifier,
- 3,
- sampleRate,
- "Acc",
- ContinuousChannel::Type::AUX,
- accelerationScale,
- "m/s^2",
- { "X", "Y", "Z" },
- "acceleration",
- { "x","y","z" }
- );
- streamInfos.add(accelerationStream);
-
- StreamInfo gravityStream = StreamInfo(
- OnixDevice::createStreamName({ port, getHubName(), getName(), "Gravity" }),
- "Bosch Bno055 9-axis inertial measurement unit (IMU) Gravity",
- streamIdentifier,
- 3,
- sampleRate,
- "Grav",
- ContinuousChannel::Type::AUX,
- accelerationScale,
- "m/s^2",
- { "X", "Y", "Z" },
- "gravity",
- { "x", "y", "z" }
- );
- streamInfos.add(gravityStream);
-
- StreamInfo temperatureStream = StreamInfo(
- OnixDevice::createStreamName({ port, getHubName(), getName(), "Temperature" }),
- "Bosch Bno055 9-axis inertial measurement unit (IMU) Temperature",
- streamIdentifier,
- 1,
- sampleRate,
- "Temp",
- ContinuousChannel::Type::AUX,
- 1.0f,
- "Celsius",
- { "" },
- "temperature"
- );
- streamInfos.add(temperatureStream);
-
- StreamInfo calibrationStatusStream = StreamInfo(
- OnixDevice::createStreamName({ port, getHubName(), getName(), "Calibration" }),
- "Bosch Bno055 9-axis inertial measurement unit (IMU) Calibration status",
- streamIdentifier,
- 4,
- sampleRate,
- "Cal",
- ContinuousChannel::Type::AUX,
- 1.0f,
- "",
- { "Mag", "Acc", "Gyr", "Sys" },
- "calibration",
- { "magnetometer", "acceleration", "gyroscope", "system" }
- );
- streamInfos.add(calibrationStatusStream);
-
- for (int i = 0; i < numFrames; i++)
- eventCodes[i] = 0;
+ auto streamIdentifier = getStreamIdentifier();
+
+ std::string port = getPortName (deviceIdx);
+ StreamInfo eulerAngleStream = StreamInfo (
+ OnixDevice::createStreamName ({ port, getHubName(), getName(), "Euler" }),
+ "Bosch Bno055 9-axis inertial measurement unit (IMU) Euler angle",
+ streamIdentifier,
+ 3,
+ sampleRate,
+ "Eul",
+ ContinuousChannel::Type::AUX,
+ eulerAngleScale,
+ "Degrees",
+ { "Y", "R", "P" },
+ "euler",
+ { "y", "r", "p" });
+ streamInfos.add (eulerAngleStream);
+
+ StreamInfo quaternionStream = StreamInfo (
+ OnixDevice::createStreamName ({ port, getHubName(), getName(), "Quaternion" }),
+ "Bosch Bno055 9-axis inertial measurement unit (IMU) Quaternion",
+ streamIdentifier,
+ 4,
+ sampleRate,
+ "Quat",
+ ContinuousChannel::Type::AUX,
+ quaternionScale,
+ "u", // NB: Quaternion data is unitless by definition
+ { "W", "X", "Y", "Z" },
+ "quaternion",
+ { "w", "x", "y", "z" });
+ streamInfos.add (quaternionStream);
+
+ StreamInfo accelerationStream = StreamInfo (
+ OnixDevice::createStreamName ({ port, getHubName(), getName(), "Acceleration" }),
+ "Bosch Bno055 9-axis inertial measurement unit (IMU) Acceleration",
+ streamIdentifier,
+ 3,
+ sampleRate,
+ "Acc",
+ ContinuousChannel::Type::AUX,
+ accelerationScale,
+ "m/s^2",
+ { "X", "Y", "Z" },
+ "acceleration",
+ { "x", "y", "z" });
+ streamInfos.add (accelerationStream);
+
+ StreamInfo gravityStream = StreamInfo (
+ OnixDevice::createStreamName ({ port, getHubName(), getName(), "Gravity" }),
+ "Bosch Bno055 9-axis inertial measurement unit (IMU) Gravity",
+ streamIdentifier,
+ 3,
+ sampleRate,
+ "Grav",
+ ContinuousChannel::Type::AUX,
+ accelerationScale,
+ "m/s^2",
+ { "X", "Y", "Z" },
+ "gravity",
+ { "x", "y", "z" });
+ streamInfos.add (gravityStream);
+
+ StreamInfo temperatureStream = StreamInfo (
+ OnixDevice::createStreamName ({ port, getHubName(), getName(), "Temperature" }),
+ "Bosch Bno055 9-axis inertial measurement unit (IMU) Temperature",
+ streamIdentifier,
+ 1,
+ sampleRate,
+ "Temp",
+ ContinuousChannel::Type::AUX,
+ 1.0f,
+ "Celsius",
+ { "" },
+ "temperature");
+ streamInfos.add (temperatureStream);
+
+ StreamInfo calibrationStatusStream = StreamInfo (
+ OnixDevice::createStreamName ({ port, getHubName(), getName(), "Calibration" }),
+ "Bosch Bno055 9-axis inertial measurement unit (IMU) Calibration status",
+ streamIdentifier,
+ 4,
+ sampleRate,
+ "Cal",
+ ContinuousChannel::Type::AUX,
+ 1.0f,
+ "",
+ { "Mag", "Acc", "Gyr", "Sys" },
+ "calibration",
+ { "magnetometer", "acceleration", "gyroscope", "system" });
+ streamInfos.add (calibrationStatusStream);
+
+ for (int i = 0; i < numFrames; i++)
+ eventCodes[i] = 0;
}
OnixDeviceType Bno055::getDeviceType()
{
- return OnixDeviceType::BNO;
+ return OnixDeviceType::BNO;
}
int Bno055::configureDevice()
{
- if (deviceContext == nullptr || !deviceContext->isInitialized())
- throw error_str("Device context is not initialized properly for " + getName());
+ if (deviceContext == nullptr || ! deviceContext->isInitialized())
+ throw error_str ("Device context is not initialized properly for " + getName());
- return deviceContext->writeRegister(deviceIdx, (uint32_t)Bno055Registers::ENABLE, isEnabled() ? 1 : 0);
+ return deviceContext->writeRegister (deviceIdx, (uint32_t) Bno055Registers::ENABLE, isEnabled() ? 1 : 0);
}
bool Bno055::updateSettings()
{
- return true;
+ return true;
}
void Bno055::startAcquisition()
{
- currentFrame = 0;
- sampleNumber = 0;
+ currentFrame = 0;
+ sampleNumber = 0;
}
-void Bno055::addSourceBuffers(OwnedArray& sourceBuffers)
+void Bno055::addSourceBuffers (OwnedArray& sourceBuffers)
{
- sourceBuffers.add(new DataBuffer(numberOfChannels, (int)sampleRate * bufferSizeInSeconds));
- bnoBuffer = sourceBuffers.getLast();
+ sourceBuffers.add (new DataBuffer (numberOfChannels, (int) sampleRate * bufferSizeInSeconds));
+ bnoBuffer = sourceBuffers.getLast();
}
void Bno055::processFrames()
{
- oni_frame_t* frame;
- while (frameQueue.try_dequeue(frame))
- {
- int16_t* dataPtr = ((int16_t*)frame->data) + 4;
-
- bnoTimestamps[currentFrame] = deviceContext->convertTimestampToSeconds(frame->time);
-
- size_t offset = 0;
-
- // Euler
- for (int i = 0; i < 3; i++)
- {
- bnoSamples[currentFrame + offset * numFrames] = float(*(dataPtr + offset)) * eulerAngleScale;
- offset++;
- }
-
- // Quaternion
- for (int i = 0; i < 4; i++)
- {
- bnoSamples[currentFrame + offset * numFrames] = float(*(dataPtr + offset)) * quaternionScale;
- offset++;
- }
-
- // Acceleration
- for (int i = 0; i < 3; i++)
- {
- bnoSamples[currentFrame + offset * numFrames] = float(*(dataPtr + offset)) * accelerationScale;
- offset++;
- }
-
- // Gravity
- for (int i = 0; i < 3; i++)
- {
- bnoSamples[currentFrame + offset * numFrames] = float(*(dataPtr + offset)) * accelerationScale;
- offset++;
- }
-
- // Temperature
- bnoSamples[currentFrame + offset * numFrames] = *((uint8_t*)(dataPtr + offset));
-
- // Calibration
- auto calibrationStatus = *((uint8_t*)(dataPtr + offset) + 1);
-
- constexpr uint8_t statusMask = 0b11;
-
- for (int i = 0; i < 4; i++)
- {
- bnoSamples[currentFrame + (offset + i + 1) * numFrames] = (calibrationStatus & (statusMask << (2 * i))) >> (2 * i);
- }
-
- oni_destroy_frame(frame);
-
- sampleNumbers[currentFrame] = sampleNumber++;
-
- currentFrame++;
-
- if (currentFrame >= numFrames)
- {
- shouldAddToBuffer = true;
- currentFrame = 0;
- }
-
- if (shouldAddToBuffer)
- {
- shouldAddToBuffer = false;
- bnoBuffer->addToBuffer(bnoSamples.data(), sampleNumbers, bnoTimestamps, eventCodes, numFrames);
- }
- }
+ oni_frame_t* frame;
+ while (frameQueue.try_dequeue (frame))
+ {
+ int16_t* dataPtr = ((int16_t*) frame->data) + 4;
+
+ bnoTimestamps[currentFrame] = deviceContext->convertTimestampToSeconds (frame->time);
+
+ size_t offset = 0;
+
+ // Euler
+ for (int i = 0; i < 3; i++)
+ {
+ bnoSamples[currentFrame + offset * numFrames] = float (*(dataPtr + offset)) * eulerAngleScale;
+ offset++;
+ }
+
+ // Quaternion
+ for (int i = 0; i < 4; i++)
+ {
+ bnoSamples[currentFrame + offset * numFrames] = float (*(dataPtr + offset)) * quaternionScale;
+ offset++;
+ }
+
+ // Acceleration
+ for (int i = 0; i < 3; i++)
+ {
+ bnoSamples[currentFrame + offset * numFrames] = float (*(dataPtr + offset)) * accelerationScale;
+ offset++;
+ }
+
+ // Gravity
+ for (int i = 0; i < 3; i++)
+ {
+ bnoSamples[currentFrame + offset * numFrames] = float (*(dataPtr + offset)) * accelerationScale;
+ offset++;
+ }
+
+ // Temperature
+ bnoSamples[currentFrame + offset * numFrames] = *((uint8_t*) (dataPtr + offset));
+
+ // Calibration
+ auto calibrationStatus = *((uint8_t*) (dataPtr + offset) + 1);
+
+ constexpr uint8_t statusMask = 0b11;
+
+ for (int i = 0; i < 4; i++)
+ {
+ bnoSamples[currentFrame + (offset + i + 1) * numFrames] = (calibrationStatus & (statusMask << (2 * i))) >> (2 * i);
+ }
+
+ oni_destroy_frame (frame);
+
+ sampleNumbers[currentFrame] = sampleNumber++;
+
+ currentFrame++;
+
+ if (currentFrame >= numFrames)
+ {
+ shouldAddToBuffer = true;
+ currentFrame = 0;
+ }
+
+ if (shouldAddToBuffer)
+ {
+ shouldAddToBuffer = false;
+ bnoBuffer->addToBuffer (bnoSamples.data(), sampleNumbers, bnoTimestamps, eventCodes, numFrames);
+ }
+ }
}
diff --git a/Source/Devices/Bno055.h b/Source/Devices/Bno055.h
index 8830a3e..0623595 100644
--- a/Source/Devices/Bno055.h
+++ b/Source/Devices/Bno055.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 .
*/
@@ -26,53 +26,51 @@
namespace OnixSourcePlugin
{
- enum class Bno055Registers
- {
- ENABLE = 0x00
- };
-
- /*
- Configures and streams data from a BNO055 device
- */
- class Bno055 : public OnixDevice
- {
- public:
-
- /** Constructor */
- Bno055(std::string name, std::string hubName, const oni_dev_idx_t, std::shared_ptr ctx);
+enum class Bno055Registers
+{
+ ENABLE = 0x00
+};
- int configureDevice() override;
- bool updateSettings() override;
- void startAcquisition() override;
- void processFrames() override;
- void addSourceBuffers(OwnedArray& sourceBuffers) override;
+/*
+ Configures and streams data from a BNO055 device
+*/
+class Bno055 : public OnixDevice
+{
+public:
+ /** Constructor */
+ Bno055 (std::string name, std::string hubName, const oni_dev_idx_t, std::shared_ptr ctx);
- static OnixDeviceType getDeviceType();
+ int configureDevice() override;
+ bool updateSettings() override;
+ void startAcquisition() override;
+ void processFrames() override;
+ void addSourceBuffers (OwnedArray& sourceBuffers) override;
- private:
+ static OnixDeviceType getDeviceType();
- DataBuffer* bnoBuffer;
+private:
+ DataBuffer* bnoBuffer;
- const float eulerAngleScale = 1.0f / 16; // 1 degree = 16 LSB
- const float quaternionScale = 1.0f / (1 << 14); // 1 = 2^14 LSB
- const float accelerationScale = 1.0f / 100; // 1m / s^2 = 100 LSB
+ const float eulerAngleScale = 1.0f / 16; // 1 degree = 16 LSB
+ const float quaternionScale = 1.0f / (1 << 14); // 1 = 2^14 LSB
+ const float accelerationScale = 1.0f / 100; // 1m / s^2 = 100 LSB
- static const int numFrames = 2;
+ static const int numFrames = 2;
- bool shouldAddToBuffer = false;
+ bool shouldAddToBuffer = false;
- static const int numberOfChannels = 3 + 3 + 4 + 3 + 1 + 4;
- static constexpr float sampleRate = 100.0f;
+ static const int numberOfChannels = 3 + 3 + 4 + 3 + 1 + 4;
+ static constexpr float sampleRate = 100.0f;
- std::array bnoSamples;
+ std::array bnoSamples;
- double bnoTimestamps[numFrames];
- int64 sampleNumbers[numFrames];
- uint64 eventCodes[numFrames];
+ double bnoTimestamps[numFrames];
+ int64 sampleNumbers[numFrames];
+ uint64 eventCodes[numFrames];
- unsigned short currentFrame = 0;
- int sampleNumber = 0;
+ unsigned short currentFrame = 0;
+ int sampleNumber = 0;
- JUCE_LEAK_DETECTOR(Bno055);
- };
-}
+ JUCE_LEAK_DETECTOR (Bno055);
+};
+} // namespace OnixSourcePlugin
diff --git a/Source/Devices/DS90UB9x.h b/Source/Devices/DS90UB9x.h
index d15e3d3..400f979 100644
--- a/Source/Devices/DS90UB9x.h
+++ b/Source/Devices/DS90UB9x.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 .
*/
@@ -26,128 +26,128 @@
namespace OnixSourcePlugin
{
- static class DS90UB9x
- {
- public:
- // managed registers
- static const uint32_t ENABLE = 0x8000;
- static const uint32_t READSZ = 0x8001;
- static const uint32_t TRIGGER = 0x8002;
- static const uint32_t TRIGGEROFF = 0x8003;
- static const uint32_t DATAGATE = 0x8004;
- static const uint32_t SYNCBITS = 0x8005;
- static const uint32_t MARK = 0x8006;
- static const uint32_t MAGIC_MASK = 0x8007;
- static const uint32_t MAGIC = 0x8008;
- static const uint32_t MAGIC_WAIT = 0x8009;
- static const uint32_t DATAMODE = 0x800A;
- static const uint32_t DATALINES0 = 0x800B;
- static const uint32_t DATALINES1 = 0x800C;
-
- // reserved registers
- static const uint32_t GPIO_DIR = 0x8010;
- static const uint32_t GPIO_VAL = 0x8011;
- static const uint32_t LINKSTATUS = 0x8012;
- static const uint32_t LASTI2CL = 0x8013;
- static const uint32_t LASTI2CH = 0x8014;
-
- // unmanaged default serializer / deserializer I2C addresses
- static const uint32_t DES_ADDR = 0x30;
- static const uint32_t SER_ADDR = 0x58;
-
- enum class DS90UB9xTriggerMode : uint32_t
- {
- Continuous = 0,
- HsyncEdgePositive = 0b0001,
- HsyncEdgeNegative = 0b1001,
- HsyncLevelPositive = 0b0101,
- HsyncLevelNegative = 0b1101,
- VsyncEdgePositive = 0b0011,
- VsyncEdgeNegative = 0b1011,
- VsyncLevelPositive = 0b0111,
- VsyncLevelNegative = 0b1111,
- };
-
- enum class DS90UB9xDataGate : uint32_t
- {
- Disabled = 0,
- HsyncPositive = 0b001,
- HsyncNegative = 0b101,
- VsyncPositive = 0b011,
- VsyncNegative = 0b111,
- };
-
- enum class DS90UB9xMarkMode : uint32_t
- {
- Disabled = 0,
- HsyncRising = 0b001,
- HsyncFalling = 0b101,
- VsyncRising = 0b011,
- VsyncFalling = 0b111,
- };
-
- enum class DS90UB9xDeserializerI2CRegister : uint32_t
- {
- PortMode = 0x6D,
- PortSel = 0x4C,
- I2CConfig = 0x58,
- GpioCtrl0 = 0x6E,
- GpioCtrl1 = 0x6F,
-
- SerAlias = 0x5C,
-
- SlaveID1 = 0x5E,
- SlaveID2 = 0x5F,
- SlaveID3 = 0x60,
- SlaveID4 = 0x61,
- SlaveID5 = 0x62,
- SlaveID6 = 0x63,
- SlaveID7 = 0x64,
-
- SlaveAlias1 = 0x66,
- SlaveAlias2 = 0x67,
- SlaveAlias3 = 0x68,
- SlaveAlias4 = 0x69,
- SlaveAlias5 = 0x6A,
- SlaveAlias6 = 0x6B,
- SlaveAlias7 = 0x6C,
- };
-
- enum class DS90UB9xSerializerI2CRegister : uint32_t
- {
- GPIO10 = 0x0D,
- GPIO32 = 0x0E,
- SCLHIGH = 0x0A,
- SCLLOW = 0x0B
- };
-
- enum class DS90UB933SerializerI2CRegister : uint32_t
- {
- Gpio10 = 0x0D,
- Gpio32 = 0x0E,
- SclHigh = 0x11,
- SclLow = 0x12
- };
-
- enum class DS90UB953SerializerI2CRegister : uint32_t
- {
- GpioData = 0x0D,
- GpioIOControl = 0x0E,
- SclHigh = 0x0B,
- SclLow = 0x0C
- };
-
- enum class DS90UB9xMode : uint32_t
- {
- Raw12BitLowFrequency = 1,
- Raw12BitHighFrequency = 2,
- Raw10Bit = 3,
- };
-
- enum class DS90UB9xDirection : uint32_t
- {
- Input = 0,
- Output = 1
- };
- };
-}
+static class DS90UB9x
+{
+public:
+ // managed registers
+ static const uint32_t ENABLE = 0x8000;
+ static const uint32_t READSZ = 0x8001;
+ static const uint32_t TRIGGER = 0x8002;
+ static const uint32_t TRIGGEROFF = 0x8003;
+ static const uint32_t DATAGATE = 0x8004;
+ static const uint32_t SYNCBITS = 0x8005;
+ static const uint32_t MARK = 0x8006;
+ static const uint32_t MAGIC_MASK = 0x8007;
+ static const uint32_t MAGIC = 0x8008;
+ static const uint32_t MAGIC_WAIT = 0x8009;
+ static const uint32_t DATAMODE = 0x800A;
+ static const uint32_t DATALINES0 = 0x800B;
+ static const uint32_t DATALINES1 = 0x800C;
+
+ // reserved registers
+ static const uint32_t GPIO_DIR = 0x8010;
+ static const uint32_t GPIO_VAL = 0x8011;
+ static const uint32_t LINKSTATUS = 0x8012;
+ static const uint32_t LASTI2CL = 0x8013;
+ static const uint32_t LASTI2CH = 0x8014;
+
+ // unmanaged default serializer / deserializer I2C addresses
+ static const uint32_t DES_ADDR = 0x30;
+ static const uint32_t SER_ADDR = 0x58;
+
+ enum class DS90UB9xTriggerMode : uint32_t
+ {
+ Continuous = 0,
+ HsyncEdgePositive = 0b0001,
+ HsyncEdgeNegative = 0b1001,
+ HsyncLevelPositive = 0b0101,
+ HsyncLevelNegative = 0b1101,
+ VsyncEdgePositive = 0b0011,
+ VsyncEdgeNegative = 0b1011,
+ VsyncLevelPositive = 0b0111,
+ VsyncLevelNegative = 0b1111,
+ };
+
+ enum class DS90UB9xDataGate : uint32_t
+ {
+ Disabled = 0,
+ HsyncPositive = 0b001,
+ HsyncNegative = 0b101,
+ VsyncPositive = 0b011,
+ VsyncNegative = 0b111,
+ };
+
+ enum class DS90UB9xMarkMode : uint32_t
+ {
+ Disabled = 0,
+ HsyncRising = 0b001,
+ HsyncFalling = 0b101,
+ VsyncRising = 0b011,
+ VsyncFalling = 0b111,
+ };
+
+ enum class DS90UB9xDeserializerI2CRegister : uint32_t
+ {
+ PortMode = 0x6D,
+ PortSel = 0x4C,
+ I2CConfig = 0x58,
+ GpioCtrl0 = 0x6E,
+ GpioCtrl1 = 0x6F,
+
+ SerAlias = 0x5C,
+
+ SlaveID1 = 0x5E,
+ SlaveID2 = 0x5F,
+ SlaveID3 = 0x60,
+ SlaveID4 = 0x61,
+ SlaveID5 = 0x62,
+ SlaveID6 = 0x63,
+ SlaveID7 = 0x64,
+
+ SlaveAlias1 = 0x66,
+ SlaveAlias2 = 0x67,
+ SlaveAlias3 = 0x68,
+ SlaveAlias4 = 0x69,
+ SlaveAlias5 = 0x6A,
+ SlaveAlias6 = 0x6B,
+ SlaveAlias7 = 0x6C,
+ };
+
+ enum class DS90UB9xSerializerI2CRegister : uint32_t
+ {
+ GPIO10 = 0x0D,
+ GPIO32 = 0x0E,
+ SCLHIGH = 0x0A,
+ SCLLOW = 0x0B
+ };
+
+ enum class DS90UB933SerializerI2CRegister : uint32_t
+ {
+ Gpio10 = 0x0D,
+ Gpio32 = 0x0E,
+ SclHigh = 0x11,
+ SclLow = 0x12
+ };
+
+ enum class DS90UB953SerializerI2CRegister : uint32_t
+ {
+ GpioData = 0x0D,
+ GpioIOControl = 0x0E,
+ SclHigh = 0x0B,
+ SclLow = 0x0C
+ };
+
+ enum class DS90UB9xMode : uint32_t
+ {
+ Raw12BitLowFrequency = 1,
+ Raw12BitHighFrequency = 2,
+ Raw10Bit = 3,
+ };
+
+ enum class DS90UB9xDirection : uint32_t
+ {
+ Input = 0,
+ Output = 1
+ };
+};
+} // namespace OnixSourcePlugin
diff --git a/Source/Devices/DeviceList.h b/Source/Devices/DeviceList.h
index 0cf5851..a99ca82 100644
--- a/Source/Devices/DeviceList.h
+++ b/Source/Devices/DeviceList.h
@@ -1,29 +1,29 @@
/*
- ------------------------------------------------------------------
+ ------------------------------------------------------------------
- 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 .
*/
#include "AnalogIO.h"
#include "Bno055.h"
-#include "DigitalIO.h"
#include "DS90UB9x.h"
+#include "DigitalIO.h"
#include "HarpSyncInput.h"
#include "HeadStageEEPROM.h"
#include "MemoryMonitor.h"
diff --git a/Source/Devices/DigitalIO.cpp b/Source/Devices/DigitalIO.cpp
index 1d6eae9..acd6de9 100644
--- a/Source/Devices/DigitalIO.cpp
+++ b/Source/Devices/DigitalIO.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 .
*/
@@ -25,144 +25,144 @@
using namespace OnixSourcePlugin;
-DigitalIO::DigitalIO(std::string name, std::string hubName, const oni_dev_idx_t deviceIdx_, std::shared_ptr oni_ctx)
- : OnixDevice(name, hubName, DigitalIO::getDeviceType(), deviceIdx_, oni_ctx)
+DigitalIO::DigitalIO (std::string name, std::string hubName, const oni_dev_idx_t deviceIdx_, std::shared_ptr oni_ctx)
+ : OnixDevice (name, hubName, DigitalIO::getDeviceType(), deviceIdx_, oni_ctx)
{
- StreamInfo digitalInputStream = StreamInfo(
- OnixDevice::createStreamName({ getHubName(), name, "DigitalInputs" }),
- "Digital Inputs data",
- getStreamIdentifier(),
- NumDigitalInputs,
- AnalogIO::getSampleRate(),
- "CH",
- ContinuousChannel::Type::AUX,
- 1.0,
- "u", // NB: Digital data is unitless by definition
- {},
- { "input" });
- streamInfos.add(digitalInputStream);
-
- StreamInfo digitalButtonStream = StreamInfo(
- OnixDevice::createStreamName({ getHubName(), name, "DigitalButtons" }),
- "Digital Buttons data",
- getStreamIdentifier(),
- NumButtons,
- AnalogIO::getSampleRate(),
- "",
- ContinuousChannel::Type::AUX,
- 1.0,
- "u", // NB: Digital data is unitless by definition
- { "Moon", "Triangle", "X", "Check", "Circle", "Square" },
- { "input" });
- streamInfos.add(digitalButtonStream);
-
- eventCodes.fill(0);
+ StreamInfo digitalInputStream = StreamInfo (
+ OnixDevice::createStreamName ({ getHubName(), name, "DigitalInputs" }),
+ "Digital Inputs data",
+ getStreamIdentifier(),
+ NumDigitalInputs,
+ AnalogIO::getSampleRate(),
+ "CH",
+ ContinuousChannel::Type::AUX,
+ 1.0,
+ "u", // NB: Digital data is unitless by definition
+ {},
+ { "input" });
+ streamInfos.add (digitalInputStream);
+
+ StreamInfo digitalButtonStream = StreamInfo (
+ OnixDevice::createStreamName ({ getHubName(), name, "DigitalButtons" }),
+ "Digital Buttons data",
+ getStreamIdentifier(),
+ NumButtons,
+ AnalogIO::getSampleRate(),
+ "",
+ ContinuousChannel::Type::AUX,
+ 1.0,
+ "u", // NB: Digital data is unitless by definition
+ { "Moon", "Triangle", "X", "Check", "Circle", "Square" },
+ { "input" });
+ streamInfos.add (digitalButtonStream);
+
+ eventCodes.fill (0);
}
OnixDeviceType DigitalIO::getDeviceType()
{
- return OnixDeviceType::DIGITALIO;
+ return OnixDeviceType::DIGITALIO;
}
int DigitalIO::configureDevice()
{
- if (deviceContext == nullptr || !deviceContext->isInitialized())
- throw error_str("Device context is not initialized properly for " + getName());
-
- int rc = deviceContext->writeRegister(deviceIdx, (uint32_t)DigitalIORegisters::ENABLE, (oni_reg_val_t)(isEnabled() ? 1 : 0));
- if (rc != ONI_ESUCCESS)
- throw error_str("Failed to enable the DigitalIO device.");
-
- oni_reg_val_t baseFreqHz;
- rc = deviceContext->readRegister(deviceIdx, (uint32_t)DigitalIORegisters::BASE_FREQ_HZ, &baseFreqHz);
- if (rc != ONI_ESUCCESS)
- throw error_str("Could not read the base frequency register on the DigitalIO device.");
-
- // NB: Two states are not accounted for when comparing clock ticks on the hardware,
- // therefore the periodTicks variable must be decreased by 2 to get the correct sample rate.
- uint32_t periodTicks = (baseFreqHz / (uint32_t)AnalogIO::getSampleRate()) - 2u;
- rc = deviceContext->writeRegister(deviceIdx, (uint32_t)DigitalIORegisters::SAMPLE_PERIOD, periodTicks);
- if (rc != ONI_ESUCCESS)
- throw error_str("Could not write the sample rate for polling to the DigitalIO device.");
-
- return rc;
+ if (deviceContext == nullptr || ! deviceContext->isInitialized())
+ throw error_str ("Device context is not initialized properly for " + getName());
+
+ int rc = deviceContext->writeRegister (deviceIdx, (uint32_t) DigitalIORegisters::ENABLE, (oni_reg_val_t) (isEnabled() ? 1 : 0));
+ if (rc != ONI_ESUCCESS)
+ throw error_str ("Failed to enable the DigitalIO device.");
+
+ oni_reg_val_t baseFreqHz;
+ rc = deviceContext->readRegister (deviceIdx, (uint32_t) DigitalIORegisters::BASE_FREQ_HZ, &baseFreqHz);
+ if (rc != ONI_ESUCCESS)
+ throw error_str ("Could not read the base frequency register on the DigitalIO device.");
+
+ // NB: Two states are not accounted for when comparing clock ticks on the hardware,
+ // therefore the periodTicks variable must be decreased by 2 to get the correct sample rate.
+ uint32_t periodTicks = (baseFreqHz / (uint32_t) AnalogIO::getSampleRate()) - 2u;
+ rc = deviceContext->writeRegister (deviceIdx, (uint32_t) DigitalIORegisters::SAMPLE_PERIOD, periodTicks);
+ if (rc != ONI_ESUCCESS)
+ throw error_str ("Could not write the sample rate for polling to the DigitalIO device.");
+
+ return rc;
}
bool DigitalIO::updateSettings()
{
- return true;
+ return true;
}
void DigitalIO::startAcquisition()
{
- currentFrame = 0;
- sampleNumber = 0;
+ currentFrame = 0;
+ sampleNumber = 0;
- digitalSamples.fill(0);
+ digitalSamples.fill (0);
}
-void DigitalIO::addSourceBuffers(OwnedArray& sourceBuffers)
+void DigitalIO::addSourceBuffers (OwnedArray& sourceBuffers)
{
- sourceBuffers.add(new DataBuffer(NumChannels, (int)streamInfos.getFirst().getSampleRate() * bufferSizeInSeconds));
- digitalBuffer = sourceBuffers.getLast();
+ sourceBuffers.add (new DataBuffer (NumChannels, (int) streamInfos.getFirst().getSampleRate() * bufferSizeInSeconds));
+ digitalBuffer = sourceBuffers.getLast();
}
-EventChannel::Settings DigitalIO::getEventChannelSettings(DataStream* stream)
+EventChannel::Settings DigitalIO::getEventChannelSettings (DataStream* stream)
{
- EventChannel::Settings settings{
- EventChannel::Type::TTL,
- OnixDevice::createStreamName({getHubName(), getName(), "Events"}),
- "Digital inputs and breakout button states coming from a DigitalIO device",
- getStreamIdentifier() + ".event.digital",
- stream,
- NumChannels
- };
-
- return settings;
+ EventChannel::Settings settings {
+ EventChannel::Type::TTL,
+ OnixDevice::createStreamName ({ getHubName(), getName(), "Events" }),
+ "Digital inputs and breakout button states coming from a DigitalIO device",
+ getStreamIdentifier() + ".event.digital",
+ stream,
+ NumChannels
+ };
+
+ return settings;
}
-float DigitalIO::getChannelState(uint8_t state, int channel)
+float DigitalIO::getChannelState (uint8_t state, int channel)
{
- return (state & (1 << channel)) >> channel; // NB: Return the state of the specified channel
+ return (state & (1 << channel)) >> channel; // NB: Return the state of the specified channel
};
void DigitalIO::processFrames()
{
- oni_frame_t* frame;
- while (frameQueue.try_dequeue(frame))
- {
- size_t offset = 0;
+ oni_frame_t* frame;
+ while (frameQueue.try_dequeue (frame))
+ {
+ size_t offset = 0;
- uint16_t* dataPtr = (uint16_t*)frame->data;
+ uint16_t* dataPtr = (uint16_t*) frame->data;
- timestamps[currentFrame] = deviceContext->convertTimestampToSeconds(frame->time);
- sampleNumbers[currentFrame] = sampleNumber++;
+ timestamps[currentFrame] = deviceContext->convertTimestampToSeconds (frame->time);
+ sampleNumbers[currentFrame] = sampleNumber++;
- constexpr int inputDataOffset = 4;
- constexpr int buttonDataOffset = inputDataOffset + 1;
+ constexpr int inputDataOffset = 4;
+ constexpr int buttonDataOffset = inputDataOffset + 1;
- uint64_t inputState = *(dataPtr + inputDataOffset);
- uint64_t buttonState = *(dataPtr + buttonDataOffset);
+ uint64_t inputState = *(dataPtr + inputDataOffset);
+ uint64_t buttonState = *(dataPtr + buttonDataOffset);
- for (int i = 0; i < NumDigitalInputs; i++)
- {
- digitalSamples[currentFrame + offset++ * NumFrames] = getChannelState(inputState, i);
- }
+ for (int i = 0; i < NumDigitalInputs; i++)
+ {
+ digitalSamples[currentFrame + offset++ * NumFrames] = getChannelState (inputState, i);
+ }
- for (int i = 0; i < NumButtons; i++)
- {
- digitalSamples[currentFrame + offset++ * NumFrames] = getChannelState(buttonState, i);
- }
+ for (int i = 0; i < NumButtons; i++)
+ {
+ digitalSamples[currentFrame + offset++ * NumFrames] = getChannelState (buttonState, i);
+ }
- eventCodes[currentFrame] = (buttonState & 0x3F) << 8 | (inputState & 0xFF);
+ eventCodes[currentFrame] = (buttonState & 0x3F) << 8 | (inputState & 0xFF);
- oni_destroy_frame(frame);
+ oni_destroy_frame (frame);
- if (++currentFrame >= NumFrames)
- {
- digitalBuffer->addToBuffer(digitalSamples.data(), sampleNumbers.data(), timestamps.data(), eventCodes.data(), NumFrames);
+ if (++currentFrame >= NumFrames)
+ {
+ digitalBuffer->addToBuffer (digitalSamples.data(), sampleNumbers.data(), timestamps.data(), eventCodes.data(), NumFrames);
- currentFrame = 0;
- }
- }
+ currentFrame = 0;
+ }
+ }
}
diff --git a/Source/Devices/DigitalIO.h b/Source/Devices/DigitalIO.h
index 6589f1f..7551261 100644
--- a/Source/Devices/DigitalIO.h
+++ b/Source/Devices/DigitalIO.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 .
*/
@@ -26,84 +26,83 @@
namespace OnixSourcePlugin
{
- enum class DigitalIORegisters : uint32_t
- {
- ENABLE = 0x0,
- BASE_FREQ_HZ = 0x5,
- DEAD_TICKS = 0x6,
- SAMPLE_PERIOD = 0x7,
- };
-
- enum class DigitalPortState : uint16_t
- {
- Pin0 = 0x1,
- Pin1 = 0x2,
- Pin2 = 0x4,
- Pin3 = 0x8,
- Pin4 = 0x10,
- Pin5 = 0x20,
- Pin6 = 0x40,
- Pin7 = 0x80
- };
-
- enum class BreakoutButtonState : uint16_t
- {
- None = 0x0,
- Moon = 0x1,
- Triangle = 0x2,
- X = 0x4,
- Check = 0x8,
- Circle = 0x10,
- Square = 0x20,
- Reserved0 = 0x40,
- Reserved1 = 0x80,
- PortDOn = 0x100,
- PortCOn = 0x200,
- PortBOn = 0x400,
- PortAOn = 0x800
- };
-
- /*
- Configures and streams data from a DigitalIO device on a Breakout Board
- */
- class DigitalIO : public OnixDevice
- {
- public:
- DigitalIO(std::string name, std::string hubName, const oni_dev_idx_t, std::shared_ptr oni_ctx);
-
- int configureDevice() override;
- bool updateSettings() override;
- void startAcquisition() override;
- void addSourceBuffers(OwnedArray& sourceBuffers) override;
- void processFrames() override;
-
- EventChannel::Settings getEventChannelSettings(DataStream* stream);
-
- static OnixDeviceType getDeviceType();
-
- private:
-
- DataBuffer* digitalBuffer = nullptr;
-
- static float getChannelState(uint8_t state, int channel);
-
- static constexpr int NumFrames = 25;
-
- static constexpr int NumDigitalInputs = 8;
- static constexpr int NumButtons = 6;
- static constexpr int NumChannels = NumDigitalInputs + NumButtons;
-
- static constexpr int NumSamples = NumFrames * NumChannels;
-
- unsigned short currentFrame = 0;
- int64_t sampleNumber = 0;
-
- std::array digitalSamples;
-
- std::array timestamps;
- std::array sampleNumbers;
- std::array eventCodes;
-
- JUCE_LEAK_DETECTOR(DigitalIO);
- };
-}
+enum class DigitalIORegisters : uint32_t
+{
+ ENABLE = 0x0,
+ BASE_FREQ_HZ = 0x5,
+ DEAD_TICKS = 0x6,
+ SAMPLE_PERIOD = 0x7,
+};
+
+enum class DigitalPortState : uint16_t
+{
+ Pin0 = 0x1,
+ Pin1 = 0x2,
+ Pin2 = 0x4,
+ Pin3 = 0x8,
+ Pin4 = 0x10,
+ Pin5 = 0x20,
+ Pin6 = 0x40,
+ Pin7 = 0x80
+};
+
+enum class BreakoutButtonState : uint16_t
+{
+ None = 0x0,
+ Moon = 0x1,
+ Triangle = 0x2,
+ X = 0x4,
+ Check = 0x8,
+ Circle = 0x10,
+ Square = 0x20,
+ Reserved0 = 0x40,
+ Reserved1 = 0x80,
+ PortDOn = 0x100,
+ PortCOn = 0x200,
+ PortBOn = 0x400,
+ PortAOn = 0x800
+};
+
+/*
+ Configures and streams data from a DigitalIO device on a Breakout Board
+*/
+class DigitalIO : public OnixDevice
+{
+public:
+ DigitalIO (std::string name, std::string hubName, const oni_dev_idx_t, std::shared_ptr oni_ctx);
+
+ int configureDevice() override;
+ bool updateSettings() override;
+ void startAcquisition() override;
+ void addSourceBuffers (OwnedArray& sourceBuffers) override;
+ void processFrames() override;
+
+ EventChannel::Settings getEventChannelSettings (DataStream* stream);
+
+ static OnixDeviceType getDeviceType();
+
+private:
+ DataBuffer* digitalBuffer = nullptr;
+
+ static float getChannelState (uint8_t state, int channel);
+
+ static constexpr int NumFrames = 25;
+
+ static constexpr int NumDigitalInputs = 8;
+ static constexpr int NumButtons = 6;
+ static constexpr int NumChannels = NumDigitalInputs + NumButtons;
+
+ static constexpr int NumSamples = NumFrames * NumChannels;
+
+ unsigned short currentFrame = 0;
+ int64_t sampleNumber = 0;
+
+ std::array digitalSamples;
+
+ std::array timestamps;
+ std::array sampleNumbers;
+ std::array eventCodes;
+
+ JUCE_LEAK_DETECTOR (DigitalIO);
+};
+} // namespace OnixSourcePlugin
diff --git a/Source/Devices/HarpSyncInput.cpp b/Source/Devices/HarpSyncInput.cpp
index 8aee5cb..9e24cc8 100644
--- a/Source/Devices/HarpSyncInput.cpp
+++ b/Source/Devices/HarpSyncInput.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,88 +24,86 @@
using namespace OnixSourcePlugin;
-HarpSyncInput::HarpSyncInput(std::string name, std::string hubName, const oni_dev_idx_t deviceIdx_, std::shared_ptr oni_ctx)
- : OnixDevice(name, hubName, HarpSyncInput::getDeviceType(), deviceIdx_, oni_ctx)
+HarpSyncInput::HarpSyncInput (std::string name, std::string hubName, const oni_dev_idx_t deviceIdx_, std::shared_ptr oni_ctx)
+ : OnixDevice (name, hubName, HarpSyncInput::getDeviceType(), deviceIdx_, oni_ctx)
{
- setEnabled(false);
-
- StreamInfo harpTimeStream = StreamInfo(
- OnixDevice::createStreamName({ getHubName(), getName(), "HarpTime" }),
- "Harp clock time corresponding to the local acquisition ONIX clock count",
- getStreamIdentifier(),
- 1,
- 1,
- "HarpTime",
- ContinuousChannel::Type::AUX,
- 1.0f,
- "s",
- { "" },
- "harptime"
- );
- streamInfos.add(harpTimeStream);
-
- for (int i = 0; i < numFrames; i++)
- eventCodes[i] = 0;
+ setEnabled (false);
+
+ StreamInfo harpTimeStream = StreamInfo (
+ OnixDevice::createStreamName ({ getHubName(), getName(), "HarpTime" }),
+ "Harp clock time corresponding to the local acquisition ONIX clock count",
+ getStreamIdentifier(),
+ 1,
+ 1,
+ "HarpTime",
+ ContinuousChannel::Type::AUX,
+ 1.0f,
+ "s",
+ { "" },
+ "harptime");
+ streamInfos.add (harpTimeStream);
+
+ for (int i = 0; i < numFrames; i++)
+ eventCodes[i] = 0;
}
OnixDeviceType HarpSyncInput::getDeviceType()
{
- return OnixDeviceType::HARPSYNCINPUT;
+ return OnixDeviceType::HARPSYNCINPUT;
}
int HarpSyncInput::configureDevice()
{
- if (deviceContext == nullptr || !deviceContext->isInitialized())
- throw error_str("Device context is not initialized properly for " + getName());
+ if (deviceContext == nullptr || ! deviceContext->isInitialized())
+ throw error_str ("Device context is not initialized properly for " + getName());
- return deviceContext->writeRegister(deviceIdx, (uint32_t)HarpSyncInputRegisters::ENABLE, (oni_reg_val_t)(isEnabled() ? 1 : 0));
+ return deviceContext->writeRegister (deviceIdx, (uint32_t) HarpSyncInputRegisters::ENABLE, (oni_reg_val_t) (isEnabled() ? 1 : 0));
}
bool HarpSyncInput::updateSettings()
{
- return deviceContext->writeRegister(deviceIdx, (oni_reg_addr_t)HarpSyncInputRegisters::SOURCE, (oni_reg_val_t)HarpSyncSource::Breakout) == ONI_ESUCCESS;
+ return deviceContext->writeRegister (deviceIdx, (oni_reg_addr_t) HarpSyncInputRegisters::SOURCE, (oni_reg_val_t) HarpSyncSource::Breakout) == ONI_ESUCCESS;
}
void HarpSyncInput::startAcquisition()
{
- currentFrame = 0;
- sampleNumber = 0;
+ currentFrame = 0;
+ sampleNumber = 0;
}
-void HarpSyncInput::addSourceBuffers(OwnedArray& sourceBuffers)
+void HarpSyncInput::addSourceBuffers (OwnedArray& sourceBuffers)
{
- sourceBuffers.add(new DataBuffer(streamInfos.getFirst().getNumChannels(), (int)streamInfos.getFirst().getSampleRate() * bufferSizeInSeconds));
- harpTimeBuffer = sourceBuffers.getLast();
+ sourceBuffers.add (new DataBuffer (streamInfos.getFirst().getNumChannels(), (int) streamInfos.getFirst().getSampleRate() * bufferSizeInSeconds));
+ harpTimeBuffer = sourceBuffers.getLast();
}
void HarpSyncInput::processFrames()
{
- oni_frame_t* frame;
- while (frameQueue.try_dequeue(frame))
- {
+ oni_frame_t* frame;
+ while (frameQueue.try_dequeue (frame))
+ {
+ uint32_t* dataPtr = (uint32_t*) frame->data;
- uint32_t* dataPtr = (uint32_t*)frame->data;
+ timestamps[currentFrame] = deviceContext->convertTimestampToSeconds (frame->time);
- timestamps[currentFrame] = deviceContext->convertTimestampToSeconds(frame->time);
+ harpTimeSamples[currentFrame] = *(dataPtr + 2) + 1;
- harpTimeSamples[currentFrame] = *(dataPtr + 2) + 1;
+ oni_destroy_frame (frame);
- oni_destroy_frame(frame);
+ sampleNumbers[currentFrame] = sampleNumber++;
- sampleNumbers[currentFrame] = sampleNumber++;
+ currentFrame++;
- currentFrame++;
+ if (currentFrame >= numFrames)
+ {
+ shouldAddToBuffer = true;
+ currentFrame = 0;
+ }
- if (currentFrame >= numFrames)
- {
- shouldAddToBuffer = true;
- currentFrame = 0;
- }
-
- if (shouldAddToBuffer)
- {
- shouldAddToBuffer = false;
- harpTimeBuffer->addToBuffer(harpTimeSamples, sampleNumbers, timestamps, eventCodes, numFrames);
- }
- }
+ if (shouldAddToBuffer)
+ {
+ shouldAddToBuffer = false;
+ harpTimeBuffer->addToBuffer (harpTimeSamples, sampleNumbers, timestamps, eventCodes, numFrames);
+ }
+ }
}
diff --git a/Source/Devices/HarpSyncInput.h b/Source/Devices/HarpSyncInput.h
index 41ed645..2d28ec1 100644
--- a/Source/Devices/HarpSyncInput.h
+++ b/Source/Devices/HarpSyncInput.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 .
*/
@@ -26,51 +26,50 @@
namespace OnixSourcePlugin
{
- enum class HarpSyncInputRegisters : uint32_t
- {
- ENABLE = 0,
- SOURCE = 1
- };
-
- enum class HarpSyncSource : uint32_t
- {
- Breakout = 0,
- ClockAdapter = 1
- };
+enum class HarpSyncInputRegisters : uint32_t
+{
+ ENABLE = 0,
+ SOURCE = 1
+};
- /*
- Configures and streams data from a HarpSyncInput device on a Breakout Board
- */
- class HarpSyncInput : public OnixDevice
- {
- public:
- HarpSyncInput(std::string name, std::string hubName, const oni_dev_idx_t, std::shared_ptr oni_ctx);
+enum class HarpSyncSource : uint32_t
+{
+ Breakout = 0,
+ ClockAdapter = 1
+};
- int configureDevice() override;
- bool updateSettings() override;
- void startAcquisition() override;
- void addSourceBuffers(OwnedArray& sourceBuffers) override;
- void processFrames() override;
+/*
+ Configures and streams data from a HarpSyncInput device on a Breakout Board
+*/
+class HarpSyncInput : public OnixDevice
+{
+public:
+ HarpSyncInput (std::string name, std::string hubName, const oni_dev_idx_t, std::shared_ptr oni_ctx);
- static OnixDeviceType getDeviceType();
+ int configureDevice() override;
+ bool updateSettings() override;
+ void startAcquisition() override;
+ void addSourceBuffers (OwnedArray& sourceBuffers) override;
+ void processFrames() override;
- private:
+ static OnixDeviceType getDeviceType();
- DataBuffer* harpTimeBuffer;
+private:
+ DataBuffer* harpTimeBuffer;
- static const int numFrames = 2;
+ static const int numFrames = 2;
- unsigned short currentFrame = 0;
- int sampleNumber = 0;
+ unsigned short currentFrame = 0;
+ int sampleNumber = 0;
- bool shouldAddToBuffer = false;
+ bool shouldAddToBuffer = false;
- float harpTimeSamples[numFrames];
+ float harpTimeSamples[numFrames];
- double timestamps[numFrames];
- int64 sampleNumbers[numFrames];
- uint64 eventCodes[numFrames];
+ double timestamps[numFrames];
+ int64 sampleNumbers[numFrames];
+ uint64 eventCodes[numFrames];
- JUCE_LEAK_DETECTOR(HarpSyncInput);
- };
-}
+ JUCE_LEAK_DETECTOR (HarpSyncInput);
+};
+} // namespace OnixSourcePlugin
diff --git a/Source/Devices/HeadStageEEPROM.cpp b/Source/Devices/HeadStageEEPROM.cpp
index f6ec487..c365bd5 100644
--- a/Source/Devices/HeadStageEEPROM.cpp
+++ b/Source/Devices/HeadStageEEPROM.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 .
*/
@@ -26,28 +26,31 @@
using namespace OnixSourcePlugin;
-HeadStageEEPROM::HeadStageEEPROM(const oni_dev_idx_t dev_id, std::shared_ptr ctx)
- : I2CRegisterContext(HeadStageEEPROM::EEPROM_ADDRESS, dev_id, ctx)
+HeadStageEEPROM::HeadStageEEPROM (const oni_dev_idx_t dev_id, std::shared_ptr ctx)
+ : I2CRegisterContext (HeadStageEEPROM::EEPROM_ADDRESS, dev_id, ctx)
{
- auto deserializer = std::make_unique(DS90UB9x::DES_ADDR, dev_id, ctx);
- uint32_t alias = HeadStageEEPROM::EEPROM_ADDRESS << 1;
- int rc = deserializer->WriteByte((uint32_t)DS90UB9x::DS90UB9xDeserializerI2CRegister::SlaveID7, alias);
- if (rc != ONI_ESUCCESS) return;
- deserializer->WriteByte((uint32_t)DS90UB9x::DS90UB9xDeserializerI2CRegister::SlaveAlias7, alias);
- if (rc != ONI_ESUCCESS) return;
+ auto deserializer = std::make_unique (DS90UB9x::DES_ADDR, dev_id, ctx);
+ uint32_t alias = HeadStageEEPROM::EEPROM_ADDRESS << 1;
+ int rc = deserializer->WriteByte ((uint32_t) DS90UB9x::DS90UB9xDeserializerI2CRegister::SlaveID7, alias);
+ if (rc != ONI_ESUCCESS)
+ return;
+ deserializer->WriteByte ((uint32_t) DS90UB9x::DS90UB9xDeserializerI2CRegister::SlaveAlias7, alias);
+ if (rc != ONI_ESUCCESS)
+ return;
}
uint32_t HeadStageEEPROM::GetHeadStageID()
{
- uint32_t data = 0;
- int rc = 0;
- for (unsigned int i = 0; i < sizeof(uint32_t); i++)
- {
- oni_reg_val_t val;
- rc = ReadByte(DEVID_START_ADDR + i, &val, true);
- if (rc != ONI_ESUCCESS) return data;
- data += (val & 0xFF) << (8 * i);
- }
- return data;
+ uint32_t data = 0;
+ int rc = 0;
+ for (unsigned int i = 0; i < sizeof (uint32_t); i++)
+ {
+ oni_reg_val_t val;
+ rc = ReadByte (DEVID_START_ADDR + i, &val, true);
+ if (rc != ONI_ESUCCESS)
+ return data;
+ data += (val & 0xFF) << (8 * i);
+ }
+ return data;
}
diff --git a/Source/Devices/HeadStageEEPROM.h b/Source/Devices/HeadStageEEPROM.h
index 0c93714..f9ce657 100644
--- a/Source/Devices/HeadStageEEPROM.h
+++ b/Source/Devices/HeadStageEEPROM.h
@@ -1,26 +1,25 @@
/*
- ------------------------------------------------------------------
+ ------------------------------------------------------------------
- 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 .
*/
-
#pragma once
#include "../I2CRegisterContext.h"
@@ -30,18 +29,17 @@
namespace OnixSourcePlugin
{
- class HeadStageEEPROM :
- public I2CRegisterContext
- {
- public:
- HeadStageEEPROM(const oni_dev_idx_t, std::shared_ptr);
+class HeadStageEEPROM : public I2CRegisterContext
+{
+public:
+ HeadStageEEPROM (const oni_dev_idx_t, std::shared_ptr);
- uint32_t GetHeadStageID();
+ uint32_t GetHeadStageID();
- private:
- static const uint32_t EEPROM_ADDRESS = 0x51;
- static const uint32_t DEVID_START_ADDR = 18;
+private:
+ static const uint32_t EEPROM_ADDRESS = 0x51;
+ static const uint32_t DEVID_START_ADDR = 18;
- JUCE_LEAK_DETECTOR(HeadStageEEPROM);
- };
-}
+ JUCE_LEAK_DETECTOR (HeadStageEEPROM);
+};
+} // namespace OnixSourcePlugin
diff --git a/Source/Devices/MemoryMonitor.cpp b/Source/Devices/MemoryMonitor.cpp
index ec60757..8843852 100644
--- a/Source/Devices/MemoryMonitor.cpp
+++ b/Source/Devices/MemoryMonitor.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 .
*/
@@ -25,140 +25,139 @@
using namespace OnixSourcePlugin;
-MemoryMonitorUsage::MemoryMonitorUsage(GenericProcessor* p)
- : LevelMonitor(p)
+MemoryMonitorUsage::MemoryMonitorUsage (GenericProcessor* p)
+ : LevelMonitor (p)
{
- device = nullptr;
- setPassiveTooltip();
+ device = nullptr;
+ setPassiveTooltip();
}
void MemoryMonitorUsage::timerCallback()
{
- if (device != nullptr)
- {
- auto memoryUsedPercent = device->getLastPercentUsedValue();
- auto logMemoryUsed = std::log(memoryUsedPercent + 1) / maxLogarithmicValue;
- setFillPercentage(logMemoryUsed);
- setTooltip(getNewTooltip(memoryUsedPercent));
- repaint();
- }
+ if (device != nullptr)
+ {
+ auto memoryUsedPercent = device->getLastPercentUsedValue();
+ auto logMemoryUsed = std::log (memoryUsedPercent + 1) / maxLogarithmicValue;
+ setFillPercentage (logMemoryUsed);
+ setTooltip (getNewTooltip (memoryUsedPercent));
+ repaint();
+ }
}
-std::string MemoryMonitorUsage::getNewTooltip(float memoryUsage)
+std::string MemoryMonitorUsage::getNewTooltip (float memoryUsage)
{
- std::stringstream ss;
- ss << "Memory Used: " << std::setprecision(3) << memoryUsage << "%";
- return ss.str();
+ std::stringstream ss;
+ ss << "Memory Used: " << std::setprecision (3) << memoryUsage << "%";
+ return ss.str();
}
void MemoryMonitorUsage::setPassiveTooltip()
{
- setTooltip("Monitors the percent of the hardware memory buffer used.");
+ setTooltip ("Monitors the percent of the hardware memory buffer used.");
}
-void MemoryMonitorUsage::setMemoryMonitor(std::shared_ptr memoryMonitor)
+void MemoryMonitorUsage::setMemoryMonitor (std::shared_ptr memoryMonitor)
{
- device = memoryMonitor;
+ device = memoryMonitor;
}
void MemoryMonitorUsage::startAcquisition()
{
- startTimerHz(TimerFrequencyHz);
+ startTimerHz (TimerFrequencyHz);
}
void MemoryMonitorUsage::stopAcquisition()
{
- stopTimer();
- setFillPercentage(0.0f);
- setPassiveTooltip();
- repaint();
+ stopTimer();
+ setFillPercentage (0.0f);
+ setPassiveTooltip();
+ repaint();
}
-MemoryMonitor::MemoryMonitor(std::string name, std::string hubName, const oni_dev_idx_t deviceIdx_, std::shared_ptr oni_ctx)
- : OnixDevice(name, hubName, MemoryMonitor::getDeviceType(), deviceIdx_, oni_ctx)
+MemoryMonitor::MemoryMonitor (std::string name, std::string hubName, const oni_dev_idx_t deviceIdx_, std::shared_ptr oni_ctx)
+ : OnixDevice (name, hubName, MemoryMonitor::getDeviceType(), deviceIdx_, oni_ctx)
{
- StreamInfo percentUsedStream = StreamInfo(
- OnixDevice::createStreamName({ getHubName(), getName(), "PercentUsed" }),
- "Percent of available memory that is currently used",
- getStreamIdentifier(),
- 1,
- samplesPerSecond,
- "Percent",
- ContinuousChannel::Type::AUX,
- 1.0f,
- "%",
- { "" },
- "percent"
- );
- streamInfos.add(percentUsedStream);
+ StreamInfo percentUsedStream = StreamInfo (
+ OnixDevice::createStreamName ({ getHubName(), getName(), "PercentUsed" }),
+ "Percent of available memory that is currently used",
+ getStreamIdentifier(),
+ 1,
+ samplesPerSecond,
+ "Percent",
+ ContinuousChannel::Type::AUX,
+ 1.0f,
+ "%",
+ { "" },
+ "percent");
+ streamInfos.add (percentUsedStream);
}
OnixDeviceType MemoryMonitor::getDeviceType()
{
- return OnixDeviceType::MEMORYMONITOR;
+ return OnixDeviceType::MEMORYMONITOR;
}
int MemoryMonitor::configureDevice()
{
- if (deviceContext == nullptr || !deviceContext->isInitialized())
- throw error_str("Device context is not initialized properly for " + getName());
+ if (deviceContext == nullptr || ! deviceContext->isInitialized())
+ throw error_str ("Device context is not initialized properly for " + getName());
- setEnabled(true);
+ setEnabled (true);
- int rc = deviceContext->writeRegister(deviceIdx, (uint32_t)MemoryMonitorRegisters::ENABLE, 1);
- if (rc != ONI_ESUCCESS)
- throw error_str("Unable to enable " + getName());
+ int rc = deviceContext->writeRegister (deviceIdx, (uint32_t) MemoryMonitorRegisters::ENABLE, 1);
+ if (rc != ONI_ESUCCESS)
+ throw error_str ("Unable to enable " + getName());
- rc = deviceContext->readRegister(deviceIdx, (oni_reg_addr_t)MemoryMonitorRegisters::TOTAL_MEM, &totalMemory);
+ rc = deviceContext->readRegister (deviceIdx, (oni_reg_addr_t) MemoryMonitorRegisters::TOTAL_MEM, &totalMemory);
- if (rc != ONI_ESUCCESS)
- throw error_str("Unable to find the total memory used for " + getName());
+ if (rc != ONI_ESUCCESS)
+ throw error_str ("Unable to find the total memory used for " + getName());
- return rc;
+ return rc;
}
bool MemoryMonitor::updateSettings()
{
- oni_reg_val_t clkHz;
- int rc = deviceContext->readRegister(deviceIdx, (oni_reg_addr_t)MemoryMonitorRegisters::CLK_HZ, &clkHz);
- if (rc != ONI_ESUCCESS) return rc;
+ oni_reg_val_t clkHz;
+ int rc = deviceContext->readRegister (deviceIdx, (oni_reg_addr_t) MemoryMonitorRegisters::CLK_HZ, &clkHz);
+ if (rc != ONI_ESUCCESS)
+ return rc;
- rc = deviceContext->writeRegister(deviceIdx, (oni_reg_addr_t)MemoryMonitorRegisters::CLK_DIV, clkHz / samplesPerSecond);
+ rc = deviceContext->writeRegister (deviceIdx, (oni_reg_addr_t) MemoryMonitorRegisters::CLK_DIV, clkHz / samplesPerSecond);
- return rc == ONI_ESUCCESS;
+ return rc == ONI_ESUCCESS;
}
void MemoryMonitor::startAcquisition()
{
-
- sampleNumber = 0;
- lastPercentUsedValue = 0.0f;
+ sampleNumber = 0;
+ lastPercentUsedValue = 0.0f;
}
-void MemoryMonitor::addSourceBuffers(OwnedArray& sourceBuffers)
+void MemoryMonitor::addSourceBuffers (OwnedArray& sourceBuffers)
{
- sourceBuffers.add(new DataBuffer(streamInfos.getFirst().getNumChannels(), (int)streamInfos.getFirst().getSampleRate() * bufferSizeInSeconds));
- percentUsedBuffer = sourceBuffers.getLast();
+ sourceBuffers.add (new DataBuffer (streamInfos.getFirst().getNumChannels(), (int) streamInfos.getFirst().getSampleRate() * bufferSizeInSeconds));
+ percentUsedBuffer = sourceBuffers.getLast();
}
float MemoryMonitor::getLastPercentUsedValue()
{
- return lastPercentUsedValue;
+ return lastPercentUsedValue;
}
void MemoryMonitor::processFrames()
{
- static uint64_t ec = 0;
- oni_frame_t* frame;
-
- while (frameQueue.try_dequeue(frame))
- {
- uint32_t* dataPtr = (uint32_t*)frame->data;
- auto t = deviceContext->convertTimestampToSeconds(frame->time);
- auto p = 100.0f * float(*(dataPtr + 2)) / totalMemory;
- lastPercentUsedValue = p;
- oni_destroy_frame(frame);
- auto sn = sampleNumber++;
- percentUsedBuffer->addToBuffer(&p, &sn, &t, &ec, 1);
- }
+ static uint64_t ec = 0;
+ oni_frame_t* frame;
+
+ while (frameQueue.try_dequeue (frame))
+ {
+ uint32_t* dataPtr = (uint32_t*) frame->data;
+ auto t = deviceContext->convertTimestampToSeconds (frame->time);
+ auto p = 100.0f * float (*(dataPtr + 2)) / totalMemory;
+ lastPercentUsedValue = p;
+ oni_destroy_frame (frame);
+ auto sn = sampleNumber++;
+ percentUsedBuffer->addToBuffer (&p, &sn, &t, &ec, 1);
+ }
}
diff --git a/Source/Devices/MemoryMonitor.h b/Source/Devices/MemoryMonitor.h
index 127ce9d..a053670 100644
--- a/Source/Devices/MemoryMonitor.h
+++ b/Source/Devices/MemoryMonitor.h
@@ -1,104 +1,102 @@
/*
- ------------------------------------------------------------------
+ ------------------------------------------------------------------
- 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 .
*/
#pragma once
#include
+
#include "../OnixDevice.h"
namespace OnixSourcePlugin
{
- enum class MemoryMonitorRegisters : uint32_t
- {
- ENABLE = 0,
- CLK_DIV = 1,
- CLK_HZ = 2,
- TOTAL_MEM = 3
- };
-
- /*
- Configures and streams data from a MemoryMonitor device on a Breakout Board
- */
- class MemoryMonitor : public OnixDevice
- {
- public:
- MemoryMonitor(std::string name, std::string hubName, const oni_dev_idx_t, std::shared_ptr oni_ctx);
-
- int configureDevice() override;
- bool updateSettings() override;
- void startAcquisition() override;
- void addSourceBuffers(OwnedArray& sourceBuffers) override;
- void processFrames() override;
-
- float getLastPercentUsedValue();
+enum class MemoryMonitorRegisters : uint32_t
+{
+ ENABLE = 0,
+ CLK_DIV = 1,
+ CLK_HZ = 2,
+ TOTAL_MEM = 3
+};
- static OnixDeviceType getDeviceType();
+/*
+ Configures and streams data from a MemoryMonitor device on a Breakout Board
+*/
+class MemoryMonitor : public OnixDevice
+{
+public:
+ MemoryMonitor (std::string name, std::string hubName, const oni_dev_idx_t, std::shared_ptr oni_ctx);
- private:
+ int configureDevice() override;
+ bool updateSettings() override;
+ void startAcquisition() override;
+ void addSourceBuffers (OwnedArray& sourceBuffers) override;
+ void processFrames() override;
- DataBuffer* percentUsedBuffer;
+ float getLastPercentUsedValue();
- int64_t sampleNumber = 0;
+ static OnixDeviceType getDeviceType();
- /** The frequency at which memory use is recorded in Hz. */
- const uint32_t samplesPerSecond = 100;
+private:
+ DataBuffer* percentUsedBuffer;
- bool shouldAddToBuffer = false;
+ int64_t sampleNumber = 0;
+ /** The frequency at which memory use is recorded in Hz. */
+ const uint32_t samplesPerSecond = 100;
- /** The total amount of memory, in 32-bit words, on the hardware that is available for data buffering*/
- uint32_t totalMemory;
+ bool shouldAddToBuffer = false;
- std::atomic lastPercentUsedValue = 0.0f;
+ /** The total amount of memory, in 32-bit words, on the hardware that is available for data buffering*/
+ uint32_t totalMemory;
- JUCE_LEAK_DETECTOR(MemoryMonitor);
- };
+ std::atomic lastPercentUsedValue = 0.0f;
- /*
- Tracks the MemoryMonitor usage while data acquisition is running
- */
- class MemoryMonitorUsage : public LevelMonitor
- {
- public:
- MemoryMonitorUsage(GenericProcessor*);
+ JUCE_LEAK_DETECTOR (MemoryMonitor);
+};
- void timerCallback() override;
+/*
+ Tracks the MemoryMonitor usage while data acquisition is running
+*/
+class MemoryMonitorUsage : public LevelMonitor
+{
+public:
+ MemoryMonitorUsage (GenericProcessor*);
- void setMemoryMonitor(std::shared_ptr memoryMonitor);
- void startAcquisition();
- void stopAcquisition();
- void setPassiveTooltip();
- static std::string getNewTooltip(float memoryUsage);
+ void timerCallback() override;
- private:
+ void setMemoryMonitor (std::shared_ptr memoryMonitor);
+ void startAcquisition();
+ void stopAcquisition();
+ void setPassiveTooltip();
+ static std::string getNewTooltip (float memoryUsage);
- std::shared_ptr device;
+private:
+ std::shared_ptr device;
- // NB: Calculate the maximum logarithmic value to convert from linear scale (x: 0-100) to logarithmic scale (y: 0-1)
- // using the following equation: y = log_e(x + 1) / log_e(x_max + 1);
- const float maxLogarithmicValue = std::log(101);
+ // NB: Calculate the maximum logarithmic value to convert from linear scale (x: 0-100) to logarithmic scale (y: 0-1)
+ // using the following equation: y = log_e(x + 1) / log_e(x_max + 1);
+ const float maxLogarithmicValue = std::log (101);
- const int TimerFrequencyHz = 10;
+ const int TimerFrequencyHz = 10;
- JUCE_LEAK_DETECTOR(MemoryMonitorUsage);
- };
-}
+ JUCE_LEAK_DETECTOR (MemoryMonitorUsage);
+};
+} // namespace OnixSourcePlugin
diff --git a/Source/Devices/Neuropixels1.cpp b/Source/Devices/Neuropixels1.cpp
index 3cd85f0..fca20cf 100644
--- a/Source/Devices/Neuropixels1.cpp
+++ b/Source/Devices/Neuropixels1.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,492 +24,493 @@
using namespace OnixSourcePlugin;
-NeuropixelsV1BackgroundUpdater::NeuropixelsV1BackgroundUpdater(Neuropixels1* d)
- : ThreadWithProgressWindow("Writing calibration files to Neuropixels Probe: " + d->getName(), true, false)
+NeuropixelsV1BackgroundUpdater::NeuropixelsV1BackgroundUpdater (Neuropixels1* d)
+ : ThreadWithProgressWindow ("Writing calibration files to Neuropixels Probe: " + d->getName(), true, false)
{
- device = d;
+ device = d;
}
bool NeuropixelsV1BackgroundUpdater::updateSettings()
{
- if (device->isEnabled())
- runThread();
- else
- return false;
+ if (device->isEnabled())
+ runThread();
+ else
+ return false;
- return result;
+ return result;
}
-Neuropixels1::Neuropixels1(std::string name, std::string hubName, OnixDeviceType deviceType, const oni_dev_idx_t deviceIndex, std::shared_ptr context) :
- OnixDevice(name, hubName, deviceType, deviceIndex, context, deviceType == OnixDeviceType::NEUROPIXELSV1E),
- I2CRegisterContext(ProbeI2CAddress, deviceIndex, context),
- INeuropixel(NeuropixelsV1Values::numberOfSettings, NeuropixelsV1Values::numberOfShanks)
+Neuropixels1::Neuropixels1 (std::string name, std::string hubName, OnixDeviceType deviceType, const oni_dev_idx_t deviceIndex, std::shared_ptr context)
+ : OnixDevice (name, hubName, deviceType, deviceIndex, context, deviceType == OnixDeviceType::NEUROPIXELSV1E),
+ I2CRegisterContext (ProbeI2CAddress, deviceIndex, context),
+ INeuropixel (NeuropixelsV1Values::numberOfSettings, NeuropixelsV1Values::numberOfShanks)
{
}
-void Neuropixels1::setSettings(ProbeSettings* settings_, int index)
+void Neuropixels1::setSettings (ProbeSettings* settings_, int index)
{
- if (index >= settings.size())
- {
- LOGE("Invalid index given when trying to update settings.");
- return;
- }
+ if (index >= settings.size())
+ {
+ LOGE ("Invalid index given when trying to update settings.");
+ return;
+ }
- settings[index]->updateProbeSettings(settings_);
+ settings[index]->updateProbeSettings (settings_);
}
-std::vector Neuropixels1::selectElectrodeConfiguration(int electrodeConfigurationIndex)
+std::vector Neuropixels1::selectElectrodeConfiguration (int electrodeConfigurationIndex)
{
- std::vector selection;
-
- if (electrodeConfigurationIndex == (int32_t)ElectrodeConfiguration::BankA)
- {
- 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)
- {
- 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);
- }
- }
-
- assert(selection.size() == numberOfChannels && "Invalid number of selected channels.");
-
- return selection;
+ std::vector selection;
+
+ if (electrodeConfigurationIndex == (int32_t) ElectrodeConfiguration::BankA)
+ {
+ 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)
+ {
+ 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);
+ }
+ }
+
+ assert (selection.size() == numberOfChannels && "Invalid number of selected channels.");
+
+ return selection;
}
-void Neuropixels1::updateApOffsets(std::array& samples, int64 sampleNumber)
+void Neuropixels1::updateApOffsets (std::array& samples, int64 sampleNumber)
{
- if (sampleNumber > apSampleRate * secondsToSettle)
- {
- uint32_t counter = 0;
-
- while (apOffsetValues[0].size() < samplesToAverage)
- {
- if (counter >= superFramesPerUltraFrame * numUltraFrames) break;
-
- for (size_t i = 0; i < numberOfChannels; i++)
- {
- apOffsetValues[i].emplace_back(samples[i * superFramesPerUltraFrame * numUltraFrames + counter]);
- }
-
- counter++;
- }
-
- if (apOffsetValues[0].size() >= samplesToAverage)
- {
- for (int i = 0; i < numberOfChannels; i++)
- {
- apOffsets[i] = std::reduce(apOffsetValues.at(i).begin(), apOffsetValues.at(i).end()) / apOffsetValues.at(i).size();
- }
-
- apOffsetCalculated = true;
- apOffsetValues.clear();
- }
- }
+ if (sampleNumber > apSampleRate * secondsToSettle)
+ {
+ uint32_t counter = 0;
+
+ while (apOffsetValues[0].size() < samplesToAverage)
+ {
+ if (counter >= superFramesPerUltraFrame * numUltraFrames)
+ break;
+
+ for (size_t i = 0; i < numberOfChannels; i++)
+ {
+ apOffsetValues[i].emplace_back (samples[i * superFramesPerUltraFrame * numUltraFrames + counter]);
+ }
+
+ counter++;
+ }
+
+ if (apOffsetValues[0].size() >= samplesToAverage)
+ {
+ for (int i = 0; i < numberOfChannels; i++)
+ {
+ apOffsets[i] = std::reduce (apOffsetValues.at (i).begin(), apOffsetValues.at (i).end()) / apOffsetValues.at (i).size();
+ }
+
+ apOffsetCalculated = true;
+ apOffsetValues.clear();
+ }
+ }
}
-void Neuropixels1::updateLfpOffsets(std::array& samples, int64 sampleNumber)
+void Neuropixels1::updateLfpOffsets (std::array& samples, int64 sampleNumber)
{
- if (sampleNumber > lfpSampleRate * secondsToSettle)
- {
- uint32_t counter = 0;
-
- while (lfpOffsetValues[0].size() < samplesToAverage)
- {
- if (counter >= numUltraFrames) break;
-
- for (size_t i = 0; i < numberOfChannels; i++)
- {
- lfpOffsetValues[i].emplace_back(samples[i * numUltraFrames + counter]);
- }
-
- counter++;
- }
-
- if (lfpOffsetValues[0].size() >= samplesToAverage)
- {
- for (int i = 0; i < numberOfChannels; i++)
- {
- lfpOffsets[i] = std::reduce(lfpOffsetValues.at(i).begin(), lfpOffsetValues.at(i).end()) / lfpOffsetValues.at(i).size();
- }
-
- lfpOffsetCalculated = true;
- lfpOffsetValues.clear();
- }
- }
+ if (sampleNumber > lfpSampleRate * secondsToSettle)
+ {
+ uint32_t counter = 0;
+
+ while (lfpOffsetValues[0].size() < samplesToAverage)
+ {
+ if (counter >= numUltraFrames)
+ break;
+
+ for (size_t i = 0; i < numberOfChannels; i++)
+ {
+ lfpOffsetValues[i].emplace_back (samples[i * numUltraFrames + counter]);
+ }
+
+ counter++;
+ }
+
+ if (lfpOffsetValues[0].size() >= samplesToAverage)
+ {
+ for (int i = 0; i < numberOfChannels; i++)
+ {
+ lfpOffsets[i] = std::reduce (lfpOffsetValues.at (i).begin(), lfpOffsetValues.at (i).end()) / lfpOffsetValues.at (i).size();
+ }
+
+ lfpOffsetCalculated = true;
+ lfpOffsetValues.clear();
+ }
+ }
}
-void Neuropixels1::defineMetadata(ProbeSettings* settings)
+void Neuropixels1::defineMetadata (ProbeSettings* settings)
{
- settings->probeType = ProbeType::NPX_V1;
- settings->probeMetadata.name = "Neuropixels 1.0";
-
- std::vector> shankOutline{
- {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}
- };
-
- settings->probeMetadata.shank_count = 1;
- settings->probeMetadata.electrodes_per_shank = numberOfElectrodes;
- settings->probeMetadata.rows_per_shank = numberOfElectrodes / 2;
- settings->probeMetadata.columns_per_shank = 2;
- settings->probeMetadata.shankOutline = shankOutline;
- settings->probeMetadata.probeContour = probeContour;
- settings->probeMetadata.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++)
- {
- ElectrodeMetadata metadata;
-
- metadata.shank = 0;
- metadata.shank_local_index = i % settings->probeMetadata.electrodes_per_shank;
- metadata.global_index = i;
- metadata.xpos = xpositions[i % 4];
- metadata.ypos = (i - (i % 2)) * 10.0f;
- metadata.site_width = 12;
- metadata.column_index = i % 2;
- metadata.row_index = i / 2;
- metadata.isSelected = false;
- metadata.colour = Colours::lightgrey;
-
- if (i < 384)
- {
- metadata.bank = Bank::A;
- metadata.channel = i;
- metadata.status = ElectrodeStatus::CONNECTED;
- }
- else if (i >= 384 && i < 768)
- {
- metadata.bank = Bank::B;
- metadata.channel = i - 384;
- metadata.status = ElectrodeStatus::DISCONNECTED;
- }
- else
- {
- metadata.bank = Bank::C;
- metadata.channel = i - 768;
- metadata.status = ElectrodeStatus::DISCONNECTED;
- }
-
- if (i == 191 || i == 575 || i == 959)
- {
- metadata.type = ElectrodeType::REFERENCE;
- }
- else
- {
- metadata.type = ElectrodeType::ELECTRODE;
- }
-
- settings->electrodeMetadata[i] = metadata;
- }
-
- settings->apGainIndex = 4; // NB: AP Gain Index of 4 = Gain1000
- settings->lfpGainIndex = 0; // NB: LFP Gain Index of 0 = Gain50
- settings->referenceIndex = 0;
- settings->apFilterState = true;
-
- for (int i = 0; i < numberOfChannels; i++)
- {
- settings->selectedBank[i] = Bank::A;
- settings->selectedShank[i] = 0;
- settings->selectedElectrode[i] = i;
- }
-
- settings->availableApGains.add(50.0f);
- settings->availableApGains.add(125.0f);
- settings->availableApGains.add(250.0f);
- settings->availableApGains.add(500.0f);
- settings->availableApGains.add(1000.0f);
- settings->availableApGains.add(1500.0f);
- settings->availableApGains.add(2000.0f);
- settings->availableApGains.add(3000.0f);
-
- settings->availableLfpGains.add(50.0f);
- settings->availableLfpGains.add(125.0f);
- settings->availableLfpGains.add(250.0f);
- settings->availableLfpGains.add(500.0f);
- settings->availableLfpGains.add(1000.0f);
- settings->availableLfpGains.add(1500.0f);
- settings->availableLfpGains.add(2000.0f);
- settings->availableLfpGains.add(3000.0f);
-
- settings->availableReferences.add("Ext");
- settings->availableReferences.add("Tip");
-
- for (const auto& [_, config] : electrodeConfiguration)
- {
- settings->availableElectrodeConfigurations.add(config);
- }
-
- settings->electrodeConfigurationIndex = (int32_t)ElectrodeConfiguration::BankA;
- auto selection = selectElectrodeConfiguration(settings->electrodeConfigurationIndex);
- settings->selectElectrodes(selection);
-
- settings->isValid = true;
+ settings->probeType = ProbeType::NPX_V1;
+ settings->probeMetadata.name = "Neuropixels 1.0";
+
+ std::vector> shankOutline {
+ { 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 }
+ };
+
+ settings->probeMetadata.shank_count = 1;
+ settings->probeMetadata.electrodes_per_shank = numberOfElectrodes;
+ settings->probeMetadata.rows_per_shank = numberOfElectrodes / 2;
+ settings->probeMetadata.columns_per_shank = 2;
+ settings->probeMetadata.shankOutline = shankOutline;
+ settings->probeMetadata.probeContour = probeContour;
+ settings->probeMetadata.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++)
+ {
+ ElectrodeMetadata metadata;
+
+ metadata.shank = 0;
+ metadata.shank_local_index = i % settings->probeMetadata.electrodes_per_shank;
+ metadata.global_index = i;
+ metadata.xpos = xpositions[i % 4];
+ metadata.ypos = (i - (i % 2)) * 10.0f;
+ metadata.site_width = 12;
+ metadata.column_index = i % 2;
+ metadata.row_index = i / 2;
+ metadata.isSelected = false;
+ metadata.colour = Colours::lightgrey;
+
+ if (i < 384)
+ {
+ metadata.bank = Bank::A;
+ metadata.channel = i;
+ metadata.status = ElectrodeStatus::CONNECTED;
+ }
+ else if (i >= 384 && i < 768)
+ {
+ metadata.bank = Bank::B;
+ metadata.channel = i - 384;
+ metadata.status = ElectrodeStatus::DISCONNECTED;
+ }
+ else
+ {
+ metadata.bank = Bank::C;
+ metadata.channel = i - 768;
+ metadata.status = ElectrodeStatus::DISCONNECTED;
+ }
+
+ if (i == 191 || i == 575 || i == 959)
+ {
+ metadata.type = ElectrodeType::REFERENCE;
+ }
+ else
+ {
+ metadata.type = ElectrodeType::ELECTRODE;
+ }
+
+ settings->electrodeMetadata[i] = metadata;
+ }
+
+ settings->apGainIndex = 4; // NB: AP Gain Index of 4 = Gain1000
+ settings->lfpGainIndex = 0; // NB: LFP Gain Index of 0 = Gain50
+ settings->referenceIndex = 0;
+ settings->apFilterState = true;
+
+ for (int i = 0; i < numberOfChannels; i++)
+ {
+ settings->selectedBank[i] = Bank::A;
+ settings->selectedShank[i] = 0;
+ settings->selectedElectrode[i] = i;
+ }
+
+ settings->availableApGains.add (50.0f);
+ settings->availableApGains.add (125.0f);
+ settings->availableApGains.add (250.0f);
+ settings->availableApGains.add (500.0f);
+ settings->availableApGains.add (1000.0f);
+ settings->availableApGains.add (1500.0f);
+ settings->availableApGains.add (2000.0f);
+ settings->availableApGains.add (3000.0f);
+
+ settings->availableLfpGains.add (50.0f);
+ settings->availableLfpGains.add (125.0f);
+ settings->availableLfpGains.add (250.0f);
+ settings->availableLfpGains.add (500.0f);
+ settings->availableLfpGains.add (1000.0f);
+ settings->availableLfpGains.add (1500.0f);
+ settings->availableLfpGains.add (2000.0f);
+ settings->availableLfpGains.add (3000.0f);
+
+ settings->availableReferences.add ("Ext");
+ settings->availableReferences.add ("Tip");
+
+ for (const auto& [_, config] : electrodeConfiguration)
+ {
+ settings->availableElectrodeConfigurations.add (config);
+ }
+
+ settings->electrodeConfigurationIndex = (int32_t) ElectrodeConfiguration::BankA;
+ auto selection = selectElectrodeConfiguration (settings->electrodeConfigurationIndex);
+ settings->selectElectrodes (selection);
+
+ settings->isValid = true;
}
-uint64_t Neuropixels1::getProbeSerialNumber(int index)
+uint64_t Neuropixels1::getProbeSerialNumber (int index)
{
- return probeNumber;
+ return probeNumber;
}
bool Neuropixels1::parseGainCalibrationFile()
{
- if (gainCalibrationFilePath == "None" || gainCalibrationFilePath == "")
- {
- Onix1::showWarningMessageBoxAsync("Missing File", "Missing gain calibration file for probe " + std::to_string(probeNumber));
- return false;
- }
+ if (gainCalibrationFilePath == "None" || gainCalibrationFilePath == "")
+ {
+ Onix1::showWarningMessageBoxAsync ("Missing File", "Missing gain calibration file for probe " + std::to_string (probeNumber));
+ return false;
+ }
- File gainFile = File(gainCalibrationFilePath);
+ File gainFile = File (gainCalibrationFilePath);
- if (!gainFile.existsAsFile())
- {
- Onix1::showWarningMessageBoxAsync("Invalid File", "Invalid gain calibration file for probe " + std::to_string(probeNumber));
- return false;
- }
+ if (! gainFile.existsAsFile())
+ {
+ Onix1::showWarningMessageBoxAsync ("Invalid File", "Invalid gain calibration file for probe " + std::to_string (probeNumber));
+ return false;
+ }
- StringArray gainFileLines;
- gainFile.readLines(gainFileLines);
+ StringArray gainFileLines;
+ gainFile.readLines (gainFileLines);
- auto gainSN = std::stoull(gainFileLines[0].toStdString());
+ auto gainSN = std::stoull (gainFileLines[0].toStdString());
- LOGD("Gain calibration file SN = ", gainSN);
+ LOGD ("Gain calibration file SN = ", gainSN);
- if (gainSN != probeNumber)
- {
- Onix1::showWarningMessageBoxAsync("Serial Number Mismatch", "Gain calibration file serial number (" + std::to_string(gainSN) + ") does not match probe serial number (" + std::to_string(probeNumber) + ").");
- return false;
- }
+ if (gainSN != probeNumber)
+ {
+ Onix1::showWarningMessageBoxAsync ("Serial Number Mismatch", "Gain calibration file serial number (" + std::to_string (gainSN) + ") does not match probe serial number (" + std::to_string (probeNumber) + ").");
+ return false;
+ }
- if (gainFileLines.size() != numberOfElectrodes + 2)
- {
- Onix1::showWarningMessageBoxAsync("Invalid Gain Calibration File", "Expected to find " + std::to_string(numberOfElectrodes + 1) + " lines, but found " + std::to_string(gainFileLines.size()) + " instead.");
- return false;
- }
+ if (gainFileLines.size() != numberOfElectrodes + 2)
+ {
+ Onix1::showWarningMessageBoxAsync ("Invalid Gain Calibration File", "Expected to find " + std::to_string (numberOfElectrodes + 1) + " lines, but found " + std::to_string (gainFileLines.size()) + " instead.");
+ return false;
+ }
- StringRef gainCalLine = gainFileLines[1];
- StringRef breakCharacters = ",";
- StringRef noQuote = "";
+ StringRef gainCalLine = gainFileLines[1];
+ StringRef breakCharacters = ",";
+ StringRef noQuote = "";
- StringArray calibrationValues = StringArray::fromTokens(gainCalLine, breakCharacters, noQuote);
+ StringArray calibrationValues = StringArray::fromTokens (gainCalLine, breakCharacters, noQuote);
- static constexpr int NumberOfGainFactors = 8;
+ static constexpr int NumberOfGainFactors = 8;
- if (calibrationValues.size() != NumberOfGainFactors * 2 + 1)
- {
- Onix1::showWarningMessageBoxAsync("Gain Calibration File Error", "Expected to find " + std::to_string(NumberOfGainFactors * 2 + 1) + " elements per line, but found " + std::to_string(calibrationValues.size()) + " instead.");
- return false;
- }
+ if (calibrationValues.size() != NumberOfGainFactors * 2 + 1)
+ {
+ Onix1::showWarningMessageBoxAsync ("Gain Calibration File Error", "Expected to find " + std::to_string (NumberOfGainFactors * 2 + 1) + " elements per line, but found " + std::to_string (calibrationValues.size()) + " instead.");
+ return false;
+ }
- apGainCorrection = std::stod(calibrationValues[settings[0]->apGainIndex + 1].toStdString());
- lfpGainCorrection = std::stod(calibrationValues[settings[0]->lfpGainIndex + NumberOfGainFactors + 1].toStdString());
+ apGainCorrection = std::stod (calibrationValues[settings[0]->apGainIndex + 1].toStdString());
+ lfpGainCorrection = std::stod (calibrationValues[settings[0]->lfpGainIndex + NumberOfGainFactors + 1].toStdString());
- LOGD("AP gain correction = ", apGainCorrection, ", LFP gain correction = ", lfpGainCorrection);
+ LOGD ("AP gain correction = ", apGainCorrection, ", LFP gain correction = ", lfpGainCorrection);
- return true;
+ return true;
}
bool Neuropixels1::parseAdcCalibrationFile()
{
- if (adcCalibrationFilePath == "None" || adcCalibrationFilePath == "")
- {
- Onix1::showWarningMessageBoxAsync("Missing File", "Missing ADC calibration file for probe " + std::to_string(probeNumber));
- return false;
- }
-
- File adcFile = File(adcCalibrationFilePath);
-
- if (!adcFile.existsAsFile())
- {
- Onix1::showWarningMessageBoxAsync("Invalid File", "Invalid ADC calibration file for probe " + std::to_string(probeNumber));
- return false;
- }
-
- StringArray adcFileLines;
- adcFile.readLines(adcFileLines);
-
- auto adcSN = std::stoull(adcFileLines[0].toStdString());
-
- LOGD("ADC calibration file SN = ", adcSN);
-
- if (adcSN != probeNumber)
- {
- Onix1::showWarningMessageBoxAsync("Serial Number Mismatch", "ADC calibration serial number (" + std::to_string(adcSN) + ") does not match probe serial number (" + std::to_string(probeNumber)+").");
- return false;
- }
-
- if (adcFileLines.size() != NeuropixelsV1Values::AdcCount + 2)
- {
- Onix1::showWarningMessageBoxAsync("ADC Calibration File Error", "ADC calibration file does not have the correct number of lines. Expected " + std::to_string(NeuropixelsV1Values::AdcCount + 1) + " lines, found " + std::to_string(adcFileLines.size()) + " instead.");
- return false;
- }
-
- static constexpr int NumAdcValues = 9; // NB: ADC number + 8 values
-
- StringRef gainCalLine = adcFileLines[1];
- StringRef breakCharacters = ",";
- StringRef noQuote = "";
-
- adcValues.clear();
-
- for (int i = 1; i < adcFileLines.size() - 1; i++)
- {
- auto adcLine = StringArray::fromTokens(adcFileLines[i], breakCharacters, noQuote);
-
- if (adcLine.size() != NumAdcValues)
- {
- Onix1::showWarningMessageBoxAsync("ADC Calibration File Error", "ADC Calibration file line " + std::to_string(i) + " is invalid. Expected " + std::to_string(NumAdcValues) + " values, found " + std::to_string(adcLine.size()) + " instead.");
- return false;
- }
-
- adcValues.emplace_back(
- NeuropixelsV1Adc(
- std::stoi(adcLine[1].toStdString()),
- std::stoi(adcLine[2].toStdString()),
- std::stoi(adcLine[3].toStdString()),
- std::stoi(adcLine[4].toStdString()),
- std::stoi(adcLine[5].toStdString()),
- std::stoi(adcLine[6].toStdString()),
- std::stoi(adcLine[7].toStdString()),
- std::stoi(adcLine[8].toStdString())
- ));
- }
-
- return true;
+ if (adcCalibrationFilePath == "None" || adcCalibrationFilePath == "")
+ {
+ Onix1::showWarningMessageBoxAsync ("Missing File", "Missing ADC calibration file for probe " + std::to_string (probeNumber));
+ return false;
+ }
+
+ File adcFile = File (adcCalibrationFilePath);
+
+ if (! adcFile.existsAsFile())
+ {
+ Onix1::showWarningMessageBoxAsync ("Invalid File", "Invalid ADC calibration file for probe " + std::to_string (probeNumber));
+ return false;
+ }
+
+ StringArray adcFileLines;
+ adcFile.readLines (adcFileLines);
+
+ auto adcSN = std::stoull (adcFileLines[0].toStdString());
+
+ LOGD ("ADC calibration file SN = ", adcSN);
+
+ if (adcSN != probeNumber)
+ {
+ Onix1::showWarningMessageBoxAsync ("Serial Number Mismatch", "ADC calibration serial number (" + std::to_string (adcSN) + ") does not match probe serial number (" + std::to_string (probeNumber) + ").");
+ return false;
+ }
+
+ if (adcFileLines.size() != NeuropixelsV1Values::AdcCount + 2)
+ {
+ Onix1::showWarningMessageBoxAsync ("ADC Calibration File Error", "ADC calibration file does not have the correct number of lines. Expected " + std::to_string (NeuropixelsV1Values::AdcCount + 1) + " lines, found " + std::to_string (adcFileLines.size()) + " instead.");
+ return false;
+ }
+
+ static constexpr int NumAdcValues = 9; // NB: ADC number + 8 values
+
+ StringRef gainCalLine = adcFileLines[1];
+ StringRef breakCharacters = ",";
+ StringRef noQuote = "";
+
+ adcValues.clear();
+
+ for (int i = 1; i < adcFileLines.size() - 1; i++)
+ {
+ auto adcLine = StringArray::fromTokens (adcFileLines[i], breakCharacters, noQuote);
+
+ if (adcLine.size() != NumAdcValues)
+ {
+ Onix1::showWarningMessageBoxAsync ("ADC Calibration File Error", "ADC Calibration file line " + std::to_string (i) + " is invalid. Expected " + std::to_string (NumAdcValues) + " values, found " + std::to_string (adcLine.size()) + " instead.");
+ return false;
+ }
+
+ adcValues.emplace_back (
+ NeuropixelsV1Adc (
+ std::stoi (adcLine[1].toStdString()),
+ std::stoi (adcLine[2].toStdString()),
+ std::stoi (adcLine[3].toStdString()),
+ std::stoi (adcLine[4].toStdString()),
+ std::stoi (adcLine[5].toStdString()),
+ std::stoi (adcLine[6].toStdString()),
+ std::stoi (adcLine[7].toStdString()),
+ std::stoi (adcLine[8].toStdString())));
+ }
+
+ return true;
}
-NeuropixelsV1Gain Neuropixels1::getGainEnum(int index)
+NeuropixelsV1Gain Neuropixels1::getGainEnum (int index)
{
- switch (index)
- {
- case 0:
- return NeuropixelsV1Gain::Gain50;
- case 1:
- return NeuropixelsV1Gain::Gain125;
- case 2:
- return NeuropixelsV1Gain::Gain250;
- case 3:
- return NeuropixelsV1Gain::Gain500;
- case 4:
- return NeuropixelsV1Gain::Gain1000;
- case 5:
- return NeuropixelsV1Gain::Gain1500;
- case 6:
- return NeuropixelsV1Gain::Gain2000;
- case 7:
- return NeuropixelsV1Gain::Gain3000;
- default:
- return NeuropixelsV1Gain::Gain50;
- }
+ switch (index)
+ {
+ case 0:
+ return NeuropixelsV1Gain::Gain50;
+ case 1:
+ return NeuropixelsV1Gain::Gain125;
+ case 2:
+ return NeuropixelsV1Gain::Gain250;
+ case 3:
+ return NeuropixelsV1Gain::Gain500;
+ case 4:
+ return NeuropixelsV1Gain::Gain1000;
+ case 5:
+ return NeuropixelsV1Gain::Gain1500;
+ case 6:
+ return NeuropixelsV1Gain::Gain2000;
+ case 7:
+ return NeuropixelsV1Gain::Gain3000;
+ default:
+ return NeuropixelsV1Gain::Gain50;
+ }
}
-int Neuropixels1::getGainValue(NeuropixelsV1Gain gain)
+int Neuropixels1::getGainValue (NeuropixelsV1Gain gain)
{
- switch (gain)
- {
- case NeuropixelsV1Gain::Gain50:
- return 50;
- case NeuropixelsV1Gain::Gain125:
- return 125;
- case NeuropixelsV1Gain::Gain250:
- return 250;
- case NeuropixelsV1Gain::Gain500:
- return 500;
- case NeuropixelsV1Gain::Gain1000:
- return 1000;
- case NeuropixelsV1Gain::Gain1500:
- return 1500;
- case NeuropixelsV1Gain::Gain2000:
- return 2000;
- case NeuropixelsV1Gain::Gain3000:
- return 3000;
- default:
- return 50;
- }
+ switch (gain)
+ {
+ case NeuropixelsV1Gain::Gain50:
+ return 50;
+ case NeuropixelsV1Gain::Gain125:
+ return 125;
+ case NeuropixelsV1Gain::Gain250:
+ return 250;
+ case NeuropixelsV1Gain::Gain500:
+ return 500;
+ case NeuropixelsV1Gain::Gain1000:
+ return 1000;
+ case NeuropixelsV1Gain::Gain1500:
+ return 1500;
+ case NeuropixelsV1Gain::Gain2000:
+ return 2000;
+ case NeuropixelsV1Gain::Gain3000:
+ return 3000;
+ default:
+ return 50;
+ }
}
-NeuropixelsV1Reference Neuropixels1::getReference(int index)
+NeuropixelsV1Reference Neuropixels1::getReference (int index)
{
- switch (index)
- {
- case 0:
- return NeuropixelsV1Reference::External;
- case 1:
- return NeuropixelsV1Reference::Tip;
- default:
- break;
- }
-
- return NeuropixelsV1Reference::External;
+ switch (index)
+ {
+ case 0:
+ return NeuropixelsV1Reference::External;
+ case 1:
+ return NeuropixelsV1Reference::Tip;
+ default:
+ break;
+ }
+
+ return NeuropixelsV1Reference::External;
}
std::string Neuropixels1::getAdcCalibrationFilePath()
{
- return adcCalibrationFilePath;
+ return adcCalibrationFilePath;
}
-void Neuropixels1::setAdcCalibrationFilePath(std::string filepath)
+void Neuropixels1::setAdcCalibrationFilePath (std::string filepath)
{
- adcCalibrationFilePath = filepath;
+ adcCalibrationFilePath = filepath;
}
std::string Neuropixels1::getGainCalibrationFilePath()
{
- return gainCalibrationFilePath;
+ return gainCalibrationFilePath;
}
-void Neuropixels1::setGainCalibrationFilePath(std::string filepath)
+void Neuropixels1::setGainCalibrationFilePath (std::string filepath)
{
- gainCalibrationFilePath = filepath;
+ gainCalibrationFilePath = filepath;
}
diff --git a/Source/Devices/Neuropixels1.h b/Source/Devices/Neuropixels1.h
index 94eb030..3d5e5d4 100644
--- a/Source/Devices/Neuropixels1.h
+++ b/Source/Devices/Neuropixels1.h
@@ -1,172 +1,168 @@
/*
- ------------------------------------------------------------------
+ ------------------------------------------------------------------
- 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 .
*/
#pragma once
-#include "../OnixDevice.h"
-#include "../NeuropixelsComponents.h"
#include "../I2CRegisterContext.h"
+#include "../NeuropixelsComponents.h"
+#include "../OnixDevice.h"
namespace OnixSourcePlugin
{
- class Neuropixels1 : public INeuropixel,
- public OnixDevice,
- public I2CRegisterContext
- {
- public:
-
- Neuropixels1(std::string, std::string, OnixDeviceType, const oni_dev_idx_t, std::shared_ptr);
-
- NeuropixelsV1Gain getGainEnum(int index);
-
- int getGainValue(NeuropixelsV1Gain);
-
- NeuropixelsV1Reference getReference(int index);
+class Neuropixels1 : public INeuropixel,
+ public OnixDevice,
+ public I2CRegisterContext
+{
+public:
+ Neuropixels1 (std::string, std::string, OnixDeviceType, const oni_dev_idx_t, std::shared_ptr);
- std::string getAdcCalibrationFilePath();
- void setAdcCalibrationFilePath(std::string filepath);
- std::string getGainCalibrationFilePath();
- void setGainCalibrationFilePath(std::string filepath);
+ NeuropixelsV1Gain getGainEnum (int index);
- // INeuropixels methods
- void defineMetadata(ProbeSettings* settings) override;
+ int getGainValue (NeuropixelsV1Gain);
- /** Select a preset electrode configuration, based on the index of the given enum */
- std::vector selectElectrodeConfiguration(int electrodeConfigurationIndex) override;
+ NeuropixelsV1Reference getReference (int index);
- uint64_t getProbeSerialNumber(int index = 0) override;
+ std::string getAdcCalibrationFilePath();
+ void setAdcCalibrationFilePath (std::string filepath);
+ std::string getGainCalibrationFilePath();
+ void setGainCalibrationFilePath (std::string filepath);
- void setSettings(ProbeSettings* settings_, int index = 0) override;
+ // INeuropixels methods
+ void defineMetadata (ProbeSettings* settings) override;
- bool parseGainCalibrationFile();
- bool parseAdcCalibrationFile();
+ /** Select a preset electrode configuration, based on the index of the given enum */
+ std::vector selectElectrodeConfiguration (int electrodeConfigurationIndex) override;
- protected:
+ uint64_t getProbeSerialNumber (int index = 0) override;
- DataBuffer* apBuffer;
- DataBuffer* lfpBuffer;
+ void setSettings (ProbeSettings* settings_, int index = 0) override;
- std::string adcCalibrationFilePath;
- std::string gainCalibrationFilePath;
+ bool parseGainCalibrationFile();
+ bool parseAdcCalibrationFile();
- double apGainCorrection = 0;
- double lfpGainCorrection = 0;
+protected:
+ DataBuffer* apBuffer;
+ DataBuffer* lfpBuffer;
- uint64_t probeNumber = 0;
+ std::string adcCalibrationFilePath;
+ std::string gainCalibrationFilePath;
- const uint32_t ENABLE = 0x8000;
+ double apGainCorrection = 0;
+ double lfpGainCorrection = 0;
- static constexpr int ProbeI2CAddress = 0x70;
+ uint64_t probeNumber = 0;
- static constexpr int superFramesPerUltraFrame = 12;
- static constexpr int framesPerSuperFrame = 13;
- static constexpr int framesPerUltraFrame = superFramesPerUltraFrame * framesPerSuperFrame;
- static constexpr int numUltraFrames = 12;
- static constexpr int dataOffset = 4 + 1; // NB: 4 bytes [hubClock] + 1 byte [probeIndex]
+ const uint32_t ENABLE = 0x8000;
- static constexpr uint16_t NumberOfAdcBins = 1024;
- static constexpr float DataMidpoint = NumberOfAdcBins / 2;
+ static constexpr int ProbeI2CAddress = 0x70;
- static constexpr int secondsToSettle = 5;
- static constexpr int samplesToAverage = 100;
+ static constexpr int superFramesPerUltraFrame = 12;
+ static constexpr int framesPerSuperFrame = 13;
+ static constexpr int framesPerUltraFrame = superFramesPerUltraFrame * framesPerSuperFrame;
+ static constexpr int numUltraFrames = 12;
+ static constexpr int dataOffset = 4 + 1; // NB: 4 bytes [hubClock] + 1 byte [probeIndex]
- static constexpr uint32_t numLfpSamples = 384 * numUltraFrames;
- static constexpr uint32_t numApSamples = 384 * numUltraFrames * superFramesPerUltraFrame;
+ static constexpr uint16_t NumberOfAdcBins = 1024;
+ static constexpr float DataMidpoint = NumberOfAdcBins / 2;
- static constexpr float lfpSampleRate = 2500.0f;
- static constexpr float apSampleRate = 30000.0f;
+ static constexpr int secondsToSettle = 5;
+ static constexpr int samplesToAverage = 100;
- bool lfpOffsetCalculated = false;
- bool apOffsetCalculated = false;
+ static constexpr uint32_t numLfpSamples = 384 * numUltraFrames;
+ static constexpr uint32_t numApSamples = 384 * numUltraFrames * superFramesPerUltraFrame;
- std::array apOffsets;
- std::array lfpOffsets;
+ static constexpr float lfpSampleRate = 2500.0f;
+ static constexpr float apSampleRate = 30000.0f;
- std::vector> apOffsetValues;
- std::vector> lfpOffsetValues;
+ bool lfpOffsetCalculated = false;
+ bool apOffsetCalculated = false;
- std::array lfpSamples;
- std::array apSamples;
+ std::array apOffsets;
+ std::array lfpOffsets;
- int64 apSampleNumbers[numUltraFrames * superFramesPerUltraFrame];
- double apTimestamps[numUltraFrames * superFramesPerUltraFrame];
- uint64 apEventCodes[numUltraFrames * superFramesPerUltraFrame];
+ std::vector> apOffsetValues;
+ std::vector> lfpOffsetValues;
- int64 lfpSampleNumbers[numUltraFrames];
- double lfpTimestamps[numUltraFrames];
- uint64 lfpEventCodes[numUltraFrames];
+ std::array lfpSamples;
+ std::array apSamples;
- int superFrameCount = 0;
- int ultraFrameCount = 0;
+ int64 apSampleNumbers[numUltraFrames * superFramesPerUltraFrame];
+ double apTimestamps[numUltraFrames * superFramesPerUltraFrame];
+ uint64 apEventCodes[numUltraFrames * superFramesPerUltraFrame];
- int apSampleNumber = 0;
- int lfpSampleNumber = 0;
+ int64 lfpSampleNumbers[numUltraFrames];
+ double lfpTimestamps[numUltraFrames];
+ uint64 lfpEventCodes[numUltraFrames];
- int apGain = 1000;
- int lfpGain = 50;
+ int superFrameCount = 0;
+ int ultraFrameCount = 0;
- std::vector adcValues;
+ int apSampleNumber = 0;
+ int lfpSampleNumber = 0;
- void updateLfpOffsets(std::array&, int64);
- void updateApOffsets(std::array&, int64);
+ int apGain = 1000;
+ int lfpGain = 50;
- enum class ElectrodeConfiguration : int32_t
- {
- BankA = 0,
- BankB = 1,
- BankC = 2,
- SingleColumn = 3,
- Tetrodes = 4
- };
+ std::vector adcValues;
- std::map electrodeConfiguration = {
- {ElectrodeConfiguration::BankA, "Bank A"},
- {ElectrodeConfiguration::BankB, "Bank B"},
- {ElectrodeConfiguration::BankC, "Bank C"},
- {ElectrodeConfiguration::SingleColumn, "Single Column"},
- {ElectrodeConfiguration::Tetrodes, "Tetrodes"}
- };
+ void updateLfpOffsets (std::array&, int64);
+ void updateApOffsets (std::array&, int64);
- JUCE_LEAK_DETECTOR(Neuropixels1);
- };
+ enum class ElectrodeConfiguration : int32_t
+ {
+ BankA = 0,
+ BankB = 1,
+ BankC = 2,
+ SingleColumn = 3,
+ Tetrodes = 4
+ };
- /*
- A thread that updates Neuropixels 1.0 probe settings in the background and shows a progress bar
- */
- class NeuropixelsV1BackgroundUpdater : public ThreadWithProgressWindow
- {
- public:
- NeuropixelsV1BackgroundUpdater(Neuropixels1* d);
+ std::map electrodeConfiguration = {
+ { ElectrodeConfiguration::BankA, "Bank A" },
+ { ElectrodeConfiguration::BankB, "Bank B" },
+ { ElectrodeConfiguration::BankC, "Bank C" },
+ { ElectrodeConfiguration::SingleColumn, "Single Column" },
+ { ElectrodeConfiguration::Tetrodes, "Tetrodes" }
+ };
- bool updateSettings();
+ JUCE_LEAK_DETECTOR (Neuropixels1);
+};
- protected:
+/*
+ A thread that updates Neuropixels 1.0 probe settings in the background and shows a progress bar
+*/
+class NeuropixelsV1BackgroundUpdater : public ThreadWithProgressWindow
+{
+public:
+ NeuropixelsV1BackgroundUpdater (Neuropixels1* d);
- Neuropixels1* device;
+ bool updateSettings();
- std::atomic result = false;
+protected:
+ Neuropixels1* device;
- private:
+ std::atomic result = false;
- JUCE_LEAK_DETECTOR(NeuropixelsV1BackgroundUpdater);
- };
-}
+private:
+ JUCE_LEAK_DETECTOR (NeuropixelsV1BackgroundUpdater);
+};
+} // namespace OnixSourcePlugin
diff --git a/Source/Devices/Neuropixels1e.cpp b/Source/Devices/Neuropixels1e.cpp
index b26d9a3..ae9a995 100644
--- a/Source/Devices/Neuropixels1e.cpp
+++ b/Source/Devices/Neuropixels1e.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,398 +24,398 @@
using namespace OnixSourcePlugin;
-NeuropixelsV1eBackgroundUpdater::NeuropixelsV1eBackgroundUpdater(Neuropixels1e* d)
- : NeuropixelsV1BackgroundUpdater(d)
+NeuropixelsV1eBackgroundUpdater::NeuropixelsV1eBackgroundUpdater (Neuropixels1e* d)
+ : NeuropixelsV1BackgroundUpdater (d)
{
}
void NeuropixelsV1eBackgroundUpdater::run()
{
- setProgress(0);
-
- ((Neuropixels1e*)device)->resetProbe();
-
- if (!device->parseGainCalibrationFile())
- {
- result = false;
- return;
- }
-
- if (!device->parseAdcCalibrationFile())
- {
- result = false;
- return;
- }
-
- setProgress(0.5);
-
- device->WriteByte((uint32_t)NeuropixelsV1Registers::CAL_MOD, (uint32_t)NeuropixelsV1CalibrationRegisterValues::CAL_OFF);
- device->WriteByte((uint32_t)NeuropixelsV1Registers::TEST_CONFIG1, 0);
- device->WriteByte((uint32_t)NeuropixelsV1Registers::TEST_CONFIG2, 0);
- device->WriteByte((uint32_t)NeuropixelsV1Registers::TEST_CONFIG3, 0);
- device->WriteByte((uint32_t)NeuropixelsV1Registers::TEST_CONFIG4, 0);
- device->WriteByte((uint32_t)NeuropixelsV1Registers::TEST_CONFIG5, 0);
- device->WriteByte((uint32_t)NeuropixelsV1Registers::SYNC, 0);
- device->WriteByte((uint32_t)NeuropixelsV1Registers::REC_MOD, (uint32_t)NeuropixelsV1RecordRegisterValues::ACTIVE);
- device->WriteByte((uint32_t)NeuropixelsV1Registers::OP_MODE, (uint32_t)NeuropixelsV1OperationRegisterValues::RECORD);
-
- try
- {
- ((Neuropixels1e*)device)->writeShiftRegisters();
- }
- catch (const error_str& e)
- {
- Onix1::showWarningMessageBoxAsync("Error Writing Shift Registers", e.what());
- result = false;
- return;
- }
-
- setProgress(1);
-
- result = true;
+ setProgress (0);
+
+ ((Neuropixels1e*) device)->resetProbe();
+
+ if (! device->parseGainCalibrationFile())
+ {
+ result = false;
+ return;
+ }
+
+ if (! device->parseAdcCalibrationFile())
+ {
+ result = false;
+ return;
+ }
+
+ setProgress (0.5);
+
+ device->WriteByte ((uint32_t) NeuropixelsV1Registers::CAL_MOD, (uint32_t) NeuropixelsV1CalibrationRegisterValues::CAL_OFF);
+ device->WriteByte ((uint32_t) NeuropixelsV1Registers::TEST_CONFIG1, 0);
+ device->WriteByte ((uint32_t) NeuropixelsV1Registers::TEST_CONFIG2, 0);
+ device->WriteByte ((uint32_t) NeuropixelsV1Registers::TEST_CONFIG3, 0);
+ device->WriteByte ((uint32_t) NeuropixelsV1Registers::TEST_CONFIG4, 0);
+ device->WriteByte ((uint32_t) NeuropixelsV1Registers::TEST_CONFIG5, 0);
+ device->WriteByte ((uint32_t) NeuropixelsV1Registers::SYNC, 0);
+ device->WriteByte ((uint32_t) NeuropixelsV1Registers::REC_MOD, (uint32_t) NeuropixelsV1RecordRegisterValues::ACTIVE);
+ device->WriteByte ((uint32_t) NeuropixelsV1Registers::OP_MODE, (uint32_t) NeuropixelsV1OperationRegisterValues::RECORD);
+
+ try
+ {
+ ((Neuropixels1e*) device)->writeShiftRegisters();
+ }
+ catch (const error_str& e)
+ {
+ Onix1::showWarningMessageBoxAsync ("Error Writing Shift Registers", e.what());
+ result = false;
+ return;
+ }
+
+ setProgress (1);
+
+ result = true;
}
-Neuropixels1e::Neuropixels1e(std::string name, std::string hubName, const oni_dev_idx_t deviceIdx_, std::shared_ptr ctx_) :
- Neuropixels1(name, hubName, OnixDeviceType::NEUROPIXELSV1E, deviceIdx_, ctx_)
+Neuropixels1e::Neuropixels1e (std::string name, std::string hubName, const oni_dev_idx_t deviceIdx_, std::shared_ptr ctx_)
+ : Neuropixels1 (name, hubName, OnixDeviceType::NEUROPIXELSV1E, deviceIdx_, ctx_)
{
- std::string port = getPortName(getDeviceIdx());
- StreamInfo apStream = StreamInfo(
- OnixDevice::createStreamName({ port, getHubName(), getName(), STREAM_NAME_AP }),
- "Neuropixels 1.0 AP band data stream",
- getStreamIdentifier(),
- numberOfChannels,
- apSampleRate,
- STREAM_NAME_AP,
- ContinuousChannel::Type::ELECTRODE,
- 0.195f,
- "uV",
- {},
- "ap"
- );
- streamInfos.add(apStream);
-
- StreamInfo lfpStream = StreamInfo(
- OnixDevice::createStreamName({ port, getHubName(), getName(), STREAM_NAME_LFP }),
- "Neuropixels 1.0 LFP band data stream",
- getStreamIdentifier(),
- numberOfChannels,
- lfpSampleRate,
- STREAM_NAME_LFP,
- ContinuousChannel::Type::ELECTRODE,
- 0.195f,
- "uV",
- {},
- "lfp"
- );
- streamInfos.add(lfpStream);
-
- defineMetadata(settings[0].get());
-
- adcCalibrationFilePath = "None";
- gainCalibrationFilePath = "None";
-
- for (int i = 0; i < numUltraFrames; i++)
- {
- apEventCodes[i] = 0;
- lfpEventCodes[i] = 0;
- }
-
- probeNumber = 0;
+ std::string port = getPortName (getDeviceIdx());
+ StreamInfo apStream = StreamInfo (
+ OnixDevice::createStreamName ({ port, getHubName(), getName(), STREAM_NAME_AP }),
+ "Neuropixels 1.0 AP band data stream",
+ getStreamIdentifier(),
+ numberOfChannels,
+ apSampleRate,
+ STREAM_NAME_AP,
+ ContinuousChannel::Type::ELECTRODE,
+ 0.195f,
+ "uV",
+ {},
+ "ap");
+ streamInfos.add (apStream);
+
+ StreamInfo lfpStream = StreamInfo (
+ OnixDevice::createStreamName ({ port, getHubName(), getName(), STREAM_NAME_LFP }),
+ "Neuropixels 1.0 LFP band data stream",
+ getStreamIdentifier(),
+ numberOfChannels,
+ lfpSampleRate,
+ STREAM_NAME_LFP,
+ ContinuousChannel::Type::ELECTRODE,
+ 0.195f,
+ "uV",
+ {},
+ "lfp");
+ streamInfos.add (lfpStream);
+
+ defineMetadata (settings[0].get());
+
+ adcCalibrationFilePath = "None";
+ gainCalibrationFilePath = "None";
+
+ for (int i = 0; i < numUltraFrames; i++)
+ {
+ apEventCodes[i] = 0;
+ lfpEventCodes[i] = 0;
+ }
+
+ probeNumber = 0;
}
int Neuropixels1e::configureDevice()
{
- if (deviceContext == nullptr || !deviceContext->isInitialized())
- throw error_str("Device context is not initialized properly for " + getName());
+ if (deviceContext == nullptr || ! deviceContext->isInitialized())
+ throw error_str ("Device context is not initialized properly for " + getName());
- configureSerDes();
+ configureSerDes();
- int rc = serializer->set933I2cRate(400e3);
- if (rc != ONI_ESUCCESS)
- throw error_str("Unable to set I2C rate for " + getName());
+ int rc = serializer->set933I2cRate (400e3);
+ if (rc != ONI_ESUCCESS)
+ throw error_str ("Unable to set I2C rate for " + getName());
- // Get Probe SN
+ // Get Probe SN
- int errorCode = 0;
+ int errorCode = 0;
- for (int i = 0; i < 8; i++)
- {
- oni_reg_val_t reg_val;
- rc = flex->ReadByte(OFFSET_ID + i, ®_val);
+ for (int i = 0; i < 8; i++)
+ {
+ oni_reg_val_t reg_val;
+ rc = flex->ReadByte (OFFSET_ID + i, ®_val);
- if (rc != ONI_ESUCCESS)
- throw error_str("Unable to read the probe serial number for device at address " + getDeviceIdx());
+ if (rc != ONI_ESUCCESS)
+ throw error_str ("Unable to read the probe serial number for device at address " + getDeviceIdx());
- if (reg_val <= 0xFF)
- {
- probeNumber |= (((uint64_t)reg_val) << (i * 8));
- }
- }
+ if (reg_val <= 0xFF)
+ {
+ probeNumber |= (((uint64_t) reg_val) << (i * 8));
+ }
+ }
- LOGD("Probe SN: ", probeNumber);
+ LOGD ("Probe SN: ", probeNumber);
- return ONI_ESUCCESS;
+ return ONI_ESUCCESS;
}
OnixDeviceType Neuropixels1e::getDeviceType()
{
- return OnixDeviceType::NEUROPIXELSV1E;
+ return OnixDeviceType::NEUROPIXELSV1E;
}
void Neuropixels1e::configureSerDes()
{
- deviceContext->writeRegister(deviceIdx, DS90UB9x::ENABLE, 1);
-
- deviceContext->writeRegister(deviceIdx, DS90UB9x::TRIGGEROFF, 0);
- deviceContext->writeRegister(deviceIdx, DS90UB9x::TRIGGER, (uint32_t)DS90UB9x::DS90UB9xTriggerMode::Continuous);
- deviceContext->writeRegister(deviceIdx, DS90UB9x::SYNCBITS, 0);
- deviceContext->writeRegister(deviceIdx, DS90UB9x::DATAGATE, 0b00000001000100110000000000000001);
- deviceContext->writeRegister(deviceIdx, DS90UB9x::MARK, (uint32_t)DS90UB9x::DS90UB9xMarkMode::Disabled);
-
- // configure one magic word-triggered stream for the PSB bus
- deviceContext->writeRegister(deviceIdx, DS90UB9x::READSZ, 851973); // 13 frames/superframe, 7x 140-bit words on each serial line per frame
- deviceContext->writeRegister(deviceIdx, DS90UB9x::MAGIC_MASK, 0b11000000000000000000001111111111); // Enable inverse, wait for non-inverse, 10-bit magic word
- deviceContext->writeRegister(deviceIdx, DS90UB9x::MAGIC, 816); // Super-frame sync word
- deviceContext->writeRegister(deviceIdx, DS90UB9x::MAGIC_WAIT, 0);
- deviceContext->writeRegister(deviceIdx, DS90UB9x::DATAMODE, 913);
- deviceContext->writeRegister(deviceIdx, DS90UB9x::DATALINES0, 0x3245106B); // Sync, psb[0], psb[1], psb[2], psb[3], psb[4], psb[5], psb[6],
- deviceContext->writeRegister(deviceIdx, DS90UB9x::DATALINES1, 0xFFFFFFFF);
-
- std::this_thread::sleep_for(100ms); // Empirical. The gateware seems to need some milliseconds to get i2c initialized.
-
- deserializer = std::make_unique(DS90UB9x::DES_ADDR, deviceIdx, deviceContext);
- deserializer->WriteByte((uint32_t)DS90UB9x::DS90UB9xDeserializerI2CRegister::PortSel, 0x01); // Enable port 0
- int coaxMode = 0x4 + (uint32_t)(DS90UB9x::DS90UB9xMode::Raw12BitHighFrequency); // 0x4 maintains coax mode
- deserializer->WriteByte((uint32_t)DS90UB9x::DS90UB9xDeserializerI2CRegister::PortMode, coaxMode); // 0x4 maintains coax mode
- deserializer->WriteByte((uint32_t)DS90UB9x::DS90UB9xDeserializerI2CRegister::I2CConfig, 0b01011000); // 7: i2c pass all (0), 6: i2c pass (1), 5: auto_ack (0), 4: BC enable (1), 3: BC crc en (1), 2: reserved (0) 1:0: bc freq (00) 2.5Mbps
- deserializer->WriteByte((uint32_t)DS90UB9x::DS90UB9xDeserializerI2CRegister::SerAlias, DS90UB9x::SER_ADDR << 1);
- // Enable backchannel GPIO on deserializer. It is then the serializer task to decide if using them or use manual output
- deserializer->WriteByte((uint32_t)DS90UB9x::DS90UB9xDeserializerI2CRegister::GpioCtrl0, 0x10);
- deserializer->WriteByte((uint32_t)DS90UB9x::DS90UB9xDeserializerI2CRegister::GpioCtrl1, 0x32);
-
- auto alias = ProbeI2CAddress << 1;
- deserializer->WriteByte((uint32_t)DS90UB9x::DS90UB9xDeserializerI2CRegister::SlaveID1, alias);
- deserializer->WriteByte((uint32_t)DS90UB9x::DS90UB9xDeserializerI2CRegister::SlaveAlias1, alias);
-
- alias = FlexEepromI2CAddress << 1;
- deserializer->WriteByte((uint32_t)DS90UB9x::DS90UB9xDeserializerI2CRegister::SlaveID2, alias);
- deserializer->WriteByte((uint32_t)DS90UB9x::DS90UB9xDeserializerI2CRegister::SlaveAlias2, alias);
-
- serializer = std::make_unique(DS90UB9x::SER_ADDR, deviceIdx, deviceContext);
- flex = std::make_unique(FlexEepromI2CAddress, deviceIdx, deviceContext);
+ deviceContext->writeRegister (deviceIdx, DS90UB9x::ENABLE, 1);
+
+ deviceContext->writeRegister (deviceIdx, DS90UB9x::TRIGGEROFF, 0);
+ deviceContext->writeRegister (deviceIdx, DS90UB9x::TRIGGER, (uint32_t) DS90UB9x::DS90UB9xTriggerMode::Continuous);
+ deviceContext->writeRegister (deviceIdx, DS90UB9x::SYNCBITS, 0);
+ deviceContext->writeRegister (deviceIdx, DS90UB9x::DATAGATE, 0b00000001000100110000000000000001);
+ deviceContext->writeRegister (deviceIdx, DS90UB9x::MARK, (uint32_t) DS90UB9x::DS90UB9xMarkMode::Disabled);
+
+ // configure one magic word-triggered stream for the PSB bus
+ deviceContext->writeRegister (deviceIdx, DS90UB9x::READSZ, 851973); // 13 frames/superframe, 7x 140-bit words on each serial line per frame
+ deviceContext->writeRegister (deviceIdx, DS90UB9x::MAGIC_MASK, 0b11000000000000000000001111111111); // Enable inverse, wait for non-inverse, 10-bit magic word
+ deviceContext->writeRegister (deviceIdx, DS90UB9x::MAGIC, 816); // Super-frame sync word
+ deviceContext->writeRegister (deviceIdx, DS90UB9x::MAGIC_WAIT, 0);
+ deviceContext->writeRegister (deviceIdx, DS90UB9x::DATAMODE, 913);
+ deviceContext->writeRegister (deviceIdx, DS90UB9x::DATALINES0, 0x3245106B); // Sync, psb[0], psb[1], psb[2], psb[3], psb[4], psb[5], psb[6],
+ deviceContext->writeRegister (deviceIdx, DS90UB9x::DATALINES1, 0xFFFFFFFF);
+
+ std::this_thread::sleep_for (100ms); // Empirical. The gateware seems to need some milliseconds to get i2c initialized.
+
+ deserializer = std::make_unique (DS90UB9x::DES_ADDR, deviceIdx, deviceContext);
+ deserializer->WriteByte ((uint32_t) DS90UB9x::DS90UB9xDeserializerI2CRegister::PortSel, 0x01); // Enable port 0
+ int coaxMode = 0x4 + (uint32_t) (DS90UB9x::DS90UB9xMode::Raw12BitHighFrequency); // 0x4 maintains coax mode
+ deserializer->WriteByte ((uint32_t) DS90UB9x::DS90UB9xDeserializerI2CRegister::PortMode, coaxMode); // 0x4 maintains coax mode
+ deserializer->WriteByte ((uint32_t) DS90UB9x::DS90UB9xDeserializerI2CRegister::I2CConfig, 0b01011000); // 7: i2c pass all (0), 6: i2c pass (1), 5: auto_ack (0), 4: BC enable (1), 3: BC crc en (1), 2: reserved (0) 1:0: bc freq (00) 2.5Mbps
+ deserializer->WriteByte ((uint32_t) DS90UB9x::DS90UB9xDeserializerI2CRegister::SerAlias, DS90UB9x::SER_ADDR << 1);
+ // Enable backchannel GPIO on deserializer. It is then the serializer task to decide if using them or use manual output
+ deserializer->WriteByte ((uint32_t) DS90UB9x::DS90UB9xDeserializerI2CRegister::GpioCtrl0, 0x10);
+ deserializer->WriteByte ((uint32_t) DS90UB9x::DS90UB9xDeserializerI2CRegister::GpioCtrl1, 0x32);
+
+ auto alias = ProbeI2CAddress << 1;
+ deserializer->WriteByte ((uint32_t) DS90UB9x::DS90UB9xDeserializerI2CRegister::SlaveID1, alias);
+ deserializer->WriteByte ((uint32_t) DS90UB9x::DS90UB9xDeserializerI2CRegister::SlaveAlias1, alias);
+
+ alias = FlexEepromI2CAddress << 1;
+ deserializer->WriteByte ((uint32_t) DS90UB9x::DS90UB9xDeserializerI2CRegister::SlaveID2, alias);
+ deserializer->WriteByte ((uint32_t) DS90UB9x::DS90UB9xDeserializerI2CRegister::SlaveAlias2, alias);
+
+ serializer = std::make_unique (DS90UB9x::SER_ADDR, deviceIdx, deviceContext);
+ flex = std::make_unique (FlexEepromI2CAddress, deviceIdx, deviceContext);
}
void Neuropixels1e::resetProbe()
{
- auto gpo10Config = DefaultGPO10Config & ~Gpo10ResetMask;
- serializer->WriteByte((uint32_t)DS90UB9x::DS90UB933SerializerI2CRegister::Gpio10, gpo10Config);
- std::this_thread::sleep_for(1ms);
- gpo10Config |= Gpo10ResetMask;
- serializer->WriteByte((uint32_t)DS90UB9x::DS90UB933SerializerI2CRegister::Gpio10, gpo10Config);
+ auto gpo10Config = DefaultGPO10Config & ~Gpo10ResetMask;
+ serializer->WriteByte ((uint32_t) DS90UB9x::DS90UB933SerializerI2CRegister::Gpio10, gpo10Config);
+ std::this_thread::sleep_for (1ms);
+ gpo10Config |= Gpo10ResetMask;
+ serializer->WriteByte ((uint32_t) DS90UB9x::DS90UB933SerializerI2CRegister::Gpio10, gpo10Config);
}
bool Neuropixels1e::updateSettings()
{
- auto updater = NeuropixelsV1eBackgroundUpdater(this);
+ auto updater = NeuropixelsV1eBackgroundUpdater (this);
- return updater.updateSettings() && adcValues.size() == NeuropixelsV1Values::AdcCount;
+ return updater.updateSettings() && adcValues.size() == NeuropixelsV1Values::AdcCount;
}
void Neuropixels1e::startAcquisition()
{
- apGain = getGainValue(getGainEnum(settings[0]->apGainIndex));
- lfpGain = getGainValue(getGainEnum(settings[0]->lfpGainIndex));
-
- apOffsetValues.clear();
- apOffsetValues.reserve(numberOfChannels);
- lfpOffsetValues.clear();
- lfpOffsetValues.reserve(numberOfChannels);
-
- for (int i = 0; i < numberOfChannels; i++)
- {
- apOffsets[i] = 0;
- lfpOffsets[i] = 0;
-
- apOffsetValues.emplace_back(std::vector{});
- lfpOffsetValues.emplace_back(std::vector{});
- }
-
- lfpOffsetCalculated = false;
- apOffsetCalculated = false;
-
- // WONTFIX: Soft reset inside settings.WriteShiftRegisters() above puts probe in reset set that
- // needs to be undone here
- WriteByte((uint32_t)NeuropixelsV1Registers::OP_MODE, (uint32_t)NeuropixelsV1OperationRegisterValues::RECORD);
- WriteByte((uint32_t)NeuropixelsV1Registers::REC_MOD, (uint32_t)NeuropixelsV1RecordRegisterValues::ACTIVE);
-
- if (ledEnabled)
- {
- auto gpo23Config = DefaultGPO32Config & ~Gpo32LedMask;
- serializer->WriteByte((uint32_t)DS90UB9x::DS90UB933SerializerI2CRegister::Gpio32, gpo23Config);
- }
-
- superFrameCount = 0;
- ultraFrameCount = 0;
- apSampleNumber = 0;
- lfpSampleNumber = 0;
+ apGain = getGainValue (getGainEnum (settings[0]->apGainIndex));
+ lfpGain = getGainValue (getGainEnum (settings[0]->lfpGainIndex));
+
+ apOffsetValues.clear();
+ apOffsetValues.reserve (numberOfChannels);
+ lfpOffsetValues.clear();
+ lfpOffsetValues.reserve (numberOfChannels);
+
+ for (int i = 0; i < numberOfChannels; i++)
+ {
+ apOffsets[i] = 0;
+ lfpOffsets[i] = 0;
+
+ apOffsetValues.emplace_back (std::vector {});
+ lfpOffsetValues.emplace_back (std::vector {});
+ }
+
+ lfpOffsetCalculated = false;
+ apOffsetCalculated = false;
+
+ // WONTFIX: Soft reset inside settings.WriteShiftRegisters() above puts probe in reset set that
+ // needs to be undone here
+ WriteByte ((uint32_t) NeuropixelsV1Registers::OP_MODE, (uint32_t) NeuropixelsV1OperationRegisterValues::RECORD);
+ WriteByte ((uint32_t) NeuropixelsV1Registers::REC_MOD, (uint32_t) NeuropixelsV1RecordRegisterValues::ACTIVE);
+
+ if (ledEnabled)
+ {
+ auto gpo23Config = DefaultGPO32Config & ~Gpo32LedMask;
+ serializer->WriteByte ((uint32_t) DS90UB9x::DS90UB933SerializerI2CRegister::Gpio32, gpo23Config);
+ }
+
+ superFrameCount = 0;
+ ultraFrameCount = 0;
+ apSampleNumber = 0;
+ lfpSampleNumber = 0;
}
void Neuropixels1e::stopAcquisition()
{
- serializer->WriteByte((uint32_t)DS90UB9x::DS90UB933SerializerI2CRegister::Gpio10, DefaultGPO10Config);
- serializer->WriteByte((uint32_t)DS90UB9x::DS90UB933SerializerI2CRegister::Gpio32, DefaultGPO32Config);
+ serializer->WriteByte ((uint32_t) DS90UB9x::DS90UB933SerializerI2CRegister::Gpio10, DefaultGPO10Config);
+ serializer->WriteByte ((uint32_t) DS90UB9x::DS90UB933SerializerI2CRegister::Gpio32, DefaultGPO32Config);
- OnixDevice::stopAcquisition();
+ OnixDevice::stopAcquisition();
}
-void Neuropixels1e::addSourceBuffers(OwnedArray& sourceBuffers)
+void Neuropixels1e::addSourceBuffers (OwnedArray& sourceBuffers)
{
- for (StreamInfo streamInfo : streamInfos)
- {
- sourceBuffers.add(new DataBuffer(streamInfo.getNumChannels(), (int)streamInfo.getSampleRate() * bufferSizeInSeconds));
-
- if (streamInfo.getChannelPrefix() == STREAM_NAME_AP)
- apBuffer = sourceBuffers.getLast();
- else if (streamInfo.getChannelPrefix() == STREAM_NAME_LFP)
- lfpBuffer = sourceBuffers.getLast();
- }
+ for (StreamInfo streamInfo : streamInfos)
+ {
+ sourceBuffers.add (new DataBuffer (streamInfo.getNumChannels(), (int) streamInfo.getSampleRate() * bufferSizeInSeconds));
+
+ if (streamInfo.getChannelPrefix() == STREAM_NAME_AP)
+ apBuffer = sourceBuffers.getLast();
+ else if (streamInfo.getChannelPrefix() == STREAM_NAME_LFP)
+ lfpBuffer = sourceBuffers.getLast();
+ }
}
void Neuropixels1e::processFrames()
{
- const float apConversion = (1171.875 / apGain) * -1.0f;
- const float lfpConversion = (1171.875 / lfpGain) * -1.0f;
-
- oni_frame_t* frame;
- while (frameQueue.try_dequeue(frame))
- {
- uint16_t* dataPtr = (uint16_t*)frame->data;
- dataPtr += dataOffset;
-
- apTimestamps[superFrameCount] = deviceContext->convertTimestampToSeconds(frame->time);
- apSampleNumbers[superFrameCount] = apSampleNumber++;
-
- for (size_t i = 0; i < framesPerSuperFrame; i++)
- {
- if (i == 0) // LFP data
- {
- size_t superCountOffset = superFrameCount % superFramesPerUltraFrame;
- if (superCountOffset == 0)
- {
- lfpTimestamps[ultraFrameCount] = apTimestamps[superFrameCount];
- lfpSampleNumbers[ultraFrameCount] = lfpSampleNumber++;
- }
-
- for (int adc = 0; adc < NeuropixelsV1Values::AdcCount; adc++)
- {
- auto sample = *(dataPtr + adcToFrameIndex[adc]);
- sample = sample > adcValues.at(adc).threshold ? sample - adcValues.at(adc).offset : sample;
- lfpSamples[(rawToChannel[adc][superCountOffset] * numUltraFrames) + ultraFrameCount] =
- lfpConversion * (lfpGainCorrection * sample - DataMidpoint) - lfpOffsets.at(rawToChannel[adc][superCountOffset]);
- }
- }
- else // AP data
- {
- for (int adc = 0; adc < NeuropixelsV1Values::AdcCount; adc++)
- {
- auto sample = *(dataPtr + adcToFrameIndex[adc] + i * NeuropixelsV1Values::FrameWordsV1e);
- sample = sample > adcValues.at(adc).threshold ? sample - adcValues.at(adc).offset : sample;
- apSamples[(rawToChannel[adc][i - 1] * superFramesPerUltraFrame * numUltraFrames) + superFrameCount] =
- apConversion * (apGainCorrection * sample - DataMidpoint) - apOffsets.at(rawToChannel[adc][i - 1]);
- }
- }
- }
-
- oni_destroy_frame(frame);
-
- superFrameCount++;
-
- if (superFrameCount % superFramesPerUltraFrame == 0)
- {
- ultraFrameCount++;
- }
-
- if (ultraFrameCount >= numUltraFrames)
- {
- ultraFrameCount = 0;
- superFrameCount = 0;
-
- lfpBuffer->addToBuffer(lfpSamples.data(), lfpSampleNumbers, lfpTimestamps, lfpEventCodes, numUltraFrames);
- apBuffer->addToBuffer(apSamples.data(), apSampleNumbers, apTimestamps, apEventCodes, numUltraFrames * superFramesPerUltraFrame);
-
- if (!lfpOffsetCalculated) updateLfpOffsets(lfpSamples, lfpSampleNumbers[0]);
- if (!apOffsetCalculated) updateApOffsets(apSamples, apSampleNumbers[0]);
- }
- }
+ const float apConversion = (1171.875 / apGain) * -1.0f;
+ const float lfpConversion = (1171.875 / lfpGain) * -1.0f;
+
+ oni_frame_t* frame;
+ while (frameQueue.try_dequeue (frame))
+ {
+ uint16_t* dataPtr = (uint16_t*) frame->data;
+ dataPtr += dataOffset;
+
+ apTimestamps[superFrameCount] = deviceContext->convertTimestampToSeconds (frame->time);
+ apSampleNumbers[superFrameCount] = apSampleNumber++;
+
+ for (size_t i = 0; i < framesPerSuperFrame; i++)
+ {
+ if (i == 0) // LFP data
+ {
+ size_t superCountOffset = superFrameCount % superFramesPerUltraFrame;
+ if (superCountOffset == 0)
+ {
+ lfpTimestamps[ultraFrameCount] = apTimestamps[superFrameCount];
+ lfpSampleNumbers[ultraFrameCount] = lfpSampleNumber++;
+ }
+
+ for (int adc = 0; adc < NeuropixelsV1Values::AdcCount; adc++)
+ {
+ auto sample = *(dataPtr + adcToFrameIndex[adc]);
+ sample = sample > adcValues.at (adc).threshold ? sample - adcValues.at (adc).offset : sample;
+ lfpSamples[(rawToChannel[adc][superCountOffset] * numUltraFrames) + ultraFrameCount] =
+ lfpConversion * (lfpGainCorrection * sample - DataMidpoint) - lfpOffsets.at (rawToChannel[adc][superCountOffset]);
+ }
+ }
+ else // AP data
+ {
+ for (int adc = 0; adc < NeuropixelsV1Values::AdcCount; adc++)
+ {
+ auto sample = *(dataPtr + adcToFrameIndex[adc] + i * NeuropixelsV1Values::FrameWordsV1e);
+ sample = sample > adcValues.at (adc).threshold ? sample - adcValues.at (adc).offset : sample;
+ apSamples[(rawToChannel[adc][i - 1] * superFramesPerUltraFrame * numUltraFrames) + superFrameCount] =
+ apConversion * (apGainCorrection * sample - DataMidpoint) - apOffsets.at (rawToChannel[adc][i - 1]);
+ }
+ }
+ }
+
+ oni_destroy_frame (frame);
+
+ superFrameCount++;
+
+ if (superFrameCount % superFramesPerUltraFrame == 0)
+ {
+ ultraFrameCount++;
+ }
+
+ if (ultraFrameCount >= numUltraFrames)
+ {
+ ultraFrameCount = 0;
+ superFrameCount = 0;
+
+ lfpBuffer->addToBuffer (lfpSamples.data(), lfpSampleNumbers, lfpTimestamps, lfpEventCodes, numUltraFrames);
+ apBuffer->addToBuffer (apSamples.data(), apSampleNumbers, apTimestamps, apEventCodes, numUltraFrames * superFramesPerUltraFrame);
+
+ if (! lfpOffsetCalculated)
+ updateLfpOffsets (lfpSamples, lfpSampleNumbers[0]);
+ if (! apOffsetCalculated)
+ updateApOffsets (apSamples, apSampleNumbers[0]);
+ }
+ }
}
void Neuropixels1e::writeShiftRegisters()
{
- if (adcValues.size() != NeuropixelsV1Values::AdcCount)
- throw error_str("Invalid number of ADC values found.");
-
- auto shankBits = NeuropixelsV1::makeShankBits(getReference(settings[0]->referenceIndex), settings[0]->selectedElectrode);
- auto configBits = NeuropixelsV1::makeConfigBits(getReference(settings[0]->referenceIndex), getGainEnum(settings[0]->apGainIndex), getGainEnum(settings[0]->lfpGainIndex), true, adcValues);
-
- auto shankBytes = toBitReversedBytes(shankBits);
-
- int rc = WriteByte((uint32_t)NeuropixelsV1ShiftRegisters::SR_LENGTH1, (uint32_t)shankBytes.size() % 0x100);
- if (rc != ONI_ESUCCESS)
- throw error_str("Could not set shift register length.");
-
- rc = WriteByte((uint32_t)NeuropixelsV1ShiftRegisters::SR_LENGTH2, (uint32_t)shankBytes.size() / 0x100);
- if (rc != ONI_ESUCCESS)
- throw error_str("Could not set shift register length.");
-
- for (auto b : shankBytes)
- {
- rc = WriteByte((uint32_t)NeuropixelsV1ShiftRegisters::SR_CHAIN1, b);
- if (rc != ONI_ESUCCESS)
- throw error_str("Could not write byte for shift register chain for shank configuration.");
- }
-
- const uint32_t shiftRegisterSuccess = 1 << 7;
-
- for (int i = 0; i < configBits.size(); i++)
- {
- auto srAddress = i == 0 ? (uint32_t)NeuropixelsV1ShiftRegisters::SR_CHAIN2 : (uint32_t)NeuropixelsV1ShiftRegisters::SR_CHAIN3;
-
- for (int j = 0; j < 2; j++)
- {
- // WONTFIX: Without this reset, the ShiftRegisterSuccess check below will always fail
- // on whatever the second shift register write sequence regardless of order or
- // contents. Could be increased current draw during internal process causes MCLK
- // to droop and mess up internal state. Or that MCLK is just not good enough to
- // prevent metastability in some logic in the ASIC that is only entered in between
- // SR accesses.
- WriteByte((uint32_t)NeuropixelsV1ShiftRegisters::SOFT_RESET, 0xFF);
- WriteByte((uint32_t)NeuropixelsV1ShiftRegisters::SOFT_RESET, 0x00);
-
- auto baseBytes = toBitReversedBytes(configBits[i]);
-
- rc = WriteByte((uint32_t)NeuropixelsV1ShiftRegisters::SR_LENGTH1, (uint32_t)baseBytes.size() % 0x100);
- if (rc != ONI_ESUCCESS)
- throw error_str("Could not set shift register length.");
-
- rc = WriteByte((uint32_t)NeuropixelsV1ShiftRegisters::SR_LENGTH2, (uint32_t)baseBytes.size() / 0x100);
- if (rc != ONI_ESUCCESS)
- throw error_str("Could not set shift register length.");
-
- for (auto b : baseBytes)
- {
- rc = WriteByte(srAddress, b);
- if (rc != ONI_ESUCCESS)
- throw error_str("Could not set write byte to shift register for base configuration.");
- }
- }
-
- oni_reg_val_t value;
- rc = ReadByte((uint32_t)NeuropixelsV1Registers::STATUS, &value);
-
- if (rc != ONI_ESUCCESS || value != shiftRegisterSuccess)
- {
- LOGE("Shift register ", srAddress, " status check failed.");
- return;
- }
- }
+ if (adcValues.size() != NeuropixelsV1Values::AdcCount)
+ throw error_str ("Invalid number of ADC values found.");
+
+ auto shankBits = NeuropixelsV1::makeShankBits (getReference (settings[0]->referenceIndex), settings[0]->selectedElectrode);
+ auto configBits = NeuropixelsV1::makeConfigBits (getReference (settings[0]->referenceIndex), getGainEnum (settings[0]->apGainIndex), getGainEnum (settings[0]->lfpGainIndex), true, adcValues);
+
+ auto shankBytes = toBitReversedBytes (shankBits);
+
+ int rc = WriteByte ((uint32_t) NeuropixelsV1ShiftRegisters::SR_LENGTH1, (uint32_t) shankBytes.size() % 0x100);
+ if (rc != ONI_ESUCCESS)
+ throw error_str ("Could not set shift register length.");
+
+ rc = WriteByte ((uint32_t) NeuropixelsV1ShiftRegisters::SR_LENGTH2, (uint32_t) shankBytes.size() / 0x100);
+ if (rc != ONI_ESUCCESS)
+ throw error_str ("Could not set shift register length.");
+
+ for (auto b : shankBytes)
+ {
+ rc = WriteByte ((uint32_t) NeuropixelsV1ShiftRegisters::SR_CHAIN1, b);
+ if (rc != ONI_ESUCCESS)
+ throw error_str ("Could not write byte for shift register chain for shank configuration.");
+ }
+
+ const uint32_t shiftRegisterSuccess = 1 << 7;
+
+ for (int i = 0; i < configBits.size(); i++)
+ {
+ auto srAddress = i == 0 ? (uint32_t) NeuropixelsV1ShiftRegisters::SR_CHAIN2 : (uint32_t) NeuropixelsV1ShiftRegisters::SR_CHAIN3;
+
+ for (int j = 0; j < 2; j++)
+ {
+ // WONTFIX: Without this reset, the ShiftRegisterSuccess check below will always fail
+ // on whatever the second shift register write sequence regardless of order or
+ // contents. Could be increased current draw during internal process causes MCLK
+ // to droop and mess up internal state. Or that MCLK is just not good enough to
+ // prevent metastability in some logic in the ASIC that is only entered in between
+ // SR accesses.
+ WriteByte ((uint32_t) NeuropixelsV1ShiftRegisters::SOFT_RESET, 0xFF);
+ WriteByte ((uint32_t) NeuropixelsV1ShiftRegisters::SOFT_RESET, 0x00);
+
+ auto baseBytes = toBitReversedBytes (configBits[i]);
+
+ rc = WriteByte ((uint32_t) NeuropixelsV1ShiftRegisters::SR_LENGTH1, (uint32_t) baseBytes.size() % 0x100);
+ if (rc != ONI_ESUCCESS)
+ throw error_str ("Could not set shift register length.");
+
+ rc = WriteByte ((uint32_t) NeuropixelsV1ShiftRegisters::SR_LENGTH2, (uint32_t) baseBytes.size() / 0x100);
+ if (rc != ONI_ESUCCESS)
+ throw error_str ("Could not set shift register length.");
+
+ for (auto b : baseBytes)
+ {
+ rc = WriteByte (srAddress, b);
+ if (rc != ONI_ESUCCESS)
+ throw error_str ("Could not set write byte to shift register for base configuration.");
+ }
+ }
+
+ oni_reg_val_t value;
+ rc = ReadByte ((uint32_t) NeuropixelsV1Registers::STATUS, &value);
+
+ if (rc != ONI_ESUCCESS || value != shiftRegisterSuccess)
+ {
+ LOGE ("Shift register ", srAddress, " status check failed.");
+ return;
+ }
+ }
}
diff --git a/Source/Devices/Neuropixels1e.h b/Source/Devices/Neuropixels1e.h
index 8641b5b..b33146d 100644
--- a/Source/Devices/Neuropixels1e.h
+++ b/Source/Devices/Neuropixels1e.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 .
*/
@@ -26,123 +26,146 @@
namespace OnixSourcePlugin
{
- /**
- Configures and streams data from a Neuropixels 1.0e device
- */
- class Neuropixels1e : public Neuropixels1
- {
- public:
- friend class NeuropixelsV1eBackgroundUpdater;
-
- Neuropixels1e(std::string, std::string, const oni_dev_idx_t, std::shared_ptr);
-
- int configureDevice() override;
- bool updateSettings() override;
- void startAcquisition() override;
- void stopAcquisition() override;
- void addSourceBuffers(OwnedArray& sourceBuffers) override;
- void processFrames() override;
-
- void configureSerDes();
-
- static OnixDeviceType getDeviceType();
-
- private:
-
- static constexpr char* STREAM_NAME_AP = "AP";
- static constexpr char* STREAM_NAME_LFP = "LFP";
-
- static constexpr int FlexEepromI2CAddress = 0x50;
-
- static constexpr uint32_t OFFSET_ID = 0;
- static constexpr uint32_t OFFSET_VERSION = 10;
- static constexpr uint32_t OFFSET_REVISION = 11;
- static constexpr uint32_t OFFSET_FLEXPN = 20;
- static constexpr uint32_t OFFSET_PROBEPN = 40;
-
- static constexpr uint8_t DefaultGPO10Config = 0b00010001; // GPIO0 Low, NP in MUX reset
- static constexpr uint8_t DefaultGPO32Config = 0b10010001; // LED off, GPIO1 Low
- static constexpr uint32_t Gpo10ResetMask = 1 << 3; // Used to issue mux reset command to probe
- static constexpr uint32_t Gpo32LedMask = 1 << 7; // Used to turn on and off LED
-
- std::unique_ptr deserializer;
- std::unique_ptr serializer;
- std::unique_ptr flex;
-
- void resetProbe();
- void writeShiftRegisters();
-
- bool ledEnabled = true;
-
- // ADC to frame index
- // Input: ADC index
- // Output: index of ADC's data within a frame
- static constexpr std::array adcToFrameIndex = {
- 1, 9 , 17, 25, 33,
- 2, 10, 18, 26, 34,
- 3, 11, 19, 27, 35,
- 4, 12, 20, 28, 36,
- 5, 13, 21, 29, 37,
- 6, 14, 22, 30, 38,
- 7, 15
- };
-
- // ADC to channel
- // First dimension: ADC index
- // Second dimension: frame index within super frame
- // Output: channel number
- static constexpr std::array, NeuropixelsV1Values::AdcCount> rawToChannel = { {
- {0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22 },
- {1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23 },
- {24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46 },
- {25, 27, 29, 31, 33, 35, 37, 39, 41, 43, 45, 47 },
- {48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70 },
- {49, 51, 53, 55, 57, 59, 61, 63, 65, 67, 69, 71 },
- {72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94 },
- {73, 75, 77, 79, 81, 83, 85, 87, 89, 91, 93, 95 },
- {96, 98, 100, 102, 104, 106, 108, 110, 112, 114, 116, 118 },
- {97, 99, 101, 103, 105, 107, 109, 111, 113, 115, 117, 119 },
- {120, 122, 124, 126, 128, 130, 132, 134, 136, 138, 140, 142 },
- {121, 123, 125, 127, 129, 131, 133, 135, 137, 139, 141, 143 },
- {144, 146, 148, 150, 152, 154, 156, 158, 160, 162, 164, 166 },
- {145, 147, 149, 151, 153, 155, 157, 159, 161, 163, 165, 167 },
- {168, 170, 172, 174, 176, 178, 180, 182, 184, 186, 188, 190 },
- {169, 171, 173, 175, 177, 179, 181, 183, 185, 187, 189, 191 },
- {192, 194, 196, 198, 200, 202, 204, 206, 208, 210, 212, 214 },
- {193, 195, 197, 199, 201, 203, 205, 207, 209, 211, 213, 215 },
- {216, 218, 220, 222, 224, 226, 228, 230, 232, 234, 236, 238 },
- {217, 219, 221, 223, 225, 227, 229, 231, 233, 235, 237, 239 },
- {240, 242, 244, 246, 248, 250, 252, 254, 256, 258, 260, 262 },
- {241, 243, 245, 247, 249, 251, 253, 255, 257, 259, 261, 263 },
- {264, 266, 268, 270, 272, 274, 276, 278, 280, 282, 284, 286 },
- {265, 267, 269, 271, 273, 275, 277, 279, 281, 283, 285, 287 },
- {288, 290, 292, 294, 296, 298, 300, 302, 304, 306, 308, 310 },
- {289, 291, 293, 295, 297, 299, 301, 303, 305, 307, 309, 311 },
- {312, 314, 316, 318, 320, 322, 324, 326, 328, 330, 332, 334 },
- {313, 315, 317, 319, 321, 323, 325, 327, 329, 331, 333, 335 },
- {336, 338, 340, 342, 344, 346, 348, 350, 352, 354, 356, 358 },
- {337, 339, 341, 343, 345, 347, 349, 351, 353, 355, 357, 359 },
- {360, 362, 364, 366, 368, 370, 372, 374, 376, 378, 380, 382 },
- {361, 363, 365, 367, 369, 371, 373, 375, 377, 379, 381, 383 }
- } };
-
- JUCE_LEAK_DETECTOR(Neuropixels1e);
- };
-
- /*
-
- A thread that updates probe settings in the background and shows a progress bar
-
- */
- class NeuropixelsV1eBackgroundUpdater : public NeuropixelsV1BackgroundUpdater
- {
- public:
- NeuropixelsV1eBackgroundUpdater(Neuropixels1e* d);
-
- void run() override;
-
- private:
-
- JUCE_LEAK_DETECTOR(NeuropixelsV1eBackgroundUpdater);
- };
-}
+/**
+ Configures and streams data from a Neuropixels 1.0e device
+*/
+class Neuropixels1e : public Neuropixels1
+{
+public:
+ friend class NeuropixelsV1eBackgroundUpdater;
+
+ Neuropixels1e (std::string, std::string, const oni_dev_idx_t, std::shared_ptr);
+
+ int configureDevice() override;
+ bool updateSettings() override;
+ void startAcquisition() override;
+ void stopAcquisition() override;
+ void addSourceBuffers (OwnedArray& sourceBuffers) override;
+ void processFrames() override;
+
+ void configureSerDes();
+
+ static OnixDeviceType getDeviceType();
+
+private:
+ static constexpr char* STREAM_NAME_AP = "AP";
+ static constexpr char* STREAM_NAME_LFP = "LFP";
+
+ static constexpr int FlexEepromI2CAddress = 0x50;
+
+ static constexpr uint32_t OFFSET_ID = 0;
+ static constexpr uint32_t OFFSET_VERSION = 10;
+ static constexpr uint32_t OFFSET_REVISION = 11;
+ static constexpr uint32_t OFFSET_FLEXPN = 20;
+ static constexpr uint32_t OFFSET_PROBEPN = 40;
+
+ static constexpr uint8_t DefaultGPO10Config = 0b00010001; // GPIO0 Low, NP in MUX reset
+ static constexpr uint8_t DefaultGPO32Config = 0b10010001; // LED off, GPIO1 Low
+ static constexpr uint32_t Gpo10ResetMask = 1 << 3; // Used to issue mux reset command to probe
+ static constexpr uint32_t Gpo32LedMask = 1 << 7; // Used to turn on and off LED
+
+ std::unique_ptr deserializer;
+ std::unique_ptr serializer;
+ std::unique_ptr flex;
+
+ void resetProbe();
+ void writeShiftRegisters();
+
+ bool ledEnabled = true;
+
+ // ADC to frame index
+ // Input: ADC index
+ // Output: index of ADC's data within a frame
+ static constexpr std::array adcToFrameIndex = {
+ 1,
+ 9,
+ 17,
+ 25,
+ 33,
+ 2,
+ 10,
+ 18,
+ 26,
+ 34,
+ 3,
+ 11,
+ 19,
+ 27,
+ 35,
+ 4,
+ 12,
+ 20,
+ 28,
+ 36,
+ 5,
+ 13,
+ 21,
+ 29,
+ 37,
+ 6,
+ 14,
+ 22,
+ 30,
+ 38,
+ 7,
+ 15
+ };
+
+ // ADC to channel
+ // First dimension: ADC index
+ // Second dimension: frame index within super frame
+ // Output: channel number
+ static constexpr std::array, NeuropixelsV1Values::AdcCount> rawToChannel = {
+ { { 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22 },
+ { 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23 },
+ { 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46 },
+ { 25, 27, 29, 31, 33, 35, 37, 39, 41, 43, 45, 47 },
+ { 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70 },
+ { 49, 51, 53, 55, 57, 59, 61, 63, 65, 67, 69, 71 },
+ { 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94 },
+ { 73, 75, 77, 79, 81, 83, 85, 87, 89, 91, 93, 95 },
+ { 96, 98, 100, 102, 104, 106, 108, 110, 112, 114, 116, 118 },
+ { 97, 99, 101, 103, 105, 107, 109, 111, 113, 115, 117, 119 },
+ { 120, 122, 124, 126, 128, 130, 132, 134, 136, 138, 140, 142 },
+ { 121, 123, 125, 127, 129, 131, 133, 135, 137, 139, 141, 143 },
+ { 144, 146, 148, 150, 152, 154, 156, 158, 160, 162, 164, 166 },
+ { 145, 147, 149, 151, 153, 155, 157, 159, 161, 163, 165, 167 },
+ { 168, 170, 172, 174, 176, 178, 180, 182, 184, 186, 188, 190 },
+ { 169, 171, 173, 175, 177, 179, 181, 183, 185, 187, 189, 191 },
+ { 192, 194, 196, 198, 200, 202, 204, 206, 208, 210, 212, 214 },
+ { 193, 195, 197, 199, 201, 203, 205, 207, 209, 211, 213, 215 },
+ { 216, 218, 220, 222, 224, 226, 228, 230, 232, 234, 236, 238 },
+ { 217, 219, 221, 223, 225, 227, 229, 231, 233, 235, 237, 239 },
+ { 240, 242, 244, 246, 248, 250, 252, 254, 256, 258, 260, 262 },
+ { 241, 243, 245, 247, 249, 251, 253, 255, 257, 259, 261, 263 },
+ { 264, 266, 268, 270, 272, 274, 276, 278, 280, 282, 284, 286 },
+ { 265, 267, 269, 271, 273, 275, 277, 279, 281, 283, 285, 287 },
+ { 288, 290, 292, 294, 296, 298, 300, 302, 304, 306, 308, 310 },
+ { 289, 291, 293, 295, 297, 299, 301, 303, 305, 307, 309, 311 },
+ { 312, 314, 316, 318, 320, 322, 324, 326, 328, 330, 332, 334 },
+ { 313, 315, 317, 319, 321, 323, 325, 327, 329, 331, 333, 335 },
+ { 336, 338, 340, 342, 344, 346, 348, 350, 352, 354, 356, 358 },
+ { 337, 339, 341, 343, 345, 347, 349, 351, 353, 355, 357, 359 },
+ { 360, 362, 364, 366, 368, 370, 372, 374, 376, 378, 380, 382 },
+ { 361, 363, 365, 367, 369, 371, 373, 375, 377, 379, 381, 383 } }
+ };
+
+ JUCE_LEAK_DETECTOR (Neuropixels1e);
+};
+
+/*
+
+ A thread that updates probe settings in the background and shows a progress bar
+
+*/
+class NeuropixelsV1eBackgroundUpdater : public NeuropixelsV1BackgroundUpdater
+{
+public:
+ NeuropixelsV1eBackgroundUpdater (Neuropixels1e* d);
+
+ void run() override;
+
+private:
+ JUCE_LEAK_DETECTOR (NeuropixelsV1eBackgroundUpdater);
+};
+} // namespace OnixSourcePlugin
diff --git a/Source/Devices/Neuropixels1f.cpp b/Source/Devices/Neuropixels1f.cpp
index 7253338..e7e77cd 100644
--- a/Source/Devices/Neuropixels1f.cpp
+++ b/Source/Devices/Neuropixels1f.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,374 +24,384 @@
using namespace OnixSourcePlugin;
-NeuropixelsV1fBackgroundUpdater::NeuropixelsV1fBackgroundUpdater(Neuropixels1f* d)
- : NeuropixelsV1BackgroundUpdater(d)
+NeuropixelsV1fBackgroundUpdater::NeuropixelsV1fBackgroundUpdater (Neuropixels1f* d)
+ : NeuropixelsV1BackgroundUpdater (d)
{
}
void NeuropixelsV1fBackgroundUpdater::run()
{
- setProgress(0);
-
- if (!device->parseGainCalibrationFile())
- {
- result = false;
- return;
- }
-
- if (!device->parseAdcCalibrationFile())
- {
- result = false;
- return;
- }
-
- setProgress(0.5);
-
- try
- {
- ((Neuropixels1f*)device)->writeShiftRegisters();
- }
- catch (const error_str& e)
- {
- Onix1::showWarningMessageBoxAsync("Error Writing Shift Registers", e.what());
- result = false;
- return;
- }
-
- setProgress(1);
-
- result = true;
+ setProgress (0);
+
+ if (! device->parseGainCalibrationFile())
+ {
+ result = false;
+ return;
+ }
+
+ if (! device->parseAdcCalibrationFile())
+ {
+ result = false;
+ return;
+ }
+
+ setProgress (0.5);
+
+ try
+ {
+ ((Neuropixels1f*) device)->writeShiftRegisters();
+ }
+ catch (const error_str& e)
+ {
+ Onix1::showWarningMessageBoxAsync ("Error Writing Shift Registers", e.what());
+ result = false;
+ return;
+ }
+
+ setProgress (1);
+
+ result = true;
}
-Neuropixels1f::Neuropixels1f(std::string name, std::string hubName, const oni_dev_idx_t deviceIdx_, std::shared_ptr ctx_) :
- Neuropixels1(name, hubName, OnixDeviceType::NEUROPIXELSV1F, deviceIdx_, ctx_)
+Neuropixels1f::Neuropixels1f (std::string name, std::string hubName, const oni_dev_idx_t deviceIdx_, std::shared_ptr ctx_)
+ : Neuropixels1 (name, hubName, OnixDeviceType::NEUROPIXELSV1F, deviceIdx_, ctx_)
{
- std::string port = getPortName(deviceIdx);
- StreamInfo apStream = StreamInfo(
- OnixDevice::createStreamName({ port, getHubName(), getName(), STREAM_NAME_AP }),
- "Neuropixels 1.0 AP band data stream",
- getStreamIdentifier(),
- numberOfChannels,
- apSampleRate,
- STREAM_NAME_AP,
- ContinuousChannel::Type::ELECTRODE,
- 0.195f,
- "uV",
- {},
- "ap"
- );
- streamInfos.add(apStream);
-
- StreamInfo lfpStream = StreamInfo(
- OnixDevice::createStreamName({ port, getHubName(), getName(), STREAM_NAME_LFP }),
- "Neuropixels 1.0 LFP band data stream",
- getStreamIdentifier(),
- numberOfChannels,
- lfpSampleRate,
- STREAM_NAME_LFP,
- ContinuousChannel::Type::ELECTRODE,
- 0.195f,
- "uV",
- {},
- "lfp"
- );
- streamInfos.add(lfpStream);
-
- defineMetadata(settings[0].get());
-
- adcCalibrationFilePath = "None";
- gainCalibrationFilePath = "None";
-
- for (int i = 0; i < numUltraFrames; i++)
- {
- apEventCodes[i] = 0;
- lfpEventCodes[i] = 0;
- }
-
- probeNumber = 0;
+ std::string port = getPortName (deviceIdx);
+ StreamInfo apStream = StreamInfo (
+ OnixDevice::createStreamName ({ port, getHubName(), getName(), STREAM_NAME_AP }),
+ "Neuropixels 1.0 AP band data stream",
+ getStreamIdentifier(),
+ numberOfChannels,
+ apSampleRate,
+ STREAM_NAME_AP,
+ ContinuousChannel::Type::ELECTRODE,
+ 0.195f,
+ "uV",
+ {},
+ "ap");
+ streamInfos.add (apStream);
+
+ StreamInfo lfpStream = StreamInfo (
+ OnixDevice::createStreamName ({ port, getHubName(), getName(), STREAM_NAME_LFP }),
+ "Neuropixels 1.0 LFP band data stream",
+ getStreamIdentifier(),
+ numberOfChannels,
+ lfpSampleRate,
+ STREAM_NAME_LFP,
+ ContinuousChannel::Type::ELECTRODE,
+ 0.195f,
+ "uV",
+ {},
+ "lfp");
+ streamInfos.add (lfpStream);
+
+ defineMetadata (settings[0].get());
+
+ adcCalibrationFilePath = "None";
+ gainCalibrationFilePath = "None";
+
+ for (int i = 0; i < numUltraFrames; i++)
+ {
+ apEventCodes[i] = 0;
+ lfpEventCodes[i] = 0;
+ }
+
+ probeNumber = 0;
}
int Neuropixels1f::configureDevice()
{
- if (deviceContext == nullptr || !deviceContext->isInitialized())
- throw error_str("Device context is not initialized properly for " + getName());
-
- int rc = deviceContext->writeRegister(deviceIdx, ENABLE, isEnabled() ? 1 : 0);
- if (rc != ONI_ESUCCESS)
- throw error_str("Unable to enable " + getName());
-
- if (!isEnabled())
- {
- return ONI_ESUCCESS;
- }
-
- // Get Probe SN
- uint32_t eepromOffset = 0;
- uint32_t i2cAddr = 0x50;
- int errorCode = 0;
-
- for (int i = 0; i < 8; i++)
- {
- oni_reg_addr_t reg_addr = ((eepromOffset + i) << 7) | i2cAddr;
-
- oni_reg_val_t reg_val;
- rc = deviceContext->readRegister(deviceIdx, reg_addr, ®_val);
-
- if (rc != ONI_ESUCCESS)
- {
- LOGE(oni_error_str(rc));
- throw error_str("Could not communicate with " + getName() + " on " + getHubName() + ". Ensure that the flex connection is properly seated, or disable the device if it is not connected.");
- }
-
- if (reg_val <= 0xFF)
- {
- probeNumber |= (((uint64_t)reg_val) << (i * 8));
- }
- }
-
- LOGD("Probe SN: ", probeNumber);
-
- // Enable device streaming
- rc = deviceContext->writeRegister(deviceIdx, 0x8000, 1);
- if (rc != ONI_ESUCCESS)
- throw error_str("Unable to activate streaming for device at address " + std::to_string(deviceIdx));
-
- rc = WriteByte((uint32_t)NeuropixelsV1Registers::CAL_MOD, (uint32_t)NeuropixelsV1CalibrationRegisterValues::CAL_OFF);
- if (rc != ONI_ESUCCESS)
- throw error_str("Error configuring device at address " + std::to_string(deviceIdx));
-
- rc = WriteByte((uint32_t)NeuropixelsV1Registers::SYNC, (uint32_t)0);
- if (rc != ONI_ESUCCESS)
- throw error_str("Error configuring device at address " + std::to_string(deviceIdx));
-
- rc = WriteByte((uint32_t)NeuropixelsV1Registers::REC_MOD, (uint32_t)NeuropixelsV1RecordRegisterValues::DIG_CH_RESET);
- if (rc != ONI_ESUCCESS)
- throw error_str("Error configuring device at address " + std::to_string(deviceIdx));
-
- rc = WriteByte((uint32_t)NeuropixelsV1Registers::OP_MODE, (uint32_t)NeuropixelsV1OperationRegisterValues::RECORD);
- if (rc != ONI_ESUCCESS)
- throw error_str("Error configuring device at address " + std::to_string(deviceIdx));
-
- return rc;
+ if (deviceContext == nullptr || ! deviceContext->isInitialized())
+ throw error_str ("Device context is not initialized properly for " + getName());
+
+ int rc = deviceContext->writeRegister (deviceIdx, ENABLE, isEnabled() ? 1 : 0);
+ if (rc != ONI_ESUCCESS)
+ throw error_str ("Unable to enable " + getName());
+
+ if (! isEnabled())
+ {
+ return ONI_ESUCCESS;
+ }
+
+ // Get Probe SN
+ uint32_t eepromOffset = 0;
+ uint32_t i2cAddr = 0x50;
+ int errorCode = 0;
+
+ for (int i = 0; i < 8; i++)
+ {
+ oni_reg_addr_t reg_addr = ((eepromOffset + i) << 7) | i2cAddr;
+
+ oni_reg_val_t reg_val;
+ rc = deviceContext->readRegister (deviceIdx, reg_addr, ®_val);
+
+ if (rc != ONI_ESUCCESS)
+ {
+ LOGE (oni_error_str (rc));
+ throw error_str ("Could not communicate with " + getName() + " on " + getHubName()
+ + ". Ensure that the flex connection is properly seated, or disable the device if it is not connected.");
+ }
+
+ if (reg_val <= 0xFF)
+ {
+ probeNumber |= (((uint64_t) reg_val) << (i * 8));
+ }
+ }
+
+ LOGD ("Probe SN: ", probeNumber);
+
+ // Enable device streaming
+ rc = deviceContext->writeRegister (deviceIdx, 0x8000, 1);
+ if (rc != ONI_ESUCCESS)
+ throw error_str ("Unable to activate streaming for device at address " + std::to_string (deviceIdx));
+
+ rc = WriteByte ((uint32_t) NeuropixelsV1Registers::CAL_MOD, (uint32_t) NeuropixelsV1CalibrationRegisterValues::CAL_OFF);
+ if (rc != ONI_ESUCCESS)
+ throw error_str ("Error configuring device at address " + std::to_string (deviceIdx));
+
+ rc = WriteByte ((uint32_t) NeuropixelsV1Registers::SYNC, (uint32_t) 0);
+ if (rc != ONI_ESUCCESS)
+ throw error_str ("Error configuring device at address " + std::to_string (deviceIdx));
+
+ rc = WriteByte ((uint32_t) NeuropixelsV1Registers::REC_MOD, (uint32_t) NeuropixelsV1RecordRegisterValues::DIG_CH_RESET);
+ if (rc != ONI_ESUCCESS)
+ throw error_str ("Error configuring device at address " + std::to_string (deviceIdx));
+
+ rc = WriteByte ((uint32_t) NeuropixelsV1Registers::OP_MODE, (uint32_t) NeuropixelsV1OperationRegisterValues::RECORD);
+ if (rc != ONI_ESUCCESS)
+ throw error_str ("Error configuring device at address " + std::to_string (deviceIdx));
+
+ return rc;
}
bool Neuropixels1f::updateSettings()
{
- auto updater = NeuropixelsV1fBackgroundUpdater(this);
+ auto updater = NeuropixelsV1fBackgroundUpdater (this);
- return updater.updateSettings() && adcValues.size() == NeuropixelsV1Values::AdcCount;
+ return updater.updateSettings() && adcValues.size() == NeuropixelsV1Values::AdcCount;
}
OnixDeviceType Neuropixels1f::getDeviceType()
{
- return OnixDeviceType::NEUROPIXELSV1F;
+ return OnixDeviceType::NEUROPIXELSV1F;
}
void Neuropixels1f::startAcquisition()
{
- apGain = getGainValue(getGainEnum(settings[0]->apGainIndex));
- lfpGain = getGainValue(getGainEnum(settings[0]->lfpGainIndex));
+ apGain = getGainValue (getGainEnum (settings[0]->apGainIndex));
+ lfpGain = getGainValue (getGainEnum (settings[0]->lfpGainIndex));
- apOffsetValues.clear();
- apOffsetValues.reserve(numberOfChannels);
- lfpOffsetValues.clear();
- lfpOffsetValues.reserve(numberOfChannels);
+ apOffsetValues.clear();
+ apOffsetValues.reserve (numberOfChannels);
+ lfpOffsetValues.clear();
+ lfpOffsetValues.reserve (numberOfChannels);
- for (int i = 0; i < numberOfChannels; i++)
- {
- apOffsets[i] = 0;
- lfpOffsets[i] = 0;
+ for (int i = 0; i < numberOfChannels; i++)
+ {
+ apOffsets[i] = 0;
+ lfpOffsets[i] = 0;
- apOffsetValues.emplace_back(std::vector{});
- lfpOffsetValues.emplace_back(std::vector{});
- }
+ apOffsetValues.emplace_back (std::vector {});
+ lfpOffsetValues.emplace_back (std::vector {});
+ }
- lfpOffsetCalculated = false;
- apOffsetCalculated = false;
+ lfpOffsetCalculated = false;
+ apOffsetCalculated = false;
- WriteByte((uint32_t)NeuropixelsV1Registers::REC_MOD, (uint32_t)NeuropixelsV1RecordRegisterValues::ACTIVE);
+ WriteByte ((uint32_t) NeuropixelsV1Registers::REC_MOD, (uint32_t) NeuropixelsV1RecordRegisterValues::ACTIVE);
- superFrameCount = 0;
- ultraFrameCount = 0;
- apSampleNumber = 0;
- lfpSampleNumber = 0;
+ superFrameCount = 0;
+ ultraFrameCount = 0;
+ apSampleNumber = 0;
+ lfpSampleNumber = 0;
}
void Neuropixels1f::stopAcquisition()
{
- WriteByte((uint32_t)NeuropixelsV1Registers::REC_MOD, (uint32_t)NeuropixelsV1RecordRegisterValues::RESET_ALL);
+ WriteByte ((uint32_t) NeuropixelsV1Registers::REC_MOD, (uint32_t) NeuropixelsV1RecordRegisterValues::RESET_ALL);
- OnixDevice::stopAcquisition();
+ OnixDevice::stopAcquisition();
}
-void Neuropixels1f::addSourceBuffers(OwnedArray& sourceBuffers)
+void Neuropixels1f::addSourceBuffers (OwnedArray& sourceBuffers)
{
- for (StreamInfo streamInfo : streamInfos)
- {
- sourceBuffers.add(new DataBuffer(streamInfo.getNumChannels(), (int)streamInfo.getSampleRate() * bufferSizeInSeconds));
-
- if (streamInfo.getChannelPrefix() == STREAM_NAME_AP)
- apBuffer = sourceBuffers.getLast();
- else if (streamInfo.getChannelPrefix() == STREAM_NAME_LFP)
- lfpBuffer = sourceBuffers.getLast();
- }
+ for (StreamInfo streamInfo : streamInfos)
+ {
+ sourceBuffers.add (new DataBuffer (streamInfo.getNumChannels(), (int) streamInfo.getSampleRate() * bufferSizeInSeconds));
+
+ if (streamInfo.getChannelPrefix() == STREAM_NAME_AP)
+ apBuffer = sourceBuffers.getLast();
+ else if (streamInfo.getChannelPrefix() == STREAM_NAME_LFP)
+ lfpBuffer = sourceBuffers.getLast();
+ }
}
void Neuropixels1f::processFrames()
{
- const float apConversion = (1171.875 / apGain) * -1.0f;
- const float lfpConversion = (1171.875 / lfpGain) * -1.0f;
-
- oni_frame_t* frame;
- while (frameQueue.try_dequeue(frame))
- {
- uint16_t* dataPtr = (uint16_t*)frame->data;
-
- apTimestamps[superFrameCount] = deviceContext->convertTimestampToSeconds(frame->time);
- apSampleNumbers[superFrameCount] = apSampleNumber++;
-
- for (int i = 0; i < framesPerSuperFrame; i++)
- {
- if (i == 0) // LFP data
- {
- size_t superCountOffset = superFrameCount % superFramesPerUltraFrame;
- if (superCountOffset == 0)
- {
- lfpTimestamps[ultraFrameCount] = apTimestamps[superFrameCount];
- lfpSampleNumbers[ultraFrameCount] = lfpSampleNumber++;
- }
-
- for (int adc = 0; adc < NeuropixelsV1Values::AdcCount; adc++)
- {
- size_t chanIndex = adcToChannel[adc] + superCountOffset * 2;
- lfpSamples[(chanIndex * numUltraFrames) + ultraFrameCount] =
- lfpConversion * (float(*(dataPtr + adcToFrameIndex[adc]) >> 5) - DataMidpoint) - lfpOffsets.at(chanIndex);
- }
- }
- else // AP data
- {
- int chanOffset = 2 * (i - 1);
- for (int adc = 0; adc < NeuropixelsV1Values::AdcCount; adc++)
- {
- size_t chanIndex = adcToChannel[adc] + chanOffset;
- apSamples[(chanIndex * superFramesPerUltraFrame * numUltraFrames) + superFrameCount] =
- apConversion * (float(*(dataPtr + adcToFrameIndex[adc] + i * NeuropixelsV1Values::FrameWordsV1f) >> 5) - DataMidpoint) - apOffsets.at(chanIndex);
- }
- }
- }
-
- oni_destroy_frame(frame);
-
- superFrameCount++;
-
- if (superFrameCount % superFramesPerUltraFrame == 0)
- {
- ultraFrameCount++;
- }
-
- if (ultraFrameCount >= numUltraFrames)
- {
- ultraFrameCount = 0;
- superFrameCount = 0;
-
- lfpBuffer->addToBuffer(lfpSamples.data(), lfpSampleNumbers, lfpTimestamps, lfpEventCodes, numUltraFrames);
- apBuffer->addToBuffer(apSamples.data(), apSampleNumbers, apTimestamps, apEventCodes, numUltraFrames * superFramesPerUltraFrame);
-
- if (!lfpOffsetCalculated) updateLfpOffsets(lfpSamples, lfpSampleNumbers[0]);
- if (!apOffsetCalculated) updateApOffsets(apSamples, apSampleNumbers[0]);
- }
- }
+ const float apConversion = (1171.875 / apGain) * -1.0f;
+ const float lfpConversion = (1171.875 / lfpGain) * -1.0f;
+
+ oni_frame_t* frame;
+ while (frameQueue.try_dequeue (frame))
+ {
+ uint16_t* dataPtr = (uint16_t*) frame->data;
+
+ apTimestamps[superFrameCount] = deviceContext->convertTimestampToSeconds (frame->time);
+ apSampleNumbers[superFrameCount] = apSampleNumber++;
+
+ for (int i = 0; i < framesPerSuperFrame; i++)
+ {
+ if (i == 0) // LFP data
+ {
+ size_t superCountOffset = superFrameCount % superFramesPerUltraFrame;
+ if (superCountOffset == 0)
+ {
+ lfpTimestamps[ultraFrameCount] = apTimestamps[superFrameCount];
+ lfpSampleNumbers[ultraFrameCount] = lfpSampleNumber++;
+ }
+
+ for (int adc = 0; adc < NeuropixelsV1Values::AdcCount; adc++)
+ {
+ size_t chanIndex = adcToChannel[adc] + superCountOffset * 2;
+ lfpSamples[(chanIndex * numUltraFrames) + ultraFrameCount] =
+ lfpConversion * (float (*(dataPtr + adcToFrameIndex[adc]) >> 5) - DataMidpoint) - lfpOffsets.at (chanIndex);
+ }
+ }
+ else // AP data
+ {
+ int chanOffset = 2 * (i - 1);
+ for (int adc = 0; adc < NeuropixelsV1Values::AdcCount; adc++)
+ {
+ size_t chanIndex = adcToChannel[adc] + chanOffset;
+ apSamples[(chanIndex * superFramesPerUltraFrame * numUltraFrames) + superFrameCount] =
+ apConversion * (float (*(dataPtr + adcToFrameIndex[adc] + i * NeuropixelsV1Values::FrameWordsV1f) >> 5) - DataMidpoint) - apOffsets.at (chanIndex);
+ }
+ }
+ }
+
+ oni_destroy_frame (frame);
+
+ superFrameCount++;
+
+ if (superFrameCount % superFramesPerUltraFrame == 0)
+ {
+ ultraFrameCount++;
+ }
+
+ if (ultraFrameCount >= numUltraFrames)
+ {
+ ultraFrameCount = 0;
+ superFrameCount = 0;
+
+ lfpBuffer->addToBuffer (lfpSamples.data(), lfpSampleNumbers, lfpTimestamps, lfpEventCodes, numUltraFrames);
+ apBuffer->addToBuffer (apSamples.data(), apSampleNumbers, apTimestamps, apEventCodes, numUltraFrames * superFramesPerUltraFrame);
+
+ if (! lfpOffsetCalculated)
+ updateLfpOffsets (lfpSamples, lfpSampleNumbers[0]);
+ if (! apOffsetCalculated)
+ updateApOffsets (apSamples, apSampleNumbers[0]);
+ }
+ }
}
void Neuropixels1f::writeShiftRegisters()
{
- if (adcValues.size() != NeuropixelsV1Values::AdcCount)
- throw error_str("Invalid number of ADC values found.");
-
- auto shankBits = NeuropixelsV1::makeShankBits(getReference(settings[0]->referenceIndex), settings[0]->selectedElectrode);
- auto configBits = NeuropixelsV1::makeConfigBits(getReference(settings[0]->referenceIndex), getGainEnum(settings[0]->apGainIndex), getGainEnum(settings[0]->lfpGainIndex), true, adcValues);
-
- auto shankBytes = toBitReversedBytes(shankBits);
-
- int rc = WriteByte((uint32_t)NeuropixelsV1ShiftRegisters::SR_LENGTH1, (uint32_t)shankBytes.size() % 0x100);
- if (rc != ONI_ESUCCESS) return;
-
- rc = WriteByte((uint32_t)NeuropixelsV1ShiftRegisters::SR_LENGTH2, (uint32_t)shankBytes.size() / 0x100);
- if (rc != ONI_ESUCCESS) return;
-
- for (auto b : shankBytes)
- {
- rc = WriteByte((uint32_t)NeuropixelsV1ShiftRegisters::SR_CHAIN1, b);
- if (rc != ONI_ESUCCESS) return;
- }
-
- const uint32_t shiftRegisterSuccess = 1 << 7;
-
- for (int i = 0; i < configBits.size(); i++)
- {
- auto srAddress = i == 0 ? (uint32_t)NeuropixelsV1ShiftRegisters::SR_CHAIN2 : (uint32_t)NeuropixelsV1ShiftRegisters::SR_CHAIN3;
-
- for (int j = 0; j < 2; j++)
- {
- auto baseBytes = toBitReversedBytes(configBits[i]);
-
- rc = WriteByte((uint32_t)NeuropixelsV1ShiftRegisters::SR_LENGTH1, (uint32_t)baseBytes.size() % 0x100);
- if (rc != ONI_ESUCCESS) return;
-
- rc = WriteByte((uint32_t)NeuropixelsV1ShiftRegisters::SR_LENGTH2, (uint32_t)baseBytes.size() / 0x100);
- if (rc != ONI_ESUCCESS) return;
-
- for (auto b : baseBytes)
- {
- rc = WriteByte(srAddress, b);
- if (rc != ONI_ESUCCESS) return;
- }
- }
-
- oni_reg_val_t value;
- rc = ReadByte((uint32_t)NeuropixelsV1Registers::STATUS, &value);
-
- if (rc != ONI_ESUCCESS || value != shiftRegisterSuccess)
- {
- LOGE("Shift register ", srAddress, " status check failed.");
- return;
- }
- }
-
- const uint32_t ADC01_00_OFF_THRESH = 0x8001;
-
- for (size_t i = 0; i < adcValues.size(); i += 2)
- {
- auto value = (uint32_t)(adcValues.at(i + 1).offset << 26 | adcValues.at(i + 1).threshold << 16 | adcValues.at(i).offset << 10 | adcValues.at(i).threshold);
- rc = deviceContext->writeRegister(deviceIdx, ADC01_00_OFF_THRESH + i, value);
-
- if (rc != ONI_ESUCCESS)
- {
- LOGE("Error writing to register ", ADC01_00_OFF_THRESH + i, ".");
- return;
- }
- }
-
- auto fixedPointLfPGain = (uint32_t)(lfpGainCorrection * (1 << 14)) & 0xFFFF;
- auto fixedPointApGain = (uint32_t)(apGainCorrection * (1 << 14)) & 0xFFFF;
-
- const uint32_t CHAN001_000_LFPGAIN = 0x8011;
- const uint32_t CHAN001_000_APGAIN = 0x80D1;
-
- for (uint32_t i = 0; i < numberOfChannels / 2; i++)
- {
- rc = deviceContext->writeRegister(deviceIdx, CHAN001_000_LFPGAIN + i, fixedPointLfPGain << 16 | fixedPointLfPGain);
- if (rc != ONI_ESUCCESS)
- {
- LOGE("Error writing to register ", CHAN001_000_LFPGAIN + i, ".");
- return;
- }
-
- rc = deviceContext->writeRegister(deviceIdx, CHAN001_000_APGAIN + i, fixedPointApGain << 16 | fixedPointApGain);
- if (rc != ONI_ESUCCESS)
- {
- LOGE("Error writing to register ", CHAN001_000_APGAIN + i, ".");
- return;
- }
- }
+ if (adcValues.size() != NeuropixelsV1Values::AdcCount)
+ throw error_str ("Invalid number of ADC values found.");
+
+ auto shankBits = NeuropixelsV1::makeShankBits (getReference (settings[0]->referenceIndex), settings[0]->selectedElectrode);
+ auto configBits = NeuropixelsV1::makeConfigBits (getReference (settings[0]->referenceIndex), getGainEnum (settings[0]->apGainIndex), getGainEnum (settings[0]->lfpGainIndex), true, adcValues);
+
+ auto shankBytes = toBitReversedBytes (shankBits);
+
+ int rc = WriteByte ((uint32_t) NeuropixelsV1ShiftRegisters::SR_LENGTH1, (uint32_t) shankBytes.size() % 0x100);
+ if (rc != ONI_ESUCCESS)
+ return;
+
+ rc = WriteByte ((uint32_t) NeuropixelsV1ShiftRegisters::SR_LENGTH2, (uint32_t) shankBytes.size() / 0x100);
+ if (rc != ONI_ESUCCESS)
+ return;
+
+ for (auto b : shankBytes)
+ {
+ rc = WriteByte ((uint32_t) NeuropixelsV1ShiftRegisters::SR_CHAIN1, b);
+ if (rc != ONI_ESUCCESS)
+ return;
+ }
+
+ const uint32_t shiftRegisterSuccess = 1 << 7;
+
+ for (int i = 0; i < configBits.size(); i++)
+ {
+ auto srAddress = i == 0 ? (uint32_t) NeuropixelsV1ShiftRegisters::SR_CHAIN2 : (uint32_t) NeuropixelsV1ShiftRegisters::SR_CHAIN3;
+
+ for (int j = 0; j < 2; j++)
+ {
+ auto baseBytes = toBitReversedBytes (configBits[i]);
+
+ rc = WriteByte ((uint32_t) NeuropixelsV1ShiftRegisters::SR_LENGTH1, (uint32_t) baseBytes.size() % 0x100);
+ if (rc != ONI_ESUCCESS)
+ return;
+
+ rc = WriteByte ((uint32_t) NeuropixelsV1ShiftRegisters::SR_LENGTH2, (uint32_t) baseBytes.size() / 0x100);
+ if (rc != ONI_ESUCCESS)
+ return;
+
+ for (auto b : baseBytes)
+ {
+ rc = WriteByte (srAddress, b);
+ if (rc != ONI_ESUCCESS)
+ return;
+ }
+ }
+
+ oni_reg_val_t value;
+ rc = ReadByte ((uint32_t) NeuropixelsV1Registers::STATUS, &value);
+
+ if (rc != ONI_ESUCCESS || value != shiftRegisterSuccess)
+ {
+ LOGE ("Shift register ", srAddress, " status check failed.");
+ return;
+ }
+ }
+
+ const uint32_t ADC01_00_OFF_THRESH = 0x8001;
+
+ for (size_t i = 0; i < adcValues.size(); i += 2)
+ {
+ auto value = (uint32_t) (adcValues.at (i + 1).offset << 26
+ | adcValues.at (i + 1).threshold << 16
+ | adcValues.at (i).offset << 10
+ | adcValues.at (i).threshold);
+ rc = deviceContext->writeRegister (deviceIdx, ADC01_00_OFF_THRESH + i, value);
+
+ if (rc != ONI_ESUCCESS)
+ {
+ LOGE ("Error writing to register ", ADC01_00_OFF_THRESH + i, ".");
+ return;
+ }
+ }
+
+ auto fixedPointLfPGain = (uint32_t) (lfpGainCorrection * (1 << 14)) & 0xFFFF;
+ auto fixedPointApGain = (uint32_t) (apGainCorrection * (1 << 14)) & 0xFFFF;
+
+ const uint32_t CHAN001_000_LFPGAIN = 0x8011;
+ const uint32_t CHAN001_000_APGAIN = 0x80D1;
+
+ for (uint32_t i = 0; i < numberOfChannels / 2; i++)
+ {
+ rc = deviceContext->writeRegister (deviceIdx, CHAN001_000_LFPGAIN + i, fixedPointLfPGain << 16 | fixedPointLfPGain);
+ if (rc != ONI_ESUCCESS)
+ {
+ LOGE ("Error writing to register ", CHAN001_000_LFPGAIN + i, ".");
+ return;
+ }
+
+ rc = deviceContext->writeRegister (deviceIdx, CHAN001_000_APGAIN + i, fixedPointApGain << 16 | fixedPointApGain);
+ if (rc != ONI_ESUCCESS)
+ {
+ LOGE ("Error writing to register ", CHAN001_000_APGAIN + i, ".");
+ return;
+ }
+ }
}
diff --git a/Source/Devices/Neuropixels1f.h b/Source/Devices/Neuropixels1f.h
index b217a65..b7daad3 100644
--- a/Source/Devices/Neuropixels1f.h
+++ b/Source/Devices/Neuropixels1f.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 .
*/
@@ -26,66 +26,117 @@
namespace OnixSourcePlugin
{
- /**
- Configures and streams data from a Neuropixels 1.0f device
- */
- class Neuropixels1f : public Neuropixels1
- {
- public:
- Neuropixels1f(std::string name, std::string hubName, const oni_dev_idx_t, std::shared_ptr);
-
- int configureDevice() override;
- bool updateSettings() override;
- void startAcquisition() override;
- void stopAcquisition() override;
- void addSourceBuffers(OwnedArray& sourceBuffers) override;
- void processFrames() override;
-
- void writeShiftRegisters();
-
- static OnixDeviceType getDeviceType();
-
- private:
-
- static constexpr char* STREAM_NAME_AP = "AP";
- static constexpr char* STREAM_NAME_LFP = "LFP";
-
- // ADC number to frame index mapping
- static constexpr int adcToFrameIndex[] = {
- 0, 7 , 14, 21, 28,
- 1, 8 , 15, 22, 29,
- 2, 9 , 16, 23, 30,
- 3, 10, 17, 24, 31,
- 4, 11, 18, 25, 32,
- 5, 12, 19, 26, 33,
- 6, 13
- };
-
- // ADC to muxed channel mapping
- static constexpr size_t adcToChannel[] = {
- 0, 1, 24, 25, 48, 49, 72, 73, 96, 97,
- 120, 121, 144, 145, 168, 169, 192, 193,
- 216, 217, 240, 241, 264, 265, 288, 289,
- 312, 313, 336, 337, 360, 361
- };
-
- JUCE_LEAK_DETECTOR(Neuropixels1f);
- };
-
- /*
-
- A thread that updates probe settings in the background and shows a progress bar
-
- */
- class NeuropixelsV1fBackgroundUpdater : public NeuropixelsV1BackgroundUpdater
- {
- public:
- NeuropixelsV1fBackgroundUpdater(Neuropixels1f* d);
-
- void run() override;
-
- private:
-
- JUCE_LEAK_DETECTOR(NeuropixelsV1fBackgroundUpdater);
- };
-}
+/**
+ Configures and streams data from a Neuropixels 1.0f device
+*/
+class Neuropixels1f : public Neuropixels1
+{
+public:
+ Neuropixels1f (std::string name, std::string hubName, const oni_dev_idx_t, std::shared_ptr);
+
+ int configureDevice() override;
+ bool updateSettings() override;
+ void startAcquisition() override;
+ void stopAcquisition() override;
+ void addSourceBuffers (OwnedArray& sourceBuffers) override;
+ void processFrames() override;
+
+ void writeShiftRegisters();
+
+ static OnixDeviceType getDeviceType();
+
+private:
+ static constexpr char* STREAM_NAME_AP = "AP";
+ static constexpr char* STREAM_NAME_LFP = "LFP";
+
+ // ADC number to frame index mapping
+ static constexpr int adcToFrameIndex[] = {
+ 0,
+ 7,
+ 14,
+ 21,
+ 28,
+ 1,
+ 8,
+ 15,
+ 22,
+ 29,
+ 2,
+ 9,
+ 16,
+ 23,
+ 30,
+ 3,
+ 10,
+ 17,
+ 24,
+ 31,
+ 4,
+ 11,
+ 18,
+ 25,
+ 32,
+ 5,
+ 12,
+ 19,
+ 26,
+ 33,
+ 6,
+ 13
+ };
+
+ // ADC to muxed channel mapping
+ static constexpr size_t adcToChannel[] = {
+ 0,
+ 1,
+ 24,
+ 25,
+ 48,
+ 49,
+ 72,
+ 73,
+ 96,
+ 97,
+ 120,
+ 121,
+ 144,
+ 145,
+ 168,
+ 169,
+ 192,
+ 193,
+ 216,
+ 217,
+ 240,
+ 241,
+ 264,
+ 265,
+ 288,
+ 289,
+ 312,
+ 313,
+ 336,
+ 337,
+ 360,
+ 361
+ };
+
+ JUCE_LEAK_DETECTOR (Neuropixels1f);
+};
+
+/*
+
+ A thread that updates probe settings in the background and shows a progress bar
+
+*/
+class NeuropixelsV1fBackgroundUpdater : public NeuropixelsV1BackgroundUpdater
+{
+public:
+ NeuropixelsV1fBackgroundUpdater (Neuropixels1f* d);
+
+ void run() override;
+
+private:
+ JUCE_LEAK_DETECTOR (NeuropixelsV1fBackgroundUpdater);
+};
+} // namespace OnixSourcePlugin
diff --git a/Source/Devices/Neuropixels2e.cpp b/Source/Devices/Neuropixels2e.cpp
index 5a62282..fbce27b 100644
--- a/Source/Devices/Neuropixels2e.cpp
+++ b/Source/Devices/Neuropixels2e.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,1067 +24,1068 @@
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)
+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)
{
- probeSN.fill(0);
- frameCount.fill(0);
- sampleNumber.fill(0);
+ probeSN.fill (0);
+ frameCount.fill (0);
+ sampleNumber.fill (0);
- for (int i = 0; i < NeuropixelsV2eValues::numberOfSettings; i++)
- {
- defineMetadata(settings[i].get(), NeuropixelsV2eValues::numberOfShanks);
- }
+ for (int i = 0; i < NeuropixelsV2eValues::numberOfSettings; i++)
+ {
+ defineMetadata (settings[i].get(), NeuropixelsV2eValues::numberOfShanks);
+ }
- for (int i = 0; i < NumberOfProbes; i++)
- eventCodes[i].fill(0);
+ for (int i = 0; i < NumberOfProbes; i++)
+ eventCodes[i].fill (0);
}
Neuropixels2e::~Neuropixels2e()
{
- if (serializer != nullptr)
- {
- selectProbe(NoProbeSelected);
- serializer->WriteByte((uint32_t)DS90UB9x::DS90UB9xSerializerI2CRegister::GPIO10, DefaultGPO10Config);
- }
-
- if (deviceContext != nullptr && deviceContext->isInitialized())
- deviceContext->setOption(ONIX_OPT_PASSTHROUGH, 0);
+ if (serializer != nullptr)
+ {
+ selectProbe (NoProbeSelected);
+ serializer->WriteByte ((uint32_t) DS90UB9x::DS90UB9xSerializerI2CRegister::GPIO10, DefaultGPO10Config);
+ }
+
+ if (deviceContext != nullptr && deviceContext->isInitialized())
+ deviceContext->setOption (ONIX_OPT_PASSTHROUGH, 0);
}
-void Neuropixels2e::createDataStream(int n)
+void Neuropixels2e::createDataStream (int n)
{
- StreamInfo apStream = StreamInfo(
- OnixDevice::createStreamName({ getPortName(getDeviceIdx()), getHubName(), "Probe" + std::to_string(n) }),
- "Neuropixels 2.0 data stream",
- getStreamIdentifier(),
- numberOfChannels,
- sampleRate,
- "CH",
- ContinuousChannel::Type::ELECTRODE,
- 0.195f,
- "uV",
- {},
- "ap"
- );
- streamInfos.add(apStream);
+ StreamInfo apStream = StreamInfo (
+ OnixDevice::createStreamName ({ getPortName (getDeviceIdx()), getHubName(), "Probe" + std::to_string (n) }),
+ "Neuropixels 2.0 data stream",
+ getStreamIdentifier(),
+ numberOfChannels,
+ sampleRate,
+ "CH",
+ ContinuousChannel::Type::ELECTRODE,
+ 0.195f,
+ "uV",
+ {},
+ "ap");
+ streamInfos.add (apStream);
}
int Neuropixels2e::getNumProbes() const
{
- return m_numProbes;
+ return m_numProbes;
}
-void Neuropixels2e::selectElectrodesInRange(std::vector& selection, int startIndex, int numberOfElectrodes)
+void Neuropixels2e::selectElectrodesInRange (std::vector& selection, int startIndex, int numberOfElectrodes)
{
- for (int i = startIndex; i < startIndex + numberOfElectrodes; i++)
- selection.emplace_back(i);
+ for (int i = startIndex; i < startIndex + numberOfElectrodes; i++)
+ selection.emplace_back (i);
}
-void Neuropixels2e::selectElectrodesAcrossShanks(std::vector& selection, int startIndex, int numberOfElectrodes)
+void Neuropixels2e::selectElectrodesAcrossShanks (std::vector& selection, int startIndex, int numberOfElectrodes)
{
- for (int shank = 0; shank < 4; shank++)
- {
- auto shankOffset = NeuropixelsV2eValues::electrodesPerShank * shank;
- for (int i = startIndex + shankOffset; i < startIndex + numberOfElectrodes + shankOffset; i++)
- {
- selection.emplace_back(i);
- }
- }
+ for (int shank = 0; shank < 4; shank++)
+ {
+ auto shankOffset = NeuropixelsV2eValues::electrodesPerShank * shank;
+ for (int i = startIndex + shankOffset; i < startIndex + numberOfElectrodes + shankOffset; i++)
+ {
+ selection.emplace_back (i);
+ }
+ }
}
-std::vector Neuropixels2e::selectElectrodeConfiguration(int electrodeConfigurationIndex)
+std::vector Neuropixels2e::selectElectrodeConfiguration (int electrodeConfigurationIndex)
{
- static int numberOfElectrodesAcrossShanks = 96;
-
- std::vector selection;
-
- if (numberOfShanks == 1)
- {
- if (electrodeConfigurationIndex == (int32_t)ElectrodeConfigurationSingleShank::BankA)
- {
- selectElectrodesInRange(selection, 0, numberOfChannels);
- }
- else if (electrodeConfigurationIndex == (int32_t)ElectrodeConfigurationSingleShank::BankB)
- {
- selectElectrodesInRange(selection, numberOfChannels, numberOfChannels);
- }
- else if (electrodeConfigurationIndex == (int32_t)ElectrodeConfigurationSingleShank::BankC)
- {
- selectElectrodesInRange(selection, numberOfChannels * 2, numberOfChannels);
- }
- else if (electrodeConfigurationIndex == (int32_t)ElectrodeConfigurationSingleShank::BankD)
- {
- static int32_t bankDOffset = 896;
- selectElectrodesInRange(selection, bankDOffset, numberOfChannels);
- }
- }
- else if (numberOfShanks == 4)
- {
- if (electrodeConfigurationIndex == (int32_t)ElectrodeConfigurationQuadShank::Shank1BankA)
- {
- selectElectrodesInRange(selection, 0, numberOfChannels);
- }
- else if (electrodeConfigurationIndex == (int32_t)ElectrodeConfigurationQuadShank::Shank1BankB)
- {
- selectElectrodesInRange(selection, numberOfChannels, numberOfChannels);
- }
- else if (electrodeConfigurationIndex == (int32_t)ElectrodeConfigurationQuadShank::Shank1BankC)
- {
- selectElectrodesInRange(selection, numberOfChannels * 2, numberOfChannels);
- }
- else if (electrodeConfigurationIndex == (int32_t)ElectrodeConfigurationQuadShank::Shank2BankA)
- {
- selectElectrodesInRange(selection, NeuropixelsV2eValues::electrodesPerShank, numberOfChannels);
- }
- else if (electrodeConfigurationIndex == (int32_t)ElectrodeConfigurationQuadShank::Shank2BankB)
- {
- selectElectrodesInRange(selection, NeuropixelsV2eValues::electrodesPerShank + numberOfChannels, numberOfChannels);
- }
- else if (electrodeConfigurationIndex == (int32_t)ElectrodeConfigurationQuadShank::Shank2BankC)
- {
- selectElectrodesInRange(selection, NeuropixelsV2eValues::electrodesPerShank + numberOfChannels * 2, numberOfChannels);
- }
- else if (electrodeConfigurationIndex == (int32_t)ElectrodeConfigurationQuadShank::Shank3BankA)
- {
- selectElectrodesInRange(selection, NeuropixelsV2eValues::electrodesPerShank * 2, numberOfChannels);
- }
- else if (electrodeConfigurationIndex == (int32_t)ElectrodeConfigurationQuadShank::Shank3BankB)
- {
- selectElectrodesInRange(selection, NeuropixelsV2eValues::electrodesPerShank * 2 + numberOfChannels, numberOfChannels);
- }
- else if (electrodeConfigurationIndex == (int32_t)ElectrodeConfigurationQuadShank::Shank3BankC)
- {
- selectElectrodesInRange(selection, NeuropixelsV2eValues::electrodesPerShank * 2 + numberOfChannels * 2, numberOfChannels);
- }
- else if (electrodeConfigurationIndex == (int32_t)ElectrodeConfigurationQuadShank::Shank4BankA)
- {
- selectElectrodesInRange(selection, NeuropixelsV2eValues::electrodesPerShank * 3, numberOfChannels);
- }
- else if (electrodeConfigurationIndex == (int32_t)ElectrodeConfigurationQuadShank::Shank4BankB)
- {
- selectElectrodesInRange(selection, NeuropixelsV2eValues::electrodesPerShank * 3 + numberOfChannels, numberOfChannels);
- }
- else if (electrodeConfigurationIndex == (int32_t)ElectrodeConfigurationQuadShank::Shank4BankC)
- {
- selectElectrodesInRange(selection, NeuropixelsV2eValues::electrodesPerShank * 3 + numberOfChannels * 2, numberOfChannels);
- }
- else if (electrodeConfigurationIndex == (int32_t)ElectrodeConfigurationQuadShank::AllShanks1To96)
- {
- selectElectrodesAcrossShanks(selection, 0, numberOfElectrodesAcrossShanks);
- }
- else if (electrodeConfigurationIndex == (int32_t)ElectrodeConfigurationQuadShank::AllShanks97To192)
- {
- selectElectrodesAcrossShanks(selection, numberOfElectrodesAcrossShanks, numberOfElectrodesAcrossShanks);
- }
- else if (electrodeConfigurationIndex == (int32_t)ElectrodeConfigurationQuadShank::AllShanks193To288)
- {
- selectElectrodesAcrossShanks(selection, numberOfElectrodesAcrossShanks * 2, numberOfElectrodesAcrossShanks);
- }
- else if (electrodeConfigurationIndex == (int32_t)ElectrodeConfigurationQuadShank::AllShanks289To384)
- {
- selectElectrodesAcrossShanks(selection, numberOfElectrodesAcrossShanks * 3, numberOfElectrodesAcrossShanks);
- }
- else if (electrodeConfigurationIndex == (int32_t)ElectrodeConfigurationQuadShank::AllShanks385To480)
- {
- selectElectrodesAcrossShanks(selection, numberOfElectrodesAcrossShanks * 4, numberOfElectrodesAcrossShanks);
- }
- else if (electrodeConfigurationIndex == (int32_t)ElectrodeConfigurationQuadShank::AllShanks481To576)
- {
- selectElectrodesAcrossShanks(selection, numberOfElectrodesAcrossShanks * 5, numberOfElectrodesAcrossShanks);
- }
- else if (electrodeConfigurationIndex == (int32_t)ElectrodeConfigurationQuadShank::AllShanks577To672)
- {
- selectElectrodesAcrossShanks(selection, numberOfElectrodesAcrossShanks * 6, numberOfElectrodesAcrossShanks);
- }
- else if (electrodeConfigurationIndex == (int32_t)ElectrodeConfigurationQuadShank::AllShanks673To768)
- {
- selectElectrodesAcrossShanks(selection, numberOfElectrodesAcrossShanks * 7, numberOfElectrodesAcrossShanks);
- }
- else if (electrodeConfigurationIndex == (int32_t)ElectrodeConfigurationQuadShank::AllShanks769To864)
- {
- selectElectrodesAcrossShanks(selection, numberOfElectrodesAcrossShanks * 8, numberOfElectrodesAcrossShanks);
- }
- else if (electrodeConfigurationIndex == (int32_t)ElectrodeConfigurationQuadShank::AllShanks865To960)
- {
- selectElectrodesAcrossShanks(selection, numberOfElectrodesAcrossShanks * 9, numberOfElectrodesAcrossShanks);
- }
- else if (electrodeConfigurationIndex == (int32_t)ElectrodeConfigurationQuadShank::AllShanks961To1056)
- {
- selectElectrodesAcrossShanks(selection, numberOfElectrodesAcrossShanks * 10, numberOfElectrodesAcrossShanks);
- }
- else if (electrodeConfigurationIndex == (int32_t)ElectrodeConfigurationQuadShank::AllShanks1057To1152)
- {
- selectElectrodesAcrossShanks(selection, numberOfElectrodesAcrossShanks * 11, numberOfElectrodesAcrossShanks);
- }
- else if (electrodeConfigurationIndex == (int32_t)ElectrodeConfigurationQuadShank::AllShanks1153To1248)
- {
- selectElectrodesAcrossShanks(selection, numberOfElectrodesAcrossShanks * 12, numberOfElectrodesAcrossShanks);
- }
- }
-
- return selection;
+ static int numberOfElectrodesAcrossShanks = 96;
+
+ std::vector selection;
+
+ if (numberOfShanks == 1)
+ {
+ if (electrodeConfigurationIndex == (int32_t) ElectrodeConfigurationSingleShank::BankA)
+ {
+ selectElectrodesInRange (selection, 0, numberOfChannels);
+ }
+ else if (electrodeConfigurationIndex == (int32_t) ElectrodeConfigurationSingleShank::BankB)
+ {
+ selectElectrodesInRange (selection, numberOfChannels, numberOfChannels);
+ }
+ else if (electrodeConfigurationIndex == (int32_t) ElectrodeConfigurationSingleShank::BankC)
+ {
+ selectElectrodesInRange (selection, numberOfChannels * 2, numberOfChannels);
+ }
+ else if (electrodeConfigurationIndex == (int32_t) ElectrodeConfigurationSingleShank::BankD)
+ {
+ static int32_t bankDOffset = 896;
+ selectElectrodesInRange (selection, bankDOffset, numberOfChannels);
+ }
+ }
+ else if (numberOfShanks == 4)
+ {
+ if (electrodeConfigurationIndex == (int32_t) ElectrodeConfigurationQuadShank::Shank1BankA)
+ {
+ selectElectrodesInRange (selection, 0, numberOfChannels);
+ }
+ else if (electrodeConfigurationIndex == (int32_t) ElectrodeConfigurationQuadShank::Shank1BankB)
+ {
+ selectElectrodesInRange (selection, numberOfChannels, numberOfChannels);
+ }
+ else if (electrodeConfigurationIndex == (int32_t) ElectrodeConfigurationQuadShank::Shank1BankC)
+ {
+ selectElectrodesInRange (selection, numberOfChannels * 2, numberOfChannels);
+ }
+ else if (electrodeConfigurationIndex == (int32_t) ElectrodeConfigurationQuadShank::Shank2BankA)
+ {
+ selectElectrodesInRange (selection, NeuropixelsV2eValues::electrodesPerShank, numberOfChannels);
+ }
+ else if (electrodeConfigurationIndex == (int32_t) ElectrodeConfigurationQuadShank::Shank2BankB)
+ {
+ selectElectrodesInRange (selection, NeuropixelsV2eValues::electrodesPerShank + numberOfChannels, numberOfChannels);
+ }
+ else if (electrodeConfigurationIndex == (int32_t) ElectrodeConfigurationQuadShank::Shank2BankC)
+ {
+ selectElectrodesInRange (selection, NeuropixelsV2eValues::electrodesPerShank + numberOfChannels * 2, numberOfChannels);
+ }
+ else if (electrodeConfigurationIndex == (int32_t) ElectrodeConfigurationQuadShank::Shank3BankA)
+ {
+ selectElectrodesInRange (selection, NeuropixelsV2eValues::electrodesPerShank * 2, numberOfChannels);
+ }
+ else if (electrodeConfigurationIndex == (int32_t) ElectrodeConfigurationQuadShank::Shank3BankB)
+ {
+ selectElectrodesInRange (selection, NeuropixelsV2eValues::electrodesPerShank * 2 + numberOfChannels, numberOfChannels);
+ }
+ else if (electrodeConfigurationIndex == (int32_t) ElectrodeConfigurationQuadShank::Shank3BankC)
+ {
+ selectElectrodesInRange (selection, NeuropixelsV2eValues::electrodesPerShank * 2 + numberOfChannels * 2, numberOfChannels);
+ }
+ else if (electrodeConfigurationIndex == (int32_t) ElectrodeConfigurationQuadShank::Shank4BankA)
+ {
+ selectElectrodesInRange (selection, NeuropixelsV2eValues::electrodesPerShank * 3, numberOfChannels);
+ }
+ else if (electrodeConfigurationIndex == (int32_t) ElectrodeConfigurationQuadShank::Shank4BankB)
+ {
+ selectElectrodesInRange (selection, NeuropixelsV2eValues::electrodesPerShank * 3 + numberOfChannels, numberOfChannels);
+ }
+ else if (electrodeConfigurationIndex == (int32_t) ElectrodeConfigurationQuadShank::Shank4BankC)
+ {
+ selectElectrodesInRange (selection, NeuropixelsV2eValues::electrodesPerShank * 3 + numberOfChannels * 2, numberOfChannels);
+ }
+ else if (electrodeConfigurationIndex == (int32_t) ElectrodeConfigurationQuadShank::AllShanks1To96)
+ {
+ selectElectrodesAcrossShanks (selection, 0, numberOfElectrodesAcrossShanks);
+ }
+ else if (electrodeConfigurationIndex == (int32_t) ElectrodeConfigurationQuadShank::AllShanks97To192)
+ {
+ selectElectrodesAcrossShanks (selection, numberOfElectrodesAcrossShanks, numberOfElectrodesAcrossShanks);
+ }
+ else if (electrodeConfigurationIndex == (int32_t) ElectrodeConfigurationQuadShank::AllShanks193To288)
+ {
+ selectElectrodesAcrossShanks (selection, numberOfElectrodesAcrossShanks * 2, numberOfElectrodesAcrossShanks);
+ }
+ else if (electrodeConfigurationIndex == (int32_t) ElectrodeConfigurationQuadShank::AllShanks289To384)
+ {
+ selectElectrodesAcrossShanks (selection, numberOfElectrodesAcrossShanks * 3, numberOfElectrodesAcrossShanks);
+ }
+ else if (electrodeConfigurationIndex == (int32_t) ElectrodeConfigurationQuadShank::AllShanks385To480)
+ {
+ selectElectrodesAcrossShanks (selection, numberOfElectrodesAcrossShanks * 4, numberOfElectrodesAcrossShanks);
+ }
+ else if (electrodeConfigurationIndex == (int32_t) ElectrodeConfigurationQuadShank::AllShanks481To576)
+ {
+ selectElectrodesAcrossShanks (selection, numberOfElectrodesAcrossShanks * 5, numberOfElectrodesAcrossShanks);
+ }
+ else if (electrodeConfigurationIndex == (int32_t) ElectrodeConfigurationQuadShank::AllShanks577To672)
+ {
+ selectElectrodesAcrossShanks (selection, numberOfElectrodesAcrossShanks * 6, numberOfElectrodesAcrossShanks);
+ }
+ else if (electrodeConfigurationIndex == (int32_t) ElectrodeConfigurationQuadShank::AllShanks673To768)
+ {
+ selectElectrodesAcrossShanks (selection, numberOfElectrodesAcrossShanks * 7, numberOfElectrodesAcrossShanks);
+ }
+ else if (electrodeConfigurationIndex == (int32_t) ElectrodeConfigurationQuadShank::AllShanks769To864)
+ {
+ selectElectrodesAcrossShanks (selection, numberOfElectrodesAcrossShanks * 8, numberOfElectrodesAcrossShanks);
+ }
+ else if (electrodeConfigurationIndex == (int32_t) ElectrodeConfigurationQuadShank::AllShanks865To960)
+ {
+ selectElectrodesAcrossShanks (selection, numberOfElectrodesAcrossShanks * 9, numberOfElectrodesAcrossShanks);
+ }
+ else if (electrodeConfigurationIndex == (int32_t) ElectrodeConfigurationQuadShank::AllShanks961To1056)
+ {
+ selectElectrodesAcrossShanks (selection, numberOfElectrodesAcrossShanks * 10, numberOfElectrodesAcrossShanks);
+ }
+ else if (electrodeConfigurationIndex == (int32_t) ElectrodeConfigurationQuadShank::AllShanks1057To1152)
+ {
+ selectElectrodesAcrossShanks (selection, numberOfElectrodesAcrossShanks * 11, numberOfElectrodesAcrossShanks);
+ }
+ else if (electrodeConfigurationIndex == (int32_t) ElectrodeConfigurationQuadShank::AllShanks1153To1248)
+ {
+ selectElectrodesAcrossShanks (selection, numberOfElectrodesAcrossShanks * 12, numberOfElectrodesAcrossShanks);
+ }
+ }
+
+ return selection;
}
-uint64_t Neuropixels2e::getProbeSerialNumber(int index)
+uint64_t Neuropixels2e::getProbeSerialNumber (int index)
{
- try {
- return probeSN.at(index);
- }
- catch (const std::out_of_range& ex) // filter for out of range
- {
- LOGE("Invalid index given requesting probe serial number.");
- }
-
- return 0ull;
+ try
+ {
+ return probeSN.at (index);
+ }
+ catch (const std::out_of_range& ex) // filter for out of range
+ {
+ LOGE ("Invalid index given requesting probe serial number.");
+ }
+
+ return 0ull;
}
OnixDeviceType Neuropixels2e::getDeviceType()
{
- return OnixDeviceType::NEUROPIXELSV2E;
+ return OnixDeviceType::NEUROPIXELSV2E;
}
int Neuropixels2e::configureDevice()
{
- if (deviceContext == nullptr || !deviceContext->isInitialized())
- throw error_str("Device context is not initialized properly for " + getName());
-
- int rc = deviceContext->writeRegister(deviceIdx, DS90UB9x::ENABLE, isEnabled() ? 1 : 0);
- if (rc != ONI_ESUCCESS)
- throw error_str("Unable to enable " + getName());
-
- configureSerDes();
- setProbeSupply(true);
- rc = serializer->set933I2cRate(400e3);
- if (rc != ONI_ESUCCESS)
- throw error_str("Unable to set I2C rate for " + getName());
- probeSN[0] = getProbeSN(ProbeASelected);
- probeSN[1] = getProbeSN(ProbeBSelected);
- setProbeSupply(false);
- LOGD("Probe A SN: ", probeSN[0]);
- LOGD("Probe B SN: ", probeSN[1]);
-
- if (probeSN[0] == 0 && probeSN[1] == 0)
- {
- m_numProbes = 0;
- throw error_str("No probes were found connected at address " + std::to_string(getDeviceIdx()));
- }
- else if (probeSN[0] != 0 && probeSN[1] != 0)
- {
- m_numProbes = 2;
- }
- else
- {
- m_numProbes = 1;
- }
-
- streamInfos.clear();
-
- for (int i = 0; i < m_numProbes; i++)
- {
- createDataStream(i);
- }
-
- return ONI_ESUCCESS;
+ if (deviceContext == nullptr || ! deviceContext->isInitialized())
+ throw error_str ("Device context is not initialized properly for " + getName());
+
+ int rc = deviceContext->writeRegister (deviceIdx, DS90UB9x::ENABLE, isEnabled() ? 1 : 0);
+ if (rc != ONI_ESUCCESS)
+ throw error_str ("Unable to enable " + getName());
+
+ configureSerDes();
+ setProbeSupply (true);
+ rc = serializer->set933I2cRate (400e3);
+ if (rc != ONI_ESUCCESS)
+ throw error_str ("Unable to set I2C rate for " + getName());
+ probeSN[0] = getProbeSN (ProbeASelected);
+ probeSN[1] = getProbeSN (ProbeBSelected);
+ setProbeSupply (false);
+ LOGD ("Probe A SN: ", probeSN[0]);
+ LOGD ("Probe B SN: ", probeSN[1]);
+
+ if (probeSN[0] == 0 && probeSN[1] == 0)
+ {
+ m_numProbes = 0;
+ throw error_str ("No probes were found connected at address " + std::to_string (getDeviceIdx()));
+ }
+ else if (probeSN[0] != 0 && probeSN[1] != 0)
+ {
+ m_numProbes = 2;
+ }
+ else
+ {
+ m_numProbes = 1;
+ }
+
+ streamInfos.clear();
+
+ for (int i = 0; i < m_numProbes; i++)
+ {
+ createDataStream (i);
+ }
+
+ return ONI_ESUCCESS;
}
bool Neuropixels2e::updateSettings()
{
- for (int i = 0; i < 2; i++)
- {
- if (probeSN[i] != 0)
- {
- if (gainCorrectionFilePath[i] == "None" || gainCorrectionFilePath[i] == "")
- {
- Onix1::showWarningMessageBoxAsync("Missing File", "Missing gain correction file for probe " + std::to_string(probeSN[i]));
- return false;
- }
-
- File gainCorrectionFile = File(gainCorrectionFilePath[i]);
-
- if (!gainCorrectionFile.existsAsFile())
- {
- Onix1::showWarningMessageBoxAsync("Missing File", "The gain correction file \"" + gainCorrectionFilePath[i] + "\" for probe " + std::to_string(probeSN[i]) + " does not exist.");
- return false;
- }
-
- StringArray fileLines;
- gainCorrectionFile.readLines(fileLines);
-
- fileLines.removeEmptyStrings(true);
-
- auto gainSN = std::stoull(fileLines[0].toStdString());
-
- if (gainSN != probeSN[i])
- {
- Onix1::showWarningMessageBoxAsync("Invalid Serial Number", "Gain correction serial number (" + std::to_string(gainSN) + ") does not match probe serial number (" + std::to_string(probeSN[i]) + ").");
- return false;
- }
-
- if (fileLines.size() != numberOfChannels + 1)
- {
- Onix1::showWarningMessageBoxAsync("File Format Invalid", "Found the wrong number of lines in the calibration file. Expected " + std::to_string(numberOfChannels + 1) + ", found " + std::to_string(fileLines.size()));
- return false;
- }
-
- StringRef breakCharacters = ",";
- StringRef noQuote = "";
- StringArray firstLine = StringArray::fromTokens(fileLines[1], breakCharacters, noQuote);
- auto correctionValue = std::stod(firstLine[1].toStdString());
-
- for (int j = 0; j < numberOfChannels; j++)
- {
- StringArray calibrationValues = StringArray::fromTokens(fileLines[j + 1], breakCharacters, noQuote);
-
- if (std::stoi(calibrationValues[0].toStdString()) != j || std::stod(calibrationValues[1].toStdString()) != correctionValue)
- {
- Onix1::showWarningMessageBoxAsync("File Format Invalid", "Calibration file is incorrectly formatted for probe " + std::to_string(probeSN[i]));
- return false;
- }
- }
-
- gainCorrection[i] = correctionValue * -1.0f;
- }
- else
- gainCorrection[i] = 0;
- }
-
- setProbeSupply(true);
- resetProbes();
-
- for (int i = 0; i < NumberOfProbes; i++)
- {
- if (probeSN[i] != 0)
- {
- selectProbe(i == 0 ? ProbeASelected : ProbeBSelected);
- writeConfiguration(settings[i].get());
- configureProbeStreaming();
- }
- }
-
- selectProbe(NoProbeSelected);
- //IMPORTANT! BNO polling thread must be started after this
-
- return true;
+ for (int i = 0; i < 2; i++)
+ {
+ if (probeSN[i] != 0)
+ {
+ if (gainCorrectionFilePath[i] == "None" || gainCorrectionFilePath[i] == "")
+ {
+ Onix1::showWarningMessageBoxAsync ("Missing File", "Missing gain correction file for probe " + std::to_string (probeSN[i]));
+ return false;
+ }
+
+ File gainCorrectionFile = File (gainCorrectionFilePath[i]);
+
+ if (! gainCorrectionFile.existsAsFile())
+ {
+ Onix1::showWarningMessageBoxAsync ("Missing File", "The gain correction file \"" + gainCorrectionFilePath[i] + "\" for probe " + std::to_string (probeSN[i]) + " does not exist.");
+ return false;
+ }
+
+ StringArray fileLines;
+ gainCorrectionFile.readLines (fileLines);
+
+ fileLines.removeEmptyStrings (true);
+
+ auto gainSN = std::stoull (fileLines[0].toStdString());
+
+ if (gainSN != probeSN[i])
+ {
+ Onix1::showWarningMessageBoxAsync ("Invalid Serial Number", "Gain correction serial number (" + std::to_string (gainSN) + ") does not match probe serial number (" + std::to_string (probeSN[i]) + ").");
+ return false;
+ }
+
+ if (fileLines.size() != numberOfChannels + 1)
+ {
+ Onix1::showWarningMessageBoxAsync ("File Format Invalid", "Found the wrong number of lines in the calibration file. Expected " + std::to_string (numberOfChannels + 1) + ", found " + std::to_string (fileLines.size()));
+ return false;
+ }
+
+ StringRef breakCharacters = ",";
+ StringRef noQuote = "";
+ StringArray firstLine = StringArray::fromTokens (fileLines[1], breakCharacters, noQuote);
+ auto correctionValue = std::stod (firstLine[1].toStdString());
+
+ for (int j = 0; j < numberOfChannels; j++)
+ {
+ StringArray calibrationValues = StringArray::fromTokens (fileLines[j + 1], breakCharacters, noQuote);
+
+ if (std::stoi (calibrationValues[0].toStdString()) != j || std::stod (calibrationValues[1].toStdString()) != correctionValue)
+ {
+ Onix1::showWarningMessageBoxAsync ("File Format Invalid", "Calibration file is incorrectly formatted for probe " + std::to_string (probeSN[i]));
+ return false;
+ }
+ }
+
+ gainCorrection[i] = correctionValue * -1.0f;
+ }
+ else
+ gainCorrection[i] = 0;
+ }
+
+ setProbeSupply (true);
+ resetProbes();
+
+ for (int i = 0; i < NumberOfProbes; i++)
+ {
+ if (probeSN[i] != 0)
+ {
+ selectProbe (i == 0 ? ProbeASelected : ProbeBSelected);
+ writeConfiguration (settings[i].get());
+ configureProbeStreaming();
+ }
+ }
+
+ selectProbe (NoProbeSelected);
+ // IMPORTANT! BNO polling thread must be started after this
+
+ return true;
}
void Neuropixels2e::configureProbeStreaming()
{
- // Write super sync bits into ASIC
- probeControl->WriteByte(SUPERSYNC11, 0b00011000);
- probeControl->WriteByte(SUPERSYNC10, 0b01100001);
- probeControl->WriteByte(SUPERSYNC9, 0b10000110);
- probeControl->WriteByte(SUPERSYNC8, 0b00011000);
- probeControl->WriteByte(SUPERSYNC7, 0b01100001);
- probeControl->WriteByte(SUPERSYNC6, 0b10000110);
- probeControl->WriteByte(SUPERSYNC5, 0b00011000);
- probeControl->WriteByte(SUPERSYNC4, 0b01100001);
- probeControl->WriteByte(SUPERSYNC3, 0b10000110);
- probeControl->WriteByte(SUPERSYNC2, 0b00011000);
- probeControl->WriteByte(SUPERSYNC1, 0b01100001);
- probeControl->WriteByte(SUPERSYNC0, 0b10111001);
-
- // Activate recording mode on NP
- probeControl->WriteByte(OP_MODE, 0b01000000);
+ // Write super sync bits into ASIC
+ probeControl->WriteByte (SUPERSYNC11, 0b00011000);
+ probeControl->WriteByte (SUPERSYNC10, 0b01100001);
+ probeControl->WriteByte (SUPERSYNC9, 0b10000110);
+ probeControl->WriteByte (SUPERSYNC8, 0b00011000);
+ probeControl->WriteByte (SUPERSYNC7, 0b01100001);
+ probeControl->WriteByte (SUPERSYNC6, 0b10000110);
+ probeControl->WriteByte (SUPERSYNC5, 0b00011000);
+ probeControl->WriteByte (SUPERSYNC4, 0b01100001);
+ probeControl->WriteByte (SUPERSYNC3, 0b10000110);
+ probeControl->WriteByte (SUPERSYNC2, 0b00011000);
+ probeControl->WriteByte (SUPERSYNC1, 0b01100001);
+ probeControl->WriteByte (SUPERSYNC0, 0b10111001);
+
+ // Activate recording mode on NP
+ probeControl->WriteByte (OP_MODE, 0b01000000);
}
void Neuropixels2e::configureSerDes()
{
- deviceContext->writeRegister(deviceIdx, DS90UB9x::ENABLE, 1);
-
- // configure deserializer trigger mode
- deviceContext->writeRegister(deviceIdx, DS90UB9x::TRIGGEROFF, 0);
- deviceContext->writeRegister(deviceIdx, DS90UB9x::TRIGGER, (uint32_t)(DS90UB9x::DS90UB9xTriggerMode::Continuous));
- deviceContext->writeRegister(deviceIdx, DS90UB9x::SYNCBITS, 0);
- deviceContext->writeRegister(deviceIdx, DS90UB9x::DATAGATE, (uint32_t)(DS90UB9x::DS90UB9xDataGate::Disabled));
- deviceContext->writeRegister(deviceIdx, DS90UB9x::MARK, (uint32_t)(DS90UB9x::DS90UB9xMarkMode::Disabled));
-
- // configure two 4-bit magic word-triggered streams, one for each probe
- deviceContext->writeRegister(deviceIdx, DS90UB9x::READSZ, 0x00100009); // 16 frames/superframe, 8x 12-bit words + magic bits
- deviceContext->writeRegister(deviceIdx, DS90UB9x::MAGIC_MASK, 0xC000003F); // Enable inverse, wait for non-inverse, 14-bit magic word
- deviceContext->writeRegister(deviceIdx, DS90UB9x::MAGIC, 0b0000000000101110); // Super-frame sync word
- deviceContext->writeRegister(deviceIdx, DS90UB9x::MAGIC_WAIT, 0);
- deviceContext->writeRegister(deviceIdx, DS90UB9x::DATAMODE, 0b00100000000000000000001010110101);
- deviceContext->writeRegister(deviceIdx, DS90UB9x::DATALINES0, 0xFFFFF8A6); // NP A
- deviceContext->writeRegister(deviceIdx, DS90UB9x::DATALINES1, 0xFFFFF97B); // NP B
-
- deserializer = std::make_unique(DS90UB9x::DES_ADDR, deviceIdx, deviceContext);
- deserializer->WriteByte((uint32_t)DS90UB9x::DS90UB9xDeserializerI2CRegister::PortSel, 0x01);
- int coaxMode = 0x4 + (uint32_t)(DS90UB9x::DS90UB9xMode::Raw12BitHighFrequency); // 0x4 maintains coax mode
- deserializer->WriteByte((uint32_t)(DS90UB9x::DS90UB9xDeserializerI2CRegister::PortMode), coaxMode);
- deserializer->WriteByte((uint32_t)DS90UB9x::DS90UB9xDeserializerI2CRegister::I2CConfig, 0b01011000);
- deserializer->WriteByte((uint32_t)DS90UB9x::DS90UB9xDeserializerI2CRegister::SerAlias, DS90UB9x::SER_ADDR << 1);
-
- deserializer->WriteByte((uint32_t)DS90UB9x::DS90UB9xDeserializerI2CRegister::GpioCtrl0, 0x10);
- deserializer->WriteByte((uint32_t)DS90UB9x::DS90UB9xDeserializerI2CRegister::GpioCtrl1, 0x32);
-
- int alias = ProbeI2CAddress << 1;
- deserializer->WriteByte((uint32_t)(DS90UB9x::DS90UB9xDeserializerI2CRegister::SlaveID1), alias);
- deserializer->WriteByte((uint32_t)(DS90UB9x::DS90UB9xDeserializerI2CRegister::SlaveAlias1), alias);
-
- alias = FlexAddress << 1;
- deserializer->WriteByte((uint32_t)(DS90UB9x::DS90UB9xDeserializerI2CRegister::SlaveID2), alias);
- deserializer->WriteByte((uint32_t)(DS90UB9x::DS90UB9xDeserializerI2CRegister::SlaveAlias2), alias);
-
- serializer = std::make_unique(DS90UB9x::SER_ADDR, deviceIdx, deviceContext);
- flex = std::make_unique(FlexAddress, deviceIdx, deviceContext);
- probeControl = std::make_unique(ProbeI2CAddress, deviceIdx, deviceContext);
+ deviceContext->writeRegister (deviceIdx, DS90UB9x::ENABLE, 1);
+
+ // configure deserializer trigger mode
+ deviceContext->writeRegister (deviceIdx, DS90UB9x::TRIGGEROFF, 0);
+ deviceContext->writeRegister (deviceIdx, DS90UB9x::TRIGGER, (uint32_t) (DS90UB9x::DS90UB9xTriggerMode::Continuous));
+ deviceContext->writeRegister (deviceIdx, DS90UB9x::SYNCBITS, 0);
+ deviceContext->writeRegister (deviceIdx, DS90UB9x::DATAGATE, (uint32_t) (DS90UB9x::DS90UB9xDataGate::Disabled));
+ deviceContext->writeRegister (deviceIdx, DS90UB9x::MARK, (uint32_t) (DS90UB9x::DS90UB9xMarkMode::Disabled));
+
+ // configure two 4-bit magic word-triggered streams, one for each probe
+ deviceContext->writeRegister (deviceIdx, DS90UB9x::READSZ, 0x00100009); // 16 frames/superframe, 8x 12-bit words + magic bits
+ deviceContext->writeRegister (deviceIdx, DS90UB9x::MAGIC_MASK, 0xC000003F); // Enable inverse, wait for non-inverse, 14-bit magic word
+ deviceContext->writeRegister (deviceIdx, DS90UB9x::MAGIC, 0b0000000000101110); // Super-frame sync word
+ deviceContext->writeRegister (deviceIdx, DS90UB9x::MAGIC_WAIT, 0);
+ deviceContext->writeRegister (deviceIdx, DS90UB9x::DATAMODE, 0b00100000000000000000001010110101);
+ deviceContext->writeRegister (deviceIdx, DS90UB9x::DATALINES0, 0xFFFFF8A6); // NP A
+ deviceContext->writeRegister (deviceIdx, DS90UB9x::DATALINES1, 0xFFFFF97B); // NP B
+
+ deserializer = std::make_unique (DS90UB9x::DES_ADDR, deviceIdx, deviceContext);
+ deserializer->WriteByte ((uint32_t) DS90UB9x::DS90UB9xDeserializerI2CRegister::PortSel, 0x01);
+ int coaxMode = 0x4 + (uint32_t) (DS90UB9x::DS90UB9xMode::Raw12BitHighFrequency); // 0x4 maintains coax mode
+ deserializer->WriteByte ((uint32_t) (DS90UB9x::DS90UB9xDeserializerI2CRegister::PortMode), coaxMode);
+ deserializer->WriteByte ((uint32_t) DS90UB9x::DS90UB9xDeserializerI2CRegister::I2CConfig, 0b01011000);
+ deserializer->WriteByte ((uint32_t) DS90UB9x::DS90UB9xDeserializerI2CRegister::SerAlias, DS90UB9x::SER_ADDR << 1);
+
+ deserializer->WriteByte ((uint32_t) DS90UB9x::DS90UB9xDeserializerI2CRegister::GpioCtrl0, 0x10);
+ deserializer->WriteByte ((uint32_t) DS90UB9x::DS90UB9xDeserializerI2CRegister::GpioCtrl1, 0x32);
+
+ int alias = ProbeI2CAddress << 1;
+ deserializer->WriteByte ((uint32_t) (DS90UB9x::DS90UB9xDeserializerI2CRegister::SlaveID1), alias);
+ deserializer->WriteByte ((uint32_t) (DS90UB9x::DS90UB9xDeserializerI2CRegister::SlaveAlias1), alias);
+
+ alias = FlexAddress << 1;
+ deserializer->WriteByte ((uint32_t) (DS90UB9x::DS90UB9xDeserializerI2CRegister::SlaveID2), alias);
+ deserializer->WriteByte ((uint32_t) (DS90UB9x::DS90UB9xDeserializerI2CRegister::SlaveAlias2), alias);
+
+ serializer = std::make_unique (DS90UB9x::SER_ADDR, deviceIdx, deviceContext);
+ flex = std::make_unique (FlexAddress, deviceIdx, deviceContext);
+ probeControl = std::make_unique (ProbeI2CAddress, deviceIdx, deviceContext);
}
-void Neuropixels2e::setProbeSupply(bool en)
+void Neuropixels2e::setProbeSupply (bool en)
{
- auto gpo10Config = en ? DefaultGPO10Config | GPO10SupplyMask : DefaultGPO10Config;
+ auto gpo10Config = en ? DefaultGPO10Config | GPO10SupplyMask : DefaultGPO10Config;
- selectProbe(NoProbeSelected);
- serializer->WriteByte((uint32_t)(DS90UB9x::DS90UB9xSerializerI2CRegister::GPIO10), gpo10Config);
- Thread::sleep(20);
+ selectProbe (NoProbeSelected);
+ serializer->WriteByte ((uint32_t) (DS90UB9x::DS90UB9xSerializerI2CRegister::GPIO10), gpo10Config);
+ Thread::sleep (20);
}
-void Neuropixels2e::selectProbe(uint8_t probeSelect)
+void Neuropixels2e::selectProbe (uint8_t probeSelect)
{
- if (serializer == nullptr)
- {
- LOGE("Serializer is not initialized for Neuropixels 2.0");
- return;
- }
-
- serializer->WriteByte((uint32_t)(DS90UB9x::DS90UB9xSerializerI2CRegister::GPIO32), probeSelect);
- Thread::sleep(20);
+ if (serializer == nullptr)
+ {
+ LOGE ("Serializer is not initialized for Neuropixels 2.0");
+ return;
+ }
+
+ serializer->WriteByte ((uint32_t) (DS90UB9x::DS90UB9xSerializerI2CRegister::GPIO32), probeSelect);
+ Thread::sleep (20);
}
void Neuropixels2e::resetProbes()
{
- auto gpo10Config = DefaultGPO10Config | GPO10SupplyMask;
- gpo10Config &= ~GPO10ResetMask;
- serializer->WriteByte((uint32_t)(DS90UB9x::DS90UB9xSerializerI2CRegister::GPIO10), gpo10Config);
- gpo10Config |= GPO10ResetMask;
- serializer->WriteByte((uint32_t)(DS90UB9x::DS90UB9xSerializerI2CRegister::GPIO10), gpo10Config);
+ auto gpo10Config = DefaultGPO10Config | GPO10SupplyMask;
+ gpo10Config &= ~GPO10ResetMask;
+ serializer->WriteByte ((uint32_t) (DS90UB9x::DS90UB9xSerializerI2CRegister::GPIO10), gpo10Config);
+ gpo10Config |= GPO10ResetMask;
+ serializer->WriteByte ((uint32_t) (DS90UB9x::DS90UB9xSerializerI2CRegister::GPIO10), gpo10Config);
}
-uint64_t Neuropixels2e::getProbeSN(uint8_t probeSelect)
+uint64_t Neuropixels2e::getProbeSN (uint8_t probeSelect)
{
- if (flex == nullptr)
- {
- LOGE("Flex is not initialized for Neuropixels 2.0");
- return 0ull;
- }
-
- selectProbe(probeSelect);
- uint64_t probeSN = 0ull;
- int errorCode = 0, rc;
- for (unsigned int i = 0; i < sizeof(probeSN); i++)
- {
- oni_reg_addr_t reg_addr = OFFSET_PROBE_SN + i;
- oni_reg_val_t val;
-
- rc = flex->ReadByte(reg_addr, &val);
-
- if (rc != ONI_ESUCCESS) return 0ull;
-
- if (val <= 0xFF)
- {
- probeSN |= (((uint64_t)val) << (i * 8));
- }
- }
- return probeSN;
+ if (flex == nullptr)
+ {
+ LOGE ("Flex is not initialized for Neuropixels 2.0");
+ return 0ull;
+ }
+
+ selectProbe (probeSelect);
+ uint64_t probeSN = 0ull;
+ int errorCode = 0, rc;
+ for (unsigned int i = 0; i < sizeof (probeSN); i++)
+ {
+ oni_reg_addr_t reg_addr = OFFSET_PROBE_SN + i;
+ oni_reg_val_t val;
+
+ rc = flex->ReadByte (reg_addr, &val);
+
+ if (rc != ONI_ESUCCESS)
+ return 0ull;
+
+ if (val <= 0xFF)
+ {
+ probeSN |= (((uint64_t) val) << (i * 8));
+ }
+ }
+ return probeSN;
}
void Neuropixels2e::startAcquisition()
{
- frameCount.fill(0);
- sampleNumber.fill(0);
+ frameCount.fill (0);
+ sampleNumber.fill (0);
}
void Neuropixels2e::stopAcquisition()
{
- setProbeSupply(false);
+ setProbeSupply (false);
- OnixDevice::stopAcquisition();
+ OnixDevice::stopAcquisition();
}
-void Neuropixels2e::addSourceBuffers(OwnedArray& sourceBuffers)
+void Neuropixels2e::addSourceBuffers (OwnedArray& sourceBuffers)
{
- if (m_numProbes == 1)
- {
- sourceBuffers.add(new DataBuffer(streamInfos.getFirst().getNumChannels(), (int)streamInfos.getFirst().getSampleRate() * bufferSizeInSeconds));
- auto bufferIndex = probeSN[0] != 0 ? 0 : 1;
- amplifierBuffer[bufferIndex] = sourceBuffers.getLast();
- }
- else
- {
- int bufferIdx = 0;
- for (const auto& streamInfo : streamInfos)
- {
- sourceBuffers.add(new DataBuffer(streamInfo.getNumChannels(), (int)streamInfo.getSampleRate() * bufferSizeInSeconds));
- amplifierBuffer[bufferIdx++] = sourceBuffers.getLast();
- }
- }
+ if (m_numProbes == 1)
+ {
+ sourceBuffers.add (new DataBuffer (streamInfos.getFirst().getNumChannels(), (int) streamInfos.getFirst().getSampleRate() * bufferSizeInSeconds));
+ auto bufferIndex = probeSN[0] != 0 ? 0 : 1;
+ amplifierBuffer[bufferIndex] = sourceBuffers.getLast();
+ }
+ else
+ {
+ int bufferIdx = 0;
+ for (const auto& streamInfo : streamInfos)
+ {
+ sourceBuffers.add (new DataBuffer (streamInfo.getNumChannels(), (int) streamInfo.getSampleRate() * bufferSizeInSeconds));
+ amplifierBuffer[bufferIdx++] = sourceBuffers.getLast();
+ }
+ }
}
void Neuropixels2e::processFrames()
{
- oni_frame_t* frame;
- while (frameQueue.try_dequeue(frame))
- {
- uint16_t* dataPtr = (uint16_t*)frame->data;
+ oni_frame_t* frame;
+ while (frameQueue.try_dequeue (frame))
+ {
+ uint16_t* dataPtr = (uint16_t*) frame->data;
- uint16_t probeIndex = *(dataPtr + 4);
- uint16_t* amplifierData = dataPtr + 9;
+ uint16_t probeIndex = *(dataPtr + 4);
+ uint16_t* amplifierData = dataPtr + 9;
- sampleNumbers[probeIndex][frameCount[probeIndex]] = sampleNumber[probeIndex]++;
- timestamps[probeIndex][frameCount[probeIndex]] = deviceContext->convertTimestampToSeconds(frame->time);
+ sampleNumbers[probeIndex][frameCount[probeIndex]] = sampleNumber[probeIndex]++;
+ timestamps[probeIndex][frameCount[probeIndex]] = deviceContext->convertTimestampToSeconds (frame->time);
- for (int i = 0; i < FramesPerSuperFrame; i++)
- {
- auto adcDataOffset = i * FrameWords;
+ for (int i = 0; i < FramesPerSuperFrame; i++)
+ {
+ auto adcDataOffset = i * FrameWords;
- for (int j = 0; j < AdcsPerProbe; j++)
- {
- const size_t channelIndex = rawToChannel[j][i];
+ for (int j = 0; j < AdcsPerProbe; j++)
+ {
+ const size_t channelIndex = rawToChannel[j][i];
- samples[probeIndex][channelIndex * numFrames + frameCount[probeIndex]] =
- (float)(*(amplifierData + adcIndices[j] + adcDataOffset)) * gainCorrection[probeIndex] + DataMidpoint;
- }
- }
+ samples[probeIndex][channelIndex * numFrames + frameCount[probeIndex]] =
+ (float) (*(amplifierData + adcIndices[j] + adcDataOffset)) * gainCorrection[probeIndex] + DataMidpoint;
+ }
+ }
- frameCount[probeIndex]++;
+ frameCount[probeIndex]++;
- if (frameCount[probeIndex] >= numFrames)
- {
- amplifierBuffer[probeIndex]->addToBuffer(samples[probeIndex].data(), sampleNumbers[probeIndex].data(), timestamps[probeIndex].data(), eventCodes[probeIndex].data(), numFrames);
- frameCount[probeIndex] = 0;
- }
+ if (frameCount[probeIndex] >= numFrames)
+ {
+ amplifierBuffer[probeIndex]->addToBuffer (samples[probeIndex].data(), sampleNumbers[probeIndex].data(), timestamps[probeIndex].data(), eventCodes[probeIndex].data(), numFrames);
+ frameCount[probeIndex] = 0;
+ }
- oni_destroy_frame(frame);
- }
+ oni_destroy_frame (frame);
+ }
}
-void Neuropixels2e::writeConfiguration(ProbeSettings* settings)
+void Neuropixels2e::writeConfiguration (ProbeSettings* settings)
{
- auto baseBits = makeBaseBits(getReference(settings->referenceIndex));
- writeShiftRegister(SR_CHAIN5, baseBits[0]);
- writeShiftRegister(SR_CHAIN6, baseBits[1]);
-
- auto shankBits = makeShankBits(getReference(settings->referenceIndex), settings->electrodeMetadata);
- writeShiftRegister(SR_CHAIN1, shankBits[0]);
- writeShiftRegister(SR_CHAIN2, shankBits[1]);
- writeShiftRegister(SR_CHAIN3, shankBits[2]);
- writeShiftRegister(SR_CHAIN4, shankBits[3]);
+ auto baseBits = makeBaseBits (getReference (settings->referenceIndex));
+ writeShiftRegister (SR_CHAIN5, baseBits[0]);
+ writeShiftRegister (SR_CHAIN6, baseBits[1]);
+
+ auto shankBits = makeShankBits (getReference (settings->referenceIndex), settings->electrodeMetadata);
+ writeShiftRegister (SR_CHAIN1, shankBits[0]);
+ writeShiftRegister (SR_CHAIN2, shankBits[1]);
+ writeShiftRegister (SR_CHAIN3, shankBits[2]);
+ writeShiftRegister (SR_CHAIN4, shankBits[3]);
}
-template
-void Neuropixels2e::writeShiftRegister(uint32_t srAddress, std::bitset bits)
+template
+void Neuropixels2e::writeShiftRegister (uint32_t srAddress, std::bitset bits)
{
- std::vector bytes = toBitReversedBytes(bits);
-
- for (int i = 2; i > 0; i -= 1)
- {
- WriteByte(SOFT_RESET, 0xFF);
- WriteByte(SOFT_RESET, 0x00);
-
- WriteByte(SR_LENGTH1, (uint32_t)(bytes.size() % 0x100));
- WriteByte(SR_LENGTH2, (uint32_t)(bytes.size() / 0x100));
-
- for (auto b : bytes)
- {
- WriteByte(srAddress, b);
- }
- }
-
- uint32_t status;
- ReadByte(STATUS, &status);
- if (status != (uint32_t)NeuropixelsV2Status::SR_OK)
- {
- LOGE("Warning: Shift register ", srAddress, " status check failed. ", getShankName(srAddress), " may be damaged.");
- }
+ std::vector bytes = toBitReversedBytes (bits);
+
+ for (int i = 2; i > 0; i -= 1)
+ {
+ WriteByte (SOFT_RESET, 0xFF);
+ WriteByte (SOFT_RESET, 0x00);
+
+ WriteByte (SR_LENGTH1, (uint32_t) (bytes.size() % 0x100));
+ WriteByte (SR_LENGTH2, (uint32_t) (bytes.size() / 0x100));
+
+ for (auto b : bytes)
+ {
+ WriteByte (srAddress, b);
+ }
+ }
+
+ uint32_t status;
+ ReadByte (STATUS, &status);
+ if (status != (uint32_t) NeuropixelsV2Status::SR_OK)
+ {
+ LOGE ("Warning: Shift register ", srAddress, " status check failed. ", getShankName (srAddress), " may be damaged.");
+ }
}
-std::string Neuropixels2e::getShankName(uint32_t shiftRegisterAddress)
+std::string Neuropixels2e::getShankName (uint32_t shiftRegisterAddress)
{
- switch (shiftRegisterAddress)
- {
- case SR_CHAIN1:
- return "Shank 1";
- case SR_CHAIN2:
- return "Shank 2";
- case SR_CHAIN3:
- return "Shank 3";
- case SR_CHAIN4:
- return "Shank 4";
- default:
- return "";
- }
+ switch (shiftRegisterAddress)
+ {
+ case SR_CHAIN1:
+ return "Shank 1";
+ case SR_CHAIN2:
+ return "Shank 2";
+ case SR_CHAIN3:
+ return "Shank 3";
+ case SR_CHAIN4:
+ return "Shank 4";
+ default:
+ return "";
+ }
}
-void Neuropixels2e::setGainCorrectionFile(int index, std::string filename)
+void Neuropixels2e::setGainCorrectionFile (int index, std::string filename)
{
- if (index < gainCorrectionFilePath.size())
- {
- gainCorrectionFilePath[index] = filename;
- }
+ if (index < gainCorrectionFilePath.size())
+ {
+ gainCorrectionFilePath[index] = filename;
+ }
}
-std::string Neuropixels2e::getGainCorrectionFile(int index)
+std::string Neuropixels2e::getGainCorrectionFile (int index)
{
- if (index < gainCorrectionFilePath.size())
- {
- return gainCorrectionFilePath[index];
- }
- else
- return "";
+ if (index < gainCorrectionFilePath.size())
+ {
+ return gainCorrectionFilePath[index];
+ }
+ else
+ return "";
}
-NeuropixelsV2Reference Neuropixels2e::getReference(int index)
+NeuropixelsV2Reference Neuropixels2e::getReference (int index)
{
- switch (index)
- {
- case 0:
- return NeuropixelsV2Reference::External;
- case 1:
- return NeuropixelsV2Reference::Tip1;
- case 2:
- return NeuropixelsV2Reference::Tip2;
- case 3:
- return NeuropixelsV2Reference::Tip3;
- case 4:
- return NeuropixelsV2Reference::Tip4;
- default:
- break;
- }
-
- return NeuropixelsV2Reference::External;
+ switch (index)
+ {
+ case 0:
+ return NeuropixelsV2Reference::External;
+ case 1:
+ return NeuropixelsV2Reference::Tip1;
+ case 2:
+ return NeuropixelsV2Reference::Tip2;
+ case 3:
+ return NeuropixelsV2Reference::Tip3;
+ case 4:
+ return NeuropixelsV2Reference::Tip4;
+ default:
+ break;
+ }
+
+ return NeuropixelsV2Reference::External;
}
-Neuropixels2e::BaseBitsArray Neuropixels2e::makeBaseBits(NeuropixelsV2Reference reference)
+Neuropixels2e::BaseBitsArray Neuropixels2e::makeBaseBits (NeuropixelsV2Reference reference)
{
- BaseBitsArray baseBits;
+ BaseBitsArray baseBits;
- int referenceBit;
+ int referenceBit;
- if (reference == NeuropixelsV2Reference::External)
- referenceBit = 1;
- else
- referenceBit = 2;
+ if (reference == NeuropixelsV2Reference::External)
+ referenceBit = 1;
+ else
+ referenceBit = 2;
- for (size_t i = 0; i < numberOfChannels; i++)
- {
- auto configIndex = i % 2;
- auto bitOffset = (382 - i + configIndex) / 2 * baseBitsPerChannel;
- baseBits[configIndex][bitOffset + 0] = false;
- baseBits[configIndex][bitOffset + referenceBit] = true;
- }
+ for (size_t i = 0; i < numberOfChannels; i++)
+ {
+ auto configIndex = i % 2;
+ auto bitOffset = (382 - i + configIndex) / 2 * baseBitsPerChannel;
+ baseBits[configIndex][bitOffset + 0] = false;
+ baseBits[configIndex][bitOffset + referenceBit] = true;
+ }
- return baseBits;
+ return baseBits;
}
-Neuropixels2e::ShankBitsArray Neuropixels2e::makeShankBits(NeuropixelsV2Reference reference, std::array channelMap)
+Neuropixels2e::ShankBitsArray Neuropixels2e::makeShankBits (NeuropixelsV2Reference reference, std::array channelMap)
{
- ShankBitsArray shankBits;
-
- if (reference != NeuropixelsV2Reference::External)
- {
- shankBits[(size_t)reference - 1][643] = true;
- shankBits[(size_t)reference - 1][644] = true;
- }
- else
- {
- shankBits[0][2] = true;
- shankBits[0][1285] = true;
- shankBits[1][2] = true;
- shankBits[1][1285] = true;
- shankBits[2][2] = true;
- shankBits[2][1285] = true;
- shankBits[3][2] = true;
- shankBits[3][1285] = true;
- }
-
- const int pixelOffset = (NeuropixelsV2eValues::electrodesPerShank - 1) / 2;
- const int referencePixelOffset = 3;
-
- int count = 0;
-
- for (const auto& e : channelMap)
- {
- if (e.status == ElectrodeStatus::CONNECTED)
- {
- auto baseIndex = e.shank_local_index % 2;
- auto pixelIndex = e.shank_local_index / 2;
- pixelIndex = baseIndex == 0
- ? pixelIndex + pixelOffset + 2 * referencePixelOffset
- : pixelOffset - pixelIndex + referencePixelOffset;
-
- shankBits[e.shank][pixelIndex] = true;
-
- count++;
- }
- }
-
- if (count != numberOfChannels)
- {
- LOGE("Invalid number of channels connected for Neuropixels 2.0e, configuration might be invalid.");
- }
-
- return shankBits;
+ ShankBitsArray shankBits;
+
+ if (reference != NeuropixelsV2Reference::External)
+ {
+ shankBits[(size_t) reference - 1][643] = true;
+ shankBits[(size_t) reference - 1][644] = true;
+ }
+ else
+ {
+ shankBits[0][2] = true;
+ shankBits[0][1285] = true;
+ shankBits[1][2] = true;
+ shankBits[1][1285] = true;
+ shankBits[2][2] = true;
+ shankBits[2][1285] = true;
+ shankBits[3][2] = true;
+ shankBits[3][1285] = true;
+ }
+
+ const int pixelOffset = (NeuropixelsV2eValues::electrodesPerShank - 1) / 2;
+ const int referencePixelOffset = 3;
+
+ int count = 0;
+
+ for (const auto& e : channelMap)
+ {
+ if (e.status == ElectrodeStatus::CONNECTED)
+ {
+ auto baseIndex = e.shank_local_index % 2;
+ auto pixelIndex = e.shank_local_index / 2;
+ pixelIndex = baseIndex == 0
+ ? pixelIndex + pixelOffset + 2 * referencePixelOffset
+ : pixelOffset - pixelIndex + referencePixelOffset;
+
+ shankBits[e.shank][pixelIndex] = true;
+
+ count++;
+ }
+ }
+
+ if (count != numberOfChannels)
+ {
+ LOGE ("Invalid number of channels connected for Neuropixels 2.0e, configuration might be invalid.");
+ }
+
+ return shankBits;
}
-void Neuropixels2e::setSettings(ProbeSettings* settings_, int index)
+void Neuropixels2e::setSettings (ProbeSettings* settings_, int index)
{
- if (index >= settings.size())
- {
- LOGE("Invalid index given when trying to update settings.");
- return;
- }
+ if (index >= settings.size())
+ {
+ LOGE ("Invalid index given when trying to update settings.");
+ return;
+ }
- settings[index]->updateProbeSettings(settings_);
+ settings[index]->updateProbeSettings (settings_);
}
-void Neuropixels2e::defineMetadata(ProbeSettings* settings, int shankCount)
+void Neuropixels2e::defineMetadata (ProbeSettings* settings, int shankCount)
{
- settings->probeType = ProbeType::NPX_V2;
- settings->probeMetadata.name = "Neuropixels 2.0e" + (shankCount == 1) ? " - Single Shank" : " - Quad Shank";
-
- constexpr float shankTipY = 0.0f;
- constexpr float shankBaseY = 155.0f;
- constexpr float shankLengthY = 10000.0f;
- constexpr float probeLengthY = 10155.0f;
- constexpr float shankOffsetX = 200.0f;
- constexpr float shankWidthX = 70.0f;
- constexpr float shankPitchX = 250.0f;
-
- std::vector> probeContour{
- {0, probeLengthY},
- {0, shankLengthY},
- };
-
- for (int i = 0; i < shankCount; i++)
- {
- probeContour.emplace_back(std::array{ shankOffsetX + (shankWidthX + shankPitchX) * i, shankLengthY });
- probeContour.emplace_back(std::array{ shankOffsetX + (shankWidthX + shankPitchX) * i, shankBaseY });
- probeContour.emplace_back(std::array{ shankOffsetX + (shankWidthX + shankPitchX) * i + shankWidthX / 2, shankTipY });
- probeContour.emplace_back(std::array{ shankOffsetX + (shankWidthX + shankPitchX) * i + shankWidthX, shankBaseY });
- probeContour.emplace_back(std::array{ shankOffsetX + (shankWidthX + shankPitchX) * i + shankWidthX, shankLengthY });
- }
-
- probeContour.emplace_back(std::array{shankOffsetX * 2 + (shankWidthX + shankPitchX) * (numberOfShanks - 1) + shankWidthX, shankLengthY});
- probeContour.emplace_back(std::array{shankOffsetX * 2 + (shankWidthX + shankPitchX) * (numberOfShanks - 1) + shankWidthX, probeLengthY});
- probeContour.emplace_back(std::array{0.0f, probeLengthY});
-
- std::vector> shankOutline{
- {27, 31},
- {27, 514},
- {27 + 5, 522},
- {27 + 10, 514},
- {27 + 10, 31}
- };
-
- settings->probeMetadata.shank_count = shankCount;
- settings->probeMetadata.electrodes_per_shank = NeuropixelsV2eValues::electrodesPerShank;
- settings->probeMetadata.rows_per_shank = NeuropixelsV2eValues::electrodesPerShank / 2;
- settings->probeMetadata.columns_per_shank = 2;
- settings->probeMetadata.shankOutline = shankOutline;
- settings->probeMetadata.probeContour = probeContour;
- settings->probeMetadata.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;
-
- metadata.global_index = i;
-
- metadata.shank = i / settings->probeMetadata.electrodes_per_shank;
- metadata.shank_local_index = i % settings->probeMetadata.electrodes_per_shank;
-
- auto offset = shankOffsetX + (shankWidthX + shankPitchX) * metadata.shank + 11.0f;
- metadata.xpos = offset + (i % 2) * 32.0f + 8.0f;
- metadata.ypos = std::floor((i % settings->probeMetadata.electrodes_per_shank) / 2.0f) * 15 + 170;
- metadata.site_width = 12;
-
- metadata.column_index = i % 2;
- metadata.row_index = metadata.shank_local_index / 2;
-
- metadata.isSelected = false;
-
- metadata.colour = Colours::lightgrey;
-
- if (shankCount == 1)
- {
- if (i < 384)
- {
- metadata.bank = Bank::A;
-
- int bank_index = metadata.shank_local_index % 384;
- int block = bank_index / 32;
- int row = (bank_index % 32) / 2;
-
- if (i % 2 == 0)
- {
- metadata.channel = row * 2 + block * 32;
- }
- else
- {
- metadata.channel = row * 2 + block * 32 + 1;
- }
-
- metadata.status = ElectrodeStatus::CONNECTED;
- }
- else if (i >= 384 && i < 768)
- {
- metadata.bank = Bank::B;
-
- int bank_index = metadata.shank_local_index % 384;
- int block = bank_index / 32;
- int row = (bank_index % 32) / 2;
-
- if (i % 2 == 0)
- {
- metadata.channel = ((row * 7) % 16) * 2 + block * 32;
- }
- else
- {
- metadata.channel = ((row * 7 + 4) % 16) * 2 + block * 32 + 1;
- }
-
- metadata.status = ElectrodeStatus::DISCONNECTED;
- }
- else if (i >= 768 && i < 1152)
- {
- metadata.bank = Bank::C;
-
- int bank_index = metadata.shank_local_index % 384;
- int block = bank_index / 32;
- int row = (bank_index % 32) / 2;
-
- if (i % 2 == 0)
- {
- metadata.channel = ((row * 5) % 16) * 2 + block * 32;
- }
- else
- {
- metadata.channel = ((row * 5 + 8) % 16) * 2 + block * 32 + 1;
- }
-
- metadata.status = ElectrodeStatus::DISCONNECTED;
- }
- else
- {
- metadata.bank = Bank::D;
-
- int bank_index = metadata.shank_local_index % 384;
- int block = bank_index / 32;
- int row = (bank_index % 32) / 2;
-
- if (i % 2 == 0)
- {
- metadata.channel = ((row * 3) % 16) * 2 + block * 32;
- }
- else
- {
- metadata.channel = ((row * 3 + 12) % 16) * 2 + block * 32 + 1;
- }
-
- metadata.status = ElectrodeStatus::DISCONNECTED;
- }
- }
- else if (shankCount == 4)
- {
- if (i < 384)
- {
- metadata.status = ElectrodeStatus::CONNECTED;
- }
- else
- {
- metadata.status = ElectrodeStatus::DISCONNECTED;
- }
-
- if (metadata.shank_local_index < 384)
- metadata.bank = Bank::A;
- else if (metadata.shank_local_index >= 384 && metadata.shank_local_index < 768)
- metadata.bank = Bank::B;
- else if (metadata.shank_local_index >= 768 && metadata.shank_local_index < 1152)
- metadata.bank = Bank::C;
- else
- metadata.bank = Bank::D;
-
- int block = metadata.shank_local_index % 384 / 48 + 1;
- int block_index = metadata.shank_local_index % 48;
-
- if (metadata.shank == 0)
- {
- switch (block)
- {
- case 1:
- metadata.channel = block_index + 48 * 0; // 1-48 (Bank 0-3)
- break;
- case 2:
- metadata.channel = block_index + 48 * 2; // 96-144 (Bank 0-3)
- break;
- case 3:
- metadata.channel = block_index + 48 * 4; // 192-223 (Bank 0-3)
- break;
- case 4:
- metadata.channel = block_index + 48 * 6; // 288-336 (Bank 0-2)
- break;
- case 5:
- metadata.channel = block_index + 48 * 5; // 240-288 (Bank 0-2)
- break;
- case 6:
- metadata.channel = block_index + 48 * 7; // 336-384 (Bank 0-2)
- break;
- case 7:
- metadata.channel = block_index + 48 * 1; // 48-96 (Bank 0-2)
- break;
- case 8:
- metadata.channel = block_index + 48 * 3; // 144-192 (Bank 0-2)
- break;
- default:
- metadata.channel = -1;
- }
- }
- else if (metadata.shank == 1)
- {
- switch (block)
- {
- case 1:
- metadata.channel = block_index + 48 * 1;
- break;
- case 2:
- metadata.channel = block_index + 48 * 3;
- break;
- case 3:
- metadata.channel = block_index + 48 * 5;
- break;
- case 4:
- metadata.channel = block_index + 48 * 7;
- break;
- case 5:
- metadata.channel = block_index + 48 * 4;
- break;
- case 6:
- metadata.channel = block_index + 48 * 6;
- break;
- case 7:
- metadata.channel = block_index + 48 * 0;
- break;
- case 8:
- metadata.channel = block_index + 48 * 2;
- break;
- default:
- metadata.channel = -1;
- }
- }
- else if (metadata.shank == 2)
- {
- switch (block)
- {
- case 1:
- metadata.channel = block_index + 48 * 4;
- break;
- case 2:
- metadata.channel = block_index + 48 * 6;
- break;
- case 3:
- metadata.channel = block_index + 48 * 0;
- break;
- case 4:
- metadata.channel = block_index + 48 * 2;
- break;
- case 5:
- metadata.channel = block_index + 48 * 1;
- break;
- case 6:
- metadata.channel = block_index + 48 * 3;
- break;
- case 7:
- metadata.channel = block_index + 48 * 5;
- break;
- case 8:
- metadata.channel = block_index + 48 * 7;
- break;
- default:
- metadata.channel = -1;
- }
- }
- else if (metadata.shank == 3)
- {
- switch (block)
- {
- case 1:
- metadata.channel = block_index + 48 * 5;
- break;
- case 2:
- metadata.channel = block_index + 48 * 7;
- break;
- case 3:
- metadata.channel = block_index + 48 * 1;
- break;
- case 4:
- metadata.channel = block_index + 48 * 3;
- break;
- case 5:
- metadata.channel = block_index + 48 * 0;
- break;
- case 6:
- metadata.channel = block_index + 48 * 2;
- break;
- case 7:
- metadata.channel = block_index + 48 * 4;
- break;
- case 8:
- metadata.channel = block_index + 48 * 6;
- break;
- default:
- metadata.channel = -1;
- }
- }
-
- metadata.type = ElectrodeType::ELECTRODE;
- }
-
- settings->electrodeMetadata[i] = metadata;
- }
-
- settings->apGainIndex = -1;
- settings->lfpGainIndex = -1;
- settings->referenceIndex = 0;
- settings->apFilterState = false;
-
- settings->electrodeConfigurationIndex = (int32_t)ElectrodeConfigurationSingleShank::BankA;
- auto selection = selectElectrodeConfiguration(settings->electrodeConfigurationIndex);
- settings->selectElectrodes(selection);
-
- settings->availableReferences.add("Ext");
- settings->availableReferences.add("Tip1");
-
- if (shankCount == 4)
- {
- settings->availableReferences.add("Tip2");
- settings->availableReferences.add("Tip3");
- settings->availableReferences.add("Tip4");
- }
-
- if (shankCount == 1)
- {
- for (const auto& [_, config] : electrodeConfigurationSingleShank)
- {
- settings->availableElectrodeConfigurations.add(config);
- }
- }
- else if (shankCount == 4)
- {
- for (const auto& [_, config] : electrodeConfigurationQuadShank)
- {
- settings->availableElectrodeConfigurations.add(config);
- }
- }
+ settings->probeType = ProbeType::NPX_V2;
+ settings->probeMetadata.name = "Neuropixels 2.0e" + (shankCount == 1) ? " - Single Shank" : " - Quad Shank";
+
+ constexpr float shankTipY = 0.0f;
+ constexpr float shankBaseY = 155.0f;
+ constexpr float shankLengthY = 10000.0f;
+ constexpr float probeLengthY = 10155.0f;
+ constexpr float shankOffsetX = 200.0f;
+ constexpr float shankWidthX = 70.0f;
+ constexpr float shankPitchX = 250.0f;
+
+ std::vector> probeContour {
+ { 0, probeLengthY },
+ { 0, shankLengthY },
+ };
+
+ for (int i = 0; i < shankCount; i++)
+ {
+ probeContour.emplace_back (std::array { shankOffsetX + (shankWidthX + shankPitchX) * i, shankLengthY });
+ probeContour.emplace_back (std::array { shankOffsetX + (shankWidthX + shankPitchX) * i, shankBaseY });
+ probeContour.emplace_back (std::array { shankOffsetX + (shankWidthX + shankPitchX) * i + shankWidthX / 2, shankTipY });
+ probeContour.emplace_back (std::array { shankOffsetX + (shankWidthX + shankPitchX) * i + shankWidthX, shankBaseY });
+ probeContour.emplace_back (std::array { shankOffsetX + (shankWidthX + shankPitchX) * i + shankWidthX, shankLengthY });
+ }
+
+ probeContour.emplace_back (std::array { shankOffsetX * 2 + (shankWidthX + shankPitchX) * (numberOfShanks - 1) + shankWidthX, shankLengthY });
+ probeContour.emplace_back (std::array { shankOffsetX * 2 + (shankWidthX + shankPitchX) * (numberOfShanks - 1) + shankWidthX, probeLengthY });
+ probeContour.emplace_back (std::array { 0.0f, probeLengthY });
+
+ std::vector> shankOutline {
+ { 27, 31 },
+ { 27, 514 },
+ { 27 + 5, 522 },
+ { 27 + 10, 514 },
+ { 27 + 10, 31 }
+ };
+
+ settings->probeMetadata.shank_count = shankCount;
+ settings->probeMetadata.electrodes_per_shank = NeuropixelsV2eValues::electrodesPerShank;
+ settings->probeMetadata.rows_per_shank = NeuropixelsV2eValues::electrodesPerShank / 2;
+ settings->probeMetadata.columns_per_shank = 2;
+ settings->probeMetadata.shankOutline = shankOutline;
+ settings->probeMetadata.probeContour = probeContour;
+ settings->probeMetadata.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;
+
+ metadata.global_index = i;
+
+ metadata.shank = i / settings->probeMetadata.electrodes_per_shank;
+ metadata.shank_local_index = i % settings->probeMetadata.electrodes_per_shank;
+
+ auto offset = shankOffsetX + (shankWidthX + shankPitchX) * metadata.shank + 11.0f;
+ metadata.xpos = offset + (i % 2) * 32.0f + 8.0f;
+ metadata.ypos = std::floor ((i % settings->probeMetadata.electrodes_per_shank) / 2.0f) * 15 + 170;
+ metadata.site_width = 12;
+
+ metadata.column_index = i % 2;
+ metadata.row_index = metadata.shank_local_index / 2;
+
+ metadata.isSelected = false;
+
+ metadata.colour = Colours::lightgrey;
+
+ if (shankCount == 1)
+ {
+ if (i < 384)
+ {
+ metadata.bank = Bank::A;
+
+ int bank_index = metadata.shank_local_index % 384;
+ int block = bank_index / 32;
+ int row = (bank_index % 32) / 2;
+
+ if (i % 2 == 0)
+ {
+ metadata.channel = row * 2 + block * 32;
+ }
+ else
+ {
+ metadata.channel = row * 2 + block * 32 + 1;
+ }
+
+ metadata.status = ElectrodeStatus::CONNECTED;
+ }
+ else if (i >= 384 && i < 768)
+ {
+ metadata.bank = Bank::B;
+
+ int bank_index = metadata.shank_local_index % 384;
+ int block = bank_index / 32;
+ int row = (bank_index % 32) / 2;
+
+ if (i % 2 == 0)
+ {
+ metadata.channel = ((row * 7) % 16) * 2 + block * 32;
+ }
+ else
+ {
+ metadata.channel = ((row * 7 + 4) % 16) * 2 + block * 32 + 1;
+ }
+
+ metadata.status = ElectrodeStatus::DISCONNECTED;
+ }
+ else if (i >= 768 && i < 1152)
+ {
+ metadata.bank = Bank::C;
+
+ int bank_index = metadata.shank_local_index % 384;
+ int block = bank_index / 32;
+ int row = (bank_index % 32) / 2;
+
+ if (i % 2 == 0)
+ {
+ metadata.channel = ((row * 5) % 16) * 2 + block * 32;
+ }
+ else
+ {
+ metadata.channel = ((row * 5 + 8) % 16) * 2 + block * 32 + 1;
+ }
+
+ metadata.status = ElectrodeStatus::DISCONNECTED;
+ }
+ else
+ {
+ metadata.bank = Bank::D;
+
+ int bank_index = metadata.shank_local_index % 384;
+ int block = bank_index / 32;
+ int row = (bank_index % 32) / 2;
+
+ if (i % 2 == 0)
+ {
+ metadata.channel = ((row * 3) % 16) * 2 + block * 32;
+ }
+ else
+ {
+ metadata.channel = ((row * 3 + 12) % 16) * 2 + block * 32 + 1;
+ }
+
+ metadata.status = ElectrodeStatus::DISCONNECTED;
+ }
+ }
+ else if (shankCount == 4)
+ {
+ if (i < 384)
+ {
+ metadata.status = ElectrodeStatus::CONNECTED;
+ }
+ else
+ {
+ metadata.status = ElectrodeStatus::DISCONNECTED;
+ }
+
+ if (metadata.shank_local_index < 384)
+ metadata.bank = Bank::A;
+ else if (metadata.shank_local_index >= 384 && metadata.shank_local_index < 768)
+ metadata.bank = Bank::B;
+ else if (metadata.shank_local_index >= 768 && metadata.shank_local_index < 1152)
+ metadata.bank = Bank::C;
+ else
+ metadata.bank = Bank::D;
+
+ int block = metadata.shank_local_index % 384 / 48 + 1;
+ int block_index = metadata.shank_local_index % 48;
+
+ if (metadata.shank == 0)
+ {
+ switch (block)
+ {
+ case 1:
+ metadata.channel = block_index + 48 * 0; // 1-48 (Bank 0-3)
+ break;
+ case 2:
+ metadata.channel = block_index + 48 * 2; // 96-144 (Bank 0-3)
+ break;
+ case 3:
+ metadata.channel = block_index + 48 * 4; // 192-223 (Bank 0-3)
+ break;
+ case 4:
+ metadata.channel = block_index + 48 * 6; // 288-336 (Bank 0-2)
+ break;
+ case 5:
+ metadata.channel = block_index + 48 * 5; // 240-288 (Bank 0-2)
+ break;
+ case 6:
+ metadata.channel = block_index + 48 * 7; // 336-384 (Bank 0-2)
+ break;
+ case 7:
+ metadata.channel = block_index + 48 * 1; // 48-96 (Bank 0-2)
+ break;
+ case 8:
+ metadata.channel = block_index + 48 * 3; // 144-192 (Bank 0-2)
+ break;
+ default:
+ metadata.channel = -1;
+ }
+ }
+ else if (metadata.shank == 1)
+ {
+ switch (block)
+ {
+ case 1:
+ metadata.channel = block_index + 48 * 1;
+ break;
+ case 2:
+ metadata.channel = block_index + 48 * 3;
+ break;
+ case 3:
+ metadata.channel = block_index + 48 * 5;
+ break;
+ case 4:
+ metadata.channel = block_index + 48 * 7;
+ break;
+ case 5:
+ metadata.channel = block_index + 48 * 4;
+ break;
+ case 6:
+ metadata.channel = block_index + 48 * 6;
+ break;
+ case 7:
+ metadata.channel = block_index + 48 * 0;
+ break;
+ case 8:
+ metadata.channel = block_index + 48 * 2;
+ break;
+ default:
+ metadata.channel = -1;
+ }
+ }
+ else if (metadata.shank == 2)
+ {
+ switch (block)
+ {
+ case 1:
+ metadata.channel = block_index + 48 * 4;
+ break;
+ case 2:
+ metadata.channel = block_index + 48 * 6;
+ break;
+ case 3:
+ metadata.channel = block_index + 48 * 0;
+ break;
+ case 4:
+ metadata.channel = block_index + 48 * 2;
+ break;
+ case 5:
+ metadata.channel = block_index + 48 * 1;
+ break;
+ case 6:
+ metadata.channel = block_index + 48 * 3;
+ break;
+ case 7:
+ metadata.channel = block_index + 48 * 5;
+ break;
+ case 8:
+ metadata.channel = block_index + 48 * 7;
+ break;
+ default:
+ metadata.channel = -1;
+ }
+ }
+ else if (metadata.shank == 3)
+ {
+ switch (block)
+ {
+ case 1:
+ metadata.channel = block_index + 48 * 5;
+ break;
+ case 2:
+ metadata.channel = block_index + 48 * 7;
+ break;
+ case 3:
+ metadata.channel = block_index + 48 * 1;
+ break;
+ case 4:
+ metadata.channel = block_index + 48 * 3;
+ break;
+ case 5:
+ metadata.channel = block_index + 48 * 0;
+ break;
+ case 6:
+ metadata.channel = block_index + 48 * 2;
+ break;
+ case 7:
+ metadata.channel = block_index + 48 * 4;
+ break;
+ case 8:
+ metadata.channel = block_index + 48 * 6;
+ break;
+ default:
+ metadata.channel = -1;
+ }
+ }
+
+ metadata.type = ElectrodeType::ELECTRODE;
+ }
+
+ settings->electrodeMetadata[i] = metadata;
+ }
+
+ settings->apGainIndex = -1;
+ settings->lfpGainIndex = -1;
+ settings->referenceIndex = 0;
+ settings->apFilterState = false;
+
+ settings->electrodeConfigurationIndex = (int32_t) ElectrodeConfigurationSingleShank::BankA;
+ auto selection = selectElectrodeConfiguration (settings->electrodeConfigurationIndex);
+ settings->selectElectrodes (selection);
+
+ settings->availableReferences.add ("Ext");
+ settings->availableReferences.add ("Tip1");
+
+ if (shankCount == 4)
+ {
+ settings->availableReferences.add ("Tip2");
+ settings->availableReferences.add ("Tip3");
+ settings->availableReferences.add ("Tip4");
+ }
+
+ if (shankCount == 1)
+ {
+ for (const auto& [_, config] : electrodeConfigurationSingleShank)
+ {
+ settings->availableElectrodeConfigurations.add (config);
+ }
+ }
+ else if (shankCount == 4)
+ {
+ for (const auto& [_, config] : electrodeConfigurationQuadShank)
+ {
+ settings->availableElectrodeConfigurations.add (config);
+ }
+ }
}
diff --git a/Source/Devices/Neuropixels2e.h b/Source/Devices/Neuropixels2e.h
index 00682a5..1e5f541 100644
--- a/Source/Devices/Neuropixels2e.h
+++ b/Source/Devices/Neuropixels2e.h
@@ -1,321 +1,338 @@
/*
- ------------------------------------------------------------------
+ ------------------------------------------------------------------
- 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 .
*/
#pragma once
-#include "../OnixDevice.h"
#include "../I2CRegisterContext.h"
#include "../NeuropixelsComponents.h"
+#include "../OnixDevice.h"
#include "DS90UB9x.h"
namespace OnixSourcePlugin
{
- enum class NeuropixelsV2Reference : uint32_t
- {
- External,
- Tip1,
- Tip2,
- Tip3,
- Tip4
- };
+enum class NeuropixelsV2Reference : uint32_t
+{
+ External,
+ Tip1,
+ Tip2,
+ Tip3,
+ Tip4
+};
+
+enum class NeuropixelsV2Status : uint32_t
+{
+ SR_OK = 1 << 7
+};
+
+/*
+ Configures and streams data from a Neuropixels 2.0e device (aka a configured raw deserializer)
+*/
+class Neuropixels2e : public INeuropixel,
+ public OnixDevice,
+ public I2CRegisterContext
+{
+public:
+ Neuropixels2e (std::string name, std::string hubName, const oni_dev_idx_t, std::shared_ptr);
+
+ ~Neuropixels2e();
- enum class NeuropixelsV2Status : uint32_t
- {
- SR_OK = 1 << 7
- };
+ int configureDevice() override;
+ bool updateSettings() override;
+ void startAcquisition() override;
+ void stopAcquisition() override;
+ void processFrames() override;
+ void addSourceBuffers (OwnedArray& sourceBuffers) override;
- /*
- Configures and streams data from a Neuropixels 2.0e device (aka a configured raw deserializer)
- */
- class Neuropixels2e : public INeuropixel,
- public OnixDevice,
- public I2CRegisterContext
- {
- public:
- Neuropixels2e(std::string name, std::string hubName, const oni_dev_idx_t, std::shared_ptr);
+ int getNumProbes() const;
- ~Neuropixels2e();
+ static const int baseBitsPerChannel = 4;
+ static const int configurationBitCount = NeuropixelsV2eValues::numberOfChannels * baseBitsPerChannel / 2;
- int configureDevice() override;
- bool updateSettings() override;
- void startAcquisition() override;
- void stopAcquisition() override;
- void processFrames() override;
- void addSourceBuffers(OwnedArray& sourceBuffers) override;
+ static const int referencePixelCount = 4;
+ static const int dummyPixelCount = 4;
+ static const int registersPerShank = NeuropixelsV2eValues::electrodesPerShank + referencePixelCount + dummyPixelCount;
- int getNumProbes() const;
+ using BaseBitsArray = std::array, 2>;
+ using ShankBitsArray = std::array, 4>;
- static const int baseBitsPerChannel = 4;
- static const int configurationBitCount = NeuropixelsV2eValues::numberOfChannels * baseBitsPerChannel / 2;
+ BaseBitsArray static makeBaseBits (NeuropixelsV2Reference reference);
+ ShankBitsArray static makeShankBits (NeuropixelsV2Reference reference, std::array channelMap);
- static const int referencePixelCount = 4;
- static const int dummyPixelCount = 4;
- static const int registersPerShank = NeuropixelsV2eValues::electrodesPerShank + referencePixelCount + dummyPixelCount;
-
- using BaseBitsArray = std::array, 2>;
- using ShankBitsArray = std::array, 4>;
-
- BaseBitsArray static makeBaseBits(NeuropixelsV2Reference reference);
- ShankBitsArray static makeShankBits(NeuropixelsV2Reference reference, std::array channelMap);
-
- template
- void writeShiftRegister(uint32_t srAddress, std::bitset bits);
-
- void setGainCorrectionFile(int index, std::string filename);
- std::string getGainCorrectionFile(int index);
-
- // INeuropixel Methods
-
- std::vector selectElectrodeConfiguration(int electrodeConfigurationIndex) override;
- uint64_t getProbeSerialNumber(int index) override;
- void defineMetadata(ProbeSettings*, int);
- void setSettings(ProbeSettings* settings_, int index) override;
- static OnixDeviceType getDeviceType();
-
- private:
-
- static constexpr int NumberOfProbes = 2;
-
- static constexpr uint16_t NumberOfAdcBins = 4096;
- static constexpr float DataMidpoint = NumberOfAdcBins / 2;
-
- DataBuffer* amplifierBuffer[NumberOfProbes];
-
- std::array probeSN;
- std::array gainCorrection;
- std::array gainCorrectionFilePath;
-
- void createDataStream(int n);
-
- uint64_t getProbeSN(uint8_t probeSelect);
- void configureSerDes();
- void setProbeSupply(bool);
- void resetProbes();
-
- void selectProbe(uint8_t probeSelect);
- void configureProbeStreaming();
- void writeConfiguration(ProbeSettings*);
-
- NeuropixelsV2Reference getReference(int);
- static std::string getShankName(uint32_t shiftRegisterAddress);
-
- void selectElectrodesInRange(std::vector& selection, int startIndex, int numberOfElectrodes);
- void selectElectrodesAcrossShanks(std::vector& selection, int startIndex, int numberOfElectrodes);
-
- int m_numProbes = 0;
-
- const float sampleRate = 30000.0f;
- static const int numFrames = 10;
- static const int numSamples = numberOfChannels * numFrames;
-
- std::array, NumberOfProbes> samples {};
-
- std::array, NumberOfProbes> sampleNumbers {};
- std::array