added examplePVADoubleGet; updated to latest pvDataCPP-md
This commit is contained in:
@ -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, 25-Jul-2013</h2>
|
||||
<h2 class="nocount">EPICS v4 Working Group, Working Draft, 06-Aug-2013</h2>
|
||||
<dl>
|
||||
<dt>Latest version:</dt>
|
||||
<dd><a
|
||||
@ -47,13 +47,14 @@
|
||||
<dt>This version:</dt>
|
||||
<dd><a
|
||||
href=
|
||||
"http://epics-pvdata.hg.sourceforge.net/hgweb/epics-pvdata/pvDatabaseCPP/raw-file/tip/documentation/pvDatabaseCPP_20130725.html">
|
||||
pvDatabaseCPP20130725.html</a>
|
||||
"http://epics-pvdata.hg.sourceforge.net/hgweb/epics-pvdata/pvDatabaseCPP/raw-file/tip/documentation/pvDatabaseCPP_20130806.html">
|
||||
pvDatabaseCPP20130806.html</a>
|
||||
</dd>
|
||||
<dt>Previous version:</dt>
|
||||
<dd><a
|
||||
href="http://epics-pvdata.hg.sourceforge.net/hgweb/epics-pvdata/pvDatabaseCPP/raw-file/tip/documentation/pvDatabaseCPP_20130627.html">
|
||||
pvDatabaseCPP20130627.html</a>
|
||||
href=
|
||||
"http://epics-pvdata.hg.sourceforge.net/hgweb/epics-pvdata/pvDatabaseCPP/raw-file/tip/documentation/pvDatabaseCPP_20130725.html">
|
||||
pvDatabaseCPP20130725.html</a>
|
||||
</dd>
|
||||
<dt>Editors:</dt>
|
||||
<dd>Marty Kraimer, BNL</dd>
|
||||
@ -77,7 +78,7 @@ The minimum that an extenson must provide is a top level PVStructure and a proce
|
||||
|
||||
<h2 class="nocount">Status of this Document</h2>
|
||||
|
||||
<p>This is the 25-Jul-2013 version of the definition of pvDatabaseCPP.
|
||||
<p>This is the 06-Aug-2013 version of the definition of pvDatabaseCPP.
|
||||
<p><b>NOTE:</b>
|
||||
This is built against pvDataCPP-md NOT against pvDataCPP.
|
||||
To build you must also
|
||||
@ -90,11 +91,8 @@ This project is ready for alpha users.
|
||||
</p>
|
||||
<p>Future enhancements in priority order:</p>
|
||||
<dl>
|
||||
<dt>pvAccess directly to local channelProvider</dt>
|
||||
<dd>Create an example record that communicates with another
|
||||
record via pvAccess but directly connects to channelProviderLocal.
|
||||
Thus channelGet and monitor of arrays will be done without
|
||||
copying raw array data.</dd>
|
||||
<dt>Termination issues.</dt>
|
||||
<dd>There are memory leak and other issues when either the main programs or v3IOC terminates.</dd>
|
||||
<dt>Array performance</dt>
|
||||
<dd>Create an example record that continuously creates array data.
|
||||
The idea is to compare performance allocating memory from the
|
||||
@ -105,8 +103,6 @@ This project is ready for alpha users.
|
||||
<dt>Monitor Algorithms</dt>
|
||||
<dd>Monitor algorithms have not been implemented.
|
||||
Thus all monitors are onPut.</dd>
|
||||
<dt>Memory leaks</dt>
|
||||
<dd>I think all memory leaks have been fixed.</dd>
|
||||
<dt>Testing</dt>
|
||||
<dd>Needs more testing</dd>
|
||||
</dl>
|
||||
@ -157,7 +153,13 @@ A record is smart because code can be attached to a record, which is accessed vi
|
||||
<dt>exampleServer</dt>
|
||||
<dd>This example has a set of PVRecords.
|
||||
Again the records can be deployed either as a standalone process or
|
||||
as part of a V3IOC.
|
||||
as part of a V3IOC.</dd>
|
||||
<dt>examplePVADoubleArrayGet</dt>
|
||||
<dd>This is an example PVRecord that uses channelGet to get an array of doubles from
|
||||
another PVRecord via pvAccess. The example shows how to get the value either via
|
||||
remote pvAccess or by directly accessing the local channelProvider.
|
||||
Again the records can be deployed either as a standalone process or
|
||||
as part of a V3IOC.</dd>
|
||||
</dl>
|
||||
<p><b>database</b> provides base classes that make it easy to create record instances.
|
||||
The code attached to each record must create the top
|
||||
@ -171,10 +173,10 @@ level PVStructure and the following three methods:</p>
|
||||
<dd>This is what makes a record smart.
|
||||
</dd>
|
||||
<dt>destroy</dt>
|
||||
<dd>This releases and resorurces used by the impplementation.</dd>
|
||||
<dd>This releases and resources used by the implementation.</dd>
|
||||
</dl>
|
||||
<h3>Getting started</h3>
|
||||
<p>Included with this project are two examples that are useful for
|
||||
<p>Included with this project are three examples that are useful for
|
||||
seeing how pvDatabase can be used by clients.
|
||||
Each can be deployed either as a standalone process or as part of a V3IOC.
|
||||
The examples are:
|
||||
@ -188,6 +190,10 @@ The examples are:
|
||||
<dd>This has a database with several records.</dd>
|
||||
<dt>exampleServer</dt>
|
||||
<dd>This is exampleServer as part of a V3IOC</dd>
|
||||
<dt>examplePVADoubleArrayGetMain</dt>
|
||||
<dd>This is the example of how to use pvAccess to get data.</dd>
|
||||
<dt>examplePVADoubleArrayGet</dt>
|
||||
<dd>This is examplePVADoubleArrayGet as part of a V3IOC</dd>
|
||||
</dt>
|
||||
</p>
|
||||
<h3>exampleCounter</h3>
|
||||
@ -218,24 +224,11 @@ exampleCounter is a pvRecord.
|
||||
After successfully running exampleCounterMain and exampleCounter then
|
||||
try starting exampleServerMain and exampleServer.
|
||||
</p>
|
||||
<h3>swtshell</h3>
|
||||
<p>The Java program
|
||||
<a
|
||||
href="http://epics-pvdata.hg.sourceforge.net/hgweb/epics-pvdata/swtshellJava/raw-file/tip/documentation/swtshellJava.html">
|
||||
swtshell</a>
|
||||
can be used to access pvDatabase.</p>
|
||||
<p>In particular read the sections "Getting Started" and "Simple Example".
|
||||
They will work on the exampleServer with the following differences:
|
||||
<dl>
|
||||
<dt>startExample.zip</dt>
|
||||
<dd>Do NOT use this. Instead run exampleServer</dd>
|
||||
<dt>channelList result</dt>
|
||||
<dd>The result of channelList will show the list of records that
|
||||
exampleServer has rather than the records from startExample.zip</dd>
|
||||
</dl>
|
||||
</p>
|
||||
<h3>exampleServer</h3>
|
||||
<p>The exampleServer pvDatabase includes the following records:
|
||||
<p>This example provides the exampleCounter record in addition to a number of other PVRecords.
|
||||
Like exampleCounter it can be started either as a standalone main program or as
|
||||
a part of a V3IOC.
|
||||
The exampleServer pvDatabase includes the following records:</p>
|
||||
<dl>
|
||||
<dt>exampleCounter</dt>
|
||||
<dd>A record that is an instance of exampleCounter described below.
|
||||
@ -257,6 +250,22 @@ They will work on the exampleServer with the following differences:
|
||||
<dd>This can be used via channelPutGet to set the trace level of another record.</dd>
|
||||
</dl>
|
||||
<p>It also has a number of other scalar and array records.</p>
|
||||
<h3>swtshell</h3>
|
||||
<p>The Java program
|
||||
<a
|
||||
href="http://epics-pvdata.hg.sourceforge.net/hgweb/epics-pvdata/swtshellJava/raw-file/tip/documentation/swtshellJava.html">
|
||||
swtshell</a>
|
||||
can be used to access pvDatabase.</p>
|
||||
<p>In particular read the sections "Getting Started" and "Simple Example".
|
||||
They will work on the exampleServer with the following differences:
|
||||
<dl>
|
||||
<dt>startExample.zip</dt>
|
||||
<dd>Do NOT use this. Instead run exampleServer</dd>
|
||||
<dt>channelList result</dt>
|
||||
<dd>The result of channelList will show the list of records that
|
||||
exampleServer has rather than the records from startExample.zip</dd>
|
||||
</dl>
|
||||
</p>
|
||||
|
||||
<h3>Relationship with pvIOCJava.</h3>
|
||||
<p>This document descibes a C++ implementation of some of the components in pvIOCJava,
|
||||
@ -580,6 +589,32 @@ The following are the minimium features required</p>
|
||||
</dl>
|
||||
<p>The following sections describes the classes required for the first phase.</p>
|
||||
|
||||
<h2>iocshell commands</h2>
|
||||
<p>The following iocsh commands are provided:</p>
|
||||
<dl>
|
||||
<dt>startPVAClient</dt>
|
||||
<dd>Starts the client side of pvAccess.s
|
||||
It makes channel provider <b>pvAccess</b> available.
|
||||
After startPVAServer is called the channel provider <b>local</b> will
|
||||
also be available.
|
||||
</dd>
|
||||
<dt>stopPVAClient</dt>
|
||||
<dd>Stops pvAccess.</dd>
|
||||
<dt>startPVAServer</dt>
|
||||
<dd>Starts the local channel provider</p>
|
||||
<dt>stopPVAServer</dt>
|
||||
<dd>Stop the local channel provider</dd>
|
||||
<dt>pvdbl</dt>
|
||||
<dd>Provides a list of all the pvRecords in database <b>master</b>
|
||||
It is similar to the iocsh command <b>dbl</b></dd>
|
||||
</dl>
|
||||
<p>The client commands are provided via PVAClientRegister.dbd and the othet 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>
|
||||
|
||||
|
||||
<h2>database</h2>
|
||||
<p>This directory has the following files:</p>
|
||||
<dl>
|
||||
@ -1236,6 +1271,314 @@ if(!result) cout<< "record " << recordName << " not added" <
|
||||
<h3>powerSupplyRecordTest</h3>
|
||||
<p>This simulates a simple power supply record.
|
||||
It is used for testing.</p>
|
||||
<h2>Accessing Other PVRecords</h2>
|
||||
<p>This section 1) starts with a discussion of accessing data via pvAccess
|
||||
and 2) gives a brief description of an example that gets data for an array of doubles.</p>
|
||||
<h3>Discussion</h3>
|
||||
<h4>Access Alternatives</h4>
|
||||
<p>The process routine of a PVRecord can access other PVRecords in two ways:</p>
|
||||
<dl>
|
||||
<dt>Directly accessing local pvDatabase</dt>
|
||||
<dd>
|
||||
If the other PVRecord is accessed via the master PVDatabase then
|
||||
threading issues are up to the implementation.
|
||||
For now this method will not be discussed.</dd>
|
||||
<dt>Access via pvAccess</dt>
|
||||
<dd>
|
||||
If access is via pvAccess then locking is handled by pvAccess.</dd>
|
||||
</dl>
|
||||
<p>Access via pvAccess can be done either by local or remote channel provider.</p>
|
||||
</dl>
|
||||
<dl>
|
||||
<dt>Access via channelProviderLocal</dt>
|
||||
<dd>
|
||||
If the local pvAccess server is used the implementation must be careful that it does not
|
||||
caused deadlocks.
|
||||
When the process method is called the pvRecord for the process method is locked.
|
||||
When it makes a pvAccess get, put, etc request the other record is locked.
|
||||
Thus if a set of pvAccess links are implemented the possibility of deadlocks
|
||||
exists. A simple example is two records that have links to each other.
|
||||
More complex sets are easily created.
|
||||
Unless the developer has complete control of the set of records then remote pvAccess should
|
||||
be used.
|
||||
But this results in more context switches.
|
||||
</dd>
|
||||
<dt>Access via remote pvAccess</dt>
|
||||
<dd>If remote pvAccess is used then all lockimg issues are handled by pvAccess.
|
||||
The linked channel can be a pvRecord in the local pvDatabase or can be implemented
|
||||
by a remote pvAccess server.</dd>
|
||||
</dl>
|
||||
<h4>Data synchronization</h4>
|
||||
<p>If pvAccess is used then it handles data synchronization.
|
||||
This is done by making a copy of the data that is transfered between the two pvRecords.
|
||||
This is true if either remote or local pvAccess is used.
|
||||
Each get, put, etc request results in data being copied between the two records.</p>
|
||||
<p>
|
||||
If the linked channel is a local pvRecord then,
|
||||
for scalar and structure arrays,
|
||||
raw data is NOT copied for gets.
|
||||
This is because pvData uses shared_vector to hold the raw data.
|
||||
Instead of copying the raw data the reference count is incremented.</p>
|
||||
<p>For puts the linked array will force a new allocation of the raw data in the linked record,
|
||||
i. e. copy on write semantics are enforced. This is done automatically
|
||||
by pvData and not by pvDatabase.</p>
|
||||
<h4>Some details</h4>
|
||||
<p>As mentioned before a pvDatabase server can be either a separate process,
|
||||
i. e. a main program, or can be part of a v3IOC.</p>
|
||||
<p>A main pvDatabase server issues the following calls:</p>
|
||||
<pre>
|
||||
ClientFactory::start();
|
||||
ChannelProviderLocalPtr channelProvider = getChannelProviderLocal();
|
||||
...
|
||||
ServerContext::shared_pointer serverContext = startPVAServer(PVACCESS_ALL_PROVIDERS,0,true,true);
|
||||
</pre>
|
||||
<p>The first call is only necessary if some of the pvRecords
|
||||
have pvAccess links.
|
||||
These must be called before any code that uses links is initialized.
|
||||
After these two calls there will be two channel providers: <b>local</b>, and <b>pvAccess</b>.
|
||||
|
||||
</p>
|
||||
<p>A pvDatabase that is part of a V3IOC has the following in the st.cmd file.</p>
|
||||
<pre>
|
||||
...
|
||||
iocInit()
|
||||
startPVAClient
|
||||
startPVAServer
|
||||
## commands to create pvRecords
|
||||
</pre>
|
||||
<p>
|
||||
Once the client and local provider code has started then the following creates a channel access link.
|
||||
</p>
|
||||
<pre>
|
||||
PVDatabasePtr master = PVDatabase::getMaster();
|
||||
ChannelAccess::shared_pointer channelAccess = getChannelAccess();
|
||||
ChannelProvider::shared_pointer provider = channelAccess->getProvider(providerName);
|
||||
Channel::shared_pointer channel = provider->createChannel(channelName,channelRequester);
|
||||
</pre>
|
||||
<h3>examplePVADoubleArrayGet</h3>
|
||||
examplePVADoubleArrayGet shows how to use pvAccess to get data.</p>
|
||||
<p>The code resides in three directories:</p>
|
||||
<dl>
|
||||
<dt>example/src/examplePVADoubleArrayGet</dt>
|
||||
<dd>This is the implementation code for the example.</dd>
|
||||
<dt>example/examplePVADoubleArrayGet</dt>
|
||||
<dd>This is the code that starts the example as a main program.</dd>
|
||||
<dt>example/v3IOC/examplePVADoubleArrayGet/src</dt>
|
||||
<dd>This is the code for starting the example as part of a V3IOC.</dd>
|
||||
<dt>iocBoot/examplePVADoubleArrayGet</dt>
|
||||
<dd>This has the st.cmd files to start the example.</dd>
|
||||
</dl>
|
||||
<h4>examplePVADoubleArrayGet Implementation</h4>
|
||||
<p>examplePVADoubleArrayGet.h contains the following:</p>
|
||||
<pre>
|
||||
...
|
||||
class ExamplePVADoubleArrayGet :
|
||||
public PVRecord,
|
||||
public epics::pvAccess::ChannelRequester,
|
||||
public epics::pvAccess::ChannelGetRequester
|
||||
{
|
||||
public:
|
||||
POINTER_DEFINITIONS(ExamplePVADoubleArrayGet);
|
||||
static ExamplePVADoubleArrayGetPtr create(
|
||||
epics::pvData::String const & recordName,
|
||||
epics::pvData::String const & providerName,
|
||||
epics::pvData::String const & channelName
|
||||
);
|
||||
virtual ~ExamplePVADoubleArrayGet() {}
|
||||
virtual void destroy();
|
||||
virtual bool init();
|
||||
virtual void process();
|
||||
virtual void channelCreated(
|
||||
const epics::pvData::Status& status,
|
||||
epics::pvAccess::Channel::shared_pointer const & channel);
|
||||
virtual void channelStateChange(
|
||||
epics::pvAccess::Channel::shared_pointer const & channel,
|
||||
epics::pvAccess::Channel::ConnectionState connectionState);
|
||||
virtual void channelGetConnect(
|
||||
const epics::pvData::Status& status,
|
||||
epics::pvAccess::ChannelGet::shared_pointer const & channelGet,
|
||||
epics::pvData::PVStructure::shared_pointer const & pvStructure,
|
||||
epics::pvData::BitSet::shared_pointer const & bitSet);
|
||||
virtual void getDone(const epics::pvData::Status& status);
|
||||
private:
|
||||
...
|
||||
</pre>
|
||||
<p>All the non-static methods are either PVRecord, PVChannel, or PVChannelGet methods
|
||||
and will not be discussed further.
|
||||
The create method is called to create a new PVRecord instance with code that will issue
|
||||
a ChannelGet::get request every time the process method of the instance is called.
|
||||
Some other pvAccess client can issue a channelGet, to the record instance, with a request
|
||||
to process in order to test the example.</p>
|
||||
<p>All of the initialization is done by a combination of the create and init methods so
|
||||
lets look at them:</p>
|
||||
<pre>
|
||||
ExamplePVADoubleArrayGetPtr ExamplePVADoubleArrayGet::create(
|
||||
String const & recordName,
|
||||
String const & providerName,
|
||||
String const & channelName)
|
||||
{
|
||||
PVStructurePtr pvStructure = getStandardPVField()->scalarArray(
|
||||
pvDouble,"alarm.timeStamp");
|
||||
ExamplePVADoubleArrayGetPtr pvRecord(
|
||||
new ExamplePVADoubleArrayGet(
|
||||
recordName,providerName,channelName,pvStructure));
|
||||
if(!pvRecord->init()) pvRecord.reset();
|
||||
return pvRecord;
|
||||
}
|
||||
</pre>
|
||||
<p>This first creates a new ExamplePVADoubleArrayGet instance,
|
||||
and then calls the init method and the returns a ExamplePVADoubleArrayGetPtr.
|
||||
Note that if init returns false it returns a pointer to NULL.</p>
|
||||
<p>The init method is:</p>
|
||||
<pre>
|
||||
bool ExamplePVADoubleArrayGet::init()
|
||||
{
|
||||
initPVRecord();
|
||||
|
||||
PVStructurePtr pvStructure = getPVRecordStructure()->getPVStructure();
|
||||
pvTimeStamp.attach(pvStructure->getSubField("timeStamp"));
|
||||
pvAlarm.attach(pvStructure->getSubField("alarm"));
|
||||
pvValue = static_pointer_cast<PVDoubleArray>(
|
||||
pvStructure->getScalarArrayField("value",pvDouble));
|
||||
if(pvValue==NULL) {
|
||||
return false;
|
||||
}
|
||||
ChannelAccess::shared_pointer channelAccess = getChannelAccess();
|
||||
ChannelProvider::shared_pointer provider =
|
||||
channelAccess->getProvider(providerName);
|
||||
if(provider==NULL) {
|
||||
cout << getRecordName() << " provider "
|
||||
<< providerName << " does not exist" << endl;
|
||||
return false;
|
||||
}
|
||||
ChannelRequester::shared_pointer channelRequester =
|
||||
dynamic_pointer_cast<ChannelRequester>(getPtrSelf());
|
||||
channel = provider->createChannel(channelName,channelRequester);
|
||||
event.wait();
|
||||
if(!status.isOK()) {
|
||||
cout << getRecordName() << " createChannel failed "
|
||||
<< status.getMessage() << endl;
|
||||
return false;
|
||||
}
|
||||
ChannelGetRequester::shared_pointer channelGetRequester =
|
||||
dynamic_pointer_cast<ChannelGetRequester>(getPtrSelf());
|
||||
PVStructurePtr pvRequest = getCreateRequest()->createRequest(
|
||||
"value,alarm,timeStamp",getPtrSelf());
|
||||
channelGet = channel->createChannelGet(channelGetRequester,pvRequest);
|
||||
event.wait();
|
||||
if(!status.isOK()) {
|
||||
cout << getRecordName() << " createChannelGet failed "
|
||||
<< status.getMessage() << endl;
|
||||
return false;
|
||||
}
|
||||
getPVValue = static_pointer_cast<PVDoubleArray>(
|
||||
getPVStructure->getScalarArrayField("value",pvDouble));
|
||||
if(getPVValue==NULL) {
|
||||
cout << getRecordName() << " get value not PVDoubleArray" << endl;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
</pre>
|
||||
<p>This first makes sure the pvStructure has the fields it requires:</p>
|
||||
<dl>
|
||||
<dt>timeStamp</dt>
|
||||
<dd>A timeStamp structure. This will be set to the current time when process is called.</dd>
|
||||
<dt>alarm</dt>
|
||||
<dd>An alarm structure. This will be used to pass status information to the client when
|
||||
process is called.</dd>
|
||||
<dt>value</dt>
|
||||
<dd>This must be a scalarArray of type double.
|
||||
It is where data is copied when the channelGet is issued.</dd>
|
||||
</dl>
|
||||
<p>Next it makes sure the channelProvider exists.</p>
|
||||
<p>Next it creates the channel and waits until it connects.</p>
|
||||
<p>Next it creates the channelGet and waits until it is created.</p>
|
||||
<p>Next it makes sure it has connected to a double array field.</p>
|
||||
<p>If anything goes wrong during initialization it returns false.
|
||||
This a return of true means that it has successfully created a channelGet and is ready
|
||||
to issue gets when process is called.</p>
|
||||
<p>Look at the code for more details.</p>
|
||||
<h4>Starting the example as a main program</h4>
|
||||
<pre>
|
||||
...
|
||||
int main(int argc,char *argv[])
|
||||
{
|
||||
PVDatabasePtr master = PVDatabase::getMaster();
|
||||
ClientFactory::start();
|
||||
ChannelProviderLocalPtr channelProvider = getChannelProviderLocal();
|
||||
PVRecordPtr pvRecord;
|
||||
bool result(false);
|
||||
String recordName;
|
||||
PVStructurePtr pvStructure = standardPVField->scalarArray(
|
||||
pvDouble,"alarm,timeStamp");
|
||||
recordName = "doubleArray";
|
||||
pvRecord = PVRecord::create(recordName,pvStructure);
|
||||
result = master->addRecord(pvRecord);
|
||||
if(!result) cout<< "record " << recordName << " not added" << endl;
|
||||
ServerContext::shared_pointer serverContext = startPVAServer(PVACCESS_ALL_PROVIDERS,0,true,true);
|
||||
recordName = "examplePVADoubleArrayGet";
|
||||
if(argc>1) recordName = argv[1];
|
||||
String providerName("local");
|
||||
if(argc>2) providerName = argv[2];
|
||||
String channelName("doubleArray");
|
||||
if(argc>3) channelName = argv[3];
|
||||
pvRecord = ExamplePVADoubleArrayGet::create(
|
||||
recordName,providerName,channelName);
|
||||
if(pvRecord!=NULL) {
|
||||
result = master->addRecord(pvRecord);
|
||||
cout << "result of addRecord " << recordName << " " << result << endl;
|
||||
} else {
|
||||
cout << "ExamplePVADoubleArrayGet::create failed" << endl;
|
||||
}
|
||||
string str;
|
||||
while(true) {
|
||||
cout << "Type exit to stop: \n";
|
||||
getline(cin,str);
|
||||
if(str.compare("exit")==0) break;
|
||||
|
||||
}
|
||||
serverContext->shutdown();
|
||||
epicsThreadSleep(1.0);
|
||||
serverContext->destroy();
|
||||
ClientFactory::stop();
|
||||
channelProvider->destroy();
|
||||
return 0;
|
||||
}
|
||||
</pre>
|
||||
<p>The first statements initializes the client factory and localChannelProvider.</p>
|
||||
<p>
|
||||
It then creates a PVRecord that has a double array as the value field.
|
||||
The name of the record is <b>doubleArray</b>.
|
||||
This is the record that can be accessed via pvAccess if the channelName is
|
||||
<b>doubleArray</b>.
|
||||
</p>
|
||||
<p>It then creates a examplePVADoubleArrayGet instance.</p>
|
||||
<p>It the runs forever until the exit is typed.</p>
|
||||
|
||||
<h4>Start the example as part of a V3IOC</h4>
|
||||
The directory example/v3IOC/examplePVADoubleArrayGet has two subdirectories: Db and src.
|
||||
These are like for any other V3IOC application.
|
||||
The Db directory is for a regular ai record.
|
||||
The src directory has code similar to any V3IOC application.
|
||||
In particular it has definitions and code for creating the following iocsh commands:</p>
|
||||
<pre>
|
||||
examplePVADoubleArrayGetRegister recordName providerName channelName
|
||||
</pre>
|
||||
where
|
||||
<dl>
|
||||
<dt>recordName</dt>
|
||||
<dt>providerName</dt>
|
||||
<dt>channelName</dt>
|
||||
</dl>
|
||||
<p>The directory iocBoot/examplePVADoubleArrayGet has two st.cmd files:</p>
|
||||
<dl>
|
||||
<dt>st.local</dt>
|
||||
<dd>This creates the example using localChannelProvider.</dd>
|
||||
<dt>st.remote</dt>
|
||||
<dd>This creates the example using the remote channel provider.</dd>
|
||||
</dl>
|
||||
|
||||
|
||||
</div>
|
||||
</body>
|
||||
|
@ -5,6 +5,7 @@ DIRS += record
|
||||
DIRS += pvCopy
|
||||
DIRS += exampleCounter
|
||||
DIRS += exampleServer
|
||||
DIRS += examplePVADoubleArrayGet
|
||||
DIRS += v3IOC
|
||||
include $(TOP)/configure/RULES_DIRS
|
||||
|
||||
|
14
example/examplePVADoubleArrayGet/Makefile
Normal file
14
example/examplePVADoubleArrayGet/Makefile
Normal file
@ -0,0 +1,14 @@
|
||||
TOP=../..
|
||||
|
||||
include $(TOP)/configure/CONFIG
|
||||
|
||||
PROD_HOST += examplePVADoubleArrayGetMain
|
||||
examplePVADoubleArrayGetMain_SRCS += examplePVADoubleArrayGetMain.cpp
|
||||
examplePVADoubleArrayGetMain_LIBS += pvDatabase pvAccess pvData Com
|
||||
examplePVADoubleArrayGetMain_LIBS += pvDatabaseExample
|
||||
|
||||
|
||||
include $(TOP)/configure/RULES
|
||||
#----------------------------------------
|
||||
# ADD RULES AFTER THIS LINE
|
||||
|
@ -0,0 +1,80 @@
|
||||
/*ExamplePVADoubleArrayGetMain.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/examplePVADoubleArrayGet.h>
|
||||
#include <pv/traceRecord.h>
|
||||
#include <pv/channelProviderLocal.h>
|
||||
#include <pv/serverContext.h>
|
||||
#include <pv/clientFactory.h>
|
||||
|
||||
using namespace std;
|
||||
using std::tr1::static_pointer_cast;
|
||||
using namespace epics::pvData;
|
||||
using namespace epics::pvAccess;
|
||||
using namespace epics::pvDatabase;
|
||||
|
||||
static StandardPVFieldPtr standardPVField = getStandardPVField();
|
||||
|
||||
int main(int argc,char *argv[])
|
||||
{
|
||||
PVDatabasePtr master = PVDatabase::getMaster();
|
||||
ClientFactory::start();
|
||||
ChannelProviderLocalPtr channelProvider = getChannelProviderLocal();
|
||||
PVRecordPtr pvRecord;
|
||||
bool result(false);
|
||||
String recordName;
|
||||
PVStructurePtr pvStructure = standardPVField->scalarArray(
|
||||
pvDouble,"alarm,timeStamp");
|
||||
recordName = "doubleArray";
|
||||
pvRecord = PVRecord::create(recordName,pvStructure);
|
||||
result = master->addRecord(pvRecord);
|
||||
if(!result) cout<< "record " << recordName << " not added" << endl;
|
||||
ServerContext::shared_pointer serverContext = startPVAServer(PVACCESS_ALL_PROVIDERS,0,true,true);
|
||||
recordName = "examplePVADoubleArrayGet";
|
||||
if(argc>1) recordName = argv[1];
|
||||
String providerName("local");
|
||||
if(argc>2) providerName = argv[2];
|
||||
String channelName("doubleArray");
|
||||
if(argc>3) channelName = argv[3];
|
||||
pvRecord = ExamplePVADoubleArrayGet::create(
|
||||
recordName,providerName,channelName);
|
||||
if(pvRecord!=NULL) {
|
||||
result = master->addRecord(pvRecord);
|
||||
cout << "result of addRecord " << recordName << " " << result << endl;
|
||||
} else {
|
||||
cout << "ExamplePVADoubleArrayGet::create failed" << endl;
|
||||
}
|
||||
string str;
|
||||
while(true) {
|
||||
cout << "Type exit to stop: \n";
|
||||
getline(cin,str);
|
||||
if(str.compare("exit")==0) break;
|
||||
|
||||
}
|
||||
serverContext->shutdown();
|
||||
epicsThreadSleep(1.0);
|
||||
serverContext->destroy();
|
||||
ClientFactory::stop();
|
||||
channelProvider->destroy();
|
||||
return 0;
|
||||
}
|
||||
|
@ -192,17 +192,15 @@ static void testPVScalarArray(
|
||||
BitSetPtr bitSet;
|
||||
String builder;
|
||||
size_t offset;
|
||||
ConvertPtr convert = getConvert();
|
||||
size_t n = 5;
|
||||
//DoubleArray values(n);
|
||||
shared_vector<double> values(n);
|
||||
|
||||
pvRecord->lock_guard();
|
||||
cout << endl;
|
||||
pvStructureRecord = pvRecord->getPVRecordStructure()->getPVStructure();
|
||||
pvValueRecord = pvStructureRecord->getScalarArrayField(valueNameRecord,scalarType);
|
||||
for(size_t i=0; i<n; i++) values[i] = i;
|
||||
pvValueRecord->PVScalarArray::putFrom<pvDouble>(values);
|
||||
const shared_vector<const double> xxx(freeze(values));
|
||||
pvValueRecord->putFrom(xxx);
|
||||
StructureConstPtr structure = pvCopy->getStructure();
|
||||
builder.clear(); structure->toString(&builder);
|
||||
cout << "structure from copy" << endl << builder << endl;
|
||||
@ -213,8 +211,10 @@ ConvertPtr convert = getConvert();
|
||||
builder.clear(); pvValueCopy->toString(&builder);
|
||||
cout << "after initCopy pvValueCopy " << builder << endl;
|
||||
cout << endl;
|
||||
values.resize(n);
|
||||
for(size_t i=0; i<n; i++) values[i] = i + .06;
|
||||
pvValueRecord->PVScalarArray::putFrom<pvDouble>(values);
|
||||
const shared_vector<const double> yyy(freeze(values));
|
||||
pvValueRecord->putFrom(yyy);
|
||||
pvCopy->updateCopySetBitSet(pvStructureCopy,bitSet,true);
|
||||
builder.clear(); pvValueCopy->toString(&builder);
|
||||
cout << "after put(i+ .06) pvValueCopy " << builder << endl;
|
||||
@ -232,8 +232,10 @@ ConvertPtr convert = getConvert();
|
||||
cout << " bitSet " << builder;
|
||||
cout << endl;
|
||||
bitSet->clear();
|
||||
values.resize(n);
|
||||
for(size_t i=0; i<n; i++) values[i] = i + 1.0;
|
||||
pvValueRecord->PVScalarArray::putFrom<pvDouble>(values);
|
||||
const shared_vector<const double> zzz(freeze(values));
|
||||
pvValueRecord->putFrom(zzz);
|
||||
builder.clear();
|
||||
bitSet->toString(&builder);
|
||||
cout << "before updateCopyFromBitSet";
|
||||
@ -256,8 +258,10 @@ ConvertPtr convert = getConvert();
|
||||
bitSet->toString(&builder);
|
||||
cout << " bitSet " << builder;
|
||||
cout << endl;
|
||||
values.resize(n);
|
||||
for(size_t i=0; i<n; i++) values[i] = i + 2.0;
|
||||
pvValueRecord->PVScalarArray::putFrom<pvDouble>(values);
|
||||
const shared_vector<const double> ttt(freeze(values));
|
||||
pvValueRecord->putFrom(ttt);
|
||||
bitSet->set(0);
|
||||
cout << "before updateRecord";
|
||||
builder.clear(); pvValueRecord->toString(&builder);
|
||||
|
@ -14,6 +14,10 @@ SRC_DIRS += $(EXAMPLESRC)/exampleServer
|
||||
INC+= exampleServerCreateRecords.h
|
||||
LIBSRCS += exampleServerCreateRecords.cpp
|
||||
|
||||
SRC_DIRS += $(EXAMPLESRC)/examplePVADoubleArrayGet
|
||||
INC+= examplePVADoubleArrayGet.h
|
||||
LIBSRCS += examplePVADoubleArrayGet.cpp
|
||||
|
||||
|
||||
include $(TOP)/configure/RULES
|
||||
|
||||
|
@ -0,0 +1,161 @@
|
||||
/* examplePVADoubleArrayGet.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
|
||||
* @date 2013.08.02
|
||||
*/
|
||||
|
||||
#include <pv/examplePVADoubleArrayGet.h>
|
||||
#include <pv/standardPVField.h>
|
||||
#include <pv/convert.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;
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
|
||||
ExamplePVADoubleArrayGetPtr ExamplePVADoubleArrayGet::create(
|
||||
String const & recordName,
|
||||
String const & providerName,
|
||||
String const & channelName)
|
||||
{
|
||||
PVStructurePtr pvStructure = getStandardPVField()->scalarArray(
|
||||
pvDouble,"alarm.timeStamp");
|
||||
ExamplePVADoubleArrayGetPtr pvRecord(
|
||||
new ExamplePVADoubleArrayGet(
|
||||
recordName,providerName,channelName,pvStructure));
|
||||
if(!pvRecord->init()) pvRecord.reset();
|
||||
return pvRecord;
|
||||
}
|
||||
|
||||
ExamplePVADoubleArrayGet::ExamplePVADoubleArrayGet(
|
||||
String const & recordName,
|
||||
String providerName,
|
||||
String channelName,
|
||||
PVStructurePtr const & pvStructure)
|
||||
: PVRecord(recordName,pvStructure),
|
||||
providerName(providerName),
|
||||
channelName(channelName),
|
||||
convert(getConvert())
|
||||
{
|
||||
}
|
||||
|
||||
void ExamplePVADoubleArrayGet::destroy()
|
||||
{
|
||||
PVRecord::destroy();
|
||||
}
|
||||
|
||||
bool ExamplePVADoubleArrayGet::init()
|
||||
{
|
||||
initPVRecord();
|
||||
|
||||
PVStructurePtr pvStructure = getPVRecordStructure()->getPVStructure();
|
||||
pvTimeStamp.attach(pvStructure->getSubField("timeStamp"));
|
||||
pvAlarm.attach(pvStructure->getSubField("alarm"));
|
||||
pvValue = static_pointer_cast<PVDoubleArray>(
|
||||
pvStructure->getScalarArrayField("value",pvDouble));
|
||||
if(pvValue==NULL) {
|
||||
return false;
|
||||
}
|
||||
ChannelAccess::shared_pointer channelAccess = getChannelAccess();
|
||||
ChannelProvider::shared_pointer provider =
|
||||
channelAccess->getProvider(providerName);
|
||||
if(provider==NULL) {
|
||||
cout << getRecordName() << " provider "
|
||||
<< providerName << " does not exist" << endl;
|
||||
return false;
|
||||
}
|
||||
ChannelRequester::shared_pointer channelRequester =
|
||||
dynamic_pointer_cast<ChannelRequester>(getPtrSelf());
|
||||
channel = provider->createChannel(channelName,channelRequester);
|
||||
event.wait();
|
||||
if(!status.isOK()) {
|
||||
cout << getRecordName() << " createChannel failed "
|
||||
<< status.getMessage() << endl;
|
||||
return false;
|
||||
}
|
||||
ChannelGetRequester::shared_pointer channelGetRequester =
|
||||
dynamic_pointer_cast<ChannelGetRequester>(getPtrSelf());
|
||||
PVStructurePtr pvRequest = getCreateRequest()->createRequest(
|
||||
"value,alarm,timeStamp",getPtrSelf());
|
||||
channelGet = channel->createChannelGet(channelGetRequester,pvRequest);
|
||||
event.wait();
|
||||
if(!status.isOK()) {
|
||||
cout << getRecordName() << " createChannelGet failed "
|
||||
<< status.getMessage() << endl;
|
||||
return false;
|
||||
}
|
||||
getPVValue = static_pointer_cast<PVDoubleArray>(
|
||||
getPVStructure->getScalarArrayField("value",pvDouble));
|
||||
if(getPVValue==NULL) {
|
||||
cout << getRecordName() << " get value not PVDoubleArray" << endl;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void ExamplePVADoubleArrayGet::process()
|
||||
{
|
||||
status = Status::Ok;
|
||||
channelGet->get(false);
|
||||
event.wait();
|
||||
timeStamp.getCurrent();
|
||||
pvTimeStamp.set(timeStamp);
|
||||
AlarmSeverity severity(noAlarm);
|
||||
if(!status.isOK()) {
|
||||
switch(status.getType()) {
|
||||
case Status::STATUSTYPE_OK: severity = noAlarm; break;
|
||||
case Status::STATUSTYPE_WARNING: severity = minorAlarm; break;
|
||||
case Status::STATUSTYPE_ERROR: severity = majorAlarm; break;
|
||||
case Status::STATUSTYPE_FATAL: severity = invalidAlarm; break;
|
||||
}
|
||||
alarm.setSeverity(severity);
|
||||
} else {
|
||||
convert->copy(getPVValue,pvValue);
|
||||
}
|
||||
alarm.setMessage(status.getMessage());
|
||||
pvAlarm.set(alarm);
|
||||
}
|
||||
|
||||
void ExamplePVADoubleArrayGet::channelCreated(
|
||||
const Status& status,
|
||||
Channel::shared_pointer const & channel)
|
||||
{
|
||||
this->status = status;
|
||||
this->channel = channel;
|
||||
event.signal();
|
||||
}
|
||||
|
||||
void ExamplePVADoubleArrayGet::channelStateChange(
|
||||
Channel::shared_pointer const & channel,
|
||||
Channel::ConnectionState connectionState)
|
||||
{
|
||||
}
|
||||
|
||||
void ExamplePVADoubleArrayGet::channelGetConnect(
|
||||
const Status& status,
|
||||
ChannelGet::shared_pointer const & channelGet,
|
||||
PVStructure::shared_pointer const & pvStructure,
|
||||
BitSet::shared_pointer const & bitSet)
|
||||
{
|
||||
this->status = status;
|
||||
this->channelGet = channelGet;
|
||||
this->getPVStructure = pvStructure;
|
||||
this->bitSet = bitSet;
|
||||
event.signal();
|
||||
}
|
||||
|
||||
void ExamplePVADoubleArrayGet::getDone(const Status& status)
|
||||
{
|
||||
this->status = status;
|
||||
event.signal();
|
||||
}
|
||||
|
||||
}}
|
@ -0,0 +1,83 @@
|
||||
/* examplePVADoubleArrayGet.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.08.02
|
||||
*/
|
||||
#ifndef EXAMPLEPVADOUBLEARRAYGET_H
|
||||
#define EXAMPLEPVADOUBLEARRAYGET_H
|
||||
|
||||
|
||||
#include <pv/timeStamp.h>
|
||||
#include <pv/pvTimeStamp.h>
|
||||
#include <pv/alarm.h>
|
||||
#include <pv/pvAlarm.h>
|
||||
#include <pv/pvDatabase.h>
|
||||
#include <pv/pvCopy.h>
|
||||
#include <pv/pvAccess.h>
|
||||
#include <pv/serverContext.h>
|
||||
|
||||
namespace epics { namespace pvDatabase {
|
||||
|
||||
|
||||
class ExamplePVADoubleArrayGet;
|
||||
typedef std::tr1::shared_ptr<ExamplePVADoubleArrayGet> ExamplePVADoubleArrayGetPtr;
|
||||
|
||||
class ExamplePVADoubleArrayGet :
|
||||
public PVRecord,
|
||||
public epics::pvAccess::ChannelRequester,
|
||||
public epics::pvAccess::ChannelGetRequester
|
||||
{
|
||||
public:
|
||||
POINTER_DEFINITIONS(ExamplePVADoubleArrayGet);
|
||||
static ExamplePVADoubleArrayGetPtr create(
|
||||
epics::pvData::String const & recordName,
|
||||
epics::pvData::String const & providerName,
|
||||
epics::pvData::String const & channelName
|
||||
);
|
||||
virtual ~ExamplePVADoubleArrayGet() {}
|
||||
virtual void destroy();
|
||||
virtual bool init();
|
||||
virtual void process();
|
||||
virtual void channelCreated(
|
||||
const epics::pvData::Status& status,
|
||||
epics::pvAccess::Channel::shared_pointer const & channel);
|
||||
virtual void channelStateChange(
|
||||
epics::pvAccess::Channel::shared_pointer const & channel,
|
||||
epics::pvAccess::Channel::ConnectionState connectionState);
|
||||
virtual void channelGetConnect(
|
||||
const epics::pvData::Status& status,
|
||||
epics::pvAccess::ChannelGet::shared_pointer const & channelGet,
|
||||
epics::pvData::PVStructure::shared_pointer const & pvStructure,
|
||||
epics::pvData::BitSet::shared_pointer const & bitSet);
|
||||
virtual void getDone(const epics::pvData::Status& status);
|
||||
private:
|
||||
ExamplePVADoubleArrayGet(epics::pvData::String const & recordName,
|
||||
epics::pvData::String providerName,
|
||||
epics::pvData::String channelName,
|
||||
epics::pvData::PVStructurePtr const & pvStructure);
|
||||
epics::pvData::String providerName;
|
||||
epics::pvData::String channelName;
|
||||
epics::pvData::ConvertPtr convert;
|
||||
epics::pvData::PVDoubleArrayPtr pvValue;
|
||||
epics::pvData::PVTimeStamp pvTimeStamp;
|
||||
epics::pvData::TimeStamp timeStamp;
|
||||
epics::pvData::PVAlarm pvAlarm;
|
||||
epics::pvData::Alarm alarm;
|
||||
epics::pvAccess::Channel::shared_pointer channel;
|
||||
epics::pvAccess::ChannelGet::shared_pointer channelGet;
|
||||
epics::pvData::Mutex mutex;
|
||||
epics::pvData::Event event;
|
||||
epics::pvData::Status status;
|
||||
epics::pvData::PVStructurePtr getPVStructure;
|
||||
epics::pvData::BitSetPtr bitSet;
|
||||
epics::pvData::PVDoubleArrayPtr getPVValue;
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif /* EXAMPLEPVADOUBLEARRAYGET_H */
|
@ -2,5 +2,6 @@ TOP = ../..
|
||||
include $(TOP)/configure/CONFIG
|
||||
DIRS += exampleCounter
|
||||
DIRS += exampleServer
|
||||
DIRS += examplePVADoubleArrayGet
|
||||
include $(TOP)/configure/RULES_DIRS
|
||||
|
||||
|
21
example/v3IOC/examplePVADoubleArrayGet/Db/Makefile
Normal file
21
example/v3IOC/examplePVADoubleArrayGet/Db/Makefile
Normal file
@ -0,0 +1,21 @@
|
||||
TOP=../../../..
|
||||
include $(TOP)/configure/CONFIG
|
||||
#----------------------------------------
|
||||
# ADD MACRO DEFINITIONS AFTER THIS LINE
|
||||
|
||||
#----------------------------------------------------
|
||||
# Optimization of db files using dbst (DEFAULT: NO)
|
||||
#DB_OPT = YES
|
||||
|
||||
#----------------------------------------------------
|
||||
# Create and install (or just install)
|
||||
# databases, templates, substitutions like this
|
||||
DB += ai.db
|
||||
#----------------------------------------------------
|
||||
# If <anyname>.db template is not named <anyname>*.template add
|
||||
# <anyname>_TEMPLATE = <templatename>
|
||||
|
||||
include $(TOP)/configure/RULES
|
||||
#----------------------------------------
|
||||
# ADD RULES AFTER THIS LINE
|
||||
|
13
example/v3IOC/examplePVADoubleArrayGet/Db/ai.db
Normal file
13
example/v3IOC/examplePVADoubleArrayGet/Db/ai.db
Normal file
@ -0,0 +1,13 @@
|
||||
record(ai, "$(name)")
|
||||
{
|
||||
field(PREC, "1")
|
||||
field(EGU, "amps")
|
||||
field(HIHI, "8")
|
||||
field(HIGH, "6")
|
||||
field(LOW, "4")
|
||||
field(LOLO, "2")
|
||||
field(HHSV, "MAJOR")
|
||||
field(HSV, "MINOR")
|
||||
field(LSV, "MINOR")
|
||||
field(LLSV, "MAJOR")
|
||||
}
|
8
example/v3IOC/examplePVADoubleArrayGet/Makefile
Normal file
8
example/v3IOC/examplePVADoubleArrayGet/Makefile
Normal file
@ -0,0 +1,8 @@
|
||||
TOP = ../../..
|
||||
include $(TOP)/configure/CONFIG
|
||||
DIRS := $(DIRS) $(filter-out $(DIRS), $(wildcard *src*))
|
||||
DIRS := $(DIRS) $(filter-out $(DIRS), $(wildcard *Src*))
|
||||
DIRS := $(DIRS) $(filter-out $(DIRS), $(wildcard *db*))
|
||||
DIRS := $(DIRS) $(filter-out $(DIRS), $(wildcard *Db*))
|
||||
include $(TOP)/configure/RULES_DIRS
|
||||
|
48
example/v3IOC/examplePVADoubleArrayGet/src/Makefile
Normal file
48
example/v3IOC/examplePVADoubleArrayGet/src/Makefile
Normal file
@ -0,0 +1,48 @@
|
||||
TOP=../../../..
|
||||
|
||||
include $(TOP)/configure/CONFIG
|
||||
#----------------------------------------
|
||||
# ADD MACRO DEFINITIONS AFTER THIS LINE
|
||||
#=============================
|
||||
|
||||
#==================================================
|
||||
# Build an IOC support library
|
||||
#
|
||||
|
||||
DBD += examplePVADoubleArrayGet.dbd
|
||||
|
||||
LIBRARY_IOC += examplePVADoubleArrayGetSupport
|
||||
examplePVADoubleArrayGetSupport_SRCS += examplePVADoubleArrayGet.cpp
|
||||
examplePVADoubleArrayGetSupport_LIBS += pvData
|
||||
examplePVADoubleArrayGetSupport_LIBS += pvAccess
|
||||
examplePVADoubleArrayGetSupport_LIBS += pvDatabase
|
||||
examplePVADoubleArrayGetSupport_LIBS += pvDatabaseExample
|
||||
examplePVADoubleArrayGetSupport_LIBS += $(EPICS_BASE_IOC_LIBS)
|
||||
|
||||
#=============================
|
||||
# build an ioc application
|
||||
|
||||
PROD_IOC += examplePVADoubleArrayGet
|
||||
|
||||
|
||||
# <name>_registerRecordDeviceDriver.cpp will be created from <name>.dbd
|
||||
examplePVADoubleArrayGet_SRCS += examplePVADoubleArrayGet_registerRecordDeviceDriver.cpp
|
||||
examplePVADoubleArrayGet_SRCS_DEFAULT += examplePVADoubleArrayGetMain.cpp
|
||||
examplePVADoubleArrayGet_SRCS_vxWorks += -nil-
|
||||
|
||||
|
||||
# The following adds support from base/src/vxWorks
|
||||
examplePVADoubleArrayGet_OBJS_vxWorks += $(EPICS_BASE_BIN)/vxComLibrary
|
||||
|
||||
examplePVADoubleArrayGet_LIBS += pvData pvAccess
|
||||
examplePVADoubleArrayGet_LIBS += pvDatabase
|
||||
examplePVADoubleArrayGet_LIBS += pvDatabaseExample
|
||||
examplePVADoubleArrayGet_LIBS += examplePVADoubleArrayGetSupport
|
||||
examplePVADoubleArrayGet_LIBS += $(EPICS_BASE_IOC_LIBS)
|
||||
|
||||
#===========================
|
||||
|
||||
include $(TOP)/configure/RULES
|
||||
#----------------------------------------
|
||||
# ADD RULES AFTER THIS LINE
|
||||
|
@ -0,0 +1,85 @@
|
||||
/*examplePVADoubleArrayGet.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
|
||||
* @date 2013.07.24
|
||||
*/
|
||||
|
||||
|
||||
/* Author: Marty Kraimer */
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdlib>
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <cstdio>
|
||||
#include <memory>
|
||||
#include <iostream>
|
||||
|
||||
#include <cantProceed.h>
|
||||
#include <epicsStdio.h>
|
||||
#include <epicsMutex.h>
|
||||
#include <epicsEvent.h>
|
||||
#include <epicsThread.h>
|
||||
#include <iocsh.h>
|
||||
|
||||
#include <epicsExport.h>
|
||||
|
||||
#include <pv/pvIntrospect.h>
|
||||
#include <pv/pvData.h>
|
||||
#include <pv/standardField.h>
|
||||
#include <pv/standardPVField.h>
|
||||
#include <pv/pvAccess.h>
|
||||
#include <pv/pvDatabase.h>
|
||||
#include <pv/examplePVADoubleArrayGet.h>
|
||||
|
||||
using namespace epics::pvData;
|
||||
using namespace epics::pvAccess;
|
||||
using namespace epics::pvDatabase;
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
|
||||
static StandardPVFieldPtr standardPVField = getStandardPVField();
|
||||
|
||||
static const iocshArg testArg0 = { "recordName", iocshArgString };
|
||||
static const iocshArg testArg1 = { "providerName", iocshArgString };
|
||||
static const iocshArg testArg2 = { "channelName", iocshArgString };
|
||||
static const iocshArg *testArgs[] = {
|
||||
&testArg0,&testArg1,&testArg2};
|
||||
|
||||
static const iocshFuncDef examplePVADoubleArrayGetFuncDef = {
|
||||
"examplePVADoubleArrayGetCreateRecord", 3, testArgs};
|
||||
static void examplePVADoubleArrayGetCallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
PVDatabasePtr master = PVDatabase::getMaster();
|
||||
PVRecordPtr pvRecord;
|
||||
bool result(false);
|
||||
String recordName;
|
||||
PVStructurePtr pvStructure = standardPVField->scalarArray(
|
||||
pvDouble,"alarm,timeStamp");
|
||||
pvRecord = PVRecord::create("doubleArray",pvStructure);
|
||||
result = master->addRecord(pvRecord);
|
||||
if(!result) cout<< "record " << recordName << " not added" << endl;
|
||||
|
||||
recordName = args[0].sval;
|
||||
char *providerName = args[1].sval;
|
||||
char *channelName = args[2].sval;
|
||||
ExamplePVADoubleArrayGetPtr record = ExamplePVADoubleArrayGet::create(recordName,providerName,channelName);
|
||||
if(record!=NULL)
|
||||
result = master->addRecord(record);
|
||||
if(!result) cout << "recordname" << " not added" << endl;
|
||||
}
|
||||
|
||||
static void examplePVADoubleArrayGetRegister(void)
|
||||
{
|
||||
static int firstTime = 1;
|
||||
if (firstTime) {
|
||||
firstTime = 0;
|
||||
iocshRegister(&examplePVADoubleArrayGetFuncDef, examplePVADoubleArrayGetCallFunc);
|
||||
}
|
||||
}
|
||||
epicsExportRegistrar(examplePVADoubleArrayGetRegister);
|
@ -0,0 +1,4 @@
|
||||
include "base.dbd"
|
||||
include "PVAServerRegister.dbd"
|
||||
include "PVAClientRegister.dbd"
|
||||
registrar("examplePVADoubleArrayGetRegister")
|
@ -0,0 +1,31 @@
|
||||
/* examplePVADoubleArrayGetMain.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
|
||||
* @date 2013.07.24
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "epicsExit.h"
|
||||
#include "epicsThread.h"
|
||||
#include "iocsh.h"
|
||||
|
||||
int main(int argc,char *argv[])
|
||||
{
|
||||
if(argc>=2) {
|
||||
iocsh(argv[1]);
|
||||
epicsThreadSleep(.2);
|
||||
}
|
||||
iocsh(NULL);
|
||||
epicsExit(0);
|
||||
return(0);
|
||||
}
|
5
iocBoot/examplePVADoubleArrayGet/Makefile
Normal file
5
iocBoot/examplePVADoubleArrayGet/Makefile
Normal file
@ -0,0 +1,5 @@
|
||||
TOP = ../..
|
||||
include $(TOP)/configure/CONFIG
|
||||
ARCH = $(EPICS_HOST_ARCH)
|
||||
TARGETS = envPaths
|
||||
include $(TOP)/configure/RULES.ioc
|
16
iocBoot/examplePVADoubleArrayGet/st.local
Normal file
16
iocBoot/examplePVADoubleArrayGet/st.local
Normal file
@ -0,0 +1,16 @@
|
||||
< envPaths
|
||||
|
||||
cd ${TOP}
|
||||
|
||||
## Register all support components
|
||||
dbLoadDatabase("dbd/examplePVADoubleArrayGet.dbd")
|
||||
examplePVADoubleArrayGet_registerRecordDeviceDriver(pdbbase)
|
||||
|
||||
## Load record instances
|
||||
dbLoadRecords("db/dbArray.db","name=double01,type=DOUBLE")
|
||||
|
||||
cd ${TOP}/iocBoot/${IOC}
|
||||
iocInit()
|
||||
startPVAClient
|
||||
startPVAServer
|
||||
examplePVADoubleArrayGetCreateRecord examplePVADoubleArrayGet local doubleArray
|
16
iocBoot/examplePVADoubleArrayGet/st.remote
Normal file
16
iocBoot/examplePVADoubleArrayGet/st.remote
Normal file
@ -0,0 +1,16 @@
|
||||
< envPaths
|
||||
|
||||
cd ${TOP}
|
||||
|
||||
## Register all support components
|
||||
dbLoadDatabase("dbd/examplePVADoubleArrayGet.dbd")
|
||||
examplePVADoubleArrayGet_registerRecordDeviceDriver(pdbbase)
|
||||
|
||||
## Load record instances
|
||||
dbLoadRecords("db/dbArray.db","name=double01,type=DOUBLE")
|
||||
|
||||
cd ${TOP}/iocBoot/${IOC}
|
||||
iocInit()
|
||||
startPVAClient
|
||||
startPVAServer
|
||||
examplePVADoubleArrayGetCreateRecord examplePVADoubleArrayGet pvAccess arrayDouble
|
@ -27,7 +27,9 @@ LIBSRCS += monitorFactory.cpp
|
||||
|
||||
SRC_DIRS += $(DATABASE)/v3IOC
|
||||
DBD += PVAServerRegister.dbd
|
||||
DBD += PVAClientRegister.dbd
|
||||
LIBSRCS += PVAServerRegister.cpp
|
||||
LIBSRCS += PVAClientRegister.cpp
|
||||
|
||||
SRC_DIRS += $(DATABASE)/special
|
||||
INC += recordList.h
|
||||
|
@ -91,7 +91,8 @@ PVStringArrayPtr PVDatabase::getRecordNames()
|
||||
for(iter = recordMap.begin(); iter!=recordMap.end(); ++iter) {
|
||||
names[i++] = (*iter).first;
|
||||
}
|
||||
pvStringArray->replace(names);
|
||||
shared_vector<const String> temp(freeze(names));
|
||||
pvStringArray->replace(temp);
|
||||
return pvStringArray;
|
||||
}
|
||||
|
||||
|
@ -46,7 +46,7 @@ typedef std::tr1::shared_ptr<PVDatabase> PVDatabasePtr;
|
||||
* @author mrk
|
||||
*/
|
||||
class PVRecord :
|
||||
public epics::pvData::Requester,
|
||||
public virtual epics::pvData::Requester,
|
||||
public std::tr1::enable_shared_from_this<PVRecord>
|
||||
{
|
||||
public:
|
||||
|
@ -280,7 +280,7 @@ ChannelGetLocalPtr ChannelGetLocal::create(
|
||||
PVCopyPtr pvCopy = PVCopy::create(
|
||||
pvRecord,
|
||||
pvRequest,
|
||||
"field");
|
||||
"");
|
||||
if(pvCopy.get()==NULL) {
|
||||
Status status(
|
||||
Status::Status::STATUSTYPE_ERROR,
|
||||
@ -434,7 +434,7 @@ ChannelPutLocalPtr ChannelPutLocal::create(
|
||||
PVCopyPtr pvCopy = PVCopy::create(
|
||||
pvRecord,
|
||||
pvRequest,
|
||||
"field");
|
||||
"");
|
||||
if(pvCopy.get()==NULL) {
|
||||
Status status(
|
||||
Status::Status::STATUSTYPE_ERROR,
|
||||
|
@ -31,13 +31,15 @@ void copy(
|
||||
throw std::length_error("pvSubArrayCopy from length error");
|
||||
}
|
||||
size_t capacity = pvTo.getCapacity();
|
||||
if(toOffset+len>capacity) pvTo.setCapacity(toOffset+len);
|
||||
if(toOffset+len>capacity) capacity = toOffset + len;
|
||||
shared_vector<T> temp(capacity);
|
||||
typename PVValueArray<T>::const_svector vecFrom = pvFrom.view();
|
||||
typename PVValueArray<T>::const_svector vecTo = pvTo.view();
|
||||
shared_vector<T> temp;
|
||||
pvTo.swap(temp);
|
||||
for(size_t i=0; i<toOffset; ++i) temp[i] = vecTo[i];
|
||||
for(size_t i=0; i<len; ++i) temp[i + toOffset] = vecFrom[i + fromOffset];
|
||||
pvTo.replace(temp);
|
||||
for(size_t i=len + toOffset; i<capacity; ++i) temp[i] = vecTo[i];
|
||||
shared_vector<const T> temp2(freeze(temp));
|
||||
pvTo.replace(temp2);
|
||||
}
|
||||
|
||||
void copy(
|
||||
@ -162,15 +164,15 @@ void copy(
|
||||
throw std::length_error("pvSubArrayCopy from length error");
|
||||
}
|
||||
size_t capacity = to.getCapacity();
|
||||
if(toOffset+len>capacity) to.setCapacity(toOffset+len);
|
||||
if(toOffset+len>capacity) capacity = toOffset+len;
|
||||
shared_vector<PVStructurePtr> temp(capacity);
|
||||
typename PVValueArray<PVStructurePtr>::const_svector vecFrom = from.view();
|
||||
typename PVValueArray<PVStructurePtr>::const_svector vecTo = to.view();
|
||||
shared_vector<PVStructurePtr> temp;
|
||||
to.swap(temp);
|
||||
for(size_t i=0; i<len; ++i) {
|
||||
temp[i + toOffset] = vecFrom[i + fromOffset];
|
||||
}
|
||||
to.replace(temp);
|
||||
for(size_t i=0; i<toOffset; ++i) temp[i] = vecTo[i];
|
||||
for(size_t i=0; i<len; ++i) temp[i + toOffset] = vecFrom[i + fromOffset];
|
||||
for(size_t i=len + toOffset; i<capacity; ++i) temp[i] = vecTo[i];
|
||||
shared_vector<const PVStructurePtr> temp2(freeze(temp));
|
||||
to.replace(temp2);
|
||||
}
|
||||
|
||||
void copy(
|
||||
|
72
src/v3IOC/PVAClientRegister.cpp
Normal file
72
src/v3IOC/PVAClientRegister.cpp
Normal file
@ -0,0 +1,72 @@
|
||||
/*PVAClientRegister.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
|
||||
* @date 2013.08.05
|
||||
*/
|
||||
|
||||
/* Author: Marty Kraimer */
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdlib>
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <cstdio>
|
||||
#include <memory>
|
||||
#include <iostream>
|
||||
|
||||
#include <iocsh.h>
|
||||
|
||||
#include <epicsExport.h>
|
||||
|
||||
#include <pv/pvAccess.h>
|
||||
#include <pv/clientFactory.h>
|
||||
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
using namespace epics::pvData;
|
||||
using namespace epics::pvAccess;
|
||||
|
||||
|
||||
static const iocshFuncDef startPVAClientFuncDef = {
|
||||
"startPVAClient", 0, 0
|
||||
};
|
||||
extern "C" void startPVAClient(const iocshArgBuf *args)
|
||||
{
|
||||
ClientFactory::start();
|
||||
}
|
||||
|
||||
static const iocshFuncDef stopPVAClientFuncDef = {
|
||||
"stopPVAClient", 0, 0
|
||||
};
|
||||
extern "C" void stopPVAClient(const iocshArgBuf *args)
|
||||
{
|
||||
ClientFactory::stop();
|
||||
}
|
||||
|
||||
|
||||
static void startPVAClientRegister(void)
|
||||
{
|
||||
static int firstTime = 1;
|
||||
if (firstTime) {
|
||||
firstTime = 0;
|
||||
iocshRegister(&startPVAClientFuncDef, startPVAClient);
|
||||
}
|
||||
}
|
||||
|
||||
static void stopPVAClientRegister(void)
|
||||
{
|
||||
static int firstTime = 1;
|
||||
if (firstTime) {
|
||||
firstTime = 0;
|
||||
iocshRegister(&stopPVAClientFuncDef, stopPVAClient);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
epicsExportRegistrar(startPVAClientRegister);
|
||||
epicsExportRegistrar(stopPVAClientRegister);
|
2
src/v3IOC/PVAClientRegister.dbd
Normal file
2
src/v3IOC/PVAClientRegister.dbd
Normal file
@ -0,0 +1,2 @@
|
||||
registrar("startPVAClientRegister")
|
||||
registrar("stopPVAClientRegister")
|
Reference in New Issue
Block a user