diff --git a/Source/Devices/Bno055.cpp b/Source/Devices/Bno055.cpp index a1ff5c7..df188c1 100644 --- a/Source/Devices/Bno055.cpp +++ b/Source/Devices/Bno055.cpp @@ -93,11 +93,9 @@ Bno055::~Bno055() int Bno055::configureDevice() { - int result = oni_write_reg(ctx, deviceIdx, (uint32_t)Bno055Registers::ENABLE, isEnabled() ? (oni_reg_val_t)1 : (oni_reg_val_t)0); + ONI_OK_RETURN_INT(oni_write_reg(ctx, deviceIdx, (uint32_t)Bno055Registers::ENABLE, isEnabled() ? (oni_reg_val_t)1 : (oni_reg_val_t)0)); - if (result != ONI_ESUCCESS) LOGE(oni_error_str(result)); - - return result; + return 0; } int Bno055::updateSettings() diff --git a/Source/Devices/DeviceList.h b/Source/Devices/DeviceList.h index 228ff3c..d4ed212 100644 --- a/Source/Devices/DeviceList.h +++ b/Source/Devices/DeviceList.h @@ -3,3 +3,4 @@ #include "HeadStageEEPROM.h" #include "Neuropixels_1.h" #include "Neuropixels2e.h" +#include "PortController.h" diff --git a/Source/Devices/Neuropixels_1.cpp b/Source/Devices/Neuropixels_1.cpp index dbb201c..fd0a9d3 100644 --- a/Source/Devices/Neuropixels_1.cpp +++ b/Source/Devices/Neuropixels_1.cpp @@ -36,7 +36,10 @@ BackgroundUpdaterWithProgressWindow::~BackgroundUpdaterWithProgressWindow() int BackgroundUpdaterWithProgressWindow::updateSettings() { - runThread(); + if (device->isEnabled()) + runThread(); + else + return 0; return result; } diff --git a/Source/Devices/PortController.cpp b/Source/Devices/PortController.cpp new file mode 100644 index 0000000..4794a39 --- /dev/null +++ b/Source/Devices/PortController.cpp @@ -0,0 +1,171 @@ +/* + ------------------------------------------------------------------ + + This file is part of the Open Ephys GUI + Copyright (C) 2023 Allen Institute for Brain Science and 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 "PortController.h" + +PortController::PortController(PortName port_, oni_ctx ctx_) : + OnixDevice(getPortNameString(port_), OnixDeviceType::PORT_CONTROL, (oni_dev_idx_t)port_, ctx_), + port(port_) +{ +} + +PortController::~PortController() +{ +} + +int PortController::configureDevice() +{ + ONI_OK_RETURN_INT(oni_write_reg(ctx, deviceIdx, (uint32_t)PortControllerRegister::ENABLE, (uint32_t)1)) + + return 0; +} + +void PortController::startAcquisition() +{ + errorFlag = false; +} + +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); +} + +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; + + int dataOffset = 8; + + uint32_t code = (uint32_t) *(dataPtr + dataOffset); + uint32_t data = (uint32_t) *(dataPtr + dataOffset + 1); + + errorFlag = errorFlag || ((uint32_t)data & LINKSTATE_SL) == 0; + + oni_destroy_frame(frame); + + LOGE("Port status changed for " + getName() + "."); + } +} + +void PortController::updateDiscoveryParameters(DiscoveryParameters parameters) +{ + discoveryParameters = parameters; +} + +DiscoveryParameters PortController::getHeadstageDiscoveryParameters(String headstage) +{ + if (headstage == "Neuropixels 1.0f") + { + return DiscoveryParameters(5.0f, 7.0f, 1.0f, 0.2f); + } + + return DiscoveryParameters(); +} + +bool PortController::configureVoltage(float voltage) +{ + if (ctx == NULL) return false; + + if (voltage == defaultVoltage) + { + if (discoveryParameters == DiscoveryParameters()) return false; + + for (voltage = discoveryParameters.minVoltage; voltage <= discoveryParameters.maxVoltage; voltage += discoveryParameters.voltageIncrement) + { + setVoltage(voltage); + + if (checkLinkState()) + { + setVoltage(voltage + discoveryParameters.voltageOffset); + return checkLinkState(); + } + } + } + else + { + setVoltage(voltage); + + return checkLinkState(); + } + + return false; +} + +void PortController::setVoltageOverride(float voltage, bool waitToSettle) +{ + if (ctx == NULL) return; + + ONI_OK(oni_write_reg(ctx, (oni_dev_idx_t)port, (oni_reg_addr_t)PortControllerRegister::PORTVOLTAGE, (oni_reg_val_t)(voltage * 10))); + if (waitToSettle) sleep_for(std::chrono::milliseconds(500)); +} + +void PortController::setVoltage(float voltage) +{ + if (ctx == NULL) return; + + ONI_OK(oni_write_reg(ctx, (oni_dev_idx_t)port, (oni_reg_addr_t)PortControllerRegister::PORTVOLTAGE, 0)); + sleep_for(std::chrono::milliseconds(300)); + + ONI_OK(oni_write_reg(ctx, (oni_dev_idx_t)port, (oni_reg_addr_t)PortControllerRegister::PORTVOLTAGE, (oni_reg_val_t)(voltage * 10))); + sleep_for(std::chrono::milliseconds(500)); +} + +bool PortController::checkLinkState() const +{ + if (ctx == NULL) return false; + + oni_reg_val_t linkState; + int result = oni_read_reg(ctx, (oni_dev_idx_t)port, (oni_reg_addr_t)PortControllerRegister::LINKSTATE, &linkState); + + if (result != 0) { LOGE(oni_error_str(result)); return false; } + else if ((linkState & LINKSTATE_SL) == 0) { LOGE("Unable to acquire communication lock."); return false; } + else return true; +} + +String PortController::getPortNameString(PortName portName) +{ + switch (portName) + { + case PortName::PortA: + return "Port A"; + case PortName::PortB: + return "Port B"; + default: + break; + } +} diff --git a/Source/Devices/PortController.h b/Source/Devices/PortController.h new file mode 100644 index 0000000..8e3a561 --- /dev/null +++ b/Source/Devices/PortController.h @@ -0,0 +1,137 @@ +/* + ------------------------------------------------------------------ + + This file is part of the Open Ephys GUI + Copyright (C) 2023 Allen Institute for Brain Science and 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 . + +*/ + +#ifndef __PORTCONTROLLER_H__ +#define __PORTCONTROLLER_H__ + +#include +#include + +#include "oni.h" +#include "../OnixDevice.h" + +using namespace std::this_thread; + +enum class PortControllerRegister : uint32_t +{ + ENABLE = 0, + GPOSTATE = 1, + DESPWR = 2, + PORTVOLTAGE = 3, + SAVEVOLTAGE = 4, + LINKSTATE = 5 +}; + +enum class PortStatusCode : uint32_t +{ + SerdesLock = 0x0001, + SerdesParityPass = 0x0002, + CrcError = 0x0100, + TooManyDevices = 0x0200, + InitializationError = 0x0400, + BadPacketFormat = 0x0800, + InitializationCrcError = 0x1000, +}; + +class DiscoveryParameters +{ +public: + float minVoltage = 0.0f; + float maxVoltage = 0.0f; + float voltageOffset = 0.0f; + float voltageIncrement = 0.0f; + + DiscoveryParameters() {}; + + DiscoveryParameters(float minVoltage_, float maxVoltage_, float voltageOffset_, float voltageIncrement_) + { + minVoltage = minVoltage_; + maxVoltage = maxVoltage_; + voltageOffset = voltageOffset_; + voltageIncrement = voltageIncrement_; + } + + ~DiscoveryParameters() {}; + + bool operator==(const DiscoveryParameters& rhs) const + { + return rhs.minVoltage == minVoltage && rhs.maxVoltage == maxVoltage && rhs.voltageOffset == voltageOffset && rhs.voltageIncrement == voltageIncrement; + } +}; + +class PortController : public OnixDevice +{ +public: + PortController(PortName port_, const oni_ctx ctx_); + + ~PortController(); + + int configureDevice() override; + + int updateSettings() override { return 0; } + + void startAcquisition() override; + + void stopAcquisition() override; + + void addFrame(oni_frame_t*) override; + + void processFrames() override; + + void addSourceBuffers(OwnedArray& sourceBuffers) override {}; + + void updateDiscoveryParameters(DiscoveryParameters parameters); + + bool configureVoltage(float voltage = defaultVoltage); + + /** Sets the voltage to the given value, after setting the voltage to zero */ + void setVoltage(float voltage); + + /** Overrides the voltage setting and directly sets it to the given voltage */ + void setVoltageOverride(float voltage, bool waitToSettle = true); + + bool checkLinkState() const; + + String getPortNameString(PortName portName); + + static DiscoveryParameters getHeadstageDiscoveryParameters(String headstage); + + /** Check if the port status changed and there is an error reported */ + bool getErrorFlag() { return errorFlag; } + +private: + Array frameArray; + + const PortName port; + + static constexpr float defaultVoltage = -1.0f; + + const uint32_t LINKSTATE_PP = 0x2; // parity check pass bit + const uint32_t LINKSTATE_SL = 0x1; // SERDES lock bit + + DiscoveryParameters discoveryParameters; + + std::atomic errorFlag = false; +}; + +#endif // !__PORTCONTROLLER_H__ diff --git a/Source/FrameReader.cpp b/Source/FrameReader.cpp index 6b902bb..8f9f145 100644 --- a/Source/FrameReader.cpp +++ b/Source/FrameReader.cpp @@ -23,7 +23,7 @@ #include "FrameReader.h" -FrameReader::FrameReader(OwnedArray& sources_, oni_ctx ctx_) +FrameReader::FrameReader(Array sources_, oni_ctx ctx_) : Thread("FrameReader"), sources(sources_), ctx(ctx_) @@ -62,6 +62,7 @@ void FrameReader::run() { source->addFrame(frame); destroyFrame = false; + break; } } diff --git a/Source/FrameReader.h b/Source/FrameReader.h index db21fdf..f72ae91 100644 --- a/Source/FrameReader.h +++ b/Source/FrameReader.h @@ -32,7 +32,7 @@ class FrameReader : public Thread { public: - FrameReader(OwnedArray& sources_, oni_ctx ctx_); + FrameReader(Array sources_, oni_ctx ctx_); ~FrameReader(); @@ -40,7 +40,7 @@ class FrameReader : public Thread private: - OwnedArray& sources; + Array sources; oni_ctx ctx; }; diff --git a/Source/OnixDevice.h b/Source/OnixDevice.h index 95d5321..d95f8c2 100644 --- a/Source/OnixDevice.h +++ b/Source/OnixDevice.h @@ -39,7 +39,7 @@ #define ONI_OK(exp) {int res = exp; if (res != ONI_ESUCCESS){LOGD(oni_error_str(res));}} #define ONI_OK_RETURN_BOOL(exp) {int res = exp; if (res != ONI_ESUCCESS){LOGD(oni_error_str(res));return false;}} -#define ONI_OK_RETURN_INT(exp, val) {int res = exp; if (res != ONI_ESUCCESS){LOGD(oni_error_str(res));return val;}} +#define ONI_OK_RETURN_INT(exp) {int res = exp; if (res != ONI_ESUCCESS){LOGD(oni_error_str(res));return res;}} using namespace std::chrono; @@ -54,7 +54,8 @@ enum class OnixDeviceType { BNO, NEUROPIXELS_1, NEUROPIXELS_2, - ADC + ADC, + PORT_CONTROL }; struct StreamInfo { diff --git a/Source/OnixSource.cpp b/Source/OnixSource.cpp index adb5527..e0d84ef 100644 --- a/Source/OnixSource.cpp +++ b/Source/OnixSource.cpp @@ -35,6 +35,9 @@ OnixSource::OnixSource(SourceNode* sn) : addBooleanParameter(Parameter::PROCESSOR_SCOPE, "connected", "Connect", "Connect to Onix hardware", false, true); + portA = std::make_unique(PortName::PortA, context.get()); + portB = std::make_unique(PortName::PortB, context.get()); + if (!context.isInitialized()) { LOGE("Failed to initialize context."); return; } } @@ -64,7 +67,7 @@ void OnixSource::initializeDevices(bool updateStreamInfo) { if (!context.isInitialized()) { - LOGE("Cannot initialize devices, context is not initialized correctly. Please try removing the plugin and adding it again."); + LOGE("Cannot initialize devices, context is not initialized correctly. Please try removing the plugin and adding it again."); return; } @@ -96,9 +99,9 @@ void OnixSource::initializeDevices(bool updateStreamInfo) size_t devices_sz = sizeof(oni_device_t) * num_devs; devices = (oni_device_t*)realloc(devices, devices_sz); - if (devices == NULL) - { - LOGE("No devices found."); + if (devices == NULL) + { + LOGE("No devices found."); if (updateStreamInfo) CoreServices::updateSignalChain(editor); return; } @@ -195,7 +198,7 @@ void OnixSource::initializeDevices(bool updateStreamInfo) auto serializer = std::make_unique(DS90UB9x::SER_ADDR, devices[dev_idx].idx, ctx); serializer->WriteByte((uint32_t)DS90UB9x::DS90UB9xSerializerI2CRegister::SCLHIGH, 20); serializer->WriteByte((uint32_t)DS90UB9x::DS90UB9xSerializerI2CRegister::SCLLOW, 20); - + auto EEPROM = std::make_unique(devices[dev_idx].idx, ctx); uint32_t hsid = EEPROM->GetHeadStageID(); LOGD("Detected headstage ", hsid); @@ -221,6 +224,9 @@ void OnixSource::initializeDevices(bool updateStreamInfo) } } + portA->configureDevice(); + portB->configureDevice(); + context.issueReset(); oni_size_t frame_size = 0; @@ -270,10 +276,10 @@ void OnixSource::updateDiscoveryParameters(PortName port, DiscoveryParameters pa switch (port) { case PortName::PortA: - portA.updateDiscoveryParameters(parameters); + portA->updateDiscoveryParameters(parameters); break; case PortName::PortB: - portB.updateDiscoveryParameters(parameters); + portB->updateDiscoveryParameters(parameters); break; default: break; @@ -289,30 +295,30 @@ bool OnixSource::configurePortVoltage(PortName port, String voltage) const switch (port) { case PortName::PortA: - if (voltage == "") return portA.configureVoltage(ctx); - else return portA.configureVoltage(ctx, voltage.getFloatValue()); + if (voltage == "") return portA->configureVoltage(); + else return portA->configureVoltage(voltage.getFloatValue()); case PortName::PortB: - if (voltage == "") return portB.configureVoltage(ctx); - else return portB.configureVoltage(ctx, voltage.getFloatValue()); + if (voltage == "") return portB->configureVoltage(); + else return portB->configureVoltage(voltage.getFloatValue()); default: return false; } } -bool OnixSource::setPortVoltage(PortName port, float voltage) const +void OnixSource::setPortVoltage(PortName port, float voltage) const { - if (!context.isInitialized()) return false; - - oni_ctx ctx = context.get(); + if (!context.isInitialized()) return; switch (port) { case PortName::PortA: - return portA.setVoltage(ctx, voltage); + portA->setVoltageOverride(voltage); + return; case PortName::PortB: - return portB.setVoltage(ctx, voltage); + portB->setVoltageOverride(voltage); + return; default: - return false; + return; } } @@ -421,8 +427,8 @@ bool OnixSource::isReady() if (!context.isInitialized() || !devicesFound) return false; - if (editor->isHeadstageSelected(PortName::PortA) && !portA.checkLinkState(context.get())) return false; - if (editor->isHeadstageSelected(PortName::PortB) && !portB.checkLinkState(context.get())) return false; + if (editor->isHeadstageSelected(PortName::PortA) && !portA->checkLinkState()) return false; + if (editor->isHeadstageSelected(PortName::PortB) && !portB->checkLinkState()) return false; for (auto source : sources) { @@ -448,20 +454,30 @@ bool OnixSource::isReady() bool OnixSource::startAcquisition() { - startThread(); - frameReader.reset(); - frameReader = std::make_unique(sources, context.get()); - frameReader->startThread(); + Array devices; for (auto source : sources) + { + devices.add(source); + } + + devices.add(portA.get()); + devices.add(portB.get()); + + for (auto source : devices) { if (!source->isEnabled()) continue; source->startAcquisition(); } + frameReader = std::make_unique(devices, context.get()); + frameReader->startThread(); + + startThread(); + return true; } @@ -473,7 +489,8 @@ bool OnixSource::stopAcquisition() if (frameReader->isThreadRunning()) frameReader->signalThreadShouldExit(); - waitForThreadToExit(2000); + if (!portA->getErrorFlag() && !portB->getErrorFlag()) + waitForThreadToExit(2000); if (devicesFound) { @@ -495,9 +512,33 @@ bool OnixSource::stopAcquisition() source->stopAcquisition(); } + portA->stopAcquisition(); + portB->stopAcquisition(); + for (auto buffers : sourceBuffers) buffers->clear(); + if (portA->getErrorFlag() || portB->getErrorFlag()) + { + if (portA->getErrorFlag()) + { + LOGE("Port A lost communication lock. Reconnect hardware to continue."); + CoreServices::sendStatusMessage("Port A lost communication lock"); + } + + if (portB->getErrorFlag()) + { + LOGE("Port B lost communication lock. Reconnect hardware to continue."); + CoreServices::sendStatusMessage("Port B lost communication lock"); + } + + devicesFound = false; + + MessageManager::callAsync([] { AlertWindow::showMessageBoxAsync(MessageBoxIconType::WarningIcon, "Port Communication Lock Lost", + "The port communication lock was lost during acquisition, inspect hardware connections and port switch." + + String("\n\nTo continue, press disconnect in the GUI, then press connect."), "Okay"); }); + } + return true; } @@ -510,5 +551,8 @@ bool OnixSource::updateBuffer() source->processFrames(); } - return true; + portA->processFrames(); + portB->processFrames(); + + return !portA->getErrorFlag() && !portB->getErrorFlag(); } diff --git a/Source/OnixSource.h b/Source/OnixSource.h index 100743c..898fb42 100644 --- a/Source/OnixSource.h +++ b/Source/OnixSource.h @@ -33,7 +33,6 @@ #include "OnixSourceEditor.h" #include "Devices/DeviceList.h" #include "FrameReader.h" -#include "PortController.h" class Onix1 { @@ -93,8 +92,8 @@ class OnixSource : public DataThread { if (context.isInitialized()) { - portA.setVoltage(context.get(), 0.0f); - portB.setVoltage(context.get(), 0.0f); + portA->setVoltageOverride(0.0f, false); + portB->setVoltageOverride(0.0f, false); } } @@ -125,9 +124,7 @@ class OnixSource : public DataThread bool configurePortVoltage(PortName port, String voltage) const; /** Sets the port voltage */ - bool setPortVoltage(PortName port, float voltage) const; - - void initializeContext(); + void setPortVoltage(PortName port, float voltage) const; int resetContext() { return context.issueReset(); } @@ -160,8 +157,8 @@ class OnixSource : public DataThread Onix1 context; - PortController portA = PortController(PortName::PortA); - PortController portB = PortController(PortName::PortB); + std::unique_ptr portA; + std::unique_ptr portB; const oni_size_t block_read_size = 2048; diff --git a/Source/OnixSourceEditor.cpp b/Source/OnixSourceEditor.cpp index a98e5c3..fd82d0b 100644 --- a/Source/OnixSourceEditor.cpp +++ b/Source/OnixSourceEditor.cpp @@ -111,8 +111,32 @@ OnixSourceEditor::OnixSourceEditor(GenericProcessor* parentNode, OnixSource* oni void OnixSourceEditor::labelTextChanged(Label* l) { + // TODO: Add headstage specific parameters to limit voltage within safe levels if (l == portVoltageValueA.get()) { + float input = l->getText().getFloatValue(); + + if (input < 0.0f) + { + l->setText("0.0", dontSendNotification); + } + else if (input > 7.0f) + { + l->setText("7.0", dontSendNotification); + } + } + else if (l == portVoltageValueB.get()) + { + float input = l->getText().getFloatValue(); + + if (input < 0.0f) + { + l->setText("0.0", dontSendNotification); + } + else if (input > 7.0f) + { + l->setText("7.0", dontSendNotification); + } } } @@ -120,59 +144,65 @@ void OnixSourceEditor::buttonClicked(Button* b) { if (b == connectButton.get()) { - if (connectButton->getToggleState() == true) - { - // NB: Configure port voltages, using either the automated voltage discovery algorithm, or the explicit voltage value given - if (isHeadstageSelected(PortName::PortA)) - { - if (!thread->configurePortVoltage(PortName::PortA, portVoltageValueA->getText())) - { - CoreServices::sendStatusMessage("Unable to set port voltage for Port A."); - connectButton->setToggleState(false, true); - return; - } - } - - if (isHeadstageSelected(PortName::PortB)) - { - if (!thread->configurePortVoltage(PortName::PortB, portVoltageValueB->getText())) - { - CoreServices::sendStatusMessage("Unable to set port voltage for Port B."); - connectButton->setToggleState(false, true); - return; - } - } - - thread->initializeDevices(true); - canvas->refreshTabs(); + setConnectedStatus(connectButton->getToggleState()); + } +} - connectButton->setLabel("DISCONNECT"); +void OnixSourceEditor::setConnectedStatus(bool connected) +{ + connectButton->setToggleState(connected, dontSendNotification); - if (!thread->foundInputSource()) + if (connected) + { + // NB: Configure port voltages, using either the automated voltage discovery algorithm, or the explicit voltage value given + if (isHeadstageSelected(PortName::PortA)) + { + if (!thread->configurePortVoltage(PortName::PortA, portVoltageValueA->getText())) { - CoreServices::sendStatusMessage("No Onix hardware found."); - connectButton->setToggleState(false, true); + CoreServices::sendStatusMessage("Unable to acquire communication lock on Port A."); + connectButton->setToggleState(false, dontSendNotification); + return; } } else { - if (!thread->setPortVoltage(PortName::PortA, 0)) - { - CoreServices::sendStatusMessage("Unable to set port voltage to 0 for Port A."); - return; - } + thread->setPortVoltage(PortName::PortA, 0); + } - if (!thread->setPortVoltage(PortName::PortB, 0)) + if (isHeadstageSelected(PortName::PortB)) + { + if (!thread->configurePortVoltage(PortName::PortB, portVoltageValueB->getText())) { - CoreServices::sendStatusMessage("Unable to set port voltage to 0 for Port B."); + CoreServices::sendStatusMessage("Unable to acquire communication lock on Port B."); + connectButton->setToggleState(false, dontSendNotification); return; } + } + else + { + thread->setPortVoltage(PortName::PortB, 0); + } + + thread->initializeDevices(true); + canvas->refreshTabs(); + + connectButton->setLabel("DISCONNECT"); - canvas->removeTabs(); - thread->disconnectDevices(true); - connectButton->setLabel("CONNECT"); + if (!thread->foundInputSource()) + { + CoreServices::sendStatusMessage("No Onix hardware found."); + connectButton->setToggleState(false, sendNotification); } } + else + { + thread->setPortVoltage(PortName::PortA, 0); + thread->setPortVoltage(PortName::PortB, 0); + + canvas->removeTabs(); + thread->disconnectDevices(true); + connectButton->setLabel("CONNECT"); + } } void OnixSourceEditor::comboBoxChanged(ComboBox* cb) diff --git a/Source/OnixSourceEditor.h b/Source/OnixSourceEditor.h index 3c704ff..383db5a 100644 --- a/Source/OnixSourceEditor.h +++ b/Source/OnixSourceEditor.h @@ -76,6 +76,8 @@ class OnixSourceEditor : public VisualizerEditor, bool isHeadstageSelected(PortName port); + void setConnectedStatus(bool); + OnixSourceCanvas* canvas; private: diff --git a/Source/PortController.cpp b/Source/PortController.cpp deleted file mode 100644 index 00b1006..0000000 --- a/Source/PortController.cpp +++ /dev/null @@ -1,105 +0,0 @@ -/* - ------------------------------------------------------------------ - - This file is part of the Open Ephys GUI - Copyright (C) 2023 Allen Institute for Brain Science and 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 "PortController.h" - -PortController::PortController(PortName port_) : - port(port_) -{ -} - -PortController::~PortController() -{ -} - -void PortController::updateDiscoveryParameters(DiscoveryParameters parameters) -{ - discoveryParameters = parameters; -} - -DiscoveryParameters PortController::getHeadstageDiscoveryParameters(String headstage) -{ - if (headstage == "Neuropixels 1.0f") - { - return DiscoveryParameters(5.0f, 7.0f, 1.0f, 0.2f); - } - - return DiscoveryParameters(); -} - -bool PortController::configureVoltage(oni_ctx ctx, float voltage) const -{ - if (ctx == NULL) return false; - - if (voltage == defaultVoltage) - { - for (voltage = discoveryParameters.minVoltage; voltage <= discoveryParameters.maxVoltage; voltage += discoveryParameters.voltageIncrement) - { - setVoltage(ctx, voltage); - - if (checkLinkState(ctx) == 0) - { - setVoltage(ctx, voltage + discoveryParameters.voltageOffset); - return checkLinkState(ctx); - } - } - } - else - { - return setVoltage(ctx, voltage); - } -} - -bool PortController::setVoltage(oni_ctx ctx, float voltage) const -{ - if (ctx == NULL) return false; - - ONI_OK_RETURN_BOOL(oni_write_reg(ctx, (oni_dev_idx_t)port, voltageRegister, 0)); - - if (voltage == 0.0f) return true; - - sleep_for(std::chrono::milliseconds(300)); - - ONI_OK_RETURN_BOOL(oni_write_reg(ctx, (oni_dev_idx_t)port, voltageRegister, (oni_reg_val_t)(voltage * 10))); - - sleep_for(std::chrono::milliseconds(500)); - - auto val = 1; - oni_set_opt(ctx, ONI_OPT_RESET, &val, sizeof(val)); - - sleep_for(std::chrono::milliseconds(200)); - - return true; -} - -bool PortController::checkLinkState(oni_ctx ctx) const -{ - if (ctx == NULL) return false; - - oni_reg_val_t linkState; - int result = oni_read_reg(ctx, (oni_dev_idx_t)port, linkStateRegister, &linkState); - - if (result != 0) { LOGE(oni_error_str(result)); return false; } - else if ((linkState & (uint32_t)0x1) == 0) { LOGE("Unable to acquire communication lock."); return false; } - else return true; -} diff --git a/Source/PortController.h b/Source/PortController.h deleted file mode 100644 index 91a10f4..0000000 --- a/Source/PortController.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - ------------------------------------------------------------------ - - This file is part of the Open Ephys GUI - Copyright (C) 2023 Allen Institute for Brain Science and 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 . - -*/ - -#ifndef __PORTCONTROLLER_H__ -#define __PORTCONTROLLER_H__ - -#include -#include - -#include "oni.h" -#include "OnixDevice.h" - -using namespace std::this_thread; - -struct DiscoveryParameters -{ - float minVoltage = 0.0f; - float maxVoltage = 0.0f; - float voltageOffset = 0.0f; - float voltageIncrement = 0.0f; - - DiscoveryParameters() {}; - - DiscoveryParameters(float minVoltage_, float maxVoltage_, float voltageOffset_, float voltageIncrement_) - { - minVoltage = minVoltage_; - maxVoltage = maxVoltage_; - voltageOffset = voltageOffset_; - voltageIncrement = voltageIncrement_; - } -}; - -class PortController -{ -public: - PortController(PortName port_); - - ~PortController(); - - void updateDiscoveryParameters(DiscoveryParameters parameters); - - bool configureVoltage(oni_ctx ctx, float voltage = defaultVoltage) const; - - bool setVoltage(oni_ctx ctx, float voltage) const; - - bool checkLinkState(oni_ctx ctx) const; - - static DiscoveryParameters getHeadstageDiscoveryParameters(String headstage); - -private: - const PortName port; - - static constexpr float defaultVoltage = -1.0f; - - const oni_reg_addr_t voltageRegister = 3; - const oni_reg_addr_t linkStateRegister = 5; - - DiscoveryParameters discoveryParameters; -}; - -#endif // !__PORTCONTROLLER_H__ diff --git a/Source/UI/Bno055Interface.cpp b/Source/UI/Bno055Interface.cpp index 1187278..9d3ee83 100644 --- a/Source/UI/Bno055Interface.cpp +++ b/Source/UI/Bno055Interface.cpp @@ -48,7 +48,7 @@ void Bno055Interface::buttonClicked(Button* button) if (button == deviceEnableButton.get()) { device->setEnabled(deviceEnableButton->getToggleState()); - device->enableDevice(); + device->configureDevice(); canvas->resetContext(); if (device->isEnabled()) diff --git a/Source/UI/NeuropixV1Interface.cpp b/Source/UI/NeuropixV1Interface.cpp index 8694aa9..df62553 100644 --- a/Source/UI/NeuropixV1Interface.cpp +++ b/Source/UI/NeuropixV1Interface.cpp @@ -583,7 +583,7 @@ void NeuropixV1Interface::buttonClicked(Button* button) if (button == probeEnableButton.get()) { device->setEnabled(probeEnableButton->getToggleState()); - device->enableDevice(); + device->configureDevice(); canvas->resetContext(); if (device->isEnabled())