diff --git a/Source/Devices/AnalogIO.cpp b/Source/Devices/AnalogIO.cpp index 25db21c..4df8687 100644 --- a/Source/Devices/AnalogIO.cpp +++ b/Source/Devices/AnalogIO.cpp @@ -32,7 +32,7 @@ AnalogIO::AnalogIO(std::string name, std::string hubName, const oni_dev_idx_t de "Analog Input data", getStreamIdentifier(), getNumChannels(), - std::floor(AnalogIOFrequencyHz / framesToAverage), + getSampleRate(), "AnalogInput", ContinuousChannel::Type::ADC, getVoltsPerDivision(AnalogIOVoltageRange::TenVolts), // NB: +/- 10 Volts @@ -53,6 +53,11 @@ AnalogIO::AnalogIO(std::string name, std::string hubName, const oni_dev_idx_t de dataType = AnalogIODataType::Volts; } +int AnalogIO::getSampleRate() +{ + return std::floor(AnalogIOFrequencyHz / framesToAverage); +} + OnixDeviceType AnalogIO::getDeviceType() { return OnixDeviceType::ANALOGIO; @@ -109,6 +114,78 @@ float AnalogIO::getVoltsPerDivision(AnalogIOVoltageRange voltageRange) } } +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; + } + + return channelDirection[channelNumber]; +} + +std::string AnalogIO::getChannelDirection(AnalogIODirection direction) +{ + switch (direction) + { + case AnalogIODirection::Input: + return "Input"; + case AnalogIODirection::Output: + return "Output"; + default: + return ""; + } +} + +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; + } + + channelDirection[channelNumber] = direction; +} + +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; + } + + return channelVoltageRange[channelNumber]; +} + +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; + } + + channelVoltageRange[channelNumber] = direction; +} + +AnalogIODataType AnalogIO::getDataType() const +{ + return dataType; +} + +void AnalogIO::setDataType(AnalogIODataType type) +{ + dataType = type; +} + +int AnalogIO::getNumChannels() +{ + return numChannels; +} + void AnalogIO::startAcquisition() { currentFrame = 0; @@ -122,73 +199,81 @@ void AnalogIO::stopAcquisition() { while (!frameArray.isEmpty()) { - const GenericScopedLock frameLock(frameArray.getLock()); oni_destroy_frame(frameArray.removeAndReturn(0)); } } void AnalogIO::addFrame(oni_frame_t* frame) { - const GenericScopedLock frameLock(frameArray.getLock()); frameArray.add(frame); } +int AnalogIO::getNumberOfFrames() +{ + return frameArray.size(); +} + void AnalogIO::addSourceBuffers(OwnedArray& sourceBuffers) { sourceBuffers.add(new DataBuffer(streamInfos.getFirst().getNumChannels(), (int)streamInfos.getFirst().getSampleRate() * bufferSizeInSeconds)); analogInputBuffer = sourceBuffers.getLast(); } -void AnalogIO::processFrames() +void AnalogIO::processFrame(uint64_t eventWord) { - while (!frameArray.isEmpty()) - { - const GenericScopedLock frameLock(frameArray.getLock()); - oni_frame_t* frame = frameArray.removeAndReturn(0); + oni_frame_t* frame = frameArray.removeAndReturn(0); - 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]; + } + + currentAverageFrame++; + + if (currentAverageFrame >= framesToAverage) + { 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]; + analogInputSamples[currentFrame + i * numFrames] /= framesToAverage; } - currentAverageFrame++; + currentAverageFrame = 0; - if (currentAverageFrame >= framesToAverage) - { - for (size_t i = 0; i < numChannels; i++) - { - analogInputSamples[currentFrame + i * numFrames] /= framesToAverage; - } + timestamps[currentFrame] = deviceContext->convertTimestampToSeconds(frame->time); + sampleNumbers[currentFrame] = sampleNumber++; + eventCodes[currentFrame] = eventWord; - currentAverageFrame = 0; + currentFrame++; + } - timestamps[currentFrame] = deviceContext->convertTimestampToSeconds(frame->time); - sampleNumbers[currentFrame] = sampleNumber++; + oni_destroy_frame(frame); - currentFrame++; - } - - oni_destroy_frame(frame); + if (currentFrame >= numFrames) + { + shouldAddToBuffer = true; + currentFrame = 0; + } - if (currentFrame >= numFrames) - { - shouldAddToBuffer = true; - currentFrame = 0; - } + if (shouldAddToBuffer) + { + shouldAddToBuffer = false; + analogInputBuffer->addToBuffer(analogInputSamples.data(), sampleNumbers, timestamps, eventCodes, numFrames); - if (shouldAddToBuffer) - { - shouldAddToBuffer = false; - analogInputBuffer->addToBuffer(analogInputSamples.data(), sampleNumbers, timestamps, eventCodes, numFrames); + analogInputSamples.fill(0); + } +} - analogInputSamples.fill(0); - } +void AnalogIO::processFrames() +{ + while (!frameArray.isEmpty()) + { + processFrame(); } } diff --git a/Source/Devices/AnalogIO.h b/Source/Devices/AnalogIO.h index 8bd5c03..6f674a7 100644 --- a/Source/Devices/AnalogIO.h +++ b/Source/Devices/AnalogIO.h @@ -71,102 +71,46 @@ namespace OnixSourcePlugin public: AnalogIO(std::string name, std::string hubName, const oni_dev_idx_t, std::shared_ptr oni_ctx); - /** Configures the device so that it is ready to stream with default settings */ int configureDevice() override; - - /** Update the settings of the device */ bool updateSettings() override; - - /** Starts probe data streaming */ void startAcquisition() override; - - /** Stops probe data streaming*/ void stopAcquisition() override; - - /** Given the sourceBuffers from OnixSource, add all streams for the current device to the array */ void addSourceBuffers(OwnedArray& sourceBuffers) override; - void addFrame(oni_frame_t*) override; - void processFrames() override; - AnalogIODirection getChannelDirection(int channelNumber) - { - if (channelNumber > numChannels || channelNumber < 0) - { - LOGE("Channel number must be between 0 and " + std::to_string(channelNumber)); - return AnalogIODirection::Input; - } - - return channelDirection[channelNumber]; - } - - static std::string getChannelDirection(AnalogIODirection direction) - { - switch (direction) - { - case AnalogIODirection::Input: - return "Input"; - case AnalogIODirection::Output: - return "Output"; - default: - return ""; - } - } - - void setChannelDirection(int channelNumber, AnalogIODirection direction) - { - if (channelNumber > numChannels || channelNumber < 0) - { - LOGE("Channel number must be between 0 and " + std::to_string(channelNumber)); - return; - } - - channelDirection[channelNumber] = direction; - } - - AnalogIOVoltageRange getChannelVoltageRange(int channelNumber) - { - if (channelNumber > numChannels || channelNumber < 0) - { - LOGE("Channel number must be between 0 and " + std::to_string(channelNumber)); - return AnalogIOVoltageRange::FiveVolts; - } - - return channelVoltageRange[channelNumber]; - } - - void setChannelVoltageRange(int channelNumber, AnalogIOVoltageRange direction) - { - if (channelNumber > numChannels || channelNumber < 0) - { - LOGE("Channel number must be between 0 and " + std::to_string(channelNumber)); - return; - } - - channelVoltageRange[channelNumber] = direction; - } - - AnalogIODataType getDataType() const { return dataType; } - - void setDataType(AnalogIODataType type) { dataType = type; } - - int getNumChannels() { return numChannels; } + 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); + + int getNumChannels(); static OnixDeviceType getDeviceType(); + static constexpr int framesToAverage = 4; // NB: Downsampling from 100 kHz to 25 kHz + static int getSampleRate(); + + int getNumberOfFrames(); + private: DataBuffer* analogInputBuffer = nullptr; - static const int AnalogIOFrequencyHz = 100000; + static constexpr int AnalogIOFrequencyHz = 100000; - static const int numFrames = 25; - static const int framesToAverage = 4; // NB: Downsampling from 100 kHz to 25 kHz - static const int numChannels = 12; + static constexpr int numFrames = 25; + static constexpr int numChannels = 12; - static const int numberOfDivisions = 1 << 16; - const int dacMidScale = 1 << 15; + static constexpr int numberOfDivisions = 1 << 16; + static constexpr int dacMidScale = 1 << 15; std::array channelDirection; std::array channelVoltageRange; diff --git a/Source/Devices/AuxiliaryIO.cpp b/Source/Devices/AuxiliaryIO.cpp new file mode 100644 index 0000000..56c0775 --- /dev/null +++ b/Source/Devices/AuxiliaryIO.cpp @@ -0,0 +1,112 @@ +/* + ------------------------------------------------------------------ + + 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 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 . + +*/ + +#include "AuxiliaryIO.h" +#include "AnalogIO.h" +#include "DigitalIO.h" + +using namespace OnixSourcePlugin; + +AuxiliaryIO::AuxiliaryIO(std::string name, std::string hubName, const oni_dev_idx_t analogIndex, const oni_dev_idx_t digitalIndex, std::shared_ptr oni_ctx) + : CompositeDevice(name, hubName, AuxiliaryIO::getCompositeDeviceType(), createAuxiliaryIODevices(hubName, analogIndex, digitalIndex, oni_ctx), oni_ctx) +{ + analogIO = getDevice(OnixDeviceType::ANALOGIO); + digitalIO = getDevice(OnixDeviceType::DIGITALIO); +} + +// NB: This constructor assumes that the digitalIO device is located at one index above the analogIndex +AuxiliaryIO::AuxiliaryIO(std::string name, std::string hubName, const oni_dev_idx_t analogIndex, std::shared_ptr oni_ctx) + : AuxiliaryIO(name, hubName, analogIndex, analogIndex + 1, oni_ctx) +{ +} + +OnixDeviceVector AuxiliaryIO::createAuxiliaryIODevices(std::string hubName, const oni_dev_idx_t analogIndex, const oni_dev_idx_t digitalIndex, std::shared_ptr oni_ctx) +{ + OnixDeviceVector devices; + + devices.emplace_back(std::make_shared("AnalogIO", hubName, analogIndex, oni_ctx)); + devices.emplace_back(std::make_shared("DigitalIO", hubName, digitalIndex, oni_ctx)); + + return devices; +} + +bool AuxiliaryIO::isEnabled() const +{ + return analogIO->isEnabled(); +} + +void AuxiliaryIO::processFrames() +{ + if (!digitalIO->isEnabled() && !analogIO->isEnabled()) + { + return; + } + else if (!digitalIO->isEnabled()) + { + analogIO->processFrames(); + return; + } + else if (!analogIO->isEnabled()) + { + digitalIO->processFrames(); + while (digitalIO->hasEventWord()) + { + digitalIO->getEventWord(); + } + + return; + } + + digitalIO->processFrames(); + + while (analogIO->getNumberOfFrames() >= AnalogIO::framesToAverage && digitalIO->getNumberOfWords() >= 1) + { + auto eventWord = digitalIO->getEventWord(); + + for (int i = 0; i < AnalogIO::framesToAverage; i++) + { + analogIO->processFrame(eventWord); + } + + digitalIO->processFrames(); + } +} + +OnixDeviceType AuxiliaryIO::getDeviceType() +{ + return OnixDeviceType::COMPOSITE; +} + +CompositeDeviceType AuxiliaryIO::getCompositeDeviceType() +{ + return CompositeDeviceType::AUXILIARYIO; +} + +std::shared_ptr AuxiliaryIO::getAnalogIO() +{ + return analogIO; +} + +std::shared_ptr AuxiliaryIO::getDigitalIO() +{ + return digitalIO; +} diff --git a/Source/Devices/AuxiliaryIO.h b/Source/Devices/AuxiliaryIO.h new file mode 100644 index 0000000..794418f --- /dev/null +++ b/Source/Devices/AuxiliaryIO.h @@ -0,0 +1,62 @@ +/* + ------------------------------------------------------------------ + + 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 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 . + +*/ + +#pragma once + +#include "../OnixDevice.h" + +namespace OnixSourcePlugin +{ + class AnalogIO; + class DigitalIO; + + /* + Abstract device that configures and streams data from both an AnalogIO device and a DigitalIO device on a Breakout Board + */ + class AuxiliaryIO : public CompositeDevice + { + public: + + AuxiliaryIO(std::string name, std::string hubName, const oni_dev_idx_t analogIndex, std::shared_ptr oni_ctx); + + AuxiliaryIO(std::string name, std::string hubName, const oni_dev_idx_t analogIndex, const oni_dev_idx_t digitalIndex, std::shared_ptr oni_ctx); + + bool isEnabled() const override; + + static OnixDeviceType getDeviceType(); + static CompositeDeviceType getCompositeDeviceType(); + + std::shared_ptr getAnalogIO(); + std::shared_ptr getDigitalIO(); + + void processFrames() override; + + private: + + static OnixDeviceVector createAuxiliaryIODevices(std::string hubName, const oni_dev_idx_t analogIndex, const oni_dev_idx_t digitalIndex, std::shared_ptr oni_ctx); + + std::shared_ptr analogIO; + std::shared_ptr digitalIO; + + JUCE_LEAK_DETECTOR(AuxiliaryIO); + }; +} diff --git a/Source/Devices/Bno055.cpp b/Source/Devices/Bno055.cpp index 489d698..bf04c47 100644 --- a/Source/Devices/Bno055.cpp +++ b/Source/Devices/Bno055.cpp @@ -157,7 +157,6 @@ void Bno055::stopAcquisition() { while (!frameArray.isEmpty()) { - const GenericScopedLock frameLock(frameArray.getLock()); oni_destroy_frame(frameArray.removeAndReturn(0)); } @@ -167,7 +166,6 @@ void Bno055::stopAcquisition() void Bno055::addFrame(oni_frame_t* frame) { - const GenericScopedLock frameLock(frameArray.getLock()); frameArray.add(frame); } @@ -181,7 +179,6 @@ void Bno055::processFrames() { while (!frameArray.isEmpty()) { - const GenericScopedLock frameLock(frameArray.getLock()); oni_frame_t* frame = frameArray.removeAndReturn(0); int16_t* dataPtr = ((int16_t*)frame->data) + 4; diff --git a/Source/Devices/DeviceList.h b/Source/Devices/DeviceList.h index 85961f4..2e697e2 100644 --- a/Source/Devices/DeviceList.h +++ b/Source/Devices/DeviceList.h @@ -20,15 +20,15 @@ */ +#include "AuxiliaryIO.h" +#include "AnalogIO.h" #include "Bno055.h" +#include "DigitalIO.h" #include "DS90UB9x.h" +#include "HarpSyncInput.h" #include "HeadStageEEPROM.h" +#include "MemoryMonitor.h" #include "Neuropixels1f.h" #include "Neuropixels2e.h" -#include "MemoryMonitor.h" #include "OutputClock.h" -#include "HarpSyncInput.h" -#include "AnalogIO.h" -#include "DigitalIO.h" #include "PortController.h" -#include "PolledBno055.h" diff --git a/Source/Devices/DigitalIO.cpp b/Source/Devices/DigitalIO.cpp index 34457fe..a04aa21 100644 --- a/Source/Devices/DigitalIO.cpp +++ b/Source/Devices/DigitalIO.cpp @@ -21,6 +21,7 @@ */ #include "DigitalIO.h" +#include "AnalogIO.h" using namespace OnixSourcePlugin; @@ -39,7 +40,21 @@ int DigitalIO::configureDevice() if (deviceContext == nullptr || !deviceContext->isInitialized()) throw error_str("Device context is not initialized properly for " + getName()); - return deviceContext->writeRegister(deviceIdx, (uint32_t)DigitalIORegisters::ENABLE, (oni_reg_val_t)(isEnabled() ? 1 : 0)); + 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."); + + uint32_t periodTicks = baseFreqHz / (uint32_t)AnalogIO::getSampleRate(); + 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() @@ -55,20 +70,18 @@ void DigitalIO::stopAcquisition() { while (!frameArray.isEmpty()) { - const GenericScopedLock frameLock(frameArray.getLock()); oni_destroy_frame(frameArray.removeAndReturn(0)); } } -EventChannel::Settings DigitalIO::getEventChannelSettings() +EventChannel::Settings DigitalIO::getEventChannelSettings(DataStream* stream) { - // NB: The stream must be assigned before adding the channel 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", - nullptr, + stream, numButtons + numDigitalInputs }; @@ -77,16 +90,18 @@ EventChannel::Settings DigitalIO::getEventChannelSettings() void DigitalIO::addFrame(oni_frame_t* frame) { - const GenericScopedLock frameLock(frameArray.getLock()); frameArray.add(frame); } +int DigitalIO::getNumberOfWords() +{ + return eventWords.size(); +} + void DigitalIO::processFrames() { while (!frameArray.isEmpty()) { - const GenericScopedLock frameLock(frameArray.getLock()); - const GenericScopedLock digitalInputsLock(eventWords.getLock()); oni_frame_t* frame = frameArray.removeAndReturn(0); uint16_t* dataPtr = (uint16_t*)frame->data; @@ -97,11 +112,8 @@ void DigitalIO::processFrames() uint64_t portState = *(dataPtr + dataOffset); uint64_t buttonState = *(dataPtr + dataOffset + 1); - if (portState != 0 || buttonState != 0) - { - uint64_t ttlEventWord = (portState & 255) << 6 | (buttonState & 63); - eventWords.add(ttlEventWord); - } + uint64_t ttlEventWord = (buttonState & 0x3F) << 8 | (portState & 0xFF); + eventWords.add(ttlEventWord); oni_destroy_frame(frame); } @@ -109,8 +121,6 @@ void DigitalIO::processFrames() uint64_t DigitalIO::getEventWord() { - const GenericScopedLock digitalInputsLock(eventWords.getLock()); - if (eventWords.size() != 0) return eventWords.removeAndReturn(0); @@ -119,7 +129,5 @@ uint64_t DigitalIO::getEventWord() bool DigitalIO::hasEventWord() { - const GenericScopedLock digitalInputsLock(eventWords.getLock()); - return eventWords.size() > 0; } diff --git a/Source/Devices/DigitalIO.h b/Source/Devices/DigitalIO.h index 57849f8..920a07e 100644 --- a/Source/Devices/DigitalIO.h +++ b/Source/Devices/DigitalIO.h @@ -28,7 +28,10 @@ namespace OnixSourcePlugin { enum class DigitalIORegisters : uint32_t { - ENABLE = 0 + ENABLE = 0x0, + BASE_FREQ_HZ = 0x5, + DEAD_TICKS = 0x6, + SAMPLE_PERIOD = 0x7, }; enum class DigitalPortState : uint16_t @@ -45,6 +48,7 @@ namespace OnixSourcePlugin enum class BreakoutButtonState : uint16_t { + None = 0x0, Moon = 0x1, Triangle = 0x2, X = 0x4, @@ -60,44 +64,33 @@ namespace OnixSourcePlugin }; /* - Configures and streams data from an AnalogIO device on a Breakout Board + 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); - /** Configures the device so that it is ready to stream with default settings */ int configureDevice() override; - - /** Update the settings of the device */ bool updateSettings() override; - - /** Starts probe data streaming */ void startAcquisition() override; - - /** Stops probe data streaming*/ void stopAcquisition() override; - - /** Given the sourceBuffers from OnixSource, add all streams for the current device to the array */ void addSourceBuffers(OwnedArray& sourceBuffers) override {}; - - EventChannel::Settings getEventChannelSettings(); - void addFrame(oni_frame_t*) override; - void processFrames() override; - uint64_t getEventWord(); + EventChannel::Settings getEventChannelSettings(DataStream* stream); + int getNumberOfWords(); + uint64_t getEventWord(); bool hasEventWord(); static OnixDeviceType getDeviceType(); private: - static const int numDigitalInputs = 8; - static const int numButtons = 6; + static constexpr int numDigitalInputs = 8; + static constexpr int numButtons = 6; Array frameArray; Array eventWords; diff --git a/Source/Devices/HarpSyncInput.cpp b/Source/Devices/HarpSyncInput.cpp index c73ee76..5c0b31b 100644 --- a/Source/Devices/HarpSyncInput.cpp +++ b/Source/Devices/HarpSyncInput.cpp @@ -76,14 +76,12 @@ void HarpSyncInput::stopAcquisition() { while (!frameArray.isEmpty()) { - const GenericScopedLock frameLock(frameArray.getLock()); oni_destroy_frame(frameArray.removeAndReturn(0)); } } void HarpSyncInput::addFrame(oni_frame_t* frame) { - const GenericScopedLock frameLock(frameArray.getLock()); frameArray.add(frame); } @@ -97,7 +95,6 @@ void HarpSyncInput::processFrames() { while (!frameArray.isEmpty()) { - const GenericScopedLock frameLock(frameArray.getLock()); oni_frame_t* frame = frameArray.removeAndReturn(0); uint32_t* dataPtr = (uint32_t*)frame->data; diff --git a/Source/Devices/MemoryMonitor.cpp b/Source/Devices/MemoryMonitor.cpp index ac81cd7..0926dae 100644 --- a/Source/Devices/MemoryMonitor.cpp +++ b/Source/Devices/MemoryMonitor.cpp @@ -143,14 +143,12 @@ void MemoryMonitor::stopAcquisition() { while (!frameArray.isEmpty()) { - const GenericScopedLock frameLock(frameArray.getLock()); oni_destroy_frame(frameArray.removeAndReturn(0)); } } void MemoryMonitor::addFrame(oni_frame_t* frame) { - const GenericScopedLock frameLock(frameArray.getLock()); frameArray.add(frame); } @@ -169,7 +167,6 @@ void MemoryMonitor::processFrames() { while (!frameArray.isEmpty()) { - const GenericScopedLock frameLock(frameArray.getLock()); oni_frame_t* frame = frameArray.removeAndReturn(0); uint32_t* dataPtr = (uint32_t*)frame->data; @@ -184,10 +181,6 @@ void MemoryMonitor::processFrames() sampleNumbers[currentFrame] = sampleNumber++; - prevWord = m_digitalIO != nullptr && m_digitalIO->hasEventWord() ? m_digitalIO->getEventWord() : prevWord; - - eventCodes[currentFrame] = prevWord; - currentFrame++; if (currentFrame >= numFrames) diff --git a/Source/Devices/MemoryMonitor.h b/Source/Devices/MemoryMonitor.h index fe99bdb..b5c5b48 100644 --- a/Source/Devices/MemoryMonitor.h +++ b/Source/Devices/MemoryMonitor.h @@ -27,8 +27,6 @@ namespace OnixSourcePlugin { - class DigitalIO; - enum class MemoryMonitorRegisters : uint32_t { ENABLE = 0, @@ -66,18 +64,12 @@ namespace OnixSourcePlugin float getLastPercentUsedValue(); - void setDigitalIO(std::shared_ptr digitalIO) { m_digitalIO = digitalIO; } - static OnixDeviceType getDeviceType(); private: DataBuffer* percentUsedBuffer; - std::shared_ptr m_digitalIO; - - uint64_t prevWord = 0; - static const int numFrames = 10; Array frameArray; diff --git a/Source/Devices/Neuropixels1e.cpp b/Source/Devices/Neuropixels1e.cpp index a5f2e2a..97c7a60 100644 --- a/Source/Devices/Neuropixels1e.cpp +++ b/Source/Devices/Neuropixels1e.cpp @@ -268,7 +268,6 @@ void Neuropixels1e::stopAcquisition() while (!frameArray.isEmpty()) { - const GenericScopedLock frameLock(frameArray.getLock()); oni_destroy_frame(frameArray.removeAndReturn(0)); } } @@ -288,7 +287,6 @@ void Neuropixels1e::addSourceBuffers(OwnedArray& sourceBuffers) void Neuropixels1e::addFrame(oni_frame_t* frame) { - const GenericScopedLock frameLock(frameArray.getLock()); frameArray.add(frame); } @@ -299,7 +297,6 @@ void Neuropixels1e::processFrames() while (!frameArray.isEmpty()) { - const GenericScopedLock frameLock(frameArray.getLock()); oni_frame_t* frame = frameArray.removeAndReturn(0); uint16_t* dataPtr = (uint16_t*)frame->data; diff --git a/Source/Devices/Neuropixels1f.cpp b/Source/Devices/Neuropixels1f.cpp index 549609a..7f7e0ff 100644 --- a/Source/Devices/Neuropixels1f.cpp +++ b/Source/Devices/Neuropixels1f.cpp @@ -223,7 +223,6 @@ void Neuropixels1f::stopAcquisition() while (!frameArray.isEmpty()) { - const GenericScopedLock frameLock(frameArray.getLock()); oni_destroy_frame(frameArray.removeAndReturn(0)); } } @@ -243,7 +242,6 @@ void Neuropixels1f::addSourceBuffers(OwnedArray& sourceBuffers) void Neuropixels1f::addFrame(oni_frame_t* frame) { - const GenericScopedLock frameLock(frameArray.getLock()); frameArray.add(frame); } @@ -254,7 +252,6 @@ void Neuropixels1f::processFrames() while (!frameArray.isEmpty()) { - const GenericScopedLock frameLock(frameArray.getLock()); oni_frame_t* frame = frameArray.removeAndReturn(0); uint16_t* dataPtr = (uint16_t*)frame->data; diff --git a/Source/Devices/Neuropixels2e.cpp b/Source/Devices/Neuropixels2e.cpp index 2ec186f..3f6466f 100644 --- a/Source/Devices/Neuropixels2e.cpp +++ b/Source/Devices/Neuropixels2e.cpp @@ -493,14 +493,12 @@ void Neuropixels2e::stopAcquisition() while (!frameArray.isEmpty()) { - const GenericScopedLock frameLock(frameArray.getLock()); oni_destroy_frame(frameArray.removeAndReturn(0)); } } void Neuropixels2e::addFrame(oni_frame_t* frame) { - const GenericScopedLock frameLock(frameArray.getLock()); frameArray.add(frame); } @@ -527,7 +525,6 @@ void Neuropixels2e::processFrames() { while (!frameArray.isEmpty()) { - const GenericScopedLock frameLock(frameArray.getLock()); oni_frame_t* frame = frameArray.removeAndReturn(0); uint16_t* dataPtr = (uint16_t*)frame->data; diff --git a/Source/Devices/PortController.cpp b/Source/Devices/PortController.cpp index 11abff1..4b26093 100644 --- a/Source/Devices/PortController.cpp +++ b/Source/Devices/PortController.cpp @@ -103,14 +103,12 @@ void PortController::stopAcquisition() { while (!frameArray.isEmpty()) { - const GenericScopedLock frameLock(frameArray.getLock()); oni_destroy_frame(frameArray.removeAndReturn(0)); } } void PortController::addFrame(oni_frame_t* frame) { - const GenericScopedLock frameLock(frameArray.getLock()); frameArray.add(frame); } @@ -118,7 +116,6 @@ void PortController::processFrames() { while (!frameArray.isEmpty()) { - const GenericScopedLock frameLock(frameArray.getLock()); oni_frame_t* frame = frameArray.removeAndReturn(0); int8_t* dataPtr = (int8_t*)frame->data; diff --git a/Source/FrameReader.cpp b/Source/FrameReader.cpp index 16500fd..e66faba 100644 --- a/Source/FrameReader.cpp +++ b/Source/FrameReader.cpp @@ -50,7 +50,7 @@ void FrameReader::run() for (const auto& source : sources) { - if (frame->dev_idx == source->getDeviceIdx(true)) + if (source->compareIndex(frame->dev_idx)) { source->addFrame(frame); destroyFrame = false; diff --git a/Source/NeuropixelsComponents.h b/Source/NeuropixelsComponents.h index 1af947c..900337a 100644 --- a/Source/NeuropixelsComponents.h +++ b/Source/NeuropixelsComponents.h @@ -33,15 +33,6 @@ namespace OnixSourcePlugin { - enum class VisualizationMode - { - ENABLE_VIEW, - AP_GAIN_VIEW, - LFP_GAIN_VIEW, - REFERENCE_VIEW, - ACTIVITY_VIEW - }; - enum class ProbeType { NONE = 1, diff --git a/Source/OnixDevice.cpp b/Source/OnixDevice.cpp index 4597b3a..892a05b 100644 --- a/Source/OnixDevice.cpp +++ b/Source/OnixDevice.cpp @@ -222,3 +222,146 @@ Array OnixDevice::getUniquePorts(std::vector indices) return ports; } + +bool OnixDevice::compareIndex(uint32_t index) +{ + return index == deviceIdx; +} + +CompositeDevice::CompositeDevice(std::string name_, std::string hubName, CompositeDeviceType type_, OnixDeviceVector devices_, std::shared_ptr oni_ctx) + : OnixDevice(name_, hubName, OnixDeviceType::COMPOSITE, devices_.at(0)->getDeviceIdx(), oni_ctx) +{ + compositeType = type_; + devices = devices_; +} + +CompositeDeviceType CompositeDevice::getCompositeDeviceType() const +{ + return compositeType; +} + +bool CompositeDevice::compareIndex(uint32_t index) +{ + for (const auto& device : devices) + { + if (device->getDeviceIdx() == index) + return true; + } + + return false; +} + +bool CompositeDevice::isEnabled() const +{ + bool enabled = true; + + for (const auto& device : devices) + { + enabled &= device->isEnabled(); + } + + return enabled; +} + +bool CompositeDevice::isEnabled(uint32_t index) +{ + for (const auto& device : devices) + { + if (device->compareIndex(index)) + return device->isEnabled(); + } + + Onix1::showWarningMessageBoxAsync( + "Unknown Index", + "Could not get the enabled status of a device at index " + std::to_string(index) + ", it was not found in " + getName() + ); + + return false; +} + +void CompositeDevice::setEnabled(bool newState) +{ + for (const auto& device : devices) + { + device->setEnabled(newState); + } +} + +void CompositeDevice::setEnabled(uint32_t index, bool newState) +{ + for (const auto& device : devices) + { + if (device->compareIndex(index)) + { + device->setEnabled(newState); + return; + } + } + + Onix1::showWarningMessageBoxAsync( + "Unknown Index", + "Could not set the enabled status of a device at index " + std::to_string(index) + ", it was not found in " + getName() + ); + + return; +} + +int CompositeDevice::configureDevice() +{ + int result = ONI_ESUCCESS; + + for (const auto& device : devices) + { + result |= device->configureDevice(); + } + + return result; +} + +bool CompositeDevice::updateSettings() +{ + bool result = true; + + for (const auto& device : devices) + { + result &= device->updateSettings(); + } + + return result; +} + +void CompositeDevice::startAcquisition() +{ + for (const auto& device : devices) + { + device->startAcquisition(); + } +} + +void CompositeDevice::stopAcquisition() +{ + for (const auto& device : devices) + { + device->stopAcquisition(); + } +} + +void CompositeDevice::addSourceBuffers(OwnedArray& sourceBuffers) +{ + for (const auto& device : devices) + { + device->addSourceBuffers(sourceBuffers); + } +} + +void CompositeDevice::addFrame(oni_frame_t* frame) +{ + for (const auto& device : devices) + { + if (device->compareIndex(frame->dev_idx)) + { + device->addFrame(frame); + return; + } + } +} diff --git a/Source/OnixDevice.h b/Source/OnixDevice.h index 59737bd..b8dcad4 100644 --- a/Source/OnixDevice.h +++ b/Source/OnixDevice.h @@ -51,6 +51,7 @@ namespace OnixSourcePlugin HARPSYNCINPUT, ANALOGIO, DIGITALIO, + COMPOSITE, }; struct StreamInfo { @@ -157,18 +158,17 @@ namespace OnixSourcePlugin virtual void addFrame(oni_frame_t*) {}; virtual void processFrames() {}; - - const std::string getName() { return name; } - bool isEnabled() const { return enabled; } - void setEnabled(bool newState) { enabled = newState; } - oni_dev_idx_t getDeviceIdx(bool getPassthroughIndex = false); - virtual int configureDevice() { return -1; }; virtual bool updateSettings() { return false; }; virtual void startAcquisition() {}; virtual void stopAcquisition() {}; - /** Given the sourceBuffers from OnixSource, add all streams for the current device to the array */ virtual void addSourceBuffers(OwnedArray& sourceBuffers) {}; + virtual bool compareIndex(uint32_t index); + + const std::string getName() { return name; } + virtual bool isEnabled() const { return enabled; } + virtual void setEnabled(bool newState) { enabled = newState; } + oni_dev_idx_t getDeviceIdx(bool getPassthroughIndex = false); /** Creates a stream name using the provided inputs, returning a string following the pattern: name[0]-name[1]-name[2]-etc., with all spaces removed */ static std::string createStreamName(std::vector names); @@ -227,5 +227,55 @@ namespace OnixSourcePlugin JUCE_LEAK_DETECTOR(OnixDevice); }; + enum class CompositeDeviceType { + AUXILIARYIO = 0 + }; + using OnixDeviceVector = std::vector>; + + /* + Abstract device that contains two or more devices + */ + class CompositeDevice : public OnixDevice + { + public: + + CompositeDevice(std::string name_, std::string hubName, CompositeDeviceType type_, OnixDeviceVector devices_, std::shared_ptr oni_ctx); + + CompositeDeviceType getCompositeDeviceType() const; + + bool compareIndex(uint32_t index) override; + bool isEnabled() const override; + bool isEnabled(uint32_t index); + void setEnabled(bool newState) override; + void setEnabled(uint32_t index, bool newState); + int configureDevice() override; + bool updateSettings() override; + void startAcquisition() override; + void stopAcquisition() override; + void addSourceBuffers(OwnedArray& sourceBuffers) override; + void addFrame(oni_frame_t*) override; + + template + std::shared_ptr getDevice(OnixDeviceType deviceType) + { + for (const auto& device : devices) + { + if (device->getDeviceType() == deviceType) + return std::static_pointer_cast(device); + } + + return nullptr; + } + + protected: + + OnixDeviceVector devices; + + CompositeDeviceType compositeType; + + private: + + JUCE_LEAK_DETECTOR(CompositeDevice); + }; } diff --git a/Source/OnixSource.cpp b/Source/OnixSource.cpp index c73a9ab..7e0c76f 100644 --- a/Source/OnixSource.cpp +++ b/Source/OnixSource.cpp @@ -358,14 +358,8 @@ bool OnixSource::initializeDevices(device_map_t deviceTable, bool updateStreamIn return false; } - devicesFound = configureDevice(sources, editor, "Analog IO", BREAKOUT_BOARD_NAME, AnalogIO::getDeviceType(), hubIndex + 6, context); - if (!devicesFound) - { - sources.clear(); - return false; - } - - devicesFound = configureDevice(sources, editor, "Digital IO", BREAKOUT_BOARD_NAME, DigitalIO::getDeviceType(), hubIndex + 7, context); + // NB: Configures AnalogIO and DigitalIO + devicesFound = configureDevice(sources, editor, "Auxiliary IO", BREAKOUT_BOARD_NAME, AuxiliaryIO::getDeviceType(), hubIndex + 6, context); if (!devicesFound) { sources.clear(); @@ -786,8 +780,6 @@ void OnixSource::updateSettings(OwnedArray* continuousChannel updateSourceBuffers(); - std::shared_ptr digitalIO = std::static_pointer_cast(getDevice(OnixDeviceType::DIGITALIO, BREAKOUT_BOARD_OFFSET)); - if (devicesFound) { for (const auto& source : sources) @@ -857,29 +849,6 @@ void OnixSource::updateSettings(OwnedArray* continuousChannel deviceInfos->add(new DeviceInfo(deviceSettings)); addIndividualStreams(source->streamInfos, dataStreams, deviceInfos, continuousChannels); - - if (digitalIO != nullptr && digitalIO->isEnabled()) - { - auto ttlChannelSettings = digitalIO->getEventChannelSettings(); - ttlChannelSettings.stream = dataStreams->getLast(); - eventChannels->add(new EventChannel(ttlChannelSettings)); - - std::static_pointer_cast(source)->setDigitalIO(digitalIO); - } - } - else if (source->getDeviceType() == OnixDeviceType::ANALOGIO) - { - DeviceInfo::Settings deviceSettings{ - source->getName(), - "Analog IO", - "analogio", - "0000000", - "" - }; - - deviceInfos->add(new DeviceInfo(deviceSettings)); - - addIndividualStreams(source->streamInfos, dataStreams, deviceInfos, continuousChannels); } else if (source->getDeviceType() == OnixDeviceType::HARPSYNCINPUT) { @@ -909,6 +878,48 @@ void OnixSource::updateSettings(OwnedArray* continuousChannel addIndividualStreams(source->streamInfos, dataStreams, deviceInfos, continuousChannels); } + else if (source->getDeviceType() == OnixDeviceType::OUTPUTCLOCK) + { + continue; + } + else if (source->getDeviceType() == OnixDeviceType::COMPOSITE) + { + auto compositeDevice = std::static_pointer_cast(source); + + if (compositeDevice->getCompositeDeviceType() == CompositeDeviceType::AUXILIARYIO) + { + DeviceInfo::Settings deviceSettings{ + source->getName(), + "Auxiliary device containing analog and digital IO data", + "auxiliaryio", + "0000000", + "" + }; + + deviceInfos->add(new DeviceInfo(deviceSettings)); + + auto auxiliaryIO = std::static_pointer_cast(compositeDevice); + + addIndividualStreams(auxiliaryIO->getAnalogIO()->streamInfos, dataStreams, deviceInfos, continuousChannels); + + auto eventChannelSettings = auxiliaryIO->getDigitalIO()->getEventChannelSettings(dataStreams->getLast()); + eventChannels->add(new EventChannel(eventChannelSettings)); + } + else + { + Onix1::showWarningMessageBoxAsync( + "Unknown Composite Source", + "Found an unknown composite source (" + source->getName() + ") on hub " + source->getHubName() + + " at address " + std::to_string(source->getDeviceIdx())); + } + } + else + { + Onix1::showWarningMessageBoxAsync( + "Unknown Source", + "Found an unknown source (" + source->getName() + ") on hub " + source->getHubName() + + " at address " + std::to_string(source->getDeviceIdx())); + } } } } @@ -1111,14 +1122,14 @@ bool OnixSource::stopAcquisition() if (!portA->getErrorFlag() && !portB->getErrorFlag()) waitForThreadToExit(2000); + oni_size_t reg = 0; + context->setOption(ONI_OPT_RUNNING, reg); + for (const auto& source : enabledSources) { source->stopAcquisition(); } - oni_size_t reg = 0; - context->setOption(ONI_OPT_RUNNING, reg); - for (auto buffers : sourceBuffers) buffers->clear(); @@ -1165,8 +1176,5 @@ bool OnixSource::updateBuffer() if (threadShouldExit()) return true; } - portA->processFrames(); - portB->processFrames(); - return !portA->getErrorFlag() && !portB->getErrorFlag(); } diff --git a/Source/OnixSourceCanvas.cpp b/Source/OnixSourceCanvas.cpp index 322521d..40110f2 100644 --- a/Source/OnixSourceCanvas.cpp +++ b/Source/OnixSourceCanvas.cpp @@ -23,6 +23,7 @@ #include "OnixSourceCanvas.h" #include "OnixSource.h" #include "OnixSourceEditor.h" +#include "UI/SettingsInterface.h" using namespace OnixSourcePlugin; @@ -54,6 +55,13 @@ void OnixSourceCanvas::addHub(std::string hubName, int offset) CustomTabComponent* tab = nullptr; OnixDeviceVector devices; PortName port = PortController::getPortFromIndex(offset); + auto context = source->getContext(); + + if (context == nullptr || !context->isInitialized()) + { + Onix1::showWarningMessageBoxAsync("Invalid Context", "Unable to find an initialized context when adding hubs to the canvas."); + return; + } if (hubName == NEUROPIXELSV1E_HEADSTAGE_NAME) { @@ -61,25 +69,24 @@ void OnixSourceCanvas::addHub(std::string hubName, int offset) const int passthroughIndex = (offset >> 8) + 7; - devices.emplace_back(std::make_shared("Probe", hubName, passthroughIndex, source->getContext())); - devices.emplace_back(std::make_shared("BNO055", hubName, passthroughIndex, source->getContext())); + devices.emplace_back(std::make_shared("Probe", hubName, passthroughIndex, context)); + devices.emplace_back(std::make_shared("BNO055", hubName, passthroughIndex, context)); } else if (hubName == NEUROPIXELSV1F_HEADSTAGE_NAME) { tab = addTopLevelTab(getTopLevelTabName(port, hubName), (int)port); - devices.emplace_back(std::make_shared("Probe0", hubName, offset, source->getContext())); - devices.emplace_back(std::make_shared("Probe1", hubName, offset + 1, source->getContext())); - devices.emplace_back(std::make_shared("BNO055", hubName, offset + 2, source->getContext())); + devices.emplace_back(std::make_shared("Probe0", hubName, offset, context)); + devices.emplace_back(std::make_shared("Probe1", hubName, offset + 1, context)); + devices.emplace_back(std::make_shared("BNO055", hubName, offset + 2, context)); } else if (hubName == BREAKOUT_BOARD_NAME) { tab = addTopLevelTab(hubName, 0); - devices.emplace_back(std::make_shared("Output Clock", hubName, 5, source->getContext())); - devices.emplace_back(std::make_shared("Analog IO", hubName, 6, source->getContext())); - devices.emplace_back(std::make_shared("Digital IO", hubName, 7, source->getContext())); - devices.emplace_back(std::make_shared("Harp Sync Input", hubName, 12, source->getContext())); + devices.emplace_back(std::make_shared("Auxiliary IO", hubName, 6, 7, context)); + devices.emplace_back(std::make_shared("Harp Sync Input", hubName, 12, context)); + devices.emplace_back(std::make_shared("Output Clock", hubName, 5, context)); } else if (hubName == NEUROPIXELSV2E_HEADSTAGE_NAME) { @@ -87,8 +94,8 @@ void OnixSourceCanvas::addHub(std::string hubName, int offset) tab = addTopLevelTab(getTopLevelTabName(port, hubName), (int)port); - devices.emplace_back(std::make_shared("", hubName, passthroughIndex, source->getContext())); - devices.emplace_back(std::make_shared("BNO055", hubName, passthroughIndex, source->getContext())); + devices.emplace_back(std::make_shared("", hubName, passthroughIndex, context)); + devices.emplace_back(std::make_shared("BNO055", hubName, passthroughIndex, context)); } if (tab != nullptr && devices.size() > 0) @@ -143,16 +150,6 @@ void OnixSourceCanvas::populateSourceTabs(CustomTabComponent* tab, OnixDeviceVec auto harpSyncInputInterface = std::make_shared(std::static_pointer_cast(device), editor, this); addInterfaceToTab(device->getName(), tab, harpSyncInputInterface); } - else if (device->getDeviceType() == OnixDeviceType::ANALOGIO) - { - auto analogIOInterface = std::make_shared(std::static_pointer_cast(device), editor, this); - addInterfaceToTab(device->getName(), tab, analogIOInterface); - } - else if (device->getDeviceType() == OnixDeviceType::DIGITALIO) - { - auto digitalIOInterface = std::make_shared(std::static_pointer_cast(device), editor, this); - addInterfaceToTab(device->getName(), tab, digitalIOInterface); - } else if (device->getDeviceType() == OnixDeviceType::NEUROPIXELSV2E) { auto npxv2eInterface = std::make_shared(std::static_pointer_cast(device), editor, this); @@ -165,6 +162,26 @@ void OnixSourceCanvas::populateSourceTabs(CustomTabComponent* tab, OnixDeviceVec auto polledBnoInterface = std::make_shared(std::static_pointer_cast(device), editor, this); addInterfaceToTab(device->getName(), tab, polledBnoInterface); } + else if (device->getDeviceType() == OnixDeviceType::COMPOSITE) + { + auto compositeDevice = std::static_pointer_cast(device); + + if (compositeDevice->getCompositeDeviceType() == CompositeDeviceType::AUXILIARYIO) + { + auto auxiliaryIOInterface = std::make_shared(std::static_pointer_cast(device), editor, this); + addInterfaceToTab(device->getName(), tab, auxiliaryIOInterface); + } + else + { + Onix1::showWarningMessageBoxAsync("Composite Device Type Not Found", "Could not find a valid composite device type when adding devices to the canvas."); + return; + } + } + else + { + Onix1::showWarningMessageBoxAsync("Device Type Not Found", "Could not find a valid device type when adding devices to the canvas."); + return; + } } } diff --git a/Source/OnixSourceEditor.cpp b/Source/OnixSourceEditor.cpp index 41fb7db..0627124 100644 --- a/Source/OnixSourceEditor.cpp +++ b/Source/OnixSourceEditor.cpp @@ -23,6 +23,7 @@ #include "OnixSourceEditor.h" #include "OnixSource.h" #include "OnixSourceCanvas.h" +#include "Devices/MemoryMonitor.h" using namespace OnixSourcePlugin; diff --git a/Source/OnixSourceEditor.h b/Source/OnixSourceEditor.h index 7046835..71a0960 100644 --- a/Source/OnixSourceEditor.h +++ b/Source/OnixSourceEditor.h @@ -23,13 +23,13 @@ #pragma once #include - -#include "Devices/MemoryMonitor.h" +#include "OnixDevice.h" namespace OnixSourcePlugin { class OnixSource; class OnixSourceCanvas; + class MemoryMonitorUsage; /** diff --git a/Source/UI/AnalogIOInterface.cpp b/Source/UI/AnalogIOInterface.cpp index 069a38d..92574a8 100644 --- a/Source/UI/AnalogIOInterface.cpp +++ b/Source/UI/AnalogIOInterface.cpp @@ -21,6 +21,8 @@ */ #include "AnalogIOInterface.h" +#include "../OnixSourceEditor.h" +#include "../OnixSourceCanvas.h" using namespace OnixSourcePlugin; @@ -34,7 +36,7 @@ AnalogIOInterface::AnalogIOInterface(std::shared_ptr d, OnixSourceEdit deviceEnableButton = std::make_unique(enabledButtonText); deviceEnableButton->setFont(font); deviceEnableButton->setRadius(3.0f); - deviceEnableButton->setBounds(50, 40, 100, 22); + deviceEnableButton->setBounds(40, 20, 100, 22); deviceEnableButton->setClickingTogglesState(true); deviceEnableButton->setTooltip("If disabled, AnalogIO will not stream or receive data during acquisition"); deviceEnableButton->setToggleState(true, dontSendNotification); diff --git a/Source/UI/AnalogIOInterface.h b/Source/UI/AnalogIOInterface.h index 720d774..4d3f7ef 100644 --- a/Source/UI/AnalogIOInterface.h +++ b/Source/UI/AnalogIOInterface.h @@ -23,14 +23,14 @@ #pragma once #include - -#include "../OnixSourceEditor.h" -#include "../OnixSourceCanvas.h" - +#include "SettingsInterface.h" #include "../Devices/AnalogIO.h" namespace OnixSourcePlugin { + class OnixSourceEditor; + class OnixSourceCanvas; + class AnalogIOInterface : public SettingsInterface, public Button::Listener, public ComboBox::Listener @@ -39,20 +39,15 @@ namespace OnixSourcePlugin AnalogIOInterface(std::shared_ptr d, OnixSourceEditor* e, OnixSourceCanvas* c); void saveParameters(XmlElement* xml) override; - void loadParameters(XmlElement* xml) override; - void updateInfoString() override {}; - void updateSettings() override; - void buttonClicked(Button*) override; void comboBoxChanged(ComboBox* cb) override; + void setInterfaceEnabledState(bool newState) override; private: - void setInterfaceEnabledState(bool newState) override; - static const int numChannels = 12; std::array, numChannels> channelDirectionLabels; diff --git a/Source/UI/AuxiliaryIOInterface.cpp b/Source/UI/AuxiliaryIOInterface.cpp new file mode 100644 index 0000000..83d54b1 --- /dev/null +++ b/Source/UI/AuxiliaryIOInterface.cpp @@ -0,0 +1,86 @@ +/* + ------------------------------------------------------------------ + + 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 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 . + +*/ + +#include "AuxiliaryIOInterface.h" +#include "../OnixSourceEditor.h" +#include "../OnixSourceCanvas.h" +#include "AnalogIOInterface.h" +#include "DigitalIOInterface.h" + +using namespace OnixSourcePlugin; + +AuxiliaryIOInterface::AuxiliaryIOInterface(std::shared_ptr d, OnixSourceEditor* e, OnixSourceCanvas* c) : + SettingsInterface(d, e, c) +{ + if (device != nullptr) + { + auto auxiliaryIO = std::static_pointer_cast(device); + + static int offset = 55; + FontOptions font = FontOptions("Fira Code", "Bold", 22.0f); + + analogDigitalLabel = std::make_unique