more PDB
This commit is contained in:
+23
-2
@@ -132,11 +132,32 @@ void PDBProvider::destroy() {}
|
||||
|
||||
std::string PDBProvider::getProviderName() { return "PDBProvider"; }
|
||||
|
||||
namespace {
|
||||
struct ChannelFindRequesterNOOP : public pva::ChannelFind
|
||||
{
|
||||
const pva::ChannelProvider::weak_pointer provider;
|
||||
ChannelFindRequesterNOOP(const pva::ChannelProvider::shared_pointer& prov) : provider(prov) {}
|
||||
virtual ~ChannelFindRequesterNOOP() {}
|
||||
virtual void destroy() {}
|
||||
virtual std::tr1::shared_ptr<pva::ChannelProvider> getChannelProvider() { return provider.lock(); }
|
||||
virtual void cancel() {}
|
||||
};
|
||||
}
|
||||
|
||||
pva::ChannelFind::shared_pointer
|
||||
PDBProvider::channelFind(const std::string &channelName, const pva::ChannelFindRequester::shared_pointer &requester)
|
||||
{
|
||||
pva::ChannelFind::shared_pointer ret;
|
||||
requester->channelFindResult(pvd::Status(pvd::Status::STATUSTYPE_ERROR, ""), ret, false);
|
||||
pva::ChannelFind::shared_pointer ret(new ChannelFindRequesterNOOP(shared_from_this()));
|
||||
|
||||
bool found = false;
|
||||
{
|
||||
epicsGuard<epicsMutex> G(transient_pv_map.mutex());
|
||||
if(persist_pv_map.find(channelName)!=persist_pv_map.end()
|
||||
|| transient_pv_map.find(channelName)
|
||||
|| dbChannelTest(channelName.c_str())==0)
|
||||
found = true;
|
||||
}
|
||||
requester->channelFindResult(pvd::Status(), ret, found);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -82,6 +82,9 @@ void PDBGroupGet::get()
|
||||
pvif[i]->put(*changed, DBE_VALUE|DBE_ALARM|DBE_PROPERTY, NULL);
|
||||
}
|
||||
}
|
||||
//TODO: report unused fields as changed?
|
||||
changed->clear();
|
||||
changed->set(0);
|
||||
requester->getDone(pvd::Status(), shared_from_this(), pvf, changed);
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,14 @@
|
||||
namespace pvd = epics::pvData;
|
||||
namespace pva = epics::pvAccess;
|
||||
|
||||
PDBSinglePV::PDBSinglePV(DBCH& chan,
|
||||
const PDBProvider::shared_pointer& prov)
|
||||
:provider(prov)
|
||||
{
|
||||
this->chan.swap(chan);
|
||||
fielddesc = PVIF::dtype(this->chan);
|
||||
}
|
||||
|
||||
pva::Channel::shared_pointer
|
||||
PDBSinglePV::connect(const std::tr1::shared_ptr<PDBProvider>& prov,
|
||||
const pva::ChannelRequester::shared_pointer& req)
|
||||
@@ -53,5 +61,8 @@ void PDBSingleGet::get()
|
||||
DBScanLocker L(channel->pv->chan);
|
||||
pvif->put(*changed, DBE_VALUE|DBE_ALARM|DBE_PROPERTY, NULL);
|
||||
}
|
||||
//TODO: report unused fields as changed?
|
||||
changed->clear();
|
||||
changed->set(0);
|
||||
requester->getDone(pvd::Status(), shared_from_this(), pvf, changed);
|
||||
}
|
||||
|
||||
+1
-5
@@ -19,11 +19,7 @@ struct PDBSinglePV : public PDBPV, public std::tr1::enable_shared_from_this<PDBS
|
||||
PDBProvider::shared_pointer provider;
|
||||
|
||||
PDBSinglePV(DBCH& chan,
|
||||
const PDBProvider::shared_pointer& prov)
|
||||
:provider(prov)
|
||||
{
|
||||
this->chan.swap(chan);
|
||||
}
|
||||
const PDBProvider::shared_pointer& prov);
|
||||
virtual ~PDBSinglePV() {}
|
||||
|
||||
epics::pvAccess::Channel::shared_pointer
|
||||
|
||||
@@ -9,6 +9,10 @@ namespace pvd = epics::pvData;
|
||||
|
||||
DBCH::DBCH(dbChannel *ch) :chan(ch)
|
||||
{
|
||||
if(dbChannelOpen(chan)) {
|
||||
dbChannelDelete(chan);
|
||||
throw std::invalid_argument("Failed to open channel");
|
||||
}
|
||||
if(!chan)
|
||||
throw std::invalid_argument("Invalid channel");
|
||||
}
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@
|
||||
struct DBCH {
|
||||
dbChannel *chan;
|
||||
DBCH() :chan(0) {}
|
||||
explicit DBCH(dbChannel *ch);
|
||||
explicit DBCH(dbChannel *ch); // calls dbChannelOpen()
|
||||
explicit DBCH(const std::string& name);
|
||||
explicit DBCH(const char *name);
|
||||
~DBCH();
|
||||
|
||||
@@ -36,8 +36,18 @@ TESTPROD_HOST += testpvif
|
||||
testpvif_SRCS += testpvif.cpp
|
||||
testpvif_SRCS += p2pTestIoc_registerRecordDeviceDriver.cpp
|
||||
testpvif_LIBS += pdbcore pvAccess pvData $(EPICS_BASE_IOC_LIBS)
|
||||
TESTS += testpvif
|
||||
|
||||
TESTPROD_HOST += testpdb
|
||||
testpdb_SRCS += testpdb.cpp
|
||||
testpdb_SRCS += p2pTestIoc_registerRecordDeviceDriver.cpp
|
||||
testpdb_LIBS += testutils pdbcore pvAccess pvData $(EPICS_BASE_IOC_LIBS)
|
||||
TESTS += testpdb
|
||||
|
||||
|
||||
TESTSCRIPTS_HOST += $(TESTS:%=%.t)
|
||||
|
||||
|
||||
#===========================
|
||||
|
||||
include $(TOP)/configure/RULES
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
|
||||
#include <testMain.h>
|
||||
|
||||
#include <dbAccess.h>
|
||||
|
||||
#include <pv/epicsException.h>
|
||||
|
||||
#include "utilities.h"
|
||||
#include "pdb.h"
|
||||
|
||||
namespace pvd = epics::pvData;
|
||||
namespace pva = epics::pvAccess;
|
||||
|
||||
namespace {
|
||||
|
||||
template<typename PVD>
|
||||
void testFieldEqual(const pvd::PVStructurePtr& val, const char *name, typename PVD::value_type expect)
|
||||
{
|
||||
typename PVD::shared_pointer fval(val->getSubField<PVD>(name));
|
||||
if(!fval) {
|
||||
testFail("field '%s' with type %s does not exist", name, typeid(PVD).name());
|
||||
} else {
|
||||
typename PVD::value_type actual(fval->get());
|
||||
std::cout<<"# expect='"<<expect<<"' actual='"<<actual<<"'\n";
|
||||
testOk1(actual==expect);
|
||||
}
|
||||
}
|
||||
|
||||
pvd::PVStructurePtr pvget(const pva::ChannelProvider::shared_pointer& prov, const char *name,
|
||||
bool atomic)
|
||||
{
|
||||
pvd::StructureConstPtr def(pvd::getFieldCreate()->createFieldBuilder()
|
||||
->addNestedStructure("record")
|
||||
->addNestedStructure("_options")
|
||||
->add("atomic", pvd::pvBoolean)
|
||||
->endNested()
|
||||
->endNested()
|
||||
->createStructure());
|
||||
pvd::PVStructurePtr pvr(pvd::getPVDataCreate()->createPVStructure(def));
|
||||
pvr->getSubFieldT<pvd::PVBoolean>("record._options.atomic")->put(atomic);
|
||||
|
||||
|
||||
TestChannelRequester::shared_pointer req(new TestChannelRequester());
|
||||
pva::Channel::shared_pointer chan(prov->createChannel(name, req));
|
||||
|
||||
testOk1(!!chan);
|
||||
testOk1(chan && chan->isConnected());
|
||||
testOk1(req->laststate == pva::Channel::CONNECTED);
|
||||
testOk1(req->status.isOK());
|
||||
if(!chan || !chan->isConnected())
|
||||
testAbort("'%s' channel not connected", name);
|
||||
|
||||
TestChannelGetRequester::shared_pointer greq(new TestChannelGetRequester());
|
||||
pva::ChannelGet::shared_pointer get(chan->createChannelGet(greq, pvr));
|
||||
|
||||
testOk1(!!get);
|
||||
testOk1(greq->connected);
|
||||
testOk1(!greq->done);
|
||||
testOk1(greq->statusDone.isOK());
|
||||
if(!greq || !greq->connected)
|
||||
testAbort("'%s channelGet not connected", name);
|
||||
|
||||
get->get();
|
||||
|
||||
testOk1(greq->done);
|
||||
testOk1(greq->statusDone.isOK());
|
||||
testOk1(!!greq->value);
|
||||
if(!greq->value)
|
||||
testAbort("'%s' get w/o data", name);
|
||||
return greq->value;
|
||||
}
|
||||
|
||||
void testSingle(const PDBProvider::shared_pointer& prov)
|
||||
{
|
||||
pvd::PVStructurePtr value;
|
||||
|
||||
value = pvget(prov, "rec1", false);
|
||||
testFieldEqual<pvd::PVDouble>(value, "value", 1.0);
|
||||
|
||||
value = pvget(prov, "rec1.RVAL", false);
|
||||
testFieldEqual<pvd::PVInt>(value, "value", 10);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
extern "C"
|
||||
void p2pTestIoc_registerRecordDeviceDriver(struct dbBase *);
|
||||
|
||||
MAIN(testpdb)
|
||||
{
|
||||
testPlan(0);
|
||||
try{
|
||||
TestIOC IOC;
|
||||
|
||||
testdbReadDatabase("p2pTestIoc.dbd", NULL, NULL);
|
||||
p2pTestIoc_registerRecordDeviceDriver(pdbbase);
|
||||
testdbReadDatabase("testpdb.db", NULL, NULL);
|
||||
|
||||
IOC.init();
|
||||
|
||||
PDBProvider::shared_pointer prov(new PDBProvider());
|
||||
testSingle(prov);
|
||||
|
||||
}catch(std::exception& e){
|
||||
PRINT_EXCEPTION(e);
|
||||
testAbort("Unexpected Exception: %s", e.what());
|
||||
}
|
||||
return testDone();
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
record(ai, "rec1") {
|
||||
field(VAL, "1.0")
|
||||
field(RVAL, "10")
|
||||
}
|
||||
record(ai, "rec2") {
|
||||
field(VAL, "2.0")
|
||||
field(RVAL, "20")
|
||||
}
|
||||
record(ai, "rec3") {
|
||||
field(VAL, "3.0")
|
||||
field(RVAL, "30")
|
||||
info(pdbGroup, "grp1|fld1=VAL|fld2=RVAL")
|
||||
}
|
||||
record(ai, "rec4") {
|
||||
field(VAL, "4.0")
|
||||
field(RVAL, "40")
|
||||
info(pdbGroup, "grp1|fld3=VAL|fld4=RVAL")
|
||||
}
|
||||
@@ -64,6 +64,44 @@ bool TestChannelRequester::waitForConnect()
|
||||
|
||||
}
|
||||
|
||||
static size_t countTestChannelGetRequester;
|
||||
|
||||
TestChannelGetRequester::TestChannelGetRequester()
|
||||
:connected(false)
|
||||
,done(false)
|
||||
{
|
||||
epicsAtomicIncrSizeT(&countTestChannelGetRequester);
|
||||
}
|
||||
|
||||
TestChannelGetRequester::~TestChannelGetRequester()
|
||||
{
|
||||
epicsAtomicDecrSizeT(&countTestChannelGetRequester);
|
||||
}
|
||||
|
||||
void TestChannelGetRequester::channelGetConnect(const epics::pvData::Status &status,
|
||||
const epics::pvAccess::ChannelGet::shared_pointer &get,
|
||||
const epics::pvData::Structure::const_shared_pointer &structure)
|
||||
{
|
||||
if(connected)
|
||||
testFail("channelGetConnect() called twice");
|
||||
statusConnect = status;
|
||||
channelGet = get;
|
||||
fielddesc = structure;
|
||||
connected = true;
|
||||
}
|
||||
|
||||
void TestChannelGetRequester::getDone(const epics::pvData::Status &status,
|
||||
const epics::pvAccess::ChannelGet::shared_pointer &get,
|
||||
const epics::pvData::PVStructure::shared_pointer &pvStructure,
|
||||
const epics::pvData::BitSet::shared_pointer &bitSet)
|
||||
{
|
||||
statusDone = status;
|
||||
channelGet = get;
|
||||
value = pvStructure;
|
||||
changed = bitSet;
|
||||
done = true;
|
||||
}
|
||||
|
||||
static size_t countTestChannelMonitorRequester;
|
||||
|
||||
TestChannelMonitorRequester::TestChannelMonitorRequester()
|
||||
|
||||
+34
-2
@@ -89,6 +89,33 @@ struct TestChannelRequester : public epics::pvAccess::ChannelRequester
|
||||
bool waitForConnect();
|
||||
};
|
||||
|
||||
struct TestChannelGetRequester : public epics::pvAccess::ChannelGetRequester
|
||||
{
|
||||
POINTER_DEFINITIONS(TestChannelGetRequester);
|
||||
DUMBREQUESTER(TestChannelGetRequester)
|
||||
|
||||
bool connected, done;
|
||||
epics::pvData::Status statusConnect, statusDone;
|
||||
epics::pvAccess::ChannelGet::shared_pointer channelGet;
|
||||
epics::pvData::Structure::const_shared_pointer fielddesc;
|
||||
epics::pvData::PVStructure::shared_pointer value;
|
||||
epics::pvData::BitSet::shared_pointer changed;
|
||||
|
||||
TestChannelGetRequester();
|
||||
virtual ~TestChannelGetRequester();
|
||||
|
||||
virtual void channelGetConnect(
|
||||
const epics::pvData::Status& status,
|
||||
epics::pvAccess::ChannelGet::shared_pointer const & channelGet,
|
||||
epics::pvData::Structure::const_shared_pointer const & structure);
|
||||
|
||||
virtual void getDone(
|
||||
const epics::pvData::Status& status,
|
||||
epics::pvAccess::ChannelGet::shared_pointer const & channelGet,
|
||||
epics::pvData::PVStructure::shared_pointer const & pvStructure,
|
||||
epics::pvData::BitSet::shared_pointer const & bitSet);
|
||||
};
|
||||
|
||||
struct TestChannelMonitorRequester : public epics::pvData::MonitorRequester
|
||||
{
|
||||
POINTER_DEFINITIONS(TestChannelMonitorRequester);
|
||||
@@ -262,8 +289,7 @@ struct TestIOC {
|
||||
testdbPrepare();
|
||||
}
|
||||
~TestIOC() {
|
||||
if(hasInit)
|
||||
testIocShutdownOk();
|
||||
this->shutdown();
|
||||
testdbCleanup();
|
||||
}
|
||||
void init() {
|
||||
@@ -274,6 +300,12 @@ struct TestIOC {
|
||||
hasInit = true;
|
||||
}
|
||||
}
|
||||
void shutdown() {
|
||||
if(hasInit) {
|
||||
testIocShutdownOk();
|
||||
hasInit = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif // UTILITIES_H
|
||||
|
||||
Reference in New Issue
Block a user