Files
normativeTypes/src/ntmultiChannel.cpp

328 lines
8.6 KiB
C++

/* ntmultiChannel.cpp */
/*
* Copyright information and license terms for this software can be
* found in the file LICENSE that is included with the distribution
*/
#include <algorithm>
#include "validator.h"
#define epicsExportSharedSymbols
#include <pv/ntmultiChannel.h>
#include <pv/ntutils.h>
using namespace std;
using namespace epics::pvData;
namespace epics { namespace nt {
static FieldCreatePtr fieldCreate = getFieldCreate();
static PVDataCreatePtr pvDataCreate = getPVDataCreate();
static NTFieldPtr ntField = NTField::get();
namespace detail {
NTMultiChannelBuilder::shared_pointer NTMultiChannelBuilder::value(UnionConstPtr valuePtr)
{
valueType = valuePtr;
return shared_from_this();
}
NTMultiChannelBuilder::shared_pointer NTMultiChannelBuilder::addDescriptor()
{
descriptor = true;
return shared_from_this();
}
NTMultiChannelBuilder::shared_pointer NTMultiChannelBuilder::addAlarm()
{
alarm = true;
return shared_from_this();
}
NTMultiChannelBuilder::shared_pointer NTMultiChannelBuilder::addTimeStamp()
{
timeStamp = true;
return shared_from_this();
}
NTMultiChannelBuilder::shared_pointer NTMultiChannelBuilder::addSeverity()
{
severity = true;
return shared_from_this();
}
NTMultiChannelBuilder::shared_pointer NTMultiChannelBuilder::addStatus()
{
status = true;
return shared_from_this();
}
NTMultiChannelBuilder::shared_pointer NTMultiChannelBuilder::addMessage()
{
message = true;
return shared_from_this();
}
NTMultiChannelBuilder::shared_pointer NTMultiChannelBuilder::addSecondsPastEpoch()
{
secondsPastEpoch = true;
return shared_from_this();
}
NTMultiChannelBuilder::shared_pointer NTMultiChannelBuilder::addNanoseconds()
{
nanoseconds = true;
return shared_from_this();
}
NTMultiChannelBuilder::shared_pointer NTMultiChannelBuilder::addUserTag()
{
userTag = true;
return shared_from_this();
}
NTMultiChannelBuilder::shared_pointer NTMultiChannelBuilder::addIsConnected()
{
isConnected = true;
return shared_from_this();
}
StructureConstPtr NTMultiChannelBuilder::createStructure()
{
StandardFieldPtr standardField = getStandardField();
size_t nfields = 2;
size_t extraCount = extraFieldNames.size();
nfields += extraCount;
if(descriptor) ++nfields;
if(alarm) ++nfields;
if(timeStamp) ++nfields;
if(severity) ++nfields;
if(status) ++nfields;
if(message) ++nfields;
if(secondsPastEpoch) ++nfields;
if(nanoseconds) ++nfields;
if(userTag) ++nfields;
if(isConnected) ++nfields;
FieldConstPtrArray fields(nfields);
StringArray names(nfields);
size_t ind = 0;
names[ind] = "value";
if(valueType) {
fields[ind++] = fieldCreate->createUnionArray(valueType);
} else {
fields[ind++] = fieldCreate->createVariantUnionArray();
}
names[ind] = "channelName";
fields[ind++] = fieldCreate->createScalarArray(pvString);
if(descriptor) {
names[ind] = "descriptor";
fields[ind++] = fieldCreate->createScalar(pvString);
}
if(alarm) {
names[ind] = "alarm";
fields[ind++] = standardField->alarm();
}
if(timeStamp) {
names[ind] = "timeStamp";
fields[ind++] = standardField->timeStamp();
}
if(severity) {
names[ind] = "severity";
fields[ind++] = fieldCreate->createScalarArray(pvInt);
}
if(status) {
names[ind] = "status";
fields[ind++] = fieldCreate->createScalarArray(pvInt);
}
if(message) {
names[ind] = "message";
fields[ind++] = fieldCreate->createScalarArray(pvString);
}
if(secondsPastEpoch) {
names[ind] = "secondsPastEpoch";
fields[ind++] = fieldCreate->createScalarArray(pvLong);
}
if(nanoseconds) {
names[ind] = "nanoseconds";
fields[ind++] = fieldCreate->createScalarArray(pvInt);
}
if(userTag) {
names[ind] = "userTag";
fields[ind++] = fieldCreate->createScalarArray(pvInt);
}
if(isConnected) {
names[ind] = "isConnected";
fields[ind++] = fieldCreate->createScalarArray(pvBoolean);
}
for (size_t i = 0; i< extraCount; i++) {
names[ind] = extraFieldNames[i];
fields[ind++] = extraFields[i];
}
StructureConstPtr st = fieldCreate->createStructure(NTMultiChannel::URI,names,fields);
reset();
return st;
}
PVStructurePtr NTMultiChannelBuilder::createPVStructure()
{
return pvDataCreate->createPVStructure(createStructure());
}
NTMultiChannelPtr NTMultiChannelBuilder::create()
{
return NTMultiChannelPtr(new NTMultiChannel(createPVStructure()));
}
NTMultiChannelBuilder::NTMultiChannelBuilder()
{
reset();
}
void NTMultiChannelBuilder::reset()
{
valueType.reset();
extraFieldNames.clear();
extraFields.clear();
descriptor = false;
alarm = false;
timeStamp = false;
severity = false;
status = false;
message = false;
secondsPastEpoch = false;
nanoseconds = false;
userTag = false;
isConnected = false;
}
NTMultiChannelBuilder::shared_pointer NTMultiChannelBuilder::add(string const & name, FieldConstPtr const & field)
{
extraFields.push_back(field); extraFieldNames.push_back(name);
return shared_from_this();
}
}
const std::string NTMultiChannel::URI("epics:nt/NTMultiChannel:1.0");
NTMultiChannel::shared_pointer NTMultiChannel::wrap(PVStructurePtr const & pvStructure)
{
if(!isCompatible(pvStructure)) return shared_pointer();
return wrapUnsafe(pvStructure);
}
NTMultiChannel::shared_pointer NTMultiChannel::wrapUnsafe(PVStructurePtr const & pvStructure)
{
return shared_pointer(new NTMultiChannel(pvStructure));
}
bool NTMultiChannel::is_a(StructureConstPtr const &structure)
{
return NTUtils::is_a(structure->getID(), URI);
}
bool NTMultiChannel::is_a(PVStructurePtr const & pvStructure)
{
return is_a(pvStructure->getStructure());
}
bool NTMultiChannel::isCompatible(StructureConstPtr const & structure)
{
if (!structure)
return false;
Result result(structure);
return result
.is<Structure>()
.has<UnionArray>("value")
.has<ScalarArray>("channelName")
.maybeHas<ScalarArray>("severity")
.maybeHas<ScalarArray>("status")
.maybeHas<ScalarArray>("message")
.maybeHas<ScalarArray>("secondsPastEpoch")
.maybeHas<ScalarArray>("nanoseconds")
.maybeHas<ScalarArray>("userTag")
.maybeHas<Scalar>("descriptor")
.maybeHas<&NTField::isAlarm, Structure>("alarm")
.maybeHas<&NTField::isTimeStamp, Structure>("timeStamp")
.valid();
}
bool NTMultiChannel::isCompatible(PVStructurePtr const &pvStructure)
{
if(!pvStructure.get()) return false;
return isCompatible(pvStructure->getStructure());
}
bool NTMultiChannel::isValid()
{
size_t valueLength = getValue()->getLength();
if (getChannelName()->getLength() != valueLength) return false;
PVScalarArrayPtr arrayFields[] = {
getSeverity(), getStatus(), getMessage(),
getSecondsPastEpoch(), getNanoseconds(), getUserTag()
};
size_t N = sizeof(arrayFields)/sizeof(arrayFields[0]);
PVScalarArrayPtr arrayField;
for (PVScalarArrayPtr * pa = arrayFields; pa != arrayFields+N; ++pa)
{
arrayField = *pa;
if (arrayField.get() && arrayField->getLength() != valueLength)
return false;
}
return true;
}
NTMultiChannelBuilderPtr NTMultiChannel::createBuilder()
{
return NTMultiChannelBuilderPtr(new detail::NTMultiChannelBuilder());
}
NTMultiChannel::NTMultiChannel(PVStructurePtr const & pvStructure)
: pvNTMultiChannel(pvStructure),
pvTimeStamp(pvStructure->getSubField<PVStructure>("timeStamp")),
pvAlarm(pvStructure->getSubField<PVStructure>("alarm")),
pvValue(pvStructure->getSubField<PVUnionArray>("value")),
pvChannelName(pvStructure->getSubField<PVStringArray>("channelName")),
pvIsConnected(pvStructure->getSubField<PVBooleanArray>("isConnected")),
pvSeverity(pvStructure->getSubField<PVIntArray>("severity")),
pvStatus(pvStructure->getSubField<PVIntArray>("status")),
pvMessage(pvStructure->getSubField<PVStringArray>("message")),
pvSecondsPastEpoch(pvStructure->getSubField<PVLongArray>("secondsPastEpoch")),
pvNanoseconds(pvStructure->getSubField<PVIntArray>("nanoseconds")),
pvUserTag(pvStructure->getSubField<PVIntArray>("userTag")),
pvDescriptor(pvStructure->getSubField<PVString>("descriptor"))
{
}
bool NTMultiChannel::attachTimeStamp(PVTimeStamp &pv) const
{
if (pvTimeStamp)
return pv.attach(pvTimeStamp);
else
return false;
}
bool NTMultiChannel::attachAlarm(PVAlarm &pv) const
{
if (pvAlarm)
return pv.attach(pvAlarm);
else
return false;
}
}}