more work on memory issues.
Still problems. Added channelLocalDebug.
This commit is contained in:
@ -38,7 +38,7 @@
|
||||
<h1>pvDatabaseCPP</h1>
|
||||
<!-- Maturity: Working Draft or Request for Comments, or Recommendation, and date. -->
|
||||
|
||||
<h2 class="nocount">EPICS v4 Working Group, Working Draft, 16-May-2013</h2>
|
||||
<h2 class="nocount">EPICS v4 Working Group, Working Draft, 23-May-2013</h2>
|
||||
<dl>
|
||||
<dt>Latest version:</dt>
|
||||
<dd><a
|
||||
@ -46,11 +46,11 @@
|
||||
</dd>
|
||||
<dt>This version:</dt>
|
||||
<dd><a
|
||||
href="http://epics-pvdata.hg.sourceforge.net/hgweb/epics-pvdata/pvDatabaseCPP/raw-file/tip/documentation/pvDatabaseCPP_20130516.html">pvDatabaseCPP20130516.html</a>
|
||||
href="http://epics-pvdata.hg.sourceforge.net/hgweb/epics-pvdata/pvDatabaseCPP/raw-file/tip/documentation/pvDatabaseCPP_20130523.html">pvDatabaseCPP20130523.html</a>
|
||||
</dd>
|
||||
<dt>Previous version:</dt>
|
||||
<dd><a
|
||||
href="http://epics-pvdata.hg.sourceforge.net/hgweb/epics-pvdata/pvDatabaseCPP/raw-file/tip/documentation/pvDatabaseCPP_20130417.html">pvDatabaseCPP20130417.html</a>
|
||||
href="http://epics-pvdata.hg.sourceforge.net/hgweb/epics-pvdata/pvDatabaseCPP/raw-file/tip/documentation/pvDatabaseCPP_20130516.html">pvDatabaseCPP20130516.html</a>
|
||||
</dd>
|
||||
<dt>Editors:</dt>
|
||||
<dd>Marty Kraimer, BNL</dd>
|
||||
@ -74,24 +74,29 @@ The minimum that an extenson must provide is a top level PVStructure and a proce
|
||||
|
||||
<h2 class="nocount">Status of this Document</h2>
|
||||
|
||||
<p>This is the 16-May-2013 version of the definition of pvDatabaseCPP.
|
||||
<p>This is the 23-May-2013 version of the definition of pvDatabaseCPP.
|
||||
</p>
|
||||
<p>The following Channel methods are implemented and working: getField,
|
||||
channelProcess, channelGet, channelPut, channelPutGet, and Monitor.
|
||||
But lots of work remains:</p>
|
||||
<dl>
|
||||
<dt>Other Channel Methods</dt>
|
||||
<dd>ChannelArray is next.</dd>
|
||||
<dd>Only ChannelArray remains.
|
||||
Note that pvIOCJava does not implement the pvRequest for channelArray
|
||||
correctly. It uses a private convention rather than using the output
|
||||
of CreateRequest. This will be fixed before pvDatabaseCPP implements ChannelArray.
|
||||
</dd>
|
||||
<dt>Monitor Algorithms</dt>
|
||||
<dd>Monitor algorithms have no been implemented.
|
||||
<dd>Monitor algorithms have not been implemented.
|
||||
Thus all monitors are onPut.</dd>
|
||||
<dt>Lifecycle problems</dt>
|
||||
<dd>Problems when channel clients disconnect.
|
||||
May need help from Matej</dd>
|
||||
<dt>Memory leaks at exit</dt>
|
||||
<dd>May need help from Matej.</dd>
|
||||
I am asking for help from Matej</dd>
|
||||
<dt>Memory leak at exit</dt>
|
||||
<dd>I am asking for help from Matej</dd>
|
||||
<dt>Scalar Arrays</dt>
|
||||
<dd>Have not been tested. Share has not been implemented.</dd>
|
||||
<dd>Share has not been implemented.
|
||||
This will wait until Michael has new implementation of ScalarArray.</dd>
|
||||
<dt>Structure Arrays</dt>
|
||||
<dd>Has not been implemented</dd>
|
||||
<dt>Testing</dt>
|
||||
@ -116,7 +121,7 @@ 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.</p>
|
||||
|
||||
<p>This document describes components that provides the following features:
|
||||
<p>This document describes components that provide the following features:
|
||||
<dl>
|
||||
<dt>database<dt>
|
||||
<dd>This encapsulates the concept of a database of memory resident smart records.
|
||||
@ -188,8 +193,9 @@ mrk> bin/linux-x86_64/exampleCounter
|
||||
<h4>ExampleCounter.h</h4>
|
||||
<p>The example resides in src/database.
|
||||
The complete implementation is in the header file.
|
||||
A serious implementation would probably break the code into two files:
|
||||
1) a header, and 2) the implementation. The description consists of</p>
|
||||
A serious implementation might break the code into a header and an
|
||||
implementation file.<p>
|
||||
</p>The description consists of</p>
|
||||
<pre>
|
||||
class ExampleCounter;
|
||||
typedef std::tr1::shared_ptr<ExampleCounter> ExampleCounterPtr;
|
||||
@ -455,6 +461,18 @@ The following are the minimium features required</p>
|
||||
Thus code will be generated only if other code includes the
|
||||
header file and creates a record instance.
|
||||
</dd>
|
||||
<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 testExampleServer creates an instance via the following code:
|
||||
<pre>
|
||||
recordName = "laptoprecordListPGRPC";
|
||||
pvRecord = RecordListRecord::create(recordName);
|
||||
result = master->addRecord(pvRecord);
|
||||
</pre>
|
||||
</dd>
|
||||
|
||||
</dl>
|
||||
<p>The classes in pvDatabase.h describe a database of memory resident
|
||||
smart records.
|
||||
@ -856,16 +874,123 @@ private:
|
||||
<dd>Virtual message of Requester.</dd>
|
||||
</dl>
|
||||
<h2>pvAccess</h2>
|
||||
<p>Not yet described.
|
||||
It is only of interest to someone who wants to understand how it works.
|
||||
</p>
|
||||
<p>A brief description is that it implements the following components of pvIOCJava:</p>
|
||||
<p>This is code that provides an implementation of channelProvider as
|
||||
defined by pvAccess.
|
||||
It provides access to PVRecords and is access by the server side of remote pvAccess.</p>
|
||||
<h3>channelProviderLocal</h3>
|
||||
<p>This is a complete implementation of channelProvider and ,
|
||||
except for channelRPC, provides a complete implementation of Channel
|
||||
as defined by pvAccess.
|
||||
For monitors it calls the code described in the following sections.</p>
|
||||
<h3>ChannelLocalDebug</h3>
|
||||
<p>The channelProvider implementation provides the ability to generate
|
||||
debug messages based a debug level with the following meaning:</p>
|
||||
<dl>
|
||||
<dt>pvCopy</dt>
|
||||
<dt>monitor</dt>
|
||||
<dt>local ChannelProvider and Channel</dt>
|
||||
<dt><=0</dt>
|
||||
<dd>No debug messages </dd>
|
||||
<dt>>0</dt>
|
||||
<dd>Generate a message when anything is created or destroyed</dd>
|
||||
<dt>>1</dt>
|
||||
<dd>Also generate processing messages.</dd>
|
||||
</dl>
|
||||
<p>ChannelProviderLocal has a method:</p>
|
||||
<pre>
|
||||
void createChannelLocalDebugRecord(
|
||||
String const & recordName);
|
||||
</pre>
|
||||
<p>This method creates a PVRecord that allows a pvAccess client to set the
|
||||
debug level.</p>
|
||||
<h3>pvCopy</h3>
|
||||
<p>This provides code that creates a top level PVStructure that is an arbitrary
|
||||
subset of the fields in the PVStructure from a PVRecord.
|
||||
In addition it provides code that monitors changes to the fields in a PVRecord.
|
||||
A client configures the desired set of subfields and monitoring options
|
||||
via a pvRequest structure.
|
||||
pvAccess provides a class CreatePVRequest that creates a pvRequest.
|
||||
The pvCopy code provides the same functionality as the pvCopy code in pvIOCJava.
|
||||
</p>
|
||||
<h3>monitorAlgorithm</h3>
|
||||
<p>Currently all that is implemented is a header file.
|
||||
The only algorithm currently implemented is <b>onPut</b>
|
||||
</p>
|
||||
<h3>monitorFactory</h3>
|
||||
<h4>Overview</h4>
|
||||
<p><b>epics::pvData::monitor</b> defines the monitor interfaces
|
||||
as seen by a client.
|
||||
See
|
||||
<a href="http://epics-pvdata.hg.sourceforge.net/hgweb/epics-pvdata/pvDatabaseCPP/raw-file/tip/documentation/pvDatabaseCPP.html">pvDatabaseCPP.html</a>
|
||||
For details.</p>
|
||||
<p>
|
||||
monitorFactory implements the
|
||||
monitoring interfaces for a PVRecord.
|
||||
It implements queueSize=0 and queueSize>=2.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The implementation uses PVCopy and PVCopyMonitor which are implemented in pvCopy.
|
||||
When PVCopyMonitor tells monitor that changes
|
||||
have occurred, monitor applies the appropriate algorithm to each changed field.</p>
|
||||
|
||||
<p>Currently only algorithm <b>onPut</b> is implemented but,
|
||||
like pvIOCJava there are plans to support for the following monitor algorithms:</p>
|
||||
<dl>
|
||||
<dt>onPut</dt>
|
||||
<dd>A monitor is issued whenever a put is issued to the field. This is the
|
||||
default unless the record defines deadbands for a field. An exception is
|
||||
the top level timeStamp which by default is made onChange and monitor
|
||||
will not be raised.</dd>
|
||||
<dt>onChange</dt>
|
||||
<dd>This provides two options: 1) A monitor is raised whenever a field
|
||||
changes value, and 2) A monitor will never be raised for the field.</dd>
|
||||
<dt>deadband</dt>
|
||||
<dd>The field must be a numeric scalar. Whenever the absolute or percentage
|
||||
value of the field changes by more than a deadband a monitor is issued.
|
||||
The record instance can also define deadbands.</dd>
|
||||
<dt>periodic</dt>
|
||||
<dd>A monitor is issued at a periodic rate if a put was issued to any field
|
||||
being monitored.</dd>
|
||||
</dl>
|
||||
<h4>MonitorFactory</h4>
|
||||
<p>MonitorFactory provides the following methods:</p>
|
||||
<pre>class MonitorFactory
|
||||
{
|
||||
static MonitorPtr create(
|
||||
PVRecordPtr const & pvRecord,
|
||||
MonitorRequester::shared_pointer const & monitorRequester,
|
||||
PVStructurePtr const & pvRequest);
|
||||
static void registerMonitorAlgorithmCreater(
|
||||
MonitorAlgorithmCreatePtr const & monitorAlgorithmCreate,
|
||||
String const & algorithmName);
|
||||
}</pre>
|
||||
|
||||
<p>where</p>
|
||||
<dl>
|
||||
<dt>create</dt>
|
||||
<dd>Create a monitor. The arguments are:
|
||||
<dl>
|
||||
<dt>pvRecord</dt>
|
||||
<dd>The record being monitored.</dd>
|
||||
<dt>monitorRequester</dt>
|
||||
<dd>The monitor requester. This is the code to which monitot events
|
||||
will be delivered.</dd>
|
||||
<dt>pvRequest</dt>
|
||||
<dd>The request options</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dt>registerMonitorAlgorithmCreater</dt>
|
||||
<dd>Called by code that implements a monitor algorithm.</dd>
|
||||
</dl>
|
||||
<h3>channelLocalDebugRecord</h3>
|
||||
<p>This implements a PVRecord that allows a client to set
|
||||
a debug level for the local channel provider implementation.
|
||||
The top level structure has a single integer field named value.
|
||||
See ChannelProviderLocal for the meaning associated with value.</p>
|
||||
<p>ChannelProviderLocal has a method:</p>
|
||||
<pre>
|
||||
void createChannelLocalDebugRecord(String const & recordName);
|
||||
</pre>
|
||||
<p>This creates an instance of a ChannelLocalDebugRecord and installs it
|
||||
into the PVDatabase.</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
996
documentation/pvDatabaseCPP_20130523.html
Normal file
996
documentation/pvDatabaseCPP_20130523.html
Normal file
@ -0,0 +1,996 @@
|
||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
|
||||
<title>pvDatabaseCPP</title>
|
||||
<link rel="stylesheet" type="text/css"
|
||||
href="http://epics-pvdata.sourceforge.net/base.css" />
|
||||
<link rel="stylesheet" type="text/css"
|
||||
href="http://epics-pvdata.sourceforge.net/epicsv4.css" />
|
||||
<style type="text/css">
|
||||
/*<![CDATA[*/
|
||||
.about { margin-left: 3em; margin-right: 3em; font-size: .83em}
|
||||
table { margin-left: auto; margin-right: auto }
|
||||
.diagram { text-align: center; margin: 2.5em 0 }
|
||||
span.opt { color: grey }
|
||||
span.nterm { font-style:italic }
|
||||
span.term { font-family:courier }
|
||||
span.user { font-family:courier }
|
||||
span.user:before { content:"<" }
|
||||
span.user:after { content:">" }
|
||||
.nonnorm { font-style:italic }
|
||||
p.ed { color: #AA0000 }
|
||||
span.ed { color: #AA0000 }
|
||||
p.ed.priv { display: inline; }
|
||||
span.ed.priv { display: inline; }
|
||||
/*]]>*/</style>
|
||||
<!-- Script that generates the Table of Contents -->
|
||||
<script type="text/javascript"
|
||||
src="http://epics-pvdata.sourceforge.net/script/tocgen.js">
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div class="head">
|
||||
<h1>pvDatabaseCPP</h1>
|
||||
<!-- Maturity: Working Draft or Request for Comments, or Recommendation, and date. -->
|
||||
|
||||
<h2 class="nocount">EPICS v4 Working Group, Working Draft, 23-May-2013</h2>
|
||||
<dl>
|
||||
<dt>Latest version:</dt>
|
||||
<dd><a
|
||||
href="http://epics-pvdata.hg.sourceforge.net/hgweb/epics-pvdata/pvDatabaseCPP/raw-file/tip/documentation/pvDatabaseCPP.html">pvDatabaseCPP.html</a>
|
||||
</dd>
|
||||
<dt>This version:</dt>
|
||||
<dd><a
|
||||
href="http://epics-pvdata.hg.sourceforge.net/hgweb/epics-pvdata/pvDatabaseCPP/raw-file/tip/documentation/pvDatabaseCPP_20130523.html">pvDatabaseCPP20130523.html</a>
|
||||
</dd>
|
||||
<dt>Previous version:</dt>
|
||||
<dd><a
|
||||
href="http://epics-pvdata.hg.sourceforge.net/hgweb/epics-pvdata/pvDatabaseCPP/raw-file/tip/documentation/pvDatabaseCPP_20130516.html">pvDatabaseCPP20130516.html</a>
|
||||
</dd>
|
||||
<dt>Editors:</dt>
|
||||
<dd>Marty Kraimer, BNL</dd>
|
||||
</dl>
|
||||
|
||||
<p class="copyright">This product is made available subject to acceptance of the <a
|
||||
href="http://epics-pvdata.sourceforge.net/LICENSE.html">EPICS open source license.</a></p>
|
||||
<hr />
|
||||
</div>
|
||||
|
||||
<h2 class="nocount">Abstract</h2>
|
||||
|
||||
<p>This document describes pvDatabaseCPP,
|
||||
which is a framework for implementing a network accessable database of smart memory resident
|
||||
records. Network access is via pvAccess. The data in each record is a top level PVStructure as defined by
|
||||
pvData. The framework includes a complete implementation of ChannelProvider as defined by pvAccess.
|
||||
The framework can be extended in order to create record instances that implements services.
|
||||
The minimum that an extenson must provide is a top level PVStructure and a process method.
|
||||
</p>
|
||||
|
||||
|
||||
<h2 class="nocount">Status of this Document</h2>
|
||||
|
||||
<p>This is the 23-May-2013 version of the definition of pvDatabaseCPP.
|
||||
</p>
|
||||
<p>The following Channel methods are implemented and working: getField,
|
||||
channelProcess, channelGet, channelPut, channelPutGet, and Monitor.
|
||||
But lots of work remains:</p>
|
||||
<dl>
|
||||
<dt>Other Channel Methods</dt>
|
||||
<dd>Only ChannelArray remains.
|
||||
Note that pvIOCJava does not implement the pvRequest for channelArray
|
||||
correctly. It uses a private convention rather than using the output
|
||||
of CreateRequest. This will be fixed before pvDatabaseCPP implements ChannelArray.
|
||||
</dd>
|
||||
<dt>Monitor Algorithms</dt>
|
||||
<dd>Monitor algorithms have not been implemented.
|
||||
Thus all monitors are onPut.</dd>
|
||||
<dt>Lifecycle problems</dt>
|
||||
<dd>Problems when channel clients disconnect.
|
||||
I am asking for help from Matej</dd>
|
||||
<dt>Memory leak at exit</dt>
|
||||
<dd>I am asking for help from Matej</dd>
|
||||
<dt>Scalar Arrays</dt>
|
||||
<dd>Share has not been implemented.
|
||||
This will wait until Michael has new implementation of ScalarArray.</dd>
|
||||
<dt>Structure Arrays</dt>
|
||||
<dd>Has not been implemented</dd>
|
||||
<dt>Testing</dt>
|
||||
<dd>Needs lots more testing</dd>
|
||||
</dl>
|
||||
|
||||
<div id="toc">
|
||||
<h2 class="nocount" style="page-break-before: always">Table of Contents</h2>
|
||||
</div>
|
||||
<div id="contents" class="contents">
|
||||
|
||||
|
||||
<h2>Introduction</h2>
|
||||
<h3>Overview</h3>
|
||||
<p>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.</p>
|
||||
|
||||
<p>This document describes components that provide the following features:
|
||||
<dl>
|
||||
<dt>database<dt>
|
||||
<dd>This encapsulates the concept of a database of memory resident smart records.
|
||||
The two main components are:
|
||||
<dl>
|
||||
<dt>pvRecord</dt>
|
||||
<dd>This encapsulates the concept of a smart record. It can be processed.
|
||||
Changes to field values can be trapped. A record can be locked.</dd>
|
||||
<dt>pvDatabase<dt>
|
||||
<dd>This is a database of pvRecords.
|
||||
Records can be added and removed from a database.</dd>
|
||||
</dl>
|
||||
<dt>pvAccess</dt>
|
||||
<dd>This is a complete implementation of ChannelProvider and Channel
|
||||
as defined by pvAccess.
|
||||
It is used by the server side of pvAccess to attach to pvRecords.
|
||||
This component also includes the monitor and pvCopy components from pvIOCJava</dd>
|
||||
</dl>
|
||||
<p>database provides base classes that make it easy to create record instances.
|
||||
The code attached to each record must create the top
|
||||
level PVStructure and the following two methods:</p>
|
||||
<dl>
|
||||
<dt>init</dt>
|
||||
<dd>This is a method for initializing the support.
|
||||
It returns true if successful and false otherwise.
|
||||
</dd>
|
||||
<dt>process</dt>
|
||||
<dd>This is what makes a record smart.
|
||||
</dd>
|
||||
</dl>
|
||||
<h3>Relationship with pvIOCJava.</h3>
|
||||
<p>This document descibes a C++ implementation of some of the components in pvIOCJava,
|
||||
which also implements a pvDatabase.
|
||||
PVDatabaseCPP extracts the core components required to create a network accessible database of smart
|
||||
memory resident records.
|
||||
pvDatabaseCPP does not implement any of the specialized support that pvIOCJava
|
||||
provides.
|
||||
It is expected that many services will be created that do not require the full features provided
|
||||
by pvIOCJava. In the future pvIOCJava should be split into multiple projects with one of
|
||||
them named pvDatabaseJava.</p>
|
||||
<p>Similar to epics base, pvIOCJava implements the concept of synchronous and asynchronous record processing.
|
||||
For pvDatabaseCPP the process method is allowed to block.
|
||||
Until a need is demonstrated this will remain true.
|
||||
The main user of a pvDatabase is pvAccess, and in particular, remote pvAccess.
|
||||
The server side of remote pvAccess creates two threads for each client and always accesses
|
||||
a record via these threads.
|
||||
It is expected that these threads will be sufficient to efficently handle all channel methods except
|
||||
channelRPC. For channelRPC pvAccess provides (or will provide) a thread pool for channelRPC requests.
|
||||
If, in the future, a scanning facility is provided by pvDatabaseCPP or some other facility,
|
||||
then the scanning facility will have to provide some way of handling process requests that block.</p>
|
||||
</p>
|
||||
<h3>Example PVRecord Extension</h3>
|
||||
<p>The example implements a simple counter.
|
||||
The example can be run on linux as follows:</p>
|
||||
<pre>
|
||||
mrk> pwd
|
||||
/home/hg/pvDatabaseCPP
|
||||
mrk> bin/linux-x86_64/exampleCounter
|
||||
|
||||
</pre>
|
||||
<p>The example consists of two components:</p>
|
||||
<dl>
|
||||
<dt>ExampleCounter.h</dt>
|
||||
<dd>The source code for the counter.</dd>
|
||||
<dt>exampleCounterMain.cpp</dt>
|
||||
<dd>A main program that runs the example so that it can be accessed
|
||||
by a pvAccess client.</dd>
|
||||
</dl>
|
||||
<h4>ExampleCounter.h</h4>
|
||||
<p>The example resides in src/database.
|
||||
The complete implementation is in the header file.
|
||||
A serious implementation might break the code into a header and an
|
||||
implementation file.<p>
|
||||
</p>The description consists of</p>
|
||||
<pre>
|
||||
class ExampleCounter;
|
||||
typedef std::tr1::shared_ptr<ExampleCounter> ExampleCounterPtr;
|
||||
|
||||
class ExampleCounter :
|
||||
public PVRecord
|
||||
{
|
||||
public:
|
||||
POINTER_DEFINITIONS(ExampleCounter);
|
||||
static ExampleCounterPtr create(
|
||||
epics::pvData::String const & recordName);
|
||||
virtual ~ExampleCounter();
|
||||
virtual void destroy();
|
||||
virtual bool init();
|
||||
virtual void process();
|
||||
private:
|
||||
ExampleCounter(epics::pvData::String const & recordName,
|
||||
epics::pvData::PVStructurePtr const & pvStructure);
|
||||
epics::pvData::PVLongPtr pvValue;
|
||||
epics::pvData::PVTimeStamp pvTimeStamp;
|
||||
epics::pvData::TimeStamp timeStamp;
|
||||
};
|
||||
</pre>
|
||||
<p>where</p>
|
||||
<dl>
|
||||
<dt>create<dt>
|
||||
<dd>This is example specific but each support could provide
|
||||
a similar static method.
|
||||
</dd>
|
||||
<dt>~ExampleCounter<dt>
|
||||
<dd>The destructor must be declared virtual.</dd>
|
||||
<dt><destroy</dt>
|
||||
<dd>Called when the record is being destroyed.
|
||||
This must call the base class destroy method.
|
||||
<dt>init<dt>
|
||||
<dd>A method to initialize the support. It returns true
|
||||
if initialization is successful and false if not.
|
||||
NOTE that this is a virtual method of PVRecord itself.</dd>
|
||||
<dt>process<dt>
|
||||
<dd>
|
||||
This again is a virtual method of PVRecord.
|
||||
</dd>
|
||||
<dt>ExampleCounter<dt>
|
||||
<dd>For the example this is private.</dd>
|
||||
<dt>pvValue</dt>
|
||||
<dd>This is the field of the top level structure that process
|
||||
accesses.
|
||||
</dd>
|
||||
<dl>
|
||||
<p>The implementation of create method is:</p>
|
||||
<pre>
|
||||
ExampleCounterPtr ExampleCounter::create(
|
||||
epics::pvData::String const & recordName)
|
||||
{
|
||||
epics::pvData::PVStructurePtr pvStructure =
|
||||
epics::pvData::getStandardPVField()->scalar(
|
||||
epics::pvData::pvDouble,"timeStamp,alarm"");
|
||||
ExampleCounterPtr pvRecord(
|
||||
new ExampleCounter(recordName,pvStructure));
|
||||
if(!pvRecord->init()) pvRecord.reset();
|
||||
return pvRecord;
|
||||
}
|
||||
</pre>
|
||||
This:
|
||||
<ul>
|
||||
<li>Creates the top level structure.</li>
|
||||
<li>Creates a ExampleCounterPtr via the constructor.</li>
|
||||
<li>Calls init and if it fails resets the shared pointer.</li>
|
||||
<li>Returns the shared pointer to the newly created record.</li>
|
||||
</ul>
|
||||
<p>The private constructor method is:</p>
|
||||
<pre>
|
||||
ExampleCounter::ExampleCounter(
|
||||
epics::pvData::String const & recordName,
|
||||
epics::pvData::PVStructurePtr const & pvStructure)
|
||||
: PVRecord(recordName,pvStructure)
|
||||
{
|
||||
pvTimeStamp.attach(pvStructure->getSubField("timeStamp"));
|
||||
}
|
||||
</pre>
|
||||
The example is very simple. It just calls the base class constructor.
|
||||
<p>The destructor and destroy methods are:</p>
|
||||
<pre>
|
||||
ExampleCounter::~ExampleCounter()
|
||||
{
|
||||
destroy();
|
||||
}
|
||||
|
||||
void ExampleCounter::destroy()
|
||||
{
|
||||
PVRecord::destroy();
|
||||
}
|
||||
</pre>
|
||||
The destructor just calls destroy.
|
||||
The destroy method, which is virtual, just calls the destroy method of the base class.
|
||||
A more complicated example can clean up any resources it used but must call the base
|
||||
class destroy method.
|
||||
<p>The implementation of init is:</p>
|
||||
<pre>
|
||||
bool ExampleCounter::init()
|
||||
{
|
||||
|
||||
initPVRecord();
|
||||
epics::pvData::PVFieldPtr pvField;
|
||||
pvValue = getPVStructure()->getLongField("value");
|
||||
if(pvValue.get()==NULL) return false;
|
||||
return true;
|
||||
}
|
||||
</pre>
|
||||
This:
|
||||
<ul>
|
||||
<li>Calls initRecord which is implemented by the base class.
|
||||
It MUST be called.</li>
|
||||
<li>Calls getLongField to get the interface to the value field,
|
||||
which must be a scalar with type long.</li>
|
||||
<li>If a long value field was not found it returns false.</li>
|
||||
<li>Returns true</li>
|
||||
</ul>
|
||||
<p>The implementation of process is:</p>
|
||||
<pre>
|
||||
void ExampleCounter::process()
|
||||
{
|
||||
pvValue->put(pvValue->get() + 1.0);
|
||||
timeStamp.getCurrent();
|
||||
pvTimeStamp.set(timeStamp);
|
||||
}
|
||||
</pre>
|
||||
It adds 1.0 to the current value.
|
||||
It then sets the timeStamp to the current time.
|
||||
<h4>exampleCounterMain.cpp</h4>
|
||||
<p>This is in test/server.
|
||||
The main program is:</p>
|
||||
<pre>
|
||||
int main(int argc,char *argv[])
|
||||
{
|
||||
PVDatabasePtr master = PVDatabase::getMaster();
|
||||
ChannelProviderLocalPtr channelProvider = ChannelProviderLocal::create();
|
||||
String recordName("exampleCounter");
|
||||
PVRecordPtr pvRecord = ExampleCounter::create(recordName);
|
||||
bool result = master->addRecord(pvRecord);
|
||||
cout << "result of addRecord " << recordName << " " << result << endl;
|
||||
pvRecord.reset();
|
||||
cout << "exampleServer\n";
|
||||
string str;
|
||||
while(true) {
|
||||
cout << "Type exit to stop: \n";
|
||||
getline(cin,str);
|
||||
if(str.compare("exit")==0) break;
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
</pre>
|
||||
This:
|
||||
<ul>
|
||||
<li>Gets a pointer to the master database.</li>
|
||||
<li>Creates the local Channel Provider. This starts the pvAccess server.</li>
|
||||
<li>Creates a ExampleCounter record with the name exampleCounter
|
||||
</li>
|
||||
<li>Prints exampleCounter on standard out.</li>
|
||||
<li>Runs forever until the user types exit on standard in.</li>
|
||||
</ul>
|
||||
<h3>Phased Development</h3>
|
||||
<p>This documentation describes the first phase of a phased implementation of pvDatabaseCPP:</pp>
|
||||
<dl>
|
||||
<dt>pvRecord</d>
|
||||
<dd>Wrapper on PVStructure that implements methods required by Local Channel Provider.</dd>
|
||||
<dt>pvDatabase</d>
|
||||
<dd>Database of PVRecords. Has methods find, add, and remove.</dd>
|
||||
<dt>Local Channel Provider</dt>
|
||||
<dd>Complete implementation of ChannelProvider and Channel.
|
||||
This means that pvCopy and monitor are also implemented.</dd>
|
||||
</dl>
|
||||
<p>Future phases of pvDatabaseCPP might include:</p>
|
||||
<dl>
|
||||
<dt>Install</dt>
|
||||
<dd>This provides complete support for on-line add and delete
|
||||
of sets of records.
|
||||
With the first phase each "service" is responsible for it's own implementation.
|
||||
All that is provided is addRecord and removeRecord.
|
||||
</dd>
|
||||
<dt>Field support</dt>
|
||||
<dd>Add the ability to optionally add support to fields.
|
||||
In addition some of the basic support defined in pvIOCJava could also be implemented.</dd>
|
||||
<dt>XML parser</dt>
|
||||
<dd>This provides the ability to create record instances without writing any code.</dd>
|
||||
</dl>
|
||||
<p>The completion of each phase provides useful features that can be used without waiting for the
|
||||
completion of later phases.
|
||||
The rest of this document discusses only the first phase.</p>
|
||||
<h3>Features Required for localChannelProvider</h3>
|
||||
<dl>
|
||||
<dt>pvCopy</dt>
|
||||
<dd>Creates a PVStructure that contains a copy of an arbitary
|
||||
subset of the fields of another top level PVStructure.
|
||||
It can copy data between the two and maintains a bitSet that show
|
||||
which fields are changed.<dd>
|
||||
<dt>monitor</dt>
|
||||
<dd>This provides the ability to monitor changes to fields of a record.</dd>
|
||||
<dt>PVRecord and PVDatabase</dt>
|
||||
<dd>Defined below.</dd>
|
||||
<dt>The localChannelProvider itself</dt>
|
||||
<dd>This is the pvAccess package in pvIOCJava.
|
||||
The localChannelProvider will access data from PVRecords.
|
||||
It will implement all channel methods.</dd>
|
||||
</dl>
|
||||
<h3>Minumum Features Required for pvRecord</h3>
|
||||
<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 starting to implement services.
|
||||
The following are the minimium features required</p>
|
||||
<dl>
|
||||
<dt>PVDatabase</dt>
|
||||
<dd>This holds a set of PVRecords. It has methods to find, add, and remove records.</dd>
|
||||
<dt>PVRecord</dt>
|
||||
<dd>This, and a set of related interfaces, provides the following:
|
||||
<dl>
|
||||
<dt>Access to top level PVStructure</dt>
|
||||
<dd>PVRecord is a wrapper on a top level pvStructure.</dd>
|
||||
<dt>Record locking</dt>
|
||||
<dd>A record can be locked and unlocked.
|
||||
A record must be locked whenever data in the pvStructure is accessed.</dd>
|
||||
<dt>Trapping data changes</dt>
|
||||
<dd>A client can request to be notified when data in the pvStructure is modified.
|
||||
It can do this on a field by field basis.</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
<p>The following sections describes the classes required for the first phase.</p>
|
||||
|
||||
<h2>database</h2>
|
||||
<p>This directory has the following files:</p>
|
||||
<dl>
|
||||
<dt>pvDatabase.h</dt>
|
||||
<dd>
|
||||
This is what is described in this section.
|
||||
</dd>
|
||||
<dt>pvDatabase.cpp</dt>
|
||||
<dd>
|
||||
The implementation of PVDatabase.
|
||||
</dd>
|
||||
<dt>pvRecord.cpp</dt>
|
||||
<dd>
|
||||
The implementation of the base class for PVREcord.
|
||||
It can also implement record instances with a process
|
||||
method does nothing.
|
||||
This can be used to create a "dumb" record where all changes are
|
||||
done by clients.
|
||||
The complete implementation is provided in the header file.
|
||||
Thus code will be generated only if other code includes the
|
||||
header file and creates a record instance.
|
||||
</dd>
|
||||
<dt>exampleCounter.h</dt>
|
||||
<dd>
|
||||
This was described in the introduction.
|
||||
</dd>
|
||||
<dt>powerSupplyRecordTest.h</dt>
|
||||
<dd>
|
||||
This provides code that simulates a power supply.
|
||||
It computes the current from the voltage and power.
|
||||
It is used for testing.
|
||||
The complete implementation is provided in the header file.
|
||||
Thus code will be generated only if other code includes the
|
||||
header file and creates a record instance.
|
||||
</dd>
|
||||
<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 testExampleServer creates an instance via the following code:
|
||||
<pre>
|
||||
recordName = "laptoprecordListPGRPC";
|
||||
pvRecord = RecordListRecord::create(recordName);
|
||||
result = master->addRecord(pvRecord);
|
||||
</pre>
|
||||
</dd>
|
||||
|
||||
</dl>
|
||||
<p>The classes in pvDatabase.h describe a database of memory resident
|
||||
smart records.
|
||||
It describes the following classes:</p>
|
||||
<dl>
|
||||
<dt>PVRecord</dt>
|
||||
<dd>This provides the methods required by localChannelProvider to implement Channel.</dd>
|
||||
<dt>PVRecordField</dt>
|
||||
<dt>PVRecordStructure</dt>
|
||||
<dd>These wrap PVField and PVStructure so that pvCopy and monitor
|
||||
can be implemented.</dd>
|
||||
<dt>PVRecordClient</dt>
|
||||
<dd>This is called by anything that acceses PVRecord.</dd>
|
||||
<dt>PVListener</dt>
|
||||
<dd>This is implemented by anything that wants to trap calls to PVRecord::message.</dd>
|
||||
<dt>PVDatabase</dt>
|
||||
<dd>This is a database of PVRecords.</dd>
|
||||
</dl>
|
||||
<p>Each class is described in a separate subsection.</p>
|
||||
<h3>C++ namespace and typedefs</h3>
|
||||
<pre>
|
||||
namespace epics { namespace pvDatabase {
|
||||
|
||||
class PVRecord;
|
||||
typedef std::tr1::shared_ptr<PVRecord> PVRecordPtr;
|
||||
typedef std::map<epics::pvData::String,PVRecordPtr> PVRecordMap;
|
||||
|
||||
class PVRecordField;
|
||||
typedef std::tr1::shared_ptr<PVRecordField> PVRecordFieldPtr;
|
||||
typedef std::vector<PVRecordFieldPtr> PVRecordFieldPtrArray;
|
||||
typedef std::tr1::shared_ptr<PVRecordFieldPtrArray> PVRecordFieldPtrArrayPtr;
|
||||
|
||||
class PVRecordStructure;
|
||||
typedef std::tr1::shared_ptr<PVRecordStructure> PVRecordStructurePtr;
|
||||
|
||||
class PVRecordClient;
|
||||
typedef std::tr1::shared_ptr<PVRecordClient> PVRecordClientPtr;
|
||||
|
||||
class PVListener;
|
||||
typedef std::tr1::shared_ptr<PVListener> PVListenerPtr;
|
||||
|
||||
class RecordProcessRequester;
|
||||
typedef std::tr1::shared_ptr<RecordProcessRequester> RecordProcessRequesterPtr;
|
||||
|
||||
class RecordPutRequester;
|
||||
typedef std::tr1::shared_ptr<RecordPutRequester> RecordPutRequesterPtr;
|
||||
|
||||
class PVDatabase;
|
||||
typedef std::tr1::shared_ptr<PVDatabase> PVDatabasePtr;
|
||||
</pre>
|
||||
|
||||
<h3>class PVRecord</h3>
|
||||
<p>NOTES:
|
||||
<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.
|
||||
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.
|
||||
Most of the methods are used by the pvAccess code.
|
||||
Service implementers will mostly be interested in methods init and process.
|
||||
These are described first.
|
||||
</ul>
|
||||
<hr>PVRecord Methods</h4>
|
||||
<pre>
|
||||
class PVRecord
|
||||
public epics::pvData::Requester,
|
||||
public std::tr1::enable_shared_from_this<PVRecord>
|
||||
{
|
||||
public:
|
||||
POINTER_DEFINITIONS(PVRecord);
|
||||
|
||||
virtual bool init() {initPVRecord(); return true;}
|
||||
virtual void process() {}
|
||||
|
||||
static PVRecordPtr create(
|
||||
epics::pvData::String const & recordName,
|
||||
epics::pvData::PVStructurePtr const & pvStructure);
|
||||
virtual ~PVRecord();
|
||||
virtual void destroy();
|
||||
epics::pvData::String getRecordName();
|
||||
PVRecordStructurePtr getPVRecordStructure();
|
||||
PVRecordFieldPtr findPVRecordField(
|
||||
epics::pvData::PVFieldPtr const & pvField);
|
||||
bool addRequester(epics::pvData::RequesterPtr const & requester);
|
||||
bool removeRequester(epics::pvData::RequesterPtr const & requester);
|
||||
inline void lock_guard() { epics::pvData::Lock theLock(mutex); }
|
||||
void lock();
|
||||
void unlock();
|
||||
bool tryLock();
|
||||
void lockOtherRecord(PVRecordPtr const & otherRecord);
|
||||
bool addPVRecordClient(PVRecordClientPtr const & pvRecordClient);
|
||||
bool removePVRecordClient(PVRecordClientPtr const & pvRecordClient);
|
||||
void detachClients();
|
||||
bool addListener(PVListenerPtr const & pvListener);
|
||||
bool removeListener(PVListenerPtr const & pvListener);
|
||||
void beginGroupPut();
|
||||
void endGroupPut();
|
||||
epics::pvData::String getRequesterName() {return getRecordName();}
|
||||
virtual void message(
|
||||
epics::pvData::String const & message,
|
||||
epics::pvData::MessageType messageType);
|
||||
void message(
|
||||
PVRecordFieldPtr const & pvRecordField,
|
||||
epics::pvData::String const & message,
|
||||
epics::pvData::MessageType messageType);
|
||||
void toString(epics::pvData::StringBuilder buf);
|
||||
void toString(epics::pvData::StringBuilder buf,int indentLevel);
|
||||
protected:
|
||||
PVRecord(
|
||||
epics::pvData::String const & recordName,
|
||||
epics::pvData::PVStructurePtr const & pvStructure);
|
||||
void initPVRecord();
|
||||
epics::pvData::PVStructurePtr getPVStructure();
|
||||
PVRecordPtr getPtrSelf()
|
||||
{
|
||||
return shared_from_this();
|
||||
}
|
||||
private:
|
||||
...
|
||||
}
|
||||
</pre>
|
||||
<p>The methods are:</h3>
|
||||
<dl>
|
||||
<dt>init</dt>
|
||||
<dd>Virtual method.
|
||||
<p>Derived classes must implement this method.
|
||||
This method Must call initPVRecord.</p>
|
||||
</dd>
|
||||
<dt>process</dt>
|
||||
<dd>Virtual method.
|
||||
<p>Derived classes must implement this method.
|
||||
The base implementation does nothing.</p>
|
||||
</dd>
|
||||
<dt>create</dt>
|
||||
<dd>Static method to create dumb records, i.e. records with a process method
|
||||
that does nothing.</dd>
|
||||
<dt>~PVRecord</dt>
|
||||
<dd>The destructor which must be virtual. A derived class must also have
|
||||
a virtual destructor.</dd>
|
||||
<dt>destroy</dt>
|
||||
<dd>This is a virtual method.
|
||||
</dd>
|
||||
<dt>getRecordName</dt>
|
||||
<dd>Return the recordName.</dd>
|
||||
<dt>getPVRecordStructure</dt>
|
||||
<dd>Get the top level PVStructure.</dd>
|
||||
<dt>findPVRecordField</dt>
|
||||
<dd>Given a PVFieldPtr return the PVRecordFieldPtr for the field.</dd>
|
||||
<dt>addRequester</dt>
|
||||
<dd>Add a requester to receive messages.</dd>
|
||||
<dt>removeRequester</dt>
|
||||
<dd>Remove a message requester.</dd>
|
||||
<dt>lock_guard</dt>
|
||||
<dd>This is an inline method that locks the record. The record will automatically
|
||||
be unlocked when control leaves the block that has the call.
|
||||
<dt>lock</dt>
|
||||
<dt>unlock</dt>
|
||||
<dd>Lock and Unlock the record.
|
||||
Any code accessing the data in the record or calling other PVRecord methods
|
||||
must have the record locked.</dd>
|
||||
<dt>tryLock</dt>
|
||||
<dd>If true then just like lock.
|
||||
If falseclient can not access record.
|
||||
A client can try to simultaneously hold the lock for more than two records
|
||||
by calling this method. But must be willing to accept failure.
|
||||
</dd>
|
||||
<dt>lockOtherRecord</dt>
|
||||
<dd>A client that holds the lock for one record can lock one other record.
|
||||
A client must not call this if the client already has the lock for
|
||||
more then one record.
|
||||
</dd>
|
||||
<dt>addPVRecordClient</dt>
|
||||
<dd>Every client that accesses the record must call this so that the client can be notified when the record is deleted.</dd>
|
||||
<dt>removePVRecordClient</dt>
|
||||
<dd>Client is no longer accessing the record.</dd>
|
||||
<dt>detachClients</dt>
|
||||
<dd>Ask all clients to detach from the record</dd>
|
||||
<dt>addListener</dt>
|
||||
<dd>Add a PVListener. This must be called before calling pvRecordField.addListener.</dd>
|
||||
<dt>removeListener</dt>
|
||||
<dd>Removes a listener. The listener will also be removed from all fields to which it is attached.</dd>
|
||||
<dt>beginGroupPut</dt>
|
||||
<dd>Begin a group of puts.
|
||||
This results in all registered PVListeners being called</dd>
|
||||
<dt>endGroupPut</dt>
|
||||
<dd>End a group of puts.
|
||||
This results in all registered PVListeners being called.</dd>
|
||||
<dt>getRequesterName</dt>
|
||||
<dd>virtual method of Requester
|
||||
</dd>
|
||||
<dt>message</dt>
|
||||
<dd>Can be called by implementation code.
|
||||
The message will be sent to every requester.</dd>
|
||||
<dt>toString</dt>
|
||||
<dd>Just calls the top level PVStructure toString method.</dd>
|
||||
<dt>PVRecord</dt>
|
||||
<dd>The constructor. It requires a recordName and a top level PVStructure.</dd>
|
||||
<dt>initPVRecord</dt>
|
||||
<dd>This method must be called by derived class.</dd>
|
||||
<dt>getPVStructure</dt>
|
||||
<dd>Called by derived class.</dd>
|
||||
</dl>
|
||||
<h3>class PVRecordField</h3>
|
||||
<pre>
|
||||
class PVRecordField {
|
||||
public virtual epics::pvData::PostHandler,
|
||||
public std::tr1::enable_shared_from_this<PVRecordField>
|
||||
public:
|
||||
POINTER_DEFINITIONS(PVRecordField);
|
||||
PVRecordField(
|
||||
epics::pvData::PVFieldPtr const & pvField,
|
||||
PVRecordStructurePtr const &parent,
|
||||
PVRecordPtr const & pvRecord);
|
||||
virtual ~PVRecordField();
|
||||
virtual void destroy();
|
||||
PVRecordStructurePtr getParent();
|
||||
epics::pvData::PVFieldPtr getPVField();
|
||||
epics::pvData::String getFullFieldName();
|
||||
epics::pvData::String getFullName();
|
||||
PVRecordPtr getPVRecord();
|
||||
bool addListener(PVListenerPtr const & pvListener);
|
||||
virtual void removeListener(PVListenerPtr const & pvListener);
|
||||
virtual void postPut();
|
||||
virtual void message(
|
||||
epics::pvData::String const & message,
|
||||
epics::pvData::MessageType messageType);
|
||||
protected:
|
||||
PVRecordFieldPtr getPtrSelf()
|
||||
{
|
||||
return shared_from_this();
|
||||
}
|
||||
virtual void init();
|
||||
private:
|
||||
...
|
||||
};
|
||||
</pre>
|
||||
<p>When PVRecord is created it creates a PVRecordField for every field in the PVStructure
|
||||
that holds the data. It has the following methods:
|
||||
</p>
|
||||
|
||||
<dl>
|
||||
<dt>PVRecordField</dt>
|
||||
<dd>The constructor.</dd>
|
||||
<dt>~PVRecordField</dt>
|
||||
<dd>The destructor.</dd>
|
||||
<dt>destroy</dt>
|
||||
<dd>Called by PVRecordStructure when it's destroy method is called.</dd>
|
||||
<dt>getParent</dt>
|
||||
<dd>Get the parent PVRecordStructure for this field.</dd>
|
||||
<dt>getPVField</dt>
|
||||
<dd>Get the PVField associated with this PVRecordField.</dd>
|
||||
<dt>getFullFieldName</dt>
|
||||
<dd>This gets the full name of the field, i.e. field,field,..</dd>
|
||||
<dt>getFullName</dt>
|
||||
<dd>This gets recordName plus the full name of the field, i.e. recordName.field,field,..</dd>
|
||||
<dt>getPVRecord</dt>
|
||||
<dd>Returns the PVRecord to which this field belongs.</dd>
|
||||
<dt>addListener</dt>
|
||||
<dd>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.</dd>
|
||||
<dt>removeListener</dt>
|
||||
<dd>Remove a PVListener.</dd>
|
||||
<dt>postPut</dt>
|
||||
<dd>This is called by the code that implements the data interface.
|
||||
It is called whenever the put method is called.</dd>
|
||||
<dt>message</dt>
|
||||
<dd>Called by implementation code. It calls PVRecord::message after prepending the full
|
||||
fieldname.</dd>
|
||||
</dl>
|
||||
<h3>class PVRecordStructure</h3>
|
||||
<pre>
|
||||
class PVRecordStructure : public PVRecordField {
|
||||
public:
|
||||
POINTER_DEFINITIONS(PVRecordStructure);
|
||||
PVRecordStructure(
|
||||
epics::pvData::PVStructurePtr const & pvStructure,
|
||||
PVRecordFieldPtrArrayPtr const & pvRecordField);
|
||||
virtual ~PVRecordStructure();
|
||||
virtual void destroy();
|
||||
PVRecordFieldPtrArrayPtr getPVRecordFields();
|
||||
epics::pvData::PVStructurePtr getPVStructure();
|
||||
virtual void removeListener(PVListenerPtr const & pvListener);
|
||||
virtual void postPut();
|
||||
protected:
|
||||
virtual void init();
|
||||
private:
|
||||
...
|
||||
};
|
||||
</pre>
|
||||
<p>When PVRecord is created it creates a PVRecordStructure for every structure field in the PVStructure
|
||||
that holds the data. It has the following methods:
|
||||
</p>
|
||||
<dl>
|
||||
<dt>PVRecordStructure</dt>
|
||||
<dd>The constructor.</dd>
|
||||
<dt>~PVRecordStructure</dt>
|
||||
<dd>The destructor.</dd>
|
||||
<dt>getPVRecordFields</dt>
|
||||
<dd>Get the PVRecordField array for the subfields</dd>
|
||||
<dt>getPVStructure</dt>
|
||||
<dd>Get the PVStructure for this field.</dd>
|
||||
<dt>removeListener</dt>
|
||||
<dd>Remove a PVListener.</dd>
|
||||
<dt>postPut</dt>
|
||||
<dd>This is called by the code that implements the data interface.
|
||||
It is called whenever the put method is called.</dd>
|
||||
<h3>class PVRecordClient</h3>
|
||||
<pre>
|
||||
class PVRecordClient {
|
||||
POINTER_DEFINITIONS(PVRecordClient);
|
||||
virtual ~PVRecordClient();
|
||||
virtual void detach(PVRecordPtr const & pvRecord);
|
||||
};
|
||||
</pre>
|
||||
<p>where</p>
|
||||
<dl>
|
||||
<dt>~PVRecordClient</dt>
|
||||
<dd>The destructor.</dd>
|
||||
<dt>detach</dt>
|
||||
<dd>The record is being removed from the master database,</dd>
|
||||
</dl>
|
||||
</dl>
|
||||
<h3>class PVListener</h3>
|
||||
<pre>
|
||||
class PVListener {
|
||||
virtual public PVRecordClient
|
||||
public:
|
||||
POINTER_DEFINITIONS(PVListener);
|
||||
virtual ~PVListener();
|
||||
virtual void dataPut(PVRecordFieldPtr const & pvRecordField) = 0;
|
||||
virtual void dataPut(
|
||||
PVRecordStructurePtr const &
|
||||
requested,PVRecordFieldPtr const & pvRecordField) = 0;
|
||||
virtual void beginGroupPut(PVRecordPtr const & pvRecord) = 0;
|
||||
virtual void endGroupPut(PVRecordPtr const & pvRecord) = 0;
|
||||
};
|
||||
</pre>
|
||||
<p>where</p>
|
||||
<dl>
|
||||
<dt>~PVListener</dt>
|
||||
<dd>The destructor.</dd>
|
||||
<dt>dataPut(PVRecordFieldPtr const & pvRecordField)</dt>
|
||||
<dd>pvField has been modified.
|
||||
This is called if the listener has called PVRecordField::addListener for pvRecordField.</dd>
|
||||
<dt>dataPut(
|
||||
PVRecordStructurePtr const &
|
||||
requested,PVRecordFieldPtr const & pvRecordField)</dt>
|
||||
<dd>pvField has been modified.
|
||||
Requested is the field to which the requester issued a pvField-&addListener.
|
||||
This is called if the listener has called PVRecordField-&addListener for requested.</dd>
|
||||
<dt>beginGroupPut</dt>
|
||||
<dd>A related set of changes is being started.</dd>
|
||||
<dt>endGroupPut</dt>
|
||||
<dd>A related set of changes is done.</dd>
|
||||
</dl>
|
||||
<h3>class PVDatabase</h3>
|
||||
<pre>
|
||||
class PVDatabase : virtual public epics::pvData::Requester {
|
||||
public:
|
||||
POINTER_DEFINITIONS(PVDatabase);
|
||||
static PVDatabasePtr getMaster();
|
||||
virtual ~PVDatabase();
|
||||
virtual void destroy();
|
||||
PVRecordPtr findRecord(epics::pvData::String const& recordName);
|
||||
bool addRecord(PVRecordPtr const & record);
|
||||
bool removeRecord(PVRecordPtr const & record);
|
||||
virtual epics::pvData::String getRequesterName();
|
||||
virtual void message(
|
||||
epics::pvData::String const &message,
|
||||
epics::pvData::MessageType messageType);
|
||||
private:
|
||||
PVDatabase();
|
||||
};
|
||||
</pre>
|
||||
<p>where</p>
|
||||
<dl>
|
||||
<dt>getMaster</dt>
|
||||
<dd>Get the master database. This is the database that localChannelProvider access.</dd>
|
||||
<dt>~PVDatabase</dt>
|
||||
<dd>The destructor.</dd>
|
||||
<dt>destroy</dt>
|
||||
<dd>This is called by remote channelAccess when process exits.
|
||||
This destroys and removes all records in the PVDatabase.</dd>
|
||||
<dt>findRecord</dt>
|
||||
<dd>Find a record. An empty pointer is returned if the record is not in the database.</dd>
|
||||
<dt>addRecord</dt>
|
||||
<dd>Add a record to the database.
|
||||
If the record already exists it is not modified and false is returned.</dd>
|
||||
<dt>removeRecord</dt>
|
||||
<dd>Remove a record from the database.
|
||||
If the record was not in the database false is returned.</dd>
|
||||
<dt>getRequesterName</dt>
|
||||
<dd>Virtual method of Requester</dd>
|
||||
<dt>message</dt>
|
||||
<dd>Virtual message of Requester.</dd>
|
||||
</dl>
|
||||
<h2>pvAccess</h2>
|
||||
<p>This is code that provides an implementation of channelProvider as
|
||||
defined by pvAccess.
|
||||
It provides access to PVRecords and is access by the server side of remote pvAccess.</p>
|
||||
<h3>channelProviderLocal</h3>
|
||||
<p>This is a complete implementation of channelProvider and ,
|
||||
except for channelRPC, provides a complete implementation of Channel
|
||||
as defined by pvAccess.
|
||||
For monitors it calls the code described in the following sections.</p>
|
||||
<h3>ChannelLocalDebug</h3>
|
||||
<p>The channelProvider implementation provides the ability to generate
|
||||
debug messages based a debug level with the following meaning:</p>
|
||||
<dl>
|
||||
<dt><=0</dt>
|
||||
<dd>No debug messages </dd>
|
||||
<dt>>0</dt>
|
||||
<dd>Generate a message when anything is created or destroyed</dd>
|
||||
<dt>>1</dt>
|
||||
<dd>Also generate processing messages.</dd>
|
||||
</dl>
|
||||
<p>ChannelProviderLocal has a method:</p>
|
||||
<pre>
|
||||
void createChannelLocalDebugRecord(
|
||||
String const & recordName);
|
||||
</pre>
|
||||
<p>This method creates a PVRecord that allows a pvAccess client to set the
|
||||
debug level.</p>
|
||||
<h3>pvCopy</h3>
|
||||
<p>This provides code that creates a top level PVStructure that is an arbitrary
|
||||
subset of the fields in the PVStructure from a PVRecord.
|
||||
In addition it provides code that monitors changes to the fields in a PVRecord.
|
||||
A client configures the desired set of subfields and monitoring options
|
||||
via a pvRequest structure.
|
||||
pvAccess provides a class CreatePVRequest that creates a pvRequest.
|
||||
The pvCopy code provides the same functionality as the pvCopy code in pvIOCJava.
|
||||
</p>
|
||||
<h3>monitorAlgorithm</h3>
|
||||
<p>Currently all that is implemented is a header file.
|
||||
The only algorithm currently implemented is <b>onPut</b>
|
||||
</p>
|
||||
<h3>monitorFactory</h3>
|
||||
<h4>Overview</h4>
|
||||
<p><b>epics::pvData::monitor</b> defines the monitor interfaces
|
||||
as seen by a client.
|
||||
See
|
||||
<a href="http://epics-pvdata.hg.sourceforge.net/hgweb/epics-pvdata/pvDatabaseCPP/raw-file/tip/documentation/pvDatabaseCPP.html">pvDatabaseCPP.html</a>
|
||||
For details.</p>
|
||||
<p>
|
||||
monitorFactory implements the
|
||||
monitoring interfaces for a PVRecord.
|
||||
It implements queueSize=0 and queueSize>=2.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The implementation uses PVCopy and PVCopyMonitor which are implemented in pvCopy.
|
||||
When PVCopyMonitor tells monitor that changes
|
||||
have occurred, monitor applies the appropriate algorithm to each changed field.</p>
|
||||
|
||||
<p>Currently only algorithm <b>onPut</b> is implemented but,
|
||||
like pvIOCJava there are plans to support for the following monitor algorithms:</p>
|
||||
<dl>
|
||||
<dt>onPut</dt>
|
||||
<dd>A monitor is issued whenever a put is issued to the field. This is the
|
||||
default unless the record defines deadbands for a field. An exception is
|
||||
the top level timeStamp which by default is made onChange and monitor
|
||||
will not be raised.</dd>
|
||||
<dt>onChange</dt>
|
||||
<dd>This provides two options: 1) A monitor is raised whenever a field
|
||||
changes value, and 2) A monitor will never be raised for the field.</dd>
|
||||
<dt>deadband</dt>
|
||||
<dd>The field must be a numeric scalar. Whenever the absolute or percentage
|
||||
value of the field changes by more than a deadband a monitor is issued.
|
||||
The record instance can also define deadbands.</dd>
|
||||
<dt>periodic</dt>
|
||||
<dd>A monitor is issued at a periodic rate if a put was issued to any field
|
||||
being monitored.</dd>
|
||||
</dl>
|
||||
<h4>MonitorFactory</h4>
|
||||
<p>MonitorFactory provides the following methods:</p>
|
||||
<pre>class MonitorFactory
|
||||
{
|
||||
static MonitorPtr create(
|
||||
PVRecordPtr const & pvRecord,
|
||||
MonitorRequester::shared_pointer const & monitorRequester,
|
||||
PVStructurePtr const & pvRequest);
|
||||
static void registerMonitorAlgorithmCreater(
|
||||
MonitorAlgorithmCreatePtr const & monitorAlgorithmCreate,
|
||||
String const & algorithmName);
|
||||
}</pre>
|
||||
|
||||
<p>where</p>
|
||||
<dl>
|
||||
<dt>create</dt>
|
||||
<dd>Create a monitor. The arguments are:
|
||||
<dl>
|
||||
<dt>pvRecord</dt>
|
||||
<dd>The record being monitored.</dd>
|
||||
<dt>monitorRequester</dt>
|
||||
<dd>The monitor requester. This is the code to which monitot events
|
||||
will be delivered.</dd>
|
||||
<dt>pvRequest</dt>
|
||||
<dd>The request options</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dt>registerMonitorAlgorithmCreater</dt>
|
||||
<dd>Called by code that implements a monitor algorithm.</dd>
|
||||
</dl>
|
||||
<h3>channelLocalDebugRecord</h3>
|
||||
<p>This implements a PVRecord that allows a client to set
|
||||
a debug level for the local channel provider implementation.
|
||||
The top level structure has a single integer field named value.
|
||||
See ChannelProviderLocal for the meaning associated with value.</p>
|
||||
<p>ChannelProviderLocal has a method:</p>
|
||||
<pre>
|
||||
void createChannelLocalDebugRecord(String const & recordName);
|
||||
</pre>
|
||||
<p>This creates an instance of a ChannelLocalDebugRecord and installs it
|
||||
into the PVDatabase.</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -20,10 +20,12 @@ SRC_DIRS += $(DATABASE)/pvAccess
|
||||
INC += channelProviderLocal.h
|
||||
INC += pvCopy.h
|
||||
INC += monitorAlgorithm.h
|
||||
INC += channelLocalDebugRecord.h
|
||||
LIBSRCS += channelProviderLocal.cpp
|
||||
LIBSRCS += channelLocal.cpp
|
||||
LIBSRCS += pvCopy.cpp
|
||||
LIBSRCS += monitorFactory.cpp
|
||||
LIBSRCS += channelLocalDebugRecord.cpp
|
||||
|
||||
|
||||
include $(TOP)/configure/RULES
|
||||
|
@ -39,12 +39,6 @@ typedef std::tr1::shared_ptr<ChannelRPCLocal> ChannelRPCLocalPtr;
|
||||
class ChannelArrayLocal;
|
||||
typedef std::tr1::shared_ptr<ChannelArrayLocal> ChannelArrayLocalPtr;
|
||||
|
||||
class ChannelLocalDebug {
|
||||
public:
|
||||
static void setLevel(int level);
|
||||
static int getLevel();
|
||||
};
|
||||
|
||||
static bool getProcess(PVStructurePtr pvRequest,bool processDefault)
|
||||
{
|
||||
PVFieldPtr pvField = pvRequest->getSubField("record._options.process");
|
||||
@ -69,12 +63,19 @@ class ChannelProcessLocal :
|
||||
{
|
||||
public:
|
||||
POINTER_DEFINITIONS(ChannelProcessLocal);
|
||||
virtual ~ChannelProcessLocal() {destroy();}
|
||||
virtual ~ChannelProcessLocal()
|
||||
{
|
||||
if(channelLocalDebug->getLevel()>0)
|
||||
{
|
||||
std::cout << "~ChannelProcessLocal() " << std::endl;
|
||||
}
|
||||
}
|
||||
static ChannelProcessLocalPtr create(
|
||||
ChannelLocalPtr const &channelLocal,
|
||||
ChannelProcessRequester::shared_pointer const & channelProcessRequester,
|
||||
PVStructurePtr const & pvRequest,
|
||||
PVRecordPtr const &pvRecord);
|
||||
PVRecordPtr const &pvRecord,
|
||||
ChannelLocalDebugPtr const &channelLocalDebug);
|
||||
virtual void process(bool lastRequest);
|
||||
virtual void destroy();
|
||||
virtual void lock() {thelock.lock();}
|
||||
@ -88,12 +89,14 @@ private:
|
||||
ChannelLocalPtr const &channelLocal,
|
||||
ChannelProcessRequester::shared_pointer const & channelProcessRequester,
|
||||
PVRecordPtr const &pvRecord,
|
||||
ChannelLocalDebugPtr const &channelLocalDebug,
|
||||
int nProcess)
|
||||
:
|
||||
isDestroyed(false),
|
||||
channelLocal(channelLocal),
|
||||
channelProcessRequester(channelProcessRequester),
|
||||
pvRecord(pvRecord),
|
||||
channelLocalDebug(channelLocalDebug),
|
||||
thelock(mutex),
|
||||
nProcess(nProcess)
|
||||
{
|
||||
@ -104,6 +107,7 @@ private:
|
||||
ChannelLocalPtr channelLocal;
|
||||
ChannelProcessRequester::shared_pointer channelProcessRequester,;
|
||||
PVRecordPtr pvRecord;
|
||||
ChannelLocalDebugPtr channelLocalDebug;
|
||||
Mutex mutex;
|
||||
Lock thelock;
|
||||
int nProcess;
|
||||
@ -113,7 +117,8 @@ ChannelProcessLocalPtr ChannelProcessLocal::create(
|
||||
ChannelLocalPtr const &channelLocal,
|
||||
ChannelProcessRequester::shared_pointer const & channelProcessRequester,
|
||||
PVStructurePtr const & pvRequest,
|
||||
PVRecordPtr const &pvRecord)
|
||||
PVRecordPtr const &pvRecord,
|
||||
ChannelLocalDebugPtr const &channelLocalDebug)
|
||||
{
|
||||
PVFieldPtr pvField;
|
||||
PVStructurePtr pvOptions;
|
||||
@ -137,7 +142,13 @@ ChannelProcessLocalPtr ChannelProcessLocal::create(
|
||||
channelLocal,
|
||||
channelProcessRequester,
|
||||
pvRecord,
|
||||
channelLocalDebug,
|
||||
nProcess));
|
||||
if(channelLocalDebug->getLevel()>0)
|
||||
{
|
||||
std::cout << "ChannelProcessLocal::create";
|
||||
std::cout << " recordName " << pvRecord->getRecordName() << std::endl;
|
||||
}
|
||||
channelLocal->addChannelProcess(process);
|
||||
channelProcessRequester->channelProcessConnect(Status::Ok, process);
|
||||
return process;
|
||||
@ -146,6 +157,11 @@ ChannelProcessLocalPtr ChannelProcessLocal::create(
|
||||
|
||||
void ChannelProcessLocal::destroy()
|
||||
{
|
||||
if(channelLocalDebug->getLevel()>0)
|
||||
{
|
||||
std::cout << "ChannelProcessLocal::destroy";
|
||||
std::cout << " destroyed " << isDestroyed << std::endl;
|
||||
}
|
||||
if(isDestroyed) return;
|
||||
isDestroyed = true;
|
||||
channelLocal->removeChannelProcess(getPtrSelf());
|
||||
@ -156,6 +172,18 @@ void ChannelProcessLocal::destroy()
|
||||
|
||||
void ChannelProcessLocal::process(bool lastRequest)
|
||||
{
|
||||
if(isDestroyed) {
|
||||
Status status(
|
||||
Status::Status::STATUSTYPE_ERROR,
|
||||
"was destroyed");
|
||||
channelProcessRequester->processDone(status);
|
||||
return;
|
||||
}
|
||||
if(channelLocalDebug->getLevel()>1)
|
||||
{
|
||||
std::cout << "ChannelProcessLocal::process";
|
||||
std::cout << " nProcess " << nProcess << std::endl;
|
||||
}
|
||||
for(int i=0; i< nProcess; i++) {
|
||||
pvRecord->lock();
|
||||
pvRecord->beginGroupPut();
|
||||
@ -163,12 +191,6 @@ void ChannelProcessLocal::process(bool lastRequest)
|
||||
pvRecord->endGroupPut();
|
||||
pvRecord->unlock();
|
||||
}
|
||||
if(isDestroyed) {
|
||||
Status status(
|
||||
Status::Status::STATUSTYPE_ERROR,
|
||||
"was destroyed");
|
||||
channelProcessRequester->processDone(status);
|
||||
}
|
||||
channelProcessRequester->processDone(Status::Ok);
|
||||
if(lastRequest) destroy();
|
||||
}
|
||||
@ -179,12 +201,19 @@ class ChannelGetLocal :
|
||||
{
|
||||
public:
|
||||
POINTER_DEFINITIONS(ChannelGetLocal);
|
||||
virtual ~ChannelGetLocal(){destroy();}
|
||||
virtual ~ChannelGetLocal()
|
||||
{
|
||||
if(channelLocalDebug->getLevel()>0)
|
||||
{
|
||||
std::cout << "~ChannelGetLocal()" << std::endl;
|
||||
}
|
||||
}
|
||||
static ChannelGetLocalPtr create(
|
||||
ChannelLocalPtr const &channelLocal,
|
||||
ChannelGetRequester::shared_pointer const & channelGetRequester,
|
||||
PVStructurePtr const & pvRequest,
|
||||
PVRecordPtr const &pvRecord);
|
||||
PVRecordPtr const &pvRecord,
|
||||
ChannelLocalDebugPtr const &channelLocalDebug);
|
||||
virtual void get(bool lastRequest);
|
||||
virtual void destroy();
|
||||
virtual void lock() {thelock.lock();}
|
||||
@ -201,7 +230,8 @@ private:
|
||||
PVCopyPtr const &pvCopy,
|
||||
PVStructurePtr const&pvStructure,
|
||||
BitSetPtr const & bitSet,
|
||||
PVRecordPtr const &pvRecord)
|
||||
PVRecordPtr const &pvRecord,
|
||||
ChannelLocalDebugPtr const &channelLocalDebug)
|
||||
:
|
||||
firstTime(true),
|
||||
isDestroyed(false),
|
||||
@ -212,6 +242,7 @@ private:
|
||||
pvStructure(pvStructure),
|
||||
bitSet(bitSet),
|
||||
pvRecord(pvRecord),
|
||||
channelLocalDebug(channelLocalDebug),
|
||||
thelock(mutex)
|
||||
{
|
||||
thelock.unlock();
|
||||
@ -225,6 +256,7 @@ private:
|
||||
PVStructurePtr pvStructure;
|
||||
BitSetPtr bitSet;
|
||||
PVRecordPtr pvRecord;
|
||||
ChannelLocalDebugPtr channelLocalDebug;
|
||||
Mutex mutex;
|
||||
Lock thelock;
|
||||
};
|
||||
@ -233,7 +265,8 @@ ChannelGetLocalPtr ChannelGetLocal::create(
|
||||
ChannelLocalPtr const &channelLocal,
|
||||
ChannelGetRequester::shared_pointer const & channelGetRequester,
|
||||
PVStructurePtr const & pvRequest,
|
||||
PVRecordPtr const &pvRecord)
|
||||
PVRecordPtr const &pvRecord,
|
||||
ChannelLocalDebugPtr const &channelLocalDebug)
|
||||
{
|
||||
PVCopyPtr pvCopy = PVCopy::create(
|
||||
pvRecord,
|
||||
@ -263,7 +296,13 @@ ChannelGetLocalPtr ChannelGetLocal::create(
|
||||
pvCopy,
|
||||
pvStructure,
|
||||
bitSet,
|
||||
pvRecord));
|
||||
pvRecord,
|
||||
channelLocalDebug));
|
||||
if(channelLocalDebug->getLevel()>0)
|
||||
{
|
||||
std::cout << "ChannelGetLocal::create";
|
||||
std::cout << " recordName " << pvRecord->getRecordName() << std::endl;
|
||||
}
|
||||
channelLocal->addChannelGet(get);
|
||||
channelGetRequester->channelGetConnect(Status::Ok, get, pvStructure,bitSet);
|
||||
return get;
|
||||
@ -272,6 +311,11 @@ ChannelGetLocalPtr ChannelGetLocal::create(
|
||||
|
||||
void ChannelGetLocal::destroy()
|
||||
{
|
||||
if(channelLocalDebug->getLevel()>0)
|
||||
{
|
||||
std::cout << "ChannelGetLocal::destroy";
|
||||
std::cout << " destroyed " << isDestroyed << std::endl;
|
||||
}
|
||||
if(isDestroyed) return;
|
||||
isDestroyed = true;
|
||||
channelLocal->removeChannelGet(getPtrSelf());
|
||||
@ -290,6 +334,7 @@ void ChannelGetLocal::get(bool lastRequest)
|
||||
Status::Status::STATUSTYPE_ERROR,
|
||||
"was destroyed");
|
||||
channelGetRequester->getDone(status);
|
||||
return;
|
||||
}
|
||||
bitSet->clear();
|
||||
pvRecord->lock();
|
||||
@ -306,6 +351,10 @@ void ChannelGetLocal::get(bool lastRequest)
|
||||
firstTime = false;
|
||||
}
|
||||
channelGetRequester->getDone(Status::Ok);
|
||||
if(channelLocalDebug->getLevel()>1)
|
||||
{
|
||||
std::cout << "ChannelGetLocal::get" << std::endl;
|
||||
}
|
||||
if(lastRequest) destroy();
|
||||
}
|
||||
|
||||
@ -315,12 +364,19 @@ class ChannelPutLocal :
|
||||
{
|
||||
public:
|
||||
POINTER_DEFINITIONS(ChannelPutLocal);
|
||||
virtual ~ChannelPutLocal(){destroy();}
|
||||
virtual ~ChannelPutLocal()
|
||||
{
|
||||
if(channelLocalDebug->getLevel()>0)
|
||||
{
|
||||
std::cout << "~ChannelPutLocal()" << std::endl;
|
||||
}
|
||||
}
|
||||
static ChannelPutLocalPtr create(
|
||||
ChannelLocalPtr const &channelLocal,
|
||||
ChannelPutRequester::shared_pointer const & channelPutRequester,
|
||||
PVStructurePtr const & pvRequest,
|
||||
PVRecordPtr const &pvRecord);
|
||||
PVRecordPtr const &pvRecord,
|
||||
ChannelLocalDebugPtr const &channelLocalDebug);
|
||||
virtual void put(bool lastRequest);
|
||||
virtual void get();
|
||||
virtual void destroy();
|
||||
@ -338,7 +394,8 @@ private:
|
||||
PVCopyPtr const &pvCopy,
|
||||
PVStructurePtr const&pvStructure,
|
||||
BitSetPtr const & bitSet,
|
||||
PVRecordPtr const &pvRecord)
|
||||
PVRecordPtr const &pvRecord,
|
||||
ChannelLocalDebugPtr const &channelLocalDebug)
|
||||
:
|
||||
isDestroyed(false),
|
||||
callProcess(callProcess),
|
||||
@ -348,6 +405,7 @@ private:
|
||||
pvStructure(pvStructure),
|
||||
bitSet(bitSet),
|
||||
pvRecord(pvRecord),
|
||||
channelLocalDebug(channelLocalDebug),
|
||||
thelock(mutex)
|
||||
{
|
||||
thelock.unlock();
|
||||
@ -360,6 +418,7 @@ private:
|
||||
PVStructurePtr pvStructure;
|
||||
BitSetPtr bitSet;
|
||||
PVRecordPtr pvRecord;
|
||||
ChannelLocalDebugPtr channelLocalDebug;
|
||||
Mutex mutex;
|
||||
Lock thelock;
|
||||
};
|
||||
@ -368,7 +427,8 @@ ChannelPutLocalPtr ChannelPutLocal::create(
|
||||
ChannelLocalPtr const &channelLocal,
|
||||
ChannelPutRequester::shared_pointer const & channelPutRequester,
|
||||
PVStructurePtr const & pvRequest,
|
||||
PVRecordPtr const &pvRecord)
|
||||
PVRecordPtr const &pvRecord,
|
||||
ChannelLocalDebugPtr const &channelLocalDebug)
|
||||
{
|
||||
PVCopyPtr pvCopy = PVCopy::create(
|
||||
pvRecord,
|
||||
@ -398,14 +458,25 @@ ChannelPutLocalPtr ChannelPutLocal::create(
|
||||
pvCopy,
|
||||
pvStructure,
|
||||
bitSet,
|
||||
pvRecord));
|
||||
pvRecord,
|
||||
channelLocalDebug));
|
||||
channelLocal->addChannelPut(put);
|
||||
channelPutRequester->channelPutConnect(Status::Ok, put, pvStructure,bitSet);
|
||||
if(channelLocalDebug->getLevel()>0)
|
||||
{
|
||||
std::cout << "ChannelPutLocal::create";
|
||||
std::cout << " recordName " << pvRecord->getRecordName() << std::endl;
|
||||
}
|
||||
return put;
|
||||
}
|
||||
|
||||
void ChannelPutLocal::destroy()
|
||||
{
|
||||
if(channelLocalDebug->getLevel()>0)
|
||||
{
|
||||
std::cout << "ChannelPutLocal::destroy";
|
||||
std::cout << " destroyed " << isDestroyed << std::endl;
|
||||
}
|
||||
if(isDestroyed) return;
|
||||
isDestroyed = true;
|
||||
channelLocal->removeChannelPut(getPtrSelf());
|
||||
@ -424,6 +495,7 @@ void ChannelPutLocal::get()
|
||||
Status::Status::STATUSTYPE_ERROR,
|
||||
"was destroyed");
|
||||
channelPutRequester->getDone(status);
|
||||
return;
|
||||
}
|
||||
bitSet->clear();
|
||||
bitSet->set(0);
|
||||
@ -431,6 +503,10 @@ void ChannelPutLocal::get()
|
||||
pvCopy->updateCopyFromBitSet(pvStructure, bitSet, false);
|
||||
pvRecord->unlock();
|
||||
channelPutRequester->getDone(Status::Ok);
|
||||
if(channelLocalDebug->getLevel()>1)
|
||||
{
|
||||
std::cout << "ChannelPutLocal::get" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void ChannelPutLocal::put(bool lastRequest)
|
||||
@ -440,6 +516,7 @@ void ChannelPutLocal::put(bool lastRequest)
|
||||
Status::Status::STATUSTYPE_ERROR,
|
||||
"was destroyed");
|
||||
channelPutRequester->getDone(status);
|
||||
return;
|
||||
}
|
||||
pvRecord->lock();
|
||||
pvRecord->beginGroupPut();
|
||||
@ -449,7 +526,11 @@ void ChannelPutLocal::put(bool lastRequest)
|
||||
}
|
||||
pvRecord->endGroupPut();
|
||||
pvRecord->unlock();
|
||||
channelPutRequester->getDone(Status::Ok);
|
||||
channelPutRequester->putDone(Status::Ok);
|
||||
if(channelLocalDebug->getLevel()>1)
|
||||
{
|
||||
std::cout << "ChannelPutLocal::get" << std::endl;
|
||||
}
|
||||
if(lastRequest) destroy();
|
||||
}
|
||||
|
||||
@ -460,12 +541,19 @@ class ChannelPutGetLocal :
|
||||
{
|
||||
public:
|
||||
POINTER_DEFINITIONS(ChannelPutGetLocal);
|
||||
virtual ~ChannelPutGetLocal(){destroy();}
|
||||
virtual ~ChannelPutGetLocal()
|
||||
{
|
||||
if(channelLocalDebug->getLevel()>0)
|
||||
{
|
||||
std::cout << "~ChannelPutGetLocal()" << std::endl;
|
||||
}
|
||||
}
|
||||
static ChannelPutGetLocalPtr create(
|
||||
ChannelLocalPtr const &channelLocal,
|
||||
ChannelPutGetRequester::shared_pointer const & channelPutGetRequester,
|
||||
PVStructurePtr const & pvRequest,
|
||||
PVRecordPtr const &pvRecord);
|
||||
PVRecordPtr const &pvRecord,
|
||||
ChannelLocalDebugPtr const &channelLocalDebug);
|
||||
virtual void putGet(bool lastRequest);
|
||||
virtual void getPut();
|
||||
virtual void getGet();
|
||||
@ -487,7 +575,8 @@ private:
|
||||
PVStructurePtr const&pvGetStructure,
|
||||
BitSetPtr const & putBitSet,
|
||||
BitSetPtr const & getBitSet,
|
||||
PVRecordPtr const &pvRecord)
|
||||
PVRecordPtr const &pvRecord,
|
||||
ChannelLocalDebugPtr const &channelLocalDebug)
|
||||
:
|
||||
isDestroyed(false),
|
||||
callProcess(callProcess),
|
||||
@ -500,6 +589,7 @@ private:
|
||||
putBitSet(putBitSet),
|
||||
getBitSet(getBitSet),
|
||||
pvRecord(pvRecord),
|
||||
channelLocalDebug(channelLocalDebug),
|
||||
thelock(mutex)
|
||||
{
|
||||
thelock.unlock();
|
||||
@ -515,6 +605,7 @@ private:
|
||||
BitSetPtr putBitSet;
|
||||
BitSetPtr getBitSet;
|
||||
PVRecordPtr pvRecord;
|
||||
ChannelLocalDebugPtr channelLocalDebug;
|
||||
Mutex mutex;
|
||||
Lock thelock;
|
||||
};
|
||||
@ -523,7 +614,8 @@ ChannelPutGetLocalPtr ChannelPutGetLocal::create(
|
||||
ChannelLocalPtr const &channelLocal,
|
||||
ChannelPutGetRequester::shared_pointer const & channelPutGetRequester,
|
||||
PVStructurePtr const & pvRequest,
|
||||
PVRecordPtr const &pvRecord)
|
||||
PVRecordPtr const &pvRecord,
|
||||
ChannelLocalDebugPtr const &channelLocalDebug)
|
||||
{
|
||||
PVCopyPtr pvPutCopy = PVCopy::create(
|
||||
pvRecord,
|
||||
@ -562,7 +654,13 @@ ChannelPutGetLocalPtr ChannelPutGetLocal::create(
|
||||
pvGetStructure,
|
||||
putBitSet,
|
||||
getBitSet,
|
||||
pvRecord));
|
||||
pvRecord,
|
||||
channelLocalDebug));
|
||||
if(channelLocalDebug->getLevel()>0)
|
||||
{
|
||||
std::cout << "ChannelPutGetLocal::create";
|
||||
std::cout << " recordName " << pvRecord->getRecordName() << std::endl;
|
||||
}
|
||||
channelLocal->addChannelPutGet(putGet);
|
||||
channelPutGetRequester->channelPutGetConnect(
|
||||
Status::Ok, putGet, pvPutStructure,pvGetStructure);
|
||||
@ -572,6 +670,11 @@ ChannelPutGetLocalPtr ChannelPutGetLocal::create(
|
||||
|
||||
void ChannelPutGetLocal::destroy()
|
||||
{
|
||||
if(channelLocalDebug->getLevel()>0)
|
||||
{
|
||||
std::cout << "ChannelPutGetLocal::destroy";
|
||||
std::cout << " destroyed " << isDestroyed << std::endl;
|
||||
}
|
||||
if(isDestroyed) return;
|
||||
isDestroyed = true;
|
||||
channelLocal->removeChannelPutGet(getPtrSelf());
|
||||
@ -593,6 +696,7 @@ void ChannelPutGetLocal::putGet(bool lastRequest)
|
||||
Status::Status::STATUSTYPE_ERROR,
|
||||
"was destroyed");
|
||||
channelPutGetRequester->putGetDone(status);
|
||||
return;
|
||||
}
|
||||
putBitSet->clear();
|
||||
putBitSet->set(0);
|
||||
@ -606,6 +710,10 @@ void ChannelPutGetLocal::putGet(bool lastRequest)
|
||||
getBitSet->clear();
|
||||
getBitSet->set(0);
|
||||
channelPutGetRequester->putGetDone(Status::Ok);
|
||||
if(channelLocalDebug->getLevel()>1)
|
||||
{
|
||||
std::cout << "ChannelPutGetLocal::putGet" << std::endl;
|
||||
}
|
||||
if(lastRequest) destroy();
|
||||
}
|
||||
|
||||
@ -616,6 +724,7 @@ void ChannelPutGetLocal::getPut()
|
||||
Status::Status::STATUSTYPE_ERROR,
|
||||
"was destroyed");
|
||||
channelPutGetRequester->getPutDone(status);
|
||||
return;
|
||||
}
|
||||
pvRecord->lock();
|
||||
pvPutCopy->updateCopySetBitSet(pvPutStructure, putBitSet, false);
|
||||
@ -623,6 +732,10 @@ void ChannelPutGetLocal::getPut()
|
||||
putBitSet->clear();
|
||||
putBitSet->set(0);
|
||||
channelPutGetRequester->getPutDone(Status::Ok);
|
||||
if(channelLocalDebug->getLevel()>1)
|
||||
{
|
||||
std::cout << "ChannelPutGetLocal::getPut" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void ChannelPutGetLocal::getGet()
|
||||
@ -632,6 +745,7 @@ void ChannelPutGetLocal::getGet()
|
||||
Status::Status::STATUSTYPE_ERROR,
|
||||
"was destroyed");
|
||||
channelPutGetRequester->getGetDone(status);
|
||||
return;
|
||||
}
|
||||
pvRecord->lock();
|
||||
pvGetCopy->updateCopySetBitSet(pvGetStructure, getBitSet, false);
|
||||
@ -639,6 +753,10 @@ void ChannelPutGetLocal::getGet()
|
||||
getBitSet->clear();
|
||||
getBitSet->set(0);
|
||||
channelPutGetRequester->getGetDone(Status::Ok);
|
||||
if(channelLocalDebug->getLevel()>1)
|
||||
{
|
||||
std::cout << "ChannelPutGetLocal::getGet" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
class ChannelRPCLocal :
|
||||
@ -657,38 +775,32 @@ public:
|
||||
bool lastRequest);
|
||||
};
|
||||
|
||||
int ChannelLocalDebugLevel = 0;
|
||||
void ChannelLocalDebug::setLevel(int level) {ChannelLocalDebugLevel = level;}
|
||||
int ChannelLocalDebug::getLevel() {return ChannelLocalDebugLevel;}
|
||||
|
||||
|
||||
|
||||
ChannelLocal::ChannelLocal(
|
||||
ChannelProviderLocalPtr const & provider,
|
||||
ChannelRequester::shared_pointer const & requester,
|
||||
PVRecordPtr const & pvRecord)
|
||||
PVRecordPtr const & pvRecord,
|
||||
ChannelLocalDebugPtr const &channelLocalDebug)
|
||||
: provider(provider),
|
||||
requester(requester),
|
||||
pvRecord(pvRecord),
|
||||
channelLocalDebug(channelLocalDebug),
|
||||
beingDestroyed(false)
|
||||
{
|
||||
if(ChannelLocalDebug::getLevel()>0) {
|
||||
printf("ChannelLocal::ChannelLocal\n");
|
||||
}
|
||||
}
|
||||
|
||||
ChannelLocal::~ChannelLocal()
|
||||
{
|
||||
if(ChannelLocalDebug::getLevel()>0) {
|
||||
printf("ChannelLocal::~ChannelLocal\n");
|
||||
if(channelLocalDebug->getLevel()>0) {
|
||||
std::cout << "~ChannelLocal()" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void ChannelLocal::destroy()
|
||||
{
|
||||
if(ChannelLocalDebug::getLevel()>0) {
|
||||
printf("ChannelLocal::destroy beingDestroyed %s\n",
|
||||
(beingDestroyed ? "true" : "false"));
|
||||
if(channelLocalDebug->getLevel()>0) {
|
||||
std::cout << "ChannelLocal::destroy() ";
|
||||
std::cout << "beingDestroyed " << beingDestroyed << std::endl;
|
||||
}
|
||||
{
|
||||
Lock xx(mutex);
|
||||
@ -723,13 +835,6 @@ void ChannelLocal::destroy()
|
||||
it->get()->destroy();
|
||||
channelPutGetList.erase(it);
|
||||
}
|
||||
while(true) {
|
||||
std::set<Monitor::shared_pointer>::iterator it;
|
||||
it = channelMonitorList.begin();
|
||||
if(it==channelMonitorList.end()) break;
|
||||
it->get()->destroy();
|
||||
channelMonitorList.erase(it);
|
||||
}
|
||||
while(true) {
|
||||
std::set<ChannelRPC::shared_pointer>::iterator it;
|
||||
it = channelRPCList.begin();
|
||||
@ -750,8 +855,8 @@ void ChannelLocal::destroy()
|
||||
|
||||
void ChannelLocal::addChannelProcess(ChannelProcess::shared_pointer const & channelProcess)
|
||||
{
|
||||
if(ChannelLocalDebug::getLevel()>0) {
|
||||
printf("ChannelLocal::addChannelProcess\n");
|
||||
if(channelLocalDebug->getLevel()>1) {
|
||||
std::cout << "ChannelLocal::addChannelProcess() " << std::endl;
|
||||
}
|
||||
Lock xx(mutex);
|
||||
if(beingDestroyed) return;
|
||||
@ -760,8 +865,8 @@ void ChannelLocal::addChannelProcess(ChannelProcess::shared_pointer const & chan
|
||||
|
||||
void ChannelLocal::addChannelGet(ChannelGet::shared_pointer const &channelGet)
|
||||
{
|
||||
if(ChannelLocalDebug::getLevel()>0) {
|
||||
printf("ChannelLocal::addChannelGet\n");
|
||||
if(channelLocalDebug->getLevel()>1) {
|
||||
std::cout << "ChannelLocal::addChannelGet() " << std::endl;
|
||||
}
|
||||
Lock xx(mutex);
|
||||
if(beingDestroyed) return;
|
||||
@ -770,8 +875,8 @@ void ChannelLocal::addChannelGet(ChannelGet::shared_pointer const &channelGet)
|
||||
|
||||
void ChannelLocal::addChannelPut(ChannelPut::shared_pointer const &channelPut)
|
||||
{
|
||||
if(ChannelLocalDebug::getLevel()>0) {
|
||||
printf("ChannelLocal::addChannelPut\n");
|
||||
if(channelLocalDebug->getLevel()>1) {
|
||||
std::cout << "ChannelLocal::addChannelPut() " << std::endl;
|
||||
}
|
||||
Lock xx(mutex);
|
||||
if(beingDestroyed) return;
|
||||
@ -780,28 +885,18 @@ void ChannelLocal::addChannelPut(ChannelPut::shared_pointer const &channelPut)
|
||||
|
||||
void ChannelLocal::addChannelPutGet(ChannelPutGet::shared_pointer const &channelPutGet)
|
||||
{
|
||||
if(ChannelLocalDebug::getLevel()>0) {
|
||||
printf("ChannelLocal::addChannelPutGet\n");
|
||||
if(channelLocalDebug->getLevel()>1) {
|
||||
std::cout << "ChannelLocal::addChannelPutGet() " << std::endl;
|
||||
}
|
||||
Lock xx(mutex);
|
||||
if(beingDestroyed) return;
|
||||
channelPutGetList.insert(channelPutGet);
|
||||
}
|
||||
|
||||
void ChannelLocal::addChannelMonitor(Monitor::shared_pointer const &monitor)
|
||||
{
|
||||
if(ChannelLocalDebug::getLevel()>0) {
|
||||
printf("ChannelLocal::addChannelMonitor\n");
|
||||
}
|
||||
Lock xx(mutex);
|
||||
if(beingDestroyed) return;
|
||||
channelMonitorList.insert(monitor);
|
||||
}
|
||||
|
||||
void ChannelLocal::addChannelRPC(ChannelRPC::shared_pointer const &channelRPC)
|
||||
{
|
||||
if(ChannelLocalDebug::getLevel()>0) {
|
||||
printf("ChannelLocal::addChannelRPC\n");
|
||||
if(channelLocalDebug->getLevel()>1) {
|
||||
std::cout << "ChannelLocal::addChannelRPC() " << std::endl;
|
||||
}
|
||||
Lock xx(mutex);
|
||||
if(beingDestroyed) return;
|
||||
@ -810,8 +905,8 @@ void ChannelLocal::addChannelRPC(ChannelRPC::shared_pointer const &channelRPC)
|
||||
|
||||
void ChannelLocal::addChannelArray(ChannelArray::shared_pointer const &channelArray)
|
||||
{
|
||||
if(ChannelLocalDebug::getLevel()>0) {
|
||||
printf("ChannelLocal::addChannelArray\n");
|
||||
if(channelLocalDebug->getLevel()>1) {
|
||||
std::cout << "ChannelLocal::addChannelArray() " << std::endl;
|
||||
}
|
||||
Lock xx(mutex);
|
||||
if(beingDestroyed) return;
|
||||
@ -820,8 +915,8 @@ void ChannelLocal::addChannelArray(ChannelArray::shared_pointer const &channelAr
|
||||
|
||||
void ChannelLocal::removeChannelProcess(ChannelProcess::shared_pointer const &ref)
|
||||
{
|
||||
if(ChannelLocalDebug::getLevel()>0) {
|
||||
printf("ChannelLocal::removeChannelProcess\n");
|
||||
if(channelLocalDebug->getLevel()>1) {
|
||||
std::cout << "ChannelLocal::removeChannelProcess() " << std::endl;
|
||||
}
|
||||
Lock xx(mutex);
|
||||
if(beingDestroyed) return;
|
||||
@ -830,8 +925,8 @@ void ChannelLocal::removeChannelProcess(ChannelProcess::shared_pointer const &re
|
||||
|
||||
void ChannelLocal::removeChannelGet(ChannelGet::shared_pointer const &ref)
|
||||
{
|
||||
if(ChannelLocalDebug::getLevel()>0) {
|
||||
printf("ChannelLocal::removeChannelGet\n");
|
||||
if(channelLocalDebug->getLevel()>1) {
|
||||
std::cout << "ChannelLocal::removeChannelGet() " << std::endl;
|
||||
}
|
||||
Lock xx(mutex);
|
||||
if(beingDestroyed) return;
|
||||
@ -840,8 +935,8 @@ void ChannelLocal::removeChannelGet(ChannelGet::shared_pointer const &ref)
|
||||
|
||||
void ChannelLocal::removeChannelPut(ChannelPut::shared_pointer const &ref)
|
||||
{
|
||||
if(ChannelLocalDebug::getLevel()>0) {
|
||||
printf("ChannelLocal::removeChannelPut\n");
|
||||
if(channelLocalDebug->getLevel()>1) {
|
||||
std::cout << "ChannelLocal::removeChannelPut() " << std::endl;
|
||||
}
|
||||
Lock xx(mutex);
|
||||
if(beingDestroyed) return;
|
||||
@ -850,28 +945,18 @@ void ChannelLocal::removeChannelPut(ChannelPut::shared_pointer const &ref)
|
||||
|
||||
void ChannelLocal::removeChannelPutGet(ChannelPutGet::shared_pointer const &ref)
|
||||
{
|
||||
if(ChannelLocalDebug::getLevel()>0) {
|
||||
printf("ChannelLocal::removeChannelPutGet\n");
|
||||
if(channelLocalDebug->getLevel()>1) {
|
||||
std::cout << "ChannelLocal::removeChannelPutGet() " << std::endl;
|
||||
}
|
||||
Lock xx(mutex);
|
||||
if(beingDestroyed) return;
|
||||
channelPutGetList.erase(ref);
|
||||
}
|
||||
|
||||
void ChannelLocal::removeChannelMonitor(Monitor::shared_pointer const &ref)
|
||||
{
|
||||
if(ChannelLocalDebug::getLevel()>0) {
|
||||
printf("ChannelLocal::removeChannelMonitor\n");
|
||||
}
|
||||
Lock xx(mutex);
|
||||
if(beingDestroyed) return;
|
||||
channelMonitorList.erase(ref);
|
||||
}
|
||||
|
||||
void ChannelLocal::removeChannelRPC(ChannelRPC::shared_pointer const &ref)
|
||||
{
|
||||
if(ChannelLocalDebug::getLevel()>0) {
|
||||
printf("ChannelLocal::removeChannelRPC\n");
|
||||
if(channelLocalDebug->getLevel()>1) {
|
||||
std::cout << "ChannelLocal::removeChannelRPC() " << std::endl;
|
||||
}
|
||||
Lock xx(mutex);
|
||||
if(beingDestroyed) return;
|
||||
@ -880,8 +965,8 @@ void ChannelLocal::removeChannelRPC(ChannelRPC::shared_pointer const &ref)
|
||||
|
||||
void ChannelLocal::removeChannelArray(ChannelArray::shared_pointer const &ref)
|
||||
{
|
||||
if(ChannelLocalDebug::getLevel()>0) {
|
||||
printf("ChannelLocal::removeChannelArray\n");
|
||||
if(channelLocalDebug->getLevel()>1) {
|
||||
std::cout << "ChannelLocal::removeChannelArray() " << std::endl;
|
||||
}
|
||||
Lock xx(mutex);
|
||||
if(beingDestroyed) return;
|
||||
@ -900,11 +985,6 @@ void ChannelLocal::message(
|
||||
requester->message(message,messageType);
|
||||
}
|
||||
|
||||
ChannelProvider::shared_pointer ChannelLocal::getProvider()
|
||||
{
|
||||
return provider;
|
||||
}
|
||||
|
||||
String ChannelLocal::getRemoteAddress()
|
||||
{
|
||||
return String("local");
|
||||
@ -963,7 +1043,8 @@ ChannelProcess::shared_pointer ChannelLocal::createChannelProcess(
|
||||
getPtrSelf(),
|
||||
channelProcessRequester,
|
||||
pvRequest,
|
||||
pvRecord);
|
||||
pvRecord,
|
||||
channelLocalDebug);
|
||||
return channelProcess;
|
||||
}
|
||||
|
||||
@ -976,7 +1057,8 @@ ChannelGet::shared_pointer ChannelLocal::createChannelGet(
|
||||
getPtrSelf(),
|
||||
channelGetRequester,
|
||||
pvRequest,
|
||||
pvRecord);
|
||||
pvRecord,
|
||||
channelLocalDebug);
|
||||
return channelGet;
|
||||
}
|
||||
|
||||
@ -989,7 +1071,8 @@ ChannelPut::shared_pointer ChannelLocal::createChannelPut(
|
||||
getPtrSelf(),
|
||||
channelPutRequester,
|
||||
pvRequest,
|
||||
pvRecord);
|
||||
pvRecord,
|
||||
channelLocalDebug);
|
||||
return channelPut;
|
||||
}
|
||||
|
||||
@ -1002,7 +1085,8 @@ ChannelPutGet::shared_pointer ChannelLocal::createChannelPutGet(
|
||||
getPtrSelf(),
|
||||
channelPutGetRequester,
|
||||
pvRequest,
|
||||
pvRecord);
|
||||
pvRecord,
|
||||
channelLocalDebug);
|
||||
return channelPutGet;
|
||||
}
|
||||
|
||||
@ -1021,7 +1105,11 @@ Monitor::shared_pointer ChannelLocal::createMonitor(
|
||||
PVStructure::shared_pointer const &pvRequest)
|
||||
{
|
||||
MonitorPtr monitor =
|
||||
getMonitorFactory()->createMonitor(pvRecord,monitorRequester,pvRequest);
|
||||
getMonitorFactory()->createMonitor(
|
||||
pvRecord,
|
||||
monitorRequester,
|
||||
pvRequest,
|
||||
channelLocalDebug);
|
||||
return monitor;
|
||||
}
|
||||
|
||||
@ -1040,7 +1128,7 @@ ChannelArray::shared_pointer ChannelLocal::createChannelArray(
|
||||
|
||||
void ChannelLocal::printInfo()
|
||||
{
|
||||
printf("ChannelLocal provides access to service\n");
|
||||
std::cout << "ChannelLocal provides access to service" << std::endl;
|
||||
}
|
||||
|
||||
void ChannelLocal::printInfo(StringBuilder out)
|
||||
|
75
src/pvAccess/channelLocalDebugRecord.cpp
Normal file
75
src/pvAccess/channelLocalDebugRecord.cpp
Normal file
@ -0,0 +1,75 @@
|
||||
/* channelListDebugRecord.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
|
||||
*/
|
||||
|
||||
#include <pv/channelLocalDebugRecord.h>
|
||||
|
||||
using std::tr1::static_pointer_cast;
|
||||
using namespace epics::pvData;
|
||||
using namespace epics::pvAccess;
|
||||
using namespace std;
|
||||
|
||||
namespace epics { namespace pvDatabase {
|
||||
|
||||
ChannelLocalDebugRecordPtr ChannelLocalDebugRecord::create(
|
||||
ChannelLocalDebugPtr const &channelLocalDebug,
|
||||
epics::pvData::String const & recordName)
|
||||
{
|
||||
FieldCreatePtr fieldCreate = getFieldCreate();
|
||||
PVDataCreatePtr pvDataCreate = getPVDataCreate();
|
||||
StringArray argNames(1);
|
||||
FieldConstPtrArray argFields(1);
|
||||
argNames[0] = "value";
|
||||
argFields[0] = fieldCreate->createScalar(pvInt);
|
||||
StructureConstPtr topStructure =
|
||||
fieldCreate->createStructure(argNames,argFields);
|
||||
PVStructurePtr pvStructure = pvDataCreate->createPVStructure(topStructure);
|
||||
ChannelLocalDebugRecordPtr pvRecord(
|
||||
new ChannelLocalDebugRecord(channelLocalDebug,recordName,pvStructure));
|
||||
if(!pvRecord->init()) pvRecord.reset();
|
||||
return pvRecord;
|
||||
}
|
||||
|
||||
ChannelLocalDebugRecord::ChannelLocalDebugRecord(
|
||||
ChannelLocalDebugPtr const &channelLocalDebug,
|
||||
epics::pvData::String const & recordName,
|
||||
epics::pvData::PVStructurePtr const & pvStructure)
|
||||
: PVRecord(recordName,pvStructure),
|
||||
channelLocalDebug(channelLocalDebug)
|
||||
{
|
||||
}
|
||||
|
||||
ChannelLocalDebugRecord::~ChannelLocalDebugRecord()
|
||||
{
|
||||
}
|
||||
|
||||
void ChannelLocalDebugRecord::destroy()
|
||||
{
|
||||
PVRecord::destroy();
|
||||
}
|
||||
|
||||
bool ChannelLocalDebugRecord::init()
|
||||
{
|
||||
initPVRecord();
|
||||
PVStructurePtr pvStructure = getPVStructure();
|
||||
|
||||
pvValue = pvStructure->getIntField("value");
|
||||
if(pvValue==NULL) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void ChannelLocalDebugRecord::process()
|
||||
{
|
||||
channelLocalDebug->setLevel(pvValue->get());
|
||||
}
|
||||
|
||||
|
||||
}}
|
||||
|
46
src/pvAccess/channelLocalDebugRecord.h
Normal file
46
src/pvAccess/channelLocalDebugRecord.h
Normal file
@ -0,0 +1,46 @@
|
||||
/* channelLocalDebugRecord.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 CHANNELLOCALREBUGRECORD_H
|
||||
#define CHANNELLOCALREBUGRECORD_H
|
||||
|
||||
#include <pv/channelProviderLocal.h>
|
||||
|
||||
namespace epics { namespace pvDatabase {
|
||||
|
||||
|
||||
class ChannelLocalDebugRecord;
|
||||
typedef std::tr1::shared_ptr<ChannelLocalDebugRecord> ChannelLocalDebugRecordPtr;
|
||||
|
||||
class ChannelLocalDebugRecord :
|
||||
public PVRecord
|
||||
{
|
||||
public:
|
||||
POINTER_DEFINITIONS(ChannelLocalDebugRecord);
|
||||
static ChannelLocalDebugRecordPtr create(
|
||||
ChannelLocalDebugPtr const &channelLocalDebug,
|
||||
epics::pvData::String const & recordName);
|
||||
virtual ~ChannelLocalDebugRecord();
|
||||
virtual void destroy();
|
||||
virtual bool init();
|
||||
virtual void process();
|
||||
private:
|
||||
ChannelLocalDebugRecord(
|
||||
ChannelLocalDebugPtr const &channelLocalDebug,
|
||||
epics::pvData::String const & recordName,
|
||||
epics::pvData::PVStructurePtr const & pvStructure);
|
||||
ChannelLocalDebugPtr channelLocalDebug;
|
||||
epics::pvData::PVIntPtr pvValue;
|
||||
bool isDestroyed;
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif /* CHANNELLOCALREBUGRECORD_H */
|
@ -11,6 +11,7 @@
|
||||
|
||||
#include <pv/serverContext.h>
|
||||
#include <pv/channelProviderLocal.h>
|
||||
#include <pv/channelLocalDebugRecord.h>
|
||||
|
||||
namespace epics { namespace pvDatabase {
|
||||
|
||||
@ -75,11 +76,13 @@ LocalChannelCTX::LocalChannelCTX(
|
||||
|
||||
LocalChannelCTX::~LocalChannelCTX()
|
||||
{
|
||||
std::cout << "LocalChannelCTX::~LocalChannelCTX()" << std::endl;
|
||||
ctx->shutdown();
|
||||
// we need thead.waitForCompletion()
|
||||
event.wait();
|
||||
epicsThreadSleep(1.0);
|
||||
ctx.reset();
|
||||
channelProvider.reset();
|
||||
delete thread;
|
||||
}
|
||||
void LocalChannelCTX::run()
|
||||
@ -90,11 +93,7 @@ void LocalChannelCTX::run()
|
||||
ctx->initialize(getChannelAccess());
|
||||
ctx->printInfo();
|
||||
ctx->run(0);
|
||||
// Matej if I switch which is commented then errors when exit
|
||||
// BUT this way causes lots of memory leaks
|
||||
channelProvider->destroy();
|
||||
//ctx->destroy();
|
||||
// Matej end of comments
|
||||
ctx->destroy();
|
||||
event.signal();
|
||||
}
|
||||
|
||||
@ -114,18 +113,27 @@ ChannelProviderLocalPtr getChannelProviderLocal()
|
||||
|
||||
ChannelProviderLocal::ChannelProviderLocal()
|
||||
: pvDatabase(PVDatabase::getMaster()),
|
||||
beingDestroyed(false)
|
||||
beingDestroyed(false),
|
||||
channelLocalDebug(new ChannelLocalDebug())
|
||||
{
|
||||
}
|
||||
|
||||
ChannelProviderLocal::~ChannelProviderLocal()
|
||||
{
|
||||
destroy();
|
||||
if(channelLocalDebug->getLevel()>0)
|
||||
{
|
||||
std::cout << "~ChannelProviderLocal()" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void ChannelProviderLocal::destroy()
|
||||
{
|
||||
Lock xx(mutex);
|
||||
if(channelLocalDebug->getLevel()>0)
|
||||
{
|
||||
std::cout << "ChannelProviderLocal::destroy";
|
||||
std::cout << " destroyed " << beingDestroyed << std::endl;
|
||||
}
|
||||
if(beingDestroyed) return;
|
||||
beingDestroyed = true;
|
||||
ChannelLocalList::iterator iter;
|
||||
@ -135,7 +143,6 @@ void ChannelProviderLocal::destroy()
|
||||
(*iter)->destroy();
|
||||
channelList.erase(iter);
|
||||
}
|
||||
|
||||
pvDatabase->destroy();
|
||||
}
|
||||
|
||||
@ -206,10 +213,15 @@ Channel::shared_pointer ChannelProviderLocal::createChannel(
|
||||
PVRecordPtr pvRecord = pvDatabase->findRecord(channelName);
|
||||
if(pvRecord.get()!=NULL) {
|
||||
Channel::shared_pointer channel(new ChannelLocal(
|
||||
getPtrSelf(),channelRequester,pvRecord));
|
||||
getPtrSelf(),channelRequester,pvRecord,channelLocalDebug));
|
||||
channelRequester->channelCreated(
|
||||
Status::Ok,
|
||||
channel);
|
||||
if(channelLocalDebug->getLevel()>1)
|
||||
{
|
||||
std::cout << "ChannelProviderLocal::createChannel";
|
||||
std::cout << " channelName " << channelName << std::endl;
|
||||
}
|
||||
return channel;
|
||||
}
|
||||
Status notFoundStatus(Status::STATUSTYPE_ERROR,String("pv not found"));
|
||||
@ -228,10 +240,27 @@ void ChannelProviderLocal::removeChannel(
|
||||
for(iter = channelList.begin(); iter!=channelList.end(); ++iter)
|
||||
{
|
||||
if((*iter).get()==channel.get()) {
|
||||
if(channelLocalDebug->getLevel()>1)
|
||||
{
|
||||
std::cout << "ChannelProviderLocal::createChannel";
|
||||
std::cout << " channelName " << channel->getChannelName() << std::endl;
|
||||
}
|
||||
channelList.erase(iter);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ChannelProviderLocal::createChannelLocalDebugRecord(
|
||||
String const &recordName)
|
||||
{
|
||||
ChannelLocalDebugRecordPtr pvRecord
|
||||
= ChannelLocalDebugRecord::create(channelLocalDebug,recordName);
|
||||
PVDatabasePtr master = PVDatabase::getMaster();
|
||||
bool result = master->addRecord(pvRecord);
|
||||
if(!result) {
|
||||
cout << "result of addRecord " << recordName << " " << result << endl;
|
||||
}
|
||||
}
|
||||
|
||||
}}
|
||||
|
@ -28,9 +28,16 @@
|
||||
|
||||
namespace epics { namespace pvDatabase {
|
||||
|
||||
class ChannelLocalDebug;
|
||||
typedef std::tr1::shared_ptr<ChannelLocalDebug> ChannelLocalDebugPtr;
|
||||
|
||||
class MonitorFactory;
|
||||
typedef std::tr1::shared_ptr<MonitorFactory> MonitorFactoryPtr;
|
||||
|
||||
class MonitorLocal;
|
||||
typedef std::tr1::shared_ptr<MonitorLocal> MonitorLocalPtr;
|
||||
|
||||
|
||||
class ChannelProviderLocal;
|
||||
typedef std::tr1::shared_ptr<ChannelProviderLocal> ChannelProviderLocalPtr;
|
||||
class ChannelLocal;
|
||||
@ -42,6 +49,23 @@ class MonitorLocal;
|
||||
typedef std::tr1::shared_ptr<MonitorLocal> MonitorLocalPtr;
|
||||
typedef std::set<MonitorLocalPtr> MonitorLocalList;
|
||||
|
||||
class ChannelLocalDebug {
|
||||
public:
|
||||
ChannelLocalDebug()
|
||||
: channelLocalDebugLevel(0)
|
||||
{}
|
||||
~ChannelLocalDebug(){}
|
||||
void setLevel(int level)
|
||||
{
|
||||
channelLocalDebugLevel = level;
|
||||
}
|
||||
int getLevel()
|
||||
{
|
||||
return channelLocalDebugLevel;
|
||||
}
|
||||
private:
|
||||
int channelLocalDebugLevel;
|
||||
};
|
||||
|
||||
class MonitorFactory
|
||||
{
|
||||
@ -52,13 +76,14 @@ public:
|
||||
epics::pvData::MonitorPtr createMonitor(
|
||||
PVRecordPtr const & pvRecord,
|
||||
epics::pvData::MonitorRequester::shared_pointer const & monitorRequester,
|
||||
epics::pvData::PVStructurePtr const & pvRequest);
|
||||
epics::pvData::PVStructurePtr const & pvRequest,
|
||||
ChannelLocalDebugPtr const &channelLocalDebug);
|
||||
void registerMonitorAlgorithmCreate(
|
||||
MonitorAlgorithmCreatePtr const &monitorAlgorithmCreate);
|
||||
MonitorAlgorithmCreatePtr getMonitorAlgorithmCreate(epics::pvData::String algorithmName);
|
||||
MonitorAlgorithmCreatePtr getMonitorAlgorithmCreate(
|
||||
epics::pvData::String algorithmName);
|
||||
private:
|
||||
MonitorFactory();
|
||||
void removeMonitor(MonitorLocal * monitor);
|
||||
friend class MonitorLocal;
|
||||
friend MonitorFactoryPtr getMonitorFactory();
|
||||
std::set<MonitorAlgorithmCreatePtr> monitorAlgorithmCreateList;
|
||||
@ -93,6 +118,7 @@ public:
|
||||
epics::pvData::String const &address);
|
||||
void removeChannel(
|
||||
epics::pvAccess::Channel::shared_pointer const &channel);
|
||||
void createChannelLocalDebugRecord(epics::pvData::String const &recordName);
|
||||
private:
|
||||
shared_pointer getPtrSelf()
|
||||
{
|
||||
@ -104,6 +130,7 @@ private:
|
||||
ChannelLocalList channelList;
|
||||
epics::pvData::Mutex mutex;
|
||||
bool beingDestroyed;
|
||||
ChannelLocalDebugPtr channelLocalDebug;
|
||||
friend class ChannelProviderLocalRun;
|
||||
};
|
||||
|
||||
@ -116,7 +143,8 @@ public:
|
||||
ChannelLocal(
|
||||
ChannelProviderLocalPtr const &channelProvider,
|
||||
epics::pvAccess::ChannelRequester::shared_pointer const & requester,
|
||||
PVRecordPtr const & pvRecord
|
||||
PVRecordPtr const & pvRecord,
|
||||
ChannelLocalDebugPtr const &channelLocalDebug
|
||||
);
|
||||
virtual ~ChannelLocal();
|
||||
virtual void destroy();
|
||||
@ -124,7 +152,10 @@ public:
|
||||
virtual void message(
|
||||
epics::pvData::String const & message,
|
||||
epics::pvData::MessageType messageType);
|
||||
virtual epics::pvAccess::ChannelProvider::shared_pointer getProvider();
|
||||
virtual epics::pvAccess::ChannelProvider::shared_pointer getProvider()
|
||||
{
|
||||
return provider;
|
||||
}
|
||||
virtual epics::pvData::String getRemoteAddress();
|
||||
virtual epics::pvAccess::Channel::ConnectionState getConnectionState();
|
||||
virtual epics::pvData::String getChannelName();
|
||||
@ -163,14 +194,12 @@ public:
|
||||
void addChannelGet(epics::pvAccess::ChannelGet::shared_pointer const &);
|
||||
void addChannelPut(epics::pvAccess::ChannelPut::shared_pointer const &);
|
||||
void addChannelPutGet(epics::pvAccess::ChannelPutGet::shared_pointer const &);
|
||||
void addChannelMonitor(epics::pvData::Monitor::shared_pointer const &);
|
||||
void addChannelRPC(epics::pvAccess::ChannelRPC::shared_pointer const &);
|
||||
void addChannelArray(epics::pvAccess::ChannelArray::shared_pointer const &);
|
||||
void removeChannelProcess(epics::pvAccess::ChannelProcess::shared_pointer const &);
|
||||
void removeChannelGet(epics::pvAccess::ChannelGet::shared_pointer const &);
|
||||
void removeChannelPut(epics::pvAccess::ChannelPut::shared_pointer const &);
|
||||
void removeChannelPutGet(epics::pvAccess::ChannelPutGet::shared_pointer const &);
|
||||
void removeChannelMonitor(epics::pvData::Monitor::shared_pointer const &);
|
||||
void removeChannelRPC(epics::pvAccess::ChannelRPC::shared_pointer const &);
|
||||
void removeChannelArray(epics::pvAccess::ChannelArray::shared_pointer const &);
|
||||
protected:
|
||||
@ -182,12 +211,12 @@ private:
|
||||
ChannelProviderLocalPtr provider;
|
||||
epics::pvAccess::ChannelRequester::shared_pointer requester;
|
||||
PVRecordPtr pvRecord;
|
||||
ChannelLocalDebugPtr channelLocalDebug;
|
||||
bool beingDestroyed;
|
||||
std::set<epics::pvAccess::ChannelProcess::shared_pointer> channelProcessList;
|
||||
std::set<epics::pvAccess::ChannelGet::shared_pointer> channelGetList;
|
||||
std::set<epics::pvAccess::ChannelPut::shared_pointer> channelPutList;
|
||||
std::set<epics::pvAccess::ChannelPutGet::shared_pointer> channelPutGetList;
|
||||
std::set<epics::pvData::Monitor::shared_pointer> channelMonitorList;
|
||||
std::set<epics::pvAccess::ChannelRPC::shared_pointer> channelRPCList;
|
||||
std::set<epics::pvAccess::ChannelArray::shared_pointer> channelArrayList;
|
||||
epics::pvData::Mutex mutex;
|
||||
|
@ -38,9 +38,6 @@ typedef std::tr1::shared_ptr<NOQueue> NOQueuePtr;
|
||||
class RealQueue;
|
||||
typedef std::tr1::shared_ptr<RealQueue> RealQueuePtr;
|
||||
|
||||
class MonitorLocal;
|
||||
typedef std::tr1::shared_ptr<MonitorLocal> MonitorLocalPtr;
|
||||
|
||||
//class MonitorFieldNode
|
||||
//{
|
||||
//public:
|
||||
@ -131,9 +128,9 @@ public:
|
||||
virtual void release(MonitorElementPtr const & monitorElement);
|
||||
bool init(PVStructurePtr const & pvRequest);
|
||||
MonitorLocal(
|
||||
ChannelProviderLocalPtr const &channelProvider,
|
||||
MonitorRequester::shared_pointer const & channelMonitorRequester,
|
||||
PVRecordPtr const &pvRecord);
|
||||
PVRecordPtr const &pvRecord,
|
||||
ChannelLocalDebugPtr const &channelLocalDebug);
|
||||
PVCopyPtr getPVCopy() { return pvCopy;}
|
||||
PVCopyMonitorPtr getPVCopyMonitor() { return pvCopyMonitor;}
|
||||
private:
|
||||
@ -141,8 +138,9 @@ private:
|
||||
{
|
||||
return shared_from_this();
|
||||
}
|
||||
PVRecordPtr pvRecord;
|
||||
MonitorRequester::shared_pointer monitorRequester;
|
||||
PVRecordPtr pvRecord;
|
||||
ChannelLocalDebugPtr channelLocalDebug;
|
||||
bool isDestroyed;
|
||||
bool firstMonitor;
|
||||
PVCopyPtr pvCopy;
|
||||
@ -153,11 +151,12 @@ private:
|
||||
};
|
||||
|
||||
MonitorLocal::MonitorLocal(
|
||||
ChannelProviderLocalPtr const &channelProvider,
|
||||
MonitorRequester::shared_pointer const & channelMonitorRequester,
|
||||
PVRecordPtr const &pvRecord)
|
||||
: pvRecord(pvRecord),
|
||||
monitorRequester(channelMonitorRequester),
|
||||
PVRecordPtr const &pvRecord,
|
||||
ChannelLocalDebugPtr const &channelLocalDebug)
|
||||
: monitorRequester(channelMonitorRequester),
|
||||
pvRecord(pvRecord),
|
||||
channelLocalDebug(channelLocalDebug),
|
||||
isDestroyed(false),
|
||||
firstMonitor(true)
|
||||
{
|
||||
@ -165,17 +164,18 @@ MonitorLocal::MonitorLocal(
|
||||
|
||||
MonitorLocal::~MonitorLocal()
|
||||
{
|
||||
destroy();
|
||||
std::cout << "MonitorLocal::~MonitorLocal()" << std::endl;
|
||||
}
|
||||
|
||||
void MonitorLocal::destroy()
|
||||
{
|
||||
//std::cout << "MonitorLocal::destroy " << isDestroyed << std::endl;
|
||||
std::cout << "MonitorLocal::destroy " << isDestroyed << std::endl;
|
||||
{
|
||||
Lock xx(mutex);
|
||||
if(isDestroyed) return;
|
||||
isDestroyed = true;
|
||||
}
|
||||
unlisten();
|
||||
stop();
|
||||
// monitorFieldList.clear();
|
||||
pvCopyMonitor.reset();
|
||||
@ -194,7 +194,7 @@ Status MonitorLocal::start()
|
||||
|
||||
Status MonitorLocal::stop()
|
||||
{
|
||||
//std::cout << "MonitorLocal::stop" << std::endl;
|
||||
std::cout << "MonitorLocal::stop" << std::endl;
|
||||
pvCopyMonitor->stopMonitoring();
|
||||
queue->stop();
|
||||
return Status::Ok;
|
||||
@ -222,7 +222,7 @@ void MonitorLocal::dataChanged()
|
||||
|
||||
void MonitorLocal::unlisten()
|
||||
{
|
||||
//std::cout << "MonitorLocal::unlisten" << std::endl;
|
||||
std::cout << "MonitorLocal::unlisten" << std::endl;
|
||||
monitorRequester->unlisten(getPtrSelf());
|
||||
}
|
||||
|
||||
@ -309,7 +309,7 @@ MonitorFactory::~MonitorFactory()
|
||||
|
||||
void MonitorFactory::destroy()
|
||||
{
|
||||
//std::cout << "MonitorFactory::destroy " << isDestroyed << std::endl;
|
||||
std::cout << "MonitorFactory::destroy " << isDestroyed << std::endl;
|
||||
Lock lock(mutex);
|
||||
if(isDestroyed) return;
|
||||
isDestroyed = true;
|
||||
@ -327,7 +327,8 @@ void MonitorFactory::destroy()
|
||||
MonitorPtr MonitorFactory::createMonitor(
|
||||
PVRecordPtr const & pvRecord,
|
||||
MonitorRequester::shared_pointer const & monitorRequester,
|
||||
PVStructurePtr const & pvRequest)
|
||||
PVStructurePtr const & pvRequest,
|
||||
ChannelLocalDebugPtr const &channelLocalDebug)
|
||||
{
|
||||
Lock xx(mutex);
|
||||
if(isDestroyed) {
|
||||
@ -335,27 +336,18 @@ MonitorPtr MonitorFactory::createMonitor(
|
||||
return nullMonitor;
|
||||
}
|
||||
MonitorLocalPtr monitor(new MonitorLocal(
|
||||
getChannelProviderLocal(),monitorRequester,pvRecord));
|
||||
monitorRequester,pvRecord,channelLocalDebug));
|
||||
bool result = monitor->init(pvRequest);
|
||||
if(!result) return nullMonitor;
|
||||
if(channelLocalDebug->getLevel()>0)
|
||||
{
|
||||
std::cout << "MonitorFactory::createMonitor";
|
||||
std::cout << " recordName " << pvRecord->getRecordName() << std::endl;
|
||||
}
|
||||
monitorLocalList.insert(monitor);
|
||||
return monitor;
|
||||
}
|
||||
|
||||
void MonitorFactory::removeMonitor(MonitorLocal * monitor)
|
||||
{
|
||||
//std::cout << "MonitorFactory::removeMonitor" << std::endl;
|
||||
Lock xx(mutex);
|
||||
if(isDestroyed) return;
|
||||
std::set<MonitorLocalPtr>::iterator iter;
|
||||
for (iter = monitorLocalList.begin(); iter!= monitorLocalList.end(); ++iter) {
|
||||
if(iter->get()==monitor) {
|
||||
monitorLocalList.erase(iter);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MonitorFactory::registerMonitorAlgorithmCreate(
|
||||
MonitorAlgorithmCreatePtr const &monitorAlgorithmCreate)
|
||||
{
|
||||
|
@ -1027,6 +1027,7 @@ void PVCopyMonitor::startMonitoring(
|
||||
|
||||
void PVCopyMonitor::stopMonitoring()
|
||||
{
|
||||
std::cout << "PVCopyMonitor::stopMonitoring()" << std::endl;
|
||||
pvRecord->removeListener(getPtrSelf());
|
||||
}
|
||||
|
||||
|
@ -33,6 +33,7 @@ int main(int argc,char *argv[])
|
||||
{
|
||||
PVDatabasePtr master = PVDatabase::getMaster();
|
||||
ChannelProviderLocalPtr channelProvider = getChannelProviderLocal();
|
||||
channelProvider->createChannelLocalDebugRecord("channelLocalDebug");
|
||||
String recordName("exampleCounter");
|
||||
PVRecordPtr pvRecord = ExampleCounter::create(recordName);
|
||||
bool result = master->addRecord(pvRecord);
|
||||
|
@ -62,6 +62,7 @@ int main(int argc,char *argv[])
|
||||
{
|
||||
PVDatabasePtr master = PVDatabase::getMaster();
|
||||
ChannelProviderLocalPtr channelProvider = getChannelProviderLocal();
|
||||
channelProvider->createChannelLocalDebugRecord("channelLocalDebug");
|
||||
StandardPVFieldPtr standardPVField = getStandardPVField();
|
||||
String properties;
|
||||
ScalarType scalarType;
|
||||
@ -82,6 +83,14 @@ int main(int argc,char *argv[])
|
||||
pvRecord->process();
|
||||
}
|
||||
result = master->addRecord(pvRecord);
|
||||
recordName = "exampleDoubleArray";
|
||||
pvStructure = standardPVField->scalarArray(scalarType,properties);
|
||||
pvRecord = PVRecord::create(recordName,pvStructure);
|
||||
{
|
||||
pvRecord->lock_guard();
|
||||
pvRecord->process();
|
||||
}
|
||||
result = master->addRecord(pvRecord);
|
||||
recordName = "examplePowerSupply";
|
||||
pvStructure = createPowerSupply();
|
||||
PowerSupplyRecordTestPtr psr =
|
||||
|
Reference in New Issue
Block a user