Skip to content
Merged
163 changes: 124 additions & 39 deletions Source/Devices/AnalogIO.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ AnalogIO::AnalogIO(std::string name, std::string hubName, const oni_dev_idx_t de
"Analog Input data",
getStreamIdentifier(),
getNumChannels(),
std::floor(AnalogIOFrequencyHz / framesToAverage),
getSampleRate(),
"AnalogInput",
ContinuousChannel::Type::ADC,
getVoltsPerDivision(AnalogIOVoltageRange::TenVolts), // NB: +/- 10 Volts
Expand All @@ -53,6 +53,11 @@ AnalogIO::AnalogIO(std::string name, std::string hubName, const oni_dev_idx_t de
dataType = AnalogIODataType::Volts;
}

int AnalogIO::getSampleRate()
{
return std::floor(AnalogIOFrequencyHz / framesToAverage);
}

OnixDeviceType AnalogIO::getDeviceType()
{
return OnixDeviceType::ANALOGIO;
Expand Down Expand Up @@ -109,6 +114,78 @@ float AnalogIO::getVoltsPerDivision(AnalogIOVoltageRange voltageRange)
}
}

AnalogIODirection AnalogIO::getChannelDirection(int channelNumber)
{
if (channelNumber > numChannels || channelNumber < 0)
{
LOGE("Channel number must be between 0 and " + std::to_string(channelNumber));
return AnalogIODirection::Input;
}

return channelDirection[channelNumber];
}

std::string AnalogIO::getChannelDirection(AnalogIODirection direction)
{
switch (direction)
{
case AnalogIODirection::Input:
return "Input";
case AnalogIODirection::Output:
return "Output";
default:
return "";
}
}

void AnalogIO::setChannelDirection(int channelNumber, AnalogIODirection direction)
{
if (channelNumber > numChannels || channelNumber < 0)
{
LOGE("Channel number must be between 0 and " + std::to_string(channelNumber));
return;
}

channelDirection[channelNumber] = direction;
}

AnalogIOVoltageRange AnalogIO::getChannelVoltageRange(int channelNumber)
{
if (channelNumber > numChannels || channelNumber < 0)
{
LOGE("Channel number must be between 0 and " + std::to_string(channelNumber));
return AnalogIOVoltageRange::FiveVolts;
}

return channelVoltageRange[channelNumber];
}

void AnalogIO::setChannelVoltageRange(int channelNumber, AnalogIOVoltageRange direction)
{
if (channelNumber > numChannels || channelNumber < 0)
{
LOGE("Channel number must be between 0 and " + std::to_string(channelNumber));
return;
}

channelVoltageRange[channelNumber] = direction;
}

AnalogIODataType AnalogIO::getDataType() const
{
return dataType;
}

void AnalogIO::setDataType(AnalogIODataType type)
{
dataType = type;
}

int AnalogIO::getNumChannels()
{
return numChannels;
}

