updated documentation; fixed bugs while updating documentation

This commit is contained in:
Marty Kraimer
2014-07-10 13:25:58 -04:00
parent fa53d72258
commit 2fe3e66047
13 changed files with 2242 additions and 356 deletions

View 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
View 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

View File

@ -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&gt; 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&gt; 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-&gt;addRecord(pvRecord);
if(pvRecord==NULL) {
cout &lt;&lt; "RecordListRecord::create failed" &lt;&lt; endl;
} else {
result = master->addRecord(pvRecord);
if(!result) cout&lt;&lt; "record " &lt;&lt; recordName &lt;&lt; " not added" &lt;&lt; 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 &amp; pvField);
bool addRequester(epics::pvData::RequesterPtr const &amp; requester);
bool removeRequester(epics::pvData::RequesterPtr const &amp; 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 &amp; pvListener);
void beginGroupPut();
void endGroupPut();
std::string getRequesterName() {return getRecordName();}
virtual void message(
std::string const &amp; message,
epics::pvData::MessageType messageType);
void message(
PVRecordFieldPtr const &amp; pvRecordField,
std::string const &amp; 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 &amp; pvListener);
virtual void removeListener(PVListenerPtr const &amp; pvListener);
virtual void postPut();
virtual void message(
std::string const &amp; 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 &amp; pvStructure,
PVRecordFieldPtrArrayPtr const &amp; pvRecordField);
PVRecordStructurePtr const &amp; parent,
PVRecordPtr const &amp; pvRecord);
virtual ~PVRecordStructure();
virtual void destroy();
PVRecordFieldPtrArrayPtr getPVRecordFields();
@ -901,9 +864,6 @@ public:
epics::pvData::PVStringArrayPtr getRecordNames();
bool removeRecord(PVRecordPtr const &amp; record);
virtual std::string getRequesterName();
virtual void message(
std::string const &amp;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&gt;=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 &amp; pvRecord,
MonitorRequester::shared_pointer const &amp; monitorRequester,
PVStructurePtr const &amp; pvRequest);
static void registerMonitorAlgorithmCreater(
MonitorAlgorithmCreatePtr const &amp; monitorAlgorithmCreate,
String const &amp; 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&lt;&lt; "record " &lt;&lt; recordName &lt;&lt; " not added" &lt
</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-&gt;addRecord(pvRecord);
if(!result) cout&lt;&lt; "record " &lt;&lt; recordName &lt;&lt; " not added" &lt;&lt; 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 &amp; recordName)
{
StandardPVFieldPtr standardPVField = getStandardPVField();
StandardFieldPtr standardField = getStandardField();
FieldCreatePtr fieldCreate = getFieldCreate();
PVDataCreatePtr pvDataCreate = getPVDataCreate();
PVStructurePtr pvArgument = standardPVField-&gt;scalar(pvString,"");
PVStructurePtr pvResult = standardPVField-&gt;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-&gt;createPVStructure(names,fields);
StructureConstPtr topStructure = fieldCreate-&gt;createFieldBuilder()-&gt;
addNestedStructure("argument")-&gt;
add("value",pvString)-&gt;
endNested()-&gt;
addNestedStructure("result") -&gt;
add("value",pvString) -&gt;
add("timeStamp",standardField-&gt;timeStamp()) -&gt;
endNested()-&gt;
createStructure();
PVStructurePtr pvStructure = pvDataCreate-&gt;createPVStructure(topStructure);
ExampleServerPtr pvRecord(
new ExampleServer(recordName,pvStructure));
if(!pvRecord-&gt;init()) pvRecord.reset();
@ -1364,15 +1249,23 @@ int main(int argc,char *argv[])
String recordName("exampleServer");
PVRecordPtr pvRecord = ExampleServer::create(recordName);
bool result = master-&gt;addRecord(pvRecord);
cout &lt;&lt; "result of addRecord " &lt;&lt; recordName &lt;&lt; " " &lt;&lt; result &lt;&lt; endl;
pvRecord.reset();
startPVAServer(PVACCESS_ALL_PROVIDERS,0,true,true);
cout &lt;&lt; "exampleServer\n";
if(!result) cout&lt;&lt; "record " &lt;&lt; recordName &lt;&lt; " not added" &lt;&lt; endl;
recordName = "traceRecordPGRPC";
pvRecord = TraceRecord::create(recordName);
result = master-&gtr;addRecord(pvRecord);
if(!result) cout&lt;&lt; "record " &lt;&lt; recordName &lt;&lt; " not added" &lt;&lt; endl;
recordName = "recordListPGRPC";
pvRecord = RecordListRecord::create(recordName);
result = master-&gtr;addRecord(pvRecord);
if(!result) cout&lt;&lt; "record " &lt;&lt; recordName &lt;&lt; " not added" &lt;&lt; endl;
ServerContext::shared_pointer pvaServer =
startPVAServer(PVACCESS_ALL_PROVIDERS,0,true,true);
PVStringArrayPtr pvNames = master-&gtr;getRecordNames();
shared_vector&lt;const string&gtr; names = pvNames-&gtr;view();
for(size_t i=0; i&lt;names.size(); ++i) cout &lt;&lt; names[i] &lt;&lt; endl;
string str;
while(true) {
cout &lt;&lt; "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&gt; ../../../bin/linux-x86_64/exampleServer st.cmd
<p>You can then issue the commands dbl and pvdbl:
<pre>
epics&gt; dbl
double01
pvdouble
pvcounter
pvenum
pvdoubleArray
pvstringArray
epics&gt; pvdbl
exampleServer
epics&gt;
</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-&gt;getProvider(providerName);
ChannelProvider::shared_pointer provider =
getChannelProviderRegistry()-&gt;getProvider(providerName);
Channel::shared_pointer channel = provider-&gt;createChannel(channelName,channelRequester);
</pre>

File diff suppressed because it is too large Load Diff

View File

@ -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()

View File

@ -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;
}
}

View File

@ -1,4 +1,5 @@
include "base.dbd"
include "PVAClientRegister.dbd"
include "PVAServerRegister.dbd"
include "registerChannelProviderLocal.dbd"
include "dbPv.dbd"

View File

@ -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();

View File

@ -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";

View File

@ -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 ";

View File

@ -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;
};
}}

View File

@ -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));

View File

@ -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;
}