715 lines
28 KiB
HTML
715 lines
28 KiB
HTML
<?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, 27-Nov-2012</h2>
|
|
<dl>
|
|
<dt>Latest version:</dt>
|
|
<dd><a
|
|
href="pvDatabaseCPP.html">pvDatabaseCPP.html</a>
|
|
</dd>
|
|
<dt>This version:</dt>
|
|
<dd><a
|
|
href="pvDatabaseCPP_20121127.html">pvDatabaseCPP_20121127.html</a>
|
|
</dd>
|
|
<dt>Previous version:</dt>
|
|
<dd>None</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:<br />
|
|
<a href="http://epics-pvdata.sourceforge.net/relatedDocumemntsV4.html">relatedDocumentsV4.html</a>
|
|
</p>
|
|
|
|
<h2 class="nocount">Status of this Document</h2>
|
|
|
|
<p>This is the 27-Nov-2012 version of the definition of pvDatabaseCPP.
|
|
This is the original version.
|
|
</p>
|
|
<p>This is the beginning of the implementation of pvDataBaseCPP.
|
|
It describes the features that will be provided.
|
|
The class definitions for PVRecord and 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)
|
|
{
|
|
pvValue->put(pvValue->get() + 1);
|
|
processRequester->recordProcessResult(Status::Ok);
|
|
processRequester->recordProcessComplete();
|
|
}
|
|
</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. The next subsection has the definitions for all the classes
|
|
defined in this header file.
|
|
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>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>PVRecordClient</dt>
|
|
<dd>This is called by anything that acceses PVRecord.</dd>
|
|
<dt>PVDatabase</dt>
|
|
<dd>This is a database of PVRecords.</dd>
|
|
</dl>
|
|
<p>Each class is described in a separate subsection.</p>
|
|
|
|
<h3>class PVRecord</h3>
|
|
<pre>
|
|
class PVRecord
|
|
{
|
|
public:
|
|
POINTER_DEFINITIONS(PVRecord);
|
|
PVRecord(
|
|
epics::pvData::String const & recordName,
|
|
epics::pvData::PVStructurePtr const & pvStructure);
|
|
virtual ~PVRecord();
|
|
virtual void process(
|
|
RecordProcessRequesterPtr const &recordProcessRequester) = 0;
|
|
virtual bool isSynchronous() = 0;
|
|
epics::pvData::String getRecordName();
|
|
PVRecordStructurePtr getPVRecordStructure();
|
|
PVRecordFieldPtr findPVRecordField(
|
|
epics::pvData::PVFieldPtr const & pvField);
|
|
void lock();
|
|
void unlock();
|
|
void registerClient(PVRecordClientPtr const & pvRecordClient);
|
|
void unregisterClient(PVRecordClientPtr const & pvRecordClient);
|
|
void detachClients();
|
|
void beginGroupPut();
|
|
void endGroupPut();
|
|
void registerListener(PVListenerPtr const & pvListener);
|
|
void unregisterListener(PVListenerPtr const & pvListener);
|
|
void removeEveryListener();
|
|
epics::pvData::Status processRequest();
|
|
void queueProcessRequest(
|
|
RecordProcessRequesterPtr const &recordProcessRequester);
|
|
void addRequester(epics::pvData::RequesterPtr const & requester);
|
|
void removeRequester(epics::pvData::RequesterPtr const & requester);
|
|
void message(
|
|
epics::pvData::String const & message,
|
|
epics::pvData::MessageType messageType);
|
|
epics::pvData::String toString();
|
|
epics::pvData::String toString(int indentLevel);
|
|
};
|
|
</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 desctructor which must be virtual. A derived class must also have
|
|
a virtual destructor.</dd>
|
|
<dt>process</dt>
|
|
<dd>Pure virtual method. Derived classes must implement this method.</dd>
|
|
<dt>isSynchronous</dt>
|
|
<dd>Pure virtual method. Derived classes must implement this 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>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>registerClient</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>unregisterClient</dt>
|
|
<dd>Client is no longer accessing the record.</dd>
|
|
<dt>detachClients</dt>
|
|
<dd>Ask all clients to detach from the record</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>registerListener</dt>
|
|
<dd>Register a PVListener. This must be called before calling pvRecordField.addListener.</dd>
|
|
<dt>unregisterListener</dt>
|
|
<dd>Unregister a listener. The listener will also be removed from all fields to which it is attached.</dd>
|
|
<dt>removeEveryListener</dt>
|
|
<dd>This must be called by any code that is deleting or changing the structure of a record.</dd>
|
|
<dt>processRequest</dt>
|
|
<dd>This is a convenience method for clients that are willing to block if
|
|
process is asynchronous. It implements RecordProcessRequester.
|
|
If process is synchronous it just calls process and returns the result
|
|
to the caller. If process is asynchronous it calls queueProcessRequest,
|
|
and process and waits for completion and then returns the result to the caller.</dd>
|
|
<dt>queueProcessRequest</dt>
|
|
<dd>Queue a process request.</dd>
|
|
<dt>addRequester</dt>
|
|
<dd>Add a requester to receive messages.</dd>
|
|
<dt>removeRequester</dt>
|
|
<dd>Remove a message requester.</dd>
|
|
<dt>message</dt>
|
|
<dd>Can be called by implementation code.
|
|
The message will be sent to every requester.</dd>
|
|
</dl>
|
|
<h3>class PVRecordField</h3>
|
|
<pre>
|
|
class PVRecordField {
|
|
public:
|
|
POINTER_DEFINITIONS(PVRecordField);
|
|
PVRecordField(
|
|
epics::pvData::PVFieldPtr const & pvField,
|
|
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);
|
|
void removeListener(PVListenerPtr const & pvListener);
|
|
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 message(
|
|
epics::pvData::String const & message,
|
|
epics::pvData::MessageType messageType);
|
|
};
|
|
</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>message</dt>
|
|
<dd>Called by implementation code. It calls PVRecord::message after prepending the full
|
|
fieldname.</dd>
|
|
</dl>
|
|
<h3>class PVListener</h3>
|
|
<pre>
|
|
class PVListener {
|
|
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;
|
|
virtual void unlisten(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>
|
|
<dt>unlisten</dt>
|
|
<dd>The PVLister is being removed from the record.
|
|
This is called when the record is being destroyed or when the record structure
|
|
(not the data values) is being changed.</dd>
|
|
</dl>
|
|
<h3>class RecordProcessRequester</h3>
|
|
<pre>
|
|
class RecordProcessRequester :
|
|
virtual public epics::pvData::Requester
|
|
{
|
|
public:
|
|
POINTER_DEFINITIONS(RecordProcessRequester);
|
|
virtual ~RecordProcessRequester();
|
|
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>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 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>
|
|
<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>
|