This is Developer's Guide for EPICS V4,
which is one of a
related set of products:
relatedDocumentsV4.html
This is the 19-May-2015 version of the Developer's Guide. It is for EPICS V4 Release 4.4 but also includes components that are intentended for the next release of V4. This document is actively being developed and is subject to being updated at any time. It should be stable by the May EPICS meeting.
This document briefly describes the application programming interfaces (API) for the following components of EPICS V4.
The following are some examples that use this toolkit:
Each normative type defines a structure that has a set of standard fields. For example NTScalar defines:
epics:nt/NTScalar:1.0 double value // mandatory and can be any numeric type string descriptor // optional alarm_t alarm // optional int severity int status string message time_t timeStamp // optional long secondsPastEpoch int nanoseconds int userTag display_t display // optional double limitLow double limitHigh string description string format string units control_t control // optional double limitLow double limitHigh double minStep string extra1 // extra string[] extra2 //
A client written in either Java or C++ can communicate with a server written in either Java or C++. All communication between client and server is done via the methods provided by pvAccess and by pvData objects.
pvAccess provides:
channelPutGet and channelRPC provide the equivalent of a Remote Procedure Call. The client passes a pvData object to the server. This pvData object is the argument for the RPC. The server uses this to decide what to do and sends a pvData object back to the client, which is the RPC result.
easyPVA is a synchronous wrapper for the pvAccess API, which is a callback based API. In addition easyPVA provides many convenience methods. Thus it is easier to use than pvAccess itself.
A framework for implementing a network accessible database of smart memory resident records. Network access is via pvAccess. The data in each record is a top level PVStructure as defined by pvData. The framework includes a complete implementation of ChannelProvider as defined by pvAccess. The framework can be extended in order to create record instances that implement services. The minimum that an extension must provide is a top level PVStructure and a process method.
pvaSrv is a pvAccess server that runs in a EPICS V3 IOC. pvaSrv allows clients to get, put and monitor V3 PVs (fields of EPICS DB records) via pvAccess, translating the value and its meta data (graphics limits, alarm status, timestamp) to or from V4 Normative Type (NT) pvData structures (NTScalar, NTScalarArray).
A Python wrapper for pvData and pvAccess.
This document is a tutorial rather then a detailed reference manual. The following should be consulted for detailed documentation:
In addition a standard for normativeTypes exists:
pvAccessCPP provides command line tools. Each provides help. For example:
pvlist -help
The examples shown in this section assume that the example database described in the next secton is running. Also your PATH environment variable must include the appropriate bin directory from pvAccessCPP. For example:
export PATH=$PATH:${EPICSV4}/pvAccessCPP/bin/${EPICS_HOST_ARCH}
Without any arguments this shows the location of all V4 servers it can locate. For example:
pvlist GUID 0x3989545500000000B14EFE12, version 1: tcp@[<IP_ADDRESS>:36448]
This only shows one line because only the exampleDatabase server is running. In an operational system the output could be quite extensive.
Once the location of a server is known the list of channel names can be shown by asking for either the GUID or tcp address. This either:
pvlist 0x3989545500000000B14EFE12or
pvlist <IP_ADDRESS>:36448produces:
ao01 double00 double01 bo00 bo01 calc00 ...
The options are:
mrk> pvlist -help Usage: pvlist [options] [<server address or GUID starting with '0x'>]... -h: Help: Print this message options: -i Print server info (when server address list/GUID is given) -w <sec>: Wait time, specifies timeout, default is 3.000000 second(s) -q: Quiet mode, print only error messages -d: Enable debug output examples: pvlist pvlist ioc0001 pvlist <IP_ADDRESS>:10000 pvlist 0x83DE3C540000000000BF351Ffor details.
pvget provides functionality similar to caget. For example:
mrk> caget double01 double01 0 mrk> pvget double01 double01 0
The options are:
mrk> pvget -help Usage: pvget [options] <PV name>... -h: Help: Print this message options: -r <pv request>: Request, specifies what fields to return and options, default is 'field(value)' -w <sec>: Wait time, specifies timeout, default is 3.000000 second(s) -t: Terse mode - print only value, without names -i: Do not format standard types (enum_t, time_t, ...) -m: Monitor mode -p <provider>: Set default provider name, default is 'pva' -q: Quiet mode, print only error messages -d: Enable debug output -F <ofs>: Use <ofs> as an alternate output field separator -f <input file>: Use <input file> as an input that provides a list PV name(s) to be read, use '-' for stdin -c: Wait for clean shutdown and report used instance count (for expert users) enum format: -n: Force enum interpretation of values as numbers (default is enum string) example: pvget double01
Some examples are:
mrk> pvget enum01 enum01 zero mrk> pvget -i enum01 enum01 epics:nt/NTEnum:1.0 enum_t value int index 0 string[] choices [zero,one,two,three] mrk> pvget -i -r "value,alarm,timeStamp" enum01 enum01 epics:nt/NTEnum:1.0 enum_t value int index 0 string[] choices [zero,one,two,three] alarm_t alarm int severity 3 int status 0 string message UDF time_t timeStamp long secondsPastEpoch 631152000 int nanoseconds 0 int userTag 0
Multiple channels can be accessed witn a single command. For example:
mrk> pvget double01 double02 double01 0 double02 0
The above examples all used the pva server, i. e. the pvAccess server for network communication. It is also possible to use ca, i. e. the channel access server that comes with iocCore. Thus it can access a V3 IOC even if the IOC has no V4 support.
mrk> pvget -p ca double01 double01 0 mrk> pvget -p ca -r "value,alarm,timeStamp" double01 double01 epics:nt/NTScalar:1.0 double value 0 alarm_t alarm INVALID RECORD UDF_ALARM time_t timeStamp <undefined> 0
pvget can also be used to monitor, i. e. it has functionality similer to camonitor.
mrk> pvget -m -r "value,alarm,timeStamp" double02 'double02 epics:nt/NTScalar:1.0 double value 0 alarm_t alarm INVALID NO_STATUS UDF time_t timeStamp <undefine>> 0 double02 epics:nt/NTScalar:1.0 double value 1 alarm_t alarm NO_ALARM NO_STATUS NO_ALARM time_t timeStamp 2015-05-14T08:29:55.769 0
pvput provides functionality similar to caput. For example:
mrk> caput double01 1.0 Old : double01 1 New : double01 1 mrk> pvput double01 1.0 Old : double01 1 New : double01 1
The options are:
mrk> pvput -help Usage: pvput [options] <PV name> <values>... -h: Help: Print this message options: -r <pv request>: Request, specifies what fields to return and options, default is 'field(value)' -w <sec>: Wait time, specifies timeout, default is 3.000000 second(s) -t: Terse mode - print only successfully written value, without names -p <provider>: Set default provider name, default is 'pva' -q: Quiet mode, print only error messages -d: Enable debug output -F <ofs>: Use <ofs> as an alternate output field separator -f <input file>: Use <input file> as an input that provides a list PV name(s) to be read, use '-' for stdin enum format: default: Auto - try value as enum string, then as index number -n: Force enum interpretation of values as numbers -s: Force enum interpretation of values as strings example: pvput double01 1.234
At the present time it is not possible to send output to multiple channels with one command.
eget provides many of the same features but in addition supports channelRPC and understands some of the normative types.
The options are:
mrk> eget -h Usage: eget [options] [<PV name>... | -s <service name>] -h: Help: Print this message options: -s <service name>: Service API compliant based RPC service name (accepts NTURI request argument) -a <service arg>: Service argument in 'name[=value]' or 'name value' form -r <pv request>: Get request string, specifies what fields to return and options, default is 'field(value)' -w <sec>: Wait time, specifies timeout, default is 3.000000 second(s) -z: Pure pvAccess RPC based service (send NTURI.query as request argument) -N: Do not format NT types, dump structure instead -i: Do not format standard types (enum_t, time_t, ...) -t: Terse mode -T: Transpose vector, table, matrix -m: Monitor mode -x: Use column-major order to decode matrix -p <provider>: Set default provider name, default is 'pva' -q: Quiet mode, print only error messages -d: Enable debug output -F <ofs>: Use <ofs> as an alternate output field separator -f <input file>: Use <input file> as an input that provides a list PV name(s) to be read, use '-' for stdin -c: Wait for clean shutdown and report used instance count (for expert users) enum format: -n: Force enum interpretation of values as numbers (default is enum string) examples: #! Get the value of the PV corr:li32:53:bdes > eget corr:li32:53:bdes #! Get the table of all correctors from the rdb service > eget -s rdbService -a entity=swissfel:devicenames #! Get the archive history of quad45:bdes;history between 2 times, from the archive service > eget -s archiveService -a entity=quad45:bdes;history -a starttime=2012-02-12T10:04:56 -a endtime=2012-02-01T10:04:56 #! Get polynomials for bunch of quads using a stdin to give a list of PV names > eget -s names -a pattern=QUAD:LTU1:8%:POLYCOEF | eget -f -
pvDatabaseCPP has an exampleDatabase. This section explains what is in it.
easyPVACPP has a file exampleDatabaseEasyPVA.zip. It is like exampleDatabase but creates a few extra records. It also has two extra example servers:
I suggest looking at exampleDatabaseEasyPVA.zip Most of this section describes both.
The example can be run either as a standalone main program or as part of a V3 IOC (Input Output Controller). If as part of a V3 IOC the IOC has both V3 and V4 records. It also starts pvaSrv so that the V3 records can be accessed via either ca or pva.
To run the example as a main program:
mrk> pwd /home/mrk/pvcpp/exampleDatabaseEasyPVA mrk> bin/linux-x86_64/exampleDatabaseMain
To start the example as part of a V3 IOC:
mrk> pwd /home/mrk/pvcpp/exampleDatabaseEasyPVA/iocBoot/exampleDatabase mrk> ../../bin/linux-x86_64/exampleDatabase st.cmd
This is the file that runs the example as a main program. The main program is:
int main(int argc,char *argv[]) { ExampleDatabase::create(); ContextLocal::shared_pointer contextLocal = ContextLocal::create(); contextLocal->start(); cout << "pvAccess server exampleDatabase running..." << endl; epics::pvData::PVStringArrayPtr pvNames = PVDatabase::getMaster()->getRecordNames(); cout << "Hosted records: " << endl << *pvNames << endl; contextLocal->waitForExit(); return 0; }The only code that is not generic is:
ExampleDatabase::create();
static const iocshArg testArg0 = { "prefix", iocshArgString }; static const iocshArg *testArgs[] = { &testArg0}; static const iocshFuncDef exampleDatabaseFuncDef = { "exampleDatabase", 1, testArgs}; static void exampleDatabaseCallFunc(const iocshArgBuf *args) { ExampleDatabase::create(); } static void exampleDatabaseRegister(void) { static int firstTime = 1; if (firstTime) { firstTime = 0; iocshRegister(&exampleDatabaseFuncDef, exampleDatabaseCallFunc); } } extern "C" { epicsExportRegistrar(exampleDatabaseRegister); }Other than exampleDatabase as part of the names it is boiler plate code.
registrar("exampleDatabaseRegister")It again is generic except for exampleDatabase as part of the name.
class epicsShareClass ExampleDatabase{ public: static void create(); };It defines a factory methods for creating the example database.
exampleDatabase.cpp is not generic. It shows how to create records of various types. Most of the records have only the default process method. The default process does nothing except that if a timeStamp field is present the time is set to the current time. Look at the code to see examples of how to create records.
exampleDatabaseMain.cpp is standard code to start a V3 IOC
exampleDatabaseInclude.dbd contains:
include "base.dbd" include "PVAServerRegister.dbd" include "registerChannelProviderLocal.dbd" include "dbPv.dbd" registrar("exampleDatabaseRegister")
base.dbd is standard way to include the base V3 code. PVAServerRegister.dbd is how the pvAccess Server code is included. registerChannelProviderLocal.dbd is how the local pva server is started. The local server is implemented by pvDatabaseCPP. dbPv.dbd is how pvaSrv, the pva server that accesses V3 revords, is started.
registrar("exampleDatabaseRegister") is the only example specific statement. It is used to start the example database.
This is where the V3 IOC is started. The st.cmd starts with normal way to start a V3 IOC. What is different is the statements after iocInit:
exampleDatabase startPVAServer
The first statement creates the example database. The second statement starts the pva server. After it is started clients can access the V4 records and the V3 records via pva.
This defines the pvData primitive types:
A pvData object consists of a set of fields where each field has one on the following types:
NOTE: In the examples alarm_t, time_t, and enum_t are used as type names. All have type structure. They are examples of special fields described later. The core part of pvData and pvAccess, which are discussed before section interlude treat them as type structure.
The following is a top level structure that has three sub-fields:
structure double value 5.0 alarm_t alarm int severity 0 int status 0 string message no alarm time_t timeStamp long secondsPastEpoch 0 int nanoseconds 0 int userTag 0
The following is an example where the value field is a scalar string array.
structure string[] value ["aaa","bbb","ccc","ddd"] time_t timeStamp long secondsPastEpoch 0 int nanoseconds 0 int userTag 0
The following is an example is a structure with a single subfield that is itself a structure.
structure enum_t value int index 0 string[] choices [true,false]
The following has two examples of a restricted union.
structure union value time_t long secondsPastEpoch 1000 int nanoseconds 0 int userTag 0 structure union value double 100000
This is like the previous example but now the value field is a variant union.
structure any value time_t long secondsPastEpoch 1000 int nanoseconds 0 int userTag 0 structure any value double 100000
The first example is a union array where each element is variant union. The second is where each element is a restricted union.
structure any[] value any (none) any double 1.245 ` structure union[] value union (none) union double 1.245
This is an example of a structure array where each element is a time_t structure.
structure time_t[] value time_t long secondsPastEpoch 1000 int nanoseconds 0 int userTag 0 time_t long secondsPastEpoch 3000 int nanoseconds 0 int userTag 0
This is a structure that has data for a power supply.
structure alarm_t alarm int severity 0 int status 0 string message time_t timestamp 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
Field string getID() Type getType() serialize/deserialize display Scalar ScalarType getScalarType() Union size_t getNumberFields() Field getField(string fieldName) size_t getFieldIndex(string fieldName) Field[] getFields() Field getField(size_t fieldIndex) string[] getFieldNames() string getFieldName(size_t fieldIndex) boolean isVariant() Array ArraySizeType getArraySizeType() size_t getMaximumCapacity() ScalarArray ScalarType getElementType() StructureArray Structure getStructure() UnionArray Union getUnion() Structure Field getField(string fieldName) size_t getFieldIndex(string fieldName) Field[] getFields() Field getField(size_t fieldIndex) string[] getFieldNames() string getFieldName(size_t fieldIndex)
This is the base class for the Introspection API. It has the members:
This is the API for all scalar types, i. e. boolean, byte, ... , string. It has method:
This is the API for type union. A union is a field that has a single subField. The subField has no name. A union can be either a variant union or a restricted union. The subField for a variant union can have any supported type. A restricted union has a Field array and a string array. Each element of the string array is associated with the corresponding element of the field array.
Union has the methods:
Base class for all array types. It has the methods:
This is the API for type scalarArray. It has the method:
This is the API for type structureArray. It has the method:
This is the API for type unionArray. It has the method:
This is the API for type structure. It has the methods:
FieldCreate is a factory for creating introspection objects.
FieldCreate FieldBuilder createFieldBuilder() Scalar createScalar(ScalarType scalarType) BoundedString createBoundedString(size_t maxLength) ScalarArray createScalarArray(ScalarType elementType) ScalarArray createFixedScalarArray(ScalarType elementType, size_t size) ScalarArray createBoundedScalarArray(ScalarType elementType, size_t bound) StructureArray createStructureArray(Structure elementStructure) UnionArray createUnionArray(Union elementUnion) UnionArray createVariantUnionArray() Structure createStructure() //Java does not implement Structure createStructure(string[] fieldNames, Field[] fields) Structure createStructure(string id, string[] fieldNames, Field[] fields) Structure appendField(Structure structure,string fieldName, Field field) Structure appendFields(Structure structure,string[] fieldNames, Field[] fields) Structure createStructure(Structure structToClone) // CPP does not implement Union createVariantUnion() Union createUnion(string[] fieldNames, Field[] fields) Union createUnion(string id, string[] fieldNames, Field[] fields)
FieldBuilder FieldBuilder setId(string id) FieldBuilder add(string name, ScalarType scalarType) FieldBuilder addBoundedString(string name, size_t maxLength) FieldBuilder add(string name, Field field) FieldBuilder addArray(string name, ScalarType scalarType) FieldBuilder addFixedArray(string name, ScalarType scalarType, size_t size) FieldBuilder addBoundedArray(string name, ScalarType scalarType, size_t bound) FieldBuilder addArray(string name, Field field) Structure createStructure() Union createUnion() FieldBuilder addNestedStructure(string name) FieldBuilder addNestedUnion(string name) FieldBuilder addNestedStructureArray(string name) FieldBuilder addNestedUnionArray(string name) FieldBuilder endNested()
The methods are:
This is an easier way to create introspection interfaces. A single instance can be used to create multiple introspection interfaces because everytime createStructure or createUnion is called the internal state is reset to start over. Each method except createStructure and createUnion return the FieldBuilder itself so that methods can be chained together. See the examples below. The methods are:
The first example creates a Structure with a single subField:
String[] fieldName = new String[1]; Field[] field = new Field[1]; fieldName[0] = "value"; field[0] = fieldCreate.createScalar(ScalarType.pvDouble); Structure structure = fieldCreate.createStructure(fieldName, field); System.out.println(structure);
This produces:
structure double value
Using FieldBuilder the code is:
FieldBuilder fb = fieldCreate.createFieldBuilder(); Structure structure = fb.add("value", ScalarType.pvDouble). createStructure(); System.out.println(structure);
The output is again:
structure double value
The next example shows how to create a structure that has three field: a value field that is a scalarArray with element type double, an alarm structure, and a timeStamp structure. Later examples show that fieldBuilder and standard fields make it much easier to create complex structures.
String[] fieldName = new String[3]; Field[] field = new Field[3]; fieldName[0] ="severity"; fieldName[1] ="status"; fieldName[2] ="message"; field[0] = fieldCreate.createScalar(ScalarType.pvInt); field[1] = fieldCreate.createScalar(ScalarType.pvInt); field[2] = fieldCreate.createScalar(ScalarType.pvString); Structure alarm = fieldCreate.createStructure(fieldName, field); fieldName = new String[3]; field = new Field[3]; fieldName[0] = "secondsPastEpoch"; fieldName[1] = "nanoseconds"; fieldName[2] = "userTag"; field[0] = fieldCreate.createScalar(ScalarType.pvLong); field[1] = fieldCreate.createScalar(ScalarType.pvInt); field[2] = fieldCreate.createScalar(ScalarType.pvInt); Structure timeStamp = fieldCreate.createStructure(fieldName, field); fieldName = new String[3]; field = new Field[3]; fieldName[0] = "value"; fieldName[1] = "alarm"; fieldName[2] = "timeStamp"; field[0] = fieldCreate.createScalarArray(ScalarType.pvDouble); field[1] = alarm; field[2] = timeStamp; Structure structure = fieldCreate.createStructure(fieldName, field); System.out.println(structure);This produces:
structure double[] value structure alarm int severity int status string message structure timeStamp long secondsPastEpoch int nanoseconds int userTag
The section after next shows the same example using FieldBuilder.
The first example creates a Structure with a single subField:
StringArray fieldName(1); FieldConstPtrArray field(1); fieldName[0] = "value"; field[0] = fieldCreate->createScalar(pvDouble); StructureConstPtr structure = fieldCreate->createStructure(fieldName, field); cout << *structure << endl;
This produces:
structure double value
The next example shows how to create a structure that has three field: a value field that is a scalarArray with element type double, an alarm structure, and a timeStamp structure.
size_t n = 3; StringArray fieldName(n); FieldConstPtrArray field(n); fieldName[0] ="severity"; fieldName[1] ="status"; fieldName[2] ="message"; field[0] = fieldCreate->createScalar(pvInt); field[1] = fieldCreate->createScalar(pvInt); field[2] = fieldCreate->createScalar(pvString); StructureConstPtr alarm = fieldCreate->createStructure(fieldName, field); fieldName = StringArray(n); field = FieldConstPtrArray(n); fieldName[0] = "secondsPastEpoch"; fieldName[1] = "nanoseconds"; fieldName[2] = "userTag"; field[0] = fieldCreate->createScalar(pvLong); field[1] = fieldCreate->createScalar(pvInt); field[2] = fieldCreate->createScalar(pvInt); StructureConstPtr timeStamp = fieldCreate->createStructure(fieldName, field); fieldName = StringArray(n); field = FieldConstPtrArray(n); fieldName[0] = "value"; fieldName[1] = "alarm"; fieldName[2] = "timeStamp"; field[0] = fieldCreate->createScalarArray(pvDouble); field[1] = alarm; field[2] = timeStamp; StructureConstPtr structure = fieldCreate->createStructure(fieldName, field); cout << *structure << endl;This produces:
structure double[] value structure alarm int severity int status string message structure timeStamp long secondsPastEpoch int nanoseconds int userTag
The next two sections shows the same example using FieldBuilder.
System.out.println("valueAlarmTimeStamp"); FieldBuilder fb = fieldCreate.createFieldBuilder(); Structure alarm = fb.add("severity", ScalarType.pvInt). add("status",ScalarType.pvInt). add("message",ScalarType.pvString). createStructure(); Structure timeStamp = fb.add("secondsPastEpoch", ScalarType.pvLong). add("nanoseconds",ScalarType.pvInt). add("userTag",ScalarType.pvInt). createStructure(); Structure structure = fb.addArray("value", ScalarType.pvDouble). add("alarm",alarm). add("timeStamp",timeStamp). createStructure(); System.out.println(structure);This produces:
valueAlarmTimeStamp structure double[] value structure alarm int severity int status string message structure timeStamp long secondsPastEpoch int nanoseconds int userTag
System.out.println("valueAlarmTimeStampNested"); FieldBuilder fb = fieldCreate.createFieldBuilder(); Structure structure = fb.addArray("value", ScalarType.pvDouble). addNestedStructure("alarm"). add("severity", ScalarType.pvInt). add("status",ScalarType.pvInt). add("message",ScalarType.pvString). endNested(). addNestedStructure("timeStamp"). add("secondsPastEpoch", ScalarType.pvLong). add("nanoseconds",ScalarType.pvInt). add("userTag",ScalarType.pvInt). endNested(). createStructure(); System.out.println(structure);This produces the same output as valueAlarmTimeStamp.
System.out.println("valueAlarmTimeStampEasy"); FieldBuilder fb = fieldCreate.createFieldBuilder(); Structure structure = fb.addArray("value", ScalarType.pvDouble). add("alarm",standardField.alarm()). add("timeStamp",standardField.timeStamp()). createStructure(); System.out.println(structure);This produces:
structure double[] value alarm_t alarm int severity int status string message time_t timeStamp long secondsPastEpoch int nanoseconds int userTag
System.out.println("union"); FieldBuilder fb = fieldCreate.createFieldBuilder(); Union union = fb.add("short", ScalarType.pvShort). add("long", ScalarType.pvLong). createUnion(); Structure structure = fb.add("value",union). createStructure(); System.out.println(structure);This produces:
union structure union value short short long long`
System.out.println("unionNested"); FieldBuilder fb = fieldCreate.createFieldBuilder(); Structure structure = fb.addNestedUnion("value"). add("short", ScalarType.pvShort). add("long", ScalarType.pvLong). endNested(). createStructure(); System.out.println(structure);This produces the same result as union.
System.out.println("unionArray"); FieldBuilder fb = fieldCreate.createFieldBuilder(); Union union = fb.add("short", ScalarType.pvShort). add("long", ScalarType.pvLong). createUnion(); Structure structure = fb.addArray("value",union). createStructure(); System.out.println(structure);This produces:
unionArray structure union[] value union short short long long
System.out.println("unionArrayNested"); FieldBuilder fb = fieldCreate.createFieldBuilder(); Structure structure = fb.addNestedUnionArray("value"). add("short", ScalarType.pvShort). add("long", ScalarType.pvLong). endNested(). createStructure(); System.out.println(structure);This produces the same result as unionArray.
System.out.println("structureArray"); FieldBuilder fb = fieldCreate.createFieldBuilder(); Structure subStruct = fb.add("short", ScalarType.pvShort). add("long", ScalarType.pvLong). createStructure(); Structure structure = fb.addArray("value",subStruct). createStructure(); System.out.println(structure);This produces:
structureArray structure structure[] value structure short short long long
System.out.println("structureArrayNested"); FieldBuilder fb = fieldCreate.createFieldBuilder(); Structure structure = fb.addNestedStructureArray("value"). add("short", ScalarType.pvShort). add("long", ScalarType.pvLong). endNested(). createStructure(); System.out.println(structure);`This produces the same result as structureArray.
cout << "valueAlarmTimeStamp\n"; FieldBuilderPtr fb = fieldCreate->createFieldBuilder(); StructureConstPtr alarm = fb->add("severity", pvInt)-> add("status",pvInt)-> add("message",pvString)-> createStructure(); StructureConstPtr timeStamp = fb->add("secondsPastEpoch", pvLong)-> add("nanoseconds",pvInt)-> add("userTag",pvInt)-> createStructure(); StructureConstPtr structure = fb->addArray("value", pvDouble)-> add("alarm",alarm)-> add("timeStamp",timeStamp)-> createStructure(); cout << *structure << endl;This produces:
valueAlarmTimeStamp structure double[] value structure alarm int severity int status string message structure timeStamp long secondsPastEpoch int nanoseconds int userTag
cout << "valueAlarmTimeStampNested\n"; FieldBuilderPtr fb = fieldCreate->createFieldBuilder(); StructureConstPtr structure = fb->addArray("value", pvDouble)-> addNestedStructure("alarm")-> add("severity", pvInt)-> add("status",pvInt)-> add("message",pvString)-> endNested()-> addNestedStructure("timeStamp")-> add("secondsPastEpoch", pvLong)-> add("nanoseconds",pvInt)-> add("userTag",pvInt)-> endNested()-> createStructure(); cout << *structure << endl;This produces the same output as valueAlarmTimeStamp.
cout << "valueAlarmTimeStampEasy\n"; FieldBuilderPtr fb = fieldCreate->createFieldBuilder(); StructureConstPtr structure = fb->addArray("value", pvDouble)-> add("alarm",standardField->alarm())-> add("timeStamp",standardField->timeStamp())-> createStructure(); cout << *structure << endl;This produces:
structure double[] value alarm_t alarm int severity int status string message time_t timeStamp long secondsPastEpoch int nanoseconds int userTag
cout << "union\n"; FieldBuilderPtr fb = fieldCreate->createFieldBuilder(); UnionConstPtr unionx = fb->add("short", pvShort)-> add("long", pvLong)-> createUnion(); StructureConstPtr structure = fb->add("value",unionx)-> createStructure(); cout << *structure << endl;This produces:
union structure union value short short long long`
cout << "unionNested\n"; FieldBuilderPtr fb = fieldCreate->createFieldBuilder(); StructureConstPtr structure = fb->addNestedUnion("value")-> add("short", pvShort)-> add("long", pvLong)-> endNested()-> createStructure(); cout << *structure << endl;This produces the same result as union.
cout << "unionArray\n"; FieldBuilderPtr fb = fieldCreate->createFieldBuilder(); UnionConstPtr unionx = fb->add("short", pvShort)-> add("long", pvLong)-> createUnion(); StructureConstPtr structure = fb->addArray("value",unionx)-> createStructure(); cout << *structure << endl;This produces:
unionArray structure union[] value union short short long long
cout << "unionArrayNested\n"; FieldBuilderPtr fb = fieldCreate->createFieldBuilder(); StructureConstPtr structure = fb->addNestedUnionArray("value")-> add("short", pvShort)-> add("long", pvLong)-> endNested()-> createStructure(); cout << *structure << endl;This produces the same result as unionArray.
cout << "structureArray\n"; FieldBuilderPtr fb = fieldCreate->createFieldBuilder(); StructureConstPtr subStruct = fb->add("short", pvShort)-> add("long", pvLong)-> createStructure(); StructureConstPtr structure = fb->addArray("value",subStruct)-> createStructure(); cout << *structure << endl;This produces:
structureArray structure structure[] value structure short short long long
cout << "structureArrayNested\n"; FieldBuilderPtr fb = fieldCreate->createFieldBuilder(); StructureConstPtr structure = fb->addNestedStructureArray("value")-> add("short", pvShort)-> add("long", pvLong)-> endNested()-> createStructure(); cout << *structure << endl;This produces the same result as structureArray.
PVField serialize/deserialize display string getFieldName() string getFullName() size_t getFieldOffset() size_t getNextFieldOffset() size_t getNumberFields() boolean isImmutable() void setImmutable() Field getField() PVStructure getParent() void postPut() void setPostHandler(PostHandler postHandler) PVScalar Scalar getScalar() PVScalarType // each scalarType, e. g. PVBoolean scalarType get() void put (scalarType value) PVUnion Union getUnion() PVField get() PVType get(Class c) //PVType is valid PVField extension PVField select(int index) PVType select(Class c,int index) PVField select(string fieldName) PVType select(Class c,string fieldName) int getSelectedIndex() string getSelectedFieldName() void set(PVField value) void set(int index, PVField value) void set(string fieldName, PVField value) PVArray Array getArray() size_t getLength( void setLength(size_t length) size_t getCapacity( void setCapacity(size_t length) boolean isCapacityMutable() void setCapacityMutable(boolean isMutable) PVScalarArray ScalarArray getScalarArray() PVScalarTypeArray // each scalarType, e.g. PVBooleanArray // C++ and Java have different semantics. See below PVUnionArray UnionArray getUnionArray() // C++ and Java have different semantics. See below PVStructureArray StructureArray getStructureArray() // C++ and Java have different semantics. See below.
Most methods are different for Java and C++. See following sections.
Most methods are different for Java and C++. See following sections.
Most methods are different for Java and C++. See following sections.
PVDataCreate PVField createPVField(Field field) PVField createPVField(PVField fieldToClone) PVScalar createPVScalar(Scalar scalar) PVScalar createPVScalar(ScalarType fieldType) PVScalar createPVScalar(PVScalar scalarToClone) PVScalarType createPVScalar(Class scalarType) // generic PVUnion createPVUnion(Union union) PVUnion createPVVariantUnion() PVUnion createPVUnion(PVUnion unionToClone) PVStructure createPVStructure(Structure structure) PVStructure createPVStructure(string[] fieldNames,PVField[] pvFields) PVStructure createPVStructure(PVStructure structToClone) PVScalarArray createPVScalarArray(ScalarArray array) PVScalarArray createPVScalarArray(ScalarType elementType) PVScalarArray createPVScalarArray(PVScalarArray arrayToClone) PVScalarTypeArray createPVScalarArray(Class element) // generic PVStructureArray createPVStructureArray(StructureArray structureArray) PVStructureArray createPVStructureArray(Struture structure) PVUnionArray createPVUnionArray(UnionArray unionArray) PVUnionArray createPVVariantUnionArray() PVUnionArray createPVUnionArray(Union union)where
The following is for PVDoubleArray. There are similar definitions for each scalarType.
public class DoubleArrayData { public double[] data public int offset } interface PVDoubleArray extends PVArray { int get(int offset, int len, DoubleArrayData data) int put(int offset,int len, double[] from, int fromOffset) void shareData(double[] from) }
For PVStructureArray and PVUnionArray the definitions are:
public class StructureArrayData { public PVStructure[] data public int offset } interface PVStructureArray extends PVArray { StructureArray getStructureArray() int get(int offset, int length, StructureArrayData data) int put(int offset,int length, PVStructure[] from, int fromOffset) void shareData(PVStructure[] from) } public class UnionArrayData { public PVUnion[] data public int offset } interface PVUnionArray extends PVArray{ UnionArray getUnionArray() int get(int offset, int length, UnionArrayData data) int put(int offset,int length, PVUnion[] from, int fromOffset) void shareData(PVUnion[] from) }
The C++ Array API inforces Copy On Write (COW) semantics. The actual definition is template based. But the following is the psuedo code for PVDoubleArray. Each scalarType, PVUnionArray, and PVStructureArray have similar psuedo code.
class PVDoubleArray ... shared_vector<const double> view() void swap(shared_vector<const double> other) void replace(const shared_vector<const double> next) shared_vector<double> reuse() ... // to change the raw array use code like: shared_vector<double> data(n) // put values into data and then pvDoubleArray->replace(freeze(data))
System.out.println("simple"); FieldBuilder fb = fieldCreate.createFieldBuilder(); Structure structure = fb.add("value", ScalarType.pvDouble). createStructure(); PVStructure pvStructure = pvDataCreate.createPVStructure(structure); PVDouble pvDouble = pvStructure.getSubField(PVDouble.class, "value"); pvDouble.put(10.0); System.out.println(pvStructure);This produces:
simple structure double value 10.0
System.out.println("valueAlarmTimeStamp"); FieldBuilder fb = fieldCreate.createFieldBuilder(); Structure structure = fb.addArray("value", ScalarType.pvDouble). add("alarm",standardField.alarm()). add("timeStamp",standardField.timeStamp()). createStructure(); PVStructure pvStructure = pvDataCreate.createPVStructure(structure); PVDoubleArray pvDoubleArray = pvStructure.getSubField(PVDoubleArray.class, "value"); int length = 4; double[] data = new double[length]; for (int i=0; <length; ++i) data[i] = i+1; convert.fromDoubleArray(pvDoubleArray, 0, length, data, 0); System.out.println(pvStructure);This produces:
valueAlarmTimeStamp structure double[] value [1.0,2.0,3.0,4.0] alarm_t alarm int severity 0 int status 0 string message time_t timeStamp long secondsPastEpoch 0 int nanoseconds 0 int userTag 0
System.out.println("union"); FieldBuilder fb = fieldCreate.createFieldBuilder(); Structure structure = fb.addNestedUnion("value"). add("short", ScalarType.pvShort). add("long", ScalarType.pvLong). endNested(). createStructure(); PVStructure pvStructure = pvDataCreate.createPVStructure(structure); PVUnion pvUnion = pvStructure.getSubField(PVUnion.class,"value"); PVLong pvLong = (PVLong)pvDataCreate.createPVScalar(ScalarType.pvLong); pvLong.put(1000); pvUnion.set("long",pvLong); System.out.println(pvStructure);This produces:
union structure union value long 1000
System.out.println("unionArray"); FieldBuilder fb = fieldCreate.createFieldBuilder(); Structure structure = fb.addNestedUnionArray("value"). add("short", ScalarType.pvShort). add("long", ScalarType.pvLong). endNested(). createStructure(); PVStructure pvStructure = pvDataCreate.createPVStructure(structure); PVUnionArray pvValue = pvStructure.getSubField(PVUnionArray.class,"value"); int len = 2; PVUnion[] pvUnions = new PVUnion[len]; for(int i=0; <len; ++i) pvUnions[i] = pvDataCreate.createPVUnion(pvValue.getUnionArray().getUnion()); pvUnions[0].select("short"); pvUnions[1].select("long"); PVShort pvShort = pvUnions[0].get(PVShort.class); pvShort.put((short)1); PVLong pvLong = pvUnions[1].get(PVLong.class); pvLong.put(5); pvValue.put(0, len, pvUnions, 0); System.out.println(pvStructure);This produces:
unionArray structure union[] value union short 1 union long 5
System.out.println("structureArray"); FieldBuilder fb = fieldCreate.createFieldBuilder(); Structure structure = fb.addNestedStructureArray("value"). add("short", ScalarType.pvShort). add("long", ScalarType.pvLong). endNested(). createStructure(); PVStructure pvStructure = pvDataCreate.createPVStructure(structure); PVStructureArray pvValue = pvStructure.getSubField(PVStructureArray.class,"value"); int len = 2; PVStructure[] pvStructures = new PVStructure[len]; for(int i=0; i<len; ++i) { pvStructures[i] = pvDataCreate.createPVStructure(pvValue.getStructureArray().getStructure()); PVStructure pvs = pvStructures[i]; PVShort pvShort = pvs.getSubField(PVShort.class,"short"); pvShort.put((short)i); PVLong pvLong = pvs.getSubField(PVLong.class,"long"); pvLong.put(i); } pvValue.put(0, len,pvStructures , 0); System.out.println(pvStructure);This produces:
structureArray structure structure[] value structure short short 0 long long 0 structure short short 1 long long 1
System.out.println("structureArray"); FieldBuilder fb = fieldCreate.createFieldBuilder(); Structure structure = fb.addNestedStructureArray("value"). add("short", ScalarType.pvShort). add("long", ScalarType.pvLong). endNested(). createStructure(); System.out.println(structure);`This produces the same result as structureArray.
cout << "simple\n"; FieldBuilderPtr fb = fieldCreate->createFieldBuilder(); StructureConstPtr structure = fb->add("value", pvDouble)-> createStructure(); PVStructurePtr pvStructure = pvDataCreate->createPVStructure(structure); PVDoublePtr pvDouble = pvStructure->getSubField<PVDouble>( "value"); pvDouble->put(10.0); cout << *pvStructure << endl;This produces:
simple structure double value 10.0
cout << "valueAlarmTimeStamp\n"; FieldBuilderPtr fb = fieldCreate->createFieldBuilder(); StructureConstPtr structure = fb->addArray("value", pvDouble)-> add("alarm",standardField->alarm())-> add("timeStamp",standardField->timeStamp())-> createStructure(); PVStructurePtr pvStructure = pvDataCreate->createPVStructure(structure); PVDoubleArrayPtr pvDoubleArray = pvStructure->getSubField<PVDoubleArray>("value"); size_t len = 4; PVDoubleArray::svector data(4); for(size_t i=0; i<len; ++i) data[i] = i+1; pvDoubleArray->replace(freeze(data)); cout << *pvStructure << endl;This produces:
valueAlarmTimeStamp structure double[] value [1.0,2.0,3.0,4.0] alarm_t alarm int severity 0 int status 0 string message time_t timeStamp long secondsPastEpoch 0 int nanoseconds 0 int userTag 0
cout << "unionNested\n"; FieldBuilderPtr fb = fieldCreate->createFieldBuilder(); StructureConstPtr structure = fb->addNestedUnion("value")-> add("short", pvShort)-> add("long", pvLong)-> endNested()-> createStructure(); PVStructurePtr pvStructure = pvDataCreate->createPVStructure(structure); PVLongPtr pvlong = pvDataCreate->createPVScalar<PVLong>(); pvlong->put(1000); PVUnionPtr pvUnion = pvStructure->getSubField<PVUnion>("value"); pvUnion->set("long",pvlong); cout << *pvStructure << endl;This produces:
union structure union value long 1000
cout << "unionArrayNested\n"; FieldBuilderPtr fb = fieldCreate->createFieldBuilder(); StructureConstPtr structure = fb->addNestedUnionArray("value")-> add("short", pvShort)-> add("long", pvLong)-> endNested()-> createStructure(); PVStructurePtr pvStructure = pvDataCreate->createPVStructure(structure); PVUnionArrayPtr pvValue = pvStructure->getSubField<PVUnionArray>("value"); size_t len = 2; PVUnionArray::svector pvUnions(len); for(size_t i=0; i<len; ++i) pvUnions[i] = pvDataCreate->createPVUnion(pvValue->getUnionArray()->getUnion()); pvUnions[0]->select("short"); pvUnions[1]->select("long"); PVShortPtr pvshort = pvUnions[0]->get<PVShort>(); pvshort->put(1); PVLongPtr pvlong = pvUnions[1]->get<PVLong>(); pvlong->put(5); pvValue->replace(freeze(pvUnions)); cout << *pvStructure << endl;This produces:
unionArray structure union[] value union short 1 union long 5
cout << "structureArrayNested\n"; FieldBuilderPtr fb = fieldCreate->createFieldBuilder(); StructureConstPtr structure = fb->addNestedStructureArray("value")-> add("short", pvShort)-> add("long", pvLong)-> endNested()-> createStructure(); PVStructurePtr pvStructure = pvDataCreate->createPVStructure(structure); PVStructureArrayPtr pvValue = pvStructure->getSubField<PVStructureArray>("value"); size_t len = 2; PVStructureArray::svector pvStructures(len); for(size_t i=0; i<len; ++i) { pvStructures[i] = pvDataCreate->createPVStructure( pvValue->getStructureArray()->getStructure()); PVStructurePtr pvs = pvStructures[i]; PVShortPtr pvshort = pvs->getSubField<PVShort>("short"); pvshort->put(i); PVLongPtr pvlong = pvs->getSubField<PVLong>("long"); pvlong->put(i); } pvValue->replace(freeze(pvStructures)); cout << *pvStructure << endl;This produces:
structureArray structure structure[] value structure short short 0 long long 0 structure short short 1 long long 1
System.out.println("structureArray"); FieldBuilder fb = fieldCreate.createFieldBuilder(); Structure structure = fb.addNestedStructureArray("value"). add("short", ScalarType.pvShort). add("long", ScalarType.pvLong). endNested(). createStructure(); System.out.println(structure);`This produces the same result as structureArray.
Some important features of pvAccess are:
In order to implement the above features pvAccess uses bitSets, where each bit is associated with a field. The following is a top level pvStructure and how bits from a bitSet are assigned:
bit# field 0 structure 1 double scalarValue 2 double[] scalarArrayValue 3 structure timeStamp 4 long secondsPastEpoch 5 int nanoSeconds 6 int userTag 7 union unionValue structure timeStamp long secondsPastEpoch int nanoSeconds int userTag 8 structure[] structureValue structure timeStamp long secondsPastEpoch int nanoSeconds int userTag structure timeStamp long secondsPastEpoch int nanoSeconds int userTag 9 any[] unionValue any structure timeStamp long secondsPastEpoch int nanoSeconds int userTag any double value 10 string lastValue
Note that bits for structure subfields are assigned recursively. But each scalar, union, scalarArray, structureArray, and unionArray field are assigned a single bit. This means that each subfield of a union, structuctureArray, or unionArray is treated just like a new top level field. If ANY change is made to a union, scalarArray, structureArray, or unionArray, the complete set of data for that field is sent.
Below the following are discussed:
An important featured provided by Convert is to copy data between compatible PVStructures.
Java feature: pvDataJava does a deep copies of all fields with the possible exception of scalar array fields. If the source and destination have the same scalarType and the source is immutable then the raw data array is shared and the destination is made immutable.
C++ feature: pvDataCPP does deep copies between scalar and structure fields but shallow copies between scalarArray, structureArray, and unionArray fields. For scalarArray fields this is safe because the implementation of arrays implements COW (Copy on Write) by making the array data const. This forces code to create new raw data in order to change a scalar array field. It also uses const for structureArray and unionArray fields but this does not force all elements of the array to be const. Thus the elements can be changed. Thus any code that wants to share a top level PVStructure must be very careful when changing the value of a union, structureArray, or unionArray field. The rule is that the union, structureArray, or unionArray must be replaced with a new value.
Since the pvCopy facility makes extensive use of Convert the same rules apply to it.
normativeTypes defines a set of standard structures. Each normative type consists of a set of mandatory fields, a set of optional fields, and any arbitrary number of extra fields. The mandatory and optional fields are meant for use by standard tools such as Display Managers and Alarm Handlers. The extra fields are for specialized tools.
normativeTypesCPP provides a set of helper classes for implementing and using normative types. At present it has support for the following:
For example NTScalar is defined as :
epics:nt/NTScalar:1.0 double value // mandatory and can be any numeric type string descriptor // optional alarm_t alarm // optional int severity int status string message time_t timeStamp // optional long secondsPastEpoch int nanoseconds int userTag display_t display // optional double limitLow double limitHigh string description string format string units control_t control // optional double limitLow double limitHigh double minStep string extra1 // extra string[] extra2 //
ChannelProviderRegistry ChannelProvider getProvider(string providerName) ChannelProvider createProvider(string providerName) string[] getProviderNames() ChannelProvider string getProviderName() ChannelFind channelFind( string channelName, ChannelFindRequester channelFindRequester) ChannelFind channelList( ChannelListRequester channelListRequester) Channel createChannel( string channelName, ChannelRequester, short priority) Channel createChannel( string channelName, ChannelRequester channelRequester, short priority, string address) ChannelFindRequester void channelFindResult( Status status, ChannelFind channelFind, boolean wasFound) ChannelFind ChannelProvider getChannelProvider() void cancelChannelFind()
This method is to be used to by local pvAccess implementations (e.g. pvAccess server queries pvIOCJava. A client can determine if a channel exists without creating a channel. The client must implement a requester interface and the implementation provides an interface that the client can use to cancel the request.
ChannelRequester extends Requester void channelCreated( Status status, Channel channel) void channelStateChange( Channel channel, ConnectionState connectionState) enum AccessRights { none, read, readWrite } Channel extends Requester ChannelProvider getProvider() string getRemoteAddress() ConnectionState getConnectionState() void destroy() string getChannelName() ChannelRequester getChannelRequester() boolean isConnected() AccessRights getAccessRights(PVField pvField) void getField(GetFieldRequester requester,string subField) ChannelProcess createChannelProcess( ChannelProcessRequester channelProcessRequester, PVStructure pvRequest) ChannelGet createChannelGet( ChannelGetRequester channelGetRequester, PVStructure pvRequest) ChannelPut createChannelPut( ChannelPutRequester channelPutRequester, PVStructure pvRequest) ChannelPutGet createChannelPutGet( ChannelPutGetRequester channelPutGetRequester, PVStructure pvRequest) ChannelRPC createChannelRPC( ChannelRPCRequester channelRPCRequester, PVStructure pvRequest) ChannelArray createChannelArray( ChannelArrayRequester channelArrayRequester, PVStructure pvRequest) Monitor createMonitor( MonitorRequester MonitorRequester, PVStructure pvRequest)
The caller must implement the interface ChannelRequester.
where
The remaining methods are described in later sections of this package overview.
Many of the interface described in the later sections are created via a create call that has as one of it's arguments:
PVStructure pvRequest
This is also discussed in a later section.
The method:
Channel.getField(GetFieldRequester requester, String subField);
Gets the introspection interface for the specified sub field of the record it which the channel is connected. The subField can be null, which means get the introspection interface for the entire record, or is of the form "name.name..." . Thus it can be a request for any field within a record. The requester must implement the interface:
interface GetFieldRequester extends Requester { void getDone(Status status, Field field); }
where
Many of the interfaces described in later sections extend the following interface.
interface ChannelRequest extends Lockable, Destroyable { Channel getChannel(); void cancel(); void lastRequest();
where
A ChannelProcess is created via a call to:
interface Channel extends Requester { ChannelProcess createChannelProcess( ChannelProcessRequester channelProcessRequester); }
The definition is:
ChannelProcessRequester extends Requester void channelProcessConnect( Status status, ChannelProcess channelProcess) void processDone( Status status, ChannelProcess channelProcess) ChannelProcess extends ChannelRequest void process()
The requester must implement this interface.
A ChannelGet is created via a call to:
interface Channel extends Requester { ChannelGet createChannelGet( ChannelGetRequester channelGetRequester, PVStructure pvRequest); }
The definition is:
ChannelGetRequester extends Requester void channelGetConnect( Status status, ChannelGet channelGet, Structure structure) void getDone( Status status, ChannelGet channelGet, PVStructure pvStructure, BitSet bitSet) ChannelGet extends ChannelRequest void get()
A ChannelPut is created via a call to:
interface Channel extends Requester { ChannelPut createChannelPut( ChannelPutRequester channelPutRequester, PVStructure pvRequest); }
The definition is:
ChannelPutRequester extends Requester void channelPutConnect( Status status, ChannelPut channelPut, Structure structure) void putDone( Status status, ChannelPut channelPut) void getDone( Status status, ChannelPut channelPut, PVStructure pvStructure, BitSet bitSet) ChannelPut extends ChannelRequest void put(PVStructure pvPutStructure, BitSet bitSet) void get()
The requester must implement this interface.
NOTE: Only one of put and get can be outstanding at the same time. Another get or put must not be issued until getDone or putDone is called.
A channelPutGet request puts data into a record, optionally processes the record, and gets data from the record.
A channel putGet is created via a call to:
interface Channel extends Requester { ChannelPutGet createChannelPutGet( ChannelPutGetRequester channelPutGetRequester, PVStructure pvRequest); }
The definition is:
ChannelPutGetRequester extends Requester void channelPutGetConnect( Status status, ChannelPutGet channelPutGet, Structure putStructure, Structure getStructure) void putGetDone( Status status, ChannelPutGet channelPutGet, PVStructure getPVStructure, BitSet getBitSet) void getPutDone( Status status, ChannelPutGet channelPutGet, PVStructure putPVStructure, BitSet putBitSet) void getGetDone( Status status, ChannelPutGet channelPutGet, PVStructure getPVStructure, BitSet getBitSet) ChannelPutGet extends ChannelRequest void putGet(PVStructure pvPutStructure, BitSet putBitSet) void getPut() void getGet()
The requester must implement this interface.
NOTE: Only one of putGet, getPut, or getGet can be outstanding at the same time. Another request must not be issued until the appropriate xxxDone is called.
ChannelArray provides the ability to read or write a sub-array of an array field in a record. Note that all the other transfer methods can also read or write arrays but always transfer entire arrays. ChannelArray provides the ability to transfer a subarray. A ChannelArray is created via a call to:
interface Channel extends Requester { ChannelArray createChannelArray( ChannelArrayRequester channelArrayRequester, PVStructure pvRequest); }
The definition is:
ChannelArrayRequester extends Requester void channelArrayConnect( Status status, ChannelArray channelArray, Array array) void putArrayDone( Status status, ChannelArray channelArray) void getArrayDone( Status status, ChannelArray channelArray, PVArray pvArray) void getLengthDone( Status status, ChannelArray channelArray, int length, int capacity) void setLengthDone( Status status, ChannelArray channelArray) ChannelArray extends ChannelRequest void putArray( PVArray putArray, int offset, int count, int stride) void getArray( int offset, int count, int stride) void getLength() void setLength( int length)
The requester must implement this interface.
Monitor provides the ability to set monitors on data in a PVRecord. What triggers a monitor depends on the monitor support in the server. The standard server provides support for the following: onPut, onChange, onAbsoluteChange, and onPercentChange.
A Monitor is created via a call to:
void createMonitor( MonitorRequester monitorRequester, PVStructure pvRequest); }
The definition is:
MonitorRequester extends Requester void monitorConnect(Status status, Monitor monitor, Structure structure)) void monitorEvent((Monitor monitor) void unlisten() Monitor Status start() Status stop() MonitorElement poll() void release(MonitorElement monitorElement) MonitorElement PVStructure getPVStructure() BitSet getChangedBitSet() BitSet getOverrunBitSet()
The requester must implement this interface.
The following is the Monitor interface which is defined in project pvData
interface Monitor extends Destroyable { Status start(); Status stop(); MonitorElement poll(); void release(MonitorElement monitorElement); }
where
A monitorElement is defined as:
interface MonitorElement { PVStructure getPVStructure(); BitSet getChangedBitSet(); BitSet getOverrunBitSet(); }
where
A ChannelRPC is like a channelPutGet except that a completely different pvStructure can be sent and returned for each request. It is created via a call to:
interface Channel extends Requester { ChannelRPC createChannelRPC( ChannelRPCRequester channelRPCRequester, PVStructure pvRequest); }
The definition is:
ChannelRPCRequester extends Requester void channelRPCConnect( Status status, ChannelRPC channelRPC) void requestDone( Status status, ChannelRPC channelRPC, PVStructure pvResponse) ChannelRPC extends ChannelRequest void request(PVStructure pvArgument)
The requester must implement this interface.
EasyPVA is a synchronous API for accessing PVData via PVAccess. It also provides a number of convenience methods. It allows the client to request access without checking for failure, but throws an exception when a reuest fails. A client can also check for failues and thus prevent failures.
The EasyPVA API has the following features:
Simple examples of using easyPVA:
// easyGet EasyPVAPtr easyPVA = EasyPVA::create(); double value = easyPVA->channel("exampleDouble")->get()->getData()->getDouble(); // easyPut EasyChannelPtr channel = easyPVA->channel("exampleDouble"); EasyPutPtr put = channel->put(); EasyPutDataPtr putData = put->getData(); putData->putDouble(3.0); put->put(); // easyMonitor EasyMonitorPtr monitor = easyPVA->channel("examplePowerSupply")->monitor(""); EasyMonitorDataPtr easyData = monitor->getData(); while(true) { monitor->waitEvent(); cout << "changed\n"; easyData->showChanged(cout); cout << "overrun\n"; easyData->showOverrun(cout); monitor->releaseEvent(); } // easyProcess EasyChannelPtr channel = easyPVA->channel("exampleDouble"); EasyProcessPtr process = channel->createProcess(); process->process();
A brief description of a pvDatabase is that it is a set of network accessible, smart, memory resident records. Each record has data composed of a top level PVStructure. Each record has a name which is the channelName for pvAccess. A local Channel Provider implements the complete ChannelProvider and Channel interfaces as defined by pvAccess. The local provider provides access to the records in the pvDatabase. This local provider is accessed by the remote pvAccess server. A record is smart because code can be attached to a record, which is accessed via a method named process.
Implementations for both Java and C++ are available. With the C++ implementation (pvDatabaseCPP) the pvDatabase can be provided via a Main program or can be part of a V3IOC. In the later case the IOC has both a database of V3 Records and a pvDatabase. This version allows the development of V4 services for V3IOCs.
exampleDatabaseEasyPVA.zip provides a good example of creating C++ PVRecords that are part of a V3IOC or run as a Main program. It has the following examples:
If the database is running then the following can access exampleHello:
pvput -r "argument" exampleHello World pvget -r "result.value" exampleHello exampleHello structure structure result string value Hello World
pvaSrv is a pvAccess server that runs in the EPICS V3 IOC
pvaSrv allows you to get, put and monitor V3 PVs (fields of EPICS DB records) over pvAccess, translating the value and its meta data (graphics limits, alarm status, timestamp) to or from V4 Normative Type (NT) pvData structures (NTScalar, NTScalarArray).
pvaPy provides a python interface to pvData and pvAccess.
The following:
#!/usr/bin/env python from pvaccess import Channel c = Channel('double01') oldValue = c.get().getDouble() print 'Got old value: ', oldValue value = oldValue + 1.1 print 'Putting value via putDouble(): ', value c.putDouble(value) newValue = c.get().getDouble() print 'Got new value: ', newValueproduces:
python examplePut.py Got old value: 5.3 Putting value via putDouble(): 6.4 Got new value: 6.4
pvAccessJava and pvAccessCPP implement the following providers:
Providers can be provided for other data sources. A provider must implement ChannelProvider and Channel. pvAccess supports an arbitrary number of providers. On the server side of remote pvAccess providers must be implemented, because it calls the providers to implement the CHannel methods.
At present C++ provides two server side providers:
Both pvDataJava and pvDataCPP have a Convert Facility. Although they have some common features they are different enough that they will be discussed separately. They main difference is support for scalar arrays.
The Java Convert facility supports sub-array copies between any two numeric arrays. It does a deep copy except for a complete copy between two array of the same type and the source array is immutable. In this case to calls the shareData method and also makes the destination array immutable.
The C++ faclity only supports complete array copies between two scalar arrays of the same type and only does a shallow copy. It also does a shallow copy for union, unionArray, and structureArray fields. It also has a separate facility that does sub-array copies between two arrays of the same type.
NOTE: 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.
This section describes the supported conversions between data types.
interface Convert { void getFullFieldName(StringBuilder builder,PVField pvField) void getString(StringBuilder buf,PVField pv, int indentLevel); void getString(StringBuilder buf,PVField pv); void fromString(PVScalar pv,String from); void fromString(PVScalarArray pv,String from); int fromStringArray(PVScalarArray pv, int offset, int len, String[]from, int fromOffset); int toStringArray(PVScalarArray pv, int offset, int len, String[]to, int toOffset); boolean isCopyCompatible(Field from, Field to); void copy(PVField from,PVField to); boolean isCopyScalarCompatible(Field from, Field to); void copyScalar(PVField from, PVField to); boolean isCopyScalarArrayCompatible(ScalarArray from, ScalarArray to); int copyScalarArray(PVScalarArray from, int offset, PVScalarArray to, int toOffset, int len); boolean isCopyStructureCompatible(Structure from, Structure to); void copyStructure(PVStructure from, PVStructure to); boolean isCopyUnionCompatible(Union from, Union to); void copyUnion(PVUnion from, PVUnion to); boolean isCopyStructureArrayCompatible(StructureArray from, StructureArray to); void copyStructureArray(PVStructureArray from, PVStructureArray to); boolean isCopyUnionArrayCompatible(UnionArray from, UnionArray to); void copyUnionArray(PVUnionArray from, PVUnionArray to); // For the following the pv Type must be PVByte, ...., PVDouble byte toByte(PVField pv); short toShort(PVField pv); int toInt(PVField pv); long toLong(PVField pv); float toFloat(PVField pv); double toDouble(PVField pv); String toString(PVScalar pv); void fromByte(PVField pv, byte from); void fromShort(PVField pv, short from); void fromInt(PVField pv, int from); void fromLong(PVField pv, long from); void fromUByte(PVField pv, byte from); void fromUShort(PVField pv, short from); void fromUInt(PVField pv, int from); void fromULong(PVField pv, long from); void fromFloat(PVField pv, float from); void fromDouble(PVField pv, double from); // For the following the element type must be pvByte, ...., pvDouble int toByteArray(PVScalarArray pv, int offset, int len, byte[]to, int toOffset); int toShortArray(PVScalarArray pv, int offset, int len, short[]to, int toOffset); int toIntArray(PVScalarArray pv, int offset, int len, int[]to, int toOffset); int toLongArray(PVScalarArray pv, int offset, int len, long[]to, int toOffset); int toFloatArray(PVScalarArray pv, int offset, int len, float[]to, int toOffset); int toDoubleArray(PVScalarArray pv, int offset, int len, double[]to, int toOffset); int fromByteArray(PVScalarArray pv, int offset, int len, byte[]from, fromOffset); int fromShortArray(PVScalarArray pv, int offset, int len, short[]from, fromOffset); int fromIntArray(PVScalarArray pv, int offset, int len, int[]from, fromOffset); int fromLongArray(PVScalarArray pv, int offset, int len, long[]from, fromOffset); int fromUByteArray(PVScalarArray pv, int offset, int len, byte[]from, fromOffset); int fromUShortArray(PVScalarArray pv, int offset, int len, short[]from, fromOffset); int fromUIntArray(PVScalarArray pv, int offset, int len, int[]from, fromOffset); int fromULongArray(PVScalarArray pv, int offset, int len, long[]from, fromOffset); int fromFloatArray(PVScalarArray pv, int offset, int len, float[]from, fromOffset); int fromDoubleArray(PVScalarArray pv, int offset, int len, double[]from, fromOffset); void newLine(StringBuilder builder, int indentLevel); }
The array methods all return the number of elements copied or converted. This can be less than len if the PVField array contains less than len elements.
newLine is a convenience method for code that implements toString It generates a newline and inserts blanks at the beginning of the newline.
The getString methods dump the data in the metadata syntax described in the pvData project overview. Note that the toString methods of PVField are implemented by calling these convert methods.
This section describes the supported conversions between data types.
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(std::string * buf,PVFieldPtr const & pvField); bool equals(PVFieldPtr const &a,PVFieldPtr const &b); bool equals(PVField &a,PVField &b); void getString(std::string * buf,PVFieldPtr const & pvField,int indentLevel); void getString(std::string * buf,PVFieldPtr const & pvField); void getString(std::string * buf,PVField const * pvField,int indentLevel); void getString(std::string * buf,PVField const * pvField); std::size_t fromString( PVStructurePtr const &pv, StringArray const & from, std::size_t fromStartIndex = 0); void fromString(PVScalarPtr const & pv, std::string const & from); std::size_t fromString(PVScalarArrayPtr const & pv, std::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); std::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(std::string * buf, int indentLevel); ... } extern ConvertPtr getConvert();
newLine is a convenience method for code that implements toString It generates a newline and inserts blanks at the beginning of the newline.
This supports sub-array copying between arrays that have the same type.
template<typename T> void copy( PVValueArray<T> & pvFrom, size_t fromOffset, size_t fromStride, PVValueArray<T> & pvTo, size_t toOffset, size_t toStride, size_t count); void copy( PVScalarArray & from, size_t fromOffset, size_t fromStride, PVScalarArray & to, size_t toOffset, size_t toStride, size_t count); void copy( PVStructureArray & from, size_t fromOffset, size_t fromStride, PVStructureArray & to, size_t toOffset, size_t toStride, size_t count); void copy( PVArray & from, size_t fromOffset, size_t fromStride, PVArray & to, size_t toOffset, size_t toStride, size_t count);
The last copy is the only one most client need to call. It either throws an error if the element types do not match or calls the other copy functions. The arguments are:
An exception is thrown if:
PVField has a method copy. It allows copying between any two compatible fields. Both fields must have the same type. For scalar and scalarArray conversion between the various scalarTypes is supported.
The following:
PVDataCreatePtr create = getPVDataCreate(); PVDoublePtr pvDouble = create->createPVScalar<PVDouble>(); PVBytePtr pvByte = create->createPVScalar<PVByte>(); pvByte->put(10); pvDouble->copy(*pvByte); cout << "double " << pvDouble << " byte " << pvByte << endl; PVStringPtr pvString = create->createPVScalar<PVString>(); pvString->copy(*pvByte); cout << "string " << pvString << " byte " << pvByte << endl;produces:
double 10 byte 10 string 10 byte 10
Likewise for scalarArray:
PVDataCreatePtr create = getPVDataCreate(); PVDoubleArrayPtr pvDoubleArray = create->createPVScalarArray<PVDoubleArray>(); PVByteArrayPtr pvByteArray = create->createPVScalarArray<PVByteArray>(); shared_vector<int8> data(2); data[0] = 1; data[1] = 10; pvByteArray->replace(freeze(data)); pvDoubleArray->copy(*pvByteArray); cout << "double " << pvDoubleArray << " byte " << pvByteArray << endl; PVStringArrayPtr pvStringArray = create->createPVScalarArray<PVStringArray>(); pvStringArray->copy(*pvByteArray); cout << "string " << pvStringArray << " byte " << pvByteArray << endl;produces:
double [1,10] byte [1,10] string [1,10] byte [1,10]
What has been defined prevously is the core part of pvData and pvAccess. Any code that is implemented via the above can be used to transfer data via the pva or the ca network protocol.
The remainder of this document describes additional features provided by pvData. These additional features make it easier to create services based on the pvAccess network protocol.
The introspection interface for every field has an ID, which is available via method:
class Field { ... string getID(); ... };
This section describes how the IDs are assigned.
boolean byte short int long ubyte ushort ulong float double string
boolean[] byte[] short[] int[] long[] ubyte[] ushort[] ulong[] float[] double[] string[]
any // variant union union // restricted union
any[] union[]
structure
alarm_t time_t display_t control_t enum_t alarmLimit_t valueAlarm_t
Issues:
string formatThe allowed syntax should be defined.
Like structure except that [] is appended.
Both pvDataJava and pvDataCPP provide facilities:
ChannelGet createChannelGet( ChannelGetRequester channelGetRequester, PVStructure pvRequest);
CreateRequest PVStructure createRequest(string request) string getMessage()
CreateRequest allows the clients to select an arbitrary subset of the fields in the top level structure associated with the channel. It also allows the client to specify options. Thus the client can specify:
NOTE: The term record is adapted from pvDatabase. A pvDatabase has a memory resident database of smart records. A pvAcccess channel is a connection to a record. A record has a top level PVStructure that holds the data for the record. A pvAcccess server can be implemented that does not use the pvDatabase model but it must provide top level PVStructures to which a pvAcccess Channel can be attached. pvaSrv, which provides access to iocCore V3 records, is an example that also accepts a pvRequest created by a call to createRequest.
A request argument has the syntax:
record[option,...]field(fieldDef,...)putField(fieldDef,...)getField(fieldDef,...) OR fieldDef,...
Thus a request consists of record options and sets of field definitions or just field definitions. A record option is of the form:
record[name=value,...]
A field,putFeld,getField is a comma separated set of fieldDefs which are of the form:
fullFieldName or fullFieldName[option,...] or fullFieldName{fieldDef} // recursive definition
A fullFieldName is the full name of a field in the PVRecord. The name in a generated data structure will have just the field name. If fieldName{request} is given then the generated data structure will have a structure field with subfields. Note that request is a recursive definition.
If request is null or an empty string than the entire top level structure of the PVRecord is selected.
The syntax was chosen to be easy to use and to parse:
At present the following record options are in use:
record[queueSize=2]A larger size can be specified.
record[process=false]
record[block=false]
Clients like CSS, Synoptic Displays, Alarm, and Archive only want access to some combination of the following fields: value, alarm, timeStamp, display, and control. If the request is for a record that has these all as top level fields the request string is just a comma separated list of the field names. For example:
"value,alarm,timeStamp"
If the record is does not have the desired field at the top level then the field can still be accessed but in this case the full structure is preserved. For example:
"alarm,timeStamp,power.value"
Will get the top level alarm and timeStamp and the value from a structure named power. Thus the above works for a record that is structured as follows:
powerSupply alarm timeStamp power value display ... ...What is returned to the client is:
powerSupply alarm timeStamp power value
The only option most clients want is to request that a record be processed as part of a get or put requests. This is done via requests like the following:
"record[process=true]field(value,alarm,timeStamp)"
The following examples are for a power supply record:
powerSupply alarm timeStamp power value alarm .. other fields voltage value alarm .. other fields current value alarm .. other fields .. other fields
The following request:
"field(alarm,timeStamp,power.value)"
Will return to the client the following:
record psSimple alarm_t alarm severity NONE status NONE message null time_t 2013-02-27 06:04:30.997 userTag 0 structure power double value 10.0
Note that if the actual record does not have a requested field than it will not be present in the structure returned to the client.
The following is the same except that a record option and an option for the value field will be given.
"record[process=true]field(alarm,timeStamp,power.value[monitorAlgorithm=onChange])"
The options are to process the record and to cause power.value to cause a monitor only if the value changes.
The following:
"field(alarm,timeStamp,power{value,alarm},current{value,alarm},voltage{value,alarm})"
Will return to the client the following:
record psEmbeded alarm_t alarm severity NONE status NONE message time_t 1969-12-31 19:00:00.000 userTag 0 structure power double value 0.0 structure current double value 0.0 alarm_t alarm severity NONE status NONE message structure voltage double value 0.0 alarm_t alarm severity NONE status NONE message
NOTE: This section is only of interest to someone who is implementing code that has to introspect a structure generated by createRequest.
pvRequest is a PVStructure that describes 1) record options and 2) field requests and options. It has the following structure:
structure structure record structure _options option ... structure field structure fieldName structure _options option ... structure fieldName structure _options option ... ... structure putField structure fieldName structure _options option ... structure fieldName structure _options option ... ... structure getField structure fieldName structure _options option ... structure fieldName structure _options option ... ...
where
Note:
An example of option is process.
Process is a record option:
structure structure record structure _options string process true
For example if process is an option to createGet then the record will be processed before data is fetched. NOTE: scalarType boolean is also supported.
The following is an example of a field option:
structure structure field structure value structure _options string monitorAlgorithm onChange
Some examples are:
request structure request alarm,timeStamp,power.value structure structure alarm structure timeStamp structure power structure value request record[process=true]field(alarm,timeStamp,power.value) structure structure record structure _options string process true structure field structure alarm structure timeStamp structure power structure value request record[process=true]field(alarm,timeStamp[algorithm=onChange,causeMonitor=false],power{value,alarm}) structure structure record structure _options string process true structure field structure alarm structure timeStamp structure _options string algorithm onChange string causeMonitor false structure power structure value structure alarm request record[process=true,xxx=yyy]field(alarm,timeStamp[causeMonitor=true],power.value) structure structure record structure _options string process true string xxx yyy structure field structure alarm structure timeStamp structure _options string causeMonitor true structure power structure value
This is the interface for mapping between a PVStructure that contain a copy of the data for a subset of the fields in a PVRecord. Note that this interface is NOT for a single PVStructure but for a single PVRecord and a single Structure introspection interface that describes a subset of the fields in the PVRecord. For example if a server supports monitor queues then the server will allocate a PVStructure for each queue element but will create a single PVCopy.
PVCopy PVMaster getPVMaster() void traverseMaster(PVCopyTraverseMasterCallback callback) Structure getStructure() PVStructure createPVStructure() int getCopyOffset(PVField masterPVField) int getCopyOffset(PVStructure masterPVStructure,PVField masterPVField) PVField getMasterPVField(int structureOffset) void initCopy(PVStructure pvCopy, BitSet bitSet,boolean masterLocked) void updateCopySetBitSet(PVStructure copyPVStructure,BitSet bitSet,boolean lockMaster) void updateCopyFromBitSet(PVStructure copyPVStructure,BitSet bitSet,boolean lockMaster) boolean updateMaster(PVStructure pvCopy,BitSet bitSet,boolean lockMaster) PVStructure getOptions(PVStructure copyPVStructure,int fieldOffset) String dump() }
where
This section is for services that use pvDatabaseCPP. Such services do not have to provide a top level PVStructure and methods init, process, and destroy. pvDatabaseCPP and pvAccessCPP provide a complete implementation of the server side of pvAccess. From the PVStructure a PVRecord is created. This record can be locked.
A server is providing data for multiple clients. Each client has it's own top level PVStructures that has data for a subset of the fields in the servers top level PVStructure. The service must be careful of how it updates data in it's top leve PVStructure or else data for a client can change after process completes and before it is sent to the client.
Previously the mapping between a PVStructure and it's associated bitSet as shown: bitSet for pvStructure
This can also be used to present guidelines for modifing fields in the top level PVStructure for the service:
The pvRecord must be locked whenever any field is modfied.
Any union, unionArray, or structureArray field that has a bit of the bitSet assigned to it must be replaced. Modifing subFields of the field is not permisible.
An enumerated structure is a structure that has fields:
enum_t int index string[] choices
PVEnumerated boolean attach(PVField pvField) void detach() boolean isAttached() boolean setIndex(int index) int getIndex() String getChoice() boolean choicesMutable() String[] getChoices() boolean setChoices(String[] choices)
where
An alarm structure is defined as follows:
alarm_t alarm int severity int status string message
Note that severity and status are NOT defined as enumerated structures. The reason is performance, i. e. prevent passing the array of choice strings everywhere. The AlarmStatus and AlarmSeverity provide the equivalent of choices for an enumerated structure.
Alarm Severity defines the possible alarm severities
enum AlarmSeverity NONE,MINOR,MAJOR,INVALID,UNDEFINED AlarmSeverity getSeverity(int value) final String[] alarmSeverityNames String[] getSeverityNames()where
Alarm Status defines the possible alarm status conditions
enum AlarmStatus NONE,DEVICE,DRIVER,RECORD,DB,CONF,UNDEFINED,CLIENT; AlarmStatus getStatus(int value) String[] alarmStatusNames String[] getStatusNames()where
Alarm String getMessage() void setMessage(String message) AlarmSeverity getSeverity() void setSeverity(AlarmSeverity alarmSeverity) AlarmStatus getStatus() void setStatus(AlarmStatus alarmStatus) }where
PVAlarm boolean attach(PVField pvField) void detach() boolean isAttached() void get(Alarm alarm) boolean set(Alarm alarm)
where
A timeStamp is represented by the following structure
time_t timeStamp long secondsPastEpoch int nanoseconds int userTag
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 normalized, i. e. it has is 0<=nanoseconds<nanoSecPerSec..
The definition of TimeStamp is:
TimeStamp void normalize() long getSecondsPastEpoch() long getEpicsSecondsPastEpoch() int getNanoseconds() int getUserTag() void setUserTag(int userTag) void put(long secondsPastEpoch,int nanoseconds) long getMilliSeconds() void put(long milliSeconds) void getCurrentTime() boolean equals(TimeStamp other) boolean lt(TimeStamp other) boolean le(TimeStamp other) void add(long seconds) void add(double seconds) double diff(TimeStamp a,TimeStamp b) }
where:
The TimeStamp class provides arithmetic and comparison methods for time stamps. The result is always kept in normalized form, which means that the nanosecond portion is 0≤=nano<nanoSecPerSec. Note that it is OK to have timeStamps for times previous to the epoch.
PVTimeStamp boolean attach(PVField pvField) void detach() boolean isAttached() void get(TimeStamp timeStamp) boolean set(TimeStamp timeStamp)where
Display information is represented by the following structure
display_t display double limitLow double limitHigh string description string format string units
Display double getLow() double getHigh() void setLow(double value) void setHigh(double value) String getDescription() void setDescription(String value) String getFormat() void setFormat(String value) String getUnits() void setUnits(String value)
where
PVDisplay boolean attach(PVField pvField) void detach() boolean isAttached() void get(Display display) boolean set(Display display)
where
Control information is represented by the following structure
structure control double limitLow double limitHigh double minStep
Control double getLow() double getHigh() void setLow(double value) void setHigh(double value)
where
PVControl boolean attach(PVField pvField) void detach() boolean isAttached() void get(Control control) boolean set(Control control)
where
This has unresolved issues.


