Skip to content

Commit e2a37a9

Browse files
committed
Check for PortStatus changes
- Add PortController as an OnixDevice, implement the necessary methods - Add PortController devices to the FrameReader so the IDs are processed
1 parent b5f9037 commit e2a37a9

12 files changed

+362
-223
lines changed

Source/Devices/Bno055.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ Bno055::~Bno055()
9393

9494
int Bno055::enableDevice()
9595
{
96-
oni_write_reg(ctx, deviceIdx, (uint32_t)Bno055Registers::ENABLE, (uint32_t)1);
96+
ONI_OK_RETURN_INT(oni_write_reg(ctx, deviceIdx, (uint32_t)Bno055Registers::ENABLE, (uint32_t)1))
9797

9898
return 0;
9999
}

Source/Devices/DeviceList.h

+1
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@
33
#include "HeadStageEEPROM.h"
44
#include "Neuropixels_1.h"
55
#include "Neuropixels2e.h"
6+
#include "PortController.h"

Source/Devices/PortController.cpp

+165
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
/*
2+
------------------------------------------------------------------
3+
4+
This file is part of the Open Ephys GUI
5+
Copyright (C) 2023 Allen Institute for Brain Science and Open Ephys
6+
7+
------------------------------------------------------------------
8+
9+
This program is free software: you can redistribute it and/or modify
10+
it under the terms of the GNU General Public License as published by
11+
the Free Software Foundation, either version 3 of the License, or
12+
(at your option) any later version.
13+
14+
This program is distributed in the hope that it will be useful,
15+
but WITHOUT ANY WARRANTY; without even the implied warranty of
16+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17+
GNU General Public License for more details.
18+
19+
You should have received a copy of the GNU General Public License
20+
along with this program. If not, see <http://www.gnu.org/licenses/>.
21+
22+
*/
23+
24+
#include "PortController.h"
25+
26+
PortController::PortController(PortName port_, oni_ctx ctx_) :
27+
OnixDevice(getPortNameString(port_), OnixDeviceType::PORT_CONTROL, (oni_dev_idx_t)port_, ctx_),
28+
port(port_)
29+
{
30+
}
31+
32+
PortController::~PortController()
33+
{
34+
}
35+
36+
int PortController::enableDevice()
37+
{
38+
ONI_OK_RETURN_INT(oni_write_reg(ctx, deviceIdx, (uint32_t)PortControllerRegister::ENABLE, (uint32_t)1))
39+
40+
return 0;
41+
}
42+
43+
void PortController::stopAcquisition()
44+
{
45+
while (!frameArray.isEmpty())
46+
{
47+
const GenericScopedLock<CriticalSection> frameLock(frameArray.getLock());
48+
oni_destroy_frame(frameArray.removeAndReturn(0));
49+
}
50+
}
51+
52+
void PortController::addFrame(oni_frame_t* frame)
53+
{
54+
const GenericScopedLock<CriticalSection> frameLock(frameArray.getLock());
55+
frameArray.add(frame);
56+
}
57+
58+
void PortController::processFrames()
59+
{
60+
while (!frameArray.isEmpty())
61+
{
62+
const GenericScopedLock<CriticalSection> frameLock(frameArray.getLock());
63+
oni_frame_t* frame = frameArray.removeAndReturn(0);
64+
65+
int16_t* dataPtr = (int16_t*)frame->data;
66+
67+
int dataOffset = 4;
68+
69+
PortStatusCode code = (PortStatusCode) *(int8_t*)(dataPtr + dataOffset);
70+
71+
errorFlag = ((uint32_t)code & LINKSTATE_SL) == 0;
72+
73+
oni_destroy_frame(frame);
74+
75+
if (errorFlag)
76+
{
77+
LOGE("Port status changed and indicated an error occurred. Port status code is " + String((uint32_t)code))
78+
return;
79+
}
80+
}
81+
}
82+
83+
void PortController::updateDiscoveryParameters(DiscoveryParameters parameters)
84+
{
85+
discoveryParameters = parameters;
86+
}
87+
88+
DiscoveryParameters PortController::getHeadstageDiscoveryParameters(String headstage)
89+
{
90+
if (headstage == "Neuropixels 1.0f")
91+
{
92+
return DiscoveryParameters(5.0f, 7.0f, 1.0f, 0.2f);
93+
}
94+
95+
return DiscoveryParameters();
96+
}
97+
98+
bool PortController::configureVoltage(float voltage) const
99+
{
100+
if (voltage == defaultVoltage)
101+
{
102+
if (discoveryParameters == DiscoveryParameters()) return false;
103+
104+
for (voltage = discoveryParameters.minVoltage; voltage <= discoveryParameters.maxVoltage; voltage += discoveryParameters.voltageIncrement)
105+
{
106+
setVoltage(voltage);
107+
108+
if (checkLinkState())
109+
{
110+
setVoltage(voltage + discoveryParameters.voltageOffset);
111+
return checkLinkState();
112+
}
113+
}
114+
}
115+
else
116+
{
117+
setVoltage(voltage);
118+
119+
return checkLinkState();
120+
}
121+
122+
return false;
123+
}
124+
125+
void PortController::setVoltageOverride(float voltage, bool waitToSettle) const
126+
{
127+
if (ctx == NULL) return;
128+
129+
ONI_OK(oni_write_reg(ctx, (oni_dev_idx_t)port, (oni_reg_addr_t)PortControllerRegister::PORTVOLTAGE, (oni_reg_val_t)(voltage * 10)));
130+
if (waitToSettle) sleep_for(std::chrono::milliseconds(500));
131+
}
132+
133+
void PortController::setVoltage(float voltage) const
134+
{
135+
if (ctx == NULL) return;
136+
137+
ONI_OK(oni_write_reg(ctx, (oni_dev_idx_t)port, (oni_reg_addr_t)PortControllerRegister::PORTVOLTAGE, 0));
138+
sleep_for(std::chrono::milliseconds(300));
139+
140+
ONI_OK(oni_write_reg(ctx, (oni_dev_idx_t)port, (oni_reg_addr_t)PortControllerRegister::PORTVOLTAGE, (oni_reg_val_t)(voltage * 10)));
141+
sleep_for(std::chrono::milliseconds(500));
142+
}
143+
144+
bool PortController::checkLinkState() const
145+
{
146+
oni_reg_val_t linkState;
147+
int result = oni_read_reg(ctx, (oni_dev_idx_t)port, (oni_reg_addr_t)PortControllerRegister::LINKSTATE, &linkState);
148+
149+
if (result != 0) { LOGE(oni_error_str(result)); return false; }
150+
else if ((linkState & LINKSTATE_SL) == 0) { LOGE("Unable to acquire communication lock."); return false; }
151+
else return true;
152+
}
153+
154+
String PortController::getPortNameString(PortName portName)
155+
{
156+
switch (portName)
157+
{
158+
case PortName::PortA:
159+
return "Port A";
160+
case PortName::PortB:
161+
return "Port B";
162+
default:
163+
break;
164+
}
165+
}

