Skip to content

Commit e8fec31

Browse files
committed
Add PortController, for both Port A and B, and add automatic port voltage discovery
- Moves the port voltage modifications, and checking the link state, to the new PortController class - Add macros for checking the results of register read/writes to OnixDevice - Ensures that the context is reset correctly so that devices stream data - Automated port voltage discovery uses the same logic as OpenEphys.Onix1 - Changed the order of operations during stopAcquisition so that bad frames aren't read due to the context resetting - Fixed an issue where PathParameters were being set with a value other than the default
1 parent 60ffb2d commit e8fec31

9 files changed

+314
-67
lines changed

Source/Devices/Neuropixels2e.cpp

-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
#include "Neuropixels2e.h"
22
#include "DS90UB9x.h"
33

4-
#define ONI_OK(exp) {int res = exp; if (res != ONI_ESUCCESS){LOGD(oni_error_str(res));}}
5-
64
Neuropixels2e::Neuropixels2e(String name, const oni_dev_idx_t deviceIdx_, const oni_ctx ctx_)
75
: OnixDevice(name, OnixDeviceType::NEUROPIXELS_2, deviceIdx_, ctx_)
86
{}

Source/Devices/Neuropixels_1.cpp

+15-8
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,17 @@ void BackgroundUpdaterWithProgressWindow::run()
4646
setProgress(-1);
4747

4848
// Parse ADC and Gain calibration files
49-
File adcFile = File(device->getAdcPathParameter());
50-
File gainFile = File(device->getGainPathParameter());
49+
String adcPath = device->getAdcPathParameter();
50+
String gainPath = device->getGainPathParameter();
51+
52+
if (adcPath == "None" || gainPath == "None")
53+
{
54+
result = -3;
55+
return;
56+
}
57+
58+
File adcFile = File(adcPath);
59+
File gainFile = File(gainPath);
5160

5261
if (!adcFile.existsAsFile() || !gainFile.existsAsFile())
5362
{
@@ -157,12 +166,14 @@ Neuropixels_1::Neuropixels_1(String name, OnixSource* s, const oni_dev_idx_t dev
157166
//validExtensions.add("*_ADCCalibration.csv");
158167

159168
source->addPathParameter(Parameter::PROCESSOR_SCOPE, getAdcPathParameterName(), "ADC Calibration File", "Path to the ADC calibration file for this Neuropixels probe",
160-
File::getSpecialLocation(File::userHomeDirectory).getFullPathName(), validExtensions, false, false, true);
169+
"", validExtensions, false, false, true);
170+
source->getParameter(getAdcPathParameterName())->setNextValue(File::getSpecialLocation(File::userHomeDirectory).getFullPathName());
161171

162172
//validExtensions.set(0, "*_gainCalValues.csv");
163173

164174
source->addPathParameter(Parameter::PROCESSOR_SCOPE, getGainPathParameterName(), "Gain Calibration File", "Path to the gain calibration file for this Neuropixels probe",
165-
File::getSpecialLocation(File::userHomeDirectory).getFullPathName(), validExtensions, false, false, true);
175+
"", validExtensions, false, false, true);
176+
source->getParameter(getGainPathParameterName())->setNextValue(File::getSpecialLocation(File::userHomeDirectory).getFullPathName());
166177
}
167178

168179
Neuropixels_1::~Neuropixels_1()
@@ -234,10 +245,6 @@ NeuropixelsReference Neuropixels_1::getReference(int index)
234245

