diff --git a/pdbApp/configparse.cpp b/pdbApp/configparse.cpp index 27f83b7..91ec19a 100644 --- a/pdbApp/configparse.cpp +++ b/pdbApp/configparse.cpp @@ -59,9 +59,6 @@ struct context { } else if(key=="+trigger") { fld.trigger = value.ref(); - } else if(key=="+predef") { - fld.predef = value.ref(); - } else if(key=="+putorder") { fld.putorder = value.as(); diff --git a/pdbApp/pdb.cpp b/pdbApp/pdb.cpp index 27998d3..c6e393d 100644 --- a/pdbApp/pdb.cpp +++ b/pdbApp/pdb.cpp @@ -44,14 +44,6 @@ struct Splitter { } }; -pvd::StructureConstPtr NTNDArray(pvd::getFieldCreate()->createFieldBuilder() - ->setId("epics:nt/NTNDArray:1.0") - //->add("value", pvd::getFieldCreate()->createVariantUnion()) - ->addNestedStructureArray("dimension") - ->add("size", pvd::pvInt) - ->endNested() - ->createStructure()); - struct GroupMemberInfo { // consumes builder GroupMemberInfo(const std::string& a, const std::string& b, p2p::auto_ptr& builder) @@ -80,9 +72,6 @@ struct GroupInfo { enum tribool {Unset,True,False} atomic; bool hastriggers; - - typedef std::map predefs_t; - predefs_t predefs; }; // Iterates all PDB records and gathers info() to construct PDB groups @@ -199,18 +188,6 @@ struct PDBProcessor const std::string& fldname = fit->first; const GroupConfig::Field& fld = fit->second; - if(!fld.predef.empty()) { - if(fld.predef=="epics:nt/NTNDArray:1.0") { - curgroup->predefs[fldname] = NTNDArray; - } else { - fprintf(stderr, "%s.%s : unknown pre-defined type \"%s\"\n", - grpname.c_str(), fldname.c_str(), fld.predef.c_str()); - } - // allow pre-defined fields to skip a channel mapping - if(fld.channel.empty()) - continue; - } - if(fld.channel.empty()) throw std::runtime_error("Missing required +channel"); @@ -322,31 +299,6 @@ PDBProvider::PDBProvider(const epics::pvAccess::Configuration::shared_pointer &) pvd::FieldBuilderPtr builder(fcreate->createFieldBuilder()); builder->add("record", _options); - for(GroupInfo::predefs_t::const_iterator it=info.predefs.begin(), end=info.predefs.end(); - it!=end; ++it) - { - if(PDBProviderDebug>2) - fprintf(stderr, "%s.%s add pre-defined %s\n", - info.name.c_str(), it->first.c_str(), it->second->getID().c_str()); - - std::vector parts; - { - Splitter S(it->first.c_str(), '.'); - std::string part; - while(S.snip(part)) - parts.push_back(part); - } - assert(!parts.empty()); - - for(size_t j=0; jaddNestedStructure(parts[j]); - - builder->add(parts.back(), it->second); - - for(size_t j=0; jendNested(); - } - for(size_t i=0; i parts; - { - Splitter S(mem.pvfldname.c_str(), '.'); - std::string part; - while(S.snip(part)) - parts.push_back(part); + if(info.builder->buildsType) { + + std::vector parts; + { + Splitter S(mem.pvfldname.c_str(), '.'); + std::string part; + while(S.snip(part)) + parts.push_back(part); + } + assert(!parts.empty()); + + for(size_t j=0; jaddNestedStructure(parts[j]); + + builder->add(parts.back(), info.builder->dtype(chan)); + + for(size_t j=0; jendNested(); } - assert(!parts.empty()); - - for(size_t j=0; jaddNestedStructure(parts[j]); - - builder->add(parts.back(), info.builder->dtype(chan)); - - for(size_t j=0; jendNested(); info.attachment = mem.pvfldname; info.chan.swap(chan); @@ -382,6 +337,7 @@ PDBProvider::PDBProvider(const epics::pvAccess::Configuration::shared_pointer &) info.triggers.push_back(*idx); } + assert(info.chan); records[i] = dbChannelRecord(info.chan); } pv->members.swap(members); diff --git a/pdbApp/pdbgroup.h b/pdbApp/pdbgroup.h index edef3bc..55671c5 100644 --- a/pdbApp/pdbgroup.h +++ b/pdbApp/pdbgroup.h @@ -22,7 +22,7 @@ struct epicsShareClass GroupConfig { struct epicsShareClass Field { - std::string type, channel, trigger, predef; + std::string type, channel, trigger; int putorder; Field() :putorder(std::numeric_limits::min()) {} @@ -31,7 +31,6 @@ struct epicsShareClass GroupConfig std::swap(type, o.type); std::swap(channel, o.channel); std::swap(trigger, o.trigger); - std::swap(predef, o.predef); std::swap(putorder, o.putorder); } }; diff --git a/pdbApp/pvif.cpp b/pdbApp/pvif.cpp index 7c4a607..784230b 100644 --- a/pdbApp/pvif.cpp +++ b/pdbApp/pvif.cpp @@ -573,7 +573,10 @@ struct PVIFPlain : public PVIF :PVIF(channel) ,field(std::tr1::static_pointer_cast(fld)) ,channel(channel) - {} + { + if(!field) + throw std::logic_error("PVIFPlain attached type mis-match"); + } virtual ~PVIFPlain() {} @@ -601,7 +604,7 @@ struct PVIFPlain : public PVIF struct PlainBuilder : public PVIFBuilder { - PlainBuilder() {} + PlainBuilder() :PVIFBuilder(true) {} virtual ~PlainBuilder() {} // fetch the structure description @@ -632,9 +635,98 @@ struct PlainBuilder : public PVIFBuilder return new PVIFPlain(channel, root); } }; + +struct ExistingBuilder : public PVIFBuilder +{ + ExistingBuilder() :PVIFBuilder(false) {} + virtual ~ExistingBuilder() {} + + // fetch the structure description + virtual epics::pvData::FieldConstPtr dtype(dbChannel *channel) OVERRIDE FINAL { + throw std::logic_error("Don't call me"); + } + + // 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::PVFieldPtr& root) OVERRIDE FINAL + { + const long maxelem = dbChannelFinalElements(channel); + + if(maxelem==1) + return new PVIFPlain(channel, root); + else + return new PVIFPlain(channel, root); + } +}; + +pvd::StructureConstPtr NTNDArray(pvd::getFieldCreate()->createFieldBuilder() + ->setId("epics:nt/NTNDArray:1.0") + ->add("value", pvd::getFieldCreate()->createVariantUnion()) + ->addNestedStructureArray("dimension") + ->add("size", pvd::pvInt) + ->endNested() + ->createStructure()); + + +struct NTNDArrayBuilder : public PVIFBuilder +{ + NTNDArrayBuilder() :PVIFBuilder(true) {} + virtual ~NTNDArrayBuilder() {} + + // fetch the structure description + virtual epics::pvData::FieldConstPtr dtype(dbChannel *channel) OVERRIDE FINAL { + (void)channel; //ignored + return NTNDArray; + } + + // 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::PVFieldPtr& root) OVERRIDE FINAL + { + pvd::PVDataCreatePtr create(pvd::getPVDataCreate()); + const short dbr = dbChannelFinalFieldType(channel); + const pvd::ScalarType pvt = DBR2PVD(dbr); + + pvd::PVStructure *base = dynamic_cast(root.get()); + if(!base) + throw std::logic_error("Mis-matched attachment point"); + + // auto-magically ensure that dimension array has at least 2 elements + // TODO: bit of a hack, should be able to do this as needed from builder for size field(s) + { + pvd::PVStructureArrayPtr dims(base->getSubFieldT("dimension")); + pvd::PVStructureArray::const_svector cur(dims->view()); + if(cur.size()<2 || !cur[0] || !cur[1]) { + pvd::PVStructureArray::svector D(dims->reuse()); + pvd::StructureConstPtr dtype(dims->getStructureArray()->getStructure()); + if(D.size()<2) D.resize(2); + if(!D[0]) + D[0] = create->createPVStructure(dtype); + if(!D[1]) + D[1] = create->createPVStructure(dtype); + dims->replace(pvd::freeze(D)); + } + } + + pvd::PVUnionPtr value(base->getSubFieldT("value")); + + pvd::PVFieldPtr arr(value->get()); + if(!arr) { + arr = create->createPVScalarArray(pvt); + value->set(arr); + } + + return new PVIFPlain(channel, arr); + } + +}; + }//namespace -PVIFBuilder::PVIFBuilder() +PVIFBuilder::PVIFBuilder(bool buildsType) + :buildsType(buildsType) {} PVIFBuilder::~PVIFBuilder() {} @@ -646,6 +738,10 @@ PVIFBuilder* PVIFBuilder::create(const std::string& type) return new ScalarBuilder; else if(type=="plain") return new PlainBuilder; + else if(type=="existing") + return new ExistingBuilder; + else if(type=="NTNDArray" || type=="NTNDArray:1.0") + return new NTNDArrayBuilder; else throw std::runtime_error(std::string("Unknown +type=")+type); } diff --git a/pdbApp/pvif.h b/pdbApp/pvif.h index ef408c9..480f419 100644 --- a/pdbApp/pvif.h +++ b/pdbApp/pvif.h @@ -277,6 +277,8 @@ private: struct epicsShareClass PVIFBuilder { + const bool buildsType; + virtual ~PVIFBuilder(); // fetch the structure description @@ -289,7 +291,7 @@ struct epicsShareClass PVIFBuilder { static PVIFBuilder* create(const std::string& name); protected: - PVIFBuilder(); + PVIFBuilder(bool buildsType); private: PVIFBuilder(const PVIFBuilder&); PVIFBuilder& operator=(const PVIFBuilder&); @@ -297,7 +299,7 @@ private: struct epicsShareClass ScalarBuilder : public PVIFBuilder { - ScalarBuilder() {} + ScalarBuilder() :PVIFBuilder(true) {} virtual ~ScalarBuilder() {}