Source/Devices/PortController.h

+137
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
/*
2+
------------------------------------------------------------------
3+
4+
This file is part of the Open Ephys GUI
5+
Copyright (C) 2023 Allen Institute for Brain Science and Open Ephys
6+
7+
------------------------------------------------------------------
8+
9+
This program is free software: you can redistribute it and/or modify
10+
it under the terms of the GNU General Public License as published by
11+
the Free Software Foundation, either version 3 of the License, or
12+
(at your option) any later version.
13+
14+
This program is distributed in the hope that it will be useful,
15+
but WITHOUT ANY WARRANTY; without even the implied warranty of
16+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17+
GNU General Public License for more details.
18+
19+
You should have received a copy of the GNU General Public License
20+
along with this program. If not, see <http://www.gnu.org/licenses/>.
21+
22+
*/
23+
24+
#ifndef __PORTCONTROLLER_H__
25+
#define __PORTCONTROLLER_H__
26+
27+
#include <thread>
28+
#include <chrono>
29+
30+
#include "oni.h"
31+
#include "../OnixDevice.h"
32+
33+
using namespace std::this_thread;
34+
35+
enum class PortControllerRegister : uint32_t
36+
{
37+
ENABLE = 0,
38+
GPOSTATE = 1,
39+
DESPWR = 2,
40+
PORTVOLTAGE = 3,
41+
SAVEVOLTAGE = 4,
42+
LINKSTATE = 5
43+
};
44+
45+
enum class PortStatusCode : uint32_t
46+
{
47+
SerdesLock = 0x0001,
48+
SerdesParityPass = 0x0002,
49+
CrcError = 0x0100,
50+
TooManyDevices = 0x0200,
51+
InitializationError = 0x0400,
52+
BadPacketFormat = 0x0800,
53+
InitializationCrcError = 0x1000,
54+
};
55+
56+
class DiscoveryParameters
57+
{
58+
public:
59+
float minVoltage = 0.0f;
60+
float maxVoltage = 0.0f;
61+
float voltageOffset = 0.0f;
62+
float voltageIncrement = 0.0f;
63+
64+
DiscoveryParameters() {};
65+
66+
DiscoveryParameters(float minVoltage_, float maxVoltage_, float voltageOffset_, float voltageIncrement_)
67+
{
68+
minVoltage = minVoltage_;
69+
maxVoltage = maxVoltage_;
70+
voltageOffset = voltageOffset_;
71+
voltageIncrement = voltageIncrement_;
72+
}
73+
74+
~DiscoveryParameters() {};
75+
76+
bool operator==(const DiscoveryParameters& rhs) const
77+
{
78+
return rhs.minVoltage == minVoltage && rhs.maxVoltage == maxVoltage && rhs.voltageOffset == voltageOffset && rhs.voltageIncrement == voltageIncrement;
79+
}
80+
};
81+
82+
class PortController : public OnixDevice
83+
{
84+
public:
85+
PortController(PortName port_, const oni_ctx ctx_);
86+
87+
~PortController();
88+
89+
int enableDevice() override;
90+
91+
int updateSettings() override { return 0; }
92+
93+
void startAcquisition() override {};
94+
95+
void stopAcquisition() override;
96+
97+
void addFrame(oni_frame_t*) override;
98+
99+
void processFrames() override;
100+
101+
void addSourceBuffers(OwnedArray<DataBuffer>& sourceBuffers) override {};
102+
103+
void updateDiscoveryParameters(DiscoveryParameters parameters);
104+
105+
bool configureVoltage(float voltage = defaultVoltage) const;
106+
107+
/** Sets the voltage to the given value, after setting the voltage to zero */
108+
void setVoltage(float voltage) const;
109+
110+
/** Overrides the voltage setting and directly sets it to the given voltage */
111+
void setVoltageOverride(float voltage, bool waitToSettle = true) const;
112+
113+
bool checkLinkState() const;
114+
115+
String getPortNameString(PortName portName);
116+
117+
static DiscoveryParameters getHeadstageDiscoveryParameters(String headstage);
118+
119+
/** Check if the port status changed and there is an error reported */
120+
bool getErrorFlag() { return errorFlag; }
121+
122+
private:
123+
Array<oni_frame_t*, CriticalSection, 10> frameArray;
124+
125+
const PortName port;
126+
127+
static constexpr float defaultVoltage = -1.0f;
128+
129+
const uint32_t LINKSTATE_PP = 0x2; // parity check pass bit
130+
const uint32_t LINKSTATE_SL = 0x1; // SERDES lock bit
131+
132+
DiscoveryParameters discoveryParameters;
133+
134+
std::atomic<bool> errorFlag = false;
135+
};
136+
137+
#endif // !__PORTCONTROLLER_H__

