diff --git a/pdbApp/configparse.cpp b/pdbApp/configparse.cpp index e786b5d..27f83b7 100644 --- a/pdbApp/configparse.cpp +++ b/pdbApp/configparse.cpp @@ -50,8 +50,6 @@ struct context { if(key=="+type") { fld.type = value.ref(); - if(fld.type.empty()) - throw std::runtime_error("+type can't be empty string"); } else if(key=="+channel") { fld.channel = value.ref(); @@ -60,8 +58,9 @@ struct context { } else if(key=="+trigger") { fld.trigger = value.ref(); - if(fld.trigger.empty()) - throw std::runtime_error("+trigger can't be empty string"); + + } 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 5dfb8c4..27998d3 100644 --- a/pdbApp/pdb.cpp +++ b/pdbApp/pdb.cpp @@ -44,12 +44,21 @@ 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) :pvname(a), pvfldname(b), builder(PTRMOVE(builder)) {} - std::string pvname, pvfldname; + + std::string pvname, // aka. name passed to dbChannelOpen() + pvfldname; // PVStructure sub-field std::set triggers; // indices in GroupInfo::members which are post()d on events from pvfldname size_t index; // index in GroupInfo::members p2p::auto_ptr builder; @@ -58,15 +67,22 @@ struct GroupMemberInfo { struct GroupInfo { GroupInfo(const std::string& name) : name(name),atomic(Unset),hastriggers(false) {} std::string name; + typedef std::vector members_t; members_t members; + typedef std::map members_map_t; members_map_t members_map; + typedef std::set triggers_set_t; typedef std::map triggers_t; triggers_t triggers; + 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 @@ -183,6 +199,18 @@ 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"); @@ -294,6 +322,31 @@ 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::min()) {} @@ -31,6 +31,7 @@ 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); } };