Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b8769aa0ca | ||
|
|
a938f2325c |
13
.gitignore
vendored
13
.gitignore
vendored
@@ -1,13 +0,0 @@
|
||||
bin/
|
||||
lib/
|
||||
doc/
|
||||
include/
|
||||
db/
|
||||
dbd/
|
||||
documentation/html
|
||||
documentation/*.tag
|
||||
envPaths
|
||||
configure/*.local
|
||||
!configure/ExampleRELEASE.local
|
||||
**/O.*
|
||||
QtC-*
|
||||
8
.hgflow
Normal file
8
.hgflow
Normal file
@@ -0,0 +1,8 @@
|
||||
[branchname]
|
||||
master = master
|
||||
develop = default
|
||||
feature = feature/
|
||||
release = release/
|
||||
hotfix = hotfix/
|
||||
support = support/
|
||||
|
||||
11
.hgignore
Normal file
11
.hgignore
Normal file
@@ -0,0 +1,11 @@
|
||||
^QtC-
|
||||
bin/
|
||||
lib/
|
||||
doc/
|
||||
include/
|
||||
db/
|
||||
dbd/
|
||||
documentation/html
|
||||
envPaths
|
||||
configure/.*\.local
|
||||
/O\..*
|
||||
9
.hgtags
Normal file
9
.hgtags
Normal file
@@ -0,0 +1,9 @@
|
||||
bba6a2491bdf73681cef01caf0bd89c87d7989cd 0.9.1
|
||||
abdc90bf52a0c31e24e2f9a079ef72350ee31686 before_merge_changesAfter3_0_2
|
||||
395f48d5196dde5bf7f24a1849aee3f8d92e91b8 3.1.0
|
||||
e2e041fa7d04a37836a4343589077001588ae031 4.0.0
|
||||
e2e041fa7d04a37836a4343589077001588ae031 4.0.0
|
||||
42dbe8a17f851861a16be7d426ef1206324aa197 4.0.0
|
||||
42dbe8a17f851861a16be7d426ef1206324aa197 4.0.0
|
||||
85d46a2614f925ccb423d6abd5dfe20d42fb5099 4.0.0
|
||||
541b0a7a645c63d136e397994ed0ab7178cf02cf 4.0.1
|
||||
38
README.md
38
README.md
@@ -1,38 +0,0 @@
|
||||
pvaDatabaseCPP
|
||||
============
|
||||
|
||||
|
||||
A brief description of a pvDatabase is that it is a set of network accessible, smart, memory resident records. Each record has data composed of a top level PVStructure. Each record has a name which is the channelName for pvAccess. A local Channel Provider implements the complete ChannelProvider and Channel interfaces as defined by pvAccess. The local provider provides access to the records in the pvDatabase. This local provider is accessed by the remote pvAccess server. A record is smart because code can be attached to a record, which is accessed via a method named process.
|
||||
pvaDatabase is a synchronous Database interface to pvAccess,
|
||||
which is callback based.
|
||||
pvaDatabase is thus easier to use than pvAccess itself.
|
||||
|
||||
See documentation/pvaDatabaseCPP.html for details.
|
||||
|
||||
Building
|
||||
--------
|
||||
|
||||
If a proper RELEASE.local file exists one directory level above pvaDatabaseCPP
|
||||
then just type:
|
||||
|
||||
make
|
||||
|
||||
If RELEASE.local does not exist then look at <b>configure/RELEASE</b>
|
||||
for directions for how to build.
|
||||
|
||||
Examples
|
||||
------------
|
||||
|
||||
The examples require the database in pvaDatabaseTestCPP.
|
||||
For example:
|
||||
|
||||
mrk> pwd
|
||||
/home/epicsv4/pvaDatabaseTestCPP/database/iocBoot/exampleDatabase
|
||||
mrk> ../../bin/linux-x86_64/exampleDatabase st.cmd
|
||||
|
||||
Status
|
||||
------
|
||||
|
||||
* The API is for EPICS Version 4 release 4.5.0
|
||||
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
EPICS V4 release 4.5
|
||||
====================
|
||||
|
||||
This release is one component of EPICS V4 release 4.5.
|
||||
|
||||
This is the first release of pvDatabaseCPP.
|
||||
|
||||
It provides functionality equivalent to pvDatabaseJava.
|
||||
|
||||
|
||||
@@ -59,9 +59,9 @@ bool ArrayPerformance::init()
|
||||
{
|
||||
|
||||
initPVRecord();
|
||||
PVLongArrayPtr pvLongArray = getPVStructure()->getSubField<PVLongArray>("value");
|
||||
if(!pvLongArray) return false;
|
||||
pvValue = pvLongArray;
|
||||
PVScalarArrayPtr pvScalarArray = getPVStructure()->getScalarArrayField("value",pvLong);
|
||||
if(!pvScalarArray) return false;
|
||||
pvValue = static_pointer_cast<PVLongArray>(pvScalarArray);
|
||||
ArrayPerformancePtr xxx = dynamic_pointer_cast<ArrayPerformance>(getPtrSelf());
|
||||
arrayPerformanceThread = ArrayPerformanceThreadPtr(new ArrayPerformanceThread(xxx));
|
||||
arrayPerformanceThread->init();
|
||||
|
||||
@@ -2,9 +2,7 @@
|
||||
TEMPLATE_TOP=$(EPICS_BASE)/templates/makeBaseApp/top
|
||||
|
||||
EPICS_BASE=/home/install/epics/base
|
||||
V4BASE=/home/epicsv4
|
||||
PVCOMMON=${V4BASE}/pvCommonCPP
|
||||
PVDATA=${V4BASE}/pvDataCPP
|
||||
NORMATIVETYPES=${V4BASE}/normativeTypesCPP
|
||||
PVACCESS=${V4BASE}/pvAccessCPP
|
||||
PVASRV=${V4BASE}/pvaSrv
|
||||
PVCOMMON=/home/hg/pvCommonCPP
|
||||
PVDATA=/home/hg/pvDataCPP
|
||||
PVACCESS=/home/hg/pvAccessCPP
|
||||
PVASRV=/home/hg/pvaSrv
|
||||
|
||||
25
documentation/RELEASE_NOTES.html
Normal file
25
documentation/RELEASE_NOTES.html
Normal file
@@ -0,0 +1,25 @@
|
||||
<h1>Release 4.0 IN DEVELOPMENT</h1>
|
||||
<p>The main changes since release 3.0.2 are:</p>
|
||||
<ul>
|
||||
<li>array semantics now enforce Copy On Write.</li>
|
||||
<li>String no longer defined.</li>
|
||||
<li>toString replaced by stream I/O </li>
|
||||
<li>union is new type.</li>
|
||||
<li>copy and monitor use new code in pvDataCPP</li>
|
||||
</ul>
|
||||
<h2>New Semantics for Arrays</h2>
|
||||
<p>pvDatabaseCPP has been changed to use the new array implementation from pvDataCPP.</p>
|
||||
<h2>String no longer defined</h2>
|
||||
<p>String is replaced by std::string.</p>
|
||||
<h2>toString replaced by stream I/O</h2>
|
||||
<p>All uses of toString have been changed to use the steam I/O that pvDataCPP implements.</p>
|
||||
<h2>union is a new basic type.</h2>
|
||||
<p>exampleDatabase now has example records for union and union array.
|
||||
There are records for regular union and for variant union.</p>
|
||||
<h2>copy</h2>
|
||||
<p>The implementation of copy and monitor for pvAccess has been changed
|
||||
to use the new monitor and copy support from pvDataCPP.</p>
|
||||
<h2>monitorPlugin</h2>
|
||||
<p>exampleDatabase now has a example plugin that implements onChange.</p>
|
||||
<h1>Release 0.9.2</h1>
|
||||
<p>This was the starting point for RELEASE_NOTES</p>
|
||||
50
documentation/RELEASE_NOTES.md
Normal file
50
documentation/RELEASE_NOTES.md
Normal file
@@ -0,0 +1,50 @@
|
||||
Release 4.0 IN DEVELOPMENT
|
||||
===========
|
||||
|
||||
The main changes since release 3.0.2 are:
|
||||
|
||||
* array semantics now enforce Copy On Write.
|
||||
* String no longer defined.
|
||||
* toString replaced by stream I/O
|
||||
* union is new type.
|
||||
* copy and monitor use new code in pvDataCPP
|
||||
|
||||
New Semantics for Arrays
|
||||
--------
|
||||
|
||||
pvDatabaseCPP has been changed to use the new array implementation from pvDataCPP.
|
||||
|
||||
String no longer defined
|
||||
---------
|
||||
|
||||
String is replaced by std::string.
|
||||
|
||||
|
||||
toString replaced by stream I/O
|
||||
---------
|
||||
|
||||
All uses of toString have been changed to use the steam I/O that pvDataCPP implements.
|
||||
|
||||
|
||||
union is a new basic type.
|
||||
------------
|
||||
|
||||
exampleDatabase now has example records for union and union array.
|
||||
There are records for regular union and for variant union.
|
||||
|
||||
|
||||
copy
|
||||
----
|
||||
|
||||
|
||||
The implementation of copy and monitor for pvAccess has been changed
|
||||
to use the new monitor and copy support from pvDataCPP.
|
||||
|
||||
monitorPlugin
|
||||
-------------
|
||||
|
||||
exampleDatabase now has a example plugin that implements onChange.
|
||||
|
||||
Release 0.9.2
|
||||
==========
|
||||
This was the starting point for RELEASE_NOTES
|
||||
@@ -1,4 +1,9 @@
|
||||
<h1>TODO</h1>
|
||||
<h2>recordList</h2>
|
||||
<p>This is putGet support that provides a list of all the records in an IOC.
|
||||
Since pvAccess implements pvlist this is no longer needed.
|
||||
Remove it from pvDatabaseCPP and pvIOCCPP.
|
||||
Also remove channelList from swtshell.</p>
|
||||
<h2>monitorPlugin</h2>
|
||||
<p>A debate is on-going about what semantics should be.</p>
|
||||
<h2>Must test record delete.</h2>
|
||||
|
||||
@@ -1,6 +1,15 @@
|
||||
TODO
|
||||
===========
|
||||
|
||||
|
||||
recordList
|
||||
----------
|
||||
|
||||
This is putGet support that provides a list of all the records in an IOC.
|
||||
Since pvAccess implements pvlist this is no longer needed.
|
||||
Remove it from pvDatabaseCPP and pvIOCCPP.
|
||||
Also remove channelList from swtshell.
|
||||
|
||||
monitorPlugin
|
||||
-------------
|
||||
|
||||
|
||||
@@ -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, 02-October-2015</h2>
|
||||
<h2 class="nocount">EPICS v4 Working Group, Working Draft, 09-Oct-2014</h2>
|
||||
<dl>
|
||||
<dt>Latest version:</dt>
|
||||
<dd><a
|
||||
@@ -46,11 +46,11 @@
|
||||
</dd>
|
||||
<dt>This version:</dt>
|
||||
<dd><a
|
||||
href= "pvDatabaseCPP_20151002.html">pvDatabaseCPP20151002.html
|
||||
href= "pvDatabaseCPP_20141009.html">pvDatabaseCPP_20141009.html
|
||||
</a> </dd>
|
||||
<dt>Previous version:</dt>
|
||||
<dd><a
|
||||
href= "pvDatabaseCPP_20140811.html">pvDatabaseCPP20140811.html
|
||||
href= "pvDatabaseCPP_20140811.html">pvDatabaseCPP_20140811.html
|
||||
</a> </dd>
|
||||
<dt>Editors:</dt>
|
||||
<dd>Marty Kraimer, BNL</dd>
|
||||
@@ -78,7 +78,7 @@ V4 control system programming environment:<br />
|
||||
|
||||
<h2 class="nocount">Status of this Document</h2>
|
||||
|
||||
<p>This is the 02-October-2015 version of of pvDatabaseCPP.</p>
|
||||
<p>This is the 09-Oct-2014 version of of pvDatabaseCPP.</p>
|
||||
<p>This version is a complete implementation of what is described in this manual.
|
||||
</p>
|
||||
</div>
|
||||
@@ -243,7 +243,7 @@ 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, examplePowerSupply,
|
||||
<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>
|
||||
@@ -320,7 +320,7 @@ The rest of this document discusses only the first phase.</p>
|
||||
</dd>
|
||||
</dl>
|
||||
<h3>Minimum Features Required for pvRecord</h3>
|
||||
<p>The first phase will only implement record processing, i. e.
|
||||
<p>The first phase will only implement record processing, i.e.
|
||||
the process method has to do everything itself without any generic field support.
|
||||
This will be sufficient for implementing many services.
|
||||
The following are the minimum features required</p>
|
||||
@@ -474,6 +474,22 @@ include "dbPv.dbd"
|
||||
<h3>src/special</h3>
|
||||
<p>This directory has the following files:</p>
|
||||
<dl>
|
||||
<dt>recordList.h</dt>
|
||||
<dd>This implements a PVRecord that provides a list of the names
|
||||
of the records in the PVDatabase.
|
||||
It also serves as an example of how to implement a service.
|
||||
The exampleDatabase creates an instance via the following code:
|
||||
<pre>
|
||||
recordName = "laptoprecordListPGRPC";
|
||||
pvRecord = RecordListRecord::create(recordName);
|
||||
if(pvRecord==NULL) {
|
||||
cout << "RecordListRecord::create failed" << endl;
|
||||
} else {
|
||||
result = master->addRecord(pvRecord);
|
||||
if(!result) cout<< "record " << recordName << " not added" << endl;
|
||||
}
|
||||
</pre>
|
||||
</dd>
|
||||
<dt>traceRecord.h</dt>
|
||||
<dd>This implements a PVRecord that can set the trace level for
|
||||
another record. See below for a discussion of trace level.</dd>
|
||||
@@ -529,7 +545,7 @@ typedef std::tr1::shared_ptr<PVDatabase> PVDatabasePtr;
|
||||
<ul>
|
||||
<li>This section uses the name record instead of "an instance of PVRecord".</li>
|
||||
<li>Most clients will access a record via the local channel provider,
|
||||
i. e. via pvAccess.
|
||||
i.e. via pvAccess.
|
||||
Thus this section is mainly of interest to
|
||||
the local channel provider and record implementers.</li>
|
||||
<li>Most readers will not care about most of the PVRecord methods.
|
||||
@@ -1100,6 +1116,45 @@ pvRecord = TraceRecord::create(recordName);
|
||||
result = master->addRecord(pvRecord);
|
||||
if(!result) cout<< "record " << recordName << " not added" << endl;
|
||||
</pre>
|
||||
<h3>recordList</h3>
|
||||
<p>This implements a PVRecord that allows a client to
|
||||
get the names of all the PVRecords in the PVDatabase.
|
||||
It follows the pattern of a channelPutGet
|
||||
record:
|
||||
</p>
|
||||
<pre>
|
||||
traceRecord
|
||||
structure argument
|
||||
string database master
|
||||
string regularExpression .*
|
||||
structure result
|
||||
string status
|
||||
string[] name
|
||||
</pre>
|
||||
where:
|
||||
<dl>
|
||||
<dt>database</dt>
|
||||
<dd>The name of the database. The default is "master"</dd>
|
||||
<dt>regularExpression</dt>
|
||||
<dd>For now this is ignored and the complete list of names is always
|
||||
returned.</dd>
|
||||
<dt>status</dt>
|
||||
<dd>The status of a putGet request.</dd>
|
||||
<dt>name</dt>
|
||||
<dd>The array of record names.</dd>
|
||||
</dl>
|
||||
<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>
|
||||
<p>testExampleServerMain.cpp has an example of how to create a traceRecord:
|
||||
</p>
|
||||
<pre>
|
||||
recordName = "recordListPGRPC";
|
||||
pvRecord = RecordListRecord::create(recordName);
|
||||
result = master->addRecord(pvRecord);
|
||||
if(!result) cout<< "record " << recordName << " not added" << endl;
|
||||
</pre>
|
||||
|
||||
<h2>exampleServer</h2>
|
||||
<h3>Overview</h3>
|
||||
@@ -1373,6 +1428,10 @@ int main(int argc,char *argv[])
|
||||
pvRecord = TraceRecord::create(recordName);
|
||||
result = master->addRecord(pvRecord);
|
||||
if(!result) cout<< "record " << recordName << " not added" << endl;
|
||||
recordName = "recordListPGRPC";
|
||||
pvRecord = RecordListRecord::create(recordName);
|
||||
result = master->addRecord(pvRecord);
|
||||
if(!result) cout<< "record " << recordName << " not added" << endl;
|
||||
ServerContext::shared_pointer pvaServer =
|
||||
startPVAServer(PVACCESS_ALL_PROVIDERS,0,true,true);
|
||||
PVStringArrayPtr pvNames = master->getRecordNames();
|
||||
@@ -1391,7 +1450,7 @@ This:
|
||||
<li>Gets a pointer to the master database.</li>
|
||||
<li>Creates the local Channel Provider. This starts the pvAccess server.</li>
|
||||
<li>Creates record exampleServer </li>
|
||||
<li>creates record traceRecordPGRPC</li>
|
||||
<li>creates records traceRecordPGRPC and recordListPGRPC</li>
|
||||
<li>lists all the records</li>
|
||||
<li>Runs forever until the user types exit on standard in.</li>
|
||||
</ul>
|
||||
@@ -1430,6 +1489,9 @@ or via PVAccess.</p>
|
||||
<dd>An array record that is an instance of a record with a process method
|
||||
that does nothing. It can be tested like exampleDouble. In addition channelArray can
|
||||
also be used.</dd>
|
||||
<dt>laptoprecordListPGRPC</dt>
|
||||
<dd>Implements the record expected by swtshell channelList.
|
||||
It can also be used via channelPutGet.</dd>
|
||||
<dt>traceRecordPGRPC</dt>
|
||||
<dd>This can be used via channelPutGet to set the trace level of another record.</dd>
|
||||
</dl>
|
||||
@@ -1487,11 +1549,11 @@ 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
|
||||
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>
|
||||
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();
|
||||
@@ -1943,7 +2005,7 @@ mrk> bin/linux-x86_64/arrayPerformanceMain
|
||||
<p>This means that the array will hold 10 million elements.
|
||||
The delay will be a millisecond.
|
||||
There will be a single monitor and it will connect directly
|
||||
to the local channelProvider, i. e. it will not use any network
|
||||
to the local channelProvider, i.e. it will not use any network
|
||||
connection.</p>
|
||||
<p>The report shows that arrayPerformance can perform about 50 iterations per second
|
||||
and is putting about 500million elements per second.
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
</dd>
|
||||
<dt>This version:</dt>
|
||||
<dd><a
|
||||
href="pvDatabaseCPP.html">pvDatabaseCPP.html</a>
|
||||
href="pvDatabaseCPP_20121127.html">pvDatabaseCPP_20121127.html</a>
|
||||
</dd>
|
||||
<dt>Previous version:</dt>
|
||||
<dd>None</dd>
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
</dd>
|
||||
<dt>This version:</dt>
|
||||
<dd><a
|
||||
href="pvDatabaseCPP_20121211.html">pvDatabaseCPP20121211.html</a>
|
||||
href="pvDatabaseCPP_20121211.html">pvDatabaseCPP_20121211.html</a>
|
||||
</dd>
|
||||
<dt>Previous version:</dt>
|
||||
<dd><a
|
||||
|
||||
@@ -46,11 +46,11 @@
|
||||
</dd>
|
||||
<dt>This version:</dt>
|
||||
<dd><a
|
||||
href="pvDatabaseCPP_20130417.html">pvDatabaseCPP20130417.html</a>
|
||||
href="pvDatabaseCPP_20130417.html">pvDatabaseCPP_20130417.html</a>
|
||||
</dd>
|
||||
<dt>Previous version:</dt>
|
||||
<dd><a
|
||||
href="pvDatabaseCPP_20121211.html">pvDatabaseCPP20121211.html</a>
|
||||
href="pvDatabaseCPP_20121211.html">pvDatabaseCPP_20121211.html</a>
|
||||
</dd>
|
||||
<dt>Editors:</dt>
|
||||
<dd>Marty Kraimer, BNL</dd>
|
||||
|
||||
@@ -46,11 +46,11 @@
|
||||
</dd>
|
||||
<dt>This version:</dt>
|
||||
<dd><a
|
||||
href="pvDatabaseCPP_20130516.html">pvDatabaseCPP20130516.html</a>
|
||||
href="pvDatabaseCPP_20130516.html">pvDatabaseCPP_20130516.html</a>
|
||||
</dd>
|
||||
<dt>Previous version:</dt>
|
||||
<dd><a
|
||||
href="pvDatabaseCPP_20130417.html">pvDatabaseCPP20130417.html</a>
|
||||
href="pvDatabaseCPP_20130417.html">pvDatabaseCPP_20130417.html</a>
|
||||
</dd>
|
||||
<dt>Editors:</dt>
|
||||
<dd>Marty Kraimer, BNL</dd>
|
||||
|
||||
@@ -46,11 +46,11 @@
|
||||
</dd>
|
||||
<dt>This version:</dt>
|
||||
<dd><a
|
||||
href="pvDatabaseCPP_20130523.html">pvDatabaseCPP20130523.html</a>
|
||||
href="pvDatabaseCPP_20130523.html">pvDatabaseCPP_20130523.html</a>
|
||||
</dd>
|
||||
<dt>Previous version:</dt>
|
||||
<dd><a
|
||||
href="pvDatabaseCPP_20130516.html">pvDatabaseCPP20130516.html</a>
|
||||
href="pvDatabaseCPP_20130516.html">pvDatabaseCPP_20130516.html</a>
|
||||
</dd>
|
||||
<dt>Editors:</dt>
|
||||
<dd>Marty Kraimer, BNL</dd>
|
||||
|
||||
@@ -46,11 +46,11 @@
|
||||
</dd>
|
||||
<dt>This version:</dt>
|
||||
<dd><a
|
||||
href="pvDatabaseCPP_20130627.html">pvDatabaseCPP20130627.html</a>
|
||||
href="pvDatabaseCPP_20130627.html">pvDatabaseCPP_20130627.html</a>
|
||||
</dd>
|
||||
<dt>Previous version:</dt>
|
||||
<dd><a
|
||||
href="pvDatabaseCPP_20130523.html">pvDatabaseCPP20130523.html</a>
|
||||
href="pvDatabaseCPP_20130523.html">pvDatabaseCPP_20130523.html</a>
|
||||
</dd>
|
||||
<dt>Editors:</dt>
|
||||
<dd>Marty Kraimer, BNL</dd>
|
||||
|
||||
@@ -46,11 +46,11 @@
|
||||
</dd>
|
||||
<dt>This version:</dt>
|
||||
<dd><a
|
||||
href= "pvDatabaseCPP_20130725.html">pvDatabaseCPP20130725.html</a>
|
||||
href= "pvDatabaseCPP_20130725.html">pvDatabase_CPP20130725.html</a>
|
||||
</dd>
|
||||
<dt>Previous version:</dt>
|
||||
<dd><a
|
||||
href="pvDatabaseCPP_20130627.html">pvDatabaseCPP20130627.html</a>
|
||||
href="pvDatabaseCPP_20130627.html">pvDatabase_CPP20130627.html</a>
|
||||
</dd>
|
||||
<dt>Editors:</dt>
|
||||
<dd>Marty Kraimer, BNL</dd>
|
||||
|
||||
@@ -46,10 +46,10 @@
|
||||
</dd>
|
||||
<dt>This version:</dt>
|
||||
<dd><a
|
||||
href= "pvDatabaseCPP_20130828.html">pvDatabaseCPP20130828.html</a>
|
||||
href= "pvDatabaseCPP_20130828.html">pvDatabase_CPP20130828.html</a>
|
||||
</dd>
|
||||
<dt>Previous version:</dt>
|
||||
<dd><a href="pvDatabaseCPP_20130725.html">pvDatabaseCPP20130725.html</a>
|
||||
<dd><a href="pvDatabaseCPP_20130725.html">pvDatabase_CPP20130725.html</a>
|
||||
</dd>
|
||||
<dt>Editors:</dt>
|
||||
<dd>Marty Kraimer, BNL</dd>
|
||||
|
||||
@@ -46,11 +46,11 @@
|
||||
</dd>
|
||||
<dt>This version:</dt>
|
||||
<dd><a
|
||||
href= "pvDatabaseCPP_20130904.html">pvDatabaseCPP20130904.html</a>
|
||||
href= "pvDatabaseCPP_20130904.html">pvDatabaseCPP_20130904.html</a>
|
||||
</dd>
|
||||
<dt>Previous version:</dt>
|
||||
<dd><a
|
||||
href= "pvDatabaseCPP_20130828.html">pvDatabaseCPP20130828.html</a>
|
||||
href= "pvDatabaseCPP_20130828.html">pvDatabaseCPP_20130828.html</a>
|
||||
</dd>
|
||||
<dt>Editors:</dt>
|
||||
<dd>Marty Kraimer, BNL</dd>
|
||||
|
||||
@@ -46,11 +46,11 @@
|
||||
</dd>
|
||||
<dt>This version:</dt>
|
||||
<dd><a
|
||||
href= "pvDatabaseCPP_20131112.html">pvDatabaseCPP20131112.html</a>
|
||||
href= "pvDatabaseCPP_20131112.html">pvDatabaseCPP_20131112.html</a>
|
||||
</dd>
|
||||
<dt>Previous version:</dt>
|
||||
<dd><a
|
||||
href= "pvDatabaseCPP_20130904.html">pvDatabaseCPP20130904.html</a>
|
||||
href= "pvDatabaseCPP_20130904.html">pvDatabaseCPP_20130904.html</a>
|
||||
</dd>
|
||||
<dt>Editors:</dt>
|
||||
<dd>Marty Kraimer, BNL</dd>
|
||||
|
||||
@@ -46,11 +46,11 @@
|
||||
</dd>
|
||||
<dt>This version:</dt>
|
||||
<dd><a
|
||||
href= "pvDatabaseCPP_20131113.html">pvDatabaseCPP20131113.html</a>
|
||||
href= "pvDatabaseCPP_20131113.html">pvDatabaseCPP_20131113.html</a>
|
||||
</dd>
|
||||
<dt>Previous version:</dt>
|
||||
<dd><a
|
||||
href= "pvDatabaseCPP_20131112.html">pvDatabaseCPP20131112.html</a>
|
||||
href= "pvDatabaseCPP_20131112.html">pvDatabaseCPP_20131112.html</a>
|
||||
</dd>
|
||||
<dt>Editors:</dt>
|
||||
<dd>Marty Kraimer, BNL</dd>
|
||||
|
||||
@@ -46,11 +46,11 @@
|
||||
</dd>
|
||||
<dt>This version:</dt>
|
||||
<dd><a
|
||||
href= "pvDatabaseCPP_20131120.html">pvDatabaseCPP20131120.html</a>
|
||||
href= "pvDatabaseCPP_20131120.html">pvDatabaseCPP_20131120.html</a>
|
||||
</dd>
|
||||
<dt>Previous version:</dt>
|
||||
<dd><a
|
||||
href= "pvDatabaseCPP_20131112.html">pvDatabaseCPP20131112.html</a>
|
||||
href= "pvDatabaseCPP_20131112.html">pvDatabaseCPP_20131112.html</a>
|
||||
</dd>
|
||||
<dt>Editors:</dt>
|
||||
<dd>Marty Kraimer, BNL</dd>
|
||||
|
||||
@@ -46,11 +46,11 @@
|
||||
</dd>
|
||||
<dt>This version:</dt>
|
||||
<dd><a
|
||||
href= "pvDatabaseCPP_20131121.html">pvDatabaseCPP20131121.html</a>
|
||||
href= "pvDatabaseCPP_20131121.html">pvDatabaseCPP_20131121.html</a>
|
||||
</dd>
|
||||
<dt>Previous version:</dt>
|
||||
<dd><a
|
||||
href= "pvDatabaseCPP_20131120.html">pvDatabaseCPP20131120.html</a>
|
||||
href= "pvDatabaseCPP_20131120.html">pvDatabaseCPP_20131120.html</a>
|
||||
</dd>
|
||||
<dt>Editors:</dt>
|
||||
<dd>Marty Kraimer, BNL</dd>
|
||||
|
||||
@@ -46,11 +46,11 @@
|
||||
</dd>
|
||||
<dt>This version:</dt>
|
||||
<dd><a
|
||||
href= "pvDatabaseCPP_20140207.html">pvDatabaseCPP20140207.html</a>
|
||||
href= "pvDatabaseCPP_20140207.html">pvDatabaseCPP_20140207.html</a>
|
||||
</dd>
|
||||
<dt>Previous version:</dt>
|
||||
<dd><a
|
||||
href= "pvDatabaseCPP_20131121.html">pvDatabaseCPP20131121.html</a>
|
||||
href= "pvDatabaseCPP_20131121.html">pvDatabaseCPP_20131121.html</a>
|
||||
</dd>
|
||||
<dt>Editors:</dt>
|
||||
<dd>Marty Kraimer, BNL</dd>
|
||||
|
||||
@@ -46,11 +46,11 @@
|
||||
</dd>
|
||||
<dt>This version:</dt>
|
||||
<dd><a
|
||||
href= "pvDatabaseCPP_20140219.html">pvDatabaseCPP20140219.html</a>
|
||||
href= "pvDatabaseCPP_20140219.html">pvDatabaseCPP_20140219.html</a>
|
||||
</dd>
|
||||
<dt>Previous version:</dt>
|
||||
<dd><a
|
||||
href= "pvDatabaseCPP_20140207.html">pvDatabaseCPP20140207.html</a>
|
||||
href= "pvDatabaseCPP_20140207.html">pvDatabaseCPP_20140207.html</a>
|
||||
</dd>
|
||||
<dt>Editors:</dt>
|
||||
<dd>Marty Kraimer, BNL</dd>
|
||||
|
||||
@@ -46,11 +46,11 @@
|
||||
</dd>
|
||||
<dt>This version:</dt>
|
||||
<dd><a
|
||||
href= "pvDatabaseCPP_20140710.html">pvDatabaseCPP20140710.html
|
||||
href= "pvDatabaseCPP_20140710.html">pvDatabaseCPP_20140710.html
|
||||
</a> </dd>
|
||||
<dt>Previous version:</dt>
|
||||
<dd><a
|
||||
href= "pvDatabaseCPP_20140219.html">pvDatabaseCPP20140219.html
|
||||
href= "pvDatabaseCPP_20140219.html">pvDatabaseCPP_20140219.html
|
||||
</a> </dd>
|
||||
<dt>Editors:</dt>
|
||||
<dd>Marty Kraimer, BNL</dd>
|
||||
|
||||
@@ -46,11 +46,11 @@
|
||||
</dd>
|
||||
<dt>This version:</dt>
|
||||
<dd><a
|
||||
href= "pvDatabaseCPP_20140811.html">pvDatabaseCPP20140811.html
|
||||
href= "pvDatabaseCPP_20140811.html">pvDatabaseCPP_20140811.html
|
||||
</a> </dd>
|
||||
<dt>Previous version:</dt>
|
||||
<dd><a
|
||||
href= "pvDatabaseCPP_20140710.html">pvDatabaseCPP20140710.html
|
||||
href= "pvDatabaseCPP_20140710.html">pvDatabaseCPP_20140710.html
|
||||
</a> </dd>
|
||||
<dt>Editors:</dt>
|
||||
<dd>Marty Kraimer, BNL</dd>
|
||||
|
||||
@@ -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, 02-October-2015</h2>
|
||||
<h2 class="nocount">EPICS v4 Working Group, Working Draft, 09-Oct-2014</h2>
|
||||
<dl>
|
||||
<dt>Latest version:</dt>
|
||||
<dd><a
|
||||
@@ -46,11 +46,11 @@
|
||||
</dd>
|
||||
<dt>This version:</dt>
|
||||
<dd><a
|
||||
href= "pvDatabaseCPP_20151002.html">pvDatabaseCPP20151002.html
|
||||
href= "pvDatabaseCPP_20141009.html">pvDatabaseCPP_20141009.html
|
||||
</a> </dd>
|
||||
<dt>Previous version:</dt>
|
||||
<dd><a
|
||||
href= "pvDatabaseCPP_20140811.html">pvDatabaseCPP20140811.html
|
||||
href= "pvDatabaseCPP_20140811.html">pvDatabaseCPP_20140811.html
|
||||
</a> </dd>
|
||||
<dt>Editors:</dt>
|
||||
<dd>Marty Kraimer, BNL</dd>
|
||||
@@ -78,7 +78,7 @@ V4 control system programming environment:<br />
|
||||
|
||||
<h2 class="nocount">Status of this Document</h2>
|
||||
|
||||
<p>This is the 02-October-2015 version of of pvDatabaseCPP.</p>
|
||||
<p>This is the 09-Oct-2014 version of of pvDatabaseCPP.</p>
|
||||
<p>This version is a complete implementation of what is described in this manual.
|
||||
</p>
|
||||
</div>
|
||||
@@ -243,7 +243,7 @@ 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, examplePowerSupply,
|
||||
<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>
|
||||
@@ -320,7 +320,7 @@ The rest of this document discusses only the first phase.</p>
|
||||
</dd>
|
||||
</dl>
|
||||
<h3>Minimum Features Required for pvRecord</h3>
|
||||
<p>The first phase will only implement record processing, i. e.
|
||||
<p>The first phase will only implement record processing, i.e.
|
||||
the process method has to do everything itself without any generic field support.
|
||||
This will be sufficient for implementing many services.
|
||||
The following are the minimum features required</p>
|
||||
@@ -474,6 +474,22 @@ include "dbPv.dbd"
|
||||
<h3>src/special</h3>
|
||||
<p>This directory has the following files:</p>
|
||||
<dl>
|
||||
<dt>recordList.h</dt>
|
||||
<dd>This implements a PVRecord that provides a list of the names
|
||||
of the records in the PVDatabase.
|
||||
It also serves as an example of how to implement a service.
|
||||
The exampleDatabase creates an instance via the following code:
|
||||
<pre>
|
||||
recordName = "laptoprecordListPGRPC";
|
||||
pvRecord = RecordListRecord::create(recordName);
|
||||
if(pvRecord==NULL) {
|
||||
cout << "RecordListRecord::create failed" << endl;
|
||||
} else {
|
||||
result = master->addRecord(pvRecord);
|
||||
if(!result) cout<< "record " << recordName << " not added" << endl;
|
||||
}
|
||||
</pre>
|
||||
</dd>
|
||||
<dt>traceRecord.h</dt>
|
||||
<dd>This implements a PVRecord that can set the trace level for
|
||||
another record. See below for a discussion of trace level.</dd>
|
||||
@@ -529,7 +545,7 @@ typedef std::tr1::shared_ptr<PVDatabase> PVDatabasePtr;
|
||||
<ul>
|
||||
<li>This section uses the name record instead of "an instance of PVRecord".</li>
|
||||
<li>Most clients will access a record via the local channel provider,
|
||||
i. e. via pvAccess.
|
||||
i.e. via pvAccess.
|
||||
Thus this section is mainly of interest to
|
||||
the local channel provider and record implementers.</li>
|
||||
<li>Most readers will not care about most of the PVRecord methods.
|
||||
@@ -1100,6 +1116,45 @@ pvRecord = TraceRecord::create(recordName);
|
||||
result = master->addRecord(pvRecord);
|
||||
if(!result) cout<< "record " << recordName << " not added" << endl;
|
||||
</pre>
|
||||
<h3>recordList</h3>
|
||||
<p>This implements a PVRecord that allows a client to
|
||||
get the names of all the PVRecords in the PVDatabase.
|
||||
It follows the pattern of a channelPutGet
|
||||
record:
|
||||
</p>
|
||||
<pre>
|
||||
traceRecord
|
||||
structure argument
|
||||
string database master
|
||||
string regularExpression .*
|
||||
structure result
|
||||
string status
|
||||
string[] name
|
||||
</pre>
|
||||
where:
|
||||
<dl>
|
||||
<dt>database</dt>
|
||||
<dd>The name of the database. The default is "master"</dd>
|
||||
<dt>regularExpression</dt>
|
||||
<dd>For now this is ignored and the complete list of names is always
|
||||
returned.</dd>
|
||||
<dt>status</dt>
|
||||
<dd>The status of a putGet request.</dd>
|
||||
<dt>name</dt>
|
||||
<dd>The array of record names.</dd>
|
||||
</dl>
|
||||
<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>
|
||||
<p>testExampleServerMain.cpp has an example of how to create a traceRecord:
|
||||
</p>
|
||||
<pre>
|
||||
recordName = "recordListPGRPC";
|
||||
pvRecord = RecordListRecord::create(recordName);
|
||||
result = master->addRecord(pvRecord);
|
||||
if(!result) cout<< "record " << recordName << " not added" << endl;
|
||||
</pre>
|
||||
|
||||
<h2>exampleServer</h2>
|
||||
<h3>Overview</h3>
|
||||
@@ -1373,6 +1428,10 @@ int main(int argc,char *argv[])
|
||||
pvRecord = TraceRecord::create(recordName);
|
||||
result = master->addRecord(pvRecord);
|
||||
if(!result) cout<< "record " << recordName << " not added" << endl;
|
||||
recordName = "recordListPGRPC";
|
||||
pvRecord = RecordListRecord::create(recordName);
|
||||
result = master->addRecord(pvRecord);
|
||||
if(!result) cout<< "record " << recordName << " not added" << endl;
|
||||
ServerContext::shared_pointer pvaServer =
|
||||
startPVAServer(PVACCESS_ALL_PROVIDERS,0,true,true);
|
||||
PVStringArrayPtr pvNames = master->getRecordNames();
|
||||
@@ -1391,7 +1450,7 @@ This:
|
||||
<li>Gets a pointer to the master database.</li>
|
||||
<li>Creates the local Channel Provider. This starts the pvAccess server.</li>
|
||||
<li>Creates record exampleServer </li>
|
||||
<li>creates record traceRecordPGRPC</li>
|
||||
<li>creates records traceRecordPGRPC and recordListPGRPC</li>
|
||||
<li>lists all the records</li>
|
||||
<li>Runs forever until the user types exit on standard in.</li>
|
||||
</ul>
|
||||
@@ -1430,6 +1489,9 @@ or via PVAccess.</p>
|
||||
<dd>An array record that is an instance of a record with a process method
|
||||
that does nothing. It can be tested like exampleDouble. In addition channelArray can
|
||||
also be used.</dd>
|
||||
<dt>laptoprecordListPGRPC</dt>
|
||||
<dd>Implements the record expected by swtshell channelList.
|
||||
It can also be used via channelPutGet.</dd>
|
||||
<dt>traceRecordPGRPC</dt>
|
||||
<dd>This can be used via channelPutGet to set the trace level of another record.</dd>
|
||||
</dl>
|
||||
@@ -1487,11 +1549,11 @@ 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
|
||||
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>
|
||||
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();
|
||||
@@ -1943,7 +2005,7 @@ mrk> bin/linux-x86_64/arrayPerformanceMain
|
||||
<p>This means that the array will hold 10 million elements.
|
||||
The delay will be a millisecond.
|
||||
There will be a single monitor and it will connect directly
|
||||
to the local channelProvider, i. e. it will not use any network
|
||||
to the local channelProvider, i.e. it will not use any network
|
||||
connection.</p>
|
||||
<p>The report shows that arrayPerformance can perform about 50 iterations per second
|
||||
and is putting about 500million elements per second.
|
||||
@@ -4,3 +4,4 @@ include "registerChannelProviderLocal.dbd"
|
||||
include "dbPv.dbd"
|
||||
include "powerSupplyRegister.dbd"
|
||||
registrar("exampleDatabaseRegister")
|
||||
registrar("exampleMonitorPluginRegister")
|
||||
|
||||
@@ -3,5 +3,5 @@ include $(TOP)/configure/CONFIG
|
||||
DIRS += $(wildcard *ioc*)
|
||||
DIRS += $(wildcard as*)
|
||||
DIRS += $(wildcard example*)
|
||||
include $(CONFIG)/RULES_DIRS
|
||||
include $(EPICS_BASE)/configure/RULES_DIRS
|
||||
|
||||
|
||||
@@ -7,10 +7,13 @@ include $(TOP)/configure/CONFIG
|
||||
DBD += exampleDatabase.dbd
|
||||
|
||||
INC += exampleDatabase.h
|
||||
INC += exampleMonitorPlugin.h
|
||||
|
||||
LIBRARY += exampleDatabase
|
||||
exampleDatabase_SRCS += exampleDatabase.cpp
|
||||
exampleDatabase_SRCS += exampleMonitorPlugin.cpp
|
||||
exampleDatabase_SRCS += exampleDatabaseRegister.cpp
|
||||
exampleDatabase_SRCS += exampleMonitorPluginRegister.cpp
|
||||
exampleDatabase_LIBS += powerSupply
|
||||
exampleDatabase_LIBS += pvDatabase
|
||||
exampleDatabase_LIBS += pvAccess
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <pv/standardField.h>
|
||||
#include <pv/standardPVField.h>
|
||||
#include <pv/channelProviderLocal.h>
|
||||
#include <pv/recordList.h>
|
||||
#include <pv/traceRecord.h>
|
||||
|
||||
#include <pv/powerSupply.h>
|
||||
@@ -155,5 +156,13 @@ void ExampleDatabase::create()
|
||||
result = master->addRecord(psr);
|
||||
if(!result) cout<< "record " << recordName << " not added" << endl;
|
||||
}
|
||||
recordName = "laptoprecordListPGRPC";
|
||||
pvRecord = RecordListRecord::create(recordName);
|
||||
if(!pvRecord) {
|
||||
cout << "RecordListRecord::create failed" << endl;
|
||||
} else {
|
||||
result = master->addRecord(pvRecord);
|
||||
if(!result) cout<< "record " << recordName << " not added" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
registrar("exampleDatabaseRegister")
|
||||
registrar("exampleMonitorPluginRegister")
|
||||
|
||||
@@ -10,27 +10,48 @@
|
||||
|
||||
/* 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/serverContext.h>
|
||||
|
||||
#include <pv/exampleDatabase.h>
|
||||
#include <pv/exampleMonitorPlugin.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();
|
||||
ExampleMonitorPlugin::create();
|
||||
ServerContext::shared_pointer ctx =
|
||||
startPVAServer(PVACCESS_ALL_PROVIDERS,0,true,true);
|
||||
cout << "exampleDatabase\n";
|
||||
PVStringArrayPtr pvNames = master->getRecordNames();
|
||||
cout << "recordNames" << endl << *pvNames << endl;
|
||||
string str;
|
||||
while(true) {
|
||||
cout << "Type exit to stop: \n";
|
||||
getline(cin,str);
|
||||
if(str.compare("exit")==0) break;
|
||||
|
||||
ContextLocal::shared_pointer contextLocal = ContextLocal::create();
|
||||
contextLocal->start();
|
||||
|
||||
cout << "pvAccess server exampleDatabase running..." << endl;
|
||||
epics::pvData::PVStringArrayPtr pvNames = PVDatabase::getMaster()->getRecordNames();
|
||||
cout << "Hosted records: " << endl << *pvNames << endl;
|
||||
|
||||
contextLocal->waitForExit();
|
||||
|
||||
}
|
||||
ctx->destroy();
|
||||
epicsThreadSleep(1.0);
|
||||
channelProvider->destroy();
|
||||
return 0;
|
||||
}
|
||||
|
||||
101
exampleDatabase/src/exampleMonitorPlugin.cpp
Normal file
101
exampleDatabase/src/exampleMonitorPlugin.cpp
Normal file
@@ -0,0 +1,101 @@
|
||||
/* exampleMonitorPlugin.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 2014.04.16
|
||||
*/
|
||||
|
||||
#include <pv/convert.h>
|
||||
#include <pv/monitorPlugin.h>
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include <pv/exampleMonitorPlugin.h>
|
||||
|
||||
using namespace epics::pvData;
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
using std::string;
|
||||
|
||||
namespace epics { namespace pvDatabase {
|
||||
|
||||
static string pluginName("onChange");
|
||||
static ConvertPtr convert(getConvert());
|
||||
|
||||
class OnChangePlugin;
|
||||
typedef std::tr1::shared_ptr<OnChangePlugin> OnChangePluginPtr;
|
||||
class OnChangePluginCreator;
|
||||
typedef std::tr1::shared_ptr<OnChangePluginCreator> OnChangePluginCreatorPtr;
|
||||
|
||||
class OnChangePlugin : public MonitorPlugin
|
||||
{
|
||||
public:
|
||||
virtual ~OnChangePlugin(){}
|
||||
OnChangePlugin() {}
|
||||
bool init(
|
||||
FieldConstPtr const &field,
|
||||
StructureConstPtr const &top,
|
||||
PVStructurePtr const &pvFieldOptions)
|
||||
{
|
||||
pvField = getPVDataCreate()->createPVField(field);
|
||||
raiseMonitor = true;
|
||||
if(pvFieldOptions) {
|
||||
PVStringPtr pvString =
|
||||
pvFieldOptions->getSubField<PVString>("raiseMonitor");
|
||||
if(pvString) {
|
||||
string value = pvString->get();
|
||||
if(value.compare("false")==0) raiseMonitor = false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
virtual string &getName(){return pluginName;}
|
||||
virtual bool causeMonitor(
|
||||
PVFieldPtr const &pvNew,
|
||||
PVStructurePtr const &pvTop,
|
||||
MonitorElementPtr const &monitorElement)
|
||||
{
|
||||
bool isSame = convert->equals(pvNew,pvField);
|
||||
if(isSame) return false;
|
||||
convert->copy(pvNew,pvField);
|
||||
return raiseMonitor;
|
||||
}
|
||||
private:
|
||||
PVFieldPtr pvField;
|
||||
bool raiseMonitor;
|
||||
};
|
||||
|
||||
class OnChangePluginCreator : public MonitorPluginCreator
|
||||
{
|
||||
public:
|
||||
virtual string &getName(){return pluginName;}
|
||||
virtual MonitorPluginPtr create(
|
||||
FieldConstPtr const &field,
|
||||
StructureConstPtr const &top,
|
||||
PVStructurePtr const &pvFieldOptions)
|
||||
{
|
||||
OnChangePluginPtr plugin(new OnChangePlugin());
|
||||
bool result = plugin->init(field,top,pvFieldOptions);
|
||||
if(!result) return MonitorPluginPtr();
|
||||
return plugin;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
void ExampleMonitorPlugin::create()
|
||||
{
|
||||
static OnChangePluginCreatorPtr plugin;
|
||||
static Mutex mutex;
|
||||
Lock xx(mutex);
|
||||
if(!plugin) {
|
||||
plugin = OnChangePluginCreatorPtr(new OnChangePluginCreator());
|
||||
MonitorPluginManager::get()->addPlugin(pluginName,plugin);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}}
|
||||
|
||||
40
exampleDatabase/src/exampleMonitorPlugin.h
Normal file
40
exampleDatabase/src/exampleMonitorPlugin.h
Normal file
@@ -0,0 +1,40 @@
|
||||
/* exampleMonitorPlugin.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 2014.04.16
|
||||
*/
|
||||
#ifndef EXAMPLEMONITORPLUGIN_H
|
||||
#define EXAMPLEMONITORPLUGIN_H
|
||||
|
||||
#ifdef epicsExportSharedSymbols
|
||||
# define examplemonitorPluginEpicsExportSharedSymbols
|
||||
# undef epicsExportSharedSymbols
|
||||
#endif
|
||||
|
||||
#include <pv/pvDatabase.h>
|
||||
#include <pv/monitorPlugin.h>
|
||||
|
||||
#ifdef examplemonitorPluginEpicsExportSharedSymbols
|
||||
# define epicsExportSharedSymbols
|
||||
# undef examplemonitorPluginEpicsExportSharedSymbols
|
||||
#endif
|
||||
|
||||
#include <shareLib.h>
|
||||
|
||||
|
||||
namespace epics { namespace pvDatabase {
|
||||
|
||||
class epicsShareClass ExampleMonitorPlugin{
|
||||
public:
|
||||
static void create();
|
||||
};
|
||||
|
||||
|
||||
}}
|
||||
|
||||
#endif /* EXAMPLEMONITORPLUGIN_H */
|
||||
65
exampleDatabase/src/exampleMonitorPluginRegister.cpp
Normal file
65
exampleDatabase/src/exampleMonitorPluginRegister.cpp
Normal file
@@ -0,0 +1,65 @@
|
||||
/*exampleMonitorPlugin.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.07.24
|
||||
*/
|
||||
|
||||
|
||||
/* Author: Marty Kraimer */
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdlib>
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <cstdio>
|
||||
#include <memory>
|
||||
|
||||
#include <cantProceed.h>
|
||||
#include <epicsStdio.h>
|
||||
#include <epicsMutex.h>
|
||||
#include <epicsEvent.h>
|
||||
#include <epicsThread.h>
|
||||
#include <iocsh.h>
|
||||
|
||||
#include <pv/pvIntrospect.h>
|
||||
#include <pv/pvData.h>
|
||||
#include <pv/pvAccess.h>
|
||||
#include <pv/pvDatabase.h>
|
||||
|
||||
#include <epicsExport.h>
|
||||
#include <pv/exampleMonitorPlugin.h>
|
||||
|
||||
|
||||
using namespace epics::pvData;
|
||||
using namespace epics::pvAccess;
|
||||
using namespace epics::pvDatabase;
|
||||
|
||||
|
||||
static const iocshFuncDef exampleMonitorPluginFuncDef = {
|
||||
"exampleMonitorPlugin", 0,0 };
|
||||
|
||||
|
||||
static void exampleMonitorPluginCallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
ExampleMonitorPlugin::create();
|
||||
}
|
||||
|
||||
static void exampleMonitorPluginRegister(void)
|
||||
{
|
||||
std::cout << "exampleMonitorPluginRegister\n";
|
||||
static int firstTime = 1;
|
||||
if (firstTime) {
|
||||
firstTime = 0;
|
||||
iocshRegister(&exampleMonitorPluginFuncDef, exampleMonitorPluginCallFunc);
|
||||
}
|
||||
std::cout << "exampleMonitorPluginRegister returning\n";
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
epicsExportRegistrar(exampleMonitorPluginRegister);
|
||||
}
|
||||
@@ -3,5 +3,5 @@ include $(TOP)/configure/CONFIG
|
||||
DIRS += $(wildcard *ioc*)
|
||||
DIRS += $(wildcard as*)
|
||||
DIRS += $(wildcard example*)
|
||||
include $(CONFIG)/RULES_DIRS
|
||||
include $(EPICS_BASE)/configure/RULES_DIRS
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
*/
|
||||
|
||||
#include <pv/standardPVField.h>
|
||||
#include <pv/convert.h>
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include <pv/exampleLink.h>
|
||||
@@ -45,7 +46,8 @@ ExampleLink::ExampleLink(
|
||||
PVStructurePtr const & pvStructure)
|
||||
: PVRecord(recordName,pvStructure),
|
||||
providerName(providerName),
|
||||
channelName(channelName)
|
||||
channelName(channelName),
|
||||
convert(getConvert())
|
||||
{
|
||||
}
|
||||
|
||||
@@ -61,7 +63,8 @@ bool ExampleLink::init()
|
||||
PVStructurePtr pvStructure = getPVRecordStructure()->getPVStructure();
|
||||
pvTimeStamp.attach(pvStructure->getSubField("timeStamp"));
|
||||
pvAlarm.attach(pvStructure->getSubField("alarm"));
|
||||
pvValue = pvStructure->getSubField<PVDoubleArray>("value");
|
||||
pvValue = static_pointer_cast<PVDoubleArray>(
|
||||
pvStructure->getScalarArrayField("value",pvDouble));
|
||||
if(!pvValue) {
|
||||
return false;
|
||||
}
|
||||
@@ -92,7 +95,8 @@ bool ExampleLink::init()
|
||||
<< status.getMessage() << endl;
|
||||
return false;
|
||||
}
|
||||
getPVValue = getPVStructure->getSubField<PVDoubleArray>("value");
|
||||
getPVValue = static_pointer_cast<PVDoubleArray>(
|
||||
getPVStructure->getScalarArrayField("value",pvDouble));
|
||||
if(!getPVValue) {
|
||||
cout << getRecordName() << " get value not PVDoubleArray" << endl;
|
||||
return false;
|
||||
@@ -117,7 +121,7 @@ void ExampleLink::process()
|
||||
}
|
||||
alarm.setSeverity(severity);
|
||||
} else {
|
||||
pvValue->copyUnchecked(*getPVValue);
|
||||
convert->copy(getPVValue,pvValue);
|
||||
}
|
||||
alarm.setMessage(status.getMessage());
|
||||
pvAlarm.set(alarm);
|
||||
@@ -156,7 +160,7 @@ void ExampleLink::getDone(
|
||||
BitSetPtr const & bitSet)
|
||||
{
|
||||
this->status = status;
|
||||
getPVStructure->copyUnchecked(*pvStructure);
|
||||
convert->copyStructure(pvStructure,getPVStructure);
|
||||
this->bitSet = bitSet;
|
||||
event.signal();
|
||||
}
|
||||
|
||||
@@ -83,6 +83,7 @@ private:
|
||||
epics::pvData::PVStructurePtr const & pvStructure);
|
||||
std::string providerName;
|
||||
std::string channelName;
|
||||
epics::pvData::ConvertPtr convert;
|
||||
epics::pvData::PVDoubleArrayPtr pvValue;
|
||||
epics::pvData::PVTimeStamp pvTimeStamp;
|
||||
epics::pvData::TimeStamp timeStamp;
|
||||
|
||||
@@ -3,5 +3,5 @@ include $(TOP)/configure/CONFIG
|
||||
DIRS += $(wildcard *ioc*)
|
||||
DIRS += $(wildcard as*)
|
||||
DIRS += $(wildcard power*)
|
||||
include $(CONFIG)/RULES_DIRS
|
||||
include $(EPICS_BASE)/configure/RULES_DIRS
|
||||
|
||||
|
||||
@@ -10,14 +10,24 @@
|
||||
|
||||
/* Author: Marty Kraimer */
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdlib>
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <cstdio>
|
||||
#include <memory>
|
||||
#include <iostream>
|
||||
|
||||
#include <pv/standardField.h>
|
||||
#include <pv/standardPVField.h>
|
||||
#include <pv/recordList.h>
|
||||
#include <pv/powerSupply.h>
|
||||
#include <pv/traceRecord.h>
|
||||
#include <pv/channelProviderLocal.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;
|
||||
@@ -26,25 +36,37 @@ using namespace epics::pvDatabase;
|
||||
int main(int argc,char *argv[])
|
||||
{
|
||||
PVDatabasePtr master = PVDatabase::getMaster();
|
||||
|
||||
ChannelProviderLocalPtr channelProvider = getChannelProviderLocal();
|
||||
PVRecordPtr pvRecord;
|
||||
bool result = false;
|
||||
bool result(false);
|
||||
string recordName;
|
||||
|
||||
recordName = "powerSupply";
|
||||
PVStructurePtr pv = createPowerSupply();
|
||||
pvRecord = PowerSupply::create(recordName,pv);
|
||||
result = master->addRecord(pvRecord);
|
||||
cout << "result of addRecord " << recordName << " " << result << endl;
|
||||
|
||||
recordName = "traceRecordPGRPC";
|
||||
pvRecord = TraceRecord::create(recordName);
|
||||
result = master->addRecord(pvRecord);
|
||||
if (!result) cout<< "record " << recordName << " not added" << endl;
|
||||
|
||||
ContextLocal::shared_pointer contextLocal = ContextLocal::create();
|
||||
contextLocal->start(true);
|
||||
if(!result) cout<< "record " << recordName << " not added" << endl;
|
||||
recordName = "laptoprecordListPGRPC";
|
||||
pvRecord = RecordListRecord::create(recordName);
|
||||
result = master->addRecord(pvRecord);
|
||||
if(!result) cout<< "record " << recordName << " not added" << endl;
|
||||
ServerContext::shared_pointer pvaServer =
|
||||
startPVAServer(PVACCESS_ALL_PROVIDERS,0,true,true);
|
||||
cout << "powerSupply\n";
|
||||
string str;
|
||||
while(true) {
|
||||
cout << "Type exit to stop: \n";
|
||||
getline(cin,str);
|
||||
if(str.compare("exit")==0) break;
|
||||
|
||||
}
|
||||
pvaServer->shutdown();
|
||||
epicsThreadSleep(1.0);
|
||||
pvaServer->destroy();
|
||||
channelProvider->destroy();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,5 +3,5 @@ include $(TOP)/configure/CONFIG
|
||||
DIRS += $(wildcard *ioc*)
|
||||
DIRS += $(wildcard as*)
|
||||
DIRS += $(wildcard example*)
|
||||
include $(CONFIG)/RULES_DIRS
|
||||
include $(EPICS_BASE)/configure/RULES_DIRS
|
||||
|
||||
|
||||
@@ -66,9 +66,9 @@ bool ExampleServer::init()
|
||||
|
||||
initPVRecord();
|
||||
PVFieldPtr pvField;
|
||||
pvArgumentValue = getPVStructure()->getSubField<PVString>("argument.value");
|
||||
pvArgumentValue = getPVStructure()->getStringField("argument.value");
|
||||
if(pvArgumentValue.get()==NULL) return false;
|
||||
pvResultValue = getPVStructure()->getSubField<PVString>("result.value");
|
||||
pvResultValue = getPVStructure()->getStringField("result.value");
|
||||
if(pvResultValue.get()==NULL) return false;
|
||||
pvTimeStamp.attach(getPVStructure()->getSubField("result.timeStamp"));
|
||||
return true;
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
* @author mrk
|
||||
* @date 2013.04.02
|
||||
*/
|
||||
#ifndef EXAMPLESERVER_H
|
||||
#define EXAMPLESERVER_H
|
||||
#ifndef EXAMPLECOUNTER_H
|
||||
#define EXAMPLECOUNTER_H
|
||||
|
||||
#ifdef epicsExportSharedSymbols
|
||||
# define exampleServerEpicsExportSharedSymbols
|
||||
@@ -58,4 +58,4 @@ private:
|
||||
|
||||
}}
|
||||
|
||||
#endif /* EXAMPLESERVER_H */
|
||||
#endif /* EXAMPLECOUNTER_H */
|
||||
|
||||
@@ -10,14 +10,24 @@
|
||||
|
||||
/* Author: Marty Kraimer */
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdlib>
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <cstdio>
|
||||
#include <memory>
|
||||
#include <iostream>
|
||||
|
||||
#include <pv/standardField.h>
|
||||
#include <pv/standardPVField.h>
|
||||
#include <pv/exampleServer.h>
|
||||
#include <pv/traceRecord.h>
|
||||
#include <pv/recordList.h>
|
||||
#include <pv/channelProviderLocal.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;
|
||||
@@ -26,30 +36,38 @@ using namespace epics::exampleServer;
|
||||
int main(int argc,char *argv[])
|
||||
{
|
||||
PVDatabasePtr master = PVDatabase::getMaster();
|
||||
ChannelProviderLocalPtr channelProvider = getChannelProviderLocal();
|
||||
PVRecordPtr pvRecord;
|
||||
bool result = false;
|
||||
bool result(false);
|
||||
string recordName;
|
||||
|
||||
recordName = "exampleServer";
|
||||
pvRecord = ExampleServer::create(recordName);
|
||||
result = master->addRecord(pvRecord);
|
||||
if(!result) cout<< "record " << recordName << " not added" << endl;
|
||||
|
||||
recordName = "traceRecordPGRPC";
|
||||
pvRecord = TraceRecord::create(recordName);
|
||||
result = master->addRecord(pvRecord);
|
||||
if(!result) cout<< "record " << recordName << " not added" << endl;
|
||||
|
||||
|
||||
ContextLocal::shared_pointer contextLocal = ContextLocal::create();
|
||||
contextLocal->start();
|
||||
|
||||
recordName = "laptoprecordListPGRPC";
|
||||
pvRecord = RecordListRecord::create(recordName);
|
||||
result = master->addRecord(pvRecord);
|
||||
if(!result) cout<< "record " << recordName << " not added" << endl;
|
||||
ServerContext::shared_pointer pvaServer =
|
||||
startPVAServer(PVACCESS_ALL_PROVIDERS,0,true,true);
|
||||
PVStringArrayPtr pvNames = master->getRecordNames();
|
||||
shared_vector<const string> names = pvNames->view();
|
||||
for(size_t i=0; i<names.size(); ++i) cout << names[i] << endl;
|
||||
string str;
|
||||
while(true) {
|
||||
cout << "Type exit to stop: \n";
|
||||
getline(cin,str);
|
||||
if(str.compare("exit")==0) break;
|
||||
|
||||
contextLocal->waitForExit();
|
||||
|
||||
}
|
||||
pvaServer->shutdown();
|
||||
epicsThreadSleep(1.0);
|
||||
pvaServer->destroy();
|
||||
channelProvider->destroy();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include <pv/pvData.h>
|
||||
#include <pv/pvAccess.h>
|
||||
#include <pv/pvDatabase.h>
|
||||
#include <pv/recordList.h>
|
||||
|
||||
#include <epicsExport.h>
|
||||
#include <pv/exampleServer.h>
|
||||
@@ -55,6 +56,14 @@ static void exampleServerCallFunc(const iocshArgBuf *args)
|
||||
ExampleServerPtr record = ExampleServer::create(recordName);
|
||||
bool result = master->addRecord(record);
|
||||
if(!result) cout << "recordname" << " not added" << endl;
|
||||
PVRecordPtr pvRecord = RecordListRecord::create(
|
||||
"laptoprecordListPGRPC");
|
||||
if(!pvRecord) {
|
||||
cout << "RecordListRecord::create failed" << endl;
|
||||
} else {
|
||||
result = master->addRecord(pvRecord);
|
||||
if(!result) cout<< "record " << recordName << " not added" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
static void exampleServerRegister(void)
|
||||
|
||||
@@ -1,28 +1,13 @@
|
||||
# pvDatabase C++ implementation
|
||||
# pvDatabaseCPP
|
||||
# Jenkins @ Cloudbees build script
|
||||
#
|
||||
# Jenkins invokes scripts with the "-ex" option. So the build is considered a failure
|
||||
# if any of the commands exits with a non-zero exit code.
|
||||
#
|
||||
# Author: Ralph Lange <ralph.lange@gmx.de>
|
||||
# Author: Ralph Lange <Ralph.Lange@gmx.de>
|
||||
# Copyright (C) 2014 Helmholtz-Zentrum Berlin für Materialien und Energie GmbH
|
||||
# Copyright (C) 2014-2015 ITER Organization.
|
||||
# All rights reserved. Use is subject to license terms.
|
||||
|
||||
###########################################
|
||||
# Determine EPICS Base version
|
||||
|
||||
DEFAULT_BASE=3.14.12.5
|
||||
|
||||
BASE=${1:-${DEFAULT_BASE}}
|
||||
USE_MB=${2:-"MB_NO"}
|
||||
|
||||
# Dependent module branches (empty = master)
|
||||
PVCOMMON_BRANCH="Release-4.1-"
|
||||
PVDATA_BRANCH="Release-5.0-"
|
||||
PVACCESS_BRANCH="Release-4.1-"
|
||||
PVASRV_BRANCH="Release-0.11-"
|
||||
|
||||
###########################################
|
||||
# Fetch and unpack dependencies
|
||||
|
||||
@@ -32,20 +17,17 @@ rm -fr ${STUFF}
|
||||
mkdir -p ${STUFF}
|
||||
cd ${STUFF}
|
||||
|
||||
wget -nv https://openepics.ci.cloudbees.com/job/Base-${BASE}_Build/lastSuccessfulBuild/artifact/base-${BASE}.CB-dist.tar.gz
|
||||
wget -nv https://openepics.ci.cloudbees.com/job/pvDataCPP_${PVDATA_BRANCH}Build/BASE=${BASE},USE_MB=MB_NO/lastSuccessfulBuild/artifact/pvData.CB-dist.tar.gz
|
||||
wget -nv https://openepics.ci.cloudbees.com/job/pvAccessCPP_${PVACCESS_BRANCH}Build/BASE=${BASE},USE_MB=${USE_MB}/lastSuccessfulBuild/artifact/pvAccess.CB-dist.tar.gz
|
||||
wget -nv https://openepics.ci.cloudbees.com/job/pvaSrvCPP_${PVASRV_BRANCH}Build/BASE=${BASE},USE_MB=MB_NO/lastSuccessfulBuild/artifact/pvaSrv.CB-dist.tar.gz
|
||||
tar -xzf base-${BASE}.CB-dist.tar.gz
|
||||
wget -nv https://openepics.ci.cloudbees.com/job/Base-3.14.12.3_Build/lastSuccessfulBuild/artifact/baseR3.14.12.3.CB-dist.tar.gz
|
||||
wget -nv https://openepics.ci.cloudbees.com/job/Doxygen-1.8.3_Build/lastSuccessfulBuild/artifact/doxygen-1.8.3.CB-dist.tar.gz
|
||||
wget -nv https://openepics.ci.cloudbees.com/job/pvData_CPP_Build/lastSuccessfulBuild/artifact/pvData.CB-dist.tar.gz
|
||||
wget -nv https://openepics.ci.cloudbees.com/job/pvAccess_CPP_Build/lastSuccessfulBuild/artifact/pvAccess.CB-dist.tar.gz
|
||||
wget -nv https://openepics.ci.cloudbees.com/job/pvaSrv_CPP_Build/lastSuccessfulBuild/artifact/pvaSrv.CB-dist.tar.gz
|
||||
tar -xzf baseR3.14.12.3.CB-dist.tar.gz
|
||||
tar -xzf doxygen-1.8.3.CB-dist.tar.gz
|
||||
tar -xzf pvData.CB-dist.tar.gz
|
||||
tar -xzf pvAccess.CB-dist.tar.gz
|
||||
tar -xzf pvaSrv.CB-dist.tar.gz
|
||||
|
||||
if [ "${USE_MB}" = "MB_YES" ]; then
|
||||
wget -nv https://openepics.ci.cloudbees.com/job/pvCommonCPP_${PVCOMMON_BRANCH}Build/BASE=${BASE},USE_MB=MB_YES/lastSuccessfulBuild/artifact/pvCommon.CB-dist.tar.gz
|
||||
tar -xzf pvCommon.CB-dist.tar.gz
|
||||
fi
|
||||
|
||||
###########################################
|
||||
# Build
|
||||
|
||||
@@ -61,6 +43,7 @@ EPICS_BASE=${EPICS_BASE}
|
||||
EOF
|
||||
|
||||
make distclean all
|
||||
doxygen
|
||||
|
||||
###########################################
|
||||
# Test
|
||||
@@ -70,4 +53,9 @@ make distclean all
|
||||
###########################################
|
||||
# Create distribution
|
||||
|
||||
tar -czf pvDatabase.CB-dist.tar.gz lib include dbd COPYRIGHT LICENSE
|
||||
tar -czf pvDatabaseCPP.CB-dist.tar.gz lib include dbd COPYRIGHT LICENSE
|
||||
|
||||
###########################################
|
||||
# Publish documentation
|
||||
|
||||
rsync -aP --delete -e ssh documentation epics-jenkins@web.sourceforge.net:/home/project-web/epics-pvdata/htdocs/docbuild/pvDatabaseCPP/tip
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
# pvDatabase C++ implementation
|
||||
# Jenkins @ Cloudbees documentation generation and deployment
|
||||
#
|
||||
# Jenkins invokes scripts with the "-ex" option. So the build is considered a failure
|
||||
# if any of the commands exits with a non-zero exit code.
|
||||
#
|
||||
# Author: Ralph Lange <ralph.lange@gmx.de>
|
||||
# Copyright (C) 2014 Helmholtz-Zentrum Berlin für Materialien und Energie GmbH
|
||||
# Copyright (C) 2014-2015 ITER Organization.
|
||||
# All rights reserved. Use is subject to license terms.
|
||||
|
||||
###########################################
|
||||
# Set EPICS Base version and upload target
|
||||
|
||||
BASE=3.15.2
|
||||
PUBLISH=${1:-DONT}
|
||||
|
||||
###########################################
|
||||
# Fetch and unpack dependencies
|
||||
|
||||
export STUFF=/tmp/stuff
|
||||
|
||||
rm -fr ${STUFF}
|
||||
mkdir -p ${STUFF}
|
||||
cd ${STUFF}
|
||||
|
||||
wget -nv https://openepics.ci.cloudbees.com/job/Doxygen-1.8.3_Build/lastSuccessfulBuild/artifact/doxygen-1.8.3.CB-dist.tar.gz
|
||||
tar -xzf doxygen-1.8.3.CB-dist.tar.gz
|
||||
|
||||
###########################################
|
||||
# Generate
|
||||
|
||||
cd ${WORKSPACE}
|
||||
|
||||
wget -nv https://openepics.ci.cloudbees.com/job/pvDatabaseCPP_Build/BASE=${BASE},USE_MB=MB_NO/lastSuccessfulBuild/artifact/pvDatabase.CB-dist.tar.gz
|
||||
tar -xzf pvDatabase.CB-dist.tar.gz
|
||||
|
||||
export PATH=${STUFF}/bin:${PATH}
|
||||
|
||||
doxygen
|
||||
|
||||
###########################################
|
||||
# Publish
|
||||
|
||||
if [ "${PUBLISH}" != "DONT" ]; then
|
||||
# Upload explicit dummy to ensure target directory exists
|
||||
echo "Created by CloudBees Jenkins upload job. Should be deleted as part of the job." > DUMMY
|
||||
rsync -q -e ssh DUMMY epics-jenkins@web.sourceforge.net:/home/project-web/epics-pvdata/htdocs/docbuild/pvDatabaseCPP/${PUBLISH}/
|
||||
|
||||
rsync -aqP --delete -e ssh documentation epics-jenkins@web.sourceforge.net:/home/project-web/epics-pvdata/htdocs/docbuild/pvDatabaseCPP/${PUBLISH}/
|
||||
fi
|
||||
20
jenkins/cloudbees_hgweb
Normal file
20
jenkins/cloudbees_hgweb
Normal file
@@ -0,0 +1,20 @@
|
||||
# pvDatabaseCPP
|
||||
# Jenkins @ Cloudbees hgweb sync script
|
||||
#
|
||||
# Jenkins invokes scripts with the "-ex" option. So the build is considered a failure
|
||||
# if any of the commands exits with a non-zero exit code.
|
||||
#
|
||||
# Author: Ralph Lange <Ralph.Lange@gmx.de>
|
||||
# Copyright (C) 2014 Helmholtz-Zentrum Berlin für Materialien und Energie GmbH
|
||||
# All rights reserved. Use is subject to license terms.
|
||||
|
||||
###########################################
|
||||
# Fetch complete repo
|
||||
|
||||
rm -fr hgweb
|
||||
hg clone -U http://hg.code.sf.net/p/epics-pvdata/pvDatabaseCPP hgweb
|
||||
|
||||
###########################################
|
||||
# Sync into SF webspace
|
||||
|
||||
rsync -aqP --delete --exclude=\.hg/hgrc -e ssh hgweb/.hg epics-jenkins@web.sourceforge.net:/home/project-web/epics-pvdata/repos/pvDatabaseCPP
|
||||
1
pvDatabase.config
Normal file
1
pvDatabase.config
Normal file
@@ -0,0 +1 @@
|
||||
// ADD PREDEFINED MACROS HERE!
|
||||
1
pvDatabase.creator
Normal file
1
pvDatabase.creator
Normal file
@@ -0,0 +1 @@
|
||||
[General]
|
||||
124
pvDatabase.files
Normal file
124
pvDatabase.files
Normal file
@@ -0,0 +1,124 @@
|
||||
arrayPerformance/src/arrayPerformance.cpp
|
||||
arrayPerformance/src/arrayPerformance.h
|
||||
arrayPerformance/src/arrayPerformanceMain.cpp
|
||||
arrayPerformance/src/longArrayGet.cpp
|
||||
arrayPerformance/src/longArrayGet.h
|
||||
arrayPerformance/src/longArrayGetMain.cpp
|
||||
arrayPerformance/src/longArrayMonitor.cpp
|
||||
arrayPerformance/src/longArrayMonitor.h
|
||||
arrayPerformance/src/longArrayMonitorMain.cpp
|
||||
arrayPerformance/src/longArrayPut.cpp
|
||||
arrayPerformance/src/longArrayPut.h
|
||||
arrayPerformance/src/longArrayPutMain.cpp
|
||||
arrayPerformance/src/vectorPerformanceMain.cpp
|
||||
exampleDatabase/ioc/src/O.linux-x86_64/exampleDatabase_registerRecordDeviceDriver.cpp
|
||||
exampleDatabase/ioc/src/exampleDatabaseMain.cpp
|
||||
exampleDatabase/src/exampleDatabase.cpp
|
||||
exampleDatabase/src/exampleDatabase.h
|
||||
exampleDatabase/src/exampleDatabaseMain.cpp
|
||||
exampleDatabase/src/exampleDatabaseRegister.cpp
|
||||
exampleLink/ioc/src/O.linux-x86_64/exampleLink_registerRecordDeviceDriver.cpp
|
||||
exampleLink/ioc/src/exampleLinkMain.cpp
|
||||
exampleLink/src/exampleLink.cpp
|
||||
exampleLink/src/exampleLink.h
|
||||
exampleLink/src/exampleLinkRegister.cpp
|
||||
examplePowerSupply/ioc/src/O.linux-x86_64/powerSupply_registerRecordDeviceDriver.cpp
|
||||
examplePowerSupply/ioc/src/powerSupplyMain.cpp
|
||||
examplePowerSupply/src/powerSupplyMain.cpp
|
||||
exampleServer/ioc/src/O.linux-x86_64/exampleServer_registerRecordDeviceDriver.cpp
|
||||
exampleServer/ioc/src/exampleServerMain.cpp
|
||||
exampleServer/src/exampleServer.cpp
|
||||
exampleServer/src/exampleServer.h
|
||||
exampleServer/src/exampleServerMain.cpp
|
||||
exampleServer/src/exampleServerRegister.cpp
|
||||
src/database/pvDatabase.cpp
|
||||
src/database/pvDatabase.h
|
||||
src/database/pvRecord.cpp
|
||||
src/pvAccess/channelLocal.cpp
|
||||
src/pvAccess/channelProviderLocal.cpp
|
||||
src/pvAccess/channelProviderLocal.h
|
||||
src/pvAccess/monitorAlgorithm.h
|
||||
src/pvAccess/monitorFactory.cpp
|
||||
src/pvAccess/pvCopy.cpp
|
||||
src/pvAccess/pvCopy.h
|
||||
src/pvAccess/registerChannelProviderLocal.cpp
|
||||
src/special/recordList.cpp
|
||||
src/special/recordList.h
|
||||
src/special/traceRecord.cpp
|
||||
src/special/traceRecord.h
|
||||
test/src/powerSupply.cpp
|
||||
test/src/powerSupply.h
|
||||
test/src/powerSupplyRegister.cpp
|
||||
test/src/testExampleRecord.cpp
|
||||
test/src/testPVCopy.cpp
|
||||
test/src/testPVRecord.cpp
|
||||
arrayPerformance/include/pv/arrayPerformance.h
|
||||
arrayPerformance/include/pv/longArrayGet.h
|
||||
arrayPerformance/include/pv/longArrayMonitor.h
|
||||
arrayPerformance/include/pv/longArrayPut.h
|
||||
arrayPerformance/src/arrayPerformance.cpp
|
||||
arrayPerformance/src/arrayPerformance.h
|
||||
arrayPerformance/src/arrayPerformanceMain.cpp
|
||||
arrayPerformance/src/longArrayGet.cpp
|
||||
arrayPerformance/src/longArrayGet.h
|
||||
arrayPerformance/src/longArrayGetMain.cpp
|
||||
arrayPerformance/src/longArrayMonitor.cpp
|
||||
arrayPerformance/src/longArrayMonitor.h
|
||||
arrayPerformance/src/longArrayMonitorMain.cpp
|
||||
arrayPerformance/src/longArrayPut.cpp
|
||||
arrayPerformance/src/longArrayPut.h
|
||||
arrayPerformance/src/longArrayPutMain.cpp
|
||||
arrayPerformance/src/vectorPerformanceMain.cpp
|
||||
exampleDatabase/include/pv/exampleDatabase.h
|
||||
exampleDatabase/include/pv/exampleMonitorPlugin.h
|
||||
exampleDatabase/ioc/src/O.darwin-x86/exampleDatabase_registerRecordDeviceDriver.cpp
|
||||
exampleDatabase/ioc/src/exampleDatabaseMain.cpp
|
||||
exampleDatabase/src/exampleDatabase.cpp
|
||||
exampleDatabase/src/exampleDatabase.h
|
||||
exampleDatabase/src/exampleDatabaseMain.cpp
|
||||
exampleDatabase/src/exampleDatabaseRegister.cpp
|
||||
exampleDatabase/src/exampleMonitorPlugin.cpp
|
||||
exampleDatabase/src/exampleMonitorPlugin.h
|
||||
exampleDatabase/src/exampleMonitorPluginRegister.cpp
|
||||
exampleLink/include/pv/exampleLink.h
|
||||
exampleLink/ioc/src/O.darwin-x86/exampleLink_registerRecordDeviceDriver.cpp
|
||||
exampleLink/ioc/src/exampleLinkMain.cpp
|
||||
exampleLink/src/exampleLink.cpp
|
||||
exampleLink/src/exampleLink.h
|
||||
exampleLink/src/exampleLinkRegister.cpp
|
||||
examplePowerSupply/ioc/src/O.darwin-x86/powerSupply_registerRecordDeviceDriver.cpp
|
||||
examplePowerSupply/ioc/src/powerSupplyMain.cpp
|
||||
examplePowerSupply/src/powerSupplyMain.cpp
|
||||
exampleServer/include/pv/exampleServer.h
|
||||
exampleServer/ioc/src/O.darwin-x86/exampleServer_registerRecordDeviceDriver.cpp
|
||||
exampleServer/ioc/src/exampleServerMain.cpp
|
||||
exampleServer/src/exampleServer.cpp
|
||||
exampleServer/src/exampleServer.h
|
||||
exampleServer/src/exampleServerMain.cpp
|
||||
exampleServer/src/exampleServerRegister.cpp
|
||||
include/pv/channelProviderLocal.h
|
||||
include/pv/pvCopyMonitor.h
|
||||
include/pv/pvDatabase.h
|
||||
include/pv/recordList.h
|
||||
include/pv/traceRecord.h
|
||||
src/database/pvDatabase.cpp
|
||||
src/database/pvDatabase.h
|
||||
src/database/pvRecord.cpp
|
||||
src/pvAccess/channelLocal.cpp
|
||||
src/pvAccess/channelProviderLocal.cpp
|
||||
src/pvAccess/channelProviderLocal.h
|
||||
src/pvAccess/monitorFactory.cpp
|
||||
src/pvAccess/pvCopyMonitor.cpp
|
||||
src/pvAccess/pvCopyMonitor.h
|
||||
src/pvAccess/registerChannelProviderLocal.cpp
|
||||
src/special/recordList.cpp
|
||||
src/special/recordList.h
|
||||
src/special/traceRecord.cpp
|
||||
src/special/traceRecord.h
|
||||
test/include/pv/powerSupply.h
|
||||
test/src/powerSupply.cpp
|
||||
test/src/powerSupply.h
|
||||
test/src/powerSupplyRegister.cpp
|
||||
test/src/testExampleRecord.cpp
|
||||
test/src/testPVCopy.cpp
|
||||
test/src/testPVRecord.cpp
|
||||
8
pvDatabase.includes
Normal file
8
pvDatabase.includes
Normal file
@@ -0,0 +1,8 @@
|
||||
arrayPerformance/src
|
||||
exampleDatabase/src
|
||||
exampleLink/src
|
||||
exampleServer/src
|
||||
src/database
|
||||
src/pvAccess
|
||||
src/special
|
||||
test/src
|
||||
@@ -21,8 +21,8 @@
|
||||
#include <deque>
|
||||
|
||||
#include <pv/pvData.h>
|
||||
#include <pv/pvCopy.h>
|
||||
#include <pv/pvTimeStamp.h>
|
||||
|
||||
#include <pv/convert.h>
|
||||
|
||||
#ifdef pvdatabaseEpicsExportSharedSymbols
|
||||
# define epicsExportSharedSymbols
|
||||
@@ -56,12 +56,10 @@ class PVDatabase;
|
||||
typedef std::tr1::shared_ptr<PVDatabase> PVDatabasePtr;
|
||||
|
||||
/**
|
||||
* @brief Base interface for a record.
|
||||
*
|
||||
* Base interface for a record.
|
||||
* @author mrk
|
||||
*/
|
||||
class epicsShareClass PVRecord :
|
||||
public epics::pvData::PVCopyTraverseMasterCallback,
|
||||
public std::tr1::enable_shared_from_this<PVRecord>
|
||||
{
|
||||
public:
|
||||
@@ -85,7 +83,7 @@ public:
|
||||
* If it encounters errors it should raise alarms and/or
|
||||
* call the <b>message</b> method provided by the base class.
|
||||
*/
|
||||
virtual void process();
|
||||
virtual void process() {}
|
||||
/**
|
||||
* Destroy the PVRecord. Release any resources used and
|
||||
* get rid of listeners and requesters.
|
||||
@@ -169,26 +167,15 @@ public:
|
||||
* Add a PVListener.
|
||||
* This must be called before calling pvRecordField.addListener.
|
||||
* @param pvListener The listener.
|
||||
* @param pvCopy The pvStructure that has the client fields.
|
||||
* @return <b>true</b> if the listener was added.
|
||||
*/
|
||||
bool addListener(
|
||||
PVListenerPtr const & pvListener,
|
||||
epics::pvData::PVCopyPtr const & pvCopy);
|
||||
/*
|
||||
* PVCopyTraverseMasterCallback method
|
||||
* @param pvField The next client field.
|
||||
*/
|
||||
void nextMasterPVField(epics::pvData::PVFieldPtr const & pvField);
|
||||
bool addListener(PVListenerPtr const & pvListener);
|
||||
/**
|
||||
* Remove a listener.
|
||||
* @param pvListener The listener.
|
||||
* @param pvCopy The pvStructure that has the client fields.
|
||||
* @return <b>true</b> if the listener was removed.
|
||||
*/
|
||||
bool removeListener(
|
||||
PVListenerPtr const & pvListener,
|
||||
epics::pvData::PVCopyPtr const & pvCopy);
|
||||
bool removeListener(PVListenerPtr const & pvListener);
|
||||
/**
|
||||
* Begins a group of puts.
|
||||
*/
|
||||
@@ -233,9 +220,9 @@ private:
|
||||
PVRecordFieldPtr findPVRecordField(
|
||||
PVRecordStructurePtr const & pvrs,
|
||||
epics::pvData::PVFieldPtr const & pvField);
|
||||
|
||||
std::string recordName;
|
||||
epics::pvData::PVStructurePtr pvStructure;
|
||||
epics::pvData::ConvertPtr convert;
|
||||
PVRecordStructurePtr pvRecordStructure;
|
||||
std::list<PVListenerPtr> pvListenerList;
|
||||
std::list<PVRecordClientPtr> pvRecordClientList;
|
||||
@@ -243,20 +230,12 @@ private:
|
||||
std::size_t depthGroupPut;
|
||||
int traceLevel;
|
||||
bool isDestroyed;
|
||||
|
||||
epics::pvData::PVTimeStamp pvTimeStamp;
|
||||
epics::pvData::TimeStamp timeStamp;
|
||||
|
||||
// following only valid while addListener or removeListener is active.
|
||||
bool isAddListener;
|
||||
PVListenerPtr pvListener;
|
||||
};
|
||||
|
||||
epicsShareExtern std::ostream& operator<<(std::ostream& o, const PVRecord& record);
|
||||
|
||||
/**
|
||||
* @brief Interface for a field of a record.
|
||||
*
|
||||
* Interface for a field of a record.
|
||||
* One exists for each field of the top level PVStructure.
|
||||
* @author mrk
|
||||
*/
|
||||
@@ -269,8 +248,7 @@ public:
|
||||
/**
|
||||
* Constructor.
|
||||
* @param pvField The field from the top level structure.
|
||||
* @param parent The parent.
|
||||
* @param pvRecord The PVRecord.
|
||||
* @param The parent.
|
||||
*/
|
||||
PVRecordField(
|
||||
epics::pvData::PVFieldPtr const & pvField,
|
||||
@@ -309,6 +287,21 @@ public:
|
||||
* @return The shared pointer,
|
||||
*/
|
||||
PVRecordPtr getPVRecord();
|
||||
/**
|
||||
* Add A PVListener to this field.
|
||||
* Whenever this field or any subfield if this field is modified the listener will be notified.
|
||||
* PVListener is described below.
|
||||
* Before a listener can call addListener it must first call PVRecord.registerListener.
|
||||
* @param pvListener The listener.
|
||||
* @return <b<true</b> if listener is added.
|
||||
*/
|
||||
bool addListener(PVListenerPtr const & pvListener);
|
||||
/**
|
||||
* Remove a listener.
|
||||
* @param pvListener The listener.
|
||||
* @return <b<true</b> if listener is removed.
|
||||
*/
|
||||
virtual void removeListener(PVListenerPtr const & pvListener);
|
||||
/**
|
||||
* This is called by the code that implements the data interface.
|
||||
* It is called whenever the put method is called.
|
||||
@@ -323,8 +316,6 @@ protected:
|
||||
virtual void postParent(PVRecordFieldPtr const & subField);
|
||||
virtual void postSubField();
|
||||
private:
|
||||
bool addListener(PVListenerPtr const & pvListener);
|
||||
virtual void removeListener(PVListenerPtr const & pvListener);
|
||||
void callListener();
|
||||
|
||||
std::list<PVListenerPtr> pvListenerList;
|
||||
@@ -339,8 +330,7 @@ private:
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Interface for a field that is a structure.
|
||||
*
|
||||
* Interface for a field that is a structure.
|
||||
* One exists for each structure field of the top level PVStructure.
|
||||
* @author mrk
|
||||
*/
|
||||
@@ -375,6 +365,11 @@ public:
|
||||
* @return The shared pointer.
|
||||
*/
|
||||
epics::pvData::PVStructurePtr getPVStructure();
|
||||
/**
|
||||
* Called by PVRecord::removeListener.
|
||||
* @param pvListener The listener.
|
||||
*/
|
||||
virtual void removeListener(PVListenerPtr const & pvListener);
|
||||
/**
|
||||
* Called by implementation code of PVRecord.
|
||||
*/
|
||||
@@ -385,16 +380,13 @@ protected:
|
||||
*/
|
||||
virtual void init();
|
||||
private:
|
||||
virtual void removeListener(PVListenerPtr const & pvListener);
|
||||
|
||||
epics::pvData::PVStructurePtr pvStructure;
|
||||
PVRecordFieldPtrArrayPtr pvRecordFields;
|
||||
friend class PVRecord;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief An interface implemented by code that accesses the record.
|
||||
*
|
||||
* An interface that must be implemented by any code that accesses the record.
|
||||
* @author mrk
|
||||
*/
|
||||
class epicsShareClass PVRecordClient {
|
||||
@@ -412,8 +404,6 @@ public:
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Listener for PVRecord::message.
|
||||
*
|
||||
* An interface that is implemented by code that traps calls to PVRecord::message.
|
||||
* @author mrk
|
||||
*/
|
||||
@@ -458,8 +448,7 @@ public:
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The interface for a database of PVRecords.
|
||||
*
|
||||
* The interface to a database of PVRecords.
|
||||
* @author mrk
|
||||
*/
|
||||
class epicsShareClass PVDatabase {
|
||||
@@ -514,10 +503,3 @@ private:
|
||||
}}
|
||||
|
||||
#endif /* PVDATABASE_H */
|
||||
|
||||
/** @page Overview Documentation
|
||||
*
|
||||
* <a href = "pvDatabaseCPP.html">pvDatabase.html</a>
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
@@ -39,10 +39,10 @@ PVRecord::PVRecord(
|
||||
PVStructurePtr const & pvStructure)
|
||||
: recordName(recordName),
|
||||
pvStructure(pvStructure),
|
||||
convert(getConvert()),
|
||||
depthGroupPut(0),
|
||||
traceLevel(0),
|
||||
isDestroyed(false),
|
||||
isAddListener(false)
|
||||
isDestroyed(false)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -59,8 +59,6 @@ void PVRecord::initPVRecord()
|
||||
pvRecordStructure = PVRecordStructurePtr(
|
||||
new PVRecordStructure(pvStructure,parent,getPtrSelf()));
|
||||
pvRecordStructure->init();
|
||||
PVFieldPtr pvField = pvStructure->getSubField("timeStamp");
|
||||
if(pvField) pvTimeStamp.attach(pvField);
|
||||
}
|
||||
|
||||
void PVRecord::destroy()
|
||||
@@ -75,7 +73,6 @@ void PVRecord::destroy()
|
||||
return;
|
||||
}
|
||||
isDestroyed = true;
|
||||
pvTimeStamp.detach();
|
||||
|
||||
std::list<PVRecordClientPtr>::iterator clientIter;
|
||||
while(true) {
|
||||
@@ -97,6 +94,7 @@ void PVRecord::destroy()
|
||||
}
|
||||
pvRecordStructure->destroy();
|
||||
pvRecordStructure.reset();
|
||||
convert.reset();
|
||||
pvStructure.reset();
|
||||
unlock();
|
||||
} catch(...) {
|
||||
@@ -105,17 +103,6 @@ void PVRecord::destroy()
|
||||
}
|
||||
}
|
||||
|
||||
void PVRecord::process()
|
||||
{
|
||||
if(traceLevel>2) {
|
||||
cout << "PVRecord::process() " << recordName << endl;
|
||||
}
|
||||
if(pvTimeStamp.isAttached()) {
|
||||
timeStamp.getCurrent();
|
||||
pvTimeStamp.set(timeStamp);
|
||||
}
|
||||
}
|
||||
|
||||
string PVRecord::getRecordName() const {return recordName;}
|
||||
|
||||
PVRecordStructurePtr PVRecord::getPVRecordStructure() const {return pvRecordStructure;}
|
||||
@@ -276,9 +263,7 @@ void PVRecord::detachClients()
|
||||
}
|
||||
}
|
||||
|
||||
bool PVRecord::addListener(
|
||||
PVListenerPtr const & pvListener,
|
||||
PVCopyPtr const & pvCopy)
|
||||
bool PVRecord::addListener(PVListenerPtr const & pvListener)
|
||||
{
|
||||
if(traceLevel>1) {
|
||||
cout << "PVRecord::addListener() " << recordName << endl;
|
||||
@@ -298,10 +283,6 @@ bool PVRecord::addListener(
|
||||
}
|
||||
}
|
||||
pvListenerList.push_back(pvListener);
|
||||
this->pvListener = pvListener;
|
||||
isAddListener = true;
|
||||
pvCopy->traverseMaster(getPtrSelf());
|
||||
this->pvListener = PVListenerPtr();;
|
||||
unlock();
|
||||
return true;
|
||||
} catch(...) {
|
||||
@@ -310,19 +291,7 @@ bool PVRecord::addListener(
|
||||
}
|
||||
}
|
||||
|
||||
void PVRecord::nextMasterPVField(PVFieldPtr const & pvField)
|
||||
{
|
||||
PVRecordFieldPtr pvRecordField = findPVRecordField(pvField);
|
||||
if(isAddListener) {
|
||||
pvRecordField->addListener(pvListener);
|
||||
} else {
|
||||
pvRecordField->removeListener(pvListener);
|
||||
}
|
||||
}
|
||||
|
||||
bool PVRecord::removeListener(
|
||||
PVListenerPtr const & pvListener,
|
||||
PVCopyPtr const & pvCopy)
|
||||
bool PVRecord::removeListener(PVListenerPtr const & pvListener)
|
||||
{
|
||||
if(traceLevel>1) {
|
||||
cout << "PVRecord::removeListener() " << recordName << endl;
|
||||
@@ -338,10 +307,7 @@ bool PVRecord::removeListener(
|
||||
{
|
||||
if((*iter).get()==pvListener.get()) {
|
||||
pvListenerList.erase(iter);
|
||||
this->pvListener = pvListener;
|
||||
isAddListener = false;
|
||||
pvCopy->traverseMaster(getPtrSelf());
|
||||
this->pvListener = PVListenerPtr();;
|
||||
pvRecordStructure->removeListener(pvListener);
|
||||
unlock();
|
||||
return true;
|
||||
}
|
||||
@@ -445,9 +411,6 @@ PVRecordPtr PVRecordField::getPVRecord() {return pvRecord;}
|
||||
|
||||
bool PVRecordField::addListener(PVListenerPtr const & pvListener)
|
||||
{
|
||||
if(pvRecord->getTraceLevel()>1) {
|
||||
cout << "PVRecordField::addListener() " << getFullName() << endl;
|
||||
}
|
||||
std::list<PVListenerPtr>::iterator iter;
|
||||
for (iter = pvListenerList.begin(); iter!=pvListenerList.end(); iter++ ) {
|
||||
if((*iter).get()==pvListener.get()) {
|
||||
@@ -460,9 +423,6 @@ bool PVRecordField::addListener(PVListenerPtr const & pvListener)
|
||||
|
||||
void PVRecordField::removeListener(PVListenerPtr const & pvListener)
|
||||
{
|
||||
if(pvRecord->getTraceLevel()>1) {
|
||||
cout << "PVRecordField::removeListener() " << getFullName() << endl;
|
||||
}
|
||||
std::list<PVListenerPtr>::iterator iter;
|
||||
for (iter = pvListenerList.begin(); iter!=pvListenerList.end(); iter++ ) {
|
||||
if((*iter).get()==pvListener.get()) {
|
||||
|
||||
@@ -3,11 +3,13 @@
|
||||
SRC_DIRS += $(PVDATABASE_SRC)/pvAccess
|
||||
|
||||
INC += channelProviderLocal.h
|
||||
INC += pvCopyMonitor.h
|
||||
|
||||
DBD += registerChannelProviderLocal.dbd
|
||||
|
||||
LIBSRCS += channelProviderLocal.cpp
|
||||
LIBSRCS += channelLocal.cpp
|
||||
LIBSRCS += pvCopyMonitor.cpp
|
||||
LIBSRCS += monitorFactory.cpp
|
||||
LIBSRCS += registerChannelProviderLocal.cpp
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
|
||||
#include <epicsThread.h>
|
||||
#include <pv/timeStamp.h>
|
||||
#include <pv/convert.h>
|
||||
#include <pv/pvSubArrayCopy.h>
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
@@ -29,6 +30,7 @@ using std::string;
|
||||
|
||||
namespace epics { namespace pvDatabase {
|
||||
|
||||
static ConvertPtr convert = getConvert();
|
||||
static StructureConstPtr nullStructure;
|
||||
static PVStructurePtr nullPVStructure;
|
||||
static BitSetPtr nullBitSet;
|
||||
@@ -107,8 +109,8 @@ public:
|
||||
{return channelLocal;}
|
||||
virtual void cancel(){}
|
||||
virtual void lastRequest() {}
|
||||
virtual void lock() {pvRecord->lock();}
|
||||
virtual void unlock() {pvRecord->unlock();}
|
||||
virtual void lock() {mutex.lock();}
|
||||
virtual void unlock() {mutex.unlock();}
|
||||
private:
|
||||
shared_pointer getPtrSelf()
|
||||
{
|
||||
@@ -131,8 +133,8 @@ private:
|
||||
ChannelLocalPtr channelLocal;
|
||||
ChannelProcessRequester::shared_pointer channelProcessRequester;
|
||||
PVRecordPtr pvRecord;
|
||||
int nProcess;
|
||||
Mutex mutex;
|
||||
int nProcess;
|
||||
};
|
||||
|
||||
ChannelProcessLocalPtr ChannelProcessLocal::create(
|
||||
@@ -149,7 +151,7 @@ ChannelProcessLocalPtr ChannelProcessLocal::create(
|
||||
pvOptions = static_pointer_cast<PVStructure>(pvField);
|
||||
pvField = pvOptions->getSubField("nProcess");
|
||||
if(pvField) {
|
||||
PVStringPtr pvString = pvOptions->getSubField<PVString>("nProcess");
|
||||
PVStringPtr pvString = pvOptions->getStringField("nProcess");
|
||||
if(pvString) {
|
||||
int size;
|
||||
std::stringstream ss;
|
||||
@@ -240,8 +242,8 @@ public:
|
||||
{return channelLocal;}
|
||||
virtual void cancel(){}
|
||||
virtual void lastRequest() {}
|
||||
virtual void lock() {pvRecord->lock();}
|
||||
virtual void unlock() {pvRecord->unlock();}
|
||||
virtual void lock() {mutex.lock();}
|
||||
virtual void unlock() {mutex.unlock();}
|
||||
private:
|
||||
shared_pointer getPtrSelf()
|
||||
{
|
||||
@@ -399,8 +401,8 @@ public:
|
||||
{return channelLocal;}
|
||||
virtual void cancel(){}
|
||||
virtual void lastRequest() {}
|
||||
virtual void lock() {pvRecord->lock();}
|
||||
virtual void unlock() {pvRecord->unlock();}
|
||||
virtual void lock() {mutex.lock();}
|
||||
virtual void unlock() {mutex.unlock();}
|
||||
private:
|
||||
shared_pointer getPtrSelf()
|
||||
{
|
||||
@@ -568,8 +570,8 @@ public:
|
||||
{return channelLocal;}
|
||||
virtual void cancel(){}
|
||||
virtual void lastRequest() {}
|
||||
virtual void lock() {pvRecord->lock();}
|
||||
virtual void unlock() {pvRecord->unlock();}
|
||||
virtual void lock() {mutex.lock();}
|
||||
virtual void unlock() {mutex.unlock();}
|
||||
private:
|
||||
shared_pointer getPtrSelf()
|
||||
{
|
||||
@@ -781,8 +783,8 @@ public:
|
||||
{return channelLocal;}
|
||||
virtual void cancel(){}
|
||||
virtual void lastRequest() {}
|
||||
virtual void lock() {pvRecord->lock();}
|
||||
virtual void unlock() {pvRecord->unlock();}
|
||||
virtual void lock() {mutex.lock();}
|
||||
virtual void unlock() {mutex.unlock();}
|
||||
private:
|
||||
shared_pointer getPtrSelf()
|
||||
{
|
||||
@@ -871,29 +873,66 @@ ChannelArrayLocalPtr ChannelArrayLocal::create(
|
||||
PVScalarArrayPtr xxx = static_pointer_cast<PVScalarArray>(pvField);
|
||||
pvCopy = getPVDataCreate()->createPVScalarArray(
|
||||
xxx->getScalarArray()->getElementType());
|
||||
} else if(pvField->getField()->getType()==structureArray) {
|
||||
ChannelArrayLocalPtr array(new ChannelArrayLocal(
|
||||
channelLocal,
|
||||
channelArrayRequester,
|
||||
pvArray,
|
||||
pvCopy,
|
||||
pvRecord));
|
||||
if(pvRecord->getTraceLevel()>0)
|
||||
{
|
||||
cout << "ChannelArrayLocal::create";
|
||||
cout << " recordName " << pvRecord->getRecordName() << endl;
|
||||
}
|
||||
channelArrayRequester->channelArrayConnect(
|
||||
Status::Ok, array, pvCopy->getArray());
|
||||
return array;
|
||||
}
|
||||
if(pvField->getField()->getType()==structureArray) {
|
||||
PVStructureArrayPtr xxx = static_pointer_cast<PVStructureArray>(pvField);
|
||||
pvCopy = getPVDataCreate()->createPVStructureArray(
|
||||
xxx->getStructureArray()->getStructure());
|
||||
} else {
|
||||
ChannelArrayLocalPtr array(new ChannelArrayLocal(
|
||||
channelLocal,
|
||||
channelArrayRequester,
|
||||
pvArray,
|
||||
pvCopy,
|
||||
pvRecord));
|
||||
if(pvRecord->getTraceLevel()>0)
|
||||
{
|
||||
cout << "ChannelArrayLocal::create";
|
||||
cout << " recordName " << pvRecord->getRecordName() << endl;
|
||||
}
|
||||
channelArrayRequester->channelArrayConnect(
|
||||
Status::Ok, array, pvCopy->getArray());
|
||||
return array;
|
||||
}
|
||||
if(pvField->getField()->getType()==unionArray) {
|
||||
PVUnionArrayPtr xxx = static_pointer_cast<PVUnionArray>(pvField);
|
||||
pvCopy = getPVDataCreate()->createPVUnionArray(
|
||||
xxx->getUnionArray()->getUnion());
|
||||
ChannelArrayLocalPtr array(new ChannelArrayLocal(
|
||||
channelLocal,
|
||||
channelArrayRequester,
|
||||
pvArray,
|
||||
pvCopy,
|
||||
pvRecord));
|
||||
if(pvRecord->getTraceLevel()>0)
|
||||
{
|
||||
cout << "ChannelArrayLocal::create";
|
||||
cout << " recordName " << pvRecord->getRecordName() << endl;
|
||||
}
|
||||
channelArrayRequester->channelArrayConnect(
|
||||
Status::Ok, array, pvCopy->getArray());
|
||||
return array;
|
||||
}
|
||||
ChannelArrayLocalPtr array(new ChannelArrayLocal(
|
||||
channelLocal,
|
||||
channelArrayRequester,
|
||||
pvArray,
|
||||
pvCopy,
|
||||
pvRecord));
|
||||
if(pvRecord->getTraceLevel()>0)
|
||||
{
|
||||
cout << "ChannelArrayLocal::create";
|
||||
cout << " recordName " << pvRecord->getRecordName() << endl;
|
||||
}
|
||||
channelArrayRequester->channelArrayConnect(
|
||||
Status::Ok, array, pvCopy->getArray());
|
||||
return array;
|
||||
|
||||
Status status(Status::STATUSTYPE_ERROR,
|
||||
"Logic error. Should not reach this code");
|
||||
ChannelArrayLocalPtr channelArray;
|
||||
ArrayConstPtr array;
|
||||
channelArrayRequester->channelArrayConnect(status,channelArray,array);
|
||||
return channelArray;
|
||||
}
|
||||
|
||||
|
||||
@@ -1044,6 +1083,23 @@ void ChannelArrayLocal::setLength(size_t length)
|
||||
}
|
||||
|
||||
|
||||
class ChannelRPCLocal :
|
||||
public ChannelRPC
|
||||
{
|
||||
public:
|
||||
POINTER_DEFINITIONS(ChannelRPCLocal);
|
||||
virtual ~ChannelRPCLocal();
|
||||
static ChannelRPC::shared_pointer create(
|
||||
ChannelProviderLocalPtr const &channelProvider,
|
||||
ChannelRPC::shared_pointer const & channelRPCRequester,
|
||||
PVStructurePtr const & pvRequest,
|
||||
PVRecordPtr const &pvRecord);
|
||||
virtual void request(
|
||||
PVStructurePtr const & pvArgument,
|
||||
bool lastRequest);
|
||||
};
|
||||
|
||||
|
||||
ChannelLocal::ChannelLocal(
|
||||
ChannelProviderLocalPtr const & provider,
|
||||
ChannelRequester::shared_pointer const & requester,
|
||||
@@ -1105,8 +1161,6 @@ string ChannelLocal::getRemoteAddress()
|
||||
|
||||
Channel::ConnectionState ChannelLocal::getConnectionState()
|
||||
{
|
||||
Lock xx(mutex);
|
||||
if(beingDestroyed) return Channel::DESTROYED;
|
||||
return Channel::CONNECTED;
|
||||
}
|
||||
|
||||
@@ -1122,8 +1176,6 @@ ChannelRequester::shared_pointer ChannelLocal::getChannelRequester()
|
||||
|
||||
bool ChannelLocal::isConnected()
|
||||
{
|
||||
Lock xx(mutex);
|
||||
if(beingDestroyed) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -88,12 +88,12 @@ ChannelProviderLocal::ChannelProviderLocal()
|
||||
|
||||
ChannelProviderLocal::~ChannelProviderLocal()
|
||||
{
|
||||
// TODO should I call destroy() here
|
||||
destroy();
|
||||
cout << "~ChannelProviderLocal()" << endl;
|
||||
}
|
||||
|
||||
void ChannelProviderLocal::destroy()
|
||||
{
|
||||
cout << "ChannelProviderLocal::destroy()" << endl;
|
||||
Lock xx(mutex);
|
||||
if(beingDestroyed) return;
|
||||
beingDestroyed = true;
|
||||
@@ -172,47 +172,4 @@ Channel::shared_pointer ChannelProviderLocal::createChannel(
|
||||
return Channel::shared_pointer();
|
||||
}
|
||||
|
||||
|
||||
ContextLocal::shared_pointer ContextLocal::create()
|
||||
{
|
||||
return ContextLocal::shared_pointer(new ContextLocal());
|
||||
}
|
||||
|
||||
void ContextLocal::start(bool _waitForExit)
|
||||
{
|
||||
m_context = startPVAServer(
|
||||
PVACCESS_ALL_PROVIDERS,
|
||||
0,
|
||||
true,
|
||||
true);
|
||||
|
||||
if (_waitForExit)
|
||||
waitForExit();
|
||||
}
|
||||
|
||||
void ContextLocal::waitForExit()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
std::cout << "Type 'exit' to stop: ";
|
||||
std::string input;
|
||||
std::cin >> input;
|
||||
if (input == "exit")
|
||||
break;
|
||||
}
|
||||
|
||||
destroy();
|
||||
}
|
||||
|
||||
void ContextLocal::destroy()
|
||||
{
|
||||
if (m_context)
|
||||
m_context->destroy();
|
||||
}
|
||||
|
||||
ContextLocal::ContextLocal()
|
||||
{
|
||||
m_channelProvider = getChannelProviderLocal();
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
@@ -25,10 +25,10 @@
|
||||
#include <pv/lock.h>
|
||||
#include <pv/pvType.h>
|
||||
#include <pv/pvData.h>
|
||||
#include <pv/monitorPlugin.h>
|
||||
#include <pv/pvCopy.h>
|
||||
#include <pv/pvAccess.h>
|
||||
#include <pv/status.h>
|
||||
#include <pv/serverContext.h>
|
||||
|
||||
#ifdef channelProviderLocalEpicsExportSharedSymbols
|
||||
# define epicsExportSharedSymbols
|
||||
@@ -57,9 +57,7 @@ typedef std::tr1::shared_ptr<ChannelLocal> ChannelLocalPtr;
|
||||
|
||||
epicsShareExtern MonitorFactoryPtr getMonitorFactory();
|
||||
|
||||
/**
|
||||
* @brief MonitorFactory
|
||||
*
|
||||
/** MonitorFactory
|
||||
* This class provides a static method to create a monitor for a PVRecord
|
||||
*/
|
||||
class epicsShareClass MonitorFactory
|
||||
@@ -101,8 +99,6 @@ private:
|
||||
epicsShareExtern ChannelProviderLocalPtr getChannelProviderLocal();
|
||||
|
||||
/**
|
||||
* @brief ChannelProvider for PVDatabase.
|
||||
*
|
||||
* An implementation of channelProvider that provides access to records in PVDatabase.
|
||||
*/
|
||||
class epicsShareClass ChannelProviderLocal :
|
||||
@@ -195,8 +191,6 @@ private:
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Channel for accessing a PVRecord.
|
||||
*
|
||||
* A Channel for accessing a record in the PVDatabase.
|
||||
* It is a complete implementation of Channel
|
||||
*/
|
||||
@@ -231,7 +225,7 @@ public:
|
||||
virtual void destroy();
|
||||
/**
|
||||
* Get the requester name.
|
||||
* @return returns the name of the channel requester.
|
||||
* @param returns the name of the channel requester.
|
||||
*/
|
||||
virtual std::string getRequesterName();
|
||||
/**
|
||||
@@ -279,7 +273,7 @@ public:
|
||||
* Get the introspection interface for subField.
|
||||
* The introspection interface is given via GetFieldRequester::getDone.
|
||||
* @param requester The client callback.
|
||||
* @param subField The subField of the record.
|
||||
* @param The subField of the record.
|
||||
* If an empty string then the interface for the top level structure of
|
||||
* the record is provided.
|
||||
*/
|
||||
@@ -384,7 +378,7 @@ public:
|
||||
/**
|
||||
* This is called when a record is being removed from the database.
|
||||
* Calls destroy.
|
||||
* @param pvRecord The record being destroyed.
|
||||
* @record The record being destroyed.
|
||||
*/
|
||||
virtual void detach(PVRecordPtr const &pvRecord);
|
||||
protected:
|
||||
@@ -400,44 +394,7 @@ private:
|
||||
epics::pvData::Mutex mutex;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief A pvAccess server context that provides
|
||||
* remote access to a local channel providers (i.e. pvDatabase records).
|
||||
*/
|
||||
class epicsShareClass ContextLocal
|
||||
{
|
||||
|
||||
public:
|
||||
POINTER_DEFINITIONS(ContextLocal);
|
||||
|
||||
static shared_pointer create();
|
||||
|
||||
/**
|
||||
* Start the context thread.
|
||||
* After this is called clients can connect to the server.
|
||||
* @param waitForExit In true then waitForExit() method is called after the server is started.
|
||||
*/
|
||||
void start(bool waitForExit = false);
|
||||
|
||||
/**
|
||||
* Waits for "exit" to be entered on standard input and calls destroy() before returning.
|
||||
*/
|
||||
void waitForExit();
|
||||
|
||||
/**
|
||||
* This destroys the context.
|
||||
* All clients will be disconnected.
|
||||
*/
|
||||
void destroy();
|
||||
|
||||
private:
|
||||
ContextLocal();
|
||||
|
||||
ChannelProviderLocalPtr m_channelProvider;
|
||||
epics::pvAccess::ServerContext::shared_pointer m_context;
|
||||
};
|
||||
|
||||
|
||||
|
||||
}}
|
||||
#endif /* CHANNELPROVIDERLOCAL_H */
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
|
||||
#include <pv/pvCopyMonitor.h>
|
||||
#include <pv/channelProviderLocal.h>
|
||||
|
||||
using namespace epics::pvData;
|
||||
@@ -32,11 +33,9 @@ namespace epics { namespace pvDatabase {
|
||||
|
||||
static MonitorPtr nullMonitor;
|
||||
static MonitorElementPtr NULLMonitorElement;
|
||||
static Status failedToCreateMonitorStatus(Status::STATUSTYPE_ERROR,"failed to create monitor");
|
||||
static Status wasDestroyedStatus(Status::STATUSTYPE_ERROR,"was destroyed");
|
||||
static Status alreadyStartedStatus(Status::STATUSTYPE_ERROR,"already started");
|
||||
static Status notStartedStatus(Status::STATUSTYPE_ERROR,"not started");
|
||||
|
||||
static ConvertPtr convert = getConvert();
|
||||
|
||||
|
||||
typedef Queue<MonitorElement> MonitorElementQueue;
|
||||
@@ -46,10 +45,9 @@ typedef std::tr1::shared_ptr<MonitorElementQueue> MonitorElementQueuePtr;
|
||||
|
||||
class MonitorLocal :
|
||||
public Monitor,
|
||||
public PVListener,
|
||||
public PVCopyMonitorRequester,
|
||||
public std::tr1::enable_shared_from_this<MonitorLocal>
|
||||
{
|
||||
enum MonitorState {idle,active, destroyed};
|
||||
public:
|
||||
POINTER_DEFINITIONS(MonitorLocal);
|
||||
virtual ~MonitorLocal();
|
||||
@@ -57,22 +55,16 @@ public:
|
||||
virtual Status stop();
|
||||
virtual MonitorElementPtr poll();
|
||||
virtual void destroy();
|
||||
virtual void detach(PVRecordPtr const & pvRecord){destroy();}
|
||||
virtual void release(MonitorElementPtr const & monitorElement);
|
||||
virtual void dataPut(PVRecordFieldPtr const & pvRecordField);
|
||||
virtual void dataPut(
|
||||
PVRecordStructurePtr const & requested,
|
||||
PVRecordFieldPtr const & pvRecordField);
|
||||
virtual void beginGroupPut(PVRecordPtr const & pvRecord);
|
||||
virtual void endGroupPut(PVRecordPtr const & pvRecord);
|
||||
virtual void unlisten(PVRecordPtr const & pvRecord);
|
||||
MonitorElementPtr getActiveElement();
|
||||
void releaseActiveElement();
|
||||
MonitorElementPtr releaseActiveElement();
|
||||
void unlisten();
|
||||
bool init(PVStructurePtr const & pvRequest);
|
||||
MonitorLocal(
|
||||
MonitorRequester::shared_pointer const & channelMonitorRequester,
|
||||
PVRecordPtr const &pvRecord);
|
||||
PVCopyPtr getPVCopy() { return pvCopy;}
|
||||
PVCopyMonitorPtr getPVCopyMonitor() { return pvCopyMonitor;}
|
||||
private:
|
||||
MonitorLocalPtr getPtrSelf()
|
||||
{
|
||||
@@ -80,14 +72,13 @@ private:
|
||||
}
|
||||
MonitorRequester::shared_pointer monitorRequester;
|
||||
PVRecordPtr pvRecord;
|
||||
MonitorState state;
|
||||
bool isDestroyed;
|
||||
bool firstMonitor;
|
||||
PVCopyPtr pvCopy;
|
||||
MonitorElementQueuePtr queue;
|
||||
MonitorElementPtr activeElement;
|
||||
bool isGroupPut;
|
||||
bool dataChanged;
|
||||
PVCopyMonitorPtr pvCopyMonitor;
|
||||
Mutex mutex;
|
||||
Mutex queueMutex;
|
||||
};
|
||||
|
||||
MonitorLocal::MonitorLocal(
|
||||
@@ -95,9 +86,8 @@ MonitorLocal::MonitorLocal(
|
||||
PVRecordPtr const &pvRecord)
|
||||
: monitorRequester(channelMonitorRequester),
|
||||
pvRecord(pvRecord),
|
||||
state(idle),
|
||||
isGroupPut(false),
|
||||
dataChanged(false)
|
||||
isDestroyed(false),
|
||||
firstMonitor(true)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -113,21 +103,17 @@ void MonitorLocal::destroy()
|
||||
{
|
||||
if(pvRecord->getTraceLevel()>0)
|
||||
{
|
||||
cout << "MonitorLocal::destroy state " << state << endl;
|
||||
cout << "MonitorLocal::destroy " << isDestroyed << endl;
|
||||
}
|
||||
{
|
||||
Lock xx(mutex);
|
||||
if(state==destroyed) return;
|
||||
}
|
||||
if(pvCopy) pvCopy->destroy();
|
||||
{
|
||||
Lock xx(mutex);
|
||||
state = destroyed;
|
||||
}
|
||||
{
|
||||
Lock xx(queueMutex);
|
||||
queue.reset();
|
||||
if(isDestroyed) return;
|
||||
isDestroyed = true;
|
||||
}
|
||||
pvCopyMonitor->destroy();
|
||||
pvCopy->destroy();
|
||||
pvCopyMonitor.reset();
|
||||
queue.reset();
|
||||
pvCopy.reset();
|
||||
}
|
||||
|
||||
@@ -137,27 +123,16 @@ Status MonitorLocal::start()
|
||||
{
|
||||
cout << "MonitorLocal::start() " << endl;
|
||||
}
|
||||
if(isDestroyed) return wasDestroyedStatus;
|
||||
{
|
||||
Lock xx(mutex);
|
||||
if(state==destroyed) return wasDestroyedStatus;
|
||||
if(state==active) return alreadyStartedStatus;
|
||||
}
|
||||
pvRecord->addListener(getPtrSelf(),pvCopy);
|
||||
pvRecord->lock();
|
||||
try {
|
||||
Lock xx(mutex);
|
||||
state = active;
|
||||
firstMonitor = true;
|
||||
queue->clear();
|
||||
isGroupPut = false;
|
||||
activeElement = queue->getFree();
|
||||
activeElement->changedBitSet->clear();
|
||||
activeElement->overrunBitSet->clear();
|
||||
activeElement->changedBitSet->set(0);
|
||||
releaseActiveElement();
|
||||
pvRecord->unlock();
|
||||
} catch(...) {
|
||||
pvRecord->unlock();
|
||||
}
|
||||
pvCopyMonitor->startMonitoring(activeElement);
|
||||
return Status::Ok;
|
||||
}
|
||||
|
||||
@@ -166,13 +141,8 @@ Status MonitorLocal::stop()
|
||||
if(pvRecord->getTraceLevel()>0){
|
||||
cout << "MonitorLocal::stop() " << endl;
|
||||
}
|
||||
{
|
||||
Lock xx(mutex);
|
||||
if(state==destroyed) return wasDestroyedStatus;
|
||||
if(state==idle) return notStartedStatus;
|
||||
state = idle;
|
||||
}
|
||||
pvRecord->removeListener(getPtrSelf(),pvCopy);
|
||||
if(isDestroyed) return Status::Ok;
|
||||
pvCopyMonitor->stopMonitoring();
|
||||
return Status::Ok;
|
||||
}
|
||||
|
||||
@@ -182,11 +152,9 @@ MonitorElementPtr MonitorLocal::poll()
|
||||
{
|
||||
cout << "MonitorLocal::poll() " << endl;
|
||||
}
|
||||
{
|
||||
Lock xx(queueMutex);
|
||||
if(state!=active) return NULLMonitorElement;
|
||||
return queue->getUsed();
|
||||
}
|
||||
if(isDestroyed) return NULLMonitorElement;
|
||||
Lock xx(mutex);
|
||||
return queue->getUsed();
|
||||
}
|
||||
|
||||
void MonitorLocal::release(MonitorElementPtr const & monitorElement)
|
||||
@@ -195,24 +163,22 @@ void MonitorLocal::release(MonitorElementPtr const & monitorElement)
|
||||
{
|
||||
cout << "MonitorLocal::release() " << endl;
|
||||
}
|
||||
{
|
||||
Lock xx(queueMutex);
|
||||
if(state!=active) return;
|
||||
queue->releaseUsed(monitorElement);
|
||||
}
|
||||
if(isDestroyed) return;
|
||||
Lock xx(mutex);
|
||||
queue->releaseUsed(monitorElement);
|
||||
}
|
||||
|
||||
void MonitorLocal::releaseActiveElement()
|
||||
MonitorElementPtr MonitorLocal::releaseActiveElement()
|
||||
{
|
||||
if(pvRecord->getTraceLevel()>1)
|
||||
{
|
||||
cout << "MonitorLocal::releaseActiveElement() " << endl;
|
||||
}
|
||||
if(isDestroyed) return activeElement;
|
||||
{
|
||||
Lock xx(queueMutex);
|
||||
if(state!=active) return;
|
||||
Lock xx(mutex);
|
||||
MonitorElementPtr newActive = queue->getFree();
|
||||
if(!newActive) return;
|
||||
if(!newActive) return activeElement;
|
||||
pvCopy->updateCopyFromBitSet(activeElement->pvStructurePtr,activeElement->changedBitSet);
|
||||
BitSetUtil::compress(activeElement->changedBitSet,activeElement->pvStructurePtr);
|
||||
BitSetUtil::compress(activeElement->overrunBitSet,activeElement->pvStructurePtr);
|
||||
@@ -222,128 +188,45 @@ void MonitorLocal::releaseActiveElement()
|
||||
activeElement->overrunBitSet->clear();
|
||||
}
|
||||
monitorRequester->monitorEvent(getPtrSelf());
|
||||
return;
|
||||
return activeElement;
|
||||
}
|
||||
|
||||
void MonitorLocal::dataPut(PVRecordFieldPtr const & pvRecordField)
|
||||
void MonitorLocal::unlisten()
|
||||
{
|
||||
if(pvRecord->getTraceLevel()>1)
|
||||
if(pvRecord->getTraceLevel()>0)
|
||||
{
|
||||
cout << "PVCopyMonitor::dataPut(pvRecordField)" << endl;
|
||||
}
|
||||
if(state!=active) return;
|
||||
{
|
||||
Lock xx(mutex);
|
||||
size_t offset = pvCopy->getCopyOffset(pvRecordField->getPVField());
|
||||
BitSetPtr const &changedBitSet = activeElement->changedBitSet;
|
||||
BitSetPtr const &overrunBitSet = activeElement->overrunBitSet;
|
||||
bool isSet = changedBitSet->get(offset);
|
||||
changedBitSet->set(offset);
|
||||
if(isSet) overrunBitSet->set(offset);
|
||||
dataChanged = true;
|
||||
}
|
||||
if(!isGroupPut) {
|
||||
releaseActiveElement();
|
||||
dataChanged = false;
|
||||
cout << "MonitorLocal::unlisten() " << endl;
|
||||
}
|
||||
monitorRequester->unlisten(getPtrSelf());
|
||||
}
|
||||
|
||||
void MonitorLocal::dataPut(
|
||||
PVRecordStructurePtr const & requested,
|
||||
PVRecordFieldPtr const & pvRecordField)
|
||||
{
|
||||
if(pvRecord->getTraceLevel()>1)
|
||||
{
|
||||
cout << "PVCopyMonitor::dataPut(requested,pvRecordField)" << endl;
|
||||
}
|
||||
if(state!=active) return;
|
||||
{
|
||||
Lock xx(mutex);
|
||||
BitSetPtr const &changedBitSet = activeElement->changedBitSet;
|
||||
BitSetPtr const &overrunBitSet = activeElement->overrunBitSet;
|
||||
size_t offsetCopyRequested = pvCopy->getCopyOffset(
|
||||
requested->getPVField());
|
||||
size_t offset = offsetCopyRequested
|
||||
+ (pvRecordField->getPVField()->getFieldOffset()
|
||||
- requested->getPVField()->getFieldOffset());
|
||||
bool isSet = changedBitSet->get(offset);
|
||||
changedBitSet->set(offset);
|
||||
if(isSet) overrunBitSet->set(offset);
|
||||
dataChanged = true;
|
||||
}
|
||||
if(!isGroupPut) {
|
||||
releaseActiveElement();
|
||||
dataChanged = false;
|
||||
}
|
||||
}
|
||||
|
||||
void MonitorLocal::beginGroupPut(PVRecordPtr const & pvRecord)
|
||||
{
|
||||
if(pvRecord->getTraceLevel()>1)
|
||||
{
|
||||
cout << "PVCopyMonitor::beginGroupPut()" << endl;
|
||||
}
|
||||
if(state!=active) return;
|
||||
{
|
||||
Lock xx(mutex);
|
||||
isGroupPut = true;
|
||||
dataChanged = false;
|
||||
}
|
||||
}
|
||||
|
||||
void MonitorLocal::endGroupPut(PVRecordPtr const & pvRecord)
|
||||
{
|
||||
if(pvRecord->getTraceLevel()>1)
|
||||
{
|
||||
cout << "PVCopyMonitor::endGroupPut() dataChanged " << dataChanged << endl;
|
||||
}
|
||||
if(state!=active) return;
|
||||
{
|
||||
Lock xx(mutex);
|
||||
isGroupPut = false;
|
||||
}
|
||||
if(dataChanged) {
|
||||
dataChanged = false;
|
||||
releaseActiveElement();
|
||||
}
|
||||
}
|
||||
|
||||
void MonitorLocal::unlisten(PVRecordPtr const & pvRecord)
|
||||
{
|
||||
if(pvRecord->getTraceLevel()>1)
|
||||
{
|
||||
cout << "PVCopyMonitor::unlisten\n";
|
||||
}
|
||||
pvRecord->removeListener(getPtrSelf(),pvCopy);
|
||||
}
|
||||
|
||||
|
||||
bool MonitorLocal::init(PVStructurePtr const & pvRequest)
|
||||
{
|
||||
PVFieldPtr pvField;
|
||||
PVStructurePtr pvOptions;
|
||||
size_t queueSize = 2;
|
||||
PVStructurePtr pvOptions = pvRequest->getSubField<PVStructure>("record._options");
|
||||
if(pvOptions) {
|
||||
PVStringPtr pvString = pvOptions->getSubField<PVString>("queueSize");
|
||||
if(pvString) {
|
||||
try {
|
||||
pvField = pvRequest->getSubField("record._options");
|
||||
if(pvField.get()!=NULL) {
|
||||
pvOptions = static_pointer_cast<PVStructure>(pvField);
|
||||
pvField = pvOptions->getSubField("queueSize");
|
||||
if(pvField.get()!=NULL) {
|
||||
PVStringPtr pvString = pvOptions->getStringField("queueSize");
|
||||
if(pvString.get()!=NULL) {
|
||||
int32 size;
|
||||
std::stringstream ss;
|
||||
ss << pvString->get();
|
||||
ss >> size;
|
||||
queueSize = size;
|
||||
} catch (...) {
|
||||
monitorRequester->message("queueSize " +pvString->get() + " illegal",errorMessage);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pvField = pvRequest->getSubField("field");
|
||||
if(!pvField) {
|
||||
if(pvField.get()==NULL) {
|
||||
pvCopy = PVCopy::create(
|
||||
pvRecord->getPVRecordStructure()->getPVStructure(),
|
||||
pvRequest,"");
|
||||
if(!pvCopy) {
|
||||
if(pvCopy.get()==NULL) {
|
||||
monitorRequester->message("illegal pvRequest",errorMessage);
|
||||
return false;
|
||||
}
|
||||
@@ -355,21 +238,27 @@ bool MonitorLocal::init(PVStructurePtr const & pvRequest)
|
||||
pvCopy = PVCopy::create(
|
||||
pvRecord->getPVRecordStructure()->getPVStructure(),
|
||||
pvRequest,"field");
|
||||
if(!pvCopy) {
|
||||
if(pvCopy.get()==NULL) {
|
||||
monitorRequester->message("illegal pvRequest",errorMessage);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
pvCopyMonitor = PVCopyMonitor::create(
|
||||
getPtrSelf(),pvRecord,pvCopy);
|
||||
// MARTY MUST IMPLEMENT periodic
|
||||
if(queueSize<2) queueSize = 2;
|
||||
std::vector<MonitorElementPtr> monitorElementArray;
|
||||
monitorElementArray.reserve(queueSize);
|
||||
size_t nfields = 0;
|
||||
for(size_t i=0; i<queueSize; i++) {
|
||||
PVStructurePtr pvStructure = pvCopy->createPVStructure();
|
||||
if(nfields==0) nfields = pvStructure->getNumberFields();
|
||||
MonitorElementPtr monitorElement(
|
||||
new MonitorElement(pvStructure));
|
||||
monitorElementArray.push_back(monitorElement);
|
||||
}
|
||||
queue = MonitorElementQueuePtr(new MonitorElementQueue(monitorElementArray));
|
||||
// MARTY MUST IMPLEMENT algorithm
|
||||
monitorRequester->monitorConnect(
|
||||
Status::Ok,
|
||||
getPtrSelf(),
|
||||
@@ -390,6 +279,7 @@ MonitorFactory::~MonitorFactory()
|
||||
void MonitorFactory::destroy()
|
||||
{
|
||||
Lock lock(mutex);
|
||||
if(isDestroyed) return;
|
||||
isDestroyed = true;
|
||||
}
|
||||
|
||||
@@ -406,12 +296,7 @@ MonitorPtr MonitorFactory::createMonitor(
|
||||
MonitorLocalPtr monitor(new MonitorLocal(
|
||||
monitorRequester,pvRecord));
|
||||
bool result = monitor->init(pvRequest);
|
||||
if(!result) {
|
||||
MonitorPtr monitor;
|
||||
StructureConstPtr structure;
|
||||
monitorRequester->monitorConnect(failedToCreateMonitorStatus,monitor,structure);
|
||||
return nullMonitor;
|
||||
}
|
||||
if(!result) return nullMonitor;
|
||||
if(pvRecord->getTraceLevel()>0)
|
||||
{
|
||||
cout << "MonitorFactory::createMonitor";
|
||||
|
||||
318
src/pvAccess/pvCopyMonitor.cpp
Normal file
318
src/pvAccess/pvCopyMonitor.cpp
Normal file
@@ -0,0 +1,318 @@
|
||||
/* pvCopyMonitor.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 Marty Kraimer
|
||||
* @date 2013.04
|
||||
*/
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
|
||||
#include <pv/thread.h>
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
|
||||
#include <pv/channelProviderLocal.h>
|
||||
#include <pv/pvCopyMonitor.h>
|
||||
|
||||
using namespace epics::pvData;
|
||||
using std::tr1::static_pointer_cast;
|
||||
using std::tr1::dynamic_pointer_cast;
|
||||
using std::size_t;
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
using std::string;
|
||||
|
||||
namespace epics { namespace pvDatabase {
|
||||
|
||||
struct PVCopyMonitorFieldNode
|
||||
{
|
||||
MonitorPluginPtr monitorPlugin;
|
||||
size_t offset; // in pvCopy
|
||||
};
|
||||
|
||||
PVCopyMonitorPtr PVCopyMonitor::create(
|
||||
PVCopyMonitorRequesterPtr const &pvCopyMonitorRequester,
|
||||
PVRecordPtr const &pvRecord,
|
||||
PVCopyPtr const & pvCopy)
|
||||
{
|
||||
PVCopyMonitorPtr pvCopyMonitor( new PVCopyMonitor(
|
||||
pvRecord,pvCopy,pvCopyMonitorRequester));
|
||||
pvCopyMonitor->init(pvRecord->getPVRecordStructure()->getPVStructure());
|
||||
return pvCopyMonitor;
|
||||
}
|
||||
|
||||
|
||||
PVCopyMonitor::PVCopyMonitor(
|
||||
PVRecordPtr const &pvRecord,
|
||||
PVCopyPtr const &pvCopy,
|
||||
PVCopyMonitorRequesterPtr const &pvCopyMonitorRequester
|
||||
)
|
||||
: pvRecord(pvRecord),
|
||||
pvCopy(pvCopy),
|
||||
pvCopyMonitorRequester(pvCopyMonitorRequester),
|
||||
isGroupPut(false),
|
||||
dataChanged(false),
|
||||
isMonitoring(false),
|
||||
isDestroyed(false)
|
||||
{
|
||||
}
|
||||
|
||||
PVCopyMonitor::~PVCopyMonitor()
|
||||
{
|
||||
if(pvRecord->getTraceLevel()>0)
|
||||
{
|
||||
cout << "~PVCopyMonitor" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
// pvField is in top level structure of PVRecord.
|
||||
void PVCopyMonitor::init(PVFieldPtr const &pvField)
|
||||
{
|
||||
size_t offset = pvCopy->getCopyOffset(pvField);
|
||||
if(offset==string::npos) return;
|
||||
PVStructurePtr pvOptions = pvCopy->getOptions(offset);
|
||||
if(pvOptions) {
|
||||
PVStringPtr pvName = pvOptions->getSubField<PVString>("plugin");
|
||||
if(pvName) {
|
||||
string pluginName = pvName->get();
|
||||
MonitorPluginManagerPtr manager = MonitorPluginManager::get();
|
||||
MonitorPluginCreatorPtr pluginCreator = manager->findPlugin(pluginName);
|
||||
if(pluginCreator) {
|
||||
StructureConstPtr top = pvCopy->getStructure();
|
||||
FieldConstPtr field = pvField->getField();
|
||||
MonitorPluginPtr monitorPlugin = pluginCreator->create(field,top,pvOptions);
|
||||
if(monitorPlugin) {
|
||||
PVCopyMonitorFieldNodePtr fieldNode(new PVCopyMonitorFieldNode());
|
||||
fieldNode->monitorPlugin = monitorPlugin;
|
||||
fieldNode->offset = offset;
|
||||
monitorFieldNodeList.push_back(fieldNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(pvField->getField()->getType()!=structure) return;
|
||||
PVStructurePtr pv = static_pointer_cast<PVStructure>(pvField);
|
||||
const PVFieldPtrArray &pvFields = pv->getPVFields();
|
||||
for(size_t i=0; i<pvFields.size(); ++i ) init(pvFields[i]);
|
||||
}
|
||||
|
||||
MonitorPluginPtr PVCopyMonitor::getMonitorPlugin(size_t offset)
|
||||
{
|
||||
std::list<PVCopyMonitorFieldNodePtr>::iterator iter;
|
||||
for (iter = monitorFieldNodeList.begin();iter!=monitorFieldNodeList.end();++iter)
|
||||
{
|
||||
if((*iter)->offset==offset) return (*iter)->monitorPlugin;
|
||||
}
|
||||
return MonitorPluginPtr();
|
||||
}
|
||||
|
||||
void PVCopyMonitor::destroy()
|
||||
{
|
||||
if(pvRecord->getTraceLevel()>0)
|
||||
{
|
||||
cout << "PVCopyMonitor::destroy()" << endl;
|
||||
}
|
||||
if(isDestroyed) return;
|
||||
Lock xx(mutex);
|
||||
isDestroyed = true;
|
||||
stopMonitoring();
|
||||
pvCopyMonitorRequester.reset();
|
||||
pvCopy.reset();
|
||||
}
|
||||
|
||||
void PVCopyMonitor::startMonitoring(MonitorElementPtr const & startElement)
|
||||
{
|
||||
if(pvRecord->getTraceLevel()>0)
|
||||
{
|
||||
cout << "PVCopyMonitor::startMonitoring()" << endl;
|
||||
}
|
||||
if(isDestroyed) return;
|
||||
monitorElement = startElement;
|
||||
Lock xx(mutex);
|
||||
if(isMonitoring) return;
|
||||
isMonitoring = true;
|
||||
isGroupPut = false;
|
||||
std::list<PVCopyMonitorFieldNodePtr>::iterator iter;
|
||||
for (iter = monitorFieldNodeList.begin();iter!=monitorFieldNodeList.end();++iter)
|
||||
{
|
||||
(*iter)->monitorPlugin->startMonitoring();
|
||||
}
|
||||
pvRecord->addListener(getPtrSelf());
|
||||
pvRecord->lock();
|
||||
try {
|
||||
pvCopy->traverseMaster(getPtrSelf());
|
||||
monitorElement->changedBitSet->clear();
|
||||
monitorElement->overrunBitSet->clear();
|
||||
monitorElement->changedBitSet->set(0);
|
||||
monitorElement = pvCopyMonitorRequester->releaseActiveElement();
|
||||
pvRecord->unlock();
|
||||
} catch(...) {
|
||||
pvRecord->unlock();
|
||||
}
|
||||
}
|
||||
|
||||
void PVCopyMonitor::nextMasterPVField(epics::pvData::PVFieldPtr const &pvField)
|
||||
{
|
||||
pvRecord->findPVRecordField(pvField)->addListener(getPtrSelf());
|
||||
}
|
||||
|
||||
void PVCopyMonitor::stopMonitoring()
|
||||
{
|
||||
if(pvRecord->getTraceLevel()>0)
|
||||
{
|
||||
cout << "PVCopyMonitor::stopMonitoring()" << endl;
|
||||
}
|
||||
if(isDestroyed) return;
|
||||
if(!isMonitoring) return;
|
||||
pvRecord->removeListener(getPtrSelf());
|
||||
Lock xx(mutex);
|
||||
std::list<PVCopyMonitorFieldNodePtr>::iterator iter;
|
||||
for (iter = monitorFieldNodeList.begin();iter!=monitorFieldNodeList.end();++iter)
|
||||
{
|
||||
(*iter)->monitorPlugin->stopMonitoring();
|
||||
}
|
||||
isMonitoring = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void PVCopyMonitor::detach(PVRecordPtr const & pvRecord)
|
||||
{
|
||||
if(pvRecord->getTraceLevel()>0)
|
||||
{
|
||||
cout << "PVCopyMonitor::detach()" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
void PVCopyMonitor::dataPut(PVRecordFieldPtr const & pvRecordField)
|
||||
{
|
||||
if(pvRecord->getTraceLevel()>1)
|
||||
{
|
||||
cout << "PVCopyMonitor::dataPut(pvRecordField)" << endl;
|
||||
}
|
||||
if(isDestroyed) return;
|
||||
bool causeMonitor = true;
|
||||
{
|
||||
Lock xx(mutex);
|
||||
size_t offset = pvCopy->getCopyOffset(pvRecordField->getPVField());
|
||||
BitSetPtr const &changedBitSet = monitorElement->changedBitSet;
|
||||
BitSetPtr const &overrunBitSet = monitorElement->overrunBitSet;
|
||||
bool isSet = changedBitSet->get(offset);
|
||||
changedBitSet->set(offset);
|
||||
if(isSet) overrunBitSet->set(offset);
|
||||
MonitorPluginPtr monitorPlugin = getMonitorPlugin(offset);
|
||||
if(monitorPlugin) {
|
||||
causeMonitor = monitorPlugin->causeMonitor(
|
||||
pvRecordField->getPVField(),
|
||||
pvRecord->getPVRecordStructure()->getPVStructure(),
|
||||
monitorElement);
|
||||
}
|
||||
if(causeMonitor) dataChanged = true;
|
||||
}
|
||||
if(causeMonitor) {
|
||||
if(!isGroupPut) {
|
||||
monitorElement = pvCopyMonitorRequester->releaseActiveElement();
|
||||
dataChanged = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PVCopyMonitor::dataPut(
|
||||
PVRecordStructurePtr const & requested,
|
||||
PVRecordFieldPtr const & pvRecordField)
|
||||
{
|
||||
if(pvRecord->getTraceLevel()>1)
|
||||
{
|
||||
cout << "PVCopyMonitor::dataPut(requested,pvRecordField)" << endl;
|
||||
}
|
||||
if(isDestroyed) return;
|
||||
bool causeMonitor = true;
|
||||
{
|
||||
Lock xx(mutex);
|
||||
BitSetPtr const &changedBitSet = monitorElement->changedBitSet;
|
||||
BitSetPtr const &overrunBitSet = monitorElement->overrunBitSet;
|
||||
size_t offsetCopyRequested = pvCopy->getCopyOffset(
|
||||
requested->getPVField());
|
||||
size_t offset = offsetCopyRequested
|
||||
+ (pvRecordField->getPVField()->getFieldOffset()
|
||||
- requested->getPVField()->getFieldOffset());
|
||||
bool isSet = changedBitSet->get(offset);
|
||||
changedBitSet->set(offset);
|
||||
if(isSet) overrunBitSet->set(offset);
|
||||
MonitorPluginPtr monitorPlugin = getMonitorPlugin(offsetCopyRequested);
|
||||
if(monitorPlugin) {
|
||||
causeMonitor = monitorPlugin->causeMonitor(
|
||||
requested->getPVField(),
|
||||
pvRecord->getPVRecordStructure()->getPVStructure(),
|
||||
monitorElement);
|
||||
}
|
||||
if(causeMonitor) dataChanged = true;
|
||||
}
|
||||
if(causeMonitor) {
|
||||
if(!isGroupPut) {
|
||||
monitorElement = pvCopyMonitorRequester->releaseActiveElement();
|
||||
dataChanged = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PVCopyMonitor::beginGroupPut(PVRecordPtr const & pvRecord)
|
||||
{
|
||||
if(pvRecord->getTraceLevel()>1)
|
||||
{
|
||||
cout << "PVCopyMonitor::beginGroupPut()" << endl;
|
||||
}
|
||||
if(isDestroyed) return;
|
||||
{
|
||||
Lock xx(mutex);
|
||||
isGroupPut = true;
|
||||
dataChanged = false;
|
||||
}
|
||||
std::list<PVCopyMonitorFieldNodePtr>::iterator iter;
|
||||
for (iter = monitorFieldNodeList.begin();
|
||||
iter!=monitorFieldNodeList.end();
|
||||
++iter)
|
||||
{
|
||||
(*iter)->monitorPlugin->beginGroupPut();
|
||||
}
|
||||
}
|
||||
|
||||
void PVCopyMonitor::endGroupPut(PVRecordPtr const & pvRecord)
|
||||
{
|
||||
if(pvRecord->getTraceLevel()>1)
|
||||
{
|
||||
cout << "PVCopyMonitor::endGroupPut() dataChanged " << dataChanged << endl;
|
||||
}
|
||||
if(isDestroyed) return;
|
||||
std::list<PVCopyMonitorFieldNodePtr>::iterator iter;
|
||||
for (iter = monitorFieldNodeList.begin();iter!=monitorFieldNodeList.end();++iter)
|
||||
{
|
||||
(*iter)->monitorPlugin->endGroupPut();
|
||||
}
|
||||
{
|
||||
Lock xx(mutex);
|
||||
isGroupPut = false;
|
||||
}
|
||||
if(dataChanged) {
|
||||
monitorElement = pvCopyMonitorRequester->releaseActiveElement();
|
||||
dataChanged = false;
|
||||
}
|
||||
}
|
||||
|
||||
void PVCopyMonitor::unlisten(PVRecordPtr const & pvRecord)
|
||||
{
|
||||
if(pvRecord->getTraceLevel()>1)
|
||||
{
|
||||
cout << "PVCopyMonitor::unlisten\n";
|
||||
}
|
||||
if(isDestroyed) return;
|
||||
pvCopyMonitorRequester->unlisten();
|
||||
}
|
||||
|
||||
}}
|
||||
168
src/pvAccess/pvCopyMonitor.h
Normal file
168
src/pvAccess/pvCopyMonitor.h
Normal file
@@ -0,0 +1,168 @@
|
||||
/* pvCopyMonitor.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 Marty Kraimer
|
||||
* @date 2013.04
|
||||
*/
|
||||
#ifndef PVCOPYMONITOR_H
|
||||
#define PVCOPYMONITOR_H
|
||||
|
||||
#ifdef epicsExportSharedSymbols
|
||||
# define pvCopyMonitorEpicsExportSharedSymbols
|
||||
# undef epicsExportSharedSymbols
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
#include <memory>
|
||||
#include <list>
|
||||
|
||||
#include <pv/monitorPlugin.h>
|
||||
#include <pv/pvCopy.h>
|
||||
#include <pv/pvAccess.h>
|
||||
|
||||
#ifdef pvCopyMonitorEpicsExportSharedSymbols
|
||||
# define epicsExportSharedSymbols
|
||||
# undef pvCopyMonitorEpicsExportSharedSymbols
|
||||
#endif
|
||||
|
||||
#include <shareLib.h>
|
||||
|
||||
#include <pv/pvDatabase.h>
|
||||
|
||||
namespace epics { namespace pvDatabase {
|
||||
|
||||
class PVCopyMonitor;
|
||||
typedef std::tr1::shared_ptr<PVCopyMonitor> PVCopyMonitorPtr;
|
||||
class PVCopyMonitorRequester;
|
||||
typedef std::tr1::shared_ptr<PVCopyMonitorRequester> PVCopyMonitorRequesterPtr;
|
||||
|
||||
struct PVCopyMonitorFieldNode;
|
||||
typedef std::tr1::shared_ptr<PVCopyMonitorFieldNode> PVCopyMonitorFieldNodePtr;
|
||||
|
||||
|
||||
/**
|
||||
* PVCopyMonitor
|
||||
* This class manages changes to fields being monitored in a PVRecord.
|
||||
*/
|
||||
class epicsShareClass PVCopyMonitor :
|
||||
public PVListener,
|
||||
public epics::pvData::PVCopyTraverseMasterCallback,
|
||||
public std::tr1::enable_shared_from_this<PVCopyMonitor>
|
||||
{
|
||||
public:
|
||||
POINTER_DEFINITIONS(PVCopyMonitor);
|
||||
/**
|
||||
* Factory method to create a PVCopyMonoitor
|
||||
* @param pvCopyMonitorRequester This is usually MonitorLocal.
|
||||
* @param pvRecord The record being monitored.
|
||||
* @param pvCopy An instance of pvCopy
|
||||
* @return A shared pointer to a PVCopyMonitor.
|
||||
*/
|
||||
static PVCopyMonitorPtr create(
|
||||
PVCopyMonitorRequesterPtr const &pvCopyMonitorRequester,
|
||||
PVRecordPtr const &pvRecord,
|
||||
epics::pvData::PVCopyPtr const & pvCopy);
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
virtual ~PVCopyMonitor();
|
||||
/**
|
||||
* Destroy the PVCopyMonitor
|
||||
*/
|
||||
virtual void destroy();
|
||||
/**
|
||||
* Calls pvRecord methods to start monitoring for calls to postPut.
|
||||
* @param monitorElement the initial monotorElement
|
||||
* This holds the change and overrun bitSets that are updated
|
||||
* when postPut is called.
|
||||
*/
|
||||
void startMonitoring(
|
||||
epics::pvData::MonitorElementPtr const & monitorElement);
|
||||
/**
|
||||
* Calls pvRecord methods to stop monitoring for calls to postPut.
|
||||
*/
|
||||
void stopMonitoring();
|
||||
// following are PVListener methods
|
||||
/**
|
||||
* The record is being removed from the PVDatabase.
|
||||
* @param The record being removed.
|
||||
*/
|
||||
virtual void detach(PVRecordPtr const & pvRecord);
|
||||
/**
|
||||
* A postPut has been issued to a field being monitored.
|
||||
* @param pvRecordField The field.
|
||||
*/
|
||||
virtual void dataPut(PVRecordFieldPtr const & pvRecordField);
|
||||
/**
|
||||
* A postPut has been issued to a subfield of a field being monitored.
|
||||
* @param requested The field being monitored.
|
||||
* @param pvRecordField The field being modified.
|
||||
*/
|
||||
virtual void dataPut(
|
||||
PVRecordStructurePtr const & requested,
|
||||
PVRecordFieldPtr const & pvRecordField);
|
||||
/**
|
||||
* A group of puts are being changed.
|
||||
* No monitors should be issued until endGroupPut is called.
|
||||
* @param pvRecord The record.
|
||||
*/
|
||||
virtual void beginGroupPut(PVRecordPtr const & pvRecord);
|
||||
/**
|
||||
* The end of a group of puts.
|
||||
* If any fields have changed value since beginGroupPut a monitor
|
||||
* can be issued.
|
||||
* @param pvRecord The record.
|
||||
*/
|
||||
virtual void endGroupPut(PVRecordPtr const & pvRecord);
|
||||
/**
|
||||
* The record is being removed from the database.
|
||||
* @param pvRecord The record.
|
||||
*/
|
||||
virtual void unlisten(PVRecordPtr const & pvRecord);
|
||||
// following is PVCopyTraverseMasterCallback method
|
||||
/**
|
||||
* The PVCopyTraverseMasterCallback callback
|
||||
* Called for every field of PVRecord that is being monoitored.
|
||||
* @param pvField The field in the PVRecord.
|
||||
*/
|
||||
virtual void nextMasterPVField(epics::pvData::PVFieldPtr const &pvField);
|
||||
private:
|
||||
PVCopyMonitorPtr getPtrSelf()
|
||||
{
|
||||
return shared_from_this();
|
||||
}
|
||||
PVCopyMonitor(
|
||||
PVRecordPtr const &pvRecord,
|
||||
epics::pvData::PVCopyPtr const &pvCopy,
|
||||
PVCopyMonitorRequesterPtr const &pvCopyMonitorRequester);
|
||||
void init(epics::pvData::PVFieldPtr const &pvField);
|
||||
epics::pvData::MonitorPluginPtr getMonitorPlugin(size_t offset);
|
||||
PVRecordPtr pvRecord;
|
||||
epics::pvData::PVCopyPtr pvCopy;
|
||||
PVCopyMonitorRequesterPtr pvCopyMonitorRequester;
|
||||
epics::pvData::MonitorElementPtr monitorElement;
|
||||
bool isGroupPut;
|
||||
bool dataChanged;
|
||||
bool isMonitoring;
|
||||
bool isDestroyed;
|
||||
epics::pvData::Mutex mutex;
|
||||
std::list<PVCopyMonitorFieldNodePtr> monitorFieldNodeList;
|
||||
};
|
||||
|
||||
class epicsShareClass PVCopyMonitorRequester
|
||||
{
|
||||
public:
|
||||
POINTER_DEFINITIONS(PVCopyMonitorRequester);
|
||||
virtual ~PVCopyMonitorRequester() {}
|
||||
virtual epics::pvData::MonitorElementPtr releaseActiveElement() = 0;
|
||||
virtual void unlisten() = 0;
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif /* PVCOPYMONITOR_H */
|
||||
@@ -44,7 +44,7 @@ using namespace epics::pvDatabase;
|
||||
static const iocshFuncDef pvdblFuncDef = {
|
||||
"pvdbl", 0, 0
|
||||
};
|
||||
extern "C" void pvdbl(const iocshArgBuf *args)
|
||||
extern "C" void epicsShareAPI pvdbl(const iocshArgBuf *args)
|
||||
{
|
||||
PVDatabasePtr master = PVDatabase::getMaster();
|
||||
PVStringArrayPtr pvNames = master->getRecordNames();
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
SRC_DIRS += $(PVDATABASE_SRC)/special
|
||||
|
||||
INC += recordList.h
|
||||
INC += traceRecord.h
|
||||
|
||||
LIBSRCS += recordList.cpp
|
||||
LIBSRCS += traceRecord.cpp
|
||||
|
||||
99
src/special/recordList.cpp
Normal file
99
src/special/recordList.cpp
Normal file
@@ -0,0 +1,99 @@
|
||||
/* recordList.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.18
|
||||
*/
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
|
||||
#include <pv/recordList.h>
|
||||
|
||||
using std::tr1::static_pointer_cast;
|
||||
using namespace epics::pvData;
|
||||
using namespace std;
|
||||
|
||||
namespace epics { namespace pvDatabase {
|
||||
|
||||
RecordListRecordPtr RecordListRecord::create(
|
||||
std::string const & recordName)
|
||||
{
|
||||
FieldCreatePtr fieldCreate = getFieldCreate();
|
||||
PVDataCreatePtr pvDataCreate = getPVDataCreate();
|
||||
StructureConstPtr topStructure = fieldCreate->createFieldBuilder()->
|
||||
addNestedStructure("argument")->
|
||||
add("database",pvString)->
|
||||
add("regularExpression",pvString)->
|
||||
endNested()->
|
||||
addNestedStructure("result") ->
|
||||
add("status",pvString) ->
|
||||
addArray("names",pvString) ->
|
||||
endNested()->
|
||||
createStructure();
|
||||
PVStructurePtr pvStructure = pvDataCreate->createPVStructure(topStructure);
|
||||
RecordListRecordPtr pvRecord(
|
||||
new RecordListRecord(recordName,pvStructure));
|
||||
if(!pvRecord->init()) pvRecord.reset();
|
||||
return pvRecord;
|
||||
}
|
||||
|
||||
RecordListRecord::RecordListRecord(
|
||||
std::string const & recordName,
|
||||
epics::pvData::PVStructurePtr const & pvStructure)
|
||||
: PVRecord(recordName,pvStructure)
|
||||
{
|
||||
}
|
||||
|
||||
RecordListRecord::~RecordListRecord()
|
||||
{
|
||||
}
|
||||
|
||||
void RecordListRecord::destroy()
|
||||
{
|
||||
PVRecord::destroy();
|
||||
}
|
||||
|
||||
bool RecordListRecord::init()
|
||||
{
|
||||
initPVRecord();
|
||||
PVStructurePtr pvStructure = getPVStructure();
|
||||
database = pvStructure->getStringField("argument.database");
|
||||
if(database.get()==NULL) return false;
|
||||
regularExpression = pvStructure->getStringField(
|
||||
"argument.regularExpression");
|
||||
if(regularExpression.get()==NULL) return false;
|
||||
status = pvStructure->getStringField("result.status");
|
||||
if(status.get()==NULL) return false;
|
||||
PVFieldPtr pvField = pvStructure->getSubField("result.names");
|
||||
if(pvField.get()==NULL) {
|
||||
std::cerr << "no result.names" << std::endl;
|
||||
return false;
|
||||
}
|
||||
name = static_pointer_cast<PVStringArray>(
|
||||
pvStructure->getScalarArrayField("result.names",pvString));
|
||||
if(name.get()==NULL) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void RecordListRecord::process()
|
||||
{
|
||||
PVStringArrayPtr pvNames = PVDatabase::getMaster()->getRecordNames();
|
||||
name->replace(pvNames->view());
|
||||
string message("");
|
||||
if(database->get().compare("master")!=0) {
|
||||
message += " can only access master ";
|
||||
}
|
||||
string regEx = regularExpression->get();
|
||||
if(regEx.compare("")!=0 && regEx.compare(".*")!=0) {
|
||||
message += " regularExpression not implemented ";
|
||||
}
|
||||
status->put(message);
|
||||
}
|
||||
|
||||
|
||||
}}
|
||||
|
||||
68
src/special/recordList.h
Normal file
68
src/special/recordList.h
Normal file
@@ -0,0 +1,68 @@
|
||||
/* recordListTest.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.18
|
||||
*/
|
||||
#ifndef RECORDLIST_H
|
||||
#define RECORDLIST_H
|
||||
|
||||
#include <shareLib.h>
|
||||
|
||||
#include <pv/pvDatabase.h>
|
||||
|
||||
namespace epics { namespace pvDatabase {
|
||||
|
||||
class RecordListRecord;
|
||||
typedef std::tr1::shared_ptr<RecordListRecord> RecordListRecordPtr;
|
||||
|
||||
/**
|
||||
* This is a record that provides a PVStringArray that
|
||||
* has the record names of all records in the local PVDatabase.
|
||||
* It is meant to be used by a channelPutGet request.
|
||||
*/
|
||||
class epicsShareClass RecordListRecord :
|
||||
public PVRecord
|
||||
{
|
||||
public:
|
||||
POINTER_DEFINITIONS(RecordListRecord);
|
||||
/**
|
||||
* Factory methods to create RecordListRecord.
|
||||
* @param recordName The name for the RecordListRecord.
|
||||
* @return A shared pointer to RecordListRecord..
|
||||
*/
|
||||
static RecordListRecordPtr create(
|
||||
std::string const & recordName);
|
||||
/**
|
||||
* destructor
|
||||
*/
|
||||
virtual ~RecordListRecord();
|
||||
/**
|
||||
* Clean up any resources used.
|
||||
*/
|
||||
virtual void destroy();
|
||||
/**
|
||||
* standard init method required by PVRecord
|
||||
* @return true unless record name already exists.
|
||||
*/
|
||||
virtual bool init();
|
||||
/*
|
||||
* Generated the list of record names.
|
||||
*/
|
||||
virtual void process();
|
||||
private:
|
||||
RecordListRecord(std::string const & recordName,
|
||||
epics::pvData::PVStructurePtr const & pvStructure);
|
||||
epics::pvData::PVStringPtr database;
|
||||
epics::pvData::PVStringPtr regularExpression;
|
||||
epics::pvData::PVStringPtr status;
|
||||
epics::pvData::PVStringArrayPtr name;
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif /* RECORDLIST_H */
|
||||
@@ -62,11 +62,11 @@ bool TraceRecord::init()
|
||||
{
|
||||
initPVRecord();
|
||||
PVStructurePtr pvStructure = getPVStructure();
|
||||
pvRecordName = pvStructure->getSubField<PVString>("argument.recordName");
|
||||
pvRecordName = pvStructure->getStringField("argument.recordName");
|
||||
if(!pvRecordName) return false;
|
||||
pvLevel = pvStructure->getSubField<PVInt>("argument.level");
|
||||
pvLevel = pvStructure->getIntField("argument.level");
|
||||
if(!pvLevel) return false;
|
||||
pvResult = pvStructure->getSubField<PVString>("result.status");
|
||||
pvResult = pvStructure->getStringField("result.status");
|
||||
if(!pvResult) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -18,17 +18,15 @@
|
||||
namespace epics { namespace pvDatabase {
|
||||
|
||||
|
||||
class TraceRecord;
|
||||
typedef std::tr1::shared_ptr<TraceRecord> TraceRecordPtr;
|
||||
|
||||
/**
|
||||
* @brief Trace activity of PVRecord.
|
||||
*
|
||||
* A record to set the trace value for another record
|
||||
* It is meant to be used via a channelPutGet request.
|
||||
* The argument has two fields: recordName and level.
|
||||
* The result has a field named status.
|
||||
*/
|
||||
class TraceRecord;
|
||||
typedef std::tr1::shared_ptr<TraceRecord> TraceRecordPtr;
|
||||
|
||||
class epicsShareClass TraceRecord :
|
||||
public PVRecord
|
||||
{
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
#include <pv/standardField.h>
|
||||
#include <pv/standardPVField.h>
|
||||
#include <pv/channelProviderLocal.h>
|
||||
#include <pv/convert.h>
|
||||
#include "powerSupply.h"
|
||||
|
||||
|
||||
@@ -144,6 +143,7 @@ static void testPVScalar(
|
||||
}
|
||||
|
||||
static void testPVScalarArray(
|
||||
ScalarType scalarType,
|
||||
string const & valueNameRecord,
|
||||
string const & valueNameCopy,
|
||||
PVRecordPtr const & pvRecord,
|
||||
@@ -159,14 +159,14 @@ static void testPVScalarArray(
|
||||
shared_vector<double> values(n);
|
||||
cout << endl;
|
||||
pvStructureRecord = pvRecord->getPVRecordStructure()->getPVStructure();
|
||||
pvValueRecord = pvStructureRecord->getSubField<PVScalarArray>(valueNameRecord);
|
||||
pvValueRecord = pvStructureRecord->getScalarArrayField(valueNameRecord,scalarType);
|
||||
for(size_t i=0; i<n; i++) values[i] = i;
|
||||
const shared_vector<const double> xxx(freeze(values));
|
||||
pvValueRecord->putFrom(xxx);
|
||||
StructureConstPtr structure = pvCopy->getStructure();
|
||||
cout << "structure from copy" << endl << *structure << endl;
|
||||
pvStructureCopy = pvCopy->createPVStructure();
|
||||
pvValueCopy = pvStructureCopy->getSubField<PVScalarArray>(valueNameCopy);
|
||||
pvValueCopy = pvStructureCopy->getScalarArrayField(valueNameCopy,scalarType);
|
||||
bitSet = BitSetPtr(new BitSet(pvStructureCopy->getNumberFields()));
|
||||
pvCopy->initCopy(pvStructureCopy, bitSet);
|
||||
cout << "after initCopy pvValueCopy " << *pvValueCopy << endl;
|
||||
@@ -276,21 +276,21 @@ static void arrayTest()
|
||||
cout << "request " << request << endl << "pvRequest" << *pvRequest << endl ;
|
||||
pvCopy = PVCopy::create(pvRecord->getPVRecordStructure()->getPVStructure(),pvRequest,"");
|
||||
valueNameCopy = "value";
|
||||
testPVScalarArray(valueNameRecord,valueNameCopy,pvRecord,pvCopy);
|
||||
testPVScalarArray(pvDouble,valueNameRecord,valueNameCopy,pvRecord,pvCopy);
|
||||
request = "";
|
||||
valueNameRecord = "value";
|
||||
pvRequest = createRequest->createRequest(request);
|
||||
cout << "request " << request << endl << "pvRequest" << *pvRequest << endl ;
|
||||
pvCopy = PVCopy::create(pvRecord->getPVRecordStructure()->getPVStructure(),pvRequest,"");
|
||||
valueNameCopy = "value";
|
||||
testPVScalarArray(valueNameRecord,valueNameCopy,pvRecord,pvCopy);
|
||||
testPVScalarArray(pvDouble,valueNameRecord,valueNameCopy,pvRecord,pvCopy);
|
||||
request = "alarm,timeStamp,value";
|
||||
valueNameRecord = "value";
|
||||
pvRequest = createRequest->createRequest(request);
|
||||
cout << "request " << request << endl << "pvRequest" << *pvRequest << endl ;
|
||||
pvCopy = PVCopy::create(pvRecord->getPVRecordStructure()->getPVStructure(),pvRequest,"");
|
||||
valueNameCopy = "value";
|
||||
testPVScalarArray(valueNameRecord,valueNameCopy,pvRecord,pvCopy);
|
||||
testPVScalarArray(pvDouble,valueNameRecord,valueNameCopy,pvRecord,pvCopy);
|
||||
pvRecord->destroy();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user