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())