monitors now implemented
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, 17-Apr-2013</h2>
|
||||
<h2 class="nocount">EPICS v4 Working Group, Working Draft, 16-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_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>Previous version:</dt>
|
||||
<dd><a
|
||||
href="http://epics-pvdata.hg.sourceforge.net/hgweb/epics-pvdata/pvDatabaseCPP/raw-file/tip/documentation/pvDatabaseCPP_20121211.html">pvDatabaseCPP20121211.html</a>
|
||||
href="http://epics-pvdata.hg.sourceforge.net/hgweb/epics-pvdata/pvDatabaseCPP/raw-file/tip/documentation/pvDatabaseCPP_20130417.html">pvDatabaseCPP20130417.html</a>
|
||||
</dd>
|
||||
<dt>Editors:</dt>
|
||||
<dd>Marty Kraimer, BNL</dd>
|
||||
@ -74,14 +74,20 @@ 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 17-Apr-2013 version of the definition of pvDatabaseCPP.
|
||||
<p>This is the 16-May-2013 version of the definition of pvDatabaseCPP.
|
||||
</p>
|
||||
<p>The following Channel methods are implemented and working: getField,i
|
||||
channelProcess, channelGet, channelPut, and channelPutGet.
|
||||
<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>Monitor is next.</dd>
|
||||
<dd>ChannelArray is next.</dd>
|
||||
<dt>Monitor Algorithms</dt>
|
||||
<dd>Monitor algorithms have no 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>
|
||||
<dt>Scalar Arrays</dt>
|
||||
|
871
documentation/pvDatabaseCPP_20130516.html
Normal file
871
documentation/pvDatabaseCPP_20130516.html
Normal file
@ -0,0 +1,871 @@
|
||||
<?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, 16-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_20130516.html">pvDatabaseCPP20130516.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>
|
||||
</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 16-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>
|
||||
<dt>Monitor Algorithms</dt>
|
||||
<dd>Monitor algorithms have no 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>
|
||||
<dt>Scalar Arrays</dt>
|
||||
<dd>Have not been tested. Share has not been implemented.</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 provides 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 would probably break the code into two files:
|
||||
1) a header, and 2) the implementation. 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>
|
||||
</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>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>
|
||||
<dl>
|
||||
<dt>pvCopy</dt>
|
||||
<dt>monitor</dt>
|
||||
<dt>local ChannelProvider and Channel</dt>
|
||||
</dl>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -19,9 +19,12 @@ LIBSRCS += recordList.cpp
|
||||
SRC_DIRS += $(DATABASE)/pvAccess
|
||||
INC += channelProviderLocal.h
|
||||
INC += pvCopy.h
|
||||
INC += monitorAlgorithm.h
|
||||
LIBSRCS += channelProviderLocal.cpp
|
||||
LIBSRCS += channelLocal.cpp
|
||||
LIBSRCS += pvCopy.cpp
|
||||
LIBSRCS += monitorFactory.cpp
|
||||
|
||||
|
||||
include $(TOP)/configure/RULES
|
||||
|
||||
|
@ -11,6 +11,7 @@
|
||||
#ifndef EXAMPLECOUNTER_H
|
||||
#define EXAMPLECOUNTER_H
|
||||
|
||||
|
||||
#include <pv/pvDatabase.h>
|
||||
#include <pv/standardPVField.h>
|
||||
#include <pv/timeStamp.h>
|
||||
|
@ -61,9 +61,13 @@ void PVDatabase::destroy()
|
||||
}
|
||||
}
|
||||
|
||||
void PVDatabase::lock() {thelock.lock();}
|
||||
void PVDatabase::lock() {
|
||||
thelock.lock();
|
||||
}
|
||||
|
||||
void PVDatabase::unlock() {thelock.unlock();}
|
||||
void PVDatabase::unlock() {
|
||||
thelock.unlock();
|
||||
}
|
||||
|
||||
PVRecordPtr PVDatabase::findRecord(String const& recordName)
|
||||
{
|
||||
|
@ -346,11 +346,14 @@ protected:
|
||||
return shared_from_this();
|
||||
}
|
||||
virtual void init();
|
||||
virtual void postParent(PVRecordFieldPtr const & subField);
|
||||
virtual void postSubField();
|
||||
private:
|
||||
void callListener();
|
||||
|
||||
std::list<PVListenerPtr> pvListenerList;
|
||||
epics::pvData::PVFieldPtr pvField;
|
||||
bool isStructure;
|
||||
PVRecordStructurePtr parent;
|
||||
PVRecordPtr pvRecord;
|
||||
epics::pvData::String fullName;
|
||||
@ -470,6 +473,11 @@ public:
|
||||
* @param pvRecord The record.
|
||||
*/
|
||||
virtual void endGroupPut(PVRecordPtr const & pvRecord) = 0;
|
||||
/**
|
||||
* Connection to record is being terminated.
|
||||
* @param pvRecord The record.
|
||||
*/
|
||||
virtual void unlisten(PVRecordPtr const & pvRecord) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -169,11 +169,17 @@ PVRecordFieldPtr PVRecord::findPVRecordField(
|
||||
+ pvField->getFieldName() + " not in PVRecord");
|
||||
}
|
||||
|
||||
void PVRecord::lock() {thelock.lock();}
|
||||
void PVRecord::lock() {
|
||||
thelock.lock();
|
||||
}
|
||||
|
||||
void PVRecord::unlock() {thelock.unlock();}
|
||||
void PVRecord::unlock() {
|
||||
thelock.unlock();
|
||||
}
|
||||
|
||||
bool PVRecord::tryLock() {return thelock.tryLock();}
|
||||
bool PVRecord::tryLock() {
|
||||
return thelock.tryLock();
|
||||
}
|
||||
|
||||
void PVRecord::lockOtherRecord(PVRecordPtr const & otherRecord)
|
||||
{
|
||||
@ -347,6 +353,7 @@ PVRecordField::PVRecordField(
|
||||
PVRecordStructurePtr const &parent,
|
||||
PVRecordPtr const & pvRecord)
|
||||
: pvField(pvField),
|
||||
isStructure(pvField->getField()->getType()==structure ? true : false),
|
||||
parent(parent),
|
||||
pvRecord(pvRecord)
|
||||
{
|
||||
@ -419,15 +426,33 @@ void PVRecordField::removeListener(PVListenerPtr const & pvListener)
|
||||
|
||||
void PVRecordField::postPut()
|
||||
{
|
||||
callListener();
|
||||
if(parent!=NULL) {
|
||||
parent->postParent(getPtrSelf());
|
||||
}
|
||||
postSubField();
|
||||
}
|
||||
|
||||
void PVRecordField::postParent(PVRecordFieldPtr const & subField)
|
||||
{
|
||||
PVRecordStructurePtr pvrs = static_pointer_cast<PVRecordStructure>(getPtrSelf());
|
||||
std::list<PVListenerPtr>::iterator iter;
|
||||
PVRecordStructurePtr pvParent = getParent();
|
||||
while(pvParent.get()!=NULL) {
|
||||
std::list<PVListenerPtr> list = pvParent->pvListenerList;
|
||||
for (iter = list.begin(); iter!=list.end(); iter++ ) {
|
||||
(*iter)->dataPut(pvParent,getPtrSelf());
|
||||
for(iter = pvListenerList.begin(); iter != pvListenerList.end(); ++iter)
|
||||
{
|
||||
(*iter)->dataPut(pvrs,subField);
|
||||
}
|
||||
if(parent!=NULL) parent->postParent(subField);
|
||||
}
|
||||
|
||||
void PVRecordField::postSubField()
|
||||
{
|
||||
callListener();
|
||||
if(isStructure) {
|
||||
PVRecordStructurePtr pvrs = static_pointer_cast<PVRecordStructure>(getPtrSelf());
|
||||
PVRecordFieldPtrArrayPtr pvRecordFields = pvrs->getPVRecordFields();
|
||||
PVRecordFieldPtrArray::iterator iter;
|
||||
for(iter = pvRecordFields->begin() ; iter !=pvRecordFields->end(); iter++) {
|
||||
(*iter)->postSubField();
|
||||
}
|
||||
pvParent = pvParent->getParent();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,10 +5,16 @@
|
||||
* in file LICENSE that is included with this distribution.
|
||||
*/
|
||||
/**
|
||||
* @author mrk
|
||||
* @author Marty Kraimer
|
||||
* @date 2013.04
|
||||
*/
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include <epicsThread.h>
|
||||
|
||||
#include <pv/channelProviderLocal.h>
|
||||
#include <pv/convert.h>
|
||||
|
||||
namespace epics { namespace pvDatabase {
|
||||
using namespace epics::pvData;
|
||||
@ -16,6 +22,8 @@ using namespace epics::pvAccess;
|
||||
using std::tr1::static_pointer_cast;
|
||||
using std::tr1::dynamic_pointer_cast;
|
||||
|
||||
static ConvertPtr convert = getConvert();
|
||||
|
||||
class ChannelProcessLocal;
|
||||
typedef std::tr1::shared_ptr<ChannelProcessLocal> ChannelProcessLocalPtr;
|
||||
class ChannelGetLocal;
|
||||
@ -79,13 +87,15 @@ private:
|
||||
ChannelProcessLocal(
|
||||
ChannelLocalPtr const &channelLocal,
|
||||
ChannelProcessRequester::shared_pointer const & channelProcessRequester,
|
||||
PVRecordPtr const &pvRecord)
|
||||
PVRecordPtr const &pvRecord,
|
||||
int nProcess)
|
||||
:
|
||||
isDestroyed(false),
|
||||
channelLocal(channelLocal),
|
||||
channelProcessRequester(channelProcessRequester),
|
||||
pvRecord(pvRecord),
|
||||
thelock(mutex)
|
||||
thelock(mutex),
|
||||
nProcess(nProcess)
|
||||
{
|
||||
thelock.unlock();
|
||||
}
|
||||
@ -96,6 +106,7 @@ private:
|
||||
PVRecordPtr pvRecord;
|
||||
Mutex mutex;
|
||||
Lock thelock;
|
||||
int nProcess;
|
||||
};
|
||||
|
||||
ChannelProcessLocalPtr ChannelProcessLocal::create(
|
||||
@ -104,10 +115,29 @@ ChannelProcessLocalPtr ChannelProcessLocal::create(
|
||||
PVStructurePtr const & pvRequest,
|
||||
PVRecordPtr const &pvRecord)
|
||||
{
|
||||
PVFieldPtr pvField;
|
||||
PVStructurePtr pvOptions;
|
||||
int nProcess = 1;
|
||||
if(pvRequest!=NULL) pvField = pvRequest->getSubField("record._options");
|
||||
if(pvField.get()!=NULL) {
|
||||
pvOptions = static_pointer_cast<PVStructure>(pvField);
|
||||
pvField = pvOptions->getSubField("nProcess");
|
||||
if(pvField.get()!=NULL) {
|
||||
PVStringPtr pvString = pvOptions->getStringField("nProcess");
|
||||
if(pvString.get()!=NULL) {
|
||||
int size;
|
||||
std::stringstream ss;
|
||||
ss << pvString->get();
|
||||
ss >> size;
|
||||
nProcess = size;
|
||||
}
|
||||
}
|
||||
}
|
||||
ChannelProcessLocalPtr process(new ChannelProcessLocal(
|
||||
channelLocal,
|
||||
channelProcessRequester,
|
||||
pvRecord));
|
||||
pvRecord,
|
||||
nProcess));
|
||||
channelLocal->addChannelProcess(process);
|
||||
channelProcessRequester->channelProcessConnect(Status::Ok, process);
|
||||
return process;
|
||||
@ -126,9 +156,13 @@ void ChannelProcessLocal::destroy()
|
||||
|
||||
void ChannelProcessLocal::process(bool lastRequest)
|
||||
{
|
||||
pvRecord->lock();
|
||||
pvRecord->process();
|
||||
pvRecord->unlock();
|
||||
for(int i=0; i< nProcess; i++) {
|
||||
pvRecord->lock();
|
||||
pvRecord->beginGroupPut();
|
||||
pvRecord->process();
|
||||
pvRecord->endGroupPut();
|
||||
pvRecord->unlock();
|
||||
}
|
||||
if(isDestroyed) {
|
||||
Status status(
|
||||
Status::Status::STATUSTYPE_ERROR,
|
||||
@ -259,7 +293,11 @@ void ChannelGetLocal::get(bool lastRequest)
|
||||
}
|
||||
bitSet->clear();
|
||||
pvRecord->lock();
|
||||
if(callProcess) pvRecord->process();
|
||||
if(callProcess) {
|
||||
pvRecord->beginGroupPut();
|
||||
pvRecord->process();
|
||||
pvRecord->endGroupPut();
|
||||
}
|
||||
pvCopy->updateCopySetBitSet(pvStructure, bitSet, false);
|
||||
pvRecord->unlock();
|
||||
if(firstTime) {
|
||||
@ -404,8 +442,12 @@ void ChannelPutLocal::put(bool lastRequest)
|
||||
channelPutRequester->getDone(status);
|
||||
}
|
||||
pvRecord->lock();
|
||||
pvRecord->beginGroupPut();
|
||||
pvCopy->updateRecord(pvStructure, bitSet, false);
|
||||
if(callProcess) pvRecord->process();
|
||||
if(callProcess) {
|
||||
pvRecord->process();
|
||||
}
|
||||
pvRecord->endGroupPut();
|
||||
pvRecord->unlock();
|
||||
channelPutRequester->getDone(Status::Ok);
|
||||
if(lastRequest) destroy();
|
||||
@ -555,9 +597,11 @@ void ChannelPutGetLocal::putGet(bool lastRequest)
|
||||
putBitSet->clear();
|
||||
putBitSet->set(0);
|
||||
pvRecord->lock();
|
||||
pvRecord->beginGroupPut();
|
||||
pvPutCopy->updateRecord(pvPutStructure, putBitSet, false);
|
||||
if(callProcess) pvRecord->process();
|
||||
pvGetCopy->updateCopySetBitSet(pvGetStructure, getBitSet, false);
|
||||
pvRecord->endGroupPut();
|
||||
pvRecord->unlock();
|
||||
getBitSet->clear();
|
||||
getBitSet->set(0);
|
||||
@ -597,23 +641,6 @@ void ChannelPutGetLocal::getGet()
|
||||
channelPutGetRequester->getGetDone(Status::Ok);
|
||||
}
|
||||
|
||||
class ChannelMonitorLocal :
|
||||
public Monitor
|
||||
{
|
||||
public:
|
||||
POINTER_DEFINITIONS(ChannelMonitorLocal);
|
||||
virtual ~ChannelMonitorLocal();
|
||||
static Monitor::shared_pointer create(
|
||||
ChannelProviderLocalPtr const &channelProvider,
|
||||
MonitorRequester::shared_pointer const & channelMonitorRequester,
|
||||
PVStructurePtr const & pvRequest,
|
||||
PVRecordPtr const &pvRecord);
|
||||
virtual Status start();
|
||||
virtual Status stop();
|
||||
virtual MonitorElementPtr poll();
|
||||
virtual void release(MonitorElementPtr const & monitorElement);
|
||||
};
|
||||
|
||||
class ChannelRPCLocal :
|
||||
public ChannelRPC
|
||||
{
|
||||
@ -630,22 +657,6 @@ public:
|
||||
bool lastRequest);
|
||||
};
|
||||
|
||||
class ChannelArrayLocal :
|
||||
public ChannelArray
|
||||
{
|
||||
public:
|
||||
POINTER_DEFINITIONS(ChannelArrayLocal);
|
||||
virtual ~ChannelArrayLocal();
|
||||
static ChannelArray::shared_pointer create(
|
||||
ChannelProviderLocalPtr const &channelProvider,
|
||||
ChannelArray::shared_pointer const & channelArrayRequester,
|
||||
PVStructurePtr const & pvRequest,
|
||||
PVRecordPtr const &pvRecord);
|
||||
virtual void putArray(bool lastRequest, int offset, int count);
|
||||
virtual void getArray(bool lastRequest, int offset, int count);
|
||||
virtual void setLength(bool lastRequest, int length, int capacity);
|
||||
};
|
||||
|
||||
int ChannelLocalDebugLevel = 0;
|
||||
void ChannelLocalDebug::setLevel(int level) {ChannelLocalDebugLevel = level;}
|
||||
int ChannelLocalDebug::getLevel() {return ChannelLocalDebugLevel;}
|
||||
@ -1009,14 +1020,9 @@ Monitor::shared_pointer ChannelLocal::createMonitor(
|
||||
MonitorRequester::shared_pointer const &monitorRequester,
|
||||
PVStructure::shared_pointer const &pvRequest)
|
||||
{
|
||||
Status status(Status::STATUSTYPE_ERROR,
|
||||
String("ChannelMonitor not supported"));
|
||||
Monitor::shared_pointer thisPointer = dynamic_pointer_cast<Monitor>(getPtrSelf());
|
||||
monitorRequester->monitorConnect(
|
||||
status,
|
||||
thisPointer,
|
||||
StructureConstPtr());
|
||||
return Monitor::shared_pointer();
|
||||
MonitorPtr monitor =
|
||||
getMonitorFactory()->createMonitor(pvRecord,monitorRequester,pvRequest);
|
||||
return monitor;
|
||||
}
|
||||
|
||||
ChannelArray::shared_pointer ChannelLocal::createChannelArray(
|
||||
|
@ -5,7 +5,8 @@
|
||||
* in file LICENSE that is included with this distribution.
|
||||
*/
|
||||
/**
|
||||
* @author mrk
|
||||
* @author Marty Kraimer
|
||||
* @date 2013.04
|
||||
*/
|
||||
|
||||
#include <pv/serverContext.h>
|
||||
@ -98,11 +99,17 @@ void LocalChannelCTX::run()
|
||||
}
|
||||
|
||||
|
||||
ChannelProviderLocalPtr ChannelProviderLocal::create()
|
||||
ChannelProviderLocalPtr getChannelProviderLocal()
|
||||
{
|
||||
ChannelProviderLocalPtr channelProvider(new ChannelProviderLocal());
|
||||
LocalChannelCTX::create(channelProvider);
|
||||
return channelProvider;
|
||||
static ChannelProviderLocalPtr channelProviderLocal;
|
||||
static Mutex mutex;
|
||||
Lock xx(mutex);
|
||||
if(channelProviderLocal.get()==NULL) {
|
||||
channelProviderLocal = ChannelProviderLocalPtr(
|
||||
new ChannelProviderLocal());
|
||||
LocalChannelCTX::create(channelProviderLocal);
|
||||
}
|
||||
return channelProviderLocal;
|
||||
}
|
||||
|
||||
ChannelProviderLocal::ChannelProviderLocal()
|
||||
|
@ -5,7 +5,8 @@
|
||||
* in file LICENSE that is included with this distribution.
|
||||
*/
|
||||
/**
|
||||
* @author mrk
|
||||
* @author Marty Kraimer
|
||||
* @data 2013.04
|
||||
*/
|
||||
#ifndef CHANNELPROVIDERLOCAL_H
|
||||
#define CHANNELPROVIDERLOCAL_H
|
||||
@ -22,10 +23,13 @@
|
||||
#include <pv/pvDatabase.h>
|
||||
#include <pv/status.h>
|
||||
#include <pv/pvCopy.h>
|
||||
#include <pv/monitorAlgorithm.h>
|
||||
|
||||
|
||||
namespace epics { namespace pvDatabase {
|
||||
|
||||
class MonitorFactory;
|
||||
typedef std::tr1::shared_ptr<MonitorFactory> MonitorFactoryPtr;
|
||||
|
||||
class ChannelProviderLocal;
|
||||
typedef std::tr1::shared_ptr<ChannelProviderLocal> ChannelProviderLocalPtr;
|
||||
@ -33,14 +37,45 @@ class ChannelLocal;
|
||||
typedef std::tr1::shared_ptr<ChannelLocal> ChannelLocalPtr;
|
||||
typedef std::set<ChannelLocalPtr> ChannelLocalList;
|
||||
|
||||
extern MonitorFactoryPtr getMonitorFactory();
|
||||
class MonitorLocal;
|
||||
typedef std::tr1::shared_ptr<MonitorLocal> MonitorLocalPtr;
|
||||
typedef std::set<MonitorLocalPtr> MonitorLocalList;
|
||||
|
||||
|
||||
class MonitorFactory
|
||||
{
|
||||
public:
|
||||
POINTER_DEFINITIONS(MonitorFactory);
|
||||
virtual ~MonitorFactory();
|
||||
virtual void destroy();
|
||||
epics::pvData::MonitorPtr createMonitor(
|
||||
PVRecordPtr const & pvRecord,
|
||||
epics::pvData::MonitorRequester::shared_pointer const & monitorRequester,
|
||||
epics::pvData::PVStructurePtr const & pvRequest);
|
||||
void registerMonitorAlgorithmCreate(
|
||||
MonitorAlgorithmCreatePtr const &monitorAlgorithmCreate);
|
||||
MonitorAlgorithmCreatePtr getMonitorAlgorithmCreate(epics::pvData::String algorithmName);
|
||||
private:
|
||||
MonitorFactory();
|
||||
void removeMonitor(MonitorLocal * monitor);
|
||||
friend class MonitorLocal;
|
||||
friend MonitorFactoryPtr getMonitorFactory();
|
||||
std::set<MonitorAlgorithmCreatePtr> monitorAlgorithmCreateList;
|
||||
std::set<MonitorLocalPtr> monitorLocalList;
|
||||
bool isDestroyed;
|
||||
epics::pvData::Mutex mutex;
|
||||
};
|
||||
|
||||
|
||||
extern ChannelProviderLocalPtr getChannelProviderLocal();
|
||||
|
||||
class ChannelProviderLocal :
|
||||
public epics::pvAccess::ChannelProvider,
|
||||
public std::tr1::enable_shared_from_this<ChannelProviderLocal>
|
||||
{
|
||||
public:
|
||||
POINTER_DEFINITIONS(ChannelProviderLocal);
|
||||
|
||||
static ChannelProviderLocalPtr create();
|
||||
virtual ~ChannelProviderLocal();
|
||||
virtual void destroy();
|
||||
virtual epics::pvData::String getProviderName();
|
||||
@ -64,7 +99,7 @@ private:
|
||||
return shared_from_this();
|
||||
}
|
||||
ChannelProviderLocal();
|
||||
|
||||
friend ChannelProviderLocalPtr getChannelProviderLocal();
|
||||
PVDatabasePtr pvDatabase;
|
||||
ChannelLocalList channelList;
|
||||
epics::pvData::Mutex mutex;
|
||||
|
@ -4,35 +4,55 @@
|
||||
* EPICS pvData is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
*/
|
||||
/* Marty Kraimer 2011.03 */
|
||||
/**
|
||||
* @author Marty Kraimer
|
||||
* @data 2013.04
|
||||
*/
|
||||
#ifndef MONITORALGORITHM_H
|
||||
#define MONITORALGORITHM_H
|
||||
#include <string>
|
||||
|
||||
#include <pv/pvData.h>
|
||||
#include <pv/pvCopy.h>
|
||||
|
||||
namespace epics { namespace pvIOC {
|
||||
namespace epics { namespace pvDatabase {
|
||||
|
||||
class MonitorAlgorithm {
|
||||
class MonitorAlgorithm;
|
||||
typedef std::tr1::shared_ptr<MonitorAlgorithm> MonitorAlgorithmPtr;
|
||||
class MonitorAlgorithmCreate;
|
||||
typedef std::tr1::shared_ptr<MonitorAlgorithmCreate> MonitorAlgorithmCreatePtr;
|
||||
|
||||
class MonitorAlgorithm
|
||||
{
|
||||
public:
|
||||
MonitorAlgorithm(){}
|
||||
virtual ~MonitorAlgorithm(){}
|
||||
virtual epics::pvData::String getAlgorithmName() = 0;
|
||||
virtual bool causeMonitor() = 0;
|
||||
void monitorIssued() = 0;
|
||||
}}
|
||||
|
||||
class MonitorAlgorithmCreate {
|
||||
public:
|
||||
virtual String getAlgorithmName() = 0;
|
||||
virtual std::auto_ptr<MonitorAlgorithm> create(
|
||||
PVRecord &pvRecord;
|
||||
MonitorRequester &requester;
|
||||
PVRecordField &pvRecordField;
|
||||
PVStructure &pvStructure);
|
||||
POINTER_DEFINITIONS(MonitorAlgorithm);
|
||||
virtual ~MonitorAlgorithm(){}
|
||||
virtual epics::pvData::String getAlgorithmName(){return algorithmName;}
|
||||
virtual bool causeMonitor() = 0;
|
||||
virtual void monitorIssued() = 0;
|
||||
protected:
|
||||
MonitorAlgorithm(epics::pvData::String algorithmName)
|
||||
: algorithmName(algorithmName)
|
||||
{}
|
||||
epics::pvData::String algorithmName;
|
||||
};
|
||||
|
||||
extern MonitorAlgorithmCreate& getAlgorithmDeadband();
|
||||
extern MonitorAlgorithmCreate& getAlgorithmOnChange();
|
||||
class MonitorAlgorithmCreate
|
||||
{
|
||||
public:
|
||||
POINTER_DEFINITIONS(MonitorAlgorithmCreate);
|
||||
virtual ~MonitorAlgorithmCreate(){}
|
||||
virtual epics::pvData::String getAlgorithmName(){return algorithmName;}
|
||||
virtual MonitorAlgorithmPtr create(
|
||||
PVRecordPtr const &pvRecord,
|
||||
epics::pvData::MonitorRequester::shared_pointer const &requester,
|
||||
PVRecordFieldPtr const &fromPVRecord,
|
||||
epics::pvData::PVStructurePtr const &pvOptions) = 0;
|
||||
protected:
|
||||
MonitorAlgorithmCreate(epics::pvData::String algorithmName)
|
||||
: algorithmName(algorithmName)
|
||||
{}
|
||||
epics::pvData::String algorithmName;
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif /* MONITORALGORITHM_H */
|
||||
|
541
src/pvAccess/monitorFactory.cpp
Normal file
541
src/pvAccess/monitorFactory.cpp
Normal file
@ -0,0 +1,541 @@
|
||||
/* monitorFactory.cpp */
|
||||
/**
|
||||
* Copyright - See the COPYRIGHT that is included with this distribution.
|
||||
* EPICS pvData is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
*/
|
||||
/**
|
||||
* @author Marty Kraimer
|
||||
* @date 2013.04
|
||||
*/
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include <pv/channelProviderLocal.h>
|
||||
#include <pv/channelProviderLocal.h>
|
||||
#include <pv/bitSetUtil.h>
|
||||
#include <pv/queue.h>
|
||||
|
||||
namespace epics { namespace pvDatabase {
|
||||
using namespace epics::pvData;
|
||||
using namespace epics::pvAccess;
|
||||
using std::tr1::static_pointer_cast;
|
||||
using std::tr1::dynamic_pointer_cast;
|
||||
|
||||
static MonitorAlgorithmCreatePtr nullMonitorAlgorithmCreate;
|
||||
static MonitorPtr nullMonitor;
|
||||
static MonitorElementPtr NULLMonitorElement;
|
||||
|
||||
static ConvertPtr convert = getConvert();
|
||||
|
||||
//class MonitorFieldNode;
|
||||
//typedef std::tr1::shared_ptr<MonitorFieldNode> MonitorFieldNodePtr;
|
||||
|
||||
class MonitorQueue;
|
||||
typedef std::tr1::shared_ptr<MonitorQueue> MonitorQueuePtr;
|
||||
class NOQueue;
|
||||
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:
|
||||
// MonitorAlgorithmPtr monitorAlgorithm;
|
||||
// size_t bitOffset; // pv pvCopy
|
||||
//};
|
||||
|
||||
class MonitorQueue :
|
||||
public std::tr1::enable_shared_from_this<MonitorQueue>
|
||||
{
|
||||
public:
|
||||
POINTER_DEFINITIONS(MonitorQueue);
|
||||
virtual ~MonitorQueue(){}
|
||||
virtual Status start() = 0;
|
||||
virtual void stop() = 0;
|
||||
virtual bool dataChanged() = 0;
|
||||
virtual MonitorElementPtr poll() = 0;
|
||||
virtual void release(MonitorElementPtr const &monitorElement) = 0;
|
||||
protected:
|
||||
MonitorQueuePtr getPtrSelf()
|
||||
{
|
||||
return shared_from_this();
|
||||
}
|
||||
};
|
||||
|
||||
class NOQueue :
|
||||
public MonitorQueue
|
||||
{
|
||||
public:
|
||||
POINTER_DEFINITIONS(NOQueue);
|
||||
virtual ~NOQueue(){}
|
||||
NOQueue(
|
||||
MonitorLocalPtr const &monitorLocal);
|
||||
|
||||
virtual Status start();
|
||||
virtual void stop();
|
||||
virtual bool dataChanged();
|
||||
virtual MonitorElementPtr poll();
|
||||
virtual void release(MonitorElementPtr const &monitorElement);
|
||||
private:
|
||||
MonitorLocalPtr monitorLocal;
|
||||
PVStructurePtr pvCopyStructure;
|
||||
MonitorElementPtr monitorElement;
|
||||
bool gotMonitor;
|
||||
bool wasReleased;
|
||||
BitSetPtr changedBitSet;
|
||||
BitSetPtr overrunBitSet;
|
||||
Mutex mutex;
|
||||
};
|
||||
|
||||
class RealQueue :
|
||||
public MonitorQueue
|
||||
{
|
||||
public:
|
||||
POINTER_DEFINITIONS(RealQueue);
|
||||
virtual ~RealQueue(){}
|
||||
RealQueue(
|
||||
MonitorLocalPtr const &monitorLocal,
|
||||
std::vector<MonitorElementPtr> &monitorElementArray);
|
||||
virtual Status start();
|
||||
virtual void stop();
|
||||
virtual bool dataChanged();
|
||||
virtual MonitorElementPtr poll();
|
||||
virtual void release(MonitorElementPtr const &monitorElement);
|
||||
private:
|
||||
MonitorLocalPtr monitorLocal;
|
||||
Queue<MonitorElement> queue;
|
||||
bool queueIsFull;
|
||||
MonitorElementPtr monitorElement;
|
||||
Mutex mutex;
|
||||
};
|
||||
|
||||
|
||||
class MonitorLocal :
|
||||
public Monitor,
|
||||
public PVCopyMonitorRequester,
|
||||
public std::tr1::enable_shared_from_this<MonitorLocal>
|
||||
{
|
||||
public:
|
||||
POINTER_DEFINITIONS(MonitorLocal);
|
||||
virtual ~MonitorLocal();
|
||||
virtual Status start();
|
||||
virtual Status stop();
|
||||
virtual MonitorElementPtr poll();
|
||||
virtual void destroy();
|
||||
virtual void dataChanged();
|
||||
virtual void unlisten();
|
||||
virtual void release(MonitorElementPtr const & monitorElement);
|
||||
bool init(PVStructurePtr const & pvRequest);
|
||||
MonitorLocal(
|
||||
ChannelProviderLocalPtr const &channelProvider,
|
||||
MonitorRequester::shared_pointer const & channelMonitorRequester,
|
||||
PVRecordPtr const &pvRecord);
|
||||
PVCopyPtr getPVCopy() { return pvCopy;}
|
||||
PVCopyMonitorPtr getPVCopyMonitor() { return pvCopyMonitor;}
|
||||
private:
|
||||
MonitorLocalPtr getPtrSelf()
|
||||
{
|
||||
return shared_from_this();
|
||||
}
|
||||
PVRecordPtr pvRecord;
|
||||
MonitorRequester::shared_pointer monitorRequester;
|
||||
bool isDestroyed;
|
||||
bool firstMonitor;
|
||||
PVCopyPtr pvCopy;
|
||||
MonitorQueuePtr queue;
|
||||
PVCopyMonitorPtr pvCopyMonitor;
|
||||
// std::list<MonitorFieldNodePtr> monitorFieldList;
|
||||
Mutex mutex;
|
||||
};
|
||||
|
||||
MonitorLocal::MonitorLocal(
|
||||
ChannelProviderLocalPtr const &channelProvider,
|
||||
MonitorRequester::shared_pointer const & channelMonitorRequester,
|
||||
PVRecordPtr const &pvRecord)
|
||||
: pvRecord(pvRecord),
|
||||
monitorRequester(channelMonitorRequester),
|
||||
isDestroyed(false),
|
||||
firstMonitor(true)
|
||||
{
|
||||
}
|
||||
|
||||
MonitorLocal::~MonitorLocal()
|
||||
{
|
||||
destroy();
|
||||
}
|
||||
|
||||
void MonitorLocal::destroy()
|
||||
{
|
||||
//std::cout << "MonitorLocal::destroy " << isDestroyed << std::endl;
|
||||
{
|
||||
Lock xx(mutex);
|
||||
if(isDestroyed) return;
|
||||
isDestroyed = true;
|
||||
}
|
||||
stop();
|
||||
// monitorFieldList.clear();
|
||||
pvCopyMonitor.reset();
|
||||
queue.reset();
|
||||
pvCopy.reset();
|
||||
monitorRequester.reset();
|
||||
pvRecord.reset();
|
||||
}
|
||||
|
||||
Status MonitorLocal::start()
|
||||
{
|
||||
//std::cout << "MonitorLocal::start" << std::endl;
|
||||
firstMonitor = true;
|
||||
return queue->start();
|
||||
}
|
||||
|
||||
Status MonitorLocal::stop()
|
||||
{
|
||||
//std::cout << "MonitorLocal::stop" << std::endl;
|
||||
pvCopyMonitor->stopMonitoring();
|
||||
queue->stop();
|
||||
return Status::Ok;
|
||||
}
|
||||
|
||||
MonitorElementPtr MonitorLocal::poll()
|
||||
{
|
||||
//std::cout << "MonitorLocal::poll" << std::endl;
|
||||
return queue->poll();
|
||||
}
|
||||
|
||||
void MonitorLocal::dataChanged()
|
||||
{
|
||||
//std::cout << "MonitorLocal::dataChanged" << std::endl;
|
||||
if(firstMonitor) {
|
||||
queue->dataChanged();
|
||||
firstMonitor = false;
|
||||
monitorRequester->monitorEvent(getPtrSelf());
|
||||
return;
|
||||
}
|
||||
if(queue->dataChanged()) {
|
||||
monitorRequester->monitorEvent(getPtrSelf());
|
||||
}
|
||||
}
|
||||
|
||||
void MonitorLocal::unlisten()
|
||||
{
|
||||
//std::cout << "MonitorLocal::unlisten" << std::endl;
|
||||
monitorRequester->unlisten(getPtrSelf());
|
||||
}
|
||||
|
||||
void MonitorLocal::release(MonitorElementPtr const & monitorElement)
|
||||
{
|
||||
//std::cout << "MonitorLocal::release" << std::endl;
|
||||
queue->release(monitorElement);
|
||||
}
|
||||
|
||||
bool MonitorLocal::init(PVStructurePtr const & pvRequest)
|
||||
{
|
||||
PVFieldPtr pvField;
|
||||
PVStructurePtr pvOptions;
|
||||
size_t queueSize = 2;
|
||||
pvField = pvRequest->getSubField("record._options");
|
||||
if(pvField.get()!=NULL) {
|
||||
pvOptions = static_pointer_cast<PVStructure>(pvField);
|
||||
pvField = pvOptions->getSubField("queueSize");
|
||||
if(pvField.get()!=NULL) {
|
||||
PVStringPtr pvString = pvOptions->getStringField("queueSize");
|
||||
if(pvString.get()!=NULL) {
|
||||
int32 size;
|
||||
std::stringstream ss;
|
||||
ss << pvString->get();
|
||||
ss >> size;
|
||||
queueSize = size;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(queueSize==1) {
|
||||
monitorRequester->message("queueSize can not be 1",errorMessage);
|
||||
return false;
|
||||
}
|
||||
pvField = pvRequest->getSubField("field");
|
||||
if(pvField.get()==NULL) {
|
||||
pvCopy = PVCopy::create(pvRecord,pvRequest,"");
|
||||
if(pvCopy.get()==NULL) {
|
||||
monitorRequester->message("illegal pvRequest",errorMessage);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if(pvField->getField()->getType()!=structure) {
|
||||
monitorRequester->message("illegal pvRequest",errorMessage);
|
||||
return false;
|
||||
}
|
||||
pvCopy = PVCopy::create(pvRecord,pvRequest,"field");
|
||||
if(pvCopy.get()==NULL) {
|
||||
monitorRequester->message("illegal pvRequest",errorMessage);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
pvCopyMonitor = pvCopy->createPVCopyMonitor(getPtrSelf());
|
||||
// MARTY MUST IMPLEMENT periodic
|
||||
if(queueSize==0) {
|
||||
queue = NOQueuePtr(new NOQueue(getPtrSelf()));
|
||||
} else {
|
||||
std::vector<MonitorElementPtr> monitorElementArray;
|
||||
monitorElementArray.reserve(queueSize);
|
||||
for(size_t i=0; i<queueSize; i++) {
|
||||
PVStructurePtr pvStructure = pvCopy->createPVStructure();
|
||||
MonitorElementPtr monitorElement(
|
||||
new MonitorElement(pvStructure));
|
||||
monitorElementArray.push_back(monitorElement);
|
||||
}
|
||||
queue = RealQueuePtr(new RealQueue(getPtrSelf(),monitorElementArray));
|
||||
}
|
||||
// MARTY MUST IMPLEMENT algorithm
|
||||
monitorRequester->monitorConnect(
|
||||
Status::Ok,
|
||||
getPtrSelf(),
|
||||
pvCopy->getStructure());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
MonitorFactory::MonitorFactory()
|
||||
: isDestroyed(false)
|
||||
{
|
||||
}
|
||||
|
||||
MonitorFactory::~MonitorFactory()
|
||||
{
|
||||
}
|
||||
|
||||
void MonitorFactory::destroy()
|
||||
{
|
||||
//std::cout << "MonitorFactory::destroy " << isDestroyed << std::endl;
|
||||
Lock lock(mutex);
|
||||
if(isDestroyed) return;
|
||||
isDestroyed = true;
|
||||
while(true) {
|
||||
std::set<MonitorLocalPtr>::iterator it;
|
||||
it = monitorLocalList.begin();
|
||||
if(it==monitorLocalList.end()) break;
|
||||
monitorLocalList.erase(it);
|
||||
lock.unlock();
|
||||
it->get()->destroy();
|
||||
lock.lock();
|
||||
}
|
||||
}
|
||||
|
||||
MonitorPtr MonitorFactory::createMonitor(
|
||||
PVRecordPtr const & pvRecord,
|
||||
MonitorRequester::shared_pointer const & monitorRequester,
|
||||
PVStructurePtr const & pvRequest)
|
||||
{
|
||||
Lock xx(mutex);
|
||||
if(isDestroyed) {
|
||||
monitorRequester->message("MonitorFactory is destroyed",errorMessage);
|
||||
return nullMonitor;
|
||||
}
|
||||
MonitorLocalPtr monitor(new MonitorLocal(
|
||||
getChannelProviderLocal(),monitorRequester,pvRecord));
|
||||
bool result = monitor->init(pvRequest);
|
||||
if(!result) return nullMonitor;
|
||||
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)
|
||||
{
|
||||
Lock xx(mutex);
|
||||
if(isDestroyed) return;
|
||||
// monitorAlgorithmCreateList.insert(monitorAlgorithmCreate);
|
||||
}
|
||||
|
||||
MonitorAlgorithmCreatePtr MonitorFactory::getMonitorAlgorithmCreate(
|
||||
String algorithmName)
|
||||
{
|
||||
Lock xx(mutex);
|
||||
if(isDestroyed) return nullMonitorAlgorithmCreate;
|
||||
// std::set<MonitorAlgorithmCreatePtr>::iterator iter;
|
||||
// for(iter = monitorAlgorithmCreateList.begin();
|
||||
// iter!= monitorAlgorithmCreateList.end();
|
||||
// ++iter)
|
||||
// {
|
||||
// if((*iter)->getAlgorithmName().compare(algorithmName))
|
||||
// return *iter;
|
||||
// }
|
||||
return nullMonitorAlgorithmCreate;
|
||||
}
|
||||
|
||||
NOQueue::NOQueue(
|
||||
MonitorLocalPtr const &monitorLocal)
|
||||
: monitorLocal(monitorLocal),
|
||||
pvCopyStructure(monitorLocal->getPVCopy()->createPVStructure()),
|
||||
monitorElement(new MonitorElement(pvCopyStructure)),
|
||||
gotMonitor(false),
|
||||
wasReleased(false),
|
||||
changedBitSet(new BitSet(pvCopyStructure->getNumberFields())),
|
||||
overrunBitSet(new BitSet(pvCopyStructure->getNumberFields()))
|
||||
{
|
||||
monitorElement->pvStructurePtr = pvCopyStructure;
|
||||
monitorElement->changedBitSet =
|
||||
BitSetPtr(new BitSet(pvCopyStructure->getNumberFields()));
|
||||
monitorElement->overrunBitSet =
|
||||
BitSetPtr(new BitSet(pvCopyStructure->getNumberFields()));
|
||||
}
|
||||
|
||||
Status NOQueue::start()
|
||||
{
|
||||
Lock xx(mutex);
|
||||
gotMonitor = true;
|
||||
wasReleased = true;
|
||||
changedBitSet->clear();
|
||||
overrunBitSet->clear();
|
||||
monitorLocal->getPVCopyMonitor()->startMonitoring(
|
||||
monitorElement->changedBitSet,
|
||||
monitorElement->overrunBitSet);
|
||||
return Status::Ok;
|
||||
}
|
||||
|
||||
void NOQueue::stop()
|
||||
{
|
||||
}
|
||||
|
||||
bool NOQueue::dataChanged()
|
||||
{
|
||||
Lock xx(mutex);
|
||||
(*changedBitSet) |= (*monitorElement->changedBitSet);
|
||||
(*overrunBitSet) |= (*monitorElement->overrunBitSet);
|
||||
gotMonitor = true;
|
||||
return wasReleased ? true : false;
|
||||
}
|
||||
|
||||
MonitorElementPtr NOQueue::poll()
|
||||
{
|
||||
Lock xx(mutex);
|
||||
if(!gotMonitor) return NULLMonitorElement;
|
||||
BitSetPtr changed = monitorElement->changedBitSet;
|
||||
BitSetPtr overrun = monitorElement->overrunBitSet;
|
||||
(*changed) |= (*changedBitSet);
|
||||
(*overrun) |= (*overrunBitSet);
|
||||
monitorLocal->getPVCopy()->updateCopyFromBitSet(
|
||||
pvCopyStructure, changed,true);
|
||||
BitSetUtil::compress(changed,pvCopyStructure);
|
||||
BitSetUtil::compress(overrun,pvCopyStructure);
|
||||
changedBitSet->clear();
|
||||
overrunBitSet->clear();
|
||||
return monitorElement;
|
||||
}
|
||||
|
||||
void NOQueue::release(MonitorElementPtr const &monitorElement)
|
||||
{
|
||||
Lock xx(mutex);
|
||||
gotMonitor = false;
|
||||
monitorElement->changedBitSet->clear();
|
||||
monitorElement->overrunBitSet->clear();
|
||||
}
|
||||
|
||||
RealQueue::RealQueue(
|
||||
MonitorLocalPtr const &monitorLocal,
|
||||
std::vector<MonitorElementPtr> &monitorElementArray)
|
||||
: monitorLocal(monitorLocal),
|
||||
queue(monitorElementArray),
|
||||
queueIsFull(false)
|
||||
{
|
||||
}
|
||||
|
||||
Status RealQueue::start()
|
||||
{
|
||||
Lock xx(mutex);
|
||||
queue.clear();
|
||||
monitorElement = queue.getFree();
|
||||
monitorElement->changedBitSet->clear();
|
||||
monitorElement->overrunBitSet->clear();
|
||||
monitorLocal->getPVCopyMonitor()->startMonitoring(
|
||||
monitorElement->changedBitSet,
|
||||
monitorElement->overrunBitSet);
|
||||
return Status::Ok;
|
||||
}
|
||||
|
||||
void RealQueue::stop()
|
||||
{
|
||||
}
|
||||
|
||||
bool RealQueue::dataChanged()
|
||||
{
|
||||
Lock xx(mutex);
|
||||
PVStructurePtr pvStructure = monitorElement->pvStructurePtr;
|
||||
monitorLocal->getPVCopy()->updateCopyFromBitSet(
|
||||
pvStructure,monitorElement->changedBitSet,false);
|
||||
MonitorElementPtr newElement = queue.getFree();
|
||||
if(newElement==NULL) {
|
||||
queueIsFull = true;
|
||||
return true;
|
||||
}
|
||||
BitSetUtil::compress(monitorElement->changedBitSet,pvStructure);
|
||||
BitSetUtil::compress(monitorElement->overrunBitSet,pvStructure);
|
||||
convert->copy(pvStructure,newElement->pvStructurePtr);
|
||||
newElement->changedBitSet->clear();
|
||||
newElement->overrunBitSet->clear();
|
||||
monitorLocal->getPVCopyMonitor()->switchBitSets(
|
||||
newElement->changedBitSet,newElement->overrunBitSet,false);
|
||||
queue.setUsed(monitorElement);
|
||||
monitorElement = newElement;
|
||||
return true;
|
||||
}
|
||||
|
||||
MonitorElementPtr RealQueue::poll()
|
||||
{
|
||||
Lock xx(mutex);
|
||||
return queue.getUsed();
|
||||
}
|
||||
|
||||
void RealQueue::release(MonitorElementPtr const ¤tElement)
|
||||
{
|
||||
Lock xx(mutex);
|
||||
queue.releaseUsed(currentElement);
|
||||
currentElement->changedBitSet->clear();
|
||||
currentElement->overrunBitSet->clear();
|
||||
if(!queueIsFull) return;
|
||||
queueIsFull = false;
|
||||
PVStructurePtr pvStructure = monitorElement->pvStructurePtr;
|
||||
MonitorElementPtr newElement = queue.getFree();
|
||||
BitSetUtil::compress(monitorElement->changedBitSet,pvStructure);
|
||||
BitSetUtil::compress(monitorElement->overrunBitSet,pvStructure);
|
||||
convert->copy(pvStructure,newElement->pvStructurePtr);
|
||||
newElement->changedBitSet->clear();
|
||||
newElement->overrunBitSet->clear();
|
||||
monitorLocal->getPVCopyMonitor()->switchBitSets(
|
||||
newElement->changedBitSet,newElement->overrunBitSet,false);
|
||||
queue.setUsed(monitorElement);
|
||||
monitorElement = newElement;
|
||||
|
||||
}
|
||||
|
||||
MonitorFactoryPtr getMonitorFactory()
|
||||
{
|
||||
static MonitorFactoryPtr monitorFactoryPtr;
|
||||
static Mutex mutex;
|
||||
Lock xx(mutex);
|
||||
|
||||
if(monitorFactoryPtr.get()==NULL) {
|
||||
monitorFactoryPtr = MonitorFactoryPtr(
|
||||
new MonitorFactory());
|
||||
}
|
||||
return monitorFactoryPtr;
|
||||
}
|
||||
|
||||
}}
|
@ -5,11 +5,13 @@
|
||||
* in file LICENSE that is included with this distribution.
|
||||
*/
|
||||
/**
|
||||
* @author mrk
|
||||
* @author Marty Kraimer
|
||||
* @date 2013.04
|
||||
*/
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
|
||||
#include <pv/pvCopy.h>
|
||||
|
||||
@ -23,8 +25,8 @@ static PVCopyPtr NULLPVCopy;
|
||||
static FieldConstPtr NULLField;
|
||||
static StructureConstPtr NULLStructure;
|
||||
static PVStructurePtr NULLPVStructure;
|
||||
static CopyNodePtr NULLCopyNodePtr;
|
||||
static CopyRecordNodePtr NULLCopyRecordNodePtr;
|
||||
static CopyNodePtr NULLCopyNode;
|
||||
static CopyRecordNodePtr NULLCopyRecordNode;
|
||||
|
||||
struct CopyNode {
|
||||
CopyNode()
|
||||
@ -48,10 +50,6 @@ typedef std::vector<CopyNodePtr> CopyNodePtrArray;
|
||||
typedef std::tr1::shared_ptr<CopyNodePtrArray> CopyNodePtrArrayPtr;
|
||||
|
||||
struct CopyStructureNode : public CopyNode {
|
||||
// CopyStructureNode(size_t numNodes)
|
||||
// : nodes(CopyNodePtrArrayPtr(new CopyNodePtrArray(numNodes)))
|
||||
// {
|
||||
// }
|
||||
CopyNodePtrArrayPtr nodes;
|
||||
};
|
||||
|
||||
@ -92,7 +90,11 @@ StructureConstPtr PVCopy::getStructure()
|
||||
|
||||
PVStructurePtr PVCopy::createPVStructure()
|
||||
{
|
||||
if(cacheInitStructure.get()!=NULL) return cacheInitStructure;
|
||||
if(cacheInitStructure.get()!=NULL) {
|
||||
PVStructurePtr save = cacheInitStructure;
|
||||
cacheInitStructure.reset();
|
||||
return save;
|
||||
}
|
||||
PVStructurePtr pvStructure =
|
||||
getPVDataCreate()->createPVStructure(structure);
|
||||
return pvStructure;
|
||||
@ -279,12 +281,51 @@ void PVCopy::updateRecord(
|
||||
PVCopyMonitorPtr PVCopy::createPVCopyMonitor(
|
||||
PVCopyMonitorRequesterPtr const &pvCopyMonitorRequester)
|
||||
{
|
||||
throw std::logic_error(String("Not Implemented"));
|
||||
PVCopyMonitorPtr pvCopyMonitor( new PVCopyMonitor(
|
||||
pvRecord,headNode,getPtrSelf(),pvCopyMonitorRequester));
|
||||
return pvCopyMonitor;
|
||||
}
|
||||
|
||||
epics::pvData::String PVCopy::dump()
|
||||
{
|
||||
throw std::logic_error(String("Not Implemented"));
|
||||
String builder;
|
||||
dump(&builder,headNode,0);
|
||||
return builder;
|
||||
}
|
||||
|
||||
void PVCopy::dump(String *builder,CopyNodePtr const &node,int indentLevel)
|
||||
{
|
||||
getConvert()->newLine(builder,indentLevel);
|
||||
std::stringstream ss;
|
||||
ss << (node->isStructure ? "structureNode" : "recordNode");
|
||||
ss << " structureOffset " << node->structureOffset;
|
||||
ss << " nfields " << node->nfields;
|
||||
*builder += ss.str();
|
||||
PVStructurePtr options = node->options;
|
||||
if(options.get()!=NULL) {
|
||||
getConvert()->newLine(builder,indentLevel +1);
|
||||
options->toString(builder);
|
||||
getConvert()->newLine(builder,indentLevel);
|
||||
}
|
||||
if(!node->isStructure) {
|
||||
CopyRecordNodePtr recordNode = static_pointer_cast<CopyRecordNode>(node);
|
||||
String name = recordNode->recordPVField->getFullName();
|
||||
*builder += " recordField " + name;
|
||||
return;
|
||||
}
|
||||
CopyStructureNodePtr structureNode =
|
||||
static_pointer_cast<CopyStructureNode>(node);
|
||||
CopyNodePtrArrayPtr nodes = structureNode->nodes;
|
||||
for(size_t i=0; i<nodes->size(); ++i) {
|
||||
if((*nodes)[i].get()==NULL) {
|
||||
getConvert()->newLine(builder,indentLevel +1);
|
||||
ss.str("");
|
||||
ss << "node[" << i << "] is null";
|
||||
*builder += ss.str();
|
||||
continue;
|
||||
}
|
||||
dump(builder,(*nodes)[i],indentLevel+1);
|
||||
}
|
||||
}
|
||||
|
||||
bool PVCopy::init(epics::pvData::PVStructurePtr const &pvRequest)
|
||||
@ -589,7 +630,7 @@ CopyNodePtr PVCopy::createStructureNodes(
|
||||
nameFromRecord = getFullName(pvFromRequest,nameFromRecord);
|
||||
PVFieldPtr pvField = pvRecordStructure->
|
||||
getPVStructure()->getSubField(nameFromRecord);
|
||||
if(pvField.get()==NULL) return NULLCopyNodePtr;
|
||||
if(pvField.get()==NULL) return NULLCopyNode;
|
||||
PVRecordFieldPtr pvRecordField = pvRecordStructure->
|
||||
getPVRecord()->findPVRecordField(pvField);
|
||||
size_t structureOffset = pvFromField->getFieldOffset();
|
||||
@ -650,7 +691,7 @@ CopyNodePtr PVCopy::createStructureNodes(
|
||||
++indFromStructure;
|
||||
}
|
||||
size_t len = nodes->size();
|
||||
if(len==String::npos) return NULLCopyNodePtr;
|
||||
if(len==String::npos) return NULLCopyNode;
|
||||
CopyStructureNodePtr structureNode(new CopyStructureNode());
|
||||
structureNode->isStructure = true;
|
||||
structureNode->nodes = nodes;
|
||||
@ -915,7 +956,7 @@ CopyRecordNodePtr PVCopy::getCopyOffset(
|
||||
if(recordNode.get()!=NULL) return recordNode;
|
||||
}
|
||||
}
|
||||
return NULLCopyRecordNodePtr;
|
||||
return NULLCopyRecordNode;
|
||||
}
|
||||
|
||||
CopyRecordNodePtr PVCopy::getRecordNode(
|
||||
@ -935,37 +976,163 @@ CopyRecordNodePtr PVCopy::getRecordNode(
|
||||
static_pointer_cast<CopyStructureNode>(node);
|
||||
return getRecordNode(subNode,structureOffset);
|
||||
}
|
||||
return NULLCopyRecordNodePtr;
|
||||
return NULLCopyRecordNode;
|
||||
}
|
||||
|
||||
|
||||
PVCopyMonitor::PVCopyMonitor()
|
||||
PVCopyMonitor::PVCopyMonitor(
|
||||
PVRecordPtr const &pvRecord,
|
||||
CopyNodePtr const &headNode,
|
||||
PVCopyPtr const &pvCopy,
|
||||
PVCopyMonitorRequesterPtr const &pvCopyMonitorRequester
|
||||
)
|
||||
: pvRecord(pvRecord),
|
||||
headNode(headNode),
|
||||
pvCopy(pvCopy),
|
||||
pvCopyMonitorRequester(pvCopyMonitorRequester),
|
||||
isGroupPut(false),
|
||||
dataChanged(false)
|
||||
{
|
||||
throw std::logic_error(String("Not Implemented"));
|
||||
}
|
||||
|
||||
PVCopyMonitor::~PVCopyMonitor()
|
||||
{
|
||||
throw std::logic_error(String("Not Implemented"));
|
||||
pvRecord.reset();
|
||||
headNode.reset();
|
||||
pvCopy.reset();
|
||||
pvCopyMonitorRequester.reset();
|
||||
changeBitSet.reset();
|
||||
overrunBitSet.reset();
|
||||
}
|
||||
|
||||
void PVCopyMonitor::startMonitoring(
|
||||
BitSetPtr const &changeBitSet,
|
||||
BitSetPtr const &overrunBitSet)
|
||||
{
|
||||
throw std::logic_error(String("Not Implemented"));
|
||||
this->changeBitSet = changeBitSet;
|
||||
this->overrunBitSet = overrunBitSet;
|
||||
isGroupPut = false;
|
||||
pvRecord->addListener(getPtrSelf());
|
||||
addListener(headNode);
|
||||
pvRecord->lock();
|
||||
try {
|
||||
changeBitSet->clear();
|
||||
overrunBitSet->clear();
|
||||
changeBitSet->set(0);
|
||||
pvCopyMonitorRequester->dataChanged();
|
||||
pvRecord->unlock();
|
||||
} catch(...) {
|
||||
pvRecord->unlock();
|
||||
}
|
||||
}
|
||||
|
||||
void PVCopyMonitor::stopMonitoring()
|
||||
{
|
||||
throw std::logic_error(String("Not Implemented"));
|
||||
pvRecord->removeListener(getPtrSelf());
|
||||
}
|
||||
|
||||
void PVCopyMonitor::switchBitSets(
|
||||
BitSetPtr const &newChangeBitSet,
|
||||
BitSetPtr const &newOverrunBitSet, bool lockRecord)
|
||||
BitSetPtr const &newOverrunBitSet,
|
||||
bool lockRecord)
|
||||
{
|
||||
throw std::logic_error(String("Not Implemented"));
|
||||
if(lockRecord) pvRecord->lock();
|
||||
try {
|
||||
changeBitSet = newChangeBitSet;
|
||||
overrunBitSet = newOverrunBitSet;
|
||||
if(lockRecord) pvRecord->unlock();
|
||||
} catch(...) {
|
||||
if(lockRecord) pvRecord->unlock();
|
||||
}
|
||||
}
|
||||
|
||||
void PVCopyMonitor::detach(PVRecordPtr const & pvRecord)
|
||||
{
|
||||
}
|
||||
|
||||
void PVCopyMonitor::dataPut(PVRecordFieldPtr const & pvRecordField)
|
||||
{
|
||||
CopyNodePtr node = findNode(headNode,pvRecordField);
|
||||
if(node.get()==NULL) {
|
||||
throw std::logic_error("Logic error");
|
||||
}
|
||||
size_t offset = node->structureOffset;
|
||||
bool isSet = changeBitSet->get(offset);
|
||||
changeBitSet->set(offset);
|
||||
if(isSet) overrunBitSet->set(offset);
|
||||
if(!isGroupPut) pvCopyMonitorRequester->dataChanged();
|
||||
dataChanged = true;
|
||||
}
|
||||
|
||||
void PVCopyMonitor::dataPut(
|
||||
PVRecordStructurePtr const & requested,
|
||||
PVRecordFieldPtr const & pvRecordField)
|
||||
{
|
||||
CopyNodePtr node = findNode(headNode,requested);
|
||||
if(node.get()==NULL || node->isStructure) {
|
||||
throw std::logic_error("Logic error");
|
||||
}
|
||||
CopyRecordNodePtr recordNode = static_pointer_cast<CopyRecordNode>(node);
|
||||
size_t offset = recordNode->structureOffset
|
||||
+ (pvRecordField->getPVField()->getFieldOffset()
|
||||
- recordNode->recordPVField->getPVField()->getFieldOffset());
|
||||
bool isSet = changeBitSet->get(offset);
|
||||
changeBitSet->set(offset);
|
||||
if(isSet) overrunBitSet->set(offset);
|
||||
if(!isGroupPut) pvCopyMonitorRequester->dataChanged();
|
||||
dataChanged = true;
|
||||
}
|
||||
|
||||
void PVCopyMonitor::beginGroupPut(PVRecordPtr const & pvRecord)
|
||||
{
|
||||
isGroupPut = true;
|
||||
dataChanged = false;
|
||||
}
|
||||
|
||||
void PVCopyMonitor::endGroupPut(PVRecordPtr const & pvRecord)
|
||||
{
|
||||
isGroupPut = false;
|
||||
if(dataChanged) {
|
||||
dataChanged = false;
|
||||
pvCopyMonitorRequester->dataChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void PVCopyMonitor::unlisten(PVRecordPtr const & pvRecord)
|
||||
{
|
||||
pvCopyMonitorRequester->unlisten();
|
||||
}
|
||||
|
||||
|
||||
void PVCopyMonitor::addListener(CopyNodePtr const & node)
|
||||
{
|
||||
if(!node->isStructure) {
|
||||
PVRecordFieldPtr pvRecordField =
|
||||
pvCopy->getRecordPVField(node->structureOffset);
|
||||
pvRecordField->addListener(getPtrSelf());
|
||||
return;
|
||||
}
|
||||
CopyStructureNodePtr structureNode =
|
||||
static_pointer_cast<CopyStructureNode>(node);
|
||||
for(size_t i=0; i< structureNode->nodes->size(); i++) {
|
||||
addListener((*structureNode->nodes)[i]);
|
||||
}
|
||||
}
|
||||
|
||||
CopyNodePtr PVCopyMonitor::findNode(
|
||||
CopyNodePtr const & node,
|
||||
PVRecordFieldPtr const & pvRecordField)
|
||||
{
|
||||
if(!node->isStructure) {
|
||||
CopyRecordNodePtr recordNode = static_pointer_cast<CopyRecordNode>(node);
|
||||
if(recordNode->recordPVField==pvRecordField) return node;
|
||||
return NULLCopyNode;
|
||||
}
|
||||
CopyStructureNodePtr structureNode = static_pointer_cast<CopyStructureNode>(node);
|
||||
for(size_t i=0; i<structureNode->nodes->size(); i++) {
|
||||
CopyNodePtr xxx = findNode((*structureNode->nodes)[i],pvRecordField);
|
||||
if(xxx.get()!=NULL) return xxx;
|
||||
}
|
||||
return NULLCopyNode;
|
||||
}
|
||||
|
||||
}}
|
||||
|
@ -5,8 +5,8 @@
|
||||
* in file LICENSE that is included with this distribution.
|
||||
*/
|
||||
/**
|
||||
* @author mrk
|
||||
* @date 2013.03.25
|
||||
* @author Marty Kraimer
|
||||
* @date 2013.04
|
||||
*/
|
||||
#ifndef PVCOPY_H
|
||||
#define PVCOPY_H
|
||||
@ -81,6 +81,10 @@ public:
|
||||
epics::pvData::PVStructurePtr const ©PVStructure,std::size_t fieldOffset);
|
||||
epics::pvData::String dump();
|
||||
private:
|
||||
void dump(
|
||||
epics::pvData::String *builder,
|
||||
CopyNodePtr const &node,
|
||||
int indentLevel);
|
||||
PVCopyPtr getPtrSelf()
|
||||
{
|
||||
return shared_from_this();
|
||||
@ -92,6 +96,7 @@ private:
|
||||
epics::pvData::PVStructurePtr cacheInitStructure;
|
||||
private:
|
||||
PVCopy(PVRecordPtr const &pvRecord);
|
||||
friend class PVCopyMonitor;
|
||||
bool init(epics::pvData::PVStructurePtr const &pvRequest);
|
||||
epics::pvData::String dump(
|
||||
epics::pvData::String const &value,
|
||||
@ -155,6 +160,7 @@ private:
|
||||
};
|
||||
|
||||
class PVCopyMonitor :
|
||||
public PVListener,
|
||||
public std::tr1::enable_shared_from_this<PVCopyMonitor>
|
||||
{
|
||||
public:
|
||||
@ -167,28 +173,46 @@ public:
|
||||
void switchBitSets(
|
||||
epics::pvData::BitSetPtr const &newChangeBitSet,
|
||||
epics::pvData::BitSetPtr const &newOverrunBitSet, bool lockRecord);
|
||||
// following are PVListener methods
|
||||
virtual void detach(PVRecordPtr const & pvRecord);
|
||||
virtual void dataPut(PVRecordFieldPtr const & pvRecordField);
|
||||
virtual void dataPut(
|
||||
PVRecordStructurePtr const & requested,
|
||||
PVRecordFieldPtr const & pvRecordField);
|
||||
virtual void beginGroupPut(PVRecordPtr const & pvRecord);
|
||||
virtual void endGroupPut(PVRecordPtr const & pvRecord);
|
||||
virtual void unlisten(PVRecordPtr const & pvRecord);
|
||||
private:
|
||||
void addListener(CopyNodePtr const & node);
|
||||
CopyNodePtr findNode(
|
||||
CopyNodePtr const & node,
|
||||
PVRecordFieldPtr const & pvRecordField);
|
||||
PVCopyMonitorPtr getPtrSelf()
|
||||
{
|
||||
return shared_from_this();
|
||||
}
|
||||
PVCopyMonitor();
|
||||
PVCopyMonitor(
|
||||
PVRecordPtr const &pvRecord,
|
||||
CopyNodePtr const &headNode,
|
||||
PVCopyPtr const &pvCopy,
|
||||
PVCopyMonitorRequesterPtr const &pvCopyMonitorRequester);
|
||||
friend class PVCopy;
|
||||
// TBD
|
||||
PVRecordPtr pvRecord;
|
||||
CopyNodePtr headNode;
|
||||
PVCopyPtr pvCopy;
|
||||
PVCopyMonitorRequesterPtr pvCopyMonitorRequester;
|
||||
epics::pvData::BitSetPtr changeBitSet;
|
||||
epics::pvData::BitSetPtr overrunBitSet;
|
||||
bool isGroupPut;
|
||||
bool dataChanged;
|
||||
};
|
||||
|
||||
class PVCopyMonitorRequester :
|
||||
public std::tr1::enable_shared_from_this<PVCopyMonitorRequester>
|
||||
class PVCopyMonitorRequester
|
||||
{
|
||||
public:
|
||||
POINTER_DEFINITIONS(PVCopyMonitorRequester);
|
||||
virtual void dataChanged() = 0;
|
||||
virtual void unlisten() = 0;
|
||||
private:
|
||||
PVCopyMonitorRequesterPtr getPtrSelf()
|
||||
{
|
||||
return shared_from_this();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
@ -5,7 +5,8 @@
|
||||
* in file LICENSE that is included with this distribution.
|
||||
*/
|
||||
/**
|
||||
* @author mrk
|
||||
* @author Marty Kraimer
|
||||
* @date 2013.04
|
||||
*/
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
@ -18,7 +19,7 @@
|
||||
#include <pv/support.h>
|
||||
#include <pv/pvCopy.h>
|
||||
|
||||
namespace epics { namespace pvIOC {
|
||||
namespace epics { namespace pvDatabase {
|
||||
|
||||
using namespace epics::pvData;
|
||||
|
||||
|
@ -5,7 +5,8 @@
|
||||
* in file LICENSE that is included with this distribution.
|
||||
*/
|
||||
/**
|
||||
* @author mrk
|
||||
* @author Marty Kraimer
|
||||
* @date 2013.04
|
||||
*/
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
@ -18,7 +19,7 @@
|
||||
#include <pv/support.h>
|
||||
#include <pv/pvCopy.h>
|
||||
|
||||
namespace epics { namespace pvIOC {
|
||||
namespace epics { namespace pvDatabase {
|
||||
|
||||
using namespace epics::pvData;
|
||||
|
||||
|
@ -32,7 +32,7 @@ using namespace epics::pvDatabase;
|
||||
int main(int argc,char *argv[])
|
||||
{
|
||||
PVDatabasePtr master = PVDatabase::getMaster();
|
||||
ChannelProviderLocalPtr channelProvider = ChannelProviderLocal::create();
|
||||
ChannelProviderLocalPtr channelProvider = getChannelProviderLocal();
|
||||
String recordName("exampleCounter");
|
||||
PVRecordPtr pvRecord = ExampleCounter::create(recordName);
|
||||
bool result = master->addRecord(pvRecord);
|
||||
|
@ -61,7 +61,7 @@ static PVStructurePtr createPowerSupply()
|
||||
int main(int argc,char *argv[])
|
||||
{
|
||||
PVDatabasePtr master = PVDatabase::getMaster();
|
||||
ChannelProviderLocalPtr channelProvider = ChannelProviderLocal::create();
|
||||
ChannelProviderLocalPtr channelProvider = getChannelProviderLocal();
|
||||
StandardPVFieldPtr standardPVField = getStandardPVField();
|
||||
String properties;
|
||||
ScalarType scalarType;
|
||||
|
Reference in New Issue
Block a user