void AnalogIO::startAcquisition()
{
currentFrame = 0;
Expand All @@ -122,73 +199,81 @@ void AnalogIO::stopAcquisition()
{
while (!frameArray.isEmpty())
{
const GenericScopedLock<CriticalSection> frameLock(frameArray.getLock());
oni_destroy_frame(frameArray.removeAndReturn(0));
}
}

void AnalogIO::addFrame(oni_frame_t* frame)
{
const GenericScopedLock<CriticalSection> frameLock(frameArray.getLock());
frameArray.add(frame);
}

int AnalogIO::getNumberOfFrames()
{
return frameArray.size();
}

void AnalogIO::addSourceBuffers(OwnedArray<DataBuffer>& sourceBuffers)
{
sourceBuffers.add(new DataBuffer(streamInfos.getFirst().getNumChannels(), (int)streamInfos.getFirst().getSampleRate() * bufferSizeInSeconds));
analogInputBuffer = sourceBuffers.getLast();
}

void AnalogIO::processFrames()
void AnalogIO::processFrame(uint64_t eventWord)
{
while (!frameArray.isEmpty())
{
const GenericScopedLock<CriticalSection> frameLock(frameArray.getLock());
oni_frame_t* frame = frameArray.removeAndReturn(0);
oni_frame_t* frame = frameArray.removeAndReturn(0);

int16_t* dataPtr = (int16_t*)frame->data;
int16_t* dataPtr = (int16_t*)frame->data;

int dataOffset = 4;
int dataOffset = 4;

for (size_t i = 0; i < numChannels; i++)
{
if (dataType == AnalogIODataType::S16)
analogInputSamples[currentFrame + i * numFrames] += *(dataPtr + dataOffset + i);
else
analogInputSamples[currentFrame + i * numFrames] += *(dataPtr + dataOffset + i) * voltsPerDivision[i];
}

currentAverageFrame++;

if (currentAverageFrame >= framesToAverage)
{
for (size_t i = 0; i < numChannels; i++)
{
if (dataType == AnalogIODataType::S16)
analogInputSamples[currentFrame + i * numFrames] += *(dataPtr + dataOffset + i);
else
analogInputSamples[currentFrame + i * numFrames] += *(dataPtr + dataOffset + i) * voltsPerDivision[i];
analogInputSamples[currentFrame + i * numFrames] /= framesToAverage;
}

currentAverageFrame++;
currentAverageFrame = 0;

if (currentAverageFrame >= framesToAverage)
{
for (size_t i = 0; i < numChannels; i++)
{
analogInputSamples[currentFrame + i * numFrames] /= framesToAverage;
}
timestamps[currentFrame] = deviceContext->convertTimestampToSeconds(frame->time);
sampleNumbers[currentFrame] = sampleNumber++;
eventCodes[currentFrame] = eventWord;

currentAverageFrame = 0;
currentFrame++;
}

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

currentFrame++;
}

oni_destroy_frame(frame);
if (currentFrame >= numFrames)
{
shouldAddToBuffer = true;
currentFrame = 0;
}

if (currentFrame >= numFrames)
{
shouldAddToBuffer = true;
currentFrame = 0;
}
if (shouldAddToBuffer)
{
shouldAddToBuffer = false;
analogInputBuffer->addToBuffer(analogInputSamples.data(), sampleNumbers, timestamps, eventCodes, numFrames);

if (shouldAddToBuffer)
{
shouldAddToBuffer = false;
analogInputBuffer->addToBuffer(analogInputSamples.data(), sampleNumbers, timestamps, eventCodes, numFrames);
analogInputSamples.fill(0);
}
}

analogInputSamples.fill(0);
}
void AnalogIO::processFrames()
{
while (!frameArray.isEmpty())
{
processFrame();
}
}
102 changes: 23 additions & 79 deletions Source/Devices/AnalogIO.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,102 +71,46 @@ namespace OnixSourcePlugin
public:
AnalogIO(std::string name, std::string hubName, const oni_dev_idx_t, std::shared_ptr<Onix1> oni_ctx);

/** Configures the device so that it is ready to stream with default settings */
int configureDevice() override;

/** Update the settings of the device */
bool updateSettings() override;

/** Starts probe data streaming */
void startAcquisition() override;

/** Stops probe data streaming*/
void stopAcquisition() override;

/** Given the sourceBuffers from OnixSource, add all streams for the current device to the array */
void addSourceBuffers(OwnedArray<DataBuffer>& sourceBuffers) override;

void addFrame(oni_frame_t*) override;

void processFrames() override;

AnalogIODirection getChannelDirection(int channelNumber)
{
if (channelNumber > numChannels || channelNumber < 0)
{
LOGE("Channel number must be between 0 and " + std::to_string(channelNumber));
return AnalogIODirection::Input;
}

return channelDirection[channelNumber];
}

static std::string getChannelDirection(AnalogIODirection direction)
{
switch (direction)
{
case AnalogIODirection::Input:
return "Input";
case AnalogIODirection::Output:
return "Output";
default:
return "";
}
}

void setChannelDirection(int channelNumber, AnalogIODirection direction)
{
if (channelNumber > numChannels || channelNumber < 0)
{
LOGE("Channel number must be between 0 and " + std::to_string(channelNumber));
return;
}

channelDirection[channelNumber] = direction;
}

AnalogIOVoltageRange getChannelVoltageRange(int channelNumber)
{
if (channelNumber > numChannels || channelNumber < 0)
{
LOGE("Channel number must be between 0 and " + std::to_string(channelNumber));
return AnalogIOVoltageRange::FiveVolts;
}

return channelVoltageRange[channelNumber];
}

void setChannelVoltageRange(int channelNumber, AnalogIOVoltageRange direction)
{
if (channelNumber > numChannels || channelNumber < 0)
{
LOGE("Channel number must be between 0 and " + std::to_string(channelNumber));
return;
}

channelVoltageRange[channelNumber] = direction;
}

AnalogIODataType getDataType() const { return dataType; }

void setDataType(AnalogIODataType type) { dataType = type; }

int getNumChannels() { return numChannels; }
void processFrame(uint64_t eventWord = 0);

AnalogIODirection getChannelDirection(int channelNumber);
static std::string getChannelDirection(AnalogIODirection direction);
void setChannelDirection(int channelNumber, AnalogIODirection direction);

AnalogIOVoltageRange getChannelVoltageRange(int channelNumber);
void setChannelVoltageRange(int channelNumber, AnalogIOVoltageRange direction);

AnalogIODataType getDataType() const;
void setDataType(AnalogIODataType type);

int getNumChannels();

static OnixDeviceType getDeviceType();

static constexpr int framesToAverage = 4; // NB: Downsampling from 100 kHz to 25 kHz
static int getSampleRate();

int getNumberOfFrames();

private:

DataBuffer* analogInputBuffer = nullptr;

static const int AnalogIOFrequencyHz = 100000;
static constexpr int AnalogIOFrequencyHz = 100000;

static const int numFrames = 25;
static const int framesToAverage = 4; // NB: Downsampling from 100 kHz to 25 kHz
static const int numChannels = 12;
static constexpr int numFrames = 25;
static constexpr int numChannels = 12;

static const int numberOfDivisions = 1 << 16;
const int dacMidScale = 1 << 15;
static constexpr int numberOfDivisions = 1 << 16;
static constexpr int dacMidScale = 1 << 15;

std::array<AnalogIODirection, numChannels> channelDirection;
std::array<AnalogIOVoltageRange, numChannels> channelVoltageRange;
Expand Down
Loading