updated documentation; fixed bugs while updating documentation
This commit is contained in:
50
documentation/RELEASE_NOTES.md
Normal file
50
documentation/RELEASE_NOTES.md
Normal file
@ -0,0 +1,50 @@
|
||||
Release release/0.9.3 IN DEVELOPMENT
|
||||
===========
|
||||
|
||||
The main changes since release 3.0.2 are:
|
||||
|
||||
* array semantics now enforce Copy On Write.
|
||||
* String no longer defined.
|
||||
* toString replaced by stream I/O
|
||||
* union is new type.
|
||||
* copy and monitor use new code in pvDataCPP
|
||||
|
||||
New Semantics for Arrays
|
||||
--------
|
||||
|
||||
pvDatabaseCPP has been changed to use the new array implementation from pvDataCPP.
|
||||
|
||||
String no longer defined
|
||||
---------
|
||||
|
||||
String is replaced by std::string.
|
||||
|
||||
|
||||
toString replaced by stream I/O
|
||||
---------
|
||||
|
||||
All uses of toString have been changed to use the steam I/O that pvDataCPP implements.
|
||||
|
||||
|
||||
union is a new basic type.
|
||||
------------
|
||||
|
||||
exampleDatabase now has example records for union and union array.
|
||||
There are records for regular union and for variant union.
|
||||
|
||||
|
||||
copy
|
||||
----
|
||||
|
||||
|
||||
The implementation of copy and monitor for pvAccess has been changed
|
||||
to use the new monitor and copy support from pvDataCPP.
|
||||
|
||||
monitorPlugin
|
||||
-------------
|
||||
|
||||
exampleDatabase now has a example plugin that implements onChange.
|
||||
|
||||
Release 0.9.2
|
||||
==========
|
||||
This was the starting point for RELEASE_NOTES
|
25
documentation/TODO.md
Normal file
25
documentation/TODO.md
Normal file
@ -0,0 +1,25 @@
|
||||
TODO
|
||||
===========
|
||||
|
||||
|
||||
|
||||
monitorPlugin
|
||||
-------------
|
||||
|
||||
A debate is on-going about what semantics should be.
|
||||
|
||||
|
||||
memory leak
|
||||
--------
|
||||
|
||||
arrayPerformanceMain shows a slight memory leak at termination.
|
||||
|
||||
channel destroy and recreate
|
||||
-------------------
|
||||
|
||||
longArrayGet and longArrayPut fail if the channel is destroyed and immediately recreated. If epicsThreadSleep(1.0) is called between destroy and recreate then they work. The current version of each does wait.
|
||||
|
||||
create more regresion tests
|
||||
----------------
|
||||
|
||||
Currently only some simple tests exist. Most of the testing has been via the examples
|
@ -38,7 +38,7 @@
|
||||
<h1>pvDatabaseCPP</h1>
|
||||
<!-- Maturity: Working Draft or Request for Comments, or Recommendation, and date. -->
|
||||
|
||||
<h2 class="nocount">EPICS v4 Working Group, Working Draft, 19-Feb-2014</h2>
|
||||
<h2 class="nocount">EPICS v4 Working Group, Working Draft, 10-July-2014</h2>
|
||||
<dl>
|
||||
<dt>Latest version:</dt>
|
||||
<dd><a
|
||||
@ -46,12 +46,12 @@
|
||||
</dd>
|
||||
<dt>This version:</dt>
|
||||
<dd><a
|
||||
href= "pvDatabaseCPP_20140219.html">pvDatabaseCPP20140219.html</a>
|
||||
</dd>
|
||||
href= "pvDatabaseCPP_20140710.html">pvDatabaseCPP20140710.html
|
||||
</a> </dd>
|
||||
<dt>Previous version:</dt>
|
||||
<dd><a
|
||||
href= "pvDatabaseCPP_20140207.html">pvDatabaseCPP20140207.html</a>
|
||||
</dd>
|
||||
href= "pvDatabaseCPP_20140219.html">pvDatabaseCPP20140219.html
|
||||
</a> </dd>
|
||||
<dt>Editors:</dt>
|
||||
<dd>Marty Kraimer, BNL</dd>
|
||||
</dl>
|
||||
@ -59,7 +59,6 @@
|
||||
<p class="copyright">This product is made available subject to acceptance of the <a
|
||||
href="http://epics-pvdata.sourceforge.net/LICENSE.html">EPICS open source license.</a></p>
|
||||
<hr />
|
||||
</div>
|
||||
|
||||
<h2 class="nocount">Abstract</h2>
|
||||
|
||||
@ -79,54 +78,10 @@ V4 control system programming environment:<br />
|
||||
|
||||
<h2 class="nocount">Status of this Document</h2>
|
||||
|
||||
<p>This is the 19-Feb-2014 version of of pvDatabaseCPP.</p>
|
||||
<p>This is the 10-July-2014 version of of pvDatabaseCPP.</p>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Since the last version of the documentation:
|
||||
<dl>
|
||||
<dt>examples</dt>
|
||||
<dd>The examples have been moved to separate top level build areas.</dd>
|
||||
<dt>test</dt>
|
||||
<dd>The regression tests have been moved to a separate top level build area.
|
||||
It is built from the top but nothing from the tests appears in the top
|
||||
level bin directory.
|
||||
<dt>exampleServer</dt>
|
||||
<dd>This example now also includes pvaSrv, i. e. the pvAccess server for
|
||||
interfacing to iocCore V3 records.
|
||||
</dd>
|
||||
</dl>
|
||||
<p>
|
||||
This project is ready for alpha users.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
I have not had time to look at
|
||||
two unresolved problems reported in the previous version of this document:
|
||||
<dl>
|
||||
<dt>memory leak</dt>
|
||||
<dd>arrayPerformanceMain shows a slight memory leak at termination.</dd>
|
||||
<dt>channel destroy and recreate</dt>
|
||||
<dd>longArrayGet and longArrayPut fail if the channel is destroyed and
|
||||
immediately recreated.
|
||||
If epicsThreadSleep(1.0) is called between destroy and recreate then they work.
|
||||
The current version of each does wait.
|
||||
</dd>
|
||||
</dl>
|
||||
</p>
|
||||
<p>Future enhancements in priority order:</p>
|
||||
<dl>
|
||||
<dt>channelArray</dt>
|
||||
<dd>The arguments that have type <b>int</b> should be changed to <b>size_t</b>.
|
||||
This requires changes to pvAccessCPP.
|
||||
</dd>
|
||||
<dt>Monitor Algorithms</dt>
|
||||
<dd>Monitor algorithms have not been implemented.
|
||||
Thus all monitors are onPut.</dd>
|
||||
<dt>Create more regression tests</dt>
|
||||
<dd>Currently only some simple tests exist.
|
||||
Most of the testing has been via the examples.</dd>
|
||||
</dl>
|
||||
<p>This version is a complete implementation of what is described in this manual.
|
||||
</div>
|
||||
|
||||
<div id="toc">
|
||||
<h2 class="nocount" style="page-break-before: always">Table of Contents</h2>
|
||||
@ -343,13 +298,14 @@ completion of later phases.
|
||||
The rest of this document discusses only the first phase.</p>
|
||||
<h3>Features Required for localChannelProvider</h3>
|
||||
<dl>
|
||||
<dt>pvCopy</dt>
|
||||
<dd>Creates a PVStructure that contains a copy of an arbitary
|
||||
subset of the fields of another top level PVStructure.
|
||||
It can copy data between the two and maintains a bitSet that show
|
||||
which fields are changed.<dd>
|
||||
<dt>monitor</dt>
|
||||
<dd>This provides the ability to monitor changes to fields of a record.</dd>
|
||||
<dt>copy and monitor</dt>
|
||||
<dd>pvDataCPP provides facilities copy and monitor.
|
||||
This facilities allow a client to access an arbitrary subset
|
||||
of the fields in the top level structure associated with a channel,
|
||||
and to monitor changes in the top level structure.
|
||||
pvDatabaseCPP uses what pvDataCPP provides and has code that
|
||||
associates these facilities with a PVRecord.
|
||||
</dd>
|
||||
<dt>PVRecord and PVDatabase</dt>
|
||||
<dd>Defined below.</dd>
|
||||
<dt>The localChannelProvider itself</dt>
|
||||
@ -435,6 +391,22 @@ mrk> make
|
||||
<p>This builds the example.</p>
|
||||
|
||||
<h2>iocshell commands</h2>
|
||||
<p>Shell commands are made available via the standard DBD include mechanism
|
||||
provided by iocCore.
|
||||
The following provide EPICS V4 shell commands:</p>
|
||||
<dl>
|
||||
<dt>pvAccessCPP</dt>
|
||||
<dd>PVAClientRegister.dbd and PVAServerRegister.dbd</dd>
|
||||
<dt>pvaSrv</dt>
|
||||
<dd>dbPv.dbd</dd>
|
||||
<dt>pvDatabaseCPP</dt>
|
||||
<dd>registerChannelProviderLocal.dbd</dd>
|
||||
</dl>
|
||||
<p>
|
||||
Look at exampleServer/ioc/src/exampleServerInclude.dbd for an example
|
||||
of how an application can make the shell commands available.
|
||||
</p>
|
||||
<h3>Commands From pvAccessCPP</h3>
|
||||
<p>The following iocsh commands are provided for a V3IOC:</p>
|
||||
<dl>
|
||||
<dt>startPVAClient</dt>
|
||||
@ -449,16 +421,25 @@ mrk> make
|
||||
<dd>Starts the local channel provider</p>
|
||||
<dt>stopPVAServer</dt>
|
||||
<dd>Stop the local channel provider</dd>
|
||||
</dl>
|
||||
</p>
|
||||
<h3>Commands implemented by pvDatabaseCPP</h3>
|
||||
<p>The following iocsh commands are provided for a V3IOC:</p>
|
||||
<dl>
|
||||
<dt>pvdbl</dt>
|
||||
<dd>Provides a list of all the pvRecords in database <b>master</b>
|
||||
</dd>
|
||||
</dl>
|
||||
<p>The client commands are provided via PVAClientRegister.dbd and the other commands
|
||||
via PVAServerRegister.dbd.</p>
|
||||
<p>In addition any code that implements a PVRecord must implement an ioc command.
|
||||
The directory example has examples of how to implement the registration code.
|
||||
See example/V3IOC/exampleCounter/src/ for a simple example.</p>
|
||||
|
||||
<p>In addition any code that implements a PVRecord must implement an ioc command.</p>
|
||||
<p>Look at any of the examples to see how to implement shell commands.</p>
|
||||
<h3>Commands implemented by pvaSrv</h3>
|
||||
<p><b>pvaSrv</b> provides a pvAccess server that provides access to iocCore records.</p>
|
||||
<p>pvaSrv does not provide any shell commands but it can be part of an IOC.
|
||||
Just make sure your application configures pvaSrv and then include the following file:
|
||||
<pre>
|
||||
include "dbPv.dbd"
|
||||
</pre>
|
||||
</p>
|
||||
|
||||
<h2>database</h2>
|
||||
<h3>src/database</h3>
|
||||
@ -492,7 +473,12 @@ See example/V3IOC/exampleCounter/src/ for a simple example.</p>
|
||||
<pre>
|
||||
recordName = "laptoprecordListPGRPC";
|
||||
pvRecord = RecordListRecord::create(recordName);
|
||||
result = master->addRecord(pvRecord);
|
||||
if(pvRecord==NULL) {
|
||||
cout << "RecordListRecord::create failed" << endl;
|
||||
} else {
|
||||
result = master->addRecord(pvRecord);
|
||||
if(!result) cout<< "record " << recordName << " not added" << endl;
|
||||
}
|
||||
</pre>
|
||||
</dd>
|
||||
<dt>traceRecord.h</dt>
|
||||
@ -571,6 +557,7 @@ public:
|
||||
POINTER_DEFINITIONS(PVRecord);
|
||||
|
||||
virtual bool init() {initPVRecord(); return true;}
|
||||
virtual void start() {}
|
||||
virtual void process() {}
|
||||
virtual void destroy();
|
||||
|
||||
@ -582,9 +569,6 @@ public:
|
||||
PVRecordStructurePtr getPVRecordStructure();
|
||||
PVRecordFieldPtr findPVRecordField(
|
||||
epics::pvData::PVFieldPtr const & pvField);
|
||||
bool addRequester(epics::pvData::RequesterPtr const & requester);
|
||||
bool removeRequester(epics::pvData::RequesterPtr const & requester);
|
||||
inline void lock_guard() { epics::pvData::Lock theLock(mutex); }
|
||||
void lock();
|
||||
void unlock();
|
||||
bool tryLock();
|
||||
@ -596,16 +580,6 @@ public:
|
||||
bool removeListener(PVListenerPtr const & pvListener);
|
||||
void beginGroupPut();
|
||||
void endGroupPut();
|
||||
std::string getRequesterName() {return getRecordName();}
|
||||
virtual void message(
|
||||
std::string const & message,
|
||||
epics::pvData::MessageType messageType);
|
||||
void message(
|
||||
PVRecordFieldPtr const & pvRecordField,
|
||||
std::string const & message,
|
||||
epics::pvData::MessageType messageType);
|
||||
void toString(epics::pvData::StringBuilder buf);
|
||||
void toString(epics::pvData::StringBuilder buf,int indentLevel);
|
||||
int getTraceLevel();
|
||||
void setTraceLevel(int level);
|
||||
protected:
|
||||
@ -629,19 +603,28 @@ private:
|
||||
Derived classes must implement this method.
|
||||
This method Must call initPVRecord.
|
||||
</dd>
|
||||
<dt>start</dt>
|
||||
<dd>Virtual method.
|
||||
Optional method for derived class.
|
||||
It is called before record is added to database.
|
||||
The base method does nothing.
|
||||
</dd>
|
||||
<dt>process</dt>
|
||||
<dd>Virtual method.
|
||||
Derived classes must implement this method.
|
||||
Derived classes usually implement this method.
|
||||
It implements the semantics for the record.
|
||||
The base implementation does nothing.
|
||||
</dd>
|
||||
<dt>destroy</dt>
|
||||
<dd>This is a virtual method.
|
||||
A derived class must call the base class destroy method after it
|
||||
<dd>Virtual method.
|
||||
Optional method for derived class.
|
||||
If the derived class implements this it
|
||||
must call the base class destroy method after it
|
||||
has released any resources it uses.</dd>
|
||||
<dt>create</dt>
|
||||
<dd>Static method to create dumb records,
|
||||
i.e. records with a process method that does nothing.
|
||||
A derived class should have it';s own static create method.
|
||||
A derived class should have it's own static create method.
|
||||
</dd>
|
||||
<dt>~PVRecord</dt>
|
||||
<dd>The destructor which must be virtual. A derived class must also have
|
||||
@ -652,13 +635,6 @@ private:
|
||||
<dd>Get the top level PVStructure.</dd>
|
||||
<dt>findPVRecordField</dt>
|
||||
<dd>Given a PVFieldPtr return the PVRecordFieldPtr for the field.</dd>
|
||||
<dt>addRequester</dt>
|
||||
<dd>Add a requester to receive messages.</dd>
|
||||
<dt>removeRequester</dt>
|
||||
<dd>Remove a message requester.</dd>
|
||||
<dt>lock_guard</dt>
|
||||
<dd>This is an inline method that locks the record. The record will automatically
|
||||
be unlocked when control leaves the block that has the call.
|
||||
<dt>lock</dt>
|
||||
<dt>unlock</dt>
|
||||
<dd>Lock and Unlock the record.
|
||||
@ -691,14 +667,6 @@ private:
|
||||
<dt>endGroupPut</dt>
|
||||
<dd>End a group of puts.
|
||||
This results in all registered PVListeners being called.</dd>
|
||||
<dt>getRequesterName</dt>
|
||||
<dd>virtual method of Requester
|
||||
</dd>
|
||||
<dt>message</dt>
|
||||
<dd>Can be called by implementation code.
|
||||
The message will be sent to every requester.</dd>
|
||||
<dt>toString</dt>
|
||||
<dd>Just calls the top level PVStructure toString method.</dd>
|
||||
<dt>getTraceLevel</dt>
|
||||
<dd>This can be used for debugging. There are currently three
|
||||
levels that are used by existing code.
|
||||
@ -748,9 +716,6 @@ public:
|
||||
bool addListener(PVListenerPtr const & pvListener);
|
||||
virtual void removeListener(PVListenerPtr const & pvListener);
|
||||
virtual void postPut();
|
||||
virtual void message(
|
||||
std::string const & message,
|
||||
epics::pvData::MessageType messageType);
|
||||
protected:
|
||||
PVRecordFieldPtr getPtrSelf()
|
||||
{
|
||||
@ -794,9 +759,6 @@ that holds the data. It has the following methods:
|
||||
<dt>postPut</dt>
|
||||
<dd>This is called by the code that implements the data interface.
|
||||
It is called whenever the put method is called.</dd>
|
||||
<dt>message</dt>
|
||||
<dd>Called by implementation code. It calls PVRecord::message after prepending the full
|
||||
fieldname.</dd>
|
||||
</dl>
|
||||
<h3>class PVRecordStructure</h3>
|
||||
<pre>
|
||||
@ -805,7 +767,8 @@ public:
|
||||
POINTER_DEFINITIONS(PVRecordStructure);
|
||||
PVRecordStructure(
|
||||
epics::pvData::PVStructurePtr const & pvStructure,
|
||||
PVRecordFieldPtrArrayPtr const & pvRecordField);
|
||||
PVRecordStructurePtr const & parent,
|
||||
PVRecordPtr const & pvRecord);
|
||||
virtual ~PVRecordStructure();
|
||||
virtual void destroy();
|
||||
PVRecordFieldPtrArrayPtr getPVRecordFields();
|
||||
@ -901,9 +864,6 @@ public:
|
||||
epics::pvData::PVStringArrayPtr getRecordNames();
|
||||
bool removeRecord(PVRecordPtr const & record);
|
||||
virtual std::string getRequesterName();
|
||||
virtual void message(
|
||||
std::string const &message,
|
||||
epics::pvData::MessageType messageType);
|
||||
private:
|
||||
PVDatabase();
|
||||
};
|
||||
@ -929,98 +889,14 @@ private:
|
||||
If the record was not in the database false is returned.</dd>
|
||||
<dt>getRequesterName</dt>
|
||||
<dd>Virtual method of Requester</dd>
|
||||
<dt>message</dt>
|
||||
<dd>Virtual message of Requester.</dd>
|
||||
</dl>
|
||||
<h2>pvAccess</h2>
|
||||
<p>This is code that provides an implementation of channelProvider as
|
||||
defined by pvAccess.
|
||||
It provides access to PVRecords and is access by the server side of remote pvAccess.</p>
|
||||
<h3>channelProviderLocal</h3>
|
||||
<p>This is a complete implementation of channelProvider and ,
|
||||
except for channelRPC, provides a complete implementation of Channel
|
||||
as defined by pvAccess.
|
||||
For monitors it calls the code described in the following sections.</p>
|
||||
<h3>pvCopy</h3>
|
||||
<p>This provides code that creates a top level PVStructure that is an arbitrary
|
||||
subset of the fields in the PVStructure from a PVRecord.
|
||||
In addition it provides code that monitors changes to the fields in a PVRecord.
|
||||
A client configures the desired set of subfields and monitoring options
|
||||
via a pvRequest structure.
|
||||
pvAccess provides a class CreatePVRequest that creates a pvRequest.
|
||||
The pvCopy code provides the same functionality as the pvCopy code in pvIOCJava.
|
||||
It provides access to PVRecords and is accessed by the server side of remote pvAccess.
|
||||
It uses the copy and monitor facilities from pvDataCPP and connects
|
||||
them to a PVRecord.
|
||||
</p>
|
||||
<h3>monitorAlgorithm</h3>
|
||||
<p>Currently all that is implemented is a header file.
|
||||
The only algorithm currently implemented is <b>onPut</b>
|
||||
</p>
|
||||
<h3>monitorFactory</h3>
|
||||
<h4>Overview</h4>
|
||||
<p><b>epics::pvData::monitor</b> defines the monitor interfaces
|
||||
as seen by a client.
|
||||
See
|
||||
<a href="http://epics-pvdata.sourceforge.net/docbuild/pvDatabaseCPP/tip/documentation/pvDatabaseCPP.html">pvDatabaseCPP.html</a>
|
||||
For details.</p>
|
||||
<p>
|
||||
monitorFactory implements the
|
||||
monitoring interfaces for a PVRecord.
|
||||
It implements queueSize=0 and queueSize>=2.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The implementation uses PVCopy and PVCopyMonitor which are implemented in pvCopy.
|
||||
When PVCopyMonitor tells monitor that changes
|
||||
have occurred, monitor applies the appropriate algorithm to each changed field.</p>
|
||||
|
||||
<p>Currently only algorithm <b>onPut</b> is implemented but,
|
||||
like pvIOCJava there are plans to support for the following monitor algorithms:</p>
|
||||
<dl>
|
||||
<dt>onPut</dt>
|
||||
<dd>A monitor is issued whenever a put is issued to the field. This is the
|
||||
default unless the record defines deadbands for a field. An exception is
|
||||
the top level timeStamp which by default is made onChange and monitor
|
||||
will not be raised.</dd>
|
||||
<dt>onChange</dt>
|
||||
<dd>This provides two options: 1) A monitor is raised whenever a field
|
||||
changes value, and 2) A monitor will never be raised for the field.</dd>
|
||||
<dt>deadband</dt>
|
||||
<dd>The field must be a numeric scalar. Whenever the absolute or percentage
|
||||
value of the field changes by more than a deadband a monitor is issued.
|
||||
The record instance can also define deadbands.</dd>
|
||||
<dt>periodic</dt>
|
||||
<dd>A monitor is issued at a periodic rate if a put was issued to any field
|
||||
being monitored.</dd>
|
||||
</dl>
|
||||
<h4>MonitorFactory</h4>
|
||||
<p>MonitorFactory provides the following methods:</p>
|
||||
<pre>class MonitorFactory
|
||||
{
|
||||
static MonitorPtr create(
|
||||
PVRecordPtr const & pvRecord,
|
||||
MonitorRequester::shared_pointer const & monitorRequester,
|
||||
PVStructurePtr const & pvRequest);
|
||||
static void registerMonitorAlgorithmCreater(
|
||||
MonitorAlgorithmCreatePtr const & monitorAlgorithmCreate,
|
||||
String const & algorithmName);
|
||||
}</pre>
|
||||
|
||||
<p>where</p>
|
||||
<dl>
|
||||
<dt>create</dt>
|
||||
<dd>Create a monitor. The arguments are:
|
||||
<dl>
|
||||
<dt>pvRecord</dt>
|
||||
<dd>The record being monitored.</dd>
|
||||
<dt>monitorRequester</dt>
|
||||
<dd>The monitor requester. This is the code to which monitot events
|
||||
will be delivered.</dd>
|
||||
<dt>pvRequest</dt>
|
||||
<dd>The request options</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dt>registerMonitorAlgorithmCreater</dt>
|
||||
<dd>Called by code that implements a monitor algorithm.</dd>
|
||||
</dl>
|
||||
<h2>special</h2>
|
||||
<p>This section provides two useful record support modules
|
||||
and one that is used for testing.</p>
|
||||
@ -1030,7 +906,7 @@ the trace level of a record. It follows the pattern of a channelPutGet
|
||||
record:
|
||||
<pre>
|
||||
traceRecord
|
||||
structure arguments
|
||||
structure argument
|
||||
string recordName
|
||||
int level 0
|
||||
structure result
|
||||
@ -1071,17 +947,18 @@ if(!result) cout<< "record " << recordName << " not added" <
|
||||
</pre>
|
||||
</p>
|
||||
<h3>recordList</h3>
|
||||
<p>This implements a PVRecord that allows a client to set
|
||||
the trace level of a record. It follows the pattern of a channelPutGet
|
||||
<p>This implements a PVRecord that allows a client to
|
||||
get the names of all the PVRecords in the PVDatabase.
|
||||
It follows the pattern of a channelPutGet
|
||||
record:
|
||||
<pre>
|
||||
traceRecord
|
||||
structure arguments
|
||||
structure argument
|
||||
string database master
|
||||
string regularExpression .*
|
||||
structure result
|
||||
string status
|
||||
string[] names
|
||||
string[] name
|
||||
</pre>
|
||||
where:
|
||||
<dl>
|
||||
@ -1092,8 +969,8 @@ where:
|
||||
returned.</dd>
|
||||
<dt>status</dt>
|
||||
<dd>The status of a putGet request.</dd>
|
||||
<dt>names</dt>
|
||||
<dd>The list of record names.</dd>
|
||||
<dt>name</dt>
|
||||
<dd>The array of record names.</dd>
|
||||
</dl>
|
||||
<p>Note that swtshell, which is a Java GUI tool, has a command <b>channelList</b> that
|
||||
requires that a record of this type is present and calls it.
|
||||
@ -1101,7 +978,7 @@ Thus user code does not have to use a channelGetPut to get the list
|
||||
of record names.</p>
|
||||
<p>testExampleServerMain.cpp has an example of how to create a traceRecord:
|
||||
<pre>
|
||||
recordName = "laptoprecordListPGRPC";
|
||||
recordName = "recordListPGRPC";
|
||||
pvRecord = RecordListRecord::create(recordName);
|
||||
result = master->addRecord(pvRecord);
|
||||
if(!result) cout<< "record " << recordName << " not added" << endl;
|
||||
@ -1151,6 +1028,7 @@ exampleServer
|
||||
exampleServerInclude.dbd
|
||||
exampleServerMain.cpp
|
||||
exampleServerRegister.cpp
|
||||
exampleServerRegister.dbd
|
||||
ioc
|
||||
Db
|
||||
...
|
||||
@ -1165,7 +1043,10 @@ exampleServer
|
||||
where
|
||||
<dl>
|
||||
<dt>ExampleRELEASE.local</dt>
|
||||
<dd>This is the file that must be copied to RELEASE.local
|
||||
<dd>
|
||||
If you make a copy of exampleServer and use it
|
||||
to create a new server,
|
||||
This is the file that must be copied to RELEASE.local
|
||||
and edited.</dd>
|
||||
<dt>exampleServer.h</dt>
|
||||
<dd>The header file for the service.</dd>
|
||||
@ -1182,6 +1063,9 @@ where
|
||||
<dt>exampleServerRegister.cpp</dt>
|
||||
<dd>This has the code to start the service via the following iocsh
|
||||
command.
|
||||
<dt>exampleServerRegister.dbd</dt>
|
||||
<dd>This is the file that is used to create the shell command
|
||||
exampleServerCreateRecord.</dd>
|
||||
<pre>
|
||||
exampleServerCreateRecord exampleServer
|
||||
</pre>
|
||||
@ -1273,19 +1157,20 @@ private:
|
||||
ExampleServerPtr ExampleServer::create(
|
||||
std::string const & recordName)
|
||||
{
|
||||
StandardPVFieldPtr standardPVField = getStandardPVField();
|
||||
StandardFieldPtr standardField = getStandardField();
|
||||
FieldCreatePtr fieldCreate = getFieldCreate();
|
||||
PVDataCreatePtr pvDataCreate = getPVDataCreate();
|
||||
PVStructurePtr pvArgument = standardPVField->scalar(pvString,"");
|
||||
PVStructurePtr pvResult = standardPVField->scalar(pvString,"timeStamp");
|
||||
StringArray names;
|
||||
names.reserve(2);
|
||||
PVFieldPtrArray fields;
|
||||
fields.reserve(2);
|
||||
names.push_back("argument");
|
||||
fields.push_back(pvArgument);
|
||||
names.push_back("result");
|
||||
fields.push_back(pvResult);
|
||||
PVStructurePtr pvStructure = pvDataCreate->createPVStructure(names,fields);
|
||||
StructureConstPtr topStructure = fieldCreate->createFieldBuilder()->
|
||||
addNestedStructure("argument")->
|
||||
add("value",pvString)->
|
||||
endNested()->
|
||||
addNestedStructure("result") ->
|
||||
add("value",pvString) ->
|
||||
add("timeStamp",standardField->timeStamp()) ->
|
||||
endNested()->
|
||||
createStructure();
|
||||
PVStructurePtr pvStructure = pvDataCreate->createPVStructure(topStructure);
|
||||
|
||||
ExampleServerPtr pvRecord(
|
||||
new ExampleServer(recordName,pvStructure));
|
||||
if(!pvRecord->init()) pvRecord.reset();
|
||||
@ -1364,15 +1249,23 @@ int main(int argc,char *argv[])
|
||||
String recordName("exampleServer");
|
||||
PVRecordPtr pvRecord = ExampleServer::create(recordName);
|
||||
bool result = master->addRecord(pvRecord);
|
||||
cout << "result of addRecord " << recordName << " " << result << endl;
|
||||
pvRecord.reset();
|
||||
startPVAServer(PVACCESS_ALL_PROVIDERS,0,true,true);
|
||||
cout << "exampleServer\n";
|
||||
if(!result) cout<< "record " << recordName << " not added" << endl;
|
||||
recordName = "traceRecordPGRPC";
|
||||
pvRecord = TraceRecord::create(recordName);
|
||||
result = master->r;addRecord(pvRecord);
|
||||
if(!result) cout<< "record " << recordName << " not added" << endl;
|
||||
recordName = "recordListPGRPC";
|
||||
pvRecord = RecordListRecord::create(recordName);
|
||||
result = master->r;addRecord(pvRecord);
|
||||
if(!result) cout<< "record " << recordName << " not added" << endl;
|
||||
ServerContext::shared_pointer pvaServer =
|
||||
startPVAServer(PVACCESS_ALL_PROVIDERS,0,true,true);
|
||||
PVStringArrayPtr pvNames = master->r;getRecordNames();
|
||||
shared_vector<const string>r; names = pvNames->r;view();
|
||||
for(size_t i=0; i<names.size(); ++i) cout << names[i] << endl;
|
||||
string str;
|
||||
while(true) {
|
||||
cout << "Type exit to stop: \n";
|
||||
getline(cin,str);
|
||||
if(str.compare("exit")==0) break;
|
||||
|
||||
}
|
||||
return 0;
|
||||
@ -1382,9 +1275,9 @@ This:
|
||||
<ul>
|
||||
<li>Gets a pointer to the master database.</li>
|
||||
<li>Creates the local Channel Provider. This starts the pvAccess server.</li>
|
||||
<li>Creates a ExampleServer record with the name exampleServer
|
||||
</li>
|
||||
<li>Prints exampleServer on standard out.</li>
|
||||
<li>Creates record exampleServer </li>
|
||||
<li>creates records traceRecordPGRPC and recordListPGRPC</li>
|
||||
<li>lists all the records</li>
|
||||
<li>Runs forever until the user types exit on standard in.</li>
|
||||
</ul>
|
||||
<h3>V3IOC exampleServer</h3>
|
||||
@ -1397,16 +1290,20 @@ mrk> ../../../bin/linux-x86_64/exampleServer st.cmd
|
||||
<p>You can then issue the commands dbl and pvdbl:
|
||||
<pre>
|
||||
epics> dbl
|
||||
double01
|
||||
pvdouble
|
||||
pvcounter
|
||||
pvenum
|
||||
pvdoubleArray
|
||||
pvstringArray
|
||||
epics> pvdbl
|
||||
exampleServer
|
||||
epics>
|
||||
</pre>
|
||||
double01 is a v3Record.
|
||||
exampleServer is a pvRecord.
|
||||
dbl shows the V3 records.
|
||||
pvdbl shows the pvRecords.
|
||||
</p>
|
||||
<p>
|
||||
It starts pvASrv so that the V3 records can be accessed via Channel Access
|
||||
It starts pvaSrv so that the V3 records can be accessed via Channel Access
|
||||
or via PVAccess.</p>
|
||||
|
||||
<h2>exampleDatabase</h2>
|
||||
@ -1511,8 +1408,8 @@ Once the client and local provider code has started then the following creates a
|
||||
</p>
|
||||
<pre>
|
||||
PVDatabasePtr master = PVDatabase::getMaster();
|
||||
ChannelAccess::shared_pointer channelAccess = getChannelAccess();
|
||||
ChannelProvider::shared_pointer provider = channelAccess->getProvider(providerName);
|
||||
ChannelProvider::shared_pointer provider =
|
||||
getChannelProviderRegistry()->getProvider(providerName);
|
||||
Channel::shared_pointer channel = provider->createChannel(channelName,channelRequester);
|
||||
</pre>
|
||||
|
||||
|
1940
documentation/pvDatabaseCPP_20140710.html
Normal file
1940
documentation/pvDatabaseCPP_20140710.html
Normal file
File diff suppressed because it is too large
Load Diff
@ -16,6 +16,8 @@ dbLoadRecords("db/dbDouble.db","name=double05")
|
||||
dbLoadRecords("db/dbStringArray.db","name=stringArray01")
|
||||
dbLoadRecords("db/dbEnum.db","name=enum01")
|
||||
dbLoadRecords("db/dbCounter.db","name=counter01");
|
||||
dbLoadRecords("db/dbArray.db","name=doubleArray,type=DOUBLE");
|
||||
|
||||
|
||||
cd ${TOP}/iocBoot/${IOC}
|
||||
iocInit()
|
||||
|
@ -147,17 +147,20 @@ void ExampleDatabase::create()
|
||||
createVariantUnionArrayRecord(master,"exampleVariantUnionArray");
|
||||
recordName = "examplePowerSupply";
|
||||
PVStructurePtr pvStructure = createPowerSupply();
|
||||
PowerSupplyPtr psr =
|
||||
PowerSupply::create(recordName,pvStructure);
|
||||
if(psr.get()==NULL) {
|
||||
cout << "PowerSupply::create failed" << endl;
|
||||
return;
|
||||
PowerSupplyPtr psr = PowerSupply::create(recordName,pvStructure);
|
||||
if(psr==NULL) {
|
||||
cout << "PowerSupply::create failed" << endl;
|
||||
} else {
|
||||
result = master->addRecord(psr);
|
||||
if(!result) cout<< "record " << recordName << " not added" << endl;
|
||||
}
|
||||
result = master->addRecord(psr);
|
||||
if(!result) cout<< "record " << recordName << " not added" << endl;
|
||||
recordName = "laptoprecordListPGRPC";
|
||||
pvRecord = RecordListRecord::create(recordName);
|
||||
result = master->addRecord(pvRecord);
|
||||
if(!result) cout<< "record " << recordName << " not added" << endl;
|
||||
if(pvRecord==NULL) {
|
||||
cout << "RecordListRecord::create failed" << endl;
|
||||
} else {
|
||||
result = master->addRecord(pvRecord);
|
||||
if(!result) cout<< "record " << recordName << " not added" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
include "base.dbd"
|
||||
include "PVAClientRegister.dbd"
|
||||
include "PVAServerRegister.dbd"
|
||||
include "registerChannelProviderLocal.dbd"
|
||||
include "dbPv.dbd"
|
||||
|
@ -9,7 +9,7 @@
|
||||
* @date 2013.04.02
|
||||
*/
|
||||
|
||||
#include <pv/standardPVField.h>
|
||||
#include <pv/standardField.h>
|
||||
#include <pv/exampleServer.h>
|
||||
|
||||
using namespace epics::pvData;
|
||||
@ -23,19 +23,20 @@ namespace epics { namespace exampleServer {
|
||||
ExampleServerPtr ExampleServer::create(
|
||||
string const & recordName)
|
||||
{
|
||||
StandardPVFieldPtr standardPVField = getStandardPVField();
|
||||
StandardFieldPtr standardField = getStandardField();
|
||||
FieldCreatePtr fieldCreate = getFieldCreate();
|
||||
PVDataCreatePtr pvDataCreate = getPVDataCreate();
|
||||
PVStructurePtr pvArgument = standardPVField->scalar(pvString,"");
|
||||
PVStructurePtr pvResult = standardPVField->scalar(pvString,"timeStamp");
|
||||
StringArray names;
|
||||
names.reserve(2);
|
||||
PVFieldPtrArray fields;
|
||||
fields.reserve(2);
|
||||
names.push_back("argument");
|
||||
fields.push_back(pvArgument);
|
||||
names.push_back("result");
|
||||
fields.push_back(pvResult);
|
||||
PVStructurePtr pvStructure = pvDataCreate->createPVStructure(names,fields);
|
||||
StructureConstPtr topStructure = fieldCreate->createFieldBuilder()->
|
||||
addNestedStructure("argument")->
|
||||
add("value",pvString)->
|
||||
endNested()->
|
||||
addNestedStructure("result") ->
|
||||
add("value",pvString) ->
|
||||
add("timeStamp",standardField->timeStamp()) ->
|
||||
endNested()->
|
||||
createStructure();
|
||||
PVStructurePtr pvStructure = pvDataCreate->createPVStructure(topStructure);
|
||||
|
||||
ExampleServerPtr pvRecord(
|
||||
new ExampleServer(recordName,pvStructure));
|
||||
if(!pvRecord->init()) pvRecord.reset();
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include <pv/standardPVField.h>
|
||||
#include <pv/exampleServer.h>
|
||||
#include <pv/traceRecord.h>
|
||||
#include <pv/recordList.h>
|
||||
#include <pv/channelProviderLocal.h>
|
||||
#include <pv/serverContext.h>
|
||||
|
||||
@ -42,15 +43,20 @@ int main(int argc,char *argv[])
|
||||
recordName = "exampleServer";
|
||||
pvRecord = ExampleServer::create(recordName);
|
||||
result = master->addRecord(pvRecord);
|
||||
cout << "result of addRecord " << recordName << " " << result << endl;
|
||||
if(!result) cout<< "record " << recordName << " not added" << endl;
|
||||
recordName = "traceRecordPGRPC";
|
||||
pvRecord = TraceRecord::create(recordName);
|
||||
result = master->addRecord(pvRecord);
|
||||
if(!result) cout<< "record " << recordName << " not added" << endl;
|
||||
pvRecord.reset();
|
||||
recordName = "recordListPGRPC";
|
||||
pvRecord = RecordListRecord::create(recordName);
|
||||
result = master->addRecord(pvRecord);
|
||||
if(!result) cout<< "record " << recordName << " not added" << endl;
|
||||
ServerContext::shared_pointer pvaServer =
|
||||
startPVAServer(PVACCESS_ALL_PROVIDERS,0,true,true);
|
||||
cout << "exampleServer\n";
|
||||
PVStringArrayPtr pvNames = master->getRecordNames();
|
||||
shared_vector<const string> names = pvNames->view();
|
||||
for(size_t i=0; i<names.size(); ++i) cout << names[i] << endl;
|
||||
string str;
|
||||
while(true) {
|
||||
cout << "Type exit to stop: \n";
|
||||
|
@ -24,26 +24,16 @@ RecordListRecordPtr RecordListRecord::create(
|
||||
{
|
||||
FieldCreatePtr fieldCreate = getFieldCreate();
|
||||
PVDataCreatePtr pvDataCreate = getPVDataCreate();
|
||||
StringArray argNames(2);
|
||||
FieldConstPtrArray argFields(2);
|
||||
argNames[0] = "database";
|
||||
argFields[0] = fieldCreate->createScalar(pvString);
|
||||
argNames[1] = "regularExpression";
|
||||
argFields[1] = fieldCreate->createScalar(pvString);
|
||||
StringArray resNames(2);
|
||||
FieldConstPtrArray resFields(2);
|
||||
resNames[0] = "status";
|
||||
resFields[0] = fieldCreate->createScalar(pvString);
|
||||
resNames[1] = "names";
|
||||
resFields[1] = fieldCreate->createScalarArray(pvString);
|
||||
StringArray topNames(2);
|
||||
FieldConstPtrArray topFields(2);
|
||||
topNames[0] = "argument";
|
||||
topFields[0] = fieldCreate->createStructure(argNames,argFields);
|
||||
topNames[1] = "result";
|
||||
topFields[1] = fieldCreate->createStructure(resNames,resFields);
|
||||
StructureConstPtr topStructure =
|
||||
fieldCreate->createStructure(topNames,topFields);
|
||||
StructureConstPtr topStructure = fieldCreate->createFieldBuilder()->
|
||||
addNestedStructure("argument")->
|
||||
add("database",pvString)->
|
||||
add("regularExpression",pvString)->
|
||||
endNested()->
|
||||
addNestedStructure("result") ->
|
||||
add("status",pvString) ->
|
||||
addArray("name",pvString) ->
|
||||
endNested()->
|
||||
createStructure();
|
||||
PVStructurePtr pvStructure = pvDataCreate->createPVStructure(topStructure);
|
||||
RecordListRecordPtr pvRecord(
|
||||
new RecordListRecord(recordName,pvStructure));
|
||||
@ -78,21 +68,21 @@ bool RecordListRecord::init()
|
||||
if(regularExpression.get()==NULL) return false;
|
||||
status = pvStructure->getStringField("result.status");
|
||||
if(status.get()==NULL) return false;
|
||||
PVFieldPtr pvField = pvStructure->getSubField("result.names");
|
||||
PVFieldPtr pvField = pvStructure->getSubField("result.name");
|
||||
if(pvField.get()==NULL) {
|
||||
std::cerr << "no result.names" << std::endl;
|
||||
std::cerr << "no result.name" << std::endl;
|
||||
return false;
|
||||
}
|
||||
names = static_pointer_cast<PVStringArray>(
|
||||
pvStructure->getScalarArrayField("result.names",pvString));
|
||||
if(names.get()==NULL) return false;
|
||||
name = static_pointer_cast<PVStringArray>(
|
||||
pvStructure->getScalarArrayField("result.name",pvString));
|
||||
if(name.get()==NULL) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void RecordListRecord::process()
|
||||
{
|
||||
PVStringArrayPtr pvNames = PVDatabase::getMaster()->getRecordNames();
|
||||
names->replace(pvNames->view());
|
||||
name->replace(pvNames->view());
|
||||
string message("");
|
||||
if(database->get().compare("master")!=0) {
|
||||
message += " can only access master ";
|
||||
|
@ -37,7 +37,7 @@ private:
|
||||
epics::pvData::PVStringPtr database;
|
||||
epics::pvData::PVStringPtr regularExpression;
|
||||
epics::pvData::PVStringPtr status;
|
||||
epics::pvData::PVStringArrayPtr names;
|
||||
epics::pvData::PVStringArrayPtr name;
|
||||
};
|
||||
|
||||
}}
|
||||
|
@ -24,24 +24,15 @@ TraceRecordPtr TraceRecord::create(
|
||||
{
|
||||
FieldCreatePtr fieldCreate = getFieldCreate();
|
||||
PVDataCreatePtr pvDataCreate = getPVDataCreate();
|
||||
StringArray topNames(2);
|
||||
FieldConstPtrArray topFields(2);
|
||||
topNames[0] = "argument";
|
||||
topNames[1] = "result";
|
||||
StringArray argNames(2);
|
||||
FieldConstPtrArray argFields(2);
|
||||
argNames[0] = "recordName";
|
||||
argNames[1] = "level";
|
||||
argFields[0] = fieldCreate->createScalar(pvString);
|
||||
argFields[1] = fieldCreate->createScalar(pvInt);
|
||||
topFields[0] = fieldCreate->createStructure(argNames,argFields);
|
||||
StringArray resNames(1);
|
||||
FieldConstPtrArray resFields(1);
|
||||
resNames[0] = "status";
|
||||
resFields[0] = fieldCreate->createScalar(pvString);
|
||||
topFields[1] = fieldCreate->createStructure(resNames,resFields);
|
||||
StructureConstPtr topStructure =
|
||||
fieldCreate->createStructure(topNames,topFields);
|
||||
StructureConstPtr topStructure = fieldCreate->createFieldBuilder()->
|
||||
addNestedStructure("argument")->
|
||||
add("recordName",pvString)->
|
||||
add("level",pvInt)->
|
||||
endNested()->
|
||||
addNestedStructure("result") ->
|
||||
add("status",pvString) ->
|
||||
endNested()->
|
||||
createStructure();
|
||||
PVStructurePtr pvStructure = pvDataCreate->createPVStructure(topStructure);
|
||||
TraceRecordPtr pvRecord(
|
||||
new TraceRecord(recordName,pvStructure));
|
||||
|
@ -15,6 +15,9 @@
|
||||
|
||||
using namespace epics::pvData;
|
||||
using std::string;
|
||||
using std::cout;
|
||||
using std::cerr;
|
||||
using std::endl;
|
||||
|
||||
namespace epics { namespace pvDatabase {
|
||||
|
||||
@ -24,24 +27,23 @@ PVStructurePtr createPowerSupply()
|
||||
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));
|
||||
fieldCreate->createFieldBuilder()->
|
||||
add("alarm",standardField->alarm()) ->
|
||||
add("timeStamp",standardField->timeStamp()) ->
|
||||
addNestedStructure("power") ->
|
||||
add("value",pvDouble) ->
|
||||
add("alarm",standardField->alarm()) ->
|
||||
endNested()->
|
||||
addNestedStructure("voltage") ->
|
||||
add("value",pvDouble) ->
|
||||
add("alarm",standardField->alarm()) ->
|
||||
endNested()->
|
||||
addNestedStructure("current") ->
|
||||
add("value",pvDouble) ->
|
||||
add("alarm",standardField->alarm()) ->
|
||||
endNested()->
|
||||
createStructure());
|
||||
}
|
||||
|
||||
PowerSupplyPtr PowerSupply::create(
|
||||
@ -77,62 +79,40 @@ bool PowerSupply::init()
|
||||
PVFieldPtr pvField;
|
||||
bool result;
|
||||
pvField = pvStructure->getSubField("timeStamp");
|
||||
if(pvField.get()==NULL) {
|
||||
std::cerr << "no timeStamp" << std::endl;
|
||||
if(pvField==NULL) {
|
||||
cerr << "no timeStamp" << endl;
|
||||
return false;
|
||||
}
|
||||
result = pvTimeStamp.attach(pvField);
|
||||
if(!result) {
|
||||
std::cerr << "no timeStamp" << std::endl;
|
||||
cerr << "no timeStamp" << endl;
|
||||
return false;
|
||||
}
|
||||
pvField = pvStructure->getSubField("alarm");
|
||||
if(pvField.get()==NULL) {
|
||||
std::cerr << "no alarm" << std::endl;
|
||||
if(pvField==NULL) {
|
||||
cerr << "no alarm" << endl;
|
||||
return false;
|
||||
}
|
||||
result = pvAlarm.attach(pvField);
|
||||
if(!result) {
|
||||
std::cerr << "no alarm" << std::endl;
|
||||
cerr << "no alarm" << endl;
|
||||
return false;
|
||||
}
|
||||
string name;
|
||||
name = "current.value";
|
||||
pvField = pvStructure->getSubField(name);
|
||||
if(pvField.get()==NULL) {
|
||||
name = "current";
|
||||
pvField = pvStructure->getSubField(name);
|
||||
}
|
||||
if(pvField.get()==NULL) {
|
||||
std::cerr << "no current" << std::endl;
|
||||
pvCurrent = pvStructure->getSubField<PVDouble>("current.value");
|
||||
if(pvCurrent==NULL) {
|
||||
cerr << "no current\n";
|
||||
return false;
|
||||
}
|
||||
pvCurrent = pvStructure->getDoubleField(name);
|
||||
if(pvCurrent.get()==NULL) return false;
|
||||
name = "voltage.value";
|
||||
pvField = pvStructure->getSubField(name);
|
||||
if(pvField.get()==NULL) {
|
||||
name = "voltage";
|
||||
pvField = pvStructure->getSubField(name);
|
||||
}
|
||||
if(pvField.get()==NULL) {
|
||||
std::cerr << "no voltage" << std::endl;
|
||||
pvVoltage = pvStructure->getSubField<PVDouble>("voltage.value");
|
||||
if(pvVoltage==NULL) {
|
||||
cerr << "no current\n";
|
||||
return false;
|
||||
}
|
||||
pvVoltage = pvStructure->getDoubleField(name);
|
||||
if(pvVoltage.get()==NULL) return false;
|
||||
name = "power.value";
|
||||
pvField = pvStructure->getSubField(name);
|
||||
if(pvField.get()==NULL) {
|
||||
name = "power";
|
||||
pvField = pvStructure->getSubField(name);
|
||||
}
|
||||
if(pvField.get()==NULL) {
|
||||
std::cerr << "no power" << std::endl;
|
||||
pvPower = pvStructure->getSubField<PVDouble>("power.value");
|
||||
if(pvPower==NULL) {
|
||||
cerr << "no powert\n";
|
||||
return false;
|
||||
}
|
||||
pvPower = pvStructure->getDoubleField(name);
|
||||
if(pvPower.get()==NULL) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user