When I read the announcement for the open address research internship a few weeks ago, I had mixed-feelings. On one hand I was excited. This position looks like a great opportunity to face the noble challenge of opening up the data silos dotting server rooms, desks, laptop bags, key chain thumb drives, etc. around the world. I was disappointed because this position is an internship. I already have a good job doing mapping work for the public and according to most career path narratives, seeking an internship would be a backwards move. It would mean moving from a stable job to a short-term position with no guarantee of anything beyond. The rationalist voices in my head were screaming, "It's just not practical!" Nonetheless, I am compelled to apply for this open data internship. Why?
First, I have parallel passions for geography and language. It's why in my undergraduate work at Ball State University I double-majored in geography and German. While my career path has leaned more towards the geography, my interest in languages remains unabated. This internship would allow me to again reunite my dual passions for language. I think my German experience and general curiosity for language would prove beneficial in carrying out the international scope of the open addressing research project.
Secong, open data are of sincere interest to me. I work in a government office where our data are sold to the public by the acre. We charge citizens for data about their own property! I've talked to neighboring municipalities about acquiring simple parcel data only to be told my options were to pay for a digital copy or come to their office and look at their computer screen. And when I express the curiousness of these closed-data situations, there is little sense of urgency to seek an alternative.
While I am committed to the slow process of bringing incremental change in my office's data policy, given my position as GIS Technician, it may be quite a while before I can really help alter the data conversation. In the meantime, I get my open data fix by contributing regularly to OpenStreetMap. Thus much of my interest in in this internship stems from the opportunity I see to contribute on a grander scale to the open data movement and to work with people who feel similarly passionate about the importance of open data.
Finally, I'm a work in progress. My programming skills, GIS knowledge, and data wrangle-fu have grown by leaps and bounds in the past couple of years. I've learned enough to know that there is a ton about digital mapping design, and data that I don't know. No matter what my University of Kentucky diploma says, I'm a master of nothing. Indeed, I've barely scratched the surface, but I want to dig deeper. Mapbox is known for surrounding itself with talented people who excel in a variety of fields. I look at this internship as an opportunity to feed off the collective knowledge of the Mapbox staff and develop further as a professional.
For whomever you ultimately decide to offer this internship position, I know it will be a great experience. And while my current work situation perhaps makes me an odd candidate for this internship, I hope you'll take some time to look over the application materials included on this webpage. I would relish the opportunity discuss how I might be able to work alongside the Mapbox team in contributing to the open address research project. If you have any questions, don't hesitate to contact me. Thank you for your time and consideration.
Maintained local thematic and parcel datasets for Scott County, collaborated with citizens, business partners, and public officials to create custom print and web map products, designed and maintained new GSCPC website, examined and signed off geographic accuracy of developer site plans, worked with planners to develop and visualize a proposed county-wide trail network, presented on web mapping at professional conferences
Mapped installation and removal of electric service and meters in the Lexington and Midway KU service areas, insured service location and connectivity accuracy by synthesizing information from field work and online research, adhered to departmental best practices to maintain consistency in LG&E-KU's distribution databases, logged and distributed completed work requests to appropriate colleagues, developed browser tool to accelerate the input of common text strings
Led weekly discussion sections and provided individual support for introductory GIS/digital mapping courses, provided technical support for undergraduate/graduate students involved in GIS-based community partnership projects, developed and coordinated course curriculum in cooperation with fellow teaching assistants and professors
Led weekly lab and provided individual support for introductory physical geography class, developed supplemental academic materials for students
Assisted clients with course work for undergraduate physical and human geography courses, assessed client progress, adapted tutoring sessions based on client progress and learning style
Developed Access-based media library check-out system, maintained media library, edited and created content for quarterly newsletter
I've worked quite a bit with TileMill in the past, but the was my first deep dive into Mapbox Studio. As a GIS technician for a local planning authority, the day-to-day mapping I do entails an attention to locational accuracy and precision in the characterization of map features. I'm increasingly intrigued by the communicative potential of generalization in reference maps. At the same time, I've been inspired by the communicative power of flat design. In its bold simplicity, flat design helps you say exactly what you need to say without a lot of clutter. This map was my attempt to bring the fresh colors and thick features often times seen in flat design.


