interim commit
This commit is contained in:
@ -38,7 +38,7 @@
|
|||||||
<h1>pvDatabaseCPP</h1>
|
<h1>pvDatabaseCPP</h1>
|
||||||
<!-- Maturity: Working Draft or Request for Comments, or Recommendation, and date. -->
|
<!-- Maturity: Working Draft or Request for Comments, or Recommendation, and date. -->
|
||||||
|
|
||||||
<h2 class="nocount">EPICS v4 Working Group, Working Draft, 11-Dec-2012</h2>
|
<h2 class="nocount">EPICS v4 Working Group, Working Draft, 09-Apr-2013</h2>
|
||||||
<dl>
|
<dl>
|
||||||
<dt>Latest version:</dt>
|
<dt>Latest version:</dt>
|
||||||
<dd><a
|
<dd><a
|
||||||
@ -46,11 +46,11 @@
|
|||||||
</dd>
|
</dd>
|
||||||
<dt>This version:</dt>
|
<dt>This version:</dt>
|
||||||
<dd><a
|
<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_20130409.html">pvDatabaseCPP20131211.html</a>
|
||||||
</dd>
|
</dd>
|
||||||
<dt>Previous version:</dt>
|
<dt>Previous version:</dt>
|
||||||
<dd><a
|
<dd><a
|
||||||
href="http://epics-pvdata.hg.sourceforge.net/hgweb/epics-pvdata/pvDatabaseCPP/raw-file/tip/documentation/pvDatabaseCPP_20121127.html">pvDatabaseCPP_20121127.html</a>
|
href="http://epics-pvdata.hg.sourceforge.net/hgweb/epics-pvdata/pvDatabaseCPP/raw-file/tip/documentation/pvDatabaseCPP_20131211.html">pvDatabaseCPP20131211.html</a>
|
||||||
</dd>
|
</dd>
|
||||||
<dt>Editors:</dt>
|
<dt>Editors:</dt>
|
||||||
<dd>Marty Kraimer, BNL</dd>
|
<dd>Marty Kraimer, BNL</dd>
|
||||||
@ -67,7 +67,7 @@ href="http://epics-pvdata.sourceforge.net/LICENSE.html">EPICS open source licens
|
|||||||
which is a framework for implementing a network accessable database of smart memory resident
|
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
|
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.
|
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 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
|
The minimum that an extenson must provide is a top level PVStructure and a process method
|
||||||
but the framework provides for complex extensions.</p>
|
but the framework provides for complex extensions.</p>
|
||||||
|
|
||||||
@ -97,7 +97,7 @@ V4 control system programming environment:</p>
|
|||||||
|
|
||||||
<h2 class="nocount">Status of this Document</h2>
|
<h2 class="nocount">Status of this Document</h2>
|
||||||
|
|
||||||
<p>This is the 11-Dec-2012 version of the definition of pvDatabaseCPP.
|
<p>This is the 09-Apr-2013 version of the definition of pvDatabaseCPP.
|
||||||
</p>
|
</p>
|
||||||
<p>This is the beginning of the implementation of pvDataBaseCPP.
|
<p>This is the beginning of the implementation of pvDataBaseCPP.
|
||||||
It describes the features that will be provided.
|
It describes the features that will be provided.
|
||||||
@ -113,22 +113,16 @@ The class definition for PVDatabase are defined but not implemented.</p>
|
|||||||
|
|
||||||
<h2>Introduction</h2>
|
<h2>Introduction</h2>
|
||||||
<h3>Overview</h3>
|
<h3>Overview</h3>
|
||||||
<p>This document descibes a C++ implementation of some of the components in pvIOCJava.
|
<p>A brief description of a pvDatabase is that it is a set of network accessible, smart,
|
||||||
It extracts the core components required to create a network accessible database of smart
|
|
||||||
memory resident records.
|
memory resident records.
|
||||||
pvDatabaseCPP does not and will not implement any of the specialized support that pvIOCJava
|
Each record has data composed of a top level PVStructure.
|
||||||
provides. Instead other projects will implement the specialized support.
|
Each record has a name which is the channelName for pvAccess.
|
||||||
It is expected that many services will be created that do not require the full features provided
|
A local Channel Provider implements the complete ChannelProvider and
|
||||||
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.
|
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.
|
This local provider is accessed by the remote pvAccess server.
|
||||||
A record is smart because code can be attached to a record.</p>
|
A record is smart because code can be attached to a record, which is accessed via a method named <b>process</b>.</p>
|
||||||
|
|
||||||
<p>This document describes components that provides the following features:
|
<p>This document describes components that provides the following features:
|
||||||
<dl>
|
<dl>
|
||||||
<dt>database<dt>
|
<dt>database<dt>
|
||||||
@ -142,135 +136,182 @@ A record is smart because code can be attached to a record.</p>
|
|||||||
<dd>This is a database of pvRecords.
|
<dd>This is a database of pvRecords.
|
||||||
Records can be added and removed from a database.</dd>
|
Records can be added and removed from a database.</dd>
|
||||||
</dl>
|
</dl>
|
||||||
<dt>localChannelProvider</dt>
|
<dt>pvAccess</dt>
|
||||||
<dd>This is a complete implementation of ChannelProvider and Channel as defined by pvAccess.
|
<dd>This is a complete implementation of a local ChannelProvider and Channel as defined by pvAccess.
|
||||||
It is used by the server side of pvAccess to attach to pvRecords.
|
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>
|
This component also includes the monitor and pvCopy components from pvIOCJava</dd>
|
||||||
</dl>
|
</dl>
|
||||||
<p><b>database</b> does not itself implement pvRecord instances.
|
<p><b>database</b>
|
||||||
Instead it provides a base classes that make it easy to create record instances.
|
provides base classes that make it easy to create record instances.
|
||||||
What does have to be implemented is a top
|
The code attached to each record must create the top
|
||||||
level PVStructure and the following two methods:</p>
|
level PVStructure and the following two methods:</p>
|
||||||
<dl>
|
<dl>
|
||||||
|
<dt>init</dt>
|
||||||
|
<dd>This is a method for initializing the support.
|
||||||
|
It returns <b>true</b> if successful and <b>false</b> otherwise.
|
||||||
|
</dd>
|
||||||
<dt>process</dt>
|
<dt>process</dt>
|
||||||
<dd>This is what makes a record <b>smart</b>.
|
<dd>This is what makes a record <b>smart</b>.
|
||||||
What process does is up to the implementation except that it must decide if
|
</dd>
|
||||||
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>
|
</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.
|
||||||
|
It 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>
|
<h3>Example PVRecord Extension</h3>
|
||||||
<p>Directory <b>example/record</b> has an example PVRecord implementation.
|
<p>The example implements a simple counter.
|
||||||
It implements a counter.
|
The example can be run on linux as follows:</p>
|
||||||
The top level structure is:</p>
|
|
||||||
<pre>
|
<pre>
|
||||||
structure
|
mrk> pwd
|
||||||
long value
|
/home/hg/pvDatabaseCPP
|
||||||
</pre>
|
mrk> bin/linux-x86_64/exampleCounter
|
||||||
<p><b>NOTE:</b> The example compiles but does not build because nothing
|
|
||||||
is implemented.</p>
|
|
||||||
|
|
||||||
<h4>exampleRecord.h</h4>
|
</pre>
|
||||||
<p>This is the class description.
|
<p>The example consists of two components:</p>
|
||||||
The example extends PVRecord.</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 <b>pvAccess</b> client.</dd>
|
||||||
|
</dl>
|
||||||
|
<h4>ExampleCounter.h</h4>
|
||||||
|
<p>The example resides in <b>src/database</b>.
|
||||||
|
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>
|
<pre>
|
||||||
class ExampleRecord :
|
class ExampleCounter;
|
||||||
public virtual PVRecord
|
typedef std::tr1::shared_ptr<ExampleCounter> ExampleCounterPtr;
|
||||||
|
|
||||||
|
class ExampleCounter :
|
||||||
|
public PVRecord
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
POINTER_DEFINITIONS(ExampleRecord);
|
POINTER_DEFINITIONS(ExampleCounter);
|
||||||
static PVRecordPtr create(epics::pvData::String const & recordName);
|
static ExampleCounterPtr create(
|
||||||
virtual ~ExampleRecord();
|
epics::pvData::String const & recordName);
|
||||||
virtual bool isSynchronous();
|
virtual ~ExampleCounter() {}
|
||||||
virtual void process(
|
virtual bool init();
|
||||||
epics::pvDatabase::RecordProcessRequesterPtr const &processRequester);
|
virtual void process();
|
||||||
private:
|
private:
|
||||||
ExampleRecord(epics::pvData::String const & recordName,
|
ExampleCounter(epics::pvData::String const & recordName,
|
||||||
epics::pvData::PVStructurePtr const & pvStructure,
|
epics::pvData::PVStructurePtr const & pvStructure);
|
||||||
epics::pvData::PVLongPtr const &pvValue);
|
|
||||||
epics::pvData::PVLongPtr pvValue;
|
epics::pvData::PVLongPtr pvValue;
|
||||||
};
|
};
|
||||||
</pre>
|
</pre>
|
||||||
<p>where</p>
|
<p>where</p>
|
||||||
<dl>
|
<dl>
|
||||||
<dt>create<dt>
|
<dt>create<dt>
|
||||||
<dd>This is example specific. See the implemention for details.</dd>
|
<dd>This is example specific but each support should provide
|
||||||
<dt>~ExampleRecord<dt>
|
a similar static method.
|
||||||
|
</dd>
|
||||||
|
<dt>~ExampleCounter<dt>
|
||||||
<dd>The destructor must be declared virtual.</dd>
|
<dd>The destructor must be declared virtual.</dd>
|
||||||
<dt>isSynchronous<dt>
|
<dt>init<dt>
|
||||||
<dd>The implementation must say if process is synchronous or asynchronous.</dd>
|
<dd>A method to initialize the support. It returns <b>true</b>
|
||||||
|
if initialization is successful and <b>false</b> if not.
|
||||||
|
NOTE that this is a virtual method of PVRecord itself.</dd>
|
||||||
<dt>process<dt>
|
<dt>process<dt>
|
||||||
<dd><b>The</b> implementation.</dd>
|
<dd>
|
||||||
<dt>ExampleRecord<dt>
|
This again is a virtual method of PVRecord.
|
||||||
|
</dd>
|
||||||
|
<dt>ExampleCounter<dt>
|
||||||
<dd>For the example this is private.</dd>
|
<dd>For the example this is private.</dd>
|
||||||
|
<dt>pvValue</dt>
|
||||||
|
<dd>This is the field of the top level structure that <b>process</b>
|
||||||
|
accesses.
|
||||||
|
</dd>
|
||||||
<dl>
|
<dl>
|
||||||
|
<p>The implementation of <b>create</b> is:</p>
|
||||||
<h4>exampleRecord.cpp</h4>
|
|
||||||
<p>This is the class implementation.</p>
|
|
||||||
<pre>
|
<pre>
|
||||||
ExampleRecord::~ExampleRecord(){}
|
ExampleCounterPtr ExampleCounter::create(
|
||||||
|
epics::pvData::String const & recordName)
|
||||||
PVRecordPtr ExampleRecord::create(String const & recordName)
|
|
||||||
{
|
{
|
||||||
String properties;
|
epics::pvData::PVStructurePtr pvStructure =
|
||||||
PVStructurePtr pvStructure = getStandardPVField()->scalar(pvLong,properties);
|
epics::pvData::getStandardPVField()->scalar(epics::pvData::pvDouble,"");
|
||||||
PVLongPtr pvValue = pvStructure->getLongField("value");
|
ExampleCounterPtr pvRecord(
|
||||||
PVRecordPtr pvRecord(new ExampleRecord(recordName,pvStructure,pvValue));
|
new ExampleCounter(recordName,pvStructure));
|
||||||
|
if(!pvRecord->init()) pvRecord.reset();
|
||||||
return pvRecord;
|
return pvRecord;
|
||||||
}
|
}
|
||||||
|
</pre>
|
||||||
ExampleRecord::ExampleRecord(
|
This:
|
||||||
String const & recordName,
|
<ul>
|
||||||
PVStructurePtr const & pvStructure,
|
<li>Creates the top level structure.</li>
|
||||||
PVLongPtr const &pvValue)
|
<li>Creates a <b>ExampleCounterPtr</b> via the constructor.</li>
|
||||||
: PVRecord(recordName,pvStructure),
|
<li>Calls init and if it fails resets the shared pointer.</li>
|
||||||
pvValue(pvValue)
|
<li>Returns the shared pointer to the newly created record.</li>
|
||||||
{}
|
</ul>
|
||||||
|
<p>The private constructor is just:</p>
|
||||||
bool ExampleRecord::isSynchronous() {return true;}
|
<pre>
|
||||||
|
ExampleCounter::ExampleCounter(
|
||||||
void ExampleRecord::process(
|
epics::pvData::String const & recordName,
|
||||||
RecordProcessRequesterPtr const &processRequester,bool alreadyLocked)
|
epics::pvData::PVStructurePtr const & pvStructure)
|
||||||
|
: PVRecord(recordName,pvStructure)
|
||||||
|
{ }
|
||||||
|
</pre>
|
||||||
|
The example is very simple. It just calls the base class constructor.
|
||||||
|
<p>The implementation of <b>init</b> is:</p>
|
||||||
|
<pre>
|
||||||
|
bool ExampleCounter::init()
|
||||||
{
|
{
|
||||||
if(!alreadyLocked) lock();
|
|
||||||
pvValue->put(pvValue->get() + 1);
|
initPVRecord();
|
||||||
processRequester->recordProcessResult(Status::Ok);
|
epics::pvData::PVFieldPtr pvField;
|
||||||
unlock();
|
pvValue = getPVStructure()->getLongField("value");
|
||||||
processRequester->recordProcessComplete();
|
if(pvValue.get()==NULL) return false;
|
||||||
dequeueProcessRequest(processRequester);
|
return true;
|
||||||
}
|
}
|
||||||
</pre>
|
</pre>
|
||||||
<p>where</p>
|
This:
|
||||||
<dl>
|
<ul>
|
||||||
<dt>create<dt>
|
<li>Calls <b>initRecord</b> which is implemented by the base class.
|
||||||
<dd>Creates a PVStructure with a single subfield named value.
|
It MUST be called.</li>
|
||||||
It gets the interface to the value field.
|
<li>Calls <b>getLongField</b> to get the interface to the value field,
|
||||||
It then creates an ExampleRecord and returns it.
|
which must be a scalar with type long.</li>
|
||||||
</dd>
|
<li>If a long value field was not found it returns false.</li>
|
||||||
<dt>~ExampleRecord<dt>
|
<li>Returns true</li>
|
||||||
<dd>Does not have to do anything because of shared pointers.</dd>
|
</ul>
|
||||||
<dt>ExampleRecord<dt>
|
<p>The implementation of <b>process</b> is:</p>
|
||||||
<dd>Calls the base class constructor and sets pvValue.</dd>
|
<pre>
|
||||||
<dt>isSynchronous<dt>
|
void ExampleCounter::process()
|
||||||
<dd>The example is synchronous.</dd>
|
{
|
||||||
<dt>process<dt>
|
pvValue->put(pvValue->get() + 1.0);
|
||||||
<dd>Gets the curent value, increments it, and puts the new value.
|
}
|
||||||
It than calls two processRequester callbacks.</dd>
|
</pre>
|
||||||
<dl>
|
It just adds 1.0 to the current value.
|
||||||
|
<h4>exampleCounterMain.cpp</h4>
|
||||||
<h4>exampleRecordMain.cpp</h4>
|
<p>This is in <b>test/server</b>.
|
||||||
<p>This is a main for creating and running the example.</p>
|
The main program is:</p>
|
||||||
<pre>
|
<pre>
|
||||||
int main(int argc,char *argv[])
|
int main(int argc,char *argv[])
|
||||||
{
|
{
|
||||||
String recordName("exampleRecord");
|
PVDatabasePtr master = PVDatabase::getMaster();
|
||||||
PVRecordPtr pvRecord = ExampleRecord::create(recordName);
|
ChannelProviderLocalPtr channelProvider = ChannelProviderLocal::create();
|
||||||
PVDatabasePtr pvDatabase = PVDatabase::getMaster();
|
String recordName("exampleCounter");
|
||||||
pvDatabase->addRecord(pvRecord);
|
PVRecordPtr pvRecord = ExampleCounter::create(recordName);
|
||||||
cout << recordName << "\n";
|
bool result = master->addRecord(pvRecord);
|
||||||
|
cout << "result of addRecord " << recordName << " " << result << endl;
|
||||||
|
pvRecord.reset();
|
||||||
|
cout << "exampleServer\n";
|
||||||
string str;
|
string str;
|
||||||
while(true) {
|
while(true) {
|
||||||
cout << "Type exit to stop: \n";
|
cout << "Type exit to stop: \n";
|
||||||
@ -281,16 +322,15 @@ int main(int argc,char *argv[])
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
</pre>
|
</pre>
|
||||||
<p>The main program creates an example record and adds it to the database.
|
This:
|
||||||
It then runs until the process is stopped by typing <b>exit</b>.
|
<ul>
|
||||||
<p>Until the process is stopped,
|
<li>Gets a pointer to the master database.</li>
|
||||||
pvAccess clients can put and get the value field.
|
<li>Creates the local Channel Provider. This starts the pvAccess server.</li>
|
||||||
For example</p>
|
<li>Creates a <b>ExampleCounter</b> record with the name <b>exampleCounter</b>
|
||||||
<pre>
|
</li>
|
||||||
pvget exampleRecord
|
<li>Prints <b>exampleCounter</b> on standard out.</li>
|
||||||
pvput exampleRecord 5
|
<li>Runs forever until the user types <b>exit</b> on standard in.</li>
|
||||||
</pre>
|
</ul>
|
||||||
<p>Will both work.</p>
|
|
||||||
<h3>Phased Development</h3>
|
<h3>Phased Development</h3>
|
||||||
<p>This documentation describes the first phase of a phased implementation of pvDatabaseCPP:</pp>
|
<p>This documentation describes the first phase of a phased implementation of pvDatabaseCPP:</pp>
|
||||||
<dl>
|
<dl>
|
||||||
@ -299,16 +339,20 @@ pvput exampleRecord 5
|
|||||||
<dt>pvDatabase</d>
|
<dt>pvDatabase</d>
|
||||||
<dd>Database of PVRecords. Has methods find, add, and remove.</dd>
|
<dd>Database of PVRecords. Has methods find, add, and remove.</dd>
|
||||||
<dt>Local Channel Provider</dt>
|
<dt>Local Channel Provider</dt>
|
||||||
<dd>These two features will be the first phase.
|
<dd>Complete implementation of ChannelProvider and Channel.
|
||||||
But only synchronous record processing will be supported.</dd>
|
This means that pvCopy and monitor are also implemented.</dd>
|
||||||
</dl>
|
</dl>
|
||||||
<p>Future phases of pvDatabaseCPP should include:</p>
|
<p>Future phases of pvDatabaseCPP might include:</p>
|
||||||
<dl>
|
<dl>
|
||||||
<dt>Install</dt>
|
<dt>Install</dt>
|
||||||
<dd>This provides on-line add and delete.</dd>
|
<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>
|
<dt>Field support</dt>
|
||||||
<dd>Add ability to optionally add support to fields.
|
<dd>Add the ability to optionally add support to fields.
|
||||||
In addition some of the basic support defined in pvIOCJava will also be implemented.</dd>
|
In addition some of the basic support defined in pvIOCJava could also be implemented.</dd>
|
||||||
<dt>XML parser</dt>
|
<dt>XML parser</dt>
|
||||||
<dd>This provides the ability to create record instances without writing any code.</dd>
|
<dd>This provides the ability to create record instances without writing any code.</dd>
|
||||||
</dl>
|
</dl>
|
||||||
@ -326,10 +370,10 @@ The rest of this document discusses only the first phase.</p>
|
|||||||
<dd>This provides the ability to monitor changes to fields of a record.</dd>
|
<dd>This provides the ability to monitor changes to fields of a record.</dd>
|
||||||
<dt>PVRecord and PVDatabase</dt>
|
<dt>PVRecord and PVDatabase</dt>
|
||||||
<dd>Defined below.</dd>
|
<dd>Defined below.</dd>
|
||||||
<dt>local ChannelProvider</dt>
|
<dt>The localChannelProvider itself</dt>
|
||||||
<dd>This is the pvAccess package in pvIOCJava.
|
<dd>This is the pvAccess package in pvIOCJava.
|
||||||
The localChannelProvider will access data from PVRecords.
|
The localChannelProvider will access data from PVRecords.
|
||||||
It will implement all channel methods except channelRPC.</dd>
|
It will implement all channel methods.</dd>
|
||||||
</dl>
|
</dl>
|
||||||
<h3>Minumum Features Required for pvRecord</h3>
|
<h3>Minumum Features Required for pvRecord</h3>
|
||||||
<p>The first phase will only implement record processing, i. e.
|
<p>The first phase will only implement record processing, i. e.
|
||||||
@ -340,9 +384,9 @@ The following are the minimium features required</p>
|
|||||||
<dt>PVDatabase</dt>
|
<dt>PVDatabase</dt>
|
||||||
<dd>This holds a set of PVRecords. It has methods to find, add, and remove records.</dd>
|
<dd>This holds a set of PVRecords. It has methods to find, add, and remove records.</dd>
|
||||||
<dt>PVRecord</dt>
|
<dt>PVRecord</dt>
|
||||||
<dd>This, and a set of related interfaces, provide the following:
|
<dd>This, and a set of related interfaces, provides the following:
|
||||||
<dl>
|
<dl>
|
||||||
<dt>PVStructure</dt>
|
<dt>Access to top level PVStructure</dt>
|
||||||
<dd>PVRecord is a wrapper on a top level pvStructure.</dd>
|
<dd>PVRecord is a wrapper on a top level pvStructure.</dd>
|
||||||
<dt>Record locking</dt>
|
<dt>Record locking</dt>
|
||||||
<dd>A record can be locked and unlocked.
|
<dd>A record can be locked and unlocked.
|
||||||
@ -353,12 +397,45 @@ The following are the minimium features required</p>
|
|||||||
</dl>
|
</dl>
|
||||||
</dd>
|
</dd>
|
||||||
</dl>
|
</dl>
|
||||||
<p>The following sections provide a first attempt to describe the classes required for the first
|
<p>The following sections describes the classes required for the first phase.</p>
|
||||||
phase.</p>
|
|
||||||
<p>The last section gives a brief overview of the features provided by pvIOCJava.</p>
|
|
||||||
|
|
||||||
<h2>database</h2>
|
<h2>database</h2>
|
||||||
<p>The classes in <b>pvDatabase.h</b> implement a database of memory resident
|
<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 <b>PVREcord</b>.
|
||||||
|
It can also implement record instances with a <b>process</b>
|
||||||
|
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 <b>pvDatabase.h</b> describe a database of memory resident
|
||||||
smart records.
|
smart records.
|
||||||
It describes the following classes:</p>
|
It describes the following classes:</p>
|
||||||
<dl>
|
<dl>
|
||||||
@ -371,11 +448,7 @@ It describes the following classes:</p>
|
|||||||
<dt>PVRecordClient</dt>
|
<dt>PVRecordClient</dt>
|
||||||
<dd>This is called by anything that acceses PVRecord.</dd>
|
<dd>This is called by anything that acceses PVRecord.</dd>
|
||||||
<dt>PVListener</dt>
|
<dt>PVListener</dt>
|
||||||
<dd>This is implemented by anything that wants to trap calls to the PVRecord::message.</dd>
|
<dd>This is implemented by anything that wants to trap calls to 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>
|
<dt>PVDatabase</dt>
|
||||||
<dd>This is a database of PVRecords.</dd>
|
<dd>This is a database of PVRecords.</dd>
|
||||||
</dl>
|
</dl>
|
||||||
@ -419,6 +492,10 @@ typedef std::tr1::shared_ptr<PVDatabase> PVDatabasePtr;
|
|||||||
i. e. via pvAccess.
|
i. e. via pvAccess.
|
||||||
Thus this section is mainly of interest to
|
Thus this section is mainly of interest to
|
||||||
the local channel provider and record implementers.</li>
|
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 <b>init</b> and <b>process</b>.
|
||||||
|
These are described first.
|
||||||
</ul>
|
</ul>
|
||||||
<hr>PVRecord Methods</h4>
|
<hr>PVRecord Methods</h4>
|
||||||
<pre>
|
<pre>
|
||||||
@ -428,16 +505,17 @@ class PVRecord
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
POINTER_DEFINITIONS(PVRecord);
|
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);
|
||||||
PVRecord(
|
PVRecord(
|
||||||
epics::pvData::String const & recordName,
|
epics::pvData::String const & recordName,
|
||||||
epics::pvData::PVStructurePtr const & pvStructure);
|
epics::pvData::PVStructurePtr const & pvStructure);
|
||||||
virtual ~PVRecord();
|
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();
|
virtual void destroy();
|
||||||
epics::pvData::String getRecordName();
|
epics::pvData::String getRecordName();
|
||||||
PVRecordStructurePtr getPVRecordStructure();
|
PVRecordStructurePtr getPVRecordStructure();
|
||||||
@ -445,25 +523,20 @@ public:
|
|||||||
epics::pvData::PVFieldPtr const & pvField);
|
epics::pvData::PVFieldPtr const & pvField);
|
||||||
bool addRequester(epics::pvData::RequesterPtr const & requester);
|
bool addRequester(epics::pvData::RequesterPtr const & requester);
|
||||||
bool removeRequester(epics::pvData::RequesterPtr const & requester);
|
bool removeRequester(epics::pvData::RequesterPtr const & requester);
|
||||||
|
inline void lock_guard() { epics::pvData::Lock theLock(mutex); }
|
||||||
void lock();
|
void lock();
|
||||||
void unlock();
|
void unlock();
|
||||||
bool tryLock();
|
bool tryLock();
|
||||||
void lockOtherRecord(PVRecordPtr const & otherRecord);
|
void lockOtherRecord(PVRecordPtr const & otherRecord);
|
||||||
void addPVRecordClient(PVRecordClientPtr const & pvRecordClient);
|
bool addPVRecordClient(PVRecordClientPtr const & pvRecordClient);
|
||||||
void removePVRecordClient(PVRecordClientPtr const & pvRecordClient);
|
bool removePVRecordClient(PVRecordClientPtr const & pvRecordClient);
|
||||||
void detachClients();
|
void detachClients();
|
||||||
|
bool addListener(PVListenerPtr const & pvListener);
|
||||||
|
bool removeListener(PVListenerPtr const & pvListener);
|
||||||
void beginGroupPut();
|
void beginGroupPut();
|
||||||
void endGroupPut();
|
void endGroupPut();
|
||||||
void queueProcessRequest(
|
epics::pvData::String getRequesterName() {return getRecordName();}
|
||||||
RecordProcessRequesterPtr const &recordProcessRequester);
|
virtual void message(
|
||||||
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::String const & message,
|
||||||
epics::pvData::MessageType messageType);
|
epics::pvData::MessageType messageType);
|
||||||
void message(
|
void message(
|
||||||
@ -472,63 +545,39 @@ public:
|
|||||||
epics::pvData::MessageType messageType);
|
epics::pvData::MessageType messageType);
|
||||||
void toString(epics::pvData::StringBuilder buf);
|
void toString(epics::pvData::StringBuilder buf);
|
||||||
void toString(epics::pvData::StringBuilder buf,int indentLevel);
|
void toString(epics::pvData::StringBuilder buf,int indentLevel);
|
||||||
//init MUST be called after derived class is constructed
|
protected:
|
||||||
void init();
|
void initPVRecord();
|
||||||
|
epics::pvData::PVStructurePtr getPVStructure();
|
||||||
};
|
PVRecordPtr getPtrSelf()
|
||||||
|
{
|
||||||
|
return shared_from_this();
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
...
|
||||||
|
}
|
||||||
</pre>
|
</pre>
|
||||||
<p>The methods are:</h3>
|
<p>The methods are:</h3>
|
||||||
<dl>
|
<dl>
|
||||||
|
<dt>init</dt>
|
||||||
|
<dd>Virtual method.
|
||||||
|
<p>Derived classes must implement this method.
|
||||||
|
This method <b>Must</b> 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>
|
<dt>PVRecord</dt>
|
||||||
<dd>The constructor. It requires a recordName and a top level PVStructure.</dd>
|
<dd>The constructor. It requires a recordName and a top level PVStructure.</dd>
|
||||||
<dt>~PVRecord</dt>
|
<dt>~PVRecord</dt>
|
||||||
<dd>The destructor which must be virtual. A derived class must also have
|
<dd>The destructor which must be virtual. A derived class must also have
|
||||||
a virtual destructor.</dd>
|
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>
|
<dt>destroy</dt>
|
||||||
<dd>This is a virtual method.
|
<dd>This is a virtual method.
|
||||||
<p>The default does nothing.</p>
|
|
||||||
</dd>
|
</dd>
|
||||||
<dt>getRecordName</dt>
|
<dt>getRecordName</dt>
|
||||||
<dd>Return the recordName.</dd>
|
<dd>Return the recordName.</dd>
|
||||||
@ -540,6 +589,9 @@ public:
|
|||||||
<dd>Add a requester to receive messages.</dd>
|
<dd>Add a requester to receive messages.</dd>
|
||||||
<dt>removeRequester</dt>
|
<dt>removeRequester</dt>
|
||||||
<dd>Remove a message requester.</dd>
|
<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>lock</dt>
|
||||||
<dt>unlock</dt>
|
<dt>unlock</dt>
|
||||||
<dd>Lock and Unlock the record.
|
<dd>Lock and Unlock the record.
|
||||||
@ -572,31 +624,18 @@ public:
|
|||||||
<dt>endGroupPut</dt>
|
<dt>endGroupPut</dt>
|
||||||
<dd>End a group of puts.
|
<dd>End a group of puts.
|
||||||
This results in all registered PVListeners being called.</dd>
|
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>
|
<dt>getRequesterName</dt>
|
||||||
<dd>virtual method of <b>Requester</b>
|
<dd>virtual method of <b>Requester</b>
|
||||||
</dd>
|
</dd>
|
||||||
<dt>message</dt>
|
<dt>message</dt>
|
||||||
<dd>Can be called by implementation code.
|
<dd>Can be called by implementation code.
|
||||||
The message will be sent to every requester.</dd>
|
The message will be sent to every requester.</dd>
|
||||||
<dt>init</dt>
|
<dt>toString</dt>
|
||||||
<dd>This method <b>must</b> be called by derived class
|
<dd>Just calls the top level PVStructure toString method.</dd>
|
||||||
<b>after</b> class is completely constructed.</dd>
|
<dt>initRecord</dt>
|
||||||
|
<dd>This method <b>must</b> be called by derived class.</dd>
|
||||||
|
<dt>getPVStructure</dt>
|
||||||
|
<dd>Called by derived class.</dd>
|
||||||
</dl>
|
</dl>
|
||||||
<h3>class PVRecordField</h3>
|
<h3>class PVRecordField</h3>
|
||||||
<pre>
|
<pre>
|
||||||
@ -621,6 +660,14 @@ public:
|
|||||||
virtual void message(
|
virtual void message(
|
||||||
epics::pvData::String const & message,
|
epics::pvData::String const & message,
|
||||||
epics::pvData::MessageType messageType);
|
epics::pvData::MessageType messageType);
|
||||||
|
protected:
|
||||||
|
PVRecordFieldPtr getPtrSelf()
|
||||||
|
{
|
||||||
|
return shared_from_this();
|
||||||
|
}
|
||||||
|
virtual void init();
|
||||||
|
private:
|
||||||
|
...
|
||||||
};
|
};
|
||||||
</pre>
|
</pre>
|
||||||
<p>When PVRecord is created it creates a PVRecordField for every field in the PVStructure
|
<p>When PVRecord is created it creates a PVRecordField for every field in the PVStructure
|
||||||
@ -669,6 +716,10 @@ public:
|
|||||||
epics::pvData::PVStructurePtr getPVStructure();
|
epics::pvData::PVStructurePtr getPVStructure();
|
||||||
virtual void removeListener(PVListenerPtr const & pvListener);
|
virtual void removeListener(PVListenerPtr const & pvListener);
|
||||||
virtual void postPut();
|
virtual void postPut();
|
||||||
|
protected:
|
||||||
|
virtual void init();
|
||||||
|
private:
|
||||||
|
...
|
||||||
};
|
};
|
||||||
</pre>
|
</pre>
|
||||||
<p>When PVRecord is created it creates a PVRecordStructure for every structure field in the PVStructure
|
<p>When PVRecord is created it creates a PVRecordStructure for every structure field in the PVStructure
|
||||||
@ -737,63 +788,6 @@ public:
|
|||||||
<dt>endGroupPut</dt>
|
<dt>endGroupPut</dt>
|
||||||
<dd>A related set of changes is done.</dd>
|
<dd>A related set of changes is done.</dd>
|
||||||
</dl>
|
</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>
|
<h3>class PVDatabase</h3>
|
||||||
<pre>
|
<pre>
|
||||||
class PVDatabase : virtual public epics::pvData::Requester {
|
class PVDatabase : virtual public epics::pvData::Requester {
|
||||||
@ -804,6 +798,10 @@ public:
|
|||||||
PVRecordPtr findRecord(epics::pvData::String const& recordName);
|
PVRecordPtr findRecord(epics::pvData::String const& recordName);
|
||||||
bool addRecord(PVRecordPtr const & record);
|
bool addRecord(PVRecordPtr const & record);
|
||||||
bool removeRecord(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:
|
private:
|
||||||
PVDatabase();
|
PVDatabase();
|
||||||
};
|
};
|
||||||
@ -822,70 +820,21 @@ private:
|
|||||||
<dt>removeRecord</dt>
|
<dt>removeRecord</dt>
|
||||||
<dd>Remove a record from the database.
|
<dd>Remove a record from the database.
|
||||||
If the record was not in the database false is returned.</dd>
|
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>
|
</dl>
|
||||||
<h2>Local Channel Provider</h2>
|
<h2>pvAccess</h2>
|
||||||
<p>Not yet described.</p>
|
<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 must implement the following components of pvIOCJava:</p>
|
<p>A brief description is that it must implement the following components of pvIOCJava:</p>
|
||||||
<dl>
|
<dl>
|
||||||
<dt>pvCopy</dt>
|
<dt>pvCopy</dt>
|
||||||
<dt>monitor</dt>
|
<dt>monitor</dt>
|
||||||
<dt>pvAccess</dt>
|
<dt>local ChannelProvider and Channel</dt>
|
||||||
<dd>See the next section for a description</dd>
|
|
||||||
</dl>
|
</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>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
@ -10,10 +10,15 @@ pvDatabase_LIBS += Com pvData pvAccess
|
|||||||
SRC_DIRS += $(DATABASE)/database
|
SRC_DIRS += $(DATABASE)/database
|
||||||
INC += pvDatabase.h
|
INC += pvDatabase.h
|
||||||
INC += powerSupplyRecordTest.h
|
INC += powerSupplyRecordTest.h
|
||||||
|
INC += exampleCounter.h
|
||||||
LIBSRCS += pvRecord.cpp
|
LIBSRCS += pvRecord.cpp
|
||||||
|
LIBSRCS += pvDatabase.cpp
|
||||||
|
|
||||||
SRC_DIRS += $(DATABASE)/pvAccess
|
SRC_DIRS += $(DATABASE)/pvAccess
|
||||||
|
INC += channelProviderLocal.h
|
||||||
INC += pvCopy.h
|
INC += pvCopy.h
|
||||||
|
LIBSRCS += channelProviderLocal.cpp
|
||||||
|
LIBSRCS += channelLocal.cpp
|
||||||
LIBSRCS += pvCopy.cpp
|
LIBSRCS += pvCopy.cpp
|
||||||
|
|
||||||
include $(TOP)/configure/RULES
|
include $(TOP)/configure/RULES
|
||||||
|
74
src/database/exampleCounter.h
Normal file
74
src/database/exampleCounter.h
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
/* exampleCounter.h */
|
||||||
|
/**
|
||||||
|
* Copyright - See the COPYRIGHT that is included with this distribution.
|
||||||
|
* EPICS pvData is distributed subject to a Software License Agreement found
|
||||||
|
* in file LICENSE that is included with this distribution.
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* @author mrk
|
||||||
|
* @date 2013.04.02
|
||||||
|
*/
|
||||||
|
#ifndef EXAMPLECOUNTER_H
|
||||||
|
#define EXAMPLECOUNTER_H
|
||||||
|
|
||||||
|
#include <pv/pvDatabase.h>
|
||||||
|
#include <pv/standardPVField.h>
|
||||||
|
|
||||||
|
namespace epics { namespace pvDatabase {
|
||||||
|
|
||||||
|
|
||||||
|
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 bool init();
|
||||||
|
virtual void process();
|
||||||
|
private:
|
||||||
|
ExampleCounter(epics::pvData::String const & recordName,
|
||||||
|
epics::pvData::PVStructurePtr const & pvStructure);
|
||||||
|
epics::pvData::PVLongPtr pvValue;
|
||||||
|
};
|
||||||
|
|
||||||
|
ExampleCounterPtr ExampleCounter::create(
|
||||||
|
epics::pvData::String const & recordName)
|
||||||
|
{
|
||||||
|
epics::pvData::PVStructurePtr pvStructure =
|
||||||
|
epics::pvData::getStandardPVField()->scalar(epics::pvData::pvDouble,"");
|
||||||
|
ExampleCounterPtr pvRecord(
|
||||||
|
new ExampleCounter(recordName,pvStructure));
|
||||||
|
if(!pvRecord->init()) pvRecord.reset();
|
||||||
|
return pvRecord;
|
||||||
|
}
|
||||||
|
|
||||||
|
ExampleCounter::ExampleCounter(
|
||||||
|
epics::pvData::String const & recordName,
|
||||||
|
epics::pvData::PVStructurePtr const & pvStructure)
|
||||||
|
: PVRecord(recordName,pvStructure)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ExampleCounter::init()
|
||||||
|
{
|
||||||
|
|
||||||
|
initPVRecord();
|
||||||
|
epics::pvData::PVFieldPtr pvField;
|
||||||
|
pvValue = getPVStructure()->getLongField("value");
|
||||||
|
if(pvValue.get()==NULL) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExampleCounter::process()
|
||||||
|
{
|
||||||
|
pvValue->put(pvValue->get() + 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
}}
|
||||||
|
|
||||||
|
#endif /* EXAMPLECOUNTER_H */
|
@ -11,10 +11,7 @@
|
|||||||
#ifndef POWERSUPPLYRECORDTEST_H
|
#ifndef POWERSUPPLYRECORDTEST_H
|
||||||
#define POWERSUPPLYRECORDTEST_H
|
#define POWERSUPPLYRECORDTEST_H
|
||||||
|
|
||||||
#include <pv/executor.h>
|
|
||||||
#include <pv/pvDatabase.h>
|
#include <pv/pvDatabase.h>
|
||||||
#include <pv/event.h>
|
|
||||||
#include <pv/timer.h>
|
|
||||||
#include <pv/timeStamp.h>
|
#include <pv/timeStamp.h>
|
||||||
#include <pv/alarm.h>
|
#include <pv/alarm.h>
|
||||||
#include <pv/pvTimeStamp.h>
|
#include <pv/pvTimeStamp.h>
|
||||||
@ -44,7 +41,6 @@ public:
|
|||||||
private:
|
private:
|
||||||
PowerSupplyRecordTest(epics::pvData::String const & recordName,
|
PowerSupplyRecordTest(epics::pvData::String const & recordName,
|
||||||
epics::pvData::PVStructurePtr const & pvStructure);
|
epics::pvData::PVStructurePtr const & pvStructure);
|
||||||
epics::pvData::PVStructurePtr pvStructure;
|
|
||||||
epics::pvData::PVDoublePtr pvCurrent;
|
epics::pvData::PVDoublePtr pvCurrent;
|
||||||
epics::pvData::PVDoublePtr pvPower;
|
epics::pvData::PVDoublePtr pvPower;
|
||||||
epics::pvData::PVDoublePtr pvVoltage;
|
epics::pvData::PVDoublePtr pvVoltage;
|
||||||
@ -67,8 +63,7 @@ PowerSupplyRecordTestPtr PowerSupplyRecordTest::create(
|
|||||||
PowerSupplyRecordTest::PowerSupplyRecordTest(
|
PowerSupplyRecordTest::PowerSupplyRecordTest(
|
||||||
epics::pvData::String const & recordName,
|
epics::pvData::String const & recordName,
|
||||||
epics::pvData::PVStructurePtr const & pvStructure)
|
epics::pvData::PVStructurePtr const & pvStructure)
|
||||||
: PVRecord(recordName,pvStructure),
|
: PVRecord(recordName,pvStructure)
|
||||||
pvStructure(pvStructure)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,6 +75,7 @@ PowerSupplyRecordTest::~PowerSupplyRecordTest()
|
|||||||
bool PowerSupplyRecordTest::init()
|
bool PowerSupplyRecordTest::init()
|
||||||
{
|
{
|
||||||
initPVRecord();
|
initPVRecord();
|
||||||
|
epics::pvData::PVStructurePtr pvStructure = getPVStructure();
|
||||||
epics::pvData::PVFieldPtr pvField;
|
epics::pvData::PVFieldPtr pvField;
|
||||||
bool result;
|
bool result;
|
||||||
pvField = pvStructure->getSubField("timeStamp");
|
pvField = pvStructure->getSubField("timeStamp");
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
using std::tr1::static_pointer_cast;
|
using std::tr1::static_pointer_cast;
|
||||||
using namespace epics::pvData;
|
using namespace epics::pvData;
|
||||||
using namespace epics::pvAccess;
|
using namespace epics::pvAccess;
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
namespace epics { namespace pvDatabase {
|
namespace epics { namespace pvDatabase {
|
||||||
|
|
||||||
@ -21,30 +22,51 @@ PVDatabase::~PVDatabase() {}
|
|||||||
|
|
||||||
PVDatabasePtr PVDatabase::getMaster()
|
PVDatabasePtr PVDatabase::getMaster()
|
||||||
{
|
{
|
||||||
PVDatabasePtr xxx;
|
static PVDatabasePtr master;
|
||||||
return xxx;
|
static Mutex mutex;
|
||||||
|
Lock xx(mutex);
|
||||||
|
if(master.get()==NULL) {
|
||||||
|
master = PVDatabasePtr(new PVDatabase());
|
||||||
|
}
|
||||||
|
return master;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PVDatabase::PVDatabase() {}
|
||||||
|
|
||||||
PVRecordPtr PVDatabase::findRecord(String const& recordName)
|
PVRecordPtr PVDatabase::findRecord(String const& recordName)
|
||||||
{
|
{
|
||||||
|
PVRecordMap::iterator iter = recordMap.find(recordName);
|
||||||
|
if(iter!=recordMap.end()) {
|
||||||
|
return (*iter).second;
|
||||||
|
}
|
||||||
PVRecordPtr xxx;
|
PVRecordPtr xxx;
|
||||||
return xxx;
|
return xxx;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PVDatabase::addRecord(PVRecordPtr const & record)
|
bool PVDatabase::addRecord(PVRecordPtr const & record)
|
||||||
{
|
{
|
||||||
return false;
|
String recordName = record->getRecordName();
|
||||||
|
PVRecordMap::iterator iter = recordMap.find(recordName);
|
||||||
|
if(iter!=recordMap.end()) return false;
|
||||||
|
recordMap.insert(PVRecordMap::value_type(recordName,record));
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PVDatabase::removeRecord(PVRecordPtr const & record)
|
bool PVDatabase::removeRecord(PVRecordPtr const & record)
|
||||||
{
|
{
|
||||||
return false;
|
String recordName = record->getRecordName();
|
||||||
|
PVRecordMap::iterator iter = recordMap.find(recordName);
|
||||||
|
if(iter!=recordMap.end()) {
|
||||||
|
recordMap.erase(iter);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
String PVDatabase::getRequesterName()
|
String PVDatabase::getRequesterName()
|
||||||
{
|
{
|
||||||
String xxx;
|
static String name("masterDatabase");
|
||||||
return xxx;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PVDatabase::message(String const & message,MessageType messageType)
|
void PVDatabase::message(String const & message,MessageType messageType)
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
#define PVDATABASE_H
|
#define PVDATABASE_H
|
||||||
|
|
||||||
#include <list>
|
#include <list>
|
||||||
|
#include <map>
|
||||||
#include <deque>
|
#include <deque>
|
||||||
|
|
||||||
#include <pv/pvAccess.h>
|
#include <pv/pvAccess.h>
|
||||||
@ -21,6 +22,7 @@ namespace epics { namespace pvDatabase {
|
|||||||
|
|
||||||
class PVRecord;
|
class PVRecord;
|
||||||
typedef std::tr1::shared_ptr<PVRecord> PVRecordPtr;
|
typedef std::tr1::shared_ptr<PVRecord> PVRecordPtr;
|
||||||
|
typedef std::map<epics::pvData::String,PVRecordPtr> PVRecordMap;
|
||||||
|
|
||||||
class PVRecordField;
|
class PVRecordField;
|
||||||
typedef std::tr1::shared_ptr<PVRecordField> PVRecordFieldPtr;
|
typedef std::tr1::shared_ptr<PVRecordField> PVRecordFieldPtr;
|
||||||
@ -39,53 +41,201 @@ typedef std::tr1::shared_ptr<PVListener> PVListenerPtr;
|
|||||||
class PVDatabase;
|
class PVDatabase;
|
||||||
typedef std::tr1::shared_ptr<PVDatabase> PVDatabasePtr;
|
typedef std::tr1::shared_ptr<PVDatabase> PVDatabasePtr;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base interface for a record.
|
||||||
|
* @author mrk
|
||||||
|
*/
|
||||||
class PVRecord :
|
class PVRecord :
|
||||||
public epics::pvData::Requester,
|
public epics::pvData::Requester,
|
||||||
public std::tr1::enable_shared_from_this<PVRecord>
|
public std::tr1::enable_shared_from_this<PVRecord>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
POINTER_DEFINITIONS(PVRecord);
|
POINTER_DEFINITIONS(PVRecord);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Virtual initialization method.
|
||||||
|
* Must be implemented by derived classes.
|
||||||
|
* This method <b>Must</b> call initPVRecord.
|
||||||
|
* @return <b>true</b> for success and <b>false</b> for failure.
|
||||||
|
*/
|
||||||
|
virtual bool init() {initPVRecord(); return true;}
|
||||||
|
/**
|
||||||
|
* Must be implemented by derived classes.
|
||||||
|
* It is the method that makes a record smart.
|
||||||
|
* If it encounters errors it should raise alarms and/or
|
||||||
|
* call the <b>message</b> method provided by the base class.
|
||||||
|
*/
|
||||||
|
virtual void process() {}
|
||||||
|
/**
|
||||||
|
* Creates a <b>dump</b> record, i.e. a record where process does nothing.
|
||||||
|
* @param recordName The name of the record, which is also the channelName.
|
||||||
|
* @param pvStructure The top level structure.
|
||||||
|
* @return A shared pointer to the newly created record.
|
||||||
|
*/
|
||||||
static PVRecordPtr create(
|
static PVRecordPtr create(
|
||||||
epics::pvData::String const & recordName,
|
epics::pvData::String const & recordName,
|
||||||
epics::pvData::PVStructurePtr const & pvStructure);
|
epics::pvData::PVStructurePtr const & pvStructure);
|
||||||
|
/**
|
||||||
|
* The constructor.
|
||||||
|
* @param recordName The name of the record, which is also the channelName.
|
||||||
|
* @param pvStructure The top level structure.
|
||||||
|
*/
|
||||||
PVRecord(
|
PVRecord(
|
||||||
epics::pvData::String const & recordName,
|
epics::pvData::String const & recordName,
|
||||||
epics::pvData::PVStructurePtr const & pvStructure);
|
epics::pvData::PVStructurePtr const & pvStructure);
|
||||||
|
/**
|
||||||
|
* The Destructor. Must be virtual.
|
||||||
|
*/
|
||||||
virtual ~PVRecord();
|
virtual ~PVRecord();
|
||||||
|
/**
|
||||||
|
* Destroy the PVRecord. Release any resources used and
|
||||||
|
* get rid of listeners and requesters.
|
||||||
|
*/
|
||||||
virtual void destroy();
|
virtual void destroy();
|
||||||
|
/**
|
||||||
|
* Get the name of the record.
|
||||||
|
* @return The name.
|
||||||
|
*/
|
||||||
epics::pvData::String getRecordName();
|
epics::pvData::String getRecordName();
|
||||||
|
/**
|
||||||
|
* Get the top level PVStructure.
|
||||||
|
* @return The shared pointer.
|
||||||
|
*/
|
||||||
PVRecordStructurePtr getPVRecordStructure();
|
PVRecordStructurePtr getPVRecordStructure();
|
||||||
|
/**
|
||||||
|
* Find the PVRecordField for the PVField.
|
||||||
|
* @param pvField The PVField.
|
||||||
|
* @return The shared pointer to the PVRecordField.
|
||||||
|
*/
|
||||||
PVRecordFieldPtr findPVRecordField(
|
PVRecordFieldPtr findPVRecordField(
|
||||||
epics::pvData::PVFieldPtr const & pvField);
|
epics::pvData::PVFieldPtr const & pvField);
|
||||||
|
/**
|
||||||
|
* Add a requester to receive messages.
|
||||||
|
* @param requester The requester.
|
||||||
|
* @return <b>true</b> if requester was added.
|
||||||
|
*/
|
||||||
bool addRequester(epics::pvData::RequesterPtr const & requester);
|
bool addRequester(epics::pvData::RequesterPtr const & requester);
|
||||||
|
/**
|
||||||
|
* Remove a requester.
|
||||||
|
* @param requester The requester.`
|
||||||
|
* @return <b>true</b> if requester was removed.
|
||||||
|
*/
|
||||||
bool removeRequester(epics::pvData::RequesterPtr const & requester);
|
bool removeRequester(epics::pvData::RequesterPtr const & requester);
|
||||||
|
/**
|
||||||
|
* This is an inline method that locks the record.
|
||||||
|
* The record will automatically
|
||||||
|
* be unlocked when control leaves the block that has the call.
|
||||||
|
*/
|
||||||
inline void lock_guard() { epics::pvData::Lock theLock(mutex); }
|
inline void lock_guard() { epics::pvData::Lock theLock(mutex); }
|
||||||
|
/**
|
||||||
|
* Lock the record.
|
||||||
|
* Any code must lock while accessing a record.
|
||||||
|
*/
|
||||||
void lock();
|
void lock();
|
||||||
|
/**
|
||||||
|
* Unlock the record.
|
||||||
|
*/
|
||||||
void unlock();
|
void unlock();
|
||||||
|
/**
|
||||||
|
* If <b>true</b> then just like <b>lock</b>.
|
||||||
|
* If <b>false</b>client can not access record.
|
||||||
|
* Code can try to simultaneously hold the lock for more than two records
|
||||||
|
* by calling this method but must be willing to accept failure.
|
||||||
|
* @return <b>true</b> if the record is locked.
|
||||||
|
*/
|
||||||
bool tryLock();
|
bool tryLock();
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* @param otherRecord The other record to lock.
|
||||||
|
*/
|
||||||
void lockOtherRecord(PVRecordPtr const & otherRecord);
|
void lockOtherRecord(PVRecordPtr const & otherRecord);
|
||||||
|
/**
|
||||||
|
* Every client that accesses the record must call this so that the
|
||||||
|
* client can be notified when the record is deleted.
|
||||||
|
* @param pvRecordClient The client.
|
||||||
|
* @return <b>true</b> if the client is added.
|
||||||
|
*/
|
||||||
bool addPVRecordClient(PVRecordClientPtr const & pvRecordClient);
|
bool addPVRecordClient(PVRecordClientPtr const & pvRecordClient);
|
||||||
|
/**
|
||||||
|
* Remove a client.
|
||||||
|
* @param pvRecordClient The client.
|
||||||
|
* @return <b>true</b> if the client is removed.
|
||||||
|
*/
|
||||||
bool removePVRecordClient(PVRecordClientPtr const & pvRecordClient);
|
bool removePVRecordClient(PVRecordClientPtr const & pvRecordClient);
|
||||||
|
/**
|
||||||
|
* remove all attached clients.
|
||||||
|
*/
|
||||||
void detachClients();
|
void detachClients();
|
||||||
|
/**
|
||||||
|
* Add a PVListener.
|
||||||
|
* This must be called before calling pvRecordField.addListener.
|
||||||
|
* @param pvListener The listener.
|
||||||
|
* @return <b>true</b> if the listener was added.
|
||||||
|
*/
|
||||||
bool addListener(PVListenerPtr const & pvListener);
|
bool addListener(PVListenerPtr const & pvListener);
|
||||||
|
/**
|
||||||
|
* Remove a listener.
|
||||||
|
* @param pvListener The listener.
|
||||||
|
* @return <b>true</b> if the listener was removed.
|
||||||
|
*/
|
||||||
bool removeListener(PVListenerPtr const & pvListener);
|
bool removeListener(PVListenerPtr const & pvListener);
|
||||||
|
/**
|
||||||
|
* Begins a group of puts.
|
||||||
|
*/
|
||||||
void beginGroupPut();
|
void beginGroupPut();
|
||||||
|
/**
|
||||||
|
* Ends a group of puts.
|
||||||
|
*/
|
||||||
void endGroupPut();
|
void endGroupPut();
|
||||||
|
/**
|
||||||
|
* Virtual method of <b>Requester</b>
|
||||||
|
* @return the name of the requester.
|
||||||
|
*/
|
||||||
epics::pvData::String getRequesterName() {return getRecordName();}
|
epics::pvData::String getRequesterName() {return getRecordName();}
|
||||||
|
/**
|
||||||
|
* Can be called by implementation code.
|
||||||
|
* The message will be sent to every requester.
|
||||||
|
* @param message The message.
|
||||||
|
* @param messageType The severity of the message.
|
||||||
|
*/
|
||||||
virtual void message(
|
virtual void message(
|
||||||
epics::pvData::String const & message,
|
epics::pvData::String const & message,
|
||||||
epics::pvData::MessageType messageType);
|
epics::pvData::MessageType messageType);
|
||||||
|
/**
|
||||||
|
* Called for a field. It will call the previous method
|
||||||
|
* after adding field name.
|
||||||
|
* @param pvRecordField The field for which the message is associated.
|
||||||
|
* @param message The message.
|
||||||
|
* @param messageType The severity of the message.
|
||||||
|
*/
|
||||||
void message(
|
void message(
|
||||||
PVRecordFieldPtr const & pvRecordField,
|
PVRecordFieldPtr const & pvRecordField,
|
||||||
epics::pvData::String const & message,
|
epics::pvData::String const & message,
|
||||||
epics::pvData::MessageType messageType);
|
epics::pvData::MessageType messageType);
|
||||||
|
/**
|
||||||
|
* Calls the next method with indentLevel = 0.
|
||||||
|
* @param buf String Builder.
|
||||||
|
*/
|
||||||
void toString(epics::pvData::StringBuilder buf);
|
void toString(epics::pvData::StringBuilder buf);
|
||||||
|
/**
|
||||||
|
* Dumps the data from the top level PVStructure.
|
||||||
|
* @param buf String Builder.
|
||||||
|
* @param indentLevel The indentation level.
|
||||||
|
*/
|
||||||
void toString(epics::pvData::StringBuilder buf,int indentLevel);
|
void toString(epics::pvData::StringBuilder buf,int indentLevel);
|
||||||
//init MUST be called by derived class after derived class is constructed
|
|
||||||
virtual bool init() {initPVRecord(); return true;}
|
|
||||||
virtual void process() {}
|
|
||||||
protected:
|
protected:
|
||||||
|
/**
|
||||||
|
* Initializes the base class. Must be called by derived classes.
|
||||||
|
*/
|
||||||
void initPVRecord();
|
void initPVRecord();
|
||||||
|
/**
|
||||||
|
* Convience method for derived classes.
|
||||||
|
* @return The shared pointer to the top level PVStructure.
|
||||||
|
*/
|
||||||
|
epics::pvData::PVStructurePtr getPVStructure();
|
||||||
PVRecordPtr getPtrSelf()
|
PVRecordPtr getPtrSelf()
|
||||||
{
|
{
|
||||||
return shared_from_this();
|
return shared_from_this();
|
||||||
@ -107,25 +257,82 @@ private:
|
|||||||
bool isDestroyed;
|
bool isDestroyed;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for a field of a record.
|
||||||
|
* One exists for each field of the top level PVStructure.
|
||||||
|
* @author mrk
|
||||||
|
*/
|
||||||
class PVRecordField :
|
class PVRecordField :
|
||||||
public virtual epics::pvData::PostHandler,
|
public virtual epics::pvData::PostHandler,
|
||||||
public std::tr1::enable_shared_from_this<PVRecordField>
|
public std::tr1::enable_shared_from_this<PVRecordField>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
POINTER_DEFINITIONS(PVRecordField);
|
POINTER_DEFINITIONS(PVRecordField);
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
* @param pvField The field from the top level structure.
|
||||||
|
* @param The parent.
|
||||||
|
*/
|
||||||
PVRecordField(
|
PVRecordField(
|
||||||
epics::pvData::PVFieldPtr const & pvField,
|
epics::pvData::PVFieldPtr const & pvField,
|
||||||
PVRecordStructurePtr const &parent,
|
PVRecordStructurePtr const &parent,
|
||||||
PVRecordPtr const & pvRecord);
|
PVRecordPtr const & pvRecord);
|
||||||
|
/**
|
||||||
|
* Destructor.
|
||||||
|
*/
|
||||||
virtual ~PVRecordField();
|
virtual ~PVRecordField();
|
||||||
|
/**
|
||||||
|
* Get the parent.
|
||||||
|
* @return The parent.
|
||||||
|
*/
|
||||||
PVRecordStructurePtr getParent();
|
PVRecordStructurePtr getParent();
|
||||||
|
/**
|
||||||
|
* Get the PVField.
|
||||||
|
* @return The shared pointer.
|
||||||
|
*/
|
||||||
epics::pvData::PVFieldPtr getPVField();
|
epics::pvData::PVFieldPtr getPVField();
|
||||||
|
/**
|
||||||
|
* Get the full name of the field, i.e. field,field,..
|
||||||
|
* @return The full name.
|
||||||
|
*/
|
||||||
epics::pvData::String getFullFieldName();
|
epics::pvData::String getFullFieldName();
|
||||||
|
/**
|
||||||
|
* Get the recordName plus the full name of the field, i.e. recordName.field,field,..
|
||||||
|
* @return The name.
|
||||||
|
*/
|
||||||
epics::pvData::String getFullName();
|
epics::pvData::String getFullName();
|
||||||
|
/**
|
||||||
|
* Returns the PVRecord to which this field belongs.
|
||||||
|
* @return The shared pointer,
|
||||||
|
*/
|
||||||
PVRecordPtr getPVRecord();
|
PVRecordPtr getPVRecord();
|
||||||
|
/**
|
||||||
|
* Add A PVListener to this field.
|
||||||
|
* Whenever this field or any subfield if this field is modified the listener will be notified.
|
||||||
|
* PVListener is described below.
|
||||||
|
* Before a listener can call addListener it must first call PVRecord.registerListener.
|
||||||
|
* @param pvListener The listener.
|
||||||
|
* @return <b<true</b> if listener is added.
|
||||||
|
*/
|
||||||
bool addListener(PVListenerPtr const & pvListener);
|
bool addListener(PVListenerPtr const & pvListener);
|
||||||
|
/**
|
||||||
|
* Remove a listener.
|
||||||
|
* @param pvListener The listener.
|
||||||
|
* @return <b<true</b> if listener is removed.
|
||||||
|
*/
|
||||||
virtual void removeListener(PVListenerPtr const & pvListener);
|
virtual void removeListener(PVListenerPtr const & pvListener);
|
||||||
|
/**
|
||||||
|
* This is called by the code that implements the data interface.
|
||||||
|
* It is called whenever the put method is called.
|
||||||
|
*/
|
||||||
virtual void postPut();
|
virtual void postPut();
|
||||||
|
/**
|
||||||
|
* Called by implementation code.
|
||||||
|
* It calls PVRecord::message after prepending the full fieldname.
|
||||||
|
* @param message The message,
|
||||||
|
* @param messageType The message severity.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
virtual void message(
|
virtual void message(
|
||||||
epics::pvData::String const & message,
|
epics::pvData::String const & message,
|
||||||
epics::pvData::MessageType messageType);
|
epics::pvData::MessageType messageType);
|
||||||
@ -148,19 +355,51 @@ private:
|
|||||||
friend class PVRecord;
|
friend class PVRecord;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for a field that is a structure.
|
||||||
|
* One exists for each structure field of the top level PVStructure.
|
||||||
|
* @author mrk
|
||||||
|
*/
|
||||||
class PVRecordStructure : public PVRecordField {
|
class PVRecordStructure : public PVRecordField {
|
||||||
public:
|
public:
|
||||||
POINTER_DEFINITIONS(PVRecordStructure);
|
POINTER_DEFINITIONS(PVRecordStructure);
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
* @param pvStructure The data.
|
||||||
|
* @param parent The parent
|
||||||
|
* @param pvRecord The record that has this field.
|
||||||
|
*/
|
||||||
PVRecordStructure(
|
PVRecordStructure(
|
||||||
epics::pvData::PVStructurePtr const &pvStructure,
|
epics::pvData::PVStructurePtr const &pvStructure,
|
||||||
PVRecordStructurePtr const &parent,
|
PVRecordStructurePtr const &parent,
|
||||||
PVRecordPtr const & pvRecord);
|
PVRecordPtr const & pvRecord);
|
||||||
|
/**
|
||||||
|
* Destructor.
|
||||||
|
*/
|
||||||
virtual ~PVRecordStructure();
|
virtual ~PVRecordStructure();
|
||||||
|
/**
|
||||||
|
* Get the sub fields.
|
||||||
|
* @return the array of PVRecordFieldPtr.
|
||||||
|
*/
|
||||||
PVRecordFieldPtrArrayPtr getPVRecordFields();
|
PVRecordFieldPtrArrayPtr getPVRecordFields();
|
||||||
|
/**
|
||||||
|
* Get the data structure/
|
||||||
|
* @return The shared pointer.
|
||||||
|
*/
|
||||||
epics::pvData::PVStructurePtr getPVStructure();
|
epics::pvData::PVStructurePtr getPVStructure();
|
||||||
|
/**
|
||||||
|
* Called by PVRecord::removeListener.
|
||||||
|
* @param pvListener The listener.
|
||||||
|
*/
|
||||||
virtual void removeListener(PVListenerPtr const & pvListener);
|
virtual void removeListener(PVListenerPtr const & pvListener);
|
||||||
|
/**
|
||||||
|
* Called by implementation code of PVRecord.
|
||||||
|
*/
|
||||||
virtual void postPut();
|
virtual void postPut();
|
||||||
protected:
|
protected:
|
||||||
|
/**
|
||||||
|
* Called by implementation code of PVRecord.
|
||||||
|
*/
|
||||||
virtual void init();
|
virtual void init();
|
||||||
private:
|
private:
|
||||||
epics::pvData::PVStructurePtr pvStructure;
|
epics::pvData::PVStructurePtr pvStructure;
|
||||||
@ -168,41 +407,116 @@ private:
|
|||||||
friend class PVRecord;
|
friend class PVRecord;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An interface that must be implemented by any code that accesses the record.
|
||||||
|
* @author mrk
|
||||||
|
*/
|
||||||
class PVRecordClient {
|
class PVRecordClient {
|
||||||
public:
|
public:
|
||||||
POINTER_DEFINITIONS(PVRecordClient);
|
POINTER_DEFINITIONS(PVRecordClient);
|
||||||
|
/**
|
||||||
|
* Destructor.
|
||||||
|
*/
|
||||||
virtual ~PVRecordClient() {}
|
virtual ~PVRecordClient() {}
|
||||||
|
/**
|
||||||
|
* Detach from the record because it is being removed.
|
||||||
|
* @param pvRecord The record.
|
||||||
|
*/
|
||||||
virtual void detach(PVRecordPtr const & pvRecord) = 0;
|
virtual void detach(PVRecordPtr const & pvRecord) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An interface that is implemented by code that traps calls to PVRecord::message.
|
||||||
|
* @author mrk
|
||||||
|
*/
|
||||||
class PVListener :
|
class PVListener :
|
||||||
virtual public PVRecordClient
|
virtual public PVRecordClient
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
POINTER_DEFINITIONS(PVListener);
|
POINTER_DEFINITIONS(PVListener);
|
||||||
|
/**
|
||||||
|
* Destructor.
|
||||||
|
*/
|
||||||
virtual ~PVListener() {}
|
virtual ~PVListener() {}
|
||||||
|
/**
|
||||||
|
* pvField has been modified.
|
||||||
|
* This is called if the listener has called PVRecordField::addListener for pvRecordField.
|
||||||
|
* @param pvRecordField The modified field.
|
||||||
|
*/
|
||||||
virtual void dataPut(PVRecordFieldPtr const & pvRecordField) = 0;
|
virtual void dataPut(PVRecordFieldPtr const & pvRecordField) = 0;
|
||||||
|
/**
|
||||||
|
* A subfield has been modified.
|
||||||
|
* @param requested The structure that was requested.
|
||||||
|
* @param pvRecordField The field that was modified.
|
||||||
|
*/
|
||||||
virtual void dataPut(
|
virtual void dataPut(
|
||||||
PVRecordStructurePtr const & requested,
|
PVRecordStructurePtr const & requested,
|
||||||
PVRecordFieldPtr const & pvRecordField) = 0;
|
PVRecordFieldPtr const & pvRecordField) = 0;
|
||||||
|
/**
|
||||||
|
* Begin a set of puts.
|
||||||
|
* @param pvRecord The record.
|
||||||
|
*/
|
||||||
virtual void beginGroupPut(PVRecordPtr const & pvRecord) = 0;
|
virtual void beginGroupPut(PVRecordPtr const & pvRecord) = 0;
|
||||||
|
/**
|
||||||
|
* End a set of puts.
|
||||||
|
* @param pvRecord The record.
|
||||||
|
*/
|
||||||
virtual void endGroupPut(PVRecordPtr const & pvRecord) = 0;
|
virtual void endGroupPut(PVRecordPtr const & pvRecord) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The interface to a database of PVRecords.
|
||||||
|
* @author mrk
|
||||||
|
*/
|
||||||
class PVDatabase : virtual public epics::pvData::Requester {
|
class PVDatabase : virtual public epics::pvData::Requester {
|
||||||
public:
|
public:
|
||||||
POINTER_DEFINITIONS(PVDatabase);
|
POINTER_DEFINITIONS(PVDatabase);
|
||||||
|
/**
|
||||||
|
* Get the master database.
|
||||||
|
* @return The shared pointer.
|
||||||
|
*/
|
||||||
static PVDatabasePtr getMaster();
|
static PVDatabasePtr getMaster();
|
||||||
|
/**
|
||||||
|
* Destructor
|
||||||
|
*/
|
||||||
virtual ~PVDatabase();
|
virtual ~PVDatabase();
|
||||||
|
/**
|
||||||
|
* Find a record.
|
||||||
|
* An empty pointer is returned if the record is not in the database.
|
||||||
|
* @param recordName The record to find.
|
||||||
|
* @return The shared pointer.
|
||||||
|
*/
|
||||||
PVRecordPtr findRecord(epics::pvData::String const& recordName);
|
PVRecordPtr findRecord(epics::pvData::String const& recordName);
|
||||||
|
/**
|
||||||
|
* Add a record.
|
||||||
|
* @param The record to add.
|
||||||
|
* @return <b>true</b> if record was added.
|
||||||
|
*/
|
||||||
bool addRecord(PVRecordPtr const & record);
|
bool addRecord(PVRecordPtr const & record);
|
||||||
|
/**
|
||||||
|
* Remove a record.
|
||||||
|
* @param The record to remove.
|
||||||
|
* @return <b>true</b> if record was removed.
|
||||||
|
*/
|
||||||
bool removeRecord(PVRecordPtr const & record);
|
bool removeRecord(PVRecordPtr const & record);
|
||||||
|
/**
|
||||||
|
* Virtual method of Requester.
|
||||||
|
* @return The name.
|
||||||
|
*/
|
||||||
virtual epics::pvData::String getRequesterName();
|
virtual epics::pvData::String getRequesterName();
|
||||||
|
/**
|
||||||
|
* Virtual method of Requester.
|
||||||
|
* @param message The message.
|
||||||
|
* @param messageType The message severity.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
virtual void message(
|
virtual void message(
|
||||||
epics::pvData::String const & message,
|
epics::pvData::String const & message,
|
||||||
epics::pvData::MessageType messageType);
|
epics::pvData::MessageType messageType);
|
||||||
private:
|
private:
|
||||||
PVDatabase();
|
PVDatabase();
|
||||||
|
PVRecordMap recordMap;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}}
|
}}
|
||||||
|
@ -92,6 +92,8 @@ String PVRecord::getRecordName() {return recordName;}
|
|||||||
|
|
||||||
PVRecordStructurePtr PVRecord::getPVRecordStructure() {return pvRecordStructure;}
|
PVRecordStructurePtr PVRecord::getPVRecordStructure() {return pvRecordStructure;}
|
||||||
|
|
||||||
|
PVStructurePtr PVRecord::getPVStructure() {return pvStructure;}
|
||||||
|
|
||||||
PVRecordFieldPtr PVRecord::findPVRecordField(PVFieldPtr const & pvField)
|
PVRecordFieldPtr PVRecord::findPVRecordField(PVFieldPtr const & pvField)
|
||||||
{
|
{
|
||||||
return findPVRecordField(pvRecordStructure,pvField);
|
return findPVRecordField(pvRecordStructure,pvField);
|
||||||
@ -488,42 +490,4 @@ void PVRecordStructure::postPut()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PVDatabase::PVDatabase()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
PVDatabase::~PVDatabase() {}
|
|
||||||
|
|
||||||
PVDatabasePtr PVDatabase::getMaster()
|
|
||||||
{
|
|
||||||
PVDatabasePtr xxx;
|
|
||||||
return xxx;
|
|
||||||
}
|
|
||||||
|
|
||||||
PVRecordPtr PVDatabase::findRecord(String const& recordName)
|
|
||||||
{
|
|
||||||
PVRecordPtr xxx;
|
|
||||||
return xxx;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool PVDatabase::addRecord(PVRecordPtr const & record)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool PVDatabase::removeRecord(PVRecordPtr const & record)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
String PVDatabase::getRequesterName()
|
|
||||||
{
|
|
||||||
String xxx;
|
|
||||||
return xxx;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PVDatabase::message(String const & message,MessageType messageType)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
}}
|
}}
|
||||||
|
687
src/pvAccess/channelLocal.cpp
Normal file
687
src/pvAccess/channelLocal.cpp
Normal file
@ -0,0 +1,687 @@
|
|||||||
|
/* channelLocal.cpp */
|
||||||
|
/**
|
||||||
|
* Copyright - See the COPYRIGHT that is included with this distribution.
|
||||||
|
* EPICS pvData is distributed subject to a Software License Agreement found
|
||||||
|
* in file LICENSE that is included with this distribution.
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* @author mrk
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <pv/channelProviderLocal.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;
|
||||||
|
|
||||||
|
class ChannelProcessLocal;
|
||||||
|
typedef std::tr1::shared_ptr<ChannelProcessLocal> ChannelProcessLocalPtr;
|
||||||
|
class ChannelGetLocal;
|
||||||
|
typedef std::tr1::shared_ptr<ChannelGetLocal> ChannelGetLocalPtr;
|
||||||
|
class ChannelPutLocal;
|
||||||
|
typedef std::tr1::shared_ptr<ChannelPutLocal> ChannelPutLocalPtr;
|
||||||
|
class ChannelPutGetLocal;
|
||||||
|
typedef std::tr1::shared_ptr<ChannelPutGetLocal> ChannelPutGetLocalPtr;
|
||||||
|
class ChannelMonitorLocal;
|
||||||
|
typedef std::tr1::shared_ptr<ChannelMonitorLocal> ChannelMonitorLocalPtr;
|
||||||
|
class ChannelRPCLocal;
|
||||||
|
typedef std::tr1::shared_ptr<ChannelRPCLocal> ChannelRPCLocalPtr;
|
||||||
|
class ChannelArrayLocal;
|
||||||
|
typedef std::tr1::shared_ptr<ChannelArrayLocal> ChannelArrayLocalPtr;
|
||||||
|
|
||||||
|
class ChannelLocalDebug {
|
||||||
|
public:
|
||||||
|
static void setLevel(int level);
|
||||||
|
static int getLevel();
|
||||||
|
};
|
||||||
|
|
||||||
|
static bool getProcess(PVStructurePtr pvRequest,bool processDefault)
|
||||||
|
{
|
||||||
|
PVFieldPtr pvField = pvRequest->getSubField("record._options.process");
|
||||||
|
if(pvField.get()==NULL || pvField->getField()->getType()!=scalar) {
|
||||||
|
return processDefault;
|
||||||
|
}
|
||||||
|
ScalarConstPtr scalar = static_pointer_cast<const Scalar>(
|
||||||
|
pvField->getField());
|
||||||
|
if(scalar->getScalarType()==pvString) {
|
||||||
|
PVStringPtr pvString = static_pointer_cast<PVString>(pvField);
|
||||||
|
return pvString->get().compare("true")==0 ? true : false;
|
||||||
|
} else if(scalar->getScalarType()==pvBoolean) {
|
||||||
|
PVBooleanPtr pvBoolean = static_pointer_cast<PVBoolean>(pvField);
|
||||||
|
return pvBoolean.get();
|
||||||
|
}
|
||||||
|
return processDefault;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
class ChannelRequestLocal :
|
||||||
|
public ChannelRequest
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
POINTER_DEFINITIONS(ChannelRequestLocal)
|
||||||
|
ChannelRequestLocal() :thelock(mutex) {}
|
||||||
|
virtual ~ChannelRequestLocal() {}
|
||||||
|
virtual void destroy(){}
|
||||||
|
virtual void lock() {thelock.lock();}
|
||||||
|
virtual void unlock() {thelock.unlock();}
|
||||||
|
private:
|
||||||
|
Mutex mutex;
|
||||||
|
Lock thelock;
|
||||||
|
};
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
class ChannelProcessLocal :
|
||||||
|
public ChannelProcess
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
POINTER_DEFINITIONS(ChannelProcessLocal);
|
||||||
|
virtual ~ChannelProcessLocal();
|
||||||
|
static ChannelProcess::shared_pointer create(
|
||||||
|
ChannelProviderLocalPtr const &channelProvider,
|
||||||
|
ChannelProcess::shared_pointer const & channelProcessRequester,
|
||||||
|
PVStructurePtr const & pvRequest,
|
||||||
|
PVRecordPtr const &pvRecord);
|
||||||
|
virtual void process(bool lastRequest);
|
||||||
|
};
|
||||||
|
|
||||||
|
class ChannelGetLocal :
|
||||||
|
public ChannelGet,
|
||||||
|
public std::tr1::enable_shared_from_this<ChannelGetLocal>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
POINTER_DEFINITIONS(ChannelGetLocal);
|
||||||
|
virtual ~ChannelGetLocal(){}
|
||||||
|
static ChannelGetLocalPtr create(
|
||||||
|
ChannelLocalPtr const &channelLocal,
|
||||||
|
ChannelGetRequester::shared_pointer const & channelGetRequester,
|
||||||
|
PVStructurePtr const & pvRequest,
|
||||||
|
PVRecordPtr const &pvRecord);
|
||||||
|
virtual void get(bool lastRequest);
|
||||||
|
virtual void destroy();
|
||||||
|
virtual void lock() {thelock.lock();}
|
||||||
|
virtual void unlock() {thelock.unlock();}
|
||||||
|
private:
|
||||||
|
shared_pointer getPtrSelf()
|
||||||
|
{
|
||||||
|
return shared_from_this();
|
||||||
|
}
|
||||||
|
ChannelGetLocal(
|
||||||
|
bool callProcess,
|
||||||
|
ChannelLocalPtr const &channelLocal,
|
||||||
|
ChannelGetRequester::shared_pointer const & channelGetRequester,
|
||||||
|
PVCopyPtr const &pvCopy,
|
||||||
|
PVStructurePtr const&pvStructure,
|
||||||
|
BitSetPtr const & bitSet,
|
||||||
|
PVRecordPtr const &pvRecord)
|
||||||
|
:
|
||||||
|
firstTime(true),
|
||||||
|
isDestroyed(false),
|
||||||
|
callProcess(callProcess),
|
||||||
|
channelLocal(channelLocal),
|
||||||
|
channelGetRequester(channelGetRequester),
|
||||||
|
pvCopy(pvCopy),
|
||||||
|
pvStructure(pvStructure),
|
||||||
|
bitSet(bitSet),
|
||||||
|
pvRecord(pvRecord),
|
||||||
|
thelock(mutex)
|
||||||
|
{
|
||||||
|
thelock.unlock();
|
||||||
|
}
|
||||||
|
bool firstTime;
|
||||||
|
bool isDestroyed;
|
||||||
|
bool callProcess;
|
||||||
|
ChannelLocalPtr channelLocal;
|
||||||
|
ChannelGetRequester::shared_pointer channelGetRequester,;
|
||||||
|
PVCopyPtr pvCopy;
|
||||||
|
PVStructurePtr pvStructure;
|
||||||
|
BitSetPtr bitSet;
|
||||||
|
PVRecordPtr pvRecord;
|
||||||
|
Mutex mutex;
|
||||||
|
Lock thelock;
|
||||||
|
};
|
||||||
|
|
||||||
|
ChannelGetLocalPtr ChannelGetLocal::create(
|
||||||
|
ChannelLocalPtr const &channelLocal,
|
||||||
|
ChannelGetRequester::shared_pointer const & channelGetRequester,
|
||||||
|
PVStructurePtr const & pvRequest,
|
||||||
|
PVRecordPtr const &pvRecord)
|
||||||
|
{
|
||||||
|
PVCopyPtr pvCopy = PVCopy::create(
|
||||||
|
pvRecord,
|
||||||
|
pvRequest,
|
||||||
|
"field");
|
||||||
|
if(pvCopy.get()==NULL) {
|
||||||
|
Status status(
|
||||||
|
Status::Status::STATUSTYPE_ERROR,
|
||||||
|
"invalid pvRequest");
|
||||||
|
ChannelGet::shared_pointer channelGet;
|
||||||
|
PVStructurePtr pvStructure;
|
||||||
|
BitSetPtr bitSet;
|
||||||
|
channelGetRequester->channelGetConnect(
|
||||||
|
status,
|
||||||
|
channelGet,
|
||||||
|
pvStructure,
|
||||||
|
bitSet);
|
||||||
|
ChannelGetLocalPtr localGet;
|
||||||
|
return localGet;
|
||||||
|
}
|
||||||
|
PVStructurePtr pvStructure = pvCopy->createPVStructure();
|
||||||
|
BitSetPtr bitSet(new BitSet(pvStructure->getNumberFields()));
|
||||||
|
ChannelGetLocalPtr get(new ChannelGetLocal(
|
||||||
|
getProcess(pvRequest,false),
|
||||||
|
channelLocal,
|
||||||
|
channelGetRequester,
|
||||||
|
pvCopy,
|
||||||
|
pvStructure,
|
||||||
|
bitSet,
|
||||||
|
pvRecord));
|
||||||
|
channelLocal->addChannelGet(get);
|
||||||
|
channelGetRequester->channelGetConnect(Status::Ok, get, pvStructure,bitSet);
|
||||||
|
return get;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ChannelGetLocal::destroy()
|
||||||
|
{
|
||||||
|
if(isDestroyed) return;
|
||||||
|
isDestroyed = true;
|
||||||
|
channelLocal->removeChannelGet(getPtrSelf());
|
||||||
|
channelLocal.reset();
|
||||||
|
channelGetRequester.reset();
|
||||||
|
pvCopy.reset();
|
||||||
|
pvStructure.reset();
|
||||||
|
bitSet.reset();
|
||||||
|
pvRecord.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChannelGetLocal::get(bool lastRequest)
|
||||||
|
{
|
||||||
|
if(callProcess) pvRecord->process();
|
||||||
|
if(isDestroyed) {
|
||||||
|
Status status(
|
||||||
|
Status::Status::STATUSTYPE_ERROR,
|
||||||
|
"was destroyed");
|
||||||
|
channelGetRequester->getDone(status);
|
||||||
|
}
|
||||||
|
pvCopy->updateCopySetBitSet(pvStructure, bitSet, false);
|
||||||
|
if(firstTime) {
|
||||||
|
bitSet->clear();
|
||||||
|
bitSet->set(0);
|
||||||
|
firstTime = false;
|
||||||
|
}
|
||||||
|
channelGetRequester->getDone(Status::Ok);
|
||||||
|
if(lastRequest) destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class ChannelLocalPut :
|
||||||
|
public ChannelPut
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
POINTER_DEFINITIONS(ChannelLocalPut);
|
||||||
|
virtual ~ChannelLocalPut();
|
||||||
|
static ChannelPut::shared_pointer create(
|
||||||
|
ChannelProviderLocalPtr const &channelProvider,
|
||||||
|
ChannelPut::shared_pointer const & channelPutRequester,
|
||||||
|
PVStructurePtr const & pvRequest,
|
||||||
|
PVRecordPtr const &pvRecord);
|
||||||
|
virtual void put(bool lastRequest);
|
||||||
|
virtual void get(bool lastRequest);
|
||||||
|
};
|
||||||
|
|
||||||
|
class ChannelPutGetLocal :
|
||||||
|
public ChannelPutGet
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
POINTER_DEFINITIONS(ChannelPutGetLocal);
|
||||||
|
virtual ~ChannelPutGetLocal();
|
||||||
|
static ChannelPutGet::shared_pointer create(
|
||||||
|
ChannelProviderLocalPtr const &channelProvider,
|
||||||
|
ChannelPutGet::shared_pointer const & channelPutGetRequester,
|
||||||
|
PVStructurePtr const & pvRequest,
|
||||||
|
PVRecordPtr const &pvRecord);
|
||||||
|
virtual void putGet(bool lastRequest);
|
||||||
|
virtual void getPut();
|
||||||
|
virtual void getGet();
|
||||||
|
};
|
||||||
|
|
||||||
|
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
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
POINTER_DEFINITIONS(ChannelRPCLocal);
|
||||||
|
virtual ~ChannelRPCLocal();
|
||||||
|
static ChannelRPC::shared_pointer create(
|
||||||
|
ChannelProviderLocalPtr const &channelProvider,
|
||||||
|
ChannelRPC::shared_pointer const & channelRPCRequester,
|
||||||
|
PVStructurePtr const & pvRequest,
|
||||||
|
PVRecordPtr const &pvRecord);
|
||||||
|
virtual void request(
|
||||||
|
PVStructurePtr const & pvArgument,
|
||||||
|
bool lastRequest);
|
||||||
|
};
|
||||||
|
|
||||||
|
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;}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
ChannelLocal::ChannelLocal(
|
||||||
|
ChannelProviderLocalPtr const & provider,
|
||||||
|
ChannelRequester::shared_pointer const & requester,
|
||||||
|
PVRecordPtr const & pvRecord)
|
||||||
|
: provider(provider),
|
||||||
|
requester(requester),
|
||||||
|
pvRecord(pvRecord),
|
||||||
|
beingDestroyed(false)
|
||||||
|
{
|
||||||
|
if(ChannelLocalDebug::getLevel()>0) {
|
||||||
|
printf("ChannelLocal::ChannelLocal\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ChannelLocal::~ChannelLocal()
|
||||||
|
{
|
||||||
|
if(ChannelLocalDebug::getLevel()>0) {
|
||||||
|
printf("ChannelLocal::~ChannelLocal\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChannelLocal::destroy()
|
||||||
|
{
|
||||||
|
if(ChannelLocalDebug::getLevel()>0) {
|
||||||
|
printf("ChannelLocal::destroy beingDestroyed %s\n",
|
||||||
|
(beingDestroyed ? "true" : "false"));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
Lock xx(mutex);
|
||||||
|
if(beingDestroyed) return;
|
||||||
|
beingDestroyed = true;
|
||||||
|
}
|
||||||
|
while(true) {
|
||||||
|
std::set<ChannelProcess::shared_pointer>::iterator it;
|
||||||
|
it = channelProcessList.begin();
|
||||||
|
if(it==channelProcessList.end()) break;
|
||||||
|
it->get()->destroy();
|
||||||
|
channelProcessList.erase(it);
|
||||||
|
}
|
||||||
|
while(true) {
|
||||||
|
std::set<ChannelGet::shared_pointer>::iterator it;
|
||||||
|
it = channelGetList.begin();
|
||||||
|
if(it==channelGetList.end()) break;
|
||||||
|
it->get()->destroy();
|
||||||
|
channelGetList.erase(it);
|
||||||
|
}
|
||||||
|
while(true) {
|
||||||
|
std::set<ChannelPut::shared_pointer>::iterator it;
|
||||||
|
it = channelPutList.begin();
|
||||||
|
if(it==channelPutList.end()) break;
|
||||||
|
it->get()->destroy();
|
||||||
|
channelPutList.erase(it);
|
||||||
|
}
|
||||||
|
while(true) {
|
||||||
|
std::set<ChannelPutGet::shared_pointer>::iterator it;
|
||||||
|
it = channelPutGetList.begin();
|
||||||
|
if(it==channelPutGetList.end()) break;
|
||||||
|
it->get()->destroy();
|
||||||
|
channelPutGetList.erase(it);
|
||||||
|
}
|
||||||
|
while(true) {
|
||||||
|
std::set<Monitor::shared_pointer>::iterator it;
|
||||||
|
it = channelMonitorList.begin();
|
||||||
|
if(it==channelMonitorList.end()) break;
|
||||||
|
it->get()->destroy();
|
||||||
|
channelMonitorList.erase(it);
|
||||||
|
}
|
||||||
|
while(true) {
|
||||||
|
std::set<ChannelRPC::shared_pointer>::iterator it;
|
||||||
|
it = channelRPCList.begin();
|
||||||
|
if(it==channelRPCList.end()) break;
|
||||||
|
it->get()->destroy();
|
||||||
|
channelRPCList.erase(it);
|
||||||
|
}
|
||||||
|
while(true) {
|
||||||
|
std::set<ChannelArray::shared_pointer>::iterator it;
|
||||||
|
it = channelArrayList.begin();
|
||||||
|
if(it==channelArrayList.end()) break;
|
||||||
|
it->get()->destroy();
|
||||||
|
channelArrayList.erase(it);
|
||||||
|
}
|
||||||
|
provider->removeChannel(getPtrSelf());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ChannelLocal::addChannelProcess(ChannelProcess::shared_pointer const & channelProcess)
|
||||||
|
{
|
||||||
|
if(ChannelLocalDebug::getLevel()>0) {
|
||||||
|
printf("ChannelLocal::addChannelProcess\n");
|
||||||
|
}
|
||||||
|
Lock xx(mutex);
|
||||||
|
if(beingDestroyed) return;
|
||||||
|
channelProcessList.insert(channelProcess);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChannelLocal::addChannelGet(ChannelGet::shared_pointer const &channelGet)
|
||||||
|
{
|
||||||
|
if(ChannelLocalDebug::getLevel()>0) {
|
||||||
|
printf("ChannelLocal::addChannelGet\n");
|
||||||
|
}
|
||||||
|
Lock xx(mutex);
|
||||||
|
if(beingDestroyed) return;
|
||||||
|
channelGetList.insert(channelGet);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChannelLocal::addChannelPut(ChannelPut::shared_pointer const &channelPut)
|
||||||
|
{
|
||||||
|
if(ChannelLocalDebug::getLevel()>0) {
|
||||||
|
printf("ChannelLocal::addChannelPut\n");
|
||||||
|
}
|
||||||
|
Lock xx(mutex);
|
||||||
|
if(beingDestroyed) return;
|
||||||
|
channelPutList.insert(channelPut);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChannelLocal::addChannelPutGet(ChannelPutGet::shared_pointer const &channelPutGet)
|
||||||
|
{
|
||||||
|
if(ChannelLocalDebug::getLevel()>0) {
|
||||||
|
printf("ChannelLocal::addChannelPutGet\n");
|
||||||
|
}
|
||||||
|
Lock xx(mutex);
|
||||||
|
if(beingDestroyed) return;
|
||||||
|
channelPutGetList.insert(channelPutGet);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChannelLocal::addChannelMonitor(Monitor::shared_pointer const &monitor)
|
||||||
|
{
|
||||||
|
if(ChannelLocalDebug::getLevel()>0) {
|
||||||
|
printf("ChannelLocal::addChannelMonitor\n");
|
||||||
|
}
|
||||||
|
Lock xx(mutex);
|
||||||
|
if(beingDestroyed) return;
|
||||||
|
channelMonitorList.insert(monitor);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChannelLocal::addChannelRPC(ChannelRPC::shared_pointer const &channelRPC)
|
||||||
|
{
|
||||||
|
if(ChannelLocalDebug::getLevel()>0) {
|
||||||
|
printf("ChannelLocal::addChannelRPC\n");
|
||||||
|
}
|
||||||
|
Lock xx(mutex);
|
||||||
|
if(beingDestroyed) return;
|
||||||
|
channelRPCList.insert(channelRPC);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChannelLocal::addChannelArray(ChannelArray::shared_pointer const &channelArray)
|
||||||
|
{
|
||||||
|
if(ChannelLocalDebug::getLevel()>0) {
|
||||||
|
printf("ChannelLocal::addChannelArray\n");
|
||||||
|
}
|
||||||
|
Lock xx(mutex);
|
||||||
|
if(beingDestroyed) return;
|
||||||
|
channelArrayList.insert(channelArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChannelLocal::removeChannelProcess(ChannelProcess::shared_pointer const &ref)
|
||||||
|
{
|
||||||
|
if(ChannelLocalDebug::getLevel()>0) {
|
||||||
|
printf("ChannelLocal::removeChannelProcess\n");
|
||||||
|
}
|
||||||
|
Lock xx(mutex);
|
||||||
|
if(beingDestroyed) return;
|
||||||
|
channelProcessList.erase(ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChannelLocal::removeChannelGet(ChannelGet::shared_pointer const &ref)
|
||||||
|
{
|
||||||
|
if(ChannelLocalDebug::getLevel()>0) {
|
||||||
|
printf("ChannelLocal::removeChannelGet\n");
|
||||||
|
}
|
||||||
|
Lock xx(mutex);
|
||||||
|
if(beingDestroyed) return;
|
||||||
|
channelGetList.erase(ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChannelLocal::removeChannelPut(ChannelPut::shared_pointer const &ref)
|
||||||
|
{
|
||||||
|
if(ChannelLocalDebug::getLevel()>0) {
|
||||||
|
printf("ChannelLocal::removeChannelPut\n");
|
||||||
|
}
|
||||||
|
Lock xx(mutex);
|
||||||
|
if(beingDestroyed) return;
|
||||||
|
channelPutList.erase(ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChannelLocal::removeChannelPutGet(ChannelPutGet::shared_pointer const &ref)
|
||||||
|
{
|
||||||
|
if(ChannelLocalDebug::getLevel()>0) {
|
||||||
|
printf("ChannelLocal::removeChannelPutGet\n");
|
||||||
|
}
|
||||||
|
Lock xx(mutex);
|
||||||
|
if(beingDestroyed) return;
|
||||||
|
channelPutGetList.erase(ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChannelLocal::removeChannelMonitor(Monitor::shared_pointer const &ref)
|
||||||
|
{
|
||||||
|
if(ChannelLocalDebug::getLevel()>0) {
|
||||||
|
printf("ChannelLocal::removeChannelMonitor\n");
|
||||||
|
}
|
||||||
|
Lock xx(mutex);
|
||||||
|
if(beingDestroyed) return;
|
||||||
|
channelMonitorList.erase(ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChannelLocal::removeChannelRPC(ChannelRPC::shared_pointer const &ref)
|
||||||
|
{
|
||||||
|
if(ChannelLocalDebug::getLevel()>0) {
|
||||||
|
printf("ChannelLocal::removeChannelRPC\n");
|
||||||
|
}
|
||||||
|
Lock xx(mutex);
|
||||||
|
if(beingDestroyed) return;
|
||||||
|
channelRPCList.erase(ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChannelLocal::removeChannelArray(ChannelArray::shared_pointer const &ref)
|
||||||
|
{
|
||||||
|
if(ChannelLocalDebug::getLevel()>0) {
|
||||||
|
printf("ChannelLocal::removeChannelArray\n");
|
||||||
|
}
|
||||||
|
Lock xx(mutex);
|
||||||
|
if(beingDestroyed) return;
|
||||||
|
channelArrayList.erase(ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
String ChannelLocal::getRequesterName()
|
||||||
|
{
|
||||||
|
return requester->getRequesterName();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChannelLocal::message(
|
||||||
|
String const &message,
|
||||||
|
MessageType messageType)
|
||||||
|
{
|
||||||
|
requester->message(message,messageType);
|
||||||
|
}
|
||||||
|
|
||||||
|
ChannelProvider::shared_pointer ChannelLocal::getProvider()
|
||||||
|
{
|
||||||
|
return provider;
|
||||||
|
}
|
||||||
|
|
||||||
|
String ChannelLocal::getRemoteAddress()
|
||||||
|
{
|
||||||
|
return String("local");
|
||||||
|
}
|
||||||
|
|
||||||
|
Channel::ConnectionState ChannelLocal::getConnectionState()
|
||||||
|
{
|
||||||
|
return Channel::CONNECTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
String ChannelLocal::getChannelName()
|
||||||
|
{
|
||||||
|
return pvRecord->getRecordName();
|
||||||
|
}
|
||||||
|
|
||||||
|
ChannelRequester::shared_pointer ChannelLocal::getChannelRequester()
|
||||||
|
{
|
||||||
|
return requester;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ChannelLocal::isConnected()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChannelLocal::getField(GetFieldRequester::shared_pointer const &requester,
|
||||||
|
String const &subField)
|
||||||
|
{
|
||||||
|
Status status(Status::STATUSTYPE_ERROR,
|
||||||
|
String("client asked for illegal field"));
|
||||||
|
requester->getDone(status,FieldConstPtr());
|
||||||
|
}
|
||||||
|
|
||||||
|
AccessRights ChannelLocal::getAccessRights(
|
||||||
|
PVField::shared_pointer const &pvField)
|
||||||
|
{
|
||||||
|
throw std::logic_error(String("Not Implemented"));
|
||||||
|
}
|
||||||
|
|
||||||
|
ChannelProcess::shared_pointer ChannelLocal::createChannelProcess(
|
||||||
|
ChannelProcessRequester::shared_pointer const & channelProcessRequester,
|
||||||
|
PVStructure::shared_pointer const & pvRequest)
|
||||||
|
{
|
||||||
|
Status status(Status::STATUSTYPE_ERROR,
|
||||||
|
String("ChannelProcess not supported"));
|
||||||
|
channelProcessRequester->channelProcessConnect(
|
||||||
|
status,
|
||||||
|
ChannelProcess::shared_pointer());
|
||||||
|
return ChannelProcess::shared_pointer();
|
||||||
|
}
|
||||||
|
|
||||||
|
ChannelGet::shared_pointer ChannelLocal::createChannelGet(
|
||||||
|
ChannelGetRequester::shared_pointer const &channelGetRequester,
|
||||||
|
PVStructure::shared_pointer const &pvRequest)
|
||||||
|
{
|
||||||
|
ChannelGetLocalPtr channelGet =
|
||||||
|
ChannelGetLocal::create(
|
||||||
|
getPtrSelf(),
|
||||||
|
channelGetRequester,
|
||||||
|
pvRequest,
|
||||||
|
pvRecord);
|
||||||
|
return channelGet;
|
||||||
|
}
|
||||||
|
|
||||||
|
ChannelPut::shared_pointer ChannelLocal::createChannelPut(
|
||||||
|
ChannelPutRequester::shared_pointer const &channelPutRequester,
|
||||||
|
PVStructure::shared_pointer const &pvRequest)
|
||||||
|
{
|
||||||
|
Status status(Status::STATUSTYPE_ERROR,
|
||||||
|
String("ChannelPut not supported"));
|
||||||
|
channelPutRequester->channelPutConnect(
|
||||||
|
status,
|
||||||
|
ChannelPut::shared_pointer(),
|
||||||
|
PVStructure::shared_pointer(),
|
||||||
|
BitSet::shared_pointer());
|
||||||
|
return ChannelPut::shared_pointer();
|
||||||
|
}
|
||||||
|
|
||||||
|
ChannelPutGet::shared_pointer ChannelLocal::createChannelPutGet(
|
||||||
|
ChannelPutGetRequester::shared_pointer const &channelPutGetRequester,
|
||||||
|
PVStructure::shared_pointer const &pvRequest)
|
||||||
|
{
|
||||||
|
Status status(Status::STATUSTYPE_ERROR,
|
||||||
|
String("ChannelPutGet not supported"));
|
||||||
|
channelPutGetRequester->channelPutGetConnect(
|
||||||
|
status,
|
||||||
|
ChannelPutGet::shared_pointer(),
|
||||||
|
PVStructure::shared_pointer(),
|
||||||
|
PVStructure::shared_pointer());
|
||||||
|
return ChannelPutGet::shared_pointer();
|
||||||
|
}
|
||||||
|
|
||||||
|
ChannelRPC::shared_pointer ChannelLocal::createChannelRPC(
|
||||||
|
ChannelRPCRequester::shared_pointer const & channelRPCRequester,
|
||||||
|
PVStructure::shared_pointer const & pvRequest)
|
||||||
|
{
|
||||||
|
Status status(Status::STATUSTYPE_ERROR,
|
||||||
|
String("ChannelRPC not supported"));
|
||||||
|
channelRPCRequester->channelRPCConnect(status,ChannelRPC::shared_pointer());
|
||||||
|
return ChannelRPC::shared_pointer();
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
ChannelArray::shared_pointer ChannelLocal::createChannelArray(
|
||||||
|
ChannelArrayRequester::shared_pointer const &channelArrayRequester,
|
||||||
|
PVStructure::shared_pointer const &pvRequest)
|
||||||
|
{
|
||||||
|
Status status(Status::STATUSTYPE_ERROR,
|
||||||
|
String("ChannelArray not supported"));
|
||||||
|
channelArrayRequester->channelArrayConnect(
|
||||||
|
status,
|
||||||
|
ChannelArray::shared_pointer(),
|
||||||
|
PVArray::shared_pointer());
|
||||||
|
return ChannelArray::shared_pointer();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChannelLocal::printInfo()
|
||||||
|
{
|
||||||
|
printf("ChannelLocal provides access to service\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChannelLocal::printInfo(StringBuilder out)
|
||||||
|
{
|
||||||
|
*out += "ChannelLocal provides access to service";
|
||||||
|
}
|
||||||
|
|
||||||
|
}}
|
222
src/pvAccess/channelProviderLocal.cpp
Normal file
222
src/pvAccess/channelProviderLocal.cpp
Normal file
@ -0,0 +1,222 @@
|
|||||||
|
/* channelChannelProviderLocal.cpp */
|
||||||
|
/**
|
||||||
|
* Copyright - See the COPYRIGHT that is included with this distribution.
|
||||||
|
* EPICS pvData is distributed subject to a Software License Agreement found
|
||||||
|
* in file LICENSE that is included with this distribution.
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* @author mrk
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <pv/serverContext.h>
|
||||||
|
#include <pv/channelProviderLocal.h>
|
||||||
|
|
||||||
|
namespace epics { namespace pvDatabase {
|
||||||
|
|
||||||
|
using namespace epics::pvData;
|
||||||
|
using namespace epics::pvAccess;
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
static String providerName("local");
|
||||||
|
|
||||||
|
class LocalChannelCTX;
|
||||||
|
typedef std::tr1::shared_ptr<LocalChannelCTX> LocalChannelCTXPtr;
|
||||||
|
class LocalChannelCTX :
|
||||||
|
public epics::pvData::Runnable,
|
||||||
|
public std::tr1::enable_shared_from_this<LocalChannelCTX>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
POINTER_DEFINITIONS(LocalChannelCTX);
|
||||||
|
static LocalChannelCTXPtr create(
|
||||||
|
ChannelProviderLocalPtr const &channelProvider);
|
||||||
|
ChannelProviderLocalPtr getChannelProviderLocal() {return channelProvider;}
|
||||||
|
virtual ~LocalChannelCTX();
|
||||||
|
virtual void run();
|
||||||
|
private:
|
||||||
|
LocalChannelCTX(
|
||||||
|
ChannelProviderLocalPtr const &channelProvider);
|
||||||
|
shared_pointer getPtrSelf()
|
||||||
|
{
|
||||||
|
return shared_from_this();
|
||||||
|
}
|
||||||
|
epics::pvData::Event event;
|
||||||
|
ChannelProviderLocalPtr channelProvider;
|
||||||
|
epics::pvAccess::ServerContextImpl::shared_pointer ctx;
|
||||||
|
epics::pvData::Thread *thread;
|
||||||
|
};
|
||||||
|
|
||||||
|
LocalChannelCTXPtr LocalChannelCTX::create(
|
||||||
|
ChannelProviderLocalPtr const & channelProvider)
|
||||||
|
{
|
||||||
|
static LocalChannelCTXPtr pvServiceChannelCTX;
|
||||||
|
static Mutex mutex;
|
||||||
|
Lock xx(mutex);
|
||||||
|
|
||||||
|
if(pvServiceChannelCTX.get()==0) {
|
||||||
|
pvServiceChannelCTX = LocalChannelCTXPtr(
|
||||||
|
new LocalChannelCTX(channelProvider));
|
||||||
|
}
|
||||||
|
return pvServiceChannelCTX;
|
||||||
|
}
|
||||||
|
|
||||||
|
LocalChannelCTX::LocalChannelCTX(
|
||||||
|
ChannelProviderLocalPtr const &channelProvider)
|
||||||
|
:
|
||||||
|
channelProvider(channelProvider),
|
||||||
|
ctx(ServerContextImpl::create()),
|
||||||
|
thread(new Thread(
|
||||||
|
String("pvServiceChannel"),
|
||||||
|
lowerPriority,
|
||||||
|
this,
|
||||||
|
epicsThreadStackBig))
|
||||||
|
{}
|
||||||
|
|
||||||
|
LocalChannelCTX::~LocalChannelCTX()
|
||||||
|
{
|
||||||
|
ctx->shutdown();
|
||||||
|
// we need thead.waitForCompletion()
|
||||||
|
event.wait();
|
||||||
|
epicsThreadSleep(1.0);
|
||||||
|
delete thread;
|
||||||
|
}
|
||||||
|
void LocalChannelCTX::run()
|
||||||
|
{
|
||||||
|
registerChannelProvider(channelProvider);
|
||||||
|
String providerName = channelProvider->getProviderName();
|
||||||
|
ctx->setChannelProviderName(providerName);
|
||||||
|
ctx->initialize(getChannelAccess());
|
||||||
|
ctx->printInfo();
|
||||||
|
ctx->run(0);
|
||||||
|
ctx->destroy();
|
||||||
|
event.signal();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ChannelProviderLocalPtr ChannelProviderLocal::create()
|
||||||
|
{
|
||||||
|
ChannelProviderLocalPtr channelProvider(new ChannelProviderLocal());
|
||||||
|
LocalChannelCTX::create(channelProvider);
|
||||||
|
return channelProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
ChannelProviderLocal::ChannelProviderLocal()
|
||||||
|
: pvDatabase(PVDatabase::getMaster()),
|
||||||
|
beingDestroyed(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ChannelProviderLocal::~ChannelProviderLocal()
|
||||||
|
{
|
||||||
|
pvDatabase.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChannelProviderLocal::destroy()
|
||||||
|
{
|
||||||
|
Lock xx(mutex);
|
||||||
|
if(beingDestroyed) return;
|
||||||
|
unregisterChannelProvider(getPtrSelf());
|
||||||
|
beingDestroyed = true;
|
||||||
|
ChannelLocalList::iterator iter;
|
||||||
|
for(iter = channelList.begin(); iter!=channelList.end(); ++iter) {
|
||||||
|
ChannelLocalPtr channel = *iter;
|
||||||
|
channel->destroy();
|
||||||
|
}
|
||||||
|
channelList.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
String ChannelProviderLocal::getProviderName()
|
||||||
|
{
|
||||||
|
return providerName;
|
||||||
|
}
|
||||||
|
|
||||||
|
ChannelFind::shared_pointer ChannelProviderLocal::channelFind(
|
||||||
|
String const & channelName,
|
||||||
|
ChannelFindRequester::shared_pointer const &channelFindRequester)
|
||||||
|
{
|
||||||
|
Lock xx(mutex);
|
||||||
|
bool found = false;
|
||||||
|
ChannelLocalList::iterator iter;
|
||||||
|
for(iter = channelList.begin(); iter!=channelList.end(); ++iter)
|
||||||
|
{
|
||||||
|
if((*iter)->getChannelName().compare(channelName)==0) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(found) {
|
||||||
|
channelFindRequester->channelFindResult(
|
||||||
|
Status::Ok,
|
||||||
|
ChannelFind::shared_pointer(),
|
||||||
|
true);
|
||||||
|
}
|
||||||
|
PVRecordPtr pvRecord = pvDatabase->findRecord(channelName);
|
||||||
|
if(pvRecord.get()!=NULL) {
|
||||||
|
channelFindRequester->channelFindResult(
|
||||||
|
Status::Ok,
|
||||||
|
ChannelFind::shared_pointer(),
|
||||||
|
true);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Status notFoundStatus(Status::STATUSTYPE_ERROR,String("pv not found"));
|
||||||
|
channelFindRequester->channelFindResult(
|
||||||
|
notFoundStatus,
|
||||||
|
ChannelFind::shared_pointer(),
|
||||||
|
false);
|
||||||
|
}
|
||||||
|
return ChannelFind::shared_pointer();
|
||||||
|
}
|
||||||
|
|
||||||
|
Channel::shared_pointer ChannelProviderLocal::createChannel(
|
||||||
|
String const & channelName,
|
||||||
|
ChannelRequester::shared_pointer const &channelRequester,
|
||||||
|
short priority)
|
||||||
|
{
|
||||||
|
return createChannel(channelName,channelRequester,priority,"");
|
||||||
|
}
|
||||||
|
|
||||||
|
Channel::shared_pointer ChannelProviderLocal::createChannel(
|
||||||
|
String const & channelName,
|
||||||
|
ChannelRequester::shared_pointer const &channelRequester,
|
||||||
|
short priority,
|
||||||
|
String const &address)
|
||||||
|
{
|
||||||
|
Lock xx(mutex);
|
||||||
|
ChannelLocalList::iterator iter;
|
||||||
|
for(iter = channelList.begin(); iter!=channelList.end(); ++iter)
|
||||||
|
{
|
||||||
|
if((*iter)->getChannelName().compare(channelName)==0) {
|
||||||
|
return *iter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PVRecordPtr pvRecord = pvDatabase->findRecord(channelName);
|
||||||
|
if(pvRecord.get()!=NULL) {
|
||||||
|
Channel::shared_pointer channel(new ChannelLocal(
|
||||||
|
getPtrSelf(),channelRequester,pvRecord));
|
||||||
|
channelRequester->channelCreated(
|
||||||
|
Status::Ok,
|
||||||
|
channel);
|
||||||
|
return channel;
|
||||||
|
}
|
||||||
|
Status notFoundStatus(Status::STATUSTYPE_ERROR,String("pv not found"));
|
||||||
|
channelRequester->channelCreated(
|
||||||
|
notFoundStatus,
|
||||||
|
Channel::shared_pointer());
|
||||||
|
return Channel::shared_pointer();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChannelProviderLocal::removeChannel(
|
||||||
|
Channel::shared_pointer const & channel)
|
||||||
|
{
|
||||||
|
Lock xx(mutex);
|
||||||
|
if(beingDestroyed) return;
|
||||||
|
ChannelLocalList::iterator iter;
|
||||||
|
for(iter = channelList.begin(); iter!=channelList.end(); ++iter)
|
||||||
|
{
|
||||||
|
if((*iter).get()==channel.get()) {
|
||||||
|
channelList.erase(iter);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}}
|
164
src/pvAccess/channelProviderLocal.h
Normal file
164
src/pvAccess/channelProviderLocal.h
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
/* channelProviderLocal.h */
|
||||||
|
/**
|
||||||
|
* Copyright - See the COPYRIGHT that is included with this distribution.
|
||||||
|
* EPICS pvData is distributed subject to a Software License Agreement found
|
||||||
|
* in file LICENSE that is included with this distribution.
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* @author mrk
|
||||||
|
*/
|
||||||
|
#ifndef CHANNELPROVIDERLOCAL_H
|
||||||
|
#define CHANNELPROVIDERLOCAL_H
|
||||||
|
#include <string>
|
||||||
|
#include <cstring>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <memory>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
#include <pv/lock.h>
|
||||||
|
#include <pv/pvType.h>
|
||||||
|
#include <pv/pvData.h>
|
||||||
|
#include <pv/pvAccess.h>
|
||||||
|
#include <pv/pvDatabase.h>
|
||||||
|
#include <pv/status.h>
|
||||||
|
#include <pv/pvCopy.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace epics { namespace pvDatabase {
|
||||||
|
|
||||||
|
|
||||||
|
class ChannelProviderLocal;
|
||||||
|
typedef std::tr1::shared_ptr<ChannelProviderLocal> ChannelProviderLocalPtr;
|
||||||
|
class ChannelLocal;
|
||||||
|
typedef std::tr1::shared_ptr<ChannelLocal> ChannelLocalPtr;
|
||||||
|
typedef std::set<ChannelLocalPtr> ChannelLocalList;
|
||||||
|
|
||||||
|
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();
|
||||||
|
virtual epics::pvAccess::ChannelFind::shared_pointer channelFind(
|
||||||
|
epics::pvData::String const &channelName,
|
||||||
|
epics::pvAccess::ChannelFindRequester::shared_pointer const & channelFindRequester);
|
||||||
|
virtual epics::pvAccess::Channel::shared_pointer createChannel(
|
||||||
|
epics::pvData::String const &channelName,
|
||||||
|
epics::pvAccess::ChannelRequester::shared_pointer const &channelRequester,
|
||||||
|
short priority);
|
||||||
|
virtual epics::pvAccess::Channel::shared_pointer createChannel(
|
||||||
|
epics::pvData::String const &channelName,
|
||||||
|
epics::pvAccess::ChannelRequester::shared_pointer const &channelRequester,
|
||||||
|
short priority,
|
||||||
|
epics::pvData::String const &address);
|
||||||
|
void removeChannel(
|
||||||
|
epics::pvAccess::Channel::shared_pointer const &channel);
|
||||||
|
private:
|
||||||
|
shared_pointer getPtrSelf()
|
||||||
|
{
|
||||||
|
return shared_from_this();
|
||||||
|
}
|
||||||
|
ChannelProviderLocal();
|
||||||
|
|
||||||
|
PVDatabasePtr pvDatabase;
|
||||||
|
ChannelLocalList channelList;
|
||||||
|
epics::pvData::Mutex mutex;
|
||||||
|
bool beingDestroyed;
|
||||||
|
friend class ChannelProviderLocalRun;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ChannelLocal :
|
||||||
|
public epics::pvAccess::Channel,
|
||||||
|
public std::tr1::enable_shared_from_this<ChannelLocal>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
POINTER_DEFINITIONS(ChannelLocal);
|
||||||
|
ChannelLocal(
|
||||||
|
ChannelProviderLocalPtr const &channelProvider,
|
||||||
|
epics::pvAccess::ChannelRequester::shared_pointer const & requester,
|
||||||
|
PVRecordPtr const & pvRecord
|
||||||
|
);
|
||||||
|
virtual ~ChannelLocal();
|
||||||
|
virtual void destroy();
|
||||||
|
virtual epics::pvData::String getRequesterName();
|
||||||
|
virtual void message(
|
||||||
|
epics::pvData::String const & message,
|
||||||
|
epics::pvData::MessageType messageType);
|
||||||
|
virtual epics::pvAccess::ChannelProvider::shared_pointer getProvider();
|
||||||
|
virtual epics::pvData::String getRemoteAddress();
|
||||||
|
virtual epics::pvAccess::Channel::ConnectionState getConnectionState();
|
||||||
|
virtual epics::pvData::String getChannelName();
|
||||||
|
virtual epics::pvAccess::ChannelRequester::shared_pointer getChannelRequester();
|
||||||
|
virtual bool isConnected();
|
||||||
|
virtual void getField(
|
||||||
|
epics::pvAccess::GetFieldRequester::shared_pointer const &requester,
|
||||||
|
epics::pvData::String const & subField);
|
||||||
|
virtual epics::pvAccess::AccessRights getAccessRights(
|
||||||
|
epics::pvData::PVField::shared_pointer const &pvField);
|
||||||
|
virtual epics::pvAccess::ChannelProcess::shared_pointer createChannelProcess(
|
||||||
|
epics::pvAccess::ChannelProcessRequester::shared_pointer const &requester,
|
||||||
|
epics::pvData::PVStructurePtr const &pvRequest);
|
||||||
|
virtual epics::pvAccess::ChannelGet::shared_pointer createChannelGet(
|
||||||
|
epics::pvAccess::ChannelGetRequester::shared_pointer const &requester,
|
||||||
|
epics::pvData::PVStructurePtr const &pvRequest);
|
||||||
|
virtual epics::pvAccess::ChannelPut::shared_pointer createChannelPut(
|
||||||
|
epics::pvAccess::ChannelPutRequester::shared_pointer const &requester,
|
||||||
|
epics::pvData::PVStructurePtr const &pvRequest);
|
||||||
|
virtual epics::pvAccess::ChannelPutGet::shared_pointer createChannelPutGet(
|
||||||
|
epics::pvAccess::ChannelPutGetRequester::shared_pointer const &requester,
|
||||||
|
epics::pvData::PVStructurePtr const &pvRequest);
|
||||||
|
virtual epics::pvAccess::ChannelRPC::shared_pointer createChannelRPC(
|
||||||
|
epics::pvAccess::ChannelRPCRequester::shared_pointer const &requester,
|
||||||
|
epics::pvData::PVStructurePtr const &pvRequest);
|
||||||
|
virtual epics::pvData::Monitor::shared_pointer createMonitor(
|
||||||
|
epics::pvData::MonitorRequester::shared_pointer const &requester,
|
||||||
|
epics::pvData::PVStructurePtr const &pvRequest);
|
||||||
|
virtual epics::pvAccess::ChannelArray::shared_pointer createChannelArray(
|
||||||
|
epics::pvAccess::ChannelArrayRequester::shared_pointer const &requester,
|
||||||
|
epics::pvData::PVStructurePtr const &pvRequest);
|
||||||
|
virtual void printInfo();
|
||||||
|
virtual void printInfo(epics::pvData::StringBuilder out);
|
||||||
|
// following called by derived classes
|
||||||
|
void addChannelProcess(epics::pvAccess::ChannelProcess::shared_pointer const &);
|
||||||
|
void addChannelGet(epics::pvAccess::ChannelGet::shared_pointer const &);
|
||||||
|
void addChannelPut(epics::pvAccess::ChannelPut::shared_pointer const &);
|
||||||
|
void addChannelPutGet(epics::pvAccess::ChannelPutGet::shared_pointer const &);
|
||||||
|
void addChannelMonitor(epics::pvData::Monitor::shared_pointer const &);
|
||||||
|
void addChannelRPC(epics::pvAccess::ChannelRPC::shared_pointer const &);
|
||||||
|
void addChannelArray(epics::pvAccess::ChannelArray::shared_pointer const &);
|
||||||
|
void removeChannelProcess(epics::pvAccess::ChannelProcess::shared_pointer const &);
|
||||||
|
void removeChannelGet(epics::pvAccess::ChannelGet::shared_pointer const &);
|
||||||
|
void removeChannelPut(epics::pvAccess::ChannelPut::shared_pointer const &);
|
||||||
|
void removeChannelPutGet(epics::pvAccess::ChannelPutGet::shared_pointer const &);
|
||||||
|
void removeChannelMonitor(epics::pvData::Monitor::shared_pointer const &);
|
||||||
|
void removeChannelRPC(epics::pvAccess::ChannelRPC::shared_pointer const &);
|
||||||
|
void removeChannelArray(epics::pvAccess::ChannelArray::shared_pointer const &);
|
||||||
|
protected:
|
||||||
|
shared_pointer getPtrSelf()
|
||||||
|
{
|
||||||
|
return shared_from_this();
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
ChannelProviderLocalPtr provider;
|
||||||
|
epics::pvAccess::ChannelRequester::shared_pointer requester;
|
||||||
|
PVRecordPtr pvRecord;
|
||||||
|
bool beingDestroyed;
|
||||||
|
std::set<epics::pvAccess::ChannelProcess::shared_pointer> channelProcessList;
|
||||||
|
std::set<epics::pvAccess::ChannelGet::shared_pointer> channelGetList;
|
||||||
|
std::set<epics::pvAccess::ChannelPut::shared_pointer> channelPutList;
|
||||||
|
std::set<epics::pvAccess::ChannelPutGet::shared_pointer> channelPutGetList;
|
||||||
|
std::set<epics::pvData::Monitor::shared_pointer> channelMonitorList;
|
||||||
|
std::set<epics::pvAccess::ChannelRPC::shared_pointer> channelRPCList;
|
||||||
|
std::set<epics::pvAccess::ChannelArray::shared_pointer> channelArrayList;
|
||||||
|
epics::pvData::Mutex mutex;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}}
|
||||||
|
#endif /* CHANNELPROVIDERLOCAL_H */
|
@ -2,5 +2,6 @@ TOP = ..
|
|||||||
include $(TOP)/configure/CONFIG
|
include $(TOP)/configure/CONFIG
|
||||||
DIRS += record
|
DIRS += record
|
||||||
DIRS += pvCopy
|
DIRS += pvCopy
|
||||||
|
DIRS += server
|
||||||
include $(TOP)/configure/RULES_DIRS
|
include $(TOP)/configure/RULES_DIRS
|
||||||
|
|
||||||
|
17
test/server/Makefile
Normal file
17
test/server/Makefile
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
TOP=../..
|
||||||
|
|
||||||
|
include $(TOP)/configure/CONFIG
|
||||||
|
|
||||||
|
PROD_HOST += testExampleServer
|
||||||
|
testExampleServer_SRCS += testExampleServerMain.cpp
|
||||||
|
testExampleServer_LIBS += pvDatabase pvAccess pvData Com
|
||||||
|
|
||||||
|
PROD_HOST += exampleCounter
|
||||||
|
exampleCounter_SRCS += exampleCounterMain.cpp
|
||||||
|
exampleCounter_LIBS += pvDatabase pvAccess pvData Com
|
||||||
|
|
||||||
|
|
||||||
|
include $(TOP)/configure/RULES
|
||||||
|
#----------------------------------------
|
||||||
|
# ADD RULES AFTER THIS LINE
|
||||||
|
|
102
test/server/testExampleServerMain.cpp
Normal file
102
test/server/testExampleServerMain.cpp
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
/*testExampleRecordMain.cpp */
|
||||||
|
/**
|
||||||
|
* Copyright - See the COPYRIGHT that is included with this distribution.
|
||||||
|
* EPICS pvData is distributed subject to a Software License Agreement found
|
||||||
|
* in file LICENSE that is included with this distribution.
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* @author mrk
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Author: Marty Kraimer */
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <string>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <memory>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include <pv/standardField.h>
|
||||||
|
#include <pv/standardPVField.h>
|
||||||
|
#include <pv/powerSupplyRecordTest.h>
|
||||||
|
#include <pv/channelProviderLocal.h>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using std::tr1::static_pointer_cast;
|
||||||
|
using namespace epics::pvData;
|
||||||
|
using namespace epics::pvAccess;
|
||||||
|
using namespace epics::pvDatabase;
|
||||||
|
|
||||||
|
|
||||||
|
static PVStructurePtr createPowerSupply()
|
||||||
|
{
|
||||||
|
FieldCreatePtr fieldCreate = getFieldCreate();
|
||||||
|
StandardFieldPtr standardField = getStandardField();
|
||||||
|
PVDataCreatePtr pvDataCreate = getPVDataCreate();
|
||||||
|
size_t nfields = 5;
|
||||||
|
StringArray names;
|
||||||
|
names.reserve(nfields);
|
||||||
|
FieldConstPtrArray powerSupply;
|
||||||
|
powerSupply.reserve(nfields);
|
||||||
|
names.push_back("alarm");
|
||||||
|
powerSupply.push_back(standardField->alarm());
|
||||||
|
names.push_back("timeStamp");
|
||||||
|
powerSupply.push_back(standardField->timeStamp());
|
||||||
|
String properties("alarm,display");
|
||||||
|
names.push_back("voltage");
|
||||||
|
powerSupply.push_back(standardField->scalar(pvDouble,properties));
|
||||||
|
names.push_back("power");
|
||||||
|
powerSupply.push_back(standardField->scalar(pvDouble,properties));
|
||||||
|
names.push_back("current");
|
||||||
|
powerSupply.push_back(standardField->scalar(pvDouble,properties));
|
||||||
|
return pvDataCreate->createPVStructure(
|
||||||
|
fieldCreate->createStructure(names,powerSupply));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int main(int argc,char *argv[])
|
||||||
|
{
|
||||||
|
PVDatabasePtr master = PVDatabase::getMaster();
|
||||||
|
ChannelProviderLocalPtr channelProvider = ChannelProviderLocal::create();
|
||||||
|
StandardPVFieldPtr standardPVField = getStandardPVField();
|
||||||
|
String properties;
|
||||||
|
ScalarType scalarType;
|
||||||
|
String recordName;
|
||||||
|
properties = "alarm,timeStamp";
|
||||||
|
scalarType = pvDouble;
|
||||||
|
recordName = "exampleDouble";
|
||||||
|
PVStructurePtr pvStructure;
|
||||||
|
pvStructure = standardPVField->scalar(scalarType,properties);
|
||||||
|
PVRecordPtr pvRecord = PVRecord::create(recordName,pvStructure);
|
||||||
|
{
|
||||||
|
pvRecord->lock_guard();
|
||||||
|
pvRecord->process();
|
||||||
|
}
|
||||||
|
pvStructure.reset();
|
||||||
|
bool result = master->addRecord(pvRecord);
|
||||||
|
pvRecord.reset();
|
||||||
|
recordName = "powerSupplyExample";
|
||||||
|
pvStructure = createPowerSupply();
|
||||||
|
PowerSupplyRecordTestPtr psr =
|
||||||
|
PowerSupplyRecordTest::create(recordName,pvStructure);
|
||||||
|
if(psr.get()==NULL) {
|
||||||
|
cout << "PowerSupplyRecordTest::create failed" << endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
pvStructure.reset();
|
||||||
|
result = master->addRecord(psr);
|
||||||
|
cout << "result of addRecord " << recordName << " " << result << endl;
|
||||||
|
psr.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;
|
||||||
|
}
|
||||||
|
|
Reference in New Issue
Block a user