redo mappings to handle fieldOffset of structure array

This commit is contained in:
Michael Davidsaver
2017-09-20 16:28:10 -05:00
parent 25f26c678f
commit 67bda75bcb
9 changed files with 255 additions and 143 deletions

View File

@ -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:"*"}
}
})
}

View File

@ -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;
}

View File

@ -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++;

View File

@ -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;

View File

@ -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);

View File

@ -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

View File

@ -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;
};

View File

@ -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")
}

View File

@ -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;