forget to add this
This commit is contained in:
892
documentation/pvDatabaseCPP_20121211.html
Normal file
892
documentation/pvDatabaseCPP_20121211.html
Normal file
@ -0,0 +1,892 @@
|
||||
<?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, 11-Dec-2012</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_20121211.html">pvDatabaseCPP20121211.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_20121127.html">pvDatabaseCPP_20121127.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 must be extended in order to create record instances.
|
||||
The minimum that an extenson must provide is a top level PVStructure and a process method
|
||||
but the framework provides for complex extensions.</p>
|
||||
|
||||
<p>EPICS version 4 is a set of related products in the EPICS
|
||||
V4 control system programming environment:</p>
|
||||
<dl>
|
||||
<dt><a
|
||||
href="http://epics-pvdata.hg.sourceforge.net/hgweb/epics-pvdata/pvDataJava/raw-file/tip/documentation/pvDataJava.html">pvData</a></dt>
|
||||
<dd>pvData (Process Variable Data) defines and implements an efficent way
|
||||
to store, access, and communicate memory resident structured data</dd>
|
||||
<dt><a
|
||||
href="http://epics-pvdata.hg.sourceforge.net/hgweb/epics-pvdata/pvAccessJava/raw-file/tip/documentation/pvAccessJava.html">pvAccess</a></dt>
|
||||
<dd>pvAccess is a software library for high speed controls network communications,
|
||||
optimized for pvData</dd>
|
||||
<dt><a
|
||||
href="http://epics-pvdata.hg.sourceforge.net/hgweb/epics-pvdata/pvIOCJava/raw-file/tip/documentation/pvIOCJava.html">pvIOC</a></dt>
|
||||
<dd>pvIOC is a software framework for building network accessable "smart" real time
|
||||
databases, suitable for interfacing devices in a distributed control system,
|
||||
that can exchange pvData over pvAccess.
|
||||
</dd>
|
||||
<dt><a
|
||||
href="http://epics-pvdata.hg.sourceforge.net/hgweb/epics-pvdata/pvServiceJava/raw-file/tip/documentation/pvAccessJava.html">pvService</a></dt>
|
||||
<dd>A middle layer for implementing data services.</dd>
|
||||
</dl>
|
||||
|
||||
<p>Each of these products has a Java and a C++ implementation.</p>
|
||||
|
||||
<h2 class="nocount">Status of this Document</h2>
|
||||
|
||||
<p>This is the 11-Dec-2012 version of the definition of pvDatabaseCPP.
|
||||
</p>
|
||||
<p>This is the beginning of the implementation of pvDataBaseCPP.
|
||||
It describes the features that will be provided.
|
||||
The class definitions for PVRecord are implemented.
|
||||
The class definition for PVDatabase are defined but not implemented.</p>
|
||||
|
||||
|
||||
<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>This document descibes a C++ implementation of some of the components in pvIOCJava.
|
||||
It extracts the core components required to create a network accessible database of smart
|
||||
memory resident records.
|
||||
pvDatabaseCPP does not and will not implement any of the specialized support that pvIOCJava
|
||||
provides. Instead other projects will implement the specialized support.
|
||||
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>A brief description of a pvDatase is that it is a network accessible set of 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.
|
||||
This local provider is accessed by the remote pvAccess server.
|
||||
A record is smart because code can be attached to a record.</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>localChannelProvider</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><b>database</b> does not itself implement pvRecord instances.
|
||||
Instead it provides a base classes that make it easy to create record instances.
|
||||
What does have to be implemented is a top
|
||||
level PVStructure and the following two methods:</p>
|
||||
<dl>
|
||||
<dt>process</dt>
|
||||
<dd>This is what makes a record <b>smart</b>.
|
||||
What process does is up to the implementation except that it must decide if
|
||||
it's execution model is synchronous or asynchronous.
|
||||
Synchronous means that when process returns the processing is complete.
|
||||
Asynchronous means that when process returns the processing is <b>not</b> complete.
|
||||
Instead process invokes other threads that will complete the processing at a later time.</dd>
|
||||
<dt>isSynchronous</dt>
|
||||
<dd>Which execution model is being implemented.</dd>
|
||||
</dl>
|
||||
<h3>Example PVRecord Extension</h3>
|
||||
<p>Directory <b>example/record</b> has an example PVRecord implementation.
|
||||
It implements a counter.
|
||||
The top level structure is:</p>
|
||||
<pre>
|
||||
structure
|
||||
long value
|
||||
</pre>
|
||||
<p><b>NOTE:</b> The example compiles but does not build because nothing
|
||||
is implemented.</p>
|
||||
|
||||
<h4>exampleRecord.h</h4>
|
||||
<p>This is the class description.
|
||||
The example extends PVRecord.</p>
|
||||
<pre>
|
||||
class ExampleRecord :
|
||||
public virtual PVRecord
|
||||
{
|
||||
public:
|
||||
POINTER_DEFINITIONS(ExampleRecord);
|
||||
static PVRecordPtr create(epics::pvData::String const & recordName);
|
||||
virtual ~ExampleRecord();
|
||||
virtual bool isSynchronous();
|
||||
virtual void process(
|
||||
epics::pvDatabase::RecordProcessRequesterPtr const &processRequester);
|
||||
private:
|
||||
ExampleRecord(epics::pvData::String const & recordName,
|
||||
epics::pvData::PVStructurePtr const & pvStructure,
|
||||
epics::pvData::PVLongPtr const &pvValue);
|
||||
epics::pvData::PVLongPtr pvValue;
|
||||
};
|
||||
</pre>
|
||||
<p>where</p>
|
||||
<dl>
|
||||
<dt>create<dt>
|
||||
<dd>This is example specific. See the implemention for details.</dd>
|
||||
<dt>~ExampleRecord<dt>
|
||||
<dd>The destructor must be declared virtual.</dd>
|
||||
<dt>isSynchronous<dt>
|
||||
<dd>The implementation must say if process is synchronous or asynchronous.</dd>
|
||||
<dt>process<dt>
|
||||
<dd><b>The</b> implementation.</dd>
|
||||
<dt>ExampleRecord<dt>
|
||||
<dd>For the example this is private.</dd>
|
||||
<dl>
|
||||
|
||||
<h4>exampleRecord.cpp</h4>
|
||||
<p>This is the class implementation.</p>
|
||||
<pre>
|
||||
ExampleRecord::~ExampleRecord(){}
|
||||
|
||||
PVRecordPtr ExampleRecord::create(String const & recordName)
|
||||
{
|
||||
String properties;
|
||||
PVStructurePtr pvStructure = getStandardPVField()->scalar(pvLong,properties);
|
||||
PVLongPtr pvValue = pvStructure->getLongField("value");
|
||||
PVRecordPtr pvRecord(new ExampleRecord(recordName,pvStructure,pvValue));
|
||||
return pvRecord;
|
||||
}
|
||||
|
||||
ExampleRecord::ExampleRecord(
|
||||
String const & recordName,
|
||||
PVStructurePtr const & pvStructure,
|
||||
PVLongPtr const &pvValue)
|
||||
: PVRecord(recordName,pvStructure),
|
||||
pvValue(pvValue)
|
||||
{}
|
||||
|
||||
bool ExampleRecord::isSynchronous() {return true;}
|
||||
|
||||
void ExampleRecord::process(
|
||||
RecordProcessRequesterPtr const &processRequester,bool alreadyLocked)
|
||||
{
|
||||
if(!alreadyLocked) lock();
|
||||
pvValue->put(pvValue->get() + 1);
|
||||
processRequester->recordProcessResult(Status::Ok);
|
||||
unlock();
|
||||
processRequester->recordProcessComplete();
|
||||
dequeueProcessRequest(processRequester);
|
||||
}
|
||||
</pre>
|
||||
<p>where</p>
|
||||
<dl>
|
||||
<dt>create<dt>
|
||||
<dd>Creates a PVStructure with a single subfield named value.
|
||||
It gets the interface to the value field.
|
||||
It then creates an ExampleRecord and returns it.
|
||||
</dd>
|
||||
<dt>~ExampleRecord<dt>
|
||||
<dd>Does not have to do anything because of shared pointers.</dd>
|
||||
<dt>ExampleRecord<dt>
|
||||
<dd>Calls the base class constructor and sets pvValue.</dd>
|
||||
<dt>isSynchronous<dt>
|
||||
<dd>The example is synchronous.</dd>
|
||||
<dt>process<dt>
|
||||
<dd>Gets the curent value, increments it, and puts the new value.
|
||||
It than calls two processRequester callbacks.</dd>
|
||||
<dl>
|
||||
|
||||
<h4>exampleRecordMain.cpp</h4>
|
||||
<p>This is a main for creating and running the example.</p>
|
||||
<pre>
|
||||
int main(int argc,char *argv[])
|
||||
{
|
||||
String recordName("exampleRecord");
|
||||
PVRecordPtr pvRecord = ExampleRecord::create(recordName);
|
||||
PVDatabasePtr pvDatabase = PVDatabase::getMaster();
|
||||
pvDatabase->addRecord(pvRecord);
|
||||
cout << recordName << "\n";
|
||||
string str;
|
||||
while(true) {
|
||||
cout << "Type exit to stop: \n";
|
||||
getline(cin,str);
|
||||
if(str.compare("exit")==0) break;
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
</pre>
|
||||
<p>The main program creates an example record and adds it to the database.
|
||||
It then runs until the process is stopped by typing <b>exit</b>.
|
||||
<p>Until the process is stopped,
|
||||
pvAccess clients can put and get the value field.
|
||||
For example</p>
|
||||
<pre>
|
||||
pvget exampleRecord
|
||||
pvput exampleRecord 5
|
||||
</pre>
|
||||
<p>Will both work.</p>
|
||||
<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>These two features will be the first phase.
|
||||
But only synchronous record processing will be supported.</dd>
|
||||
</dl>
|
||||
<p>Future phases of pvDatabaseCPP should include:</p>
|
||||
<dl>
|
||||
<dt>Install</dt>
|
||||
<dd>This provides on-line add and delete.</dd>
|
||||
<dt>Field support</dt>
|
||||
<dd>Add ability to optionally add support to fields.
|
||||
In addition some of the basic support defined in pvIOCJava will 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>local ChannelProvider</dt>
|
||||
<dd>This is the pvAccess package in pvIOCJava.
|
||||
The localChannelProvider will access data from PVRecords.
|
||||
It will implement all channel methods except channelRPC.</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, provide the following:
|
||||
<dl>
|
||||
<dt>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 provide a first attempt to describe the classes required for the first
|
||||
phase.</p>
|
||||
<p>The last section gives a brief overview of the features provided by pvIOCJava.</p>
|
||||
|
||||
<h2>database</h2>
|
||||
<p>The classes in <b>pvDatabase.h</b> implement 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 <b>wrap</b> 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 the PVRecord::message.</dd>
|
||||
<dt>RecordProcessRequester</dt>
|
||||
<dd>This is implemented by anything that calls PVRecord::queueProcessRequest.</dd>
|
||||
<dt>RecordPutRequester</dt>
|
||||
<dd>This is implemented by anything that calls PVRecord::queuePutRequest.</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;
|
||||
|
||||
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><b>NOTES:</b>
|
||||
<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>
|
||||
</ul>
|
||||
<hr>PVRecord Methods</h4>
|
||||
<pre>
|
||||
class PVRecord
|
||||
public epics::pvData::Requester,
|
||||
public std::tr1::enable_shared_from_this<PVRecord>
|
||||
{
|
||||
public:
|
||||
POINTER_DEFINITIONS(PVRecord);
|
||||
PVRecord(
|
||||
epics::pvData::String const & recordName,
|
||||
epics::pvData::PVStructurePtr const & pvStructure);
|
||||
virtual ~PVRecord();
|
||||
virtual void process(
|
||||
RecordProcessRequesterPtr const &recordProcessRequester,
|
||||
bool alreadyLocked) = 0;
|
||||
virtual bool isSynchronous() = 0;
|
||||
virtual bool requestImmediatePut(epics::pvData::PVFieldPtr const &pvField);
|
||||
virtual void immediatePutDone();
|
||||
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);
|
||||
void lock();
|
||||
void unlock();
|
||||
bool tryLock();
|
||||
void lockOtherRecord(PVRecordPtr const & otherRecord);
|
||||
void addPVRecordClient(PVRecordClientPtr const & pvRecordClient);
|
||||
void removePVRecordClient(PVRecordClientPtr const & pvRecordClient);
|
||||
void detachClients();
|
||||
void beginGroupPut();
|
||||
void endGroupPut();
|
||||
void queueProcessRequest(
|
||||
RecordProcessRequesterPtr const &recordProcessRequester);
|
||||
void dequeueProcessRequest(
|
||||
RecordProcessRequesterPtr const &recordProcessRequester);
|
||||
void queuePutRequest(
|
||||
RecordPutRequesterPtr const &recordPutRequester);
|
||||
void putDone(
|
||||
RecordPutRequesterPtr const &recordPutRequester);
|
||||
virtual epics::pvData::String getRequesterName();
|
||||
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);
|
||||
//init MUST be called after derived class is constructed
|
||||
void init();
|
||||
|
||||
};
|
||||
</pre>
|
||||
<p>The methods are:</h3>
|
||||
<dl>
|
||||
<dt>PVRecord</dt>
|
||||
<dd>The constructor. It requires a recordName and a top level PVStructure.</dd>
|
||||
<dt>~PVRecord</dt>
|
||||
<dd>The destructor which must be virtual. A derived class must also have
|
||||
a virtual destructor.</dd>
|
||||
<dt>process</dt>
|
||||
<dd>Pure virtual method.
|
||||
<p>Derived classes must implement this method.</p>
|
||||
<p>A client <b>must</b> only call this method when
|
||||
<b>RecordProcessRequester::becomeProcessor</b> is called as a result
|
||||
of a <b>queueProcessRequest</b>.
|
||||
A client can either call lock before calling processs
|
||||
or let process lock the record.
|
||||
If a client wants to put data into the record it should lock, put, and then call
|
||||
process.</p>
|
||||
<p>If the record is synchronous, process will return only when all processing
|
||||
is complete. If the record is asynchronous then process arranges for some
|
||||
other thread to do the processing and returns.</p>
|
||||
<p>When processing is done the record calls two client callbacks:</p>
|
||||
<dl>
|
||||
<dt>RecordProcessRequester::recordProcessResult</dt>
|
||||
<dd>This is called with the record still locked.
|
||||
The clients can get data from the record.</dd>
|
||||
<dt>RecordProcessRequester::recordProcessComplete</dt>
|
||||
<dd>This is called with the record unlocked.
|
||||
The client can no longer access the record.</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dt>isSynchronous</dt>
|
||||
<dd>Pure virtual method. Derived classes must implement this method.</dd>
|
||||
<dt>requestImmediatePut</dt>
|
||||
<dd>This is a virtual method.
|
||||
<p> The purpose is to allow the implementation to provide fields
|
||||
that allow a client to abort process.
|
||||
For example a motor record might provide a field <b>stop</b></p>
|
||||
<p>The default always returns <b>false</b>.</p>
|
||||
<p>A record implementation can override the default and return <b>true</b>.
|
||||
In it does requestImmediatePut it returns with the record locked.</p>
|
||||
<p>The client can change the value of the associated field and then call
|
||||
<b>immediatePutDone</b></p>
|
||||
</dd>
|
||||
<dt>immediatePutDone</dt>
|
||||
<dd>This is a virtual method.
|
||||
<p>The default does nothing.</p>
|
||||
<p>Must be called by client as a result of a call to <b>requestImmediatePut</b>
|
||||
that returns <b>true</b>.</p>
|
||||
</dd>
|
||||
<dt>destroy</dt>
|
||||
<dd>This is a virtual method.
|
||||
<p>The default does nothing.</p>
|
||||
</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</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 <b>true</b> then just like <b>lock</b>.
|
||||
If <b>false</b>client 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 <b>must</b> 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>queueProcessRequest</dt>
|
||||
<dd>Queue a process request.</dd>
|
||||
<dt>dequeueProcessRequest</dt>
|
||||
<dd>This <b>must</b> be called by record implementation after it has
|
||||
completed a process request.
|
||||
</dd>
|
||||
<dt>queuePutRequest</dt>
|
||||
<dd>Queue a put request.
|
||||
<p>This is for code that wants to change data in a record without processing.
|
||||
If <b>RecordPutRequester::requestResult</b> is called with result <b>true</b>
|
||||
then the record is locked and the client can make changes.
|
||||
When done the client <b>must</b> call <b>putDone</b></p>
|
||||
</dd>
|
||||
<dt>putDone</dt>
|
||||
<dd>Called by <b>RecordPutRequester</b> after changing values in record.
|
||||
This method unlocks the record</dd>
|
||||
<dt>getRequesterName</dt>
|
||||
<dd>virtual method of <b>Requester</b>
|
||||
</dd>
|
||||
<dt>message</dt>
|
||||
<dd>Can be called by implementation code.
|
||||
The message will be sent to every requester.</dd>
|
||||
<dt>init</dt>
|
||||
<dd>This method <b>must</b> be called by derived class
|
||||
<b>after</b> class is completely constructed.</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();
|
||||
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);
|
||||
};
|
||||
</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>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();
|
||||
PVRecordFieldPtrArrayPtr getPVRecordFields();
|
||||
epics::pvData::PVStructurePtr getPVStructure();
|
||||
virtual void removeListener(PVListenerPtr const & pvListener);
|
||||
virtual void postPut();
|
||||
};
|
||||
</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 RecordProcessRequester</h3>
|
||||
<pre>
|
||||
class RecordProcessRequester :
|
||||
virtual public PVRecordClient,
|
||||
virtual public epics::pvData::Requester
|
||||
{
|
||||
public:
|
||||
POINTER_DEFINITIONS(RecordProcessRequester);
|
||||
virtual ~RecordProcessRequester();
|
||||
virtual void recordDestroyed() = 0;
|
||||
virtual void becomeProcessor() = 0;
|
||||
virtual void recordProcessResult(epics::pvData::Status status) = 0;
|
||||
virtual void recordProcessComplete() = 0;
|
||||
};
|
||||
</pre>
|
||||
<p>where</p>
|
||||
<dl>
|
||||
<dt>~RecordProcessRequester</dt>
|
||||
<dd>The destructor.</dd>
|
||||
<dt>recordDestroyed</dt>
|
||||
<dd>Record is being destroyed.</dd>
|
||||
<dt>becomeProcessor</dt>
|
||||
<dd>Called as a result of queueRequeProcessst. The requester can the call process.</dd>
|
||||
<dt>recordProcessResult</dt>
|
||||
<dd>The results of record processing.
|
||||
This is called with the record locked so that the process requester
|
||||
can access data from the record.</dd>
|
||||
<dt>recordProcessComplete</dt>
|
||||
<dd>Processing is complete.
|
||||
This is called with the record unlocked.
|
||||
If the process requester called process with leaveActive true then the requester
|
||||
must call setInactive.</dd>
|
||||
</dl>
|
||||
<h3>class RecordPutRequester</h3>
|
||||
<pre>
|
||||
class RecordPutRequester :
|
||||
virtual public PVRecordClient
|
||||
{
|
||||
public:
|
||||
POINTER_DEFINITIONS(RecordPutRequester);
|
||||
virtual ~RecordPutRequester();
|
||||
virtual void requestResult(bool result) = 0;
|
||||
};
|
||||
</pre>
|
||||
<p>where</p>
|
||||
<dl>
|
||||
<dt>~RecordPutRequester</dt>
|
||||
<dd>The destructor.</dd>
|
||||
<dt>requestResult</dt>
|
||||
<dd>Result of a call to queuePutRequest. If <b>requestResult</b> is <b>false</b>
|
||||
then the caller can not access the record.
|
||||
If <b>requestResult</b> is <b>true</b>
|
||||
then the record is locked and the caller can get and put data in the record.
|
||||
When done the caller must call <b>PVRecord::putDone</b>, which will unlock the
|
||||
record.
|
||||
</dd>
|
||||
</dl>
|
||||
<h3>class PVDatabase</h3>
|
||||
<pre>
|
||||
class PVDatabase : virtual public epics::pvData::Requester {
|
||||
public:
|
||||
POINTER_DEFINITIONS(PVDatabase);
|
||||
static PVDatabasePtr getMaster();
|
||||
virtual ~PVDatabase();
|
||||
PVRecordPtr findRecord(epics::pvData::String const& recordName);
|
||||
bool addRecord(PVRecordPtr const & record);
|
||||
bool removeRecord(PVRecordPtr const & record);
|
||||
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>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>
|
||||
</dl>
|
||||
<h2>Local Channel Provider</h2>
|
||||
<p>Not yet described.</p>
|
||||
<p>A brief description is that it must implement the following components of pvIOCJava:</p>
|
||||
<dl>
|
||||
<dt>pvCopy</dt>
|
||||
<dt>monitor</dt>
|
||||
<dt>pvAccess</dt>
|
||||
<dd>See the next section for a description</dd>
|
||||
</dl>
|
||||
<h2>Summary of Packages in pvIOCJAVA</h2>
|
||||
<p>The following are the direct sub packages of <b>pvIOCJava/src/org/epics/pvioc</b>:</p>
|
||||
<dl>
|
||||
<dt>pvCopy</dt>
|
||||
<dd>This provides a copy of an arbitrary subset of the fields in a PVRecord.
|
||||
It also provides the ability to detect and report changes to fields.
|
||||
It is required for pvAccess.</dd>
|
||||
<dt>monitor</dt>
|
||||
<dd>This provides the ability to monitor changes to a PVRecord. It is required for pvAccess monitors.</dd>
|
||||
<dt>pvAccess</dt>
|
||||
<dd>The local implementation of Channel Provider and Channel.
|
||||
It is accessed by the remote pvAccess server and can also be accessed by code in the same IOC.</dd>
|
||||
<dt>database</dt>
|
||||
<dd>This defines and implements PVRecord, PVDatabase , and PVListener.
|
||||
It supports the basic feature required the implement a local Channel Provider.</dd>
|
||||
<dt>support</dt>
|
||||
<dd>This provides the ability to optionally attach code to any field of a pvRecord.
|
||||
It and several sub packages provide a set of standard support modules.</dd>
|
||||
<dt>install</dt>
|
||||
<dd>This provides the ability to dynamically initialize and add new PVRecords. It also provides
|
||||
the ability to dynamicall delete PVRecords.</d>
|
||||
<dt>xml</dt>
|
||||
<dd>This provides the ability to configure record instances without writing code.</dd>
|
||||
<dt>util</dt>
|
||||
<dd>This is misnamed since it is code related to scanning.</dd>
|
||||
<dt>pdrv</dt>
|
||||
<dd>This is portDriver, which is a proposed sucessor to the asynManager component of asynDriver.</dd>
|
||||
<dt>swtshell</dt>
|
||||
<dd>This is shell that is can either run under the same process as a JavaIOC or as a remote shell.
|
||||
It is like a version of probe but for pvData/pvAccess.
|
||||
Almost all of it's features work in either local or remote mode.
|
||||
With a little more work all or it's features could work remotely.
|
||||
This should be done and then only remote mode should be supported.
|
||||
It can then be rewritten in a completely different language and using a complely different GUI
|
||||
framework.
|
||||
</dd>
|
||||
<dt>caV3</dt>
|
||||
<dd>This has two components:
|
||||
<dl>
|
||||
<dt>ClientFactory</dt>
|
||||
<dd>This is a small wrapper on top of the caV3 client support implemented by pvAccess.
|
||||
It allows code in the pvIOC to access V3Records via pvAccess.</dd>
|
||||
<dt>ServerFactory</dt>
|
||||
<dd>This is a caV3 server that allows a caV3 client to access a PVRecord.
|
||||
The Java implementation uses CAJ, which does most of the work.
|
||||
For now it will not be discussed in this document.</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dt>v3a</dt>
|
||||
<dd>I do not know what this is.</dd>
|
||||
</dl>
|
||||
<p>In addition there is one class file <b>JavaIOC.java</b>.
|
||||
This is starting a IOC instance.
|
||||
This is not required for pvIOCCPP which is either a main or runs as part of a V3 IOC.</p>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
Reference in New Issue
Block a user