-
Aaron Cuevas Lopez authoredAaron Cuevas Lopez authored
InfoObjects.cpp 11.93 KiB
/*
------------------------------------------------------------------
This file is part of the Open Ephys GUI
Copyright (C) 2014 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 <http://www.gnu.org/licenses/>.
*/
#include "InfoObjects.h"
#include "../GenericProcessor/GenericProcessor.h"
/** Common classes **/
//Empty protected constructors
HistoryObject::HistoryObject() {}
NamedInfoObject::NamedInfoObject() {}
//NodeInfoBase
NodeInfoBase::NodeInfoBase(uint16 id) :
m_nodeID(id)
{}
unsigned int NodeInfoBase::getCurrentNodeID() const
{
return m_nodeID;
}
//History Object
String HistoryObject::getHistoricString()
{
return m_historicString;
}
void HistoryObject::addToHistoricString(String entry)
{
if (m_historicString.isEmpty())
m_historicString = entry;
else
m_historicString += (" -> " + entry);
}
//SourceProcessorInfo
SourceProcessorInfo::SourceProcessorInfo(const GenericProcessor* source, uint16 subproc)
: m_sourceNodeID(source->getNodeId()),
m_sourceSubNodeIndex(subproc),
m_sourceType(source->getName()),
m_sourceName(source->getName()) //TODO: fix those two when we have the ability to rename processors
{
}
uint16 SourceProcessorInfo::getSourceNodeID() const
{
return m_sourceNodeID;
}
uint16 SourceProcessorInfo::getSubProcessorIdx() const
{
return m_sourceSubNodeIndex;
}
String SourceProcessorInfo::getSourceType() const
{
return m_sourceType;
}
String SourceProcessorInfo::getSourceName() const
{
return m_sourceName;
}
//NamedInfoObject
void NamedInfoObject::setName(String name)
{
m_name = name;
}
String NamedInfoObject::getName() const
{
return m_name;
}
void NamedInfoObject::setDescriptor(String descriptor)
{
m_descriptor = descriptor;
}
String NamedInfoObject::getDescriptor() const
{
return m_descriptor;
}
void NamedInfoObject::setDescription(String description)
{
m_description = description;
}
String NamedInfoObject::getDescription() const
{
return m_description;
}
//InfoObjectCommon
InfoObjectCommon::InfoObjectCommon(uint16 idx, uint16 typeidx, float sampleRate, const GenericProcessor* source, uint16 subproc)
: NodeInfoBase(source->getNodeId()),
SourceProcessorInfo(source, subproc),
m_sourceIndex(idx),
m_sourceTypeIndex(typeidx),
m_sampleRate(sampleRate)
{
}
float InfoObjectCommon::getSampleRate() const
{
return m_sampleRate;
}
uint16 InfoObjectCommon::getSourceIndex() const
{
return m_sourceIndex;
}
uint16 InfoObjectCommon::getSourceTypeIndex() const
{
return m_sourceTypeIndex;
}
//DataChannel
DataChannel::DataChannel(DataChannelTypes type, float sampleRate, GenericProcessor* source, uint16 subproc) :
InfoObjectCommon(source->dataChannelCount++, source->dataChannelTypeCount[type]++, sampleRate, source, subproc),
m_type(type)
{
setDefaultNameAndDescription();
}
DataChannel::DataChannel(const DataChannel& ch)
: InfoObjectCommon(ch), //Call default copy constructors of base classes
MetaDataInfoObject(ch),
HistoryObject(ch),
m_type(ch.m_type),
m_bitVolts(ch.m_bitVolts),
m_isEnabled(true),
m_isMonitored(false),
m_isRecording(false)
{
}
DataChannel::~DataChannel()
{
}
InfoObjectCommon::InfoObjectType DataChannel::getInfoObjectType() const
{
return InfoObjectCommon::DATA_CHANNEL;
}
void DataChannel::setBitVolts(float bitVolts)
{
m_bitVolts = bitVolts;
}
float DataChannel::getBitVolts() const
{
return m_bitVolts;
}
DataChannel::DataChannelTypes DataChannel::getChannelType() const
{
return m_type;
}
bool DataChannel::isEnabled() const
{
return m_isEnabled;
}
void DataChannel::setEnable(bool e)
{
m_isEnabled = e;
}
bool DataChannel::isMonitored() const
{
return m_isMonitored;
}
void DataChannel::setMonitored(bool e)
{
m_isMonitored = e;
}
void DataChannel::setRecordState(bool t)
{
m_isRecording = t;
}
bool DataChannel::getRecordState() const
{
return m_isRecording;
}
void DataChannel::reset()
{
m_bitVolts = 1.0f;
m_isEnabled = true;
m_isMonitored = false;
m_isRecording = false;
}
void DataChannel::setDefaultNameAndDescription()
{
String name;
String description;
String descriptor = "continuous.";
switch (m_type)
{
case HEADSTAGE_CHANNEL:
name = "CH";
description = "Headstage";
descriptor += "headstage";
break;
case AUX_CHANNEL:
name = "AUX ";
description = "Auxiliar";
descriptor += "aux";
break;
case ADC_CHANNEL:
name = "ADC ";
description = "ADC";
descriptor = "adc";
break;
default:
setName("INVALID");
setDescription("Invalid Channel");
setDescriptor("invalid");
return;
break;
}
name += " p";
name += String(getSourceNodeID()) + String(".") + String(getSubProcessorIdx());
name += " n";
name += String(getSourceTypeIndex());
setName(name);
setDescription(description + " data channel");
setDescriptor(descriptor);
}
//EventChannel
EventChannel::EventChannel(EventChannelTypes type, unsigned int nChannels, unsigned int dataLength, float sampleRate, GenericProcessor* source, uint16 subproc)
: InfoObjectCommon(source->eventChannelCount++, source->eventChannelTypeCount[type]++, sampleRate, source, subproc),
m_type(type)
{
m_numChannels = nChannels;
if (m_type == TTL)
{
m_length = (m_numChannels + 7) / 8;
m_dataSize = m_length;
}
else
{
m_length = dataLength;
m_dataSize = dataLength * getTypeByteSize(m_type);
//for messages, add 1 byte to account for the null terminator
if (m_type == TEXT) m_dataSize += 1;
}
setDefaultNameAndDescription();
}
EventChannel::~EventChannel()
{
}
InfoObjectCommon::InfoObjectType EventChannel::getInfoObjectType() const
{
return InfoObjectCommon::EVENT_CHANNEL;
}
EventChannel::EventChannelTypes EventChannel::getChannelType() const
{
return m_type;
}
unsigned int EventChannel::getNumChannels() const
{
return m_numChannels;
}
unsigned int EventChannel::getLength() const
{
return m_length;
}
size_t EventChannel::getDataSize() const
{
return m_dataSize;
}
void EventChannel::setShouldBeRecorded(bool status)
{
m_shouldBeRecorded = status;
}
bool EventChannel::getShouldBeRecorded() const
{
return m_shouldBeRecorded;
}
size_t EventChannel::getTypeByteSize(EventChannel::EventChannelTypes type)
{
switch (type)
{
case INT8_ARRAY: return sizeof(int8);
case UINT8_ARRAY: return sizeof(uint8);
case INT16_ARRAY: return sizeof(int16);
case UINT16_ARRAY: return sizeof(uint16);
case INT32_ARRAY: return sizeof(int32);
case UINT32_ARRAY: return sizeof(uint32);
case INT64_ARRAY: return sizeof(int64);
case UINT64_ARRAY: return sizeof(uint64);
default: return sizeof(char);
}
}
void EventChannel::setDefaultNameAndDescription()
{
String name;
switch (m_type)
{
case TTL: name = "TTL"; break;
case TEXT: name = "TEXT"; break;
case INT8_ARRAY: name = "INT8"; break;
case UINT8_ARRAY: name = "UINT8"; break;
case INT16_ARRAY: name = "INT16"; break;
case UINT16_ARRAY: name = "UINT16"; break;
case INT32_ARRAY: name = "INT32"; break;
case UINT32_ARRAY: name = "UINT32"; break;
case INT64_ARRAY: name = "INT64"; break;
case UINT64_ARRAY: name = "UINT64"; break;
default:
setName("INVALID");
setDescription("Invalid channel");
setDescriptor("invalid");
return;
break;
}
name += "p";
name += String(getSourceNodeID()) + String(".") + String(getSubProcessorIdx());
name += " n";
name += String(getSourceTypeIndex());
setName(name);
if (m_type == TTL)
{
setDescription("TTL data input");
setDescriptor("genericevent.ttl");
}
else if (m_type == TEXT)
{
setDescription("Text event");
setDescriptor("genericevent.text");
}
else
{
if (m_length > 1)
setDescription(name + " data array");
else
setDescription(name + " single value");
setDescriptor("genericevent." + name.toLowerCase());
}
}
//SpikeChannel
SpikeChannel::SpikeChannel(ElectrodeTypes type, GenericProcessor* source, const Array<const DataChannel*>& sourceChannels, uint16 subproc)
: InfoObjectCommon(source->spikeChannelCount++, source->spikeChannelTypeCount[type]++, sourceChannels[0]->getSampleRate(), source, subproc),
m_type(type) //We define the sample rate of the whole spike to be equal to that of the first channel. A spike composed from channels from different sample rates has no sense
{
int n = sourceChannels.size();
jassert(n == getNumChannels(type));
for (int i = 0; i < n; i++)
{
sourceChannelInfo info;
const DataChannel* chan = sourceChannels[i];
info.processorID = chan->getSourceNodeID();
info.subProcessorID = chan->getSubProcessorIdx();
info.channelIDX = chan->getSourceIndex();
m_sourceInfo.add(info);
m_channelBitVolts.add(chan->getBitVolts());
}
setDefaultNameAndDescription();
}
SpikeChannel::~SpikeChannel()
{}
InfoObjectCommon::InfoObjectType SpikeChannel::getInfoObjectType() const
{
return InfoObjectCommon::SPIKE_CHANNEL;
}
SpikeChannel::ElectrodeTypes SpikeChannel::getChannelType() const
{
return m_type;
}
Array<sourceChannelInfo> SpikeChannel::getSourceChannelInfo() const
{
return m_sourceInfo;
}
void SpikeChannel::setGain(float gain)
{
m_gain = gain;
}
float SpikeChannel::getGain() const
{
return m_gain;
}
void SpikeChannel::setNumSamples(unsigned int preSamples, unsigned int postSamples)
{
m_numPreSamples = preSamples;
m_numPostSamples = postSamples;
}
unsigned int SpikeChannel::getPrePeakSamples() const
{
return m_numPreSamples;
}
unsigned int SpikeChannel::getPostPeakSamples() const
{
return m_numPostSamples;
}
unsigned int SpikeChannel::getTotalSamples() const
{
return m_numPostSamples + m_numPreSamples;
}
unsigned int SpikeChannel::getNumChannels() const
{
return getNumChannels(m_type);
}
unsigned int SpikeChannel::getNumChannels(SpikeChannel::ElectrodeTypes type)
{
switch (type)
{
case SINGLE: return 1;
case STEREOTRODE: return 2;
case TETRODE: return 4;
default: return 0;
}
}
SpikeChannel::ElectrodeTypes SpikeChannel::typeFromNumChannels(unsigned int nChannels)
{
switch (nChannels)
{
case 1: return SINGLE;
case 2: return STEREOTRODE;
case 4: return TETRODE;
default: return INVALID;
}
}
size_t SpikeChannel::getDataSize() const
{
return getTotalSamples()*getNumChannels()*sizeof(float);
}
size_t SpikeChannel::getChannelDataSize() const
{
return getTotalSamples()*sizeof(float);
}
float SpikeChannel::getChannelBitVolts(int index) const
{
if (index < 0 || index >= m_channelBitVolts.size())
return 1.0f;
else
return m_channelBitVolts[index];
}
void SpikeChannel::setDefaultNameAndDescription()
{
String name;
String description;
String descriptor = "spikesource.";
switch (m_type)
{
case SINGLE:
name = "SE ";
description = "Single electrode";
descriptor += "single";
break;
case STEREOTRODE:
name = "ST ";
description = "Stereotrode";
descriptor += "stereotrode";
break;
case TETRODE:
name = "TT ";
description = "Tetrode";
descriptor += "tetrode";
break;
default: name = "INVALID "; break;
}
name += String(" p") + String(getSourceNodeID()) + String(".") + String(getSubProcessorIdx()) + String(" n") + String(getSourceTypeIndex());
setName(name);
setDescription(description + " spike data source");
setDescriptor(descriptor);
}
//ConfigurationObject
ConfigurationObject::ConfigurationObject(String descriptor, GenericProcessor* source, uint16 subproc)
: SourceProcessorInfo(source, subproc)
{
setDefaultNameAndDescription();
setDescriptor(descriptor);
}
void ConfigurationObject::setShouldBeRecorded(bool status)
{
m_shouldBeRecorded = status;
}
bool ConfigurationObject::getShouldBeRecorded() const
{
return m_shouldBeRecorded;
}
void ConfigurationObject::setDefaultNameAndDescription()
{
setName("Configuration Object");
setDescription("Generic configuration object");
}