Source/FrameReader.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323

2424
#include "FrameReader.h"
2525

26-
FrameReader::FrameReader(OwnedArray<OnixDevice>& sources_, oni_ctx& ctx_)
26+
FrameReader::FrameReader(Array<OnixDevice*> sources_, oni_ctx& ctx_)
2727
: Thread("FrameReader"),
2828
sources(sources_),
2929
ctx(ctx_)

Source/FrameReader.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -32,15 +32,15 @@
3232
class FrameReader : public Thread
3333
{
3434
public:
35-
FrameReader(OwnedArray<OnixDevice>& sources_, oni_ctx& ctx_);
35+
FrameReader(Array<OnixDevice*> sources_, oni_ctx& ctx_);
3636

3737
~FrameReader();
3838

3939
void run() override;
4040

4141
private:
4242

43-
OwnedArray<OnixDevice>& sources;
43+
Array<OnixDevice*> sources;
4444
oni_ctx& ctx;
4545
};
4646

Source/OnixDevice.h

+3-2
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939

4040
#define ONI_OK(exp) {int res = exp; if (res != ONI_ESUCCESS){LOGD(oni_error_str(res));}}
4141
#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;}}
42+
#define ONI_OK_RETURN_INT(exp) {int res = exp; if (res != ONI_ESUCCESS){LOGD(oni_error_str(res));return res;}}
4343

4444
using namespace std::chrono;
4545

@@ -54,7 +54,8 @@ enum class OnixDeviceType {
5454
BNO,
5555
NEUROPIXELS_1,
5656
NEUROPIXELS_2,
57-
ADC
57+
ADC,
58+
PORT_CONTROL
5859
};
5960

6061
struct StreamInfo {

0 commit comments

Comments
 (0)