Skip to content

Commit 550b7b2

Browse files
authored
Merge pull request #83 from open-ephys-plugins/issue-42
Add AuxiliaryIO device
2 parents 6c8cbfa + f0a6e02 commit 550b7b2

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+886
-345
lines changed

Source/Devices/AnalogIO.cpp

Lines changed: 124 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ AnalogIO::AnalogIO(std::string name, std::string hubName, const oni_dev_idx_t de
3232
"Analog Input data",
3333
getStreamIdentifier(),
3434
getNumChannels(),
35-
std::floor(AnalogIOFrequencyHz / framesToAverage),
35+
getSampleRate(),
3636
"AnalogInput",
3737
ContinuousChannel::Type::ADC,
3838
getVoltsPerDivision(AnalogIOVoltageRange::TenVolts), // NB: +/- 10 Volts
@@ -53,6 +53,11 @@ AnalogIO::AnalogIO(std::string name, std::string hubName, const oni_dev_idx_t de
5353
dataType = AnalogIODataType::Volts;
5454
}
5555

56+
int AnalogIO::getSampleRate()
57+
{
58+
return std::floor(AnalogIOFrequencyHz / framesToAverage);
59+
}
60+
5661
OnixDeviceType AnalogIO::getDeviceType()
5762
{
5863
return OnixDeviceType::ANALOGIO;
@@ -109,6 +114,78 @@ float AnalogIO::getVoltsPerDivision(AnalogIOVoltageRange voltageRange)
109114
}
110115
}
111116

