more work on EasyGet and conneection management; still work in progress

This commit is contained in:
Marty Kraimer
2015-03-02 15:09:24 -05:00
parent f677e1a091
commit be69a74094
6 changed files with 175 additions and 134 deletions

View File

@@ -28,7 +28,7 @@
<h1>EPICS easyPVA</h1>
<!-- Maturity: Working Draft or Request for Comments, or Recommendation, and date. -->
<h2 class="nocount">EPICS V4 Working Group, Working Draft,
19-Feb-2015</h2>
02-Mar-2015</h2>
<dl>
<dt>This version:</dt>
<dd><a
@@ -104,20 +104,20 @@ an interface to many of the features provided by pvData and pvAccess.</p>
<li>Allows efficient client side programs.</li>
</ol>
<p>The following describes the CPP version of EasyPVA.</p>
<p>This is the overview for EasyPVACPP. JavaDoc documentation is available at <a
<p>This document briefly describes the CPP version of EasyPVA.
Doxygen documentation is available at <a
href="./html/index.html">doxygenDoc</a></p>
<h3>Initialization</h3>
<p>A client obtains the interface to EasyPVA via the call:</p>
<pre>EasyPVA easy = EasyPVAFactory.get();</pre>
<pre>EasyPVAPtr easyPVA = EasyPVAFactorys-&gt;create();</pre>
<p>The client can make this call many times, but an instance of the EastPVA interface object is
only created in the first call. This first call also
starts the PVAccess client factory.</p>
<p>The client can call this an arbitrary number of times.
On the first call the PVAccess client factory is started.
When the last EasyPVA is destroyed the PVAccess client factory is stopped.
</p>
<h3>EasyPVA Overview</h3>
@@ -139,13 +139,6 @@ starts the PVAccess client factory.</p>
</dd>
</dl>
<p>There are additional methods that allows the client to:</p>
<ol>
<li>Control how error messages are handled.</li>
<li>Control when get/put commands are sent the channel or channels.</li>
</ol>
<h3>EasyChannel Overview</h3>
<p>This interface creates Easy support for each PVAccess::Channel create
@@ -208,15 +201,17 @@ The only requirement of the channels is that each must have a top level field na
</dd>
</dl>
<h2>shell</h2>
<p>Directory <b>shell</b> has the following files:</p>
<dl>
<dt>exampleDatabaseEasyPVA.zip</dt>
<dd>
When unzipped this is used to create an example IOC database.
The database has the record used by the examples are tests that come with easyPVAJava.
It uses pvDatabaseCPP to build the database.
After unzipping the file:
<h2>example source code</h2>
<h3>Example Database</h3>
<p>The examples require that an example pvAccess server is runnimg.
This distribution has a file <b>exampleDatabaseEasyPVA.zip</b>.
When unzipped this is used to create an example IOC database.
The database has the record used by the examples are tests that come with easyPVAJava.
It uses pvDatabaseCPP to build the database.
</p>
<p>
After unzipping the file:
</p>
<pre>
cd configure
cp ExampleRELEASE.local RELEASE.local
@@ -226,68 +221,16 @@ make
cd iocBoot/exampleDatabase
../../bin/&lt;arch:&gt;/exampleDatabase st.cmd
</pre>
You now have a running database.
</dd>
<dt>source</dt>
<dd>
This file creates the <b>CLASSPATH</b> required
to run the examples and tests.
You have to edit it for your environment.
</dd>
<dt>rpcServiceExample</dt>
<dd>
This starts the RPCServiceExample.
This is required by ExampleEasyRPC.
</dd>
<dt>exampleGet</dt>
<dd>
This runs ExampleGet.
</dd>
<dt>exampleGetDouble</dt>
<dd>
This runs ExampleGetDouble
</dd>
<dt>doublePut</dt>
<dd>
This runs DoublePut.
</dd>
<dt>doubleArrayPut</dt>
<dd>
This runs DoubleArrayPut
</dd>
<dt>exampleMonitor</dt>
<dd>
This runs ExampleMonitor
</dd>
<dt>exampleMonitorCallback</dt>
<dd>
This runs ExampleMonitorCallback
</dd>
<dt>exampleMultiMonitor</dt>
<dd>
This runs ExampleMultiMonitor.
It and polls every few seconds for monitor events.
It gets data as NTMultiChannel.
</dd>
<dt>exampleMultiMonitorDouble</dt>
<dd>
This runs ExampleMultiMonitorDouble.
It has an event listener for new events.
It gets data as an array of doubles.
</dd>
</dl>
<h3>Examples</h3>
<p>These are examples in package <b>org.epics.pvaccess.easyPVA.example</b>
<p>These are examples in directory <b>example/src</b>.
An example of how to run them is:</p>
<pre>
mrk&gt; pwd
/home/hg/easyPVACPP/example
mrk&gt; bin/linux-x86_64/exampleEasyGet
</pre>
<p>
See the source code for each example.
In order to run the examples exampleDatabaseEasyPVA must be running.
</p>
<p>There is a shell command to run each example,</p>
<h3>Tests</h3>
<p>A test directory has a number of tests for easyPVAJava.
In order to run the tests both exampleDatabaseEasyPVA and rpcServiceExample
must be running.
For now these tests are being run as eclipse unit tests.
The tests also provide examples of using EasyPVA.
</p>
</div> <!-- class="contents" -->