235246
int Neuropixels_1::enableDevice()
236247
{
237-
int result = checkLinkState((oni_dev_idx_t)PortName::PortA);
238-
239-
if (result != 0) return result;
240-
241248
// Get Probe SN
242249
uint32_t eepromOffset = 0;
243250
uint32_t i2cAddr = 0x50;

Source/OnixDevice.cpp

-12
Original file line numberDiff line numberDiff line change
@@ -28,15 +28,3 @@ OnixDevice::OnixDevice(String name_, OnixDeviceType type_, const oni_dev_idx_t d
2828
{
2929
name = name_;
3030
}
31-
32-
int OnixDevice::checkLinkState(oni_dev_idx_t port) const
33-
{
34-
const oni_reg_addr_t linkStateRegister = 5;
35-
36-
oni_reg_val_t linkState;
37-
int result = oni_read_reg(ctx, port, linkStateRegister, &linkState);
38-
39-
if (result != 0) { LOGE(oni_error_str(result)); return -1; }
40-
else if ((linkState & (uint32_t)0x1) == 0) { LOGE("Unable to acquire communication lock."); return -1; }
41-
else return result;
42-
}

Source/OnixDevice.h

+4-2
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@
3737
#include "I2CRegisterContext.h"
3838
#include "NeuropixComponents.h"
3939

40+
#define ONI_OK(exp) {int res = exp; if (res != ONI_ESUCCESS){LOGD(oni_error_str(res));}}
41+
#define ONI_OK_RETURN_BOOL(exp) {int res = exp; if (res != ONI_ESUCCESS){LOGD(oni_error_str(res));return false;}}
42+
#define ONI_OK_RETURN_INT(exp, val) {int res = exp; if (res != ONI_ESUCCESS){LOGD(oni_error_str(res));return val;}}
43+
4044
using namespace std::chrono;
4145

4246
enum class PortName
@@ -109,8 +113,6 @@ class OnixDevice
109113

110114
Array<StreamInfo> streams;
111115

112-
int checkLinkState(oni_dev_idx_t port) const;
113-
114116
const int bufferSizeInSeconds = 10;
115117

116118
protected:

Source/OnixSource.cpp

+55-30
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,6 @@ OnixSource::OnixSource(SourceNode* sn) :
4343
initializeContext();
4444

4545
if (!contextInitialized) { LOGE("Failed to initialize context."); return; }
46-
47-
size_t block_size_sz = sizeof(block_read_size);
48-
49-
// set block read size
50-
oni_set_opt(ctx, ONI_OPT_BLOCKREADSIZE, &block_read_size, block_size_sz);
5146
}
5247

5348
DataThread* OnixSource::createDataThread(SourceNode* sn)
@@ -254,6 +249,9 @@ void OnixSource::initializeDevices(bool updateStreamInfo)
254249
}
255250
}
256251

252+
val = 1;
253+
oni_set_opt(ctx, ONI_OPT_RESET, &val, sizeof(val));
254+
257255
oni_size_t frame_size = 0;
258256
size_t frame_size_sz = sizeof(frame_size);
259257
oni_get_opt(ctx, ONI_OPT_MAXREADFRAMESIZE, &frame_size, &frame_size_sz);
@@ -262,6 +260,10 @@ void OnixSource::initializeDevices(bool updateStreamInfo)
262260
oni_get_opt(ctx, ONI_OPT_MAXWRITEFRAMESIZE, &frame_size, &frame_size_sz);
263261
printf("Max. write frame size: %u bytes\n", frame_size);
264262

263+
// set block read size
264+
size_t block_size_sz = sizeof(block_read_size);
265+
oni_set_opt(ctx, ONI_OPT_BLOCKREADSIZE, &block_read_size, block_size_sz);
266+
265267
if (updateStreamInfo) CoreServices::updateSignalChain(editor);
266268

267269
LOGD("All devices initialized.");
@@ -292,28 +294,51 @@ void OnixSource::updateSourceBuffers()
292294
}
293295
}
294296

295-
bool OnixSource::setPortVoltage(oni_dev_idx_t port, int voltage) const
297+
void OnixSource::updateDiscoveryParameters(PortName port, DiscoveryParameters parameters)
296298
{
297-
if (!contextInitialized) return false;
298-
299-
const oni_reg_addr_t voltageRegister = 3;
300-
301-
auto result = oni_write_reg(ctx, port, voltageRegister, 0);
302-
303-
sleep(500);
304-
305-
result = oni_write_reg(ctx, port, voltageRegister, voltage);
306-
307-
if (result != 0) { LOGE(oni_error_str(result)); return -1; }
299+
switch (port)
300+
{
301+
case PortName::PortA:
302+
portA.updateDiscoveryParameters(parameters);
303+
break;
304+
case PortName::PortB:
305+
portB.updateDiscoveryParameters(parameters);
306+
break;
307+
default:
308+
break;
309+
}
310+
}
308311

309-
auto val = 1;
310-
result = oni_set_opt(ctx, ONI_OPT_RESET, &val, sizeof(val));
312+
bool OnixSource::configurePortVoltage(PortName port, String voltage) const
313+
{
314+
if (!contextInitialized) return false;
311315

312-
if (result != 0) { LOGE(oni_error_str(result)); return -1; }
316+
switch (port)
317+
{
318+
case PortName::PortA:
319+
if (voltage == "") return portA.configureVoltage(ctx);
320+
else return portA.configureVoltage(ctx, voltage.getFloatValue());
321+
case PortName::PortB:
322+
if (voltage == "") return portB.configureVoltage(ctx);
323+
else return portB.configureVoltage(ctx, voltage.getFloatValue());
324+
default:
325+
return false;
326+
}
327+
}
313328

