5538 lines
187 KiB
HTML
5538 lines
187 KiB
HTML
<?xml version="1.0" encoding="iso-8859-1"?>
|
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
|
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
|
<html xmlns="http://www.w3.org/1999/xhtml">
|
|
<head>
|
|
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
|
|
<title>EPICS pvDataCPP</title>
|
|
<link rel="stylesheet" type="text/css"
|
|
href="http://epics-pvdata.sourceforge.net/base.css" />
|
|
<link rel="stylesheet" type="text/css"
|
|
href="http://epics-pvdata.sourceforge.net/epicsv4.css" />
|
|
<style type="text/css">
|
|
/*<![CDATA[*/
|
|
.about { margin-left: 3em; margin-right: 3em; font-size: .83em}
|
|
table { margin-left: auto; margin-right: auto }
|
|
.diagram { text-align: center; margin: 2.5em 0 }
|
|
span.opt { color: grey }
|
|
span.nterm { font-style:italic }
|
|
span.term { font-family:courier }
|
|
span.user { font-family:courier }
|
|
span.user:before { content:"<" }
|
|
span.user:after { content:">" }
|
|
.nonnorm { font-style:italic }
|
|
p.ed { color: #AA0000 }
|
|
span.ed { color: #AA0000 }
|
|
p.ed.priv { display: inline; }
|
|
span.ed.priv { display: inline; }
|
|
/*]]>*/</style>
|
|
<!-- Script that generates the Table of Contents -->
|
|
<script type="text/javascript"
|
|
src="http://epics-pvdata.sourceforge.net/script/tocgen.js">
|
|
</script>
|
|
</head>
|
|
<body>
|
|
|
|
<div class="head">
|
|
<h1>EPICS pvDataCPP</h1>
|
|
<!-- Maturity: Working Draft or Request for Comments, or Recommendation, and date. -->
|
|
|
|
<h2 class="nocount">EPICS v4 Working Group, Working Draft, 01-May-2014</h2>
|
|
|
|
<dl>
|
|
<dt>Latest version:</dt>
|
|
<dd><a
|
|
href="pvDataCPP.html">pvDataCPP.html</a>
|
|
</dd>
|
|
<dt>This version:</dt>
|
|
<dd><a
|
|
href="pvDataCPP_20140501.html">pvDataCPP_20140501.html</a>
|
|
</dd>
|
|
<dt>Previous version:</dt>
|
|
<dd><a
|
|
href="pvDataCPP_20131023.html">pvDataCPP_20131023.html</a>
|
|
</dd>
|
|
<dt>Editors:</dt>
|
|
<dd>Marty Kraimer, BNL</dd>
|
|
<dd>Michael Davidsaver, BNL</dd>
|
|
<dd>Matej Sekoranja, CosyLab</dd>
|
|
</dl>
|
|
|
|
<p class="copyright">This product is made available subject to acceptance of the <a
|
|
href="http://epics-pvdata.sourceforge.net/LICENSE.html">EPICS open source
|
|
license.</a></p>
|
|
<hr />
|
|
</div>
|
|
|
|
<h2 class="nocount">Abstract</h2>
|
|
|
|
<p>EPICS Version 4 provides efficient
|
|
storage, access, and communication, of memory resident structured data.
|
|
pvData is the storage compoment.
|
|
pvDataCPP is the C++ implementation of pvData.
|
|
It is one part of the set of related products in the EPICS
|
|
V4 control system programming environment:<br />
|
|
<a href="http://epics-pvdata.sourceforge.net/relatedDocumentsV4.html">relatedDocumentsV4.html</a>
|
|
</p>
|
|
|
|
|
|
<h2 class="nocount">Status of this Document</h2>
|
|
|
|
<p>This is the 01-May-2014 version of the C++ implementation of pvData.
|
|
</p>
|
|
|
|
<p>RELEASE_NOTES.md provides changes since the last release.
|
|
TODO.md describes things to do before the next release.
|
|
</p>
|
|
|
|
|
|
<div id="toc">
|
|
<h2 class="nocount" style="page-break-before: always">Table of Contents</h2>
|
|
</div>
|
|
<div id="contents" class="contents">
|
|
|
|
<h2>Introduction</h2>
|
|
|
|
<p>pvData is one of a set of related projects. It describes and implements
|
|
data that the other projects support. Thus it is not useful by itself but
|
|
understanding pvData is required in order to understand the other projects. The
|
|
reader should also become familar with project pvAccess, which is
|
|
located via the same sourceforge site as this project.</p>
|
|
|
|
<p>The Java and C++ implementation of pvData implement the same data model but
|
|
differ in implementation because of the differences between Java and C++.</p>
|
|
|
|
<p>It is a good idea to read all of pvDataJava.html but read at least the
|
|
first two chapters:</p>
|
|
<dl>
|
|
<dt>Introduction</dt>
|
|
<dd>A brief descripton of pvData.</dd>
|
|
<dt>PVData Meta Language</dt>
|
|
<dd>A language used to describe data.</dd>
|
|
</dl>
|
|
|
|
<p>The material in these two chapters is NOT repeated in this documentation.</p>
|
|
|
|
<p>Doxygen documentation is available at <a
|
|
href="./html/index.html">doxygenDoc</a></p>
|
|
<p>The next section provides some examples of creating and accessing data.
|
|
</p>
|
|
<p>This document discusses the following:</p>
|
|
<dl>
|
|
<dt>pvDataAPP/pv</dt>
|
|
<dd>This subdirectory contains all the public interfaces that describe pvData.
|
|
The section from <b>Namespace and Memory Management</b>
|
|
through <b>Conversion</b> discuss these interfaces.
|
|
</dd>
|
|
<dt>pvDataApp/property</dt>
|
|
<dd>This section has support for managing "standard" fields.
|
|
</dd>
|
|
<dt>pvDataApp/misc</dt>
|
|
<dd>This section has support for facilities required by implementation code.</dd>
|
|
<dt>copy and monitor</dt>
|
|
<dd>These sections provide pvData support for implementing pvAccess providers.</dd>
|
|
</dl>
|
|
|
|
<h2>Examples</h2>
|
|
<p>This section provides some examples of creating and accessing both introspection and
|
|
data interfaces. The first time reader may not understand them but hopefully will get an
|
|
idea of how pvData works. After reading the rest of this document the examples will
|
|
be much easier to understand.
|
|
</p>
|
|
</p>The documentation directory for this project has a file <b>examples.zip</b>.
|
|
It has the code for the examples.
|
|
After it is unzipped just edit configure/RELEASE.local and then execute make.
|
|
</p>
|
|
<p>The examples assume that the following statements have been issued:</p>
|
|
<pre>
|
|
String builder;
|
|
FieldCreatePtr fieldCreate = getFieldCreate();
|
|
PVDataCreatePtr pvDataCreate = getPVDataCreate();
|
|
StandardFieldPtr standardField = getStandardField();
|
|
StandardPVFieldPtr standardPVField = getStandardPVField();
|
|
StructureConstPtr alarm = getStandardField()->alarm();
|
|
StructureConstPtr timeStamp = getStandardField()->timeStamp();
|
|
</pre>
|
|
<p>These provide access to most of pvData:</p>
|
|
<dl>
|
|
<dt>fieldCreate</dt>
|
|
<dd>This creates instances of introspection objects.
|
|
It also provides fieldBuilder, which provides an easier way to create introspection objects.
|
|
</dd>
|
|
<dt>pvDataCreate</dt>
|
|
<dd>This creates instances of data objects.
|
|
</dd>
|
|
<dt>standardField</dt>
|
|
<dd>This provides support for introspection obects for standard fields,
|
|
Standard fields are alarm, timeStamp, display, enumerated structure, and value alarm.
|
|
</dd>
|
|
<dt>standardPVField</dt>
|
|
<dd>This provides support for data obects for standard fields,
|
|
</dd>
|
|
</dl>
|
|
|
|
|
|
<h3>Introspection Examples</h3>
|
|
<p>The examples all produce a top level structure.
|
|
The reason is that top level structures are what pvAccess passes between client and server
|
|
and what pvDatabaseCPP supports.</p>
|
|
<h4>Three ways to create a structure</h4>
|
|
<p>The following is the hardest way to create structure that has a double value field and a time stamp field:
|
|
It uses only createField.
|
|
</p>
|
|
<pre>
|
|
size_t n = 3;
|
|
StringArray names;
|
|
names.reserve(n);
|
|
FieldConstPtrArray fields;
|
|
fields.reserve(n);
|
|
names.push_back("secsPastEpoch");
|
|
fields.push_back(fieldCreate->createScalar(pvLong));
|
|
names.push_back("nanoseconds");
|
|
fields.push_back(fieldCreate->createScalar(pvInt));
|
|
names.push_back("userTag");
|
|
fields.push_back(fieldCreate->createScalar(pvInt));
|
|
StructureConstPtr timeStamp = fieldCreate->createStructure(names,fields);
|
|
size_t ntop = 2;
|
|
StringArray topnames;
|
|
topnames.reserve(ntop);
|
|
FieldConstPtrArray topfields;
|
|
topfields.reserve(ntop);
|
|
topnames.push_back("value");
|
|
topfields.push_back(fieldCreate->createScalar(pvDouble));
|
|
topnames.push_back("timeStamp");
|
|
topfields.push_back(timeStamp);
|
|
StructureConstPtr doubleScalar = fieldCreate->createStructure(topnames,topfields);
|
|
builder.clear();
|
|
doubleScalar->toString(&builder);
|
|
cout << builder << "\n\n";
|
|
</pre>
|
|
<p>Using FieldBuilder the same can be done via:</p>
|
|
<pre>
|
|
StructureConstPtr doubleScalarHard =
|
|
getFieldCreate()->createFieldBuilder()->
|
|
add("value",pvDouble) ->
|
|
addNestedStructure("timeStamp")->
|
|
setId("time_t")->
|
|
add("secsPastEpoch", pvLong)->
|
|
add("nanoseconds", pvInt)->
|
|
add("userTag", pvInt)->
|
|
endNested()->
|
|
createStructure();
|
|
builder.clear();
|
|
doubleScalarHard->toString(&builder);
|
|
cout << builder << endl;
|
|
</pre>
|
|
Both produce:
|
|
<pre>
|
|
structure
|
|
double value
|
|
time_t timeStamp
|
|
long secsPastEpoch
|
|
int nanoseconds
|
|
</pre>
|
|
<p>An easy way to create a structure with a string array value field and an alarm and time stamp is
|
|
via standardField:</p>
|
|
<pre>
|
|
StructureConstPtr stringArrayEasy =
|
|
getStandardField()->scalarArray(pvString,"alarm,timeStamp");
|
|
builder.clear();
|
|
stringArrayEasy->toString(&builder);
|
|
cout << builder << endl;
|
|
</pre>
|
|
It produces :
|
|
<pre>
|
|
uri:ev4:nt/2012/pwd:NTScalarArray
|
|
string[] value
|
|
alarm_t alarm
|
|
int severity
|
|
int status
|
|
string message
|
|
time_t timeStamp
|
|
long secondsPastEpoch
|
|
int nanoSeconds
|
|
int userTag
|
|
</pre>
|
|
<h4>enumerated structure</h4>
|
|
<p>An enumerated structure is a structure with two sub-fields:
|
|
index, which is an int, and choices, which is an array of string.
|
|
The following examples create a structure which has a field names value, which
|
|
is an enumerated structure and additional fields.
|
|
A hard way to create an structure with an enumerated value field and a time stamp is:</p>
|
|
<pre>
|
|
StructureConstPtr enum_t =
|
|
getFieldCreate()->createFieldBuilder()->
|
|
setId("enum_t")->
|
|
add("index", pvInt)->
|
|
addArray("choices", pvString)->
|
|
createStructure();
|
|
|
|
StructureConstPtr ntEnumHard =
|
|
getFieldCreate()->createFieldBuilder()->
|
|
setId("uri:ev4:nt/2012/pwd/NTEnum")->
|
|
add("value", enum_t)->
|
|
addNestedStructure("timeStamp")->
|
|
setId("time_t")->
|
|
add("secsPastEpoch", pvLong)->
|
|
add("nanoseconds", pvInt)->
|
|
add("userTag", pvInt)->
|
|
endNested()->
|
|
createStructure();
|
|
builder.clear();
|
|
ntEnumHard->toString(&builder);
|
|
cout << builder << endl;
|
|
</pre>
|
|
It produces:
|
|
<pre>
|
|
uri:ev4:nt/2012/pwd/NTEnum
|
|
enum_t value
|
|
int index
|
|
string[] choices
|
|
time_t timeStamp
|
|
long secsPastEpoch
|
|
int nanoseconds
|
|
int userTag
|
|
</pre>
|
|
<p>The following is an easy way. Note that it has two additional
|
|
fields: alarm and timeStamp:</p>
|
|
<pre>
|
|
StructureConstPtr ntEnumEasy = getStandardField()->enumerated("alarm,timeStamp");
|
|
builder.clear();
|
|
ntEnumEasy->toString(&builder);
|
|
cout << builder << endl;
|
|
</pre>
|
|
It produces:
|
|
<pre>
|
|
uri:ev4:nt/2012/pwd:NTEnum
|
|
enum_t value
|
|
int index
|
|
string[] choices
|
|
alarm_t alarm
|
|
int severity
|
|
int status
|
|
string message
|
|
time_t timeStamp
|
|
long secondsPastEpoch
|
|
int nanoSeconds
|
|
int userTag
|
|
</pre>
|
|
|
|
<h4>union example</h4>
|
|
<p>The following creates a union and a structure with a union value field:</p>
|
|
|
|
<pre>
|
|
UnionConstPtr ntunion =
|
|
getFieldCreate()->createFieldBuilder()->
|
|
add("doubleValue", pvDouble)->
|
|
add("intValue", pvInt)->
|
|
add("timeStamp",timeStamp)->
|
|
createUnion();
|
|
builder.clear();
|
|
ntunion->toString(&builder);
|
|
cout << builder << endl;
|
|
|
|
StructureConstPtr unionValue = getStandardField()->regUnion(punion,"alarm,timeStamp");
|
|
builder.clear();
|
|
ntunion->toString(&builder);
|
|
cout << builder << endl;
|
|
</pre>
|
|
It produces:
|
|
<pre>
|
|
union
|
|
double doubleValue
|
|
int intValue
|
|
time_t timeStamp
|
|
long secondsPastEpoch
|
|
int nanoSeconds
|
|
int userTag
|
|
|
|
structure with value field being a union
|
|
uri:ev4:nt/2012/pwd:NTUnion
|
|
union value
|
|
double doubleValue
|
|
int intValue
|
|
time_t timeStamp
|
|
long secondsPastEpoch
|
|
int nanoSeconds
|
|
int userTag
|
|
alarm_t alarm
|
|
int severity
|
|
int status
|
|
string message
|
|
time_t timeStamp
|
|
long secondsPastEpoch
|
|
int nanoSeconds
|
|
int userTag
|
|
</pre>
|
|
<h4>power supply</h4>
|
|
<p>The following creates a more complex structure:</p>
|
|
<pre>
|
|
StructureConstPtr powerSupply =
|
|
getFieldCreate()->createFieldBuilder()->
|
|
add("alarm_t",alarm) ->
|
|
add("timestamp_t",timeStamp) ->
|
|
addNestedStructure("power") ->
|
|
add("value",pvDouble) ->
|
|
add("alarm",alarm) ->
|
|
endNested()->
|
|
addNestedStructure("voltage") ->
|
|
add("value",pvDouble) ->
|
|
add("alarm",alarm) ->
|
|
endNested()->
|
|
addNestedStructure("current") ->
|
|
add("value",pvDouble) ->
|
|
add("alarm",alarm) ->
|
|
endNested()->
|
|
createStructure();
|
|
builder.clear();
|
|
powerSupply->toString(&builder);
|
|
cout << builder << endl;
|
|
</pre>
|
|
It produces:
|
|
<pre>
|
|
structure
|
|
alarm_t alarm_t
|
|
int severity
|
|
int status
|
|
string message
|
|
time_t timestamp_t
|
|
long secondsPastEpoch
|
|
int nanoSeconds
|
|
int userTag
|
|
structure power
|
|
double value
|
|
alarm_t alarm
|
|
int severity
|
|
int status
|
|
string message
|
|
structure voltage
|
|
double value
|
|
alarm_t alarm
|
|
int severity
|
|
int status
|
|
string message
|
|
structure current
|
|
double value
|
|
alarm_t alarm
|
|
int severity
|
|
int status
|
|
string message
|
|
</pre>
|
|
<h3>Data Examples</h3>
|
|
<p>The examples all produce a top level structure.</p>
|
|
<h4>scalar example</h4>
|
|
<pre>
|
|
PVStructurePtr doubleValue = getPVDataCreate()->createPVStructure(
|
|
getStandardField()->scalar(pvDouble,"alarm,timeStamp"));
|
|
PVDoublePtr pvdouble =
|
|
doubleValue->getSubField<PVDouble>("value");
|
|
pvdouble->put(1e5);
|
|
cout << doubleValue->dumpValue(cout) << endl;
|
|
</pre>
|
|
This produces:
|
|
<pre>
|
|
uri:ev4:nt/2012/pwd:NTScalar
|
|
double value 100000
|
|
alarm_t alarm
|
|
int severity 0
|
|
int status 0
|
|
string message
|
|
time_t timeStamp
|
|
long secondsPastEpoch 0
|
|
int nanoSeconds 0
|
|
int userTag 0
|
|
0x607268
|
|
</pre>
|
|
<h4>array example</h4>
|
|
<pre>
|
|
PVStructurePtr doubleArrayValue = getPVDataCreate()->createPVStructure(
|
|
getStandardField()->scalarArray(pvDouble,"alarm,timeStamp"));
|
|
PVDoubleArrayPtr pvDoubleArray =s
|
|
doubleArrayValue->getSubField<PVDoubleArray>("value");
|
|
size_t len = 10;
|
|
shared_vector<double> xxx(len);
|
|
for(size_t i=0; i< len; ++i) xxx[i] = i;
|
|
shared_vector<const double> data(freeze(xxx));
|
|
pvDoubleArray->replace(data);
|
|
cout << doubleArrayValue->dumpValue(cout) << endl;
|
|
|
|
shared_vector<const double> getData = pvDoubleArray->view();
|
|
cout << "via getData";
|
|
for (size_t i=0; i< len; ++i) cout << " " << getData[i];
|
|
cout << endl;
|
|
</pre>
|
|
This produces:
|
|
<pre>
|
|
uri:ev4:nt/2012/pwd:NTScalarArray
|
|
double[] value [0,1,2,3,4,5,6,7,8,9]
|
|
alarm_t alarm
|
|
int severity 0
|
|
int status 0
|
|
string message
|
|
time_t timeStamp
|
|
long secondsPastEpoch 0
|
|
int nanoSeconds 0
|
|
int userTag 0
|
|
0x607268
|
|
via getData 0 1 2 3 4 5 6 7 8 9
|
|
</pre>
|
|
<h4>enumerated example</h4>
|
|
<pre>
|
|
PVStructurePtr pvntenum = getPVDataCreate()->createPVStructure(
|
|
getStandardField()->enumerated("alarm,timeStamp"));
|
|
cout << pvntenum->dumpValue(cout) << "\n\n";
|
|
</pre>
|
|
This produces:
|
|
<pre>
|
|
uri:ev4:nt/2012/pwd:NTEnum
|
|
enum_t value
|
|
int index 0
|
|
string[] choices []
|
|
alarm_t alarm
|
|
int severity 0
|
|
int status 0
|
|
string message
|
|
time_t timeStamp
|
|
long secondsPastEpoch 0
|
|
int nanoSeconds 0
|
|
int userTag 0
|
|
0x607268
|
|
</pre>
|
|
<h4>power supply example</h4>
|
|
<pre>
|
|
StructureConstPtr powerSupply =
|
|
getFieldCreate()->createFieldBuilder()->
|
|
add("alarm_t",alarm) ->
|
|
add("timestamp_t",timeStamp) ->
|
|
addNestedStructure("power") ->
|
|
add("value",pvDouble) ->
|
|
add("alarm",alarm) ->
|
|
endNested()->
|
|
addNestedStructure("voltage") ->
|
|
add("value",pvDouble) ->
|
|
add("alarm",alarm) ->
|
|
endNested()->
|
|
addNestedStructure("current") ->
|
|
add("value",pvDouble) ->
|
|
add("alarm",alarm) ->
|
|
endNested()->
|
|
createStructure();
|
|
PVStructurePtr pvpowerSupply = getPVDataCreate()->createPVStructure(powerSupply);
|
|
cout << pvpowerSupply->dumpValue(cout) << endl;
|
|
</pre>
|
|
This produces:
|
|
<pre>
|
|
structure
|
|
alarm_t alarm_t
|
|
int severity 0
|
|
int status 0
|
|
string message
|
|
time_t timestamp_t
|
|
long secondsPastEpoch 0
|
|
int nanoSeconds 0
|
|
int userTag 0
|
|
structure power
|
|
double value 0
|
|
alarm_t alarm
|
|
int severity 0
|
|
int status 0
|
|
string message
|
|
structure voltage
|
|
double value 0
|
|
alarm_t alarm
|
|
int severity 0
|
|
int status 0
|
|
string message
|
|
structure current
|
|
double value 0
|
|
alarm_t alarm
|
|
int severity 0
|
|
int status 0
|
|
string message
|
|
0x607268
|
|
</pre>
|
|
<h4>union example</h4>
|
|
<pre>
|
|
PVStructurePtr pvStructure = pvDataCreate->createPVStructure(
|
|
standardField->regUnion(
|
|
getFieldCreate()->createFieldBuilder()->
|
|
add("doubleValue", pvDouble)->
|
|
add("intValue", pvInt)->
|
|
add("timeStamp",timeStamp)->
|
|
createUnion(),
|
|
"alarm,timeStamp"));
|
|
PVStructurePtr pvTimeStamp =
|
|
pvStructure->getSubField<PVUnion>("value")->select<PVStructure>(2);
|
|
pvTimeStamp->getSubField<PVLong>("secondsPastEpoch")->put(1000);
|
|
cout << pvStructure->dumpValue(cout) << "\n";
|
|
pvStructure->getSubField<PVUnion>("value")->select<PVDouble>(0)->put(1e5);
|
|
cout << pvStructure->dumpValue(cout) << "\n\n";
|
|
</pre>
|
|
This produces:
|
|
<pre>
|
|
uri:ev4:nt/2012/pwd:NTUnion
|
|
union value
|
|
time_t
|
|
long secondsPastEpoch 1000
|
|
int nanoSeconds 0
|
|
int userTag 0
|
|
alarm_t alarm
|
|
int severity 0
|
|
int status 0
|
|
string message
|
|
time_t timeStamp
|
|
long secondsPastEpoch 0
|
|
int nanoSeconds 0
|
|
int userTag 0
|
|
0x60a2c8
|
|
uri:ev4:nt/2012/pwd:NTUnion
|
|
union value
|
|
double 100000
|
|
alarm_t alarm
|
|
int severity 0
|
|
int status 0
|
|
string message
|
|
time_t timeStamp
|
|
long secondsPastEpoch 0
|
|
int nanoSeconds 0
|
|
int userTag 0
|
|
0x60a2c8
|
|
</pre>
|
|
|
|
<h4>varient union example</h4>
|
|
<pre>
|
|
PVStructurePtr pvStructure = pvDataCreate->createPVStructure(
|
|
standardField->variantUnion("alarm,timeStamp"));
|
|
PVStructurePtr pvTimeStamp =
|
|
pvDataCreate->createPVStructure(standardField->timeStamp());
|
|
pvStructure->getSubField<PVUnion>("value")->set(pvTimeStamp);
|
|
pvTimeStamp->getSubField<PVLong>("secondsPastEpoch")->put(1000);
|
|
cout << pvStructure->dumpValue(cout) << "\n";
|
|
pvStructure->getSubField<PVUnion>("value")->set(
|
|
pvDataCreate->createPVScalar(pvDouble));
|
|
PVDoublePtr pvValue = static_pointer_cast<PVDouble>(
|
|
pvStructure->getSubField<PVUnion>("value")->get());
|
|
pvValue->put(1e5);
|
|
cout << pvStructure->dumpValue(cout) << "\n\n";
|
|
</pre>
|
|
This produces:
|
|
<pre>
|
|
uri:ev4:nt/2012/pwd:NTUnion
|
|
any value
|
|
time_t
|
|
long secondsPastEpoch 1000
|
|
int nanoSeconds 0
|
|
int userTag 0
|
|
alarm_t alarm
|
|
int severity 0
|
|
int status 0
|
|
string message
|
|
time_t timeStamp
|
|
long secondsPastEpoch 0
|
|
int nanoSeconds 0
|
|
int userTag 0
|
|
0x60a2c8
|
|
uri:ev4:nt/2012/pwd:NTUnion
|
|
any value
|
|
double 100000
|
|
alarm_t alarm
|
|
int severity 0
|
|
int status 0
|
|
string message
|
|
time_t timeStamp
|
|
long secondsPastEpoch 0
|
|
int nanoSeconds 0
|
|
int userTag 0
|
|
0x60a2c8
|
|
</pre>
|
|
|
|
<h4>big union example</h4>
|
|
<pre>
|
|
PVStructurePtr pvStructure = pvDataCreate->createPVStructure(
|
|
standardField->regUnion(
|
|
getFieldCreate()->createFieldBuilder()->
|
|
add("doubleValue", pvDouble)->
|
|
addArray("doubleArrayValue",pvDouble)->
|
|
addNestedUnion("unionValue") ->
|
|
add("doubleValue", pvDouble)->
|
|
add("alarm",standardField->alarm()) ->
|
|
endNested() ->
|
|
addNestedStructure("structValue") ->
|
|
add("doubleValue", pvDouble)->
|
|
addArray("doubleArrayValue",pvDouble)->
|
|
endNested() ->
|
|
addNestedUnionArray("unionArrayValue") ->
|
|
add("doubleValue", pvDouble)->
|
|
add("alarm",standardField->alarm()) ->
|
|
endNested() ->
|
|
addNestedStructureArray("structArrayValue") ->
|
|
add("doubleValue", pvDouble)->
|
|
addArray("doubleArrayValue",pvDouble)->
|
|
endNested() ->
|
|
createUnion(),
|
|
"alarm,timeStamp"));
|
|
builder.clear();
|
|
pvStructure->getStructure()->toString(&builder);
|
|
cout << "introspection\n";
|
|
cout << builder << endl;
|
|
cout << "data\n";
|
|
cout << pvStructure->dumpValue(cout) << "\n";
|
|
PVUnionPtr pvUnion = pvStructure->getSubField<PVUnion>("value");;
|
|
pvUnion->select("doubleValue");
|
|
PVDoublePtr pvDouble = pvUnion->get<PVDouble>();
|
|
pvDouble->put(1.55);
|
|
cout << "select valueDouble\n";
|
|
cout << pvStructure->dumpValue(cout) << "\n";
|
|
cout << "value = " << pvDouble->get() << "\n";
|
|
pvUnion->select("structValue");
|
|
pvDouble = pvUnion->get<PVStructure>()->getSubField<PVDouble>("doubleValue");
|
|
pvDouble->put(1.65);
|
|
cout << "select structValue\n";
|
|
cout << pvStructure->dumpValue(cout) << "\n";
|
|
cout << "value = " << pvDouble->get() << "\n";
|
|
</pre>
|
|
This produces:
|
|
<pre>
|
|
introspection
|
|
uri:ev4:nt/2012/pwd:NTUnion
|
|
union value
|
|
double doubleValue
|
|
double[] doubleArrayValue
|
|
union unionValue
|
|
double doubleValue
|
|
alarm_t alarm
|
|
int severity
|
|
int status
|
|
string message
|
|
structure structValue
|
|
double doubleValue
|
|
double[] doubleArrayValue
|
|
union[] unionArrayValue
|
|
union[]
|
|
union
|
|
double doubleValue
|
|
alarm_t alarm
|
|
int severity
|
|
int status
|
|
string message
|
|
structure[] structArrayValue
|
|
structure[]
|
|
structure
|
|
double doubleValue
|
|
double[] doubleArrayValue
|
|
alarm_t alarm
|
|
int severity
|
|
int status
|
|
string message
|
|
time_t timeStamp
|
|
long secondsPastEpoch
|
|
int nanoSeconds
|
|
int userTag
|
|
data
|
|
uri:ev4:nt/2012/pwd:NTUnion
|
|
union value
|
|
(none)
|
|
alarm_t alarm
|
|
int severity 0
|
|
int status 0
|
|
string message
|
|
time_t timeStamp
|
|
long secondsPastEpoch 0
|
|
int nanoSeconds 0
|
|
int userTag 0
|
|
0x60a2c8
|
|
select valueDouble
|
|
uri:ev4:nt/2012/pwd:NTUnion
|
|
union value
|
|
double 1.55
|
|
alarm_t alarm
|
|
int severity 0
|
|
int status 0
|
|
string message
|
|
time_t timeStamp
|
|
long secondsPastEpoch 0
|
|
int nanoSeconds 0
|
|
int userTag 0
|
|
0x60a2c8
|
|
value = 1.55
|
|
select structValue
|
|
uri:ev4:nt/2012/pwd:NTUnion
|
|
union value
|
|
structure
|
|
double doubleValue 1.65
|
|
double[] doubleArrayValue []
|
|
alarm_t alarm
|
|
int severity 0
|
|
int status 0
|
|
string message
|
|
time_t timeStamp
|
|
long secondsPastEpoch 0
|
|
int nanoSeconds 0
|
|
int userTag 0
|
|
0x60a2c8
|
|
value = 1.65
|
|
</pre>
|
|
|
|
<h2>Namespace and Memory Management</h2>
|
|
|
|
<h3>Namespace</h3>
|
|
|
|
<p>All code in project pvDataCPP appears in namespace: </p>
|
|
<pre>namespace epics { namespace pvData {
|
|
// ...
|
|
}}</pre>
|
|
|
|
<h3>Memory Managemment</h3>
|
|
|
|
<p>Many pvDataCPP introspection and data objects are designed to be shared. They are
|
|
made availiable via <b>std::tr1::shared_ptr</b>.
|
|
The following naming convention is used
|
|
in typedefs:</p>
|
|
<dl>
|
|
<dt>Ptr</dt>
|
|
<dd>When <b>Ptr</b> appears it stands for <b>std::tr1::shared_ptr</b>.
|
|
</dd>
|
|
</dl>
|
|
<p>For example:</p>
|
|
<pre>
|
|
typedef PVScalarValue<boolean> PVBoolean;
|
|
typedef std::tr1::shared_ptr<PVBoolean> PVBooleanPtr;
|
|
</pre>
|
|
|
|
<h2>pvDataApp/pv</h2>
|
|
|
|
<p>Directory <b>pvDataApp/pv</b> has header files that completely describe pvData.
|
|
The implementation is provided in directory <b>pvDataApp/factory</b>.
|
|
Test programs appears in <b>testApp/pv</b>.</p>
|
|
|
|
<p><b>NOTES</b>:</p>
|
|
<dl>
|
|
<dt>interface</dt>
|
|
<dd>The documention uses the word <b>interface</b>.
|
|
This is an analogy with how Java defines interface.
|
|
C++ does not have interfaces but directory pv defines classes
|
|
with public members that are similar to the Java interfaces. Most of the
|
|
implementation is in factory.</dd>
|
|
<dt>Naming Convertions</dt>
|
|
<dd>The naming convertions for variables, methods, and classes follow the
|
|
Java convertions, i. e. class name begin with an upper case letter,
|
|
variables and methods begin with a lower case letter.</dd>
|
|
</dl>
|
|
|
|
<p>A PVStructure is a field that contains an array of subfields. Each field has
|
|
code for accessing the field. The interface for each field is an interface that
|
|
extends PVField. Each field also has an introspection interface, which an
|
|
extension of Field. The next few sections describes the complete set of C++
|
|
introspection and data interfaces for pvData. </p>
|
|
|
|
<p>Class FieldCreate creates introspection objects. Class PVDataCreate creates
|
|
data objects. Class Convert provides a rich set of methods for converting and
|
|
copying data between fields.</p>
|
|
|
|
<p>Directory pvDataApp/pv has the following header files:</p>
|
|
<dl>
|
|
<dt>pvType.h</dt>
|
|
<dd>C++ definitions for primitive types.</dd>
|
|
<dt>pvIntrospect.h</dt>
|
|
<dd>A complete description of the introspection interfaces.</dd>
|
|
<dt>pvData.h</dt>
|
|
<dd>A complete description of the data interfaces.</dd>
|
|
<dt>convert.h</dt>
|
|
<dd>A facility that converts between data fields.</dd>
|
|
<dt>pvSubArrayCopy.h</dt>
|
|
<dd>This provides a facility that performs array coping between
|
|
arrays that have the same type.</dd>
|
|
<dt>standardField.h</dt>
|
|
<dd>Provides access to introspection interfaces for standard structures
|
|
like timeStamp, alarm, etc.</dd>
|
|
<dt>standardPVField.h</dt>
|
|
<dd>Cteates data interfaces for standard data structures like timeStamp,
|
|
alarm, etc.</dd>
|
|
<dt>printer.h</dt>
|
|
<dd><b>TBD</b> This is not documented.
|
|
In addition toString and dumpValue should be reviewed.
|
|
</dd>
|
|
</dl>
|
|
|
|
<h2>pvType.h</h2>
|
|
|
|
<p>This provides C/C++ definitions for the pvData primitive types: boolean,
|
|
byte, short, int, long, ubyte,ushort, uint,u long,float, double, and string.
|
|
Because pvData is network data, the C++ implementation must implement the
|
|
proper semantics for the primitive types.</p>
|
|
|
|
<p>pvType.h provides the proper semantics.</p>
|
|
|
|
<p>It includes the definitions:</p>
|
|
<pre>
|
|
typedef /*lots of stuff*/ boolean
|
|
|
|
typedef int8_t int8;
|
|
typedef int16_t int16;
|
|
typedef int32_t int32;
|
|
typedef int64_t int64;
|
|
typedef uint8_t uint8;
|
|
typedef uint16_t uint16;
|
|
typedef uint32_t uint32;
|
|
typedef uint64_t uint64;
|
|
// float and double are types
|
|
typedef std::string String;
|
|
|
|
typedef std::vector<String> StringArray;
|
|
typedef std::tr1::shared_ptr<StringArray> StringArrayPtr;
|
|
inline String * get(StringArray &value);
|
|
inline String const * get(StringArray const &value);
|
|
inline String * get(StringArrayPtr &value);
|
|
inline String const * get(StringArrayPtr const &value);
|
|
}
|
|
inline StringArray & getVector(StringArrayPtr &value);
|
|
inline StringArray const & getVector(StringArrayPtr const &value);
|
|
typedef std::vector<String>::iterator StringArray_iterator;
|
|
typedef std::vector<String>::const_iterator StringArray_const_iterator;
|
|
|
|
typedef String * StringBuilder;
|
|
</pre>
|
|
|
|
<p>where</p>
|
|
<dl>
|
|
<dt>boolean</dt>
|
|
<dd>A c++ bool has the semantics required for boolean. Only the name is
|
|
different. C++ code can use either bool or boolean.</dd>
|
|
<dt>int8,...,uint64</dt>
|
|
<dd>Integers present a problem because short, int, and long are C++
|
|
reserved words but do not have a well defined number of bits. Thus for
|
|
C++ the definitions above are used in C++ code. The above definitions
|
|
have worked on all C++ implementations tested at present. If they break
|
|
in a future implementation they should be changes via "#ifdef"
|
|
preprocessor statements.</dd>
|
|
<dt>String</dt>
|
|
<dd>pvData requires that a string be an immutable string that is transfered
|
|
over the network as a UTF8 encoded string. Since std::string implements
|
|
copy on write semantics, it can be used for support for immutable
|
|
strings. It can also be serialized/deserialized as a UTF8 encoded string.
|
|
Because it is not a C++ primitive the first letter is capitalized. This
|
|
is the same convention the Java implementation uses.
|
|
Note that string is treated like a primitive type.</dd>
|
|
<dt>StringArray definitions</dt>
|
|
<dd>typedefs are provided for an array of Strings,
|
|
which is a std::vector<String>.
|
|
This is used by introspection.
|
|
</dd>
|
|
<dt>StringBuilder</dt>
|
|
<dd>This is used to implement semantics similar to the Java toString
|
|
method. It is being replaced by the C++ stream semantics.</dd>
|
|
</dl>
|
|
<p><b>TBD</b>
|
|
<dl>
|
|
<dt>boolean</dt>
|
|
<dd>Question for Michael. Why isn't the definition of <b>boolean</b> just
|
|
<pre>
|
|
typedef uint8_t boolean;
|
|
</pre>
|
|
<dt>StringBuilder</dt>
|
|
<dd>Should this go away?
|
|
Note that it is used for both introspection and data.
|
|
</dd>
|
|
<dt>printer.h</dt>
|
|
<dd>Not documented.
|
|
How should printer, toString, and dumpValue be related?
|
|
Also limit number of elements to show if array is large.
|
|
</dd>
|
|
</dl>
|
|
</p>
|
|
|
|
<h2>pvIntrospect.h</h2>
|
|
|
|
<p>This subsection describes pvIntrospect.h This file is quite big so rather
|
|
than showing the entire file, it will be described in parts. </p>
|
|
|
|
<p>The primary purpose for pvData is to support network access to structured data.
|
|
pvAccess transports top level pvStructures. In addition a pvAccess server holds
|
|
a set of pvnames, where each name is a unique name in the local network.
|
|
This is also refered to as the channel name.
|
|
</p>
|
|
|
|
<p>Given a pvname , it is possible to introspect the types of the associated data
|
|
access to data. The reflection and data interfaces are separate because the
|
|
data may not be available. For example when a pvAccess client connects to a pvname,
|
|
the client library can obtain the reflection information without obtaining any
|
|
data. Only when a client issues an I/O request will data be available. This
|
|
separation is especially important for arrays and structures so that a client
|
|
can discover the type without requiring that a large data array or structure be
|
|
transported over the network.</p>
|
|
|
|
<h3>Type Description</h3>
|
|
|
|
<p>Types are defined as:</p>
|
|
<pre>enum Type {
|
|
scalar,
|
|
scalarArray,
|
|
structure,
|
|
structureArray,
|
|
union_,
|
|
unionArray
|
|
};
|
|
|
|
class TypeFunc {
|
|
public:
|
|
const char* name(Type);
|
|
static void toString(StringBuilder buf,const Type type);
|
|
};
|
|
|
|
enum ScalarType {
|
|
pvBoolean,
|
|
pvByte, pvShort, pvInt, pvLong,
|
|
pvUByte, pvUShort, pvUInt, pvULong,
|
|
pvFloat,pvDouble,
|
|
pvString;
|
|
};
|
|
|
|
namespace ScalarTypeFunc {
|
|
public:
|
|
bool isInteger(ScalarType type);
|
|
bool isUInteger(ScalarType type);
|
|
bool isNumeric(ScalarType type);
|
|
bool isPrimitive(ScalarType type);
|
|
ScalarType getScalarType(String const &value);
|
|
const char* name(ScalarType);
|
|
void toString(StringBuilder buf,ScalarType scalarType);
|
|
size_t elementSize(ScalarType id);
|
|
};</pre>
|
|
|
|
<p>Type is one of the following:</p>
|
|
<dl>
|
|
<dt>scalar</dt>
|
|
<dd>A scalar of one of the scalar types.</dd>
|
|
<dt>scalarArray</dt>
|
|
<dd>An array where every element has the same scalar type.</dd>
|
|
<dt>structure</dt>
|
|
<dd>A structure where each field has a name and a type. Within a structure
|
|
each field name must be unique but the types can be different.</dd>
|
|
<dt>structureArray</dt>
|
|
<dd>An array where each element is a structure. Each element has the same
|
|
structure introspection interface.</dd>
|
|
<dt>union_t</dt>
|
|
<dd>This is like a structure that has a single subfield.
|
|
The type for the subfield can either be any type, which is called a varient union,
|
|
of can be one od a specified set of types.
|
|
In the data interfaces the type can be changed dynamically.
|
|
' </dd>
|
|
<dt>unionArray</dt>
|
|
<dd>An array where each element is a union. Each element has the same
|
|
union introspection interface.</dd>
|
|
</dl>
|
|
|
|
<p>ScalarType is one of the following:</p>
|
|
<dl>
|
|
<dt>pvBoolean</dt>
|
|
<dd>Has the value false or true.</dd>
|
|
<dt>pvByte</dt>
|
|
<dd>A signed 8 bit integer.</dd>
|
|
<dt>pvShort</dt>
|
|
<dd>A signed 16 bit integer.</dd>
|
|
<dt>pvInt</dt>
|
|
<dd>A signed 32 bit integer.</dd>
|
|
<dt>pvLong</dt>
|
|
<dd>A signed 64 bit integer.</dd>
|
|
<dt>pvUByte</dt>
|
|
<dd>An unsigned 8 bit integer.</dd>
|
|
<dt>pvUShort</dt>
|
|
<dd>An unsigned 16 bit integer.</dd>
|
|
<dt>pvUInt</dt>
|
|
<dd>An unsigned 32 bit integer.</dd>
|
|
<dt>pvULong</dt>
|
|
<dd>An unsigned 64 bit integer.</dd>
|
|
<dt>pvFloat</dt>
|
|
<dd>A IEEE float.</dd>
|
|
<dt>pvDouble</dt>
|
|
<dd>A IEEE double,</dd>
|
|
<dt>pvString</dt>
|
|
<dd>An immutable string.</dd>
|
|
</dl>
|
|
|
|
<p>TypeFunction is a set of convenience methods for Type</p>
|
|
<dl>
|
|
<dt>name</dt>
|
|
<dd>Returns the name of the type.</dd>
|
|
<dt>toString</dt>
|
|
<dd>Convert the type to a string.</dd>
|
|
</dl>
|
|
|
|
<p>ScalarTypeFunction is a set of convenience methods for ScalarType</p>
|
|
<dl>
|
|
<dt>isInteger</dt>
|
|
<dd>Is the scalarType an integer type, i.e. one of pvByte,...pvULong.</dd>
|
|
<dt>isUInteger</dt>
|
|
<dd>Is the scalarType an unsigned integer type, i.e. one of
|
|
pvUByte,...pvULong</dd>
|
|
<dt>isNumeric</dt>
|
|
<dd>Is the scalarType numeric, i.e. pvByte,...,pvDouble.</dd>
|
|
<dt>isPrimitive</dt>
|
|
<dd>Is the scalarType primitive, i.e. not pvString</dd>
|
|
<dt>name</dt>
|
|
<dd>Returns the name of the scalarType.</dd>
|
|
<dt>getScalarType</dt>
|
|
<dd>Given a string of the form String("boolean"),...,String("string")
|
|
return the scalarType.</dd>
|
|
<dt>toString</dt>
|
|
<dd>Convert the scalar type to a string.</dd>
|
|
<dt>elementSize</dt>
|
|
<dd>Returns the size in bytes of an instance of the scalarType.</dd>
|
|
</dl>
|
|
|
|
<h3>Introspection Description</h3>
|
|
|
|
<p>This section describes the reflection interfaces which provide the
|
|
following: </p>
|
|
<dl>
|
|
<dt>Field</dt>
|
|
<dd>A field:
|
|
<ul>
|
|
<li>Has a Type.</li>
|
|
<li>Can be converted to a string.</li>
|
|
<li>Can be shared. A reference count is kept. When it becomes 0 the
|
|
instance is automatically deleted.</li>
|
|
</ul>
|
|
</dd>
|
|
<dt>Scalar</dt>
|
|
<dd>A scalar has a scalarType</dd>
|
|
<dt>ScalarArray</dt>
|
|
<dd>The element type is a scalarType</dd>
|
|
<dt>Structure</dt>
|
|
<dd>Has fields that can be any of the supported types.</dd>
|
|
<dt>StructureArray</dt>
|
|
<dd>The field holds an array of structures. Each element has the same
|
|
Structure interspection interface. A pvAccess client can only get/put
|
|
entire PVStructure elements NOT subfields of array elements.</dd>
|
|
<dt>Union</dt>
|
|
<dd>
|
|
This has two flavors: a varient union or a union of a fixed set
|
|
of types. A PVUnion will have a single subfield.
|
|
If the union introspection interface is a varient union then
|
|
the single field can be of any type and has the name <b>any</b>.
|
|
If the union is not a varient type then the type can be one of
|
|
a fixed set of types and a name associated with the type.
|
|
The union introspection interface has a field array and a string
|
|
array that has the fixed set of types and associated names.
|
|
</dd>
|
|
<dt>UnionArray</dt>
|
|
<dd>
|
|
This is an array of unions. A PVUnionArray is an array
|
|
of PVUnions. Each element has the same interspection interface
|
|
but the subfield of each element can have a different type.
|
|
</dd>
|
|
<dt>FieldBuilder</dt>
|
|
<dd>This is a convenience interface that makes it easier to create
|
|
top introspection interfaces.
|
|
</dd>
|
|
<dt>FieldCreate</dt>
|
|
<dd>This is an interface that provides methods to create introspection
|
|
interfaces. A factory is provides to create FieldCreate.</dd>
|
|
<dt>getFieldCreate</dt>
|
|
<dd>Gets a pointer to the single instance of FieldCreate.</dd>
|
|
</dl>
|
|
<h3>Field,Scalar,ScalarArray,Structure,StructureArray,Union,UnionArray</h3>
|
|
<pre>class Field;
|
|
class Scalar;
|
|
class ScalarArray;
|
|
class Structure;
|
|
class StructureArray;
|
|
class Union;
|
|
class UnionArray;
|
|
|
|
typedef std::tr1::shared_ptr<const Field> FieldConstPtr;
|
|
typedef std::vector<FieldConstPtr> FieldConstPtrArray;
|
|
typedef std::tr1::shared_ptr<const Scalar> ScalarConstPtr;
|
|
typedef std::tr1::shared_ptr<const ScalarArray> ScalarArrayConstPtr;
|
|
typedef std::tr1::shared_ptr<const Structure> StructureConstPtr;
|
|
typedef std::tr1::shared_ptr<const StructureArray> StructureArrayConstPtr;
|
|
typedef std::tr1::shared_ptr<const Union> UnionConstPtr;
|
|
typedef std::tr1::shared_ptr<const UnionArray> UnionArrayConstPtr;
|
|
|
|
|
|
class Field :
|
|
virtual public Serializable,
|
|
public std::tr1::enable_shared_from_this<Field>
|
|
{
|
|
public:
|
|
POINTER_DEFINITIONS(Field);
|
|
virtual ~Field();
|
|
Type getType() const{return m_type;}
|
|
virtual String getID() const = 0;
|
|
virtual void toString(StringBuilder buf) const{toString(buf,0);}
|
|
virtual void toString(StringBuilder buf,int indentLevel) const;
|
|
...
|
|
};
|
|
|
|
class Scalar : public Field{
|
|
public:
|
|
POINTER_DEFINITIONS(Scalar);
|
|
virtual ~Scalar();
|
|
typedef Scalar& reference;
|
|
typedef const Scalar& const_reference;
|
|
|
|
ScalarType getScalarType() const {return scalarType;}
|
|
virtual void toString(StringBuilder buf) const{toString(buf,0);}
|
|
virtual void toString(StringBuilder buf,int indentLevel) const;
|
|
virtual String getID() const;
|
|
virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const;
|
|
virtual void deserialize(ByteBuffer *buffer, DeserializableContol *control);
|
|
...
|
|
};
|
|
|
|
class ScalarArray : public Field{
|
|
public:
|
|
POINTER_DEFINITIONS(ScalarArray);
|
|
typedef ScalarArray& reference;
|
|
typedef const ScalarArray& const_reference;
|
|
|
|
ScalarArray(ScalarType scalarType);
|
|
ScalarType getElementType() const {return elementType;}
|
|
virtual void toString(StringBuilder buf) const{toString(buf,0);}
|
|
virtual void toString(StringBuilder buf,int indentLevel) const;
|
|
virtual String getID() const;
|
|
virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const;
|
|
virtual void deserialize(ByteBuffer *buffer, DeserializableControl *control);
|
|
...
|
|
};
|
|
|
|
class StructureArray : public Field{
|
|
public:
|
|
POINTER_DEFINITIONS(StructureArray);
|
|
typedef StructureArray& reference;
|
|
typedef const StructureArray& const_reference;
|
|
|
|
StructureConstPtr getStructure() const {return pstructure;}
|
|
virtual void toString(StringBuilder buf,int indentLevel=0) const;
|
|
virtual String getID() const;
|
|
virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const;
|
|
virtual void deserialize(ByteBuffer *buffer, DeserializableControl *control);
|
|
...
|
|
};
|
|
|
|
class Structure : public Field {
|
|
public:
|
|
POINTER_DEFINITIONS(Structure);
|
|
typedef Structure& reference;
|
|
typedef const Structure& const_reference;
|
|
|
|
std::size_t getNumberFields() const {return numberFields;}
|
|
FieldConstPtr getField(String const & fieldName) const;
|
|
FieldConstPtr getField(std::size_t index) const;
|
|
std::size_t getFieldIndex(String const &fieldName) const;
|
|
FieldConstPtrArray const & getFields() const {return fields;}
|
|
StringArray const & getFieldNames() const;
|
|
String getFieldName(std::size_t fieldIndex) const;
|
|
virtual void toString(StringBuilder buf,int indentLevel) const;
|
|
virtual String getID() const;
|
|
virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const;
|
|
virtual void deserialize(ByteBuffer *buffer, DeserializableControl *control);
|
|
...
|
|
};
|
|
|
|
class epicsShareClass Union : public Field {
|
|
public:
|
|
POINTER_DEFINITIONS(Union);
|
|
static epics::pvData::String DEFAULT_ID;
|
|
static epics::pvData::String ANY_ID;
|
|
virtual ~Union();
|
|
typedef Union& reference;
|
|
typedef const Union& const_reference;
|
|
|
|
std::size_t getNumberFields() const;
|
|
FieldConstPtr getField(String const &fieldName) const;
|
|
FieldConstPtr getField(std::size_t index);
|
|
std::size_t getFieldIndex(String const &fieldName) const;
|
|
FieldConstPtrArray const & getFields() const;
|
|
StringArray const & getFieldNames() const;
|
|
String getFieldName(std::size_t fieldIndex) const;
|
|
bool isVariant() const;
|
|
virtual void toString(StringBuilder buf) const;
|
|
virtual void toString(StringBuilder buf,int indentLevel) const;
|
|
virtual String getID() const;
|
|
virtual void serialize(
|
|
ByteBuffer *buffer, SerializableControl *control) const;
|
|
virtual void deserialize(
|
|
ByteBuffer *buffer, DeserializableControl *control);
|
|
|
|
};
|
|
|
|
class epicsShareClass UnionArray : public Field{
|
|
public:
|
|
POINTER_DEFINITIONS(UnionArray);
|
|
typedef UnionArray& reference;
|
|
typedef const UnionArray& const_reference;
|
|
UnionConstPtr getUnion() const {return punion;}
|
|
virtual void toString(StringBuilder buf,int indentLevel=0) const;
|
|
|
|
virtual String getID() const;
|
|
|
|
virtual void serialize(ByteBuffer *buffer, SerializableControl *control) const;
|
|
virtual void deserialize(ByteBuffer *buffer, DeserializableControl *control);
|
|
};
|
|
</pre>
|
|
<dl>
|
|
<dt>Constructors</dt>
|
|
<dd>Note that all constructors are protected or private. The only way to
|
|
create instances is via fieldBuilder or fieldCreate. The implementation manages all
|
|
storage via shared pointers.</dd>
|
|
<dt>toString</dt>
|
|
<dd>Many classes provide this (actually two methods). This method is called
|
|
to get a string that uses the metadata syntax described in a previous
|
|
section.</dd>
|
|
</dl>
|
|
|
|
<h4>Field</h4>
|
|
<dl>
|
|
<dt>getType</dt>
|
|
<dd>Get the field type.</dd>
|
|
<dt>getID</dt>
|
|
<dd>Get an ID for this introspection interface</dd>
|
|
</dl>
|
|
|
|
<h4>Scalar</h4>
|
|
<dl>
|
|
<dt>getScalarType</dt>
|
|
<dd>Get that scalar type.</dd>
|
|
<dt>getID</dt>
|
|
<dd>For each scalarType there is one instance of Scalar. The ID for each is
|
|
the metadata name for the type, i. e. one of "boolean" , ... , "string".
|
|
</dd>
|
|
</dl>
|
|
|
|
<h4>ScalarArray</h4>
|
|
<dl>
|
|
<dt>getElementType</dt>
|
|
<dd>Get the element type.</dd>
|
|
<dt>getID</dt>
|
|
<dd>For each elemnetType there is one instance of ScalarArray. The ID for
|
|
each is the metadata name for the type, i. e. one of "boolean[]" , ... ,
|
|
"string[]". </dd>
|
|
</dl>
|
|
|
|
<h4>StructureArray</h4>
|
|
<dl>
|
|
<dt>getStructure</dt>
|
|
<dd>Get the introspection interface that each element shares,</dd>
|
|
<dt>getID</dt>
|
|
<dd>This returns the ID[] where ID is the value returned by
|
|
structure->getID(). </dd>
|
|
</dl>
|
|
|
|
<h4>Structure</h4>
|
|
<dl>
|
|
<dt>getNumberFields</dt>
|
|
<dd>Get the number of immediate subfields.</dd>
|
|
<dt>getField</dt>
|
|
<dd>Given a name or an index get the introspection interface for the
|
|
field.</dd>
|
|
<dt>getFieldIndex</dt>
|
|
<dd>Given a name get the index, within the array returned by the next
|
|
method, of the field.</dd>
|
|
<dt>getFields</dt>
|
|
<dd>Get the array of introspection interfaces for the field,</dd>
|
|
<dt>getFieldNames</dt>
|
|
<dd>Get the array of field names for the subfields.</dd>
|
|
<dt>getFieldName</dt>
|
|
<dd>Get the field name for the specified index.</dd>
|
|
</dl>
|
|
<h4>Union</h4>
|
|
<dl>
|
|
<dt>getNumberFields</dt>
|
|
<dd>Get the number of possible field types.
|
|
Both getFields and getFieldNames will return an array with getNumberFields elements.
|
|
A value of 0 is returned for invarient arrays.
|
|
</dd>
|
|
<dt>getField</dt>
|
|
<dd>Given a name ot an index the type is returned.
|
|
NULL is returned if not found.
|
|
</dd>
|
|
<dt>getFieldIndex</dt>
|
|
<dd>Get the index for name. -1 is returned if not found.
|
|
<dt>getFields</dt>
|
|
<dd>Get the array of types.</dd>
|
|
<dt>getFieldNames</dt>
|
|
<dd>Get the array of names.</dd>
|
|
<dt>getFieldName</dt>
|
|
<dd>Get the name for the specified index.</dd>
|
|
<dt>isVariant</dt>
|
|
<dd>returns <b>true</b> if this is varient array and <b>false</b> otherwise.
|
|
</dl>
|
|
<h4>UnionArray</h4>
|
|
<dl>
|
|
<dt>getUnion</dt>
|
|
<dd>Get the union interface for each element.</dd>
|
|
</dl>
|
|
<h3>fieldBuilder and createField</h3>
|
|
<pre>
|
|
class epicsShareClass FieldBuilder :
|
|
public std::tr1::enable_shared_from_this<FieldBuilder>
|
|
{
|
|
public:
|
|
FieldBuilderPtr setId(std::string const & id);
|
|
FieldBuilderPtr add(std::string const & name, ScalarType scalarType);
|
|
FieldBuilderPtr add(std::string const & name, FieldConstPtr const & field);
|
|
FieldBuilderPtr addArray(std::string const & name, ScalarType scalarType);
|
|
FieldBuilderPtr addArray(std::string const & name, FieldConstPtr const & element);
|
|
StructureConstPtr createStructure();
|
|
UnionConstPtr createUnion();
|
|
FieldBuilderPtr addNestedStructure(std::string const & name);
|
|
FieldBuilderPtr addNestedUnion(std::string const & name);
|
|
FieldBuilderPtr addNestedStructureArray(std::string const & name);
|
|
FieldBuilderPtr addNestedUnionArray(std::string const & name);
|
|
FieldBuilderPtr endNested();
|
|
};
|
|
|
|
class epicsShareClass FieldCreate {
|
|
public:
|
|
static FieldCreatePtr getFieldCreate();
|
|
FieldBuilderPtr createFieldBuilder() const;
|
|
ScalarConstPtr createScalar(ScalarType scalarType) const;
|
|
ScalarArrayConstPtr createScalarArray(ScalarType elementType) const;
|
|
StructureArrayConstPtr createStructureArray(StructureConstPtr const & structure) const;
|
|
StructureConstPtr createStructure () const;
|
|
StructureConstPtr createStructure (
|
|
StringArray const & fieldNames,
|
|
FieldConstPtrArray const & fields) const;
|
|
StructureConstPtr createStructure (
|
|
String const & id,
|
|
StringArray const & fieldNames,
|
|
FieldConstPtrArray const & fields) const;
|
|
UnionConstPtr createUnion (
|
|
StringArray const & fieldNames,
|
|
FieldConstPtrArray const & fields) const;
|
|
UnionConstPtr createUnion (
|
|
String const & id,
|
|
StringArray const & fieldNames,
|
|
FieldConstPtrArray const & fields) const;
|
|
UnionConstPtr createVariantUnion() const;
|
|
UnionArrayConstPtr createVariantUnionArray() const;
|
|
UnionArrayConstPtr createUnionArray(UnionConstPtr const & punion) const;
|
|
StructureConstPtr appendField(
|
|
StructureConstPtr const & structure,
|
|
String const & fieldName, FieldConstPtr const & field) const;
|
|
StructureConstPtr appendFields(
|
|
StructureConstPtr const & structure,
|
|
StringArray const & fieldNames,
|
|
FieldConstPtrArray const & fields) const;
|
|
FieldConstPtr deserialize(ByteBuffer* buffer, DeserializableControl* control) const;
|
|
|
|
};
|
|
|
|
epicsShareExtern FieldCreatePtr getFieldCreate();
|
|
</pre>
|
|
|
|
<h3>FieldBuilder</h3>
|
|
<p>This is a class that makes it easier to create introspection interfaces.
|
|
It is meant to be used via stream input syntax. See the examples that follow the
|
|
description of the methods.
|
|
</p>
|
|
<dl>
|
|
<dt>setID</dt>
|
|
<dd>This sets an ID for the field, which is the name for the field when it is a subfield.
|
|
</dd>
|
|
<dt>add</dt>
|
|
<dd>
|
|
Add a scalar field.
|
|
</dd>
|
|
<dt>addArray</dt>
|
|
<dd>
|
|
Add a scalarArray field.
|
|
</dd>
|
|
<dt>createStructure</dt>
|
|
<dd>
|
|
Create a structure from the fields that are currently present.
|
|
</dd>
|
|
<dt>createUnion</dt>
|
|
<dd>
|
|
Create a union from the fields that are currently present.
|
|
</dd>
|
|
<dt>addNestedStructure</dt>
|
|
<dd>
|
|
Add a nested structure. This is followed by an arbitrary number of adds
|
|
followed by a an endNested.
|
|
</dd>
|
|
<dt>addNestedUnion</dt>
|
|
<dd>
|
|
Add a nested union. This is followed by an arbitrary number of adds
|
|
followed by a an endNested.
|
|
</dd>
|
|
<dt>addNestedStructureArray</dt>
|
|
<dd>
|
|
Add a nested structure array. This is followed by an arbitrary number of adds
|
|
followed by a an endNested.
|
|
</dd>
|
|
<dt>addNestedUnionArray</dt>
|
|
<dd>
|
|
Add a nested union array. This is followed by an arbitrary number of adds
|
|
followed by a an endNested.
|
|
</dd>
|
|
<dt>endNested</dt>
|
|
<dd>
|
|
End current nested structure or union.
|
|
</dd>
|
|
</dl>
|
|
<p>A simple example is:</p>
|
|
<pre>
|
|
StructureConstPtr structure =
|
|
getFieldCreate()->createFieldBuilder()->
|
|
setId("enum_t")->
|
|
add("index", pvDouble)->
|
|
addArray("choices", pvString)->
|
|
createStructure();
|
|
String builder;
|
|
structure->toString(&builder);
|
|
cout << builder << endl;
|
|
</pre>
|
|
This produces:
|
|
<pre>
|
|
enum_t
|
|
double index
|
|
string[] choices
|
|
</pre>
|
|
<p>Another example is:</p>
|
|
<pre>
|
|
StructureConstPtr enum_t =
|
|
getFieldCreate()->createFieldBuilder()->
|
|
setId("enum_t")->
|
|
add("index", pvInt)->
|
|
addArray("choices", pvString)->
|
|
createStructure();
|
|
|
|
StructureConstPtr ntEnum =
|
|
getFieldCreate()->createFieldBuilder()->
|
|
setId("uri:ev4:nt/2012/pwd/NTEnum")->
|
|
add("value", enum_t)->
|
|
addNestedStructure("timeStamp")->
|
|
setId("time_t")->
|
|
add("secsPastEpoch", pvLong)->
|
|
add("nanoseconds", pvInt)->
|
|
add("userTag", pvInt)->
|
|
endNested()->
|
|
createStructure();
|
|
builder.clear();
|
|
ntEnum->toString(&builder);
|
|
cout << builder << endl;
|
|
</pre>
|
|
This produces:
|
|
<pre>
|
|
uri:ev4:nt/2012/pwd/NTEnum
|
|
enum_t value
|
|
int index
|
|
string[] choices
|
|
time_t timeStamp
|
|
long secsPastEpoch
|
|
int nanoseconds
|
|
int userTag
|
|
</pre>
|
|
<p>The following example:</p>
|
|
<pre>
|
|
UnionConstPtr ntunion =
|
|
getFieldCreate()->createFieldBuilder()->
|
|
add("doubleValue", pvDouble)->
|
|
add("intValue", pvInt)->
|
|
addNestedStructure("timeStamp")->
|
|
setId("time_t")->
|
|
add("secsPastEpoch", pvLong)->
|
|
add("nanoseconds", pvInt)->
|
|
add("userTag", pvInt)->
|
|
endNested()->
|
|
createUnion();
|
|
builder.clear();
|
|
ntunion->toString(&builder);
|
|
cout << builder << endl;
|
|
</pre>
|
|
produces:
|
|
<pre>
|
|
union
|
|
double doubleValue
|
|
int intValue
|
|
time_t timeStamp
|
|
long secsPastEpoch
|
|
int nanoseconds
|
|
int userTag
|
|
</pre>
|
|
<p>A powerSupply structure can be created as follows:</p>
|
|
<pre>
|
|
StructureConstPtr alarm = getStandardField()->alarm();
|
|
StructureConstPtr timeStamp = getStandardField()->timeStamp();
|
|
|
|
StructureConstPtr powerSupply =
|
|
getFieldCreate()->createFieldBuilder()->
|
|
add("alarm_t",alarm) ->
|
|
add("timestamp_t",timeStamp) ->
|
|
addNestedStructure("power") ->
|
|
add("value",pvDouble) ->
|
|
add("alarm",alarm) ->
|
|
endNested()->
|
|
addNestedStructure("voltage") ->
|
|
add("value",pvDouble) ->
|
|
add("alarm",alarm) ->
|
|
endNested()->
|
|
addNestedStructure("current") ->
|
|
add("value",pvDouble) ->
|
|
add("alarm",alarm) ->
|
|
endNested()->
|
|
createStructure();
|
|
builder.clear();
|
|
powerSupply->toString(&builder);
|
|
cout << builder << endl;
|
|
</pre>
|
|
produces:
|
|
<pre>
|
|
structure
|
|
alarm_t alarm_t
|
|
int severity
|
|
int status
|
|
string message
|
|
time_t timestamp_t
|
|
long secondsPastEpoch
|
|
int nanoSeconds
|
|
int userTag
|
|
structure power
|
|
double value
|
|
alarm_t alarm
|
|
int severity
|
|
int status
|
|
string message
|
|
structure voltage
|
|
double value
|
|
alarm_t alarm
|
|
int severity
|
|
int status
|
|
string message
|
|
structure current
|
|
double value
|
|
alarm_t alarm
|
|
int severity
|
|
int status
|
|
string message
|
|
</pre>
|
|
<h3>FieldCreate</h3>
|
|
<dl>
|
|
<dt>getFieldCreate</dt>
|
|
<dd>Get the single instance of FieldCreate.</dd>
|
|
<dt>createFieldBuilder</dt>
|
|
<dd>Create an instance of a FieldBuilder.</dd>
|
|
<dt>createScalar</dt>
|
|
<dd>Create a scalar introspection instance.</dd>
|
|
<dt>createScalarArray</dt>
|
|
<dd>Create a scalar array introspection instance.</dd>
|
|
<dt>createStructure</dt>
|
|
<dd>Create a structure introspection instance. Three methods are provided.
|
|
The first creates an empty structure, i. e. a structure with no fields.
|
|
The other two are similar.
|
|
The only difference is that one provides an ID and the other does
|
|
not. The one without will result in ID <b>structure</b>.</dd>
|
|
<dt>createUnion</dt>
|
|
<dd>Create a union. There are two methods.
|
|
Each has arguments for an array of types and an array of names.
|
|
One method has an id. The other results in id = <b>union</b>.
|
|
</dd>
|
|
<dt>createVariantUnion</dt>
|
|
<dd>
|
|
Create a varient union. The id will be <b>any</b>.
|
|
</dd>
|
|
<dt>createUnionArray</dt>
|
|
<dd>Create a union array. <b>punion</b> is the introspection interface
|
|
for each element.</dd>
|
|
<dt>createVariantUnionArray</dt>
|
|
<dd>Create a union array where each element is a varient union.</dd>
|
|
<dt>createStructureArray</dt>
|
|
<dd>Create a structure array introspection instance. </dd>
|
|
<dt>appendField</dt>
|
|
<dd>Create a new structure that is like an existing structure but has
|
|
an extra field appended to it.
|
|
</dd>
|
|
<dt>appendFields</dt>
|
|
<dd>Create a new structure that is like an existing structure but has
|
|
extra fields appended to it.
|
|
</dd>
|
|
<dt>deserialize</dt>
|
|
<dd>Deserialize from given byte buffer.</dd>
|
|
</dl>
|
|
<p><b>TBD</b>
|
|
<dl>
|
|
<dt>toString</dt>
|
|
<dd>Should support for steams exist.</dd>
|
|
<dt>ScalarTypeTraits and ScalarTypeID</dt>
|
|
<dd>These seem to only be used by shared_vector. Do they need to be documented?</dd>
|
|
</dl>
|
|
</p>
|
|
|
|
<h2>standardField.h</h2>
|
|
|
|
<p>The file standardField.h has a class description for creating or sharing
|
|
Field objects for standard fields. For each type of field a method is provided.
|
|
Each creates a structure that has a field named "value" and a set of properyt
|
|
fields, The property field is a comma separated string of property names of the
|
|
following: alarm, timeStamp, display, control, and valueAlarm. An example is
|
|
"alarm,timeStamp,valueAlarm". The method with properties creates a structure
|
|
with fields named value and each of the property names. Each property field is
|
|
a structure defining the property. The details about each property is given in
|
|
the section named "Property". For example the call:</p>
|
|
<pre> StructureConstPtr example = standardField->scalar(
|
|
pvDouble,
|
|
"value,alarm,timeStamp");</pre>
|
|
|
|
<p>Will result in a Field definition that has the form:</p>
|
|
<pre>structure example
|
|
double value
|
|
alarm_t alarm
|
|
int severity
|
|
int status
|
|
string message
|
|
timeStamp_t timeStamp
|
|
long secondsPastEpoch
|
|
int nanoSeconds
|
|
int userTag</pre>
|
|
|
|
<p>In addition there are methods that create each of the property structures,
|
|
i.e. the methods named: alarm, .... enumeratedAlarm."</p>
|
|
|
|
<p>standardField.h contains:</p>
|
|
<pre>class StandardField;
|
|
typedef std::tr1::shared_ptr<StandardField> StandardFieldPtr;
|
|
|
|
class StandardField {
|
|
public:
|
|
static StandardFieldPtr getStandardField();
|
|
~StandardField();
|
|
StructureConstPtr scalar(ScalarType type,String const &properties);
|
|
StructureConstPtr regUnion(
|
|
UnionConstPtr const & punion,
|
|
String const & properties);
|
|
StructureConstPtr variantUnion(String const & properties);
|
|
StructureConstPtr scalarArray(
|
|
ScalarType elementType, String const &properties);
|
|
StructureConstPtr structureArray(
|
|
StructureConstPtr const & structure,String const &properties);
|
|
StructureConstPtr unionArray(UnionConstPtr const & punion,String const & properties);
|
|
StructureConstPtr enumerated();
|
|
StructureConstPtr enumerated(String const &properties);
|
|
StructureConstPtr alarm();
|
|
StructureConstPtr timeStamp();
|
|
StructureConstPtr display();
|
|
StructureConstPtr control();
|
|
StructureConstPtr booleanAlarm();
|
|
StructureConstPtr byteAlarm();
|
|
StructureConstPtr ubyteAlarm();
|
|
StructureConstPtr shortAlarm();
|
|
StructureConstPtr ushortAlarm();
|
|
StructureConstPtr intAlarm();
|
|
StructureConstPtr uintAlarm();
|
|
StructureConstPtr longAlarm();
|
|
StructureConstPtr ulongAlarm();
|
|
StructureConstPtr floatAlarm();
|
|
StructureConstPtr doubleAlarm();
|
|
StructureConstPtr enumeratedAlarm();
|
|
...
|
|
};</pre>
|
|
<dl>
|
|
<dt>scalar</dt>
|
|
<dd>Create a scalar with the specified scalar type and name. A structure
|
|
will be created with the first element being a scalar with the specified
|
|
scalar type and name value. The other fields in the structure will be the
|
|
corresponding property structures.</dd>
|
|
<dt>regUnion</dt>
|
|
<dd>A structure
|
|
will be created with the first element being a union with the specified
|
|
scalar type and name value. The other fields in the structure will be the
|
|
corresponding property structures.</dd>
|
|
<dt>varient`Union</dt>
|
|
<dd>Create a varient union. A structure
|
|
will be created with the first element being a union with the specified
|
|
scalar type and name value. The other fields in the structure will be the
|
|
corresponding property structures.</dd>
|
|
<dt>scalarArray</dt>
|
|
<dd>Create a scalarArray with each element having the specified scalar type
|
|
and name. A structure will be created with the first element being a
|
|
scalarArray with name value. The other fields in the structure will be
|
|
the corresponding property structures.</dd>
|
|
<dt>structureArray</dt>
|
|
<dd>Create a structureArray with the specified structure interface and
|
|
name. A structure will be created with the first element being a
|
|
structureArray with the specified structure interface and name value. The
|
|
other fields in the structure will be the corresponding property
|
|
structures.</dd>
|
|
<dt>unionArray</dt>
|
|
<dd>Create a unionArray with the specified union interface and
|
|
name. A structure will be created with the first element being a
|
|
unionArray with the specified structure interface and name value. The
|
|
other fields in the structure will be the corresponding property
|
|
structures.</dd>
|
|
<dt>structure</dt>
|
|
<dd>Create a structure with the specified name and fields specified by
|
|
numFields and fields. A structure will be created with the first element
|
|
being a structure with the name value and fields specified by numFields
|
|
and fields. The other fields in the structure will be the corresponding
|
|
property structures.</dd>
|
|
<dt>enumerated</dt>
|
|
<dd>Create a structure with the specified name and fields for an enumerated
|
|
structure. If properties are specified then a structure will be created
|
|
with the first element being a structure with the name value and fields
|
|
for an enumerated structure. The other fields in the structure will be
|
|
the corresponding property structures.</dd>
|
|
<dt>alarm</dt>
|
|
<dt>timeStamp</dt>
|
|
<dt>display</dt>
|
|
<dt>control</dt>
|
|
<dt>booleanAlarm</dt>
|
|
<dt>byteAlarm</dt>
|
|
<dt>shortAlarm</dt>
|
|
<dt>intAlarm</dt>
|
|
<dt>longAlarm</dt>
|
|
<dt>floatAlarm</dt>
|
|
<dt>doubleAlarm</dt>
|
|
<dt>enumeratedAlarm</dt>
|
|
<dd>The above provide introspection interfaces for standard properties. See
|
|
the section on Properties for a description of how these are defined.</dd>
|
|
</dl>
|
|
<h2>pvData.h</h2>
|
|
|
|
<p>This section describes pvData.h This file is quite big so rather than
|
|
showing the entire file, it will be described in parts. </p>
|
|
|
|
<h3>typedefs</h3>
|
|
|
|
<p>These are typedefs for Array and Ptr for the various pvData class
|
|
definitions, i.e. typdefs for "std::vector" and "std::tr1::shared_ptr".</p>
|
|
<pre>
|
|
class PVField;
|
|
class PVScalar;
|
|
class PVScalarArray;
|
|
class PVStructure;
|
|
class PVStructureArray;
|
|
|
|
|
|
typedef std::tr1::shared_ptr<PVField> PVFieldPtr;
|
|
typedef std::vector<PVFieldPtr> PVFieldPtrArray;
|
|
typedef std::vector<PVFieldPtr>::iterator PVFieldPtrArray_iterator;
|
|
typedef std::vector<PVFieldPtr>::const_iterator PVFieldPtrArray_const__iterator;
|
|
|
|
typedef std::tr1::shared_ptr<PVScalar> PVScalarPtr;
|
|
typedef std::tr1::shared_ptr<PVScalarArray> PVScalarArrayPtr;
|
|
|
|
typedef std::tr1::shared_ptr<PVStructure> PVStructurePtr;
|
|
typedef std::vector<PVStructurePtr> PVStructurePtrArray;
|
|
typedef std::vector<PVStructurePtr>::iterator PVStructurePtrArray_iterator;
|
|
typedef std::vector<PVStructurePtr>::const_iterator PVStructurePtrArray_const__iterator;
|
|
|
|
typedef PVValueArray<PVStructurePtr> PVStructureArray;
|
|
typedef std::tr1::shared_ptr<PVStructureArray> PVStructureArrayPtr;
|
|
typedef std::vector<PVStructureArrayPtr> PVStructureArrayPtrArray;
|
|
typedef std::tr1::shared_ptr<PVStructureArrayPtrArray> PVStructureArrayPtrArrayPtr;
|
|
|
|
typedef std::tr1::shared_ptr<PVUnion> PVUnionPtr;
|
|
typedef std::vector<PVUnionPtr> PVUnionPtrArray;
|
|
typedef std::vector<PVUnionPtr>::iterator PVUnionPtrArray_iterator;
|
|
typedef std::vector<PVUnionPtr>::const_iterator PVUnionPtrArray_const__iterator;
|
|
|
|
typedef PVValueArray<PVUnionPtr> PVUnionArray;
|
|
typedef std::tr1::shared_ptr<PVUnionArray> PVUnionArrayPtr;
|
|
typedef std::vector<PVUnionArrayPtr> PVUnionArrayPtrArray;
|
|
typedef std::tr1::shared_ptr<PVUnionArrayPtrArray> PVUnionArrayPtrArrayPtr;
|
|
|
|
class PVDataCreate;
|
|
typedef std::tr1::shared_ptr<PVDataCreate> PVDataCreatePtr;
|
|
|
|
|
|
/**
|
|
* typedefs for the various possible scalar types.
|
|
*/
|
|
typedef PVScalarValue<boolean> PVBoolean;
|
|
typedef PVScalarValue<int8> PVByte;
|
|
typedef PVScalarValue<int16> PVShort;
|
|
typedef PVScalarValue<int32> PVInt;
|
|
typedef PVScalarValue<int64> PVLong;
|
|
typedef PVScalarValue<uint8> PVUByte;
|
|
typedef PVScalarValue<uint16> PVUShort;
|
|
typedef PVScalarValue<uint32> PVUInt;
|
|
typedef PVScalarValue<uint64> PVULong;
|
|
typedef PVScalarValue<float> PVFloat;
|
|
typedef PVScalarValue<double> PVDouble;
|
|
class PVString;
|
|
typedef std::tr1::shared_ptr<PVBoolean> PVBooleanPtr;
|
|
typedef std::tr1::shared_ptr<PVByte> PVBytePtr;
|
|
typedef std::tr1::shared_ptr<PVShort> PVShortPtr;
|
|
typedef std::tr1::shared_ptr<PVInt> PVIntPtr;
|
|
typedef std::tr1::shared_ptr<PVLong> PVLongPtr;
|
|
typedef std::tr1::shared_ptr<PVUByte> PVUBytePtr;
|
|
typedef std::tr1::shared_ptr<PVUShort> PVUShortPtr;
|
|
typedef std::tr1::shared_ptr<PVUInt> PVUIntPtr;
|
|
typedef std::tr1::shared_ptr<PVULong> PVULongPtr;
|
|
typedef std::tr1::shared_ptr<PVFloat> PVFloatPtr;
|
|
typedef std::tr1::shared_ptr<PVDouble> PVDoublePtr;
|
|
typedef std::tr1::shared_ptr<PVString> PVStringPtr;
|
|
|
|
/**
|
|
* Definitions for the various scalarArray types.
|
|
*/
|
|
typedef PVValueArray<boolean> PVBooleanArray;
|
|
typedef PVValueArray<int8> PVByteArray;
|
|
typedef PVValueArray<int16> PVShortArray;
|
|
typedef PVValueArray<int32> PVIntArray;
|
|
typedef PVValueArray<int64> PVLongArray;
|
|
typedef PVValueArray<uint8> PVUByteArray;
|
|
typedef PVValueArray<uint16> PVUShortArray;
|
|
typedef PVValueArray<uint32> PVUIntArray;
|
|
typedef PVValueArray<uint64> PVULongArray;
|
|
typedef PVValueArray<float> PVFloatArray;
|
|
typedef PVValueArray<double> PVDoubleArray;
|
|
typedef PVValueArray<String> PVStringArray;
|
|
|
|
typedef std::tr1::shared_ptr<PVBooleanArray> PVBooleanArrayPtr;
|
|
typedef std::tr1::shared_ptr<PVByteArray> PVByteArrayPtr;
|
|
typedef std::tr1::shared_ptr<PVShortArray> PVShortArrayPtr;
|
|
typedef std::tr1::shared_ptr<PVIntArray> PVIntArrayPtr;
|
|
typedef std::tr1::shared_ptr<PVLongArray> PVLongArrayPtr;
|
|
typedef std::tr1::shared_ptr<PVUByteArray> PVUByteArrayPtr;
|
|
typedef std::tr1::shared_ptr<PVUShortArray> PVUShortArrayPtr;
|
|
typedef std::tr1::shared_ptr<PVUIntArray> PVUIntArrayPtr;
|
|
typedef std::tr1::shared_ptr<PVULongArray> PVULongArrayPtr;
|
|
typedef std::tr1::shared_ptr<PVFloatArray> PVFloatArrayPtr;
|
|
typedef std::tr1::shared_ptr<PVDoubleArray> PVDoubleArrayPtr;
|
|
typedef std::tr1::shared_ptr<PVStringArray> PVStringArrayPtr;
|
|
</pre>
|
|
|
|
<h3>PVField</h3>
|
|
|
|
<p>PVField is the base interface for accessing data. A data structure consists
|
|
of a top level PVStructure. Every field of every structure of every top level
|
|
structure has a PVField associated with it.</p>
|
|
<pre>
|
|
class PostHandler
|
|
{
|
|
public:
|
|
POINTER_DEFINITIONS(PostHandler);
|
|
virtual ~PostHandler(){}
|
|
virtual void postPut() = 0;
|
|
};
|
|
|
|
class PVField
|
|
: virtual public Serializable,
|
|
public std::tr1::enable_shared_from_this<PVField>
|
|
{
|
|
public:
|
|
POINTER_DEFINITIONS(PVField);
|
|
virtual ~PVField();
|
|
String getFieldName() const ;
|
|
String getFullName() const;
|
|
std::size_t getFieldOffset() const;
|
|
std::size_t getNextFieldOffset() const;
|
|
std::size_t getNumberFields() const;
|
|
bool isImmutable() const;
|
|
virtual void setImmutable();
|
|
const FieldConstPtr & getField() const ;
|
|
PVStructure * getParent() const
|
|
void postPut();
|
|
void setPostHandler(PostHandlerPtr const &postHandler);
|
|
virtual bool equals(PVField &pv);
|
|
virtual void toString(StringBuilder buf) ;
|
|
virtual void toString(StringBuilder buf,int indentLevel);
|
|
std::ostream& dumpValue(std::ostream& o) const;
|
|
...
|
|
}
|
|
std::ostream& operator<<(std::ostream& o, const PVField& f);
|
|
</pre>
|
|
|
|
<p>The public methods for PVField are:</p>
|
|
<dl>
|
|
<dt>~PVField</dt>
|
|
<dd>Destructor. Since shared pointers are used it should never be called by
|
|
user code.</dd>
|
|
<dt>getFieldName</dt>
|
|
<dd>Get the field name. If the field is a top level structure the field
|
|
name will be an empty string.</dd>
|
|
<dt>getFullName</dt>
|
|
<dd>Fully expand the name of this field using the
|
|
names of its parent fields with a dot '.' seperating
|
|
each name.
|
|
</dd>
|
|
<dt>getFieldOffset</dt>
|
|
<dd>Get offset of the PVField field within top level structure. Every field
|
|
within the PVStructure has a unique offset. The top level structure has
|
|
an offset of 0. The first field within the structure has offset equal to
|
|
1. The other offsets are determined by recursively traversing each
|
|
structure of the tree. </dd>
|
|
<dt>getNextFieldOffset</dt>
|
|
<dd>Get the next offset. If the field is a scalar or array field then this
|
|
is just offset + 1. If the field is a structure it is the offset of the
|
|
next field after this structure. Thus (nextOffset - offset) is always
|
|
equal to the total number of fields within the field. </dd>
|
|
<dt>getNumberFields</dt>
|
|
<dd>Get the total number of fields in this field. This is nextFieldOffset -
|
|
fieldOffset. </dd>
|
|
<dt>isImmutable</dt>
|
|
<dd>Is the field immutable?</dd>
|
|
<dt>setImmutable</dt>
|
|
<dd>Make the field immutable. Once a field is immutable it can never be
|
|
changed since there is no method to again make it mutable. This is an
|
|
important design decision since it allows immutable array fields to share
|
|
the internal primitive data array.</dd>
|
|
<dt>getField</dt>
|
|
<dd>Get the reflection interface for the data.</dd>
|
|
<dt>getParent</dt>
|
|
<dd>Get the interface for the parent or null if this is the top level
|
|
PVStructure.</dd>
|
|
<dt>postPut</dt>
|
|
<dd>If a postHandler is registered it is called otherwise no action is
|
|
taken.</dd>
|
|
<dt>setPostHandler</dt>
|
|
<dd>Set the postHandler for the record. Only a single handler can be
|
|
registered.
|
|
PostHandler is a class that must be implemented by any code that calls setPostHandler.
|
|
It's single virtual method. postPut is called whenever PVField::postPut is called.
|
|
</dd>
|
|
<dt>equals</dt>
|
|
<dd>Compare this field with another field. The result will be true only if
|
|
the fields have exactly the same field types and if the data values are
|
|
equal.</dd>
|
|
<dt>toString</dt>
|
|
<dd>Converts the field data to a string. This is mostly for debugging
|
|
purposes.</dd>
|
|
<dt>dumpValue</dt>
|
|
<dd>Method for streams I/O.</dd>
|
|
</dl>
|
|
<p><b>TBD</b>
|
|
|
|
<dl>
|
|
<dt>toString and dumpValue</dt>
|
|
<dd>toString is broken<br />
|
|
Should toString go away or be changed?
|
|
</dd>
|
|
</dl>
|
|
</p>
|
|
|
|
<h3>PVScalar</h3>
|
|
|
|
<p>This is the base class for all scalar data.</p>
|
|
<pre>class PVScalar : public PVField {
|
|
public:
|
|
POINTER_DEFINITIONS(PVScalar);
|
|
virtual ~PVScalar();
|
|
typedef PVScalar &reference;
|
|
typedef const PVScalar& const_reference;
|
|
const ScalarConstPtr getScalar() const ;
|
|
template<typename T>
|
|
T getAs() const;
|
|
...
|
|
}</pre>
|
|
|
|
<p>where</p>
|
|
<dl>
|
|
<dt>getScalar</dt>
|
|
<dd>Get the introspection interface for the PVScalar.</dd>
|
|
<dt>getAs</dt>
|
|
<dd>Convert and return the scalar value in the requested type.
|
|
Result type is determined from the function template argument
|
|
which must be one of the ScalarType enums.
|
|
For example:
|
|
<pre>
|
|
uint32 val = pv->getAs<pvInt>();
|
|
</pre>
|
|
</dd>
|
|
|
|
</dl>
|
|
|
|
<h3>PVScalarValue</h3>
|
|
|
|
<p>The interfaces for primitive data types are:</p>
|
|
<pre>template<typename T>
|
|
class PVScalarValue : public PVScalar {
|
|
public:
|
|
POINTER_DEFINITIONS(PVScalarValue);
|
|
typedef T value_type;
|
|
typedef T* pointer;
|
|
typedef const T* const_pointer;
|
|
static const ScalarType typeCode;
|
|
|
|
virtual ~PVScalarValue() {}
|
|
virtual T get() const = 0;
|
|
virtual void put(T value) = 0;
|
|
std::ostream& dumpValue(std::ostream& o) const;
|
|
void operator>>=(T& value) const;
|
|
void operator<<=(T value);
|
|
template<typename T1>
|
|
T1 getAs() const;
|
|
template<typename T1>
|
|
void putFrom(T1 val);
|
|
...
|
|
}
|
|
|
|
typedef PVScalarValue<boolean> PVBoolean;
|
|
typedef PVScalarValue<int8> PVByte;
|
|
typedef PVScalarValue<int16> PVShort;
|
|
typedef PVScalarValue<int32> PVInt;
|
|
typedef PVScalarValue<int64> PVLong;
|
|
typedef PVScalarValue<uint8> PVUByte;
|
|
typedef PVScalarValue<uint16> PVUShort;
|
|
typedef PVScalarValue<uint32> PVUInt;
|
|
typedef PVScalarValue<uint64> PVULong;
|
|
typedef PVScalarValue<float> PVFloat;
|
|
typedef PVScalarValue<double> PVDouble;
|
|
typedef std::tr1::shared_ptr<PVBoolean> PVBooleanPtr;
|
|
typedef std::tr1::shared_ptr<PVByte> PVBytePtr;
|
|
typedef std::tr1::shared_ptr<PVShort> PVShortPtr;
|
|
typedef std::tr1::shared_ptr<PVInt> PVIntPtr;
|
|
typedef std::tr1::shared_ptr<PVLong> PVLongPtr;
|
|
typedef std::tr1::shared_ptr<PVUByte> PVUBytePtr;
|
|
typedef std::tr1::shared_ptr<PVUShort> PVUShortPtr;
|
|
typedef std::tr1::shared_ptr<PVUInt> PVUIntPtr;
|
|
typedef std::tr1::shared_ptr<PVULong> PVULongPtr;
|
|
typedef std::tr1::shared_ptr<PVFloat> PVFloatPtr;
|
|
typedef std::tr1::shared_ptr<PVDouble> PVDoublePtr;
|
|
|
|
|
|
// PVString is special case, since it implements SerializableArray
|
|
class PVString : public PVScalarValue<String>, SerializableArray {
|
|
public:
|
|
virtual ~PVString() {}
|
|
...
|
|
};
|
|
|
|
|
|
</pre>
|
|
|
|
<p>where</p>
|
|
<dl>
|
|
<dt>get</dt>
|
|
<dd>Get the value stored in the object.</dd>
|
|
<dt>put</dt>
|
|
<dd>Change the value stored in the object.</dd>
|
|
<dt>dumpValue</dt>
|
|
<dd>ostream method.</dd>
|
|
<dt>operator>>=</dt>
|
|
<dd>get operator. For example:
|
|
<pre>
|
|
double value;
|
|
PVDoublePtr pvDouble;
|
|
...
|
|
pvDouble>>=value;
|
|
</pre>
|
|
</dd>
|
|
<dt>operator<<=</dt>
|
|
<dd>put operator. For example:
|
|
<pre>
|
|
double value;
|
|
PVDoublePtr pvDouble;
|
|
...
|
|
pvDouble<<=value;
|
|
</pre>
|
|
</dd>
|
|
<dt>getAs</dt>
|
|
<dd>Convert and return the scalar value in the requested type.
|
|
Result type is determined from the function template argument
|
|
which must be one of the ScalarType enums.
|
|
For example:
|
|
<pre>
|
|
int32 val = pv->getAs<pvInt>>();
|
|
</pre>
|
|
</dd>
|
|
<dt>putFrom</dt>
|
|
<dd>Convert the scalar value in the requested type
|
|
and put the value into this PVScalarValue.
|
|
The source type is determined from the function template argument
|
|
which must be one of the ScalarType enums.
|
|
For example:
|
|
<pre>
|
|
int32 val;
|
|
pv->putFrom<pvInt>(val);
|
|
</pre>
|
|
</dd>
|
|
</dl>
|
|
<p><b>TBD</b>
|
|
<dl>
|
|
<dt>dumpvalue</dt>
|
|
<dd>replace this with ostream operator<<</dd>
|
|
</dl>
|
|
</p>
|
|
|
|
<h3>PVUnion</h3>
|
|
<p>A PVUnion has a single subfield.
|
|
The Union introspection interface determines the possible
|
|
field types for the subfield.
|
|
If it is a varient union then any type is allowed and the
|
|
subfield name is normally <b>any</b>.
|
|
If it is not a varient union that the Union interface determines
|
|
the possible field types and names.</p>
|
|
<pre>
|
|
class PVUnion : public PVField
|
|
{
|
|
public:
|
|
POINTER_DEFINITIONS(PVUnion);
|
|
virtual ~PVUnion();
|
|
UnionConstPtr getUnion() const;
|
|
PVFieldPtr get() const;
|
|
|
|
template<typename PVT>
|
|
std::tr1::shared_ptr<PVT> get() const {
|
|
return std::tr1::dynamic_pointer_cast<PVT>(get());
|
|
}
|
|
|
|
PVFieldPtr select(int32 index);
|
|
|
|
template<typename PVT>
|
|
std::tr1::shared_ptr<PVT> select(int32 index) {
|
|
return std::tr1::dynamic_pointer_cast<PVT>(select(index));
|
|
}
|
|
|
|
PVFieldPtr select(String const & fieldName);
|
|
|
|
template<typename PVT>
|
|
std::tr1::shared_ptr<PVT> select(String const & fieldName) {
|
|
return std::tr1::dynamic_pointer_cast<PVT>(select(fieldName));
|
|
}
|
|
|
|
int32 getSelectedIndex() const;
|
|
String getSelectedFieldName() const;
|
|
void set(PVFieldPtr const & value);
|
|
void set(int32 index, PVFieldPtr const & value);
|
|
void set(String const & fieldName, PVFieldPtr const & value);
|
|
virtual void serialize(
|
|
ByteBuffer *pbuffer,SerializableControl *pflusher) const ;
|
|
PVUnion(UnionConstPtr const & punion);
|
|
};
|
|
</pre>
|
|
<dl>
|
|
<dt>getUnion</dt>
|
|
<dd>Get the introspection interface.</dd>
|
|
<dt>get</dt>
|
|
<dd>Get the curent field. A template version does the conversion.
|
|
<b>NULL</b> is returned if no field is selected or if the caller
|
|
' asks for the wrong type.
|
|
</dd>
|
|
<dt>select</dt>
|
|
<dd>Select and get the field by index or name.
|
|
A templated version does the conversion.
|
|
If the index is out of bounds or the name is not valid this methods throws an exception.
|
|
The method set should be used for variant unions rather than select.
|
|
</dd>
|
|
<dt>getSelectedIndex</dt>
|
|
<dd>Get the index of the currently selected field.</dd>
|
|
<dt>getSelectedFieldName</dt>
|
|
<dd>Get the name of the currently selected field.</dd>
|
|
<dt>set</dt>
|
|
<dd>Set the field to the argument. If invalid type an exception is thrown.
|
|
This should always work for a variant union.
|
|
</dd>
|
|
</dl>
|
|
|
|
<h3>PVArray</h3>
|
|
|
|
<p>PVArray is the base interface for all the other PV Array interfaces. It
|
|
extends PVField and provides the additional methods:</p>
|
|
<pre>
|
|
class PVArray : public PVField, public SerializableArray {
|
|
public:
|
|
POINTER_DEFINITIONS(PVArray);
|
|
virtual ~PVArray();
|
|
virtual void setImmutable();
|
|
std::size_t getLength() const;
|
|
virtual void setLength(std::size_t length);
|
|
std::size_t getCapacity() const;
|
|
bool isCapacityMutable() const;
|
|
void setCapacityMutable(bool isMutable);
|
|
virtual void setCapacity(std::size_t capacity) = 0;
|
|
virtual std::ostream& dumpValue(std::ostream& o, std::size_t index) const;
|
|
...
|
|
};</pre>
|
|
<dl>
|
|
<dt>setImmutable</dt>
|
|
<dd>Set the data immutable. Note that this is permanent since there is no
|
|
methods to make it mutable.</dd>
|
|
<dt>getLength</dt>
|
|
<dd>Get the current length. This is less than or equal to the capacity.</dd>
|
|
<dt>setLength</dt>
|
|
<dd>Set the length. If the PVField is not mutable then an exception is
|
|
thrown. If this is greater than the capacity setCapacity is called.</dd>
|
|
<dt>getCapacity</dt>
|
|
<dd>Get the capacity, i.e. this is the size of the underlying data
|
|
array.</dd>
|
|
<dt>setCapacity</dt>
|
|
<dd>Set the capacity. The semantics are implementation dependent but
|
|
typical semantics are as follows: If the capacity is not mutable an
|
|
exception is thrown. A new data array is created and data is copied from
|
|
the old array to the new array. </dd>
|
|
<dt>isCapacityMutable</dt>
|
|
<dd>Is the capacity mutable</dd>
|
|
<dt>setCapacityMutable</dt>
|
|
<dd>Specify if the capacity can be changed.</dd>
|
|
<dt>setCapacity</dt>
|
|
<dd>Set the capaciity.</dd>
|
|
<dt>dumpValue</dt>
|
|
<dd>ostream method</dd>
|
|
</dl>
|
|
</p>
|
|
|
|
|
|
<h3>PVScalarArray</h3>
|
|
|
|
<p>PVScalarArray is the base class for scalar array data. PVValueArray is a
|
|
templete for the various scalar array data classes. There is a class for each
|
|
possible scalar type, i. e. PVBooleanArray, ..., PVStringArray.</p>
|
|
<pre>
|
|
class PVScalarArray : public PVArray {
|
|
public:
|
|
POINTER_DEFINITIONS(PVScalarArray);
|
|
virtual ~PVScalarArray();
|
|
typedef PVScalarArray &reference;
|
|
typedef const PVScalarArray& const_reference;
|
|
|
|
const ScalarArrayConstPtr getScalarArray() const ;
|
|
|
|
template<typename T>
|
|
void getAs(shared_vector<const T>& out) const
|
|
|
|
template<typename T>
|
|
void putFrom(const shared_vector<const T>& inp)
|
|
|
|
void assign(PVScalarArray& pv);
|
|
...
|
|
}
|
|
</pre>
|
|
|
|
<p>where</p>
|
|
<dl>
|
|
<dt>getScalarArray</dt>
|
|
<dd>Get the introspection interface.</dd>
|
|
<dt>getAs</dt>
|
|
<dd>Fetch the current value and convert to the requested type.
|
|
A copy is made if the requested type does not match the element type.
|
|
If the types do match then no copy is made.
|
|
</dd>
|
|
<dt>putFrom</dt>
|
|
<dd>Assign the given value after conversion.
|
|
A copy and element-wise conversion is performed unless the element type
|
|
of the PVScalarArray matches the type of the provided data.
|
|
If the types do match then a new refernce to the provided data is kept.
|
|
</dd>
|
|
<dt>assign</dt>
|
|
<dd>Assign the given PVScalarArray's value.
|
|
A copy and element-wise conversion is performed unless the element type
|
|
of the PVScalarArray matches the type of the provided data.
|
|
If the types do match then a new refernce to the provided data is kept.
|
|
</dd>
|
|
</dl>
|
|
|
|
<h3>PVStructure</h3>
|
|
|
|
<p>The interface for a structure is:</p>
|
|
<pre>class PVStructure : public PVField,public BitSetSerializable {
|
|
public:
|
|
POINTER_DEFINITIONS(PVStructure);
|
|
virtual ~PVStructure();
|
|
typedef PVStructure & reference;
|
|
typedef const PVStructure & const_reference;
|
|
|
|
virtual void setImmutable();
|
|
StructureConstPtr getStructure() const;
|
|
const PVFieldPtrArray & getPVFields() const;
|
|
PVFieldPtr getSubField(String const &fieldName) const;
|
|
|
|
template<typename PVT>
|
|
std::tr1::shared_ptr<PVT> getSubField(String const &fieldName) const
|
|
|
|
PVFieldPtr getSubField(std::size_t fieldOffset) const;
|
|
|
|
template<typename PVT>
|
|
std::tr1::shared_ptr<PVT> getSubField(std::size_t fieldOffset) const
|
|
|
|
virtual void serialize(
|
|
ByteBuffer *pbuffer,SerializableControl *pflusher) const ;
|
|
virtual void deserialize(
|
|
ByteBuffer *pbuffer,DeserializableControl *pflusher);
|
|
virtual void serialize(ByteBuffer *pbuffer,
|
|
SerializableControl *pflusher,BitSet *pbitSet) const;
|
|
virtual void deserialize(ByteBuffer *pbuffer,
|
|
DeserializableControl*pflusher,BitSet *pbitSet);
|
|
PVStructure(StructureConstPtr const & structure);
|
|
PVStructure(StructureConstPtr const & structure,PVFieldPtrArray const & pvFields);
|
|
virtual std::ostream& dumpValue(std::ostream& o) const;
|
|
};</pre>
|
|
|
|
<p>where</p>
|
|
<dl>
|
|
<dt>getStructure</dt>
|
|
<dd>Get the introspection interface for the structure.</dd>
|
|
<dt>getPVFields</dt>
|
|
<dd>Returns the array of subfields. The set of subfields must all have
|
|
different field names.</dd>
|
|
<dt>getSubField(String fieldName)</dt>
|
|
<dd>
|
|
Get a subField of a field.d
|
|
A non-null result is
|
|
returned if fieldName is a field of the PVStructure. The fieldName can be
|
|
of the form name.name...
|
|
If the field does not exist the a Ptr to a NULL value is returned
|
|
without any error message being generated.
|
|
<br />
|
|
Note that the template version replaces getBooleanField, etc.<br/>
|
|
</dd>
|
|
<dt>getSubField(int fieldOffset)</dt>
|
|
<dd>Get the field located a fieldOffset, where fieldOffset is relative to
|
|
the top level structure. This returns null if the specified field is not
|
|
located within this PVStructure.
|
|
</dd>
|
|
<dt>dumpValue</dt>
|
|
<dd>Method for streams I/O.</dd>
|
|
</dl>
|
|
<p><b>TBD</b>
|
|
<dl>
|
|
<dt>dumpvalue</dt>
|
|
<dd>replace this with ostream operator<<</dd>
|
|
</dl>
|
|
</p>
|
|
|
|
|
|
<h3>PVValueArray</h3>
|
|
|
|
<p>This is a template class plus instances for PVBooleanArray, ...,
|
|
PVStringArray.</p>
|
|
<pre>template<typename T>
|
|
class PVValueArray : public detail::PVVectorStorage<T,PVScalarArray>
|
|
{
|
|
public:
|
|
POINTER_DEFINITIONS(PVValueArray);
|
|
typedef T value_type;
|
|
typedef T* pointer;
|
|
typedef const T* const_pointer;
|
|
typedef ::epics::pvData::shared_vector<T> svector;
|
|
typedef ::epics::pvData::shared_vector<const T> const_svector;
|
|
static const ScalarType typeCode;
|
|
|
|
virtual ~PVValueArray() {}
|
|
std::ostream& dumpValue(std::ostream& o) const;
|
|
std::ostream& dumpValue(std::ostream& o, size_t index) const;
|
|
// inherited from PVVectorStorage
|
|
const_svector view();
|
|
void swap(const_svector& other);
|
|
void replace(const const_svector& next);
|
|
svector reuse();
|
|
...
|
|
};
|
|
</pre>
|
|
|
|
<p>where</p>
|
|
<dl>
|
|
<dt>dumpValue</dt>
|
|
<dd>Method for streams I/O.</dd>
|
|
<dt>view</dt>
|
|
<dd>Fetch a read-only view of the current array data.</dd>
|
|
<dt>swap</dt>
|
|
<dd>
|
|
Callers must ensure that postPut() is called after the last swap() operation.
|
|
Before you call this directly, consider using the reuse(), or replace() methods.
|
|
</dd>
|
|
<dt>replace</dt>
|
|
<dd> Discard current contents and replaced with the provided.</dd>
|
|
<dt>reuse</dt>
|
|
<dd>Remove and return the current array data or an unique copy if shared.</dd>
|
|
</dl>
|
|
<p><b>TBD</b>
|
|
<dl>
|
|
<dt>dumpvalue</dt>
|
|
<dd>replace this with ostream operator<<</dd>
|
|
<dt>Check for completeness</dt>
|
|
<dd>Michael should check that PVScalarArray and PVValueArray
|
|
have the correct set of methods and that the descriptions are correct.</dd>
|
|
</dl>
|
|
</p>
|
|
|
|
<h3>PVStructureArray</h3>
|
|
|
|
<p>The interface for an array of structures is:</p>
|
|
<pre>
|
|
template<>
|
|
class PVValueArray<PVStructurePtr> : public detail::PVVectorStorage<PVStructurePtr,PVArray>
|
|
{
|
|
public:
|
|
POINTER_DEFINITIONS(PVStructureArray);
|
|
typedef PVStructurePtr value_type;
|
|
typedef PVStructurePtr* pointer;
|
|
typedef const PVStructurePtr* const_pointer;
|
|
typedef PVStructureArray &reference;
|
|
typedef const PVStructureArray& const_reference;
|
|
typedef ::epics::pvData::shared_vector<PVStructurePtr> svector;
|
|
typedef ::epics::pvData::shared_vector<const PVStructurePtr> const_svector;
|
|
|
|
virtual ~PVStructureArray() {}
|
|
virtual size_t getLength();
|
|
virtual size_t getCapacity();
|
|
virtual void setCapacity(size_t capacity);
|
|
virtual void setLength(std::size_t length);
|
|
virtual StructureArrayConstPtr getStructureArray() const ;
|
|
virtual std::size_t append(std::size_t number);
|
|
virtual bool remove(std::size_t offset,std::size_t number);
|
|
virtual void compress();
|
|
virtual void serialize(ByteBuffer *pbuffer,
|
|
virtual const_svector view() const;
|
|
virtual void swap(const_svector &other);
|
|
virtual void replace(const const_svector &other);
|
|
SerializableControl *pflusher) const;
|
|
virtual void deserialize(ByteBuffer *buffer,
|
|
DeserializableControl *pflusher);
|
|
virtual void serialize(ByteBuffer *pbuffer,
|
|
SerializableControl *pflusher, std::size_t offset, std::size_t count) const ;
|
|
virtual std::ostream& dumpValue(std::ostream& o) const;
|
|
virtual std::ostream& dumpValue(std::ostream& o, std::size_t index) const;
|
|
// inherited from PVVectorStorage
|
|
const_svector view();
|
|
void swap(const_svector& other);
|
|
void replace(const const_svector& next);
|
|
svector reuse();
|
|
...
|
|
}</pre>
|
|
|
|
<p>where</p>
|
|
<dl>
|
|
<dt>getStructureArray</dt>
|
|
<dd>Get the introspection interface shared by each element.</dd>
|
|
<dt>append</dt>
|
|
<dd>Create new elements and append them to the end of the array. It returns
|
|
the index of the first new element.</dd>
|
|
<dt>remove</dt>
|
|
<dd>Remove the specfied set of elements. It returns (false,true) if the
|
|
elements (were not, were) removed. It will not removed any elements
|
|
unless all requested elements exist or are null. Note that this deletes
|
|
the element and sets the array element to null. It does not change the
|
|
array capacity. </dd>
|
|
<dt>compress</dt>
|
|
<dd>This moves all null elements and then changes the array capacity. When
|
|
done there are no null elements.</dd>
|
|
</dl>
|
|
|
|
<p>The other methods are similar to the methods for other array types.
|
|
See PVArray above for details.</p>
|
|
|
|
<h3>PVUnionArray</h3>
|
|
<p>The interface for an array of unions is:</p>
|
|
<pre>
|
|
template&ly;&gt;
|
|
class epicsShareClass PVValueArray&ly;PVUnionPtr&gt; : public detail::PVVectorStorage&ly;PVUnionPtr,PVArray&gt;
|
|
{
|
|
typedef detail::PVVectorStorage&ly;PVUnionPtr,PVArray&gt; base_t;
|
|
public:
|
|
POINTER_DEFINITIONS(PVUnionArray);
|
|
typedef PVUnionPtr value_type;
|
|
typedef PVUnionPtr* pointer;
|
|
typedef const PVUnionPtr* const_pointer;
|
|
typedef PVUnionArray &reference;
|
|
typedef const PVUnionArray& const_reference;
|
|
|
|
//TODO: full namespace can be removed along with local typedef 'shared_vector'
|
|
typedef ::epics::pvData::shared_vector&ly;PVUnionPtr&gt; svector;
|
|
typedef ::epics::pvData::shared_vector&ly;const PVUnionPtr&gt; const_svector;
|
|
|
|
virtual ~PVValueArray() {}
|
|
|
|
virtual size_t getLength() const;
|
|
virtual size_t getCapacity() const;
|
|
virtual void setCapacity(size_t capacity);
|
|
virtual void setLength(std::size_t length);
|
|
UnionArrayConstPtr getUnionArray() const;
|
|
virtual std::size_t append(std::size_t number);
|
|
virtual bool remove(std::size_t offset,std::size_t number);
|
|
virtual void compress();
|
|
virtual const_svector view() const;
|
|
virtual void swap(const_svector &other);
|
|
virtual void replace(const const_svector &other);
|
|
virtual void serialize(ByteBuffer *pbuffer,
|
|
SerializableControl *pflusher) const;
|
|
virtual void deserialize(ByteBuffer *buffer,
|
|
DeserializableControl *pflusher);
|
|
virtual void serialize(ByteBuffer *pbuffer,
|
|
SerializableControl *pflusher, std::size_t offset, std::size_t count) const ;
|
|
virtual std::ostream& dumpValue(std::ostream& o) const;
|
|
virtual std::ostream& dumpValue(std::ostream& o, std::size_t index) const;
|
|
};
|
|
</pre>
|
|
<p>where</p>
|
|
<dl>
|
|
<dt>getUnionArray</dt>
|
|
<dd>Get the introspection interface shared by each element.</dd>
|
|
<dt>append</dt>
|
|
<dd>Create new elements and append them to the end of the array. It returns
|
|
the index of the first new element.</dd>
|
|
<dt>remove</dt>
|
|
<dd>Remove the specfied set of elements. It returns (false,true) if the
|
|
elements (were not, were) removed. It will not removed any elements
|
|
unless all requested elements exist or are null. Note that this deletes
|
|
the element and sets the array element to null. It does not change the
|
|
array capacity. </dd>
|
|
<dt>compress</dt>
|
|
<dd>This moves all null elements and then changes the array capacity. When
|
|
done there are no null elements.</dd>
|
|
</dl>
|
|
|
|
<p>The other methods are similar to the methods for other array types.
|
|
See PVArray above for details.</p>
|
|
|
|
<h3>PVDataCreate</h3>
|
|
|
|
<p>PVDataCreate is an interface that provides methods that create PVField
|
|
interfaces. A factory is provided that creates PVDataCreate.</p>
|
|
<pre>class PVDataCreate {
|
|
public:
|
|
static PVDataCreatePtr getPVDataCreate();
|
|
|
|
PVFieldPtr createPVField(FieldConstPtr const & field);
|
|
PVFieldPtr createPVField(PVFieldPtr const & fieldToClone);
|
|
|
|
PVScalarPtr createPVScalar(ScalarConstPtr const & scalar);
|
|
PVScalarPtr createPVScalar(ScalarType scalarType);
|
|
PVScalarPtr createPVScalar(PVScalarPtr const & scalarToClone);
|
|
template<typename PVT>
|
|
std::tr1::shared_ptr<PVT> createPVScalar();
|
|
|
|
PVStructurePtr createPVStructure(
|
|
StringArray const & fieldNames,PVFieldPtrArray const & pvFields);
|
|
PVStructurePtr createPVStructure(PVStructurePtr const & structToClone);
|
|
PVStructurePtr createPVStructure(StructureConstPtr const & structure);
|
|
|
|
PVUnionPtr createPVUnion(UnionConstPtr const & punion);
|
|
PVUnionPtr createPVUnion(PVUnionPtr const & unionToClone);
|
|
PVUnionPtr createPVVariantUnion();
|
|
|
|
PVScalarArrayPtr createPVScalarArray(ScalarArrayConstPtr const & scalarArray);
|
|
PVScalarArrayPtr createPVScalarArray(ScalarType elementType);
|
|
PVScalarArrayPtr createPVScalarArray(PVScalarArrayPtr const & scalarArrayToClone);
|
|
template<typename PVAT>
|
|
std::tr1::shared_ptr<PVAT> createPVScalarArray();
|
|
|
|
PVStructureArrayPtr createPVStructureArray(StructureArrayConstPtr const & structureArray);
|
|
PVStructureArrayPtr createPVStructureArray(StructureConstPtr const ∓ structure);
|
|
|
|
PVUnionArrayPtr createPVUnionArray(UnionArrayConstPtr const & unionArray);
|
|
PVUnionArrayPtr createPVUnionArray(UnionConstPtr const & punion);
|
|
PVUnionArrayPtr createPVVariantUnionArray();
|
|
...
|
|
};
|
|
|
|
extern PVDataCreatePtr getPVDataCreate();</pre>
|
|
|
|
<p>where </p>
|
|
<dl>
|
|
<dt>getPVDataCreate</dt>
|
|
<dd>The returns the PVDataCreate implementation, which is a singleton.</dd>
|
|
<dt>createPVField</dt>
|
|
<dd>The PVField is created reusing the Field interface. Two methods are
|
|
provided. Each calls the corresponding createPVScalar, createPVArray, or
|
|
createPVStructure depending in the type of the last argument.</dd>
|
|
<dt>createPVScalar</dt>
|
|
<dd>Creates an instance of a PVScalar. Four versions are supplied. The
|
|
first is passed an introspection interface.
|
|
The second provides the scalarType.
|
|
The third provides a PVScalar to clone.
|
|
The last is a template version. PVAT must be a valid type.
|
|
For example:
|
|
<pre>
|
|
PVDoublePtr pvDouble = getPVDataCreate()->createPVScalar<PVDouble>();
|
|
</pre>
|
|
</dd>
|
|
<dt>createPVStructure</dt>
|
|
<dd>Create an instance of a PVStructure.
|
|
Three methods are provided.
|
|
The first uses an array of field names and an array of PVFields to initialize the sub-fields.
|
|
The second initializes the subfields by cloning the fields contained in
|
|
structToClone. The newly created sub-fields will have the same values as the original.
|
|
If structToClone is null then the new structure is initialized to have 0 sub-fields.
|
|
The third method uses a previously created structure introspection interface.
|
|
</dd>
|
|
<dt>createPVUnion<dt>
|
|
<dd>Create an instance of a PVUnion. Two methods are provided.
|
|
The first uses a previously created union introspection interface.
|
|
The second clones an existing PVUnion.
|
|
</dd>
|
|
<dt>createPVVariantUnion<dt>
|
|
<dd>Creates an instance of a varient PVUnion.
|
|
This is a union which has a single field which can be any pvData supported type,
|
|
</dd>
|
|
<dt>createPVScalarArray</dt>
|
|
<dd>Create an instance of a PVArray. Four versions are supplied.
|
|
The first is passed an introspection interface.
|
|
The second provides the elementType.
|
|
The third provides a PVScalarArray to clone.
|
|
The last is a template version. PVAT must be a valid type.
|
|
For example:
|
|
<pre>
|
|
PVDoubleArrayPtr pvDoubleArray = getPVDataCreate()->createPVScalarArray<PVDoubleArray>();
|
|
</pre>
|
|
</dd>
|
|
<dt>createPVStructureArray</dt>
|
|
<dd>Create a PVStructureArray.
|
|
Two versions are provided.
|
|
The first is passed a StructureArrayConstPtr.
|
|
The second is passed a StructureConstPtr which is used to create a StructureArrayConstPtr.
|
|
The argument provides the Structure interface for ALL elements of the PVStructureArray.
|
|
</dd>
|
|
<dt>createPVUnionArray</dt>
|
|
<dd>Create a PVUnionArray.
|
|
Two versions are provided.
|
|
The first is passed a UnionArrayConstPtr.
|
|
The second is passed a UnionConstPtr which is used to create a UnionArrayConstPtr.
|
|
The argument provides the Union interface for ALL elements of the PVUnionArray.
|
|
</dd>
|
|
<dt>createPVVariantUnionArray</dt>
|
|
<dd>Create a PVUnionArray.
|
|
No arguments are needed.
|
|
</dd>
|
|
</dl>
|
|
|
|
<h2>standardPVField.h</h2>
|
|
|
|
<p>A class StandardPVField has methods for creating standard data fields. Like
|
|
class StandardField it has two forms of the methods which create a field, one
|
|
without properties and one with properties. Again the properties is some
|
|
combination of alarm, timeStamp, control, display, and valueAlarm. And just
|
|
like StandardField there are methods to create the standard properties. The
|
|
methods are:</p>
|
|
<pre>class StandardPVField;
|
|
typedef std::tr1::shared_ptr<StandardPVField> StandardPVFieldPtr;
|
|
|
|
class StandardPVField : private NoDefaultMethods {
|
|
public:
|
|
static StandardPVFieldPtr getStandardPVField();
|
|
~StandardPVField();
|
|
PVStructurePtr scalar(ScalarType type,String const &properties);
|
|
PVStructurePtr scalarArray(ScalarType elementType, String const &properties);
|
|
PVStructurePtr structureArray(StructureConstPtr const &structure,String const &properties);
|
|
PVStructurePtr unionArray(UnionConstPtr const &punion,String const &properties);
|
|
PVStructurePtr enumerated(StringArray const &choices);
|
|
PVStructurePtr enumerated(StringArray const &choices, String const &properties);
|
|
...
|
|
}
|
|
|
|
extern StandardPVFieldPtr getStandardPVField();
|
|
</pre>
|
|
|
|
<h2>Conversion</h2>
|
|
<p>There are two facilities for converting between two different PVData
|
|
objects:</p>
|
|
<dl>
|
|
<dt>Convert</dt>
|
|
<dd>This preforms all conversions except for coping subarrays.</dd>
|
|
<dt>PVSubArray</dt>
|
|
<dd>This copies a subarray from one PVArray to another.
|
|
The two arrays must have the same element type.</dd>
|
|
</dl>
|
|
<h3>convert.h</h3>
|
|
|
|
<p>NOTE about copying immutable array fields. If an entire immutable array
|
|
field is copied to another array that has the same elementType, both offsets
|
|
are 0, and the length is the length of the source array, then the shareData
|
|
method of the target array is called and the target array is set immutable.
|
|
Thus the source and target share the same primitive array.</p>
|
|
|
|
<p>This section describes the supported conversions between data types.</p>
|
|
<ul>
|
|
<li>All supported types can be converted to a string. If you ask for a 100
|
|
megabyte array to be converted to a string expect a lot of output.</li>
|
|
<li>Conversion from a string to a scalar type.</li>
|
|
<li>Conversion from an array of strings to an array of scalar types.</li>
|
|
<li>Copy between the following types of scalar PVs
|
|
<ul>
|
|
<li>Numeric type to another numeric type</li>
|
|
<li>Both have the same type.</li>
|
|
<li>Either is a string</li>
|
|
</ul>
|
|
</li>
|
|
<li>Copy between PVArrays that satisfy one of the following.
|
|
<ul>
|
|
<li>Both have the same type.</li>
|
|
<li>Either is a string.</li>
|
|
</ul>
|
|
</li>
|
|
<li>Conversions between numeric scalar types.</li>
|
|
<li>Conversion between compatible structures.</li>
|
|
<li>A utility method the returns the full field name of a field</li>
|
|
</ul>
|
|
<pre>
|
|
bool operator==(PVField&, PVField&);
|
|
|
|
static bool operator!=(PVField& a, PVField& b);
|
|
|
|
bool operator==(const Field&, const Field&);
|
|
bool operator==(const Scalar&, const Scalar&);
|
|
bool operator==(const ScalarArray&, const ScalarArray&);
|
|
bool operator==(const Structure&, const Structure&);
|
|
bool operator==(const StructureArray&, const StructureArray&);
|
|
bool operator==(const Union&, const Union&);
|
|
bool operator==(const UnionArray&, const UnionArray&);
|
|
|
|
static inline bool operator!=(const Field& a, const Field& b);
|
|
static inline bool operator!=(const Scalar& a, const Scalar& b);
|
|
static inline bool operator!=(const ScalarArray& a, const ScalarArray& b);
|
|
static inline bool operator!=(const Structure& a, const Structure& b);
|
|
static inline bool operator!=(const StructureArray& a, const StructureArray& b);
|
|
static inline bool operator!=(const Union& a, const Union& b);
|
|
static inline bool operator!=(const UnionArray& a, const UnionArray& b);
|
|
|
|
class Convert;
|
|
typedef std::tr1::shared_ptr<Convert> ConvertPtr;
|
|
|
|
class Convert {
|
|
public:
|
|
static ConvertPtr getConvert();
|
|
~Convert();
|
|
void getFullName(StringBuilder buf,PVFieldPtr const & pvField);
|
|
bool equals(PVFieldPtr const &a,PVFieldPtr const &b);
|
|
bool equals(PVField &a,PVField &b);
|
|
void getString(StringBuilder buf,PVFieldPtr const & pvField,int indentLevel);
|
|
void getString(StringBuilder buf,PVFieldPtr const & pvField);
|
|
void getString(StringBuilder buf,PVField const * pvField,int indentLevel);
|
|
void getString(StringBuilder buf,PVField const * pvField);
|
|
std::size_t fromString(
|
|
PVStructurePtr const &pv,
|
|
StringArray const & from,
|
|
std::size_t fromStartIndex = 0);
|
|
void fromString(PVScalarPtr const & pv, String const & from);
|
|
std::size_t fromString(PVScalarArrayPtr const & pv, String const &from);
|
|
std::size_t fromStringArray(
|
|
PVScalarArrayPtr const & pv,
|
|
std::size_t offset, std::size_t length,
|
|
StringArray const & from,
|
|
std::size_t fromOffset);
|
|
std::size_t toStringArray(PVScalarArrayPtr const & pv,
|
|
std::size_t offset,
|
|
std::size_t length,
|
|
StringArray & to,
|
|
std::size_t toOffset);
|
|
bool isCopyCompatible(FieldConstPtr const & from, FieldConstPtr const & to);
|
|
void copy(PVFieldPtr const & from, PVFieldPtr const & to);
|
|
bool isCopyScalarCompatible(
|
|
ScalarConstPtr const & from,
|
|
ScalarConstPtr const & to);
|
|
void copyScalar(PVScalarPtr const & from, PVScalarPtr const & to);
|
|
bool isCopyScalarArrayCompatible(
|
|
ScalarArrayConstPtr const & from,
|
|
ScalarArrayConstPtr const & to);
|
|
bool isCopyStructureCompatible(
|
|
StructureConstPtr const & from, StructureConstPtr const & to);
|
|
void copyStructure(PVStructurePtr const & from, PVStructurePtr const & to);
|
|
bool isCopyStructureArrayCompatible(
|
|
StructureArrayConstPtr const & from, StructureArrayConstPtr const & to);
|
|
void copyStructureArray(
|
|
PVStructureArrayPtr const & from, PVStructureArrayPtr const & to);
|
|
bool isCopyUnionCompatible(
|
|
UnionConstPtr const & from, UnionConstPtr const & to);
|
|
void copyUnion(
|
|
PVUnionPtr const & from, PVUnionPtr const & to);
|
|
bool isCopyUnionArrayCompatible(
|
|
UnionArrayConstPtr const & from, UnionArrayConstPtr const & to);
|
|
void copyUnionArray(
|
|
PVUnionArrayPtr const & from, PVUnionArrayPtr const & to);
|
|
int8 toByte(PVScalarPtr const & pv);
|
|
int16 toShort(PVScalarPtr const & pv);
|
|
int32 toInt(PVScalarPtr const & pv);
|
|
int64 toLong(PVScalarPtr const & pv);
|
|
uint8 toUByte(PVScalarPtr const & pv);
|
|
uint16 toUShort(PVScalarPtr const & pv);
|
|
uint32 toUInt(PVScalarPtr const & pv);
|
|
uint64 toULong(PVScalarPtr const & pv);
|
|
float toFloat(PVScalarPtr const & pv);
|
|
double toDouble(PVScalarPtr const & pv);
|
|
String toString(PVScalarPtr const & pv);
|
|
void fromByte(PVScalarPtr const & pv,int8 from);
|
|
void fromShort(PVScalarPtr const & pv,int16 from);
|
|
void fromInt(PVScalarPtr const & pv, int32 from);
|
|
void fromLong(PVScalarPtr const & pv, int64 from);
|
|
void fromUByte(PVScalarPtr const & pv,uint8 from);
|
|
void fromUShort(PVScalarPtr const & pv,uint16 from);
|
|
void fromUInt(PVScalarPtr const & pv, uint32 from);
|
|
void fromULong(PVScalarPtr const & pv, uint64 from);
|
|
void fromFloat(PVScalarPtr const & pv, float from);
|
|
void fromDouble(PVScalarPtr const & pv, double from);
|
|
void newLine(StringBuilder buf, int indentLevel);
|
|
...
|
|
}
|
|
|
|
extern ConvertPtr getConvert();
|
|
</pre>
|
|
<p>newLine is a convenience method for code that implements toString It
|
|
generates a newline and inserts blanks at the beginning of the newline.</p>
|
|
|
|
<h3>pvSubArrayCopy.h</h3>
|
|
<pre>
|
|
template<typename T>
|
|
void copy(
|
|
PVValueArray<T> & pvFrom,
|
|
size_t fromOffset,
|
|
PVValueArray<T> & pvTo,
|
|
size_t toOffset,
|
|
size_t len);
|
|
|
|
void copy(
|
|
PVScalarArray & from,
|
|
size_t fromOffset,
|
|
PVScalarArray & to,
|
|
size_t toOffset,
|
|
size_t len);
|
|
|
|
void copy(
|
|
PVStructureArray & from,
|
|
size_t fromOffset,
|
|
PVStructureArray & to,
|
|
size_t toOffset,
|
|
size_t len);
|
|
|
|
void copy(
|
|
PVArray & from,
|
|
size_t fromOffset,
|
|
PVArray & to,
|
|
size_t toOffset,
|
|
size_t len);
|
|
</pre>
|
|
<p>The last copy is the only one most client need to call.
|
|
It either throws an error of the element types do not match or calls the
|
|
other copy functions. The arguments are:</p>
|
|
<dl>
|
|
<dt>from</dt>
|
|
<dd>The source array.</dd>
|
|
<dt>fromOffset</dt>
|
|
<dd>The offset into the source array.</dd>
|
|
<dt>to</dt>
|
|
<dd>The destination array. The element type must be the same
|
|
as for the source array. If the element type is structure then
|
|
the introspection interface for the element types must be the same.
|
|
</dd>
|
|
<dt>toOffset</dt>
|
|
<dd>The offset into the destination array.</dd>
|
|
<dt>len</dt>
|
|
<dd>The number of elements to copy.</dd>
|
|
</dl>
|
|
<p>An exception is thrown if:</p>
|
|
<dl>
|
|
<dt>type mismatch</dt>
|
|
<dd>The element types for the source and destination differ.</dd>
|
|
<dt>immutable</dt>
|
|
<dd>The destination array is immutable.</dt>
|
|
<dt>capacity immutable</dt>
|
|
<dd>The destination array needs to have it's capacity extentended
|
|
but the capacity is immutable.</dd>
|
|
</dl>
|
|
|
|
<h2>pvDataApp/property</h2>
|
|
|
|
<h3>Definition of Property</h3>
|
|
|
|
<p>Only fields named "value" have properties. A record can have multiple value
|
|
fields, which can appear in the top level structure of a record or in a
|
|
substructure. All other fields in the structure containing a value field are
|
|
considered properties of the value field. The fieldname is also the property
|
|
name. The value field can have any type, i.e. scalar, scalarArray, or
|
|
structure. Typical property fields are timeStamp, alarm, display, control, and
|
|
history. The timeStamp is a special case. If it appears anywhere in the
|
|
structure hieraracy above a value field it is a property of the value field.</p>
|
|
|
|
<p>For example the following top level structure has a single value field. The
|
|
value field has properties alarm, timeStamp, and display.</p>
|
|
<pre>structure counterOutput
|
|
double value
|
|
alarm_t
|
|
int severity 0
|
|
int status 0
|
|
string message
|
|
timeStamp_t
|
|
long secondsPastEpoch
|
|
int nanoSeconds
|
|
int userTag
|
|
display_t
|
|
double limitLow 0.0
|
|
double limitHigh 10.0
|
|
string description "Sample Description"
|
|
string format "%f"
|
|
string units volts</pre>
|
|
|
|
<p>The following example has three value fields each with properties alarm and
|
|
timeStamp. Voltage, Current, and Power each have a different alarms but all
|
|
share the timeStamp.</p>
|
|
<pre>structure powerSupplyValue
|
|
double value
|
|
alarm_t
|
|
int severity 0
|
|
int status 0
|
|
string message
|
|
|
|
structure powerSupplySimple
|
|
alarm_t
|
|
int severity 0
|
|
int status 0
|
|
string message
|
|
timeStamp_t
|
|
long secondsPastEpoch
|
|
int nanoSeconds
|
|
int userTag
|
|
powerSupplyValue_t voltage
|
|
double value
|
|
alarm_t
|
|
int severity 0
|
|
int status 0
|
|
string message
|
|
powerSupplyValue_t power
|
|
double value
|
|
alarm_t
|
|
int severity 0
|
|
int status 0
|
|
string message
|
|
powerSupplyValue_t current
|
|
double value
|
|
alarm_t
|
|
int severity 0
|
|
int status 0
|
|
string message</pre>
|
|
|
|
<h3>Standard Properties</h3>
|
|
|
|
<p>The following field names have special meaning, i.e. support properties for
|
|
general purpose clients.</p>
|
|
<dl>
|
|
<dt>value</dt>
|
|
<dd>This is normally defined since most general purpose clients access this
|
|
field. All other fields in the structure support or describe the value
|
|
field. The type can any supported type but is usually one of the
|
|
following:
|
|
<dl>
|
|
<dt>scalar</dt>
|
|
<dd>Any of the scalar types.</dd>
|
|
<dt>scalarArray</dt>
|
|
<dd>An array with the elementType being a scalar type</dd>
|
|
<dt>enumerated structure</dt>
|
|
<dd>A structure that includes fields named index and choices. index
|
|
is an int that selects a choice. choices is an array of strings
|
|
that defines the complete set of choices.</dd>
|
|
<dt>other</dt>
|
|
<dd>Other structure or array types can also be defined if clients and
|
|
support code agree on the meaning. Some examples are: 1) A
|
|
structure defining a 2D matrix, 2) A structure defining an image,
|
|
3) A structure that simulates a remote method, ...</dd>
|
|
</dl>
|
|
</dd>
|
|
<dt>timeStamp</dt>
|
|
<dd>The timeStamp. The type MUST be a timeStamp structure. Also if the
|
|
PVData structure does not have a timeStamp then a search up the parent
|
|
tree is made to find a timeStamp.</dd>
|
|
<dt>alarm</dt>
|
|
<dd>The alarm. The type MUST be an alarm structure. </dd>
|
|
<dt>display</dt>
|
|
<dd>A display structure as described below. It provides display
|
|
characteristics for the value field.</dd>
|
|
<dt>control</dt>
|
|
<dd>A control structure as described below. It provides control
|
|
characteristics for the value field.</dd>
|
|
<dt>history</dt>
|
|
<dd>Provides a history buffer for the value field. Note that currently
|
|
PVData does not define history suppoprt.</dd>
|
|
<dt>other</dt>
|
|
<dd>Other standard properties can be defined.</dd>
|
|
</dl>
|
|
|
|
<p>In addition a structure can have additional fields that support the value
|
|
field but are not recognized by most general purpose client tools. Typical
|
|
examples are:</p>
|
|
<dl>
|
|
<dt>input</dt>
|
|
<dd>A field with support that changes the value field. This can be
|
|
anything. It can be a channel access link. It can obtain a value from
|
|
hardware. Etc.</dd>
|
|
<dt>valueAlarm</dt>
|
|
<dd>A field with support that looks for alarm conditions based on the
|
|
value.</dd>
|
|
<dt>output</dt>
|
|
<dd>A field with support that reads the current value and sends it
|
|
somewhere else. This can be anything. It can be a channel access link. It
|
|
can write a value to hardware. Etc.</dd>
|
|
</dl>
|
|
|
|
<p>The model allows for device records. A device record has structure fields
|
|
that that support the PVData data model. For example a powerSupport record can
|
|
have fields power, voltage, current that each support the PVData data model.
|
|
</p>
|
|
|
|
<h3>Overview of Property Support</h3>
|
|
|
|
<p>Except for enumerated, each property has two files: a property.h and a
|
|
pvProperty.h . For example: timeStamp.h and pvTimeStamp.h In each case the
|
|
property.h file defined methods for manipulating the property data and the
|
|
pvProperty.h provides methods to transfer the property data to/from a pvData
|
|
structure. </p>
|
|
|
|
<p>All methods copy data via copy by value semantics, i.e. not by pointer or by
|
|
reference. No property class calls new or delete and all allow the compiler to
|
|
generate default methods. All allow a class instance to be generated on the
|
|
stack. For example the following is permitted:</p>
|
|
<pre>void example(PVFieldPtr const &pvField) {
|
|
Alarm alarm;
|
|
PVAlarm pvAlarm;
|
|
bool result;
|
|
result = pvAlarm.attach(pvField);
|
|
assert(result);
|
|
Alarm al;
|
|
al.setMessage(String("testMessage"));
|
|
al.setSeverity(majorAlarm);
|
|
result = pvAlarm.set(al);
|
|
assert(result);
|
|
alarm = pvAlarm.get();
|
|
...
|
|
}</pre>
|
|
|
|
<h3>timeStamp</h3>
|
|
|
|
<p>A timeStamp is represented by the following structure</p>
|
|
<pre>structure timeStamp
|
|
long secondsPartEpoch
|
|
int nanoSeconds
|
|
int userTag</pre>
|
|
|
|
<p>The Epoch is the posix epoch, i.e. Jan 1, 1970 00:00:00 UTC. Both the
|
|
seconds and nanoSeconds are signed integers and thus can be negative. Since the
|
|
seconds is kept as a 64 bit integer, it allows for a time much greater than the
|
|
present age of the universe. Since the nanoSeconds portion is kept as a 32 bit
|
|
integer it is subject to overflow if a value that corresponds to a value that
|
|
is greater than a little more than 2 seconds of less that about -2 seconds. The
|
|
support code always adjust seconds so that the nanoSecconds part is normlized,
|
|
i. e. it has is 0<=nanoSeconds<nanoSecPerSec..</p>
|
|
|
|
<p>Two header files are provided for manipulating time stamps:</p>
|
|
<dl>
|
|
<dt>timeStamp.h</dt>
|
|
<dd>Defines a time stamp independent of pvData, i.e. it is a generally
|
|
useful class for manipulating timeStamps.</dd>
|
|
<dt>pvTimeStamp.h</dt>
|
|
<dd>A class that can be attached to a time stamp pvData structure. It
|
|
provides get and set methods to get/set a TimeStamp as defined by
|
|
timeStamp.h</dd>
|
|
</dl>
|
|
|
|
<h4>timeStamp.h</h4>
|
|
|
|
<p>This provides </p>
|
|
<pre>extern int32 milliSecPerSec;
|
|
extern int32 microSecPerSec;
|
|
extern int32 nanoSecPerSec;
|
|
extern int64 posixEpochAtEpicsEpoch;
|
|
|
|
class TimeStamp {
|
|
public:
|
|
TimeStamp()
|
|
:secondsPastEpoch(0), nanoSeconds(0), userTag(0) {}
|
|
TimeStamp(int64 secondsPastEpoch,int32 nanoSeconds = 0,int32 userTag = 0);
|
|
//default constructors and destructor are OK
|
|
//This class should not be extended
|
|
void normalize();
|
|
void fromTime_t(const time_t &);
|
|
void toTime_t(time_t &) const;
|
|
int64 getSecondsPastEpoch() const {return secondsPastEpoch;}
|
|
int64 getEpicsSecondsPastEpoch() const {
|
|
return secondsPastEpoch - posixEpochAtEpicsEpoch;
|
|
}
|
|
int32 getNanoSeconds() const {return nanoSeconds;}
|
|
int32 getUserTag() const {return userTag;}
|
|
void setUserTag(int userTag) {this->userTag = userTag;}
|
|
void put(int64 secondsPastEpoch,int32 nanoSeconds = 0) {
|
|
this->secondsPastEpoch = secondsPastEpoch;
|
|
this->nanoSeconds = nanoSeconds;
|
|
normalize();
|
|
}
|
|
void put(int64 milliseconds);
|
|
void getCurrent();
|
|
double toSeconds() const ;
|
|
bool operator==(TimeStamp const &) const;
|
|
bool operator!=(TimeStamp const &) const;
|
|
bool operator<=(TimeStamp const &) const;
|
|
bool operator< (TimeStamp const &) const;
|
|
bool operator>=(TimeStamp const &) const;
|
|
bool operator> (TimeStamp const &) const;
|
|
static double diff(TimeStamp const & a,TimeStamp const & b);
|
|
TimeStamp & operator+=(int64 seconds);
|
|
TimeStamp & operator-=(int64 seconds);
|
|
TimeStamp & operator+=(double seconds);
|
|
TimeStamp & operator-=(double seconds);
|
|
int64 getMilliseconds(); // milliseconds since epoch
|
|
...
|
|
}</pre>
|
|
|
|
<p>where</p>
|
|
<dl>
|
|
<dt>TimeStamp()</dt>
|
|
<dd>The defauly constuctor. Both seconds and nanoSeconds are set to 0.</dd>
|
|
<dt>TimeStamp(int64 secondsPastEpoch,int32 nanoSeconds = 0)</dt>
|
|
<dd>A constructor that gives initial values to seconds and nanoseconds.</dd>
|
|
<dt>normalize</dt>
|
|
<dd>Adjust seconds and nanoSeconds so that
|
|
0<=nanoSeconds<nanoSecPerSec.</dd>
|
|
<dt>fromTime_t</dt>
|
|
<dd>Set time from standard C time.</dd>
|
|
<dt>toTime_t</dt>
|
|
<dd>Convert timeStamp to standard C time.</dd>
|
|
<dt>getSecondsPastEpoch</dt>
|
|
<dd>Get the number of seconds since the epoch.</dd>
|
|
<dt>getEpicsSecondsPastEpoch</dt>
|
|
<dd>Get the number of EPICS seconds since the epoch. EPICS uses Jan 1, 1990
|
|
00:00:00 UTC as the epoch.</dd>
|
|
<dt>getNanoSeconds</dt>
|
|
<dd>Get the number of nanoSeconds. This is always normalized.</dd>
|
|
<dt>getUserTag</dt>
|
|
<dd>Get the userTag.</dd>
|
|
<dt>setUserTag</dt>
|
|
<dd>Set the userTag.</dd>
|
|
<dt>put(int64 secondsPastEpoch,int32 nanoSeconds = 0)</dt>
|
|
<dd>Set the timeStamp value. If necessary it will be normalized.</dd>
|
|
<dt>put(int64 milliseconds)</dt>
|
|
<dd>Set the timeStamp with a value the is the number of milliSeconds since
|
|
the epoch.</dd>
|
|
<dt>getCurrent()</dt>
|
|
<dd>Set the timeStamp to the current time.</dd>
|
|
<dt>toSeconds()</dt>
|
|
<dd>Convert the timeStamp to a value that is the number of seconds since
|
|
the epocj</dd>
|
|
<dt>operator =</dt>
|
|
<dt>operator!=</dt>
|
|
<dt>operator<=</dt>
|
|
<dt>operator<</dt>
|
|
<dt>operator>=</dt>
|
|
<dt>operator> </dt>
|
|
<dd>Standard C++ operators.</dd>
|
|
<dt>diff</dt>
|
|
<dd>diff = a - b</dd>
|
|
<dt>getMilliseconds</dt>
|
|
<dd>Get the number of milliseconds since the epoch.</dd>
|
|
</dl>
|
|
|
|
<p>The TimeStamp class provides arithmetic operations on time stamps. The
|
|
result is always kept in normalized form, which means that the nano second
|
|
portion is 0≤=nano<nanoSecPerSec. Note that it is OK to have timeStamps
|
|
for times previous to the epoch.</p>
|
|
|
|
<p>TimeStamp acts like a primitive. It can be allocated on the stack and the
|
|
compiler is free to generate default methods, i.e. copy constructor, assignment
|
|
constructor, and destructor.</p>
|
|
|
|
<p>One use for TimeStamp is to time how long a section of code takes to
|
|
execute. This is done as follows:</p>
|
|
<pre> TimeStamp startTime;
|
|
TimeStamp endTime;
|
|
...
|
|
startTime.getCurrent();
|
|
// code to be measured for elapsed time
|
|
endTime.getCurrent();
|
|
double time = TimeStamp::diff(endTime,startTime);</pre>
|
|
|
|
<h4>pvTimeStamp.h</h4>
|
|
<pre>class PVTimeStamp {
|
|
public:
|
|
PVTimeStamp();
|
|
//default constructors and destructor are OK
|
|
//This class should not be extended
|
|
//returns (false,true) if pvField(isNot, is valid timeStamp structure
|
|
bool attach(PVFieldPtr const &pvField);
|
|
void detach();
|
|
bool isAttached();
|
|
// following throw logic_error if not attached to PVField
|
|
// a set returns false if field is immutable
|
|
void get(TimeStamp &) const;
|
|
bool set(TimeStamp const & timeStamp);
|
|
};</pre>
|
|
|
|
<p>where</p>
|
|
<dl>
|
|
<dt>PVTimeStamp</dt>
|
|
<dd>The default constructor. Attach must be called before get or set can be
|
|
called.</dd>
|
|
<dt>attach</dt>
|
|
<dd>Attempts to attach to pvField It returns (false,true) if a timeStamp
|
|
structure is found. It looks first at pvField itself and if is not an
|
|
appropriate pvData structure but the field name is value it looks up the
|
|
parent structure tree.</dd>
|
|
<dt>detach</dt>
|
|
<dd>Detach from the pvData structure.</dd>
|
|
<dt>isAttached</dt>
|
|
<dd>Is there an attachment to a timeStamp structure?</dd>
|
|
<dt>get</dt>
|
|
<dd>Copies data from the pvData structure to a TimeStamp. An exception is
|
|
thrown if not attached to a pvData structure. </dd>
|
|
<dt>set</dt>
|
|
<dd>Copies data from TimeStamp to the pvData structure. An exception is
|
|
thrown if not attached to a pvData structure. </dd>
|
|
</dl>
|
|
|
|
<h3>alarm</h3>
|
|
|
|
<p>An alarm structure is defined as follows:</p>
|
|
<pre>structure alarm
|
|
int severity
|
|
int status
|
|
string message</pre>
|
|
|
|
<p>Note that neither severity or status is defined as an enumerated structure.
|
|
The reason is performance, i. e. prevent passing the array of choice strings
|
|
everywhere. The file alarm.h provides the choice strings. Thus all code that
|
|
needs to know about alarms share the exact same choice strings.</p>
|
|
|
|
<p>Two header files are provided for manipulating alarms:</p>
|
|
<dl>
|
|
<dt>alarm.h</dt>
|
|
<dd>Defines an alarm independent of pvData, i.e. it is a generally useful
|
|
class for manipulating alarms.</dd>
|
|
<dt>pvAlarm.h</dt>
|
|
<dd>A class that can be attached to an alarm pvData structure. It provides
|
|
get and set methods to get/set alarm data as defined by alarm.h</dd>
|
|
</dl>
|
|
|
|
<h4>alarm.h</h4>
|
|
<pre>enum AlarmSeverity {
|
|
noAlarm,minorAlarm,majorAlarm,invalidAlarm,undefinedAlarm
|
|
};
|
|
|
|
enum AlarmStatus {
|
|
noStatus,deviceStatus,driverStatus,recordStatus,
|
|
dbStatus,confStatus,undefinedStatus,clientStatus
|
|
};
|
|
|
|
|
|
class AlarmSeverityFunc {
|
|
public:
|
|
static AlarmSeverity getSeverity(int value);
|
|
static StringArrayPtr getSeverityNames();
|
|
};
|
|
|
|
class AlarmStatusFunc {
|
|
public:
|
|
static AlarmStatus getStatus(int value);
|
|
static StringArrayPtr getStatusNames();
|
|
};
|
|
|
|
class Alarm {
|
|
public:
|
|
Alarm();
|
|
//default constructors and destructor are OK
|
|
String getMessage();
|
|
void setMessage(String const &value);
|
|
AlarmSeverity getSeverity() const;
|
|
void setSeverity(AlarmSeverity value);
|
|
AlarmStatus getStatus() const;
|
|
void setStatus(AlarmStatus value);
|
|
};</pre>
|
|
|
|
<p>Alarm Severity defines the possible alarm severities:</p>
|
|
<dl>
|
|
<dt>getSeverity</dt>
|
|
<dd>Get the alarm severity corresponding to the integer value.</dd>
|
|
<dt>getSeverityNames</dt>
|
|
<dd>Get the array of severity choices.</dd>
|
|
</dl>
|
|
|
|
<p>Alarm Status defines the possible choices for alarm status:</p>
|
|
<dl>
|
|
<dt>getStatus</dt>
|
|
<dd>Get the alarm status corresponding to the integer value.</dd>
|
|
<dt>getStatusNames</dt>
|
|
<dd>Get the array of status choices.</dd>
|
|
</dl>
|
|
|
|
<p>Alarm has the methods:</p>
|
|
<dl>
|
|
<dt>Alarm</dt>
|
|
<dd>The constructor. It sets the severity to no alarm and the message to
|
|
"".</dd>
|
|
<dt>getMessage</dt>
|
|
<dd>Get the message.</dd>
|
|
<dt>setMessage</dt>
|
|
<dd>Set the message.</dd>
|
|
<dt>getSeverity</dt>
|
|
<dd>Get the severity.</dd>
|
|
<dt>setSeverity</dt>
|
|
<dd>Set the severity.</dd>
|
|
<dt>getStatus</dt>
|
|
<dd>Get the status.</dd>
|
|
<dt>setStatus</dt>
|
|
<dd>Set the status.</dd>
|
|
</dl>
|
|
|
|
<h4>pvAlarm.h</h4>
|
|
<pre>class PVAlarm {
|
|
public:
|
|
PVAlarm() : pvSeverity(0),pvMessage(0) {}
|
|
//default constructors and destructor are OK
|
|
//returns (false,true) if pvField(isNot, is valid enumerated structure
|
|
//An automatic detach is issued if already attached.
|
|
bool attach(PVFieldPtr const &pvField);
|
|
void detach();
|
|
bool isAttached();
|
|
// each of the following throws logic_error is not attached to PVField
|
|
// set returns false if field is immutable
|
|
void get(Alarm & alarm) const;
|
|
bool set(Alarm const & alarm);
|
|
};</pre>
|
|
|
|
<p>where</p>
|
|
<dl>
|
|
<dt>PVAlarm</dt>
|
|
<dd>The default constructor. Attach must be called before get or set can be
|
|
called.</dd>
|
|
<dt>attach</dt>
|
|
<dd>Attempts to attach to pvField It returns (false,true) if it found an
|
|
appropriate pvData structure. It looks first a pvField itself and if is
|
|
not an appropriate pvData structure but the field name is value it looks
|
|
to see if the parent structure has an appropriate sub structure.</dd>
|
|
<dt>detach</dt>
|
|
<dd>Just detaches from the pvData structure.</dd>
|
|
<dt>isAttached</dt>
|
|
<dd>Is there an attachment to an alarm structure?</dd>
|
|
<dt>get</dt>
|
|
<dd>Copies data from the pvData structure to an Alarm. An exception is
|
|
thrown if not attached to a pvData structure. </dd>
|
|
<dt>set</dt>
|
|
<dd>Copies data from Alarm to the pvData structure. An exception is thrown
|
|
if not attached to a pvData structure. </dd>
|
|
</dl>
|
|
|
|
<h3>control</h3>
|
|
|
|
<p>Control information is represented by the following structure</p>
|
|
<pre>structure control
|
|
double limitLow
|
|
double limitHigh
|
|
double minStep</pre>
|
|
|
|
<p>Two header files are provided for manipulating control:</p>
|
|
<dl>
|
|
<dt>control.h</dt>
|
|
<dd>Defines control independent of pvData, i.e. it is a generally useful
|
|
class for manipulating control.</dd>
|
|
<dt>pvControl.h</dt>
|
|
<dd>A class that can be attached to an control pvData structure. It
|
|
provides get and set methods to get/set control data as defined by
|
|
control.h</dd>
|
|
</dl>
|
|
|
|
<h4>control.h</h4>
|
|
<pre>class Control {
|
|
public:
|
|
Control();
|
|
//default constructors and destructor are OK
|
|
double getLow() const;
|
|
double getHigh() const;
|
|
double getMinStep() const;
|
|
void setLow(double value);
|
|
void setHigh(double value);
|
|
void setMinStep(double value);
|
|
};</pre>
|
|
|
|
<p>where</p>
|
|
<dl>
|
|
<dt>Control</dt>
|
|
<dd>The default constructure.</dd>
|
|
<dt>getLow</dt>
|
|
<dd>Get the low limit.</dd>
|
|
<dt>getHigh</dt>
|
|
<dd>Get the high limit.</dd>
|
|
<dt>setLow</dt>
|
|
<dd>Set the low limit.</dd>
|
|
<dt>setHigh</dt>
|
|
<dd>Set the high limit.</dd>
|
|
<dt>setMinStep</dt>
|
|
<dd>Set the minimum step size.</dd>
|
|
<dt>getMinStep</dt>
|
|
<dd>Get he minimum step size.</dd>
|
|
</dl>
|
|
|
|
<h4>pvControl.h</h4>
|
|
<pre>class PVControl {
|
|
public:
|
|
PVControl();
|
|
//default constructors and destructor are OK
|
|
//returns (false,true) if pvField(isNot, is valid enumerated structure
|
|
//An automatic detach is issued if already attached.
|
|
bool attach(PVFieldPtr const &pvField);
|
|
void detach();
|
|
bool isAttached();
|
|
// each of the following throws logic_error is not attached to PVField
|
|
// set returns false if field is immutable
|
|
void get(Control &) const;
|
|
bool set(Control const & control);
|
|
};</pre>
|
|
|
|
<p>where</p>
|
|
<dl>
|
|
<dt>PVControl</dt>
|
|
<dd>The default constructor. Attach must be called before get or set can be
|
|
called.</dd>
|
|
<dt>attach</dt>
|
|
<dd>Attempts to attach to pvField It returns (false,true) if it found an
|
|
appropriate pvData structure. It looks first a pvField itself and if is
|
|
not an appropriate pvData structure but the field name is value it looks
|
|
to see if the parent structure has an appropriate sub structure.</dd>
|
|
<dt>detach</dt>
|
|
<dd>Just detaches from the pvData structure.</dd>
|
|
<dt>isAttached</dt>
|
|
<dd>Is there an attachment to a control structure?</dd>
|
|
<dt>get</dt>
|
|
<dd>Copies data from the pvData structure to a Control. An exception is
|
|
thrown if not attached to a pvData structure. </dd>
|
|
<dt>set</dt>
|
|
<dd>Copies data from Control to the pvData structure. An exception is
|
|
thrown if not attached to a pvData structure. </dd>
|
|
</dl>
|
|
|
|
<h3>display</h3>
|
|
|
|
<p>Display information is represented by the following structure</p>
|
|
<pre>structure display
|
|
double limitLow
|
|
double limitHigh
|
|
string description
|
|
string format
|
|
string units</pre>
|
|
|
|
<p>Two header files are provided for manipulating display:</p>
|
|
<dl>
|
|
<dt>display.h</dt>
|
|
<dd>Defines display independent of pvData, i.e. it is a generally useful
|
|
class for manipulating display.</dd>
|
|
<dt>pvDisplay.h</dt>
|
|
<dd>A class that can be attached to an display pvData structure. It
|
|
provides get and set methods to get/set display data as defined by
|
|
display.h</dd>
|
|
</dl>
|
|
|
|
<h4>display.h</h4>
|
|
<pre>class Display {
|
|
public:
|
|
Display();
|
|
//default constructors and destructor are OK
|
|
double getLow() const;
|
|
double getHigh() const;
|
|
void setLow(double value);
|
|
void setHigh(double value);
|
|
String getDescription() const;
|
|
void setDescription(String const &value);
|
|
String getFormat() const;
|
|
void setFormat(String const &value);
|
|
String getUnits() const;
|
|
void setUnits(String const &value);
|
|
};</pre>
|
|
|
|
<p>where</p>
|
|
<dl>
|
|
<dt>Control</dt>
|
|
<dd>The default constructure.</dd>
|
|
<dt>getLow</dt>
|
|
<dd>Get the low limit.</dd>
|
|
<dt>getHigh</dt>
|
|
<dd>Get the high limit.</dd>
|
|
<dt>setLow</dt>
|
|
<dd>Set the low limit.</dd>
|
|
<dt>setHigh</dt>
|
|
<dd>Set the high limit.</dd>
|
|
<dt>getDescription</dt>
|
|
<dd>Get the description.</dd>
|
|
<dt>setDescription</dt>
|
|
<dd>Set the description.</dd>
|
|
<dt>getFormat</dt>
|
|
<dd>Get the format.</dd>
|
|
<dt>setFormat</dt>
|
|
<dd>Set the format.</dd>
|
|
<dt>getUnits</dt>
|
|
<dd>Get the units.</dd>
|
|
<dt>setUnits</dt>
|
|
<dd>Set the units.</dd>
|
|
</dl>
|
|
|
|
<h4>pvDisplay.h</h4>
|
|
<pre>class PVDisplay {
|
|
public:
|
|
PVDisplay()
|
|
: pvDescription(0),pvFormat(),pvUnits(),pvLow(),pvHigh() {}
|
|
//default constructors and destructor are OK
|
|
//An automatic detach is issued if already attached.
|
|
bool attach(PVFieldPtr const&pvField);
|
|
void detach();
|
|
bool isAttached();
|
|
// each of the following throws logic_error is not attached to PVField
|
|
// a set returns false if field is immutable
|
|
void get(Display &) const;
|
|
bool set(Display const & display);
|
|
};</pre>
|
|
|
|
<p>where</p>
|
|
<dl>
|
|
<dt>PVDisplay</dt>
|
|
<dd>The default constructor. Attach must be called before get or set can be
|
|
called.</dd>
|
|
<dt>attach</dt>
|
|
<dd>Attempts to attach to pvField It returns (false,true) if it found an
|
|
appropriate pvData structure. It looks first a pvField itself and if is
|
|
not an appropriate pvData structure but the field name is value it looks
|
|
to see if the parent structure has an appropriate sub structure.</dd>
|
|
<dt>detach</dt>
|
|
<dd>Just detaches from the pvData structure.</dd>
|
|
<dt>isAttached</dt>
|
|
<dd>Is there an attachment to a display structure?</dd>
|
|
<dt>get</dt>
|
|
<dd>Copies data from the pvData structure to a Display. An exception is
|
|
thrown if not attached to a pvData structure.</dd>
|
|
<dt>set</dt>
|
|
<dd>Copies data from Display to the pvData structure. An exception is
|
|
thrown if not attached to a pvData structure. </dd>
|
|
</dl>
|
|
|
|
<h3>pvEnumerated.h</h3>
|
|
|
|
<p>An enumerated structure is a structure that has fields:</p>
|
|
<pre>structure
|
|
int index
|
|
string[] choices</pre>
|
|
|
|
<p>For enumerated structures a single header file pvEnumerted.h is available</p>
|
|
<pre>class PVEnumerated {
|
|
public:
|
|
PVEnumerated();
|
|
//default constructors and destructor are OK
|
|
//This class should not be extended
|
|
//returns (false,true) if pvField(isNot, is valid enumerated structure
|
|
//An automatic detach is issued if already attached.
|
|
bool attach(PVFieldPtr const &pvField);
|
|
void detach();
|
|
bool isAttached();
|
|
// each of the following throws logic_error is not attached to PVField
|
|
// a set returns false if field is immutable
|
|
bool setIndex(int32 index);
|
|
int32 getIndex();
|
|
String getChoice();
|
|
bool choicesMutable();
|
|
StringArrayPtr const & getChoices();
|
|
int32 getNumberChoices();
|
|
bool setChoices(StringArray &choices,int32 numberChoices);
|
|
};</pre>
|
|
|
|
<p>where</p>
|
|
<dl>
|
|
<dt>PVEnumerated</dt>
|
|
<dd>The default constructor. Attach must be called before any get or set
|
|
method can be called.</dd>
|
|
<dt>attach</dt>
|
|
<dd>Attempts to attach to pvField It returns (false,true) if pvField (is
|
|
not, is) an enumerated structure.</dd>
|
|
<dt>detach</dt>
|
|
<dd>Just detaches from the pvData structure.</dd>
|
|
<dt>isAttached</dt>
|
|
<dd>Is there an attachment to an enemerated structure?</dd>
|
|
<dt>setIndex</dt>
|
|
<dd>Set the index field in the pvData structure. An exception is thrown if
|
|
not attached to a pvData structure. </dd>
|
|
<dt>getIndex</dt>
|
|
<dd>Get the index field in the pvData structure. </dd>
|
|
<dt>getChoice</dt>
|
|
<dd>Get the String value corresponding to the current index field in the
|
|
pvData structure. An exception is thrown if not attached to a pvData
|
|
structure. </dd>
|
|
<dt>choicesMutable</dt>
|
|
<dd>Can the choices be changed? Note that this is often true. An exception
|
|
is thrown if not attached to a pvData structure. </dd>
|
|
<dt>getChoices</dt>
|
|
<dd>Get the array of choices. An exception is thrown if not attached to a
|
|
pvData structure. </dd>
|
|
<dt>getNumberChoices</dt>
|
|
<dd>Get the number of choices. An exception is thrown if not attached to a
|
|
pvData structure. </dd>
|
|
<dt>setChoices</dt>
|
|
<dd>Change the choices. An exception is thrown if not attached to a pvData
|
|
structure. </dd>
|
|
</dl>
|
|
|
|
|
|
<h2>pvDataApp/factory</h2>
|
|
|
|
<p>Directory factory has code that implements everything described by the files
|
|
in directory pv</p>
|
|
|
|
<p>TypeFunc.cpp implements the functions for the enums defined in
|
|
pvIntrospecct.h</p>
|
|
|
|
<p>FieldCreateFactory.cpp automatically creates a single instance of
|
|
FieldCreate and implements getFieldCreate.</p>
|
|
|
|
<p>PVDataCreateFactory.cpp automatically creates a single instance of
|
|
PVDataCreate and implements getPVDataCreate.</p>
|
|
|
|
|
|
<p>Convert.cpp automatically creates a single instance of Convert and
|
|
implements getConvert.</p>
|
|
|
|
<p>Other files implement PVData base classes</p>
|
|
|
|
<h2>pvDataAPP/misc</h2>
|
|
|
|
<h3>Overview</h3>
|
|
|
|
<p>This package provides utility code:</p>
|
|
<dl>
|
|
<dt>bitSet.h</dt>
|
|
<dd>An implementation of BitSet that can be serialized.</dd>
|
|
<dt>byteBuffer.h</dt>
|
|
<dd>Used to serialize objects.</dd>
|
|
<dt>destroyable.h</dt>
|
|
<dd>Provides method destroy.</dd>
|
|
<dt>epicsException.h</dt>
|
|
<dd>Exception with stack trace.</dd>
|
|
<dt>event.h</dt>
|
|
<dd>Signal and wait for an event.</dd>
|
|
<dt>executor.h</dt>
|
|
<dd>Provides a thread for executing commands.</dd>
|
|
<dt>localStaticLock.h</dt>
|
|
<dd><b>TBD</b> Matej can You explain what this does?</dd>
|
|
<dt>lock.h</dt>
|
|
<dd>Support for locking and unlocking.</dd>
|
|
<dt>messageQueue.h</dt>
|
|
<dd>Support for queuing messages to give to requesters.</dd>
|
|
<dt>noDefaultMethods.h</dt>
|
|
<dd>When privately extended prevents compiler from implementing default
|
|
methods.</dd>
|
|
<dt>queue.h</dt>
|
|
<dd>A queue implementation that allows the latest queue element to continue
|
|
to be used when no free element is available.</dd>
|
|
<dt>requester.h</dt>
|
|
<dd>Allows messages to be sent to a requester.</dd>
|
|
<dt>serialize.h</dt>
|
|
<dd>Support for serializing objects.</dd>
|
|
<dt>serializeHelper.h</dt>
|
|
<dd>More support for serializing objects.</dd>
|
|
<dt>sharedPtr.h</dt>
|
|
<dd>Defines POINTER_DEFINITIONS.</dd>
|
|
<dt>sharedVector.h</dd>
|
|
<dd>Like std::vector except that std::shared_ptr is used for
|
|
the data array.</dd>
|
|
<dt>status.h</dt>
|
|
<dd>A way to pass status information to a client.</dd>
|
|
<dt>templateMeta.h</dt>
|
|
<dd><b>TBD</b> Michael can You provide an explaination?</dd>
|
|
<dt>thread.h</dt>
|
|
<dd>Provides thread support.</dd>
|
|
<dt>timeFunction.h</dt>
|
|
<dd>Time how long a function call requires.</dd>
|
|
<dt>timer.h</dt>
|
|
<dd>An implementation of Timer that does not require an object to be
|
|
created for each timer request.</dd>
|
|
<dt>typeCast.h</dt>
|
|
<dd><b>TBD</b> Michael can You provide an explaination?</dd>
|
|
</dl>
|
|
|
|
<p>Note that directory testApp/misc has test code for all the classes in misc.
|
|
The test code also can be used as examples.</p>
|
|
|
|
<h3>bitSet.h</h3>
|
|
|
|
<p>This is adapted from the java.util.BitSet. bitSet.h is:</p>
|
|
<pre>
|
|
class BitSet;
|
|
typedef std::tr1::shared_ptr<BitSet> BitSetPtr;
|
|
|
|
class BitSet : public Serializable {
|
|
public:
|
|
static BitSetPtr create(uint32 nbits);
|
|
BitSet();
|
|
BitSet(uint32 nbits);
|
|
virtual ~BitSet();
|
|
void flip(uint32 bitIndex);
|
|
void set(uint32 bitIndex);
|
|
void clear(uint32 bitIndex);
|
|
void set(uint32 bitIndex, bool value);
|
|
bool get(uint32 bitIndex) const;
|
|
void clear();
|
|
int32 nextSetBit(uint32 fromIndex) const;
|
|
int32 nextClearBit(uint32 fromIndex) const;
|
|
bool isEmpty() const;
|
|
uint32 cardinality() const;
|
|
uint32 size() const;
|
|
BitSet& operator&=(const BitSet& set);
|
|
BitSet& operator|=(const BitSet& set);
|
|
BitSet& operator^=(const BitSet& set);
|
|
BitSet& operator-=(const BitSet& set);
|
|
BitSet& operator=(const BitSet &set);
|
|
void or_and(const BitSet& set1, const BitSet& set2);
|
|
bool operator==(const BitSet &set) const;
|
|
bool operator!=(const BitSet &set) const;
|
|
void toString(StringBuilder buffer, int indentLevel = 0) const;
|
|
virtual void serialize(
|
|
ByteBuffer *buffer,SerializableControl *flusher) const;
|
|
virtual void deserialize(
|
|
ByteBuffer *buffer,DeserializableControl *flusher);
|
|
|
|
private:
|
|
};</pre>
|
|
|
|
<p>where</p>
|
|
<dl>
|
|
<dt>BitSet()</dt>
|
|
<dd>Creates a bitSet of initial size 64 bits. All bits initially false.</dd>
|
|
<dt>BitSet(uint32 nbits)</dt>
|
|
<dd>Creates a bitSet with the initial of the specified number of bits. All
|
|
bits initially false.</dd>
|
|
<dt>~BitSet()</dt>
|
|
<dd>Destructor.</dd>
|
|
<dt>flip(uint32 bitIndex)</dt>
|
|
<dd>Flip the specified bit.</dd>
|
|
<dt>set(uint32 bitIndex)</dt>
|
|
<dd>Set the specified bit true.</dd>
|
|
<dt>clear(uint32 bitIndex)</dt>
|
|
<dd>Set the specified bit false.</dd>
|
|
<dt>set(uint32 bitIndex, bool value)</dt>
|
|
<dd>Set the specified bit to value.</dd>
|
|
<dt>get(uint32 bitIndex)</dt>
|
|
<dd>Return the state of the specified bit.</dd>
|
|
<dt>clear()</dt>
|
|
<dd>Set all bits to false.</dd>
|
|
<dt>nextSetBit(uint32 fromIndex)</dt>
|
|
<dd>Get the index of the next true bit beginning with the specified
|
|
bit.</dd>
|
|
<dt>nextClearBit(uint32 fromIndex)</dt>
|
|
<dd>Get the index of the next false bit beginning with the specified
|
|
bit.</dd>
|
|
<dt>isEmpty()</dt>
|
|
<dd>Return (false,true) if (at least one bit true, all bits are false)</dd>
|
|
<dt>cardinality()</dt>
|
|
<dd>Return the number of true bits.</dd>
|
|
<dt>size()</dt>
|
|
<dd>Returns the number of bits of space actually in use.</dd>
|
|
<dt>operator&=(const BitSet& set)</dt>
|
|
<dd>Performs a logical and of this target bit set with the argument bit
|
|
set. This bit set is modified so that each bit in it has the value true
|
|
if and only if it both initially had the value true and the corresponding
|
|
bit in the bit set argument also had the value.</dd>
|
|
<dt>operator|=(const BitSet& set)</dt>
|
|
<dd>Performs a logical or of this target bit set with the argument bit
|
|
set.</dd>
|
|
<dt>operator^=(const BitSet& set)</dt>
|
|
<dd>Performs a logical exclusive or of this target bit set with the
|
|
argument bit set.</dd>
|
|
<dt>operator-=(const BitSet& set)</dt>
|
|
<dd><p>Clears all of the bits in this bitSet whose corresponding bit is set
|
|
in the specified bitSet.</p>
|
|
</dd>
|
|
<dt>operator=(const BitSet &set)</dt>
|
|
<dd>Assignment operator.</dd>
|
|
<dt>or_and(const BitSet& set1, const BitSet& set2)</dt>
|
|
<dd>Perform AND operation on set1 and set2, and then OR this bitSet with
|
|
the result.</dd>
|
|
<dt>operator==(const BitSet &set)</dt>
|
|
<dd>Does this bitSet have the same values as the argument.</dd>
|
|
<dt>operator!=(const BitSet &set)</dt>
|
|
<dd>Is this bitSet different than the argument.</dd>
|
|
<dt>toString(StringBuilder buffer, int indentLevel)</dt>
|
|
<dd>Show the current values of the bitSet.</dd>
|
|
<dt>virtual void serialize(ByteBuffer *buffer,SerializableControl *flusher)
|
|
const;</dt>
|
|
<dd>Serialize the bitSet</dd>
|
|
<dt>virtual void deserialize(ByteBuffer *buffer,DeserializableControl
|
|
*flusher);</dt>
|
|
<dd>Deserialize the bitSet.</dd>
|
|
</dl>
|
|
<p><b>TBD</b>
|
|
<dl>
|
|
<dt>toString</dt>
|
|
<dd>Should this change and also implement ostream operator?</dd>
|
|
</dl>
|
|
</p>
|
|
|
|
<h3>byteBuffer.h</h3>
|
|
|
|
<p>A ByteBuffer is used to serialize and deserialize primitive data. File
|
|
byteBuffer.h is:</p>
|
|
<pre>class ByteBuffer {
|
|
public:
|
|
ByteBuffer(std::size_t size, int byteOrder = EPICS_BYTE_ORDER)
|
|
~ByteBuffer();
|
|
void setEndianess(int byteOrder);
|
|
const char* getBuffer();
|
|
void clear();
|
|
void flip();
|
|
void rewind();
|
|
std::size_t getPosition();
|
|
void setPosition(std::size_t pos);
|
|
std::size_t getLimit();
|
|
void setLimit(std::size_t limit);
|
|
std::size_t getRemaining();
|
|
std::size_t getSize();
|
|
template<typename T>
|
|
void put(T value)
|
|
template<typename T>
|
|
void put(std::size_t index, T value);
|
|
template<typename T>
|
|
T get()
|
|
template<typename T>
|
|
T get(std::size_t index)
|
|
void put(const char* src, std::size_t src_offset, std::size_t count);
|
|
void get(char* dest, std::size_t dest_offset, std::size_t count);
|
|
template<typename T>
|
|
inline void putArray(T* values, std::size_t count)
|
|
template<typename T>
|
|
inline void getArray(T* values, std::size_t count)
|
|
template<typename T>
|
|
inline bool reverse();
|
|
inline void align(std::size_t size)
|
|
void putBoolean( bool value);
|
|
void putByte ( int8 value);
|
|
void putShort ( int16 value);
|
|
void putInt ( int32 value);
|
|
void putLong ( int64 value);
|
|
void putFloat ( float value);
|
|
void putDouble (double value);
|
|
void putBoolean(std::size_t index, bool value);
|
|
void putByte (std::size_t index, int8 value);
|
|
void putShort (std::size_t index, int16 value);
|
|
void putInt (std::size_t index, int32 value);
|
|
void putFloat (std::size_t index, float value);
|
|
void putDouble (std::size_t index, double value);
|
|
bool getBoolean();
|
|
int8 getByte ();
|
|
int16 getShort ();
|
|
int32 getInt ();
|
|
int64 getLong ();
|
|
float getFloat ();
|
|
double getDouble ();
|
|
bool getBoolean(std::size_t index);
|
|
int8 getByte (std::size_t index);
|
|
int16 getShort (std::size_t index);
|
|
int32 getInt (std::size_t index);
|
|
int64 getLong (std::size_t index);
|
|
float getFloat (std::size_t index);
|
|
double getDouble (std::size_t index);
|
|
const char* getArray();
|
|
...
|
|
};</pre>
|
|
|
|
<h3>destroyable.h</h3>
|
|
<pre>class Destroyable {
|
|
public:
|
|
POINTER_DEFINITIONS(Destroyable);
|
|
virtual void destroy() = 0;
|
|
virtual ~Destroyable() {};
|
|
};</pre>
|
|
|
|
<h3>epicsException.h</h3>
|
|
<pre>/*
|
|
* Throwing exceptions w/ file+line# and, when possibly, a stack trace
|
|
*
|
|
* THROW_EXCEPTION1( std::bad_alloc );
|
|
*
|
|
* THROW_EXCEPTION2( std::logic_error, "my message" );
|
|
*
|
|
* THROW_EXCEPTION( mySpecialException("my message", 42, "hello", ...) );
|
|
*
|
|
* Catching exceptions
|
|
*
|
|
* catch(std::logic_error& e) {
|
|
* fprintf(stderr, "%s happened\n", e.what());
|
|
* PRINT_EXCEPTION2(e, stderr);
|
|
* cout<<SHOW_EXCEPTION(e);
|
|
* }
|
|
*
|
|
* If the exception was not thrown with the above THROW_EXCEPTION*
|
|
* the nothing will be printed.
|
|
*/</pre>
|
|
|
|
<h3>event.h</h3>
|
|
|
|
<p>This class provides coordinates activity between threads. One thread can
|
|
wait for the event and the other signals the event.</p>
|
|
<pre>class Event;
|
|
typedef std::tr1::shared_ptr<Event> EventPtr;
|
|
|
|
class Event {
|
|
public:
|
|
POINTER_DEFINITIONS(Event);
|
|
explicit Event(bool = false);
|
|
~Event();
|
|
void signal();
|
|
bool wait (); /* blocks until full */
|
|
bool wait ( double timeOut ); /* false if empty at time out */
|
|
bool tryWait (); /* false if empty */
|
|
...
|
|
}; </pre>
|
|
|
|
<p>where</p>
|
|
<dl>
|
|
<dt>Event</dt>
|
|
<dd>The constructor. The initial value can be full or empty. The normal
|
|
first state is empty.</dd>
|
|
<dt>signal</dt>
|
|
<dd>The event becomes full. The current or next wait will complete.</dd>
|
|
<dt>wait</dt>
|
|
<dd>Wait until event is full or until timeout. The return value is
|
|
(false,true) if the wait completed because event (was not, was) full. A
|
|
false value normally means that that a timeout occured. It is also
|
|
returned if an error occurs or because the event is being deleted.</dd>
|
|
<dt>tryWait</dt>
|
|
<dd>returns (false,true) if the event is (empty,full)</dd>
|
|
</dl>
|
|
|
|
<h3>executor.h</h3>
|
|
|
|
<p>An Executor is a thread that can execute commands. The user can request that
|
|
a single command be executed.</p>
|
|
<pre>
|
|
class Command;
|
|
class Executor;
|
|
typedef std::tr1::shared_ptr<Command> CommandPtr;
|
|
typedef std::tr1::shared_ptr<Executor> ExecutorPtr;
|
|
|
|
class Command {
|
|
public:
|
|
POINTER_DEFINITIONS(Command);
|
|
virtual ~Command(){}
|
|
virtual void command() = 0;
|
|
private:
|
|
CommandPtr next;
|
|
friend class Executor;
|
|
};
|
|
|
|
class Executor : public Runnable{
|
|
public:
|
|
POINTER_DEFINITIONS(Executor);
|
|
Executor(String threadName,ThreadPriority priority);
|
|
~Executor();
|
|
void execute(CommandPtr const &node);
|
|
virtual void run();
|
|
...
|
|
};</pre>
|
|
|
|
<p>Command is a class that must be implemented by the code that calls execute.
|
|
It contains the single virtual method command, which is the command to
|
|
execute.</p>
|
|
|
|
<p>Executor has the methods:</p>
|
|
<dl>
|
|
<dt>Executor</dt>
|
|
<dd>The constructor. A thread name and priority must be specified.</dd>
|
|
<dt>~Executor</dt>
|
|
<dd>The destructor. If any commands remain in the execute list they are not
|
|
called. All ExecutorNodes that have been created are deleted.</dd>
|
|
<dt>execute</dt>
|
|
<dd>Request that command be executed. If it is already on the run list
|
|
nothing is done.</dd>
|
|
</dl>
|
|
|
|
<h3>localStaticLock.h</h3>
|
|
<pre>
|
|
extern epics::pvData::Mutex& getLocalStaticInitMutex();
|
|
|
|
static class MutexInitializer {
|
|
public:
|
|
MutexInitializer ();
|
|
~MutexInitializer ();
|
|
} localStaticMutexInitializer; // Note object here in the header.
|
|
</pre>
|
|
<p><b>TBD</b> Matej will explain. </p>
|
|
|
|
<h3>lock.h</h3>
|
|
<pre>
|
|
typedef epicsMutex Mutex;
|
|
|
|
class Lock : private NoDefaultMethods {
|
|
public:
|
|
explicit Lock(Mutex &pm);
|
|
~Lock();
|
|
void lock();
|
|
void unlock();
|
|
bool tryLock();
|
|
bool ownsLock() ;
|
|
...
|
|
};</pre>
|
|
|
|
<p>Lock is as easy to use as Java synchronize. To protect some object just
|
|
create a Mutex for the object and then in any method to be synchronized just
|
|
have code like:</p>
|
|
<pre>class SomeClass {
|
|
private
|
|
Mutex mutex;
|
|
...
|
|
public
|
|
SomeClass() : mutex(Mutex()) {}
|
|
...
|
|
void method()
|
|
{
|
|
Lock xx(mutex);
|
|
...
|
|
}
|
|
</pre>
|
|
|
|
<p>The method will take the lock when xx is created and release the lock when
|
|
the current code block completes.</p>
|
|
|
|
<p>Another example of Lock is initialization code that must initialize only
|
|
once. This can be implemented as follows:</p>
|
|
<pre> static void init(void) {
|
|
static Mutex mutex;
|
|
Lock guard(mutex);
|
|
if(alreadyInitialized) return;
|
|
// initialization
|
|
}</pre>
|
|
<p>
|
|
<p>Lock has a private variable:
|
|
<pre>
|
|
bool locked;
|
|
</pre>
|
|
and improves efficency by checking the local variable before calling the
|
|
mutex methods. This is <b>not</b> thread safe if any methods are called by a thread other than
|
|
the thread that created the Lock.
|
|
</p>
|
|
<p>It is thread safe if used as follows:</p>
|
|
<pre>
|
|
{
|
|
Lock guard(mutex);
|
|
...
|
|
/* the following can optionally be called
|
|
guard.unlock();
|
|
guard.lock();
|
|
*/
|
|
}
|
|
</pre>
|
|
<p>It is <b>not</b> thread safe if used as follows:</p>
|
|
<pre>
|
|
class SomeClass
|
|
{
|
|
private:
|
|
Mutex mutex;
|
|
Lock lock;
|
|
public:
|
|
SomeClass: lock(mutex) {}
|
|
...
|
|
void someMethod() {
|
|
lock.unlock();
|
|
...
|
|
}
|
|
...
|
|
};
|
|
</pre>
|
|
<p>It is only safe if all methods of Lock, including <b>~Lock()</b>,
|
|
are called by the same thread.
|
|
</p>
|
|
|
|
<h3>messageQueue.h</h3>
|
|
|
|
<h4>Definitions</h4>
|
|
|
|
<p>A messageQueue is for use by code that wants to handle messages without
|
|
blocking higher priority threads.</p>
|
|
<pre>class MessageNode;
|
|
class MessageQueue;
|
|
typedef std::tr1::shared_ptr<MessageNode> MessageNodePtr;
|
|
typedef std::vector<MessageNodePtr> MessageNodePtrArray;
|
|
typedef std::tr1::shared_ptr<MessageQueue> MessageQueuePtr;
|
|
|
|
class MessageNode {
|
|
public:
|
|
String getMessage() const;
|
|
MessageType getMessageType() const;
|
|
void setMessageNull();
|
|
};
|
|
|
|
class MessageQueue : public Queue<MessageNode> {
|
|
public:
|
|
POINTER_DEFINITIONS(MessageQueue);
|
|
static MessageQueuePtr create(int size);
|
|
MessageQueue(MessageNodePtrArray &nodeArray);
|
|
virtual ~MessageQueue();
|
|
MessageNodePtr &get();
|
|
// must call release before next get
|
|
void release();
|
|
// return (false,true) if message (was not, was) put into queue
|
|
bool put(String message,MessageType messageType,bool replaceLast);
|
|
bool isEmpty() ;
|
|
bool isFull() ;
|
|
int getClearOverrun();
|
|
...
|
|
};</pre>
|
|
|
|
<p>A messageNode is a class with two public data members:</p>
|
|
<dl>
|
|
<dt>getMessage</dt>
|
|
<dd>The message.</dd>
|
|
<dt>getMessageType</dt>
|
|
<dd>The message type.</dd>
|
|
<dt>setMessageNull</dt>
|
|
<dd>Set the message to be a null string.</dd>
|
|
</dl>
|
|
|
|
<p>A messageQueue is an interface with public methods:</p>
|
|
<dl>
|
|
<dt>MessageQueue</dt>
|
|
<dd>The constructor. The queue size must be specified.</dd>
|
|
<dt>~MessageQueue</dt>
|
|
<dd>The destructor.</dd>
|
|
<dt>put</dt>
|
|
<dd>Put a new message into the queue. False is returned if the queue was
|
|
full and true otherwise. If replaceLast is true then the last message is
|
|
replaced with this message. </dd>
|
|
<dt>get</dt>
|
|
<dd>Get the oldest queue element. If the queue is empty null is returned.
|
|
Before the next get can be issued release must be called.</dd>
|
|
<dt>release</dt>
|
|
<dd>Release the queue element returned by the last get.</dd>
|
|
<dt>isEmpty</dt>
|
|
<dd>Is the queue empty?</dd>
|
|
<dt>isFull</dt>
|
|
<dd>Is the queue full?</dd>
|
|
<dt>getClearOverrun</dt>
|
|
<dd>Get the number of times put has been called but no free element is
|
|
available.</dd>
|
|
</dl>
|
|
|
|
<p>Look at miscTest/testMessageQueue.cpp for an example.</p>
|
|
|
|
<h3>noDefaultMethods.h</h3>
|
|
|
|
<p>If a class privately extends this class then the compiler can not create any
|
|
of the following: default constructor, default copy constructror, or default
|
|
assignment contructor.</p>
|
|
<pre>/* This is based on Item 6 of
|
|
* Effective C++, Third Edition, Scott Meyers
|
|
*/
|
|
class NoDefaultMethods {
|
|
protected:
|
|
// allow by derived objects
|
|
NoDefaultMethods(){};
|
|
~NoDefaultMethods(){}
|
|
private:
|
|
// do not implment
|
|
NoDefaultMethods(const NoDefaultMethods&);
|
|
NoDefaultMethods & operator=(const NoDefaultMethods &);
|
|
};</pre>
|
|
|
|
<h3>queue.h</h3>
|
|
|
|
<p>This provides a bounded queue. When the queue is
|
|
full the user code is expected to keep using the current element until a new
|
|
free element becomes avalable.</p>
|
|
<pre>
|
|
template <typename T>
|
|
class Queue
|
|
{
|
|
public:
|
|
POINTER_DEFINITIONS(Queue);
|
|
typedef std::tr1::shared_ptr<T> queueElementPtr;
|
|
typedef std::vector<queueElementPtr> queueElementPtrArray;
|
|
Queue(queueElementPtrArray &);
|
|
virtual ~Queue();
|
|
void clear();
|
|
int capacity();
|
|
int getNumberFree();
|
|
int getNumberUsed();
|
|
queueElementPtr & getFree();
|
|
void setUsed(queueElementPtr const &element);
|
|
queueElementPtr & getUsed();
|
|
void releaseUsed(queueElementPtr const &element);
|
|
...
|
|
};</pre>
|
|
|
|
<p>testApp/misc/testQueue.cpp provides an example of how to define a queue.</p>
|
|
|
|
<p>The queue methods are:</p>
|
|
<dl>
|
|
<dt>clear</dt>
|
|
<dd>Make the queue empty.</dd>
|
|
<dt>getNumberFree</dt>
|
|
<dd>Get the number of free elements in the queue.</dd>
|
|
<dt>capacity</dt>
|
|
<dd>Get the capacity, i.e. the maximun number of elements the queue can
|
|
hold.</dd>
|
|
<dt>getNumberFree</dt>
|
|
<dd>Get the number of free elements.</dd>
|
|
<dt>getNumberUsed</dt>
|
|
<dd>Get the number of elements used.</dd>
|
|
<dt>getFree</dt>
|
|
<dd>Get the next free element. Null is returned if no free elements are
|
|
available. If a non null value is returned then the element belongs to
|
|
the caller until setUsed is called.</dd>
|
|
<dt>setUsed</dt>
|
|
<dd>Set a queue element used. This must be the element returned by the last
|
|
call to getFree. </dd>
|
|
<dt>getUsed</dt>
|
|
<dd>Get the next used element of null if no more used elements are
|
|
available.</dd>
|
|
<dt>releaseUsed</dt>
|
|
<dd>Set a queue element free. This must be the element returned by the last
|
|
call to getUsed. </dd>
|
|
</dl>
|
|
|
|
<p>A queue is created as follows:</p>
|
|
<pre> class MyClass;
|
|
typedef MyQueueElement<MyClass> MyElement;
|
|
typedef MyQueue<MyClass> MyQueue;
|
|
int numElement = 5;
|
|
...
|
|
MyClass *array[numElements];
|
|
for(int i=0; i<numElements; i++) {
|
|
array[i] = new MyClass();
|
|
}
|
|
MyQueue *queue = new MyQueue(array,numElements);</pre>
|
|
|
|
<p>A producer calls getFree and setUsed via code like the following:</p>
|
|
<pre> MyClass *getFree() {
|
|
MyElement *element = queue->getFree();
|
|
if(element==0) return 0;
|
|
return element->getObject();
|
|
}</pre>
|
|
|
|
<p>A consumer calls getUsed and releaseUsed via code like the following:</p>
|
|
<pre> while(true) {
|
|
MyElement *element = queue->getUsed();
|
|
if(element==0) break;
|
|
MyClass *myClass = element->getObject();
|
|
// do something with myClass
|
|
queue->releaseUsed(element);
|
|
}</pre>
|
|
|
|
<h3>requester.h</h3>
|
|
|
|
<p>Requester is present so that when
|
|
errors are found there is someplace to send a message.
|
|
At one time PVField extended Requester but it no longer does.
|
|
Requester is, however, used by pvAccess.
|
|
</p>
|
|
<pre>
|
|
class Requester;
|
|
typedef std::tr1::shared_ptr<Requester> RequesterPtr;
|
|
|
|
enum MessageType {
|
|
infoMessage,warningMessage,errorMessage,fatalErrorMessage
|
|
};
|
|
|
|
extern String getMessageTypeName(MessageType messageType);
|
|
extern const size_t messageTypeCount;
|
|
class Requester {
|
|
public:
|
|
POINTER_DEFINITIONS(Requester);
|
|
virtual ~Requester(){}
|
|
virtual String getRequesterName() = 0;
|
|
virtual void message(String const & message,MessageType messageType) = 0;
|
|
};</pre>
|
|
|
|
<p>where</p>
|
|
<dl>
|
|
<dt></dt>
|
|
<dt>MessageType</dt>
|
|
<dd>Type of message.</dd>
|
|
<dt>messageTypeName</dt>
|
|
<dd>An array of strings of the message type names, i.e.
|
|
String("info"),String("warning"),String("error"),String("fatalError").</dd>
|
|
<dt>getRequesterName</dt>
|
|
<dd>Returns the requester name.</dd>
|
|
<dt>message</dt>
|
|
<dd>Gives a message to the requester.</dd>
|
|
</dl>
|
|
|
|
<h3>serialize.h</h3>
|
|
<pre>
|
|
class SerializableControl;
|
|
class DeserializableControl;
|
|
class Serializable;
|
|
class BitSetSerializable;
|
|
class SerializableArray;
|
|
class BitSet;
|
|
class Field;
|
|
|
|
class SerializableControl {
|
|
public:
|
|
virtual ~SerializableControl(){}
|
|
virtual void flushSerializeBuffer() =0;
|
|
virtual void ensureBuffer(std::size_t size) =0;
|
|
virtual void alignBuffer(std::size_t alignment) =0;
|
|
virtual void cachedSerialize(
|
|
std::tr1::shared_ptr<const Field> const & field,
|
|
ByteBuffer* buffer) = 0;
|
|
};
|
|
|
|
class DeserializableControl {
|
|
public:
|
|
virtual ~DeserializableControl(){}
|
|
virtual void ensureData(std::size_t size) =0;
|
|
virtual void alignData(std::size_t alignment) =0;
|
|
virtual std::tr1::shared_ptr<const Field> cachedDeserialize(
|
|
ByteBuffer* buffer) = 0;
|
|
};
|
|
|
|
class Serializable {
|
|
public:
|
|
virtual ~Serializable(){}
|
|
virtual void serialize(ByteBuffer *buffer,
|
|
SerializableControl *flusher) const = 0;
|
|
virtual void deserialize(ByteBuffer *buffer,
|
|
DeserializableControl *flusher) = 0;
|
|
};
|
|
|
|
class BitSetSerializable {
|
|
public:
|
|
virtual ~BitSetSerializable(){}
|
|
virtual void serialize(ByteBuffer *buffer,
|
|
SerializableControl *flusher,BitSet *bitSet) const = 0;
|
|
virtual void deserialize(ByteBuffer *buffer,
|
|
DeserializableControl *flusher,BitSet *bitSet) = 0;
|
|
};
|
|
|
|
|
|
class SerializableArray : virtual public Serializable {
|
|
public:
|
|
virtual ~SerializableArray(){}
|
|
virtual void serialize(ByteBuffer *buffer,
|
|
SerializableControl *flusher, std::size_t offset,
|
|
std::size_t count) const = 0;
|
|
};</pre>
|
|
|
|
<h3>serializeHelper.h</h3>
|
|
|
|
<p>This is a helper class for serialization, which is required for sending and
|
|
receiving pvData over the nerwork.</p>
|
|
<pre>class SerializeHelper : public NoDefaultMethods {
|
|
public:
|
|
static void writeSize(int s, ByteBuffer* buffer,
|
|
SerializableControl* flusher);
|
|
static int readSize(ByteBuffer* buffer,
|
|
DeserializableControl* control);
|
|
static void serializeString(const String& value,
|
|
ByteBuffer* buffer,SerializableControl* flusher);
|
|
static void serializeSubstring(const String& value, int offset,
|
|
int count, ByteBuffer* buffer,
|
|
SerializableControl* flusher);
|
|
static String deserializeString(ByteBuffer* buffer,
|
|
DeserializableControl* control);
|
|
...
|
|
};</pre>
|
|
|
|
<p>where</p>
|
|
<dl>
|
|
<dt>writeSize</dt>
|
|
<dd>Serialize the size.</dd>
|
|
<dt>readSize</dt>
|
|
<dd>Deserialize the size.</dd>
|
|
<dt>serializeString</dt>
|
|
<dd>Serialize a String.</dd>
|
|
<dt>serializeSubstring</dt>
|
|
<dd>Serialize a substring.</dd>
|
|
<dt>deserializeString</dt>
|
|
<dd>Deserialize a string.</dd>
|
|
</dl>
|
|
|
|
<h3>sharedPtr.h</h3>
|
|
<pre>
|
|
#define POINTER_DEFINITIONS(clazz) \
|
|
typedef std::tr1::shared_ptr<clazz> shared_pointer; \
|
|
typedef std::tr1::shared_ptr<const clazz> const_shared_pointer; \
|
|
typedef std::tr1::weak_ptr<clazz> weak_pointer; \
|
|
typedef std::tr1::weak_ptr<const clazz> const_weak_pointer;</pre>
|
|
|
|
<h3>sharedVector.h</h3>
|
|
<p>
|
|
shared_vector is a holder for a contigious piece of memory.
|
|
Data is shared, but offset and length are not.
|
|
This allows one vector to have access to only a subset of a piece of memory.
|
|
</p>
|
|
<p>
|
|
shared_vector differs from std::vector as follows:</p>
|
|
<dl>
|
|
<dt>Differences in behavior</dt>
|
|
<dd>
|
|
shared_vector models const-ness like shared_ptr.
|
|
An equivalent of 'const std::vector<E>' is
|
|
'const shared_vector<const E>'.
|
|
However, it is also possible to have 'const shared_vector<E>'
|
|
analogous to 'E* const' and 'shared_vector<const E>>'
|
|
which is analogous to 'const E*'.i
|
|
<br />
|
|
Copying a shared_vector, by construction or assignment, does not copy
|
|
its contents.
|
|
Modifications to one such "copy" effect all
|
|
associated shared_vector instances.
|
|
<br />
|
|
std::vector::reserve(N) has no effect if N<=std::vector::capacity().
|
|
However, like resize(), shared_vector<E>::reserve() has the side effect
|
|
of always calling make_unique().
|
|
</dd>
|
|
<dt>Parts of std::vector interface not implemented</dt>
|
|
<dd>
|
|
Mutating methods insert(), erase(), shrink_to_fit(), emplace(), and emplace_back() are not implemented.
|
|
<br />
|
|
shared_vector does not model an allocator which is bound to the object. Therefore the get_allocator() method and the allocator_type typedef are not provided.
|
|
<br />
|
|
The assign() method and the related constructor are not implemented at this time.
|
|
<br />
|
|
The comparison operators are not implemented at this time.
|
|
</dd>
|
|
<dt>Parts not found in std::vector</dt>
|
|
<dd>
|
|
shared_vector has additional constructors from raw pointers and shared_ptr s.
|
|
The copy constructor and assignment operator allow implicit castings
|
|
from type 'shared_vector<T>' to 'shared_vector<const T>>'.
|
|
To faciliate safe modification the methods unique() and make_unique() are provided
|
|
The slice() method selects a sub-set of the shared_vector.
|
|
The low level accessors dataPtr(), dataOffset(), dataCount(), and dataTotal().
|
|
</dd>
|
|
</dl>
|
|
|
|
|
|
<pre>
|
|
template<typename E, class Enable = void& class shared_vector;
|
|
|
|
template<typename E, class Enable&
|
|
class shared_vector : public detail::shared_vector_base<E&
|
|
{
|
|
typedef detail::shared_vector_base<E& base_t;
|
|
typedef typename detail::call_with<E&::type param_type;
|
|
typedef typename meta::strip_const<E&::type _E_non_const;
|
|
public:
|
|
typedef E value_type;
|
|
typedef E& reference;
|
|
typedef typename meta::decorate_const<E&::type& const_reference;
|
|
typedef E* pointer;
|
|
typedef typename meta::decorate_const<E&::type* const_pointer;
|
|
typedef E* iterator;
|
|
typedef std::reverse_iterator<iterator& reverse_iterator;
|
|
typedef typename meta::decorate_const<E&::type* const_iterator;
|
|
typedef std::reverse_iterator<const_iterator& const_reverse_iterator;
|
|
typedef ptrdiff_t difference_type;
|
|
typedef size_t size_type;
|
|
|
|
typedef E element_type;
|
|
typedef std::tr1::shared_ptr<E& shared_pointer_type;
|
|
|
|
// allow specialization for all E to be friends
|
|
template<typename E1, class Enable1& friend class shared_vector;
|
|
|
|
shared_vector() :base_t();
|
|
explicit shared_vector(size_t c)
|
|
:base_t(new _E_non_const[c], 0, c);
|
|
shared_vector(size_t c, param_type e);
|
|
template<typename A&
|
|
shared_vector(A v, size_t o, size_t c) :base_t(v,o,c);
|
|
template<typename E1&
|
|
shared_vector(const std::tr1::shared_ptr<E1&& d, size_t o, size_t c);
|
|
template<typename A, typename B&
|
|
shared_vector(A d, B b, size_t o, size_t c);
|
|
shared_vector(const shared_vector& o) :base_t(o);
|
|
|
|
size_t max_size() const;
|
|
size_t capacity() const;
|
|
void reserve(size_t i);
|
|
void resize(size_t i);
|
|
void resize(size_t i, param_type v);
|
|
void make_unique();
|
|
|
|
iterator begin() const;
|
|
iterator end() const;
|
|
reverse_iterator rbegin() const;
|
|
reverse_iterator rend() const;
|
|
reference front() const;
|
|
reference back() const;
|
|
|
|
void push_back(param_type v);
|
|
void pop_back();
|
|
pointer data() const;
|
|
reference operator[](size_t i) const;
|
|
reference at(size_t i) const;
|
|
// inherited from detail
|
|
shared_vector_base& operator=(const shared_vector_base& o);
|
|
void swap(shared_vector_base& o);
|
|
void clear();
|
|
bool unique() const;
|
|
size_t size() const;
|
|
bool empty() const;
|
|
void slice(size_t offset, size_t length=(size_t)-1);
|
|
const std::tr1::shared_ptr<E&& dataPtr();
|
|
size_t dataOffset() const;
|
|
size_t dataCount() const;
|
|
size_t dataTotal() const;
|
|
</pre>
|
|
where
|
|
<dl>
|
|
<dt>shared_vector</dt>
|
|
<dd>Several flavors of constructor are provided. The most commingly used is:
|
|
<pre>
|
|
shared_vector(size_t c);
|
|
</pre>
|
|
This creates a shared_vector of the specified size/
|
|
</dd>
|
|
<dt>max_size</dt>
|
|
<dd>The maximum size the C++ implementation allows, i.e.,
|
|
the maximum possible capacity.
|
|
Note that units are number of elements not number of bytes.
|
|
</dd>
|
|
<dt>capacity</dt>
|
|
<dd>The current capacity.</dd>
|
|
<dt>reserve</dt>
|
|
<dd>Set array capacity.</dd>
|
|
<dt>resize</dt>
|
|
<dd>Grow or shrink array.
|
|
It the second argument is given it is the value to assign to
|
|
and new elements.
|
|
</dd>
|
|
<dt>make_unique</dt>
|
|
<dd>Ensure (by copying) that this shared_vector
|
|
is the sole owner of the data array.
|
|
</dd>
|
|
<dt>begin,...,rend</dt>
|
|
<dd>Standard interators.</dd>
|
|
<dt>front</dt>
|
|
<dd>Return a reference to the first element.</dd>
|
|
<dt>back</dt>
|
|
<dd>Return a reference to the last element.</dd>
|
|
<dt>push_back</dt>
|
|
<dd>Add an element to the end of the array.</dd>
|
|
<dt>pop_back</dt>
|
|
<dd>Remove an element from the end of the array.</dd>
|
|
<dt>data</dt>
|
|
<dd>Return a pointer to the raw array.</dd>
|
|
<dt>operator[](size_t i)</dt>
|
|
<dd>Return a reference to the specified element.</dd>
|
|
<dt>at</dt>
|
|
<dd>Like the previous except that it throws a range-error if
|
|
the specified element is out of range.</dd>
|
|
<dt>operator=</dt>
|
|
<dd>Copy an existing shared_vector.</dd>
|
|
<dt>swap</dt>
|
|
<dd>Swap the contents of this vector with another.</dd>
|
|
<dt>clear</dt>
|
|
<dd>Clear contents.</dd>
|
|
<dt>unique</dt>
|
|
<dd>returns (true,false) if data (is not, is) shared.</dd>
|
|
<dt>size</dt>
|
|
<dd>Number of elements visible through this vector.</dd>
|
|
<dt>empty</dt>
|
|
<dd>Is the number of elements zero?</dd>
|
|
<dt>slice</dt>
|
|
<dd>Reduce the view of this shared_vector.</dd>
|
|
<dt>dataPtr</dt>
|
|
<dd>A readonly shared_ptr to the array.</dd>
|
|
<dt>dataOffset</dt>
|
|
<dd>Offset in the data array of first visible element.</dd>
|
|
<dt>dataCount</dt>
|
|
<dd>Number of visible elements between dataOffset and end of data.</dd>
|
|
<dt>dataTotal</dt>
|
|
<dd>The total number of elements between dataOffset and the end of data</dd>
|
|
</dl>
|
|
<p><b>TBD</b>
|
|
Michael should decide if this is the correct set of methods to describe.
|
|
Also he should check for correct descriptions.
|
|
</p>
|
|
|
|
|
|
<h3>status.h</h3>
|
|
|
|
<p>Status provides a way to pass status back to client code:</p>
|
|
<pre>class Status : public epics::pvData::Serializable {
|
|
public:
|
|
enum StatusType {
|
|
/** Operation completed successfully. */
|
|
STATUSTYPE_OK,
|
|
/** Operation completed successfully, but there is a warning message. */
|
|
STATUSTYPE_WARNING,
|
|
/** Operation failed due to an error. */
|
|
STATUSTYPE_ERROR,
|
|
/** Operation failed due to an unexpected error. */
|
|
STATUSTYPE_FATAL
|
|
};
|
|
static const char* StatusTypeName[];
|
|
static Status OK;
|
|
Status();
|
|
Status(StatusType type, epics::pvData::String const & message);
|
|
Status(StatusType type, epics::pvData::String const & message, epics::pvData::String stackDump);
|
|
~Status()
|
|
StatusType getType() const;
|
|
String getMessage() const;
|
|
String getStackDump() const;
|
|
bool isOK() const;
|
|
bool isSuccess() const;
|
|
String toString() const;
|
|
void toString(StringBuilder buffer, int indentLevel = 0) const;
|
|
void serialize(ByteBuffer *buffer, SerializableControl *flusher) const;
|
|
void serialize(ByteBuffer *buffer, SerializableControl *flusher) const;
|
|
};</pre>
|
|
|
|
<p>The Status methods are:</p>
|
|
<dl>
|
|
<dt>StatusType</dt>
|
|
<dd>An enum for the status type.</dd>
|
|
<dt>getType</dt>
|
|
<dd>Get the statusType.</dd>
|
|
<dt>getMessage</dt>
|
|
<dd>Get a message explaining the error.</dd>
|
|
<dt>getStackDump</dt>
|
|
<dd>Get a stack dump.</dd>
|
|
</dl>
|
|
|
|
<p>The StatusCreate methods are:</p>
|
|
<dl>
|
|
<dt>getStatusOK</dt>
|
|
<dd>Get a singleton that returns StatusType.OK and a null message and
|
|
stackDump.</dd>
|
|
<dt>createStatus</dt>
|
|
<dd>Create a new Status.</dd>
|
|
<dt>deserializeStatus</dt>
|
|
<dd>Use this method instead of Status.deserialize(), since this allows OK
|
|
status optimization.</dd>
|
|
</dl>
|
|
<h3>templateMeta.h</h3>
|
|
<p><b>TBD</b> Michael will explain.</p>
|
|
|
|
<h3>thread.h</h3>
|
|
|
|
<h4>ThreadPriority</h4>
|
|
<pre>enum ThreadPriority {
|
|
lowestPriority,
|
|
lowerPriority,
|
|
lowPriority,
|
|
middlePriority,
|
|
highPriority,
|
|
higherPriority,
|
|
highestPriority
|
|
};</pre>
|
|
|
|
<h4>Thread</h4>
|
|
<pre>
|
|
class Thread;
|
|
typedef std::tr1::shared_ptr<Thread> ThreadPtr;
|
|
typedef std::tr1::shared_ptr<epicsThread> EpicsThreadPtr;
|
|
|
|
class Runnable {
|
|
public:
|
|
virtual void run() = 0;
|
|
};
|
|
|
|
class Thread;
|
|
|
|
class Thread : public epicsThread, private NoDefaultMethods {
|
|
public:
|
|
Thread(
|
|
String name,
|
|
ThreadPriority priority,
|
|
Runnable *runnableReady,
|
|
epicsThreadStackSizeClass stkcls=epicsThreadStackSmall);
|
|
~Thread();
|
|
...
|
|
};</pre>
|
|
|
|
<p>Runnable must be implement by code that wants to be run via a thread. It has
|
|
one virtual method: run. Run is the code that is run as a thread. When run
|
|
compeletes it can not be restarted. If code wants to delete a thread then it
|
|
MUST arrange that the run returns before the thread can be deleted. An
|
|
exception is thrown if run remains active when delete is called. </p>
|
|
|
|
<p>Thread has the methods:</p>
|
|
<dl>
|
|
<dt>Thread</dt>
|
|
<dd>The constructor. A thread name and priority must be specified. The run
|
|
methods of runnable is executed. When the run methods returns the thread
|
|
will no longer be active but the client code must still delete the
|
|
thread.</dd>
|
|
<dt>~Thread</dt>
|
|
<dd>The destructor. This is called as the result of:
|
|
<pre> delete pthread;</pre>
|
|
</dd>
|
|
</dl>
|
|
|
|
<h3>timeFunction.h</h3>
|
|
|
|
<p>TimeFunction is a facility that measures the average number of seconds a
|
|
function call requires. When timeCall is called, it calls function in a loop.
|
|
It starts with a loop of one iteration. If the total elapsed time is less then
|
|
.1 seconds it increases the number of iterrations by a factor of 10. It keeps
|
|
repeating until the elapsed time is greater than .1 seconds. It returns the
|
|
average number of seconds per call.</p>
|
|
<pre>class TimeFunctionRequester;
|
|
class TimeFunction;
|
|
typedef std::tr1::shared_ptr<TimeFunctionRequester> TimeFunctionRequesterPtr;
|
|
typedef std::tr1::shared_ptr<TimeFunction> TimeFunctionPtr;
|
|
|
|
class TimeFunctionRequester {
|
|
public:
|
|
POINTER_DEFINITIONS(TimeFunctionRequester);
|
|
virtual ~TimeFunctionRequester(){}
|
|
virtual void function() = 0;
|
|
};
|
|
|
|
|
|
class TimeFunction {
|
|
public:
|
|
POINTER_DEFINITIONS(TimeFunction);
|
|
TimeFunction(TimeFunctionRequesterPtr const & requester);
|
|
~TimeFunction();
|
|
double timeCall();
|
|
...
|
|
}; </pre>
|
|
|
|
<p>TimeFunctionRequester must be implemented by code that wants to time how
|
|
long a function takes. It has the single method:</p>
|
|
<dl>
|
|
<dt>function</dt>
|
|
<dd>This is the function.</dd>
|
|
</dl>
|
|
|
|
<p>TimeFunction has the methods:</p>
|
|
<dl>
|
|
<dt>TimeFunction</dt>
|
|
<dd>Constructor.</dd>
|
|
<dt>~TimeFunction</dt>
|
|
<dd>Destructor.</dd>
|
|
<dt>timeCall</dt>
|
|
<dd>Time how long it takes to execute the function. It starts by calling
|
|
the function one time. If it takes < 1 seconds to doubles the number
|
|
of times to call the function. It repeats this until it takes at least
|
|
one second to call it ntimes.</dd>
|
|
</dl>
|
|
|
|
<h3>timer.h</h3>
|
|
|
|
<p>This provides a general purpose timer. It allows a user callback to be
|
|
called after a delay or periodically. </p>
|
|
<pre>class TimerCallback;
|
|
class Timer;
|
|
typedef std::tr1::shared_ptr<TimerCallback> TimerCallbackPtr;
|
|
typedef std::tr1::shared_ptr<Timer> TimerPtr;
|
|
|
|
|
|
class TimerCallback {
|
|
public:
|
|
POINTER_DEFINITIONS(TimerCallback);
|
|
TimerCallback();
|
|
virtual ~TimerCallback(){}
|
|
virtual void callback() = 0;
|
|
virtual void timerStopped() = 0;
|
|
};
|
|
|
|
class Timer : private Runnable {
|
|
public:
|
|
POINTER_DEFINITIONS(Timer);
|
|
Timer(String threadName, ThreadPriority priority);
|
|
virtual ~Timer();
|
|
virtual void run();
|
|
void scheduleAfterDelay(
|
|
TimerCallbackPtr const &timerCallback,
|
|
double delay);
|
|
void schedulePeriodic(
|
|
TimerCallbackPtr const &timerCallback,
|
|
double delay,
|
|
double period));
|
|
void cancel(TimerCallbackPtr const &timerCallback);
|
|
bool isScheduled(TimerCallbackPtr const &timerCallback);
|
|
void toString(StringBuilder builder);
|
|
...
|
|
};</pre>
|
|
|
|
<p>TimerCallback must be implemented by the user. It has the following methods:
|
|
</p>
|
|
<dl>
|
|
<dt>callback</dt>
|
|
<dd>This is called when a timer expires. This is called with no locks held.
|
|
When called a delay timer is no longer on the queue but a periodioc timer
|
|
is on a queue. Thus the callback for a delay timer can issue a new
|
|
schedule request but a periodic timer must not. Note the explaination of
|
|
TimerNode.cancel below.</dd>
|
|
<dt>timerStopped</dt>
|
|
<dd>Timer.stop was called when a timer request was queued. or if the timer
|
|
is stopped and a schedule request is made.</dd>
|
|
</dl>
|
|
|
|
<p>In order to schedule a callback client code must allocate a TimerNode It can
|
|
be used to schedule multiple callbacks. It has the methods:</p>
|
|
<dl>
|
|
<dt>TimerNode</dt>
|
|
<dd>The constructor. User code must create a TimeNode in order to call a
|
|
schedule method.</dd>
|
|
<dt>~TimerNode</dt>
|
|
<dd>The destructor. This is called as a result of the client calling:
|
|
<pre> delete timerNode;</pre>
|
|
</dd>
|
|
<dt>cancel</dt>
|
|
<dd>This is called to cancel a timer request. If a callback has been
|
|
dequeued but the callback not called when cancel is called then a
|
|
callback may still happen. New schedule requests can be made after a
|
|
cancel request has been made.</dd>
|
|
<dt>isScheduled</dt>
|
|
<dd>Is the timerNode scheduled to be called.</dd>
|
|
</dl>
|
|
|
|
<p>Timer has the methods:</p>
|
|
<dl>
|
|
<dt>Timer</dt>
|
|
<dd>The consttructor.</dd>
|
|
<dt>~Timer</dt>
|
|
<dd>The destructor. The queue is emptied and TimerCallback.timerStopped is
|
|
called for each element of the queue.</dd>
|
|
<dt>scheduleAfterDelay</dt>
|
|
<dd>A request to schedule a callback after a delay specified in
|
|
seconds.</dd>
|
|
<dt>schedulePeriodic</dt>
|
|
<dd>Schedule a periodic callback.</dd>
|
|
</dl>
|
|
<h3>typeCast.h</h3>
|
|
<p><b>TBD</b> Michael will explain.</p>
|
|
|
|
<h2>pvDataApp/pvMisc</h2>
|
|
|
|
<h3>bitSetUtil.h</h3>
|
|
|
|
<p>The following is also provided:</p>
|
|
<pre>class BitSetUtil : private NoDefaultMethods {
|
|
public:
|
|
static bool compress(BitSet const &bitSet,PVStructure const &pvStructure);
|
|
};</pre>
|
|
|
|
<p>This provides functions that operate on a BitSet for a PVStructure. It
|
|
currently has only one method:</p>
|
|
<dl>
|
|
<dt>compress</dt>
|
|
<dd>Compress the bits in a BitSet related to a structure.<br />
|
|
For each structure:
|
|
<ol>
|
|
<li>If the bit for the structure is set then the bit for all subfields
|
|
of the structure are cleared. </li>
|
|
<li>If the bit for the structure is not set but all immediate subfields
|
|
have their bit set then the bit for the structure is set and the bits
|
|
for all subfields are cleared. </li>
|
|
</ol>
|
|
Note that this is a recursive algorithm. That is if every immediate
|
|
subfield has it's offset bit set then the bits for ALL fields that reside
|
|
in the structure will be cleared.</dd>
|
|
<dd>Channel Access can call this before sending data. It can then pass
|
|
entire structures if the structure offset bit is set. </dd>
|
|
</dl>
|
|
|
|
<h2>support for copy and monitor</h2>
|
|
<p><b>copy</b> and <b>monitor</b> are not used in this project.
|
|
They are intended for use by pvAccess and by pvAccess servers.
|
|
They are provided with this project because the code depends only on
|
|
pvData itself.
|
|
</p>
|
|
<p>This document describes C++ specific code.
|
|
<a href="http://epics-pvdata.sourceforge.net/informative/pvRequest.html">
|
|
pvRequest.html</a>
|
|
provides a language independent overview of <b>copy</b> and <b>monitor</b>.
|
|
</p>
|
|
<p>
|
|
<b>NOTE:pvRequest.html</b> must be updated since it is based on an earlier version of pvCopy that
|
|
had knowlege of PVRecord. The C++ version was implemented in pvDatabaseCPP
|
|
and the Java version on pvIOCJava.
|
|
At present only the C++ version of the new API for pvCopy is implemented.
|
|
</p>
|
|
<p>Copy provides:
|
|
<dl>
|
|
<dt>createRequest</dt>
|
|
<dd>
|
|
The Channel create methods in pvAccess all have an argument
|
|
<b>PVStructure pvRequest</b>.<br />
|
|
Given an ascii string createRequest creates a PVStructure that provides
|
|
a pvData representation of the information from the ascii string.
|
|
It is this structure that can be passed to the channel create methods.<br />
|
|
The information in a pvRequest selects an arbitrarary subset of the
|
|
fields in a top level structure that resides in the server.
|
|
In addition options can be specified. Both global and field specific
|
|
options can be specified.
|
|
</dd>
|
|
<dt>pvCopy</dt>
|
|
<dd>This is a faculity used by channel providers.
|
|
It provides client specific code that manages a copy of an arbitrary
|
|
subset of the fields in a top level structure that resides in the
|
|
provider. It also allows provider access to options specified
|
|
by the client.
|
|
</dd>
|
|
</dl>
|
|
Monitor provides:
|
|
<dl>
|
|
<dt>monitor</dt>
|
|
<dd>This is support code for channel providers that implement channel
|
|
monitor. It, together with the queue facility, provides support for
|
|
monitor queues.
|
|
</dd>
|
|
<dt>monitorPlugin</dt>
|
|
<dd>This is support for implementing monitor plugins.
|
|
A monitor plugin can be developed that has no knowledge
|
|
of pvAccess but only pvData.
|
|
</dd>
|
|
</dl>
|
|
</p>
|
|
|
|
<h2>support for copy</h2>
|
|
<p><b>copy</b> provides the ability to create a structure that has
|
|
a copy of an arbitrary subset of the fields in an existing top level
|
|
structure. In addition it allows global options and field specific options.
|
|
It has two main components: <b>createRequest</b> and <b>pvCopy</b>.
|
|
Given a string createRequest creates a pvRequest, which is a PVStructure
|
|
that has the format expected by <b>pvCopy</b>.
|
|
</p>
|
|
|
|
<h3>createRequest</h3>
|
|
<p>This is mainly used by pvAccess clients. Given a request string it creates
|
|
a pvRequest structure that can be passed to the pvAccess create methods.
|
|
In turn pvAccess passes the pvRequest to a local channel provider which
|
|
then passes it to pvCopy.
|
|
</p>
|
|
<p>The definition of the public members is:</p>
|
|
<pre>
|
|
class CreateRequest {
|
|
...
|
|
static CreateRequestPtr create();
|
|
virtual PVStructurePtr createRequest(String const &request);
|
|
String getMessage();
|
|
};
|
|
</pre>
|
|
<p>An example of how it is used is:</p>
|
|
<pre>
|
|
CreateRequestPtr createRequest = CreateRequest::create();
|
|
PVStructurePtr pvRequest = createRequest->createRequest(request);
|
|
if(pvRequest==NULL) {
|
|
String error = createRequest->getMessage();
|
|
// take some action
|
|
} else {
|
|
//success do something
|
|
}
|
|
</pre>
|
|
<h3>pvCopy</h3>
|
|
<p>The definition of the public members is:</p>
|
|
<pre>
|
|
class epicsShareClass PVCopyTraverseMasterCallback
|
|
{
|
|
...
|
|
virtual void nextMasterPVField(PVFieldPtr const &pvField);
|
|
};
|
|
|
|
class class epicsShareClass PVCopy
|
|
{
|
|
...
|
|
static PVCopyPtr create(
|
|
PVStructurePtr const &pvMaster,
|
|
PVStructurePtr const &pvRequest,
|
|
String const & structureName);
|
|
PVStructurePtr getPVMaster();
|
|
void traverseMaster(PVCopyTraverseMasterCallbackPtr const & callback);
|
|
StructureConstPtr getStructure();
|
|
PVStructurePtr createPVStructure();
|
|
size_t getCopyOffset(PVFieldPtr const &masterPVField);
|
|
size_t getCopyOffset(
|
|
PVStructurePtr const &masterPVStructure,
|
|
PVFieldPtr const &masterPVField);
|
|
PVFieldPtr getMasterPVField(std::size_t structureOffset);
|
|
void initCopy(
|
|
PVStructurePtr const &copyPVStructure,
|
|
BitSetPtr const &bitSet);
|
|
void updateCopySetBitSet(
|
|
PVStructurePtr const &copyPVStructure,
|
|
BitSetPtr const &bitSet);
|
|
void updateCopyFromBitSet(
|
|
PVStructurePtr const &copyPVStructure,
|
|
BitSetPtr const &bitSet);
|
|
void updateMaster(
|
|
PVStructurePtr const &copyPVStructure,
|
|
BitSetPtr const &bitSet);
|
|
PVStructurePtr getOptions(std::size_t fieldOffset);
|
|
...
|
|
};
|
|
</pre>
|
|
where
|
|
<dl>
|
|
<dt>PVCopyTraverseMasterCallback::nextMasterPVField</dt>
|
|
<dd>
|
|
<b>PVCopyTraverseMasterCallback</b> is a callback which must
|
|
be implemented by the code that uses pvCopy, normally
|
|
the channel provider. It has the single method <b>nextMasterPVField</b>
|
|
<br />
|
|
<b>nextMasterPVField</b> is called for each field in the master
|
|
as a result of a call to <b>traverseMaster</b>.
|
|
</dd>
|
|
<dt>create</dt>
|
|
<dd>
|
|
This is the method for creating a PVCopy instance.<br/>
|
|
<dl>
|
|
<dt>pvMaster</dt>
|
|
<dd>the top level sructure managed by the server.</dd>
|
|
<dt>pvRequest</dt>
|
|
<dd>selects the set of subfields desired
|
|
and options for each field.</dd>
|
|
<dt>structureName</dt>
|
|
<dd>the name for the top level of any PVStructure created.
|
|
</dd>
|
|
</dl>
|
|
</dd>
|
|
<dt>getPVMaster</dt>
|
|
<dd>
|
|
Gets the top level structure from pvMaster.
|
|
</dd>
|
|
<dt>traverseMaster</dt>
|
|
<dd>
|
|
Traverse all fields of the top level structure of pvMaster.
|
|
For each field the callback is called.
|
|
</dd>
|
|
<dt>getStructure</dt>
|
|
<dd>
|
|
Get the introspection interface for a PVStructure for e copy.
|
|
</dd>
|
|
<dt>createPVStructure</dt>
|
|
<dd>Create a copy instance.
|
|
Monitors keep a queue of monitor elements.
|
|
Since each element needs a PVStructure, multiple top level structures
|
|
will be created.
|
|
</dd>
|
|
<dt>getCopyOffset</dt>
|
|
<dd>Given a field in pvMaster.
|
|
return the offset in copy for the same field.
|
|
A value of String::npos means that the copy does not have this field.
|
|
Two overloaded methods are provided. The first is called if
|
|
the field of master is not a structure. The second is for
|
|
subfields of a structure.
|
|
</dd>
|
|
<dt>getMasterPVField</dt>
|
|
<dd>
|
|
Given a offset in the copy get the corresponding field in pvMaster.
|
|
</dd>
|
|
<dt>initCopy</dt>
|
|
<dd>
|
|
Initialize the fields in copyPVStructure
|
|
by giving each field the value from the corresponding field in pvMaster.
|
|
bitSet will be set to show that all fields are changed.
|
|
This means that bit set will have the value <b>{0}</b>.
|
|
</dd>
|
|
<dt>updateCopySetBitSet</dt>
|
|
<dd>
|
|
Set all fields in copyPVStructure to the value of the corresponding field
|
|
in pvMaster. Each field that is changed has it's corresponding
|
|
bit set in bitSet.
|
|
</dd>
|
|
<dt>updateCopyFromBitSet</dt>
|
|
<dd>
|
|
For each set bit in bitSet set the field in copyPVStructure to the value
|
|
of the corrseponding field in pvMaster.
|
|
</dd>
|
|
<dt>updateMaster</dt>
|
|
<dd>
|
|
For each set bit in bitSet set the field in pvMaster to the value
|
|
of the corrseponding field in copyPVStructure.
|
|
|
|
</dd>
|
|
<dt>getOptions</dt>
|
|
<dd>
|
|
Get the options for the field at the specified offset.
|
|
A NULL is returned if no options were specified for the field.
|
|
If options were specified,PVStructurePtr is
|
|
a structure with a set of PVString subfields that specify name,value
|
|
pairs. name is the subField name and value is the subField value.
|
|
</dd>
|
|
</dl>
|
|
|
|
|
|
|
|
|
|
<h2>support for monitor</h2>
|
|
<p>This consists of two components:
|
|
<dl>
|
|
<dt>monitor</dt>
|
|
<dd>Used by code that implements pvAccess montors.</dd>
|
|
<dt>monitorPlugin</dt>
|
|
<dd>Code that provides special semantics for monitors.</dd>
|
|
</dl>
|
|
</p>
|
|
<h3>monitor</h3>
|
|
<pre>
|
|
class MonitorElement {
|
|
MonitorElement(PVStructurePtr const & pvStructurePtr);
|
|
PVStructurePtr pvStructurePtr;
|
|
BitSetPtr changedBitSet;
|
|
BitSetPtr overrunBitSet;
|
|
};
|
|
|
|
class Monitor {
|
|
virtual Status start() = 0;
|
|
virtual Status stop() = 0;
|
|
virtual MonitorElementPtr poll() = 0;
|
|
virtual void release(MonitorElementPtr const & monitorElement) = 0;
|
|
};
|
|
|
|
class MonitorRequester : public virtual Requester {
|
|
virtual void monitorConnect(Status const & status,
|
|
MonitorPtr const & monitor, StructureConstPtr const & structure) = 0;
|
|
virtual void monitorEvent(MonitorPtr const & monitor) = 0;
|
|
virtual void unlisten(MonitorPtr const & monitor) = 0;
|
|
};
|
|
</pre>
|
|
<h4>monitorElement</h4>
|
|
<p><b>MonitorElement</b> holds the data for one element of a monitor queue.
|
|
It has the fields:
|
|
<dl>
|
|
<dt>pvStructurePtr</dt>
|
|
<dd>A top level structure with data values at the time the monitors occurs.</dd>
|
|
<dt>changedBitSet</dt>
|
|
<dd>Shows which fields have changed since the previous monitor.</dd>
|
|
<dt>overrunBitSet</dt>
|
|
<dd>Shows which fields have changed more han once since the previous monitor.</dd>
|
|
</dl>
|
|
</p>
|
|
<h4>monitorElement queue</h4>
|
|
<p>
|
|
A queue of monitor elements must be implemented by any channel provider that implements
|
|
<b>Channel::createMonitor</b>.
|
|
For an example implementation look at pvDatabaseCPP.
|
|
It has the following:
|
|
<pre>
|
|
typedef Queue<MonitorElement> MonitorElementQueue;
|
|
typedef std::tr1::shared_ptr<MonitorElementQueue> MonitorElementQueuePtr;
|
|
|
|
class MultipleElementQueue :
|
|
public ElementQueue
|
|
{
|
|
public:
|
|
POINTER_DEFINITIONS(MultipleElementQueue);
|
|
virtual ~MultipleElementQueue(){}
|
|
MultipleElementQueue(
|
|
MonitorLocalPtr const &monitorLocal,
|
|
MonitorElementQueuePtr const &queue,
|
|
size_t nfields);
|
|
virtual void destroy(){}
|
|
virtual Status start();
|
|
virtual Status stop();
|
|
virtual bool dataChanged();
|
|
virtual MonitorElementPtr poll();
|
|
virtual void release(MonitorElementPtr const &monitorElement);
|
|
...
|
|
};
|
|
</pre>
|
|
<h4>Monitor</h4>
|
|
<p><b>Monitor</b> must be implemented by any channel provider that implements
|
|
<b>Channel::createMonitor</b>.
|
|
Remote PVAccess also implements Monitor on the client side.
|
|
Note that each client has it's own queue that is not shared with other client.
|
|
</p>
|
|
<p>Monitor has the following methods:</p>
|
|
<dl>
|
|
<dt>start</dt>
|
|
<dd>
|
|
Start monitoring.
|
|
This will result in a an inital monitor that has the current value
|
|
of all fields.
|
|
</dd>
|
|
<dt>stop</dt>
|
|
<dd>
|
|
Stop monitoring.
|
|
</dd>
|
|
<dt>poll</dt>
|
|
<dd>
|
|
Called to get a monitor element.
|
|
If no new elemants are available then a null pointer is returned.
|
|
</dd>
|
|
<dt>release</dt>
|
|
<dd>
|
|
Release the monotor element.
|
|
The caller owns the monitor element between the calls to poll and release.
|
|
</dd>
|
|
<dl>
|
|
</dl>
|
|
<h4>MonitorRequester</h4>
|
|
<p>This must be implemented by a pvAccess client.
|
|
It has the methods:</p>
|
|
<dl>
|
|
<dt>monitorConnect</dt>
|
|
<dd>
|
|
A monitor has either connected of disconnected.
|
|
</dd>
|
|
<dt>monitorEvent</dt>
|
|
<dd>
|
|
A new monitor element is available.
|
|
</dd>
|
|
<dt>unlisten</dt>
|
|
<dd>
|
|
The channel is going away. The client cam no longer access the monitor.
|
|
</dd>
|
|
</dl>
|
|
|
|
<h3>monitorPlugin</h3>
|
|
<pre>
|
|
class MonitorPlugin
|
|
{
|
|
virtual String const & getName() = 0;
|
|
virtual bool causeMonitor(
|
|
PVFieldPtr const &pvField,
|
|
PVStructurePtr const &pvTop,
|
|
MonitorElementPtr const &monitorElement) = 0;
|
|
virtual void monitorDone(
|
|
MonitorElementPtr const &monitorElement);
|
|
virtual void startMonitoring();
|
|
virtual void stopMonitoring();
|
|
virtual void beginGroupPut();
|
|
virtual void endGroupPut();
|
|
};
|
|
|
|
class MonitorPluginCreator
|
|
{
|
|
virtual MonitorPluginPtr create(
|
|
FieldConstPtr const &field,
|
|
StructureConstPtr const &top,
|
|
PVStructurePtr const &pvFieldOptions) = 0;
|
|
virtual String const & getName() = 0;
|
|
}
|
|
|
|
class MonitorPluginManager
|
|
{
|
|
static MonitorPluginManagerPtr get();
|
|
bool addPlugin(
|
|
String const &pluginName,
|
|
MonitorPluginCreatorPtr const &creator);
|
|
MonitorPluginCreatorPtr findPlugin(String const &pluginName);
|
|
void showNames();
|
|
};
|
|
|
|
</pre>
|
|
<h4>MonitorPlugin</h4>
|
|
<p><b>MonitorPlugin</b> must be implemented by the plugin implementation.
|
|
It has methods:</p>
|
|
<dl>
|
|
<dt>getName</dt>
|
|
<dd>Get the name of the plugin.</dd>
|
|
<dt>causeMonitor</dt>
|
|
<dd>
|
|
Should the value of pvField cause a monitor to be raised.
|
|
pvField and pvTop are fields in the top level structure
|
|
being monitored. monitorElement has the top level structure
|
|
for the copy</b>.
|
|
The implementation should <b>not</b> modify the fields in the structure
|
|
being monitored.
|
|
Called with pvTop locked.
|
|
</dd>
|
|
<dt>monitorDone</dt>
|
|
<dd>
|
|
Called just before monitorElement will be given to client.
|
|
The plugin can change the data values and bitSets in monitorElement.
|
|
Called with pvTop unlocked.
|
|
</dd>
|
|
<dt>startMonitoring</dt>
|
|
<dd>
|
|
Monitoring is starting.
|
|
</dd>
|
|
<dt>stopMonitoring</dt>
|
|
<dd>
|
|
Monitoring is being stopped.
|
|
</dd>
|
|
<dt>beginGroupPut</dt>
|
|
<dd>
|
|
A set of puts is starting.
|
|
Called with pvTop locked.
|
|
</dd>
|
|
<dt>endGroupPut</dt>
|
|
<dd>
|
|
The set of puts is complete.
|
|
Called with pvTop locked.
|
|
</dd>
|
|
</dl>
|
|
<h4>MonitorPluginCreator</h4>
|
|
<p><b>MonitorPluginCreator</b> must also be implemented by the plugin implementation.
|
|
It is called for each field instance that has options of the from
|
|
<b>[plugin=name...]</b> where <b>name</b> is the name of the plugin.
|
|
Note that a plugin instance will belong to a single client.
|
|
It has methods:</p>
|
|
<dl>
|
|
<dt>getName</dt>
|
|
<dd>Get the name of the plugin.</dd>
|
|
<dt>create</dt>
|
|
<dd>
|
|
Create a new plugin instance.
|
|
If the arguments are not compatible with the plugin a NULL shared pointer is
|
|
returned.<br/>
|
|
pvFieldOptions is
|
|
a structure with a set of PVString subfields that specify <b>name,value</b>
|
|
pairs. name is the subField name and value is the subField value.<br/>
|
|
Note that a plugin will below to a single client.
|
|
</dd>
|
|
<dl>
|
|
<h4>MonitorPluginManager</h4>
|
|
<p><b>MonitorPluginManager</b> has the methods:</p>
|
|
<dl>
|
|
<dt>get</dt>
|
|
<dd>
|
|
MonitorPluginManager is a singleton.
|
|
The first call to get will create the single instance.
|
|
Further calls will rerurn the single instance.
|
|
</dd>
|
|
<dt>addPlugin</dt>
|
|
<dd>
|
|
Add a new plugin.
|
|
</dd>
|
|
<dt>findPlugin</dt>
|
|
<dd>
|
|
Find a plugin. A NULL shared pointer is reurned if it has not been added.
|
|
</dd>
|
|
<dt>showNames</dt>
|
|
<dd>
|
|
Show the names of all puugins that have been added.
|
|
</dd>
|
|
</dl>
|
|
<p><b>NOTE:</b>
|
|
Should the method <b>causeMonitor</b>
|
|
have arguments <b>pvField</b> and <b>pvTop</b>
|
|
be defined so that they can not be modfied.
|
|
This would be posssible if the following was defined:
|
|
<pre>
|
|
typedef std::tr1::shared_ptr<const PVField> PVFieldConstPtr;
|
|
typedef std::tr1::shared_ptr<const PVStructure> PVStructureConstPtr;
|
|
</pre>
|
|
then the definition for causeMonitor could be:
|
|
<pre>
|
|
virtual bool causeMonitor(
|
|
PVFieldConstPtr const &pvField,
|
|
PVStructureConstPtr const &pvTop,
|
|
MonitorElementPtr const &monitorElement) = 0;
|
|
</pre>
|
|
But just adding these definitions is not sufficent.
|
|
In addition all methods defined in pvDataCPP must be checked.
|
|
In particular many of the methods in <b>Convert</b> must have
|
|
their arguments modified.
|
|
Big job.
|
|
</p>
|
|
<h2>monitorPlugin example</h2>
|
|
<h3>Example Plugin Overview</h3>
|
|
<p>This section describes an example plugin that:</p>
|
|
<ul>
|
|
<li>Only raises monitors when a field changes value.<br />
|
|
If no plugin is provided
|
|
the default is to raise a monitor when a put is issued to a field.</li>
|
|
<li>Optionally a change will not raise a monitor.<br />
|
|
The change will, however,
|
|
appear if a put to another field raise a monitor.</li>
|
|
</ul>
|
|
<p>As an example assume that a channel provided by pvAccess has a top level structure
|
|
that represents a power supply.</p>
|
|
<pre>
|
|
structure powerSupply
|
|
structure alarm
|
|
structure timeStamp
|
|
structure power
|
|
double value
|
|
structure alarm
|
|
struvture display
|
|
structure voltage
|
|
double value
|
|
structure alarm
|
|
struvture display
|
|
structure current
|
|
double value
|
|
structure alarm
|
|
struvture display
|
|
</pre>
|
|
<p>A pvAccess client wants to create a monitor on the powerSupply as follows:
|
|
The client wants a top level structure that looks like:
|
|
<pre>
|
|
structure powerSupply
|
|
structure alarm
|
|
structure timeStamp
|
|
structure power
|
|
double value
|
|
structure voltage
|
|
double value
|
|
structure current
|
|
double value
|
|
</pre>
|
|
In addition the client wants monitors to occur only when one of the monitored
|
|
fields changes value but not just because a put occured.
|
|
Also if only the timeStamp changes value then that should not cause a monitor.
|
|
</p>
|
|
<p>The example monitor plugin implements the semantics the
|
|
client wants. It can be attached to any field via the following options:
|
|
<pre>
|
|
[plugin=onChange,raiseMonitor=value]
|
|
</pre>
|
|
This plugin will trigger a monitor for the field only if the field changes
|
|
value. In addition <b>value</b> equals <b>false</b> means do not raise a monotor
|
|
for changes to this field.
|
|
But if a change to another field does cause a monitor the change to this field
|
|
will be passed to the client.
|
|
</p>
|
|
<p>
|
|
Assume that the client has already connected to the channel.
|
|
The client can then issue the commands:</p>
|
|
<pre>
|
|
String request("field(alarm[plugin=onChange]");
|
|
request += ",timeStamp[plugin=onChange,raiseMonitor=false]";
|
|
request += ",power.value[plugin=onChange";
|
|
request += ",voltage.value[plugin=onChange";
|
|
request += ",current.value[plugin=onChange";
|
|
|
|
PVStructurePtr pvRequest = createRequest->createRequest(request);
|
|
|
|
MonitorPtr monitor = channel->createMonitor(monitorRequester,pvRequest);
|
|
</pre>
|
|
<h3>Example Plugin Code</h3>
|
|
<p>The header file to create the example has the definition:</p>
|
|
<pre>
|
|
class ExampleMonitorPlugin{
|
|
public:
|
|
static void create();
|
|
};
|
|
</pre>
|
|
<p>The implementation is:</p>
|
|
<pre>
|
|
class OnChangePlugin : public MonitorPlugin
|
|
{
|
|
public:
|
|
virtual ~OnChangePlugin(){}
|
|
OnChangePlugin() {}
|
|
bool init(
|
|
FieldConstPtr const &field,
|
|
StructureConstPtr const &top,
|
|
PVStructurePtr const &pvFieldOptions)
|
|
{
|
|
pvField = getPVDataCreate()->createPVField(field);
|
|
raiseMonitor = true;
|
|
if(pvFieldOptions!=NULL) {
|
|
PVStringPtr pvString =
|
|
pvFieldOptions->getSubField<PVString>("raiseMonitor");
|
|
if(pvString!=NULL) {
|
|
String value = pvString->get();
|
|
if(value.compare("false")==0) raiseMonitor = false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
virtual String &getName(){return pluginName;}
|
|
virtual bool causeMonitor(
|
|
PVFieldPtr const &pvNew,
|
|
PVStructurePtr const &pvTop,
|
|
MonitorElementPtr const &monitorElement)
|
|
{
|
|
bool isSame = convert->equals(pvNew,pvField);
|
|
if(isSame) return false;
|
|
convert->copy(pvNew,pvField);
|
|
return raiseMonitor;
|
|
}
|
|
private:
|
|
PVFieldPtr pvField;
|
|
bool raiseMonitor;
|
|
};
|
|
class OnChangePluginCreator : public MonitorPluginCreator
|
|
{
|
|
public:
|
|
virtual String &getName(){return pluginName;}
|
|
virtual MonitorPluginPtr create(
|
|
FieldConstPtr const &field,
|
|
StructureConstPtr const &top,
|
|
PVStructurePtr const &pvFieldOptions)
|
|
{
|
|
OnChangePluginPtr plugin(new OnChangePlugin());
|
|
bool result = plugin->init(field,top,pvFieldOptions);
|
|
if(!result) return MonitorPluginPtr();
|
|
return plugin;
|
|
}
|
|
|
|
};
|
|
|
|
void ExampleMonitorPlugin::create()
|
|
{
|
|
static OnChangePluginCreatorPtr plugin;
|
|
static Mutex mutex;
|
|
Lock xx(mutex);
|
|
if(plugin==NULL) {
|
|
plugin = OnChangePluginCreatorPtr(new OnChangePluginCreator());
|
|
MonitorPluginManager::get()->addPlugin(pluginName,plugin);
|
|
}
|
|
}
|
|
</pre>
|
|
|
|
|
|
</div>
|
|
</body>
|
|
</html>
|