View File

@@ -13,18 +13,17 @@
#include <iostream>
#include <pv/easyPVA.h>
#include <pv/clientFactory.h>
using namespace std;
using namespace epics::pvData;
using namespace epics::pvAccess;
using namespace epics::easyPVA;
int main(int argc,char *argv[])
{
ClientFactory::start();
EasyPVAPtr easyPVA = EasyPVA::create();
static EasyPVAPtr easyPVA;
static void exampleDouble()
{
cout << "example double scalar\n";
double value;
try {
cout << "short way\n";
@@ -43,7 +42,52 @@ int main(int argc,char *argv[])
} catch (std::runtime_error e) {
cout << "exception " << e.what() << endl;
}
}
static void exampleDoubleArray()
{
cout << "example double array\n";
shared_vector<double> value;
try {
cout << "short way\n";
value = easyPVA->createChannel("exampleDoubleArray")->createGet()->getDoubleArray();
cout << "as doubleArray " << value << endl;
} catch (std::runtime_error e) {
cout << "exception " << e.what() << endl;
}
try {
cout << "long way\n";
EasyChannelPtr easyChannel = easyPVA->createChannel("exampleDoubleArray");
easyChannel->connect(2.0);
EasyGetPtr easyGet = easyChannel->createGet();
value = easyGet->getDoubleArray();
cout << "as doubleArray " << value << endl;
} catch (std::runtime_error e) {
cout << "exception " << e.what() << endl;
}
}
static void examplePowerSupply()
{
cout << "example powerSupply\n";
PVStructurePtr pvStructure;
try {
cout << "short way\n";
pvStructure = easyPVA->createChannel("examplePowerSupply")->createGet("field()")->getPVStructure();
cout << pvStructure << endl;
} catch (std::runtime_error e) {
cout << "exception " << e.what() << endl;
}
}
int main(int argc,char *argv[])
{
easyPVA = EasyPVA::create();
exampleDouble();
exampleDoubleArray();
examplePowerSupply();
cout << "done\n";
ClientFactory::stop();
easyPVA->destroy();
return 0;
}

BIN
exampleDatabaseEasyPVA.zip Normal file

Binary file not shown.

View File

@@ -143,19 +143,23 @@ EasyChannelImpl::~EasyChannelImpl()
void EasyChannelImpl::channelCreated(const Status& status, Channel::shared_pointer const & channel)
{
if(isDestroyed) throw std::runtime_error("easyChannel was destroyed");
channelConnectStatus = status;
this->channel = channel;
if(status.isOK()) {
this->channel = channel;
return;
}
cout << "EasyChannelImpl::channelCreated status " << status.getMessage() << " why??\n";
}
void EasyChannelImpl::channelStateChange(
Channel::shared_pointer const & channel,
Channel::ConnectionState connectionState)
{
if(isDestroyed) throw std::runtime_error("easyChannel was destroyed");
if(isDestroyed) return;
bool waitingForConnect = false;
if(connectState==connectActive) waitingForConnect = true;
if(connectionState!=Channel::CONNECTED) {
string mess(channelName + " connection state " + Channel::ConnectionStateNames[connectionState]);
string mess(channelName +
" connection state " + Channel::ConnectionStateNames[connectionState]);
message(mess,errorMessage);
channelConnectStatus = Status(Status::STATUSTYPE_ERROR,mess);
connectState = notConnected;
@@ -220,10 +224,14 @@ void EasyChannelImpl::issueConnect()
}
channelRequester = ChannelRequester::shared_pointer(new ChannelRequesterImpl(this));
channelConnectStatus = Status(Status::STATUSTYPE_ERROR,"createChannel failed");
connectState = connectActive;
ChannelProviderRegistry::shared_pointer reg = getChannelProviderRegistry();
ChannelProvider::shared_pointer provider = reg->getProvider(providerName);
channel = provider->createChannel(channelName,channelRequester,ChannelProvider::PRIORITY_DEFAULT);
if(!channel) {
throw std::runtime_error(channelConnectStatus.getMessage());
}
}
Status EasyChannelImpl::waitConnect(double timeout)
@@ -268,7 +276,7 @@ EasyProcessPtr EasyChannelImpl::createProcess(PVStructurePtr const & pvRequest)
EasyGetPtr EasyChannelImpl::createGet()
{
return EasyChannelImpl::createGet("value,alarm.timeStamp");
return EasyChannelImpl::createGet("value,alarm,timeStamp");
}
EasyGetPtr EasyChannelImpl::createGet(string const & request)

View File

@@ -101,6 +101,7 @@ public:
return shared_from_this();
}
private:
void checkGetState();
enum GetConnectState {connectIdle,connectActive,connected};
EasyPVAPtr easyPVA;
@@ -176,6 +177,12 @@ EasyGetImpl::~EasyGetImpl()
destroy();
}
void EasyGetImpl::checkGetState()
{
if(isDestroyed) throw std::runtime_error("easyGet was destroyed");
if(connectState==connectIdle) connect();
if(getState==getIdle) get();
}
// from ChannelGetRequester
string EasyGetImpl::getRequesterName()
@@ -257,7 +264,6 @@ void EasyGetImpl::issueConnect()
throw std::runtime_error(ss.str());
}
getRequester = ChannelGetRequester::shared_pointer(new ChannelGetRequesterImpl(this));
connectState = connectActive;
channelGet = channel->createChannelGet(getRequester,pvRequest);
}
@@ -335,206 +341,206 @@ void EasyGetImpl::setPVStructure(epics::pvData::PVStructurePtr const & pvStructu
Alarm EasyGetImpl::getAlarm()
{
if(isDestroyed) throw std::runtime_error("easyGet was destroyed");
checkGetState();
return easyPVStructure->getAlarm();
}
TimeStamp EasyGetImpl::getTimeStamp()
{
if(isDestroyed) throw std::runtime_error("easyGet was destroyed");
checkGetState();
return easyPVStructure->getTimeStamp();
}
bool EasyGetImpl::hasValue()
{
if(isDestroyed) throw std::runtime_error("easyGet was destroyed");
checkGetState();
return easyPVStructure->hasValue();
}
bool EasyGetImpl::isValueScalar()
{
if(isDestroyed) throw std::runtime_error("easyGet was destroyed");
checkGetState();
return easyPVStructure->isValueScalar();
}
bool EasyGetImpl::isValueScalarArray()
{
if(isDestroyed) throw std::runtime_error("easyGet was destroyed");
checkGetState();
return easyPVStructure->isValueScalarArray();
}
PVFieldPtr EasyGetImpl::getValue()
{
if(isDestroyed) throw std::runtime_error("easyGet was destroyed");
checkGetState();
return easyPVStructure->getValue();
}
PVScalarPtr EasyGetImpl::getScalarValue()
{
if(isDestroyed) throw std::runtime_error("easyGet was destroyed");
checkGetState();
return easyPVStructure->getScalarValue();
}
std::tr1::shared_ptr<PVArray> EasyGetImpl::getArrayValue()
{
if(isDestroyed) throw std::runtime_error("easyGet was destroyed");
checkGetState();
return easyPVStructure->getArrayValue();
}
std::tr1::shared_ptr<PVScalarArray> EasyGetImpl::getScalarArrayValue()
{
if(isDestroyed) throw std::runtime_error("easyGet was destroyed");
checkGetState();
return easyPVStructure->getScalarArrayValue();
}
bool EasyGetImpl::getBoolean()
{
if(isDestroyed) throw std::runtime_error("easyGet was destroyed");
checkGetState();
return easyPVStructure->getBoolean();
}
int8 EasyGetImpl::getByte()
{
if(isDestroyed) throw std::runtime_error("easyGet was destroyed");
checkGetState();
return easyPVStructure->getByte();
}
int16 EasyGetImpl::getShort()
{
if(isDestroyed) throw std::runtime_error("easyGet was destroyed");
checkGetState();
return easyPVStructure->getShort();
}
int32 EasyGetImpl::getInt()
{
if(isDestroyed) throw std::runtime_error("easyGet was destroyed");
checkGetState();
return easyPVStructure->getInt();
}
int64 EasyGetImpl::getLong()
{
if(isDestroyed) throw std::runtime_error("easyGet was destroyed");
checkGetState();
return easyPVStructure->getLong();
}
uint8 EasyGetImpl::getUByte()
{
if(isDestroyed) throw std::runtime_error("easyGet was destroyed");
checkGetState();
return easyPVStructure->getUByte();
}
uint16 EasyGetImpl::getUShort()
{
if(isDestroyed) throw std::runtime_error("easyGet was destroyed");
checkGetState();
return easyPVStructure->getUShort();
}
uint32 EasyGetImpl::getUInt()
{
if(isDestroyed) throw std::runtime_error("easyGet was destroyed");
checkGetState();
return easyPVStructure->getUInt();
}
uint64 EasyGetImpl::getULong()
{
if(isDestroyed) throw std::runtime_error("easyGet was destroyed");
checkGetState();
return easyPVStructure->getULong();
}
float EasyGetImpl::getFloat()
{
if(isDestroyed) throw std::runtime_error("easyGet was destroyed");
checkGetState();
return easyPVStructure->getFloat();
}
double EasyGetImpl::getDouble()
{
if(isDestroyed) throw std::runtime_error("easyGet was destroyed");
return easyPVStructure->isValueScalar();
checkGetState();
return easyPVStructure->getDouble();
}
std::string EasyGetImpl::getString()
{
if(isDestroyed) throw std::runtime_error("easyGet was destroyed");
checkGetState();
return easyPVStructure->getString();
}
shared_vector<boolean> EasyGetImpl::getBooleanArray()
{
if(isDestroyed) throw std::runtime_error("easyGet was destroyed");
checkGetState();
return easyPVStructure->getBooleanArray();
}
shared_vector<int8> EasyGetImpl::getByteArray()
{
if(isDestroyed) throw std::runtime_error("easyGet was destroyed");
checkGetState();
return easyPVStructure->getByteArray();
}
shared_vector<int16> EasyGetImpl::getShortArray()
{
if(isDestroyed) throw std::runtime_error("easyGet was destroyed");
checkGetState();
return easyPVStructure->getShortArray();
}
shared_vector<int32> EasyGetImpl::getIntArray()
{
if(isDestroyed) throw std::runtime_error("easyGet was destroyed");
checkGetState();
return easyPVStructure->getIntArray();
}
shared_vector<int64> EasyGetImpl::getLongArray()
{
if(isDestroyed) throw std::runtime_error("easyGet was destroyed");
checkGetState();
return easyPVStructure->getLongArray();
}
shared_vector<uint8> EasyGetImpl::getUByteArray()
{
if(isDestroyed) throw std::runtime_error("easyGet was destroyed");
checkGetState();
return easyPVStructure->getUByteArray();
}
shared_vector<uint16> EasyGetImpl::getUShortArray()
{
if(isDestroyed) throw std::runtime_error("easyGet was destroyed");
checkGetState();
return easyPVStructure->getUShortArray();
}
shared_vector<uint32> EasyGetImpl::getUIntArray()
{
if(isDestroyed) throw std::runtime_error("easyGet was destroyed");
checkGetState();
return easyPVStructure->getUIntArray();
}
shared_vector<uint64> EasyGetImpl::getULongArray()
{
if(isDestroyed) throw std::runtime_error("easyGet was destroyed");
checkGetState();
return easyPVStructure->getULongArray();
}
shared_vector<float> EasyGetImpl::getFloatArray()
{
if(isDestroyed) throw std::runtime_error("easyGet was destroyed");
checkGetState();
return easyPVStructure->getFloatArray();
}
shared_vector<double> EasyGetImpl::getDoubleArray()
{
if(isDestroyed) throw std::runtime_error("easyGet was destroyed");
checkGetState();
return easyPVStructure->getDoubleArray();
}
shared_vector<std::string> EasyGetImpl::getStringArray()
{
if(isDestroyed) throw std::runtime_error("easyGet was destroyed");
checkGetState();
return easyPVStructure->getStringArray();
}
PVStructurePtr EasyGetImpl::getPVStructure()
{
if(isDestroyed) throw std::runtime_error("easyGet was destroyed");
checkGetState();
return easyPVStructure->getPVStructure();
}

View File

@@ -11,6 +11,7 @@
#define epicsExportSharedSymbols
#include <pv/easyPVA.h>
#include <pv/createRequest.h>
#include <pv/clientFactory.h>
using std::tr1::static_pointer_cast;
using namespace epics::pvData;
@@ -24,9 +25,46 @@ static const string easyPVAName = "easyPVA";
static const string defaultProvider = "pva";
static UnionConstPtr variantUnion = fieldCreate->createVariantUnion();
namespace easyPVAPvt {
static size_t numberEasyPVA = 0;
static bool firstTime = true;
static Mutex mutex;
class StartStopClientFactory {
public:
static void EasyPVABeingConstructed()
{
bool saveFirst = false;
{
Lock xx(mutex);
++numberEasyPVA;
saveFirst = firstTime;
firstTime = false;
}
if(saveFirst) ClientFactory::start();
}
static void EasyPVABeingDestroyed() {
size_t numLeft = 0;
{
Lock xx(mutex);
--numberEasyPVA;
numLeft = numberEasyPVA;
}
if(numLeft<=0) ClientFactory::stop();
}
};
}
using namespace epics::easyPVA::easyPVAPvt;
EasyPVAPtr EasyPVA::create()
{
EasyPVAPtr xx(new EasyPVA());
StartStopClientFactory::EasyPVABeingConstructed();
return xx;
}
@@ -45,7 +83,9 @@ EasyPVA::EasyPVA()
{
}
EasyPVA::~EasyPVA() {destroy();}
EasyPVA::~EasyPVA() {
destroy();
}
void EasyPVA::destroy()
{
@@ -61,8 +101,8 @@ void EasyPVA::destroy()
channelList.erase(channelIter);
(*channelIter)->destroy();
}
std::list<EasyMultiChannelPtr>::iterator multiChannelIter;
#ifdef NOTDONE
std::list<EasyMultiChannelPtr>::iterator multiChannelIter;
while(true) {
multiChannelIter = multiChannelList.begin();
if(multiChannelIter==multiChannelList.end()) break;
@@ -70,7 +110,7 @@ void EasyPVA::destroy()
(*multiChannelIter)->destroy();
}
#endif
StartStopClientFactory::EasyPVABeingDestroyed();
}
string EasyPVA:: getRequesterName()