all EasyChannel methods are implemented except channelArray; EasyMultiChannel not started.

This commit is contained in:
Marty Kraimer
2015-03-13 15:09:55 -04:00
parent 5dc5e746f4
commit cdc72bc5ae
32 changed files with 4366 additions and 1747 deletions
+35 -157
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,
02-Mar-2015</h2>
13-Mar-2015</h2>
<dl>
<dt>This version:</dt>
<dd><a
@@ -68,8 +68,6 @@ The first is as an NTMultiChannel. The second is as a double array.
The double array can be used if the value field of every channel is a numeric scalar.
There is code for NTMultiChannel that helps with access to more complicated data types.
</p>
<p>EasyPVA will become part of pvAccess when it is ready. </p>
<!-- last para of Abstract is boilerplate reference to EPICS -->
<p>For more information about EPICS generally, please refer to the home page of the <a
href="http://www.aps.anl.gov/epics/">Experimental Physics and Industrial
@@ -96,159 +94,35 @@ There is code for NTMultiChannel that helps with access to more complicated data
<p>EasyPVA is a synchronous API for accessing PVData via PVAccess. It provides
an interface to many of the features provided by pvData and pvAccess.</p>
<p>The EasyPVA API has the following features:</p>
<ol>
<li>Makes common requests easy to program</li>
<li>Provides full access to the pvAccess API for more demanding
applications</li>
<li>Allows efficient client side programs.</li>
</ol>
<p>This document briefly describes the CPP version of EasyPVA.
Doxygen documentation is available at <a
href="./html/index.html">doxygenDoc</a></p>
<h3>EasyPVA Interfaces</h3>
<h4>Simple</h4>
<p>The following</p>
<pre>
EasyPVAPtr easyPVA = EasyPVA::create();
double value = easyPVA-&gt;channel("exampleDouble")-&gt;get()-&gt;getDouble();
cout &lt;&lt; "as double " &lt;&lt; value &lt;&lt; endl;
</pre>
produces:
<pre>
as double 5
</pre>
<p>This is an example of the simplest way to use EasyPVA.
An important feature is that,
when the simple interface is used,
EasyPva caches Channels, ChannelGets, etc.
This if the above code is replaced by:</p>
<pre>
EasyPVAPtr easyPVA = EasyPVA::create();
double value = easyPVA-&gt;channel("exampleDouble")-&gt;get()-&gt;getDouble();
cout &lt;&lt; "as double " &lt;&lt; value &lt;&lt; endl;
value = easyPVA-&gt;channel("exampleDouble")-&gt;get()-&gt;getDouble();
cout &lt;&lt; "as double " &lt;&lt; value &lt;&lt; endl;
</pre>
The second call will reuse the channel and channelGet created by the first call.
<p>But if any problems occur using the simple interface an exception is thrown.</p>
<h4>More Complex But No Exceptions.</h4>
<p>The following</p>
<pre>
EasyPVAPtr easyPVA = EasyPVA::create();
EasyChannelPtr easyChannel = easyPVA-&gt;createChannel("exampleDouble");
easyChannel-&gt;issueConnect();
Status status = easyChannel-&gt;waitConnect(2.0);
if(!status.isOK()) {cout &lt;&lt; " connect failed\n"; return;}
EasyGetPtr easyGet = easyChannel-&gt;createGet();
easyGet-&gt;issueConnect();
status = easyGet-&gt;waitConnect();
if(!status.isOK()) {cout &lt;&lt; " createGet failed\n"; return;}
value = easyGet-&gt;getDouble();
cout &lt;&lt; "as double " &lt;&lt; value &lt;&lt; endl;
</pre>
also produces:
<pre>
as double 5
</pre>
<p>The main feature of this over the simple way is that no exceptions will be thrown.</p>
<h3>Initialization</h3>
<p>A client obtains the interface to EasyPVA via the call:</p>
<pre>EasyPVAPtr easyPVA = EasyPVAFactorys-&gt;create();</pre>
<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>This document describes the layout of the source files in this project.</p>
<p>
A user overview is available via
<a
href="./overiew.html">overview.html
</a>
</p>
<h3>EasyPVA Overview</h3>
<p>EasyPVA creates interfaces to one of the following:</p>
<dl>
<dt>EasyChannel</dt>
<dd>This creates an interface for accessing a single channel.<br />
There are two methods for creating an EasyChannel,
with the difference being that the second
specifiers the name of the provider.
The other assumes that the provider is "pva" (pvAccess).
</dd>
<dt>EasyMultiChannel</dt>
<dd>This creates an interface for accessing a set of channels.<br />
There are multiple methods for creating an EasyMultiChannel.
The provider can be supplied or use a default of "pva".
A union for the UnionArray for accessing the value fields of each channel
can be provided or a default of variant union will be used.
</dd>
</dl>
<h3>EasyChannel Overview</h3>
<p>This interface creates Easy support for each PVAccess::Channel create
method:</p>
<dl>
<dt>EasyField</dt>
<dd>This gets the introspection interface from a channel. The
implementation provides full access to the features of
Channel::getField.</dd>
<dt>EasyProcess</dt>
<dd>This is used to process a channel. The implementation provides full
access to the features of ChannelProcess.</dd>
<dt>EasyGet</dt>
<dd>This is used to get values from a channel. The implementation allows
full access to all the features of ChannelGet. By default it asks for the
fields value, alarm, and timeStamp. If the channel has a value field then
EasyGet provides convenience methods for a scalar value and for an array
value. </dd>
<dt>EasyPut</dt>
<dd>This is used to get the current value of a channel and to put values to
a channel. The implementation allows full access to all the features of
ChannelPut. By default it asks for the field value, alarm, and timeStamp.
If the channel has a value field then EasyPut provides convenience
methods for a scalar value and for an array value. </dd>
<dt>EasyRPC</dt>
<dd>This is an interface to ChannelRPC.
The implementation allows full access to all the features of ChannelRPC.
</dd>
<dt>EasyPutGet</dt>
<dd>This is an interface to ChannelPutGet. Details TBD.</dd>
<dt>EasyMonitor</dt>
<dd>This is an interface to Monitor.
The implementation allows full access to all the features of pvAccess Monitor.
</dd>
<dt>EasyArray</dt>
<dd>This is an interface to ChannelArray. Details TBD.</dd>
<dt>EasyProcess</dt>
<dd>This is an interface to ChannelProcess. Details TBD.</dd>
</dl>
<h3>EasyMultiChannel Overview</h3>
<p>This interface creates Easy support for accessing a set of channels.
The only requirement of the channels is that each must have a top level field named value.
<p>
Doxygen documentation is available at
<a
href="./html/index.html">doxygenDoc
</a>
</p>
<dl>
<dt>EasyMultiGet</dt>
<dd>This is used to get values from a a set of channels.
The result can either be an NTMultiChannel structure or a <b>double[]</b> array.
The createGet method determines the result type.
</dd>
<dt>EasyMultiPut</dt>
<dd>This is used to get and put values from/to a set of channels.
The data supplied can either be an NTMultiChannel structure or a <b>double[]</b> array.
The createPut method determines the type.
</dd>
<dt>EasyMonitor</dt>
<dd>This is used to monitor values from a set of channels.
Each event can either be an NTMultiChannel structure or a <b>double[]</b> array.
The createMonitor method determines the data type.
</dd>
</dl>
<h2>Building</h2>
<p>After obtaining the source:</p>
<pre>
cd configure
cp ExampleRELEASE.local RELEASE.local
</pre>
<p>Edit <b>RELEASE.local</b> so that all path names are correct for you environment.
</p>
<p>
Then:</p>
<pre>
cd ..
make
</pre>
<h2>example source code</h2>
<h3>Example Database</h3>
<h2>Example and Test Database</h2>
<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.
@@ -267,8 +141,14 @@ make
cd iocBoot/exampleDatabase
../../bin/&lt;arch:&gt;/exampleDatabase st.cmd
</pre>
<h3>Examples</h3>
<p>These are examples in directory <b>example/src</b>.
<h2>Testing</h2>
<p>The tests will fail unless the example database is running.</p>
<p>Once it is running:</p>
<pre>
make runtests
</pre>
<h2>Examples</h2>
<p>Examples are in directory <b>example/src</b>.
An example of how to run them is:</p>
<pre>
mrk&gt; pwd
@@ -279,8 +159,6 @@ mrk&gt; bin/linux-x86_64/exampleEasyGet
See the source code for each example.
</p>
</div> <!-- class="contents" -->
</body>
</html>
+294
View File
@@ -0,0 +1,294 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
<title>easyPVA C++ Overview</title>
<link rel="stylesheet" type="text/css"
href="http://epics-pvdata.sourceforge.net/base.css" />
<link rel="stylesheet" type="text/css"
href="http://epics-pvdata.sourceforge.net/epicsv4.css" />
<style type="text/css">
/*<![CDATA[*/
.about { margin-left: 3em; margin-right: 3em; font-size: .83em}
table { margin-left: auto; margin-right: auto }
.diagram { text-align: center; margin: 2.5em 0 }
body { margin-right: 10% }
/*]]>*/</style>
<!-- Script that generates the Table of Contents -->
<script type="text/javascript" src="http://epics-pvdata.sourceforge.net/script/tocgen.js"></script>
</head>
<body>
<div class="head">
<h1>easyPVA C++ Overview</h1>
</div> <!-- head -->
<div id="toc">
<h2 class="nocount">Table of Contents</h2>
</div>
<!-- Place what you would like in the Table of Contents, inside the contents div -->
<div id="contents" class="contents">
<hr />
<h2>Introduction</h2>
<p>EasyPVA is a synchronous API for accessing PVData via PVAccess.
It also provides a number of convience methods.
It allows the client to request access without checking for failure,
but throws an exception when a reuest fails.
A client can also check for failues and thus prevent failures.</p>
<p>The EasyPVA API has the following features:</p>
<ol>
<li>Provides a synchronous API rather than the callback API provided by pvAccess.</li>
<li>Makes common requests easy.</li>
<li>Provides full access to the pvAccess API for more demanding
applications</li>
<li>Allows efficient client side programs.</li>
<li>Takes care of most object resource management problems.</li>
</ol>
<p>Simple examples of using easyPVA:</p>
<pre>
// easyGet
EasyPVAPtr easyPVA = EasyPVA::create();
double value = easyPVA-&gt;channel("exampleDouble")-&gt;get()-&gt;getData()-&gt;getDouble();
// easyPut
EasyChannelPtr channel = easyPVA-&gt;channel("exampleDouble");
EasyPutPtr put = channel-&gt;put();
EasyPutDataPtr putData = put-&gt;getData();
putData-&gt;putDouble(3.0); put-&gt;put();
// easyMonitor
EasyMonitorPtr monitor = easyPVA-&gt;channel("examplePowerSupply")-&gt;monitor("");
EasyMonitorDataPtr easyData = monitor-&gt;getData();
while(true) {
monitor-&gt;waitEvent();
cout &lt;&lt; "changed\n";
easyData-&gt;showChanged(cout);
cout &lt;&lt; "overrun\n";
easyData-&gt;showOverrun(cout);
monitor-&gt;releaseEvent();
}
// easyProcess
EasyChannelPtr channel = easyPVA-&gt;channel("exampleDouble");
EasyProcessPtr process = channel-&gt;createProcess();
process-&gt;process();
</pre>
<h2>EasyPVA</h2>
<p>An instance of EasyPVA is obtained via the call:</p>
<pre>
EasyPVAPtr easyPVA = EasyPVA::create();
</pre>
<p>EasyPVA has methods to create instances of <b>EasyChannel</b>.
The client can specify the provider name or use the default provider.
The client can manage it's own channels or can let easyPVA cache channels.
An example of using the cache method is:</p>
<pre>
string channelName("exampleDouble");
EasyChannelPtr easyChannel = easyPVA-&gt;channel(channelName);
</pre>
<p>This will attempt to connect to channel exampleDouble.
Since the client did not specify a timeout an exception wll be thrown if
the connection request fails.
The client will block until the connection is made or an exception is thrown.
If the request succeeds, easyPVA caches the easyChannel so that if the
client makes another request for the same channel the cached object is
returned to the client.
</p>
<p>An example of using a non cached method is:</p>
<pre>
string channelName("exampleDouble");
EasyChannelPtr easyChannel = easyPVA-&gt;createChannel(channelName);
</pre>
<p>This will create an EasyChannel and return it to the client.
The client must itself connect.
This is useful if the client wants to connect to multiple channels in parallel.
</p>
<h2>EasyChannel - Wrapper For Single Channel</h2>
<h3>EasyChannel</h3>
<p>This provides methods for connecting to a channel and for creating instances of
EasyField, EasyProcess, ..., EasyRPC.</p>
<p>Connection must be made before any crete method is called or
an exception is raised.
The following is a synchronous connection request:</p>
<pre>
easyChannel-&gt;connect(5.0); // BLOCKS
</pre>
<p>This blocks until then connection is made or until timout occurs.
An exception is raised if the connection request fails.
</p>
<p>The same request can be made without blocking and without exceptions.</p>
<pre>
easyChannel-&gt;issueConnect(); // DOES NOT BLOCK
.....
Status status =easyChannel-&gt;waitConnect(5.0); // BLOCKS
if(!status.isOK()) {
// failure do something
}
</pre>
<p>Once the channel is connected other Easy objects can be created.
For example:</p>
<pre>
EasyGetPtr easyGet = easyChannel-&gt;get(); // DOES BLOCK
</pre>
<p>This is a caching request.
If the client already has made an identical request the client will receive the
cached object.
If a new easyGet is created than it is connected before it is returned to the client.
</p>
<p>The client can also managed it's own objects:</p>
<pre>
EasyGetPtr easyGet = easyChannel-&gt;createGet(); // DOES NOT BLOCK
</pre>
<p>The client must connect the easyGet.</p>
<h3>EasyGetData</h3>
<p>This provides the data returned by easyGet and easyPutGet.
It is obtained via:</p>
<pre>
EasyGetDataPtr easyData = easyGet-&gt;getData();
</pre>
<p>It provides methods to get everything returned by channelGet.
In addition there are methods that make it easier to handle a value
field that is a scalar or a scalarArray.
Also for a scalar that is a double or a scalarArray with element type double.
</p>
<p>An example is:</p>
<pre>
double value = easyData-&gt;getDouble();
</pre>
<p>It also keeps a bitSet showing which fields have changed since the last channelGet or channelPutGet.</p>
<h3>EasyMonitorData</h3>
<p>To the client this looks identical to EasyGetData except that
it provides two BitSets: changedBitSet and overrrunBitSet.
It is used by easyMonitor.
</p>
<h3>EasyPutData</h3>
<p>This is used to provided data for easyPut and easyPutGet.
It has many of the same methods as easyGetData.
It does not have a bitSet.
It also has put methods like:</p>
<pre>
void easyData-&gt;putDouble(5.0);
</pre>
<h3>EasyGet</h3>
<p>This provides methods to connect to channelGet and to issue get request.
To connect via a single synchronous call:</p>
<pre>
eastGet-&gt;connect(); // BLOCKS
</pre>
<p>This can also be done in two steps:</p>
<pre>
easyGet-&gt;issueConnect(); // DOES NOT BLOCK
...
Status status = easyGet-&gt;waitConnect(); // BLOCKS
</pre>
<p>Once connected gets are issued via either:</p>
<pre>
void easyGet-&gt;get();
</pre>
or
<pre>
easyGet-&gt;issueGet(); // DOES NOT BLOCK
...
Status status = easyGet-&gt;waitGet(); // BLOCKS
</pre>
<h3>EasyPut</h3>
<p>This is similar to easyGet except that it wraps channelPut instead of channelGet.
</p>
<p>Once connected puts are issued via either:</p>
<pre>
void easyPut-&gt;put();
</pre>
or
<pre>
easyPut-&gt;issuePut(); // DOES NOT BLOCK
...
Status status = easyPut-&gt;waitPut(); // BLOCKS
</pre>
<h3>EasyMonitor</h3>
<p>Connecting is similar to easyGet and easyPut.
The other methods are:</p>
<dl>
<dt>start</dt>
<dd>Starts monitoring</dd>
<dt>stop</dt>
<dd>Stops monitoring</dd>
<dt>poll</dt>
<dd>polls for a monitorEvent.
The data is avalable via easyMonitorData.
</dd>
<dt>releaseEvent</dt>
<dd>Release the data from the last poll.
Note that this must be called before another poll is requested.
</dd>
<dt>waitEvent</dt>
<dd>Block until a monitorEvent is available.
If true is returned a poll has already been issued.
</dd>
<dt>setRequester</dt>
<dd>A client callback is registered to receive notice of monitorEvents.</dd>
</dl>
<h3>EasyProcess</h3>
<p>Connecting is similar to easyGet.
It has methods:</p>
<dl>
<dt>process</dt>
<dd>call issueProcess and waitProcess.</dd>
<dt>issueProcess</dt>
<dd>call channelProcess-&gt;process() and return immediately.
</dd>
<dt>waitProcess</dt>
<dd>Wait for process to complete.</dd>
</dl>
<h3>EasyPutGet</h3>
<p>Connecting is similar to easyGet.
It has methods:</p>
<dl>
<dt>putGet</dt>
<dd>calls issuePutGet and waitPutGet.
throws an exception if not successfull.
</dd>
<dt>issuePutGet</dt>
<dd>
Calls channel-&gt;putGet() and returns.
</dd>
<dt>waitPutGet</dt>
<dd>
Waits until putGet completes and returns status.
</dd>
<dt>getGet,issueGetGet, and waitGetGet</dt>
<dd>Gets the data for the get part of channelPutGet.</dd>
<dt>getPut,issueGetPut,and waitGetPut</dt>
<dd>Gets the data for the put part of channelPutGet.</dd>
<dt>getPutData</dt>
<dd>
Returns the EasyData for the put part of channelPutGet.
</dd>
<dt>getGetData</dt>
<dd>
Returns the EasyData for the get part of channelPutGet.
</dd>
</dl>
<p>Look at javaDoc for details.</p>
<h2>EasyMultiChannel - Wrapper For Multiple Channels</h2>
<p>TBD</p>
</div> <!-- class="contents" -->
</body>
</html>