redo mappings to handle fieldOffset of structure array
This commit is contained in:
@ -3,7 +3,7 @@
|
||||
record(longout, "$(N):ArraySize0_RBV") {
|
||||
info(Q:group, {
|
||||
"$(N):Array":{
|
||||
"foo.dimension[0].size":{+channel:"VAL", +type:"existing"}
|
||||
"dimension[0].size":{+channel:"VAL", +type:"plain"}
|
||||
}
|
||||
})
|
||||
field(FLNK, "$(N):ArraySize1_RBV")
|
||||
@ -12,7 +12,7 @@ record(longout, "$(N):ArraySize0_RBV") {
|
||||
record(longout, "$(N):ArraySize1_RBV") {
|
||||
info(Q:group, {
|
||||
"$(N):Array":{
|
||||
"foo.dimension[1].size":{+channel:"VAL", +type:"existing"}
|
||||
"dimension[1].size":{+channel:"VAL", +type:"plain"}
|
||||
}
|
||||
})
|
||||
field(FLNK, "$(N):ArrayData_")
|
||||
@ -30,11 +30,11 @@ record(aSub, "$(N):ArrayData_") {
|
||||
}
|
||||
|
||||
record(waveform, "$(N):ArrayData") {
|
||||
field(FTVL, "UCHAR")
|
||||
field(FTVL, "USHORT")
|
||||
field(NELM, "256")
|
||||
info(Q:group, {
|
||||
"$(N):Array":{
|
||||
"foo":{+type:"NTNDArray", +channel:"VAL", +trigger:"*"}
|
||||
"value":{+type:"NTNDArray", +channel:"VAL", +trigger:"*"}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
137
pdbApp/pdb.cpp
137
pdbApp/pdb.cpp
@ -55,7 +55,14 @@ struct GroupMemberInfo {
|
||||
size_t index; // index in GroupInfo::members
|
||||
p2p::auto_ptr<PVIFBuilder> builder;
|
||||
|
||||
bool operator<(const GroupMemberInfo& o) const { return pvfldname<o.pvfldname; }
|
||||
bool operator<(const GroupMemberInfo& o) const {
|
||||
bool LT = pvfldname==".",
|
||||
RT = o.pvfldname==".";
|
||||
if(LT && RT) return false;
|
||||
else if(LT && !RT) return true;
|
||||
else if(!LT && RT) return false;
|
||||
else return pvfldname<o.pvfldname;
|
||||
}
|
||||
};
|
||||
|
||||
struct GroupInfo {
|
||||
@ -327,27 +334,24 @@ PDBProvider::PDBProvider(const epics::pvAccess::Configuration::shared_pointer &)
|
||||
info.builder = PTRMOVE(mem.builder);
|
||||
assert(info.builder.get());
|
||||
|
||||
if(info.builder->buildsType) {
|
||||
|
||||
std::vector<std::string> parts;
|
||||
{
|
||||
Splitter S(mem.pvfldname.c_str(), '.');
|
||||
std::string part;
|
||||
while(S.snip(part))
|
||||
parts.push_back(part);
|
||||
}
|
||||
assert(!parts.empty());
|
||||
// parse down attachment point to build/traverse structure
|
||||
FieldName parts(mem.pvfldname);
|
||||
assert(!parts.empty());
|
||||
|
||||
for(size_t j=0; j<parts.size()-1; j++)
|
||||
builder = builder->addNestedStructure(parts[j]);
|
||||
|
||||
builder->add(parts.back(), info.builder->dtype(chan));
|
||||
|
||||
for(size_t j=0; j<parts.size()-1; j++)
|
||||
builder = builder->endNested();
|
||||
for(size_t j=0; j<parts.size()-1; j++) {
|
||||
if(parts[j].isArray())
|
||||
builder = builder->addNestedStructureArray(parts[j].name);
|
||||
else
|
||||
builder = builder->addNestedStructure(parts[j].name);
|
||||
}
|
||||
|
||||
info.attachment = mem.pvfldname;
|
||||
builder->add(parts.back().name, info.builder->dtype(chan));
|
||||
|
||||
for(size_t j=0; j<parts.size()-1; j++)
|
||||
builder = builder->endNested();
|
||||
|
||||
info.attachment.swap(parts);
|
||||
info.chan.swap(chan);
|
||||
|
||||
info.triggers.reserve(mem.triggers.size());
|
||||
@ -404,7 +408,10 @@ PDBProvider::PDBProvider(const epics::pvAccess::Configuration::shared_pointer &)
|
||||
|
||||
// setup group monitors
|
||||
#ifdef USE_MULTILOCK
|
||||
FOREACH(it, end, persist_pv_map)
|
||||
for(persist_pv_map_t::iterator next = persist_pv_map.begin(),
|
||||
end = persist_pv_map.end(),
|
||||
it = next!=end ? next++ : end;
|
||||
it != end; it = next==end ? end : next++)
|
||||
{
|
||||
const PDBPV::shared_pointer& ppv = it->second;
|
||||
PDBGroupPV *pv = dynamic_cast<PDBGroupPV*>(ppv.get());
|
||||
@ -415,15 +422,15 @@ PDBProvider::PDBProvider(const epics::pvAccess::Configuration::shared_pointer &)
|
||||
// prepare for monitor
|
||||
|
||||
size_t i=0;
|
||||
FOREACH(it, end, pv->members)
|
||||
FOREACH(it2, end2, pv->members)
|
||||
{
|
||||
PDBGroupPV::Info& info = *it;
|
||||
PDBGroupPV::Info& info = *it2;
|
||||
info.evt_VALUE.index = info.evt_PROPERTY.index = i++;
|
||||
info.evt_VALUE.self = info.evt_PROPERTY.self = pv;
|
||||
|
||||
info.pvif.reset(info.builder->attach(info.chan,
|
||||
pv->complete->getSubFieldT(info.attachment)));
|
||||
info.pvif.reset(info.builder->attach(info.chan, pv->complete, info.attachment));
|
||||
|
||||
// TODO: don't need evt_PROPERTY for PVIF plain
|
||||
info.evt_PROPERTY.create(event_context, info.chan, &pdb_group_event, DBE_PROPERTY);
|
||||
|
||||
if(!info.triggers.empty()) {
|
||||
@ -431,7 +438,8 @@ PDBProvider::PDBProvider(const epics::pvAccess::Configuration::shared_pointer &)
|
||||
}
|
||||
}
|
||||
}catch(std::exception& e){
|
||||
fprintf(stderr, "%s: Error initializing dbEvent\n", pv->name.c_str());
|
||||
fprintf(stderr, "%s: Error during dbEvent setup : %s\n", pv->name.c_str(), e.what());
|
||||
persist_pv_map.erase(it);
|
||||
}
|
||||
}
|
||||
#endif // USE_MULTILOCK
|
||||
@ -547,3 +555,84 @@ PDBProvider::createChannel(std::string const & channelName,
|
||||
requester->channelCreated(status, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
FieldName::FieldName(const std::string& pv)
|
||||
:has_sarr(false)
|
||||
{
|
||||
Splitter S(pv.c_str(), '.');
|
||||
std::string part;
|
||||
while(S.snip(part)) {
|
||||
if(part.empty())
|
||||
throw std::runtime_error("Empty field component in: "+pv);
|
||||
|
||||
if(part.back()==']') {
|
||||
const size_t open = part.find_last_of('['),
|
||||
N = part.size();
|
||||
bool ok = open!=part.npos;
|
||||
epicsUInt32 index = 0;
|
||||
for(size_t i=open+1; ok && i<(N-1); i++) {
|
||||
ok &= part[i]>='0' && part[i]<='9';
|
||||
index = 10*index + part[i] - '0';
|
||||
}
|
||||
if(!ok)
|
||||
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));
|
||||
}
|
||||
}
|
||||
if(parts.empty())
|
||||
throw std::runtime_error("Empty field name");
|
||||
if(parts.back().isArray())
|
||||
throw std::runtime_error("leaf field may not have sub-script : "+pv);
|
||||
}
|
||||
|
||||
epics::pvData::PVFieldPtr
|
||||
FieldName::lookup(const epics::pvData::PVStructurePtr& S, epics::pvData::PVField **ppsar) const
|
||||
{
|
||||
if(ppsar)
|
||||
*ppsar = 0;
|
||||
|
||||
pvd::PVFieldPtr ret = S;
|
||||
for(size_t i=0, N=parts.size(); i<N; i++) {
|
||||
pvd::PVStructure* parent = dynamic_cast<pvd::PVStructure*>(ret.get());
|
||||
if(!parent)
|
||||
throw std::runtime_error("mid-field is not structure");
|
||||
|
||||
ret = parent->getSubFieldT(parts[i].name);
|
||||
|
||||
if(parts[i].isArray()) {
|
||||
pvd::PVStructureArray* sarr = dynamic_cast<pvd::PVStructureArray*>(ret.get());
|
||||
if(!sarr)
|
||||
throw std::runtime_error("indexed field is not structure array");
|
||||
|
||||
if(ppsar && !*ppsar)
|
||||
*ppsar = sarr;
|
||||
|
||||
pvd::PVStructureArray::const_svector V(sarr->view());
|
||||
|
||||
if(V.size()<=parts[i].index || !V[parts[i].index]) {
|
||||
// automatic re-size and ensure non-null
|
||||
V.clear(); // drop our extra ref so that reuse() might avoid a copy
|
||||
pvd::PVStructureArray::svector E(sarr->reuse());
|
||||
|
||||
if(E.size()<=parts[i].index)
|
||||
E.resize(parts[i].index+1);
|
||||
|
||||
if(!E[parts[i].index])
|
||||
E[parts[i].index] = pvd::getPVDataCreate()->createPVStructure(sarr->getStructureArray()->getStructure());
|
||||
|
||||
ret = E[parts[i].index];
|
||||
|
||||
sarr->replace(pvd::freeze(E));
|
||||
|
||||
} else {
|
||||
ret = V[parts[i].index];
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
@ -173,9 +173,7 @@ PDBGroupPut::PDBGroupPut(const PDBGroupChannel::shared_pointer& channel,
|
||||
{
|
||||
PDBGroupPV::Info& info = channel->pv->members[i];
|
||||
|
||||
pvif[i].reset(info.builder->attach(info.chan,
|
||||
pvf->getSubFieldT(info.attachment)
|
||||
));
|
||||
pvif[i].reset(info.builder->attach(info.chan, pvf, info.attachment));
|
||||
}
|
||||
}
|
||||
|
||||
@ -195,9 +193,7 @@ void PDBGroupPut::put(pvd::PVStructure::shared_pointer const & value,
|
||||
{
|
||||
PDBGroupPV::Info& info = channel->pv->members[i];
|
||||
|
||||
putpvif[i].reset(info.builder->attach(info.chan,
|
||||
value->getSubFieldT(info.attachment)
|
||||
));
|
||||
putpvif[i].reset(info.builder->attach(info.chan, value, info.attachment));
|
||||
}
|
||||
|
||||
if(atomic) {
|
||||
@ -293,6 +289,7 @@ void PDBGroupMonitor::onStart()
|
||||
} else {
|
||||
info.had_initial_VALUE = true;
|
||||
}
|
||||
assert(info.evt_PROPERTY.subscript);
|
||||
db_event_enable(info.evt_PROPERTY.subscript);
|
||||
db_post_single_event(info.evt_PROPERTY.subscript);
|
||||
ievts++;
|
||||
|
@ -83,7 +83,7 @@ struct epicsShareClass PDBGroupPV : public PDBPV
|
||||
struct Info {
|
||||
DBCH chan;
|
||||
p2p::auto_ptr<PVIFBuilder> builder;
|
||||
std::string attachment;
|
||||
FieldName attachment;
|
||||
std::vector<size_t> triggers;
|
||||
DBManyLock locker; // lock only those channels being triggered
|
||||
p2p::auto_ptr<PVIF> pvif;
|
||||
|
@ -79,7 +79,7 @@ PDBSinglePV::PDBSinglePV(DBCH& chan,
|
||||
fielddesc = std::tr1::static_pointer_cast<const pvd::Structure>(builder->dtype(this->chan));
|
||||
|
||||
complete = pvd::getPVDataCreate()->createPVStructure(fielddesc);
|
||||
pvif.reset(builder->attach(this->chan, complete));
|
||||
pvif.reset(builder->attach(this->chan, complete, FieldName()));
|
||||
|
||||
epics::atomic::increment(num_instances);
|
||||
}
|
||||
@ -207,7 +207,7 @@ PDBSinglePut::PDBSinglePut(const PDBSingleChannel::shared_pointer &channel,
|
||||
,requester(requester)
|
||||
,changed(new pvd::BitSet(channel->fielddesc->getNumberFields()))
|
||||
,pvf(pvd::getPVDataCreate()->createPVStructure(channel->fielddesc))
|
||||
,pvif(channel->pv->builder->attach(channel->pv->chan, pvf))
|
||||
,pvif(channel->pv->builder->attach(channel->pv->chan, pvf, FieldName()))
|
||||
,notifyBusy(0)
|
||||
,doProc(true)
|
||||
,doProcForce(false)
|
||||
@ -281,7 +281,7 @@ void PDBSinglePut::put(pvd::PVStructure::shared_pointer const & value,
|
||||
// TODO: dbNotify doesn't allow us for force processing
|
||||
|
||||
// assume value may be a different struct each time
|
||||
p2p::auto_ptr<PVIF> putpvif(channel->pv->builder->attach(channel->pv->chan, value));
|
||||
p2p::auto_ptr<PVIF> putpvif(channel->pv->builder->attach(channel->pv->chan, value, FieldName()));
|
||||
unsigned mask = putpvif->dbe(*changed);
|
||||
|
||||
if(mask&~DBE_VALUE) {
|
||||
@ -303,7 +303,7 @@ void PDBSinglePut::put(pvd::PVStructure::shared_pointer const & value,
|
||||
return; // skip notification
|
||||
} else {
|
||||
// assume value may be a different struct each time
|
||||
p2p::auto_ptr<PVIF> putpvif(channel->pv->builder->attach(channel->pv->chan, value));
|
||||
p2p::auto_ptr<PVIF> putpvif(channel->pv->builder->attach(channel->pv->chan, value, FieldName()));
|
||||
try{
|
||||
DBScanLocker L(chan);
|
||||
putpvif->get(*changed);
|
||||
|
137
pdbApp/pvif.cpp
137
pdbApp/pvif.cpp
@ -394,7 +394,7 @@ struct PVIFScalarNumeric : public PVIF
|
||||
PVM pvmeta;
|
||||
const epics::pvData::PVStructurePtr pvalue;
|
||||
|
||||
PVIFScalarNumeric(dbChannel *ch, const epics::pvData::PVFieldPtr& p)
|
||||
PVIFScalarNumeric(dbChannel *ch, const epics::pvData::PVFieldPtr& p, pvd::PVField *enclosing)
|
||||
:PVIF(ch)
|
||||
,pvalue(std::tr1::dynamic_pointer_cast<pvd::PVStructure>(p))
|
||||
{
|
||||
@ -404,6 +404,20 @@ struct PVIFScalarNumeric : public PVIF
|
||||
|
||||
pvmeta.chan = ch;
|
||||
attachAll(pvmeta, pvalue);
|
||||
if(enclosing) {
|
||||
size_t bit = enclosing->getFieldOffset();
|
||||
// we are inside a structure array or similar with only one bit for all ours fields
|
||||
pvmeta.maskALWAYS.clear();
|
||||
pvmeta.maskALWAYS.set(bit);
|
||||
pvmeta.maskVALUE.clear();
|
||||
pvmeta.maskVALUE.set(bit);
|
||||
pvmeta.maskALARM.clear();
|
||||
pvmeta.maskALARM.set(bit);
|
||||
pvmeta.maskPROPERTY.clear();
|
||||
pvmeta.maskPROPERTY.set(bit);
|
||||
pvmeta.maskVALUEPut.clear();
|
||||
pvmeta.maskVALUEPut.set(bit);
|
||||
}
|
||||
const char *UT = info.info("pdbUserTag");
|
||||
if(UT && strncmp(UT, "nslsb", 5)==0) {
|
||||
try{
|
||||
@ -521,8 +535,11 @@ ScalarBuilder::dtype(dbChannel *channel)
|
||||
}
|
||||
|
||||
PVIF*
|
||||
ScalarBuilder::attach(dbChannel *channel, const epics::pvData::PVFieldPtr& root)
|
||||
ScalarBuilder::attach(dbChannel *channel, const epics::pvData::PVStructurePtr& root, const FieldName& fldname)
|
||||
{
|
||||
pvd::PVField *enclosing = 0;
|
||||
pvd::PVFieldPtr fld(fldname.lookup(root, &enclosing));
|
||||
|
||||
const short dbr = dbChannelFinalFieldType(channel);
|
||||
const long maxelem = dbChannelFinalElements(channel);
|
||||
//const pvd::ScalarType pvt = DBR2PVD(dbr);
|
||||
@ -535,14 +552,14 @@ ScalarBuilder::attach(dbChannel *channel, const epics::pvData::PVFieldPtr& root)
|
||||
case DBR_USHORT:
|
||||
case DBR_LONG:
|
||||
case DBR_ULONG:
|
||||
return new PVIFScalarNumeric<pvScalar, metaLONG>(channel, root);
|
||||
return new PVIFScalarNumeric<pvScalar, metaLONG>(channel, fld, enclosing);
|
||||
case DBR_FLOAT:
|
||||
case DBR_DOUBLE:
|
||||
return new PVIFScalarNumeric<pvScalar, metaDOUBLE>(channel, root);
|
||||
return new PVIFScalarNumeric<pvScalar, metaDOUBLE>(channel, fld, enclosing);
|
||||
case DBR_ENUM:
|
||||
return new PVIFScalarNumeric<pvScalar, metaENUM>(channel, root);
|
||||
return new PVIFScalarNumeric<pvScalar, metaENUM>(channel, fld, enclosing);
|
||||
case DBR_STRING:
|
||||
return new PVIFScalarNumeric<pvScalar, metaSTRING>(channel, root);
|
||||
return new PVIFScalarNumeric<pvScalar, metaSTRING>(channel, fld, enclosing);
|
||||
}
|
||||
} else {
|
||||
switch(dbr) {
|
||||
@ -552,10 +569,10 @@ ScalarBuilder::attach(dbChannel *channel, const epics::pvData::PVFieldPtr& root)
|
||||
case DBR_USHORT:
|
||||
case DBR_LONG:
|
||||
case DBR_ULONG:
|
||||
return new PVIFScalarNumeric<pvArray, metaLONG>(channel, root);
|
||||
return new PVIFScalarNumeric<pvArray, metaLONG>(channel, fld, enclosing);
|
||||
case DBR_FLOAT:
|
||||
case DBR_DOUBLE:
|
||||
return new PVIFScalarNumeric<pvArray, metaDOUBLE>(channel, root);
|
||||
return new PVIFScalarNumeric<pvArray, metaDOUBLE>(channel, fld, enclosing);
|
||||
}
|
||||
}
|
||||
|
||||
@ -566,16 +583,21 @@ namespace {
|
||||
template<class PVD>
|
||||
struct PVIFPlain : public PVIF
|
||||
{
|
||||
typename PVD::shared_pointer field;
|
||||
dbChannel *channel;
|
||||
const typename PVD::shared_pointer field;
|
||||
size_t fieldOffset;
|
||||
dbChannel * const channel;
|
||||
|
||||
PVIFPlain(dbChannel *channel, const epics::pvData::PVFieldPtr& fld)
|
||||
PVIFPlain(dbChannel *channel, const epics::pvData::PVFieldPtr& fld, epics::pvData::PVField* enclosing=0)
|
||||
:PVIF(channel)
|
||||
,field(std::tr1::static_pointer_cast<PVD>(fld))
|
||||
,channel(channel)
|
||||
{
|
||||
if(!field)
|
||||
throw std::logic_error("PVIFPlain attached type mis-match");
|
||||
if(enclosing)
|
||||
fieldOffset = enclosing->getFieldOffset();
|
||||
else
|
||||
fieldOffset = field->getFieldOffset();
|
||||
}
|
||||
|
||||
virtual ~PVIFPlain() {}
|
||||
@ -584,19 +606,19 @@ struct PVIFPlain : public PVIF
|
||||
{
|
||||
if(dbe&DBE_VALUE) {
|
||||
putValue(channel, field.get(), pfl);
|
||||
mask.set(field->getFieldOffset());
|
||||
mask.set(fieldOffset);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void get(const epics::pvData::BitSet& mask)
|
||||
{
|
||||
if(mask.get(field->getFieldOffset()))
|
||||
if(mask.get(fieldOffset))
|
||||
getValue(channel, field.get());
|
||||
}
|
||||
|
||||
virtual unsigned dbe(const epics::pvData::BitSet& mask)
|
||||
{
|
||||
if(mask.get(field->getFieldOffset()))
|
||||
if(mask.get(fieldOffset))
|
||||
return DBE_VALUE;
|
||||
return 0;
|
||||
}
|
||||
@ -604,7 +626,6 @@ struct PVIFPlain : public PVIF
|
||||
|
||||
struct PlainBuilder : public PVIFBuilder
|
||||
{
|
||||
PlainBuilder() :PVIFBuilder(true) {}
|
||||
virtual ~PlainBuilder() {}
|
||||
|
||||
// fetch the structure description
|
||||
@ -625,112 +646,64 @@ struct PlainBuilder : public PVIFBuilder
|
||||
// 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
|
||||
virtual PVIF* attach(dbChannel *channel,
|
||||
const epics::pvData::PVStructurePtr& root,
|
||||
const FieldName& fldname) OVERRIDE FINAL
|
||||
{
|
||||
const long maxelem = dbChannelFinalElements(channel);
|
||||
|
||||
if(maxelem==1)
|
||||
return new PVIFPlain<pvd::PVScalar>(channel, root);
|
||||
else
|
||||
return new PVIFPlain<pvd::PVScalarArray>(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);
|
||||
pvd::PVField *enclosing = 0;
|
||||
pvd::PVFieldPtr fld(fldname.lookup(root, &enclosing));
|
||||
|
||||
if(maxelem==1)
|
||||
return new PVIFPlain<pvd::PVScalar>(channel, root);
|
||||
return new PVIFPlain<pvd::PVScalar>(channel, fld, enclosing);
|
||||
else
|
||||
return new PVIFPlain<pvd::PVScalarArray>(channel, root);
|
||||
return new PVIFPlain<pvd::PVScalarArray>(channel, fld, enclosing);
|
||||
}
|
||||
};
|
||||
|
||||
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;
|
||||
return pvd::getFieldCreate()->createVariantUnion();
|
||||
}
|
||||
|
||||
// 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
|
||||
virtual PVIF* attach(dbChannel *channel,
|
||||
const epics::pvData::PVStructurePtr& root,
|
||||
const FieldName& fldname) OVERRIDE FINAL
|
||||
{
|
||||
pvd::PVDataCreatePtr create(pvd::getPVDataCreate());
|
||||
const short dbr = dbChannelFinalFieldType(channel);
|
||||
const pvd::ScalarType pvt = DBR2PVD(dbr);
|
||||
|
||||
pvd::PVStructure *base = dynamic_cast<pvd::PVStructure*>(root.get());
|
||||
if(!base)
|
||||
pvd::PVField *enclosing = 0;
|
||||
pvd::PVFieldPtr fld(fldname.lookup(root, &enclosing));
|
||||
|
||||
pvd::PVUnion *value = dynamic_cast<pvd::PVUnion*>(fld.get());
|
||||
if(!value)
|
||||
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<pvd::PVStructureArray>("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<pvd::PVUnion>("value"));
|
||||
|
||||
pvd::PVFieldPtr arr(value->get());
|
||||
if(!arr) {
|
||||
arr = create->createPVScalarArray(pvt);
|
||||
value->set(arr);
|
||||
}
|
||||
|
||||
return new PVIFPlain<pvd::PVScalarArray>(channel, arr);
|
||||
return new PVIFPlain<pvd::PVScalarArray>(channel, arr, enclosing ? enclosing : arr.get());
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
}//namespace
|
||||
|
||||
PVIFBuilder::PVIFBuilder(bool buildsType)
|
||||
:buildsType(buildsType)
|
||||
{}
|
||||
|
||||
PVIFBuilder::~PVIFBuilder() {}
|
||||
|
||||
|
||||
PVIFBuilder* PVIFBuilder::create(const std::string& type)
|
||||
{
|
||||
@ -738,8 +711,6 @@ 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
|
||||
|
@ -255,6 +255,45 @@ struct DBManyLocker
|
||||
};
|
||||
#endif
|
||||
|
||||
struct epicsShareClass FieldName
|
||||
{
|
||||
struct Component {
|
||||
std::string name;
|
||||
epicsUInt32 index;
|
||||
Component() :index((epicsUInt32)-1) {}
|
||||
Component(const std::string& name, epicsUInt32 index = (epicsUInt32)-1)
|
||||
:name(name), index(index)
|
||||
{}
|
||||
bool isArray() const { return index!=(epicsUInt32)-1; }
|
||||
};
|
||||
typedef std::vector<Component> parts_t;
|
||||
parts_t parts;
|
||||
bool has_sarr;
|
||||
|
||||
FieldName() :has_sarr(false) {}
|
||||
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(); }
|
||||
size_t size() const { return parts.size(); }
|
||||
const Component& operator[](size_t i) const { return parts[i]; }
|
||||
const Component& back() const { return parts.back(); }
|
||||
|
||||
// Apply field name(s) to given structure
|
||||
// if ppenclose!=NULL then the address of the enclosing field (eg. structureArray)
|
||||
// whose fieldOffset shoulbe by used, or NULL if no enclosing
|
||||
epics::pvData::PVFieldPtr
|
||||
lookup(const epics::pvData::PVStructurePtr& S, epics::pvData::PVField** ppenclose) const;
|
||||
|
||||
private:
|
||||
FieldName(const FieldName&);
|
||||
FieldName& operator=(const FieldName&);
|
||||
};
|
||||
|
||||
struct epicsShareClass PVIF {
|
||||
PVIF(dbChannel *ch);
|
||||
virtual ~PVIF() {}
|
||||
@ -277,21 +316,19 @@ private:
|
||||
|
||||
struct epicsShareClass PVIFBuilder {
|
||||
|
||||
const bool buildsType;
|
||||
|
||||
virtual ~PVIFBuilder();
|
||||
virtual ~PVIFBuilder() {}
|
||||
|
||||
// fetch the structure description
|
||||
virtual epics::pvData::FieldConstPtr dtype(dbChannel *channel) =0;
|
||||
|
||||
// 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) =0;
|
||||
// must be the root structure
|
||||
virtual PVIF* attach(dbChannel *channel, const epics::pvData::PVStructurePtr& root, const FieldName& fld) =0;
|
||||
|
||||
static PVIFBuilder* create(const std::string& name);
|
||||
protected:
|
||||
PVIFBuilder(bool buildsType);
|
||||
PVIFBuilder() {}
|
||||
private:
|
||||
PVIFBuilder(const PVIFBuilder&);
|
||||
PVIFBuilder& operator=(const PVIFBuilder&);
|
||||
@ -299,12 +336,10 @@ private:
|
||||
|
||||
struct epicsShareClass ScalarBuilder : public PVIFBuilder
|
||||
{
|
||||
ScalarBuilder() :PVIFBuilder(true) {}
|
||||
|
||||
virtual ~ScalarBuilder() {}
|
||||
|
||||
virtual epics::pvData::FieldConstPtr dtype(dbChannel *channel) OVERRIDE FINAL;
|
||||
virtual PVIF* attach(dbChannel *channel, const epics::pvData::PVFieldPtr& root) OVERRIDE FINAL;
|
||||
virtual PVIF* attach(dbChannel *channel, const epics::pvData::PVStructurePtr& root, const FieldName& fld) OVERRIDE FINAL;
|
||||
};
|
||||
|
||||
|
||||
|
@ -11,24 +11,44 @@ record(ai, "rec2") {
|
||||
record(ai, "rec3") {
|
||||
field(VAL, "3.0")
|
||||
field(RVAL, "30")
|
||||
info(pdbGroup, "grp1|fld1=VAL|fld2=RVAL")
|
||||
field(HOPR, "200")
|
||||
field(LOPR, "-200")
|
||||
info(Q:group, {
|
||||
"grp1":{
|
||||
"fld1":{+channel:"VAL"},
|
||||
"fld2":{+channel:"RVAL"}
|
||||
}
|
||||
})
|
||||
}
|
||||
record(ai, "rec4") {
|
||||
field(VAL, "4.0")
|
||||
field(RVAL, "40")
|
||||
info(pdbGroup, "grp1|fld3=VAL|fld4=RVAL")
|
||||
info(Q:group, {
|
||||
"grp1":{
|
||||
"fld3":{+channel:"VAL"},
|
||||
"fld4":{+channel:"RVAL"}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
record(ai, "rec5") {
|
||||
field(VAL, "5.0")
|
||||
field(RVAL, "50")
|
||||
info(pdbGroup, "grp2|fld1=VAL|fld3=RVAL")
|
||||
info(Q:group, {
|
||||
"grp2":{
|
||||
"fld1":{+channel:"VAL"},
|
||||
"fld3":{+channel:"RVAL"}
|
||||
}
|
||||
})
|
||||
}
|
||||
record(ai, "rec6") {
|
||||
field(VAL, "6.0")
|
||||
field(RVAL, "60")
|
||||
info(Q:group, {
|
||||
"grp2":{
|
||||
"fld2":{+channel:"VAL", +trigger:"fld1,fld2"}
|
||||
}
|
||||
})
|
||||
info(pdbGroup, "grp2|fld2=VAL")
|
||||
info(pdbTrigger, "grp2|fld2>fld1,fld2")
|
||||
}
|
||||
|
@ -72,11 +72,11 @@ void testScalar()
|
||||
|
||||
pvd::PVStructurePtr root(pvd::getPVDataCreate()->createPVStructure(dtype_root));
|
||||
|
||||
p2p::auto_ptr<PVIF> pvif_li(builder.attach(chan_li, root->getSubField<pvd::PVStructure>("li")));
|
||||
p2p::auto_ptr<PVIF> pvif_si(builder.attach(chan_si, root->getSubField<pvd::PVStructure>("si")));
|
||||
p2p::auto_ptr<PVIF> pvif_ai(builder.attach(chan_ai, root->getSubField<pvd::PVStructure>("ai")));
|
||||
p2p::auto_ptr<PVIF> pvif_ai_rval(builder.attach(chan_ai_rval, root->getSubField<pvd::PVStructure>("ai_rval")));
|
||||
p2p::auto_ptr<PVIF> pvif_mbbi(builder.attach(chan_mbbi, root->getSubField<pvd::PVStructure>("mbbi")));
|
||||
p2p::auto_ptr<PVIF> pvif_li(builder.attach(chan_li, root, FieldName("li")));
|
||||
p2p::auto_ptr<PVIF> pvif_si(builder.attach(chan_si, root, FieldName("si")));
|
||||
p2p::auto_ptr<PVIF> pvif_ai(builder.attach(chan_ai, root, FieldName("ai")));
|
||||
p2p::auto_ptr<PVIF> pvif_ai_rval(builder.attach(chan_ai_rval, root, FieldName("ai_rval")));
|
||||
p2p::auto_ptr<PVIF> pvif_mbbi(builder.attach(chan_mbbi, root, FieldName("mbbi")));
|
||||
|
||||
pvd::BitSet mask;
|
||||
|
||||
@ -247,10 +247,10 @@ void testPlain()
|
||||
|
||||
pvd::PVStructurePtr root(pvd::getPVDataCreate()->createPVStructure(dtype_root));
|
||||
|
||||
p2p::auto_ptr<PVIF> pvif_li(builder->attach(chan_li, root->getSubFieldT("li")));
|
||||
p2p::auto_ptr<PVIF> pvif_si(builder->attach(chan_si, root->getSubFieldT("si")));
|
||||
p2p::auto_ptr<PVIF> pvif_ai(builder->attach(chan_ai, root->getSubFieldT("ai")));
|
||||
p2p::auto_ptr<PVIF> pvif_mbbi(builder->attach(chan_mbbi, root->getSubFieldT("mbbi")));
|
||||
p2p::auto_ptr<PVIF> pvif_li(builder->attach(chan_li, root, FieldName("li")));
|
||||
p2p::auto_ptr<PVIF> pvif_si(builder->attach(chan_si, root, FieldName("si")));
|
||||
p2p::auto_ptr<PVIF> pvif_ai(builder->attach(chan_ai, root, FieldName("ai")));
|
||||
p2p::auto_ptr<PVIF> pvif_mbbi(builder->attach(chan_mbbi, root, FieldName("mbbi")));
|
||||
|
||||
pvd::BitSet mask;
|
||||
|
||||
|
Reference in New Issue
Block a user