more work in examples; documentation is now up to date

This commit is contained in:
Marty Kraimer
2014-02-07 13:57:32 -05:00
parent 9a798bc05a
commit 61d884334a
72 changed files with 2404 additions and 685 deletions

View File

@ -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&gt; pvput -r "field(argument.value)" exampleServer World
...
mrk&gt; pvget -r "record{process=true}field(result.value)" exampleServer
mrk&gt; pvget -r "record[process=true]field(result.value)" exampleServer
exampleServer
structure
string value Hello World
@ -232,6 +233,9 @@ mrk&gt;
mrk&gt; pwd
/home/hg/pvDatabaseCPP/exampleServer/iocBoot/exampleServer
mrk&gt; ../../bin/linux-x86_64/exampleServer st.cmd
</pre>
<p>You will see the following:</p>
<pre>
&gt; envPaths
epicsEnvSet("ARCH","linux-x86_64")
epicsEnvSet("IOC","exampleServer")
@ -281,10 +285,12 @@ epics&gt;
</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&gt; 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&lt;&lt; "record " &lt;&lt; recordName &lt;&lt; " not added" &lt
</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&gt; pwd
/home/hg/pvDatabaseCPP/exampleService
mrk&gt; 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&gt; pwd
@ -1399,18 +1402,13 @@ epics&gt;
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-&gt;getProvider(providerName);
Channel::shared_pointer channel = provider-&gt;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&gt; pwd
/home/hg/pvDatabaseCPP/exampleLink/iocBoot/exampleLink
mrk&gt; ../../bin/linux-x86_64/exampleLink st.local
</pre>
<p>then in another window:</p>
<pre>
mrk&gt; pvput doubleArray 4 100 200 300 400
Old : doubleArray 0
New : doubleArray 4 100 200 300 400
mrk&gt; pvget -r "record[process=true]field(value)" exampleLink
exampleLink
structure
double[] value [100,200,300,400]
mrk&gt;
</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 &amp; recordName,
epics::pvData::String const &amp; providerName,
epics::pvData::String const &amp; 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 &amp; recordName,
String const &amp; providerName,
String const &amp; channelName)
{
PVStructurePtr pvStructure = getStandardPVField()-&gt;scalarArray(
pvDouble,"alarm.timeStamp");
ExamplePVADoubleArrayGetPtr pvRecord(
new ExamplePVADoubleArrayGet(
ExampleLinkPtr pvRecord(
new ExampleLink(
recordName,providerName,channelName,pvStructure));
if(!pvRecord-&gt;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-&gt;scalarArray(
pvDouble,"alarm,timeStamp");
recordName = "doubleArray";
pvRecord = PVRecord::create(recordName,pvStructure);
result = master-&gt;addRecord(pvRecord);
if(!result) cout&lt;&lt; "record " &lt;&lt; recordName &lt;&lt; " not added" &lt;&lt; endl;
ServerContext::shared_pointer serverContext = startPVAServer(PVACCESS_ALL_PROVIDERS,0,true,true);
recordName = "examplePVADoubleArrayGet";
if(argc&gt;1) recordName = argv[1];
String providerName("local");
if(argc&gt;2) providerName = argv[2];
String channelName("doubleArray");
if(argc&gt;3) channelName = argv[3];
pvRecord = ExamplePVADoubleArrayGet::create(
recordName,providerName,channelName);
if(pvRecord!=NULL) {
result = master-&gt;addRecord(pvRecord);
cout &lt;&lt; "result of addRecord " &lt;&lt; recordName &lt;&lt; " " &lt;&lt; result &lt;&lt; endl;
} else {
cout &lt;&lt; "ExamplePVADoubleArrayGet::create failed" &lt;&lt; endl;
}
string str;
while(true) {
cout &lt;&lt; "Type exit to stop: \n";
getline(cin,str);
if(str.compare("exit")==0) break;
}
serverContext-&gt;shutdown();
epicsThreadSleep(1.0);
serverContext-&gt;destroy();
ClientFactory::stop();
channelProvider-&gt;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-&gt;getProvider(providerName);
Channel::shared_pointer channel = provider-&gt;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.

File diff suppressed because it is too large Load Diff

View File

@ -6,7 +6,7 @@ DIRS += configure
DIRS += src
src_DEPEND_DIRS = configure
DIRS += example
DIRS += ioc
test_DEPEND_DIRS = src
DIRS += iocBoot

View File

@ -5,4 +5,5 @@ PVCOMMON=${EPICSV4HOME}/pvCommonCPP
PVDATA=${EPICSV4HOME}/pvDataCPP
PVACCESS=${EPICSV4HOME}/pvAccessCPP
PVDATABASE=${EPICSV4HOME}/pvDatabaseCPP
PVDATABASETEST=${EPICSV4HOME}/pvDatabaseCPP/test
PVASRV=${EPICSV4HOME}/pvaSrv

View File

@ -1,3 +0,0 @@
include "base.dbd"
include "PVAServerRegister.dbd"
registrar("exampleDatabaseRegister")

View File

@ -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;
}

View File

@ -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)
#===========================

View File

@ -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")

View 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);
}

View File

@ -17,6 +17,7 @@ exampleDatabaseMain_LIBS += pvData
exampleDatabaseMain_LIBS += pvAccess
exampleDatabaseMain_LIBS += pvDatabase
exampleDatabaseMain_LIBS += exampleDatabase
exampleDatabaseMain_LIBS += powerSupply
DBD += exampleDatabase.dbd

View File

@ -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);

View File

@ -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";

View File

@ -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

View File

@ -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

View 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

View File

@ -2,4 +2,4 @@ include "base.dbd"
include "PVAServerRegister.dbd"
include "PVAClientRegister.dbd"
include "registerChannelProviderLocal.dbd"
registrar("examplePVADoubleArrayGetRegister")
registrar("exampleLinkRegister")

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)
#===========================

View File

@ -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();

View File

@ -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);

View File

@ -0,0 +1 @@
registrar("exampleLinkRegister")

View File

@ -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);

View File

@ -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

View File

@ -5,4 +5,5 @@ PVCOMMON=${EPICSV4HOME}/pvCommonCPP
PVDATA=${EPICSV4HOME}/pvDataCPP
PVACCESS=${EPICSV4HOME}/pvAccessCPP
PVDATABASE=${EPICSV4HOME}/pvDatabaseCPP
PVDATABASETEST=${EPICSV4HOME}/pvDatabaseCPP/test
PVASRV=${EPICSV4HOME}/pvaSrv

View 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

View File

@ -2,4 +2,4 @@ include "base.dbd"
include "PVAServerRegister.dbd"
include "registerChannelProviderLocal.dbd"
include "dbPv.dbd"
include "powerSupply.dbd"
include "powerSupplyRegister.dbd"

View File

@ -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

View File

@ -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();
}
}}

View File

@ -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 */

View File

@ -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

View File

@ -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

View File

@ -0,0 +1 @@
registrar("powerSupplyRegister")