/* ntscalarMultiChannel.cpp */ /* * Copyright information and license terms for this software can be * found in the file LICENSE that is included with the distribution */ #include #include "validator.h" #define epicsExportSharedSymbols #include #include 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 { NTScalarMultiChannelBuilder::shared_pointer NTScalarMultiChannelBuilder::value(ScalarType scalarType) { valueType = scalarType; return shared_from_this(); } NTScalarMultiChannelBuilder::shared_pointer NTScalarMultiChannelBuilder::addDescriptor() { descriptor = true; return shared_from_this(); } NTScalarMultiChannelBuilder::shared_pointer NTScalarMultiChannelBuilder::addAlarm() { alarm = true; return shared_from_this(); } NTScalarMultiChannelBuilder::shared_pointer NTScalarMultiChannelBuilder::addTimeStamp() { timeStamp = true; return shared_from_this(); } NTScalarMultiChannelBuilder::shared_pointer NTScalarMultiChannelBuilder::addSeverity() { severity = true; return shared_from_this(); } NTScalarMultiChannelBuilder::shared_pointer NTScalarMultiChannelBuilder::addStatus() { status = true; return shared_from_this(); } NTScalarMultiChannelBuilder::shared_pointer NTScalarMultiChannelBuilder::addMessage() { message = true; return shared_from_this(); } NTScalarMultiChannelBuilder::shared_pointer NTScalarMultiChannelBuilder::addSecondsPastEpoch() { secondsPastEpoch = true; return shared_from_this(); } NTScalarMultiChannelBuilder::shared_pointer NTScalarMultiChannelBuilder::addNanoseconds() { nanoseconds = true; return shared_from_this(); } NTScalarMultiChannelBuilder::shared_pointer NTScalarMultiChannelBuilder::addUserTag() { userTag = true; return shared_from_this(); } NTScalarMultiChannelBuilder::shared_pointer NTScalarMultiChannelBuilder::addIsConnected() { isConnected = true; return shared_from_this(); } StructureConstPtr NTScalarMultiChannelBuilder::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"; fields[ind++] = fieldCreate->createScalarArray(valueType); 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(NTScalarMultiChannel::URI,names,fields); reset(); return st; } PVStructurePtr NTScalarMultiChannelBuilder::createPVStructure() { return pvDataCreate->createPVStructure(createStructure()); } NTScalarMultiChannelPtr NTScalarMultiChannelBuilder::create() { return NTScalarMultiChannelPtr(new NTScalarMultiChannel(createPVStructure())); } NTScalarMultiChannelBuilder::NTScalarMultiChannelBuilder() : valueType(pvDouble) { reset(); } void NTScalarMultiChannelBuilder::reset() { extraFieldNames.clear(); extraFields.clear(); valueType = pvDouble; descriptor = false; alarm = false; timeStamp = false; severity = false; status = false; message = false; secondsPastEpoch = false; nanoseconds = false; userTag = false; isConnected = false; } NTScalarMultiChannelBuilder::shared_pointer NTScalarMultiChannelBuilder::add(string const & name, FieldConstPtr const & field) { extraFields.push_back(field); extraFieldNames.push_back(name); return shared_from_this(); } } const std::string NTScalarMultiChannel::URI("epics:nt/NTScalarMultiChannel:1.0"); NTScalarMultiChannel::shared_pointer NTScalarMultiChannel::wrap(PVStructurePtr const & pvStructure) { if(!isCompatible(pvStructure)) return shared_pointer(); return wrapUnsafe(pvStructure); } NTScalarMultiChannel::shared_pointer NTScalarMultiChannel::wrapUnsafe(PVStructurePtr const & pvStructure) { return shared_pointer(new NTScalarMultiChannel(pvStructure)); } bool NTScalarMultiChannel::is_a(StructureConstPtr const &structure) { return NTUtils::is_a(structure->getID(), URI); } bool NTScalarMultiChannel::is_a(PVStructurePtr const & pvStructure) { return is_a(pvStructure->getStructure()); } static epicsThreadOnceId cachedResultOnceId = EPICS_THREAD_ONCE_INIT; static epicsThreadPrivateId cachedResultId; bool NTScalarMultiChannel::isCompatible(StructureConstPtr const & structure) { if (!structure) return false; Result& result = Result::fromCache(&cachedResultOnceId, &cachedResultId); if (result.wraps(structure)) return result.valid(); return result.reset(structure) .is() .has("value") .has("channelName") .maybeHas("severity") .maybeHas("status") .maybeHas("message") .maybeHas("secondsPastEpoch") .maybeHas("nanoseconds") .maybeHas("userTag") .maybeHas("descriptor") .maybeHas<&NTField::isAlarm, Structure>("alarm") .maybeHas<&NTField::isTimeStamp, Structure>("timeStamp") .valid(); } bool NTScalarMultiChannel::isCompatible(PVStructurePtr const &pvStructure) { if(!pvStructure.get()) return false; return isCompatible(pvStructure->getStructure()); } bool NTScalarMultiChannel::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; } NTScalarMultiChannelBuilderPtr NTScalarMultiChannel::createBuilder() { return NTScalarMultiChannelBuilderPtr(new detail::NTScalarMultiChannelBuilder()); } NTScalarMultiChannel::NTScalarMultiChannel(PVStructurePtr const & pvStructure) : pvNTScalarMultiChannel(pvStructure), pvTimeStamp(pvStructure->getSubField("timeStamp")), pvAlarm(pvStructure->getSubField("alarm")), pvValue(pvStructure->getSubField("value")), pvChannelName(pvStructure->getSubField("channelName")), pvIsConnected(pvStructure->getSubField("isConnected")), pvSeverity(pvStructure->getSubField("severity")), pvStatus(pvStructure->getSubField("status")), pvMessage(pvStructure->getSubField("message")), pvSecondsPastEpoch(pvStructure->getSubField("secondsPastEpoch")), pvNanoseconds(pvStructure->getSubField("nanoseconds")), pvUserTag(pvStructure->getSubField("userTag")), pvDescriptor(pvStructure->getSubField("descriptor")) { } bool NTScalarMultiChannel::attachTimeStamp(PVTimeStamp &pv) const { if (pvTimeStamp) return pv.attach(pvTimeStamp); else return false; } bool NTScalarMultiChannel::attachAlarm(PVAlarm &pv) const { if (pvAlarm) return pv.attach(pvAlarm); else return false; } }}