314-
sleep(200);
329+
bool OnixSource::setPortVoltage(PortName port, float voltage) const
330+
{
331+
if (!contextInitialized) return false;
315332

316-
return result;
333+
switch (port)
334+
{
335+
case PortName::PortA:
336+
return portA.setVoltage(ctx, voltage);
337+
case PortName::PortB:
338+
return portB.setVoltage(ctx, voltage);
339+
default:
340+
return false;
341+
}
317342
}
318343

319344
void OnixSource::updateSettings(OwnedArray<ContinuousChannel>* continuousChannels,
@@ -464,6 +489,14 @@ bool OnixSource::startAcquisition()
464489

465490
bool OnixSource::stopAcquisition()
466491
{
492+
if (isThreadRunning())
493+
signalThreadShouldExit();
494+
495+
if (frameReader->isThreadRunning())
496+
frameReader->signalThreadShouldExit();
497+
498+
waitForThreadToExit(2000);
499+
467500
if (devicesFound)
468501
{
469502
oni_size_t reg = 0;
@@ -479,14 +512,6 @@ bool OnixSource::stopAcquisition()
479512
oni_set_opt(ctx, ONI_OPT_BLOCKREADSIZE, &block_read_size, sizeof(block_read_size));
480513
}
481514

482-
if (isThreadRunning())
483-
signalThreadShouldExit();
484-
485-
if (frameReader->isThreadRunning())
486-
frameReader->stopThread(1000);
487-
488-
waitForThreadToExit(2000);
489-
490515
for (auto source : sources)
491516
{
492517
if (!source->isEnabled()) continue;

Source/OnixSource.h

+13-6
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,6 @@
2424
#ifndef __OnixSource_H__
2525
#define __OnixSource_H__
2626

27-
#include <stdio.h>
28-
#include <string.h>
29-
3027
#include <oni.h>
3128
#include <onix.h>
3229

@@ -36,6 +33,7 @@
3633
#include "OnixSourceEditor.h"
3734
#include "Devices/DeviceList.h"
3835
#include "FrameReader.h"
36+
#include "PortController.h"
3937

4038
/**
4139
@@ -55,8 +53,8 @@ class OnixSource : public DataThread
5553
{
5654
if (ctx != NULL && contextInitialized)
5755
{
58-
int result = setPortVoltage((oni_dev_idx_t)PortName::PortA, 0);
59-
if (result != 0) LOGE("Error setting port voltage to zero.");
56+
portA.setVoltage(ctx, 0.0f);
57+
portB.setVoltage(ctx, 0.0f);
6058
oni_destroy_ctx(ctx);
6159
}
6260
}
@@ -82,7 +80,13 @@ class OnixSource : public DataThread
8280
/** Stops data transfer.*/
8381
bool stopAcquisition();
8482

85-
bool setPortVoltage(oni_dev_idx_t port, int voltage) const;
83+
void updateDiscoveryParameters(PortName port, DiscoveryParameters parameters);
84+
85+
/** Takes a string from the editor. Can be an empty string to allow for automated discovery */
86+
bool configurePortVoltage(PortName port, String voltage) const;
87+
88+
/** Sets the port voltage */
89+
bool setPortVoltage(PortName port, float voltage) const;
8690

8791
void initializeContext();
8892

@@ -116,6 +120,9 @@ class OnixSource : public DataThread
116120
/** The ONI context object */
117121
oni_ctx ctx;
118122

123+
PortController portA = PortController(PortName::PortA);
124+
PortController portB = PortController(PortName::PortB);
125+
119126
const oni_size_t block_read_size = 2048;
120127

121128
bool contextInitialized = false;

Source/OnixSourceEditor.cpp

+47-7
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ OnixSourceEditor::OnixSourceEditor(GenericProcessor* parentNode, OnixSource* oni
4545
headstageComboBoxA->setItemEnabled(1, false);
4646
headstageComboBoxA->addSeparator();
4747
// TODO: Add list of available devices here
48+
headstageComboBoxA->addItem("Neuropixels 1.0f", 2);
49+
50+
headstageComboBoxA->setSelectedId(1, dontSendNotification);
4851
addAndMakeVisible(headstageComboBoxA.get());
4952

5053
passthroughEditorA = std::make_unique<ToggleParameterEditor>(onixSource->getParameter("passthroughA"));
@@ -75,6 +78,9 @@ OnixSourceEditor::OnixSourceEditor(GenericProcessor* parentNode, OnixSource* oni
7578
headstageComboBoxB->setItemEnabled(1, false);
7679
headstageComboBoxB->addSeparator();
7780
// TODO: Add list of available devices here
81+
headstageComboBoxB->addItem("Neuropixels 1.0f", 2);
82+
83+
headstageComboBoxB->setSelectedId(1, dontSendNotification);
7884
addAndMakeVisible(headstageComboBoxB.get());
7985

8086
passthroughEditorB = std::make_unique<ToggleParameterEditor>(onixSource->getParameter("passthroughB"));
@@ -116,9 +122,26 @@ void OnixSourceEditor::buttonClicked(Button* b)
116122
{
117123
if (connectButton->getToggleState() == true)
118124
{
119-
int result = thread->setPortVoltage((oni_dev_idx_t)PortName::PortA, (int)(portVoltageValueA->getText().getFloatValue() * 10));
120-
121-
if (result != 0) { CoreServices::sendStatusMessage("Unable to set port voltage to " + portVoltageValueA->getText() + " for Port A."); return; }
125+
// NB: Configure port voltages, using either the automated voltage discovery algorithm, or the explicit voltage value given
126+
if (headstageComboBoxA->getSelectedItemIndex() > 0)
127+
{
128+
if (!thread->configurePortVoltage(PortName::PortA, portVoltageValueA->getText()))
129+
{
130+
CoreServices::sendStatusMessage("Unable to set port voltage for Port A.");
131+
connectButton->setToggleState(false, true);
132+
return;
133+
}
134+
}
135+
136+
if (headstageComboBoxB->getSelectedItemIndex() > 0)
137+
{
138+
if (!thread->configurePortVoltage(PortName::PortB, portVoltageValueB->getText()))
139+
{
140+
CoreServices::sendStatusMessage("Unable to set port voltage for Port B.");
141+
connectButton->setToggleState(false, true);
142+
return;
143+
}
144+
}
122145

123146
thread->initializeDevices(true);
124147
canvas->refreshTabs();
@@ -128,15 +151,22 @@ void OnixSourceEditor::buttonClicked(Button* b)
128151
if (!thread->foundInputSource())
129152
{
130153
CoreServices::sendStatusMessage("No Onix hardware found.");
131-
connectButton->setToggleState(false, NotificationType::dontSendNotification);
132-
connectButton->setLabel("CONNECT");
154+
connectButton->setToggleState(false, true);
133155
}
134156
}
135157
else
136158
{
137-
int result = thread->setPortVoltage((oni_dev_idx_t)PortName::PortA, 0);
159+
if (!thread->setPortVoltage(PortName::PortA, 0))
160+
{
161+
CoreServices::sendStatusMessage("Unable to set port voltage to 0 for Port A.");
162+
return;
163+
}
138164

139-
if (result != 0) { CoreServices::sendStatusMessage("Unable to set port voltage to 0 for Port A."); return; }
165+
if (!thread->setPortVoltage(PortName::PortB, 0))
166+
{
167+
CoreServices::sendStatusMessage("Unable to set port voltage to 0 for Port B.");
168+
return;
169+
}
140170

141171
canvas->removeTabs();
142172
thread->disconnectDevices(true);
@@ -150,6 +180,16 @@ void OnixSourceEditor::comboBoxChanged(ComboBox* cb)
150180
if (cb == headstageComboBoxA.get())
151181
{
152182
// TODO: Call canvas to remove / add tabs as needed depending on what is chosen
183+
String headstage = headstageComboBoxA->getText();
184+
185+
thread->updateDiscoveryParameters(PortName::PortA, PortController::getHeadstageDiscoveryParameters(headstage));
186+
}
187+
else if (cb == headstageComboBoxB.get())
188+
{
189+
// TODO: Call canvas to remove / add tabs as needed depending on what is chosen
190+
String headstage = headstageComboBoxB->getText();
191+
192+
thread->updateDiscoveryParameters(PortName::PortB, PortController::getHeadstageDiscoveryParameters(headstage));
153193
}
154194
}
155195

0 commit comments

Comments
 (0)