From e084a9e943737a9b13c9b3d276771dfd635d9e84 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Thu, 28 Sep 2017 14:56:14 -0500 Subject: [PATCH] pdb: time/alarm meta mapping --- pdbApp/pdb.cpp | 4 +- pdbApp/pvif.cpp | 126 ++++++++++++++++++++++++++++++++++++++++++++---- pdbApp/pvif.h | 8 +-- 3 files changed, 123 insertions(+), 15 deletions(-) diff --git a/pdbApp/pdb.cpp b/pdbApp/pdb.cpp index 9bdbf4d..476fdae 100644 --- a/pdbApp/pdb.cpp +++ b/pdbApp/pdb.cpp @@ -381,7 +381,7 @@ PDBProvider::PDBProvider(const epics::pvAccess::Configuration::shared_pointer &) chan.swap(temp); } - builder->add(parts.back().name, mem.builder->dtype(chan)); + builder = mem.builder->dtype(builder, parts.back().name, chan); for(size_t j=0; jendNested(); @@ -610,7 +610,6 @@ PDBProvider::createChannel(std::string const & channelName, } FieldName::FieldName(const std::string& pv) - :has_sarr(false) { Splitter S(pv.c_str(), '.'); std::string part; @@ -631,7 +630,6 @@ FieldName::FieldName(const std::string& pv) throw std::runtime_error("Invalid field array sub-script in : "+pv); parts.push_back(Component(part.substr(0, open), index)); - has_sarr = true; } else { parts.push_back(Component(part)); diff --git a/pdbApp/pvif.cpp b/pdbApp/pvif.cpp index c9509ff..c05d649 100644 --- a/pdbApp/pvif.cpp +++ b/pdbApp/pvif.cpp @@ -66,17 +66,23 @@ PVIF::PVIF(dbChannel *ch) namespace { -struct pvCommon { +struct pvTimeAlarm { dbChannel *chan; pvd::uint32 nsecMask; - pvd::BitSet maskALWAYS, maskVALUE, maskALARM, maskPROPERTY, - maskVALUEPut; + pvd::BitSet maskALWAYS, maskALARM; pvd::PVLongPtr sec; pvd::PVIntPtr status, severity, nsec, userTag; + pvTimeAlarm() :chan(NULL), nsecMask(0) {} +}; + +struct pvCommon : public pvTimeAlarm { + + pvd::BitSet maskVALUE, maskPROPERTY, maskVALUEPut; + pvd::PVDoublePtr displayLow, displayHigh, controlLow, controlHigh; pvd::PVStringPtr egu; @@ -85,8 +91,6 @@ struct pvCommon { pvd::PVScalarPtr prec; pvd::PVStringArrayPtr enumopts; - - pvCommon() :chan(NULL), nsecMask(0) {} }; struct pvScalar : public pvCommon { @@ -167,8 +171,7 @@ struct metaSTRING { enum {mask = DBR_STATUS | DBR_TIME}; }; -// lookup fields and populate pvCommon. Non-existant fields will be NULL. -void attachMeta(pvCommon& pvm, const pvd::PVStructurePtr& pv) +void attachTime(pvTimeAlarm& pvm, const pvd::PVStructurePtr& pv) { #define FMAP(MNAME, PVT, FNAME, DBE) pvm.MNAME = pv->getSubField(FNAME); \ if(pvm.MNAME) pvm.mask ## DBE.set(pvm.MNAME->getFieldOffset()) @@ -176,6 +179,16 @@ void attachMeta(pvCommon& pvm, const pvd::PVStructurePtr& pv) FMAP(severity, PVInt, "alarm.severity", ALARM); FMAP(sec, PVLong, "timeStamp.secondsPastEpoch", ALWAYS); FMAP(nsec, PVInt, "timeStamp.nanoseconds", ALWAYS); +#undef FMAP + assert(pvm.status && pvm.severity && pvm.sec && pvm.nsec); +} + +// lookup fields and populate pvCommon. Non-existant fields will be NULL. +void attachMeta(pvCommon& pvm, const pvd::PVStructurePtr& pv) +{ + attachTime(pvm, pv); +#define FMAP(MNAME, PVT, FNAME, DBE) pvm.MNAME = pv->getSubField(FNAME); \ + if(pvm.MNAME) pvm.mask ## DBE.set(pvm.MNAME->getFieldOffset()) FMAP(displayHigh, PVDouble, "display.limitHigh", PROPERTY); FMAP(displayLow, PVDouble, "display.limitLow", PROPERTY); FMAP(controlHigh, PVDouble, "control.limitHigh", PROPERTY); @@ -188,7 +201,6 @@ void attachMeta(pvCommon& pvm, const pvd::PVStructurePtr& pv) FMAP(alarmLow, PVScalar, "alarm.lowAlarmLimit", PROPERTY); FMAP(enumopts, PVStringArray, "value.choices", PROPERTY); #undef FMAP - assert(pvm.status && pvm.severity && pvm.sec && pvm.nsec); } template @@ -206,7 +218,7 @@ void attachAll(PVM& pvm, const pvd::PVStructurePtr& pv) attachMeta(pvm, pv); } -void putTime(const pvCommon& pv, unsigned dbe, db_field_log *pfl) +void putTime(const pvTimeAlarm& pv, unsigned dbe, db_field_log *pfl) { metaTIME meta; long options = (int)metaTIME::mask, nReq = 0; @@ -719,9 +731,103 @@ struct AnyScalarBuilder : public PVIFBuilder }; +struct PVIFMeta : public PVIF +{ + pvTimeAlarm meta; + + PVIFMeta(dbChannel *channel, const epics::pvData::PVFieldPtr& fld, epics::pvData::PVField* enclosing=0) + :PVIF(channel) + { + pvd::PVStructurePtr field(std::dynamic_pointer_cast(fld)); + if(!field) + throw std::logic_error("PVIFMeta attached type mis-match"); + attachTime(meta, field); + if(enclosing) { + meta.maskALWAYS.clear(); + meta.maskALWAYS.set(enclosing->getFieldOffset()); + meta.maskALARM.clear(); + meta.maskALARM.set(enclosing->getFieldOffset()); + } + } + + virtual ~PVIFMeta() {} + + virtual void put(epics::pvData::BitSet& mask, unsigned dbe, db_field_log *pfl) + { + mask |= meta.maskALWAYS; + if(dbe&DBE_ALARM) + mask |= meta.maskALARM; + + putTime(meta, dbe, pfl); + } + + virtual void get(const epics::pvData::BitSet& mask) + { + // can't put time/alarm + } + + virtual unsigned dbe(const epics::pvData::BitSet& mask) + { + if(mask.logical_and(meta.maskALARM)) + return DBE_ALARM; + return 0; + } +}; + +struct MetaBuilder : public PVIFBuilder +{ + virtual ~MetaBuilder() {} + + // fetch the structure description + virtual epics::pvData::FieldConstPtr dtype(dbChannel *channel) OVERRIDE FINAL { + throw std::logic_error("Don't call me"); + } + + virtual epics::pvData::FieldBuilderPtr dtype(epics::pvData::FieldBuilderPtr& builder, + const std::string& fld, + dbChannel *channel) + { + pvd::StandardFieldPtr std(pvd::getStandardField()); + return builder->add("alarm", std->alarm()) + ->add("timeStamp", std->timeStamp()); + } + + // Attach to a structure instance. + // must be of the type returned by dtype(). + // need not be the root structure + virtual PVIF* attach(dbChannel *channel, + const epics::pvData::PVStructurePtr& root, + const FieldName& fldname) OVERRIDE FINAL + { + if(!channel) + throw std::runtime_error("+type:\"any\" requires +channel:"); + + pvd::PVField *enclosing = 0; + pvd::PVFieldPtr fld(fldname.lookup(root, &enclosing)); + + return new PVIFMeta(channel, fld, enclosing); + } + +}; + }//namespace +epics::pvData::FieldBuilderPtr +PVIFBuilder::dtype(epics::pvData::FieldBuilderPtr& builder, + const std::string &fld, + dbChannel *channel) +{ + if(fld.empty()) + throw std::runtime_error("Can't attach this +type to root"); + + epics::pvData::FieldConstPtr ftype(this->dtype(channel)); + if(ftype) + builder = builder->add(fld, ftype); + + return builder; +} + PVIFBuilder* PVIFBuilder::create(const std::string& type) { if(type.empty() || type=="scalar") @@ -730,6 +836,8 @@ PVIFBuilder* PVIFBuilder::create(const std::string& type) return new PlainBuilder; else if(type=="any") return new AnyScalarBuilder; + else if(type=="meta") + return new MetaBuilder; else throw std::runtime_error(std::string("Unknown +type=")+type); } diff --git a/pdbApp/pvif.h b/pdbApp/pvif.h index 6116738..7386f8b 100644 --- a/pdbApp/pvif.h +++ b/pdbApp/pvif.h @@ -268,14 +268,12 @@ struct epicsShareClass FieldName }; typedef std::vector parts_t; parts_t parts; - bool has_sarr; - FieldName() :has_sarr(false) {} + FieldName() {} explicit FieldName(const std::string&); void swap(FieldName& o) { parts.swap(o.parts); - std::swap(has_sarr, o.has_sarr); } bool empty() const { return parts.empty(); } @@ -321,6 +319,10 @@ struct epicsShareClass PVIFBuilder { // fetch the structure description virtual epics::pvData::FieldConstPtr dtype(dbChannel *channel) =0; + virtual epics::pvData::FieldBuilderPtr dtype(epics::pvData::FieldBuilderPtr& builder, + const std::string& fld, + dbChannel *channel); + // Attach to a structure instance. // must be of the type returned by dtype(). // must be the root structure