[t]Thank you[/t]
[t]An email is send to your email address with the details of the job "{$VacancyTitle}". Thank you for your intrest and we are looking forward to your application. Please be aware that your data is not stored in our database, you still need to apply on a later moment.[/t]


‘A horrible map to look at’: No rain as Australia enters grim summer
by Robyn WuthAustralia is staring down the barrel of a horrific summer season that will drag scorching temperatures and extreme conditions well into the new year.
Livio Remano has never seen such extreme conditions in the 20 years he has worked with the Bureau of Meteorology, comparing the long term seasonal outlook to a bad chest X-ray.
“It’s horrible, it’s a horrible map to look at,” he said on Thursday.
“I have never seen this before in my life … the entire country of Australia is covered in deep red.”
That red colour means 70 to 80 per cent of the country is experiencing above-average temperatures, and is being blamed on something called an extremely positive Indian Ocean Diode.
Westerly winds weaken along the equator and push warm water to shift towards Africa during a typical IOD.
The wind changes allow cool water to rise from the depths of the ocean in the east, causing a temperature difference across the tropical Indian Ocean, with unusually cooler water in the east and warmer in the west.
It means atmospheric moisture levels drop in Australia’s northwest, which alters the path of weather systems coming from Australia’s west.
The result is less rainfall and higher than normal temperatures over parts of Australia.
Queensland is moving into its wet season but there is little chance of significant rainfall until January.
But eventually, Mr Remano says the rain will come.
Whatever rain does fall will be isolated and could cause more harm than good with the threat of dry lightning strikes sparking new fires.
“What we need is English rain, but it is not forthcoming – certainly not anytime soon,” he added.
-AAP