117+
AnalogIODirection AnalogIO::getChannelDirection(int channelNumber)
118+
{
119+
if (channelNumber > numChannels || channelNumber < 0)
120+
{
121+
LOGE("Channel number must be between 0 and " + std::to_string(channelNumber));
122+
return AnalogIODirection::Input;
123+
}
124+
125+
return channelDirection[channelNumber];
126+
}
127+
128+
std::string AnalogIO::getChannelDirection(AnalogIODirection direction)
129+
{
130+
switch (direction)
131+
{
132+
case AnalogIODirection::Input:
133+
return "Input";
134+
case AnalogIODirection::Output:
135+
return "Output";
136+
default:
137+
return "";
138+
}
139+
}
140+
141+
void AnalogIO::setChannelDirection(int channelNumber, AnalogIODirection direction)
142+
{
143+
if (channelNumber > numChannels || channelNumber < 0)
144+
{
145+
LOGE("Channel number must be between 0 and " + std::to_string(channelNumber));
146+
return;
147+
}
148+
149+
channelDirection[channelNumber] = direction;
150+
}
151+
152+
AnalogIOVoltageRange AnalogIO::getChannelVoltageRange(int channelNumber)
153+
{
154+
if (channelNumber > numChannels || channelNumber < 0)
155+
{
156+
LOGE("Channel number must be between 0 and " + std::to_string(channelNumber));
157+
return AnalogIOVoltageRange::FiveVolts;
158+
}
159+
160+
return channelVoltageRange[channelNumber];
161+
}
162+
163+
void AnalogIO::setChannelVoltageRange(int channelNumber, AnalogIOVoltageRange direction)
164+
{
165+
if (channelNumber > numChannels || channelNumber < 0)
166+
{
167+
LOGE("Channel number must be between 0 and " + std::to_string(channelNumber));
168+
return;
169+
}
170+
171+
channelVoltageRange[channelNumber] = direction;
172+
}
173+
174+
AnalogIODataType AnalogIO::getDataType() const
175+
{
176+
return dataType;
177+
}
178+
179+
void AnalogIO::setDataType(AnalogIODataType type)
180+
{
181+
dataType = type;
182+
}
183+
184+
int AnalogIO::getNumChannels()
185+
{
186+
return numChannels;
187+
}
188+
112189
void AnalogIO::startAcquisition()
113190
{
114191
currentFrame = 0;
@@ -122,73 +199,81 @@ void AnalogIO::stopAcquisition()
122199
{
123200
while (!frameArray.isEmpty())
124201
{
125-
const GenericScopedLock<CriticalSection> frameLock(frameArray.getLock());
126202
oni_destroy_frame(frameArray.removeAndReturn(0));
127203
}
128204
}
129205

130206
void AnalogIO::addFrame(oni_frame_t* frame)
131207
{
132-
const GenericScopedLock<CriticalSection> frameLock(frameArray.getLock());
133208
frameArray.add(frame);
134209
}
135210

211+
int AnalogIO::getNumberOfFrames()
212+
{
213+
return frameArray.size();
214+
}
215+
136216
void AnalogIO::addSourceBuffers(OwnedArray<DataBuffer>& sourceBuffers)
137217
{
138218
sourceBuffers.add(new DataBuffer(streamInfos.getFirst().getNumChannels(), (int)streamInfos.getFirst().getSampleRate() * bufferSizeInSeconds));
139219
analogInputBuffer = sourceBuffers.getLast();
140220
}
141221

142-
void AnalogIO::processFrames()
222+
void AnalogIO::processFrame(uint64_t eventWord)
143223
{
144-
while (!frameArray.isEmpty())
145-
{
146-
const GenericScopedLock<CriticalSection> frameLock(frameArray.getLock());
147-
oni_frame_t* frame = frameArray.removeAndReturn(0);
224+
oni_frame_t* frame = frameArray.removeAndReturn(0);
148225

149-
int16_t* dataPtr = (int16_t*)frame->data;
226+
int16_t* dataPtr = (int16_t*)frame->data;
150227

151-
int dataOffset = 4;
228+
int dataOffset = 4;
152229

230+
for (size_t i = 0; i < numChannels; i++)
231+
{
232+
if (dataType == AnalogIODataType::S16)
233+
analogInputSamples[currentFrame + i * numFrames] += *(dataPtr + dataOffset + i);
234+
else
235+
analogInputSamples[currentFrame + i * numFrames] += *(dataPtr + dataOffset + i) * voltsPerDivision[i];
236+
}
237+
238+
currentAverageFrame++;
239+
240+
if (currentAverageFrame >= framesToAverage)
241+
{
153242
for (size_t i = 0; i < numChannels; i++)
154243
{
155-
if (dataType == AnalogIODataType::S16)
156-
analogInputSamples[currentFrame + i * numFrames] += *(dataPtr + dataOffset + i);
157-
else
158-
analogInputSamples[currentFrame + i * numFrames] += *(dataPtr + dataOffset + i) * voltsPerDivision[i];
244+
analogInputSamples[currentFrame + i * numFrames] /= framesToAverage;
159245
}
160246

161-
currentAverageFrame++;
247+
currentAverageFrame = 0;
162248

163-
if (currentAverageFrame >= framesToAverage)
164-
{
165-
for (size_t i = 0; i < numChannels; i++)
166-
{
167-
analogInputSamples[currentFrame + i * numFrames] /= framesToAverage;
168-
}
249+
timestamps[currentFrame] = deviceContext->convertTimestampToSeconds(frame->time);
250+
sampleNumbers[currentFrame] = sampleNumber++;
251+
eventCodes[currentFrame] = eventWord;
169252

170-
currentAverageFrame = 0;
253+
currentFrame++;
254+
}
171255

172-
timestamps[currentFrame] = deviceContext->convertTimestampToSeconds(frame->time);
173-
sampleNumbers[currentFrame] = sampleNumber++;
256+
oni_destroy_frame(frame);
174257

175-
currentFrame++;
176-
}
177-
178-
oni_destroy_frame(frame);
258+
if (currentFrame >= numFrames)
259+
{
260+
shouldAddToBuffer = true;
261+
currentFrame = 0;
262+
}
179263

180-
if (currentFrame >= numFrames)
181-
{
182-
shouldAddToBuffer = true;
183-
currentFrame = 0;
184-
}
264+
if (shouldAddToBuffer)
265+
{
266+
shouldAddToBuffer = false;
267+
analogInputBuffer->addToBuffer(analogInputSamples.data(), sampleNumbers, timestamps, eventCodes, numFrames);
185268

186-
if (shouldAddToBuffer)
187-
{
188-
shouldAddToBuffer = false;
189-
analogInputBuffer->addToBuffer(analogInputSamples.data(), sampleNumbers, timestamps, eventCodes, numFrames);
269+
analogInputSamples.fill(0);
270+
}
271+
}
190272

191-
analogInputSamples.fill(0);
192-
}
273+
void AnalogIO::processFrames()
274+
{
275+
while (!frameArray.isEmpty())
276+
{
277+
processFrame();
193278
}
194279
}

Source/Devices/AnalogIO.h

Lines changed: 23 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -71,102 +71,46 @@ namespace OnixSourcePlugin
7171
public:
7272
AnalogIO(std::string name, std::string hubName, const oni_dev_idx_t, std::shared_ptr<Onix1> oni_ctx);
7373

74-
/** Configures the device so that it is ready to stream with default settings */
7574
int configureDevice() override;
76-
77-
/** Update the settings of the device */
7875
bool updateSettings() override;
79-
80-
/** Starts probe data streaming */
8176
void startAcquisition() override;
82-
83-
/** Stops probe data streaming*/
8477
void stopAcquisition() override;
85-
86-
/** Given the sourceBuffers from OnixSource, add all streams for the current device to the array */
8778
void addSourceBuffers(OwnedArray<DataBuffer>& sourceBuffers) override;
88-
8979
void addFrame(oni_frame_t*) override;
90-
9180
void processFrames() override;
9281

93-
AnalogIODirection getChannelDirection(int channelNumber)
94-
{
95-
if (channelNumber > numChannels || channelNumber < 0)
96-
{
97-
LOGE("Channel number must be between 0 and " + std::to_string(channelNumber));
98-
return AnalogIODirection::Input;
99-
}
100-
101-
return channelDirection[channelNumber];
102-
}
103-
104-
static std::string getChannelDirection(AnalogIODirection direction)
105-
{
106-
switch (direction)
107-
{
108-
case AnalogIODirection::Input:
109-
return "Input";
110-
case AnalogIODirection::Output:
111-
return "Output";
112-
default:
113-
return "";
114-
}
115-
}
116-
117-
void setChannelDirection(int channelNumber, AnalogIODirection direction)
118-
{
119-
if (channelNumber > numChannels || channelNumber < 0)
120-
{
121-
LOGE("Channel number must be between 0 and " + std::to_string(channelNumber));
122-
return;
123-
}
124-
125-
channelDirection[channelNumber] = direction;
126-
}
127-
128-
AnalogIOVoltageRange getChannelVoltageRange(int channelNumber)
129-
{
130-
if (channelNumber > numChannels || channelNumber < 0)
131-
{
132-
LOGE("Channel number must be between 0 and " + std::to_string(channelNumber));
133-
return AnalogIOVoltageRange::FiveVolts;
134-
}
135-
136-
return channelVoltageRange[channelNumber];
137-
}
138-
139-
void setChannelVoltageRange(int channelNumber, AnalogIOVoltageRange direction)
140-
{
141-
if (channelNumber > numChannels || channelNumber < 0)
142-
{
143-
LOGE("Channel number must be between 0 and " + std::to_string(channelNumber));
144-
return;
145-
}
146-
147-
channelVoltageRange[channelNumber] = direction;
148-
}
149-
150-
AnalogIODataType getDataType() const { return dataType; }
151-
152-
void setDataType(AnalogIODataType type) { dataType = type; }
153-
154-
int getNumChannels() { return numChannels; }
82+
void processFrame(uint64_t eventWord = 0);
83+
84+
AnalogIODirection getChannelDirection(int channelNumber);
85+
static std::string getChannelDirection(AnalogIODirection direction);
86+
void setChannelDirection(int channelNumber, AnalogIODirection direction);
87+
88+
AnalogIOVoltageRange getChannelVoltageRange(int channelNumber);
89+
void setChannelVoltageRange(int channelNumber, AnalogIOVoltageRange direction);
90+
91+
AnalogIODataType getDataType() const;
92+
void setDataType(AnalogIODataType type);
93+
94+
int getNumChannels();
15595

15696
static OnixDeviceType getDeviceType();
15797

98+
static constexpr int framesToAverage = 4; // NB: Downsampling from 100 kHz to 25 kHz
99+
static int getSampleRate();
100+
101+
int getNumberOfFrames();
102+
158103
private:
159104

160105
DataBuffer* analogInputBuffer = nullptr;
161106

162-
static const int AnalogIOFrequencyHz = 100000;
107+
static constexpr int AnalogIOFrequencyHz = 100000;
163108

164-
static const int numFrames = 25;
165-
static const int framesToAverage = 4; // NB: Downsampling from 100 kHz to 25 kHz
166-
static const int numChannels = 12;
109+
static constexpr int numFrames = 25;
110+
static constexpr int numChannels = 12;
167111

168-
static const int numberOfDivisions = 1 << 16;
169-
const int dacMidScale = 1 << 15;
112+
static constexpr int numberOfDivisions = 1 << 16;
113+
static constexpr int dacMidScale = 1 << 15;
170114

171115
std::array<AnalogIODirection, numChannels> channelDirection;
172116
std::array<AnalogIOVoltageRange, numChannels> channelVoltageRange;

0 commit comments

Comments
 (0)