496 lines
14 KiB
C++
496 lines
14 KiB
C++
/* pvaChannel.cpp */
|
|
/**
|
|
* Copyright - See the COPYRIGHT that is included with this distribution.
|
|
* EPICS pvData is distributed subject to a Software License Agreement found
|
|
* in file LICENSE that is included with this distribution.
|
|
*/
|
|
/**
|
|
* @author mrk
|
|
* @date 2015.02
|
|
*/
|
|
#define epicsExportSharedSymbols
|
|
|
|
#include <map>
|
|
#include <sstream>
|
|
#include <pv/event.h>
|
|
#include <pv/lock.h>
|
|
#include <pv/pva.h>
|
|
#include <pv/createRequest.h>
|
|
|
|
|
|
using std::tr1::static_pointer_cast;
|
|
using namespace epics::pvData;
|
|
using namespace epics::pvAccess;
|
|
using namespace std;
|
|
|
|
namespace epics { namespace pva {
|
|
|
|
|
|
class PvaGetCache
|
|
{
|
|
public:
|
|
PvaGetCache(){}
|
|
~PvaGetCache();
|
|
void destroy() {
|
|
pvaGetMap.clear();
|
|
}
|
|
PvaGetPtr getGet(string const & request);
|
|
void addGet(string const & request,PvaGetPtr const & pvaGet);
|
|
private:
|
|
map<string,PvaGetPtr> pvaGetMap;
|
|
};
|
|
|
|
PvaGetCache::~PvaGetCache()
|
|
{
|
|
destroy();
|
|
}
|
|
|
|
PvaGetPtr PvaGetCache::getGet(string const & request)
|
|
{
|
|
map<string,PvaGetPtr>::iterator iter = pvaGetMap.find(request);
|
|
if(iter!=pvaGetMap.end()) return iter->second;
|
|
return PvaGetPtr();
|
|
}
|
|
|
|
void PvaGetCache::addGet(string const & request,PvaGetPtr const & pvaGet)
|
|
{
|
|
pvaGetMap.insert(std::pair<string,PvaGetPtr>(
|
|
request,pvaGet));
|
|
}
|
|
|
|
|
|
class PvaPutCache
|
|
{
|
|
public:
|
|
PvaPutCache(){}
|
|
~PvaPutCache();
|
|
void destroy() {
|
|
pvaPutMap.clear();
|
|
}
|
|
PvaPutPtr getPut(string const & request);
|
|
void addPut(string const & request,PvaPutPtr const & pvaPut);
|
|
private:
|
|
map<string,PvaPutPtr> pvaPutMap;
|
|
};
|
|
|
|
PvaPutCache::~PvaPutCache()
|
|
{
|
|
destroy();
|
|
}
|
|
|
|
PvaPutPtr PvaPutCache::getPut(string const & request)
|
|
{
|
|
map<string,PvaPutPtr>::iterator iter = pvaPutMap.find(request);
|
|
if(iter!=pvaPutMap.end()) return iter->second;
|
|
return PvaPutPtr();
|
|
}
|
|
|
|
void PvaPutCache::addPut(string const & request,PvaPutPtr const & pvaPut)
|
|
{
|
|
pvaPutMap.insert(std::pair<string,PvaPutPtr>(
|
|
request,pvaPut));
|
|
}
|
|
|
|
class ChannelRequesterImpl : public ChannelRequester
|
|
{
|
|
PvaChannel *pvaChannel;
|
|
public:
|
|
ChannelRequesterImpl(PvaChannel *pvaChannel)
|
|
: pvaChannel(pvaChannel) {}
|
|
void channelCreated(
|
|
const Status& status,
|
|
Channel::shared_pointer const & channel)
|
|
{ pvaChannel->channelCreated(status,channel); }
|
|
void channelStateChange(
|
|
Channel::shared_pointer const & channel,
|
|
Channel::ConnectionState connectionState)
|
|
{pvaChannel->channelStateChange(channel,connectionState);}
|
|
tr1::shared_ptr<Channel> getChannel() {return pvaChannel->getChannel();}
|
|
string getRequesterName()
|
|
{return pvaChannel->getRequesterName();}
|
|
void message(
|
|
string const & message,
|
|
MessageType messageType)
|
|
{ pvaChannel->message(message,messageType); }
|
|
void destroy() {pvaChannel->destroy();}
|
|
};
|
|
|
|
|
|
PvaChannel::PvaChannel(
|
|
PvaPtr const &pva,
|
|
string const & channelName,
|
|
string const & providerName)
|
|
: pva(pva),
|
|
channelName(channelName),
|
|
providerName(providerName),
|
|
connectState(connectIdle),
|
|
isDestroyed(false),
|
|
createRequest(CreateRequest::create()),
|
|
pvaGetCache(new PvaGetCache()),
|
|
pvaPutCache(new PvaPutCache())
|
|
{}
|
|
|
|
PvaChannel::~PvaChannel()
|
|
{
|
|
destroy();
|
|
}
|
|
|
|
void PvaChannel::channelCreated(const Status& status, Channel::shared_pointer const & channel)
|
|
{
|
|
if(isDestroyed) throw std::runtime_error("pvaChannel was destroyed");
|
|
if(status.isOK()) {
|
|
this->channel = channel;
|
|
return;
|
|
}
|
|
cout << "PvaChannel::channelCreated status " << status.getMessage() << " why??\n";
|
|
}
|
|
|
|
void PvaChannel::channelStateChange(
|
|
Channel::shared_pointer const & channel,
|
|
Channel::ConnectionState connectionState)
|
|
{
|
|
if(isDestroyed) return;
|
|
bool waitingForConnect = false;
|
|
if(connectState==connectActive) waitingForConnect = true;
|
|
if(connectionState!=Channel::CONNECTED) {
|
|
string mess(channelName +
|
|
" connection state " + Channel::ConnectionStateNames[connectionState]);
|
|
message(mess,errorMessage);
|
|
channelConnectStatus = Status(Status::STATUSTYPE_ERROR,mess);
|
|
connectState = notConnected;
|
|
} else {
|
|
connectState = connected;
|
|
}
|
|
if(waitingForConnect) waitForConnect.signal();
|
|
}
|
|
|
|
string PvaChannel::getRequesterName()
|
|
{
|
|
PvaPtr yyy = pva.lock();
|
|
if(!yyy) throw std::runtime_error("Pva was destroyed");
|
|
return yyy->getRequesterName();
|
|
}
|
|
|
|
void PvaChannel::message(
|
|
string const & message,
|
|
MessageType messageType)
|
|
{
|
|
if(isDestroyed) throw std::runtime_error("pvaChannel was destroyed");
|
|
PvaPtr yyy = pva.lock();
|
|
if(!yyy) throw std::runtime_error("Pva was destroyed");
|
|
yyy->message(message, messageType);
|
|
}
|
|
|
|
void PvaChannel::destroy()
|
|
{
|
|
{
|
|
Lock xx(mutex);
|
|
if(isDestroyed) return;
|
|
isDestroyed = true;
|
|
}
|
|
if(channel) channel->destroy();
|
|
channel.reset();
|
|
pvaGetCache.reset();
|
|
pvaPutCache.reset();
|
|
}
|
|
|
|
string PvaChannel::getChannelName()
|
|
{
|
|
if(isDestroyed) throw std::runtime_error("pvaChannel was destroyed");
|
|
return channelName;
|
|
}
|
|
|
|
Channel::shared_pointer PvaChannel::getChannel()
|
|
{
|
|
if(isDestroyed) throw std::runtime_error("pvaChannel was destroyed");
|
|
return channel;
|
|
}
|
|
|
|
void PvaChannel::connect(double timeout)
|
|
{
|
|
if(isDestroyed) throw std::runtime_error("pvaChannel was destroyed");
|
|
issueConnect();
|
|
Status status = waitConnect(timeout);
|
|
if(status.isOK()) return;
|
|
stringstream ss;
|
|
ss << "channel " << getChannelName() << " PvaChannel::connect " << status.getMessage();
|
|
throw std::runtime_error(ss.str());
|
|
}
|
|
|
|
void PvaChannel::issueConnect()
|
|
{
|
|
if(isDestroyed) throw std::runtime_error("pvaChannel was destroyed");
|
|
if(connectState!=connectIdle) {
|
|
throw std::runtime_error("pvaChannel already connected");
|
|
}
|
|
channelRequester = ChannelRequester::shared_pointer(new ChannelRequesterImpl(this));
|
|
|
|
channelConnectStatus = Status(
|
|
Status::STATUSTYPE_ERROR,
|
|
getChannelName() + " createChannel failed");
|
|
connectState = connectActive;
|
|
ChannelProviderRegistry::shared_pointer reg = getChannelProviderRegistry();
|
|
ChannelProvider::shared_pointer provider = reg->getProvider(providerName);
|
|
if(!provider) {
|
|
throw std::runtime_error(getChannelName() + " provider " + providerName + " not registered");
|
|
}
|
|
channel = provider->createChannel(channelName,channelRequester,ChannelProvider::PRIORITY_DEFAULT);
|
|
if(!channel) {
|
|
throw std::runtime_error(channelConnectStatus.getMessage());
|
|
}
|
|
}
|
|
|
|
Status PvaChannel::waitConnect(double timeout)
|
|
{
|
|
if(isDestroyed) throw std::runtime_error("pvaChannel was destroyed");
|
|
waitForConnect.wait(timeout);
|
|
if(connectState==connected) return Status::Ok;
|
|
return Status(Status::STATUSTYPE_ERROR,channelConnectStatus.getMessage());
|
|
}
|
|
|
|
PvaFieldPtr PvaChannel::createField()
|
|
{
|
|
return createField("");
|
|
}
|
|
|
|
PvaFieldPtr PvaChannel::createField(string const & subField)
|
|
{
|
|
throw std::runtime_error("PvaChannel::createField not implemented");
|
|
}
|
|
|
|
PvaProcessPtr PvaChannel::createProcess()
|
|
{
|
|
return createProcess("");
|
|
}
|
|
|
|
PvaProcessPtr PvaChannel::createProcess(string const & request)
|
|
{
|
|
PVStructurePtr pvRequest = createRequest->createRequest(request);
|
|
if(!pvRequest) {
|
|
stringstream ss;
|
|
ss << "channel " << getChannelName();
|
|
ss << " PvaChannel::createProcess invalid pvRequest: " + createRequest->getMessage();
|
|
throw std::runtime_error(ss.str());
|
|
}
|
|
return createProcess(pvRequest);
|
|
}
|
|
|
|
PvaProcessPtr PvaChannel::createProcess(PVStructurePtr const & pvRequest)
|
|
{
|
|
if(connectState!=connected) connect(5.0);
|
|
if(connectState!=connected) throw std::runtime_error("PvaChannel::creatProcess not connected");
|
|
PvaPtr yyy = pva.lock();
|
|
if(!yyy) throw std::runtime_error("Pva was destroyed");
|
|
return PvaProcess::create(yyy,getPtrSelf(),channel,pvRequest);
|
|
}
|
|
|
|
PvaGetPtr PvaChannel::get() {return get("value,alarm,timeStamp");}
|
|
|
|
PvaGetPtr PvaChannel::get(string const & request)
|
|
{
|
|
PvaGetPtr pvaGet = pvaGetCache->getGet(request);
|
|
if(pvaGet) return pvaGet;
|
|
pvaGet = createGet(request);
|
|
pvaGet->connect();
|
|
pvaGetCache->addGet(request,pvaGet);
|
|
return pvaGet;
|
|
}
|
|
|
|
PvaGetPtr PvaChannel::createGet()
|
|
{
|
|
return PvaChannel::createGet("value,alarm,timeStamp");
|
|
}
|
|
|
|
PvaGetPtr PvaChannel::createGet(string const & request)
|
|
{
|
|
PVStructurePtr pvRequest = createRequest->createRequest(request);
|
|
if(!pvRequest) {
|
|
stringstream ss;
|
|
ss << "channel " << getChannelName();
|
|
ss << " PvaChannel::createGet invalid pvRequest: " + createRequest->getMessage();
|
|
throw std::runtime_error(ss.str());
|
|
}
|
|
return createGet(pvRequest);
|
|
}
|
|
|
|
PvaGetPtr PvaChannel::createGet(PVStructurePtr const & pvRequest)
|
|
{
|
|
if(connectState!=connected) connect(5.0);
|
|
if(connectState!=connected) throw std::runtime_error("PvaChannel::creatGet not connected");
|
|
PvaPtr yyy = pva.lock();
|
|
if(!yyy) throw std::runtime_error("Pva was destroyed");
|
|
return PvaGet::create(yyy,getPtrSelf(),channel,pvRequest);
|
|
}
|
|
|
|
PvaPutPtr PvaChannel::put() {return put("value");}
|
|
|
|
PvaPutPtr PvaChannel::put(string const & request)
|
|
{
|
|
PvaPutPtr pvaPut = pvaPutCache->getPut(request);
|
|
if(pvaPut) return pvaPut;
|
|
pvaPut = createPut(request);
|
|
pvaPut->connect();
|
|
pvaPut->get();
|
|
pvaPutCache->addPut(request,pvaPut);
|
|
return pvaPut;
|
|
}
|
|
|
|
PvaPutPtr PvaChannel::createPut()
|
|
{
|
|
return createPut("value");
|
|
}
|
|
|
|
PvaPutPtr PvaChannel::createPut(string const & request)
|
|
{
|
|
PVStructurePtr pvRequest = createRequest->createRequest(request);
|
|
if(!pvRequest) {
|
|
stringstream ss;
|
|
ss << "channel " << getChannelName();
|
|
ss << " PvaChannel::createPut invalid pvRequest: " + createRequest->getMessage();
|
|
throw std::runtime_error(ss.str());
|
|
}
|
|
return createPut(pvRequest);
|
|
}
|
|
|
|
PvaPutPtr PvaChannel::createPut(PVStructurePtr const & pvRequest)
|
|
{
|
|
if(connectState!=connected) connect(5.0);
|
|
if(connectState!=connected) throw std::runtime_error("PvaChannel::creatPut not connected");
|
|
PvaPtr yyy = pva.lock();
|
|
if(!yyy) throw std::runtime_error("Pva was destroyed");
|
|
return PvaPut::create(yyy,getPtrSelf(),channel,pvRequest);
|
|
}
|
|
|
|
PvaPutGetPtr PvaChannel::createPutGet()
|
|
{
|
|
return createPutGet("putField(argument)getField(result)");
|
|
}
|
|
|
|
PvaPutGetPtr PvaChannel::createPutGet(string const & request)
|
|
{
|
|
PVStructurePtr pvRequest = createRequest->createRequest(request);
|
|
if(!pvRequest) {
|
|
stringstream ss;
|
|
ss << "channel " << getChannelName();
|
|
ss << " PvaChannel::createPutGet invalid pvRequest: " + createRequest->getMessage();
|
|
throw std::runtime_error(ss.str());
|
|
}
|
|
return createPutGet(pvRequest);
|
|
}
|
|
|
|
PvaPutGetPtr PvaChannel::createPutGet(PVStructurePtr const & pvRequest)
|
|
{
|
|
if(connectState!=connected) connect(5.0);
|
|
if(connectState!=connected) throw std::runtime_error("PvaChannel::creatPutGet not connected");
|
|
PvaPtr yyy = pva.lock();
|
|
if(!yyy) throw std::runtime_error("Pva was destroyed");
|
|
return PvaPutGet::create(yyy,getPtrSelf(),channel,pvRequest);
|
|
}
|
|
|
|
PvaRPCPtr PvaChannel::createRPC()
|
|
{
|
|
return createRPC("");
|
|
}
|
|
|
|
PvaRPCPtr PvaChannel::createRPC(string const & request)
|
|
{
|
|
PVStructurePtr pvRequest = createRequest->createRequest(request);
|
|
if(!pvRequest) {
|
|
stringstream ss;
|
|
ss << "channel " << getChannelName();
|
|
ss << " PvaChannel::createRPC invalid pvRequest: " + createRequest->getMessage();
|
|
throw std::runtime_error(ss.str());
|
|
}
|
|
return createRPC(pvRequest);
|
|
}
|
|
|
|
PvaRPCPtr PvaChannel::createRPC(PVStructurePtr const & pvRequest)
|
|
{
|
|
throw std::runtime_error("PvaChannel::createRPC not implemented");
|
|
}
|
|
|
|
PvaArrayPtr PvaChannel::createArray()
|
|
{
|
|
return createArray("value");
|
|
}
|
|
|
|
PvaArrayPtr PvaChannel::createArray(string const & request)
|
|
{
|
|
PVStructurePtr pvRequest = createRequest->createRequest(request);
|
|
if(!pvRequest) {
|
|
stringstream ss;
|
|
ss << "channel " << getChannelName();
|
|
ss << " PvaChannel::createArray invalid pvRequest: " + createRequest->getMessage();
|
|
throw std::runtime_error(ss.str());
|
|
}
|
|
return createArray(pvRequest);
|
|
}
|
|
|
|
PvaArrayPtr PvaChannel::createArray(PVStructurePtr const & pvRequest)
|
|
{
|
|
throw std::runtime_error("PvaChannel::createArray not implemented");
|
|
}
|
|
|
|
|
|
PvaMonitorPtr PvaChannel::monitor() {return monitor("value,alarm,timeStamp");}
|
|
|
|
PvaMonitorPtr PvaChannel::monitor(string const & request)
|
|
{
|
|
PvaMonitorPtr pvaMonitor = createMonitor(request);
|
|
pvaMonitor->connect();
|
|
pvaMonitor->start();
|
|
return pvaMonitor;
|
|
}
|
|
|
|
PvaMonitorPtr PvaChannel::monitor(PvaMonitorRequesterPtr const & pvaMonitorRequester)
|
|
{ return monitor("value,alarm,timeStamp",pvaMonitorRequester);
|
|
}
|
|
|
|
PvaMonitorPtr PvaChannel::monitor(string const & request,
|
|
PvaMonitorRequesterPtr const & pvaMonitorRequester)
|
|
{
|
|
PvaMonitorPtr pvaMonitor = createMonitor(request);
|
|
pvaMonitor->connect();
|
|
pvaMonitor->setRequester(pvaMonitorRequester);
|
|
pvaMonitor->start();
|
|
return pvaMonitor;
|
|
}
|
|
|
|
PvaMonitorPtr PvaChannel::createMonitor()
|
|
{
|
|
return createMonitor("value,alarm,timeStamp");
|
|
}
|
|
|
|
PvaMonitorPtr PvaChannel::createMonitor(string const & request)
|
|
{
|
|
PVStructurePtr pvRequest = createRequest->createRequest(request);
|
|
if(!pvRequest) {
|
|
stringstream ss;
|
|
ss << "channel " << getChannelName();
|
|
ss << " PvaChannel::createMonitor invalid pvRequest: " + createRequest->getMessage();
|
|
throw std::runtime_error(ss.str());
|
|
}
|
|
return createMonitor(pvRequest);
|
|
}
|
|
|
|
PvaMonitorPtr PvaChannel::createMonitor(PVStructurePtr const & pvRequest)
|
|
{
|
|
if(connectState!=connected) connect(5.0);
|
|
if(connectState!=connected) throw std::runtime_error("PvaChannel::createMonitor not connected");
|
|
PvaPtr yyy = pva.lock();
|
|
if(!yyy) throw std::runtime_error("Pva was destroyed");
|
|
return PvaMonitor::create(yyy,getPtrSelf(),channel,pvRequest);
|
|
}
|
|
|
|
|
|
PvaChannelPtr PvaChannel::create(
|
|
PvaPtr const &pva,
|
|
string const & channelName,
|
|
string const & providerName)
|
|
{
|
|
PvaChannelPtr channel(new PvaChannel(pva,channelName,providerName));
|
|
return channel;
|
|
}
|
|
|
|
}}
|