more work in examples; documentation is now up to date
This commit is contained in:
@ -38,7 +38,7 @@
|
||||
<h1>pvDatabaseCPP</h1>
|
||||
<!-- Maturity: Working Draft or Request for Comments, or Recommendation, and date. -->
|
||||
|
||||
<h2 class="nocount">EPICS v4 Working Group, Working Draft, 06-Feb-2014</h2>
|
||||
<h2 class="nocount">EPICS v4 Working Group, Working Draft, 07-Feb-2014</h2>
|
||||
<dl>
|
||||
<dt>Latest version:</dt>
|
||||
<dd><a
|
||||
@ -46,11 +46,11 @@
|
||||
</dd>
|
||||
<dt>This version:</dt>
|
||||
<dd><a
|
||||
href= "pvDatabaseCPP_20131121.html">pvDatabaseCPP20131121.html</a>
|
||||
href= "pvDatabaseCPP_20140207.html">pvDatabaseCPP20140207.html</a>
|
||||
</dd>
|
||||
<dt>Previous version:</dt>
|
||||
<dd><a
|
||||
href= "pvDatabaseCPP_20131120.html">pvDatabaseCPP20131120.html</a>
|
||||
href= "pvDatabaseCPP_20131121.html">pvDatabaseCPP20131121.html</a>
|
||||
</dd>
|
||||
<dt>Editors:</dt>
|
||||
<dd>Marty Kraimer, BNL</dd>
|
||||
@ -79,7 +79,7 @@ V4 control system programming environment:<br />
|
||||
|
||||
<h2 class="nocount">Status of this Document</h2>
|
||||
|
||||
<p>This is the 06-Feb-2014 version of of pvDatabaseCPP.</p>
|
||||
<p>This is the 07-Feb-2014 version of of pvDatabaseCPP.</p>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
@ -117,8 +117,8 @@ two unresolved problems reported in the previous version of this document:
|
||||
<p>Future enhancements in priority order:</p>
|
||||
<dl>
|
||||
<dt>channelArray</dt>
|
||||
<dd>The arguments that have type <b>int</b> should be changed to <b>size_t</b>
|
||||
This will not be done until pvDataCPP-md is merged into pvDataCPP.
|
||||
<dd>The arguments that have type <b>int</b> should be changed to <b>size_t</b>.
|
||||
This requires changes to pvAccessCPP.
|
||||
</dd>
|
||||
<dt>Monitor Algorithms</dt>
|
||||
<dd>Monitor algorithms have not been implemented.
|
||||
@ -137,7 +137,7 @@ two unresolved problems reported in the previous version of this document:
|
||||
<h2>Introduction</h2>
|
||||
<h3>Overview</h3>
|
||||
<p>The main purpose of this project to make it easier to implement services that are accessed via pvAccess.
|
||||
What this project supplies is a complete implementation of the server side of pvAccess.
|
||||
This project supplies is a complete implementation of the server side of pvAccess.
|
||||
All that a service has to provide is a top level PVStructure and a process method.
|
||||
A service can be run as a main process or can be part of a V3 IOC.
|
||||
Thus services can be developed that interact with V3 records, asynDriver,
|
||||
@ -170,7 +170,8 @@ A record is smart because code can be attached to a record, which is accessed vi
|
||||
<dd>This is a complete implementation of ChannelProvider and Channel
|
||||
as defined by pvAccess.
|
||||
It is used by the server side of pvAccess to attach to pvRecords.
|
||||
This component also includes the monitor and pvCopy components from pvIOCJava</dd>
|
||||
This component also provides a C++ implementation
|
||||
of the monitor and pvCopy components from pvIOCJava</dd>
|
||||
<dt>Main and V3IOC</dt>
|
||||
<dd>The pvDatabase can be provided via a Main program or can be part
|
||||
of a V3IOC. In the later case the IOC has both a database of V3 Records
|
||||
@ -221,7 +222,7 @@ Type exit to stop:
|
||||
<pre>
|
||||
mrk> pvput -r "field(argument.value)" exampleServer World
|
||||
...
|
||||
mrk> pvget -r "record{process=true}field(result.value)" exampleServer
|
||||
mrk> pvget -r "record[process=true]field(result.value)" exampleServer
|
||||
exampleServer
|
||||
structure
|
||||
string value Hello World
|
||||
@ -232,6 +233,9 @@ mrk>
|
||||
mrk> pwd
|
||||
/home/hg/pvDatabaseCPP/exampleServer/iocBoot/exampleServer
|
||||
mrk> ../../bin/linux-x86_64/exampleServer st.cmd
|
||||
</pre>
|
||||
<p>You will see the following:</p>
|
||||
<pre>
|
||||
> envPaths
|
||||
epicsEnvSet("ARCH","linux-x86_64")
|
||||
epicsEnvSet("IOC","exampleServer")
|
||||
@ -281,10 +285,12 @@ epics>
|
||||
</pre>
|
||||
<p>Just like previously you can then execute a pvput and pvget and see Hello World.
|
||||
</p>
|
||||
<p>The examples, i. e. exampleServer, exampleLink, examplePowerSupple,
|
||||
<p>The examples, i. e. exampleServer, exampleLink, examplePowerSupply,
|
||||
and exampleDatabase, are described in separate sections below.
|
||||
In addition arrayPerformance can be used to measure that performance of big
|
||||
arrays. It is also described in a later section.</p>
|
||||
<p>Reading section exampleServer and looking at it's code is a good way
|
||||
to learn how to implement a service.</p>
|
||||
|
||||
<h3>Relationship with pvIOCJava.</h3>
|
||||
<p>This document descibes a C++ implementation of some of the components in pvIOCJava,
|
||||
@ -374,22 +380,6 @@ The following are the minimium features required</p>
|
||||
</dd>
|
||||
</dl>
|
||||
<p>The following sections describes the classes required for the first phase.</p>
|
||||
<h3>swtshell</h3>
|
||||
<p>The Java program
|
||||
<a
|
||||
href="http://epics-pvdata.sourceforge.net/docbuild/swtshellJava/tip/documentation/swtshellJava.html">
|
||||
swtshell</a>
|
||||
can be used to access pvDatabase.</p>
|
||||
<p>In particular read the sections "Getting Started" and "exampleServer".
|
||||
They will work on the exampleServer with the following differences:
|
||||
<dl>
|
||||
<dt>startExample.zip</dt>
|
||||
<dd>Do NOT use this. Instead run the exampleServer as described above.</dd>
|
||||
<dt>channelList result</dt>
|
||||
<dd>The result of channelList will show the list of records that
|
||||
exampleServer has rather than the records from startExample.zip</dd>
|
||||
</dl>
|
||||
<p>The exampleService shown below provides an example of using swtshell.</p>
|
||||
|
||||
<h2>Building pvDatabaseCPP</h2>
|
||||
<p>To build pvDatabaseCPP You must provide a file RELEASE.local
|
||||
@ -458,7 +448,7 @@ mrk> make
|
||||
<dd>Stop the local channel provider</dd>
|
||||
<dt>pvdbl</dt>
|
||||
<dd>Provides a list of all the pvRecords in database <b>master</b>
|
||||
It is similar to the iocsh command <b>dbl</b></dd>
|
||||
</dd>
|
||||
</dl>
|
||||
<p>The client commands are provided via PVAClientRegister.dbd and the other commands
|
||||
via PVAServerRegister.dbd.</p>
|
||||
@ -1102,7 +1092,7 @@ where:
|
||||
<dt>names</dt>
|
||||
<dd>The list of record names.</dd>
|
||||
</dl>
|
||||
<p>Note that swtshell has a command <b>channelList</b> that
|
||||
<p>Note that swtshell, which is a Java GUI tool, has a command <b>channelList</b> that
|
||||
requires that a record of this type is present and calls it.
|
||||
Thus user code does not have to use a channelGetPut to get the list
|
||||
of record names.</p>
|
||||
@ -1116,6 +1106,7 @@ if(!result) cout<< "record " << recordName << " not added" <
|
||||
</p>
|
||||
|
||||
<h2>exampleServer</h2>
|
||||
<h3>Overview</h3>
|
||||
<p>The example implements a simple service that has a top level pvStructure:
|
||||
<pre>
|
||||
structure
|
||||
@ -1142,9 +1133,11 @@ mrk> pwd
|
||||
/home/hg/pvDatabaseCPP/exampleService
|
||||
mrk> bin/linux-x86_64/exampleService
|
||||
</pre>
|
||||
<h3>Directory Layout</h3>
|
||||
<p>
|
||||
The directory structure is:
|
||||
</pre>
|
||||
The directory layout is:
|
||||
</p>
|
||||
<pre>
|
||||
exampleServer
|
||||
configure
|
||||
ExampleRELEASE.local
|
||||
@ -1155,9 +1148,8 @@ exampleServer
|
||||
exampleServerInclude.dbd
|
||||
exampleServerMain.cpp
|
||||
exampleServerRegister.cpp
|
||||
example
|
||||
ioc
|
||||
Db
|
||||
dbArray.db
|
||||
...
|
||||
src
|
||||
exampleServerInclude.dbd
|
||||
@ -1192,24 +1184,35 @@ exampleServerCreateRecord exampleServer
|
||||
</pre>
|
||||
Multiple commands can be issued to create multiple service records.
|
||||
</dd>
|
||||
<dt>example</dt>
|
||||
<dt>ioc</dt>
|
||||
<dd>This is for building a V3 IOC application.</dd>
|
||||
<dt>example/Db</dt>
|
||||
<dt>ioc/Db</dt>
|
||||
<dd>This has template files for creating V3 records.</dd>
|
||||
<dt>example/src/exampleServerInclude.dbd</dt>
|
||||
<dd>The commands to build a V3 database</dd>
|
||||
<dt>example/src/exampleServerMain.cpp</dt>
|
||||
<dd>The source file for running a V3 IOC.</dd>
|
||||
<dt>ioc/src</dt>
|
||||
<dd>The files for running a V3 IOC.</dd>
|
||||
<dt>iocBoot/exampleServer</dt>
|
||||
<dd>A place to start exampleServer as part of a V3IOC.
|
||||
It has a st.cmd file that starts the ioc and also starts pvAccess
|
||||
and the example.</dd>
|
||||
</dl>
|
||||
<h4>exampleServer.h</h4>
|
||||
<p>If only a main program is desired then the directory layout is:</p>
|
||||
<pre>
|
||||
exampleServer
|
||||
configure
|
||||
ExampleRELEASE.local
|
||||
...
|
||||
src
|
||||
exampleServer.h
|
||||
exampleServer.cpp
|
||||
exampleServerMain.cpp
|
||||
</pre>
|
||||
<p>Thus if only a main program is required the directory layout is simple.</p>
|
||||
<p>Also many sites will want to build the src directory in an area
|
||||
separate from where the iocs are build.</p>
|
||||
<h3>exampleServer.h</h3>
|
||||
<p>The example resides in src
|
||||
The implementation is in exampleServer.cpp.
|
||||
A serious implementation might break the code into a header and an
|
||||
implementation file.<p>
|
||||
</p>
|
||||
</p>The description consists of</p>
|
||||
<pre>
|
||||
class ExampleServer;
|
||||
@ -1343,7 +1346,7 @@ void ExampleServer::process()
|
||||
</pre>
|
||||
It gives a value to result.value and
|
||||
then sets the timeStamp to the current time.
|
||||
<h4>exampleServerMain.cpp</h4>
|
||||
<h3>src/exampleServerMain.cpp</h3>
|
||||
<p><b>NOTE:</b>
|
||||
This is a shorter version of the actual code.
|
||||
It shows the essential code.
|
||||
@ -1381,7 +1384,7 @@ This:
|
||||
<li>Prints exampleServer on standard out.</li>
|
||||
<li>Runs forever until the user types exit on standard in.</li>
|
||||
</ul>
|
||||
<h4>V3IOC exampleServer</h4>
|
||||
<h3>V3IOC exampleServer</h3>
|
||||
<p>To start exampleServer as part of a V3IOC:
|
||||
<pre>
|
||||
mrk> pwd
|
||||
@ -1399,18 +1402,13 @@ epics>
|
||||
double01 is a v3Record.
|
||||
exampleServer is a pvRecord.
|
||||
</p>
|
||||
<p>
|
||||
It starts pvASrv so that the V3 records can be accessed via Channel Access
|
||||
or via PVAccess.</p>
|
||||
|
||||
<h2>exampleDatabase</h2>
|
||||
<h3>exampleDatabase</h3>
|
||||
<p>This example provides the exampleCounter record in addition to a number of other PVRecords.
|
||||
Like exampleCounter it can be started either as a standalone main program or as
|
||||
a part of a V3IOC.
|
||||
The exampleServer pvDatabase has many records including the following:</p>
|
||||
<p>The exampleServer pvDatabase has many records including the following:</p>
|
||||
<dl>
|
||||
<dt>exampleCounter</dt>
|
||||
<dd>A record that is an instance of exampleCounter described below.
|
||||
The most useful channel methods are channelGet, channelProcess,
|
||||
and monitor.</dd>
|
||||
<dt>exampleDouble</dt>
|
||||
<dd>A record that is an instance of a record with a process method
|
||||
that does nothing. To test it start a channelPut and a channelGet and/or monitor.</dd>
|
||||
@ -1425,40 +1423,161 @@ The exampleServer pvDatabase has many records including the following:</p>
|
||||
<dd>This can be used via channelPutGet to set the trace level of another record.</dd>
|
||||
</dl>
|
||||
<p>It also has a number of other scalar and array records.</p>
|
||||
<p>exampleDatabase can be started as a main program or as a V3 IOIC.
|
||||
If started as a V3 IOC it also has a number of V3 records,
|
||||
and starts pvaSrv so that the V3 records can be accessed via Channel Access
|
||||
or via PVAccess.</p>
|
||||
<h2>exampleLink</h2>
|
||||
<p>This example show how a service can access other PVRecords.
|
||||
This section 1) starts with a discussion of accessing data via pvAccess
|
||||
and 2) gives a brief description of an example that gets data for an array of doubles.</p>
|
||||
<h3>examplePVADoubleArrayGet</h3>
|
||||
examplePVADoubleArrayGet shows how to use pvAccess to get data.</p>
|
||||
<p>The code resides in three directories:</p>
|
||||
<h3>Discussion</h3>
|
||||
<h4>Access Alternatives</h4>
|
||||
<p>The process routine of a PVRecord can access other PVRecords in two ways:</p>
|
||||
<dl>
|
||||
<dt>example/src/examplePVADoubleArrayGet</dt>
|
||||
<dd>This is the implementation code for the example.</dd>
|
||||
<dt>example/examplePVADoubleArrayGet</dt>
|
||||
<dd>This is the code that starts the example as a main program.</dd>
|
||||
<dt>example/V3IOC/examplePVADoubleArrayGet/src</dt>
|
||||
<dd>This is the code for starting the example as part of a V3IOC.</dd>
|
||||
<dt>iocBoot/examplePVADoubleArrayGet</dt>
|
||||
<dd>This has the st.cmd files to start the example.</dd>
|
||||
<dt>Directly accessing local pvDatabase</dt>
|
||||
<dd>
|
||||
If the other PVRecord is accessed via the master PVDatabase then
|
||||
threading issues are up to the implementation.
|
||||
For now this method will not be discussed.</dd>
|
||||
<dt>Access via pvAccess</dt>
|
||||
<dd>
|
||||
If access is via pvAccess then locking is handled by pvAccess.</dd>
|
||||
</dl>
|
||||
<h3>examplePVADoubleArrayGet Implementation</h3>
|
||||
<p>examplePVADoubleArrayGet.h contains the following:</p>
|
||||
<p>Access via pvAccess can be done either by local or remote channel provider.</p>
|
||||
</dl>
|
||||
<dl>
|
||||
<dt>Access via channelProviderLocal</dt>
|
||||
<dd>
|
||||
If the local pvAccess server is used the implementation must be careful that it does not
|
||||
cause deadlocks.
|
||||
When the process method is called the pvRecord for the process method is locked.
|
||||
When it makes a pvAccess get, put, etc request the other record is locked.
|
||||
Thus if a set of pvAccess links are implemented the possibility of deadlocks
|
||||
exists. A simple example is two records that have links to each other.
|
||||
More complex sets are easily created.
|
||||
Unless the developer has complete control of the set of records then remote pvAccess should
|
||||
be used.
|
||||
But this results in more context switches.
|
||||
</dd>
|
||||
<dt>Access via remote pvAccess</dt>
|
||||
<dd>If remote pvAccess is used then all locking issues are handled by pvAccess.
|
||||
The linked channel can be a pvRecord in the local pvDatabase or can be implemented
|
||||
by a remote pvAccess server.</dd>
|
||||
</dl>
|
||||
<h4>Data synchronization</h4>
|
||||
<p>If pvAccess is used then it handles data synchronization.
|
||||
This is done by making a copy of the data that is transfered between the two pvRecords.
|
||||
This is true if either remote or local pvAccess is used.
|
||||
Each get, put, etc request results in data being copied between the two records.</p>
|
||||
<p>
|
||||
If the linked channel is a local pvRecord then,
|
||||
for scalar and structure arrays,
|
||||
raw data is NOT copied for gets.
|
||||
This is because pvData uses shared_vector to hold the raw data.
|
||||
Instead of copying the raw data the reference count is incremented.</p>
|
||||
<p>For puts the linked array will force a new allocation of the raw data in the linked record,
|
||||
i. e. copy on write semantics are enforced. This is done automatically
|
||||
by pvData and not by pvDatabase.</p>
|
||||
<h4>Some details</h4>
|
||||
<p>As mentioned before a pvDatabase server can be either a separate process,
|
||||
i. e. a main program, or can be part of a V3IOC.</p>
|
||||
<p>A main pvDatabase server issues the following calls:</p>
|
||||
<pre>
|
||||
ClientFactory::start();
|
||||
ChannelProviderLocalPtr channelProvider = getChannelProviderLocal();
|
||||
...
|
||||
ServerContext::shared_pointer serverContext = startPVAServer(PVACCESS_ALL_PROVIDERS,0,true,true);
|
||||
</pre>
|
||||
<p>The first call is only necessary if some of the pvRecords
|
||||
have pvAccess links.
|
||||
These must be called before any code that uses links is initialized.
|
||||
After these two calls there will be two channel providers: <b>local</b>, and <b>pvAccess</b>.
|
||||
|
||||
</p>
|
||||
<p>A pvDatabase that is part of a V3IOC has the following in the st.cmd file.</p>
|
||||
<pre>
|
||||
...
|
||||
class ExamplePVADoubleArrayGet :
|
||||
iocInit()
|
||||
startPVAClient
|
||||
startPVAServer
|
||||
## commands to create pvRecords
|
||||
</pre>
|
||||
<p>
|
||||
Once the client and local provider code has started then the following creates a channel access link.
|
||||
</p>
|
||||
<pre>
|
||||
PVDatabasePtr master = PVDatabase::getMaster();
|
||||
ChannelAccess::shared_pointer channelAccess = getChannelAccess();
|
||||
ChannelProvider::shared_pointer provider = channelAccess->getProvider(providerName);
|
||||
Channel::shared_pointer channel = provider->createChannel(channelName,channelRequester);
|
||||
</pre>
|
||||
|
||||
<h3>Directory Layout</h3>
|
||||
<pre>
|
||||
exampleLink
|
||||
configure
|
||||
ExampleRELEASE.local
|
||||
...
|
||||
src
|
||||
exampleLink.h
|
||||
exampleLink.cpp
|
||||
exampleLinkInclude.dbd
|
||||
exampleLinkRegister.cpp
|
||||
ioc
|
||||
Db
|
||||
src
|
||||
exampleLinkInclude.dbd
|
||||
exampleLinkMain.cpp
|
||||
iocBoot
|
||||
exampleLink
|
||||
st.local
|
||||
st.remote
|
||||
...
|
||||
</pre>
|
||||
<p>This example is only built to be run as part of a V3 IOC.
|
||||
Note that two startup files are available: st.local and st.remote.
|
||||
st.local has two records: doubleArray and exampleLink.
|
||||
doubleArray is a record that can be changed via a call to pvput.
|
||||
exampleLink is a record that, when processed, gets the value from doubleArray and sets its value equal
|
||||
to the value read.
|
||||
st.local has both records.
|
||||
st.remote has only one record named exampleLinkRemote.
|
||||
<p>
|
||||
<p>To start the example:</p>
|
||||
<pre>
|
||||
mrk> pwd
|
||||
/home/hg/pvDatabaseCPP/exampleLink/iocBoot/exampleLink
|
||||
mrk> ../../bin/linux-x86_64/exampleLink st.local
|
||||
</pre>
|
||||
<p>then in another window:</p>
|
||||
<pre>
|
||||
mrk> pvput doubleArray 4 100 200 300 400
|
||||
Old : doubleArray 0
|
||||
New : doubleArray 4 100 200 300 400
|
||||
mrk> pvget -r "record[process=true]field(value)" exampleLink
|
||||
exampleLink
|
||||
structure
|
||||
double[] value [100,200,300,400]
|
||||
mrk>
|
||||
</pre>
|
||||
<h3>exampleLink Implementation</h3>
|
||||
<p>exampleLink.h contains the following:</p>
|
||||
<pre>
|
||||
...
|
||||
class ExampleLink :
|
||||
public PVRecord,
|
||||
public epics::pvAccess::ChannelRequester,
|
||||
public epics::pvAccess::ChannelGetRequester
|
||||
{
|
||||
public:
|
||||
POINTER_DEFINITIONS(ExamplePVADoubleArrayGet);
|
||||
static ExamplePVADoubleArrayGetPtr create(
|
||||
POINTER_DEFINITIONS(ExampleLink);
|
||||
static ExampleLinkPtr create(
|
||||
epics::pvData::String const & recordName,
|
||||
epics::pvData::String const & providerName,
|
||||
epics::pvData::String const & channelName
|
||||
);
|
||||
virtual ~ExamplePVADoubleArrayGet() {}
|
||||
virtual ~ExampleLink() {}
|
||||
virtual void destroy();
|
||||
virtual bool init();
|
||||
virtual void process();
|
||||
@ -1486,26 +1605,26 @@ to process in order to test the example.</p>
|
||||
<p>All of the initialization is done by a combination of the create and init methods so
|
||||
lets look at them:</p>
|
||||
<pre>
|
||||
ExamplePVADoubleArrayGetPtr ExamplePVADoubleArrayGet::create(
|
||||
ExampleLinkPtr ExampleLink::create(
|
||||
String const & recordName,
|
||||
String const & providerName,
|
||||
String const & channelName)
|
||||
{
|
||||
PVStructurePtr pvStructure = getStandardPVField()->scalarArray(
|
||||
pvDouble,"alarm.timeStamp");
|
||||
ExamplePVADoubleArrayGetPtr pvRecord(
|
||||
new ExamplePVADoubleArrayGet(
|
||||
ExampleLinkPtr pvRecord(
|
||||
new ExampleLink(
|
||||
recordName,providerName,channelName,pvStructure));
|
||||
if(!pvRecord->init()) pvRecord.reset();
|
||||
return pvRecord;
|
||||
}
|
||||
</pre>
|
||||
<p>This first creates a new ExamplePVADoubleArrayGet instance,
|
||||
and then calls the init method and the returns a ExamplePVADoubleArrayGetPtr.
|
||||
<p>This first creates a new ExampleLink instance,
|
||||
and then calls the init method and the returns a ExampleLinkPtr.
|
||||
Note that if init returns false it returns a pointer to NULL.</p>
|
||||
<p>The init method is:</p>
|
||||
<pre>
|
||||
bool ExamplePVADoubleArrayGet::init()
|
||||
bool ExampleLink::init()
|
||||
{
|
||||
initPVRecord();
|
||||
|
||||
@ -1573,181 +1692,12 @@ bool ExamplePVADoubleArrayGet::init()
|
||||
This a return of true means that it has successfully created a channelGet and is ready
|
||||
to issue gets when process is called.</p>
|
||||
<p>Look at the code for more details.</p>
|
||||
<h4>Starting the example as a main program</h4>
|
||||
<pre>
|
||||
...
|
||||
int main(int argc,char *argv[])
|
||||
{
|
||||
PVDatabasePtr master = PVDatabase::getMaster();
|
||||
ClientFactory::start();
|
||||
ChannelProviderLocalPtr channelProvider = getChannelProviderLocal();
|
||||
PVRecordPtr pvRecord;
|
||||
bool result(false);
|
||||
String recordName;
|
||||
PVStructurePtr pvStructure = standardPVField->scalarArray(
|
||||
pvDouble,"alarm,timeStamp");
|
||||
recordName = "doubleArray";
|
||||
pvRecord = PVRecord::create(recordName,pvStructure);
|
||||
result = master->addRecord(pvRecord);
|
||||
if(!result) cout<< "record " << recordName << " not added" << endl;
|
||||
ServerContext::shared_pointer serverContext = startPVAServer(PVACCESS_ALL_PROVIDERS,0,true,true);
|
||||
recordName = "examplePVADoubleArrayGet";
|
||||
if(argc>1) recordName = argv[1];
|
||||
String providerName("local");
|
||||
if(argc>2) providerName = argv[2];
|
||||
String channelName("doubleArray");
|
||||
if(argc>3) channelName = argv[3];
|
||||
pvRecord = ExamplePVADoubleArrayGet::create(
|
||||
recordName,providerName,channelName);
|
||||
if(pvRecord!=NULL) {
|
||||
result = master->addRecord(pvRecord);
|
||||
cout << "result of addRecord " << recordName << " " << result << endl;
|
||||
} else {
|
||||
cout << "ExamplePVADoubleArrayGet::create failed" << endl;
|
||||
}
|
||||
string str;
|
||||
while(true) {
|
||||
cout << "Type exit to stop: \n";
|
||||
getline(cin,str);
|
||||
if(str.compare("exit")==0) break;
|
||||
|
||||
}
|
||||
serverContext->shutdown();
|
||||
epicsThreadSleep(1.0);
|
||||
serverContext->destroy();
|
||||
ClientFactory::stop();
|
||||
channelProvider->destroy();
|
||||
return 0;
|
||||
}
|
||||
</pre>
|
||||
<p>The first statements initializes the client factory and localChannelProvider.</p>
|
||||
<p>
|
||||
It then creates a PVRecord that has a double array as the value field.
|
||||
The name of the record is <b>doubleArray</b>.
|
||||
This is the record that can be accessed via pvAccess if the channelName is
|
||||
<b>doubleArray</b>.
|
||||
</p>
|
||||
<p>It then creates a examplePVADoubleArrayGet instance.</p>
|
||||
<p>It the runs forever until the exit is typed.</p>
|
||||
|
||||
<h4>Start the example as part of a V3IOC</h4>
|
||||
The directory example/V3IOC/examplePVADoubleArrayGet has two subdirectories: Db and src.
|
||||
These are like for any other V3IOC application.
|
||||
The Db directory is for a regular ai record.
|
||||
The src directory has code similar to any V3IOC application.
|
||||
In particular it has definitions and code for creating the following iocsh commands:</p>
|
||||
<pre>
|
||||
examplePVADoubleArrayGetRegister recordName providerName channelName
|
||||
</pre>
|
||||
where
|
||||
<dl>
|
||||
<dt>recordName</dt>
|
||||
<dt>providerName</dt>
|
||||
<dt>channelName</dt>
|
||||
</dl>
|
||||
<p>The directory iocBoot/examplePVADoubleArrayGet has two st.cmd files:</p>
|
||||
<dl>
|
||||
<dt>st.local</dt>
|
||||
<dd>This creates the example using localChannelProvider.</dd>
|
||||
<dt>st.remote</dt>
|
||||
<dd>This creates the example using the remote channel provider.</dd>
|
||||
</dl>
|
||||
<h3>Discussion</h3>
|
||||
<h4>Access Alternatives</h4>
|
||||
<p>The process routine of a PVRecord can access other PVRecords in two ways:</p>
|
||||
<dl>
|
||||
<dt>Directly accessing local pvDatabase</dt>
|
||||
<dd>
|
||||
If the other PVRecord is accessed via the master PVDatabase then
|
||||
threading issues are up to the implementation.
|
||||
For now this method will not be discussed.</dd>
|
||||
<dt>Access via pvAccess</dt>
|
||||
<dd>
|
||||
If access is via pvAccess then locking is handled by pvAccess.</dd>
|
||||
</dl>
|
||||
<p>Access via pvAccess can be done either by local or remote channel provider.</p>
|
||||
</dl>
|
||||
<dl>
|
||||
<dt>Access via channelProviderLocal</dt>
|
||||
<dd>
|
||||
If the local pvAccess server is used the implementation must be careful that it does not
|
||||
caused deadlocks.
|
||||
When the process method is called the pvRecord for the process method is locked.
|
||||
When it makes a pvAccess get, put, etc request the other record is locked.
|
||||
Thus if a set of pvAccess links are implemented the possibility of deadlocks
|
||||
exists. A simple example is two records that have links to each other.
|
||||
More complex sets are easily created.
|
||||
Unless the developer has complete control of the set of records then remote pvAccess should
|
||||
be used.
|
||||
But this results in more context switches.
|
||||
</dd>
|
||||
<dt>Access via remote pvAccess</dt>
|
||||
<dd>If remote pvAccess is used then all lockimg issues are handled by pvAccess.
|
||||
The linked channel can be a pvRecord in the local pvDatabase or can be implemented
|
||||
by a remote pvAccess server.</dd>
|
||||
</dl>
|
||||
<h4>Data synchronization</h4>
|
||||
<p>If pvAccess is used then it handles data synchronization.
|
||||
This is done by making a copy of the data that is transfered between the two pvRecords.
|
||||
This is true if either remote or local pvAccess is used.
|
||||
Each get, put, etc request results in data being copied between the two records.</p>
|
||||
<p>
|
||||
If the linked channel is a local pvRecord then,
|
||||
for scalar and structure arrays,
|
||||
raw data is NOT copied for gets.
|
||||
This is because pvData uses shared_vector to hold the raw data.
|
||||
Instead of copying the raw data the reference count is incremented.</p>
|
||||
<p>For puts the linked array will force a new allocation of the raw data in the linked record,
|
||||
i. e. copy on write semantics are enforced. This is done automatically
|
||||
by pvData and not by pvDatabase.</p>
|
||||
<h4>Some details</h4>
|
||||
<p>As mentioned before a pvDatabase server can be either a separate process,
|
||||
i. e. a main program, or can be part of a V3IOC.</p>
|
||||
<p>A main pvDatabase server issues the following calls:</p>
|
||||
<pre>
|
||||
ClientFactory::start();
|
||||
ChannelProviderLocalPtr channelProvider = getChannelProviderLocal();
|
||||
...
|
||||
ServerContext::shared_pointer serverContext = startPVAServer(PVACCESS_ALL_PROVIDERS,0,true,true);
|
||||
</pre>
|
||||
<p>The first call is only necessary if some of the pvRecords
|
||||
have pvAccess links.
|
||||
These must be called before any code that uses links is initialized.
|
||||
After these two calls there will be two channel providers: <b>local</b>, and <b>pvAccess</b>.
|
||||
|
||||
</p>
|
||||
<p>A pvDatabase that is part of a V3IOC has the following in the st.cmd file.</p>
|
||||
<pre>
|
||||
...
|
||||
iocInit()
|
||||
startPVAClient
|
||||
startPVAServer
|
||||
## commands to create pvRecords
|
||||
</pre>
|
||||
<p>
|
||||
Once the client and local provider code has started then the following creates a channel access link.
|
||||
</p>
|
||||
<pre>
|
||||
PVDatabasePtr master = PVDatabase::getMaster();
|
||||
ChannelAccess::shared_pointer channelAccess = getChannelAccess();
|
||||
ChannelProvider::shared_pointer provider = channelAccess->getProvider(providerName);
|
||||
Channel::shared_pointer channel = provider->createChannel(channelName,channelRequester);
|
||||
</pre>
|
||||
<h2>examplePowerSupply</h2>
|
||||
<dl>
|
||||
<dt>powerSupplyRecordTest.h</dt>
|
||||
<dd>
|
||||
This provides code that simulates a power supply.
|
||||
It computes the current from the voltage and power.
|
||||
It is used for testing.
|
||||
The complete implementation is provided in the header file.
|
||||
Thus code will be generated only if other code includes the
|
||||
header file and creates a record instance.
|
||||
</dd>
|
||||
</dl>
|
||||
<h3>powerSupplyRecordTest</h3>
|
||||
<p>This simulates a simple power supply record.
|
||||
It is used for testing.</p>
|
||||
<p>This is an example of creating a service that requires a somewhat complicated
|
||||
top level PVStructure.
|
||||
It is similar to the powerSupply example that is provided with pvIOCJava.
|
||||
Look at the code for details.
|
||||
</p>
|
||||
<h2>Array Performance and Memory Example</h2>
|
||||
<p>This section describes main programs that demonstrate performance
|
||||
of large arrays and can also be used to check for memory leaks.
|
||||
|
2040
documentation/pvDatabaseCPP_20140207.html
Normal file
2040
documentation/pvDatabaseCPP_20140207.html
Normal file
File diff suppressed because it is too large
Load Diff
@ -6,7 +6,7 @@ DIRS += configure
|
||||
DIRS += src
|
||||
src_DEPEND_DIRS = configure
|
||||
|
||||
DIRS += example
|
||||
DIRS += ioc
|
||||
test_DEPEND_DIRS = src
|
||||
|
||||
DIRS += iocBoot
|
||||
|
@ -5,4 +5,5 @@ PVCOMMON=${EPICSV4HOME}/pvCommonCPP
|
||||
PVDATA=${EPICSV4HOME}/pvDataCPP
|
||||
PVACCESS=${EPICSV4HOME}/pvAccessCPP
|
||||
PVDATABASE=${EPICSV4HOME}/pvDatabaseCPP
|
||||
PVDATABASETEST=${EPICSV4HOME}/pvDatabaseCPP/test
|
||||
PVASRV=${EPICSV4HOME}/pvaSrv
|
||||
|
@ -1,3 +0,0 @@
|
||||
include "base.dbd"
|
||||
include "PVAServerRegister.dbd"
|
||||
registrar("exampleDatabaseRegister")
|
@ -1,57 +0,0 @@
|
||||
/*exampleDatabaseMain.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
|
||||
*/
|
||||
|
||||
/* Author: Marty Kraimer */
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdlib>
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <cstdio>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
|
||||
#include <pv/channelProviderLocal.h>
|
||||
#include <pv/exampleDatabase.h>
|
||||
#include <pv/serverContext.h>
|
||||
|
||||
using namespace std;
|
||||
using std::tr1::static_pointer_cast;
|
||||
using namespace epics::pvData;
|
||||
using namespace epics::pvAccess;
|
||||
using namespace epics::pvDatabase;
|
||||
|
||||
|
||||
int main(int argc,char *argv[])
|
||||
{
|
||||
PVDatabasePtr master = PVDatabase::getMaster();
|
||||
ChannelProviderLocalPtr channelProvider = getChannelProviderLocal();
|
||||
ExampleDatabase::create();
|
||||
ServerContext::shared_pointer ctx =
|
||||
startPVAServer(PVACCESS_ALL_PROVIDERS,0,true,true);
|
||||
cout << "exampleDatabase\n";
|
||||
PVStringArrayPtr pvNames = master->getRecordNames();
|
||||
String buffer;
|
||||
pvNames->toString(&buffer);
|
||||
cout << "recordNames" << endl << buffer << endl;
|
||||
string str;
|
||||
while(true) {
|
||||
cout << "Type exit to stop: \n";
|
||||
getline(cin,str);
|
||||
if(str.compare("exit")==0) break;
|
||||
|
||||
}
|
||||
ctx->destroy();
|
||||
epicsThreadSleep(1.0);
|
||||
channelProvider->destroy();
|
||||
return 0;
|
||||
}
|
||||
|
@ -30,6 +30,7 @@ exampleDatabase_LIBS += pvData pvAccess
|
||||
exampleDatabase_LIBS += pvDatabase
|
||||
exampleDatabase_LIBS += pvaSrv
|
||||
exampleDatabase_LIBS += exampleDatabase
|
||||
exampleDatabase_LIBS += powerSupply
|
||||
exampleDatabase_LIBS += $(EPICS_BASE_IOC_LIBS)
|
||||
|
||||
#===========================
|
@ -1,5 +1,6 @@
|
||||
include "base.dbd"
|
||||
include "PVAServerRegister.dbd"
|
||||
include "PVAClientRegister.dbd"
|
||||
include "registerChannelProviderLocal.dbd"
|
||||
registrar("examplePVADoubleArrayGetRegister")
|
||||
include "dbPv.dbd"
|
||||
include "powerSupplyRegister.dbd"
|
||||
registrar("exampleDatabaseRegister")
|
33
exampleDatabase/ioc/src/exampleDatabaseMain.cpp
Normal file
33
exampleDatabase/ioc/src/exampleDatabaseMain.cpp
Normal file
@ -0,0 +1,33 @@
|
||||
/*exampleDatabaseMain.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
|
||||
*/
|
||||
|
||||
/* Author: Marty Kraimer */
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "epicsExit.h"
|
||||
#include "epicsThread.h"
|
||||
#include "iocsh.h"
|
||||
|
||||
int main(int argc,char *argv[])
|
||||
{
|
||||
if(argc>=2) {
|
||||
iocsh(argv[1]);
|
||||
epicsThreadSleep(.2);
|
||||
}
|
||||
iocsh(NULL);
|
||||
epicsExit(0);
|
||||
return(0);
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ exampleDatabaseMain_LIBS += pvData
|
||||
exampleDatabaseMain_LIBS += pvAccess
|
||||
exampleDatabaseMain_LIBS += pvDatabase
|
||||
exampleDatabaseMain_LIBS += exampleDatabase
|
||||
exampleDatabaseMain_LIBS += powerSupply
|
||||
|
||||
DBD += exampleDatabase.dbd
|
||||
|
||||
|
@ -22,7 +22,7 @@
|
||||
|
||||
#include <pv/standardField.h>
|
||||
#include <pv/standardPVField.h>
|
||||
#include <pv/powerSupplyRecordTest.h>
|
||||
#include <pv/powerSupply.h>
|
||||
#include <pv/channelProviderLocal.h>
|
||||
#include <pv/recordList.h>
|
||||
#include <pv/traceRecord.h>
|
||||
@ -39,28 +39,6 @@ static StandardFieldPtr standardField = getStandardField();
|
||||
static PVDataCreatePtr pvDataCreate = getPVDataCreate();
|
||||
static StandardPVFieldPtr standardPVField = getStandardPVField();
|
||||
|
||||
static PVStructurePtr createPowerSupply()
|
||||
{
|
||||
size_t nfields = 5;
|
||||
StringArray names;
|
||||
names.reserve(nfields);
|
||||
FieldConstPtrArray powerSupply;
|
||||
powerSupply.reserve(nfields);
|
||||
names.push_back("alarm");
|
||||
powerSupply.push_back(standardField->alarm());
|
||||
names.push_back("timeStamp");
|
||||
powerSupply.push_back(standardField->timeStamp());
|
||||
String properties("alarm,display");
|
||||
names.push_back("voltage");
|
||||
powerSupply.push_back(standardField->scalar(pvDouble,properties));
|
||||
names.push_back("power");
|
||||
powerSupply.push_back(standardField->scalar(pvDouble,properties));
|
||||
names.push_back("current");
|
||||
powerSupply.push_back(standardField->scalar(pvDouble,properties));
|
||||
return pvDataCreate->createPVStructure(
|
||||
fieldCreate->createStructure(names,powerSupply));
|
||||
}
|
||||
|
||||
static void createStructureArrayRecord(
|
||||
PVDatabasePtr const &master,
|
||||
ScalarType scalarType,
|
||||
@ -122,10 +100,10 @@ void ExampleDatabase::create()
|
||||
createStructureArrayRecord(master,pvDouble,"exampleStructureArray");
|
||||
recordName = "examplePowerSupply";
|
||||
PVStructurePtr pvStructure = createPowerSupply();
|
||||
PowerSupplyRecordTestPtr psr =
|
||||
PowerSupplyRecordTest::create(recordName,pvStructure);
|
||||
PowerSupplyPtr psr =
|
||||
PowerSupply::create(recordName,pvStructure);
|
||||
if(psr.get()==NULL) {
|
||||
cout << "PowerSupplyRecordTest::create failed" << endl;
|
||||
cout << "PowerSupply::create failed" << endl;
|
||||
return;
|
||||
}
|
||||
result = master->addRecord(psr);
|
||||
|
@ -42,9 +42,6 @@ int main(int argc,char *argv[])
|
||||
String buffer;
|
||||
pvNames->toString(&buffer);
|
||||
cout << "recordNames" << endl << buffer << endl;
|
||||
PVRecordPtr pvRecord = master->findRecord("laptoprecordListPGRPC");
|
||||
PVStructurePtr pvStructure = pvRecord->getPVRecordStructure()->getPVStructure();
|
||||
cout << "PVStructure" << endl << pvStructure->dumpValue(cout) << endl;
|
||||
string str;
|
||||
while(true) {
|
||||
cout << "Type exit to stop: \n";
|
||||
|
@ -6,8 +6,8 @@ DIRS += configure
|
||||
DIRS += src
|
||||
src_DEPEND_DIRS = configure
|
||||
|
||||
DIRS += example
|
||||
test_DEPEND_DIRS = src
|
||||
DIRS += ioc
|
||||
ioc_DEPEND_DIRS = src
|
||||
|
||||
DIRS += iocBoot
|
||||
|
||||
|
@ -1,40 +0,0 @@
|
||||
TOP=../..
|
||||
|
||||
include $(TOP)/configure/CONFIG
|
||||
#----------------------------------------
|
||||
# ADD MACRO DEFINITIONS AFTER THIS LINE
|
||||
#=============================
|
||||
|
||||
#==================================================
|
||||
# Build an IOC support library
|
||||
#
|
||||
|
||||
#=============================
|
||||
# build an ioc application
|
||||
|
||||
|
||||
DBD += examplePVADoubleArrayGet.dbd
|
||||
|
||||
PROD_IOC += examplePVADoubleArrayGet
|
||||
|
||||
|
||||
# <name>_registerRecordDeviceDriver.cpp will be created from <name>.dbd
|
||||
examplePVADoubleArrayGet_SRCS += examplePVADoubleArrayGet_registerRecordDeviceDriver.cpp
|
||||
examplePVADoubleArrayGet_SRCS_DEFAULT += examplePVADoubleArrayGetMain.cpp
|
||||
examplePVADoubleArrayGet_SRCS_vxWorks += -nil-
|
||||
|
||||
|
||||
# The following adds support from base/src/vxWorks
|
||||
examplePVADoubleArrayGet_OBJS_vxWorks += $(EPICS_BASE_BIN)/vxComLibrary
|
||||
|
||||
examplePVADoubleArrayGet_LIBS += pvData pvAccess
|
||||
examplePVADoubleArrayGet_LIBS += pvDatabase
|
||||
examplePVADoubleArrayGet_LIBS += examplePVADoubleArrayGetSupport
|
||||
examplePVADoubleArrayGet_LIBS += $(EPICS_BASE_IOC_LIBS)
|
||||
|
||||
#===========================
|
||||
|
||||
include $(TOP)/configure/RULES
|
||||
#----------------------------------------
|
||||
# ADD RULES AFTER THIS LINE
|
||||
|
40
exampleLink/ioc/src/Makefile
Normal file
40
exampleLink/ioc/src/Makefile
Normal file
@ -0,0 +1,40 @@
|
||||
TOP=../..
|
||||
|
||||
include $(TOP)/configure/CONFIG
|
||||
#----------------------------------------
|
||||
# ADD MACRO DEFINITIONS AFTER THIS LINE
|
||||
#=============================
|
||||
|
||||
#==================================================
|
||||
# Build an IOC support library
|
||||
#
|
||||
|
||||
#=============================
|
||||
# build an ioc application
|
||||
|
||||
|
||||
DBD += exampleLink.dbd
|
||||
|
||||
PROD_IOC += exampleLink
|
||||
|
||||
|
||||
# <name>_registerRecordDeviceDriver.cpp will be created from <name>.dbd
|
||||
exampleLink_SRCS += exampleLink_registerRecordDeviceDriver.cpp
|
||||
exampleLink_SRCS_DEFAULT += exampleLinkMain.cpp
|
||||
exampleLink_SRCS_vxWorks += -nil-
|
||||
|
||||
|
||||
# The following adds support from base/src/vxWorks
|
||||
exampleLink_OBJS_vxWorks += $(EPICS_BASE_BIN)/vxComLibrary
|
||||
|
||||
exampleLink_LIBS += pvData pvAccess
|
||||
exampleLink_LIBS += pvDatabase
|
||||
exampleLink_LIBS += exampleLinkSupport
|
||||
exampleLink_LIBS += $(EPICS_BASE_IOC_LIBS)
|
||||
|
||||
#===========================
|
||||
|
||||
include $(TOP)/configure/RULES
|
||||
#----------------------------------------
|
||||
# ADD RULES AFTER THIS LINE
|
||||
|
@ -2,4 +2,4 @@ include "base.dbd"
|
||||
include "PVAServerRegister.dbd"
|
||||
include "PVAClientRegister.dbd"
|
||||
include "registerChannelProviderLocal.dbd"
|
||||
registrar("examplePVADoubleArrayGetRegister")
|
||||
registrar("exampleLinkRegister")
|
@ -1,4 +1,4 @@
|
||||
/* examplePVADoubleArrayGetMain.cpp */
|
||||
/* exampleLinkMain.cpp */
|
||||
/**
|
||||
* Copyright - See the COPYRIGHT that is included with this distribution.
|
||||
* EPICS pvData is distributed subject to a Software License Agreement found
|
@ -3,8 +3,8 @@
|
||||
cd ${TOP}
|
||||
|
||||
## Register all support components
|
||||
dbLoadDatabase("dbd/examplePVADoubleArrayGet.dbd")
|
||||
examplePVADoubleArrayGet_registerRecordDeviceDriver(pdbbase)
|
||||
dbLoadDatabase("dbd/exampleLink.dbd")
|
||||
exampleLink_registerRecordDeviceDriver(pdbbase)
|
||||
|
||||
## Load record instances
|
||||
dbLoadRecords("db/dbArray.db","name=double01,type=DOUBLE")
|
||||
@ -13,4 +13,4 @@ cd ${TOP}/iocBoot/${IOC}
|
||||
iocInit()
|
||||
startPVAClient
|
||||
startPVAServer
|
||||
examplePVADoubleArrayGetCreateRecord examplePVADoubleArrayGet local doubleArray
|
||||
exampleLinkCreateRecord exampleLink local doubleArray
|
@ -3,8 +3,8 @@
|
||||
cd ${TOP}
|
||||
|
||||
## Register all support components
|
||||
dbLoadDatabase("dbd/examplePVADoubleArrayGet.dbd")
|
||||
examplePVADoubleArrayGet_registerRecordDeviceDriver(pdbbase)
|
||||
dbLoadDatabase("dbd/exampleLink.dbd")
|
||||
exampleLink_registerRecordDeviceDriver(pdbbase)
|
||||
|
||||
## Load record instances
|
||||
dbLoadRecords("db/dbArray.db","name=double01,type=DOUBLE")
|
||||
@ -13,4 +13,4 @@ cd ${TOP}/iocBoot/${IOC}
|
||||
iocInit()
|
||||
startPVAClient
|
||||
startPVAServer
|
||||
examplePVADoubleArrayGetCreateRecord examplePVADoubleArrayGet pvAccess arrayDouble
|
||||
exampleLinkCreateRecord exampleLinkRemote pvAccess doubleArray
|
@ -9,17 +9,17 @@ include $(TOP)/configure/CONFIG
|
||||
# Build an IOC support library
|
||||
#
|
||||
|
||||
DBD += examplePVADoubleArrayGet.dbd
|
||||
DBD += exampleLink.dbd
|
||||
|
||||
INC += examplePVADoubleArrayGet.h
|
||||
INC += exampleLink.h
|
||||
|
||||
LIBRARY_IOC += examplePVADoubleArrayGetSupport
|
||||
examplePVADoubleArrayGetSupport_SRCS += examplePVADoubleArrayGet.cpp
|
||||
examplePVADoubleArrayGetSupport_SRCS += examplePVADoubleArrayGetRegister.cpp
|
||||
examplePVADoubleArrayGetSupport_LIBS += pvData
|
||||
examplePVADoubleArrayGetSupport_LIBS += pvAccess
|
||||
examplePVADoubleArrayGetSupport_LIBS += pvDatabase
|
||||
examplePVADoubleArrayGetSupport_LIBS += $(EPICS_BASE_IOC_LIBS)
|
||||
LIBRARY_IOC += exampleLinkSupport
|
||||
exampleLinkSupport_SRCS += exampleLink.cpp
|
||||
exampleLinkSupport_SRCS += exampleLinkRegister.cpp
|
||||
exampleLinkSupport_LIBS += pvData
|
||||
exampleLinkSupport_LIBS += pvAccess
|
||||
exampleLinkSupport_LIBS += pvDatabase
|
||||
exampleLinkSupport_LIBS += $(EPICS_BASE_IOC_LIBS)
|
||||
|
||||
#===========================
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* examplePVADoubleArrayGet.cpp */
|
||||
/* exampleLink.cpp */
|
||||
/**
|
||||
* Copyright - See the COPYRIGHT that is included with this distribution.
|
||||
* EPICS pvData is distributed subject to a Software License Agreement found
|
||||
@ -9,7 +9,7 @@
|
||||
* @date 2013.08.02
|
||||
*/
|
||||
|
||||
#include <pv/examplePVADoubleArrayGet.h>
|
||||
#include <pv/exampleLink.h>
|
||||
#include <pv/standardPVField.h>
|
||||
#include <pv/convert.h>
|
||||
|
||||
@ -21,21 +21,21 @@ using std::tr1::dynamic_pointer_cast;
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
|
||||
ExamplePVADoubleArrayGetPtr ExamplePVADoubleArrayGet::create(
|
||||
ExampleLinkPtr ExampleLink::create(
|
||||
String const & recordName,
|
||||
String const & providerName,
|
||||
String const & channelName)
|
||||
{
|
||||
PVStructurePtr pvStructure = getStandardPVField()->scalarArray(
|
||||
pvDouble,"alarm.timeStamp");
|
||||
ExamplePVADoubleArrayGetPtr pvRecord(
|
||||
new ExamplePVADoubleArrayGet(
|
||||
ExampleLinkPtr pvRecord(
|
||||
new ExampleLink(
|
||||
recordName,providerName,channelName,pvStructure));
|
||||
if(!pvRecord->init()) pvRecord.reset();
|
||||
return pvRecord;
|
||||
}
|
||||
|
||||
ExamplePVADoubleArrayGet::ExamplePVADoubleArrayGet(
|
||||
ExampleLink::ExampleLink(
|
||||
String const & recordName,
|
||||
String providerName,
|
||||
String channelName,
|
||||
@ -47,12 +47,12 @@ ExamplePVADoubleArrayGet::ExamplePVADoubleArrayGet(
|
||||
{
|
||||
}
|
||||
|
||||
void ExamplePVADoubleArrayGet::destroy()
|
||||
void ExampleLink::destroy()
|
||||
{
|
||||
PVRecord::destroy();
|
||||
}
|
||||
|
||||
bool ExamplePVADoubleArrayGet::init()
|
||||
bool ExampleLink::init()
|
||||
{
|
||||
initPVRecord();
|
||||
|
||||
@ -101,7 +101,7 @@ bool ExamplePVADoubleArrayGet::init()
|
||||
return true;
|
||||
}
|
||||
|
||||
void ExamplePVADoubleArrayGet::process()
|
||||
void ExampleLink::process()
|
||||
{
|
||||
status = Status::Ok;
|
||||
channelGet->get(false);
|
||||
@ -124,7 +124,7 @@ void ExamplePVADoubleArrayGet::process()
|
||||
pvAlarm.set(alarm);
|
||||
}
|
||||
|
||||
void ExamplePVADoubleArrayGet::channelCreated(
|
||||
void ExampleLink::channelCreated(
|
||||
const Status& status,
|
||||
Channel::shared_pointer const & channel)
|
||||
{
|
||||
@ -133,13 +133,13 @@ void ExamplePVADoubleArrayGet::channelCreated(
|
||||
event.signal();
|
||||
}
|
||||
|
||||
void ExamplePVADoubleArrayGet::channelStateChange(
|
||||
void ExampleLink::channelStateChange(
|
||||
Channel::shared_pointer const & channel,
|
||||
Channel::ConnectionState connectionState)
|
||||
{
|
||||
}
|
||||
|
||||
void ExamplePVADoubleArrayGet::channelGetConnect(
|
||||
void ExampleLink::channelGetConnect(
|
||||
const Status& status,
|
||||
ChannelGet::shared_pointer const & channelGet,
|
||||
PVStructure::shared_pointer const & pvStructure,
|
||||
@ -152,7 +152,7 @@ void ExamplePVADoubleArrayGet::channelGetConnect(
|
||||
event.signal();
|
||||
}
|
||||
|
||||
void ExamplePVADoubleArrayGet::getDone(const Status& status)
|
||||
void ExampleLink::getDone(const Status& status)
|
||||
{
|
||||
this->status = status;
|
||||
event.signal();
|
@ -1,4 +1,4 @@
|
||||
/* examplePVADoubleArrayGet.h */
|
||||
/* exampleLink.h */
|
||||
/**
|
||||
* Copyright - See the COPYRIGHT that is included with this distribution.
|
||||
* EPICS pvData is distributed subject to a Software License Agreement found
|
||||
@ -24,22 +24,22 @@
|
||||
namespace epics { namespace pvDatabase {
|
||||
|
||||
|
||||
class ExamplePVADoubleArrayGet;
|
||||
typedef std::tr1::shared_ptr<ExamplePVADoubleArrayGet> ExamplePVADoubleArrayGetPtr;
|
||||
class ExampleLink;
|
||||
typedef std::tr1::shared_ptr<ExampleLink> ExampleLinkPtr;
|
||||
|
||||
class ExamplePVADoubleArrayGet :
|
||||
class ExampleLink :
|
||||
public PVRecord,
|
||||
public epics::pvAccess::ChannelRequester,
|
||||
public epics::pvAccess::ChannelGetRequester
|
||||
{
|
||||
public:
|
||||
POINTER_DEFINITIONS(ExamplePVADoubleArrayGet);
|
||||
static ExamplePVADoubleArrayGetPtr create(
|
||||
POINTER_DEFINITIONS(ExampleLink);
|
||||
static ExampleLinkPtr create(
|
||||
epics::pvData::String const & recordName,
|
||||
epics::pvData::String const & providerName,
|
||||
epics::pvData::String const & channelName
|
||||
);
|
||||
virtual ~ExamplePVADoubleArrayGet() {}
|
||||
virtual ~ExampleLink() {}
|
||||
virtual void destroy();
|
||||
virtual bool init();
|
||||
virtual void process();
|
||||
@ -60,10 +60,10 @@ public:
|
||||
epics::pvData::String const & message,
|
||||
epics::pvData::MessageType messageType)
|
||||
{
|
||||
std::cout << "Why is ExamplePVADoubleArrayGet::message called\n";
|
||||
std::cout << "Why is ExampleLink::message called\n";
|
||||
}
|
||||
private:
|
||||
ExamplePVADoubleArrayGet(epics::pvData::String const & recordName,
|
||||
ExampleLink(epics::pvData::String const & recordName,
|
||||
epics::pvData::String providerName,
|
||||
epics::pvData::String channelName,
|
||||
epics::pvData::PVStructurePtr const & pvStructure);
|
1
exampleLink/src/exampleLinkInclude.dbd
Normal file
1
exampleLink/src/exampleLinkInclude.dbd
Normal file
@ -0,0 +1 @@
|
||||
registrar("exampleLinkRegister")
|
@ -1,4 +1,4 @@
|
||||
/*examplePVADoubleArrayGet.cpp */
|
||||
/*exampleLink.cpp */
|
||||
/**
|
||||
* Copyright - See the COPYRIGHT that is included with this distribution.
|
||||
* EPICS pvData is distributed subject to a Software License Agreement found
|
||||
@ -35,7 +35,7 @@
|
||||
#include <pv/standardPVField.h>
|
||||
#include <pv/pvAccess.h>
|
||||
#include <pv/pvDatabase.h>
|
||||
#include <pv/examplePVADoubleArrayGet.h>
|
||||
#include <pv/exampleLink.h>
|
||||
|
||||
using namespace epics::pvData;
|
||||
using namespace epics::pvAccess;
|
||||
@ -51,9 +51,9 @@ static const iocshArg testArg2 = { "channelName", iocshArgString };
|
||||
static const iocshArg *testArgs[] = {
|
||||
&testArg0,&testArg1,&testArg2};
|
||||
|
||||
static const iocshFuncDef examplePVADoubleArrayGetFuncDef = {
|
||||
"examplePVADoubleArrayGetCreateRecord", 3, testArgs};
|
||||
static void examplePVADoubleArrayGetCallFunc(const iocshArgBuf *args)
|
||||
static const iocshFuncDef exampleLinkFuncDef = {
|
||||
"exampleLinkCreateRecord", 3, testArgs};
|
||||
static void exampleLinkCallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
PVDatabasePtr master = PVDatabase::getMaster();
|
||||
PVRecordPtr pvRecord;
|
||||
@ -68,18 +68,18 @@ static void examplePVADoubleArrayGetCallFunc(const iocshArgBuf *args)
|
||||
recordName = args[0].sval;
|
||||
char *providerName = args[1].sval;
|
||||
char *channelName = args[2].sval;
|
||||
ExamplePVADoubleArrayGetPtr record = ExamplePVADoubleArrayGet::create(recordName,providerName,channelName);
|
||||
ExampleLinkPtr record = ExampleLink::create(recordName,providerName,channelName);
|
||||
if(record!=NULL)
|
||||
result = master->addRecord(record);
|
||||
if(!result) cout << "recordname" << " not added" << endl;
|
||||
}
|
||||
|
||||
static void examplePVADoubleArrayGetRegister(void)
|
||||
static void exampleLinkRegister(void)
|
||||
{
|
||||
static int firstTime = 1;
|
||||
if (firstTime) {
|
||||
firstTime = 0;
|
||||
iocshRegister(&examplePVADoubleArrayGetFuncDef, examplePVADoubleArrayGetCallFunc);
|
||||
iocshRegister(&exampleLinkFuncDef, exampleLinkCallFunc);
|
||||
}
|
||||
}
|
||||
epicsExportRegistrar(examplePVADoubleArrayGetRegister);
|
||||
epicsExportRegistrar(exampleLinkRegister);
|
@ -6,8 +6,8 @@ DIRS += configure
|
||||
DIRS += src
|
||||
src_DEPEND_DIRS = configure
|
||||
|
||||
DIRS += example
|
||||
test_DEPEND_DIRS = src
|
||||
DIRS += ioc
|
||||
ioc_DEPEND_DIRS = src
|
||||
|
||||
DIRS += iocBoot
|
||||
|
||||
|
@ -5,4 +5,5 @@ PVCOMMON=${EPICSV4HOME}/pvCommonCPP
|
||||
PVDATA=${EPICSV4HOME}/pvDataCPP
|
||||
PVACCESS=${EPICSV4HOME}/pvAccessCPP
|
||||
PVDATABASE=${EPICSV4HOME}/pvDatabaseCPP
|
||||
PVDATABASETEST=${EPICSV4HOME}/pvDatabaseCPP/test
|
||||
PVASRV=${EPICSV4HOME}/pvaSrv
|
||||
|
9
examplePowerSupply/configure/RELEASE.local
Normal file
9
examplePowerSupply/configure/RELEASE.local
Normal file
@ -0,0 +1,9 @@
|
||||
EPICS_BASE=/home/install/epics/base
|
||||
TEMPLATE_TOP=$(EPICS_BASE)/templates/makeBaseApp/top
|
||||
EPICSV4HOME=/home/hg
|
||||
PVCOMMON=${EPICSV4HOME}/pvCommonCPP
|
||||
PVDATA=${EPICSV4HOME}/pvDataCPP
|
||||
PVACCESS=${EPICSV4HOME}/pvAccessCPP
|
||||
PVDATABASE=${EPICSV4HOME}/pvDatabaseCPP
|
||||
PVDATABASETEST=${EPICSV4HOME}/pvDatabaseCPP/test
|
||||
PVASRV=${EPICSV4HOME}/pvaSrv
|
@ -2,4 +2,4 @@ include "base.dbd"
|
||||
include "PVAServerRegister.dbd"
|
||||
include "registerChannelProviderLocal.dbd"
|
||||
include "dbPv.dbd"
|
||||
include "powerSupply.dbd"
|
||||
include "powerSupplyRegister.dbd"
|
@ -12,24 +12,13 @@ include $(TOP)/configure/CONFIG
|
||||
|
||||
PROD_HOST += powerSupplyMain
|
||||
powerSupplyMain_SRCS += powerSupplyMain.cpp
|
||||
|
||||
powerSupplyMain_LIBS += Com
|
||||
powerSupplyMain_LIBS += pvData
|
||||
powerSupplyMain_LIBS += pvAccess
|
||||
powerSupplyMain_LIBS += pvDatabase
|
||||
powerSupplyMain_LIBS += powerSupply
|
||||
|
||||
DBD += powerSupply.dbd
|
||||
|
||||
INC += powerSupply.h
|
||||
|
||||
LIBRARY_IOC += powerSupply
|
||||
powerSupply_SRCS += powerSupply.cpp
|
||||
powerSupply_SRCS += powerSupplyRegister.cpp
|
||||
powerSupply_LIBS += pvData
|
||||
powerSupply_LIBS += pvAccess
|
||||
powerSupply_LIBS += pvDatabase
|
||||
powerSupply_LIBS += $(EPICS_BASE_IOC_LIBS)
|
||||
|
||||
#===========================
|
||||
|
||||
include $(TOP)/configure/RULES
|
||||
|
@ -1,179 +0,0 @@
|
||||
/* powerSupply.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 2013.04.02
|
||||
*/
|
||||
|
||||
#include <pv/standardField.h>
|
||||
#include <pv/standardPVField.h>
|
||||
#include <pv/powerSupply.h>
|
||||
|
||||
namespace epics { namespace pvDatabase {
|
||||
|
||||
using namespace epics::pvData;
|
||||
|
||||
PVStructurePtr createPowerSupply()
|
||||
{
|
||||
FieldCreatePtr fieldCreate = getFieldCreate();
|
||||
StandardFieldPtr standardField = getStandardField();
|
||||
PVDataCreatePtr pvDataCreate = getPVDataCreate();
|
||||
|
||||
size_t nfields = 5;
|
||||
StringArray names;
|
||||
names.reserve(nfields);
|
||||
FieldConstPtrArray powerSupply;
|
||||
powerSupply.reserve(nfields);
|
||||
names.push_back("alarm");
|
||||
powerSupply.push_back(standardField->alarm());
|
||||
names.push_back("timeStamp");
|
||||
powerSupply.push_back(standardField->timeStamp());
|
||||
String properties("alarm,display");
|
||||
names.push_back("voltage");
|
||||
powerSupply.push_back(standardField->scalar(pvDouble,properties));
|
||||
names.push_back("power");
|
||||
powerSupply.push_back(standardField->scalar(pvDouble,properties));
|
||||
names.push_back("current");
|
||||
powerSupply.push_back(standardField->scalar(pvDouble,properties));
|
||||
return pvDataCreate->createPVStructure(
|
||||
fieldCreate->createStructure(names,powerSupply));
|
||||
}
|
||||
|
||||
PowerSupplyPtr PowerSupply::create(
|
||||
String const & recordName,
|
||||
PVStructurePtr const & pvStructure)
|
||||
{
|
||||
PowerSupplyPtr pvRecord(
|
||||
new PowerSupply(recordName,pvStructure));
|
||||
if(!pvRecord->init()) pvRecord.reset();
|
||||
return pvRecord;
|
||||
}
|
||||
|
||||
PowerSupply::PowerSupply(
|
||||
String const & recordName,
|
||||
PVStructurePtr const & pvStructure)
|
||||
: PVRecord(recordName,pvStructure)
|
||||
{
|
||||
}
|
||||
|
||||
PowerSupply::~PowerSupply()
|
||||
{
|
||||
}
|
||||
|
||||
void PowerSupply::destroy()
|
||||
{
|
||||
PVRecord::destroy();
|
||||
}
|
||||
|
||||
bool PowerSupply::init()
|
||||
{
|
||||
initPVRecord();
|
||||
PVStructurePtr pvStructure = getPVStructure();
|
||||
PVFieldPtr pvField;
|
||||
bool result;
|
||||
pvField = pvStructure->getSubField("timeStamp");
|
||||
if(pvField.get()==NULL) {
|
||||
std::cerr << "no timeStamp" << std::endl;
|
||||
return false;
|
||||
}
|
||||
result = pvTimeStamp.attach(pvField);
|
||||
if(!result) {
|
||||
std::cerr << "no timeStamp" << std::endl;
|
||||
return false;
|
||||
}
|
||||
pvField = pvStructure->getSubField("alarm");
|
||||
if(pvField.get()==NULL) {
|
||||
std::cerr << "no alarm" << std::endl;
|
||||
return false;
|
||||
}
|
||||
result = pvAlarm.attach(pvField);
|
||||
if(!result) {
|
||||
std::cerr << "no alarm" << std::endl;
|
||||
return false;
|
||||
}
|
||||
String name;
|
||||
name = "current.value";
|
||||
pvField = pvStructure->getSubField(name);
|
||||
if(pvField.get()==NULL) {
|
||||
name = "current";
|
||||
pvField = pvStructure->getSubField(name);
|
||||
}
|
||||
if(pvField.get()==NULL) {
|
||||
std::cerr << "no current" << std::endl;
|
||||
return false;
|
||||
}
|
||||
pvCurrent = pvStructure->getDoubleField(name);
|
||||
if(pvCurrent.get()==NULL) return false;
|
||||
name = "voltage.value";
|
||||
pvField = pvStructure->getSubField(name);
|
||||
if(pvField.get()==NULL) {
|
||||
name = "voltage";
|
||||
pvField = pvStructure->getSubField(name);
|
||||
}
|
||||
if(pvField.get()==NULL) {
|
||||
std::cerr << "no voltage" << std::endl;
|
||||
return false;
|
||||
}
|
||||
pvVoltage = pvStructure->getDoubleField(name);
|
||||
if(pvVoltage.get()==NULL) return false;
|
||||
name = "power.value";
|
||||
pvField = pvStructure->getSubField(name);
|
||||
if(pvField.get()==NULL) {
|
||||
name = "power";
|
||||
pvField = pvStructure->getSubField(name);
|
||||
}
|
||||
if(pvField.get()==NULL) {
|
||||
std::cerr << "no power" << std::endl;
|
||||
return false;
|
||||
}
|
||||
pvPower = pvStructure->getDoubleField(name);
|
||||
if(pvPower.get()==NULL) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void PowerSupply::process()
|
||||
{
|
||||
timeStamp.getCurrent();
|
||||
pvTimeStamp.set(timeStamp);
|
||||
double voltage = pvVoltage->get();
|
||||
double power = pvPower->get();
|
||||
if(voltage<1e-3 && voltage>-1e-3) {
|
||||
alarm.setMessage("bad voltage");
|
||||
alarm.setSeverity(majorAlarm);
|
||||
pvAlarm.set(alarm);
|
||||
return;
|
||||
}
|
||||
double current = power/voltage;
|
||||
pvCurrent->put(current);
|
||||
alarm.setMessage("");
|
||||
alarm.setSeverity(noAlarm);
|
||||
pvAlarm.set(alarm);
|
||||
}
|
||||
|
||||
void PowerSupply::put(double power,double voltage)
|
||||
{
|
||||
pvPower->put(power);
|
||||
pvVoltage->put(voltage);
|
||||
}
|
||||
|
||||
double PowerSupply::getPower()
|
||||
{
|
||||
return pvPower->get();
|
||||
}
|
||||
|
||||
double PowerSupply::getVoltage()
|
||||
{
|
||||
return pvVoltage->get();
|
||||
}
|
||||
|
||||
double PowerSupply::getCurrent()
|
||||
{
|
||||
return pvCurrent->get();
|
||||
}
|
||||
|
||||
|
||||
}}
|
@ -1,58 +0,0 @@
|
||||
/* powerSupply.h */
|
||||
/**
|
||||
* 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 2013.04.02
|
||||
*/
|
||||
#ifndef POWERSUPPLY_H
|
||||
#define POWERSUPPLY_H
|
||||
|
||||
#include <pv/pvDatabase.h>
|
||||
#include <pv/timeStamp.h>
|
||||
#include <pv/alarm.h>
|
||||
#include <pv/pvTimeStamp.h>
|
||||
#include <pv/pvAlarm.h>
|
||||
|
||||
namespace epics { namespace pvDatabase {
|
||||
|
||||
extern epics::pvData::PVStructurePtr createPowerSupply();
|
||||
|
||||
class PowerSupply;
|
||||
typedef std::tr1::shared_ptr<PowerSupply> PowerSupplyPtr;
|
||||
|
||||
class PowerSupply :
|
||||
public PVRecord
|
||||
{
|
||||
public:
|
||||
POINTER_DEFINITIONS(PowerSupply);
|
||||
static PowerSupplyPtr create(
|
||||
epics::pvData::String const & recordName,
|
||||
epics::pvData::PVStructurePtr const & pvStructure);
|
||||
virtual ~PowerSupply();
|
||||
virtual void destroy();
|
||||
virtual bool init();
|
||||
virtual void process();
|
||||
void put(double power,double voltage);
|
||||
double getPower();
|
||||
double getVoltage();
|
||||
double getCurrent();
|
||||
private:
|
||||
PowerSupply(epics::pvData::String const & recordName,
|
||||
epics::pvData::PVStructurePtr const & pvStructure);
|
||||
epics::pvData::PVDoublePtr pvCurrent;
|
||||
epics::pvData::PVDoublePtr pvPower;
|
||||
epics::pvData::PVDoublePtr pvVoltage;
|
||||
epics::pvData::PVAlarm pvAlarm;
|
||||
epics::pvData::PVTimeStamp pvTimeStamp;
|
||||
epics::pvData::Alarm alarm;
|
||||
epics::pvData::TimeStamp timeStamp;
|
||||
};
|
||||
|
||||
|
||||
}}
|
||||
|
||||
#endif /* POWERSUPPLY_H */
|
@ -6,8 +6,8 @@ DIRS += configure
|
||||
DIRS += src
|
||||
src_DEPEND_DIRS = configure
|
||||
|
||||
DIRS += example
|
||||
test_DEPEND_DIRS = src
|
||||
DIRS += ioc
|
||||
ioc_DEPEND_DIRS = src
|
||||
|
||||
DIRS += iocBoot
|
||||
|
||||
|
@ -2,6 +2,19 @@ TOP=..
|
||||
|
||||
include $(TOP)/configure/CONFIG
|
||||
|
||||
DBD += powerSupplyRegister.dbd
|
||||
|
||||
INC += powerSupply.h
|
||||
|
||||
LIBRARY_IOC += powerSupply
|
||||
powerSupply_SRCS += powerSupply.cpp
|
||||
powerSupply_SRCS += powerSupplyRegister.cpp
|
||||
powerSupply_LIBS += pvData
|
||||
powerSupply_LIBS += pvAccess
|
||||
powerSupply_LIBS += pvDatabase
|
||||
powerSupply_LIBS += $(EPICS_BASE_IOC_LIBS)
|
||||
|
||||
|
||||
PROD_HOST += testPVCopy
|
||||
testPVCopy_SRCS += powerSupply.cpp
|
||||
testPVCopy_SRCS += testPVCopy.cpp
|
||||
|
1
test/src/powerSupplyRegister.dbd
Normal file
1
test/src/powerSupplyRegister.dbd
Normal file
@ -0,0 +1 @@
|
||||
registrar("powerSupplyRegister")
|
Reference in New Issue
Block a user