Form History with Validation Demo
a number
(between 0 and 100, inclusive)
:
a word
(10 or fewer characters)
:
State Index :
a number :
a word :
←
Reset
→


About Me
I'm a cool guy, you already know it. I do every task with perfaction.i can find easy way to solve any problem. I have diploma certificate of information technology from gujrat technological university.
Personal Information
- Name : Patel Vikas
- Age : 19 Years
- Email<EMAIL_ADDRESS>- Address : DAMAN,INDIA


Great job!
Data updated successfully.
Products___
Add New Product
Add Product
Title
Description
Type
Labtop
Mobile
Amount
Price


UW TA Application
Account Information
UW Email:
UW NetID:
Password:
Repeat password:
Personal Information
Photo:
First Name:
Last Name:
GPA:
Specific Grades:
CSE 143
MATH 126
INFO 101
GPA
Major:
Where You're Currently Located:
Grade Level (by year, NOT by credits):
Choose a Grade Level
Freshman
Sophomore
Junior
Senior
Availability
Are you legally able to be employed in this country?
Yes
No
Which tasks do you have experience in? (check all that apply)
Teaching Section
Hosting Office Hours
Course Infrastructure
Grading
Earliest Start Date:
How many hours do you want to work per week?:
Quarter You'd Like to TA:
Choose a Quarter
Autumn
Winter
Spring
Summer
Hours available
Sun
Mon
Tue
Wed
Thu
Fri
Sat
From
Until
Personal Statement
Do you have any prior teaching experience?
Why are you interested in teaching?
Why did you choose your major?


