monitoring test infrastructure

This commit is contained in:
Michael Davidsaver
2016-01-28 17:07:07 -05:00
parent 03db900663
commit 9ee050fa25
7 changed files with 947 additions and 8 deletions

View File

@ -7,15 +7,18 @@ include $(TOP)/configure/CONFIG
PROD_HOST = p2p
p2p_SRCS += main.cpp
p2p_SRCS += server.cpp
p2p_SRCS += client.cpp
p2p_SRCS += chancache.cpp
p2p_SRCS += moncache.cpp
p2p_SRCS += channel.cpp
p2p_LIBS += p2pcore pvAccess pvData Com
p2p_LIBS += pvAccess pvData Com
LIBRARY_HOST += p2pcore
p2pcore_SRCS += server.cpp
p2pcore_SRCS += client.cpp
p2pcore_SRCS += chancache.cpp
p2pcore_SRCS += moncache.cpp
p2pcore_SRCS += channel.cpp
p2pcore_LIBS += pvAccess pvData Com
#===========================

View File

@ -2,6 +2,7 @@
#define WEAKMAP_H
#include <map>
#include <set>
#include <vector>
#include <stdexcept>
@ -9,7 +10,7 @@
#include <epicsMutex.h>
#include <epicsGuard.h>
/** @brief An associative map where the value is a weak_ptr to the value is stored.
/** @brief An associative map where a weak_ptr to the value is stored.
*
* Acts like std::map<K, weak_ptr<V> > where entries are automatically
* removed when no longer referenced.

View File

@ -7,11 +7,21 @@ include $(TOP)/configure/CONFIG
USR_CPPFLAGS = -I$(TOP)/p2pApp
LIBRARY += testutils
testutils_SRCS += utilities.cpp
testutils_LIBS += pvAccess pvData Com
TESTPROD_HOST += testweak
testweak_SRCS = testweak.cpp
testweak_LIBS = Com
TESTS += testweak
TESTPROD_HOST += testtest
testtest_SRCS = testtest.cpp
testtest_LIBS = testutils p2pcore pvAccess pvData Com
TESTS += testtest
TESTSCRIPTS_HOST += $(TESTS:%=%.t)
#===========================

View File

@ -1 +1,66 @@
#include <epicsGuard.h>
#include <epicsUnitTest.h>
#include <testMain.h>
#include <pv/monitor.h>
#include <pv/thread.h>
#include "utilities.h"
namespace pvd = epics::pvData;
typedef epicsGuard<epicsMutex> Guard;
namespace {
struct DownStreamReq : public pvd::MonitorRequester, DumbRequester
{
pvd::Mutex lock;
bool connected;
bool unlistend;
size_t eventCnt;
pvd::Status connectStatus;
pvd::MonitorPtr mon;
pvd::StructureConstPtr structure;
DownStreamReq()
:DumbRequester("DownStreamReq")
,connected(false)
,unlistend(false)
,eventCnt(0)
{}
virtual void monitorConnect(pvd::Status const & status,
pvd::MonitorPtr const & monitor, pvd::StructureConstPtr const & structure)
{
Guard G(lock);
assert(!connected);
connectStatus = status;
mon = monitor;
this->structure = structure;
connected = true;
}
virtual void monitorEvent(MonitorPtr const & monitor)
{
Guard G(lock);
mon = monitor;
eventCnt++;
}
virtual void unlisten(MonitorPtr const & monitor)
{
Guard G(lock);
assert(!unlistend);
unlistend = true;
}
};
} // namespace
MAIN(testmon)
{
testPlan(0);
return testDone();
}

176
testApp/testtest.cpp Normal file
View File

@ -0,0 +1,176 @@
// Test the testing utilities
#include <epicsGuard.h>
#include <epicsUnitTest.h>
#include <testMain.h>
#include <pv/monitor.h>
#include <pv/thread.h>
#include "utilities.h"
typedef epicsGuard<epicsMutex> Guard;
typedef epicsGuardRelease<epicsMutex> UnGuard;
namespace pvd = epics::pvData;
namespace pva = epics::pvAccess;
namespace {
template<typename T>
struct ScalarAccessor {
pvd::PVScalar::shared_pointer field;
typedef T value_type;
ScalarAccessor(const pvd::PVStructurePtr& s, const char *name)
:field(s->getSubFieldT<pvd::PVScalar>(name))
{}
operator value_type() {
return field->getAs<T>();
}
ScalarAccessor& operator=(T v) {
field->putFrom<T>(v);
return *this;
}
};
void testmonitor()
{
testDiag("Test Test* monitoring");
pvd::FieldCreatePtr fieldCreate(pvd::getFieldCreate());
pvd::PVDataCreatePtr create(pvd::getPVDataCreate());
testDiag("Setup TestProvider with \"test\"");
TestProvider::shared_pointer prov(new TestProvider);
TestPV::shared_pointer pv(prov->addPV("test",
fieldCreate->createFieldBuilder()
->add("x", pvd::pvInt)
->add("y", pvd::pvInt)
->createStructure()));
ScalarAccessor<pvd::int32> x(pv->value, "x");
x = 42;
testDiag("Create channel");
TestChannelRequester::shared_pointer creq(new TestChannelRequester);
pva::Channel::shared_pointer chan(prov->createChannel("test", creq));
testOk1(!!chan.get());
testOk1(creq->waitForConnect());
testOk1(chan==creq->chan);
if(!chan)
testAbort("Create channel failed");
testDiag("Create monitor");
TestChannelMonitorRequester::shared_pointer mreq(new TestChannelMonitorRequester);
pvd::Monitor::shared_pointer mon;
{
pvd::PVStructurePtr pvreq(create->createPVStructure(fieldCreate->createFieldBuilder()
->add("junk", pvd::pvInt)
->createStructure()));
mon = chan->createMonitor(mreq, pvreq);
}
testOk1(!!mon.get());
testOk1(mreq->connectStatus.isSuccess());
testOk1(!!mreq->dtype.get());
testOk1(mreq->eventCnt==0);
if(!mon)
testAbort("Create monitor failed");
testDiag("ensure queue is initially empty");
testOk1(!mon->poll());
testDiag("Start monitor and check initial update");
testOk1(mon->start().isSuccess());
pvd::MonitorElementPtr elem(mon->poll());
testOk1(!!elem.get());
testOk1(elem && elem->pvStructurePtr->getSubFieldT<pvd::PVInt>("x")->get()==42);
testOk1(elem && elem->changedBitSet->nextSetBit(0)==0); // initial update shows all changed
testOk1(elem && elem->changedBitSet->nextSetBit(1)==-1);
testOk1(elem && elem->overrunBitSet->isEmpty());
if(elem) mon->release(elem);
testDiag("ensure start() queues only one");
testOk1(!mon->poll());
testDiag("Change a field");
x = 43;
pvd::BitSet changed;
changed.set(1);
pv->post(changed);
testOk1(mreq->eventCnt==1);
elem = mon->poll();
testOk1(!!elem.get());
testOk1(elem && elem->pvStructurePtr->getSubFieldT<pvd::PVInt>("x")->get()==43);
testOk1(elem && elem->changedBitSet->nextSetBit(0)==1);
testOk1(elem && elem->changedBitSet->nextSetBit(2)==-1);
testOk1(elem && elem->overrunBitSet->isEmpty());
if(elem) mon->release(elem);
testDiag("ensure queues are empty");
testOk1(!mon->poll());
testDiag("overflow queue");
x = 44;
pv->post(changed, false);
x = 45;
pv->post(changed, false);
x = 46;
pv->post(changed, false);
testOk1(mreq->eventCnt==1);
x = 47;
pv->post(changed);
testOk1(mreq->eventCnt==2);
elem = mon->poll();
testOk1(!!elem.get());
testOk1(elem && elem->pvStructurePtr->getSubFieldT<pvd::PVInt>("x")->get()==44);
testOk1(elem && elem->changedBitSet->nextSetBit(0)==1);
testOk1(elem && elem->overrunBitSet->isEmpty());
if(elem) mon->release(elem); // overflow element is queued here
elem = mon->poll();
testOk1(!!elem.get());
testOk1(elem && elem->pvStructurePtr->getSubFieldT<pvd::PVInt>("x")->get()==45);
testOk1(elem && elem->changedBitSet->nextSetBit(0)==1);
testOk1(elem && elem->overrunBitSet->isEmpty());
if(elem) mon->release(elem);
elem = mon->poll();
testOk1(!!elem.get());
testOk1(elem && elem->pvStructurePtr->getSubFieldT<pvd::PVInt>("x")->get()==47);
testOk1(elem && elem->changedBitSet->nextSetBit(0)==1);
testOk1(elem && elem->overrunBitSet->nextSetBit(0)==1);
testOk1(elem && elem->overrunBitSet->nextSetBit(2)==-1);
if(elem) mon->release(elem);
testDiag("ensure queues are empty");
testOk1(!mon->poll());
testOk1(mreq->eventCnt==2);
mon->destroy();
chan->destroy();
}
} // namespace
MAIN(testtest)
{
testPlan(0);
testmonitor();
return testDone();
}

479
testApp/utilities.cpp Normal file
View File

@ -0,0 +1,479 @@
#include <utilities.h>
#include <helper.h>
typedef epicsGuard<epicsMutex> Guard;
typedef epicsGuardRelease<epicsMutex> UnGuard;
namespace pvd = epics::pvData;
namespace pva = epics::pvAccess;
TestChannelRequester::TestChannelRequester()
:laststate(pva::Channel::NEVER_CONNECTED)
{}
void TestChannelRequester::channelCreated(const pvd::Status& status, pva::Channel::shared_pointer const & channel)
{
Guard G(lock);
laststate = pva::Channel::CONNECTED;
this->status = status;
chan = channel;
wait.trigger();
}
void TestChannelRequester::channelStateChange(pva::Channel::shared_pointer const & channel,
pva::Channel::ConnectionState connectionState)
{
Guard G(lock);
laststate = connectionState;
wait.trigger();
}
bool TestChannelRequester::waitForConnect()
{
Guard G(lock);
assert(chan);
while(true) {
pva::Channel::ConnectionState cur = chan->getConnectionState();
switch(cur) {
case pva::Channel::NEVER_CONNECTED:
break;
case pva::Channel::CONNECTED:
return true;
case pva::Channel::DISCONNECTED:
case pva::Channel::DESTROYED:
return false;
}
UnGuard U(G);
wait.wait();
}
}
TestChannelMonitorRequester::TestChannelMonitorRequester()
:connected(false)
,unlistend(false)
,eventCnt(0)
{}
void TestChannelMonitorRequester::monitorConnect(pvd::Status const & status,
pvd::MonitorPtr const & monitor,
pvd::StructureConstPtr const & structure)
{
Guard G(lock);
connectStatus = status;
dtype = structure;
connected = true;
wait.trigger();
}
void TestChannelMonitorRequester::monitorEvent(pvd::MonitorPtr const & monitor)
{
mon = monitor;
eventCnt++;
wait.trigger();
}
void TestChannelMonitorRequester::unlisten(pvd::MonitorPtr const & monitor)
{
Guard G(lock);
unlistend = true;
wait.trigger();
}
bool TestChannelMonitorRequester::waitForEvent()
{
Guard G(lock);
size_t icnt = eventCnt;
while(!unlistend && eventCnt==icnt) {
UnGuard U(G);
wait.wait();
}
return !unlistend;
}
TestPVChannel::TestPVChannel(const std::tr1::shared_ptr<TestPV> &pv,
const std::tr1::shared_ptr<pva::ChannelRequester> &req)
:pv(pv)
,requester(req)
,state(CONNECTED)
{}
TestPVChannel::~TestPVChannel()
{
Guard G(pv->provider->lock);
if(requester)
testDiag("Warning: TestPVChannel dropped w/o destroy()");
}
void TestPVChannel::destroy()
{
std::tr1::shared_ptr<TestProvider> P(pv->provider);
Guard G(P->lock);
requester.reset();
state = DESTROYED;
}
std::tr1::shared_ptr<pva::ChannelProvider>
TestPVChannel::getProvider()
{ return pv->provider; }
TestPVChannel::ConnectionState TestPVChannel::getConnectionState()
{
Guard G(pv->provider->lock);
return state;
}
std::string TestPVChannel::getChannelName()
{ return pv->name; }
bool TestPVChannel::isConnected()
{
return getConnectionState()==CONNECTED;
}
void TestPVChannel::getField(pva::GetFieldRequester::shared_pointer const & requester,std::string const & subField)
{
Guard G(pv->provider->lock);
//TODO subField?
requester->getDone(pvd::Status(), pv->dtype);
}
pva::ChannelProcess::shared_pointer
TestPVChannel::createChannelProcess(
pva::ChannelProcessRequester::shared_pointer const & requester,
pvd::PVStructure::shared_pointer const & pvRequest)
{
pva::ChannelProcess::shared_pointer ret;
requester->channelProcessConnect(pvd::Status(pvd::Status::STATUSTYPE_FATAL, "Not implemented"), ret);
return ret;
}
pva::ChannelGet::shared_pointer
TestPVChannel::createChannelGet(
pva::ChannelGetRequester::shared_pointer const & requester,
pvd::PVStructure::shared_pointer const & pvRequest)
{
pva::ChannelGet::shared_pointer ret;
requester->channelGetConnect(pvd::Status(pvd::Status::STATUSTYPE_FATAL, "Not implemented"),
ret,
pvd::StructureConstPtr());
return ret;
}
pva::ChannelPut::shared_pointer
TestPVChannel::createChannelPut(
pva::ChannelPutRequester::shared_pointer const & requester,
pvd::PVStructure::shared_pointer const & pvRequest)
{
pva::ChannelPut::shared_pointer ret;
requester->channelPutConnect(pvd::Status(pvd::Status::STATUSTYPE_FATAL, "Not implemented"),
ret,
pvd::StructureConstPtr());
return ret;
}
pva::ChannelPutGet::shared_pointer
TestPVChannel::createChannelPutGet(
pva::ChannelPutGetRequester::shared_pointer const & requester,
pvd::PVStructure::shared_pointer const & pvRequest)
{
pva::ChannelPutGet::shared_pointer ret;
requester->channelPutGetConnect(pvd::Status(pvd::Status::STATUSTYPE_FATAL, "Not implemented"),
ret,
pvd::StructureConstPtr(),
pvd::StructureConstPtr());
return ret;
}
pva::ChannelRPC::shared_pointer
TestPVChannel::createChannelRPC(
pva::ChannelRPCRequester::shared_pointer const & requester,
pvd::PVStructure::shared_pointer const & pvRequest)
{
pva::ChannelRPC::shared_pointer ret;
requester->channelRPCConnect(pvd::Status(pvd::Status::STATUSTYPE_FATAL, "Not implemented"),
ret);
return ret;
}
pvd::Monitor::shared_pointer
TestPVChannel::createMonitor(
pvd::MonitorRequester::shared_pointer const & requester,
pvd::PVStructure::shared_pointer const & pvRequest)
{
shared_pointer self(weakself);
TestPVMonitor::shared_pointer ret(new TestPVMonitor(self, requester, 2));
{
Guard G(pv->provider->lock);
monitors.insert(ret);
static_cast<TestPVMonitor*>(ret.get())->weakself = ret; // save wrapped weak ref
}
requester->monitorConnect(pvd::Status(), ret, pv->dtype);
return ret;
}
pva::ChannelArray::shared_pointer
TestPVChannel::createChannelArray(
pva::ChannelArrayRequester::shared_pointer const & requester,
pvd::PVStructure::shared_pointer const & pvRequest)
{
pva::ChannelArray::shared_pointer ret;
requester->channelArrayConnect(pvd::Status(pvd::Status::STATUSTYPE_FATAL, "Not implemented"),
ret,
pvd::Array::const_shared_pointer());
return ret;
}
TestPVMonitor::TestPVMonitor(const TestPVChannel::shared_pointer& ch,
const pvd::MonitorRequester::shared_pointer& req,
size_t bsize)
:channel(ch)
,requester(req)
,running(false)
,finalize(false)
,inoverflow(false)
,needWakeup(false)
{
pvd::PVDataCreatePtr fact(pvd::PVDataCreate::getPVDataCreate());
for(size_t i=0; i<bsize; i++) {
pvd::MonitorElementPtr elem(new pvd::MonitorElement(fact->createPVStructure(channel->pv->dtype)));
free.push_back(elem);
}
}
TestPVMonitor::~TestPVMonitor()
{
Guard G(channel->pv->provider->lock);
if(requester)
testDiag("Warning: TestPVMonitor dropped w/o destroy()");
}
void TestPVMonitor::destroy()
{
Guard G(channel->pv->provider->lock);
requester.reset();
shared_pointer self(weakself);
channel->monitors.erase(self); // ensure we don't get more notifications
}
pvd::Status TestPVMonitor::start()
{
bool wake;
{
Guard G(channel->pv->provider->lock);
if(finalize && buffer.empty())
return pvd::Status();
if(!running) {
wake = running = needWakeup = true;
}
if(!this->free.empty()) {
pvd::MonitorElementPtr monitorElement(this->free.front());
if(changedMask.isEmpty()) {
changedMask.set(0); // initial update has all changed
overflowMask.clear();
}
monitorElement->pvStructurePtr->copyUnchecked(*channel->pv->value);
*monitorElement->changedBitSet = changedMask;
*monitorElement->overrunBitSet = overflowMask;
changedMask.clear();
overflowMask.clear();
buffer.push_back(monitorElement);
this->free.pop_front();
}
}
(void)wake; // todo notify?
return pvd::Status();
}
pvd::Status TestPVMonitor::stop()
{
Guard G(channel->pv->provider->lock);
running = false;
return pvd::Status();
}
pvd::MonitorElementPtr TestPVMonitor::poll()
{
pvd::MonitorElementPtr ret;
Guard G(channel->pv->provider->lock);
if(!buffer.empty()) {
ret = buffer.front();
buffer.pop_front();
}
testDiag("pop %p", ret.get());
return ret;
}
void TestPVMonitor::release(pvd::MonitorElementPtr const & monitorElement)
{
Guard G(channel->pv->provider->lock);
testDiag("release %p", monitorElement.get());
if(inoverflow) {
assert(!buffer.empty());
assert(this->free.empty());
monitorElement->pvStructurePtr->copyUnchecked(*channel->pv->value);
*monitorElement->changedBitSet = changedMask;
*monitorElement->overrunBitSet = overflowMask;
changedMask.clear();
overflowMask.clear();
buffer.push_back(monitorElement);
testDiag("overflow resume %p", monitorElement.get());
inoverflow = false;
} else {
this->free.push_back(monitorElement);
}
}
TestPV::TestPV(const std::string& name,
const std::tr1::shared_ptr<TestProvider>& provider,
const pvd::StructureConstPtr& dtype)
:name(name)
,provider(provider)
,factory(pvd::PVDataCreate::getPVDataCreate())
,dtype(dtype)
,value(factory->createPVStructure(dtype))
{}
void TestPV::post(const pvd::BitSet& changed, bool notify)
{
Guard G(provider->lock);
channels_t::vector_type toupdate(channels.lock_vector());
FOREACH(it, end, toupdate) // channel
{
TestPVChannel *chan = it->get();
TestPVChannel::monitors_t::vector_type tomon(chan->monitors.lock_vector());
FOREACH(it2, end2, tomon) // monitor/subscription
{
TestPVMonitor *mon = it2->get();
if(mon->inoverflow || mon->free.empty()) {
mon->inoverflow = true;
mon->overflowMask.or_and(mon->changedMask, changed); // oflow = prev_changed & new_changed
mon->changedMask |= changed;
testDiag("overflow");
} else {
if(!mon->needWakeup)
mon->needWakeup = mon->buffer.empty();
AUTO_REF(elem, mon->free.front());
elem->pvStructurePtr->copyUnchecked(*value);
*elem->changedBitSet = changed;
elem->overrunBitSet->clear(); // redundant/paranoia
mon->buffer.push_back(elem);
mon->free.pop_front();
testDiag("push %p", elem.get());
}
if(mon->needWakeup && notify) {
UnGuard U(G);
mon->requester->monitorEvent(*it2);
}
}
}
}
void TestPV::disconnect()
{
Guard G(provider->lock);
channels_t::vector_type toupdate(channels.lock_vector());
FOREACH(it, end, toupdate) // channel
{
TestPVChannel *chan = it->get();
chan->state = TestPVChannel::DISCONNECTED;
{
UnGuard U(G);
chan->requester->channelStateChange(*it, TestPVChannel::DISCONNECTED);
}
}
}
TestProvider::TestProvider() {}
void TestProvider::destroy()
{
// TODO: disconnect all?
}
pva::ChannelFind::shared_pointer
TestProvider::channelList(pva::ChannelListRequester::shared_pointer const & requester)
{
pva::ChannelFind::shared_pointer ret;
pvd::PVStringArray::const_svector names;
requester->channelListResult(pvd::Status(pvd::Status::STATUSTYPE_FATAL, "Not implemented"),
ret,
names,
true);
return ret;
}
pva::ChannelFind::shared_pointer
TestProvider::channelFind(std::string const & channelName,
pva::ChannelFindRequester::shared_pointer const & requester)
{
pva::ChannelFind::shared_pointer ret;
requester->channelFindResult(pvd::Status(pvd::Status::STATUSTYPE_FATAL, "Not implemented"),
ret, false);
return ret;
}
pva::Channel::shared_pointer
TestProvider::createChannel(std::string const & channelName,pva::ChannelRequester::shared_pointer const & requester,
short priority)
{
return createChannel(channelName, requester, priority, "<unused>");
}
pva::Channel::shared_pointer
TestProvider::createChannel(std::string const & channelName,
pva::ChannelRequester::shared_pointer const & requester,
short priority, std::string const & address)
{
pva::Channel::shared_pointer ret;
{
Guard G(lock);
TestPV::shared_pointer pv(pvs.find(channelName));
if(pv) {
TestPVChannel::shared_pointer chan(new TestPVChannel(pv, requester));
pv->channels.insert(chan);
chan->weakself = chan;
ret = chan;
}
}
if(ret) {
requester->channelCreated(pvd::Status(), ret);
} else {
requester->channelCreated(pvd::Status(pvd::Status::STATUSTYPE_ERROR, "PV not found"), ret);
}
return ret;
}
TestPV::shared_pointer
TestProvider::addPV(const std::string& name, const pvd::StructureConstPtr& tdef)
{
Guard G(lock);
TestPV::shared_pointer ret(new TestPV(name, shared_from_this(), tdef));
pvs.insert(name, ret);
return ret;
}

205
testApp/utilities.h Normal file
View File

@ -0,0 +1,205 @@
#ifndef UTILITIES_H
#define UTILITIES_H
#include <deque>
#include <epicsEvent.h>
#include <epicsUnitTest.h>
#include <pv/pvAccess.h>
#include "weakmap.h"
#include "weakset.h"
struct TestPV;
struct TestPVChannel;
struct TestPVMonitor;
struct TestProvider;
// minimally useful boilerplate which must appear *everywhere*
#define DUMBREQUESTER(NAME) \
virtual std::string getRequesterName() { return #NAME; } \
virtual void message(std::string const & message,epics::pvData::MessageType messageType) { \
testDiag("%s : " #NAME "(%p) : %s", epics::pvData::getMessageTypeName(messageType).c_str(), this, message.c_str()); \
}
struct TestChannelRequester : public epics::pvAccess::ChannelRequester
{
POINTER_DEFINITIONS(TestChannelRequester);
DUMBREQUESTER(TestChannelRequester)
epicsMutex lock;
epicsEvent wait;
epics::pvAccess::Channel::shared_pointer chan;
epics::pvData::Status status;
epics::pvAccess::Channel::ConnectionState laststate;
TestChannelRequester();
virtual ~TestChannelRequester() {}
virtual void channelCreated(const epics::pvData::Status& status, epics::pvAccess::Channel::shared_pointer const & channel);
virtual void channelStateChange(epics::pvAccess::Channel::shared_pointer const & channel, epics::pvAccess::Channel::ConnectionState connectionState);
bool waitForConnect();
};
struct TestChannelMonitorRequester : public epics::pvData::MonitorRequester
{
POINTER_DEFINITIONS(TestChannelMonitorRequester);
DUMBREQUESTER(TestChannelMonitorRequester)
epicsMutex lock;
epicsEvent wait;
bool connected;
bool unlistend;
size_t eventCnt;
epics::pvData::Status connectStatus;
epics::pvData::MonitorPtr mon;
epics::pvData::StructureConstPtr dtype;
TestChannelMonitorRequester();
virtual ~TestChannelMonitorRequester() {}
virtual void monitorConnect(epics::pvData::Status const & status,
epics::pvData::MonitorPtr const & monitor,
epics::pvData::StructureConstPtr const & structure);
virtual void monitorEvent(epics::pvData::MonitorPtr const & monitor);
virtual void unlisten(epics::pvData::MonitorPtr const & monitor);
bool waitForEvent();
};
struct TestPVChannel : public epics::pvAccess::Channel
{
POINTER_DEFINITIONS(TestPVChannel);
DUMBREQUESTER(TestPVChannel)
std::tr1::weak_ptr<TestPVChannel> weakself;
const std::tr1::shared_ptr<TestPV> pv;
std::tr1::shared_ptr<epics::pvAccess::ChannelRequester> requester;
ConnectionState state;
typedef weak_set<TestPVMonitor> monitors_t;
monitors_t monitors;
TestPVChannel(const std::tr1::shared_ptr<TestPV>& pv,
const std::tr1::shared_ptr<epics::pvAccess::ChannelRequester>& req);
virtual ~TestPVChannel();
virtual void destroy();
virtual std::tr1::shared_ptr<epics::pvAccess::ChannelProvider> getProvider();
virtual std::string getRemoteAddress() { return "localhost:1234"; }
virtual ConnectionState getConnectionState();
virtual std::string getChannelName();
virtual std::tr1::shared_ptr<epics::pvAccess::ChannelRequester> getChannelRequester()
{ return std::tr1::shared_ptr<epics::pvAccess::ChannelRequester>(requester); }
virtual bool isConnected();
virtual void getField(epics::pvAccess::GetFieldRequester::shared_pointer const & requester,std::string const & subField);
virtual epics::pvAccess::AccessRights getAccessRights(epics::pvData::PVField::shared_pointer const & pvField)
{ return epics::pvAccess::readWrite; }
virtual epics::pvAccess::ChannelProcess::shared_pointer createChannelProcess(
epics::pvAccess::ChannelProcessRequester::shared_pointer const & channelProcessRequester,
epics::pvData::PVStructure::shared_pointer const & pvRequest);
virtual epics::pvAccess::ChannelGet::shared_pointer createChannelGet(
epics::pvAccess::ChannelGetRequester::shared_pointer const & channelGetRequester,
epics::pvData::PVStructure::shared_pointer const & pvRequest);
virtual epics::pvAccess::ChannelPut::shared_pointer createChannelPut(
epics::pvAccess::ChannelPutRequester::shared_pointer const & channelPutRequester,
epics::pvData::PVStructure::shared_pointer const & pvRequest);
virtual epics::pvAccess::ChannelPutGet::shared_pointer createChannelPutGet(
epics::pvAccess::ChannelPutGetRequester::shared_pointer const & channelPutGetRequester,
epics::pvData::PVStructure::shared_pointer const & pvRequest);
virtual epics::pvAccess::ChannelRPC::shared_pointer createChannelRPC(
epics::pvAccess::ChannelRPCRequester::shared_pointer const & channelRPCRequester,
epics::pvData::PVStructure::shared_pointer const & pvRequest);
virtual epics::pvData::Monitor::shared_pointer createMonitor(
epics::pvData::MonitorRequester::shared_pointer const & monitorRequester,
epics::pvData::PVStructure::shared_pointer const & pvRequest);
virtual epics::pvAccess::ChannelArray::shared_pointer createChannelArray(
epics::pvAccess::ChannelArrayRequester::shared_pointer const & channelArrayRequester,
epics::pvData::PVStructure::shared_pointer const & pvRequest);
virtual void printInfo() {}
virtual void printInfo(std::ostream& out) {}
};
struct TestPVMonitor : public epics::pvData::Monitor
{
POINTER_DEFINITIONS(TestPVMonitor);
std::tr1::weak_ptr<TestPVMonitor> weakself;
TestPVChannel::shared_pointer channel;
epics::pvData::MonitorRequester::shared_pointer requester;
bool running;
bool finalize;
bool inoverflow;
bool needWakeup;
TestPVMonitor(const TestPVChannel::shared_pointer& ch,
const epics::pvData::MonitorRequester::shared_pointer& req,
size_t bsize);
virtual ~TestPVMonitor();
virtual void destroy();
virtual epics::pvData::Status start();
virtual epics::pvData::Status stop();
virtual epics::pvData::MonitorElementPtr poll();
virtual void release(epics::pvData::MonitorElementPtr const & monitorElement);
std::deque<epics::pvData::MonitorElementPtr> buffer, free;
epics::pvData::BitSet changedMask, overflowMask;
};
struct TestPV
{
POINTER_DEFINITIONS(TestPV);
std::tr1::weak_ptr<TestPV> weakself;
const std::string name;
std::tr1::shared_ptr<TestProvider> const provider;
epics::pvData::PVDataCreatePtr factory;
const epics::pvData::StructureConstPtr dtype;
epics::pvData::PVStructurePtr value;
TestPV(const std::string& name,
const std::tr1::shared_ptr<TestProvider>& provider,
const epics::pvData::StructureConstPtr& dtype);
void post(const epics::pvData::BitSet& changed, bool notify = true);
void disconnect();
typedef weak_set<TestPVChannel> channels_t;
channels_t channels;
friend struct TestProvider;
};
struct TestProvider : public epics::pvAccess::ChannelProvider, std::tr1::enable_shared_from_this<TestProvider>
{
POINTER_DEFINITIONS(TestProvider);
virtual std::string getProviderName() { return "TestProvider"; }
virtual void destroy();
virtual epics::pvAccess::ChannelFind::shared_pointer channelFind(std::string const & channelName,
epics::pvAccess::ChannelFindRequester::shared_pointer const & channelFindRequester);
virtual epics::pvAccess::ChannelFind::shared_pointer channelList(epics::pvAccess::ChannelListRequester::shared_pointer const & channelListRequester);
virtual epics::pvAccess::Channel::shared_pointer createChannel(std::string const & channelName,epics::pvAccess::ChannelRequester::shared_pointer const & channelRequester,
short priority = PRIORITY_DEFAULT);
virtual epics::pvAccess::Channel::shared_pointer createChannel(std::string const & channelName, epics::pvAccess::ChannelRequester::shared_pointer const & channelRequester,
short priority, std::string const & address);
TestProvider();
virtual ~TestProvider() {}
TestPV::shared_pointer addPV(const std::string& name, const epics::pvData::StructureConstPtr& tdef);
epicsMutex lock;
typedef weak_value_map<std::string, TestPV> pvs_t;
pvs_t pvs;
};
#endif // UTILITIES_H