diff --git a/pdbApp/pdb.cpp b/pdbApp/pdb.cpp index 3b063be..be6c539 100644 --- a/pdbApp/pdb.cpp +++ b/pdbApp/pdb.cpp @@ -125,7 +125,7 @@ struct PDBProcessor curgroup->members.push_back(GroupMemberInfo(recbase + dbf, pvf)); curgroup->members.back().index = curgroup->members.size()-1; - curgroup->members_map[curgroup->name] = curgroup->members.back().index; + curgroup->members_map[pvf] = curgroup->members.back().index; if(PDBProviderDebug>2) { fprintf(stderr, " pdb map '%s.%s' <-> '%s'\n", @@ -164,20 +164,10 @@ struct PDBProcessor Splitter sep(trigs.c_str(), ','); std::string target; - if(PDBProviderDebug>2) - fprintf(stderr, " pdb trg '%s.%s' -> ", - curgroup->name.c_str(), pvf.c_str()); - while(sep.snip(target)) { curgroup->hastriggers = true; it->second.insert(target); - if(PDBProviderDebug<=2) continue; - fprintf(stderr, "'%s.%s'", curgroup->name.c_str(), target.c_str()); - if(!!sep) fprintf(stderr, ", "); } - - if(PDBProviderDebug>2) - fprintf(stderr, "\n"); } } @@ -200,12 +190,19 @@ struct PDBProcessor } GroupMemberInfo& srcmem = info.members[it2x->second]; + if(PDBProviderDebug>2) + fprintf(stderr, " pdb trg '%s.%s' -> ", + info.name.c_str(), src.c_str()); + FOREACH(it3, end3, targets) { // for each trigger target const std::string& target = *it3; if(target=="*") { - for(size_t i=0; i2) + fprintf(stderr, "%s, ", info.members[i].pvfldname.c_str()); + } } else { @@ -219,8 +216,12 @@ struct PDBProcessor // and finally, update source BitSet srcmem.triggers.insert(targetmem.index); + if(PDBProviderDebug>2) + fprintf(stderr, "%s, ", info.members[targetmem.index].pvfldname.c_str()); } } + + if(PDBProviderDebug>2) fprintf(stderr, "\n"); } } else { if(PDBProviderDebug>1) fprintf(stderr, " pdb default triggers for '%s'\n", info.name.c_str()); @@ -407,8 +408,11 @@ PDBProvider::PDBProvider() info.evt_PROPERTY.create(event_context, info.chan, &pdb_group_event, DBE_PROPERTY); - if(!info.triggers.empty()) + if(!info.triggers.empty()) { + printf("##### setup VALUE %s\n", dbChannelName(info.chan)); info.evt_VALUE.create(event_context, info.chan, &pdb_group_event, DBE_VALUE|DBE_ALARM); + } else + printf("##### skip VALUE %s\n", dbChannelName(info.chan)); } } }catch(...){ diff --git a/pdbApp/pvif.cpp b/pdbApp/pvif.cpp index 5433fae..ff17b97 100644 --- a/pdbApp/pvif.cpp +++ b/pdbApp/pvif.cpp @@ -14,7 +14,7 @@ DBCH::DBCH(dbChannel *ch) :chan(ch) throw std::invalid_argument("Failed to open channel"); } if(!chan) - throw std::invalid_argument("Invalid channel"); + throw std::invalid_argument(std::string("Invalid channel ")+dbChannelName(ch)); } DBCH::DBCH(const std::string& name) @@ -24,7 +24,7 @@ DBCH::DBCH(const std::string& name) throw std::invalid_argument("Invalid channel"); if(dbChannelOpen(chan)) { dbChannelDelete(chan); - throw std::invalid_argument("Failed to open channel"); + throw std::invalid_argument("Failed to open channel "+name); } } @@ -35,7 +35,7 @@ DBCH::DBCH(const char *name) throw std::invalid_argument("Invalid channel"); if(dbChannelOpen(chan)) { dbChannelDelete(chan); - throw std::invalid_argument("Failed to open channel"); + throw std::invalid_argument(std::string("Failed to open channel ")+name); } } diff --git a/testApp/testpdb.cpp b/testApp/testpdb.cpp index 176119d..bc7a315 100644 --- a/testApp/testpdb.cpp +++ b/testApp/testpdb.cpp @@ -273,23 +273,16 @@ void testSingleMonitor(const PDBProvider::shared_pointer& prov) PVMonitor mon(prov, "rec1"); mon.mon->start(); - // start() will trigger two updates, one for DBE_VALUE|DBE_ALARM - // and another for DBE_PROPERTY testOk1(mon.monreq->waitForEvent()); testDiag("Initial event"); PVMonitor::Element e(mon); - // TODO: correctly check the first update - // no mather which DBE_* arrives first... e = mon.poll(); - testOk1(!!e); - while(!(e = mon.poll())) { - testDiag("Wait initial event (part 2)"); - mon.monreq->waitForEvent(); - } testOk1(!!e); + if(!!e) testEqual(toString(*e.elem->changedBitSet), "{0, 1, 3, 4, 11, 12, 14, 15, 17, 18}"); + else testFail("oops"); testFieldEqual(e, "value", 1.0); testFieldEqual(e, "display.limitHigh", 100.0); testFieldEqual(e, "display.limitLow", -100.0); @@ -378,6 +371,59 @@ void testGroupMonitor(const PDBProvider::shared_pointer& prov) testFieldEqual(e, "fld1.value", 32.0); } +void testGroupMonitorTriggers(const PDBProvider::shared_pointer& prov) +{ + testDiag("test group monitor w/ triggers"); + + testdbPutFieldOk("rec5", DBR_DOUBLE, 5.0); + testdbPutFieldOk("rec6", DBR_DOUBLE, 6.0); + testdbPutFieldOk("rec5.RVAL", DBR_LONG, 50); + + testDiag("subscribe to grp2"); + PVMonitor mon(prov, "grp2"); + PVMonitor::Element e(mon); + + testOk1(mon.mon->start().isOK()); + + testDiag("Wait for initial event"); + testOk1(mon.monreq->waitForEvent()); + testDiag("Initial event"); + + e = mon.poll(); + testOk1(!!e); + + if(!!e) testEqual(toString(*e.elem->changedBitSet), "{0, 2, 4, 5, 12, 13, 15, 16, 18, 19, 32, 33, 35, 36, 38, 39, 42, 44, 45, 52, 53, 55, 56, 58, 59}"); + else testFail("oops"); + + testFieldEqual(e, "fld1.value", 5.0); + testFieldEqual(e, "fld2.value", 6.0); + testFieldEqual(e, "fld3.value", 0); // not triggered -> no update. only get/set + + e = mon.poll(); + testOk1(!e); + + testdbPutFieldOk("rec5.RVAL", DBR_LONG, 60); // no trigger -> no event + testdbPutFieldOk("rec5", DBR_DOUBLE, 15.0); // no trigger -> no event + testdbPutFieldOk("rec6", DBR_DOUBLE, 16.0); // event triggered + + testDiag("Wait for event"); + testOk1(mon.monreq->waitForEvent()); + testDiag("event"); + + e = mon.poll(); + testOk1(!!e); + + if(!!e) testEqual(toString(*e.elem->changedBitSet), "{2, 4, 5, 42, 44, 45}"); + else testFail("oops"); + + testFieldEqual(e, "fld1.value", 15.0); + testFieldEqual(e, "fld2.value", 16.0); + testFieldEqual(e, "fld3.value", 0); // not triggered -> no update. only get/set + + e = mon.poll(); + testOk1(!e); +} + } // namespace extern "C" @@ -405,6 +451,7 @@ MAIN(testpdb) testSingleMonitor(prov); testGroupMonitor(prov); + testGroupMonitorTriggers(prov); }catch(...){ prov->destroy(); throw; diff --git a/testApp/testpdb.db b/testApp/testpdb.db index 7237976..6ba6240 100644 --- a/testApp/testpdb.db +++ b/testApp/testpdb.db @@ -20,3 +20,15 @@ record(ai, "rec4") { field(RVAL, "40") info(pdbGroup, "grp1|fld3=VAL|fld4=RVAL") } + +record(ai, "rec5") { + field(VAL, "5.0") + field(RVAL, "50") + info(pdbGroup, "grp2|fld1=VAL|fld3=RVAL") +} +record(ai, "rec6") { + field(VAL, "6.0") + field(RVAL, "60") + info(pdbGroup, "grp2|fld2=VAL") + info(pdbTrigger, "grp2|fld2>fld1,fld2") +}