Before Change
def _get_joined_entity_utterances(dataset, language):
joined_entity_utterances = dict()
for entity_name, entity in iteritems(dataset[ENTITIES]):
utterances = list(entity[UTTERANCES])
// We also add a place holder value for builtin entities
if is_builtin_entity(entity_name):
utterances.append(
After Change
joined_entity_utterances = dict()
for entity_name, entity in iteritems(dataset[ENTITIES]):
// matches are performed in a case insensitive manner
utterances = set(u.lower() for u in entity[UTTERANCES])
patterns = []
for utterance in utterances:
tokens = tokenize_light(utterance, language)
pattern = WHITESPACE_PATTERN.join(regex_escape(t) for t in tokens)
patterns.append(pattern)
// We also add a placeholder value for builtin entities
if is_builtin_entity(entity_name):
placeholder = _get_entity_name_placeholder(entity_name, language)
patterns.append(regex_escape(placeholder))


| ID |
Purchase No. |
Order No. |
SP Name |
Purchase Type |
Total CNY |
Total USD |
Total USD |
Invoiced At
|
Invoice No. |
Invoice Amount CNY |
Invoice Amount USD |
Paid At
|
Payment Amount CNY |
Payment Amount USD |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Settled Total |
|
|
|
|
Invoiced Total |
|
|
Paid Total |
|
|
|
|
|
|
Not Settled Total |
|
|
|
|
Not Invoiced Total |
|
|
Not Paid Total |
|
|


Supplementary Figure 1
Correlation of TME scores with clinical characteristics. (A) No correlation between tumor immune score and lymph node metastasis in patients was found. There was no significant correlation between stromal score and T stage (B), lymph node metastasis (C), or gender (D), respectively.
Click here for additional data file.